protocol

package
v1.19.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 24, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package protocol implements the admin-scoped `agent_config.*` Protocol methods the Console agent-config control plane consumes:

  • agent_config.get — read an agent's active config revision.
  • agent_config.set_revision — write a new immutable revision.
  • agent_config.list_revisions — the agent's revision chain.
  • agent_config.diff — server-side compare of two revisions.
  • agent_config.rollback — repoint the active pointer.
  • agent_config.skills.{list,upsert,delete} — skills control (the first consumer of the registry primitive; see skills.go).

Every write is admin-scoped (the verified `auth.ScopeAdmin` claim, enforced at the wire handler — the agent-config authorization model) and identity-mandatory. A config edit applies to the agent's NEXT run (next-turn projection — never mid-flight, per the concurrent-reuse contract).

The seam (CLAUDE.md §4.4)

The Service depends on the narrow `agentcfg.Registry` interface (the StateStore-backed concrete satisfies it) plus an optional `skills.SkillStore` for the skills consumer; tests inject fakes. The Service owns wire validation + the wire↔domain mapping; the registry owns persistence + the revision events; the SkillStore owns the skill rows + the skill events.

Identity is mandatory (CLAUDE.md §6 rule 9)

Every method takes the wire request's IdentityScope. An incomplete triple fails closed with ErrIdentityRequired. The handler overlays the verified identity onto the request body, so a caller cannot target another identity's config through this surface.

Concurrent reuse

A constructed *Service is immutable after NewService and safe to share across N goroutines: it holds only the registry / skill-store references + a clock + logger. Per-call state lives in arguments and locals.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrAuthRequired — the attacher signals the MCP server needs
	// authorization. The service parks on the unified pause/resume primitive.
	// Concrete attachers wrap this so the service reaches it via errors.Is.
	ErrAuthRequired = errors.New("agentcfg/protocol: mcp connection requires authorization")
	// ErrConnectionAttachUnavailable — add_mcp_connection was called but no
	// ConnectionAttacher is wired on this runtime (→ 501).
	ErrConnectionAttachUnavailable = errors.New("agentcfg/protocol: mcp connection attach not wired on this runtime")
	// ErrStdioNotAllowed — a stdio add named a command absent from the
	// fail-closed allowlist (→ 403). Adding a stdio server is the most
	// privileged action; the allowlist is the §7 RCE gate.
	ErrStdioNotAllowed = errors.New("agentcfg/protocol: stdio mcp connection command is not allowlisted")
	// ErrInvalidConnection — the connection descriptor failed validation
	// (empty name, unknown transport, missing/incoherent command/URL) (→ 400).
	ErrInvalidConnection = errors.New("agentcfg/protocol: invalid mcp connection descriptor")
	// ErrCoordinatorUnavailable — an auth-required attach fired but no
	// pause/resume Coordinator is wired (→ 500). Fail loud rather than drop
	// the auth requirement silently (CLAUDE.md §13).
	ErrCoordinatorUnavailable = errors.New("agentcfg/protocol: pause/resume coordinator not wired for the mcp oauth path")
)

Add-connection sentinel errors. The wire handler maps each onto a canonical Protocol Code + HTTP status; in-process callers compare with errors.Is.

View Source
var (
	// ErrConnectionNotFound — remove_mcp_connection named a connection that is
	// not in the agent's active revision (never runtime-added, or already
	// removed). No revision recorded, no event emitted (→ 404).
	ErrConnectionNotFound = errors.New("agentcfg/protocol: mcp connection not found in the agent's active revision")
	// ErrBootDeclaredConnection — remove_mcp_connection named a server that is
	// declared in the boot yaml (`tools.mcp_servers`). Distinct from
	// ErrConnectionNotFound: the verb governs revisioned state only; a
	// boot-declared server is edited in yaml + restart, not removed through
	// the control plane. No revision recorded, no event emitted (→ 400).
	ErrBootDeclaredConnection = errors.New("agentcfg/protocol: connection is boot-declared (yaml) — edit tools.mcp_servers and restart; the control plane governs runtime-added connections only")
)

