@oh-my-pi/pi-coding-agent 14.3.0 → 14.4.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/CHANGELOG.md +84 -1
- package/package.json +7 -7
- package/src/autoresearch/prompt.md +1 -1
- package/src/commit/agentic/prompts/analyze-file.md +1 -1
- package/src/config/model-registry.ts +67 -15
- package/src/config/prompt-templates.ts +5 -5
- package/src/config/settings-schema.ts +4 -4
- package/src/cursor.ts +3 -8
- package/src/discovery/helpers.ts +3 -3
- package/src/edit/diff.ts +50 -47
- package/src/edit/index.ts +86 -57
- package/src/edit/line-hash.ts +735 -19
- package/src/edit/modes/apply-patch.ts +0 -9
- package/src/edit/modes/atom.ts +658 -0
- package/src/edit/modes/chunk.ts +14 -24
- package/src/edit/modes/hashline.ts +188 -136
- package/src/edit/modes/patch.ts +5 -9
- package/src/edit/modes/replace.ts +6 -11
- package/src/edit/renderer.ts +14 -10
- package/src/edit/streaming.ts +50 -16
- package/src/exec/bash-executor.ts +2 -4
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +4 -12
- package/src/extensibility/custom-tools/types.ts +2 -0
- package/src/extensibility/custom-tools/wrapper.ts +2 -1
- package/src/internal-urls/docs-index.generated.ts +2 -2
- package/src/lsp/index.ts +1 -1
- package/src/mcp/render.ts +1 -8
- package/src/modes/components/assistant-message.ts +4 -0
- package/src/modes/components/diff.ts +23 -14
- package/src/modes/components/footer.ts +21 -16
- package/src/modes/components/settings-defs.ts +6 -1
- package/src/modes/components/todo-reminder.ts +1 -8
- package/src/modes/components/tool-execution.ts +1 -4
- package/src/modes/controllers/selector-controller.ts +1 -1
- package/src/modes/print-mode.ts +8 -0
- package/src/prompts/agents/librarian.md +1 -1
- package/src/prompts/agents/reviewer.md +4 -4
- package/src/prompts/ci-green-request.md +1 -1
- package/src/prompts/review-request.md +1 -1
- package/src/prompts/system/subagent-system-prompt.md +3 -3
- package/src/prompts/system/subagent-yield-reminder.md +11 -0
- package/src/prompts/system/system-prompt.md +3 -0
- package/src/prompts/tools/ask.md +3 -2
- package/src/prompts/tools/ast-edit.md +15 -19
- package/src/prompts/tools/ast-grep.md +18 -24
- package/src/prompts/tools/atom.md +96 -0
- package/src/prompts/tools/chunk-edit.md +37 -161
- package/src/prompts/tools/debug.md +4 -5
- package/src/prompts/tools/exit-plan-mode.md +4 -5
- package/src/prompts/tools/find.md +4 -8
- package/src/prompts/tools/github.md +18 -0
- package/src/prompts/tools/grep.md +4 -5
- package/src/prompts/tools/hashline.md +22 -89
- package/src/prompts/tools/{gemini-image.md → image-gen.md} +1 -1
- package/src/prompts/tools/inspect-image.md +6 -6
- package/src/prompts/tools/lsp.md +1 -1
- package/src/prompts/tools/patch.md +12 -19
- package/src/prompts/tools/python.md +3 -2
- package/src/prompts/tools/read-chunk.md +2 -3
- package/src/prompts/tools/read.md +2 -2
- package/src/prompts/tools/ssh.md +8 -17
- package/src/prompts/tools/todo-write.md +54 -41
- package/src/sdk.ts +14 -9
- package/src/session/agent-session.ts +25 -2
- package/src/task/executor.ts +43 -48
- package/src/task/render.ts +11 -13
- package/src/tools/ask.ts +7 -7
- package/src/tools/ast-edit.ts +45 -41
- package/src/tools/ast-grep.ts +77 -85
- package/src/tools/bash.ts +8 -9
- package/src/tools/browser.ts +32 -30
- package/src/tools/calculator.ts +4 -4
- package/src/tools/cancel-job.ts +1 -1
- package/src/tools/checkpoint.ts +2 -2
- package/src/tools/debug.ts +41 -37
- package/src/tools/exit-plan-mode.ts +1 -1
- package/src/tools/find.ts +4 -4
- package/src/tools/gh-renderer.ts +12 -4
- package/src/tools/gh.ts +509 -697
- package/src/tools/grep.ts +115 -130
- package/src/tools/{gemini-image.ts → image-gen.ts} +459 -60
- package/src/tools/index.ts +14 -32
- package/src/tools/inspect-image.ts +3 -3
- package/src/tools/json-tree.ts +114 -114
- package/src/tools/match-line-format.ts +9 -8
- package/src/tools/notebook.ts +8 -7
- package/src/tools/poll-tool.ts +2 -1
- package/src/tools/python.ts +9 -23
- package/src/tools/read.ts +32 -21
- package/src/tools/render-mermaid.ts +1 -1
- package/src/tools/render-utils.ts +18 -0
- package/src/tools/renderers.ts +2 -2
- package/src/tools/report-tool-issue.ts +3 -2
- package/src/tools/resolve.ts +1 -1
- package/src/tools/review.ts +12 -10
- package/src/tools/search-tool-bm25.ts +2 -4
- package/src/tools/ssh.ts +4 -4
- package/src/tools/todo-write.ts +172 -147
- package/src/tools/vim.ts +14 -15
- package/src/tools/write.ts +4 -4
- package/src/tools/{submit-result.ts → yield.ts} +11 -13
- package/src/utils/edit-mode.ts +2 -1
- package/src/utils/file-display-mode.ts +10 -5
- package/src/utils/git.ts +9 -5
- package/src/utils/shell-snapshot.ts +2 -3
- package/src/vim/render.ts +4 -4
- package/src/prompts/system/subagent-submit-reminder.md +0 -11
- package/src/prompts/tools/gh-issue-view.md +0 -11
- package/src/prompts/tools/gh-pr-checkout.md +0 -12
- package/src/prompts/tools/gh-pr-diff.md +0 -12
- package/src/prompts/tools/gh-pr-push.md +0 -12
- package/src/prompts/tools/gh-pr-view.md +0 -11
- package/src/prompts/tools/gh-repo-view.md +0 -11
- package/src/prompts/tools/gh-run-watch.md +0 -12
- package/src/prompts/tools/gh-search-issues.md +0 -11
- package/src/prompts/tools/gh-search-prs.md +0 -11
|
@@ -19,15 +19,14 @@ Use when:
|
|
|
19
19
|
Presents plan to user for approval. If approved, plan mode exits with full tool access restored and the plan is renamed to `local://<title>.md`.
|
|
20
20
|
</output>
|
|
21
21
|
|
|
22
|
-
<
|
|
22
|
+
<examples>
|
|
23
|
+
# Ready
|
|
23
24
|
Plan complete at local://PLAN.md, no open questions.
|
|
24
25
|
→ Call `exit_plan_mode` with `{ "title": "WP_MIGRATION_PLAN" }`
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<example name="unclear">
|
|
26
|
+
# Unclear
|
|
28
27
|
Unsure about auth method (OAuth vs JWT).
|
|
29
28
|
→ Use `ask` first to clarify, then call `exit_plan_mode`
|
|
30
|
-
</
|
|
29
|
+
</examples>
|
|
31
30
|
|
|
32
31
|
<avoid>
|
|
33
32
|
- **MUST NOT** call before plan is written to file
|
|
@@ -8,14 +8,10 @@ Finds files using fast pattern matching that works with any codebase size.
|
|
|
8
8
|
Matching file paths sorted by modification time (most recent first). Truncated at 1000 entries or 50KB (configurable via `limit`).
|
|
9
9
|
</output>
|
|
10
10
|
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
{
|
|
14
|
-
|
|
15
|
-
"limit": 1000
|
|
16
|
-
}
|
|
17
|
-
```
|
|
18
|
-
</example>
|
|
11
|
+
<examples>
|
|
12
|
+
# Find files
|
|
13
|
+
`{"pattern": "src/**/*.ts", "limit": 1000}`
|
|
14
|
+
</examples>
|
|
19
15
|
|
|
20
16
|
<avoid>
|
|
21
17
|
For open-ended searches requiring multiple rounds of globbing and grepping, you **MUST** use Task tool instead.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
GitHub CLI tool with a single op-based dispatch. Wraps `gh` for repository, issue, pull request, search, checkout, push, and Actions watch workflows.
|
|
2
|
+
|
|
3
|
+
<instruction>
|
|
4
|
+
Pick the operation via `op`. Each op uses a subset of the parameters:
|
|
5
|
+
- `repo_view` — Read repository metadata. Optional `repo` (owner/repo) and `branch`. Falls back to the current checkout or default `gh` repo.
|
|
6
|
+
- `issue_view` — Read an issue. Required `issue` (number or URL). Optional `repo`. Set `comments: false` to skip discussion.
|
|
7
|
+
- `pr_view` — Read a pull request, including reviews and inline review comments. Optional `pr` (number, URL, or branch); omitting it targets the current branch's PR. Optional `repo`. Set `comments: false` for a lighter summary.
|
|
8
|
+
- `pr_diff` — Read a pull request diff. Optional `pr`, `repo`. Set `nameOnly: true` for changed file names. Use `exclude` to drop generated paths from the diff.
|
|
9
|
+
- `pr_checkout` — Check a pull request out into a dedicated git worktree. Optional `pr`, `repo`, `branch` (local), `worktree` (path), `force` (reset existing local branch).
|
|
10
|
+
- `pr_push` — Push a checked-out PR branch back to its source branch. Requires the branch to have been checked out via `op: pr_checkout` (carries push metadata). Optional `branch`; defaults to the current checked-out git branch. Optional `forceWithLease`.
|
|
11
|
+
- `search_issues` — Search issues using normal GitHub issue search syntax. Required `query`. Optional `repo`, `limit`.
|
|
12
|
+
- `search_prs` — Search pull requests using normal GitHub PR search syntax. Required `query`. Optional `repo`, `limit`.
|
|
13
|
+
- `run_watch` — Watch a GitHub Actions workflow run. Optional `run` (id or URL). Omitting `run` watches all workflow runs for the current HEAD commit; `branch` falls back to the current branch. Optional `tail` (log lines per failed job). Streams snapshots, fast-fails on the first detected job failure (with a brief grace period to capture concurrent failures), then fetches tailed logs for the failed jobs. The full failed-job logs are saved as a session artifact for on-demand reads.
|
|
14
|
+
</instruction>
|
|
15
|
+
|
|
16
|
+
<output>
|
|
17
|
+
Returns a concise readable summary tailored to the chosen op (repo/issue/PR metadata, diff text, search results, checkout info, push target, or workflow run snapshot). For `run_watch`, the full failed-job logs are saved as a session artifact when failures occur.
|
|
18
|
+
</output>
|
|
@@ -2,21 +2,20 @@ Searches files using powerful regex matching.
|
|
|
2
2
|
|
|
3
3
|
<instruction>
|
|
4
4
|
- Supports full regex syntax (e.g., `log.*Error`, `function\\s+\\w+`); literal braces need escaping (`interface\\{\\}` for `interface{}` in Go)
|
|
5
|
-
- `path`
|
|
6
|
-
-
|
|
7
|
-
- If the pattern contains a literal `\n`, `multiline` defaults to true automatically
|
|
5
|
+
- `path` is required and accepts a file, directory, glob, comma-separated path list, or internal URL
|
|
6
|
+
- Cross-line patterns are detected from literal `\n` or escaped `\\n` in `pattern`
|
|
8
7
|
</instruction>
|
|
9
8
|
|
|
10
9
|
<output>
|
|
11
10
|
{{#if IS_HASHLINE_MODE}}
|
|
12
|
-
- Text output is
|
|
11
|
+
- Text output is anchor-prefixed: `123th:content` (match) or `123th-content` (context). The 2-letter ID is a content fingerprint.
|
|
13
12
|
{{else}}
|
|
14
13
|
{{#if IS_LINE_NUMBER_MODE}}
|
|
15
14
|
- Text output is line-number-prefixed
|
|
16
15
|
{{/if}}
|
|
17
16
|
{{/if}}
|
|
18
17
|
{{#if IS_CHUNK_MODE}}
|
|
19
|
-
- Text output is chunk-path-prefixed: `path:
|
|
18
|
+
- Text output is chunk-path-prefixed: `path:sel>123th:content`
|
|
20
19
|
{{/if}}
|
|
21
20
|
</output>
|
|
22
21
|
|
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
Applies precise file edits using
|
|
1
|
+
Applies precise file edits using full anchors from `read` output (for example `160sr`).
|
|
2
2
|
|
|
3
|
-
Read the file first. Copy anchors exactly
|
|
3
|
+
Read the file first. Copy the full anchors exactly as shown by `read`.
|
|
4
4
|
|
|
5
5
|
<operations>
|
|
6
6
|
**Top level**
|
|
7
7
|
- `edits` — array of edit entries
|
|
8
|
+
- `path` (optional) — default file path used when an entry omits its own `path`. Lets you share the path across many edits in one request.
|
|
8
9
|
|
|
9
|
-
**Edit entry**: `{ path
|
|
10
|
-
- `path` — file path
|
|
10
|
+
**Edit entry**: `{ path?, loc, content }`
|
|
11
|
+
- `path` — file path (omit to fall back to the request-level `path`)
|
|
11
12
|
- `loc` — where to apply the edit (see below)
|
|
12
|
-
- `content` — replacement/inserted lines (
|
|
13
|
-
- `delete` — delete the file
|
|
14
|
-
- `move` — move/rename the file
|
|
13
|
+
- `content` — replacement/inserted lines (`string[]`, one element per line; `null` to delete)
|
|
15
14
|
|
|
16
15
|
**`loc` values**
|
|
17
16
|
- `"append"` / `"prepend"` — insert at end/start of file
|
|
18
|
-
- `{ append: "
|
|
19
|
-
- `{ range: { pos: "
|
|
17
|
+
- `{ append: "123th" }` / `{ prepend: "123th" }` — insert after/before anchored line
|
|
18
|
+
- `{ range: { pos: "123th", end: "123th" } }` — replace inclusive range `pos..end` with new content (set `pos == end` for single-line replace)
|
|
20
19
|
</operations>
|
|
21
20
|
|
|
22
21
|
<examples>
|
|
@@ -43,92 +42,26 @@ All examples below reference the same file:
|
|
|
43
42
|
{{hline 18 "}"}}
|
|
44
43
|
```
|
|
45
44
|
|
|
46
|
-
|
|
45
|
+
# Replace a block body
|
|
47
46
|
Replace only the catch body. Do not target the shared boundary line `} catch (err) {`.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
content: [
|
|
55
|
-
"\t\tif (isEnoent(err)) return null;",
|
|
56
|
-
"\t\tthrow err;"
|
|
57
|
-
]
|
|
58
|
-
}]
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
</example>
|
|
62
|
-
|
|
63
|
-
<example name="replace whole block including closing brace">
|
|
64
|
-
Replace the entire body of `alpha`, including its closing `}`. `end` **MUST** be {{href 7 "}"}} because `content` includes `}`.
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
{
|
|
68
|
-
edits: [{
|
|
69
|
-
path: "a.ts",
|
|
70
|
-
loc: { range: { pos: {{href 6 "\tlog();"}}, end: {{href 7 "}"}} } },
|
|
71
|
-
content: [
|
|
72
|
-
"\tvalidate();",
|
|
73
|
-
"\tlog();",
|
|
74
|
-
"}"
|
|
75
|
-
]
|
|
76
|
-
}]
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
**Wrong**: `end: {{href 6 "\tlog();"}}` with the same content — line 7 (`}`) survives AND content emits `}`, producing two closing braces.
|
|
81
|
-
</example>
|
|
82
|
-
|
|
83
|
-
<example name="replace one line">
|
|
47
|
+
`{edits:[{path:"a.ts",loc:{range:{pos:{{href 15 "\t\tconsole.error(err);"}},end:{{href 16 "\t\treturn null;"}}}},content:["\t\tif (isEnoent(err)) return null;","\t\tthrow err;"]}]}`
|
|
48
|
+
# Replace whole block including closing brace
|
|
49
|
+
Replace `alpha`'s entire body including the closing `}`. `end` **MUST** be {{href 7 "}"}} because `content` includes `}`.
|
|
50
|
+
`{edits:[{path:"a.ts",loc:{range:{pos:{{href 6 "\tlog();"}},end:{{href 7 "}"}}}},content:["\tvalidate();","\tlog();","}"]}]}`
|
|
51
|
+
**Wrong**: `end: {{href 6 "\tlog();"}}` — line 7 (`}`) survives AND content emits `}`, producing two closing braces.
|
|
52
|
+
# Replace one line
|
|
84
53
|
Single-line replace uses `pos == end`.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
{
|
|
88
|
-
|
|
89
|
-
path: "a.ts",
|
|
90
|
-
loc: { range: { pos: {{href 2 "const timeout = 5000;"}}, end: {{href 2 "const timeout = 5000;"}} } },
|
|
91
|
-
content: ["const timeout = 30_000;"]
|
|
92
|
-
}]
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
</example>
|
|
96
|
-
|
|
97
|
-
<example name="delete a range">
|
|
98
|
-
```
|
|
99
|
-
{
|
|
100
|
-
edits: [{
|
|
101
|
-
path: "a.ts",
|
|
102
|
-
loc: { range: { pos: {{href 10 "\t// TODO: remove after migration"}}, end: {{href 11 "\tlegacy();"}} } },
|
|
103
|
-
content: null
|
|
104
|
-
}]
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
</example>
|
|
108
|
-
|
|
109
|
-
<example name="insert before sibling">
|
|
54
|
+
`{edits:[{path:"a.ts",loc:{range:{pos:{{href 2 "const timeout = 5000;"}},end:{{href 2 "const timeout = 5000;"}}}},content:["const timeout = 30_000;"]}]}`
|
|
55
|
+
# Delete a range
|
|
56
|
+
`{edits:[{path:"a.ts",loc:{range:{pos:{{href 10 "\t// TODO: remove after migration"}},end:{{href 11 "\tlegacy();"}}}},content:null}]}`
|
|
57
|
+
# Insert before a sibling
|
|
110
58
|
When adding a sibling declaration, prefer `prepend` on the next declaration.
|
|
111
|
-
|
|
112
|
-
```
|
|
113
|
-
{
|
|
114
|
-
edits: [{
|
|
115
|
-
path: "a.ts",
|
|
116
|
-
loc: { prepend: {{href 9 "function beta() {"}} },
|
|
117
|
-
content: [
|
|
118
|
-
"function gamma() {",
|
|
119
|
-
"\tvalidate();",
|
|
120
|
-
"}",
|
|
121
|
-
""
|
|
122
|
-
]
|
|
123
|
-
}]
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
</example>
|
|
59
|
+
`{edits:[{path:"a.ts",loc:{prepend:{{href 9 "function beta() {"}}},content:["function gamma() {","\tvalidate();","}",""]}]}`
|
|
127
60
|
</examples>
|
|
128
61
|
|
|
129
62
|
<critical>
|
|
130
|
-
- Make the minimum exact edit.
|
|
131
|
-
- Copy anchors exactly as `
|
|
63
|
+
- Make the minimum exact edit.
|
|
64
|
+
- Copy the full anchors exactly as shown by `read/grep` (for example `160sr`, not just `sr`).
|
|
132
65
|
- `range` requires both `pos` and `end`.
|
|
133
66
|
- **Closing-delimiter check**: when your replacement `content` ends with a closing delimiter (`}`, `*/`, `)`, `]`), compare it against the line immediately after `end` in the file. If they match, extend `end` to include that line — otherwise the original delimiter survives and `content` adds a second copy.
|
|
134
67
|
- For a range, replace only the body or the whole range — don't split range boundaries.
|
|
@@ -12,12 +12,12 @@ Inspects an image file with a vision-capable model and returns compact text anal
|
|
|
12
12
|
</instruction>
|
|
13
13
|
|
|
14
14
|
<examples>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
21
|
</examples>
|
|
22
22
|
|
|
23
23
|
<output>
|
package/src/prompts/tools/lsp.md
CHANGED
|
@@ -36,4 +36,4 @@ Interacts with Language Server Protocol servers for code intelligence.
|
|
|
36
36
|
- You **MUST** use `lsp` for symbol-aware operations (rename, find references, go to definition/implementation, code actions) whenever a language server is available — it is safer and more accurate than text-based alternatives.
|
|
37
37
|
- You **MUST NOT** perform cross-file renames with `ast_edit`, `sed`, `rsed`, or manual edits when `lsp` `rename` can do it. Text-based renames miss shadowing, re-exports, and usages in other files.
|
|
38
38
|
- Prefer `lsp` `code_actions` for imports, quick-fixes, and refactors the language server already knows how to apply.
|
|
39
|
-
</critical>
|
|
39
|
+
</critical>
|
|
@@ -50,25 +50,18 @@ 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
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
<example name="delete">
|
|
66
|
-
edit {"edits":[{"path":"obsolete.txt","op":"delete"}]}
|
|
67
|
-
</example>
|
|
68
|
-
|
|
69
|
-
<example name="multi-file">
|
|
70
|
-
edit {"edits":[{"path":"src/types.ts","op":"update","diff":"@@\n-old\n+new\n"},{"path":"src/index.ts","op":"update","diff":"@@\n-old\n+new\n"}]}
|
|
71
|
-
</example>
|
|
53
|
+
<examples>
|
|
54
|
+
# Create
|
|
55
|
+
`edit {"edits":[{"path":"hello.txt","op":"create","diff":"Hello\n"}]}`
|
|
56
|
+
# Update
|
|
57
|
+
`edit {"edits":[{"path":"src/app.py","op":"update","diff":"@@ def greet():\n def greet():\n-print('Hi')\n+print('Hello')\n"}]}`
|
|
58
|
+
# Rename
|
|
59
|
+
`edit {"edits":[{"path":"src/app.py","op":"update","rename":"src/main.py","diff":"@@\n …\n"}]}`
|
|
60
|
+
# Delete
|
|
61
|
+
`edit {"edits":[{"path":"obsolete.txt","op":"delete"}]}`
|
|
62
|
+
# Multi-file
|
|
63
|
+
`edit {"edits":[{"path":"src/types.ts","op":"update","diff":"@@\n-old\n+new\n"},{"path":"src/index.ts","op":"update","diff":"@@\n-old\n+new\n"}]}`
|
|
64
|
+
</examples>
|
|
72
65
|
|
|
73
66
|
<avoid>
|
|
74
67
|
- Generic anchors: `import`, `export`, `describe`, `function`, `const`
|
|
@@ -44,7 +44,8 @@ User sees output like Jupyter notebook; rich displays render fully:
|
|
|
44
44
|
- You **MUST** use `run()` for shell commands; you **MUST NOT** use raw `subprocess`
|
|
45
45
|
</critical>
|
|
46
46
|
|
|
47
|
-
<
|
|
47
|
+
<examples>
|
|
48
|
+
# Multiple small cells
|
|
48
49
|
```python
|
|
49
50
|
cells: [
|
|
50
51
|
{"title": "imports", "code": "import json\nfrom pathlib import Path"},
|
|
@@ -53,4 +54,4 @@ cells: [
|
|
|
53
54
|
{"title": "use helper", "code": "configs = [parse_config(p) for p in Path('.').glob('*.json')]"}
|
|
54
55
|
]
|
|
55
56
|
```
|
|
56
|
-
</
|
|
57
|
+
</examples>
|
|
@@ -2,7 +2,6 @@ Reads files using syntax-aware chunks. Also inspects directories, archives, SQLi
|
|
|
2
2
|
|
|
3
3
|
<instruction>
|
|
4
4
|
The chunk-aware `read` variant returns AST-scoped chunks with current checksum IDs for structural editing, and otherwise behaves like `open` for non-code content.
|
|
5
|
-
|
|
6
5
|
- You **MUST** parallelize calls when exploring related files
|
|
7
6
|
- For URLs, `read` fetches the page and returns clean extracted text/markdown by default (reader-mode). It handles HTML pages, GitHub issues/PRs, Stack Overflow, Wikipedia, Reddit, NPM, arXiv, RSS/Atom, JSON endpoints, PDFs, etc. You **SHOULD** reach for `read` — not a browser/puppeteer tool — for fetching and inspecting web content.
|
|
8
7
|
|
|
@@ -17,7 +16,7 @@ The chunk-aware `read` variant returns AST-scoped chunks with current checksum I
|
|
|
17
16
|
|---|---|
|
|
18
17
|
|*(omitted)*|Read full file as chunks (up to {{DEFAULT_LIMIT}} lines)|
|
|
19
18
|
|`class_Foo`|Read a specific chunk|
|
|
20
|
-
|`class_Foo.fn_bar#
|
|
19
|
+
|`class_Foo.fn_bar#thth~`|Read a chunk region (body `~` / head `^`) by ID|
|
|
21
20
|
|`?`|List all chunk paths with IDs|
|
|
22
21
|
|`L50`|Read from line 50 onward (shorthand for L50 to EOF)|
|
|
23
22
|
|`L50-L120`|Read lines 50 through 120|
|
|
@@ -27,7 +26,7 @@ The chunk-aware `read` variant returns AST-scoped chunks with current checksum I
|
|
|
27
26
|
Max {{DEFAULT_MAX_LINES}} lines per call.
|
|
28
27
|
|
|
29
28
|
# Chunks
|
|
30
|
-
Each anchor `@full.chunk.path#
|
|
29
|
+
Each anchor `@full.chunk.path#thth` (with `-` prefixes for nesting depth) in the output identifies a chunk. Use `full.chunk.path#thth` as-is to read truncated chunks.
|
|
31
30
|
If you need a canonical target list, run `read(path="file", sel="?")`. That listing shows chunk paths with IDs and is the safest structural discovery mode. Summary lines in this listing are orientation hints; follow a selector with `read(path="file", sel="chunk#ID")` or use `raw` when you need exact source.
|
|
32
31
|
Line numbers in the gutter are absolute file line numbers.
|
|
33
32
|
|
|
@@ -18,13 +18,13 @@ The `read` tool is multi-purpose and more capable than it looks — inspects fil
|
|
|
18
18
|
|`L50`|Read from line 50 onward (shorthand for L50 to EOF)|
|
|
19
19
|
|`L50-L120`|Read lines 50 through 120|
|
|
20
20
|
|`L20-L20`|Read exactly one line|
|
|
21
|
-
|`raw`|
|
|
21
|
+
|`raw`|Skip line-numbering / hashline / chunking; return file content as plain text. For URLs: untouched HTML.|
|
|
22
22
|
|
|
23
23
|
Max {{DEFAULT_MAX_LINES}} lines per call.
|
|
24
24
|
|
|
25
25
|
# Filesystem
|
|
26
26
|
{{#if IS_HASHLINE_MODE}}
|
|
27
|
-
- Reading from FS returns lines prefixed with anchors: `
|
|
27
|
+
- Reading from FS returns lines prefixed with anchors: `41th:def alpha():` (line number, 2-letter ID, colon, then content)
|
|
28
28
|
{{else}}
|
|
29
29
|
{{#if IS_LINE_NUMBER_MODE}}
|
|
30
30
|
- Reading from FS returns lines prefixed with line numbers: `41:def alpha():`
|
package/src/prompts/tools/ssh.md
CHANGED
|
@@ -25,20 +25,11 @@ You **MUST** build commands from the reference below
|
|
|
25
25
|
You **MUST** verify the shell type from "Available hosts" and use matching commands.
|
|
26
26
|
</critical>
|
|
27
27
|
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
Host: server1 (10.0.0.1) | linux/bash
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Host: winbox (192.168.1.5) | windows/cmd
|
|
37
|
-
Command: `tasklist /v`
|
|
38
|
-
</example>
|
|
39
|
-
|
|
40
|
-
<example name="macos">
|
|
41
|
-
Task: Get system info on "macbook"
|
|
42
|
-
Host: macbook (10.0.0.20) | macos/zsh
|
|
43
|
-
Command: `uname -a && sw_vers`
|
|
44
|
-
</example>
|
|
28
|
+
<examples>
|
|
29
|
+
# List files: Linux
|
|
30
|
+
Host: server1 (10.0.0.1) | linux/bash. Command: `ls -la /home/user`
|
|
31
|
+
# Show running processes: Windows cmd
|
|
32
|
+
Host: winbox (192.168.1.5) | windows/cmd. Command: `tasklist /v`
|
|
33
|
+
# Get system info: macOS
|
|
34
|
+
Host: macbook (10.0.0.20) | macos/zsh. Command: `uname -a && sw_vers`
|
|
35
|
+
</examples>
|
|
@@ -1,28 +1,53 @@
|
|
|
1
|
-
Manages a phased task list
|
|
1
|
+
Manages a phased task list through an `ops` array of flat operations.
|
|
2
2
|
The next pending task is auto-promoted to `in_progress` after completing the current one.
|
|
3
3
|
|
|
4
4
|
<protocol>
|
|
5
|
-
##
|
|
5
|
+
## Shape
|
|
6
|
+
|
|
7
|
+
Pass an object with an `ops` array:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
{
|
|
11
|
+
ops: [
|
|
12
|
+
{ op: "replace", phases: [...] },
|
|
13
|
+
{ op: "start", task: "task-3" },
|
|
14
|
+
{ op: "done", phase: "Implementation" },
|
|
15
|
+
{ op: "rm" },
|
|
16
|
+
{ op: "drop", task: "task-9" },
|
|
17
|
+
{ op: "append", phase: "Implementation", items: [{ id: "task-10", label: "Run tests" }] },
|
|
18
|
+
],
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Operation fields
|
|
6
23
|
|
|
7
24
|
|Field|Type|When to use|
|
|
8
25
|
|---|---|---|
|
|
9
|
-
|`
|
|
10
|
-
|`
|
|
11
|
-
|`
|
|
12
|
-
|`
|
|
13
|
-
|`
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
26
|
+
|`op`|string|Required. One of `replace`, `start`, `done`, `rm`, `drop`, `append`|
|
|
27
|
+
|`task`|string|Task id for `start`, or a task target for `done` / `rm` / `drop`|
|
|
28
|
+
|`phase`|string|Phase target for `done` / `rm` / `drop`, or append destination for `append`|
|
|
29
|
+
|`items`|{id, label}[]|Required for `append`. If the phase does not exist, it is created at the end|
|
|
30
|
+
|`phases`|Phase[]|Only for `replace`. Keeps initial phased setup available for harness bootstrap and full restructures|
|
|
31
|
+
|
|
32
|
+
## Semantics
|
|
33
|
+
- `start`: requires `task`; sets that task to `in_progress`
|
|
34
|
+
- `done`: marks one task, one phase, or all tasks completed
|
|
35
|
+
- `rm`: removes one task, one phase's tasks, or all tasks
|
|
36
|
+
- `drop`: marks one task, one phase, or all tasks abandoned
|
|
37
|
+
- `append`: appends `items` to `phase`; creates the phase if missing
|
|
38
|
+
- `replace`: replaces the full todo list
|
|
39
|
+
|
|
40
|
+
If `done`, `rm`, or `drop` omits both `task` and `phase`, it applies to all tasks.
|
|
17
41
|
|
|
18
42
|
## Task Anatomy
|
|
19
|
-
- `
|
|
20
|
-
- `
|
|
43
|
+
- `label`: Short label (5-10 words). What is being done, not how.
|
|
44
|
+
- `replace` task `content` should stay short and specific.
|
|
21
45
|
|
|
22
46
|
## Rules
|
|
23
|
-
- Mark tasks
|
|
24
|
-
- Complete phases in order — do not skip ahead while earlier ones are pending
|
|
25
|
-
- On blockers
|
|
47
|
+
- Mark tasks done immediately after finishing — never defer.
|
|
48
|
+
- Complete phases in order — do not skip ahead while earlier ones are pending.
|
|
49
|
+
- On blockers, append a new task to the active phase.
|
|
50
|
+
- Keep ids stable once introduced.
|
|
26
51
|
</protocol>
|
|
27
52
|
|
|
28
53
|
<conditions>
|
|
@@ -33,32 +58,20 @@ Create a todo list when:
|
|
|
33
58
|
4. New instructions arrive mid-task — capture before proceeding
|
|
34
59
|
</conditions>
|
|
35
60
|
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
]}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
{
|
|
49
|
-
</
|
|
50
|
-
|
|
51
|
-
<example name="add-task">
|
|
52
|
-
{add_tasks: [{phase: "Implementation", content: "Handle retries", details: "Cap exponential backoff in retry.ts"}]}
|
|
53
|
-
</example>
|
|
54
|
-
|
|
55
|
-
<example name="add-phase">
|
|
56
|
-
{add_phase: {name: "Cleanup", tasks: [{content: "Remove dead code"}]}}
|
|
57
|
-
</example>
|
|
58
|
-
|
|
59
|
-
<example name="combined">
|
|
60
|
-
{complete: ["task-2"], add_notes: [{id: "task-3", notes: "Needs extra validation"}]}
|
|
61
|
-
</example>
|
|
61
|
+
<examples>
|
|
62
|
+
# Initial setup
|
|
63
|
+
`{"ops":[{"op":"replace","phases":[{"name":"Investigation","tasks":[{"content":"Read source"},{"content":"Map callsites"}]},{"name":"Implementation","tasks":[{"content":"Apply fix"},{"content":"Run tests"}]}]}]}`
|
|
64
|
+
# Complete one task
|
|
65
|
+
`{"ops":[{"op":"done","task":"task-2"}]}`
|
|
66
|
+
# Complete a whole phase
|
|
67
|
+
`{"ops":[{"op":"done","phase":"Implementation"}]}`
|
|
68
|
+
# Remove all tasks
|
|
69
|
+
`{"ops":[{"op":"rm"}]}`
|
|
70
|
+
# Drop one task
|
|
71
|
+
`{"ops":[{"op":"drop","task":"task-7"}]}`
|
|
72
|
+
# Append tasks to a phase
|
|
73
|
+
`{"ops":[{"op":"append","phase":"Implementation","items":[{"id":"task-8","label":"Handle retries"},{"id":"task-9","label":"Run tests"}]}]}`
|
|
74
|
+
</examples>
|
|
62
75
|
|
|
63
76
|
<avoid>
|
|
64
77
|
- Single-step tasks — act directly
|
package/src/sdk.ts
CHANGED
|
@@ -128,7 +128,7 @@ import {
|
|
|
128
128
|
warmupLspServers,
|
|
129
129
|
} from "./tools";
|
|
130
130
|
import { ToolContextStore } from "./tools/context";
|
|
131
|
-
import {
|
|
131
|
+
import { getImageGenTools } from "./tools/image-gen";
|
|
132
132
|
import { wrapToolWithMetaNotice } from "./tools/output-meta";
|
|
133
133
|
import { queueResolveHandler } from "./tools/resolve";
|
|
134
134
|
import { EventBus } from "./utils/event-bus";
|
|
@@ -209,8 +209,8 @@ export interface CreateAgentSessionOptions {
|
|
|
209
209
|
|
|
210
210
|
/** Output schema for structured completion (subagents) */
|
|
211
211
|
outputSchema?: unknown;
|
|
212
|
-
/** Whether to include the
|
|
213
|
-
|
|
212
|
+
/** Whether to include the yield tool by default */
|
|
213
|
+
requireYieldTool?: boolean;
|
|
214
214
|
/** Task recursion depth (for subagent sessions). Default: 0 */
|
|
215
215
|
taskDepth?: number;
|
|
216
216
|
/** Parent task ID prefix for nested artifact naming (e.g., "6-Extensions") */
|
|
@@ -673,7 +673,12 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
673
673
|
}
|
|
674
674
|
|
|
675
675
|
const imageProvider = settings.get("providers.image");
|
|
676
|
-
if (
|
|
676
|
+
if (
|
|
677
|
+
imageProvider === "auto" ||
|
|
678
|
+
imageProvider === "openai" ||
|
|
679
|
+
imageProvider === "gemini" ||
|
|
680
|
+
imageProvider === "openrouter"
|
|
681
|
+
) {
|
|
677
682
|
setPreferredImageProvider(imageProvider);
|
|
678
683
|
}
|
|
679
684
|
|
|
@@ -916,7 +921,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
916
921
|
skills,
|
|
917
922
|
eventBus,
|
|
918
923
|
outputSchema: options.outputSchema,
|
|
919
|
-
|
|
924
|
+
requireYieldTool: options.requireYieldTool,
|
|
920
925
|
taskDepth: options.taskDepth ?? 0,
|
|
921
926
|
getSessionFile: () => sessionManager.getSessionFile() ?? null,
|
|
922
927
|
getPythonKernelOwnerId: () => pythonKernelOwnerId,
|
|
@@ -1047,10 +1052,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1047
1052
|
}
|
|
1048
1053
|
toolSession.mcpManager = mcpManager;
|
|
1049
1054
|
|
|
1050
|
-
// Add
|
|
1051
|
-
const
|
|
1052
|
-
if (
|
|
1053
|
-
customTools.push(...(
|
|
1055
|
+
// Add image tools when the active model or configured image providers can generate images.
|
|
1056
|
+
const imageGenTools = await logger.time("getImageGenTools", () => getImageGenTools(modelRegistry, model));
|
|
1057
|
+
if (imageGenTools.length > 0) {
|
|
1058
|
+
customTools.push(...(imageGenTools as unknown as CustomTool[]));
|
|
1054
1059
|
}
|
|
1055
1060
|
|
|
1056
1061
|
// Add web search tools
|
|
@@ -525,6 +525,7 @@ export class AgentSession {
|
|
|
525
525
|
#obfuscator: SecretObfuscator | undefined;
|
|
526
526
|
#checkpointState: CheckpointState | undefined = undefined;
|
|
527
527
|
#pendingRewindReport: string | undefined = undefined;
|
|
528
|
+
#lastSuccessfulYieldToolCallId: string | undefined = undefined;
|
|
528
529
|
#promptGeneration = 0;
|
|
529
530
|
#providerSessionState = new Map<string, ProviderSessionState>();
|
|
530
531
|
|
|
@@ -789,6 +790,9 @@ export class AgentSession {
|
|
|
789
790
|
this.#toolChoiceQueue.resolve();
|
|
790
791
|
}
|
|
791
792
|
}
|
|
793
|
+
if (event.type === "tool_execution_end" && event.toolName === "yield" && !event.isError) {
|
|
794
|
+
this.#lastSuccessfulYieldToolCallId = event.toolCallId;
|
|
795
|
+
}
|
|
792
796
|
if (event.type === "turn_end" && this.#pendingRewindReport) {
|
|
793
797
|
const report = this.#pendingRewindReport;
|
|
794
798
|
this.#pendingRewindReport = undefined;
|
|
@@ -1026,7 +1030,10 @@ export class AgentSession {
|
|
|
1026
1030
|
.find((message): message is AssistantMessage => message.role === "assistant");
|
|
1027
1031
|
const msg = this.#lastAssistantMessage ?? fallbackAssistant;
|
|
1028
1032
|
this.#lastAssistantMessage = undefined;
|
|
1029
|
-
if (!msg)
|
|
1033
|
+
if (!msg) {
|
|
1034
|
+
this.#lastSuccessfulYieldToolCallId = undefined;
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1030
1037
|
|
|
1031
1038
|
// Invalidate GitHub Copilot credentials on auth failure so stale tokens
|
|
1032
1039
|
// aren't reused on the next request
|
|
@@ -1040,8 +1047,15 @@ export class AgentSession {
|
|
|
1040
1047
|
|
|
1041
1048
|
if (this.#skipPostTurnMaintenanceAssistantTimestamp === msg.timestamp) {
|
|
1042
1049
|
this.#skipPostTurnMaintenanceAssistantTimestamp = undefined;
|
|
1050
|
+
this.#lastSuccessfulYieldToolCallId = undefined;
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
if (this.#assistantEndedWithSuccessfulYield(msg)) {
|
|
1055
|
+
this.#lastSuccessfulYieldToolCallId = undefined;
|
|
1043
1056
|
return;
|
|
1044
1057
|
}
|
|
1058
|
+
this.#lastSuccessfulYieldToolCallId = undefined;
|
|
1045
1059
|
|
|
1046
1060
|
// Check for retryable errors first (overloaded, rate limit, server errors)
|
|
1047
1061
|
if (this.#isRetryableError(msg)) {
|
|
@@ -3227,7 +3241,6 @@ export class AgentSession {
|
|
|
3227
3241
|
id: task.id,
|
|
3228
3242
|
content: task.content,
|
|
3229
3243
|
status: task.status,
|
|
3230
|
-
notes: task.notes,
|
|
3231
3244
|
})),
|
|
3232
3245
|
}));
|
|
3233
3246
|
}
|
|
@@ -4230,6 +4243,16 @@ export class AgentSession {
|
|
|
4230
4243
|
}
|
|
4231
4244
|
}
|
|
4232
4245
|
}
|
|
4246
|
+
#assistantEndedWithSuccessfulYield(assistantMessage: AssistantMessage): boolean {
|
|
4247
|
+
const toolCallId = this.#lastSuccessfulYieldToolCallId;
|
|
4248
|
+
if (!toolCallId) return false;
|
|
4249
|
+
const lastToolCall = assistantMessage.content
|
|
4250
|
+
.slice()
|
|
4251
|
+
.reverse()
|
|
4252
|
+
.find((content): content is ToolCall => content.type === "toolCall");
|
|
4253
|
+
return lastToolCall?.name === "yield" && lastToolCall.id === toolCallId;
|
|
4254
|
+
}
|
|
4255
|
+
|
|
4233
4256
|
#enforceRewindBeforeYield(): boolean {
|
|
4234
4257
|
if (!this.#checkpointState || this.#pendingRewindReport) {
|
|
4235
4258
|
return false;
|