feat: Phase 2 Workstream 3 — Go SDK (github.com/sentryagent/idp-sdk-go)

Single-package agentidp SDK in sdk-go/:
- AgentIdPClient composing AgentRegistryClient, CredentialClient,
  TokenServiceClient, AuditClient — all 14 endpoints covered
- Goroutine-safe TokenManager (sync.Mutex) with 60s refresh buffer
- AgentIdPError implementing error interface with Code/HTTPStatus/Details
- Context-aware: all service methods take context.Context as first arg
- doRequest shared helper; token endpoints use form-encoded POST directly
- go vet: 0 warnings | staticcheck: 0 warnings
- go test ./...: 37/37 passed | coverage: 81.0% (>80% gate)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
SentryAgent.ai Developer
2026-03-28 15:23:02 +00:00
parent c93562e685
commit 91c759f455
19 changed files with 2048 additions and 12 deletions

113
sdk-go/agents.go Normal file
View File

@@ -0,0 +1,113 @@
package agentidp
import (
"context"
"fmt"
"net/http"
"net/url"
"strings"
)
// AgentRegistryClient provides methods for the Agent Registry API endpoints.
// All methods take a context.Context as first argument.
type AgentRegistryClient struct {
baseURL string
getToken func(ctx context.Context) (string, error)
httpClient *http.Client
}
func newAgentRegistryClient(baseURL string, getToken func(ctx context.Context) (string, error), httpClient *http.Client) *AgentRegistryClient {
return &AgentRegistryClient{
baseURL: strings.TrimRight(baseURL, "/"),
getToken: getToken,
httpClient: httpClient,
}
}
// RegisterAgent registers a new AI agent identity.
// POST /api/v1/agents → 201 Agent
func (c *AgentRegistryClient) RegisterAgent(ctx context.Context, req RegisterAgentRequest) (*Agent, error) {
token, err := c.getToken(ctx)
if err != nil {
return nil, err
}
var agent Agent
if err := doRequest(ctx, c.httpClient, http.MethodPost, c.baseURL+"/api/v1/agents", req, token, &agent); err != nil {
return nil, err
}
return &agent, nil
}
// ListAgents returns a paginated list of registered agents.
// GET /api/v1/agents → 200 PaginatedAgents
func (c *AgentRegistryClient) ListAgents(ctx context.Context, params *ListAgentsParams) (*PaginatedAgents, error) {
token, err := c.getToken(ctx)
if err != nil {
return nil, err
}
rawURL := c.baseURL + "/api/v1/agents"
if params != nil {
q := url.Values{}
if params.Status != "" {
q.Set("status", params.Status)
}
if params.AgentType != "" {
q.Set("agentType", params.AgentType)
}
if params.DeploymentEnv != "" {
q.Set("deploymentEnv", params.DeploymentEnv)
}
if params.Page > 0 {
q.Set("page", fmt.Sprintf("%d", params.Page))
}
if params.Limit > 0 {
q.Set("limit", fmt.Sprintf("%d", params.Limit))
}
if len(q) > 0 {
rawURL += "?" + q.Encode()
}
}
var result PaginatedAgents
if err := doRequest(ctx, c.httpClient, http.MethodGet, rawURL, nil, token, &result); err != nil {
return nil, err
}
return &result, nil
}
// GetAgent retrieves a single agent by ID.
// GET /api/v1/agents/:id → 200 Agent
func (c *AgentRegistryClient) GetAgent(ctx context.Context, agentID string) (*Agent, error) {
token, err := c.getToken(ctx)
if err != nil {
return nil, err
}
var agent Agent
if err := doRequest(ctx, c.httpClient, http.MethodGet, c.baseURL+"/api/v1/agents/"+agentID, nil, token, &agent); err != nil {
return nil, err
}
return &agent, nil
}
// UpdateAgent partially updates an agent.
// PATCH /api/v1/agents/:id → 200 Agent
func (c *AgentRegistryClient) UpdateAgent(ctx context.Context, agentID string, req UpdateAgentRequest) (*Agent, error) {
token, err := c.getToken(ctx)
if err != nil {
return nil, err
}
var agent Agent
if err := doRequest(ctx, c.httpClient, http.MethodPatch, c.baseURL+"/api/v1/agents/"+agentID, req, token, &agent); err != nil {
return nil, err
}
return &agent, nil
}
// DecommissionAgent permanently removes an agent.
// DELETE /api/v1/agents/:id → 204 No Content
func (c *AgentRegistryClient) DecommissionAgent(ctx context.Context, agentID string) error {
token, err := c.getToken(ctx)
if err != nil {
return err
}
return doRequest(ctx, c.httpClient, http.MethodDelete, c.baseURL+"/api/v1/agents/"+agentID, nil, token, nil)
}