Remove-connection sentinel errors. The wire handler maps each onto a canonical Protocol Code + HTTP status; in-process callers compare with errors.Is.

View Source
var (
	// ErrIdentityRequired — the request carried an incomplete identity
	// triple or an empty agent id. Fails closed.
	ErrIdentityRequired = errors.New("agentcfg/protocol: identity scope incomplete")
	// ErrMisconfigured — NewService was called with a nil registry.
	ErrMisconfigured = errors.New("agentcfg/protocol: NewService missing a mandatory dependency")
	// ErrSkillsUnavailable — a skills method was called but no SkillStore
	// was wired into the Service.
	ErrSkillsUnavailable = errors.New("agentcfg/protocol: skills control not wired on this runtime")
	// ErrUnknownModel — a set_llm_params (or a set_revision carrying an
	// LLMParams.Model) named a model with no configured ModelProfile. The
	// per-agent model is validated at set time (parity with the tenant
	// model-swap), so an invalid model can never be persisted — fail loud,
	// never a silent fallback (CLAUDE.md §13).
	ErrUnknownModel = errors.New("agentcfg/protocol: unknown model (no configured ModelProfile)")
	// ErrInvalidLLMParams — a set_llm_params (or a set_revision carrying an
	// LLMParams section) supplied an out-of-range sampling value (temperature
	// outside [0,2], non-positive max-tokens, or an unknown reasoning-effort).
	// Validated at set time so an invalid value never reaches a run (parity
	// with runs.set_overrides), fail loud (CLAUDE.md §13).
	ErrInvalidLLMParams = errors.New("agentcfg/protocol: invalid LLM parameters")
	// ErrInvalidHooks — a set_revision carrying a hooks section supplied an
	// invalid run-completion hook (a negative timeout_ms). Validated at set
	// time so an invalid value is rejected loud BEFORE any registry write —
	// parity with the yaml validator's negative-timeout rejection; the
	// normalizer's negative→0 coercion is defence-in-depth behind this gate,
	// never the primary posture (CLAUDE.md §13).
	ErrInvalidHooks = errors.New("agentcfg/protocol: invalid hooks section")
	// ErrInvalidToolExposureLoading — a set_tool_exposure (or a set_revision
	// carrying a ToolExposure section) supplied a server_loading_modes /
	// tool_loading_modes entry with an empty key or a value outside
	// "always"|"deferred". Validated at set time BEFORE any registry write
	// so an invalid override can never be persisted — no revision, no
	// event — fail loud, never a silent drop (CLAUDE.md §13).
	ErrInvalidToolExposureLoading = errors.New("agentcfg/protocol: invalid tool-loading-mode override")
	// ErrInvalidNaming — a set_revision carrying a naming section supplied an
	// invalid session auto-naming policy: a negative after_turns / repeat_every
	// / max_repetitions, a max_title_len outside [8,200], a repeat_every > 0
	// with max_repetitions < 1 (no unlimited value exists), or an unknown
	// model. Validated at set time BEFORE any registry write so an invalid
	// policy can never be persisted — fail loud, never a silent clamp
	// (CLAUDE.md §13). The model is validated via the same validateModel path
	// as set_llm_params.
	ErrInvalidNaming = errors.New("agentcfg/protocol: invalid naming section")
)

Sentinel errors the Service returns. The wire handler maps each onto a canonical Protocol Code + HTTP status; in-process callers compare with errors.Is.

View Source
var (
	// ErrInvalidLLMProvider — the descriptor failed validation (empty name /
	// provider, empty/non-remote credential_source, empty inference_broker)
	// (→ 400).
	ErrInvalidLLMProvider = errors.New("agentcfg/protocol: invalid llm provider descriptor")
	// ErrLLMProviderBrokerUnknown — the descriptor's inference_broker resolves
	// to no boot-declared broker (→ 400). No admin-writable field determines a
	// sink, so an unknown broker is a loud client error, never a silent accept.
	ErrLLMProviderBrokerUnknown = errors.New("agentcfg/protocol: inference_broker resolves to no boot-declared broker")
	// ErrLLMProviderInstallUnavailable — set_llm_provider was called but no
	// LLMProviderInstaller is wired on this runtime (→ 501).
	ErrLLMProviderInstallUnavailable = errors.New("agentcfg/protocol: llm provider install not wired on this runtime")
)

