@oh-my-pi/pi-coding-agent 11.0.3 → 11.2.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 +199 -49
- package/README.md +1 -1
- package/docs/config-usage.md +3 -4
- package/docs/sdk.md +6 -5
- package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
- package/examples/sdk/README.md +1 -1
- package/package.json +19 -11
- package/src/cli/args.ts +11 -94
- package/src/cli/config-cli.ts +1 -1
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/oclif-help.ts +26 -0
- package/src/cli/web-search-cli.ts +148 -0
- package/src/cli.ts +8 -2
- package/src/commands/commit.ts +36 -0
- package/src/commands/config.ts +51 -0
- package/src/commands/grep.ts +41 -0
- package/src/commands/index/index.ts +136 -0
- package/src/commands/jupyter.ts +32 -0
- package/src/commands/plugin.ts +70 -0
- package/src/commands/setup.ts +39 -0
- package/src/commands/shell.ts +29 -0
- package/src/commands/stats.ts +29 -0
- package/src/commands/update.ts +21 -0
- package/src/commands/web-search.ts +50 -0
- package/src/commit/agentic/index.ts +3 -2
- package/src/commit/agentic/tools/analyze-file.ts +1 -3
- package/src/commit/git/errors.ts +4 -6
- package/src/commit/pipeline.ts +3 -2
- package/src/config/keybindings.ts +1 -3
- package/src/config/model-registry.ts +89 -162
- package/src/config/settings-schema.ts +10 -0
- package/src/config.ts +202 -132
- package/src/exa/mcp-client.ts +8 -41
- package/src/export/html/index.ts +1 -1
- package/src/extensibility/extensions/loader.ts +7 -10
- package/src/extensibility/extensions/runner.ts +5 -15
- package/src/extensibility/extensions/types.ts +1 -1
- package/src/extensibility/hooks/runner.ts +6 -9
- package/src/index.ts +0 -1
- package/src/ipy/kernel.ts +10 -22
- package/src/lsp/clients/biome-client.ts +4 -7
- package/src/lsp/clients/lsp-linter-client.ts +4 -6
- package/src/lsp/index.ts +5 -4
- package/src/lsp/utils.ts +18 -0
- package/src/main.ts +86 -181
- package/src/mcp/json-rpc.ts +2 -2
- package/src/mcp/transports/http.ts +12 -49
- package/src/modes/components/armin.ts +1 -3
- package/src/modes/components/assistant-message.ts +4 -4
- package/src/modes/components/bash-execution.ts +5 -3
- package/src/modes/components/branch-summary-message.ts +1 -3
- package/src/modes/components/compaction-summary-message.ts +1 -3
- package/src/modes/components/custom-message.ts +4 -5
- package/src/modes/components/extensions/extension-dashboard.ts +10 -16
- package/src/modes/components/extensions/extension-list.ts +5 -5
- package/src/modes/components/footer.ts +1 -4
- package/src/modes/components/hook-editor.ts +7 -32
- package/src/modes/components/hook-message.ts +4 -5
- package/src/modes/components/model-selector.ts +2 -2
- package/src/modes/components/plugin-settings.ts +16 -20
- package/src/modes/components/python-execution.ts +5 -5
- package/src/modes/components/session-selector.ts +6 -7
- package/src/modes/components/settings-defs.ts +49 -40
- package/src/modes/components/settings-selector.ts +8 -17
- package/src/modes/components/skill-message.ts +1 -3
- package/src/modes/components/status-line-segment-editor.ts +1 -3
- package/src/modes/components/status-line.ts +1 -3
- package/src/modes/components/todo-reminder.ts +5 -7
- package/src/modes/components/tree-selector.ts +10 -12
- package/src/modes/components/ttsr-notification.ts +1 -3
- package/src/modes/components/user-message-selector.ts +2 -4
- package/src/modes/components/welcome.ts +6 -18
- package/src/modes/controllers/event-controller.ts +1 -0
- package/src/modes/controllers/extension-ui-controller.ts +1 -1
- package/src/modes/controllers/input-controller.ts +7 -34
- package/src/modes/controllers/selector-controller.ts +3 -3
- package/src/modes/interactive-mode.ts +27 -1
- package/src/modes/rpc/rpc-client.ts +2 -5
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/theme/theme.ts +2 -6
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +6 -1
- package/src/patch/index.ts +1 -4
- package/src/prompts/agents/explore.md +1 -0
- package/src/prompts/agents/frontmatter.md +2 -1
- package/src/prompts/agents/init.md +1 -0
- package/src/prompts/agents/plan.md +1 -0
- package/src/prompts/agents/reviewer.md +1 -0
- package/src/prompts/system/subagent-submit-reminder.md +2 -0
- package/src/prompts/system/subagent-system-prompt.md +2 -0
- package/src/prompts/system/subagent-user-prompt.md +8 -0
- package/src/prompts/system/system-prompt.md +5 -3
- package/src/prompts/system/web-search.md +6 -4
- package/src/prompts/tools/task.md +216 -163
- package/src/sdk.ts +11 -110
- package/src/session/agent-session.ts +117 -83
- package/src/session/auth-storage.ts +10 -51
- package/src/session/messages.ts +17 -3
- package/src/session/session-manager.ts +30 -30
- package/src/session/streaming-output.ts +1 -1
- package/src/ssh/ssh-executor.ts +6 -3
- package/src/task/agents.ts +2 -0
- package/src/task/discovery.ts +1 -1
- package/src/task/executor.ts +5 -10
- package/src/task/index.ts +43 -23
- package/src/task/render.ts +67 -64
- package/src/task/template.ts +17 -34
- package/src/task/types.ts +49 -22
- package/src/tools/ask.ts +1 -3
- package/src/tools/bash.ts +1 -4
- package/src/tools/browser.ts +5 -7
- package/src/tools/exit-plan-mode.ts +1 -4
- package/src/tools/fetch.ts +1 -3
- package/src/tools/find.ts +4 -3
- package/src/tools/gemini-image.ts +24 -55
- package/src/tools/grep.ts +4 -4
- package/src/tools/index.ts +12 -14
- package/src/tools/notebook.ts +1 -5
- package/src/tools/python.ts +4 -3
- package/src/tools/read.ts +2 -4
- package/src/tools/render-utils.ts +23 -0
- package/src/tools/ssh.ts +8 -12
- package/src/tools/todo-write.ts +1 -4
- package/src/tools/tool-errors.ts +1 -4
- package/src/tools/write.ts +1 -3
- package/src/utils/external-editor.ts +59 -0
- package/src/utils/file-mentions.ts +39 -1
- package/src/utils/image-convert.ts +1 -1
- package/src/utils/image-resize.ts +4 -4
- package/src/web/search/auth.ts +3 -33
- package/src/web/search/index.ts +73 -139
- package/src/web/search/provider.ts +58 -0
- package/src/web/search/providers/anthropic.ts +53 -14
- package/src/web/search/providers/base.ts +22 -0
- package/src/web/search/providers/codex.ts +38 -16
- package/src/web/search/providers/exa.ts +30 -6
- package/src/web/search/providers/gemini.ts +56 -20
- package/src/web/search/providers/jina.ts +28 -5
- package/src/web/search/providers/perplexity.ts +103 -36
- package/src/web/search/render.ts +84 -74
- package/src/web/search/types.ts +285 -59
- package/src/migrations.ts +0 -175
- package/src/session/storage-migration.ts +0 -173
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Research assistant with web search capabilities. Find accurate, well-sourced information; synthesize into
|
|
1
|
+
Research assistant with web search capabilities. Find accurate, well-sourced information; synthesize into comprehensive, detailed answers.
|
|
2
2
|
|
|
3
3
|
<priorities>
|
|
4
4
|
1. Accuracy over speed — verify claims across multiple sources when possible
|
|
@@ -14,13 +14,15 @@ Answering:
|
|
|
14
14
|
- Sources conflict: acknowledge discrepancy, note which seems more authoritative
|
|
15
15
|
- Technical topics: prefer official documentation and specifications
|
|
16
16
|
- News/events: prefer primary reporting over aggregators
|
|
17
|
+
- Include concrete data: version numbers, dates, exact figures, code snippets, and specific examples
|
|
17
18
|
</synthesis>
|
|
18
19
|
|
|
19
20
|
<format>
|
|
20
|
-
-
|
|
21
|
+
- Be thorough — cover the topic in depth with specific evidence, not surface-level summaries
|
|
22
|
+
- Omit filler phrases and unnecessary hedging, but do not sacrifice detail for brevity
|
|
21
23
|
- Include publication dates when recency affects relevance
|
|
22
|
-
- Structure
|
|
24
|
+
- Structure answers with clear sections when covering multiple aspects
|
|
23
25
|
- Cite sources inline using provided search results
|
|
24
26
|
</format>
|
|
25
27
|
|
|
26
|
-
Answer thoroughly. Get facts right.
|
|
28
|
+
Answer thoroughly and in detail. Get facts right.
|
|
@@ -1,212 +1,265 @@
|
|
|
1
1
|
# Task
|
|
2
2
|
|
|
3
|
-
Launch
|
|
3
|
+
Launch subagents to execute parallel, well-scoped tasks with shared, token-efficient context.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
## Context is everything
|
|
5
|
+
Subagents have **zero implicit context** — they see only `context` + `assignment`. Treat every subagent as a senior engineer on day one: technically strong, but unfamiliar with every decision, convention, and file layout you've accumulated.
|
|
7
6
|
|
|
8
|
-
Subagents
|
|
9
|
-
1. **Goal** - What this accomplishes (one sentence)
|
|
10
|
-
2. **Constraints** - Hard requirements, banned approaches, naming conventions
|
|
11
|
-
3. **Existing Code** - File paths and function signatures to use as patterns
|
|
12
|
-
4. **API Contract** - If the task produces or consumes an interface, spell it out
|
|
13
|
-
|
|
14
|
-
Subagents CAN grep parent conversation file for supplementary details, but CANNOT grep for:
|
|
7
|
+
Subagents CAN grep the parent conversation file for supplementary details, but CANNOT grep for:
|
|
15
8
|
- Decisions you made but didn't write down
|
|
16
9
|
- Conventions that exist only in your head
|
|
17
10
|
- Which of 50 possible approaches you want
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Parameters
|
|
14
|
+
|
|
15
|
+
### `agent` (required)
|
|
16
|
+
|
|
17
|
+
Agent type for all tasks in this batch.
|
|
18
|
+
|
|
19
|
+
### `context` (optional — strongly recommended)
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
## Required context structure
|
|
21
|
+
Shared background prepended verbatim to every task `assignment`. Common info once; reduces token cost.
|
|
23
22
|
|
|
24
|
-
Use
|
|
23
|
+
Use template; omit non-applicable sections.
|
|
25
24
|
|
|
26
25
|
````
|
|
27
26
|
## Goal
|
|
28
|
-
|
|
27
|
+
One sentence: batch accomplishes together.
|
|
28
|
+
|
|
29
|
+
## Non-goals
|
|
30
|
+
Explicitly exclude tempting scope — what tasks must not touch/attempt.
|
|
29
31
|
|
|
30
32
|
## Constraints
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
33
|
+
- MUST / MUST NOT rules (naming, error handling, banned approaches)
|
|
34
|
+
- Language/framework version requirements
|
|
35
|
+
- What exists vs what to create
|
|
34
36
|
|
|
35
|
-
##
|
|
36
|
-
|
|
37
|
-
- `path/to/
|
|
38
|
-
- `path/to/other.rs` - [what to reuse from it]
|
|
37
|
+
## Reference Files
|
|
38
|
+
- `path/to/file.ext` — pattern demo
|
|
39
|
+
- `path/to/other.ext` — reuse or avoid
|
|
39
40
|
|
|
40
|
-
## API Contract (if
|
|
41
|
+
## API Contract (if tasks produce/consume shared interface)
|
|
41
42
|
```language
|
|
42
|
-
// Exact
|
|
43
|
-
fn example(input: Type) -> Result<Output>
|
|
43
|
+
// Exact type definitions, function signatures, interface shapes
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
##
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
## Files
|
|
50
|
-
{{files}}
|
|
46
|
+
## Acceptance (global)
|
|
47
|
+
- Definition of "done" for batch
|
|
48
|
+
- Note: build/test/lint verification happens AFTER all tasks complete — not inside tasks (see below)
|
|
51
49
|
````
|
|
50
|
+
**Belongs in `context`**: project goal, non-goals, constraints, conventions, reference paths, shared type definitions, API contracts, global acceptance commands — anything 2+ tasks need.
|
|
51
|
+
**Rule of thumb:** if repeat in 2+ tasks, belongs in `context`.
|
|
52
|
+
**Does NOT belong in `context`**: per-task file lists, one-off requirements (go in `assignment`), structured output format (goes in `schema`).
|
|
53
|
+
|
|
54
|
+
### `tasks` (required)
|
|
55
|
+
|
|
56
|
+
Array tasks execute in parallel.
|
|
57
|
+
|
|
58
|
+
|Field|Required|Purpose|
|
|
59
|
+
|---|---|---|
|
|
60
|
+
|`id`|✓|CamelCase identifier, max 32 chars|
|
|
61
|
+
|`description`|✓|Short one-liner for UI display only — not seen by subagent|
|
|
62
|
+
|`assignment`|✓|Complete per-task instructions. See [Writing an assignment](#writing-an-assignment).|
|
|
63
|
+
|`skills`||Skill names preload. Use only when changes correctness — don’t spam every task.|
|
|
52
64
|
|
|
53
|
-
|
|
65
|
+
{{#if isolationEnabled}}
|
|
66
|
+
### `isolated` (optional)
|
|
67
|
+
|
|
68
|
+
Run in isolated git worktree; returns patches. Use when tasks edit overlapping files or when you want clean per-task diffs.
|
|
69
|
+
{{/if}}
|
|
70
|
+
### `schema` (optional — recommended for structured output)
|
|
71
|
+
|
|
72
|
+
JTD schema defining expected response structure. Use typed properties. If you care about parsing result, define here — **never describe output format in `context` or `assignment`**.
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Writing an assignment
|
|
76
|
+
|
|
77
|
+
<critical>## Task scope
|
|
78
|
+
|
|
79
|
+
`assignment` must contain enough info for agent to act **without asking a clarifying question**.
|
|
80
|
+
**Minimum bar:** assignment under ~8 lines or missing acceptance criteria = too vague. One-liners guaranteed failure.
|
|
81
|
+
|
|
82
|
+
Use structure every assignment:
|
|
54
83
|
|
|
55
84
|
```
|
|
56
|
-
|
|
57
|
-
|
|
85
|
+
## Target
|
|
86
|
+
- Files: exact path(s)
|
|
87
|
+
- Symbols/entrypoints: specific functions, types, exports
|
|
88
|
+
- Non-goals: what task must NOT touch (prevents scope creep)
|
|
89
|
+
|
|
90
|
+
## Change
|
|
91
|
+
- Step-by-step: add/remove/rename/restructure
|
|
92
|
+
- Patterns/APIs to use; reference files if applicable
|
|
93
|
+
|
|
94
|
+
## Edge Cases / Don't Break
|
|
95
|
+
- Tricky case 1: ...
|
|
96
|
+
- Tricky case 2: ...
|
|
97
|
+
- Existing behavior must survive: ...
|
|
98
|
+
|
|
99
|
+
## Acceptance (task-local)
|
|
100
|
+
- Expected behavior or observable result
|
|
101
|
+
- DO NOT include project-wide build/test/lint commands (see below)
|
|
58
102
|
```
|
|
59
103
|
|
|
60
|
-
|
|
104
|
+
`context` carries shared background. `assignment` carries only delta: file-specific instructions, local edge cases, per-task acceptance checks. Never duplicate shared constraints across assignments.
|
|
61
105
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
106
|
+
### Anti-patterns (ban these)
|
|
107
|
+
**Vague assignments** — agent guesses wrong or stalls:
|
|
108
|
+
- "Refactor this to be cleaner."
|
|
109
|
+
- "Migrate to N-API."
|
|
110
|
+
- "Fix the bug in streaming."
|
|
111
|
+
- "Update all constructors in `src/**/*.ts`."
|
|
112
|
+
**Vague context** — forces agent invent conventions:
|
|
113
|
+
- "Use existing patterns."
|
|
114
|
+
- "Follow conventions."
|
|
115
|
+
- "No WASM."
|
|
65
116
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
117
|
+
If tempted to write above, expand using templates.
|
|
118
|
+
**Test/lint commands in parallel tasks** — edit wars:
|
|
119
|
+
Parallel agents share working tree. If two agents run `bun check` or `bun test` concurrently, they see each other's half-finished edits, "fix" phantom errors, loop. **Never tell parallel tasks run project-wide build/test/lint commands.** Each task edits, stops. Caller verifies after all tasks complete.
|
|
120
|
+
**If you can’t specify scope yet**, create **Discovery task** first: enumerate files, find callsites, list candidates. Then fan out with explicit paths.
|
|
121
|
+
|
|
122
|
+
### Delegate intent, not keystrokes
|
|
123
|
+
|
|
124
|
+
Your role as tech lead: set direction, define boundaries, call out pitfalls — then get out of way. Don’t read every file, decide every edit, dictate line-by-line. That makes you bottleneck; agent typist.
|
|
125
|
+
**Be specific about:** constraints, naming conventions, API contracts, "don’t break" items, acceptance criteria.
|
|
126
|
+
**Delegate:** code reading, approach selection, exact edit locations, implementation details. Agent has tools, can reason about code.
|
|
127
|
+
|
|
128
|
+
Micromanaging (you think, agent types):
|
|
129
|
+
```
|
|
130
|
+
assignment: "In src/api/handler.ts, line 47, change `throw err` to `throw new ApiError(err.message, 500)`.
|
|
131
|
+
On line 63, wrap fetch call try/catch return 502 on failure.
|
|
132
|
+
On line 89, add null check before accessing resp.body..."
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Delegating (agent thinks within constraints):
|
|
136
|
+
```
|
|
137
|
+
assignment: "## Target\n- Files: src/api/handler.ts\n\n## Change\nImprove error handling: replace raw throws
|
|
138
|
+
with typed ApiError instances, add try/catch around external calls, guard against null responses.\n\n
|
|
139
|
+
## Edge Cases / Don't Break\n- Existing error codes in tests must still match\n
|
|
140
|
+
- Don't change public function signatures"
|
|
89
141
|
```
|
|
90
142
|
|
|
91
|
-
|
|
92
|
-
|
|
143
|
+
First style wastes your time, brittle if code shifts. Second gives agent room to do work.
|
|
144
|
+
</critical>
|
|
93
145
|
|
|
94
|
-
##
|
|
95
|
-
{{files}}
|
|
96
|
-
````
|
|
97
|
-
</context-structure>
|
|
146
|
+
## Example
|
|
98
147
|
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
148
|
+
<example type="bad" label="Duplicated context inflates tokens">
|
|
149
|
+
<tasks>
|
|
150
|
+
<task name="Grep">
|
|
151
|
+
<description>Port grep module from WASM to N-API...</description>
|
|
152
|
+
<assignment>Port grep module from WASM to N-API... (same blob repeated)</assignment>
|
|
153
|
+
</task>
|
|
154
|
+
</tasks>
|
|
155
|
+
</example>
|
|
104
156
|
|
|
105
|
-
|
|
157
|
+
<example type="good" label="Shared rules in context, only deltas in assignment">
|
|
158
|
+
<context>
|
|
159
|
+
## Goal
|
|
160
|
+
Port WASM modules to N-API, matching existing pi-natives conventions.
|
|
161
|
+
|
|
162
|
+
## Non-goals
|
|
163
|
+
Do not touch TS bindings or downstream consumers — separate phase.
|
|
106
164
|
|
|
107
|
-
|
|
165
|
+
## Constraints
|
|
166
|
+
- MUST use `#[napi]` attribute macro on all exports
|
|
167
|
+
- MUST return `napi::Result<T>` for fallible ops; never panic
|
|
168
|
+
- MUST use `spawn_blocking` for filesystem I/O or >1ms work
|
|
169
|
+
...
|
|
170
|
+
|
|
171
|
+
## Acceptance (global)
|
|
172
|
+
- Caller verifies after all tasks: `cargo test -p pi-natives` and `cargo build -p pi-natives` with no warnings
|
|
173
|
+
- Individual tasks must NOT run these commands themselves
|
|
174
|
+
</context>
|
|
175
|
+
|
|
176
|
+
<tasks>
|
|
177
|
+
<task name="PortGrep">
|
|
178
|
+
<description>Port grep module to N-API</description>
|
|
179
|
+
<assignment>
|
|
180
|
+
## Target
|
|
181
|
+
- Files: `src/grep.rs`, `src/lib.rs` (registration only)
|
|
182
|
+
- Symbols: search, search_multi, compile_pattern
|
|
183
|
+
|
|
184
|
+
## Change
|
|
185
|
+
- Implement three N-API exports in grep.rs:
|
|
186
|
+
- `search(pattern: JsString, path: JsString, env: Env) -> napi::Result<Vec<Match>>`
|
|
187
|
+
...
|
|
188
|
+
|
|
189
|
+
## Acceptance (task-local)
|
|
190
|
+
- Three functions exported with correct signatures (caller verifies build after all tasks)
|
|
191
|
+
</assignment>
|
|
192
|
+
</task>
|
|
193
|
+
|
|
194
|
+
<task name="PortHighlight">
|
|
195
|
+
<description>Port highlight module to N-API</description>
|
|
196
|
+
<assignment>
|
|
197
|
+
## Target
|
|
198
|
+
- Files: `src/highlight.rs`, `src/lib.rs` (registration only)
|
|
199
|
+
...
|
|
200
|
+
</assignment>
|
|
201
|
+
</task>
|
|
202
|
+
</tasks>
|
|
203
|
+
</example>
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Task scope
|
|
207
|
+
|
|
208
|
+
Each task small, well-defined scope — **at most 3–5 files**.
|
|
209
|
+
**Signs task too broad:**
|
|
210
|
+
- File paths use globs (`src/**/*.ts`) instead of explicit names
|
|
211
|
+
- Assignment says "update all" / "migrate everything" / "refactor across"
|
|
212
|
+
- Scope covers entire package or directory tree
|
|
213
|
+
**Fix:** enumerate files first (grep/glob discovery), then fan out one task per file or small cluster.
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Parallelization
|
|
217
|
+
**Test:** Can task B produce correct output without seeing task A's result?
|
|
218
|
+
- **Yes** → parallelize
|
|
219
|
+
- **No** → run sequentially (A completes, then launch B with A output in context)
|
|
220
|
+
|
|
221
|
+
### Must be sequential
|
|
222
|
+
|
|
223
|
+
|First|Then|Reason|
|
|
108
224
|
|---|---|---|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|Scaffold
|
|
225
|
+
|Define types/interfaces|Implement consumers|Consumers need contract|
|
|
226
|
+
|Create API exports|Write bindings/callers|Callers need export names/signatures|
|
|
227
|
+
|Scaffold structure|Implement bodies|Bodies need shape|
|
|
112
228
|
|Core module|Dependent modules|Dependents import from core|
|
|
229
|
+
|Schema/DB migration|Application logic|Logic depends on new schema shape|
|
|
113
230
|
|
|
114
231
|
### Safe to parallelize
|
|
115
|
-
- Independent modules
|
|
232
|
+
- Independent modules, no cross-imports
|
|
116
233
|
- Tests for already-implemented code
|
|
234
|
+
- Isolated file-scoped refactors
|
|
117
235
|
- Documentation for stable APIs
|
|
118
|
-
- Refactors in isolated file scopes
|
|
119
236
|
|
|
120
|
-
### Phased execution
|
|
237
|
+
### Phased execution
|
|
121
238
|
|
|
122
|
-
|
|
123
|
-
**Phase 1
|
|
124
|
-
|
|
125
|
-
**Phase
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
Wire things together, update build/CI, fix mismatches.
|
|
129
|
-
**Phase 4 - Dependent layer:**
|
|
130
|
-
Fan out again for work consuming Phase 2 outputs.
|
|
239
|
+
Layered work with dependencies:
|
|
240
|
+
**Phase 1 — Foundation** (do yourself or single task): define interfaces, create scaffolds, establish API shape. Never fan out until contract known.
|
|
241
|
+
**Phase 2 — Parallel implementation**: fan out tasks consuming same known interface. Include Phase 1 API contract in `context`.
|
|
242
|
+
**Phase 3 — Integration** (do yourself): wire modules, fix mismatches, verify builds.
|
|
243
|
+
**Phase 4 — Dependent layer**: fan out tasks consuming Phase 2 outputs.
|
|
244
|
+
---
|
|
131
245
|
|
|
132
|
-
|
|
133
|
-
**WRONG** (launched together, will fail):
|
|
246
|
+
## Pre-flight checklist
|
|
134
247
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
]
|
|
140
|
-
|
|
141
|
-
|
|
248
|
+
Before calling tool, verify:
|
|
249
|
+
- [ ] `context` includes shared constraints, references, definition of done
|
|
250
|
+
- [ ] Each `assignment` follows assignment template — not one-liner
|
|
251
|
+
- [ ] Each `assignment` includes edge cases / "don’t break" items
|
|
252
|
+
- [ ] Tasks truly parallel (no hidden dependencies)
|
|
253
|
+
- [ ] Scope small, file paths explicit (no globs)
|
|
254
|
+
- [ ] No task runs project-wide build/test/lint — you do after all tasks complete
|
|
255
|
+
- [ ] `schema` used if you expect information
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Agents
|
|
142
259
|
|
|
143
|
-
```
|
|
144
|
-
// Phase 1: You create scaffold with signatures in lib.rs
|
|
145
|
-
|
|
146
|
-
// Phase 2: Fan out Rust implementation
|
|
147
|
-
tasks: [
|
|
148
|
-
{ id: "Grep", description: "Implement grep module", args: { files: "src/grep.rs" } },
|
|
149
|
-
{ id: "Text", description: "Implement text module", args: { files: "src/text.rs" } },
|
|
150
|
-
// Each task gets the API contract you defined in Phase 1
|
|
151
|
-
]
|
|
152
|
-
|
|
153
|
-
// Phase 3: You verify Rust compiles, exports are correct
|
|
154
|
-
|
|
155
|
-
// Phase 4: Fan out TS bindings (now they know what Rust exports)
|
|
156
|
-
tasks: [
|
|
157
|
-
{ id: "GrepBindings", description: "Update grep TS", args: { files: "src/grep/index.ts" } },
|
|
158
|
-
// Context includes actual export names from Phase 2
|
|
159
|
-
]
|
|
160
|
-
```
|
|
161
|
-
</parallelization>
|
|
162
|
-
|
|
163
|
-
<parameters>
|
|
164
|
-
- `agent`: Agent type for all tasks
|
|
165
|
-
- `context`: Template with `{{placeholders}}`; **Must follow structure above**.
|
|
166
|
-
- `isolated`: (optional) Run in git worktree, return patches
|
|
167
|
-
- `tasks`: Array of `{id, description, args}`
|
|
168
|
-
- `id`: CamelCase identifier (max 32 chars)
|
|
169
|
-
- `description`: What task does (for logging)
|
|
170
|
-
- `args`: Object with keys matching `{{placeholders}}` in context
|
|
171
|
-
- `skills`: (optional) Skill names to preload
|
|
172
|
-
- `schema`: JTD schema for response structure (**required**; use typed properties, not `{ "type": "string" }`). **Schema goes in `schema`; never describe output format in `context`.**
|
|
173
|
-
</parameters>
|
|
174
|
-
|
|
175
|
-
<agents>
|
|
176
260
|
{{#list agents join="\n"}}
|
|
177
261
|
<agent name="{{name}}"{{#if output}} output="structured"{{/if}}>
|
|
178
262
|
<description>{{description}}</description>
|
|
179
263
|
<tools>{{default (join tools ", ") "All tools"}}</tools>
|
|
180
264
|
</agent>
|
|
181
|
-
{{/list}}
|
|
182
|
-
</agents>
|
|
183
|
-
|
|
184
|
-
<critical>
|
|
185
|
-
## Task granularity
|
|
186
|
-
|
|
187
|
-
Each task MUST target a small, well-defined scope. A single task should touch at most 3-5 files.
|
|
188
|
-
**Red flags that a task is too broad:**
|
|
189
|
-
- File list uses globs (`src/**/*.ts`) instead of explicit paths
|
|
190
|
-
- Description says "update all" / "migrate all" / "refactor all"
|
|
191
|
-
- Task covers an entire package or directory tree
|
|
192
|
-
- Estimated touch surface is >5 files
|
|
193
|
-
**Fix:** Split into one task per file (or small group of related files). Fan out in parallel.
|
|
194
|
-
|
|
195
|
-
### Bad (will timeout or produce garbage)
|
|
196
|
-
```
|
|
197
|
-
tasks: [
|
|
198
|
-
{ id: "UpdateAll", description: "Update all constructor calls in src/**/*.ts" }
|
|
199
|
-
]
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### Good (focused, parallel)
|
|
203
|
-
```
|
|
204
|
-
tasks: [
|
|
205
|
-
{ id: "UpdateDebug", description: "Update constructors in debug/index.ts", args: { files: "src/debug/index.ts" } },
|
|
206
|
-
{ id: "UpdateAgent", description: "Update constructors in commit/agent.ts", args: { files: "src/commit/agentic/agent.ts" } },
|
|
207
|
-
{ id: "UpdateTodoExample", description: "Update constructors in examples/todo", args: { files: "examples/custom-tools/todo/index.ts" } },
|
|
208
|
-
]
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
When the set of files isn't known upfront, grep/glob yourself first to enumerate them, then fan out one task per file.
|
|
212
|
-
</critical>
|
|
265
|
+
{{/list}}
|
package/src/sdk.ts
CHANGED
|
@@ -1,41 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SDK for programmatic usage of AgentSession.
|
|
3
|
-
*
|
|
4
|
-
* Provides a factory function and discovery helpers that allow full control
|
|
5
|
-
* over agent configuration, or sensible defaults that match CLI behavior.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* // Minimal - everything auto-discovered
|
|
10
|
-
* const session = await createAgentSession();
|
|
11
|
-
*
|
|
12
|
-
* // With custom extensions
|
|
13
|
-
* const session = await createAgentSession({
|
|
14
|
-
* extensions: [myExtensionFactory],
|
|
15
|
-
* });
|
|
16
|
-
*
|
|
17
|
-
* // Full control
|
|
18
|
-
* const session = await createAgentSession({
|
|
19
|
-
* model: myModel,
|
|
20
|
-
* getApiKey: async () => Bun.env.MY_KEY,
|
|
21
|
-
* toolNames: ["read", "bash", "edit", "write"], // Filter tools
|
|
22
|
-
* extensions: [],
|
|
23
|
-
* skills: [],
|
|
24
|
-
* sessionFile: false,
|
|
25
|
-
* });
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
import * as fs from "node:fs";
|
|
29
|
-
import * as path from "node:path";
|
|
30
1
|
import { Agent, type AgentEvent, type AgentMessage, type AgentTool, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
31
2
|
import { type Message, type Model, supportsXhigh } from "@oh-my-pi/pi-ai";
|
|
32
3
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
33
4
|
import { $env, logger, postmortem } from "@oh-my-pi/pi-utils";
|
|
34
|
-
import { YAML } from "bun";
|
|
35
5
|
import chalk from "chalk";
|
|
36
6
|
import { loadCapability } from "./capability";
|
|
37
7
|
import { type Rule, ruleCapability } from "./capability/rule";
|
|
38
|
-
import {
|
|
8
|
+
import { getAgentDbPath, getAgentDir } from "./config";
|
|
39
9
|
import { ModelRegistry } from "./config/model-registry";
|
|
40
10
|
import { formatModelString, parseModelString } from "./config/model-resolver";
|
|
41
11
|
import { loadPromptTemplates as loadPromptTemplatesInternal, type PromptTemplate } from "./config/prompt-templates";
|
|
@@ -79,7 +49,6 @@ import { AgentSession } from "./session/agent-session";
|
|
|
79
49
|
import { AuthStorage } from "./session/auth-storage";
|
|
80
50
|
import { convertToLlm } from "./session/messages";
|
|
81
51
|
import { SessionManager } from "./session/session-manager";
|
|
82
|
-
import { migrateJsonStorage } from "./session/storage-migration";
|
|
83
52
|
import { closeAllConnections } from "./ssh/connection-manager";
|
|
84
53
|
import { unmountAll } from "./ssh/sshfs-mount";
|
|
85
54
|
import {
|
|
@@ -94,12 +63,12 @@ import {
|
|
|
94
63
|
EditTool,
|
|
95
64
|
FindTool,
|
|
96
65
|
GrepTool,
|
|
97
|
-
|
|
66
|
+
getSearchTools,
|
|
98
67
|
loadSshTool,
|
|
99
68
|
PythonTool,
|
|
100
69
|
ReadTool,
|
|
101
70
|
setPreferredImageProvider,
|
|
102
|
-
|
|
71
|
+
setPreferredSearchProvider,
|
|
103
72
|
type Tool,
|
|
104
73
|
type ToolSession,
|
|
105
74
|
WriteTool,
|
|
@@ -259,82 +228,14 @@ function getDefaultAgentDir(): string {
|
|
|
259
228
|
* Reads from primary path first, then falls back to legacy paths (.pi, .claude).
|
|
260
229
|
*/
|
|
261
230
|
export async function discoverAuthStorage(agentDir: string = getDefaultAgentDir()): Promise<AuthStorage> {
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
const allPaths = getConfigDirPaths("auth.json", { project: false });
|
|
265
|
-
const fallbackPaths = allPaths.filter(p => p !== primaryPath);
|
|
266
|
-
|
|
267
|
-
logger.debug("discoverAuthStorage", { agentDir, primaryPath, allPaths, fallbackPaths });
|
|
268
|
-
|
|
269
|
-
// Migrate legacy JSON files (settings.json, auth.json) to SQLite before loading
|
|
270
|
-
await migrateJsonStorage({
|
|
271
|
-
agentDir,
|
|
272
|
-
settingsPath: path.join(agentDir, "settings.json"),
|
|
273
|
-
authPaths: [primaryPath, ...fallbackPaths],
|
|
274
|
-
});
|
|
231
|
+
const dbPath = getAgentDbPath(agentDir);
|
|
232
|
+
logger.debug("discoverAuthStorage", { agentDir, dbPath });
|
|
275
233
|
|
|
276
|
-
const storage = await AuthStorage.create(
|
|
234
|
+
const storage = await AuthStorage.create(dbPath);
|
|
277
235
|
await storage.reload();
|
|
278
236
|
return storage;
|
|
279
237
|
}
|
|
280
238
|
|
|
281
|
-
/**
|
|
282
|
-
* Create a ModelRegistry with fallback support.
|
|
283
|
-
* Prefers models.yml over models.json. Reads from primary path first,
|
|
284
|
-
* then falls back to legacy paths (.pi, .claude).
|
|
285
|
-
*/
|
|
286
|
-
export function discoverModels(authStorage: AuthStorage, agentDir: string = getDefaultAgentDir()): ModelRegistry {
|
|
287
|
-
const yamlPath = path.join(agentDir, "models.yml");
|
|
288
|
-
const jsonPath = path.join(agentDir, "models.json");
|
|
289
|
-
|
|
290
|
-
// Check existence of yaml and json files
|
|
291
|
-
let yamlExists = fs.existsSync(yamlPath);
|
|
292
|
-
let jsonExists = fs.existsSync(jsonPath);
|
|
293
|
-
|
|
294
|
-
// Migrate models.json to models.yml if yaml doesn't exist but json does
|
|
295
|
-
if (!yamlExists && jsonExists) {
|
|
296
|
-
migrateModelsJsonToYaml(jsonPath, yamlPath);
|
|
297
|
-
yamlExists = fs.existsSync(yamlPath);
|
|
298
|
-
jsonExists = fs.existsSync(jsonPath);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Prefer models.yml, fall back to models.json
|
|
302
|
-
const primaryPath = yamlExists ? yamlPath : jsonPath;
|
|
303
|
-
|
|
304
|
-
// Get all models config paths (user-level only), excluding the primary
|
|
305
|
-
const yamlPaths = getConfigDirPaths("models.yml", { project: false });
|
|
306
|
-
const jsonPaths = getConfigDirPaths("models.json", { project: false });
|
|
307
|
-
const allPaths = [...yamlPaths, ...jsonPaths];
|
|
308
|
-
const existenceResults = allPaths.map(p => {
|
|
309
|
-
return { p, exists: fs.existsSync(p) };
|
|
310
|
-
});
|
|
311
|
-
const fallbackPaths = existenceResults.filter(({ p, exists }) => p !== primaryPath && exists).map(({ p }) => p);
|
|
312
|
-
|
|
313
|
-
logger.debug("discoverModels", { primaryPath, fallbackPaths });
|
|
314
|
-
return new ModelRegistry(authStorage, primaryPath, fallbackPaths);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Migrate models.json to models.yml.
|
|
319
|
-
* Creates models.yml from models.json and renames the json file to .bak.
|
|
320
|
-
*/
|
|
321
|
-
function migrateModelsJsonToYaml(jsonPath: string, yamlPath: string): void {
|
|
322
|
-
try {
|
|
323
|
-
const content = fs.readFileSync(jsonPath, "utf-8");
|
|
324
|
-
const parsed = JSON.parse(content);
|
|
325
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
326
|
-
logger.warn("migrateModelsJsonToYaml: invalid models.json structure", { path: jsonPath });
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
fs.mkdirSync(path.dirname(yamlPath), { recursive: true });
|
|
330
|
-
fs.writeFileSync(yamlPath, YAML.stringify(parsed, null, 2));
|
|
331
|
-
fs.renameSync(jsonPath, `${jsonPath}.bak`);
|
|
332
|
-
logger.debug("migrateModelsJsonToYaml: migrated models.json to models.yml", { from: jsonPath, to: yamlPath });
|
|
333
|
-
} catch (error) {
|
|
334
|
-
logger.warn("migrateModelsJsonToYaml: migration failed", { error: String(error) });
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
239
|
/**
|
|
339
240
|
* Discover extensions from cwd.
|
|
340
241
|
*/
|
|
@@ -585,7 +486,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
585
486
|
|
|
586
487
|
// Use provided or create AuthStorage and ModelRegistry
|
|
587
488
|
const authStorage = options.authStorage ?? (await discoverAuthStorage(agentDir));
|
|
588
|
-
const modelRegistry = options.modelRegistry ??
|
|
489
|
+
const modelRegistry = options.modelRegistry ?? new ModelRegistry(authStorage);
|
|
589
490
|
time("discoverModels");
|
|
590
491
|
|
|
591
492
|
const settingsInstance = options.settingsInstance ?? (await Settings.init({ cwd, agentDir }));
|
|
@@ -594,7 +495,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
594
495
|
time("initializeWithSettings");
|
|
595
496
|
|
|
596
497
|
// Initialize provider preferences from settings
|
|
597
|
-
|
|
498
|
+
setPreferredSearchProvider(settingsInstance.get("providers.webSearch") ?? "auto");
|
|
598
499
|
setPreferredImageProvider(settingsInstance.get("providers.image") ?? "auto");
|
|
599
500
|
|
|
600
501
|
const sessionManager = options.sessionManager ?? SessionManager.create(cwd);
|
|
@@ -839,16 +740,16 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
839
740
|
// Add specialized Exa web search tools if EXA_API_KEY is available
|
|
840
741
|
const exaSettings = settingsInstance.getGroup("exa");
|
|
841
742
|
if (exaSettings.enabled && exaSettings.enableSearch) {
|
|
842
|
-
const
|
|
743
|
+
const exaSearchTools = await getSearchTools({
|
|
843
744
|
enableLinkedin: exaSettings.enableLinkedin as boolean,
|
|
844
745
|
enableCompany: exaSettings.enableCompany as boolean,
|
|
845
746
|
});
|
|
846
747
|
// Filter out the base web_search (already in built-in tools), add specialized Exa tools
|
|
847
|
-
const specializedTools =
|
|
748
|
+
const specializedTools = exaSearchTools.filter(t => t.name !== "web_search");
|
|
848
749
|
if (specializedTools.length > 0) {
|
|
849
750
|
customTools.push(...specializedTools);
|
|
850
751
|
}
|
|
851
|
-
time("
|
|
752
|
+
time("getSearchTools");
|
|
852
753
|
}
|
|
853
754
|
|
|
854
755
|
const inlineExtensions: ExtensionFactory[] = options.extensions ? [...options.extensions] : [];
|