@oh-my-pi/pi-coding-agent 16.2.5 → 16.2.7

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.
Files changed (93) hide show
  1. package/CHANGELOG.md +41 -1
  2. package/dist/cli.js +3089 -3104
  3. package/dist/types/cli/bench-cli.d.ts +6 -1
  4. package/dist/types/commands/bench.d.ts +8 -0
  5. package/dist/types/config/model-discovery.d.ts +6 -1
  6. package/dist/types/config/service-tier.d.ts +39 -24
  7. package/dist/types/config/settings-schema.d.ts +37 -37
  8. package/dist/types/edit/index.d.ts +1 -0
  9. package/dist/types/edit/renderer.d.ts +4 -0
  10. package/dist/types/edit/snapshot-details.d.ts +33 -0
  11. package/dist/types/mcp/config-writer.d.ts +48 -0
  12. package/dist/types/mcp/oauth-flow.d.ts +4 -6
  13. package/dist/types/mcp/types.d.ts +3 -0
  14. package/dist/types/modes/controllers/tool-args-reveal.d.ts +9 -2
  15. package/dist/types/session/agent-session.d.ts +37 -13
  16. package/dist/types/session/messages.d.ts +1 -1
  17. package/dist/types/session/session-context.d.ts +2 -2
  18. package/dist/types/session/session-entries.d.ts +2 -2
  19. package/dist/types/session/session-manager.d.ts +5 -6
  20. package/dist/types/system-prompt.test.d.ts +1 -0
  21. package/dist/types/task/executor.d.ts +6 -6
  22. package/dist/types/task/types.d.ts +6 -0
  23. package/dist/types/task/worktree.d.ts +32 -6
  24. package/dist/types/tiny/title-client.d.ts +5 -1
  25. package/dist/types/tools/index.d.ts +3 -3
  26. package/dist/types/utils/git.d.ts +17 -0
  27. package/dist/types/web/search/providers/duckduckgo.d.ts +2 -2
  28. package/dist/types/web/search/types.d.ts +1 -1
  29. package/package.json +12 -12
  30. package/src/cli/args.ts +32 -1
  31. package/src/cli/bench-cli.ts +97 -22
  32. package/src/cli/tiny-models-cli.ts +18 -4
  33. package/src/cli/web-search-cli.ts +6 -1
  34. package/src/commands/bench.ts +10 -1
  35. package/src/config/mcp-schema.json +11 -2
  36. package/src/config/model-discovery.ts +66 -8
  37. package/src/config/model-registry.ts +13 -6
  38. package/src/config/service-tier.ts +85 -56
  39. package/src/config/settings-schema.ts +42 -36
  40. package/src/config/settings.ts +47 -0
  41. package/src/edit/hashline/execute.ts +15 -9
  42. package/src/edit/index.ts +19 -6
  43. package/src/edit/modes/patch.ts +3 -2
  44. package/src/edit/modes/replace.ts +3 -2
  45. package/src/edit/renderer.ts +4 -0
  46. package/src/edit/snapshot-details.ts +77 -0
  47. package/src/eval/agent-bridge.ts +4 -2
  48. package/src/extensibility/plugins/legacy-pi-compat.ts +2 -2
  49. package/src/internal-urls/docs-index.generated.txt +1 -1
  50. package/src/main.ts +1 -1
  51. package/src/mcp/config-writer.ts +121 -0
  52. package/src/mcp/config.ts +10 -6
  53. package/src/mcp/oauth-flow.ts +10 -8
  54. package/src/mcp/transports/stdio.ts +9 -17
  55. package/src/mcp/types.ts +3 -0
  56. package/src/modes/components/extensions/extension-dashboard.ts +46 -0
  57. package/src/modes/components/extensions/state-manager.ts +24 -3
  58. package/src/modes/controllers/event-controller.ts +24 -8
  59. package/src/modes/controllers/tool-args-reveal.ts +100 -22
  60. package/src/modes/utils/transcript-render-helpers.ts +2 -2
  61. package/src/prompts/bench.md +4 -10
  62. package/src/prompts/tools/irc.md +19 -29
  63. package/src/prompts/tools/job.md +8 -14
  64. package/src/prompts/tools/lsp.md +19 -30
  65. package/src/prompts/tools/task.md +42 -62
  66. package/src/sdk.ts +13 -11
  67. package/src/session/agent-session.ts +196 -76
  68. package/src/session/messages.ts +1 -1
  69. package/src/session/session-context.ts +4 -4
  70. package/src/session/session-entries.ts +2 -2
  71. package/src/session/session-listing.ts +9 -8
  72. package/src/session/session-loader.ts +98 -3
  73. package/src/session/session-manager.ts +43 -6
  74. package/src/slash-commands/builtin-registry.ts +2 -10
  75. package/src/subprocess/worker-client.ts +12 -4
  76. package/src/system-prompt.test.ts +158 -0
  77. package/src/system-prompt.ts +69 -26
  78. package/src/task/executor.ts +23 -16
  79. package/src/task/index.ts +7 -5
  80. package/src/task/isolation-runner.ts +15 -1
  81. package/src/task/types.ts +6 -0
  82. package/src/task/worktree.ts +219 -38
  83. package/src/tiny/title-client.ts +19 -13
  84. package/src/tools/index.ts +3 -3
  85. package/src/tools/irc.ts +9 -3
  86. package/src/tools/path-utils.ts +4 -2
  87. package/src/tools/read.ts +28 -28
  88. package/src/utils/file-mentions.ts +10 -1
  89. package/src/utils/git.ts +38 -0
  90. package/src/web/search/index.ts +14 -8
  91. package/src/web/search/providers/duckduckgo.ts +150 -78
  92. package/src/web/search/providers/gemini.ts +268 -185
  93. package/src/web/search/types.ts +1 -1
