controlplane

package
v0.67.0 Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2026 License: AGPL-3.0 Imports: 26 Imported by: 0

Documentation

Overview

Package controlplane owns Stella's deployment control-plane resources: LLM providers, deployment settings (embedding, CLI-tool registry, OAuth provider config), plugins (registered + manifest), and channels.

These resources are administered, not user-owned. Authorization is a single admin gate at Begin (see access.go): an Access is minted only for an admin authority, so a non-admin actor is denied before any durable read or external action — identical to the legacy requireAdmin gate this service replaces. There is no per-user ownership and no per-method authorization.

The service also owns the persistence and live-reload orchestration each control-plane mutation performs (store writes plus pool/plugin-host hot reloads), so the HTTP transport keeps only request decoding and response shaping. It never reads request-supplied identity: the caller passes a trusted authz.Authority derived from verified session claims.

Index

Constants

View Source
const ChannelPluginConfigError = "channel instance config lives on /channels, not plugin config"

ChannelPluginConfigError is the client message returned when an admin tries to read or write a channel plugin's config through the plugin API; channel instance config lives on the /channels surface instead.

View Source
const SettingsDefaultModelToolPrefix = "settings_default_model"

SettingsDefaultModelToolPrefix is the family every generated settings_default_model tool name starts with.

View Source
const SettingsEmbeddingSettingToolPrefix = "settings_embedding_setting"

SettingsEmbeddingSettingToolPrefix is the family every generated settings_embedding_setting tool name starts with.

View Source
const SettingsPluginToolPrefix = "settings_plugin"

SettingsPluginToolPrefix is the family every generated settings_plugin tool name starts with.

View Source
const SettingsProviderToolPrefix = "settings_provider"

SettingsProviderToolPrefix is the family every generated settings_provider tool name starts with.

Variables

View Source
var ErrUnavailable = errors.New("controlplane: authorization unavailable")

ErrUnavailable is returned when the service itself is not configured (a nil receiver); the transport maps it to a fail-closed 503.

Functions

func SettingsDefaultModelDispatch added in v0.66.0

func SettingsDefaultModelDispatch(ctx context.Context, h SettingsDefaultModelHandler, action string, args map[string]any) (any, error)

func SettingsDefaultModelToolNames added in v0.66.0

func SettingsDefaultModelToolNames() []string

SettingsDefaultModelToolNames lists every generated tool name, for callers that gate on names.

func SettingsEmbeddingSettingDispatch added in v0.66.0

func SettingsEmbeddingSettingDispatch(ctx context.Context, h SettingsEmbeddingSettingHandler, action string, args map[string]any) (any, error)

func SettingsEmbeddingSettingToolNames added in v0.66.0

func SettingsEmbeddingSettingToolNames() []string

SettingsEmbeddingSettingToolNames lists every generated tool name, for callers that gate on names.

func SettingsPluginDispatch added in v0.66.0

func SettingsPluginDispatch(ctx context.Context, h SettingsPluginHandler, action string, args map[string]any) (any, error)

func SettingsPluginToolNames added in v0.66.0

func SettingsPluginToolNames() []string

SettingsPluginToolNames lists every generated tool name, for callers that gate on names.

func SettingsProviderDispatch added in v0.66.0

func SettingsProviderDispatch(ctx context.Context, h SettingsProviderHandler, action string, args map[string]any) (any, error)

func SettingsProviderToolNames added in v0.66.0

func SettingsProviderToolNames() []string

SettingsProviderToolNames lists every generated tool name, for callers that gate on names.

Types

type Access

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

Access is one authorized control-plane use case. Every control-plane resource (providers, settings, plugins, channels) is admin-only, so authorization is a single gate at Begin: an Access exists only for an admin authority. Each method then performs the durable write and hot-reload the legacy handler did, with no further per-method authorization.

func (*Access) CliToolLatest

func (a *Access) CliToolLatest(ctx context.Context, tool string) (string, error)

CliToolLatest resolves the latest installable version for a mise tool key.

func (*Access) CreateProvider

func (a *Access) CreateProvider(ctx context.Context, p config.Provider) error

CreateProvider validates catalog and adapter references, applies stable defaults, then persists the provider and hot-reloads the pool.

func (*Access) DeleteChannel

func (a *Access) DeleteChannel(ctx context.Context, id string) error

DeleteChannel stops a channel's runtime and removes it.

func (*Access) DeleteManifestPlugin added in v0.63.2

func (a *Access) DeleteManifestPlugin(ctx context.Context, id string) error

DeleteManifestPlugin removes an admin-added plugin: its override row is the whole definition, so dropping it drops the plugin. A builtin ships with the server and is refused — disabling it is the reversible equivalent, and letting a delete "remove" one would only resurrect it on the next resolve. Installed binaries stay in the mise cache, exactly as they do when a plugin is disabled.

