Harness spec 3.4.0: progress phases, and subagents v2 — the main agent and its tree
ci / check (push) Waiting to run
ci / check (push) Waiting to run
progress.md: thirteen fixed phases (queued … failed), each { phase, since, data },
their texts as shared i18n keys (loop.json progress), one line every client draws,
sent beside the old status text in /api/v2 and over the link (capability progress).
subagents.md §5–§13 (supersedes team.md where they differ): only the main agent
adds, assigns, replaces, stops and decides; sub-managers direct those placed under
them; ids, positions, parents; Min above 1 opens slots; permissions inherited and
never widened, request options decided by the main agent, what nobody in the tree
can allow goes to the person; team_finish, findings, running out of context;
transcripts read-only; the tree over the link (capability tree). New tools
team_whoami, team_finish, team_findings, team_request, team_decide, team_assign,
team_replace. Conformance: progress, delegation; team updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
26 files changed
+1844
-97
No files matched your search
+35
-3
@@ -15,18 +15,19 @@ page *Harness-parity* in LLeMbas CLI's wiki.
|
||||
|---|---|
|
||||
| `VERSION` | The spec's own version, apart from LLeMbas CLI's |
|
||||
| `purpose.json` | The `purpose` argument added to a tool whose calls say what they are for |
|
||||
| `tools/<name>.json` | One tool each: name, `scope`, `sessions`, `risk`, `exclusive`, `block` (how a call is shown: `shell`, `edit`, `read`, `search`, `web`, `task`, `plan` — not drawn, the plan card refreshes — `hidden`, `tool`), `purpose`, former names (`aliases`, per project), renamed arguments, `variables`, what a project offers of the parameters (`narrow`, per project), `offered` (`subagent`: given to subagents only, never to the main agent — `report`), `requires` and `unavailable` (when it can be offered, and what a call answers when that has gone), `confirm` (`always`: the person is asked in every mode), the description and the JSON Schema of its parameters — exactly what a model is sent |
|
||||
| `tools/<name>.json` | One tool each: name, `scope`, `sessions`, `risk`, `exclusive`, `block` (how a call is shown: `shell`, `edit`, `read`, `search`, `web`, `task`, `plan` — not drawn, the plan card refreshes — `hidden`, `tool`), `purpose`, former names (`aliases`, per project), renamed arguments, `variables`, what a project offers of the parameters (`narrow`, per project), `offered` (`subagent`: given to subagents only, never to the main agent — `report`, `team_finish`, `team_request`; `main`, spec 3.4.0: given to the main agent only, never to a subagent — `team_add`, `team_assign`, `team_replace`, `team_stop`, `team_decide`), `requires` and `unavailable` (when it can be offered, and what a call answers when that has gone), `confirm` (`always`: the person is asked in every mode), the description and the JSON Schema of its parameters — exactly what a model is sent |
|
||||
| `prompts/` | The prompt texts; `prompts/index.json` says which are shared, which LLeMbas fragment each one is, and what each `{{variable}}` in a text means. `prompts/personality/` holds the personality presets both offer |
|
||||
| `permission/hardline.json` | The floor: commands refused in every mode, protected paths, and how a command is spelled plainly before it is checked again |
|
||||
| `permission/arity.json` | How much of a command an "always allow" covers |
|
||||
| `permission/defaults.json` | The rules every session starts from |
|
||||
| `permission/modes.json` | The four modes — manual, edit, auto, plan — as what each does with each risk class |
|
||||
| `models/schema.json` | Model metadata: context, output limit, efforts and the thinking switch, vision, tools, notes, capacity (`parallel`); `levels` — the effort levels a chat offers and what each sends |
|
||||
| `loop.json` | How one prompt runs: the step backstop, budgets, wrap-up, nudges, parallel calls, capacity; `jobs` — background work, its marks and limits; `subagents` — the model refusals, what names a model, the setting's label; `team` — a team's size, names, marks, refusals and texts; `context` — result ids, stubs, the output cap, the compaction table, the environment lines, the session notes |
|
||||
| `loop.json` | How one prompt runs: the step backstop, budgets, wrap-up, nudges, parallel calls, capacity; `jobs` — background work, its marks and limits; `subagents` — the model refusals, what names a model, the setting's label; `team` — a team's size, names, marks, refusals and texts; `progress` — the phases' texts; `context` — result ids, stubs, the output cap, the compaction table, the environment lines, the session notes |
|
||||
| `filesystem.md` | The file system a session works in: paths, node kinds, the four access levels, errors, listings, search and indexing by tokens, stacked instruction files, skills, memory |
|
||||
| `context.md` | Context hygiene: what happens to a tool result when it is inserted, and never afterwards; the prefix that stays still; reasoning sent back during its turn; no absolute paths in the prompt |
|
||||
| `team.md` | Teams: a lead and the members it adds, the size setting, the room, who receives what, reports, a manager's refusals, capacity, stopping |
|
||||
| `subagents.md` | Subagents: the word, which model one runs on (the session's, or one the person named), the capacity refusals, and when the Subagents setting is offered |
|
||||
| `subagents.md` | Subagents: the word, which model one runs on (the session's, or one the person named), the capacity refusals, and when the Subagents setting is offered; from 3.4.0 (§5–§13) the main agent and its tree — only it adds, permissions inherited and never widened, request options, a subagent's life and its findings, what clients show |
|
||||
| `progress.md` | Progress (3.4.0): the thirteen phases every client shows the same way, the data each carries, their texts, and where they are sent |
|
||||
| `quirks.json` | What real servers do, and how both harnesses cope |
|
||||
| `conformance/<area>.json` | Cases with their expected results, run by both test suites |
|
||||
| `acp.md` | The link between them: ACP plus every `_lembas/*` method, field and capability |
|
||||
@@ -70,6 +71,37 @@ page *Harness-parity* in LLeMbas CLI's wiki.
|
||||
approval in plan mode and answers its `unavailable` text outside it. Their permission key is
|
||||
`plan` (`permission/defaults.json`), which a rule written for the former `todo` key still reaches.
|
||||
|
||||
## 3.4.0
|
||||
|
||||
Written ahead of both implementations; the server vendors it as written, both carry it in the same
|
||||
round (`progress.md`, `subagents.md` §5–§13).
|
||||
|
||||
- **Progress** (`progress.md`, `loop.json` `progress`): one fixed set of phases — `queued`,
|
||||
`waiting_for_model`, `loading_model`, `reading_prompt`, `thinking`, `writing`, `running_tool`,
|
||||
`waiting_for_person`, `waiting_for_subagents`, `compacting`, `retrying`, `stopped`, `failed` —
|
||||
each a structured object `{ phase, since, …data }` with fixed fields, an English text that is
|
||||
the shared i18n key, and one line every client draws: `text · elapsed`. Sent beside the old
|
||||
`status` text in `/api/v2` and over the link (`acp.md` capability `progress`: the `phase` event,
|
||||
`progress` in `status`); `status` stays. Area `progress`.
|
||||
- **Subagents v2** (`subagents.md` §5–§13; supersedes `team.md` where they differ, which says so):
|
||||
the **main agent** is the session's, permanent, and **alone adds, assigns, replaces, stops and
|
||||
decides** (`offered: main`); a member with `lead: true` is a **sub-manager** that directs those
|
||||
placed under it (`team_add`'s `parent`). Every subagent has an id (`s1`…), a name, a position, a
|
||||
parent, a task, a mode and a model. Min above 1 opens `min − 1` **slots** from the start of the
|
||||
reply. **Permissions are inherited and never widened**: a subagent's mode is its parent's or
|
||||
stricter; a narrowed one may get **request options** (`read`, `write`, `execute`) and ask the
|
||||
main agent (`team_request` → `team_decide`, a grant that never reaches past the main agent's own
|
||||
mode); a call nobody in the tree can allow goes **to the person**. A subagent ends with
|
||||
`team_finish`, is stopped, or **runs out of context**: paused, one final turn to save its
|
||||
findings and tell its parent, then `out_of_context` and a report; findings and transcripts are
|
||||
kept, readable by the parent, the main agent and the person. New tools `team_whoami`,
|
||||
`team_finish`, `team_findings`, `team_request`, `team_decide`, `team_assign`, `team_replace`;
|
||||
`team_add` gains `parent`, `mode`, `request`; `team_send` takes `parent`; `team_stop` is the main
|
||||
agent's. `blocks/team_submanager.md`; `team_lead.md` and `team_member.md` reworded. Over the link,
|
||||
capability `tree`: the `team` event, `_lembas/team`, `/transcript` (read-only), `/findings`,
|
||||
`/stop`, `subagent` on an approval. Areas `team` (cases changed where a member used to add or
|
||||
stop, and new ones) and `delegation`.
|
||||
|
||||
## 3.3.0
|
||||
|
||||
Written ahead of both implementations as LLeMbas CLI 02c7282; both carry it in the same round (`subagents.md`).
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3.3.0
|
||||
3.4.0
|
||||
+34
-4
@@ -65,6 +65,8 @@ change to the protocol is a change here first, then in both projects.
|
||||
| `rewind` | `_lembas/session/rewind` |
|
||||
| `show` | spec 3.0.0: `_lembas/show`; the `show` tool is offered in a session the client opened when the client said `show: true` in `clientCapabilities._meta.lembas` |
|
||||
| `jobs` | background work (spec 2.0.0): the `job` and `job_note` events; `_lembas/jobs`, `_lembas/job/output`, `_lembas/job/stop`, `_lembas/job/send`, `_lembas/job/transcript`; `jobs` in `_lembas/session/status`; `job` on `session/request_permission`; `machine` on a `prompt` event |
|
||||
| `progress` | spec 3.4.0 (`progress.md`): the `phase` event; `progress` in `_lembas/session/status` |
|
||||
| `tree` | spec 3.4.0 (`subagents.md` §5–§13): the `team` event; `_lembas/team`, `_lembas/team/transcript`, `_lembas/team/findings`, `_lembas/team/stop`; `subagent` on `session/request_permission` |
|
||||
|
||||
## Standard ACP, as used here
|
||||
|
||||
@@ -245,7 +247,9 @@ with options `once` (allow_once), `session` (allow_always, absent where "always"
|
||||
and `deny` (reject_once), and `_meta.lembas: { reason, purpose?, always?, patient?, job? }`. `patient`: a
|
||||
person may also answer at the terminal (a shared session), so the client does not time it out.
|
||||
`job` (capability `jobs`): `{ id, agent, description }` when a subagent running as a background job asks, so the card
|
||||
can say which — a background subagent may ask while the session itself is idle.
|
||||
can say which — a background subagent may ask while the session itself is idle. `subagent` (capability `tree`, spec 3.4.0):
|
||||
`{ id, name, position }` when the call is a tree subagent's that nobody in the tree could allow (`subagents.md` §7) —
|
||||
the card names it; the answers are the same as for the main agent's own call.
|
||||
Answer: ACP's `{ outcome: { outcome: "selected", optionId } | { outcome: "cancelled" } }`, with
|
||||
optional `_meta.lembas.command` (the corrected command line, `once` only) or
|
||||
`_meta.lembas.feedback` (why it was denied). No answer within `remote.approval_timeout` is a denial.
|
||||
@@ -275,7 +279,7 @@ client hears the new limits.
|
||||
`{ sessionId, event }`: every engine event of the session, to a client that said `_meta.lembas`.
|
||||
`event.type` is one of `session`, `prompt`, `step`, `title`, `text`, `reasoning`,
|
||||
`tool_call_delta`, `progress`, `tool_start`, `tool_end`, `tool_denied`, `usage`, `inbox`,
|
||||
`steered`, `task`, `notice`, `retract`, `plan`, `compacted`, `sub_tool`, `job`, `job_note`, `mode`, `model`, `flash`,
|
||||
`steered`, `task`, `notice`, `retract`, `plan`, `compacted`, `sub_tool`, `job`, `job_note`, `phase`, `team`, `mode`, `model`, `flash`,
|
||||
`setting`, `error`, `done` (`src/bus/index.ts`). Those this protocol relies on:
|
||||
|
||||
| Event | Fields |
|
||||
@@ -291,6 +295,8 @@ client hears the new limits.
|
||||
| `job` | `state: "start" \| "update" \| "end"`, `job: JobInfo` (capability `jobs`) — a background job of the session began, has news (new output, a subagent's step; at most four a second per job), or ended. `JobInfo = { id, kind: "command" \| "subagent", state: "running" \| "done" \| "stopped" \| "error" \| "lost", description, command?, agent?, model?, started, ended?, exit?, unread, steps?, tools?, ownerJobId? }` — `description` what is shown for it (a command's `description` or its first line; a subagent's description), `unread` characters of output the model has not read, `exit` a command's exit code (null: a signal), `ownerJobId` set on a job a subagent started, `lost` a job that was running when the device's process ended |
|
||||
| `job_note` | `jobId`, `text` (capability `jobs`) — the note about that job was given to the model: inside a turn at the next step, or as the `machine` turn whose `prompt` follows |
|
||||
| `sub_tool` | `callId` (the `task` call the subagent belongs to), `jobId?` (its job, when it runs as one), `name`, `title`, `isError?` — a tool call of a subagent finished; a client draws it under the task line, or in the job's panel |
|
||||
| `phase` | `progress` — the progress object (`progress.md` §1), or `null` when nothing runs; `agent?` — the subagent's id when it is a subagent's, absent for the main agent's (capability `progress`). Sent when the phase changes, and for a change of its data at most four times a second. The existing `progress` event (the prompt's tokens read) is unchanged |
|
||||
| `team` | `tree` — the session's subagent tree (`subagents.md` §12, the data) — whenever it changes, at most four times a second (capability `tree`). A client draws it and fetches nothing else to do so |
|
||||
|
||||
### `_lembas/directories` — client → agent → result
|
||||
|
||||
@@ -319,9 +325,9 @@ with the message in the store; `attachments`, and the text without them) or `{ r
|
||||
### `_lembas/session/status` — client → agent → result
|
||||
|
||||
Params `{ sessionId }`. Result
|
||||
`{ sessionId, exists, held: "here" | "terminal" | "none", busy, title, turnId?, queued: string[], lastTurnId?, plan?, jobs? }`
|
||||
`{ sessionId, exists, held: "here" | "terminal" | "none", busy, title, turnId?, queued: string[], lastTurnId?, plan?, jobs?, progress?, tree? }`
|
||||
— `plan` the session's plan or `null` (capability `plan_state`), so a client reattaching draws it
|
||||
without waiting for the next change; `jobs` the session's background jobs, `JobInfo[]` running first (capability `jobs`), for the same reason; the turn fields with capability `turns`: the turn running now, the ones waiting, the last
|
||||
without waiting for the next change; `progress` the main agent's progress object or `null` (capability `progress`), and `tree` the subagent tree or `null` when the session has none (capability `tree`), for the same reason; `jobs` the session's background jobs, `JobInfo[]` running first (capability `jobs`), for the same reason; the turn fields with capability `turns`: the turn running now, the ones waiting, the last
|
||||
one finished (for a session not open, `held: "none"`, the last one it finished before). **Reattaching** after a restart or a dropped link, for an incomplete row with turn T:
|
||||
T running → follow it; T queued → wait, and follow it when it starts; T done → import it from
|
||||
`history`; T unknown → send the prompt again (safe: the device deduplicates).
|
||||
@@ -362,6 +368,30 @@ with its output — so a client can show the subagent as a panel and follow it w
|
||||
`job` events that come after. `-32602` for a command job. A subagent's transcript lasts as long as
|
||||
its session row on the device: it is kept with the parent session and deleted with it.
|
||||
|
||||
### `_lembas/team` — client → agent → result (capability `tree`)
|
||||
|
||||
Params `{ sessionId, since?: number }`. Result `{ tree, room }`: the subagent tree (`subagents.md`
|
||||
§12) and the room's messages numbered above `since` (default 0), every one — the person sees the
|
||||
whole room — each `{ n, from, to, recipients, text, time, report, kind }` with `kind` one of
|
||||
`message`, `report`, `assignment`, `request`, `decision`. `tree` is `null` for a session with no
|
||||
subagents. For a session held by a terminal, answered through the hub, as `status` is.
|
||||
|
||||
### `_lembas/team/transcript` — client → agent → result (capability `tree`)
|
||||
|
||||
Params `{ sessionId, id }` — a subagent's id (`s1`), live or ended. Result `{ id, state, turns }` in
|
||||
the shape of `_lembas/session/history`'s `turns`: its conversation so far, **read-only** — the link
|
||||
has no method to write into it. A client following it live refetches on the `team` event and draws
|
||||
the `sub_tool` events meanwhile. `-32602` for an id the session never had.
|
||||
|
||||
### `_lembas/team/findings` — client → agent → result (capability `tree`)
|
||||
|
||||
Params `{ sessionId, id }`. Result `{ id, findings: [{ n, text, time }] }`, ended subagents' too.
|
||||
|
||||
### `_lembas/team/stop` — client → agent → result (capability `tree`)
|
||||
|
||||
Params `{ sessionId, id }`: the person stops a subagent and its subtree (`subagents.md` §10), said to
|
||||
the main agent as a note. Result `{ stopped: [id, …] }`; `-32602` for an id that is not live.
|
||||
|
||||
### `_lembas/session/delete` — client → agent → result
|
||||
|
||||
Params `{ sessionId }`: the chat was deleted. The session stops if it works, leaves the store (its
|
||||
|
||||
@@ -0,0 +1,431 @@
|
||||
{
|
||||
"about": "Delegation (subagents.md §7, spec 3.4.0): a subagent's mode and request options, and who decides its calls. The project root is /project, nothing named exists on disk, and only the default rules apply (permission/defaults.json). `add` — team_add's mode check for a parent in `parent_mode` with `mode` and `request` as given → `{result, mode}`: the refusal word for word, or null and the mode the subagent gets. `call` — a subagent in `mode` with `request` options and `grants` (rules {tool, pattern} the main agent allowed) under a main agent in `main_mode`, calling `call` (`bash` with a `line`, or a file tool with a `path` relative to the root) → `{answer, text?}`: `run`, `person` (an approval card to the person), or `refused` with its text where the case gives one (a hardline's reason is each project's). `unattended`: nobody can answer. `request` — team_request for `tool` by a subagent with `request` options, its first → `{result}`. `switch` — the main agent's mode changes from `main_from` to `main_to` with these subagents (each with its parent and mode) → each one's mode after. LLeMbas: services/team.py; CLI: team/delegation.ts.",
|
||||
"cases": [
|
||||
{
|
||||
"about": "No mode given: the parent's.",
|
||||
"op": "add",
|
||||
"parent_mode": "edit",
|
||||
"expect": {
|
||||
"result": null,
|
||||
"mode": "edit"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Stricter is allowed.",
|
||||
"op": "add",
|
||||
"parent_mode": "edit",
|
||||
"mode": "manual",
|
||||
"expect": {
|
||||
"result": null,
|
||||
"mode": "manual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Looser is refused, naming the parent's mode.",
|
||||
"op": "add",
|
||||
"parent_mode": "manual",
|
||||
"mode": "edit",
|
||||
"expect": {
|
||||
"result": "A subagent's mode cannot be looser than its parent's (manual).",
|
||||
"mode": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Plan is the strictest: anything else under it is looser.",
|
||||
"op": "add",
|
||||
"parent_mode": "plan",
|
||||
"mode": "auto",
|
||||
"expect": {
|
||||
"result": "A subagent's mode cannot be looser than its parent's (plan).",
|
||||
"mode": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Request options with the parent's own mode: nothing to ask for.",
|
||||
"op": "add",
|
||||
"parent_mode": "auto",
|
||||
"mode": "auto",
|
||||
"request": [
|
||||
"write"
|
||||
],
|
||||
"expect": {
|
||||
"result": "Request options go with a mode stricter than the parent's: without one there is nothing to ask for.",
|
||||
"mode": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Request options with no mode given (the parent's): refused the same way.",
|
||||
"op": "add",
|
||||
"parent_mode": "edit",
|
||||
"request": [
|
||||
"execute"
|
||||
],
|
||||
"expect": {
|
||||
"result": "Request options go with a mode stricter than the parent's: without one there is nothing to ask for.",
|
||||
"mode": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Request options with a stricter mode.",
|
||||
"op": "add",
|
||||
"parent_mode": "edit",
|
||||
"mode": "manual",
|
||||
"request": [
|
||||
"write",
|
||||
"execute"
|
||||
],
|
||||
"expect": {
|
||||
"result": null,
|
||||
"mode": "manual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "An unknown kind is refused, naming it.",
|
||||
"op": "add",
|
||||
"parent_mode": "edit",
|
||||
"mode": "manual",
|
||||
"request": [
|
||||
"delete"
|
||||
],
|
||||
"expect": {
|
||||
"result": "delete is not a request option: use read, write or execute.",
|
||||
"mode": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "An empty list of request options is no options, and needs nothing.",
|
||||
"op": "add",
|
||||
"parent_mode": "edit",
|
||||
"request": [],
|
||||
"expect": {
|
||||
"result": null,
|
||||
"mode": "edit"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "All in edit: an edit inside the project runs.",
|
||||
"op": "call",
|
||||
"main_mode": "edit",
|
||||
"mode": "edit",
|
||||
"call": {
|
||||
"tool": "edit",
|
||||
"path": "src/a.ts"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "run"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "All in edit: bash that edit mode asks goes to the person — the main agent could not allow it either.",
|
||||
"op": "call",
|
||||
"main_mode": "edit",
|
||||
"mode": "edit",
|
||||
"call": {
|
||||
"tool": "bash",
|
||||
"line": "git push origin main"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "person"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "All in manual: an edit goes to the person.",
|
||||
"op": "call",
|
||||
"main_mode": "manual",
|
||||
"mode": "manual",
|
||||
"call": {
|
||||
"tool": "edit",
|
||||
"path": "src/a.ts"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "person"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Narrowed with no request options: what the main agent could allow is refused.",
|
||||
"op": "call",
|
||||
"main_mode": "edit",
|
||||
"mode": "manual",
|
||||
"call": {
|
||||
"tool": "edit",
|
||||
"path": "src/a.ts"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "refused",
|
||||
"text": "Your mode does not allow this, and you may not ask for it: tell your parent what you need."
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Narrowed with the kind in its options: it asks the main agent.",
|
||||
"op": "call",
|
||||
"main_mode": "edit",
|
||||
"mode": "manual",
|
||||
"request": [
|
||||
"write"
|
||||
],
|
||||
"call": {
|
||||
"tool": "edit",
|
||||
"path": "src/a.ts"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "refused",
|
||||
"text": "Your mode does not allow this, but the main agent may: ask for it with team_request (the tool, the pattern, why), then try again once it allows."
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Narrowed, the kind not in its options.",
|
||||
"op": "call",
|
||||
"main_mode": "auto",
|
||||
"mode": "edit",
|
||||
"request": [
|
||||
"write"
|
||||
],
|
||||
"call": {
|
||||
"tool": "bash",
|
||||
"line": "git push origin main"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "refused",
|
||||
"text": "Your mode does not allow this, and you may not ask for it: tell your parent what you need."
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Narrowed, execute in its options: asks the main agent.",
|
||||
"op": "call",
|
||||
"main_mode": "auto",
|
||||
"mode": "edit",
|
||||
"request": [
|
||||
"execute"
|
||||
],
|
||||
"call": {
|
||||
"tool": "bash",
|
||||
"line": "git push origin main"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "refused",
|
||||
"text": "Your mode does not allow this, but the main agent may: ask for it with team_request (the tool, the pattern, why), then try again once it allows."
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "A grant from the main agent lets the call run.",
|
||||
"op": "call",
|
||||
"main_mode": "auto",
|
||||
"mode": "edit",
|
||||
"request": [
|
||||
"execute"
|
||||
],
|
||||
"grants": [
|
||||
{
|
||||
"tool": "bash",
|
||||
"pattern": "git push *"
|
||||
}
|
||||
],
|
||||
"call": {
|
||||
"tool": "bash",
|
||||
"line": "git push origin main"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "run"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "A grant for another pattern does not.",
|
||||
"op": "call",
|
||||
"main_mode": "auto",
|
||||
"mode": "edit",
|
||||
"request": [
|
||||
"execute"
|
||||
],
|
||||
"grants": [
|
||||
{
|
||||
"tool": "bash",
|
||||
"pattern": "git push *"
|
||||
}
|
||||
],
|
||||
"call": {
|
||||
"tool": "bash",
|
||||
"line": "git commit -m x"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "refused",
|
||||
"text": "Your mode does not allow this, but the main agent may: ask for it with team_request (the tool, the pattern, why), then try again once it allows."
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "A grant never reaches past the main agent's own mode: what it would have to ask goes to the person.",
|
||||
"op": "call",
|
||||
"main_mode": "edit",
|
||||
"mode": "manual",
|
||||
"request": [
|
||||
"execute"
|
||||
],
|
||||
"grants": [
|
||||
{
|
||||
"tool": "bash",
|
||||
"pattern": "git push *"
|
||||
}
|
||||
],
|
||||
"call": {
|
||||
"tool": "bash",
|
||||
"line": "git push origin main"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "person"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Reading .env asks in every mode: it goes to the person.",
|
||||
"op": "call",
|
||||
"main_mode": "edit",
|
||||
"mode": "edit",
|
||||
"call": {
|
||||
"tool": "read",
|
||||
"path": ".env"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "person"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Reading .env under an auto main agent: a narrowed subagent with read in its options asks it.",
|
||||
"op": "call",
|
||||
"main_mode": "auto",
|
||||
"mode": "manual",
|
||||
"request": [
|
||||
"read"
|
||||
],
|
||||
"call": {
|
||||
"tool": "read",
|
||||
"path": ".env"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "refused",
|
||||
"text": "Your mode does not allow this, but the main agent may: ask for it with team_request (the tool, the pattern, why), then try again once it allows."
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Plan mode's refusal is final: request options do not reach past it.",
|
||||
"op": "call",
|
||||
"main_mode": "auto",
|
||||
"mode": "plan",
|
||||
"request": [
|
||||
"execute"
|
||||
],
|
||||
"call": {
|
||||
"tool": "bash",
|
||||
"line": "rm -rf build"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "refused",
|
||||
"text": "Plan mode: nothing changes but the plan. Put what this would do into the plan with plan_write or plan_update; it can be done once the person approves the plan."
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "What the rules allow runs in every mode.",
|
||||
"op": "call",
|
||||
"main_mode": "edit",
|
||||
"mode": "plan",
|
||||
"call": {
|
||||
"tool": "bash",
|
||||
"line": "git status"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "run"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "The hardline refuses in every mode, auto included.",
|
||||
"op": "call",
|
||||
"main_mode": "auto",
|
||||
"mode": "auto",
|
||||
"call": {
|
||||
"tool": "bash",
|
||||
"line": "rm -rf /"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "refused"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Unattended: what would go to the person is refused.",
|
||||
"op": "call",
|
||||
"main_mode": "edit",
|
||||
"mode": "edit",
|
||||
"unattended": true,
|
||||
"call": {
|
||||
"tool": "bash",
|
||||
"line": "git push origin main"
|
||||
},
|
||||
"expect": {
|
||||
"answer": "refused"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "team_request: a tool whose risk class is not in the options is refused, naming them.",
|
||||
"op": "request",
|
||||
"request": [
|
||||
"write"
|
||||
],
|
||||
"tool": "bash",
|
||||
"expect": {
|
||||
"result": "You may not ask for bash: your request options are write."
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "team_request: a kind in the options is asked, with the request's id.",
|
||||
"op": "request",
|
||||
"request": [
|
||||
"write",
|
||||
"execute"
|
||||
],
|
||||
"tool": "bash",
|
||||
"expect": {
|
||||
"result": "Asked the main agent (r1): you are told its decision. Carry on with what you can meanwhile."
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "The main agent made stricter: every subagent looser than its parent is made as strict as it, down the tree; a stricter one keeps its own.",
|
||||
"op": "switch",
|
||||
"agents": [
|
||||
{
|
||||
"name": "api",
|
||||
"parent": "lead",
|
||||
"mode": "auto"
|
||||
},
|
||||
{
|
||||
"name": "tests",
|
||||
"parent": "api",
|
||||
"mode": "edit"
|
||||
},
|
||||
{
|
||||
"name": "docs",
|
||||
"parent": "lead",
|
||||
"mode": "plan"
|
||||
}
|
||||
],
|
||||
"main_from": "auto",
|
||||
"main_to": "manual",
|
||||
"expect": {
|
||||
"api": "manual",
|
||||
"tests": "manual",
|
||||
"docs": "plan"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "The main agent made looser: no subagent changes.",
|
||||
"op": "switch",
|
||||
"agents": [
|
||||
{
|
||||
"name": "api",
|
||||
"parent": "lead",
|
||||
"mode": "edit"
|
||||
}
|
||||
],
|
||||
"main_from": "edit",
|
||||
"main_to": "auto",
|
||||
"expect": {
|
||||
"api": "edit"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
{
|
||||
"about": "Progress (progress.md, spec 3.4.0): the text and the line every client draws for a progress object. `progress`: the object; `now`: the client's clock (Unix ms). Expect `text` — the phase's text from loop.json progress.texts, its fields filled (numbers written plainly: integers as they are, a rate with one decimal) — and `line` — `{{text}} · {{elapsed}}` with elapsed = now − since in whole seconds (5s, 1m 05s, 1h 02m), or the text alone for stopped and failed. retrying's `in` is counted down: in − floor((now − since) / 1000), never below 0. LLeMbas: services/progress.py; CLI: session/progress.ts.",
|
||||
"cases": [
|
||||
{
|
||||
"about": "Queued, nothing more known.",
|
||||
"progress": {
|
||||
"phase": "queued",
|
||||
"since": 1762790400000
|
||||
},
|
||||
"now": 1762790405000,
|
||||
"expect": {
|
||||
"text": "Queued",
|
||||
"line": "Queued · 5s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Queued behind two turns.",
|
||||
"progress": {
|
||||
"phase": "queued",
|
||||
"since": 1762790400000,
|
||||
"ahead": 2
|
||||
},
|
||||
"now": 1762790465000,
|
||||
"expect": {
|
||||
"text": "Queued: 2 ahead",
|
||||
"line": "Queued: 2 ahead · 1m 05s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "A one-request server answering another request.",
|
||||
"progress": {
|
||||
"phase": "waiting_for_model",
|
||||
"since": 1762790400000,
|
||||
"model": "Qwen 27B",
|
||||
"reason": "busy"
|
||||
},
|
||||
"now": 1762790412400,
|
||||
"expect": {
|
||||
"text": "Waiting for Qwen 27B: it serves one request at a time and is answering another",
|
||||
"line": "Waiting for Qwen 27B: it serves one request at a time and is answering another · 12s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Every slot taken.",
|
||||
"progress": {
|
||||
"phase": "waiting_for_model",
|
||||
"since": 1762790400000,
|
||||
"model": "coder",
|
||||
"reason": "slots"
|
||||
},
|
||||
"now": 1762790401000,
|
||||
"expect": {
|
||||
"text": "Waiting for coder: all its slots are in use",
|
||||
"line": "Waiting for coder: all its slots are in use · 1s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Another model on the one-model server.",
|
||||
"progress": {
|
||||
"phase": "waiting_for_model",
|
||||
"since": 1762790400000,
|
||||
"model": "coder",
|
||||
"reason": "group"
|
||||
},
|
||||
"now": 1762790400000,
|
||||
"expect": {
|
||||
"text": "Waiting for coder: its server holds another model now",
|
||||
"line": "Waiting for coder: its server holds another model now · 0s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Loading.",
|
||||
"progress": {
|
||||
"phase": "loading_model",
|
||||
"since": 1762790400000,
|
||||
"model": "Gemma 12B"
|
||||
},
|
||||
"now": 1762794125000,
|
||||
"expect": {
|
||||
"text": "Loading Gemma 12B",
|
||||
"line": "Loading Gemma 12B · 1h 02m"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Reading the prompt: the percentage is floored.",
|
||||
"progress": {
|
||||
"phase": "reading_prompt",
|
||||
"since": 1762790400000,
|
||||
"done": 1999,
|
||||
"total": 3000
|
||||
},
|
||||
"now": 1762790402000,
|
||||
"expect": {
|
||||
"text": "Reading the prompt: 1999 / 3000 tokens (66%)",
|
||||
"line": "Reading the prompt: 1999 / 3000 tokens (66%) · 2s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Reading the prompt with no counts from the server.",
|
||||
"progress": {
|
||||
"phase": "reading_prompt",
|
||||
"since": 1762790400000
|
||||
},
|
||||
"now": 1762790402000,
|
||||
"expect": {
|
||||
"text": "Reading the prompt",
|
||||
"line": "Reading the prompt · 2s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Thinking.",
|
||||
"progress": {
|
||||
"phase": "thinking",
|
||||
"since": 1762790400000
|
||||
},
|
||||
"now": 1762790459999,
|
||||
"expect": {
|
||||
"text": "Thinking",
|
||||
"line": "Thinking · 59s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Writing, the rate with one decimal.",
|
||||
"progress": {
|
||||
"phase": "writing",
|
||||
"since": 1762790400000,
|
||||
"rate": 12.46
|
||||
},
|
||||
"now": 1762790404000,
|
||||
"expect": {
|
||||
"text": "Writing: 12.5 tok/s",
|
||||
"line": "Writing: 12.5 tok/s · 4s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Writing before a rate is measured.",
|
||||
"progress": {
|
||||
"phase": "writing",
|
||||
"since": 1762790400000
|
||||
},
|
||||
"now": 1762790400400,
|
||||
"expect": {
|
||||
"text": "Writing",
|
||||
"line": "Writing · 0s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "A tool with what it does.",
|
||||
"progress": {
|
||||
"phase": "running_tool",
|
||||
"since": 1762790400000,
|
||||
"tool": "bash",
|
||||
"what": "bun test"
|
||||
},
|
||||
"now": 1762790461000,
|
||||
"expect": {
|
||||
"text": "Running bash: bun test",
|
||||
"line": "Running bash: bun test · 1m 01s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "A tool without a title.",
|
||||
"progress": {
|
||||
"phase": "running_tool",
|
||||
"since": 1762790400000,
|
||||
"tool": "recall"
|
||||
},
|
||||
"now": 1762790401000,
|
||||
"expect": {
|
||||
"text": "Running recall",
|
||||
"line": "Running recall · 1s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "An approval, naming the tool.",
|
||||
"progress": {
|
||||
"phase": "waiting_for_person",
|
||||
"since": 1762790400000,
|
||||
"what": "approval",
|
||||
"tool": "bash"
|
||||
},
|
||||
"now": 1762790430000,
|
||||
"expect": {
|
||||
"text": "Waiting for you: allow bash?",
|
||||
"line": "Waiting for you: allow bash? · 30s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "An approval with no tool named.",
|
||||
"progress": {
|
||||
"phase": "waiting_for_person",
|
||||
"since": 1762790400000,
|
||||
"what": "approval"
|
||||
},
|
||||
"now": 1762790400000,
|
||||
"expect": {
|
||||
"text": "Waiting for you: an approval",
|
||||
"line": "Waiting for you: an approval · 0s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "A question.",
|
||||
"progress": {
|
||||
"phase": "waiting_for_person",
|
||||
"since": 1762790400000,
|
||||
"what": "question"
|
||||
},
|
||||
"now": 1762790403000,
|
||||
"expect": {
|
||||
"text": "Waiting for you: a question",
|
||||
"line": "Waiting for you: a question · 3s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "The plan.",
|
||||
"progress": {
|
||||
"phase": "waiting_for_person",
|
||||
"since": 1762790400000,
|
||||
"what": "plan"
|
||||
},
|
||||
"now": 1762790403000,
|
||||
"expect": {
|
||||
"text": "Waiting for you: the plan",
|
||||
"line": "Waiting for you: the plan · 3s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Subagents.",
|
||||
"progress": {
|
||||
"phase": "waiting_for_subagents",
|
||||
"since": 1762790400000,
|
||||
"running": 3
|
||||
},
|
||||
"now": 1762790490000,
|
||||
"expect": {
|
||||
"text": "Waiting for subagents: 3 running",
|
||||
"line": "Waiting for subagents: 3 running · 1m 30s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Compacting.",
|
||||
"progress": {
|
||||
"phase": "compacting",
|
||||
"since": 1762790400000
|
||||
},
|
||||
"now": 1762790407000,
|
||||
"expect": {
|
||||
"text": "Compacting the conversation",
|
||||
"line": "Compacting the conversation · 7s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Retrying: `in` counts down from since.",
|
||||
"progress": {
|
||||
"phase": "retrying",
|
||||
"since": 1762790400000,
|
||||
"reason": "502 Bad Gateway",
|
||||
"in": 10,
|
||||
"attempt": 2
|
||||
},
|
||||
"now": 1762790403000,
|
||||
"expect": {
|
||||
"text": "Retrying in 7 s: 502 Bad Gateway",
|
||||
"line": "Retrying in 7 s: 502 Bad Gateway · 3s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Retrying: never below 0.",
|
||||
"progress": {
|
||||
"phase": "retrying",
|
||||
"since": 1762790400000,
|
||||
"reason": "overloaded",
|
||||
"in": 2
|
||||
},
|
||||
"now": 1762790405000,
|
||||
"expect": {
|
||||
"text": "Retrying in 0 s: overloaded",
|
||||
"line": "Retrying in 0 s: overloaded · 5s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Stopped draws no elapsed time.",
|
||||
"progress": {
|
||||
"phase": "stopped",
|
||||
"since": 1762790400000
|
||||
},
|
||||
"now": 1762790405000,
|
||||
"expect": {
|
||||
"text": "Stopped",
|
||||
"line": "Stopped"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Stopped by the person.",
|
||||
"progress": {
|
||||
"phase": "stopped",
|
||||
"since": 1762790400000,
|
||||
"reason": "person"
|
||||
},
|
||||
"now": 1762790405000,
|
||||
"expect": {
|
||||
"text": "Stopped: by you",
|
||||
"line": "Stopped: by you"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Stopped at the step limit.",
|
||||
"progress": {
|
||||
"phase": "stopped",
|
||||
"since": 1762790400000,
|
||||
"reason": "steps"
|
||||
},
|
||||
"now": 1762790400000,
|
||||
"expect": {
|
||||
"text": "Stopped: step limit",
|
||||
"line": "Stopped: step limit"
|
||||
}
|
||||
},
|
||||
{
|
||||
"about": "Failed.",
|
||||
"progress": {
|
||||
"phase": "failed",
|
||||
"since": 1762790400000,
|
||||
"reason": "connection refused"
|
||||
},
|
||||
"now": 1762790405000,
|
||||
"expect": {
|
||||
"text": "Failed: connection refused",
|
||||
"line": "Failed: connection refused"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"about": "Teams (team.md, spec 3.2.0): one lead session's team, step by step, written from a reference model of the rules. `start`: the size setting `min` and `max`, `subagents` (enabled for the session; default true) and the chat model's `capacity` (models/schema.json: `parallel`, `single_session`; {} — no limit). The lead is `lead`; its first prompt is running as the case begins, and every agent is on the chat's model, and it is the only model there is (spec 3.3.0: other models are subagents.json's). Steps and what each answers: `offered` (`by` an agent, default lead) — `{tools, setting}`: the team tools listed for that agent, sorted, and whether the setting is shown; `call` (`by`, `tool`, `args`) — `{result, delivered}`: the call's answer word for word (null where an ordinary tool would run: the case looks only at whether it is refused), and what was delivered to whom by this step, `{name: [message, …]}`; `team_read` answers `{room, delivered}` instead, `room` being the messages it shows as `{n, from, to}` (the tree and the text format are loop.json team.read's, checked by each project's own tests); `task` runs a subagent that counts toward the size (and holds a slot) until `task_done` (`by`) — answers null; `finish` (`by`, `reply`, `reason`: stop by default, or steps, budget, `error — <text>`) — the agent's turn ends: a member's reply is its report — `{delivered}`; `set` (`min`, `max`, `capacity`: the person's setting or the model's metadata changed) — null; `person_stop` (`name`) — the person stopped that member in the UI — null; `user` — the person's message to the lead — `{note}`: the note on it (context.md §10), null when there is none; `state` — the team in tree order as `{name, manager, state}`: working, waiting (for a slot), finished, idle (the lead between turns). Delivering to a finished member or the idle lead wakes it (it is then working, or waiting when its model is full). LLeMbas: services/team.py; CLI: team/.",
|
||||
"about": "Teams (team.md, spec 3.2.0; the main agent and its tree, subagents.md §5–§13, spec 3.4.0 — a member's team_add is now the lead's with `parent`, and `offered` lists 3.4.0's tools): one lead session's team, step by step, written from a reference model of the rules. `start`: the size setting `min` and `max`, `subagents` (enabled for the session; default true) and the chat model's `capacity` (models/schema.json: `parallel`, `single_session`; {} — no limit). The lead is `lead`; its first prompt is running as the case begins, and every agent is on the chat's model, and it is the only model there is (spec 3.3.0: other models are subagents.json's). Steps and what each answers: `offered` (`by` an agent, default lead) — `{tools, setting}`: the team tools listed for that agent, sorted, and whether the setting is shown; `call` (`by`, `tool`, `args`) — `{result, delivered}`: the call's answer word for word (null where an ordinary tool would run: the case looks only at whether it is refused), and what was delivered to whom by this step, `{name: [message, …]}`; `team_read` answers `{room, delivered}` instead, `room` being the messages it shows as `{n, from, to}` (the tree and the text format are loop.json team.read's, checked by each project's own tests); `task` runs a subagent that counts toward the size (and holds a slot) until `task_done` (`by`) — answers null; `finish` (`by`, `reply`, `reason`: stop by default, or steps, budget, `error — <text>`) — the agent's turn ends: a member's reply is its report — `{delivered}`; `set` (`min`, `max`, `capacity`: the person's setting or the model's metadata changed) — null; `person_stop` (`name`) — the person stopped that member in the UI — null; `user` — the person's message to the lead — `{note}`: the note on it (context.md §10), null when there is none; `state` — the team in tree order as `{name, manager, state}`: working, waiting (for a slot), finished, idle (the lead between turns). Delivering to a finished member or the idle lead wakes it (it is then working, or waiting when its model is full). LLeMbas: services/team.py; CLI: team/.",
|
||||
"cases": [
|
||||
{
|
||||
"about": "Offered on a model that serves two requests at once: the lead has all four tools and the setting is shown.",
|
||||
@@ -19,9 +19,14 @@
|
||||
{
|
||||
"tools": [
|
||||
"team_add",
|
||||
"team_assign",
|
||||
"team_decide",
|
||||
"team_findings",
|
||||
"team_read",
|
||||
"team_replace",
|
||||
"team_send",
|
||||
"team_stop"
|
||||
"team_stop",
|
||||
"team_whoami"
|
||||
],
|
||||
"setting": true
|
||||
}
|
||||
@@ -43,9 +48,14 @@
|
||||
{
|
||||
"tools": [
|
||||
"team_add",
|
||||
"team_assign",
|
||||
"team_decide",
|
||||
"team_findings",
|
||||
"team_read",
|
||||
"team_replace",
|
||||
"team_send",
|
||||
"team_stop"
|
||||
"team_stop",
|
||||
"team_whoami"
|
||||
],
|
||||
"setting": true
|
||||
}
|
||||
@@ -113,9 +123,14 @@
|
||||
{
|
||||
"tools": [
|
||||
"team_add",
|
||||
"team_assign",
|
||||
"team_decide",
|
||||
"team_findings",
|
||||
"team_read",
|
||||
"team_replace",
|
||||
"team_send",
|
||||
"team_stop"
|
||||
"team_stop",
|
||||
"team_whoami"
|
||||
],
|
||||
"setting": true
|
||||
}
|
||||
@@ -200,9 +215,14 @@
|
||||
{
|
||||
"tools": [
|
||||
"team_add",
|
||||
"team_assign",
|
||||
"team_decide",
|
||||
"team_findings",
|
||||
"team_read",
|
||||
"team_replace",
|
||||
"team_send",
|
||||
"team_stop"
|
||||
"team_stop",
|
||||
"team_whoami"
|
||||
],
|
||||
"setting": true
|
||||
},
|
||||
@@ -228,7 +248,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"about": "A member that may not lead has team_send and team_read; one that may lead has all four.",
|
||||
"about": "A subagent has team_whoami, team_read, team_send, team_findings and team_finish; a sub-manager the same — it adds nothing (spec 3.4.0).",
|
||||
"start": {
|
||||
"min": 1,
|
||||
"max": 4,
|
||||
@@ -279,17 +299,21 @@
|
||||
},
|
||||
{
|
||||
"tools": [
|
||||
"team_findings",
|
||||
"team_finish",
|
||||
"team_read",
|
||||
"team_send"
|
||||
"team_send",
|
||||
"team_whoami"
|
||||
],
|
||||
"setting": true
|
||||
},
|
||||
{
|
||||
"tools": [
|
||||
"team_add",
|
||||
"team_findings",
|
||||
"team_finish",
|
||||
"team_read",
|
||||
"team_send",
|
||||
"team_stop"
|
||||
"team_whoami"
|
||||
],
|
||||
"setting": true
|
||||
}
|
||||
@@ -392,7 +416,7 @@
|
||||
],
|
||||
"expect": [
|
||||
{
|
||||
"note": "<session-note>\nThe team may have 3 to 5 agents, you included.\nWork through a team from the start: you lead, and members do the work — at least 2 of them.\n</session-note>"
|
||||
"note": "<session-note>\nThe team may have 3 to 5 agents, you included.\nWork through subagents from the start: you lead, and they do the work. The person opened 2 slots for them: fill them with team_add.\n</session-note>"
|
||||
},
|
||||
{
|
||||
"result": "You lead a team: give this to a member (team_add or team_send).",
|
||||
@@ -458,7 +482,7 @@
|
||||
],
|
||||
"expect": [
|
||||
{
|
||||
"note": "<session-note>\nThe team may have 2 to 2 agents, you included.\nWork through a team from the start: you lead, and members do the work — at least 1 of them.\n</session-note>"
|
||||
"note": "<session-note>\nThe team may have 2 to 2 agents, you included.\nWork through subagents from the start: you lead, and they do the work. The person opened 1 slots for them: fill them with team_add.\n</session-note>"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -632,7 +656,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"about": "The size is across the whole tree: a member that leads adds within the same max.",
|
||||
"about": "The size is across the whole tree: subagents placed under a sub-manager count within the same max.",
|
||||
"start": {
|
||||
"min": 1,
|
||||
"max": 4,
|
||||
@@ -653,12 +677,13 @@
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "backend",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "db",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part."
|
||||
"task": "Do the part.",
|
||||
"parent": "backend"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -673,12 +698,13 @@
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "backend",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "api",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part."
|
||||
"task": "Do the part.",
|
||||
"parent": "backend"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1538,7 +1564,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"about": "A member works; a member that leads becomes a manager when it adds one; stopping all its members makes the lead a worker again (min 1).",
|
||||
"about": "A subagent works; a sub-manager becomes a manager when one is placed under it; stopping them all makes the lead a worker again (min 1).",
|
||||
"start": {
|
||||
"min": 1,
|
||||
"max": 6,
|
||||
@@ -1565,12 +1591,13 @@
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "api",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "routes",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part."
|
||||
"task": "Do the part.",
|
||||
"parent": "api"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1805,12 +1832,13 @@
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "api",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "routes",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part."
|
||||
"task": "Do the part.",
|
||||
"parent": "api"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2009,22 +2037,24 @@
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "api",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "routes",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part."
|
||||
"task": "Do the part.",
|
||||
"parent": "api"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "api",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "db",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part."
|
||||
"task": "Do the part.",
|
||||
"parent": "api"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2396,13 +2426,14 @@
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "api",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "routes",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part.",
|
||||
"goal": "The REST API"
|
||||
"goal": "The REST API",
|
||||
"parent": "api"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2670,7 +2701,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"about": "Stopping a member stops its subtree; they leave the team, and their names are free again. Only members under the caller may be stopped.",
|
||||
"about": "Stopping is the main agent's: a subagent's team_stop is refused. Stopping a subagent stops its subtree; they leave the team, and their names are free again.",
|
||||
"start": {
|
||||
"min": 1,
|
||||
"max": 8,
|
||||
@@ -2691,33 +2722,36 @@
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "api",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "routes",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part.",
|
||||
"lead": true
|
||||
"lead": true,
|
||||
"parent": "api"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "routes",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "auth",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part."
|
||||
"task": "Do the part.",
|
||||
"parent": "routes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "api",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "db",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part."
|
||||
"task": "Do the part.",
|
||||
"parent": "api"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2756,7 +2790,7 @@
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "api",
|
||||
"by": "lead",
|
||||
"tool": "team_stop",
|
||||
"args": {
|
||||
"name": "routes"
|
||||
@@ -2767,12 +2801,13 @@
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "api",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "auth",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part."
|
||||
"task": "Do the part.",
|
||||
"parent": "api"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2817,15 +2852,15 @@
|
||||
"delivered": {}
|
||||
},
|
||||
{
|
||||
"result": "web is not under you: you can stop only the members you lead, directly or through your members.",
|
||||
"result": "Only the main agent adds, assigns, replaces and stops subagents: ask it (team_send to lead).",
|
||||
"delivered": {}
|
||||
},
|
||||
{
|
||||
"result": "api is not under you: you can stop only the members you lead, directly or through your members.",
|
||||
"result": "Only the main agent adds, assigns, replaces and stops subagents: ask it (team_send to lead).",
|
||||
"delivered": {}
|
||||
},
|
||||
{
|
||||
"result": "No agent called ghost in this team. The team: lead, api, routes, auth, db, web.",
|
||||
"result": "Only the main agent adds, assigns, replaces and stops subagents: ask it (team_send to lead).",
|
||||
"delivered": {}
|
||||
},
|
||||
{
|
||||
@@ -2900,12 +2935,13 @@
|
||||
},
|
||||
{
|
||||
"op": "call",
|
||||
"by": "api",
|
||||
"by": "lead",
|
||||
"tool": "team_add",
|
||||
"args": {
|
||||
"name": "routes",
|
||||
"role": "owns a part",
|
||||
"task": "Do the part."
|
||||
"task": "Do the part.",
|
||||
"parent": "api"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
+204
-12
@@ -84,7 +84,7 @@
|
||||
}
|
||||
},
|
||||
"team": {
|
||||
"about": "Teams (spec 3.2.0, team.md; which model a member runs on and when a team is offered: spec 3.3.0, subagents.md): a lead and the members it adds, who talk in the team's room. The texts are said word for word; {{size}} is the team's size after the call (team.md §3), {{names}} names joined with \", \" in tree order. conformance/team.json.",
|
||||
"about": "Teams (spec 3.2.0, team.md; which model a member runs on and when a team is offered: spec 3.3.0, subagents.md; the main agent, the tree, permissions and a subagent's life: spec 3.4.0, subagents.md §5–§13). The texts are said word for word; {{size}} is the team's size after the call (team.md §3), {{names}} names joined with \", \" in tree order. conformance/team.json, conformance/delegation.json.",
|
||||
"agents": {
|
||||
"about": "The chat setting agents {min, max}: the agents a team may have, the lead included. 1 ≤ min ≤ max ≤ cap. min and max are a new chat's defaults; cap is the instance's (LLeMbas) or the global configuration's (the CLI).",
|
||||
"min": 1,
|
||||
@@ -92,17 +92,24 @@
|
||||
"cap": 32
|
||||
},
|
||||
"names": {
|
||||
"about": "A member's name: unique in the team; `lead` is the lead's, `all` addresses everyone.",
|
||||
"about": "A subagent's name: unique among the subagents that have not ended; `lead` is the main agent's, `all` addresses everyone, `parent` (3.4.0) the sender's parent.",
|
||||
"pattern": "^[a-z][a-z0-9-]{0,31}$",
|
||||
"lead": "lead",
|
||||
"reserved": [
|
||||
"all",
|
||||
"lead"
|
||||
]
|
||||
"lead",
|
||||
"parent"
|
||||
],
|
||||
"parent": "parent",
|
||||
"id_prefix": "s"
|
||||
},
|
||||
"marks": {
|
||||
"message": "[Team message from {{from}} to {{to}}:]",
|
||||
"report": "[Team report from {{from}} to {{to}}:]"
|
||||
"report": "[Team report from {{from}} to {{to}}:]",
|
||||
"assignment": "[Team assignment from {{from}} to {{to}}:]",
|
||||
"request": "[Team request {{id}} from {{from}} to {{to}}:]",
|
||||
"decision": "[Team decision on {{id}} from {{from}} to {{to}}:]",
|
||||
"context_full": "[Team notice to {{to}}: your context is full]"
|
||||
},
|
||||
"unavailable": {
|
||||
"about": "What a team tool answers while its requirement `team` is not met (team.md §2). one_agent is also each team tool's own `unavailable`, and what task answers while a team is offered, max is 1 and the lead has no member. one_request: no model can serve as a subagent any more (subagents.md §4) — the session's model's capacity changed after the prompt was made.",
|
||||
@@ -153,25 +160,106 @@
|
||||
"not_yours": "{{name}} is not under you: you can stop only the members you lead, directly or through your members.",
|
||||
"nobody_to_stop": "No member is under you: there is nobody to stop.",
|
||||
"no_report": "(no report)",
|
||||
"ended": "[ended: {{reason}}]"
|
||||
"ended": "[ended: {{reason}}]",
|
||||
"only_main": "Only the main agent adds, assigns, replaces and stops subagents: ask it (team_send to lead).",
|
||||
"not_manager": "{{name}} is not a sub-manager: place a subagent under the main agent (lead) or under one added with lead: true.",
|
||||
"wider": "A subagent's mode cannot be looser than its parent's ({{parent_mode}}).",
|
||||
"request_not_narrower": "Request options go with a mode stricter than the parent's: without one there is nothing to ask for.",
|
||||
"request_kind": "{{kind}} is not a request option: use read, write or execute.",
|
||||
"requestable": "Your mode does not allow this, but the main agent may: ask for it with team_request (the tool, the pattern, why), then try again once it allows.",
|
||||
"not_delegated": "Your mode does not allow this, and you may not ask for it: tell your parent what you need.",
|
||||
"not_requestable": "You may not ask for {{tool}}: your request options are {{kinds}}.",
|
||||
"requested": "Asked the main agent ({{id}}): you are told its decision. Carry on with what you can meanwhile.",
|
||||
"no_request": "No open request {{id}}.",
|
||||
"decided": "{{decision}} {{id}} for {{name}}.",
|
||||
"allowed": "Allowed",
|
||||
"refused": "Refused",
|
||||
"decision_allowed": "Allowed: {{tool}} {{pattern}}. Try it again now.",
|
||||
"decision_refused": "Refused: {{tool}} {{pattern}}.",
|
||||
"no_parent": "You are the main agent: you have no parent.",
|
||||
"finished": "Reported to {{to}}. Your task is done: stop here.",
|
||||
"has_ended": "{{name}} has ended: replace it (team_replace) or add another.",
|
||||
"cycle": "{{name}} cannot go under {{parent}}: that is under it.",
|
||||
"assigned": "Assigned to {{name}}: it is told now.",
|
||||
"replaced": "Replaced {{name}}: {{id}} takes its place, briefed with its task and findings. The team is {{size}} of {{max}} agents.",
|
||||
"replace_brief": "{{task}}\n\nYou take over from {{name}} ({{id}}), which ended. What it found:\n{{findings}}",
|
||||
"no_findings": "(no findings)",
|
||||
"noted": "Noted (finding {{n}}).",
|
||||
"not_yours_findings": "You may read only your own findings and those of the subagents under you.",
|
||||
"context_full": "Save what you found with team_findings, then tell your parent with team_send that you are gone and what is left undone. This is your last turn: at most {{steps}} steps.",
|
||||
"gone": "{{name}} ({{id}}) ran out of context and has ended. Its findings: team_findings with of {{name}}.",
|
||||
"request_body": "{{tool}} {{pattern}} — {{why}}"
|
||||
},
|
||||
"read": {
|
||||
"about": "team_read's answer: the tree, then the room. Agents in tree order (an agent, then its members in the order they were added, depth first), indented two spaces per level below the lead. `last`: `active now` while working, else how long ago its last turn ended (durations as jobs write them: \"5s ago\", \"1m 05s ago\"). A message's text: its first line after the colon, every further line indented two spaces. Messages above `since` the caller may see, oldest first, at most read_max; `more` when there are others after the last shown.",
|
||||
"about": "team_read's answer: the tree, then the room. Agents in tree order (an agent, then its members in the order they were added, depth first), indented two spaces per level below the lead. `last`: `active now` while working, else how long ago its last turn ended (durations as jobs write them: \"5s ago\", \"1m 05s ago\"). A message's text: its first line after the colon, every further line indented two spaces. Messages above `since` the caller may see, oldest first, at most read_max; `more` when there are others after the last shown. Spec 3.4.0: the row adds the id, the mode (with request options) and the context use; open slots follow the tree, ended subagents after them.",
|
||||
"tree": "Team ({{size}} of {{max}} agents):",
|
||||
"agent": "{{indent}}- {{name}} — {{role}} · {{state}} · {{model}} · {{last}}",
|
||||
"lead_role": "leads the team",
|
||||
"agent": "{{indent}}- {{name}} ({{id}}) — {{role}} · {{state}} · {{model}} · {{mode}} · {{context}} · {{last}}",
|
||||
"lead_role": "the main agent",
|
||||
"states": {
|
||||
"working": "working",
|
||||
"waiting": "waiting for a slot",
|
||||
"finished": "finished",
|
||||
"idle": "idle"
|
||||
"idle": "idle",
|
||||
"paused": "paused: context full",
|
||||
"done": "done",
|
||||
"out_of_context": "out of context",
|
||||
"stopped": "stopped"
|
||||
},
|
||||
"active": "active now",
|
||||
"room": "Room since #{{since}}:",
|
||||
"message": "#{{n}} {{from}} → {{to}}: {{text}}",
|
||||
"report": "#{{n}} {{from}} → {{to}} (report): {{text}}",
|
||||
"none": "No messages since #{{since}}.",
|
||||
"more": "More after #{{last}}: team_read with since {{last}}."
|
||||
"more": "More after #{{last}}: team_read with since {{last}}.",
|
||||
"slots": "Open slots: {{n}} — fill them with team_add.",
|
||||
"ended": "Ended:",
|
||||
"ended_agent": "- {{name}} ({{id}}) — {{role}} · {{state}} · {{findings}} findings",
|
||||
"context": "{{percent}}% context",
|
||||
"request": "+ {{kinds}}"
|
||||
},
|
||||
"main_only": {
|
||||
"about": "Spec 3.4.0 (subagents.md §6, §8): the tools only the main agent has; a subagent's call to one, or to task, answers texts.only_main.",
|
||||
"tools": [
|
||||
"team_add",
|
||||
"team_assign",
|
||||
"team_decide",
|
||||
"team_replace",
|
||||
"team_stop"
|
||||
]
|
||||
},
|
||||
"context": {
|
||||
"about": "Spec 3.4.0 (subagents.md §9): a subagent does not compact. When its context reaches pause_at of its model's window it is paused and given one final turn of at most final_steps steps, whose user message is the context_full mark and texts.context_full.",
|
||||
"pause_at": 0.85,
|
||||
"final_steps": 8
|
||||
},
|
||||
"request": {
|
||||
"about": "Spec 3.4.0 (subagents.md §7): the kinds a request option may name — risk classes — and the ids of requests, r1, r2, … per session.",
|
||||
"kinds": [
|
||||
"read",
|
||||
"write",
|
||||
"execute"
|
||||
],
|
||||
"id_prefix": "r"
|
||||
},
|
||||
"whoami": {
|
||||
"about": "Spec 3.4.0 (subagents.md §8): team_whoami's answer, one line each; `request` only with request options, `parent` only for a subagent. {{percent}} is floor(used × 100 / window).",
|
||||
"lines": {
|
||||
"who": "You are {{name}} ({{id}}): {{role}}.",
|
||||
"parent": "Your parent: {{parent}}.",
|
||||
"task": "Your task: {{task}}",
|
||||
"mode": "Your mode: {{mode}}.",
|
||||
"request": "You may ask the main agent for: {{kinds}} (team_request).",
|
||||
"model": "Your model: {{model}}.",
|
||||
"limits": "Limits: the team is {{size}} of {{max}} agents; at most {{steps}} steps a turn; {{spawn}}",
|
||||
"spawn_yes": "you add subagents.",
|
||||
"spawn_no": "only the main agent adds subagents.",
|
||||
"context": "Context: {{used}} of {{window}} tokens ({{percent}}%)."
|
||||
}
|
||||
},
|
||||
"findings": {
|
||||
"about": "Spec 3.4.0: team_findings read's answer — the header, then one line per finding, oldest first; none: texts.no_findings after the header.",
|
||||
"header": "Findings of {{name}} ({{id}}):",
|
||||
"item": "{{n}}. {{text}}"
|
||||
}
|
||||
},
|
||||
"context": {
|
||||
@@ -239,12 +327,116 @@
|
||||
"personality": "The person chose a different personality:\n{{personality}}",
|
||||
"mcp": "Instructions from an MCP server that connected since the session began:\n{{instructions}}",
|
||||
"team": "The team may have {{min}} to {{max}} agents, you included.",
|
||||
"team_lead": "Work through a team from the start: you lead, and members do the work — at least {{members}} of them.",
|
||||
"team_lead": "Work through subagents from the start: you lead, and they do the work. The person opened {{members}} slots for them: fill them with team_add.",
|
||||
"team_one": "The person allows one agent: work alone; the team tools and task are unavailable.",
|
||||
"team_own": "This model serves one request at a time, so subagents cannot run on it: they need another model, on another server, that the person names in this chat.",
|
||||
"team_stopped": "The person stopped {{names}}; they have left the team.",
|
||||
"empty": "(none)"
|
||||
},
|
||||
"mcp_wait_ms": 3000
|
||||
},
|
||||
"progress": {
|
||||
"about": "Spec 3.4.0 (progress.md): one fixed set of phases every client shows the same way. `texts` are the shared i18n keys progress.<phase> (a variant: progress.<phase>.<variant>); `line` is drawn for every phase but stopped and failed; elapsed in whole seconds (5s, 1m 05s, 1h 02m). conformance/progress.json.",
|
||||
"phases": [
|
||||
"queued",
|
||||
"waiting_for_model",
|
||||
"loading_model",
|
||||
"reading_prompt",
|
||||
"thinking",
|
||||
"writing",
|
||||
"running_tool",
|
||||
"waiting_for_person",
|
||||
"waiting_for_subagents",
|
||||
"compacting",
|
||||
"retrying",
|
||||
"stopped",
|
||||
"failed"
|
||||
],
|
||||
"fields": {
|
||||
"queued": {
|
||||
"ahead": "int?"
|
||||
},
|
||||
"waiting_for_model": {
|
||||
"model": "string",
|
||||
"reason": "busy|slots|group"
|
||||
},
|
||||
"loading_model": {
|
||||
"model": "string"
|
||||
},
|
||||
"reading_prompt": {
|
||||
"done": "int?",
|
||||
"total": "int?"
|
||||
},
|
||||
"thinking": {},
|
||||
"writing": {
|
||||
"rate": "number?"
|
||||
},
|
||||
"running_tool": {
|
||||
"tool": "string",
|
||||
"what": "string?"
|
||||
},
|
||||
"waiting_for_person": {
|
||||
"what": "approval|question|plan",
|
||||
"tool": "string?"
|
||||
},
|
||||
"waiting_for_subagents": {
|
||||
"running": "int"
|
||||
},
|
||||
"compacting": {},
|
||||
"retrying": {
|
||||
"reason": "string",
|
||||
"in": "int",
|
||||
"attempt": "int?"
|
||||
},
|
||||
"stopped": {
|
||||
"reason": "person|steps|budget?"
|
||||
},
|
||||
"failed": {
|
||||
"reason": "string"
|
||||
}
|
||||
},
|
||||
"texts": {
|
||||
"queued": "Queued",
|
||||
"queued.ahead": "Queued: {{ahead}} ahead",
|
||||
"waiting_for_model": "Waiting for {{model}}: {{reason}}",
|
||||
"loading_model": "Loading {{model}}",
|
||||
"reading_prompt": "Reading the prompt: {{done}} / {{total}} tokens ({{percent}}%)",
|
||||
"reading_prompt.bare": "Reading the prompt",
|
||||
"thinking": "Thinking",
|
||||
"writing": "Writing: {{rate}} tok/s",
|
||||
"writing.bare": "Writing",
|
||||
"running_tool": "Running {{tool}}: {{what}}",
|
||||
"running_tool.bare": "Running {{tool}}",
|
||||
"waiting_for_person": "Waiting for you: {{what}}",
|
||||
"waiting_for_subagents": "Waiting for subagents: {{running}} running",
|
||||
"compacting": "Compacting the conversation",
|
||||
"retrying": "Retrying in {{in}} s: {{reason}}",
|
||||
"stopped": "Stopped",
|
||||
"stopped.reason": "Stopped: {{reason}}",
|
||||
"failed": "Failed: {{reason}}"
|
||||
},
|
||||
"reason": {
|
||||
"busy": "it serves one request at a time and is answering another",
|
||||
"slots": "all its slots are in use",
|
||||
"group": "its server holds another model now"
|
||||
},
|
||||
"what": {
|
||||
"approval": "allow {{tool}}?",
|
||||
"approval.bare": "an approval",
|
||||
"question": "a question",
|
||||
"plan": "the plan"
|
||||
},
|
||||
"stopped_reason": {
|
||||
"person": "by you",
|
||||
"steps": "step limit",
|
||||
"budget": "budget"
|
||||
},
|
||||
"line": "{{text}} · {{elapsed}}",
|
||||
"no_elapsed": [
|
||||
"stopped",
|
||||
"failed"
|
||||
],
|
||||
"what_max": 80,
|
||||
"pace_per_second": 4
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,13 @@
|
||||
"team_send": "allow",
|
||||
"team_read": "allow",
|
||||
"team_stop": "allow",
|
||||
"team_whoami": "allow",
|
||||
"team_finish": "allow",
|
||||
"team_findings": "allow",
|
||||
"team_request": "allow",
|
||||
"team_decide": "allow",
|
||||
"team_assign": "allow",
|
||||
"team_replace": "allow",
|
||||
"web_search": "allow",
|
||||
"memory": "allow",
|
||||
"session_search": "allow",
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
# Progress
|
||||
|
||||
Spec 3.4.0. **One way to say what a session is doing**, the same in every client — the web UI,
|
||||
Desktop, the CLI, Android — and for every agent in it, the main agent and each subagent alike.
|
||||
Before 3.4.0 each client invented its own subset from a free `status` text; that text stays, for
|
||||
compatibility, and beside it goes a structured **progress** object with one of a fixed set of
|
||||
**phases**. The texts are `loop.json` `progress`; the cases `conformance/progress.json`.
|
||||
|
||||
## 1. The object
|
||||
|
||||
```json
|
||||
{ "phase": "running_tool", "since": 1762790400000, "tool": "bash", "what": "bun test" }
|
||||
```
|
||||
|
||||
- **`phase`** — one of the thirteen names below, never another. A session doing nothing has no
|
||||
progress: `null`.
|
||||
- **`since`** — when this phase began, Unix time in **milliseconds** (an integer). A change of the
|
||||
phase's data (tokens read, the rate) keeps `since`; a new phase, or the same phase for another
|
||||
thing (another tool call, another model), starts a new one.
|
||||
- The phase's **data**, as listed: every field named here, with these names and these types. A
|
||||
field that is not known is left out (never `null`, never a guess), and the text says less.
|
||||
|
||||
## 2. The phases
|
||||
|
||||
In the order a turn usually meets them. `{{x}}` in a text is the field `x`; the texts are
|
||||
`loop.json` `progress.texts`, word for word, and they are the shared i18n keys
|
||||
`progress.<phase>` (and `progress.<phase>.<variant>`, `progress.reason.<reason>`,
|
||||
`progress.what.<what>`) in every client's translations.
|
||||
|
||||
| Phase | Data | Text (`progress.texts`) |
|
||||
|---|---|---|
|
||||
| `queued` | `ahead?: int` — turns before it | `Queued` · with `ahead`: `Queued: {{ahead}} ahead` |
|
||||
| `waiting_for_model` | `model: string` (its display name, else its id); `reason: "busy" \| "slots" \| "group"` | `Waiting for {{model}}: {{reason}}` |
|
||||
| `loading_model` | `model: string` | `Loading {{model}}` |
|
||||
| `reading_prompt` | `done: int`, `total: int` — prompt tokens processed of all | `Reading the prompt: {{done}} / {{total}} tokens ({{percent}}%)` · without `total`: `Reading the prompt` |
|
||||
| `thinking` | — | `Thinking` |
|
||||
| `writing` | `rate?: number` — tokens a second, as measured over this reply | `Writing: {{rate}} tok/s` · without `rate`: `Writing` |
|
||||
| `running_tool` | `tool: string` (the tool's name); `what?: string` — the call's short title (the command, the path, the query), one line, at most 80 characters | `Running {{tool}}: {{what}}` · without `what`: `Running {{tool}}` |
|
||||
| `waiting_for_person` | `what: "approval" \| "question" \| "plan"`; `tool?: string` (approval: the tool asked about) | `Waiting for you: {{what}}` |
|
||||
| `waiting_for_subagents` | `running: int` — subagents working or waiting now | `Waiting for subagents: {{running}} running` |
|
||||
| `compacting` | — | `Compacting the conversation` |
|
||||
| `retrying` | `reason: string` — the server's error, one line; `in: int` — seconds until the retry, counted down by the client from `since`; `attempt?: int` | `Retrying in {{in}} s: {{reason}}` |
|
||||
| `stopped` | `reason?: "person" \| "steps" \| "budget"` | `Stopped` · with `reason`: `Stopped: {{reason}}` |
|
||||
| `failed` | `reason: string` — the error, one line | `Failed: {{reason}}` |
|
||||
|
||||
The fixed words a field stands for:
|
||||
|
||||
- `reason` of `waiting_for_model` (`progress.reason`): `busy` — *it serves one request at a time
|
||||
and is answering another*; `slots` — *all its slots are in use*; `group` — *its server holds
|
||||
another model now*.
|
||||
- `what` of `waiting_for_person` (`progress.what`): `approval` — *allow {{tool}}?* (*an approval*
|
||||
without `tool`); `question` — *a question*; `plan` — *the plan*.
|
||||
- `reason` of `stopped` (`progress.stopped_reason`): `person` — *by you*; `steps` — *step limit*;
|
||||
`budget` — *budget*.
|
||||
- `percent` is `floor(done × 100 / total)`; numbers are written as integers, `rate` with one
|
||||
decimal (`12.5`), in the client's own number format.
|
||||
|
||||
## 3. The line a client draws
|
||||
|
||||
**`{{text}} · {{elapsed}}`** (`progress.line`) for every phase but `stopped` and `failed`, which
|
||||
draw their text alone. `elapsed` is now − `since`, written in whole seconds as a ticking clock writes durations
|
||||
(`5s`, `1m 05s`, `1h 02m`), and kept moving by the client at least once a second while the
|
||||
phase lasts. `retrying`'s `in` is likewise counted down from `since` (never below 0).
|
||||
|
||||
Every client draws the same line for the same object — the same words, from the same keys — and
|
||||
its own look around it (a spinner, a colour, a bar for `reading_prompt`). Where a line has no room
|
||||
(a phone's notification, a tree row) the text alone, without `· elapsed`, is enough; nothing else
|
||||
is shortened.
|
||||
|
||||
## 4. When each phase holds
|
||||
|
||||
What decides the phase, so that two implementations agree on the same moment:
|
||||
|
||||
- `queued` — a prompt waits behind a turn that runs (the device's turn queue; the server's per
|
||||
chat). `waiting_for_model` — the turn may start but its model may not take it yet: a one-request
|
||||
server answering another request (`busy`), every slot of the model held (`slots`; `team.md` §8),
|
||||
another model of its one-model server in use (`group`). `loading_model` — only where the
|
||||
implementation is told the model is being loaded (the server sees it; a device that cannot tell
|
||||
skips it).
|
||||
- `reading_prompt` — the request is sent and no output has come; with `done`/`total` from the
|
||||
server's prompt-progress frames (`quirks.json` `prompt-progress`), without them where none come.
|
||||
- `thinking` — reasoning streams; `writing` — reply text (or a tool call's arguments) streams.
|
||||
- `running_tool` — from a tool call's start to its end; with calls in parallel, the one that
|
||||
started first. `waiting_for_person` — an approval card, a question or a plan to approve is open
|
||||
for this agent. `waiting_for_subagents` — the agent's turn waits on subagents: a `task` call in
|
||||
the foreground, or the main agent with nothing to do but its subagents' reports (`subagents.md`
|
||||
§9).
|
||||
- `compacting` — a compaction runs. `retrying` — a failed request will be sent again after a wait.
|
||||
- `stopped` / `failed` — the turn ended other than by finishing: stopped by the person, a step limit
|
||||
or a budget; failed with an error. They are the last progress of that turn and stay until the
|
||||
next one begins; a turn that finished normally ends with `null`.
|
||||
|
||||
## 5. Where it is sent
|
||||
|
||||
- **`/api/v2` (LLeMbas)**: every frame of a chat's stream that carries the `status` text carries
|
||||
`progress` beside it — the object, or `null` — and a frame is sent when the progress changes:
|
||||
a new phase at once, a data-only change (`done`, `rate`) at most four times a second. `status`
|
||||
stays as it was, its text unchanged, for clients that do not read `progress`.
|
||||
- **The link (`acp.md`, capability `progress`)**: the `phase` event `{ progress, agent? }` —
|
||||
`agent` the subagent's id (`subagents.md` §5) when the progress is a subagent's, absent for the
|
||||
main agent's — under the same pacing; `progress` in `_lembas/session/status`, so a client
|
||||
reattaching draws it at once. The device sends it; the server passes it on in `/api/v2` as its
|
||||
own.
|
||||
- **The subagent tree** (`subagents.md` §12): every agent carries its current `progress`.
|
||||
|
||||
A client that reads `progress` draws it and ignores `status`; one that does not, draws `status` as
|
||||
before.
|
||||
@@ -1,12 +1,14 @@
|
||||
<!-- LLeMbas CLI and LLeMbas, spec 3.2.0 (team.md): how to lead a team, in the system prompt whenever
|
||||
the team tools are offered, and in a member's that may lead. Constant: the size the person
|
||||
allows comes in a session note, never here. -->
|
||||
# Leading a team
|
||||
You can add members to a team with team_add: agents that work in the background, each on the part of the work it owns, while you lead. A small job you may do yourself. Once you have a member you manage and no longer do the work: tools that change things are refused to you, and reading stays yours, for review.
|
||||
- Plan first: what the goal is, what the parts are, and what each one needs from the others. Split by area of ownership, not by step, so that one member owns a thing from start to finish.
|
||||
- Name each member after what it owns. Brief it so that it can work without you: what to do, what done means, what to leave alone, and what to report.
|
||||
- Keep the team flat while it is small — up to six or eight members, each reporting to you. Beyond that, add a lead for each area (`lead: true`), give it the area's goal, and let it build and run its own members; you then lead the leads.
|
||||
- Keep the team within the size the person allows, which a session note tells you. Stop a member whose part is done or no longer needed, to make room.
|
||||
- Coordinate through the room: team_send to the member who owns a thing, `all` only for what everyone needs. team_read shows the team and the room when you need to look; nothing from it reaches you unasked except your members' reports and messages addressed to you.
|
||||
- Step in when a member is stuck, when two disagree, or when the plan has to change: decide, and tell those it concerns.
|
||||
- Review every report against what you asked for — read the work itself where it matters — and send back what is not done. Then give your own answer: to the person, or, if you lead an area, as your report to your manager.
|
||||
<!-- LLeMbas CLI and LLeMbas, spec 3.2.0 (team.md), 3.4.0 (subagents.md §5–§13): how the main agent
|
||||
leads its subagents, in the system prompt whenever the team tools are offered. Constant: the
|
||||
size the person allows comes in a session note, never here. -->
|
||||
# Leading subagents
|
||||
You are the main agent of this session. You can add subagents with team_add: agents that work in the background, each on the part of the work it owns, while you lead. Only you add, assign, replace and stop them. A small job you may do yourself. Once you have a subagent you manage and no longer do the work: tools that change things are refused to you, and reading stays yours, for review.
|
||||
- Plan first: what the goal is, what the parts are, and what each one needs from the others. Split by area of ownership, not by step, so that one subagent owns a thing from start to finish.
|
||||
- Name each subagent after what it owns and give it a position (`role`). Brief it so that it can work without you: what to do, what done means, what to leave alone, and what to report.
|
||||
- Keep the tree flat while it is small — up to six or eight subagents, each reporting to you. Beyond that, add a sub-manager for each area (`lead: true`) and place that area's subagents under it (`parent`); it directs them and reports to you, and you still add and stop every one.
|
||||
- A subagent's mode is yours by default and never looser. Give a stricter one where the person wants less done unasked; with it you may give `request` options, and you decide its requests with team_decide — allow only what the task needs.
|
||||
- Keep within the size the person allows, which a session note tells you; when it says slots are open, fill them. Stop a subagent whose part is done or no longer needed, to make room.
|
||||
- Coordinate through the room: team_send to the subagent who owns a thing, `all` only for what everyone needs. team_read shows the tree and the room when you need to look; nothing from it reaches you unasked except reports, requests and messages addressed to you.
|
||||
- A subagent whose context fills saves its findings and ends. Read them with team_findings, then replace it (team_replace) if its part is not done.
|
||||
- Step in when a subagent is stuck, when two disagree, or when the plan has to change: decide, and tell those it concerns (team_assign for new work).
|
||||
- Review every report against what you asked for — read the work itself where it matters — and send back what is not done. Then give your own answer to the person.
|
||||
@@ -1,14 +1,16 @@
|
||||
<!-- LLeMbas CLI and LLeMbas, spec 3.2.0 (team.md): a team member's standing, said once at the end
|
||||
of its system prompt in place of blocks/subagent.md. The variables are what differs per member;
|
||||
each stands on a line of its own, so no punctuation of theirs matters. -->
|
||||
You are "{{name}}", a member of a team, and you report to "{{manager}}".
|
||||
Your part: {{role}}
|
||||
<!-- LLeMbas CLI and LLeMbas, spec 3.2.0 (team.md), 3.4.0 (subagents.md §13): a subagent's standing,
|
||||
said once at the end of its system prompt in place of blocks/subagent.md. The variables are what
|
||||
differs per subagent; each stands on a line of its own, so no punctuation of theirs matters. -->
|
||||
You are "{{name}}" ({{id}}), a subagent of this session, and you report to "{{manager}}".
|
||||
Your position: {{role}}
|
||||
The team's goal: {{goal}}
|
||||
|
||||
{{instructions}}
|
||||
|
||||
You work for your manager on the part you own, and you cannot ask the person anything: ask your manager, by name, with team_send. Other members own other parts. Message the one who owns a thing when you need it from them, and `all` only for what everyone on the team needs; messages to you arrive as you work. team_read shows who is on the team and the room.
|
||||
You work for your parent on the part you own, and you cannot ask the person anything: ask your parent with team_send to `parent`. Only the main agent (`lead`) adds, assigns and stops subagents. Other subagents own other parts. Message the one who owns a thing when you need it from them, and `all` only for what everyone needs; messages to you arrive as you work. team_read shows the tree and the room; team_whoami shows who you are, your mode and how full your context is.
|
||||
|
||||
Your final reply is your report to "{{manager}}" — make it complete on its own: the result, then the evidence (file:line), then anything you could not settle. A message may wake you again afterwards; your next final reply is then your next report.{{read_only}}
|
||||
Your context is limited and you do not compact: write what you find with team_findings as you go. When your context fills you are told, and you have one last turn to save your findings and tell your parent.
|
||||
|
||||
When your task is done, call team_finish with your report to "{{manager}}" — make it complete on its own: the result, then the evidence (file:line), then anything you could not settle. A final reply without it is also your report, and a message may then wake you again.{{read_only}}
|
||||
|
||||
{{lead}}
|
||||
@@ -0,0 +1,8 @@
|
||||
<!-- LLeMbas CLI and LLeMbas, spec 3.4.0 (subagents.md §5, §13): what a sub-manager is told, in
|
||||
place of the whole of blocks/team_lead.md that a member with `lead: true` got in 3.2.0. -->
|
||||
# Directing an area
|
||||
You are a sub-manager: the main agent places subagents under you, and you direct them. You do not add, assign, replace or stop subagents — ask the main agent with team_send to `lead` when your area needs one more, another task for one, or one stopped. You manage and no longer do the work: tools that change things are refused to you, and reading stays yours, for review.
|
||||
- Split your area's work among the subagents under you, tell each what it owns with team_send, and keep them from overlapping.
|
||||
- Their reports come to you. Review each against what you asked — read the work itself where it matters — and send back what is not done.
|
||||
- Read the findings of a subagent under you with team_findings, especially of one that ran out of context; tell the main agent whether it needs replacing.
|
||||
- When your area is done, call team_finish with your report to the main agent.
|
||||
@@ -251,16 +251,23 @@
|
||||
"scope": "shared",
|
||||
"llembas": [],
|
||||
"llembas_text": "identical",
|
||||
"why": "spec 3.2.0: LLeMbas reads it from the vendored spec (harness_spec.prompt), not from a fragment",
|
||||
"why": "spec 3.2.0, 3.4.0: LLeMbas reads it from the vendored spec (harness_spec.prompt), not from a fragment",
|
||||
"variables": {
|
||||
"name": "the member's name in the team",
|
||||
"role": "its role as team_add gave it: one line, what it owns",
|
||||
"manager": "the name of the agent that added it (`lead` for the team's lead)",
|
||||
"role": "its position, one line (team_add's role)",
|
||||
"manager": "its parent: lead, or the sub-manager it was placed under",
|
||||
"goal": "the team's goal as it was when the member was added: the `goal` its team_add gave, else its manager's (team.md §4)",
|
||||
"instructions": "its agent's own instructions (prompts/agents/<name>.md for a built-in one), as in blocks/subagent.md",
|
||||
"read_only": "in plan mode: the sentence saying it can read and search but change nothing (as in blocks/subagent.md); otherwise empty",
|
||||
"lead": "for a member added with `lead: true`: the whole of blocks/team_lead.md; otherwise empty"
|
||||
"lead": "for a sub-manager (added with `lead: true`): the whole of blocks/team_submanager.md (spec 3.4.0; before, blocks/team_lead.md); otherwise empty",
|
||||
"id": "the subagent's id (s1, s2, …; spec 3.4.0)"
|
||||
}
|
||||
},
|
||||
"blocks/team_submanager.md": {
|
||||
"scope": "shared",
|
||||
"llembas": [],
|
||||
"llembas_text": "identical",
|
||||
"why": "spec 3.4.0: LLeMbas reads it from the vendored spec (harness_spec.prompt), not from a fragment"
|
||||
}
|
||||
}
|
||||
}
|
||||
+261
-1
@@ -1,6 +1,6 @@
|
||||
# Subagents
|
||||
|
||||
Spec 3.3.0. **Which model a subagent runs on, and when subagents are offered at all.** A
|
||||
Spec 3.3.0; §5–§13 spec 3.4.0. **Which model a subagent runs on, and when subagents are offered at all.** A
|
||||
**subagent** is any agent a session's agent starts to work for it: a `task` subagent (in the
|
||||
foreground or as a background job) and a team's member (`team.md`) alike. The same rules in a chat
|
||||
on the server and in an agent session on a device, in both projects. The texts are `loop.json`
|
||||
@@ -88,3 +88,263 @@ before 3.3.0 for a single model.
|
||||
|
||||
What counts as **usable** is each project's: LLeMbas — the models the person may use in the chat's
|
||||
picker; the CLI — the models of the server it is logged in to.
|
||||
|
||||
---
|
||||
|
||||
# Subagents v2 — the main agent and its tree
|
||||
|
||||
Spec 3.4.0. **How subagents are organised, what each may do, and how each ends.** The owner's model:
|
||||
one permanent **main agent** per session, which alone makes subagents and places them in a tree;
|
||||
permissions are inherited and never widened; a subagent is temporary and ends with its task or its
|
||||
context. Sections 5–13 **supersede `team.md` where they say something different** — who adds a
|
||||
subagent (§6), who stops one (§10), the states (§9), what a member is told (§13) — and keep the
|
||||
rest of it: the size setting and its counting (§2–§3), the room and who receives what (§5),
|
||||
delivery and waking (§7), a manager's refusals (§6 there), capacity and waiting for a slot (§8).
|
||||
The tool names `team_*` stay (nothing stored or trained breaks); `task` and `report` are unchanged
|
||||
for a one-off subagent. The texts are `loop.json` `team` (3.4.0 additions marked there); the cases
|
||||
`conformance/team.json` (the tree, the tools, the lifecycle) and `conformance/delegation.json`
|
||||
(permissions).
|
||||
|
||||
## 5. Words
|
||||
|
||||
- **The main agent** is the session's own agent: the chat's agent on LLeMbas, the session's in the
|
||||
CLI. It is **permanent**: it compacts and never ends. In the room and in every tool it is called
|
||||
`lead` (the name is kept from 3.2.0); a person reads it as *the main agent*.
|
||||
- **A subagent** is an agent the main agent added (`team_add`). It has:
|
||||
- **`id`** — `s1`, `s2`, … in the order the session's subagents were added, never reused in the
|
||||
session (a replacement gets a new one);
|
||||
- **`name`** — the main agent's choice (`team.names.pattern`), unique among the subagents that
|
||||
have not ended, `lead`, `all` and `parent` reserved;
|
||||
- **`position`** — its designation, one line, given by the main agent (`team_add`'s `role`:
|
||||
*the API's tests*, *reviews the parser*);
|
||||
- **`parent`** — the main agent, or a **sub-manager** the main agent placed it under;
|
||||
- **`task`** — its brief, as given (and as replaced by `team_assign`);
|
||||
- **`mode`** and **`request`** — its permission mode and its request options (§7);
|
||||
- **`model`** — `subagents.md` §2–§3, unchanged.
|
||||
- **A sub-manager** is a subagent added with `lead: true`. It **directs** the subagents the main
|
||||
agent places under it — they report to it, it messages them, it reviews their work — and it does
|
||||
**not** add, assign, replace or stop subagents: only the main agent does (§6). Like every manager
|
||||
it does not do the work itself (`team.md` §6, unchanged).
|
||||
- **The tree**: the main agent at the root, every subagent under its parent, in the order added.
|
||||
**Under** an agent and **its subtree** keep their `team.md` meaning.
|
||||
|
||||
## 6. Only the main agent makes subagents
|
||||
|
||||
- **`team_add`, `team_assign`, `team_replace`, `team_stop` and `team_decide`** are the main agent's.
|
||||
A subagent's call to any of them is refused, word for word, with `team.texts.only_main`:
|
||||
|
||||
> Only the main agent adds, assigns, replaces and stops subagents: ask it (team_send to lead).
|
||||
|
||||
A subagent's tool list never has `task` (a one-off subagent is the main agent's too), and a call
|
||||
to it by a former name is refused with the same text.
|
||||
- **`team_add`** takes, beside 3.2.0's `name`, `role` (the position), `task`, `goal`, `lead`,
|
||||
`agent`, `model`: **`parent`** — the name of a sub-manager to place it under (default: the main
|
||||
agent; refused with `team.texts.not_manager` for a subagent that is not a sub-manager, and
|
||||
`unknown` for no such name), **`mode`** — its mode (default: its parent's; §7), **`request`** —
|
||||
its request options (§7). Its refusals, in order: `unavailable`, `only_main`, then 3.2.0's (`all_name`,
|
||||
`bad_name`, `taken`, `no_goal`, `full`), then `unknown` and `not_manager` for `parent`, then the mode's (`wider`, `request_not_narrower`,
|
||||
`request_kind`), then the model's (§2–§3). `parent` and the reserved names are refused as
|
||||
`taken`.
|
||||
- **The person** can tell the main agent to spawn — it is the main agent's call, as any — or set
|
||||
**Min above 1**: then **`min − 1` slots** exist from the start of the main agent's reply (the
|
||||
first one after the setting was told, `team.md` §10). A **slot** is a place in the tree for a
|
||||
subagent not added yet: it is shown (§12) and `team_read` lists it, it is **not** an agent and
|
||||
does not count toward the size, and each subagent added fills one. Open slots are
|
||||
`max(0, min − 1 − subagents that have not ended)`. The main agent is told to use them in its
|
||||
note (`context.note.team_lead`, which 3.4.0 words as slots), and is a manager from the start
|
||||
(`team.md` §6).
|
||||
- **Min/Max** (3.3.0) are unchanged: they count the main agent; 1 is the main agent alone. The
|
||||
model rules (§2–§3) are unchanged.
|
||||
|
||||
## 7. Permissions: inherited, never widened
|
||||
|
||||
**A subagent's mode is its parent's or stricter** — `permission/modes.json` `order`, loosest first:
|
||||
`auto`, `edit`, `manual`, `plan`. The main agent's mode is the session's.
|
||||
|
||||
- `team_add`'s and `team_assign`'s `mode`, looser than the parent's, is refused, word for word,
|
||||
with `team.texts.wider`:
|
||||
|
||||
> A subagent's mode cannot be looser than its parent's ({{parent_mode}}).
|
||||
|
||||
When the parent's own mode becomes stricter during the session (the person switches the main
|
||||
agent to manual), every subagent looser than its parent is made as strict as it, down the tree,
|
||||
at once; a looser switch changes no subagent.
|
||||
- **Request options** (`request`: a list of the risk classes `read`, `write`, `execute`) may be
|
||||
given **only with a mode stricter than the parent's** — otherwise refused with
|
||||
`team.texts.request_not_narrower` ("Request options go with a mode stricter than the parent's:
|
||||
without one there is nothing to ask for."); an unknown kind with `team.texts.request_kind`. They
|
||||
let the subagent **ask the main agent** for a call of that class that its own mode does not
|
||||
allow; **the main agent is the check**.
|
||||
|
||||
**Who decides a subagent's call.** The hardline and the deny rules first, as for any call. Then:
|
||||
|
||||
1. The call is evaluated in the **subagent's mode**, with the session's rules and approvals and
|
||||
the subagent's own grants (below). **Allow** — it runs. **Deny** (a rule, the hardline, plan
|
||||
mode's refusal) — refused, as always.
|
||||
2. **Ask** — the call is evaluated in the **main agent's mode** (the session's rules and
|
||||
approvals, no grants):
|
||||
- **Allow** — the main agent could allow it: the subagent was narrowed. If the call's risk class
|
||||
is in its `request`, refused with `team.texts.requestable` — it asks with `team_request`, the
|
||||
main agent decides with `team_decide`, and once allowed the same call runs. Otherwise refused
|
||||
with `team.texts.not_delegated`:
|
||||
|
||||
> Your mode does not allow this, and you may not ask for it: tell your parent what you need.
|
||||
|
||||
- **Ask** — **nobody in the tree can allow it: it goes to the person**, as an approval card that
|
||||
names the subagent (its name and position), the same card and the same answers as the main
|
||||
agent's own; unattended, refused as `modes.json` `unattended` says. So in an all-Edit tree a
|
||||
subagent's `bash` reaches the person — not the main agent, which could not allow it either.
|
||||
- **Deny** — refused with that reason.
|
||||
|
||||
A sub-manager is never asked: it may not allow more than the main agent, and the main agent is
|
||||
the check.
|
||||
|
||||
**`team_request`** (a subagent with request options; its tool list has it only then): `tool`, the
|
||||
permission `pattern` it needs (as a rule writes it: `git push *`, a path) and `why`. Refused with
|
||||
`team.texts.not_requestable` when the tool's risk class is not in its options. Posted to the main
|
||||
agent as a request, under its own mark (`team.marks.request`), the body `team.texts.request_body`,
|
||||
with an id (`r1`, `r2`, … per session); the answer `team.texts.requested` says it waits for the main agent's decision.
|
||||
|
||||
**`team_decide`** (the main agent): `id`, `allow` (a boolean), `note`. Allowed — the subagent gets
|
||||
a **grant**: the rule `{ permission: <tool's key>, pattern, action: allow }` for itself alone, for
|
||||
the rest of its life; **a grant only ever applies where the main agent's own mode would allow the
|
||||
call** (step 2's evaluation, done again at the call), so it can never widen past the main agent.
|
||||
Either way the subagent is told, under `team.marks.decision`: `team.texts.decision_allowed` or
|
||||
`decision_refused`, then the note after a blank line. The answer to the main agent is
|
||||
`team.texts.decided` (`decision` being `allowed` or `refused`). Refused:
|
||||
`team.texts.no_request` for an id that is not an open request.
|
||||
|
||||
## 8. What each agent has
|
||||
|
||||
| Tools | Main agent | Sub-manager | Subagent |
|
||||
|---|---|---|---|
|
||||
| `team_whoami`, `team_read`, `team_send`, `team_findings` | ✓ | ✓ | ✓ |
|
||||
| `team_finish` | — | ✓ | ✓ |
|
||||
| `team_request` | — | with request options | with request options |
|
||||
| `team_add`, `team_assign`, `team_replace`, `team_stop`, `team_decide` | ✓ | — | — |
|
||||
|
||||
Fixed when the prompt is made (the main agent's) or when the subagent is added (`context.md` §10,
|
||||
rule 4). What each does:
|
||||
|
||||
- **`team_whoami`** — who the caller is: `team.whoami`, one line each, in its order — id, name, position, parent, task, mode and
|
||||
request options, model, the limits (the size and Max, the steps a turn may take, whether it may
|
||||
add subagents) and its **context use** (tokens in its context now, of its model's window, and the
|
||||
percentage). For the main agent: the same, its position *the main agent*, without the parent and task lines.
|
||||
- **`team_read`** — the roster: the tree (every agent and open slot, §12's fields) and the room,
|
||||
as in 3.2.0 (`team.read`; 3.4.0's row adds the id, the mode and the context use).
|
||||
- **`team_send`** — a message `to` names, `all`, or **`parent`** (3.4.0): the caller's parent
|
||||
(refused for the main agent with `team.texts.no_parent`). Otherwise 3.2.0.
|
||||
- **`team_finish`** — `report`: the subagent's task is done. The report goes to its parent (the
|
||||
report mark, as a final reply's), and the subagent **ends** (§9): its turn stops after this call,
|
||||
it leaves the size, and its findings and transcript stay.
|
||||
- **`team_findings`** — `write` (`text`): a finding kept for the caller, numbered from 1; `read`
|
||||
(`of`: a name or an id, default the caller): the findings of the caller, or of an agent in its
|
||||
subtree (the main agent: anybody's), ended ones included — as `team.findings` writes them. A
|
||||
name that has been used more than once means its latest holder; an id is exact. Otherwise refused with
|
||||
`team.texts.not_yours_findings`. The person reads every agent's (§12).
|
||||
- **`team_assign`** — `name`, `task`, and optionally `role` (a new position), `parent` (another
|
||||
sub-manager, or `lead`), `mode` (§7): a new task for a subagent that has not ended. Its task
|
||||
becomes this one; it is told under `team.marks.assignment`, and a finished one is woken. Refused:
|
||||
`unknown`, `team.texts.ended` for one that has ended, `not_manager`, `wider`; a move under its
|
||||
own subtree with `team.texts.cycle`.
|
||||
- **`team_replace`** — `name`, and optionally `task`: the subagent ends (stopped, if it has not
|
||||
already), and a new one takes its place — the same name, position, parent, mode, request options
|
||||
and model, a new id — briefed with `task` (default: the old task) followed by the old one's
|
||||
findings (`team.texts.replace_brief`). Its subagents move under the new one. Refused: `unknown`.
|
||||
- **`team_stop`** — the main agent's only (3.2.0 let a manager stop its subtree); otherwise 3.2.0.
|
||||
- **`team_decide`** — §7.
|
||||
|
||||
## 9. A subagent's life
|
||||
|
||||
States (`team.read.states`): **`working`** (a turn runs), **`waiting`** (it has work and waits for
|
||||
a slot, `team.md` §8), **`finished`** (its last turn ended with a final reply, which was its report;
|
||||
a message wakes it — 3.2.0), **`paused`** (its context is full; its last turn runs), and the ends:
|
||||
**`done`** (`team_finish`), **`out_of_context`** (its last turn after `paused` ended), **`stopped`**
|
||||
(the main agent's `team_stop`, a replacement, or the person). The main agent is `working`,
|
||||
`waiting` or `idle`.
|
||||
|
||||
**An ended subagent** — `done`, `out_of_context`, `stopped` — leaves the size and its slot frees;
|
||||
its name may be used again; it keeps its id, and the tree keeps it (§12) with its findings and
|
||||
transcript for the rest of the session. Messages to it by name are refused as `unknown`.
|
||||
|
||||
**When its context fills.** A subagent does not compact. When its context reaches
|
||||
`team.context.pause_at` of its model's window (default 0.85, the fraction compaction would start
|
||||
at), after the step that took it there:
|
||||
|
||||
1. it is **`paused`**: nothing new reaches it — a message to it is posted in the room and not
|
||||
delivered; whoever replaces it reads it with `team_read`;
|
||||
2. it is given **one final turn**, at most `team.context.final_steps` steps (8), whose user message
|
||||
is `team.texts.context_full`, under its own mark: save what it found with `team_findings`, and
|
||||
tell its parent with `team_send` that it is gone and what is left;
|
||||
3. when that turn ends it is **`out_of_context`**, and its parent is sent `team.texts.gone` — then,
|
||||
after a blank line, that turn's final reply if it gave one — as its report (the report mark): the name, that it ran out of context, and how to read its
|
||||
findings. **The parent decides** — the main agent replaces it (`team_replace`) or uses the
|
||||
findings; a sub-manager tells the main agent.
|
||||
|
||||
**The main agent is permanent**: it compacts as every session does (`context.md` §7) and never
|
||||
ends; deleting the session ends every subagent.
|
||||
|
||||
**Waiting for subagents.** The main agent's turn may end while subagents work; their reports wake
|
||||
it (3.2.0 §7). Its progress is `waiting_for_subagents` (`progress.md`) while its turn waits on
|
||||
them — a foreground `task` — and the session shows the subagents' own phases in the tree.
|
||||
|
||||
## 10. Stopping
|
||||
|
||||
Only the main agent stops (`team_stop`, 3.2.0's refusals but `not_yours`, which no longer arises),
|
||||
and **the person** (§12) — said to the main agent as a note (`context.note.team_stopped`). A
|
||||
stopped subagent's subtree is stopped with it, unless the main agent moved it first. A sub-manager
|
||||
that wants a subagent of its own stopped asks the main agent.
|
||||
|
||||
## 11. Transcripts and findings
|
||||
|
||||
Every subagent's conversation is kept — its brief, what it wrote, every tool call with its output —
|
||||
for as long as the session: **viewable read-only by the person, live while it runs and after it
|
||||
ended**. Nobody types into it; the person speaks to a subagent only through the main agent (or by
|
||||
stopping it). Findings (§8) are kept the same way, readable by its parent, the main agent, and the
|
||||
person.
|
||||
|
||||
## 12. What clients show
|
||||
|
||||
**The tree** — the main agent, every subagent under its parent, open slots, and ended subagents
|
||||
(after the live ones, dimmed, with how each ended):
|
||||
|
||||
| Field | Shown as |
|
||||
|---|---|
|
||||
| `name`, `id`, `position` | `parser` (`s2`) — *reviews the parser* |
|
||||
| `state` | `team.read.states`, its word |
|
||||
| `model` | display name |
|
||||
| `mode` | the mode's name, and request options as `+ write` etc. |
|
||||
| `context` | `{used, window}` → `42%` (a bar where there is room) |
|
||||
| `progress` | its current phase line (`progress.md` §3) |
|
||||
| messages | the room's messages to and from it: how many unread by the person, the last one's first line |
|
||||
|
||||
- **Web UI, Desktop and the CLI** show the whole tree, the room, each subagent's findings and its
|
||||
context (the CLI: `/context <name>`), and open any subagent's transcript read-only, live and after
|
||||
it ended; the person can stop any subagent there.
|
||||
- **Android** shows a reduced list — name, position, state, progress line, context % — and opens a
|
||||
transcript read-only.
|
||||
|
||||
**The data**, the same in `/api/v2` (LLeMbas: a chat's stream carries the tree as it changes) and on
|
||||
the link (`acp.md`, capability `tree`):
|
||||
|
||||
```json
|
||||
{ "min": 1, "max": 4, "size": 2, "open_slots": 0,
|
||||
"agents": [
|
||||
{ "id": "lead", "name": "lead", "position": "the main agent", "parent": null, "state": "working",
|
||||
"model": "qwen-27b", "mode": "edit", "request": [], "manager": true,
|
||||
"context": { "used": 41200, "window": 131072 }, "progress": { "phase": "thinking", "since": 1762790400000 } },
|
||||
{ "id": "s1", "name": "parser", "position": "reviews the parser", "parent": "lead", "state": "working",
|
||||
"model": "qwen-27b", "mode": "manual", "request": ["write"], "manager": false, "task": "…",
|
||||
"context": { "used": 9100, "window": 131072 }, "progress": { "phase": "running_tool", "since": 1762790401000, "tool": "read", "what": "src/parse.ts" },
|
||||
"findings": 2, "messages": 3 }
|
||||
],
|
||||
"ended": [ { "id": "s0", "name": "scout", "position": "…", "parent": "lead", "state": "done", "ended": 1762790300000, "findings": 1 } ] }
|
||||
```
|
||||
|
||||
## 13. What each is told
|
||||
|
||||
- The main agent: `blocks/team_lead.md` (3.4.0: it alone adds; slots; positions; modes and request
|
||||
options; replacing a subagent that ran out of context) and the notes of `team.md` §10.
|
||||
- A subagent: `blocks/team_member.md` (3.4.0: its id and position, `team_whoami`, `team_findings`,
|
||||
`team_finish`, that its context is limited and it will be told when it fills); a sub-manager,
|
||||
`blocks/team_submanager.md` in place of the whole lead block it got in 3.2.0.
|
||||
+15
-1
@@ -1,6 +1,6 @@
|
||||
# Teams
|
||||
|
||||
Spec 3.2.0; the model a member runs on and when a team is offered, 3.3.0 (`subagents.md`). **Subagents that work together.** A session's agent — the **lead** — may add
|
||||
Spec 3.2.0; the model a member runs on and when a team is offered, 3.3.0 (`subagents.md`); the main agent, the tree, permissions and a subagent's life, 3.4.0 (`subagents.md` §5–§13). **Subagents that work together.** A session's agent — the **lead** — may add
|
||||
**members**, background agents that each own a part of the work, and lead them as a manager: it
|
||||
plans, splits the work, coordinates and reviews, and the members do it. Members talk to each other
|
||||
and to their managers in the team's **room**. A member may itself lead an area with members of its
|
||||
@@ -11,6 +11,16 @@ The tools are `tools/team_add.json`, `team_send.json`, `team_read.json`, `team_s
|
||||
and numbers `loop.json` `team` (and the size notes in `context.note`); the prompt texts
|
||||
`prompts/blocks/team_lead.md` and `team_member.md`; the cases `conformance/team.json`.
|
||||
|
||||
> **Spec 3.4.0 supersedes parts of this page** (`subagents.md` §5–§13, *Subagents v2*): the lead is
|
||||
> **the main agent**, and **only it adds, assigns, replaces and stops** — a member with `lead: true`
|
||||
> is a **sub-manager** that directs the members placed under it (`team_add`'s `parent`) and does not
|
||||
> add or stop (§4, §9 below); members have a mode no looser than their parent's and may ask the main
|
||||
> agent for more (`subagents.md` §7); a member ends with `team_finish` or when its context fills
|
||||
> (`subagents.md` §9); the room carries assignments, requests and decisions besides messages and
|
||||
> reports; the tree goes over the link (§11). Everything else here stands as written: the size
|
||||
> setting and its counting, the room and who receives what, delivery and waking, a manager's
|
||||
> refusals, capacity and waiting for a slot. "Member" here and "subagent" there are the same thing.
|
||||
|
||||
## 1. Words
|
||||
|
||||
- **Agent**: the lead or a member. Every agent has a **name**: the lead is `lead`; a member the name
|
||||
@@ -243,6 +253,10 @@ agent not under it (`not_yours`). The answer, `stopped`, names the stopped in tr
|
||||
|
||||
## 11. Over the link
|
||||
|
||||
*3.4.0: the tree and the room are carried — `acp.md` capability `tree`; what follows is how a device
|
||||
without it is still shown.*
|
||||
|
||||
|
||||
An agent chat's team runs on the device, as its jobs do. Spec 3.2.0 does not carry the room over
|
||||
ACP yet: a device with the `jobs` capability reports each member as a subagent job (`job` events,
|
||||
`description` being `<name>: <role>`), so the client's job strip shows them, and the room is shown
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"cli": [],
|
||||
"llembas": []
|
||||
},
|
||||
"description": "Add a member to your team and start it at once, in the background, on its part of the work. You lead: members do the work while you plan, coordinate and review — once you have a member, tools that change things are refused to you.\n\n- `name` is how everyone addresses it: lowercase letters, digits and hyphens, after what it owns (`parser`, `api-tests`), unique in the team.\n- `role` is one line: what it owns. `task` is its brief and must stand on its own — it sees nothing of this conversation: what to do, when it is done, and what to report.\n- `goal` is the team's goal in a line; your first member needs it, and every member is told it.\n- `lead: true` lets it add members of its own and lead an area; it then manages as you do.\n- The person sets how many agents the team may have, you included; past that this is refused. When the model is already serving as many requests as it can at once, the member waits for a slot and starts when one frees.\n- Its final reply comes to you as its report. Meanwhile team_send messages it, team_read shows the team and the room, team_stop stops it.\n- Agents: {{agents}}",
|
||||
"description": "Add a subagent and start it at once, in the background, on its part of the work. Only you, the main agent, add subagents. You lead: subagents do the work while you plan, coordinate and review — once you have one, tools that change things are refused to you.\n\n- `name` is how everyone addresses it: lowercase letters, digits and hyphens, after what it owns (`parser`, `api-tests`). `role` is its position, one line: what it owns. `task` is its brief and must stand on its own — it sees nothing of this conversation: what to do, when it is done, and what to report.\n- `goal` is the team's goal in a line; your first subagent needs it, and every subagent is told it.\n- `lead: true` makes it a sub-manager: it directs the subagents you place under it (`parent`), reviews their reports and reports to you; it does not add or stop subagents itself.\n- `mode` is its permission mode: its parent's by default, never looser. With a stricter mode you may give `request` options — kinds of action (read, write, execute) it may ask you for with team_request; you decide with team_decide.\n- The person sets how many agents the team may have, you included; past that this is refused. When the model is already serving as many requests as it can at once, the subagent waits for a slot and starts when one frees.\n- It reports with team_finish (or its final reply). Meanwhile team_send messages it, team_read shows the tree and the room, team_assign gives it new work, team_replace replaces it, team_stop stops it.\n- Agents: {{agents}}",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -26,7 +26,7 @@
|
||||
"role": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "One line: what it owns"
|
||||
"description": "Its position, one line: what it owns"
|
||||
},
|
||||
"task": {
|
||||
"type": "string",
|
||||
@@ -39,7 +39,7 @@
|
||||
},
|
||||
"lead": {
|
||||
"type": "boolean",
|
||||
"description": "May add members of its own and lead an area (default: false)"
|
||||
"description": "A sub-manager: directs the subagents placed under it (default: false)"
|
||||
},
|
||||
"agent": {
|
||||
"type": "string",
|
||||
@@ -48,6 +48,32 @@
|
||||
"model": {
|
||||
"type": "string",
|
||||
"description": "Run it on another model — only one the person named in this conversation (its id or name, as in the list in your instructions). Default: the session's model."
|
||||
},
|
||||
"parent": {
|
||||
"type": "string",
|
||||
"description": "The sub-manager to place it under (default: you, lead)"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auto",
|
||||
"edit",
|
||||
"manual",
|
||||
"plan"
|
||||
],
|
||||
"description": "Its permission mode: its parent's or stricter (default: its parent's)"
|
||||
},
|
||||
"request": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"read",
|
||||
"write",
|
||||
"execute"
|
||||
]
|
||||
},
|
||||
"description": "With a stricter mode only: kinds of action it may ask you for (team_request)"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -58,5 +84,6 @@
|
||||
},
|
||||
"variables": {
|
||||
"agents": "the agents a member may be: `name — description`, separated by \"; \" (as task's)"
|
||||
}
|
||||
},
|
||||
"offered": "main"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "team_assign",
|
||||
"scope": "shared",
|
||||
"sessions": "both",
|
||||
"risk": "interact",
|
||||
"exclusive": false,
|
||||
"block": "tool",
|
||||
"purpose": false,
|
||||
"requires": [
|
||||
"team"
|
||||
],
|
||||
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
|
||||
"aliases": {
|
||||
"cli": [],
|
||||
"llembas": []
|
||||
},
|
||||
"offered": "main",
|
||||
"description": "Give a subagent that has not ended a new task: it is told at its next step, or woken. Optionally a new position (`role`), another sub-manager to work under (`parent`, or lead), or a stricter `mode`.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"task": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
},
|
||||
"parent": {
|
||||
"type": "string"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auto",
|
||||
"edit",
|
||||
"manual",
|
||||
"plan"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"task"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "team_decide",
|
||||
"scope": "shared",
|
||||
"sessions": "both",
|
||||
"risk": "interact",
|
||||
"exclusive": false,
|
||||
"block": "tool",
|
||||
"purpose": false,
|
||||
"requires": [
|
||||
"team"
|
||||
],
|
||||
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
|
||||
"aliases": {
|
||||
"cli": [],
|
||||
"llembas": []
|
||||
},
|
||||
"offered": "main",
|
||||
"description": "Decide a subagent's request (team_request): allow it or refuse it, with a note it is told. You may allow only what your own mode would allow you; anything beyond that goes to the person when the subagent tries.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"allow": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"allow"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "team_findings",
|
||||
"scope": "shared",
|
||||
"sessions": "both",
|
||||
"risk": "interact",
|
||||
"exclusive": false,
|
||||
"block": "tool",
|
||||
"purpose": false,
|
||||
"requires": [
|
||||
"team"
|
||||
],
|
||||
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
|
||||
"aliases": {
|
||||
"cli": [],
|
||||
"llembas": []
|
||||
},
|
||||
"description": "Findings kept beyond your context: `write` adds one (a fact, a result, where something is) to yours; `read` shows yours, or with `of` those of a subagent under you (the main agent: anyone's), ended ones included. Write as you go: when your context fills you have one turn left, and your findings are what the next agent starts from.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"write",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "write: the finding"
|
||||
},
|
||||
"of": {
|
||||
"type": "string",
|
||||
"description": "read: a name or an id (default: yours)"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"action"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "team_finish",
|
||||
"scope": "shared",
|
||||
"sessions": "both",
|
||||
"risk": "interact",
|
||||
"exclusive": false,
|
||||
"block": "tool",
|
||||
"purpose": false,
|
||||
"requires": [
|
||||
"team"
|
||||
],
|
||||
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
|
||||
"aliases": {
|
||||
"cli": [],
|
||||
"llembas": []
|
||||
},
|
||||
"offered": "subagent",
|
||||
"description": "Your task is done: send your report to your parent and end. Make the report complete on its own — the result, then the evidence (file:line), then anything you could not settle. Save anything worth keeping beyond the report with team_findings first. Nothing runs after this call.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"report": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"report"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
"cli": [],
|
||||
"llembas": []
|
||||
},
|
||||
"description": "The team and its room: every agent (name, role, who leads it, state, model, last activity), and the room's messages after `since` that are yours to see — those you sent or received and those of the members under you; the lead sees them all. Messages are numbered: pass the last number you saw as `since` to read only what is new.",
|
||||
"description": "The tree and its room: every agent (name, id, position, parent, state, model, mode, context use, last activity), open slots, subagents that have ended, and the room's messages after `since` that are yours to see — those you sent or received and those of the subagents under you; the main agent sees them all. Messages are numbered: pass the last number you saw as `since` to read only what is new.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "team_replace",
|
||||
"scope": "shared",
|
||||
"sessions": "both",
|
||||
"risk": "interact",
|
||||
"exclusive": false,
|
||||
"block": "task",
|
||||
"purpose": false,
|
||||
"requires": [
|
||||
"team"
|
||||
],
|
||||
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
|
||||
"aliases": {
|
||||
"cli": [],
|
||||
"llembas": []
|
||||
},
|
||||
"offered": "main",
|
||||
"description": "Replace a subagent — one that ran out of context, or one that is stuck: it ends (stopped, if it has not already), and a new one with the same name, position, parent, mode and model takes its place, briefed with `task` (default: the old task) and the old one's findings. The subagents under it move under the new one.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"task": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "team_request",
|
||||
"scope": "shared",
|
||||
"sessions": "both",
|
||||
"risk": "interact",
|
||||
"exclusive": false,
|
||||
"block": "tool",
|
||||
"purpose": false,
|
||||
"requires": [
|
||||
"team"
|
||||
],
|
||||
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
|
||||
"aliases": {
|
||||
"cli": [],
|
||||
"llembas": []
|
||||
},
|
||||
"offered": "subagent",
|
||||
"description": "Ask the main agent to allow a call your mode does not, of a kind your request options name. Say the tool, the permission pattern you need (a command such as `git push *`, or a path) and why. Its decision comes to you as a message; once allowed, make the call again.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tool": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"pattern": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"why": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"tool",
|
||||
"pattern",
|
||||
"why"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
"cli": [],
|
||||
"llembas": []
|
||||
},
|
||||
"description": "Send a message through your team's room: to one or more agents by name, or to `all`. It reaches each at its next step, or wakes one that has finished, its context intact. Message the agent who owns a thing; use `all` only for what everyone needs. The team's lead is `lead`; your manager is reached by its name.",
|
||||
"description": "Send a message through the team's room: to one or more agents by name, to `parent` (the agent you report to), or to `all`. It reaches each at its next step, or wakes one that has finished, its context intact. Message the agent who owns a thing; use `all` only for what everyone needs. The main agent is `lead`.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -24,7 +24,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1,
|
||||
"description": "Names, or [\"all\"]"
|
||||
"description": "Names, [\"parent\"], or [\"all\"]"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
|
||||
@@ -14,18 +14,19 @@
|
||||
"cli": [],
|
||||
"llembas": []
|
||||
},
|
||||
"description": "Stop a member of your team, and the members under it, where they are: their work stops and they leave the team, which makes room for others. Only members under you, directly or through your members; `all` stops every one of them. Nothing they had not reported comes back — ask for a report with team_send first when you need it.",
|
||||
"description": "Stop a subagent, and the subagents under it, where they are: their work stops and they end, which makes room for others. Only you, the main agent, stop subagents; `all` stops every one. Nothing they had not reported comes back — ask for a report with team_send first, or read their findings with team_findings.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "A member under you, or all"
|
||||
"description": "A subagent's name, or all"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
},
|
||||
"offered": "main"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "team_whoami",
|
||||
"scope": "shared",
|
||||
"sessions": "both",
|
||||
"risk": "read",
|
||||
"exclusive": false,
|
||||
"block": "tool",
|
||||
"purpose": false,
|
||||
"requires": [
|
||||
"team"
|
||||
],
|
||||
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
|
||||
"aliases": {
|
||||
"cli": [],
|
||||
"llembas": []
|
||||
},
|
||||
"description": "Who you are on the team: your id, name, position, parent, task, permission mode and request options, model, limits, and how full your context is.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user