diff --git a/docs/manifests/README.md b/docs/manifests/README.md index 417d8905..9619e257 100644 --- a/docs/manifests/README.md +++ b/docs/manifests/README.md @@ -35,7 +35,7 @@ config.yaml ← project defaults (flavour, infra_refs, .env path) | Layer | Manifest kinds | Reference | |-------|----------------|-----------| | **Agent** | `Agent` | [agent.md](agent.md) | -| **MAS** | `MAS`, `Workflow` | [mas.md](mas.md), [workflow.md](workflow.md) | +| **MAS** | `MAS`, `Workflow` | [mas.md](mas.md) | | **Override** | `Overlay` | [overlay.md](overlay.md) | | **Environment** | `Flavour`, `InfraBundle`, `LLMProxy` | [flavour.md](flavour.md), [infra.md](infra.md) | | **Experiment** | `experiment:` | [experiment.md](experiment.md) | @@ -83,7 +83,7 @@ Both forms are valid in `experiment.applications[]`: Scenarios reference overlay **ids** from `configs_dir` (e.g. tutorial `cot` vs lab `pattern-cot`). Dataset: `path: ./dataset.yaml` (tutorial) or `name` + `locator: samples` (catalogued benchmarks). -See [topology-and-workflow.md](topology-and-workflow.md) for workflow vs routing overlays. +See [Topology, workflow, and routing](mas.md#topology-workflow-and-routing) for workflow vs routing overlays. --- diff --git a/docs/manifests/agent.md b/docs/manifests/agent.md index c1a7094f..79f761ea 100644 --- a/docs/manifests/agent.md +++ b/docs/manifests/agent.md @@ -12,140 +12,576 @@ more agents; **overlays** patch agents without duplicating the base file. **Terms:** [glossary.md](../glossary.md) · Hub: [README.md](README.md). -Declares one runtime participant: how it reasons, what it can call, what context it -sees, and which plugins hook its execution. +--- + +## Top-level fields + +Every manifest starts with four required top-level fields. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `apiVersion` | `string` | yes | Must be `mas/v1`. | +| `kind` | `string` | yes | Must be `Agent`. | +| `metadata` | object | yes | Identity and tagging. See [`metadata` fields](#metadata-fields). | +| `spec` | object | yes | Runtime behaviour. See [`spec` fields](#spec-fields). | + +Extension properties (`x-*`) are allowed at the top level and are ignored by the runtime (they carry UI metadata, canvas state, etc.). + +**Minimal example:** + +```yaml +apiVersion: mas/v1 +kind: Agent +metadata: + name: broker +spec: + description: "Broker agent. Routes requests to specialists." +``` --- -## Responsibilities +## `metadata` fields -| Area | `spec` fields | Trajectory impact | -|------|---------------|-------------------| -| Reasoning loop | `design_pattern` | Selects DesignPatternContract (ReAct, CoT, …) — intra-agent δ transitions | -| Peer delegation | MAS `workflow` (when embedded in a MAS) | `delegates_to` graph + `workflow.type`; executed by the entry agent's own `design_pattern` (ReAct tool loop) — see [mas.md](mas.md) | -| Context window | `context_manager` | Stack / sliding-window / summarising | -| Prompt / role | `description`, `context` | `description` → delegation tools; `context.*` → system prompt | -| Models | `models[]` | LLM routing (ids, temperature, max_tokens) | -| Tools | `tools`, `tools_ref` | ToolContract surface | -| Skills | `skills`, `context_manager.skills` | Context facets + `consult_skills` | -| Memory | `memory`, `memory_seed` | Stores + startup seeds | -| Working memory | `working_memory.persistent` | Cross-turn buffer survives repeat delegate calls within one session (default `true`) — see below | -| Kernel plugins | `plugins[]`, `governance[]`, `observability[]` | Governance and observability on Mealy envelope chokepoints (not a hook plane) | -| Execution bounds | `execution` | Timeouts, retries | +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `name` | `string` | yes | — | Agent ID — must match the workflow node id that references this agent. | +| `description` | `string` | no | `""` | Human-readable description of this agent. | +| `version` | `string` | no | `"0.1.0"` | Semver string (`major.minor.patch`). | +| `tags` | `string[]` | no | `[]` | Free-form tags for filtering and grouping. | + +Extension properties (`x-*`) are allowed and ignored by the runtime. --- -## Delegation +## `spec` fields + +`spec.description` is the only required field. + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `description` | `string` | **yes** | — | Routing-facing one-liner for delegation tools, AgentCard, and registry discovery. Written from the delegator's perspective. **Not** injected into the LLM system prompt — use `context.*` for prompt text. | +| `context` | `object` | no | — | Named chunks injected into the system prompt. Keys are author-defined (`role`, `intent`, …). See [`ContextChunk`](#contextchunk). | +| `params` | `object` | no | `{}` | Free-form string key/value params forwarded to infra middleware — not consumed by the kernel. | +| `models` | `ModelEntry[]` | no | `[]` | Preferred models for this agent. See [`ModelEntry`](#modelentry). | +| `design_pattern` | object \| null | no | `react` | Reasoning strategy. See [`DesignPattern`](#designpattern). | +| `context_manager` | object | no | `stack` | Context window management. See [`ContextManager`](#contextmanager). | +| `memory_seed` | `MemorySeedEntry[]` | no | — | Documents to pre-index into memory at startup. See [`MemorySeedEntry`](#memoryseedentry). | +| `memory` | string \| string[] \| object | no | — | Memory backend configuration. See [`MemoryConfig`](#memoryconfig). | +| `working_memory` | object | no | — | Cross-turn history persistence for delegated agents. See [`WorkingMemory`](#workingmemory). | +| `skills` | `string[]` | no | `[]` | Skills to activate. Name-only or `@library/name`. Resolution: app-local → libraries → packages. | +| `tools_ref` | `string` \| null | no | `null` | Logical tool-set name resolved by the infra `ToolRegistry` (e.g. `sre-tools`). No paths or extensions. | +| `tools` | `Tool[]` | no | `[]` | Per-agent tool declarations — three forms. Additive with `tools_ref`. See [`Tool`](#tool). | +| `behavior` | object | no | — | Runtime capability flags. See [`Behavior`](#behavior). | +| `governance` | `GovernanceBinding` | no | `{}` | Governance plugin list. See [`GovernanceBinding`](#governancebinding). | +| `llm` | `LlmBinding` | no | `{}` | Engine overrides (model, temperature, …). See [`LlmBinding`](#llmbinding). | +| `execution` | `ExecutionBinding` | no | `{}` | Execution mode (mock, cache, live, …). See [`ExecutionBinding`](#executionbinding). | +| `control` | `ControlBinding` | no | `{}` | Control-plane plugin configs. See [`ControlBinding`](#controlbinding). | +| `observability` | `ObservabilityBinding` | no | `null` | Observability sink plugin list. See [`ObservabilityBinding`](#observabilitybinding). | +| `infra_refs` | `string[]` | no | `[]` | Infra manifest references (LLM proxy, tool registry). Merged additively from overlays. | +| `infra_interceptors` | `string[]` | no | `[]` | Cross-cutting infra middleware (cache, chaos, …) outer-first. | -**Who** an agent may delegate to is declared on the **MAS** manifest, not on the agent alone: +--- -| Concern | Manifest | Field | -|---------|----------|-------| -| Delegation graph (peers) | MAS | `spec.workflow.nodes[].delegates_to`, `workflow.entry` | -| Workflow driver | MAS | `spec.workflow.type` — `dynamic` (LLM picks peers), `sequential`, or `single` | -| Per-peer tool text | Agent | `spec.description` — surfaced on `delegate_to_` tools for the entry agent | +## Sub-schemas -When `workflow.type` is **dynamic**, the entry agent's LLM receives one OpenAI tool per allowed peer: -`delegate_to_` with a `task` argument. `mas-ctl run-mas` executes those calls over the -materialized in-process CommBus via the default `LlmDelegator` plugin. There is no separate -delegation-transport plugin binding on the agent — *how* peer delegation executes is the entry -agent's own `design_pattern` (the ReAct tool loop dispatching `delegate_to_*` tool calls), the same -contract that drives its own reasoning. +### ContextChunk -See [topology-and-workflow.md](topology-and-workflow.md) and [mas.md](mas.md). +_Used by:_ `spec.context.` + +Each value under `spec.context` is a named chunk injected into the system prompt under `[key]`. Two forms: + +| Form | Type | Description | +|------|------|-------------| +| Inline string | `string` | Injected as literal text, unless the value resolves to an existing file path (e.g. `prompts/role.md` or `./prompts/role.md`). | +| File reference | `{ ref: string }` | Always loads the file at `ref`. Raises `ContextRefNotFoundError` at bootstrap when the path is missing. | + +**Example:** + +```yaml +context: + role: | + You are a telemetry analyst… + intent: + ref: "./prompts/intent.md" +``` --- -## Working memory across delegate calls +### ModelEntry + +_Used by:_ `spec.models[]` -A delegated agent's `RuntimeInstance` is materialized once per MAS run and reused for every -`delegate_to_` call in that run — so by default a sub-agent already sees its own prior -exchange on the second call: `moderator` asks for "Foo", gets it, then says "add Bar" without -repeating context, and the sub-agent still has "Foo" in its committed history. +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `model` | `string` | **yes** | — | LiteLLM-style model string, e.g. `vertex_ai/gemini-3-pro-preview`. | +| `id` | `string` | no | `"main"` | Logical model ID within this agent. Use `main` for the primary model. | +| `temperature` | `number` [0.0–2.0] | no | `0.7` | Sampling temperature. | +| `max_tokens` | `integer` ≥ 1 | no | `2000` | Maximum output tokens. | -**`spec.working_memory.persistent`** (default `true`) makes this explicit and controllable per -agent, keyed by `(session_id, agent_id)` in an in-process registry rather than relying on Python -object reuse: +Do **not** put `api_base` or `api_key_env` here — those belong in the flavour/infra manifest. + +**Example:** ```yaml -working_memory: - persistent: true # default — continue this agent's history across delegate calls in-session +models: + - model: vertex_ai/gemini-3-pro-preview + temperature: 0.3 + max_tokens: 4096 +``` + +--- + +### DesignPattern + +_Used by:_ `spec.design_pattern` + +Selects the agent's reasoning strategy (defaults to `react` when absent). + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `type` | `string` | mutually exclusive with `ref` | Builtin shorthand: `react` \| `cot` \| `cot_native` \| `plan_execute` \| `tree_of_thoughts` \| `accumulator` and role aliases. | +| `ref` | `string` | mutually exclusive with `type` | Unified plugin locator — bare name, `./local/path`, `module://pkg.Class`, or `oci://registry/img:tag`. | +| `params` | `object` | no | Plugin-specific parameters. | +| `config` | `object` | no | Alias for `params` (overlay compatibility). | + +**Example:** + +```yaml +design_pattern: + type: react + +# or a custom plugin: +design_pattern: + ref: module://my_pkg.patterns.MyCoT + params: + max_steps: 10 ``` -Set `persistent: false` for a sub-agent that must be stateless per call (e.g. a formatter or -translator that should never see a previous, unrelated delegation's turns) — its committed history -is cleared before every delegate call even though the underlying instance is reused. +--- + +### ContextManager -**Overlays can set this too** (`spec.patch.working_memory.persistent` on an `Overlay` targeting -`kind: Agent`) — useful to flip a shared agent manifest's default per deployment/experiment without -forking it. +_Used by:_ `spec.context_manager` -**`context_id`** — the delegating agent's LLM may optionally pass `context_id` as an extra argument -on `delegate_to_`, alongside `task`. When given, it selects an independent working-memory -bucket for that peer instead of the session's default one — e.g. a moderator running two unrelated -conversations with the same specialist (`context_id: "trip-paris"` vs. `"trip-tokyo"`) within one -session, with neither leaking into the other. Omit it (the common case) to use the session's -default bucket, as described above. +Controls context window management strategy (defaults to `stack` — unbounded history). -This is in-memory and scoped to one mas-ctl session/run — it does not persist across separate CLI -invocations. Cross-process persistence (`spec.memory.persistence`) is a tracked follow-up. +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `type` | `string` | mutually exclusive with `ref` | Builtin: `stack` \| `sliding-window` \| `summarising` \| `full-history`. | +| `ref` | `string` | mutually exclusive with `type` | Plugin locator — same forms as `design_pattern.ref`. | +| `params` | `ContextManagerParams` | no | Strategy-specific parameters. See [`ContextManagerParams`](#contextmanagerparams). | +| `skills` | `string[]` | no | Skills auto-injected into the system prompt via `ContextFacetProvider` (context path; complements `spec.skills` which drives the `consult_skills` tool). | +| `memory` | `string[]` | no | Memory types whose content is auto-injected into the system prompt as context facets, e.g. `[semantic]`. | -**`spec.working_memory.compaction`** — how much of the committed history to keep as it grows. A -facade over `spec.context_manager`/`CMFactory` (set `context_manager` directly instead for -lower-level control — it takes precedence if both are set): +**Example:** + +```yaml +context_manager: + type: sliding-window + params: + window_size: 20 +``` + +--- + +### ContextManagerParams + +_Used by:_ `spec.context_manager.params` + +Constructor kwargs forwarded to the `ContextManagerPlugin`. All fields are optional. + +| Field | Type | Description | +|-------|------|-------------| +| `max_turns` | `integer` ≥ 1 | Sliding-window / summarising — max prior exchange pairs. | +| `window_size` | `integer` ≥ 1 | Alias for `max_turns` (sliding-window). | +| `max_messages` | `integer` ≥ 1 | Stack CM — cap on total past messages. | +| `working_memory_messages` | `integer` ≥ 1 | Slice size for working-memory context source (default 20). | +| `token_budget` | `integer` ≥ 1 | Max estimated input tokens after assembly. | +| `max_tokens` | `integer` ≥ 1 | Alias for `token_budget`. | +| `reserve_tokens` | `integer` ≥ 0 | Tokens reserved for model completion (default 512). | +| `summary_threshold` | `integer` ≥ 1 | Summarising CM — token threshold before compression triggers. | +| `keep_turns` | `integer` ≥ 1 | Summarising CM — recent exchange pairs kept verbatim alongside the summary. | +| `working_memory_ref` | `string` | Registry ref for working-memory context source plugin. | +| `trimmer_ref` | `string` | Registry ref for token-budget trimmer plugin. | +| `token_budget_ref` | `string` | Alias for `trimmer_ref`. | + +--- + +### MemorySeedEntry + +_Used by:_ `spec.memory_seed[]` + +Pre-indexes a document into the memory backend at startup. Useful for demos and tests that need pre-populated memory without a persistent store. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `content` | `string` | **yes** | Document text to index. | +| `key` | `string` | no | Lookup key. | +| `source` | `string` | no | Source label / filename. | +| `id` | `string` | no | Explicit document ID. | +| `text` | `string` | no | Alias for `content`. | + +**Example:** + +```yaml +memory_seed: + - source: "runbook.md" + content: | + ## Restart procedure + 1. Drain traffic… +``` + +--- + +### MemoryConfig + +_Used by:_ `spec.memory` + +Three forms are accepted: + +| Form | Example | Description | +|------|---------|-------------| +| String shorthand | `memory: semantic` | Resolves to the corresponding plugin bundle. | +| Array shorthand | `memory: [semantic, episodic]` | Activates multiple named bundles. | +| Object form | `memory: {enabled: true, types: [...]}` | Full configuration — described below. | + +**Object form fields:** + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `enabled` | `boolean` | `true` | Master switch — `false` loads no memory plugins. | +| `types` | `MemoryType[]` | `[]` | Ordered list of memory layers. See [`MemoryType`](#memorytype). | +| `persistence` | object | — | Session transcript persistence. See [`MemoryPersistence`](#memorypersistence). | +| `search` | object | — | Semantic retrieval configuration. See [`MemorySearch`](#memorysearch). | +| `citations` | object | — | Citation formatting for search results. See [`MemoryCitations`](#memorycitations). | +| `sync` | object | — | File-watching and re-indexing policy. See [`MemorySync`](#memorysync). | +| `overflow_retry` | object | — | Compaction retry on context overflow. See [`MemoryOverflowRetry`](#memoryoverflowretry). | +| `qmd` | object | — | QMD (Qualitative Memory Database) backend. See [`MemoryQMD`](#memoryqmd). | + +#### MemoryType + +_Used by:_ `spec.memory.types[]` + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `name` | `string` | **yes** | — | Layer name: `session` \| `episodic` \| `semantic` \| `working` \| `procedural`. | +| `backend` | `string` | no | `"in-memory"` | Backend: `in-memory` \| `file` \| `sqlite-vec` \| `redis` \| `remote_tool`. | +| `params` | `MemoryBackendParams` | no | `{}` | Backend constructor kwargs. See [`MemoryBackendParams`](#memorybackendparams). | + +#### MemoryBackendParams + +_Used by:_ `spec.memory.types[].params` + +| Field | Type | Description | +|-------|------|-------------| +| `path` | `string` | Filesystem path (file backend). | +| `url` | `string` | Connection URL (redis, remote_tool). | +| `collection` | `string` | Collection / table name. | +| `host` | `string` | Hostname. | +| `port` | `integer` | Port number. | +| `database` | `string` | Database name. | + +#### MemoryPersistence + +_Used by:_ `spec.memory.persistence` + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `backend` | `string` | `"none"` | `none` \| `file` \| `sqlite` \| `redis`. | +| `path` | `string` | `""` | Base directory. Supports `{agent_id}` and `{session_id}` placeholders. Default: `$XDG_DATA_HOME/mas/agents/{agent_id}/sessions/`. | +| `auto_save` | `boolean` | `true` | Persist after each turn. | +| `auto_load` | `boolean` | `true` | Load session on bootstrap. | + +#### MemorySearch + +_Used by:_ `spec.memory.search` + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `enabled` | `boolean` | `false` | Enable semantic search injection into context. | +| `max_results` | `integer` | `6` | Maximum retrieved chunks per query. | +| `min_score` | `number` | `0.35` | Minimum similarity score threshold. | +| `chunking.tokens` | `integer` | `400` | Chunk size in tokens for indexing. | +| `chunking.overlap` | `integer` | `80` | Overlap tokens between chunks. | +| `hybrid.enabled` | `boolean` | `true` | Enable hybrid search (vector + full-text). | +| `hybrid.vector_weight` | `number` | `0.7` | Vector score weight in hybrid ranking. | +| `hybrid.text_weight` | `number` | `0.3` | Full-text score weight in hybrid ranking. | +| `hybrid.mmr_enabled` | `boolean` | `false` | Max Marginal Relevance re-ranking. | +| `hybrid.mmr_lambda` | `number` | `0.7` | MMR lambda (diversity vs relevance). | +| `hybrid.temporal_decay_enabled` | `boolean` | `false` | Apply time-decay to scores. | +| `hybrid.temporal_decay_half_life_days` | `integer` | `30` | Half-life for temporal decay. | +| `cache.enabled` | `boolean` | `true` | Cache search results. | +| `cache.max_entries` | `integer` | `128` | Maximum cached search results. | + +#### MemoryCitations + +_Used by:_ `spec.memory.citations` + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `mode` | `"auto"` \| `"on"` \| `"off"` | `"auto"` | Citation mode: `auto` (include when useful), `on` (always), `off` (strip source info). | +| `max_snippet_chars` | `integer` | `700` | Maximum characters per search result snippet. | + +#### MemorySync + +_Used by:_ `spec.memory.sync` + +Controls when workspace memory files (`MEMORY.md`, `memory/*.md`) are re-indexed. + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `on_session_start` | `boolean` | `true` | Re-index when a session begins. | +| `on_search` | `boolean` | `false` | Re-index before each search. | +| `interval_seconds` | `integer` | `300` | Periodic re-index interval in seconds (0 = disabled). | +| `delta_messages` | `integer` | `50` | Re-index after this many new messages. | +| `delta_bytes` | `integer` | `100000` | Re-index after this many bytes of new content. | +| `post_compaction_force` | `boolean` | `true` | Force re-index after compaction. | +| `file_watch.enabled` | `boolean` | `true` | Enable file change detection. | +| `file_watch.patterns` | `string[]` | `["MEMORY.md","memory/*.md"]` | Glob patterns to watch. | +| `file_watch.debounce_ms` | `integer` | `1500` | Debounce interval for file change events. | + +#### MemoryOverflowRetry + +_Used by:_ `spec.memory.overflow_retry` + +When an LLM call fails because the context exceeds the window, automatically compact and retry. + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `enabled` | `boolean` | `false` | Enable overflow detection and retry. | +| `max_retries` | `integer` | `2` | Maximum compaction + retry attempts. | +| `aggregate_timeout_seconds` | `number` | `60.0` | Maximum total time across all retries. | +| `budget_reduction_factor` | `number` | `0.7` | Multiply token budget by this factor on each retry. | + +#### MemoryQMD + +_Used by:_ `spec.memory.qmd` + +Alternative search via external `qmd` binary (Qualitative Memory Database). + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `enabled` | `boolean` | `false` | Enable QMD as a retriever backend. | +| `binary_path` | `string` | `""` | Path to `qmd` binary (auto-detected if empty). | +| `index_path` | `string` | `""` | Path to QMD index directory. | +| `search_mode` | `string` | `"search"` | QMD search mode. | +| `max_snippet_chars` | `integer` | `700` | Maximum characters per snippet. | +| `timeout_seconds` | `number` | `4.0` | Search timeout in seconds. | + +--- + +### WorkingMemory + +_Used by:_ `spec.working_memory` + +Controls whether a delegated agent's committed conversation history (user/assistant turns) survives across separate delegation calls within the same `mas-ctl` session, keyed by `(session_id, agent_id)`. + +Distinct from `spec.memory`: that's the `MemoryContract` retrieval-store subsystem (semantic/episodic/procedural search); this is the raw turn buffer a delegated agent falls back on. + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `persistent` | `boolean` | `true` | `true`: reuse committed turn history across delegate calls within the same session. `false`: clear working memory before every delegate call — for agents that must be stateless per call (e.g. a formatter or translator). | +| `compaction` | `WorkingMemoryCompaction` | — | How much history to keep as it grows. See [`WorkingMemoryCompaction`](#workingmemorycompaction). Facade over `spec.context_manager` — set `context_manager` directly instead for lower-level control (takes precedence if both are set). | + +**Context ID:** the delegating agent may pass `context_id` alongside `task` on a `delegate_to_` call to select an independent working-memory bucket for that peer (e.g. `"trip-paris"` vs `"trip-tokyo"` within one session). Omit it to use the session's default bucket. + +#### WorkingMemoryCompaction + +_Used by:_ `spec.working_memory.compaction` + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `strategy` | `"keep_recent"` \| `"sliding_window"` \| `"summarize"` | `"keep_recent"` | Compaction strategy (see below). | +| `max_messages` | `integer` ≥ 1 | — | `keep_recent` — cap on total committed messages. | +| `window_size` | `integer` ≥ 1 | — | `sliding_window` — number of recent exchange pairs to keep. | +| `summary_threshold` | `integer` ≥ 1 | `4000` | `summarize` — estimated-token threshold before compaction triggers. | +| `keep_turns` | `integer` ≥ 1 | `10` | `summarize` — recent exchange pairs kept verbatim alongside the summary. | + +**Strategies:** + +- `keep_recent` — cap total messages at `max_messages`, no LLM call. +- `sliding_window` — keep the last `window_size` exchange pairs, no LLM call. +- `summarize` — compress older turns into one summary block via this agent's own model, keeping `keep_turns` recent pairs verbatim. Degrades to `keep_recent` when no live model is available. + +**Example:** ```yaml working_memory: + persistent: true compaction: - strategy: keep_recent # keep_recent (default, no LLM call) | sliding_window | summarize - max_messages: 200 # keep_recent - window_size: 20 # sliding_window - summary_threshold: 4000 # summarize - keep_turns: 10 # summarize — recent exchanges kept verbatim alongside the summary + strategy: summarize + summary_threshold: 4000 + keep_turns: 10 ``` -`summarize` calls an LLM (using this agent's own resolved model) to compress older turns into one -summary block; it degrades to `keep_recent` rather than failing if no live model is available. -`keep_recent`/`sliding_window` never spend a model call. See -`docs/design/working-memory-compaction.md` for the full design and why the two dead schema surfaces -this replaces were removed. +--- + +### Tool + +_Used by:_ `spec.tools[]` + +Three forms are accepted. All are additive with `tools_ref`. + +#### Form A — manifest reference (recommended) + +References a `kind: Tool` manifest file or a `ToolBundle` entry. + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `ref` | `string` | **yes** | — | Path to a `kind: Tool` manifest (`./tools/calc.tool.yaml`) or a ToolBundle entry (`bundle://sre-tools/check-health`). | +| `priority` | `integer` | no | `100` | Registration priority (higher = loaded first). | + +#### Form B — inline anonymous + +Inline declaration for a Python class, remote tool, or OpenAPI endpoint. + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `module_path` | `string` | **yes** | — | Dotted Python module path or relative file path (`./tools/my_tool.py`). | +| `kind` | `"python"` \| `"remote_tool"` \| `"openapi"` | no | `"python"` | Implementation kind. | +| `class_name` | `string` | no | — | Class name in the module. Auto-discovered when omitted. | +| `priority` | `integer` | no | `100` | Registration priority. | +| `params` | `object` | no | `{}` | Optional tool-specific init params. | + +#### Form C — semantic name + +A bare string resolved by the flavour's `tool_providers` (e.g. `web-search`, `calculator`, `memory-search`). + +**Example:** + +```yaml +tools: + - ref: ./tools/calculator.tool.yaml # Form A + - module_path: library-samples/tools/calc.py # Form B + class_name: CalcTool + - web-search # Form C +``` --- -## Composition +### Behavior + +_Used by:_ `spec.behavior` -- **Standalone:** single `agent.yaml` via `mas-ctl chat agent.yaml` (or `mas-ctl run-mas` when embedded in a MAS). -- **In a MAS:** referenced by `MAS.spec.agency.agents[].ref`. -- **Inline:** full agent spec embedded in MAS (studio export) — same fields under agent entry. -- **Overridden:** `Overlay.spec.patch.agents.` or global `design_pattern` / `tools: {"$op": {"remove": [...]}}`. +Structural/semantic flags that affect which system tools and capabilities are exposed to the agent's LLM at runtime. + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `share_reasoning` | `boolean` | `false` | When `true`, the `send_to_caller` tool exposes an optional `reasoning_context` parameter. The sub-agent may provide a concise summary of HOW it reached its answer (key evidence, decision points, confidence signals), forwarded to the orchestrator as `result["reasoning"]`. Enable only for trusted internal agents where context leakage is acceptable. | +| `delegation_style` | `"typed"` | `"typed"` | Controls which delegation tools are registered. `typed`: `delegate_to_` tools derived from the MAS workflow. | --- -## Reference forms +### GovernanceBinding + +_Used by:_ `spec.governance` + +An ordered list of governance plugin stanzas (typically applied via overlay). Each entry is either a bare plugin id string or a single-key object mapping the plugin id to its config object. ```yaml -design_pattern: - ref: module://my_pkg.patterns.MyCoT # plugin locator - # or type: react -skills: - - triage-protocol - - "@sre-skills/memory-protocol" # library id -description: "Telemetry analyst. Call for latency baselines and error rates." -context: - role: | - You are a telemetry analyst… +governance: + - policy-enforcer # bare id + - rate-guard: # id-keyed config object + requests_per_minute: 60 ``` -Inline prompt file reference: +Plugin ids are resolved at runtime from the plugin registry. Any registered plugin (built-in or third-party) is valid without editing the schema. + +--- + +### LlmBinding + +_Used by:_ `spec.llm` + +`EngineContract` / `LiveLlmEngine` overrides. These complement `spec.models[]` — prefer `models` for per-agent routing and use `llm` for env-level or overlay-level adjustments. + +| Field | Type | Description | +|-------|------|-------------| +| `model` | `string` | LiteLLM-style model string override. | +| `provider` | `string` | Engine provider hint (`mock`, `openai`, `azure`, …). | +| `temperature` | `number` [0–2] | Sampling temperature override. | +| `max_tokens` | `integer` ≥ 1 | Maximum output tokens override. | + +**Example:** ```yaml -context: - role: - ref: "./prompts/broker.md" +llm: + provider: mock +``` + +--- + +### ExecutionBinding + +_Used by:_ `spec.execution` + +Controls the engine execution mode. + +| Field | Type | Description | +|-------|------|-------------| +| `mocking.enabled` | `boolean` | Enable mock engine (no real LLM calls). | +| `cache.enabled` | `boolean` | Enable response caching. | +| `live` | `boolean` | Force live engine (disable mock/cache). | +| `parallel` | `boolean` | Enable parallel tool execution. | +| `timeout` | `number` ≥ 0 | Per-call timeout in seconds. | + +**Example:** + +```yaml +execution: + mocking: + enabled: true ``` --- +### ControlBinding + +_Used by:_ `spec.control` + +Control-plane plugin configs keyed by plugin id. Set a key to `null` to disable the plugin. + +| Key | Fields | Description | +|-----|--------|-------------| +| `budget` | `max_tokens: integer`, `max_cost_usd: number` | Token or cost budget enforcement. | +| `circuit_breaker` | `failure_threshold: integer`, `reset_timeout_s: number` | Open circuit after `failure_threshold` consecutive failures; reset after `reset_timeout_s`. | +| `rate_limiter` | `requests_per_minute: integer` | Limit LLM call rate. | + +**Example:** + +```yaml +control: + budget: + max_tokens: 50000 + rate_limiter: + requests_per_minute: 30 +``` + +--- + +### ObservabilityBinding + +_Used by:_ `spec.observability` + +An ordered list of observability sink plugin ids. OSS sinks: `native`, `otel`. + +Each entry is either a bare plugin id or a single-key config object: + +```yaml +observability: + - native # bare id — defaults + - native: # with config + path: ./traces + events_file: events.jsonl + - otel: + output_path: ./otel-traces + otel_file: spans.json +``` + +Unknown plugin ids fail at load time. Extended sinks (`observe_sdk`, etc.) are internal-only. + +--- + ## Schema source ```bash @@ -160,7 +596,7 @@ curl http://localhost:8090/api/schemas/agent ## See also -- [MAS manifest](mas.md) — topology and transport +- [MAS manifest](mas.md) — topology, transport, and delegation - [Overlay manifest](overlay.md) — overrides - [Tutorial: building an agent](../tutorials/01-building-an-agent/README.md) -- [Design patterns](agent.md#design-pattern) — `spec.design_pattern` on agents +- [Design patterns](agent.md#designpattern) — `spec.design_pattern` on agents diff --git a/docs/manifests/mas.md b/docs/manifests/mas.md index 73c30192..aa04bb18 100644 --- a/docs/manifests/mas.md +++ b/docs/manifests/mas.md @@ -12,52 +12,369 @@ app plus **scenario** **overlays** that change topology or governance. **Terms:** [glossary.md](../glossary.md) · Hub: [README.md](README.md). -Declares multi-agent composition: participants, control flow, and system-level hooks. +--- + +## Top-level fields + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `apiVersion` | `string` | yes | Must be `mas/v1`. | +| `kind` | `string` | yes | Must be `MAS`. | +| `metadata` | object | yes | Identity and defaults. See [`metadata` fields](#metadata-fields). | +| `spec` | object | yes | Runtime behaviour. See [`spec` fields](#spec-fields). | +| `intent` | object | no | What this system knows and can do. See [`intent`](#intent). Prefer this top-level form when authoring a base manifest directly (overlays patch via `spec.intent`). | + +Extension properties (`x-*`) are allowed at the top level and are ignored by the runtime. + +**Minimal example:** + +```yaml +apiVersion: mas/v1 +kind: MAS +metadata: + name: trip-planner +spec: + agency: + agents: + - id: broker + ref: ./agents/broker.yaml + - id: flights + ref: ./agents/flights.yaml + workflow: + entry: broker + nodes: + - id: broker + delegates_to: [flights] + - id: flights +``` + +--- + +## `metadata` fields + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `name` | `string` | **yes** | — | Unique MAS identifier. Used in run output paths and agent URNs. | +| `version` | `string` | no | `"0.1.0"` | Semver string (`major.minor.patch`). | +| `description` | `string` | no | `""` | Human-readable description. | +| `tags` | `string[]` | no | `[]` | Free-form tags for filtering and grouping. | +| `default_flavour` | `string` | no | `"local"` | Name of the flavour to use when none is specified on the CLI. | + +Extension properties (`x-*`) are allowed and ignored by the runtime. + +--- + +## `spec` fields + +No fields are required; an empty `spec: {}` is valid. + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `agency` | object | — | Participants and delegation targets. See [`Agency`](#agency). | +| `agents` | array \| object | `[]` | Short-form agent list — equivalent to `agency.agents` on a base manifest. On an Overlay patch this becomes a per-agent-id override map or collection op. See [`AgentEntry`](#agententry). | +| `workflow` | object | — | Entry point and delegation graph. See [`Workflow`](#workflow). | +| `transport` | object | — | Communication protocol config. See [`Transport`](#transport). | +| `framework` | object | — | Framework surface adapter. See [`Framework`](#framework). | +| `tools_ref` | `string` \| null | `null` | MAS-level logical tool-set name resolved by the infra `ToolRegistry`. No paths or extensions. | +| `infra_refs` | `string[]` | `[]` | Infra manifest paths relative to the MAS manifest directory. | +| `memory_stores` | object | — | Named memory store artifact paths. See [`MemoryStores`](#memorystores). | +| `telemetry` | object | — | Telemetry output config. See [`Telemetry`](#telemetry). | +| `params` | `object` | `{}` | Free-form string key/value params for lab/benchmark tooling — not consumed by the runtime kernel directly. | +| `capabilities` | `object` | `{}` | Free-form capability declarations read by manifest loading — not consumed by the runtime kernel directly. | +| `intent` | object | `{}` | Overlay-patchable intent block. Prefer the top-level `intent` field when authoring a base manifest. | +| `middleware` | — | `null` | Reserved for future use. | +| `agents_add` | object | — | Overlay-only: agent entries to append to `agency.agents`, or `{"$op": {add\|clear}}`. | +| `agents_remove` | `string[]` | — | Overlay-only: agent ids to remove from `agency.agents`, or a collection op. | + +--- + +## Sub-schemas + +### `intent` + +_Used by:_ top-level `intent` (and `spec.intent` for overlays) + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `summary` | `string` | `""` | Short description of what this system knows and can do. Used in emulation and agent cards. | + +**Example:** + +```yaml +intent: + summary: "Books travel: flights, hotels, and itineraries." +``` + +--- + +### Agency + +_Used by:_ `spec.agency` + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `agents` | `AgentEntry[]` | `[]` | Ordered list of agent participants. See [`AgentEntry`](#agententry). | + +--- + +### AgentEntry + +_Used by:_ `spec.agency.agents[]`, `spec.agents[]` + +Two forms are accepted: + +#### Form A — manifest reference (recommended) + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `ref` | `string` | **yes** | Path to the agent manifest, relative to the MAS manifest directory. | +| `id` | `string` | no | Logical identifier used in workflow edges and `delegates_to` lists. Derived from `metadata.name` when omitted. | + +#### Form B — inline agent definition + +A full embedded `kind: Agent` manifest (same fields as a standalone `agent.yaml`). Used by studio exports. `kind`, `metadata`, and `spec` are required; `apiVersion` is optional. + +**Example:** + +```yaml +agency: + agents: + - id: broker + ref: ./agents/broker.yaml # Form A + - kind: Agent # Form B — inline + metadata: + name: summariser + spec: + description: "Summarises findings." +``` + +--- + +### Workflow + +_Used by:_ `spec.workflow` + +Declares the entry point and the delegation graph. The `workflow.type` is set per node on the entry agent's design pattern — there is no top-level `type` field here. + +| Field | Type | Description | +|-------|------|-------------| +| `entry` | `string` | ID of the entry-point agent (first to receive the user request). | +| `nodes` | `WorkflowNode[]` | Agent nodes in the workflow graph. See [`WorkflowNode`](#workflownode). | + +**Example:** + +```yaml +workflow: + entry: broker + nodes: + - id: broker + delegates_to: [flights, hotels] + - id: flights + - id: hotels +``` --- -## Responsibilities +### WorkflowNode -| Area | `spec` fields | Role | -|------|---------------|------| -| Participants | `agency.agents[]` | `id` + `ref` to agent manifests (or inline definitions) | -| Topology | `workflow` | `entry`, `nodes`, `delegates_to`, `edges` — see [topology-and-workflow.md](topology-and-workflow.md) | -| Transport | `transport` | High-level comm mode (`local`, `agent-remote`, emulation flags) | -| Shared tools | `tools_ref` | Default logical tool-set (resolved via infra ToolRegistry) | -| Infra wiring | `infra_refs[]` | Paths to `infra/v1` manifests / bundles | -| Memory artifacts | `memory_stores` | Episodic / semantic / procedural store paths | -| Telemetry | `telemetry.path` | Default events.jsonl location | -| System intent | `intent` (top-level) | Summary for emulation / agent cards | +_Used by:_ `spec.workflow.nodes[]` -Inter-agent **delegation graph** lives on MAS ``workflow``. Delegation *executes* through the -entry agent's own ``design_pattern`` (the ReAct tool loop dispatching ``delegate_to_*`` tool -calls) — there is no separate delegation-transport binding on the agent; see -[agent.md](agent.md#delegation). +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `id` | `string` | **yes** | — | Node identifier — must match an `agency.agents[].id`. | +| `delegates_to` | `string[]` | no | `[]` | IDs of agents this node may delegate to. Drives the `delegate_to_` tool set exposed to the entry agent's LLM. | +| `role` | `string` | no | — | Optional role label (informational). | +| `agent` | `string` | no | — | Agent id override (when the node id differs from the agent id). | +| `dispatch` | `string` | no | — | Parallel topology dispatch mode (e.g. `all`). | +| `config` | `object` | no | `{}` | Plugin-specific parameters (pattern-dependent keys). | +| `description` | `string` | no | `""` | Optional description for this node (informational). | --- -## Mealy product view +### Transport -```text -User input → workflow.entry agent → (delegation edges) → specialist agents -Each agent: own design_pattern Mealy machine + shared bus/transport +_Used by:_ `spec.transport` + +Controls how agents communicate within the MAS. + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `type` | `"local"` \| `"agent-remote"` \| `"agent-local"` | `"local"` | Communication type. | +| `mode` | `"local"` \| `"remote"` | `"local"` | High-level comm mode. | +| `emulation` | `boolean` | `true` | When `true`, delegation uses in-process function calls (no HTTP). | + +**Example:** + +```yaml +transport: + type: local + emulation: true +``` + +--- + +### Framework + +_Used by:_ `spec.framework` + +Selects which framework surface adapter wraps the native machinery skeleton. The lab infers the runner from `default_adapter` unless overridden at execution time. + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `default_adapter` | `"native"` \| `"langgraph"` \| `"autogen"` \| `"crewai"` | `"native"` | Framework adapter id. `native` = direct OSS kernel. Other adapters delegate to registered `ctl` framework wrappers (future release). | + +--- + +### MemoryStores + +_Used by:_ `spec.memory_stores` + +Named paths to shared memory store artifacts. All fields are optional strings. + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `episodic_ref` | `string` | `""` | Path to the episodic memory store artifact. | +| `semantic_ref` | `string` | `""` | Path to the semantic memory store artifact. | +| `procedural_ref` | `string` | `""` | Path to the procedural memory store artifact. | + +--- + +### Telemetry + +_Used by:_ `spec.telemetry` + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `path` | `string` | `""` | Path to the event log file (JSONL), relative to `mas.yaml`. | + +**Example:** + +```yaml +telemetry: + path: ./traces/events.jsonl +``` + +--- + +## Topology, workflow, and routing + +Three related ideas — often confused: + +| Term | What it is | Where it lives | Example | +|------|------------|----------------|---------| +| **Topology** | Which agents exist and how they relate (team shape) | `spec.agency.agents`, overlay patches | design-space Exp 1.2 sweeps five overlays (`topo-linear-pipeline`, `topo-moderator-broker`, `topo-parallel`, `topo-supervised`, `topo-verifier`) | +| **Workflow** | Turn order and who runs when (session choreography) | `spec.workflow` | Linear: fixed chain; moderator: one specialist at a time; parallel: all specialists per fan-out | +| **Routing logic** | Per-message decisions inside a turn (which tool/delegate next) | LLM + delegation tools, agent prompts | Moderator reads the user message and chooses `schedule_agent` vs `itinerary_agent` | + +**Workflow vs routing in a single user turn** — think of a trip-planning MAS answering one message: + +- **Workflow** is the *stage play*: who is allowed on stage, and in what order. + - *Linear pipeline:* schedule agent always runs first, then itinerary, then concierge — every time, regardless of the question. + - *Moderator-broker:* the moderator runs first, then **one specialist at a time** in an order the moderator chooses across turns. + - *All-parallel:* the moderator still opens the scene, but **all three specialists run in the same act** (`dispatch: parallel`); the moderator aggregates their outputs. + +- **Routing logic** is what happens *inside* the moderator's turn when it decides the next move: "This is mostly a transport question → delegate to `schedule_agent`." Routing is **per message / per LLM step** (tool calls, delegation targets). Workflow is the **declared graph** ctl enforces (`entry`, `delegates_to`, `dispatch: parallel`, sequential edges). + +You can keep the same agents and topology but change workflow overlays to switch from sequential chain to parallel fan-out without editing agent code. + +**Topology in paper labs** — [`labs/design-space.lab/02-topologies/`](../../labs/design-space.lab/02-topologies/) varies topology only via scenario overlays. Example (`topo-moderator-broker`): + +```yaml +spec: + patch: + workflow: + entry: moderator + nodes: + - id: moderator + agent: moderator_agent + delegates_to: [schedule_agent, itinerary_agent, concierge_agent] ``` -See [workflow.md](workflow.md) for the workflow manifest. +**Workflow execution in OSS:** + +| Pattern | ctl behaviour | +|---------|---------------| +| Dynamic delegation | Default multi-agent: entry agent session; LLM uses delegation tools | +| Sequential graph | `mas-ctl run-mas` when `workflow.nodes` + `workflow.edges` are set | +| Single agent | `topo-single-agent` overlay — one generalist, no inter-agent workflow | + +There is no `WorkflowContract.register_impl()` in OSS. Topology + workflow are **declarative** in YAML; ctl composes and runs them. + +**Stateful governance** — separate from topology: governance plugins track session state across turns. [`lifecycle-control.lab`](../../labs/lifecycle-control.lab/) stacks budget caps, guardrails, and HITL. See [contracts reference](../references/contracts.md#governance) and `runtime/boundary/gov/budget.py`. --- -## Overlays +## Standalone workflow manifest (`kind: Workflow`) -Topology-switching overlays replace `spec.patch.workflow` or `spec.patch.agents` — see -Scenario overlays are declared in [experiment.md](experiment.md); patch files -are documented in [overlay.md](overlay.md). +Most apps embed workflow directly under `MAS.spec.workflow`. The standalone `kind: Workflow` +manifest (`apiVersion: workflow/v1`) is for cases where the workflow document lives separately +and is referenced by multiple MAS manifests, or needs explicit routing edges with conditions. + +### Top-level fields + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `apiVersion` | `string` | yes | Must be `workflow/v1`. | +| `kind` | `string` | yes | Must be `Workflow`. | +| `metadata.name` | `string` | no | Workflow identifier. | +| `metadata.description` | `string` | no | Human-readable description. | +| `spec` | object | yes | Workflow body. | + +### `spec` fields + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `entry` | `string` | `""` | ID of the entry agent — receives the initial user prompt. | +| `nodes` | `WorkflowNode[]` | `[]` | Agent nodes. Same shape as [`WorkflowNode`](#workflownode) but without `role`, `dispatch`, and `description`. | +| `edges` | `WorkflowEdge[]` | `[]` | Explicit routing edges — required for deterministic sequential flows. See [`WorkflowEdge`](#workflowedge). | +| `context_schema` | `object` | `{}` | Optional JSON Schema fragment describing shared context keys. | + +### WorkflowEdge + +_Used by:_ `spec.edges[]` + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `from` | `string` | **yes** | — | Source node ID. | +| `to` | `string` | **yes** | — | Target node ID. | +| `condition` | `string` \| null | no | `null` | Optional routing condition (Python-like expression evaluated at runtime). | +| `label` | `string` | no | `""` | Human-readable label describing when this edge fires. | + +**Example:** + +```yaml +apiVersion: workflow/v1 +kind: Workflow +metadata: + name: research-flow +spec: + entry: moderator + nodes: + - id: moderator + agent: moderator + delegates_to: [researcher] + - id: researcher + agent: researcher + edges: + - from: moderator + to: researcher +``` + +Schema source: `GET /api/schemas/workflow` --- ## Schema source -`GET /api/schemas/mas` · file `runtime/.../mas.schema.yaml` +```bash +# From installed package +python -c "from mas.lab.schemas.paths import runtime_schema_dir; print(runtime_schema_dir() / 'mas.schema.yaml')" +python -c "from mas.lab.schemas.paths import runtime_schema_dir; print(runtime_schema_dir() / 'workflow.schema.yaml')" + +# From Web UI / controller (default port 8090) +curl http://localhost:8090/api/schemas/mas +curl http://localhost:8090/api/schemas/workflow +``` --- @@ -65,5 +382,4 @@ are documented in [overlay.md](overlay.md). - [Agent manifest](agent.md) - [Tutorial: creating a MAS](../tutorials/02-creating-a-mas/README.md) -- [Topology, workflow, and routing](topology-and-workflow.md) -- [Workflow manifest](workflow.md) +- [Standalone workflow manifest](#standalone-workflow-manifest-kind-workflow) diff --git a/docs/manifests/runtime.md b/docs/manifests/runtime.md index 880fddd1..bc148d87 100644 --- a/docs/manifests/runtime.md +++ b/docs/manifests/runtime.md @@ -19,7 +19,7 @@ Validated by `mas-ctl validate` (agents, MAS, overlays) and `mas-lab validate` | Agent | `agent.schema.yaml` | [agent.md](agent.md) | | MAS | `mas.schema.yaml` | [mas.md](mas.md) | | Overlay | `overlay.schema.yaml` | [overlay.md](overlay.md) | -| Workflow topology | `workflow.schema.yaml` | [workflow.md](workflow.md) | +| Workflow topology | `workflow.schema.yaml` | [mas.md — Standalone workflow manifest](mas.md#standalone-workflow-manifest-kind-workflow) | | Flavour | `flavour.schema.yaml` | [flavour.md](flavour.md) | | Infrastructure | Python models (`infra_manifest.py`) | [infra.md](infra.md) | | Tool | `tool.schema.yaml` | below | @@ -70,7 +70,7 @@ implemented in `mas-runtime`. In manifests, trajectory-shaping logic is declared - `MAS.spec.workflow` — topology (`entry`, `delegates_to`, `type`) and ctl workflow driver (dynamic ReAct vs `SequentialWorkflow`) `MAS.spec.workflow.plugin` (custom `WorkflowContract` registration) is a **design target** — not -resolved in OSS; see [topology-and-workflow.md](topology-and-workflow.md). +resolved in OSS; see [Topology, workflow, and routing](mas.md#topology-workflow-and-routing). Authoring detail: [agent.md](agent.md#delegation) · [mas.md](mas.md). diff --git a/docs/manifests/topology-and-workflow.md b/docs/manifests/topology-and-workflow.md deleted file mode 100644 index 2733cac6..00000000 --- a/docs/manifests/topology-and-workflow.md +++ /dev/null @@ -1,75 +0,0 @@ - -# Topology, workflow, and routing - -Three related ideas in MAS manifests — often confused: - -| Term | What it is | Where it lives | Example | -| --- | --- | --- | --- | -| **Topology** | Which agents exist and how they relate (team shape) | `MAS.spec.agency.agents`, overlay patches | design-space **Exp 1.2** sweeps five overlays (`topo-linear-pipeline`, `topo-moderator-broker`, `topo-parallel`, `topo-supervised`, `topo-verifier`) | -| **Workflow** | Turn order and who runs when (session choreography) | `MAS.spec.workflow` | Linear: fixed chain; moderator: one specialist at a time; parallel: all specialists per fan-out | -| **Routing logic** | Per-message decisions inside a turn (which tool/delegate next) | LLM + delegation tools, agent prompts | Moderator reads the user message and chooses `schedule_agent` vs `itinerary_agent` | - -## In chat — workflow vs routing - -Think of a **trip-planning MAS** answering one user message. - -**Workflow** is the *stage play*: who is allowed on stage, and in what order. - -- **Linear pipeline workflow:** schedule agent always runs first, then itinerary, then concierge — every time, regardless of the question. -- **Moderator-broker workflow:** the moderator runs first, then **one specialist at a time** in an order the moderator chooses across turns. -- **All-parallel workflow:** the moderator still opens the scene, but **all three specialists run in the same act** (`dispatch: parallel`); the moderator aggregates their outputs. - -**Routing logic** is what happens *inside* the moderator’s turn when it decides the next move: - -- “This is mostly a transport question → delegate to `schedule_agent`.” -- “User asked for hotels and trains → call itinerary, then concierge.” -- “Fan out to everyone because the prompt spans all domains.” - -Routing is **per message / per LLM step** (tool calls, delegation targets). Workflow is the **declared graph** ctl enforces (entry node, `delegates_to`, `dispatch: parallel`, sequential edges). You can keep the same agents and topology but change workflow overlays to switch from sequential chain to parallel fan-out without editing agent code. - -## Topology in paper labs - -[`labs/design-space.lab/02-topologies/`](../../labs/design-space.lab/02-topologies/) varies **topology only** via scenario overlays — no agent code changes. - -Example (`topo-moderator-broker`): - -```yaml -spec: - patch: - workflow: - entry: moderator - nodes: - - id: moderator - agent: moderator_agent - delegates_to: [schedule_agent, itinerary_agent, concierge_agent] -``` - -Compare with `topo-parallel` (fan-out to all specialists at once), `topo-linear-pipeline` (fixed sequence), `topo-supervised`, or `topo-verifier`. Each overlay is one column in the experiment matrix. - -## Workflow execution in OSS - -| Pattern | ctl behavior | -| --- | --- | -| **Dynamic delegation** | Default multi-agent: entry agent session; LLM uses delegation tools | -| **Sequential graph** | `mas-ctl run-mas` when `workflow.nodes` + `workflow.edges` are set | -| **Single agent** | `topo-single-agent` overlay — one generalist, no inter-agent workflow | - -There is no `WorkflowContract.register_impl()` in OSS. Topology + workflow are **declarative** in YAML; ctl composes and runs them. - -## Stateful governance (budget) - -Separate from topology: **governance plugins** track session state across turns. - -[`lifecycle-control.lab`](../../labs/lifecycle-control.lab/) stacks budget caps, guardrails, and HITL. Budget enforcement uses `BudgetTracker` and overlay plugins such as `budget-cap` on `budget_threshold` — an example of **stateful governance** required for paper Exp 2.1. - -See [contracts reference](../references/contracts.md#governance) and runtime `boundary/gov/budget.py`. - -## See also - -- [MAS manifest](mas.md) -- [Workflow manifest](workflow.md) (`workflow/v1` graph form) -- [Scenario overlays](overlay.md) -- [Tutorial: creating a MAS](../tutorials/02-creating-a-mas/README.md) diff --git a/docs/manifests/workflow.md b/docs/manifests/workflow.md deleted file mode 100644 index 7724efd9..00000000 --- a/docs/manifests/workflow.md +++ /dev/null @@ -1,48 +0,0 @@ - -# Workflow manifest (`kind: Workflow`, `workflow/v1`) - -**Package:** `mas-runtime` · **Schema:** `workflow.schema.yaml` - -Graph-form workflow document (`nodes` + `edges`). Most apps embed workflow under -`MAS.spec.workflow` instead. - -See **[Topology, workflow, and routing](topology-and-workflow.md)** for how this -relates to team **topology** (design-space overlays) and **routing** policy. - ---- - -## OSS execution paths - -| Pattern | How it runs | -| --- | --- | -| Single entry agent | `mas-ctl chat` / `mas-ctl run-mas` | -| Sequential graph | `mas-ctl run-mas` with `nodes` + `edges` | -| Dynamic delegation | Default multi-agent — entry agent drives delegation tools | -| Moderator-broker topology | `workflow.entry: moderator` + `delegates_to` (design-space Exp 1.2) | - -```yaml -spec: - workflow: - entry: moderator - nodes: - - {id: moderator, agent: moderator} - - {id: researcher, agent: researcher} - edges: - - {from: moderator, to: researcher} -``` - ---- - -## API - -`GET /api/schemas/workflow` - ---- - -## See also - -- [MAS manifest](mas.md) -- [Topology, workflow, and routing](topology-and-workflow.md) diff --git a/docs/references/index.md b/docs/references/index.md index fc66a8e8..0e4c0573 100644 --- a/docs/references/index.md +++ b/docs/references/index.md @@ -18,7 +18,7 @@ Declarative YAML kinds and how they compose. |-------|-----------| | Overview & composition | [Manifest overview](../manifests/README.md) | | Agent | [agent.md](../manifests/agent.md) | -| MAS & workflow | [mas.md](../manifests/mas.md), [workflow.md](../manifests/workflow.md) | +| MAS & workflow | [mas.md](../manifests/mas.md) | | Overlay | [overlay.md](../manifests/overlay.md) | | Flavour & environment | [flavour.md](../manifests/flavour.md), [infra.md](../manifests/infra.md) | | Workspace file | [user-config.md](../user-config.md), [config.schema.yaml](../schemas/config.schema.yaml) |