func (*Access) DeleteOAuthProviderConfig

func (a *Access) DeleteOAuthProviderConfig(ctx context.Context, id string) error

DeleteOAuthProviderConfig removes an OAuth provider client configuration.

func (*Access) DeleteProvider

func (a *Access) DeleteProvider(ctx context.Context, id string) error

DeleteProvider removes a provider and hot-reloads the pool.

func (*Access) DeleteProviderIfVersion added in v0.66.0

func (a *Access) DeleteProviderIfVersion(ctx context.Context, id, version string) error

func (*Access) FetchProviderModels

func (a *Access) FetchProviderModels(ctx context.Context, id, apiKey, baseURL string) ([]ProviderModelItem, error)

func (*Access) GetChannel

func (a *Access) GetChannel(ctx context.Context, id string) (config.Channel, error)

GetChannel returns one channel by id (opaque 404 when missing).

func (*Access) GetDefaultModels added in v0.66.0

func (a *Access) GetDefaultModels(ctx context.Context) (config.DefaultModels, error)

GetDefaultModels returns the deployment-wide default model configuration.

func (*Access) GetEmbeddingSettings

func (a *Access) GetEmbeddingSettings(ctx context.Context) (EmbeddingState, error)

GetEmbeddingSettings returns the deployment-wide embedding configuration.

func (*Access) GetOAuthProviderConfig

func (a *Access) GetOAuthProviderConfig(ctx context.Context, id string) (connections.OAuthProviderConfig, error)

GetOAuthProviderConfig returns the stored OAuth provider client configuration.

func (*Access) GetPluginConfig

func (a *Access) GetPluginConfig(ctx context.Context, kind, name string) (map[string]any, error)

GetPluginConfig returns a plugin's stored config. Channel plugins are rejected: their instance config lives on /channels.

func (*Access) GetPluginConfigSchema

func (a *Access) GetPluginConfigSchema(ctx context.Context, kind, name string) (map[string]any, error)

GetPluginConfigSchema returns a plugin's admin config schema.

func (*Access) GetPluginStatus

func (a *Access) GetPluginStatus(ctx context.Context, kind, name string) (any, error)

GetPluginStatus returns a plugin's admin status payload.

func (*Access) GetProvider

func (a *Access) GetProvider(ctx context.Context, id string) (config.Provider, error)

GetProvider returns one provider by id (opaque 404 when missing).

func (*Access) GetProviderSnapshot added in v0.66.0

func (a *Access) GetProviderSnapshot(ctx context.Context, id string) (config.ProviderSnapshot, error)

GetProviderSnapshot returns settings-safe fields and the CAS version from one durable read. Keeping them together prevents a stale projection from inheriting a newer version and overwriting an intervening admin change.

func (*Access) ListChannels

func (a *Access) ListChannels(ctx context.Context) ([]config.Channel, error)

func (*Access) ListManifestPlugins

func (a *Access) ListManifestPlugins(ctx context.Context) (*manifest.Manifest, error)

ListManifestPlugins returns the builtin manifest overlaid with DB overrides.

func (*Access) ListModelCatalogModels added in v0.66.0

func (a *Access) ListModelCatalogModels(ctx context.Context) ([]modelcatalog.Model, error)

func (*Access) ListModelCatalogProviders added in v0.66.0

func (a *Access) ListModelCatalogProviders(ctx context.Context, includeUnsupported bool) ([]modelcatalog.Provider, error)

ResolveProviderModel exposes the same effective merge used by the model list and runtime snapshot, preventing evidence and billing from drifting apart.

func (*Access) ListPlugins

func (a *Access) ListPlugins(ctx context.Context) ([]pkgplugins.RegisteredPlugin, error)

ListPlugins returns the admin-visible registered plugins. The transport shapes each into its admin view.

func (*Access) ListProviderModelCounts added in v0.66.0

func (a *Access) ListProviderModelCounts(ctx context.Context, providers []config.Provider) (map[string][2]int, error)

ListProviderModelCounts computes projections from one provider, cache, and catalog read. It deliberately does not call mergedProviderModels per row.

func (*Access) ListProviderModels

func (a *Access) ListProviderModels(ctx context.Context, id string) ([]ProviderModelItem, error)

ListProviderModels returns the merged custom+fetched model list for a provider.

func (*Access) ListProviderSnapshots added in v0.66.0

func (a *Access) ListProviderSnapshots(ctx context.Context) ([]config.ProviderSnapshot, error)

func (*Access) ListProviderTypes

func (a *Access) ListProviderTypes() ([]host.ProviderType, error)

ListProviderTypes returns the provider plugin types the deployment can add.

func (*Access) ListProviders

func (a *Access) ListProviders(ctx context.Context) ([]config.Provider, error)

ListProviders returns every configured LLM provider.

func (*Access) LookupAgent