Inference-provider install sentinel errors. The wire handler maps each onto a canonical Protocol Code + HTTP status.

View Source
var (
	// ErrInvalidProvider — the provider descriptor failed validation (empty
	// name, wrong driver, empty/wrong credential_source, empty credential_broker)
	// (→ 400).
	ErrInvalidProvider = errors.New("agentcfg/protocol: invalid oauth provider descriptor")
	// ErrBootDeclaredProvider — set/remove_oauth_provider named a boot-declared
	// (yaml) provider — a DISTINCT loud error (boot wins; edit yaml + restart)
	// (→ 400).
	ErrBootDeclaredProvider = errors.New("agentcfg/protocol: oauth provider is boot-declared (edit yaml + restart, not the control plane)")
	// ErrProviderNotFound — remove_oauth_provider named a provider absent from
	// the agent's revisioned installed-provider set (→ 404).
	ErrProviderNotFound = errors.New("agentcfg/protocol: oauth provider not found in the agent's installed set")
	// ErrProviderInstallUnavailable — set/remove_oauth_provider was called but
	// no ProviderInstaller is wired on this runtime (→ 501).
	ErrProviderInstallUnavailable = errors.New("agentcfg/protocol: oauth provider install not wired on this runtime")
	// ErrProviderBrokerUnknown — the descriptor's credential_broker resolves to
	// no boot-declared broker (→ 400). The installer wraps its own broker error;
	// this sentinel lets the wire handler classify it as a client error.
	ErrProviderBrokerUnknown = errors.New("agentcfg/protocol: credential_broker resolves to no boot-declared broker")
	// ErrWireDescriptorNotAllowed — a provider descriptor (set_oauth_provider or
	// an add_mcp_connection inline binding) carried a credential-sink field
	// (token_url / audience / remote) while the fail-closed
	// tools.allow_wire_oauth_descriptor opt-in was OFF (→ 400). The default
	// zero-URL name-only posture is unchanged; the reject names the offending
	// field + the opt-in key.
	ErrWireDescriptorNotAllowed = errors.New("agentcfg/protocol: wire-carried oauth-provider descriptor is not allowed (the fail-closed tools.allow_wire_oauth_descriptor opt-in is off)")
)

Provider install/uninstall sentinel errors. The wire handler maps each onto a canonical Protocol Code + HTTP status.

View Source
var ErrDiscoveryOriginsNotHTTP = errors.New("agentcfg/protocol: connection is a stdio transport — OAuth-discovery origins apply only to http connections")

ErrDiscoveryOriginsNotHTTP — set_mcp_discovery_origins named a stdio-transport connection. A stdio server speaks over a subprocess pipe with no HTTP 401 challenge and no discovery walk, so an allow-list is meaningless — refused, never stored (→ 400).

View Source
var ErrDiscoveryTargetNotLive = errors.New("agentcfg/protocol: connection not attached in the live MCP registry — allowance recorded in the revision, applied on next reconcile")

ErrDiscoveryTargetNotLive — the named connection EXISTS in the active revision but is not attached in the live MCP registry (its server was never reached, or it is awaiting the next run-start reconcile). The applier adapter translates the driver's server-not-found into this sentinel so the setter can DEGRADE — record the allowance in the revision with applied_live=false, so the run-start allowance-reconcile applies it once the server comes online — instead of failing the write and rolling the revision back. This matches the nil-applier path (revision-only) and the sibling revision-only verbs. It is DISTINCT from ErrConnectionNotFound (the connection is absent from the revision entirely, which still fails loud).

View Source
var ErrSessionOverlayUnavailable = errors.New("agentcfg/protocol: session safe-subset control not wired on this runtime")

ErrSessionOverlayUnavailable — a session-safe method was called but no session-overlay store was wired into the Service.

Functions

This section is empty.

Types

type AttachRequest

