Documentation
¶
Overview ¶
Package compose wires a workload bundle plus its specialist specs into a runnable root agent. It is the shared core behind the two entry points that construct dispatch shapes: cmd/mast (flag-driven) and the top-level mast convenience package (programmatic). Both MUST go through BuildRoot so the dispatch semantics — planner override, graph vs. coordinator, per-mode toolset offering — cannot drift between the binary and the library.
This is runtime glue, not public API (docs/library-api-design.md marks internal/ packages churnable); library consumers reach it via the root mast package or compose the pkg/ subsystems directly.
Index ¶
- func BuildClassRoot(class string, llm model.LLM, pauseRecorder planner.PauseRecorder) (adkagent.Agent, error)
- func BuildModel(ctx context.Context, provider, name string) (model.LLM, error)
- func BuildRoot(cfg RootConfig) (adkagent.Agent, error)
- func RatePer1K(modelName string) float64
- type Dispatch
- type RootConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuildClassRoot ¶
func BuildClassRoot(class string, llm model.LLM, pauseRecorder planner.PauseRecorder) (adkagent.Agent, error)
BuildClassRoot constructs the runnable root agent for one public task class — the shape behind cmd/mast's one-shot path (`mast --task=<class> "<prompt>"`). The class → mode mapping is pkg/taskclass's (docs/orchestration-design.md "Public task classes"):
- chat → a Chat-mode coordinator (pkg/agent.NewCoordinator).
- debug / implement / research / review → a Task-mode agent, wrapped in a one-node workflow root because ADK v2.1.0's runner only accepts Chat-mode LlmAgent roots directly (same idiom as pkg/planner.NewRoot).
- orchestrate → the planner-enabled root (pkg/planner.NewRoot) with an empty specialist roster — the planner scaffold runs and reports honestly that no specialists are declared; a roster needs a workload bundle, which is serve-mode territory in v0.1.
Instruction precedence (pkg/taskclass modes.go): the class profile's per-class default is passed explicitly, so it beats the generic per-mode fallback; classes without per-class text (chat) fall through to pkg/agent's mode default via the constructor's own empty-Instruction rule. pauseRecorder enables the planner classes' pause_session tool when the caller has a durable store (nil otherwise — an in-memory pause would die with the process).
func BuildModel ¶
BuildModel constructs the model.LLM for the given provider alias and model name. The provider alias is only consulted where the model id alone is ambiguous (claude-* serves against api.anthropic.com or Vertex); everything else dispatches on the name.
- "echo": fake in-process echo model (no credentials required).
- "toolactor": request-driven offline fake that drives registered tool calls deterministically (pkg/agent/toolactor.go); the v0.2 UAT harness uses it to exercise the crash/drain/abort legs against a real blocking MCP tool. No credentials required.
- "scripted": JSONL recorded-turn replay via pkg/providers/mock; the recording path comes from MAST_SCRIPT, and MAST_SCRIPT_STRICT=1 enables strict Contents matching.
- "gemini-*": ADK's Gemini model wrapped in pkg/providers/gemini's builtin-tool layer (GoogleSearch + URLContext on — core-agent's defaults; Vertex vs API key is genai's env-driven selection).
- "claude-*": pkg/providers/anthropic; see anthropicProvider for backend selection.
func BuildRoot ¶
func BuildRoot(cfg RootConfig) (adkagent.Agent, error)
BuildRoot builds the roster and assembles the dispatch shape:
- bundle.Planner.Enabled → the supervisor-body planner root (pkg/planner); Dispatch is ignored.
- DispatchGraph → the workflow graph (pkg/graph); errors without a SingleTurn classifier.
- DispatchCoordinator → the SubAgents coordinator (pkg/router).
- DispatchAuto/empty → graph when the roster has both a SingleTurn classifier and a graph.FallbackName specialist, else coordinator.
func RatePer1K ¶
RatePer1K derives pkg/budget's flat USD-per-1K-total-tokens rate for a model name (budget.Limits.RatePer1K — API unchanged).
Gemini and Claude rates come from pkg/pricing's builtin catalog (longest-prefix lookup, so dated/suffixed IDs land). The catalog prices input and output tokens separately, but the budget meter only sees UsageMetadata.TotalTokenCount, so the flat rate is the plain average of the two per-MTok rates scaled to per-1K — a deliberate v0.1 approximation that overcharges input-heavy sessions and undercharges output-heavy ones rather than complicating the budget API. Gemini IDs the catalog doesn't know keep the old flat spike rate so cost metering never silently drops to zero.
The echo fake keeps its inflated rate: offline smoke tests (scripts/demo-spike2.sh scenario 3) trip small caps with it. The scripted replay and toolactor share it — all offline test doubles.
Types ¶
type Dispatch ¶
type Dispatch string
Dispatch selects the root shape BuildRoot assembles.
const ( // DispatchCoordinator is the spike-1 SubAgents pattern: a // Chat-mode coordinator with the roster as SubAgents (pkg/router). DispatchCoordinator Dispatch = "coordinator" // DispatchGraph is the spike-2 workflow-graph LLM-as-router shape // (pkg/graph). Requires a SingleTurn classifier in the roster. DispatchGraph Dispatch = "graph" // DispatchAuto picks the shape from the roster: graph when a // SingleTurn classifier and a graph.FallbackName Task specialist // are both present (the pair graph dispatch needs), coordinator // otherwise. This is the library default — programmatic callers // declare a roster, not a flag. DispatchAuto Dispatch = "auto" )
type RootConfig ¶
type RootConfig struct {
// Bundle is the workload definition (naming, roster order,
// planner/HITL policy).
Bundle workload.Bundle
// Specs is the loaded specialist roster. Specs with an empty Mode
// build as Task-mode (the same default pkg/specialists applies).
Specs []specialists.Spec
// Model drives every built specialist (specs with a model override
// already bound it upstream — the spike binds one model per
// process).
Model model.LLM
// Toolsets are offered to Task-mode specialists (and filtered
// through each spec's allowlist by specialists.Build). SingleTurn
// classifiers never receive toolsets — they run one shot with no
// tool loop.
Toolsets []tool.Toolset
// Dispatch selects the root shape. Empty means DispatchAuto.
Dispatch Dispatch
// Logger, when non-nil, receives the same construction-time notes
// cmd/mast has always logged (e.g. planner overriding dispatch).
Logger *slog.Logger
// PauseRecorder enables the planner's pause_session tool (v0.2
// plane-A self-pause) by giving it a durable record sink —
// *transcript.Store, or the daemon's scheduler-aware wrapper. Nil
// (no durable store) leaves the tool unregistered.
PauseRecorder planner.PauseRecorder
}
RootConfig carries everything BuildRoot needs to turn a loaded bundle + specs into a root agent. Bundle and Specs use the existing pkg/workload and pkg/specialists vocabulary — file-loaded and programmatic values are indistinguishable here by design (docs/library-api-design.md, "Embeddable config vs. file-loaded config").