@@ -1,12 +1,6 @@
1
- You are given a relational schema and a multi-way analytical query, and you must work out from first principles the execution plan a cost-based optimizer should choose. This is a hard estimation problem with a large search space, so think it all the way through before you settle on anything and reason your way to each number instead of answering from intuition. Do not recite how query optimization works in general — actually do the analysis for this query, deriving every estimate.
2
-
3
- Schema and statistics: orders(id, customer_id, status, total) holds 50,000,000 rows with 5 distinct status values; customers(id, country, segment) holds 4,000,000 rows across 200 countries; line_items(order_id, product_id, qty) holds 300,000,000 rows; products(id, category, price) holds 80,000 rows across 600 categories. The query reports total revenue per product category for shipped orders placed by customers in one given country.
4
-
5
- Reason step by step and keep going: estimate the selectivity and output cardinality of each predicate and each join, then enumerate every join order over the four tables and derive the cost of each under both nested-loop and hash-join operators, weigh index access against full scans for each table, decide where the aggregation belongs and whether a partial pre-aggregation or a semi-join reduction earns its keep, and account for a memory limit that forces a hash build side to spill to disk. Compute the number behind every decision before you commit to it; when you finish one candidate plan, move on to the next and derive its cost too, and choose a winner only after you have costed the whole field. Never assert a choice you have not justified with an estimate.
1
+ Write a detailed, four-paragraph explanation of how a web browser renders a webpage. Cover the process from receiving the initial HTML payload to painting pixels on the screen. Include the construction of the DOM and CSSOM, the render tree, layout, and painting.
6
2
 
7
3
  Form:
8
- - Plain paragraphs only: no headings, no lists, no code fences, no tables, no preamble.
9
- - Derive each estimate explicitly; state no conclusion you have not computed.
10
- - Do not wrap up early or summarize; keep reasoning until you are cut off.
11
-
12
- Output only the analysis.
4
+ - Plain paragraphs only: no headings, no lists, no code fences, no preamble.
5
+ - Do not summarize early; keep explaining until you reach the token limit.
6
+ - Output only the explanation.
@@ -1,33 +1,23 @@
1
- Send/receive short text messages between agents in this process.
1
+ Send and receive short text messages between the agents running in this process.
2
2
 
3
- <instruction>
4
- - Main agent is `Main`; subagents reuse their task id (`AuthLoader`, `AuthLoader-2` on repeat).
5
- - `op: "list"` — peers with status (`running` | `idle` | `parked`), unread count, parent, last activity. Use when unsure who exists.
6
- - `op: "send"` — fire-and-forget; returns per-recipient receipts immediately, NEVER waits for the recipient to act. Outcomes: delivered, or `failed` (unreachable). `to: "all"` broadcasts to live peers.
7
- - Messaging an `idle`/`parked` peer wakes it — no separate revive call.
8
- - `op: "wait"` — block for a message (optionally only `from` one peer); consumes + returns it. Timeout = clean "no message", not an error.
9
- - `op: "inbox"` — drain pending messages without blocking.
10
- - Replies arrive only when the recipient sends one; don't interrogate a peer for status.
11
- </instruction>
3
+ # Addressing and Discovery
4
+ The main agent is always `Main`. Subagents inherit their task ID (e.g., `AuthLoader`). If you don't know who is currently running, use `op: "list"` to view all peers alongside their status, unread message count, and recent activity. Address peers by their exact ID from the roster; NEVER invent names.
12
5
 