func (a *Access) LookupAgent(ctx context.Context, id string) (config.Agent, error)

LookupAgent reads an agent for a channel-binding precondition: a registration flow binds a channel to an agent that must exist and be enabled. It is an admin-gated read (the Access already passed Begin), so a non-admin never reaches it; the caller inspects the returned agent's Enabled flag.

func (*Access) ManageChannel

func (a *Access) ManageChannel(id string) (*ChannelManagement, error)

ManageChannel opens a channel-management operation. The admin gate already ran at Begin, so this only hands back the operation handle; id is retained for call-site symmetry (registration flows keep this handle across their platform handshake, then call Save after credentials arrive).

func (*Access) ModelCatalogStatus added in v0.66.0

func (*Access) NormalizeProvider added in v0.66.0

func (a *Access) NormalizeProvider(ctx context.Context, p config.Provider) (config.Provider, error)

NormalizeProvider resolves catalog-backed defaults without guessing a catalog vendor from a generic adapter type. Explicit operator values always win.

func (*Access) ProbeProvider added in v0.66.0

func (a *Access) ProbeProvider(ctx context.Context, apiType, apiKey, baseURL string) ([]ProviderModelItem, error)

ProbeProvider lists models without creating a provider row or touching the fetched cache. It is the atomic pre-create validation boundary for the UI.

func (*Access) ProviderModelsSyncedAt added in v0.66.0

func (a *Access) ProviderModelsSyncedAt(ctx context.Context, id string) (*time.Time, error)

FetchProviderModels lists the provider's models from its live API, refreshes the cached set, and returns the merged list. Credentials fall back to the stored provider when the caller omits them. It preserves the legacy status split: a missing provider during the credential fallback is a 400 "api_key is required", while the authoritative load is a 404.

func (*Access) ResetManifestPlugin added in v0.63.2

func (a *Access) ResetManifestPlugin(ctx context.Context, id, field string) (*manifest.Manifest, error)

ResetManifestPlugin hands a builtin's definition back to the server, either one field of it or all of it. The enable switch is a separate decision and survives either way: "stop customizing this" is not "turn it on".

Releasing one field from a row written before overrides went sparse converts it first. That conversion is lossless — such a row owns every field, including the ones its JSON omits and therefore owns as empty — so the other fields stay pinned exactly where they were, and only the named one starts following the server again.

An admin-added plugin has no definition to fall back to, so resetting one is refused — deleting it is the operation that means anything there.

func (*Access) ResolveProviderModel added in v0.66.0

func (a *Access) ResolveProviderModel(ctx context.Context, id, modelID string) (modelcatalog.Result, error)

func (*Access) SaveChannel

func (a *Access) SaveChannel(ctx context.Context, ch config.Channel, cfgMap map[string]any, create bool) (config.Channel, error)

SaveChannel validates and persists a channel, ensures its plugin is enabled, and applies its runtime. create=true rejects an id that already exists (the create-only POST contract). It returns the reloaded channel.

func (*Access) SaveManifestPluginDefinition added in v0.63.2

func (a *Access) SaveManifestPluginDefinition(ctx context.Context, plugin manifest.ManifestPlugin, fields []string) (*manifest.Manifest, error)

SaveManifestPluginDefinition records the fields this request takes ownership of and leaves every other field of the row alone.

fields is the contract: a builtin's row grows exactly those keys, at the submitted values, on top of whatever it already owned. Deriving them here by diffing against the shipped definition is what this replaces — that quietly released a pinned field whenever a release happened to ship the same value.

An admin-added plugin has no definition underneath it, so its row is the whole plugin and fields does not apply; its enable state travels with it, because there is no shipped default to fall back to.

func (*Access) SearchCliToolRegistry

func (a *Access) SearchCliToolRegistry(ctx context.Context, query string, limit int) ([]manifest.RegistryTool, error)

SearchCliToolRegistry searches the mise tool registry so the UI can add a CLI tool by name instead of a hand-written backend key.

func (*Access) SetDefaultModels added in v0.66.0

func (a *Access) SetDefaultModels(ctx context.Context, d config.DefaultModels) (config.DefaultModels, error)

SetDefaultModels persists the deployment-wide default models and rebuilds the runner factories so newly admitted runners see them. An empty field clears that role; a non-empty one must carry its provider prefix, since unlike an agent tier there is no agent context to infer a provider from and a bare model name would resolve differently per agent.

Only shape is validated, not provider existence: a provider row can be deleted after a default references it, so "this provider is configured" is not an invariant a write-time check can hold, and a fresh deployment legitimately names its models before the provider rows exist.

func (*Access) SetDefaultModelsIfVersion added in v0.66.0

func (a *Access) SetDefaultModelsIfVersion(ctx context.Context, d config.DefaultModels, expectedVersion string) (config.DefaultModels, error)