type AttachRequest struct {
	// Identity is the verified caller triple (the attach runs under it; the
	// driver stamps it on transport-side events).
	Identity identity.Identity
	// AgentID is the agent whose config revision owns this runtime-added
	// connection. With Identity.TenantID it forms the (tenant, agent)
	// reconcile-view owner tag the attacher stamps on the registry entry so a
	// run-start reconcile scopes to its own owner. Registration metadata, never
	// an isolation key.
	AgentID string
	// Name is the unique MCP source id.
	Name string
	// Transport is "stdio" or "http".
	Transport agentcfg.MCPTransport
	// Command is the stdio argv (argv[0] is the binary; no shell).
	Command []string
	// URL is the http(s) endpoint.
	URL string
	// Headers are operator-supplied auth headers used ONLY for the live
	// attach. SECRET — never persisted (CLAUDE.md §7).
	Headers map[string]string
	// OAuthProvider is the non-secret provider NAME to bind for per-identity
	// southbound bearer injection (empty leaves the connection on its static
	// Headers). The attacher resolves it against the declared registry.
	OAuthProvider string
	// MetaAnnotations is the non-secret operator `_meta` annotation set the
	// attacher carries onto the live connection's per-call `_meta`.
	MetaAnnotations map[string]string
	// OAuthDiscoveryAllowedOrigins is the non-secret per-connection cross-origin
	// allow-list for OAuth-requirement discovery fetches. The attacher carries
	// it into the config.MCPServerConfig it builds so the live registry snapshots
	// it (closing the wiring gap — the walker's allowance input now flows from
	// the add request through to the registry, no longer inert for a
	// runtime-added connection). Empty leaves the authorization-server hop
	// needs-allowance.
	OAuthDiscoveryAllowedOrigins []string
}

AttachRequest is the input to a ConnectionAttacher. It carries the non-secret descriptor PLUS the optional operator-supplied auth headers used ONLY for the live transport — the attacher never persists them.

type Clock

type Clock func() time.Time

Clock is the time source the Service stamps response timestamps from.

type ConnectionAttacher

type ConnectionAttacher interface {
	Attach(ctx context.Context, req AttachRequest) error
}

ConnectionAttacher drives the real MCP attach lifecycle for a runtime add: dial → `initialize` handshake → discover → register, fail-loud per step. It is the seam that keeps the concrete MCP driver out of this package (the §4.4 boundary): the cmd/harbor + devstack boundary injects a concrete that builds a `config.MCPServerConfig` and calls the MCP driver's `Attach`.

