agentruntime

package
v0.17.0 Latest Latest
Warning

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

Go to latest
Published: Aug 10, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package agentruntime provides per-agent runtime instances for team mode (RMI-OMNIAGENT-309). A chat names an agent; each turn must run on an instance built from that agent's persona + enabled skills (and, once RMI-310 lands, its agent-scoped secrets). Building an instance is expensive — it opens an LLM client and loads skills — so instances are built lazily on first use and held in a bounded LRU cache: a busy deployment keeps only its hottest agents resident, and an idle agent is evicted rather than pinned in memory forever.

Cache satisfies the chats.AgentRuntime seam (Slug + Processor), so the chats service routes an agent-bound chat's turns to the agent's own instance. The cache itself depends only on two seams — a ConfigLoader (reads an agent's runtime configuration by ID, in system context) and a Builder (turns that configuration into a processor) — so it is independent of the LLM/skill stack and unit-testable with fakes. AgentBuilder (builder.go) is the production Builder that constructs a real *agent.Agent.

Index

Constants

View Source
const DefaultMaxInstances = 64

DefaultMaxInstances bounds how many per-agent instances the cache holds resident before evicting the least-recently-used one. TRD §9 Q3 leaves the eviction policy to be tuned in Phase 4; this is a conservative default.

Variables

This section is empty.

Functions

This section is empty.

Types

type AgentBuilder

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

AgentBuilder is the production Builder: it constructs a real *agent.Agent from an agent's persona + enabled skills + agent-scoped secrets. The persona becomes the system prompt; the enabled-skill subset is applied via WithSkillIncludes over the shared BaseOptions skill source; model/provider fall back to the deployment defaults; and, when a SecretSource is configured, the agent's secrets are resolved and injected via WithSecretEnv (per-agent MCP subprocess env and other secrets-aware skills), so two agents load disjoint secrets with no cross-leak (RMI-OMNIAGENT-310).

func NewAgentBuilder

func NewAgentBuilder(cfg BuilderConfig) *AgentBuilder

NewAgentBuilder creates the production builder.

func (*AgentBuilder) Build

Build constructs the agent instance for cfg. It satisfies Builder.

type AgentConfig

type AgentConfig struct {
	ID       uuid.UUID
	Slug     string
	Name     string
	Persona  string
	Model    string
	Provider string
	Skills   []string
}

AgentConfig is an agent's resolved runtime configuration, loaded by ID. The runtime is a system principal (not a user), so a ConfigLoader reads it in system context, independent of RLS visibility.

type Builder

type Builder interface {
	Build(ctx context.Context, cfg AgentConfig) (chats.AgentProcessor, error)
}

Builder turns a resolved AgentConfig into a processor. It is the injection point for the LLM/skill stack (and, in RMI-310, agent-scoped secret binding), keeping the cache independent of the agent package and unit-testable. A processor that holds resources (e.g. *agent.Agent) should implement io.Closer; the cache closes it on eviction and on Close.

type BuilderConfig

type BuilderConfig struct {
	// Defaults supplies the deployment-wide LLM configuration (provider, model,
	// API key, base URL, timezone, temperature/token limits). An agent's own
	// Model/Provider override the defaults when set; everything else is inherited.
	Defaults agent.Config

	// BaseOptions are agent.Options shared by every built instance — the
	// deployment's skill source (skill pack/manager or dirs), tools, session
	// store, and rollover policy. The builder layers each agent's enabled-skill
	// subset (WithSkillIncludes) on top, so BaseOptions supplies where skills
	// come from and the agent's config selects which are active.
	BaseOptions []agent.Option

	// Secrets resolves each agent's agent-scoped secrets, injected into the
	// instance's secrets-aware skills (notably per-agent MCP subprocess env) via
	// agent.WithSecretEnv. Optional; nil means no secrets are injected. Because
	// each instance is built with only its own agent's secrets, two agents load
	// disjoint secrets with no cross-leak (RMI-OMNIAGENT-310).
	Secrets SecretSource

	// Logger defaults to slog.Default().
	Logger *slog.Logger
}

BuilderConfig configures the production AgentBuilder.

type Cache

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

Cache is a lazy, bounded-LRU cache of per-agent runtime instances. It satisfies chats.AgentRuntime. Safe for concurrent use.

func New

func New(cfg Config) (*Cache, error)

New creates a runtime cache.

func (*Cache) Close

func (c *Cache) Close() error

Close evicts and closes every resident instance. The cache is reusable afterward (a later Processor call rebuilds).

func (*Cache) Invalidate

func (c *Cache) Invalidate(agentID uuid.UUID)

Invalidate evicts an agent's cached instance (if any) and closes it, so the next turn rebuilds from current configuration. Call it when an agent's persona/skills change. It is a no-op when the agent is not resident.

func (*Cache) Len

func (c *Cache) Len() int

Len reports how many instances are resident (built or building).

func (*Cache) Processor

func (c *Cache) Processor(ctx context.Context, agentID uuid.UUID) (chats.AgentProcessor, error)

Processor returns the agent's instance, building it on first use and caching it (evicting the least-recently-used instance when over capacity). Concurrent callers for the same agent share a single build. A build error is not cached: the poisoned entry is dropped so the next call retries.

func (*Cache) Slug

func (c *Cache) Slug(ctx context.Context, agentID uuid.UUID) (string, error)

Slug returns the bound agent's slug for @-mention matching. It does not build or cache an instance — only the cheap config read.

type Config

type Config struct {
	// Loader reads agents' runtime configuration. Required.
	Loader ConfigLoader
	// Builder builds an instance from a config. Required.
	Builder Builder
	// MaxInstances bounds the resident instance count; <=0 uses
	// DefaultMaxInstances.
	MaxInstances int
	// Logger defaults to slog.Default().
	Logger *slog.Logger
}

Config configures the cache.

type ConfigLoader

type ConfigLoader interface {
	// AgentSlug returns just the agent's slug — the cheap read a group turn
	// makes for @-mention matching, without building the instance.
	AgentSlug(ctx context.Context, agentID uuid.UUID) (string, error)
	// LoadConfig returns the agent's full runtime configuration.
	LoadConfig(ctx context.Context, agentID uuid.UUID) (AgentConfig, error)
}

ConfigLoader reads an agent's runtime configuration by ID, in system context. The two methods are split so a group turn can make the cheap @-mention check (AgentSlug) without triggering a full config load or instance build.

type SecretSource

type SecretSource interface {
	ResolveSecrets(ctx context.Context, agentID uuid.UUID) (map[string]string, error)
}

SecretSource resolves an agent's secrets, by ID, into the environment map its runtime instance injects (env-var name → value). It is the seam through which agent-scoped secrets (RMI-OMNIAGENT-310) reach the builder, keeping the builder independent of the secret store and unit-testable with a fake. A nil SecretSource means no secrets are injected (prior behavior). Resolution runs in system context — the runtime is a system principal, not a user.

Jump to

Keyboard shortcuts

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