SetDefaultModelsIfVersion is the atomic Settings-tool write path. The raw app_setting value is compared in SQL, so a concurrent UI write cannot be overwritten after the tool's read.

func (*Access) SetEmbeddingSettings

func (a *Access) SetEmbeddingSettings(ctx context.Context, upd EmbeddingUpdate) (EmbeddingState, error)

SetEmbeddingSettings persists the embedding lane's knobs.

Enabling the lane before its model resolves is allowed on purpose. The model lives in DefaultModels, so the two are separate writes, and rejecting here would make the admin's success depend on which one they saved first — with a half-applied deployment whenever the second call failed. config.ResolveEmbedding treats an unresolvable reference as disabled instead, so the stored flag is an intent that turns itself on the moment the model behind it resolves.

func (*Access) SetEmbeddingSettingsIfVersion added in v0.66.0

func (a *Access) SetEmbeddingSettingsIfVersion(ctx context.Context, upd EmbeddingUpdate, expectedVersion string) (EmbeddingState, error)

SetEmbeddingSettingsIfVersion closes the read/write race for a Settings tool while leaving the existing HTTP write contract untouched.

func (*Access) SetManifestPluginEnabled added in v0.63.2

func (a *Access) SetManifestPluginEnabled(ctx context.Context, id string, enabled bool) (*manifest.Manifest, error)

SetManifestPluginEnabled turns one plugin on or off. The enable switch is its own column, so this never touches the definition override: "turn this off" and "stop customizing this" stay independent decisions.

func (*Access) SetOAuthProviderConfig

SetOAuthProviderConfig persists an OAuth provider client configuration and returns the refreshed stored value.

func (*Access) SyncManifestPlugins

func (a *Access) SyncManifestPlugins(ctx context.Context) (manifest.ReconcileResult, error)

SyncManifestPlugins reconciles the merged manifest against the filesystem (installs binaries/skills) and returns the reconcile result.

func (*Access) SyncModelCatalog added in v0.66.0

func (a *Access) SyncModelCatalog(ctx context.Context) (modelcatalog.SyncResult, error)

func (*Access) TogglePlugin

func (a *Access) TogglePlugin(ctx context.Context, kind, name string, enabled bool) (config.Plugin, error)

TogglePlugin enables/disables a plugin and hot-reloads its runtime.

func (*Access) UpdatePluginConfig

func (a *Access) UpdatePluginConfig(ctx context.Context, kind, name string, cfg map[string]any) (config.Plugin, error)

UpdatePluginConfig validates and persists a plugin's config, then hot-reloads its runtime. Channel plugins are rejected (config lives on /channels).

func (*Access) UpdateProvider

func (a *Access) UpdateProvider(ctx context.Context, id string, p config.Provider) (config.Provider, error)

UpdateProvider merges the request over the stored provider (preserving Type and defaulting Name), persists it, and hot-reloads the pool. It returns the merged provider so the transport can echo it.

func (*Access) UpdateProviderIfVersion added in v0.66.0

func (a *Access) UpdateProviderIfVersion(ctx context.Context, p config.Provider, version string) (config.Provider, error)

UpdateProviderIfVersion writes only when the database row still has the version the Settings tool read. This protects a hidden key from being copied over a concurrent credential change.

type AgentChannels added in v0.63.2

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

AgentChannels is channel management confined to one caller's agents.

A channel is an agent's phone number, so the person who owns the agent owns its channels: they hold the bot token, they answer for what it says. The deployment-wide control plane stays admin-only — this reaches exactly the channels bound to agents the caller may manage, and a channel outside that set is as opaque as a missing one.

func (*AgentChannels) DeleteChannel added in v0.63.2

func (a *AgentChannels) DeleteChannel(ctx context.Context, id string) error

DeleteChannel removes one of the caller's channels.

func (*AgentChannels) GetChannel added in v0.63.2

func (a *AgentChannels) GetChannel(ctx context.Context, id string) (config.Channel, error)

GetChannel returns one of the caller's channels; anything else is a 404.

func (*AgentChannels) ListChannels added in v0.63.2

func (a *AgentChannels) ListChannels(ctx context.Context) ([]config.Channel, error)

ListChannels returns the channels bound to the caller's agents.

func (*AgentChannels) SaveChannel added in v0.63.2

func (a *AgentChannels) SaveChannel(ctx context.Context, ch config.Channel, cfgMap map[string]any, create bool) (config.Channel, error)

SaveChannel persists a channel that stays bound to one of the caller's agents. Both ends are checked: an update must target a channel they already own, and the saved row must still name an agent they manage — so a channel can neither be taken from another owner nor handed to an agent the caller cannot manage.

type ChannelAccess added in v0.63.2

type ChannelAccess interface {
	ListChannels(ctx context.Context) ([]config.Channel, error)
	GetChannel(ctx context.Context, id string) (config.Channel, error)
	SaveChannel(ctx context.Context, ch config.Channel, cfgMap map[string]any, create bool) (config.Channel, error)
	DeleteChannel(ctx context.Context, id string) error
}

ChannelAccess is the channel-management surface the transport talks to. Two authorized implementations satisfy it: the admin Access, which reaches every channel in the deployment, and AgentChannels, which reaches only the channels of the agents its caller manages. The handlers are identical either way — the scope decision is made once, when the access is opened.

type ChannelBinding added in v0.62.0

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

ChannelBinding is one authorized channel→agent binding operation.

Channel administration — credentials, naming, enablement, deletion — stays admin-only behind Begin. Choosing which agent answers on a channel is a per-user action instead, so it gets its own narrow gate here rather than widening the admin Access or letting the transport write the row directly. The operation only ever moves AgentID: the stored config (channel credentials) is carried through untouched, and it reuses the same persist + plugin-apply path as an admin save, including the (agent, platform) binding invariant.

func (*ChannelBinding) Bind added in v0.62.0

func (b *ChannelBinding) Bind(ctx context.Context, agentID string) (PublicChannel, error)

Bind points the channel at agentID, or unbinds it when agentID is empty, and returns the secret-free projection of the saved row. A bound agent must exist and be enabled; the caller's authority over that agent was already decided.

func (*ChannelBinding) CurrentAgentID added in v0.62.0

func (b *ChannelBinding) CurrentAgentID() string

CurrentAgentID is the agent this channel is bound to right now, empty when it is unbound. The caller needs it to authorize taking the channel away from its current owner.

type ChannelManagement

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

ChannelManagement is one channel-management operation. Its Save method owns the channel row plus the required channel plugin enable/apply as a single unit, so callers never need a second plugin call.

func (*ChannelManagement) Channel

func (m *ChannelManagement) Channel(ctx context.Context, id string) (config.Channel, error)

Channel reads the current row for this operation's channel so a caller can merge a partial update onto it. It is an admin-gated read (Begin already ran); a missing channel returns an error the caller treats as "start from a fresh row" rather than a hard failure.

func (*ChannelManagement) Save

func (m *ChannelManagement) Save(ctx context.Context, ch config.Channel, cfgMap map[string]any, create bool) (config.Channel, error)

Save persists the already-authorized channel and applies its plugin as one control-plane operation. It intentionally makes no further authorization call.

func (*ChannelManagement) ValidateBinding

func (m *ChannelManagement) ValidateBinding(ctx context.Context, ch config.Channel) error

ListChannels returns every configured channel. ValidateBinding checks the durable channel-binding invariant before an enrollment flow performs an external handshake. Save repeats the check and the database unique index closes the concurrent-write race.

type ConflictError

type ConflictError struct{ Msg string }

ConflictError reports a create that collides with an existing resource, mapped to 409 by the transport. It is returned only after authorization succeeds.

func (*ConflictError) Error

func (e *ConflictError) Error() string

type EmbeddingState added in v0.66.0

type EmbeddingState struct {
	Settings config.EmbeddingSettings
	Active   bool
}

EmbeddingState is the lane as an admin needs to see it: what is stored, plus whether it is actually running. The two differ whenever the embedding model does not resolve to a provider with a key, and only the server can tell — which is why Active travels with the settings instead of being re-derived in the browser from a partial view of the catalog.

type EmbeddingUpdate

type EmbeddingUpdate struct {
	Enabled   bool
	Dim       int
	Normalize bool
}

EmbeddingUpdate carries a validated embedding-settings write. It covers only the lane's own knobs: the embedding model and its credentials are named in DefaultModels alongside every other model role.

type ForbiddenError

type ForbiddenError struct{ Msg string }

ForbiddenError reports a control-plane precondition that forbids an operation for a reason other than the admin gate (e.g. a resource locked by an environment override). It maps to 403 with Msg, distinct from the opaque authz.ErrForbidden denial, and is only ever returned after authorization succeeds so it never leaks to an unauthorized caller.

func (*ForbiddenError) Error

func (e *ForbiddenError) Error() string

type ManagementTool added in v0.66.0

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

ManagementTool is one Stella-only deployment action. It obtains both direct human authority and the control-plane admin capability at execution time so a cached catalog cannot turn a role change into a write capability.

func NewDefaultModelManagementTool added in v0.66.0

func NewDefaultModelManagementTool(spec SettingsDefaultModelActionTool, service func() *Service) *ManagementTool

func NewEmbeddingSettingManagementTool added in v0.66.0

func NewEmbeddingSettingManagementTool(spec SettingsEmbeddingSettingActionTool, service func() *Service) *ManagementTool

func NewPluginManagementTool added in v0.66.0

func NewPluginManagementTool(spec SettingsPluginActionTool, service func() *Service) *ManagementTool

func NewProviderManagementTool added in v0.66.0