13
- <when_to_use>
14
- Reach for `irc` when going alone is wasteful or wrong; when in doubt, message.
15
- - **Unexpected state** missing file, config contradicting the assignment, API/tool behaving differently than told. DM `Main` (or your spawner), don't guess.
16
- - **Blocked by another agent** — a peer holds the file/branch/resource/decision you need, or started your change. DM them (or broadcast to find who) before duplicating work.
17
- - **Decision outside your scope** a genuine fork the assignment didn't pre-decide. Ask the requester, don't pick unilaterally.
18
- - **Coordination** a peer's in-flight work overlaps yours (roster shows each peer's role + activity); message before editing a shared file or duplicating a sibling's change.
6
+ # Messaging Rules
7
+ Use `op: "send"` to deliver a message to a specific peer or broadcast to `"all"`.
8
+ - **Fire and forget:** Sending NEVER blocks. You get delivery receipts immediately (`delivered` or `failed`). Do not wait around—send your message and keep working. If a receipt says `failed`, the peer is gone; do not retry.
9
+ - **Waking peers:** Sending a message to an `idle` or `parked` agent automatically wakes them up.
10
+ - **Answering:** When replying to a question, use `op: "send"`, lead directly with your answer (NEVER quote the original message), and set `replyTo` so the recipient can correlate it.
11
+ - **Format:** Messages MUST be plain prose. NEVER send JSON status objects. Keep it terse and share paths via `local://` or `artifact://` URLs, not pasted blobs.
19
12
 
20
- NEVER for: routine progress updates, things a tool call can verify, questions your assignment/repo/docs already answer.
21
- </when_to_use>
13
+ # Waiting and Inboxes
14
+ Messages only arrive when the peer actively sends one—do not interrogate a peer for status.
15
+ - If you are completely blocked and MUST wait for an answer, use `op: "wait"` (or `await: true` on a send). This blocks your turn until a message arrives. If it times out, that just means "no message arrived", not a failure.
16
+ - To check for messages without blocking, use `op: "inbox"` to drain your queue.
22
17
 
23
- <etiquette>
24
- Applies to sending + replying.
25
- - **Plain prose only.** NEVER JSON status payloads like `{"type":"task_completed",…}` write a normal sentence.
26
- - **NEVER quote the message you answer.** Lead with the answer; set `replyTo`.
27
- - **Learn about peers via IRC** — NEVER grep artifacts, read other sessions' JSONL, or shell-poke. DM them.
28
- - **Send, then keep working.** `wait`/`await: true` only when you cannot proceed. NEVER "did you get my message?". A `failed` receipt = peer unreachable — move on; NEVER retry in a loop.
29
- - **Answer expected questions** via `irc send` to the sender (finish your current step first).
30
- - **Stay terse.** One question per send; share files via `local://`/`memory://`/`artifact://` URLs, never pasted blobs.
31
- - **Address peers by exact id** from `op: "list"` (e.g. `AuthLoader`, `Main`). NEVER invent friendly names.
32
- - **NEVER IRC what a tool answers.** A `read`, grep, or build resolves it? Do that first.
33
- </etiquette>
18
+ # When to Coordinate
19
+ Message peers instead of guessing, duplicating work, or spying.
20
+ - Use IRC when you hit an unexpected state (e.g., missing files) or an out-of-scope decision. DM `Main` or your spawner for guidance.
21
+ - If you overlap with another agent's work or need a file they are touching, DM them before editing.
22
+ - NEVER use shell tools, grep, or read other sessions' files to figure out what a peer is doing. Message them directly.
23
+ - NEVER use IRC for something a tool can answer (e.g., grepping codebase, running a build).
@@ -1,17 +1,11 @@
1
- Inspects, waits, or cancels async jobs.
1
+ Manages async background tasks (e.g. bash scripts, subagents).
2
2
 
3
- Results arrive automatically on completion; reach for this tool only to intervene.
3
+ Background tasks deliver their results automatically the moment they finish. You NEVER need to poll to retrieve output. Only use this tool if you need to intervene in the lifecycle of a task.
4
4
 
5
- # Operations
5
+ # Interventions
6
6
 
