@fradser/pi-agent-teams 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.memory/MEMORY.md +3 -0
- package/.memory/openai_teammate_api_reference.md +118 -0
- package/.memory/run-centric-design.md +22 -0
- package/README.md +111 -0
- package/agents/observer.md +10 -0
- package/agents/reviewer.md +11 -0
- package/agents/specialist.md +10 -0
- package/agents/worker.md +11 -0
- package/package.json +40 -0
- package/src/agents.ts +138 -0
- package/src/console-viewport.ts +30 -0
- package/src/guidance.ts +77 -0
- package/src/index.ts +79 -0
- package/src/run-machine.ts +580 -0
- package/src/spawner.ts +549 -0
- package/src/state.ts +684 -0
- package/src/statefile.ts +140 -0
- package/src/terminal.ts +34 -0
- package/src/tools.ts +154 -0
- package/src/types.ts +231 -0
- package/src/ui.ts +411 -0
- package/src/worker.ts +56 -0
- package/src/worktree.ts +115 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# OpenAI Teammate API Reference
|
|
2
|
+
|
|
3
|
+
> Reference documentation for OpenAI's external Teammate / Workspace Agents API surface.
|
|
4
|
+
> This is a reference for the API surface OpenAI documents on developers.openai.com — not the Pi extension tools.
|
|
5
|
+
|
|
6
|
+
## Scope and terminology
|
|
7
|
+
|
|
8
|
+
In OpenAI's current developer documentation, a "teammate" is an AI teammate in the ChatGPT workspace. The Codex use-case guides describe setting up a teammate as a work chief of staff ([Set up a teammate](https://developers.openai.com/codex/use-cases/proactive-teammate)) and as a dedicated project teammate ([Set up a project teammate](https://developers.openai.com/codex/use-cases/project-teammate)). These teammates are ChatGPT workspace agents: shared agents that run repeatable workflows across ChatGPT and independently complete end-to-end tasks ([Building workspace agents in ChatGPT](https://developers.openai.com/cookbook/articles/chatgpt-agents-sales-meeting-prep)).
|
|
9
|
+
|
|
10
|
+
The developer API surface for teammates documented on developers.openai.com is the Workspace Agents API for triggering published workspace agents ([Trigger workspace agent runs](https://developers.openai.com/workspace-agents/trigger-runs)), together with the agent-building APIs that supply knowledge and conversation state: the Files API, file search, vector stores, and the Threads API.
|
|
11
|
+
|
|
12
|
+
**Terminology note.** The current OpenAI API reference defines no `/teammates` resource: there is no teammate endpoint group in the API reference. Requests that mention a Teammate API endpoint map to the Workspace Agents API and the agent-building APIs documented below. Likewise, the current developer documentation does not define a `workflow.md` file format; workflow configuration for teammates is expressed through the surfaces described in the next section. Do not assume undocumented endpoints or file formats.
|
|
13
|
+
|
|
14
|
+
## Teammates in the ChatGPT workspace
|
|
15
|
+
|
|
16
|
+
ChatGPT workspace agents are available in research preview for ChatGPT Business, Enterprise, and Edu customers; they are evolutions of GPTs that can work across tools to complete high-value tasks, and they can use connected apps, follow skills, run on a schedule, and be shared with colleagues in the workspace ([Building workspace agents in ChatGPT](https://developers.openai.com/cookbook/articles/chatgpt-agents-sales-meeting-prep)). The Codex use-case guides show two teammate configurations: a work chief of staff that checks connected messages, email, calendar, documents, and project trackers on an hourly schedule ([Set up a teammate](https://developers.openai.com/codex/use-cases/proactive-teammate)), and a project teammate with a dedicated task for one project or workstream that reviews relevant sources, tracks meaningful changes on a schedule, prepares the next step, and waits for approval before taking action ([Set up a project teammate](https://developers.openai.com/codex/use-cases/project-teammate)). Both guides ship a starter prompt and name the connected work tools the teammate may review.
|
|
17
|
+
|
|
18
|
+
## Workflow as code
|
|
19
|
+
|
|
20
|
+
The current developer documentation does not document a `workflow.md` file. Workflow configuration for teammates is expressed through the documented surfaces below, and those are the surfaces to use:
|
|
21
|
+
|
|
22
|
+
- **Workspace agents in ChatGPT.** Agents are created through a conversational builder, given access to the team's connected apps and knowledge bases, tested before publishing, scheduled to run on a recurring schedule, and shared with the workspace ([Building workspace agents in ChatGPT](https://developers.openai.com/cookbook/articles/chatgpt-agents-sales-meeting-prep)).
|
|
23
|
+
- **The Workspace Agents API.** The programmatic entry point: a trigger request carries the message text passed to the agent and an optional caller-defined conversation key that continues the same conversation across trigger events ([Trigger workspace agent runs](https://developers.openai.com/workspace-agents/trigger-runs)).
|
|
24
|
+
- **Agent Builder workflows.** Agent Builder is a visual canvas for building multi-step agent workflows; a workflow is a combination of agents, tools, and control-flow logic that encapsulates the steps and actions for handling a task, and it is published as an object with an ID and versioning. Note that OpenAI is deprecating Agent Builder and schedules the product to shut down on November 30, 2026 ([Agent Builder](https://developers.openai.com/api/docs/guides/agent-builder)).
|
|
25
|
+
|
|
26
|
+
## Workspace Agents API
|
|
27
|
+
|
|
28
|
+
The Workspace Agents API triggers a published ChatGPT workspace agent from an external system or automation ([Trigger workspace agent runs](https://developers.openai.com/workspace-agents/trigger-runs)).
|
|
29
|
+
|
|
30
|
+
- **Endpoints.** `POST https://api.chatgpt.com/v1/workspace_agents/{id}/trigger` starts a run; `GET https://api.chatgpt.com/v1/workspace_agents/{id}/runs/{run_id}` polls run status ([Trigger workspace agent runs](https://developers.openai.com/workspace-agents/trigger-runs)).
|
|
31
|
+
- **Identifiers.** `id` is the stable public API trigger identifier for the published API channel, in an `agtch_XXX` format; `run_id` is the trigger run identifier returned by a trigger request, in an `apirun_XXX` format ([Trigger workspace agent runs](https://developers.openai.com/workspace-agents/trigger-runs)).
|
|
32
|
+
- **Authentication.** Authenticate with a Workspace Agent access token as a bearer credential on `api.chatgpt.com` ([Trigger workspace agent runs](https://developers.openai.com/workspace-agents/trigger-runs), [Authenticate with Workspace Agent access tokens](https://developers.openai.com/workspace-agents/authentication)).
|
|
33
|
+
- **Request body.** `input` (string, required): message text passed to the agent as trigger input. `conversation_key` (string, optional): a caller-defined stable identifier for continuing the same agent conversation across multiple trigger events. To safely retry the same trigger event, send an optional `Idempotency-Key` header and reuse the same key only when retrying the same event; a retried request with the same key returns the original accepted outcome instead of adding a second trigger event to the queue ([Trigger workspace agent runs](https://developers.openai.com/workspace-agents/trigger-runs)).
|
|
34
|
+
- **Response.** The API durably queues the trigger event and returns `202 Accepted` with a `conversation_url` link to the ChatGPT conversation, for example `{ "conversation_url": "https://chatgpt.com/c/123" }`. The agent's response cannot currently be retrieved through the API ([Trigger workspace agent runs](https://developers.openai.com/workspace-agents/trigger-runs)).
|
|
35
|
+
- **Run status polling (beta).** Include the header `OpenAI-Beta: workspace_agent_runs=v1` when triggering to receive an `agent_trigger_run_id` in the trigger response, then poll the run endpoint until a terminal status. The run object is `workspace_agent.trigger_run` with `id`, `status`, `created_at`, `agent_id`, `api_trigger_id`, `conversation_url`, and `error`; status values are `queued`, `in_progress`, `suspended`, `completed`, and `failed`, where `completed` and `failed` are terminal ([Trigger workspace agent runs](https://developers.openai.com/workspace-agents/trigger-runs)).
|
|
36
|
+
|
|
37
|
+
**Workspace Agent access tokens.** Tokens are provisioned from the ChatGPT admin access-token flow and are scoped for workspace use. A workspace admin must first enable workspace agents and turn on "Allow users to create personal access tokens" in Admin > Permissions & roles, then create an access token in Admin > Access tokens with the **Workspace Agents** scope. The token is used as a bearer credential and is scoped to Workspace Agents API operations only ([Authenticate with Workspace Agent access tokens](https://developers.openai.com/workspace-agents/authentication)).
|
|
38
|
+
|
|
39
|
+
## Knowledge files: the Files API
|
|
40
|
+
|
|
41
|
+
Files are used to upload documents that can be used with features like Assistants and Fine-tuning ([Files](https://developers.openai.com/api/reference/resources/files)).
|
|
42
|
+
|
|
43
|
+
### FileObject
|
|
44
|
+
|
|
45
|
+
The `File` object represents a document that has been uploaded to OpenAI ([Files](https://developers.openai.com/api/reference/resources/files)). The live `FileObject` schema lists these fields:
|
|
46
|
+
|
|
47
|
+
- `id` — string; the file identifier, which can be referenced in API endpoints.
|
|
48
|
+
- `bytes` — number; the size of the file, in bytes.
|
|
49
|
+
- `created_at` — number; the Unix timestamp (in seconds) for when the file was created.
|
|
50
|
+
- `filename` — string; the name of the file.
|
|
51
|
+
- `object` — always `"file"`.
|
|
52
|
+
- `purpose` — the intended purpose of the file: `assistants`, `assistants_output`, `batch`, `batch_output`, `fine-tune`, `fine-tune-results`, `vision`, or `user_data`.
|
|
53
|
+
- `status`, `expires_at`, and `status_details` — documented on the current schema and marked deprecated.
|
|
54
|
+
|
|
55
|
+
The schema exposes the file length through `bytes`; there is no separate size field on `FileObject` ([Files](https://developers.openai.com/api/reference/resources/files)).
|
|
56
|
+
|
|
57
|
+
### POST /files
|
|
58
|
+
|
|
59
|
+
Upload a file as multipart form data with `file` (the File object, not the file name) and `purpose`, plus an optional `expires_after` object with `anchor` and `seconds`. Documented `purpose` values for upload are `assistants`, `batch`, `fine-tune`, `vision`, `user_data`, and `evals`. Individual files can be up to 512 MB, each project can store up to 2.5 TB of files in total, there is no organization-wide storage limit, and uploads to this endpoint are rate-limited to 1,000 requests per minute per authenticated user. The Assistants API supports files up to 2 million tokens and of specific file types; the Fine-tuning and Batch APIs only support `.jsonl` files. Vector store attachment has separate limits, including 2,000 attached files per minute per organization ([Upload file](https://developers.openai.com/api/reference/resources/files/methods/create)).
|
|
60
|
+
|
|
61
|
+
### GET /files and related endpoints
|
|
62
|
+
|
|
63
|
+
- `GET /files` lists files. The optional `purpose` query parameter limits the list to files with the given purpose; pagination is controlled by `limit` (1 to 10,000, default 10,000), `order` (asc or desc by the `created_at` timestamp), and `after`. The response `data` field is an array of `FileObject` ([List files](https://developers.openai.com/api/reference/resources/files/methods/list)).
|
|
64
|
+
- `GET /files/{file_id}` retrieves a file as a `FileObject` ([Retrieve file](https://developers.openai.com/api/reference/resources/files/methods/retrieve)).
|
|
65
|
+
- `DELETE /files/{file_id}` deletes a file and returns a `FileDeleted` object with `id`, `deleted`, and `object` ([Delete file](https://developers.openai.com/api/reference/resources/files/methods/delete)).
|
|
66
|
+
|
|
67
|
+
## File search and vector stores
|
|
68
|
+
|
|
69
|
+
File search is a tool available in the Responses API. It enables models to retrieve information in a knowledge base of previously uploaded files through semantic and keyword search; by creating vector stores and uploading files to them, you give the model access to these knowledge bases, or vector stores. It is a hosted tool managed by OpenAI, so no code is required to handle its execution ([File search](https://developers.openai.com/api/docs/guides/tools-file-search)).
|
|
70
|
+
|
|
71
|
+
A vector store is a collection of processed files used by the `file_search` tool ([Vector Stores](https://developers.openai.com/api/reference/resources/vector_stores)). Adding a file to a vector store automatically parses, chunks, embeds, and stores the file in a vector database capable of both keyword and semantic search; each vector store can hold up to 10,000 files, and for vector stores created starting in November 2025 the limit is 100,000,000 files. Vector stores can be attached to both assistants and threads, at most one per assistant and at most one per thread ([File Search tool](https://developers.openai.com/api/docs/assistants/tools/file-search)). By default `max_chunk_size_tokens` is 800 and `chunk_overlap_tokens` is 400; chunking is configurable per file through `chunking_strategy`, where `max_chunk_size_tokens` must be between 100 and 4096 inclusive. The maximum file size is 512 MB and each file should contain no more than 5,000,000 tokens ([File Search tool](https://developers.openai.com/api/docs/assistants/tools/file-search)).
|
|
72
|
+
|
|
73
|
+
Vector Stores endpoints, all documented in the reference ([Vector Stores](https://developers.openai.com/api/reference/resources/vector_stores)):
|
|
74
|
+
|
|
75
|
+
- `POST /vector_stores` — create a vector store ([Create vector store](https://developers.openai.com/api/reference/resources/vector_stores/methods/create)).
|
|
76
|
+
- `GET /vector_stores` — list vector stores ([List vector stores](https://developers.openai.com/api/reference/resources/vector_stores/methods/list)).
|
|
77
|
+
- `GET /vector_stores/{vector_store_id}` — retrieve a vector store ([Retrieve vector store](https://developers.openai.com/api/reference/resources/vector_stores/methods/retrieve)).
|
|
78
|
+
- `POST /vector_stores/{vector_store_id}` — modify a vector store ([Modify vector store](https://developers.openai.com/api/reference/resources/vector_stores/methods/update)).
|
|
79
|
+
- `DELETE /vector_stores/{vector_store_id}` — delete a vector store ([Delete vector store](https://developers.openai.com/api/reference/resources/vector_stores/methods/delete)).
|
|
80
|
+
- `POST /vector_stores/{vector_store_id}/search` — search a vector store for relevant chunks based on a query and file attributes filter. The body takes `query` (a string or array of strings) and an optional `filters` value, either a `ComparisonFilter` with an operator (`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`) or a `CompoundFilter`; results are returned as `vector_store.search_results.page` objects with `file_id`, `filename`, `score`, `attributes`, `content`, `has_more`, and `next_page` ([Search vector store](https://developers.openai.com/api/reference/resources/vector_stores/methods/search)).
|
|
81
|
+
- Subresources for adding files: vector store files ([Vector Store Files](https://developers.openai.com/api/reference/resources/vector_stores/subresources/files), [Create vector store file](https://developers.openai.com/api/reference/resources/vector_stores/subresources/files/methods/create)) and vector store file batches for attaching many files in one request ([Vector Store File Batches](https://developers.openai.com/api/reference/resources/vector_stores/subresources/file_batches), [Create vector store file batch](https://developers.openai.com/api/reference/resources/vector_stores/subresources/file_batches/methods/create)).
|
|
82
|
+
|
|
83
|
+
## Threads and thread attachment
|
|
84
|
+
|
|
85
|
+
Threads and messages represent a conversation session between an assistant and a user ([Assistants API deep dive](https://developers.openai.com/api/docs/assistants/deep-dive)). The Threads API is documented in the Beta Threads reference group ([Threads](https://developers.openai.com/api/reference/resources/beta/subresources/threads)) and belongs to the Assistants API, which the reference labels as deprecated in favor of the Responses API ([Create thread](https://developers.openai.com/api/reference/resources/beta/subresources/threads/methods/create)).
|
|
86
|
+
|
|
87
|
+
### POST /threads
|
|
88
|
+
|
|
89
|
+
`POST /threads` creates a thread ([Create thread](https://developers.openai.com/api/reference/resources/beta/subresources/threads/methods/create)). The documented request body:
|
|
90
|
+
|
|
91
|
+
- `messages` — optional array of objects with `content`, `role`, `attachments`, and `metadata`: a list of messages to start the thread with.
|
|
92
|
+
- `content` — string, or an array of content parts: `TextContentBlockParam` with `text` and `type` (`"text"`), `ImageFileContentBlock` with `image_file` and `type` (`"image_file"`), or `ImageURLContentBlock` with `image_url` and `type` (`"image_url"`).
|
|
93
|
+
- `role` — `"user"` or `"assistant"`.
|
|
94
|
+
- `attachments` — optional array of objects with `file_id` (optional string) and `tools` (optional array of `CodeInterpreterTool` with `type` `"code_interpreter"` or `FileSearchTool` with `type` `"file_search"`), or null: the files attached to the message and the tools they should be added to.
|
|
95
|
+
- `metadata` — a set of up to 16 key-value pairs; keys have a maximum length of 64 characters and values a maximum length of 512 characters.
|
|
96
|
+
- `tool_resources` — optional object with `code_interpreter.file_ids` (a list of file IDs, up to 20 files) and `file_search.vector_store_ids` (up to 1 vector store attached to the thread), or the `file_search.vector_stores` helper that creates a vector store from `file_ids` and attaches it to the thread, with an optional `chunking_strategy` (`auto`, or `static` with `max_chunk_size_tokens` and `chunk_overlap_tokens`).
|
|
97
|
+
|
|
98
|
+
The response is a `Thread` object with `id`, `created_at`, `metadata`, `object` (`"thread"`), and `tool_resources` ([Create thread](https://developers.openai.com/api/reference/resources/beta/subresources/threads/methods/create)).
|
|
99
|
+
|
|
100
|
+
### Limits and truncation
|
|
101
|
+
|
|
102
|
+
There is a limit of 100,000 messages per thread. Once the size of the messages exceeds the context window of the model, the thread attempts smart truncation — the documentation describes the thread attempting to "smartly truncate" messages — before fully dropping the messages it considers the least important ([Assistants API deep dive](https://developers.openai.com/api/docs/assistants/deep-dive)).
|
|
103
|
+
|
|
104
|
+
### Thread and message endpoints
|
|
105
|
+
|
|
106
|
+
- Threads: create ([Create thread](https://developers.openai.com/api/reference/resources/beta/subresources/threads/methods/create)), retrieve ([Retrieve thread](https://developers.openai.com/api/reference/resources/beta/subresources/threads/methods/retrieve)), modify ([Modify thread](https://developers.openai.com/api/reference/resources/beta/subresources/threads/methods/update)), and delete ([Delete thread](https://developers.openai.com/api/reference/resources/beta/subresources/threads/methods/delete)).
|
|
107
|
+
- Messages: create ([Create message](https://developers.openai.com/api/reference/resources/beta/subresources/threads/subresources/messages/methods/create)), list ([List messages](https://developers.openai.com/api/reference/resources/beta/subresources/threads/subresources/messages/methods/list)), plus retrieve, update, and delete ([Messages](https://developers.openai.com/api/reference/resources/beta/subresources/threads/subresources/messages)).
|
|
108
|
+
- Runs, run steps, and tool outputs are documented under the thread runs resource ([Runs](https://developers.openai.com/api/reference/resources/beta/subresources/threads/subresources/runs)).
|
|
109
|
+
|
|
110
|
+
## API stability and availability
|
|
111
|
+
|
|
112
|
+
Mirror the documentation's own labeling when describing these surfaces:
|
|
113
|
+
|
|
114
|
+
- **Workspace agents** — research preview for ChatGPT Business, Enterprise, and Edu customers ([Building workspace agents in ChatGPT](https://developers.openai.com/cookbook/articles/chatgpt-agents-sales-meeting-prep)).
|
|
115
|
+
- **Run status polling** — in beta, opt-in via the `OpenAI-Beta: workspace_agent_runs=v1` header ([Trigger workspace agent runs](https://developers.openai.com/workspace-agents/trigger-runs)).
|
|
116
|
+
- **Threads, Messages, and Runs** — Beta Threads reference group; the Assistants API is deprecated in favor of the Responses API ([Threads](https://developers.openai.com/api/reference/resources/beta/subresources/threads), [Create thread](https://developers.openai.com/api/reference/resources/beta/subresources/threads/methods/create)).
|
|
117
|
+
- **FileObject** — `status`, `expires_at`, and `status_details` are marked deprecated on the current schema ([Files](https://developers.openai.com/api/reference/resources/files)).
|
|
118
|
+
- **Agent Builder** — deprecated and scheduled to shut down on November 30, 2026 ([Agent Builder](https://developers.openai.com/api/docs/guides/agent-builder)).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: teammate-autonomous-and-tui
|
|
3
|
+
description: Agent Teams (packages/agent-teams) — run-centric: declarative agent files, single-call DAG dispatch, bounded child-process nodes, one-way leader inbox reports, session-wide worker cap, per-spawn identity validation
|
|
4
|
+
type: project
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`packages/agent-teams` (0.3.0) is a run-centric multi-agent system: the Pi session is the leader; agents are declarative Markdown files; each run is a dependency-aware task graph dispatched in one call, where each node is a bounded child Pi process and a session-wide cap limits total workers to 8.
|
|
8
|
+
|
|
9
|
+
**Why:**
|
|
10
|
+
The teammate-registry model (runtime `teammate_register`/`create_task`/`start_task` ceremony, session-scoped identities, read receipts) was replaced after a design review. The ceremony critique: a one-off delegation cost 4 tool calls (list/register/create/start), identities were session-ephemeral so registration cost was paid per session, and both competitor packages (pi-maestro-teammate, @gcoder1991/pi-mesh) proved single-call DAG dispatch + declarative markdown agents. The later simplification removed the remaining half-channels: workers report only to the leader, upstream DAG results replace peer delivery, and live run status is not injected into every system prompt.
|
|
11
|
+
|
|
12
|
+
**How to apply:**
|
|
13
|
+
1. **Agents are declarative files** (`src/agents.ts`): frontmatter `name`/`description`/`tools`/`model` (inline `#` comments stripped), body = role prompt. Discovery precedence per name: project `.pi/agents/` > user `~/.pi/agent/agents/` > bundled `agents/`. Bundled: worker/reviewer/specialist/observer.
|
|
14
|
+
2. **Single-call DAG dispatch** (`teammate_run`): `tasks` with `id`/`agent`/`prompt`/`paths`/`access` (default read)/`dependsOn`/`model`/`timeoutMs`, plus `concurrency` (default 4), `worktree`, `background`, `timeoutMs`, `summarize`, and `summaryAgent`. Validates dup ids, unknown dependsOn, cycles, bad paths before any spawn. Root nodes start immediately; `scheduleRun` auto-starts dependents on completion; write nodes with overlapping paths are deferred across all runs in the session unless worktree-isolated (`findSharedWorkspaceWriteConflict`).
|
|
15
|
+
3. **Leader tools (3)**: `teammate_run`, `teammate_cancel` (run or `nodeId` node-level cancel; marks cancelled BEFORE terminating workers; SIGTERM→SIGKILL; console `x` reuses `cancelNodeAndTerminate`), and `teammate_retry` (retries failed/cancelled nodes without re-running completed ones). No leader message tool exists.
|
|
16
|
+
4. **Worker protocol (1 capability tool)**: worker-only `teammate_message` has only `subject`/`body`/optional `status` and always reports to the leader. Per-spawn identity: `PI_TEAMMATE_WORKER_NAME` = `runId:nodeId`, `PI_TEAMMATE_SPAWN_ID` = fresh UUID; `applyWorkerEvents` rejects stale-spawn events. Reports enter one leader inbox; there are no peer mailboxes, worker inboxes, or leader broadcasts. Upstream DAG results are injected into downstream prompts (`=== UPSTREAM HANDOFF ===`).
|
|
17
|
+
|
|
18
|
+
5. **Outcomes authoritative & non-polling leader**: workers message `team-leader` (`teammate_message`) with their deliverables upon completion, delivered automatically as a follow-up turn. The team leader does not sleep while tasks execute. One canonical terminal result per node built by the harness after child close; reported completion + SIGTERM close stays completed; failed node cancels its transitive pending dependents (`cancelBlockedDependents`) and fails the run. Worktree per node (`createWorktree(run.cwd, "${runId}-${nodeId}")`), diff captured for integration review. State snapshots are dirty-gated and worker task temp files are removed after close. Background runs deliver one run-completion follow-up; foreground gather (`background: false`) blocks the tool call (detaches after 5 min so turn is never hung).
|
|
19
|
+
6. **UI**: passive widget (display-only) + `/teammate` full-screen console (owns input via `ctx.ui.custom`, no global interception) — rows are nodes, detail = node lifecycle + leader reports, live activity streams tool calls and thinking deltas, SGR mouse-wheel scrolling. Follows `@packages/btw` style language.
|
|
20
|
+
7. **Testing**: BDD in `features/agent-teams.feature`, package tests in `tests/test_teammate_package.py` including node-eval runtime tests of state.ts/spawner.ts; typecheck via `npx tsc --noEmit --strict ... src/*.ts`.
|
|
21
|
+
|
|
22
|
+
**Related:** [[pi-cli-print-json-usage]] [[no-global-input-interception]] [[pi-kitty-csi-u-keys]] [[pi-custom-component-rendering]] [[pi-package-conventions]]
|
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Agent Teams Pi Package
|
|
2
|
+
|
|
3
|
+
Run-centric multi-agent system for Pi — declarative agents, single-call DAG dispatch, bounded child-process nodes, and one-way worker reports to the leader.
|
|
4
|
+
|
|
5
|
+
**Display Name**: Agent Teams
|
|
6
|
+
|
|
7
|
+
## What This Package Does
|
|
8
|
+
|
|
9
|
+
Agents are declarative Markdown files (bundled, user, and project scopes). A run is a dependency-aware task graph dispatched in **one call**: root nodes start immediately, concurrency is bounded, overlapping shared-workspace writes are deferred (advisory coordination across all runs in the session) unless worktree-isolated, and downstream nodes auto-start when their dependencies complete. Each node is a bounded child Pi process with per-spawn identity validation.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pi install /path/to/pi-packages/packages/agent-teams
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then run `/reload` in Pi.
|
|
18
|
+
|
|
19
|
+
## Agents are declarative files
|
|
20
|
+
|
|
21
|
+
Agent definitions are Markdown files with frontmatter; the body is the worker's role prompt.
|
|
22
|
+
|
|
23
|
+
```markdown
|
|
24
|
+
---
|
|
25
|
+
name: security-auditor
|
|
26
|
+
description: Read-only security reviewer; use after security-sensitive edits
|
|
27
|
+
tools: read,bash
|
|
28
|
+
model: provider/model # optional
|
|
29
|
+
---
|
|
30
|
+
Review the assigned scope for exploitable security problems. Do not edit files.
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Discovery precedence per name: **project `.pi/agents/` > user `~/.pi/agent/agents/` > bundled package `agents/`**. Bundled agents: `worker`, `reviewer`, `specialist`, `observer`. Available agents are dynamically injected into prompt guidance via `before_agent_start`.
|
|
34
|
+
|
|
35
|
+
## Dispatch a run in one call
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
teammate_run({
|
|
39
|
+
tasks: [
|
|
40
|
+
{ id: "inspect", agent: "reviewer", prompt: "Review the auth middleware", paths: ["packages/api/src"], access: "read" },
|
|
41
|
+
{ id: "fix", agent: "worker", prompt: "Apply the review findings", paths: ["packages/api"], access: "write", dependsOn: ["inspect"] },
|
|
42
|
+
{ id: "verify", agent: "reviewer", prompt: "Verify the fix", paths: ["packages/api"], access: "read", dependsOn: ["fix"] },
|
|
43
|
+
],
|
|
44
|
+
concurrency: 2,
|
|
45
|
+
worktree: false,
|
|
46
|
+
background: true
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- `access` defaults to `read`; declare `write` explicitly.
|
|
51
|
+
- `dependsOn` edges must form a DAG (duplicate ids, unknown references, and cycles are rejected before any worker starts).
|
|
52
|
+
- `worktree: true` runs every node in its own git worktree and captures each diff for integration review.
|
|
53
|
+
- `background` defaults to `true`: teammates always run in the background — the call returns the run id immediately, the model turn stays free, and workers report their deliverables through the worker-only `teammate_message` capability, delivered automatically as a follow-up turn. The team leader does not sleep or busy-wait while tasks execute. Pass `background=false` to block and gather inline (it detaches after 5 minutes so the turn is never hung).
|
|
54
|
+
- `timeoutMs` is a run-level hard cap: when exceeded, the run fails and live workers are terminated.
|
|
55
|
+
- A session-wide cap of 8 worker processes applies in addition to each run's `concurrency` limit.
|
|
56
|
+
- Multi-node runs append a `__summary` node by default (`summarize=false` to skip). Single-task runs stay compact unless `summarize=true`.
|
|
57
|
+
- Completing a node hands its result to pending dependents through the spawned worker prompt. Workers have no peer-message or inbound-reply path.
|
|
58
|
+
|
|
59
|
+
## Tools
|
|
60
|
+
|
|
61
|
+
| Tool | Description |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `teammate_run` | Dispatch a dependency-aware task graph in one call |
|
|
64
|
+
| `teammate_cancel` | Cancel a run, or one node (`nodeId`) while the rest continues |
|
|
65
|
+
| `teammate_retry` | Re-run only the failed/cancelled nodes of a settled run |
|
|
66
|
+
| `/teammate` | Full-screen console: run/node status, node detail, worker reports, cancel node |
|
|
67
|
+
|
|
68
|
+
Spawned workers receive one additional capability, `teammate_message`, for progress notes and final reports to the team leader.
|
|
69
|
+
|
|
70
|
+
Messaging is deliberately one-way: workers append validated reports to their own outbox, and the leader drains them into one leader inbox. There is no peer mailbox, worker inbox, leader broadcast tool, or worker-to-worker delivery path. Dependency results are delivered through the DAG prompt (`=== UPSTREAM HANDOFF ===`) when the dependent starts.
|
|
71
|
+
|
|
72
|
+
## Reliability protocol
|
|
73
|
+
|
|
74
|
+
- **Per-spawn identity validation**: every worker event must match the node's current spawn id; stale events from an older process cannot affect a newer spawn.
|
|
75
|
+
- **One-way message storage**: worker event ids and per-spawn identities are validated and deduplicated; every accepted report lands in the single leader inbox. No read flags, receipts, peer mailboxes, or leader-to-worker inboxes exist.
|
|
76
|
+
- **One canonical terminal result per node**: built by the harness from node state + captured output after the child closes; a worker's message with status alone is not final delivery.
|
|
77
|
+
- **Advisory write-conflict coordination (session-wide)**: the scheduler never starts a shared-workspace write node while another shared-workspace write node with overlapping paths is running — checked across **all runs in the session**, not just the same run. This is scheduling-level coordination, not isolation.
|
|
78
|
+
- **`access`/`paths` are metadata, not enforcement**: they drive conflict scheduling and prompts; a worker's real capabilities come from its agent definition's `tools` list. A `read` node whose agent has `write`/`bash` tools can still write. Use `worktree: true` or a restricted agent tool list when you need actual isolation.
|
|
79
|
+
- **Failure semantics**: a failed node cancels its not-yet-started transitive dependents and fails the run; other nodes finish. Cancelling a run or node reports the outcome in the tool call itself — it does not fire an extra completion follow-up.
|
|
80
|
+
|
|
81
|
+
## State and sessions
|
|
82
|
+
|
|
83
|
+
State is session-scoped and dies with the session (`~/.pi/agent/teammate/<sessionKey>/`); runs do not survive restarts. `background: true` runs notify via one follow-up; worker messages and node outcomes are recorded in the leader transcript and visible in `/teammate`. Agents, by contrast, live in files and survive across sessions — that is the persistent layer.
|
|
84
|
+
|
|
85
|
+
## Structure
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
agent-teams/
|
|
89
|
+
├── package.json — Pi package manifest
|
|
90
|
+
├── agents/ — bundled agent definitions (worker/reviewer/specialist/observer)
|
|
91
|
+
├── src/
|
|
92
|
+
│ ├── index.ts — composition root: Pi hooks and session lifecycle
|
|
93
|
+
│ ├── tools.ts — leader tool and /teammate command registration
|
|
94
|
+
│ ├── run-machine.ts — DAG scheduler, worker lifecycle, persistence, session cap
|
|
95
|
+
│ ├── ui.ts — passive widget and /teammate console
|
|
96
|
+
│ ├── worker.ts — worker identity binding and report capability
|
|
97
|
+
│ ├── guidance.ts — static leader/worker protocol guidance
|
|
98
|
+
│ ├── agents.ts — declarative agent discovery (frontmatter parsing, scope precedence)
|
|
99
|
+
│ ├── state.ts — runs/nodes state machine, leader inbox, dirty tracking
|
|
100
|
+
│ ├── spawner.ts — child Pi worker spawner (JSON-mode, usage accounting)
|
|
101
|
+
│ ├── statefile.ts — leader snapshot + worker outbox IO
|
|
102
|
+
│ ├── worktree.ts — git worktree isolation
|
|
103
|
+
│ ├── console-viewport.ts — console viewport math (wrap, scroll clamp, ranges)
|
|
104
|
+
│ └── terminal.ts — canonical per-node terminal result builder
|
|
105
|
+
├── features/ — BDD contract
|
|
106
|
+
└── tests/ — package E2E tests
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: observer
|
|
3
|
+
description: Read-only monitor of activity, logs, or processes; use when the task is to observe, watch, or report state rather than change it
|
|
4
|
+
tools: read
|
|
5
|
+
---
|
|
6
|
+
You are an observer agent. Observe and report on the assigned scope without
|
|
7
|
+
changing anything. Take the required snapshots or readings, summarize what you
|
|
8
|
+
observed, and report notable events or anomalies with timestamps and evidence
|
|
9
|
+
via teammate_message to team-leader with status="completed". You have no edit,
|
|
10
|
+
write, or command tools.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewer
|
|
3
|
+
description: Read-only code or content reviewer; use after implementation or plan changes to check for correctness, regressions, and security
|
|
4
|
+
tools: read,bash
|
|
5
|
+
---
|
|
6
|
+
You are a reviewer agent. Read the relevant code and tests first, then review
|
|
7
|
+
the assigned scope for correctness, regressions, and security problems. Do not
|
|
8
|
+
edit files. Report only confirmed findings with severity, evidence, exact
|
|
9
|
+
paths, and a minimal fix recommendation via teammate_message to team-leader with
|
|
10
|
+
status="completed". When no issue is confirmed, say so and list the checks
|
|
11
|
+
you performed.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: specialist
|
|
3
|
+
description: Read-only domain expert for a specific technical area (security, performance, data, platform); use when a task needs deep domain judgment rather than broad implementation
|
|
4
|
+
tools: read,bash
|
|
5
|
+
---
|
|
6
|
+
You are a specialist agent. Apply deep domain judgment to the assigned scope:
|
|
7
|
+
investigate, analyze, and produce findings or recommendations with evidence via
|
|
8
|
+
teammate_message to team-leader with status="completed". Do not edit files.
|
|
9
|
+
State your assumptions, the evidence you used, and the bounds of your expertise
|
|
10
|
+
for this task.
|
package/agents/worker.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: worker
|
|
3
|
+
description: General executor that implements changes and verifies them; use when a task needs code or file modifications, or when no more specific agent fits
|
|
4
|
+
tools: read,bash,edit,write
|
|
5
|
+
---
|
|
6
|
+
You are a worker agent. Implement the assigned task end to end within the
|
|
7
|
+
declared paths and access scope, then verify your own work by running the
|
|
8
|
+
relevant tests or commands. Follow the task's ordered procedure. Report what
|
|
9
|
+
you changed, what you verified, and any risks or follow-up work via
|
|
10
|
+
teammate_message to team-leader with status="completed". Do not touch
|
|
11
|
+
files outside the assigned scope.
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fradser/pi-agent-teams",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Multi-agent team system for Pi — DAG orchestration, leader inbox, and one-way worker reports",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pi-package",
|
|
7
|
+
"teammates",
|
|
8
|
+
"openai",
|
|
9
|
+
"workspace-agents",
|
|
10
|
+
"agents",
|
|
11
|
+
"multi-agent",
|
|
12
|
+
"team",
|
|
13
|
+
"orchestration"
|
|
14
|
+
],
|
|
15
|
+
"author": "Frad LEE <fradser@gmail.com>",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/FradSer/pi-packages.git"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"src",
|
|
26
|
+
"agents",
|
|
27
|
+
".memory",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
32
|
+
"@earendil-works/pi-tui": "*",
|
|
33
|
+
"typebox": "*"
|
|
34
|
+
},
|
|
35
|
+
"pi": {
|
|
36
|
+
"extensions": [
|
|
37
|
+
"./src/index.ts"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/agents.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declarative agent definitions: Markdown files with YAML-style frontmatter.
|
|
3
|
+
*
|
|
4
|
+
* Discovery scopes (later scopes override earlier ones for the same name):
|
|
5
|
+
* 1. bundled — agents shipped with this package (agents/)
|
|
6
|
+
* 2. user — ~/.pi/agent/agents/ (respects PI_CODING_AGENT_DIR)
|
|
7
|
+
* 3. project — <cwd>/.pi/agents/
|
|
8
|
+
*
|
|
9
|
+
* Frontmatter fields:
|
|
10
|
+
* name — unique agent id (required)
|
|
11
|
+
* description — routing contract: when the leader should choose this agent
|
|
12
|
+
* tools — comma-separated list or YAML list of Pi tool ids
|
|
13
|
+
* model — optional provider/model pin
|
|
14
|
+
* The Markdown body is the worker's role prompt.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import * as fs from "node:fs";
|
|
18
|
+
import * as os from "node:os";
|
|
19
|
+
import * as path from "node:path";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
|
|
22
|
+
export interface AgentDefinition {
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
tools: string[];
|
|
26
|
+
model?: string;
|
|
27
|
+
/** The Markdown body, trimmed; used as the worker role prompt. */
|
|
28
|
+
prompt: string;
|
|
29
|
+
/** Scope that supplied this definition ("bundled" | "user" | "project"). */
|
|
30
|
+
scope: "bundled" | "user" | "project";
|
|
31
|
+
/** Absolute path of the definition file. */
|
|
32
|
+
source: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const BUNDLED_AGENTS_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "agents");
|
|
36
|
+
|
|
37
|
+
function agentsDir(scope: "user" | "project", cwd?: string): string {
|
|
38
|
+
if (scope === "user") {
|
|
39
|
+
const base = process.env.PI_CODING_AGENT_DIR || path.join(os.homedir(), ".pi", "agent");
|
|
40
|
+
return path.join(base, "agents");
|
|
41
|
+
}
|
|
42
|
+
return path.join(cwd || process.cwd(), ".pi", "agents");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function parseFrontmatter(raw: string): { fields: Record<string, string | string[]>; body: string } {
|
|
46
|
+
const fields: Record<string, string | string[]> = {};
|
|
47
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(raw);
|
|
48
|
+
if (!match) return { fields, body: raw.trim() };
|
|
49
|
+
for (const line of match[1].split("\n")) {
|
|
50
|
+
const separator = line.indexOf(":");
|
|
51
|
+
if (separator <= 0) continue;
|
|
52
|
+
const key = line.slice(0, separator).trim();
|
|
53
|
+
// Strip inline YAML comments (# ...) and surrounding whitespace/quotes.
|
|
54
|
+
let value = line.slice(separator + 1).replace(/\s+#.*$/, "").trim();
|
|
55
|
+
if (key === "tools") {
|
|
56
|
+
const tools = value
|
|
57
|
+
.replace(/^\[|\]$/g, "")
|
|
58
|
+
.split(",")
|
|
59
|
+
.map((tool) => tool.trim().replace(/^["']|["']$/g, ""))
|
|
60
|
+
.filter(Boolean);
|
|
61
|
+
fields.tools = tools;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
fields[key] = value.replace(/^["']|["']$/g, "");
|
|
65
|
+
}
|
|
66
|
+
return { fields, body: match[2].trim() };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function loadDir(scope: "bundled" | "user" | "project", dir: string, agents: Map<string, AgentDefinition>): void {
|
|
70
|
+
let entries: fs.Dirent[];
|
|
71
|
+
try {
|
|
72
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
73
|
+
} catch {
|
|
74
|
+
return; // A missing agents directory is not an error.
|
|
75
|
+
}
|
|
76
|
+
for (const entry of entries) {
|
|
77
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
78
|
+
const source = path.join(dir, entry.name);
|
|
79
|
+
let raw: string;
|
|
80
|
+
try {
|
|
81
|
+
raw = fs.readFileSync(source, "utf8");
|
|
82
|
+
} catch {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const { fields, body } = parseFrontmatter(raw);
|
|
86
|
+
const name = typeof fields.name === "string" ? fields.name : entry.name.replace(/\.md$/, "");
|
|
87
|
+
if (!name || !body) continue;
|
|
88
|
+
const tools = Array.isArray(fields.tools) ? fields.tools : [];
|
|
89
|
+
const model = typeof fields.model === "string" && fields.model ? fields.model : undefined;
|
|
90
|
+
agents.set(name, {
|
|
91
|
+
name,
|
|
92
|
+
description: typeof fields.description === "string" ? fields.description : "",
|
|
93
|
+
tools,
|
|
94
|
+
model,
|
|
95
|
+
prompt: body,
|
|
96
|
+
scope,
|
|
97
|
+
source,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Resolve all agent definitions visible from the given cwd, with later scopes
|
|
104
|
+
* overriding earlier ones per name: project > user > bundled.
|
|
105
|
+
*/
|
|
106
|
+
export function discoverAgents(cwd?: string): Map<string, AgentDefinition> {
|
|
107
|
+
const agents = new Map<string, AgentDefinition>();
|
|
108
|
+
loadDir("bundled", BUNDLED_AGENTS_DIR, agents);
|
|
109
|
+
loadDir("user", agentsDir("user", cwd), agents);
|
|
110
|
+
loadDir("project", agentsDir("project", cwd), agents);
|
|
111
|
+
return agents;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Resolve one agent by name, or undefined when no scope defines it. */
|
|
115
|
+
export function resolveAgent(name: string, cwd?: string): AgentDefinition | undefined {
|
|
116
|
+
return discoverAgents(cwd).get(name);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** True when the agent name is defined in any scope. */
|
|
120
|
+
export function hasAgent(name: string, cwd?: string): boolean {
|
|
121
|
+
return resolveAgent(name, cwd) !== undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Format discovered agents as Markdown for prompt injection in before_agent_start.
|
|
126
|
+
*/
|
|
127
|
+
export function formatAgentGuidance(cwd?: string): string {
|
|
128
|
+
const agents = discoverAgents(cwd);
|
|
129
|
+
if (agents.size === 0) return "(none found in bundled, user, or project scopes)";
|
|
130
|
+
const lines: string[] = [];
|
|
131
|
+
for (const agent of agents.values()) {
|
|
132
|
+
const model = agent.model ? ` | Model: ${agent.model}` : "";
|
|
133
|
+
lines.push(`- **${agent.name}** (${agent.scope})`);
|
|
134
|
+
if (agent.description) lines.push(` ${agent.description}`);
|
|
135
|
+
lines.push(` Tools: ${agent.tools.join(", ") || "(role defaults)"}${model}`);
|
|
136
|
+
}
|
|
137
|
+
return lines.join("\n");
|
|
138
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
2
|
+
|
|
3
|
+
/** Leave room for the console borders, title, spacing, and footer. */
|
|
4
|
+
export function maxConsoleBody(rows: number): number {
|
|
5
|
+
return Math.max(3, rows - 5);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Wrap source records before calculating scroll positions. */
|
|
9
|
+
export function wrapConsoleDetail(lines: string[], width: number): string[] {
|
|
10
|
+
const contentWidth = Math.max(10, width - 4);
|
|
11
|
+
return lines.flatMap((line) => {
|
|
12
|
+
const wrapped = wrapTextWithAnsi(line, contentWidth);
|
|
13
|
+
return wrapped.length > 0 ? wrapped : [""];
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function clampConsoleScroll(offset: number, total: number, viewport: number): number {
|
|
18
|
+
return Math.max(0, Math.min(Math.max(0, total - viewport), offset));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function scrollConsoleDetail(offset: number, delta: number, total: number, viewport: number): number {
|
|
22
|
+
return clampConsoleScroll(offset + delta, total, viewport);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function consoleScrollRange(offset: number, total: number, viewport: number): string {
|
|
26
|
+
if (total === 0) return "no activity";
|
|
27
|
+
const start = clampConsoleScroll(offset, total, viewport);
|
|
28
|
+
const end = Math.min(total, start + viewport);
|
|
29
|
+
return total <= viewport ? `${total} lines` : `${start + 1}–${end}/${total}`;
|
|
30
|
+
}
|
package/src/guidance.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { formatAgentGuidance } from "./agents";
|
|
2
|
+
|
|
3
|
+
export const WORKER_GUIDANCE = `
|
|
4
|
+
## Spawned Teammate Protocol
|
|
5
|
+
|
|
6
|
+
You are a teammate, not the team leader. Work only on the task bound to
|
|
7
|
+
this process and its declared access/paths. Communication is one-way to the
|
|
8
|
+
team leader:
|
|
9
|
+
|
|
10
|
+
- Report: call teammate_message for plans, progress, and blockers without a
|
|
11
|
+
terminal status. For the final deliverable, use status="completed"; for a
|
|
12
|
+
blocked or failed task, use status="failed" and explain the error. The
|
|
13
|
+
final report MUST contain the full deliverable.
|
|
14
|
+
- There is no peer or leader-to-worker message channel. DAG upstream results
|
|
15
|
+
are already injected into your task prompt. Make decisions within the
|
|
16
|
+
assigned task and report blockers instead of waiting for a reply.
|
|
17
|
+
|
|
18
|
+
Do not use leader coordination tools, claim new tasks, or overwrite files
|
|
19
|
+
outside your assigned scope.
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
export function buildTeamLeaderGuidance(cwd?: string): string {
|
|
23
|
+
const agents = formatAgentGuidance(cwd);
|
|
24
|
+
return `
|
|
25
|
+
## Agent Teams Orchestration
|
|
26
|
+
|
|
27
|
+
You are the team leader: the current Pi session owns decomposition,
|
|
28
|
+
delegation, synchronization, and the final user-facing answer. Workers are
|
|
29
|
+
isolated child processes; they do not see this conversation unless you put the
|
|
30
|
+
needed context in their task.
|
|
31
|
+
|
|
32
|
+
### Agents are declarative files
|
|
33
|
+
|
|
34
|
+
Agents live in Markdown files with frontmatter (name, description, tools,
|
|
35
|
+
optional model); the body is the role prompt. Discovery precedence per name:
|
|
36
|
+
project .pi/agents > user ~/.pi/agent/agents > bundled package agents.
|
|
37
|
+
Prefer a bundled or existing agent; add a project agent under .pi/agents
|
|
38
|
+
only when its role materially differs. Never register runtime identities.
|
|
39
|
+
|
|
40
|
+
Available agents:
|
|
41
|
+
${agents}
|
|
42
|
+
|
|
43
|
+
### Dispatch a run in one call
|
|
44
|
+
|
|
45
|
+
Use teammate_run with a tasks array: each task has id, agent, prompt, paths,
|
|
46
|
+
access (read default, write explicit), optional dependsOn, model, and
|
|
47
|
+
timeoutMs. The scheduler starts root nodes immediately, bounds concurrency,
|
|
48
|
+
defers overlapping shared-workspace writes — advisory coordination across all
|
|
49
|
+
runs, not file-access isolation — unless worktree=true, and auto-starts
|
|
50
|
+
downstream nodes when their dependencies complete. access and paths coordinate
|
|
51
|
+
scheduling only; a worker's real capabilities come from its agent definition's
|
|
52
|
+
tools list.
|
|
53
|
+
|
|
54
|
+
Teammates run in the background by default: the call returns the run id
|
|
55
|
+
immediately, and the main session is free. When a teammate finishes, it sends
|
|
56
|
+
its final deliverable to team-leader through its append-only outbox. The
|
|
57
|
+
harness delivers the run completion automatically as a follow-up turn. Pass
|
|
58
|
+
background=false only when you strictly need inline synchronous blocking (it
|
|
59
|
+
detaches after 5 minutes so the turn is never hung). A session-wide cap of 8
|
|
60
|
+
worker processes applies in addition to each run's concurrency. Multi-node runs
|
|
61
|
+
append a __summary node by default; pass summarize=false to skip it.
|
|
62
|
+
|
|
63
|
+
### DO NOT poll status
|
|
64
|
+
|
|
65
|
+
- When tasks run in the background, do not run sleep commands, and do not
|
|
66
|
+
execute repetitive read/grep busywork to pass time.
|
|
67
|
+
- Teammates will report their final deliverables and the harness will deliver
|
|
68
|
+
the completion follow-up automatically.
|
|
69
|
+
- Once you dispatch background tasks, if you have no other independent
|
|
70
|
+
foreground work, end your turn immediately and wait for the follow-up.
|
|
71
|
+
- teammate_cancel stops a run or one node; teammate_retry re-runs only failed
|
|
72
|
+
or cancelled nodes of a settled run.
|
|
73
|
+
- After a run completes and the message is delivered, inspect the artifacts
|
|
74
|
+
yourself: a worker's claim is not proof until its deliverable and tests are
|
|
75
|
+
checked. Treat failed, timed-out, cancelled, and missing nodes explicitly.
|
|
76
|
+
`;
|
|
77
|
+
}
|