func NewProviderManagementTool(spec SettingsProviderActionTool, service func() *Service) *ManagementTool

func (*ManagementTool) Definition added in v0.66.0

func (t *ManagementTool) Definition() tools.Definition

func (*ManagementTool) Execute added in v0.66.0

func (t *ManagementTool) Execute(ctx context.Context, args map[string]any) (string, error)

type NotFoundError

type NotFoundError struct{ Msg string }

NotFoundError reports a control-plane resource that does not exist. Msg carries the historical per-resource client message so the transport preserves the 404 body byte-for-byte.

func (*NotFoundError) Error

func (e *NotFoundError) Error() string

type ProviderModelItem

type ProviderModelItem struct {
	ID       string                        `json:"id"`
	Name     string                        `json:"name,omitempty"`
	Source   string                        `json:"source"`
	Enabled  bool                          `json:"enabled"`
	Config   config.ProviderModel          `json:"config,omitzero"`
	Override *config.ProviderModelOverride `json:"override,omitempty"`
	Catalog  *modelcatalog.Model           `json:"catalog,omitempty"`
}

ProviderModelItem is one merged model entry for a provider: custom (config-declared) models plus fetched (cached) models, unioned. Kept here with the persistence it derives from; the transport writes it directly.

type PublicChannel

type PublicChannel struct {
	ID      string
	Type    string // effective type: the configured type, or the id when unset
	AgentID string
	Enabled bool
}

PublicChannel is the config-secret-free projection of a channel for the user-facing channel list. It deliberately omits the raw Config JSON that config.Channel carries (channel credentials), exposing only the fields the public list renders.

type Service

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

Service owns the control-plane resources: the persistence and runtime handles a control-plane mutation needs to apply and hot-reload changes. Authorization is the admin gate in Begin (see access.go); a nil receiver fails closed.

func NewService

func NewService(store config.Store, plugins *pluginhost.Host, pools *agent.PoolManager, conns *connections.Service, log *slog.Logger) *Service

NewService builds the control-plane service from its fully-wired dependencies. The composition root constructs it once and shares the same instance behind the HTTP endpoints. log defaults to slog.Default() when nil.

func (*Service) Begin

func (s *Service) Begin(_ context.Context, authority authz.Authority) (*Access, error)

Begin authorizes one control-plane use case. The control plane is administered, not user-owned: it validates the Authority and requires IsAdmin exactly once, so a non-admin or invalid authority fails closed here, before any durable read or external action — identical to the legacy requireAdmin gate this replaces. The handler never inspects identity beyond passing the trusted Authority.

func (*Service) BeginAgentChannels added in v0.63.2

func (s *Service) BeginAgentChannels(_ context.Context, authority authz.Authority, managedAgentIDs []string) (*AgentChannels, error)

BeginAgentChannels opens agent-scoped channel management for the agents the caller was already found to manage.

The Agent decision is deliberately not made here: the caller must clear the Agent PEP for every id it passes, so the "which agents may this user manage" rule stays in the one domain that owns it — the same split BeginChannelBinding uses. An empty set is forbidden rather than an empty listing, so a user with no agents of their own cannot probe channel ids at all.

func (*Service) BeginChannelBinding added in v0.62.0

func (s *Service) BeginChannelBinding(ctx context.Context, authority authz.Authority, channelID string) (*ChannelBinding, error)

BeginChannelBinding authorizes rebinding one channel's agent for a signed-in caller and loads the target row. Any valid user principal may bind, but a non-admin may only touch an enabled channel; a disabled channel is as opaque to them as a missing one, so both fail as 404.

The Agent decisions are deliberately not made here: the caller must clear the Agent PEP for CurrentAgentID (when set) and for the agent it binds, so the "which agents may this user use" rule stays in the one domain that owns it.

func (*Service) DisabledChannelTypes added in v0.63.2

func (s *Service) DisabledChannelTypes(ctx context.Context, authority authz.Authority) (map[string]bool, error)

DisabledChannelTypes returns the set of channel-plugin names an admin has explicitly switched off, used by the transport to hide their channels.

A platform is usable unless an admin explicitly switched it off, so this reads the stored override rows rather than the merged plugin list: the builtin default for a channel plugin is "disabled" (a platform with no channel has nothing to run), and treating that default as a veto would hide every channel whose plugin row nobody flipped on. The runtime applies the same rule to instances (RuntimeHost.channelPlatformDisabled), so creating a channel needs no plugin row at all.

func (*Service) ListEnabledModels

func (s *Service) ListEnabledModels(ctx context.Context, authority authz.Authority) ([]config.CachedModel, error)

ListEnabledModels returns the models available for selection: enabled models from enabled providers, plus fetched-cache models whose provider is enabled, deduplicated by provider/model and sorted. It performs no provider API calls.

func (*Service) PublicChannels

func (s *Service) PublicChannels(ctx context.Context, authority authz.Authority) ([]PublicChannel, error)

PublicChannels returns the secret-free projection of every configured channel for the user-facing channel list. The transport filters visibility by the caller's agent access and the enabled plugin types; this only supplies the projected rows.

func (*Service) SetModelCatalog added in v0.66.0

func (s *Service) SetModelCatalog(catalog *modelcatalog.Catalog)

SetModelCatalog installs the process-wide catalog snapshot after startup or synchronization. Callers may replace it atomically between requests.

type SettingsDefaultModelActionTool added in v0.66.0

type SettingsDefaultModelActionTool = toolmeta.ActionTool

SettingsDefaultModelActionTool describes one generated tool: an exact schema bound to one action.

func SettingsDefaultModelActionTools added in v0.66.0

func SettingsDefaultModelActionTools() []SettingsDefaultModelActionTool

SettingsDefaultModelActionTools lists every generated tool in a stable order.

type SettingsDefaultModelGetInput added in v0.66.0

type SettingsDefaultModelGetInput struct {
}

type SettingsDefaultModelHandler added in v0.66.0

type SettingsDefaultModelHandler interface {
	Get(context.Context, SettingsDefaultModelGetInput) (any, error)
	Update(context.Context, SettingsDefaultModelUpdateInput) (any, error)
}

type SettingsDefaultModelUpdateInput added in v0.66.0

type SettingsDefaultModelUpdateInput struct {
	ExpectedVersion     string `json:"expected_version,omitempty"`
	Model               string `json:"model,omitempty"`
	ModelEmbedding      string `json:"model_embedding,omitempty"`
	ModelFast           string `json:"model_fast,omitempty"`
	ModelFastThinking   string `json:"model_fast_thinking,omitempty"`
	ModelStrong         string `json:"model_strong,omitempty"`
	ModelStrongThinking string `json:"model_strong_thinking,omitempty"`
	ModelThinking       string `json:"model_thinking,omitempty"`
	ModelVision         string `json:"model_vision,omitempty"`
}

type SettingsEmbeddingSettingActionTool added in v0.66.0

type SettingsEmbeddingSettingActionTool = toolmeta.ActionTool

SettingsEmbeddingSettingActionTool describes one generated tool: an exact schema bound to one action.

func SettingsEmbeddingSettingActionTools added in v0.66.0

func SettingsEmbeddingSettingActionTools() []SettingsEmbeddingSettingActionTool

SettingsEmbeddingSettingActionTools lists every generated tool in a stable order.

type SettingsEmbeddingSettingGetInput added in v0.66.0

type SettingsEmbeddingSettingGetInput struct {
}

type SettingsEmbeddingSettingHandler added in v0.66.0

type SettingsEmbeddingSettingHandler interface {
	Get(context.Context, SettingsEmbeddingSettingGetInput) (any, error)
	Update(context.Context, SettingsEmbeddingSettingUpdateInput) (any, error)
}

type SettingsEmbeddingSettingUpdateInput added in v0.66.0

type SettingsEmbeddingSettingUpdateInput struct {
	Dim             int    `json:"dim,omitempty"`
	Enabled         bool   `json:"enabled,omitempty"`
	ExpectedVersion string `json:"expected_version,omitempty"`
	Normalize       bool   `json:"normalize,omitempty"`
}

type SettingsPluginActionTool added in v0.66.0

type SettingsPluginActionTool = toolmeta.ActionTool

SettingsPluginActionTool describes one generated tool: an exact schema bound to one action.

func SettingsPluginActionTools added in v0.66.0

func SettingsPluginActionTools() []SettingsPluginActionTool

SettingsPluginActionTools lists every generated tool in a stable order.

type SettingsPluginDisableInput added in v0.66.0

type SettingsPluginDisableInput struct {
	Kind string `json:"kind,omitempty"`
	Name string `json:"name,omitempty"`
}

type SettingsPluginEnableInput added in v0.66.0

type SettingsPluginEnableInput struct {
	Kind string `json:"kind,omitempty"`
	Name string `json:"name,omitempty"`
}

type SettingsPluginHandler added in v0.66.0

type SettingsPluginListInput added in v0.66.0

type SettingsPluginListInput struct {
}

type SettingsProviderActionTool added in v0.66.0

type SettingsProviderActionTool = toolmeta.ActionTool

SettingsProviderActionTool describes one generated tool: an exact schema bound to one action.

func SettingsProviderActionTools added in v0.66.0

func SettingsProviderActionTools() []SettingsProviderActionTool

SettingsProviderActionTools lists every generated tool in a stable order.

type SettingsProviderCreateInput added in v0.66.0