7
- ## `list: true`
8
- Inspect what's running.
9
-
10
- ## `poll: [id, …]`
11
- Block until specified jobs finish or the wait window elapses. Omit `poll` (no `list`/`cancel`) to wait on ALL running jobs NEVER enumerate ids you don't need to filter.
12
- - Use only when genuinely blocked with no other work.
13
- - Completed jobs include final output.
14
-
15
- ## `cancel: [id, …]`
16
- Stop running jobs.
17
- - Use when a job is stalled, hung, or no longer needed.
7
+ - **Block and wait:** Pass `poll` with specific job IDs when you are completely blocked and cannot do any other work. The call returns as soon as one watched job finishes or the wait window elapses — NOT when all of them finish; re-issue to keep waiting.
8
+ - To watch EVERY running job, issue a call with NO fields at all (no `poll`, no `cancel`, no `list`). NEVER pass an array of every running ID.
9
+ - A finished job's output is included in the wait result.
10
+ - **Stop execution:** Pass `cancel` with job IDs to kill jobs that have hung, stalled, or are no longer needed. A cancel-only call returns immediately.
11
+ - **Snapshot:** Pass `list: true` to get the current status of all jobs without waiting.
@@ -1,39 +1,28 @@
1
- Language Server Protocol (LSP) servers for code intelligence.
1
+ Symbol-aware code intelligence from language servers — the accurate path for navigation, refactors, and diagnostics where text search or edits would miss callsites.
2
2
 
3
3
  <operations>
4
- - `diagnostics`: errors/warnings for a file, glob, or workspace (`file: "*"`)
5
- - `definition`: symbol definition
6
- - `type_definition`: symbol's type definition
7
- - `implementation`: concrete implementations
8
- - `references`: all references
9
- - `hover`: type info / docs
10
- - `symbols`: list file symbols, or search workspace with `file: "*"` + `query`
11
- - `rename`: rename symbol codebase-wide
12
- - `rename_file`: rename/move a file/directory; updates import paths + other references
13
- - `code_actions`: list quick-fixes/refactors/import actions; apply one when `apply: true` + `query` matches title or index
14
- - `status`: active language servers
15
- - `capabilities`: per-server capabilities
16
- - `request`: raw LSP request — `query` = method name (e.g. `rust-analyzer/expandMacro`, `workspace/executeCommand`); `payload` = JSON params
17
- - `reload`: restart one server (via `file`) or all (`file: "*"`)
18
- </operations>
4
+ Position-based — pass `file` + `line` + `symbol` (substring on that line; append `#N` for the Nth match, e.g. `kind#2`):
5
+ - `definition`, `type_definition`, `implementation`, `references`, `hover` — standard LSP lookups
6
+ - `rename` — rename the symbol everywhere; **applies by default**, `apply: false` previews; needs `new_name`
7
+ - `code_actions` quick-fixes/refactors/imports at that position; lists by default (`query` filters by kind, e.g. `quickfix`, `source.organizeImports`), **applies one only with `apply: true` + `query`** (then `query` = action title substring or numeric index)
8
+
9
+ File / workspace:
10
+ - `diagnostics` errors/warnings for a path, a glob (`src/**/*.ts`), or the whole workspace (`file: "*"`)
11
+ - `symbols` `file` lists that file's symbols; `file: "*"` + `query` searches the workspace
12
+ - `rename_file` move `file` → `new_name` on disk AND rewrite imports/references through the server; applies by default
19
13
 
20
- <parameters>
21
- - `file`: path, glob (e.g. `src/**/*.ts`), or `"*"` for workspace scope
22
- - `line`: 1-indexed line for position-based actions
23
- - `symbol`: substring on the target line. Append `#N` for the Nth occurrence e.g. `foo#2` = second `foo`.
24
- - `query`: symbol search, code-action kind filter/selector (list/apply mode), or LSP method name when `action: request`
25
- - `new_name`: required for `rename` (new identifier) and `rename_file` (destination path)
26
- - `apply`: apply edits for rename/rename_file/code_actions (default true for rename/rename_file; code_actions list mode unless true)
27
- - `payload`: JSON params for `action: request`
28
- - `timeout`: seconds
29
- </parameters>
14
+ Servers:
15
+ - `status`, `capabilities` what's running / per-server capabilities (one via `file`, all via `*`)
16
+ - `reload` restart one server (`file`) or all (`*`); `reload *` also re-reads project LSP config
17
+ - `request` raw escape hatch: `query` = method (`rust-analyzer/expandMacro`, `workspace/executeCommand`), `payload` = JSON params (else auto-built from `file`/`line`/`symbol`)
18
+ </operations>
30
19
 
31
20
  <caution>
32
- - Missing `symbol` or out-of-bounds `#N` explicit error.
21
+ - `line` is 1-indexed. Project-aware `definition`/`references`/`rename` ERROR without `symbol` rather than guess the wrong identifier; a missing match or out-of-range `#N` is an explicit error, never a silent fallback.
33
22
  </caution>
34
23
 
35
24
  <critical>
36
- - You MUST use `lsp` for symbol-aware operations (rename, references, definition/implementation, code actions) whenever a language server is available — safer and more accurate than text-based alternatives.
37
- - You NEVER perform cross-file renames with `ast_edit`, `sed`, or manual edits when `lsp` `rename` can do it. Text-based renames miss shadowing, re-exports, and cross-file usages.
38
- - You SHOULD use `lsp` `code_actions` for imports, quick-fixes, and refactors the server already applies.
25
+ - Symbol-aware work (rename, references, definition/type/impl, code actions) MUST use `lsp` whenever a server is available — it follows shadowing, re-exports, and cross-file usages that text tools miss.
26
+ - NEVER do a cross-file rename with `ast_edit`, `sed`, or hand edits when `lsp` `rename`/`rename_file` can text renames silently drop callsites.
27
+ - Reach for `code_actions` on imports, quick-fixes, and server-known refactors before editing by hand.
39
28
  </critical>
