Documentation
¶
Overview ¶
Package projection holds the run-start agent-config projection shared by every run-loop driver (the production dev driver and the harbortest devstack twin) and exercised directly by the control-plane integration test. Extracting it here keeps the projection logic in ONE place: the drivers live in separate binaries (cmd/harbor's package main cannot be imported by harbortest/devstack), so an inlined copy in each would drift (CLAUDE.md §17.6). The integration test calls the same function, so the test exercises the real projection rather than a test-local copy (CLAUDE.md §17.4).
Index ¶
- Variables
- func ActiveLLMOverrides(ctx context.Context, reg agentcfg.Registry, agentID string, ...) (*planner.LLMOverrides, error)
- func ActivePlannerCatalogView(ctx context.Context, reg agentcfg.Registry, ov sessionoverlay.Store, ...) (tools.PlannerCatalogView, error)
- func ActivePromptLayers(ctx context.Context, reg agentcfg.Registry, agentID string, ...) (base string, user string, ok bool, err error)
- func ActiveSkillViews(ctx context.Context, reg agentcfg.Registry, ov sessionoverlay.Store, ...) ([]skills.SkillView, error)
- func ApplyPromptLayers(ctx context.Context, reg agentcfg.Registry, overlayStore sessionoverlay.Store, ...) (*planner.LLMOverrides, error)
- func FilterSkillViewsByMembership(views []skills.SkillView, names []string) []skills.SkillView
Constants ¶
This section is empty.
Variables ¶
var ErrSkillBodyMissing = errors.New("agentcfg/projection: agent-config pins a skill whose body is absent from the store")
ErrSkillBodyMissing is returned by ActiveSkillViews when an agent's active config pins an ADMIN skill-membership name whose body is absent from the store (e.g. the skill was hard-deleted, or a rollback landed on a revision referencing a since-deleted skill). An admin-pinned skill whose body is absent from the store is a LOUD failure at run-start projection — never a silent drop (CLAUDE.md §13). Session-personal skill names are exempt (a safe-subset add that may legitimately not be in the directory view).
Functions ¶
func ActiveLLMOverrides ¶
func ActiveLLMOverrides(ctx context.Context, reg agentcfg.Registry, agentID string, id identity.Quadruple) (*planner.LLMOverrides, error)
ActiveLLMOverrides resolves the PER-AGENT LLM-parameter override layer from the agent's active config revision at run start. It returns the per-agent sampling defaults (model / temperature / max-tokens / reasoning-effort) the agent has pinned, as a planner.LLMOverrides carrying ONLY those four dimensions — the layer the run loop folds BETWEEN the session override and the tenant-wide baseline (precedence session › per-agent › tenant-wide baseline › config default).
A nil registry, an empty agentID, an agent with no active revision, or an active revision with no LLM-params section returns (nil, nil) — the backward-compatible "no per-agent override" path. A registry read error is returned so the caller fails the run loudly (CLAUDE.md §13): no silent fall-through to the tenant baseline on a read failure.
The active revision is read ONCE per run; the returned bundle is fresh (its pointers are copies), so concurrent / in-flight runs keep their own snapshot (the concurrent-reuse contract). `id` carries the run's identity; only the triple is used (the registry is identity-scoped, never keyed by run). This is sampling parameters only — ExtraInstructions / prompt layers are resolved elsewhere (the agent-config prompt-layer projection), so the per-agent LLM layer never carries prompt text.
func ActivePlannerCatalogView ¶
func ActivePlannerCatalogView(ctx context.Context, reg agentcfg.Registry, ov sessionoverlay.Store, agentID string, id identity.Quadruple, cat tools.ToolCatalog, filter tools.CatalogFilter) (tools.PlannerCatalogView, error)
ActivePlannerCatalogView builds the run's planner-facing catalog view at run start, applying the agent's active-config tool exposure: a paused MCP server's tools and any individually-disabled tool are excluded from the view (next-turn projection — the live transport stays WARM). The exclusion set is the order-independent union of THREE narrow-only disable tiers — the admin baseline, the durable per-user disable set (which spans that user's sessions for the agent), and the ephemeral session overlay — so it can only ever grow: no tier can re-expose a tool a higher tier disabled. It always returns a usable view: a nil registry, an empty agentID, an agent with no active revision, or an active revision with no tool-exposure section (or an empty one) returns the plain tools.NewPlannerView over cat+filter — the backward-compatible "ungated" path. A registry read error is returned so the caller fails the run loudly (CLAUDE.md §13): no silent fall-through to the unfiltered view on a read failure.
The active revision is read ONCE per run; the returned view is fresh, so concurrent / in-flight runs keep their own snapshot (the concurrent-reuse contract). Only the identity triple is used (the registry is identity-scoped, never keyed by run).
func ActivePromptLayers ¶
func ActivePromptLayers(ctx context.Context, reg agentcfg.Registry, agentID string, id identity.Quadruple) (base string, user string, ok bool, err error)
ActivePromptLayers resolves the agent's active-config layered system prompt at run start. It returns the base + user layer text and whether the active revision carries a prompt-layer section (ok). A nil registry, an empty agentID, an agent with no active revision, or an active revision with no prompt-layer section returns ("", "", false, nil) — the backward-compatible "no durable prompt layers" path (the run keeps its configured base). A registry read error is returned so the caller fails the run loudly (CLAUDE.md §13): no silent fall-through on a read failure.
An unset layer within a present section returns the empty string for that layer (the caller treats empty as "inherit the configured default" for the base, and "no user layer" for the user layer).
The active revision is read ONCE per run; the returned values are plain strings, so concurrent / in-flight runs keep their own snapshot (the concurrent-reuse contract). Only the identity triple is used (the registry is identity-scoped, never keyed by run).
func ActiveSkillViews ¶
func ActiveSkillViews(ctx context.Context, reg agentcfg.Registry, ov sessionoverlay.Store, agentID string, id identity.Quadruple, views []skills.SkillView) ([]skills.SkillView, error)
ActiveSkillViews applies an agent's active-config skills membership to the run's skill-directory views at run start. It resolves the agent's active revision once and, when the revision pins a skills section, keeps only the views whose name is in the membership set. A nil registry, an empty agentID, or an agent with no active revision / no skills section returns the views unchanged — the backward-compatible "ungated" path. A registry read error is returned so the caller fails the run loudly (CLAUDE.md §13): no silent fall-through to the unfiltered view on a read failure.
The active revision is read ONCE per run; the returned slice is fresh, so concurrent / in-flight runs keep their own snapshot (the concurrent-reuse contract). `id` carries the run's identity; only the triple is used (the registry is identity-scoped, never keyed by run).
func ApplyPromptLayers ¶
func ApplyPromptLayers(ctx context.Context, reg agentcfg.Registry, overlayStore sessionoverlay.Store, agentID string, id identity.Quadruple, ov *planner.LLMOverrides) (*planner.LLMOverrides, error)
ApplyPromptLayers overlays the agent's active-config durable prompt layers onto the run's resolved per-run override bundle at run start. It is the ONE shared seam both run-loop drivers (the production dev driver and the harbortest devstack twin) call after resolving the LLM-parameter overrides, so the two binaries cannot drift (CLAUDE.md §17.6).
A non-empty base layer is set as ov.BasePromptLayer (overriding the run's configured base at the prompt builder); a non-empty user layer is set as ov.UserPromptLayer (composed below the base in the lower-trust position). An empty layer is treated as unset (the base inherits the configured default; no user layer is added) — so a run with no durable prompt layers is unchanged. When ov is nil but a layer is present, a fresh bundle is allocated. A registry read error is returned so the caller fails the run loudly. The returned bundle is fresh-per-run (no shared mutable state).
func FilterSkillViewsByMembership ¶
FilterSkillViewsByMembership keeps only the views whose Name is in the membership set. An empty membership keeps nothing (the rollback-to-empty case — an explicit empty skills section disables every skill for the next run). The returned slice is always freshly allocated.
Types ¶
This section is empty.