Attach returns:

  • nil on a successful attach (online — the server's tools are registered on the live catalog);
  • an error wrapping ErrAuthRequired when the server needs authorization (the service parks on the unified pause/resume primitive);
  • any other error when an attach step failed (the service records the `failed` lifecycle, never a half-attached server).

type ConnectionState

type ConnectionState string

ConnectionState is the explicit attach lifecycle state surfaced on the response + the lifecycle events. The set is closed.

const (
	// ConnectionStatePending — the attach has begun (dial → handshake →
	// discover → register). The transient initial state.
	ConnectionStatePending ConnectionState = "pending"
	// ConnectionStateOnline — the attach completed; the server's tools are
	// registered on the live catalog.
	ConnectionStateOnline ConnectionState = "online"
	// ConnectionStateFailed — an attach step failed; no revision recorded,
	// no half-attached server registered.
	ConnectionStateFailed ConnectionState = "failed"
	// ConnectionStateAuthRequired — the attach parked on the unified
	// pause/resume primitive awaiting authorization. NOTE: the resume
	// continuation that re-drives the attach to online is not yet
	// implemented — resume currently only releases the pause (tracked in
	// issue #375). The descriptor revision is recorded; the server comes
	// online on a subsequent (authorized) add.
	ConnectionStateAuthRequired ConnectionState = "auth_required"
)

The canonical attach lifecycle states.

type DiscoveryOriginApplier added in v1.14.0

type DiscoveryOriginApplier interface {
	// SetOAuthDiscoveryOrigins FULL-REPLACES the named connection's allow-list on
	// the live registry and returns the prior set so the caller computes the
	// granted / revoked delta. Identity-mandatory for authorization (the registry
	// stays bare-name). A revoke also prunes the recorded requirement's
	// now-unallowed authorization-server entries.
	SetOAuthDiscoveryOrigins(ctx context.Context, name string, origins []string) (prev []string, err error)
}

DiscoveryOriginApplier is the driver-agnostic seam the discovery-allowance write (and the run-start allowance-reconcile) use to apply a connection's OAuth-discovery cross-origin allow-list to the LIVE MCP registry. The concrete (wired at the cmd/harbor + devstack boundary) delegates to the process-global bare-name registry's SetOAuthDiscoveryOrigins mutator; keeping it an injected interface preserves this package's §4.4 boundary (no concrete MCP driver import here).

type LLMProviderInstaller added in v1.17.0

type LLMProviderInstaller interface {
	// InstallLLMProvider validates the descriptor's inference_broker against
	// the boot broker set, builds + connects the broker-pull source, and
	// installs the binding owner-tagged under (tenant, agentID). An unknown
	// broker or a connect failure fails loud. A re-install by the same owner
	// replaces (and closes) the prior binding (the rotate path).
	InstallLLMProvider(ctx context.Context, tenant, agentID string, desc agentcfg.LLMProviderDescriptor) error
	// UninstallLLMProvider removes the named binding and CLOSES it — the live
	// key is zeroed so a subsequently-bound call fails loud rather than serving
	// the old key. A missing name is an idempotent no-op.
	UninstallLLMProvider(ctx context.Context, name string) error
}

LLMProviderInstaller is the driver-agnostic seam the set_llm_provider verb (and the run-start provider reconcile) uses to install / uninstall a zero-URL, broker-pull inference provider on the LIVE owner-tagged set. The concrete (wired at the cmd/harbor + devstack boundary) resolves the descriptor's inference_broker against the boot broker set, builds the InferenceKeySource over the runtime's shared LiveKey, connects it (fail-loud), and installs it owner-tagged; keeping it an injected interface preserves this package's §4.4 boundary (no concrete LLM-credential construction here).

type Option

type Option func(*Service)

Option configures NewService.

func WithAllowWireOAuthDescriptor added in v1.18.0

func WithAllowWireOAuthDescriptor(allow bool) Option

WithAllowWireOAuthDescriptor sets the effective DEV-ONLY, fail-closed opt-in that permits set_oauth_provider / add_mcp_connection to carry a FULL OAuth provider binding over the wire (token_url / audience / scopes / remote{}). The caller passes (tools.allow_wire_oauth_descriptor config flag) OR (the HARBOR_ALLOW_WIRE_OAUTH_DESCRIPTOR boot env). Default (option not applied) is false / fail-closed — a wire descriptor carrying any credential-sink field is rejected, the zero-URL name-only posture unchanged. Injected at the cmd/harbor + devstack boundary; never Protocol-writable.

func WithBootDeclaredMCPServers added in v1.11.0

func WithBootDeclaredMCPServers(names []string) Option

WithBootDeclaredMCPServers records the set of MCP server names declared in the boot yaml (`tools.mcp_servers[].name`). `remove_mcp_connection` rejects a name in this set with ErrBootDeclaredConnection (distinct from the unknown-name error) — a boot-declared server is not revisioned state and is edited in yaml + restart. An empty / nil list leaves every unknown name a plain not-found. Injected at the cmd/harbor + devstack boundary from the loaded config so the verb (and the run-start reconcile, which never detaches a boot server) share one authoritative set.

func WithBootDeclaredOAuthProviders added in v1.14.0

func WithBootDeclaredOAuthProviders(names []string) Option

WithBootDeclaredOAuthProviders sets the set of OAuth provider names declared in the boot yaml. set_oauth_provider / remove_oauth_provider reject a name in this set with ErrBootDeclaredProvider (boot wins; edit yaml + restart). An empty / nil list leaves every unknown name a plain not-found (for remove) or installable (for set). Injected at the cmd/harbor + devstack boundary.

func WithBus

func WithBus(b events.EventBus) Option

WithBus wires the EventBus the tool-exposure consumer publishes the `mcp.connection.paused` / `.resumed` overlay events through. A nil bus leaves those events unpublished (the revision is still recorded — the generic `agent.config.revised` still fires from the registry).

func WithClock

func WithClock(c Clock) Option

WithClock injects the time source. Defaults to time.Now.

func WithConnectionAttacher

func WithConnectionAttacher(a ConnectionAttacher) Option

WithConnectionAttacher wires the concrete that drives the real MCP attach lifecycle for `agent_config.add_mcp_connection`. A nil attacher leaves the method returning ErrConnectionAttachUnavailable (→ 501 at the wire edge). The concrete (which imports the MCP driver) is injected at the cmd/harbor + devstack boundary; this package depends only on the interface.

func WithCoordinator

func WithCoordinator(c pauseresume.Coordinator) Option

WithCoordinator wires the unified pause/resume primitive an auth-required MCP attach parks on. A nil coordinator leaves an auth-required attach failing loud with ErrCoordinatorUnavailable (never a silent drop).

func WithDiscoveryOriginApplier added in v1.14.0

func WithDiscoveryOriginApplier(a DiscoveryOriginApplier) Option

WithDiscoveryOriginApplier wires the concrete that applies a connection's OAuth-discovery cross-origin allow-list to the LIVE MCP registry for `agent_config.set_mcp_discovery_origins` (and the run-start allowance-reconcile). A nil applier leaves the write recording the revision but reporting applied_live=false. The concrete (which imports the MCP driver) is injected at the cmd/harbor + devstack boundary; this package depends only on the interface.

func WithInferenceBrokers added in v1.17.0

func WithInferenceBrokers(names []string) Option

WithInferenceBrokers sets the set of boot-declared inference-broker names (`llm.inference_brokers[].name`). set_llm_provider rejects a descriptor whose inference_broker is not in this set with ErrLLMProviderBrokerUnknown (400) — no admin-writable field determines a credential sink (the credential-plane invariant). An empty / nil list leaves EVERY broker name unknown (the fail-closed default). Injected at the cmd/harbor + devstack boundary from the loaded config.

func WithLLMProviderInstaller added in v1.17.0

func WithLLMProviderInstaller(a LLMProviderInstaller) Option

WithLLMProviderInstaller wires the concrete that installs / uninstalls a Protocol-installed, zero-URL broker-pull inference provider binding live into the owner-tagged provider set for `agent_config.set_llm_provider`. A nil installer leaves the verb returning ErrLLMProviderInstallUnavailable (→ 501). The concrete (which resolves the boot inference broker + builds the InferenceKeySource) is injected at the cmd/harbor + devstack boundary; this package depends only on the interface.

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets the slog.Logger. A nil logger routes to slog.Default().

func WithProviderInstaller added in v1.14.0

func WithProviderInstaller(a ProviderInstaller) Option

WithProviderInstaller wires the concrete that installs / uninstalls a Protocol-installed, zero-URL OAuth provider live into the owner-tagged provider set for `agent_config.set_oauth_provider` / `remove_oauth_provider` (and the run-start provider reconcile). A nil installer leaves the two verbs returning ErrProviderInstallUnavailable (→ 501). The concrete (which imports the auth package + resolves the boot credential broker) is injected at the cmd/harbor + devstack boundary; this package depends only on the interface.

func WithSessionOverlay

func WithSessionOverlay(st sessionoverlay.Store) Option

WithSessionOverlay wires the session-scoped safe-subset overlay store so the NON-admin `agent_config.session.*` verbs are live. A nil store leaves those methods returning ErrSessionOverlayUnavailable (→ 501 at the wire edge). The store is keyed by the caller's real (tenant, user, session) triple, so a session's overlay is invisible to another session.

func WithSkillStore

func WithSkillStore(st skills.SkillStore) Option

WithSkillStore wires the SkillStore so the `agent_config.skills.*` methods are live. A nil store leaves the skills methods returning ErrSkillsUnavailable (→ 501 at the wire edge).

func WithStdioAllowlist

func WithStdioAllowlist(commands []string) Option

WithStdioAllowlist sets the fail-closed allowlist of permitted stdio commands (matched on argv[0]) for `agent_config.add_mcp_connection`. A stdio add whose command[0] is absent is rejected with ErrStdioNotAllowed. An empty / nil allowlist rejects EVERY stdio add (the secure default); http adds are unaffected. Adding a stdio server runs an operator-supplied command (an RCE surface) — this gate is the §7 fail-closed boundary.

func WithValidModels

func WithValidModels(models []string) Option

WithValidModels sets the set of model names with a configured ModelProfile. `set_llm_params` (and a `set_revision` carrying an LLMParams.Model) reject a model outside this set with ErrUnknownModel — parity with the tenant model-swap, validated at SET time so an invalid model can never be persisted (never a silent run-start fallback).

An empty / nil set means model-pinning is UNAVAILABLE: every non-empty model set fails loud (the binary always wires at least the bound default model, so an empty set signals a misconfiguration, not "accept anything"). This matches the governance tenant-override policy's fail-loud-on-empty stance; it deliberately DIFFERS from runs.set_overrides (the one-shot session swap), which accepts any model when no set is configured.

type ProviderInstaller added in v1.14.0

type ProviderInstaller interface {
	// InstallProvider validates the descriptor's credential_broker against the
	// boot broker set, builds the broker-pull provider, and installs it into the
	// owner-tagged provider set under (tenant, agentID). An unknown broker, a
	// boot-name collision, or another owner's install collision fails loud. A
	// re-install by the same owner replaces (and closes) the prior instance.
	InstallProvider(ctx context.Context, tenant, agentID string, desc agentcfg.OAuthProviderDescriptor) error
	// UninstallProvider removes the named provider from the owner-tagged set and
	// CLOSES it. The (tenant, agentID) pair is the caller's resolved owner; the
	// set refuses a cross-owner drop at its own boundary (defense in depth). A
	// missing name is an idempotent no-op.
	UninstallProvider(ctx context.Context, tenant, agentID, name string) error
}

ProviderInstaller is the driver-agnostic seam the provider install / uninstall verbs (and the run-start provider reconcile) use to install / uninstall a Protocol-installed, zero-URL OAuth provider on the LIVE owner-tagged provider set. The concrete (wired at the cmd/harbor + devstack boundary) resolves the descriptor's credential_broker against the boot broker set, builds the tokenexchange provider, and installs it owner-tagged; keeping it an injected interface preserves this package's §4.4 boundary (no concrete auth-provider construction here).

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service implements the admin-scoped agent-config methods.

func NewService

func NewService(registry agentcfg.Registry, opts ...Option) (*Service, error)

NewService builds the agent-config Service over a Registry. registry is mandatory — a nil fails loud with ErrMisconfigured rather than building a Service that would nil-panic on the first request (CLAUDE.md §5).

The returned *Service is immutable after construction and safe for concurrent use by N goroutines.

func (*Service) AddMCPConnection

AddMCPConnection adds a NEW MCP server connection. See the file doc for the full lifecycle, secret-hygiene, and stdio-gate contract.

func (*Service) Diff

Diff returns the server-side compare of two existing revisions.

func (*Service) Get

Get reads the agent's active config revision.

func (*Service) ListRevisions

ListRevisions returns the agent's revision chain, newest-first.

func (*Service) RemoveMCPConnection added in v1.11.0

RemoveMCPConnection removes a runtime-added MCP connection by name. See the file doc for the full contract (revision + residue prune, the two distinct loud errors, the projection-boundary teardown, token retention).

func (*Service) RemoveOAuthProvider added in v1.14.0

RemoveOAuthProvider uninstalls a Protocol-installed OAuth provider by name. See the file doc for the full contract.

func (*Service) Rollback

Rollback repoints the active pointer to an existing revision.

func (*Service) SessionSetSourceDisables

SessionSetSourceDisables records the session's narrow-only disable set (servers + tools). There is intentionally no enable field: the set names what the session wants OFF, and the run-start projection unions it into the admin exclusion set — so a session edit can only narrow the admin-allowed exposure, never widen it.

func (*Service) SessionSetUserPrompt

SessionSetUserPrompt sets ONLY the session's user prompt layer. The session-writable shape carries no base field, so this can never alter the operator base — base-unwritable-by-session is structural.

func (*Service) SessionSkillsDelete

SessionSkillsDelete deletes a personal skill under the caller's real triple and removes its name from the session overlay.

func (*Service) SessionSkillsList

SessionSkillsList lists the session's skills (metadata only) under the caller's real triple. The SkillStore is already session-scoped, so the list is naturally isolated to the caller's session.

func (*Service) SessionSkillsUpsert

SessionSkillsUpsert upserts an EPHEMERAL personal skill under the caller's real triple and records its name in the session overlay (so the run-start projection adds it back above the admin membership filter). The skill scope is FORCED to session — a session personal skill never promotes to the agent/tenant scope.

func (*Service) SetLLMParams

SetLLMParams records a new config revision pinning the supplied per-agent LLM-parameter section (model / temperature / max-tokens / reasoning-effort) as a desired-state replace of the LLM-params section. A set Model is validated against the configured ModelProfiles (an unknown model is rejected with ErrUnknownModel). The prompt-layer + skills + tool-exposure + connection + hooks sections of the active revision are carried forward unchanged.

func (*Service) SetLLMProvider added in v1.17.0

SetLLMProvider installs (upserts) / rotates a ZERO-URL, broker-pull inference provider binding. See the file doc for the full contract.

func (*Service) SetMCPDiscoveryOrigins added in v1.14.0

SetMCPDiscoveryOrigins FULL-REPLACES a runtime-added MCP connection's OAuth-discovery cross-origin allow-list. See the file doc for the full contract (revision + live apply + revoke-prune, the three distinct loud errors, the fail-closed audit, the rollback reconcile path).

func (*Service) SetOAuthProvider added in v1.14.0

SetOAuthProvider installs (upserts) a ZERO-URL, broker-pull OAuth provider. See the file doc for the full contract (the zero-URL invariant, revision + live install + fail-closed audit, the boot-declared loud error).

func (*Service) SetPromptLayers

SetPromptLayers records a new config revision pinning the supplied layered system prompt (operator base and/or user layer) as a desired-state replace of the prompt-layer section. The skills + tool-exposure + connections + llm-params + hooks sections of the active revision are carried forward unchanged.

func (*Service) SetRevision

SetRevision writes a new immutable revision and advances the active pointer.

func (*Service) SetToolExposure

SetToolExposure records a new config revision pinning the supplied MCP-exposure desired state (paused servers + disabled tools) and emits an `mcp.connection.paused` / `.resumed` event for each server whose pause state changed relative to the prior active revision. The skills + prompt-layer + connections + llm-params + hooks sections of the active revision are carried forward unchanged — every sibling section survives a tool-exposure edit.

func (*Service) SkillsDelete

SkillsDelete deletes a skill from the SkillStore and records the membership change as a config revision.

func (*Service) SkillsList

SkillsList returns the agent's skills (metadata only) from the SkillStore under the caller's identity.

func (*Service) SkillsUpsert

SkillsUpsert upserts a skill into the SkillStore and records the membership change as a config revision. A pack-overwrite refusal surfaces as the typed `skills.ErrPackOverwriteRefused` (mapped to CodeInvalidRequest at the wire edge) — never a silent overwrite.

func (*Service) UserDiff added in v1.6.0

UserDiff returns the server-side compare of two existing revisions of the caller's own variant.

func (*Service) UserGet added in v1.6.0

UserGet reads the caller's own durable config variant active revision.

func (*Service) UserListRevisions added in v1.6.0

UserListRevisions returns the caller's own variant revision chain, newest-first.

func (*Service) UserRollback added in v1.6.0

UserRollback repoints the caller's own variant active pointer to an existing revision WITHOUT mutating any revision. Serialised per-owner.

func (*Service) UserSetRevision added in v1.6.0

UserSetRevision writes a new immutable revision of the caller's durable variant from the bounded safe-subset payload and advances the active pointer. Serialised per-owner (scope, tenant, real-user, agent) so distinct users never contend.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL