@oh-my-pi/pi-coding-agent 15.13.1 → 15.13.3

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 (109) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/cli.js +1057 -289
  3. package/dist/types/config/model-registry.d.ts +1 -0
  4. package/dist/types/config/models-config-schema.d.ts +3 -0
  5. package/dist/types/config/models-config.d.ts +3 -0
  6. package/dist/types/config/settings-schema.d.ts +97 -0
  7. package/dist/types/edit/hashline/block-resolver.d.ts +1 -1
  8. package/dist/types/edit/index.d.ts +2 -0
  9. package/dist/types/eval/js/context-manager.d.ts +15 -0
  10. package/dist/types/modes/components/welcome.d.ts +1 -0
  11. package/dist/types/modes/controllers/input-controller.d.ts +4 -4
  12. package/dist/types/modes/interactive-mode.d.ts +1 -0
  13. package/dist/types/modes/rpc/rpc-types.d.ts +2 -1
  14. package/dist/types/modes/types.d.ts +6 -0
  15. package/dist/types/sdk.d.ts +3 -0
  16. package/dist/types/session/session-dump-format.d.ts +2 -1
  17. package/dist/types/session/unexpected-stop-classifier.d.ts +13 -0
  18. package/dist/types/stt/asr-client.d.ts +1 -1
  19. package/dist/types/system-prompt.d.ts +11 -0
  20. package/dist/types/tiny/title-client.d.ts +1 -1
  21. package/dist/types/tools/ask.d.ts +2 -0
  22. package/dist/types/tools/ast-edit.d.ts +2 -0
  23. package/dist/types/tools/ast-grep.d.ts +2 -0
  24. package/dist/types/tools/browser.d.ts +2 -0
  25. package/dist/types/tools/debug.d.ts +2 -0
  26. package/dist/types/tools/eval.d.ts +2 -0
  27. package/dist/types/tools/find.d.ts +2 -0
  28. package/dist/types/tools/inspect-image.d.ts +2 -1
  29. package/dist/types/tools/irc.d.ts +2 -0
  30. package/dist/types/tools/job.d.ts +1 -0
  31. package/dist/types/tools/ssh.d.ts +2 -0
  32. package/dist/types/tools/todo.d.ts +2 -0
  33. package/dist/types/tts/tts-client.d.ts +1 -1
  34. package/dist/types/tui/tree-list.d.ts +1 -0
  35. package/dist/types/utils/thinking-display.d.ts +1 -17
  36. package/package.json +12 -12
  37. package/src/cli.ts +25 -12
  38. package/src/config/model-registry.ts +16 -2
  39. package/src/config/models-config-schema.ts +2 -0
  40. package/src/config/models-config.ts +1 -0
  41. package/src/config/settings-schema.ts +78 -0
  42. package/src/edit/hashline/block-resolver.ts +1 -1
  43. package/src/edit/hashline/execute.ts +1 -6
  44. package/src/edit/index.ts +48 -0
  45. package/src/eval/__tests__/agent-bridge.test.ts +106 -46
  46. package/src/eval/__tests__/js-context-manager.test.ts +53 -3
  47. package/src/eval/js/context-manager.ts +132 -29
  48. package/src/eval/js/worker-core.ts +1 -1
  49. package/src/eval/js/worker-entry.ts +7 -0
  50. package/src/export/html/template.js +18 -22
  51. package/src/internal-urls/docs-index.generated.ts +12 -3
  52. package/src/main.ts +15 -5
  53. package/src/modes/acp/acp-agent.ts +2 -2
  54. package/src/modes/acp/acp-event-mapper.ts +2 -2
  55. package/src/modes/components/agent-hub.ts +31 -7
  56. package/src/modes/components/assistant-message.ts +24 -15
  57. package/src/modes/components/snapcompact-shape-preview-doc.md +2 -2
  58. package/src/modes/components/snapcompact-shape-preview.ts +2 -2
  59. package/src/modes/components/tree-selector.ts +3 -2
  60. package/src/modes/components/welcome.ts +14 -4
  61. package/src/modes/controllers/event-controller.ts +3 -3
  62. package/src/modes/controllers/input-controller.ts +28 -39
  63. package/src/modes/controllers/streaming-reveal.ts +4 -4
  64. package/src/modes/interactive-mode.ts +2 -0
  65. package/src/modes/rpc/rpc-mode.ts +1 -0
  66. package/src/modes/rpc/rpc-types.ts +2 -2
  67. package/src/modes/types.ts +6 -0
  68. package/src/modes/utils/ui-helpers.ts +3 -3
  69. package/src/prompts/agents/oracle.md +0 -1
  70. package/src/prompts/agents/reviewer.md +0 -1
  71. package/src/prompts/system/system-prompt.md +17 -21
  72. package/src/prompts/system/unexpected-stop-classifier.md +17 -0
  73. package/src/prompts/system/unexpected-stop-retry.md +4 -0
  74. package/src/prompts/tools/ask.md +0 -8
  75. package/src/prompts/tools/ast-edit.md +0 -15
  76. package/src/prompts/tools/ast-grep.md +0 -13
  77. package/src/prompts/tools/browser.md +0 -21
  78. package/src/prompts/tools/debug.md +0 -13
  79. package/src/prompts/tools/eval.md +0 -9
  80. package/src/prompts/tools/find.md +0 -13
  81. package/src/prompts/tools/inspect-image.md +0 -9
  82. package/src/prompts/tools/irc.md +0 -15
  83. package/src/prompts/tools/patch.md +0 -13
  84. package/src/prompts/tools/ssh.md +0 -9
  85. package/src/prompts/tools/todo.md +1 -19
  86. package/src/sdk.ts +19 -0
  87. package/src/session/agent-session.ts +289 -29
  88. package/src/session/session-dump-format.ts +17 -49
  89. package/src/session/unexpected-stop-classifier.ts +129 -0
  90. package/src/stt/asr-client.ts +1 -1
  91. package/src/system-prompt.ts +31 -0
  92. package/src/tiny/title-client.ts +1 -1
  93. package/src/tools/ask.ts +41 -0
  94. package/src/tools/ast-edit.ts +46 -0
  95. package/src/tools/ast-grep.ts +24 -0
  96. package/src/tools/browser/tab-supervisor.ts +1 -1
  97. package/src/tools/browser/tab-worker-entry.ts +12 -4
  98. package/src/tools/browser.ts +52 -0
  99. package/src/tools/debug.ts +17 -0
  100. package/src/tools/eval.ts +20 -1
  101. package/src/tools/find.ts +24 -0
  102. package/src/tools/inspect-image.ts +27 -1
  103. package/src/tools/irc.ts +41 -0
  104. package/src/tools/job.ts +1 -0
  105. package/src/tools/ssh.ts +16 -0
  106. package/src/tools/todo.ts +82 -3
  107. package/src/tts/tts-client.ts +1 -1
  108. package/src/tui/tree-list.ts +68 -19
  109. package/src/utils/thinking-display.ts +8 -34
@@ -24,27 +24,6 @@ Use tools whenever they materially improve correctness, completeness, or groundi
24
24
  - SHOULD parallelize calls when possible.
25
25
  {{#has tools "task"}}- User says `parallel`/`parallelize` → MUST use `{{toolRefs.task}}` subagents; parallel tool calls alone do not satisfy.{{/has}}
26
26
 
27
- {{#if toolInfo.length}}
28
- # Inventory
29
- {{#if mcpDiscoveryMode}}
30
- <discovery-notice>
31
- {{#if hasMCPDiscoveryServers}}Discoverable MCP servers in this session: {{#list mcpDiscoveryServerSummaries join=", "}}{{this}}{{/list}}.{{/if}}
32
- If the task may involve external systems, SaaS APIs, chat, tickets, databases, deployments, or other non-local integrations, you SHOULD call `{{toolRefs.search_tool_bm25}}` before concluding no such tool exists.
33
- </discovery-notice>
34
- {{/if}}
35
- {{#if repeatToolDescriptions}}
36
- {{#each toolInfo}}
37
- <tool name={{name}}>
38
- {{description}}
39
- </tool>
40
- {{/each}}
41
- {{else}}
42
- {{#each toolInfo}}
43
- - {{#if label}}{{label}}: `{{name}}`{{else}}`{{name}}`{{/if}}
44
- {{/each}}
45
- {{/if}}
46
- {{/if}}
47
-
48
27
  # I/O
49
28
  - For tools taking `path` or path-like fields, prefer relative paths.
50
29
  {{#if intentTracing}}- Most tools have a `{{intentField}}` parameter. Fill it with a concise intent in present participle form, 2-6 words, no period, capitalized.{{/if}}
@@ -115,6 +94,23 @@ Delegation is preferred here. Once the design is settled, you SHOULD fan substan
115
94
  {{/has}}
116
95
  {{/if}}
117
96
 
97
+ {{#if toolInfo.length}}
98
+ # Inventory
99
+ {{#if mcpDiscoveryMode}}
100
+ <discovery-notice>
101
+ {{#if hasMCPDiscoveryServers}}Discoverable MCP servers in this session: {{#list mcpDiscoveryServerSummaries join=", "}}{{this}}{{/list}}.{{/if}}
102
+ If the task may involve external systems, SaaS APIs, chat, tickets, databases, deployments, or other non-local integrations, you SHOULD call `{{toolRefs.search_tool_bm25}}` before concluding no such tool exists.
103
+ </discovery-notice>
104
+ {{/if}}
105
+ {{#if toolListMode}}
106
+ {{#each toolInfo}}
107
+ - {{#if label}}{{label}}: `{{name}}`{{else}}`{{name}}`{{/if}}
108
+ {{/each}}
109
+ {{else}}
110
+ {{toolInventory}}
111
+ {{/if}}
112
+ {{/if}}
113
+
118
114
  ENV
119
115
  ===================================
120
116
 
@@ -0,0 +1,17 @@
1
+ You are checking whether an assistant message is an unexpected stop. A message is an unexpected stop if the assistant says it will take an action, continue working, or call a tool, but then ends without actually doing so.
2
+
3
+ Examples of unexpected stops:
4
+ - "I should do the same for the JS eval worker. Doing that now."
5
+ - "Let me run the tests next."
6
+ - "I'll fix that now."
7
+ - "Should I do that for you?"
8
+
9
+ Not an unexpected stop:
10
+ - "I've completed the task."
11
+ - "Is there anything else I can help with?"
12
+ - "The fix is done and tests pass."
13
+
14
+ Message:
15
+ {{message}}
16
+
17
+ Answer with a single word: YES if this is an unexpected stop, NO otherwise.
@@ -0,0 +1,4 @@
1
+ <system-injection>
2
+ You said you would continue with a tool call or action but stopped. Continue now.
3
+ Attempt #{{retryCount}}/{{maxRetries}}
4
+ </system-injection>
@@ -20,11 +20,3 @@ Asks user when you need clarification or input during task execution.
20
20
  - **If multiple choices are acceptable**, pick the most conservative/standard option and proceed; state the choice.
21
21
  - **Do NOT include "Other" option** — UI automatically adds "Other (type your own)" to every question.
22
22
  </critical>
23
-
24
- <examples>
25
- # Single question
26
- questions: [{"id": "auth_method", "question": "Which authentication method should this API use?", "options": [{"label": "JWT", "description": "Bearer tokens for stateless API clients."}, {"label": "OAuth2", "description": "Delegated authorization with external identity providers."}, {"label": "Session cookies", "description": "Browser-first authentication backed by server-side sessions."}], "recommended": 0}]
27
-
28
- # Multiple questions
29
- questions: [{"id": "storage_type", "question": "Which storage backend?", "options": [{"label": "SQLite"}, {"label": "PostgreSQL"}]}, {"id": "auth_method", "question": "Which auth method?", "options": [{"label": "JWT"}, {"label": "Session cookies"}]}]
30
- </examples>
@@ -18,21 +18,6 @@ Performs structural AST-aware rewrites via native ast-grep.
18
18
  - Parse issues when files cannot be processed
19
19
  </output>
20
20
 
21
- <examples>
22
- # Rename a call site across TypeScript files
23
- `{"ops":[{"pat":"oldApi($$$ARGS)","out":"newApi($$$ARGS)"}],"paths":["src/**/*.ts"]}`
24
- # Delete matching calls
25
- `{"ops":[{"pat":"console.log($$$ARGS)","out":""}],"paths":["src/**/*.ts"]}`
26
- # Rewrite import source path
27
- `{"ops":[{"pat":"import { $$$IMPORTS } from \"old-package\"","out":"import { $$$IMPORTS } from \"new-package\""}],"paths":["src/**/*.ts"]}`
28
- # Modernize to optional chaining (same metavariable enforces identity)
29
- `{"ops":[{"pat":"$A && $A()","out":"$A?.()"}],"paths":["src/**/*.ts"]}`
30
- # Swap two arguments using captures
31
- `{"ops":[{"pat":"assertEqual($A, $B)","out":"assertEqual($B, $A)"}],"paths":["tests/**/*.ts"]}`
32
- # Python — convert print calls to logging
33
- `{"ops":[{"pat":"print($$$ARGS)","out":"logger.info($$$ARGS)"}],"paths":["src/**/*.py"]}`
34
- </examples>
35
-
36
21
  <critical>
37
22
  - Parse issues mean the rewrite is malformed or mis-scoped — fix the pattern before assuming a clean no-op
38
23
  - For one-off local text edits, you SHOULD prefer the Edit tool
@@ -22,19 +22,6 @@ Performs structural code search using AST matching via native ast-grep.
22
22
  - Summary counts (`totalMatches`, `filesWithMatches`, `filesSearched`) and parse issues when present
23
23
  </output>
24
24
 
25
- <examples>
26
- # Search TypeScript files under src
27
- `{"pat":"console.log($$$)","paths":["src/**/*.ts"]}`
28
- # Named imports from a specific package
29
- `{"pat":"import { $$$IMPORTS } from \"react\"","paths":["src/**/*.ts"]}`
30
- # Arrow functions assigned to a const
31
- `{"pat":"const $NAME = ($$$ARGS) => $BODY","paths":["src/utils/**/*.ts"]}`
32
- # Method call on any object, ignoring method name with `$_`
33
- `{"pat":"logger.$_($$$ARGS)","paths":["src/**/*.ts"]}`
34
- # Loosest existence check for a symbol in one file
35
- `{"pat":"processItems","paths":["src/worker.ts"]}`
36
- </examples>
37
-
38
25
  <critical>
39
26
  - AVOID repo-root scans — narrow `paths` first
40
27
  - Parse issues are query failure, not evidence of absence: repair the pattern or tighten `paths` before concluding "no matches"
@@ -37,27 +37,6 @@ Drives real Chromium tab; full puppeteer access via JS execution.
37
37
  - `code` runs with full Node access. Treat as your code, not sandboxed code.
38
38
  </critical>
39
39
 
40
- <examples>
41
- # Open a tab and read structured page data
42
- `{"action":"open","name":"docs","url":"https://example.com"}`
43
- `{"action":"run","name":"docs","code":"const obs = await tab.observe(); display(obs); return obs.elements.length;"}`
44
-
45
- # Click an observed element by id
46
- `{"action":"run","name":"docs","code":"const obs = await tab.observe(); const link = obs.elements.find(e => e.role === 'link' && e.name === 'Sign in'); assert(link, 'Sign in link missing'); await (await tab.id(link.id)).click();"}`
47
-
48
- # Fill and submit a form via selectors
49
- `{"action":"run","name":"docs","code":"await tab.fill('input[name=email]', 'me@example.com'); await tab.click('text/Continue');"}`
50
-
51
- # Screenshot to look at the page — no save path
52
- `{"action":"run","name":"docs","code":"await tab.screenshot();"}`
53
-
54
- # Attach to an existing Electron app
55
- `{"action":"open","name":"cursor","app":{"path":"/Applications/Cursor.app/Contents/MacOS/Cursor"}}`
56
-
57
- # Close every tab and kill spawned-app processes
58
- `{"action":"close","all":true,"kill":true}`
59
- </examples>
60
-
61
40
  <output>
62
41
  Per call: `display(value)` outputs (text/images), then the JSON-stringified return value of `code`. `run` always produces at least a status line.
63
42
  </output>
@@ -19,16 +19,3 @@ Use for launching or attaching debuggers, setting breakpoints, stepping through
19
19
  - `program` must be an executable file or debug target, not a directory or interpreter name that resolves to a workspace directory.
20
20
  - Python debugging requires `debugpy`; install with `pip install debugpy` if the adapter is unavailable.
21
21
  </caution>
22
-
23
- <examples>
24
- # Launch and inspect hang
25
- 1. `debug(action: "launch", program: "./my_app")`
26
- 2. `debug(action: "set_breakpoint", file: "src/main.c", line: 42)`
27
- 3. `debug(action: "continue")`
28
- 4. If the program appears hung: `debug(action: "pause")`
29
- 5. Inspect state with `threads`, `stack_trace`, `scopes`, and `variables`
30
- # Launch a Python script with debugpy
31
- `debug(action: "launch", adapter: "debugpy", program: "scripts/job.py", args: ["--flag"])`
32
- # Raw debugger command through repl
33
- `debug(action: "evaluate", expression: "info registers", context: "repl")`
34
- </examples>
@@ -58,12 +58,3 @@ budget → per-turn token budget
58
58
  {{#if py}}`budget.total` (ceiling or None), `budget.spent()`, `budget.remaining()` (math.inf when no ceiling), `budget.hard` (bool).{{/if}}{{#if js}}`await budget.total()` (ceiling or null), `await budget.spent()`, `await budget.remaining()` (Infinity when no ceiling), `await budget.hard()`.{{/if}} Ceiling comes from a `+Nk` directive (advisory) or `+Nk!`/Goal Mode (hard — `agent()` refuses to spawn past it); otherwise None/null, spend still tracked across the turn.
59
59
  ```
60
60
  </prelude>
61
-
62
- <example>
63
- {
64
- "cells": [
65
- { "language": "py", "title": "imports", "timeout": 10, "code": "import json\nfrom pathlib import Path" },
66
- { "language": "py", "title": "load config", "code": "data = json.loads(read('package.json'))\ndisplay(data)" }
67
- ]
68
- }
69
- </example>
@@ -14,19 +14,6 @@ Finds files and directories using fast pattern matching that works with any code
14
14
  Matching file and directory paths sorted by modification time (most recent first), grouped by directory to reduce token usage. Each group starts with `# <dir>/` followed by basenames (one per line); directory entries get a trailing `/`. Root-level entries have no header. Truncated at 200 entries or 50KB.
15
15
  </output>
16
16
 
17
- <examples>
18
- # Find files
19
- `{"paths": ["src/**/*.ts"]}`
20
- # Multiple targets — separate array elements
21
- `{"paths": ["src/**/*.ts", "test/**/*.ts"]}`
22
- # Find gitignored files like .env
23
- `{"paths": [".env*"], "gitignore": false}`
24
- # Find directories matching a name (returns both files and dirs; directories are suffixed with `/`)
25
- `{"paths": ["**/tests"]}`
26
- # Long-running search on a slow volume
27
- `{"paths": ["/Volumes/Storage/**/*.py"], "timeout": 30}`
28
- </examples>
29
-
30
17
  <avoid>
31
18
  For open-ended searches requiring multiple rounds of globbing and searching, you MUST use Task tool instead.
32
19
  </avoid>
@@ -11,15 +11,6 @@ Inspects an image file with a vision-capable model and returns compact text anal
11
11
  - Use this tool over `read` when the goal is image analysis
12
12
  </instruction>
13
13
 
14
- <examples>
15
- # OCR with strict formatting
16
- `{"path":"screenshots/error.png","question":"Extract all visible text verbatim. Return as bullet list in reading order."}`
17
- # Screenshot debugging
18
- `{"path":"screenshots/settings.png","question":"Identify the likely cause of the disabled Save button. Return: (1) observations, (2) likely cause, (3) confidence."}`
19
- # Scene/object question
20
- `{"path":"photos/shelf.jpg","question":"List all clearly visible product labels and their shelf positions (top/middle/bottom). If unreadable, say unreadable."}`
21
- </examples>
22
-
23
14
  <output>
24
15
  - Returns text-only analysis from the vision model
25
16
  - No image content blocks are returned in tool output
@@ -40,18 +40,3 @@ Applies to sending and replying.
40
40
  - `inbox`: pending messages, oldest first.
41
41
  - `list`: peers with status, unread count, parent, last activity.
42
42
  </output>
43
-
44
- <examples>
45
- # List peers
46
- `{"op": "list"}`
47
- # Fire-and-forget DM — same send wakes idle/parked peers
48
- `{"op": "send", "to": "AuthLoader", "message": "Still touching src/server/auth.ts? I need to add a 401 path."}`
49
- # Round-trip when you cannot proceed without the answer
50
- `{"op": "send", "to": "Main", "message": "JWT or session cookies for the auth flow?", "await": true}`
51
- # Block until a specific peer answers
52
- `{"op": "wait", "from": "AuthLoader", "timeoutMs": 60000}`
53
- # Drain pending messages
54
- `{"op": "inbox"}`
55
- # Broadcast to live peers (no replies expected)
56
- `{"op": "send", "to": "all", "message": "About to refactor src/server/middleware/*. Anyone already in there?"}`
57
- </examples>
@@ -50,19 +50,6 @@ Returns success/failure; on failure, error message indicates:
50
50
  - NEVER use edit to fix indentation, whitespace, or reformat code. Formatting is a single command run once at the end (`bun fmt`, `cargo fmt`, `prettier --write`, etc.) — not N individual edits. If you see inconsistent indentation after an edit, leave it; the formatter will fix all of it in one pass.
51
51
  </critical>
52
52
 
53
- <examples>
54
- # Create
55
- `edit {"path":"hello.txt","edits":[{"op":"create","diff":"Hello\n"}]}`
56
- # Update
57
- `edit {"path":"src/app.py","edits":[{"op":"update","diff":"@@ def greet():\n def greet():\n-print('Hi')\n+print('Hello')\n"}]}`
58
- # Rename
59
- `edit {"path":"src/app.py","edits":[{"op":"update","rename":"src/main.py","diff":"@@\n …\n"}]}`
60
- # Delete
61
- `edit {"path":"obsolete.txt","edits":[{"op":"delete"}]}`
62
- # Multiple entries
63
- All entries in one call apply to the top-level `path`; use separate calls for different files.
64
- </examples>
65
-
66
53
  <avoid>
67
54
  - Generic anchors: `import`, `export`, `describe`, `function`, `const`
68
55
  - Repeating same addition in multiple hunks (duplicate blocks)
@@ -20,12 +20,3 @@ Runs commands on remote hosts.
20
20
  <critical>
21
21
  You MUST verify the shell type from "Available hosts" and use matching commands.
22
22
  </critical>
23
-
24
- <examples>
25
- # List files: Linux
26
- Host: server1 (10.0.0.1) | linux/bash. Command: `ls -la /home/user`
27
- # Show running processes: Windows cmd
28
- Host: winbox (192.168.1.5) | windows/cmd. Command: `tasklist /v`
29
- # Get system info: macOS
30
- Host: macbook (10.0.0.20) | macos/zsh. Command: `uname -a && sw_vers`
31
- </examples>
@@ -9,6 +9,7 @@ Allowed `op` values are only `init`, `start`, `done`, `drop`, `rm`, `append`, an
9
9
  |`op`|Required fields|Effect|
10
10
  |---|---|---|
11
11
  |`init`|`list: [{phase, items: string[]}]`|Initialize the full list (replaces any existing list)|
12
+ |`init`|`items: string[]`|Flattened single-phase init|
12
13
  |`start`|`task`|Mark in progress|
13
14
  |`done`|`task` or `phase`|Mark completed|
14
15
  |`drop`|`task` or `phase`|Mark abandoned|
@@ -33,25 +34,6 @@ Allowed `op` values are only `init`, `start`, `done`, `drop`, `rm`, `append`, an
33
34
  - User provides a set of tasks to complete
34
35
  - New instructions arrive mid-task — capture before proceeding
35
36
 
36
- <examples>
37
- # Initial setup (multi-phase)
38
- `{"ops":[{"op":"init","list":[{"phase":"Foundation","items":["Scaffold crate","Wire workspace"]},{"phase":"Auth","items":["Port credential store","Wire OAuth providers"]},{"phase":"Verification","items":["Run cargo test"]}]}]}`
39
- # View current state (read-only)
40
- `{"ops":[{"op":"view"}]}`
41
- # Initial setup (single phase)
42
- `{"ops":[{"op":"init","list":[{"phase":"Implementation","items":["Apply fix","Run tests"]}]}]}`
43
- # Complete one task
44
- `{"ops":[{"op":"done","task":"Wire workspace"}]}`
45
- # Complete a whole phase
46
- `{"ops":[{"op":"done","phase":"Auth"}]}`
47
- # Remove all tasks
48
- `{"ops":[{"op":"rm"}]}`
49
- # Drop one task
50
- `{"ops":[{"op":"drop","task":"Run cargo test"}]}`
51
- # Append tasks to a phase
52
- `{"ops":[{"op":"append","phase":"Auth","items":["Handle retries","Run tests"]}]}`
53
- </examples>
54
-
55
37
  <critical>
56
38
  When the user hands you a multi-step plan — a phased todo, a numbered or bulleted checklist, or "N bugs/items/tasks" to work through:
57
39
  - You MUST `init` the list with EVERY item as its own task before doing the work.
package/src/sdk.ts CHANGED
@@ -16,6 +16,7 @@ import {
16
16
  type SimpleStreamOptions,
17
17
  streamSimple,
18
18
  } from "@oh-my-pi/pi-ai";
19
+ import type { ToolCallSyntax } from "@oh-my-pi/pi-ai/grammar";
19
20
  import {
20
21
  getOpenAICodexTransportDetails,
21
22
  prewarmOpenAICodexResponses,
@@ -550,6 +551,17 @@ export interface CreateAgentSessionResult {
550
551
  eventBus: EventBus;
551
552
  }
552
553
 
554
+ export type ToolCallFormat = "auto" | "native" | ToolCallSyntax;
555
+
556
+ export function resolveToolCallSyntax(
557
+ format: ToolCallFormat,
558
+ model: Pick<Model, "supportsTools"> | undefined,
559
+ ): ToolCallSyntax | undefined {
560
+ if (format === "native") return undefined;
561
+ if (format === "auto") return model?.supportsTools === false ? "glm" : undefined;
562
+ return format;
563
+ }
564
+
553
565
  // Re-exports
554
566
 
555
567
  export type { PromptTemplate } from "./config/prompt-templates";
@@ -2149,6 +2161,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2149
2161
  }
2150
2162
  appendPrompt = parts.join("\n\n");
2151
2163
  }
2164
+ // Owned/in-band tool syntax (non-native) repeats the catalog as `# Tool:`
2165
+ // sections; native tool calling lets the compact name list suffice.
2166
+ const nativeTools =
2167
+ resolveToolCallSyntax(settings.get("tools.format"), agent?.state.model ?? model) === undefined;
2152
2168
  const defaultPrompt = await buildSystemPromptInternal({
2153
2169
  cwd,
2154
2170
  skills,
@@ -2160,6 +2176,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2160
2176
  skillsSettings: settings.getGroup("skills"),
2161
2177
  appendSystemPrompt: appendPrompt,
2162
2178
  repeatToolDescriptions,
2179
+ nativeTools,
2163
2180
  intentField,
2164
2181
  mcpDiscoveryMode: hasDiscoverableTools,
2165
2182
  mcpDiscoveryServerSummaries: discoverableToolSummary.servers.map(formatDiscoverableToolServerSummary),
@@ -2489,6 +2506,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2489
2506
  return result;
2490
2507
  },
2491
2508
  intentTracing: !!intentField,
2509
+ toolCallSyntax: resolveToolCallSyntax(settings.get("tools.format"), model),
2510
+ abortOnFabricatedToolResult: settings.get("tools.abortOnFabricatedResult"),
2492
2511
  getToolChoice: () => session?.nextToolChoice(),
2493
2512
  telemetry: options.telemetry,
2494
2513
  appendOnlyContext: model