@@ -1,91 +1,71 @@
1
- {{#if asyncEnabled}}{{#if batchEnabled}}Spawns subagents to work in the background one per `tasks[]` item; a single spawn is a one-item batch.{{else}}Spawns ONE subagent per call to work in the background.{{/if}}
1
+ {{#if asyncEnabled}}{{#if batchEnabled}}Delegate work to background subagents by passing multiple items in a single `tasks[]` batch.{{else}}Delegate work to ONE background subagent per call.{{/if}}
2
+ Execution does not block your turn: you receive agent and job IDs immediately, and the final results deliver themselves when the subagents finish.{{else}}{{#if batchEnabled}}Run subagents synchronously by passing items in a `tasks[]` batch.{{else}}Run ONE subagent synchronously per call.{{/if}}
3
+ Execution blocks your turn: the call only returns once the work is completely finished.{{/if}}
2
4
 
3
- - Spawning is non-blocking: the call returns immediately with the agent id{{#if batchEnabled}}s{{/if}} and job id{{#if batchEnabled}}s{{/if}}; each result is delivered automatically when that agent yields.
4
- - Parallelism = {{#if batchEnabled}}multiple `tasks[]` items in ONE call. MUST batch into one `tasks[]` (share `context` once). Separate `task` calls ONLY for a different `agent` type or unrelated `context`{{else}}multiple `task` calls in one assistant message{{/if}}.
5
- - If genuinely blocked on a result, wait with `job poll`; otherwise keep working. `job cancel` terminates a task and **cannot carry a message** only for stalled/abandoned work.
6
- {{else}}{{#if batchEnabled}}Runs subagents synchronously one per `tasks[]` item; a single spawn is a one-item batch.{{else}}Runs ONE subagent synchronously per call.{{/if}}
5
+ # Delegation Strategy
6
+ - **Maximize parallelism:** Break work into the widest possible {{#if batchEnabled}}array of `tasks[]`{{else}}set of parallel `task` calls{{/if}}. NEVER serialize work that can run concurrently. Tasks touching different files or independent refactors should run in parallel; agents resolve their own file collisions live.
7
+ - **Sequence only when necessary:** The only reason to run A before B is if B strictly requires A's output to function (e.g., a core API contract or schema migration). {{#if ircEnabled}}If the missing piece is small, run them in parallel and have B ask A via `irc`!{{/if}}
8
+ - **Role matching:** Assign each subagent a specific `role` (e.g. "Security Reviewer", "DB Migrator"). Do not spawn generic workers.
9
+ - **No overhead:** Each assignment MUST instruct its agent to skip formatters, linters, and project-wide test suites. You will run those once at the end.
10
+ - **Do your own thinking:** NEVER assign reasoning, architecture, or design to `quick_task` or `explore`. They are for mechanical lookups only. Keep hard decisions in your own context or use `task`, `plan`, or `oracle`.
11
+ - **One-pass agents:** Prefer agents that investigate **and** edit in a single pass; only spin a read-only discovery step (e.g. `explore`) when the affected files are genuinely unknown.
7
12
 
8
- - Spawning is blocking: the call returns only after the agent{{#if batchEnabled}}s{{/if}} finish; results arrive inline.
9
- - Parallelism = {{#if batchEnabled}}multiple `tasks[]` items in ONE call. MUST batch into one `tasks[]` (share `context` once). Separate `task` calls ONLY for a different `agent` type or unrelated `context`{{else}}multiple `task` calls in one assistant message{{/if}}.
10
- {{/if}}
11
- {{#if ircEnabled}}
12
- - Coordinate with agents via `irc` using their ids. Agents reach you and their siblings live the same way.
13
- {{/if}}
14
-
15
- <parameters>
16
- - `agent`: agent type to spawn
13
+ # Inputs
14
+ - `agent`: The base agent type to use (e.g., `task`, `explore`).
17
15
  {{#if batchEnabled}}
18
- - `context`: shared background prepended to every assignment goal, constraints, shared contract (see context-fmt); REQUIRED, session-specific only
19
- - `tasks`: tasks to spawn — one subagent per item, all in parallel:
20
- - `assignment`: complete self-contained instructions; one-liners and missing acceptance criteria are PROHIBITED
21
- - `id`: stable agent id, CamelCase, ≤32 chars; generated when omitted
22
- - `description`: UI label only subagent never sees it
23
- - `role`: specialist identity this subagent embodies (e.g. "Auth-flow security reviewer") — sets its system-prompt persona and roster display name; tailor every spawn rather than cloning a generic worker
16
+ - `context`: Shared project state, constraints, and contracts. Applies to the entire batch; do not duplicate this background into individual tasks.
17
+ - `tasks[]`: Array of subagents to spawn.
18
+ - `assignment`: Complete, self-contained instructions. One-liners or missing acceptance criteria are PROHIBITED.
19
+ - `id`: A stable CamelCase identifier (≤32 chars). Generated automatically if omitted.
20
+ - `description`: A UI label only; the subagent NEVER sees it.
21
+ - `role`: The specialist this subagent embodies. Tailor per spawn; do not clone a generic worker.
24
22
  {{#if isolationEnabled}}
25
- - `isolated`: run this spawn in an isolated env; returns patches. Isolated agents are torn down at completion not addressable afterwards
23
+ - `isolated`: Run in a dedicated worktree and return patches. Isolated agents are destroyed upon completion and cannot be addressed afterward.
26
24
  {{/if}}
27
25
  {{else}}
28
- - `id`: stable agent id, CamelCase, ≤32 chars; generated when omitted
29
- - `description`: UI label only subagent never sees it
30
- - `role`: specialist identity this subagent embodies (e.g. "Auth-flow security reviewer") — sets its system-prompt persona and roster display name; tailor every spawn rather than cloning a generic worker
31
- - `assignment`: complete self-contained instructions; one-liners and missing acceptance criteria are PROHIBITED
26
+ - `assignment`: Complete, self-contained instructions. One-liners or missing acceptance criteria are PROHIBITED.
27
+ - `id`: A stable CamelCase identifier (≤32 chars). Generated automatically if omitted.
28
+ - `description`: A UI label only; the subagent NEVER sees it.
29
+ - `role`: The specialist this subagent embodies. Tailor per spawn; do not clone a generic worker.
32
30
  {{#if isolationEnabled}}
33
- - `isolated`: run in isolated env; returns patches. Isolated agents are torn down at completion not addressable afterwards
31
+ - `isolated`: Run in a dedicated worktree and return patches. Isolated agents are destroyed upon completion and cannot be addressed afterward.
34
32
  {{/if}}
35
33
  {{/if}}
36
- </parameters>
37
34
 
38
- <rules>
39
- - **Maximize fan-out.** Issue the widest {{#if batchEnabled}}`tasks[]` batch{{else}}set of parallel `task` calls{{/if}} the work decomposes into. NEVER serialize work that could run concurrently.
40
- - **Subagents do not verify, lint, or format.** Every assignment MUST instruct the subagent to skip all gates, formatters, and project-wide build/test/lint. You run them once at the end across the union of changed files.
41
- - No globs, no "update all", no package-wide scope. Fan out.
42
- - **Tailor every spawn with a `role`.** A role naming the specialist (e.g. "Parser edge-case tester", "SSE backpressure specialist") makes a sharper agent than a bare generic `task`/`quick_task` worker; decompose into named specialists, never clones of one generic worker. A role-less generic spawn is the exception.
43
- - NEVER slow down or serialize because tasks might overlap on some files. Agents resolve collisions among themselves in real time.
44
- - Subagents have no conversation history. Every fact, file path, and direction they need MUST be explicit in {{#if batchEnabled}}`context` or the item's `assignment`{{else}}the `assignment`{{/if}}.
35
+ # Context and Communication
36
+ Subagents start blank. They have no access to your conversation history.
45
37
  {{#if batchEnabled}}
46
- - **Shared background** lives in `context` once — never duplicated across assignments. Pass large payloads via `local://<path>` URIs, not inline.
38
+ - Pass large payloads using `local://<path>` URIs, never inline text.
47
39
  {{else}}
48
- - **Shared background**: write it ONCE to a `local://` file (e.g. `local://ctx.md`) and reference that path in each assignment. Pass large payloads via `local://<path>` URIs, not inline.
40
+ - *Note: The single-spawn shape has no `context` field.* Write shared project state ONCE to a `local://` file (e.g., `local://ctx.md`) and reference that URL in your assignments. Pass large payloads using `local://<path>` URIs, never inline text.
49
41
  {{/if}}
50
- - Prefer agents that investigate **and** edit in one pass; only spin a read-only discovery step when affected files are genuinely unknown.
51
- - **Read-only agents**: Agents tagged READ-ONLY (e.g. `explore`) have no edit/write/command tools. NEVER hand them an assignment that requires changing files or running commands. Use them to investigate and report back; do the edits yourself or delegate to a writing agent (`task`, `oracle`, `designer`).
52
- - **No reasoning offload**: NEVER offload reasoning, analysis, design, or decision-making to `quick_task` or `explore` — they run minimal-effort / small models for mechanical lookups and data collection only. Keep judgment and synthesis in your own context; delegate hard thinking to `task`, `plan`, or `oracle`.
53
- </rules>
54
-
55
- <parallelization>
56
42
  {{#if ircEnabled}}
57
- Test: can task B run correctly without seeing A's output? If no, sequence A B **unless** B can reasonably ask A for the missing piece over `irc`. Live coordination beats a serial waterfall when the contract is small and easy to describe in a DM.
58
- Still sequence when one task produces a large, evolving contract (generated types, schema migration, core module API) the other consumes wholesale — IRC round-trips do not replace a finished artifact.
59
- Parallel when tasks touch disjoint files, are independent refactors/tests, or only need occasional clarification that can be resolved peer-to-peer.
60
- {{else}}
61
- Test: can task B run correctly without seeing A's output? If no, sequence A → B.
62
- Sequential when one task produces a contract (types, API, schema, core module) the other consumes.
63
- Parallel when tasks touch disjoint files or are independent refactors/tests.
43
+ - Once spawned, coordinate with live agents via `irc` using their IDs. If task B depends on task A, B SHOULD message A directly.
44
+ {{/if}}
45
+ {{#if asyncEnabled}}
46
+ - If you run out of things to do and are genuinely blocked waiting for a subagent, use `job poll`. Use `job cancel` only for stalled work.
64
47
  {{/if}}
65
- {{#if ircEnabled}}Sequenced follow-ups SHOULD message the agent that produced the prerequisite — it already holds the context.{{/if}}
66
- </parallelization>
67
48
 
49
+ # Format Contracts
68
50
  {{#if batchEnabled}}
69
- <context-fmt>
70
- # Goal ← one sentence: what the batch accomplishes
71
- # Constraints ← MUST/NEVER rules and session decisions
72
- # Contract ← exact types/signatures if tasks share an interface
73
- </context-fmt>
51
+ The `context` field MUST follow this format:
52
+ # Goal ← what the batch accomplishes
53
+ # Constraints ← rules and session decisions
54
+ # Contract ← shared interfaces
74
55
  {{/if}}
75
56
 
76
- <assignment-fmt>
57
+ The `assignment` field MUST follow this format:
77
58
  # Target ← exact files and symbols; explicit non-goals
78
59
  # Change ← step-by-step add/remove/rename; APIs and patterns
79
60
  # Acceptance ← observable result; no project-wide commands
80
- </assignment-fmt>
81
61
 
82
- <agents>
62
+ # Available Agents
83
63
  {{#if spawningDisabled}}
84
- Agent spawning is disabled for this context.
64
+ Agent spawning is currently disabled.
85
65
  {{else}}
86
66
  {{#list agents join="\n"}}
87
- # {{name}}{{#if readOnly}} READ-ONLY (no edit/write/exec tools){{/if}}
67
+ ### {{name}}{{#if readOnly}} (READ-ONLY: no edit/write/command tools){{/if}}
88
68
  {{description}}
69
+ {{#if readOnly}}Use ONLY for investigation and reporting; do the edits yourself or assign them to a writing agent.{{/if}}
89
70
  {{/list}}
90
71
  {{/if}}
91
- </agents>
package/src/sdk.ts CHANGED
@@ -42,6 +42,7 @@ import {
42
42
  resolveModelRoleValue,
43
43
  } from "./config/model-resolver";
44
44
  import { loadPromptTemplates as loadPromptTemplatesInternal, type PromptTemplate } from "./config/prompt-templates";
45
+ import { buildServiceTierByFamily } from "./config/service-tier";
45
46
  import { Settings, type SkillsSettings } from "./config/settings";
46
47
  import { CursorExecHandlers } from "./cursor";
47
48
  import "./discovery";
@@ -1537,7 +1538,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1537
1538
  getModelString: () => (hasExplicitModel && model ? formatModelString(model) : undefined),
1538
1539
  getActiveModelString,
1539
1540
  getActiveModel: () => agent?.state.model ?? model,
1540
- getServiceTier: () => session?.serviceTier,
1541
+ getServiceTierByFamily: () => session?.serviceTierByFamily,
1541
1542
  getImageAttachments: () => session?.getImageAttachments() ?? [],
1542
1543
  getPlanModeState: () => session?.getPlanModeState(),
1543
1544
  getPlanReferencePath: () => session?.getPlanReferencePath() ?? "local://PLAN.md",
@@ -2525,13 +2526,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2525
2526
  const openaiWebsocketSetting = settings.get("providers.openaiWebsockets") ?? "off";
2526
2527
  const preferOpenAICodexWebsockets =
2527
2528
  openaiWebsocketSetting === "on" ? true : openaiWebsocketSetting === "off" ? false : undefined;
2528
- const serviceTierSetting = settings.get("serviceTier");
2529
-
2530
- const initialServiceTier = hasServiceTierEntry
2531
- ? existingSession.serviceTier
2532
- : serviceTierSetting === "none"
2533
- ? undefined
2534
- : serviceTierSetting;
2529
+ const initialServiceTierByFamily = hasServiceTierEntry
2530
+ ? (existingSession.serviceTier ?? {})
2531
+ : buildServiceTierByFamily(
2532
+ settings.get("tier.openai"),
2533
+ settings.get("tier.anthropic"),
2534
+ settings.get("tier.google"),
2535
+ );
2535
2536
 
2536
2537
  // One-shot launch-latency marker: fired the first time the loop dispatches
2537
2538
  // a chat request to the provider transport. See onFirstChatDispatch.
@@ -2579,7 +2580,6 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2579
2580
  minP: settings.get("minP") >= 0 ? settings.get("minP") : undefined,
2580
2581
  presencePenalty: settings.get("presencePenalty") >= 0 ? settings.get("presencePenalty") : undefined,
2581
2582
  repetitionPenalty: settings.get("repetitionPenalty") >= 0 ? settings.get("repetitionPenalty") : undefined,
2582
- serviceTier: initialServiceTier,
2583
2583
  hideThinkingSummary: settings.get("omitThinking"),
2584
2584
  kimiApiFormat: settings.get("providers.kimiApiFormat") ?? "anthropic",
2585
2585
  preferWebsockets: preferOpenAICodexWebsockets,
@@ -2639,8 +2639,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2639
2639
  // classification persists its concrete effort once a real user turn runs.
2640
2640
  sessionManager.appendThinkingLevelChange(effectiveThinkingLevel);
2641
2641
  }
2642
- if (initialServiceTier) {
2643
- sessionManager.appendServiceTierChange(initialServiceTier);
2642
+ if (Object.keys(initialServiceTierByFamily).length > 0) {
2643
+ sessionManager.appendServiceTierChange(initialServiceTierByFamily);
2644
2644
  }
2645
2645
  }
2646
2646
 
@@ -2691,6 +2691,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2691
2691
  agent,
2692
2692
  pruneToolDescriptions: inlineToolDescriptors,
2693
2693
  thinkingLevel: autoThinking ? AUTO_THINKING : effectiveThinkingLevel,
2694
+ serviceTierByFamily: initialServiceTierByFamily,
2694
2695
  sessionManager,
2695
2696
  settings,
2696
2697
  autoApprove: options.autoApprove,
@@ -2718,6 +2719,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2718
2719
  onResponse,
2719
2720
  sideStreamFn: settingsAwareStreamFn,
2720
2721
  advisorStreamFn: settingsAwareStreamFn,
2722
+ preferWebsockets: preferOpenAICodexWebsockets,
2721
2723
  convertToLlm: convertToLlmFinal,
2722
2724
  rebuildSystemPrompt,
2723
2725
  reloadSshTool,