type SettingsProviderCreateInput struct {
	BaseUrl string `json:"base_url,omitempty"`
	Enabled bool   `json:"enabled,omitempty"`
	Id      string `json:"id,omitempty"`
	Models  map[string]struct {
		CatalogModel  string `json:"catalogModel,omitempty"`
		ContextWindow int    `json:"contextWindow,omitempty"`
		Cost          struct {
			CacheRead   float64 `json:"cacheRead,omitempty"`
			CacheWrite  float64 `json:"cacheWrite,omitempty"`
			Input       float64 `json:"input,omitempty"`
			InputAudio  float64 `json:"inputAudio,omitempty"`
			Output      float64 `json:"output,omitempty"`
			OutputAudio float64 `json:"outputAudio,omitempty"`
			Reasoning   float64 `json:"reasoning,omitempty"`
			Tiers       []struct {
				CacheRead   float64 `json:"cacheRead,omitempty"`
				CacheWrite  float64 `json:"cacheWrite,omitempty"`
				Input       float64 `json:"input,omitempty"`
				InputAudio  float64 `json:"inputAudio,omitempty"`
				MinContext  int     `json:"minContext,omitempty"`
				Output      float64 `json:"output,omitempty"`
				OutputAudio float64 `json:"outputAudio,omitempty"`
				Reasoning   float64 `json:"reasoning,omitempty"`
			} `json:"tiers,omitempty"`
		} `json:"cost,omitempty"`
		Enabled   bool     `json:"enabled,omitempty"`
		Id        string   `json:"id,omitempty"`
		Input     []string `json:"input,omitempty"`
		MaxTokens int      `json:"maxTokens,omitempty"`
		Name      string   `json:"name,omitempty"`
		Output    []string `json:"output,omitempty"`
		Reasoning *bool    `json:"reasoning,omitempty"`
	} `json:"models,omitempty"`
	Name string `json:"name,omitempty"`
	Type string `json:"type,omitempty"`
}

type SettingsProviderDeleteInput added in v0.66.0

type SettingsProviderDeleteInput struct {
	ExpectedVersion string `json:"expected_version,omitempty"`
	Id              string `json:"id,omitempty"`
}

type SettingsProviderGetInput added in v0.66.0

type SettingsProviderGetInput struct {
	Id string `json:"id,omitempty"`
}

type SettingsProviderListInput added in v0.66.0

type SettingsProviderListInput struct {
}

type SettingsProviderUpdateInput added in v0.66.0

type SettingsProviderUpdateInput struct {
	BaseUrl         string `json:"base_url,omitempty"`
	Enabled         bool   `json:"enabled,omitempty"`
	ExpectedVersion string `json:"expected_version,omitempty"`
	Id              string `json:"id,omitempty"`
	Models          map[string]struct {
		CatalogModel  string `json:"catalogModel,omitempty"`
		ContextWindow int    `json:"contextWindow,omitempty"`
		Cost          struct {
			CacheRead   float64 `json:"cacheRead,omitempty"`
			CacheWrite  float64 `json:"cacheWrite,omitempty"`
			Input       float64 `json:"input,omitempty"`
			InputAudio  float64 `json:"inputAudio,omitempty"`
			Output      float64 `json:"output,omitempty"`
			OutputAudio float64 `json:"outputAudio,omitempty"`
			Reasoning   float64 `json:"reasoning,omitempty"`
			Tiers       []struct {
				CacheRead   float64 `json:"cacheRead,omitempty"`
				CacheWrite  float64 `json:"cacheWrite,omitempty"`
				Input       float64 `json:"input,omitempty"`
				InputAudio  float64 `json:"inputAudio,omitempty"`
				MinContext  int     `json:"minContext,omitempty"`
				Output      float64 `json:"output,omitempty"`
				OutputAudio float64 `json:"outputAudio,omitempty"`
				Reasoning   float64 `json:"reasoning,omitempty"`
			} `json:"tiers,omitempty"`
		} `json:"cost,omitempty"`
		Enabled   bool     `json:"enabled,omitempty"`
		Id        string   `json:"id,omitempty"`
		Input     []string `json:"input,omitempty"`
		MaxTokens int      `json:"maxTokens,omitempty"`
		Name      string   `json:"name,omitempty"`
		Output    []string `json:"output,omitempty"`
		Reasoning *bool    `json:"reasoning,omitempty"`
	} `json:"models,omitempty"`
	Name string `json:"name,omitempty"`
	Type string `json:"type,omitempty"`
}

type UpstreamError

type UpstreamError struct{ Err error }

UpstreamError reports a failed call to an external control-plane dependency (e.g. a provider's model-listing endpoint), mapped to 502 by the transport.

func (*UpstreamError) Error

func (e *UpstreamError) Error() string

func (*UpstreamError) Unwrap

func (e *UpstreamError) Unwrap() error

type ValidationError

type ValidationError struct{ Msg string }

ValidationError reports a rejected control-plane input (the legacy 400 path). Msg carries the exact historical client message.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Jump to

Keyboard shortcuts

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