@oh-my-pi/pi-coding-agent 13.9.2 → 13.9.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.
- package/CHANGELOG.md +53 -0
- package/examples/sdk/02-custom-model.ts +2 -1
- package/package.json +7 -7
- package/src/cli/args.ts +6 -5
- package/src/cli/list-models.ts +2 -2
- package/src/commands/launch.ts +3 -3
- package/src/config/model-registry.ts +85 -39
- package/src/config/model-resolver.ts +47 -21
- package/src/config/settings-schema.ts +56 -2
- package/src/discovery/helpers.ts +2 -2
- package/src/extensibility/custom-tools/types.ts +2 -0
- package/src/extensibility/extensions/loader.ts +3 -2
- package/src/extensibility/extensions/types.ts +10 -7
- package/src/extensibility/hooks/types.ts +2 -0
- package/src/main.ts +5 -22
- package/src/memories/index.ts +7 -3
- package/src/modes/components/footer.ts +10 -8
- package/src/modes/components/model-selector.ts +33 -38
- package/src/modes/components/settings-defs.ts +31 -2
- package/src/modes/components/settings-selector.ts +16 -5
- package/src/modes/components/status-line/context-thresholds.ts +68 -0
- package/src/modes/components/status-line/segments.ts +11 -12
- package/src/modes/components/thinking-selector.ts +7 -7
- package/src/modes/components/tree-selector.ts +3 -2
- package/src/modes/controllers/command-controller.ts +11 -26
- package/src/modes/controllers/event-controller.ts +16 -3
- package/src/modes/controllers/input-controller.ts +4 -2
- package/src/modes/controllers/selector-controller.ts +5 -4
- package/src/modes/interactive-mode.ts +2 -2
- package/src/modes/rpc/rpc-client.ts +5 -10
- package/src/modes/rpc/rpc-types.ts +5 -5
- package/src/modes/theme/theme.ts +8 -3
- package/src/priority.json +1 -0
- package/src/prompts/system/auto-handoff-threshold-focus.md +1 -0
- package/src/prompts/system/system-prompt.md +18 -2
- package/src/prompts/tools/hashline.md +139 -83
- package/src/sdk.ts +22 -14
- package/src/session/agent-session.ts +259 -117
- package/src/session/agent-storage.ts +14 -14
- package/src/session/compaction/compaction.ts +500 -13
- package/src/session/messages.ts +12 -1
- package/src/session/session-manager.ts +77 -19
- package/src/slash-commands/builtin-registry.ts +48 -0
- package/src/task/agents.ts +3 -2
- package/src/task/executor.ts +2 -2
- package/src/task/types.ts +2 -1
- package/src/thinking.ts +87 -0
- package/src/tools/browser.ts +15 -6
- package/src/tools/fetch.ts +118 -100
- package/src/web/search/providers/exa.ts +74 -3
|
@@ -1,12 +1,31 @@
|
|
|
1
1
|
Applies precise, surgical file edits by referencing `LINE#ID` tags from `read` output. Each tag uniquely identifies a line, so edits remain stable even when lines shift.
|
|
2
2
|
|
|
3
|
+
<critical>
|
|
4
|
+
- Never anchor insertions on blank lines or lone closing delimiters like `}`, `]`, `)`, `};`, or `),` — they are mechanically valid tags but semantically unstable edit boundaries.
|
|
5
|
+
- For `append`/`prepend`, `lines` **MUST** contain only the newly introduced content. Do not re-emit surrounding braces, brackets, parentheses, or sibling declarations that already exist in the file.
|
|
6
|
+
- `append`/`prepend` are for self-contained new content only: sibling declarations, new object/list members, new test cases, or similar additions whose surrounding structure stays unchanged.
|
|
7
|
+
- When changing existing code near a block tail or closing delimiter, default to `replace` over the owned span instead of inserting around the boundary.
|
|
8
|
+
- When adding a sibling declaration, default to `prepend` on the next sibling declaration instead of `append` on the previous block's closing brace.
|
|
9
|
+
- If any inserted line is just a closing delimiter, stop and re-check the edit shape. A closing line is only valid when it belongs to newly introduced structure; if it belongs to surrounding existing structure, your edit should be a `replace` that consumes the old boundary.
|
|
10
|
+
</critical>
|
|
11
|
+
|
|
3
12
|
<workflow>
|
|
4
13
|
Follow these steps in order for every edit:
|
|
5
14
|
1. You **SHOULD** issue a `read` call before editing to get fresh `LINE#ID` tags. Editing without current tags causes mismatches because other edits or external changes may have shifted line numbers since your last read.
|
|
6
15
|
2. You **MUST** submit one `edit` call per file with all operations. Multiple calls to the same file require re-reading between each one (tags shift after each edit), so batching avoids wasted round-trips. Think your changes through before submitting.
|
|
7
|
-
3. You **MUST** pick the
|
|
16
|
+
3. You **MUST** pick the operation that matches the owning structure, not merely the smallest textual diff. Use the smallest operation only when it still cleanly owns the changed syntax. If a tiny edit would patch around a block tail, delimiter, or neighboring structural line, expand it to the semantically correct `replace` span instead.
|
|
8
17
|
</workflow>
|
|
9
18
|
|
|
19
|
+
<checklist>
|
|
20
|
+
Before choosing the payload, answer these questions in order:
|
|
21
|
+
1. **Am I replacing existing lines or inserting new ones?** If any existing line changes, use `replace` for the full changed span.
|
|
22
|
+
2. **What declaration or block owns this anchor line?** Prefer declaration/header lines over blank lines or delimiters.
|
|
23
|
+
3. **Am I inserting self-contained new content, or changing an existing block?** Use `append`/`prepend` only for self-contained additions. If surrounding code, indentation, or closers also change, use `replace`.
|
|
24
|
+
4. **Am I editing near a block tail or closing delimiter?** If yes, expand the edit to own that tail instead of patching just the last line or two.
|
|
25
|
+
5. **Does `lines` contain only new content?** For `append`/`prepend`, do not include existing closing braces or other surrounding syntax from the file.
|
|
26
|
+
6. **Would the replacement duplicate the line immediately after `end`?** If yes, extend the range to consume the old boundary.
|
|
27
|
+
</checklist>
|
|
28
|
+
|
|
10
29
|
<operations>
|
|
11
30
|
**`path`** — the path to the file to edit.
|
|
12
31
|
**`move`** — if set, move the file to the given path.
|
|
@@ -25,9 +44,12 @@ Tags are applied bottom-up: later edits (by position) are applied first, so earl
|
|
|
25
44
|
</operations>
|
|
26
45
|
|
|
27
46
|
<rules>
|
|
28
|
-
1. **Anchor on unique,
|
|
29
|
-
2. **Use `prepend`/`append` only
|
|
30
|
-
3. **
|
|
47
|
+
1. **Anchor on unique declaration or header lines, not delimiters.** Safe anchors are lines like `function beta() {`, `if (…) {`, `const value =`, or other unique structural headers. Blank lines and lone closers like `}` are never good insertion anchors.
|
|
48
|
+
2. **Use `prepend`/`append` only for self-contained additions whose surrounding structure stays unchanged.** If you are adding a sibling declaration, prefer `prepend` on the next sibling declaration instead of `append` on the previous block closer.
|
|
49
|
+
3. **If the change touches existing code near a block tail, use range `replace` over the owned span.** Do not patch just the final line(s) before a closing delimiter when the surrounding structure, indentation, or control flow is also changing.
|
|
50
|
+
4. **Match surrounding indentation for new lines.** When inserting via `prepend`/`append`, look at the anchor line and its neighbors in the `read` output. New `lines` entries **MUST** carry the same leading whitespace. If the context uses tabs at depth 1 (`\t`), your inserted declarations need `\t` and bodies need `\t\t`. Inserting at indent level 0 inside an indented block is always wrong.
|
|
51
|
+
5. **Consume the old closing boundary when your replacement emits one.** If the replacement's final line is a closing delimiter like `}`, `]`, or `)`, the `end` line **MUST** include the original matching closer that would otherwise remain in the file. Before submitting, compare the replacement's last line with the line immediately after `end`; if they would be the same boundary, extend the range so the old closer is removed.
|
|
52
|
+
6. **If you expect a second tiny cleanup edit for `}`, `};`, indentation, or a duplicated boundary, your first edit shape is wrong.** Expand the first `replace` so it owns the structural tail in one shot.
|
|
31
53
|
</rules>
|
|
32
54
|
|
|
33
55
|
<recovery>
|
|
@@ -36,17 +58,38 @@ Edits can fail in two ways. Here is exactly what to do for each:
|
|
|
36
58
|
2. **No-op (`identical`):** Your replacement is identical to the existing content — nothing changed. You **MUST NOT** resubmit the same edit. Re-read the target lines to understand what is actually there, then adjust your edit.
|
|
37
59
|
</recovery>
|
|
38
60
|
|
|
39
|
-
<
|
|
61
|
+
<examples>
|
|
62
|
+
All examples below reference the same file, `util.ts`:
|
|
40
63
|
```ts
|
|
41
|
-
{{hlinefull
|
|
64
|
+
{{hlinefull 1 "// @ts-ignore"}}
|
|
65
|
+
{{hlinefull 2 "const timeout = 5000;"}}
|
|
66
|
+
{{hlinefull 3 "const tag = \"DO NOT SHIP\";"}}
|
|
67
|
+
{{hlinefull 4 ""}}
|
|
68
|
+
{{hlinefull 5 "function alpha() {"}}
|
|
69
|
+
{{hlinefull 6 "\tlog();"}}
|
|
70
|
+
{{hlinefull 7 "}"}}
|
|
71
|
+
{{hlinefull 8 ""}}
|
|
72
|
+
{{hlinefull 9 "function beta() {"}}
|
|
73
|
+
{{hlinefull 10 "\t// TODO: remove after migration"}}
|
|
74
|
+
{{hlinefull 11 "\tlegacy();"}}
|
|
75
|
+
{{hlinefull 12 "\ttry {"}}
|
|
76
|
+
{{hlinefull 13 "\t\treturn parse(data);"}}
|
|
77
|
+
{{hlinefull 14 "\t} catch (err) {"}}
|
|
78
|
+
{{hlinefull 15 "\t\tconsole.error(err);"}}
|
|
79
|
+
{{hlinefull 16 "\t\treturn null;"}}
|
|
80
|
+
{{hlinefull 17 "\t}"}}
|
|
81
|
+
{{hlinefull 18 "}"}}
|
|
42
82
|
```
|
|
83
|
+
|
|
84
|
+
<example name="single-line replace">
|
|
85
|
+
Change the timeout from `5000` to `30_000`:
|
|
43
86
|
```
|
|
44
87
|
{
|
|
45
|
-
path: "
|
|
88
|
+
path: "util.ts",
|
|
46
89
|
edits: [{
|
|
47
90
|
op: "replace",
|
|
48
|
-
pos: {{hlineref
|
|
49
|
-
lines: ["
|
|
91
|
+
pos: {{hlineref 2 "const timeout = 5000;"}},
|
|
92
|
+
lines: ["const timeout = 30_000;"]
|
|
50
93
|
}]
|
|
51
94
|
}
|
|
52
95
|
```
|
|
@@ -56,22 +99,22 @@ Edits can fail in two ways. Here is exactly what to do for each:
|
|
|
56
99
|
Single line — `lines: null` deletes entirely:
|
|
57
100
|
```
|
|
58
101
|
{
|
|
59
|
-
path: "
|
|
102
|
+
path: "util.ts",
|
|
60
103
|
edits: [{
|
|
61
104
|
op: "replace",
|
|
62
|
-
pos: {{hlineref
|
|
105
|
+
pos: {{hlineref 1 "// @ts-ignore"}},
|
|
63
106
|
lines: null
|
|
64
107
|
}]
|
|
65
108
|
}
|
|
66
109
|
```
|
|
67
|
-
Range —
|
|
110
|
+
Range — remove the legacy block (lines 10–11):
|
|
68
111
|
```
|
|
69
112
|
{
|
|
70
|
-
path: "
|
|
113
|
+
path: "util.ts",
|
|
71
114
|
edits: [{
|
|
72
115
|
op: "replace",
|
|
73
|
-
pos: {{hlineref
|
|
74
|
-
end: {{hlineref
|
|
116
|
+
pos: {{hlineref 10 "\t// TODO: remove after migration"}},
|
|
117
|
+
end: {{hlineref 11 "\tlegacy();"}},
|
|
75
118
|
lines: null
|
|
76
119
|
}]
|
|
77
120
|
}
|
|
@@ -79,15 +122,13 @@ Range — add `end`:
|
|
|
79
122
|
</example>
|
|
80
123
|
|
|
81
124
|
<example name="clear text but keep the line break">
|
|
82
|
-
|
|
83
|
-
{{hlinefull 14 " placeholder: \"DO NOT SHIP\","}}
|
|
84
|
-
```
|
|
125
|
+
Blank out a line without removing it:
|
|
85
126
|
```
|
|
86
127
|
{
|
|
87
|
-
path: "
|
|
128
|
+
path: "util.ts",
|
|
88
129
|
edits: [{
|
|
89
130
|
op: "replace",
|
|
90
|
-
pos: {{hlineref
|
|
131
|
+
pos: {{hlineref 3 "const tag = \"DO NOT SHIP\";"}},
|
|
91
132
|
lines: [""]
|
|
92
133
|
}]
|
|
93
134
|
}
|
|
@@ -95,23 +136,52 @@ Range — add `end`:
|
|
|
95
136
|
</example>
|
|
96
137
|
|
|
97
138
|
<example name="rewrite a block">
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{
|
|
101
|
-
|
|
102
|
-
{
|
|
139
|
+
Replace the catch body with smarter error handling:
|
|
140
|
+
```
|
|
141
|
+
{
|
|
142
|
+
path: "util.ts",
|
|
143
|
+
edits: [{
|
|
144
|
+
op: "replace",
|
|
145
|
+
pos: {{hlineref 15 "\t\tconsole.error(err);"}},
|
|
146
|
+
end: {{hlineref 17 "\t}"}},
|
|
147
|
+
lines: [
|
|
148
|
+
"\t\tif (isEnoent(err)) return null;",
|
|
149
|
+
"\t\tthrow err;",
|
|
150
|
+
"\t}"
|
|
151
|
+
]
|
|
152
|
+
}]
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
</example>
|
|
156
|
+
|
|
157
|
+
<example name="own the block tail instead of patching around it">
|
|
158
|
+
When changing the tail of an existing block, replace the owned span instead of appending just before the closer.
|
|
159
|
+
|
|
160
|
+
Bad — appending a new return before the existing closer leaves the old tail in place and often leads to a second cleanup edit:
|
|
161
|
+
```
|
|
162
|
+
{
|
|
163
|
+
path: "util.ts",
|
|
164
|
+
edits: [{
|
|
165
|
+
op: "append",
|
|
166
|
+
pos: {{hlineref 16 "\t\treturn null;"}},
|
|
167
|
+
lines: [
|
|
168
|
+
"\t\treturn fallback;"
|
|
169
|
+
]
|
|
170
|
+
}]
|
|
171
|
+
}
|
|
103
172
|
```
|
|
173
|
+
Good — replace the block tail so the new logic and the closing boundary are owned by one edit:
|
|
104
174
|
```
|
|
105
175
|
{
|
|
106
|
-
path: "
|
|
176
|
+
path: "util.ts",
|
|
107
177
|
edits: [{
|
|
108
178
|
op: "replace",
|
|
109
|
-
pos: {{hlineref
|
|
110
|
-
end: {{hlineref
|
|
179
|
+
pos: {{hlineref 15 "\t\tconsole.error(err);"}},
|
|
180
|
+
end: {{hlineref 17 "\t}"}},
|
|
111
181
|
lines: [
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
182
|
+
"\t\tif (isEnoent(err)) return null;",
|
|
183
|
+
"\t\treturn fallback;",
|
|
184
|
+
"\t}"
|
|
115
185
|
]
|
|
116
186
|
}]
|
|
117
187
|
}
|
|
@@ -119,40 +189,35 @@ Range — add `end`:
|
|
|
119
189
|
</example>
|
|
120
190
|
|
|
121
191
|
<example name="inclusive end avoids duplicate boundary">
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
{{hlinefull 71 " run();"}}
|
|
126
|
-
{{hlinefull 72 "}"}}
|
|
127
|
-
{{hlinefull 73 "after();"}}
|
|
128
|
-
```
|
|
129
|
-
Bad — `end` stops before `}` while `lines` already includes `}`:
|
|
192
|
+
Simplify `beta()` to a one-liner. `end` must include the original closing `}` when the replacement also ends with `}`.
|
|
193
|
+
|
|
194
|
+
Bad — `end` stops at line 17 (`\t}`), so the replacement adds `}` and the original function closer on line 18 survives. Result: two consecutive `}` lines.
|
|
130
195
|
```
|
|
131
196
|
{
|
|
132
|
-
path: "
|
|
197
|
+
path: "util.ts",
|
|
133
198
|
edits: [{
|
|
134
199
|
op: "replace",
|
|
135
|
-
pos: {{hlineref
|
|
136
|
-
end: {{hlineref
|
|
200
|
+
pos: {{hlineref 9 "function beta() {"}},
|
|
201
|
+
end: {{hlineref 17 "\t}"}},
|
|
137
202
|
lines: [
|
|
138
|
-
"
|
|
139
|
-
"
|
|
203
|
+
"function beta() {",
|
|
204
|
+
"\treturn parse(data);",
|
|
140
205
|
"}"
|
|
141
206
|
]
|
|
142
207
|
}]
|
|
143
208
|
}
|
|
144
209
|
```
|
|
145
|
-
Good — include
|
|
210
|
+
Good — include the function's own `}` on line 18 in the range, so the old closing boundary is consumed:
|
|
146
211
|
```
|
|
147
212
|
{
|
|
148
|
-
path: "
|
|
213
|
+
path: "util.ts",
|
|
149
214
|
edits: [{
|
|
150
215
|
op: "replace",
|
|
151
|
-
pos: {{hlineref
|
|
152
|
-
end: {{hlineref
|
|
216
|
+
pos: {{hlineref 9 "function beta() {"}},
|
|
217
|
+
end: {{hlineref 18 "}"}},
|
|
153
218
|
lines: [
|
|
154
|
-
"
|
|
155
|
-
"
|
|
219
|
+
"function beta() {",
|
|
220
|
+
"\treturn parse(data);",
|
|
156
221
|
"}"
|
|
157
222
|
]
|
|
158
223
|
}]
|
|
@@ -161,66 +226,54 @@ Good — include original `}` in the replaced range when replacement keeps `}`:
|
|
|
161
226
|
</example>
|
|
162
227
|
|
|
163
228
|
<example name="insert between sibling declarations">
|
|
164
|
-
|
|
165
|
-
{{hlinefull 44 "function x() {"}}
|
|
166
|
-
{{hlinefull 45 " runX();"}}
|
|
167
|
-
{{hlinefull 46 "}"}}
|
|
168
|
-
{{hlinefull 47 ""}}
|
|
169
|
-
{{hlinefull 48 "function y() {"}}
|
|
170
|
-
{{hlinefull 49 " runY();"}}
|
|
171
|
-
{{hlinefull 50 "}"}}
|
|
172
|
-
```
|
|
229
|
+
Add a `gamma()` function between `alpha()` and `beta()`:
|
|
173
230
|
```
|
|
174
231
|
{
|
|
175
|
-
path: "
|
|
232
|
+
path: "util.ts",
|
|
176
233
|
edits: [{
|
|
177
234
|
op: "prepend",
|
|
178
|
-
pos: {{hlineref
|
|
235
|
+
pos: {{hlineref 9 "function beta() {"}},
|
|
179
236
|
lines: [
|
|
180
|
-
"function
|
|
181
|
-
"
|
|
237
|
+
"function gamma() {",
|
|
238
|
+
"\tvalidate();",
|
|
182
239
|
"}",
|
|
183
240
|
""
|
|
184
241
|
]
|
|
185
242
|
}]
|
|
186
243
|
}
|
|
187
244
|
```
|
|
188
|
-
Use a trailing `""` to preserve the blank line between
|
|
245
|
+
Use a trailing `""` to preserve the blank line between sibling declarations.
|
|
189
246
|
</example>
|
|
190
247
|
|
|
191
|
-
<example name="
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
{{hlinefull 102 ""}}
|
|
196
|
-
{{hlinefull 103 "export function serialize(data: unknown): string {"}}
|
|
197
|
-
```
|
|
198
|
-
Bad — anchoring on the blank line (ambiguous, may shift):
|
|
248
|
+
<example name="avoid closer anchors">
|
|
249
|
+
When inserting a sibling declaration, do not anchor on the previous block's lone closing brace. Anchor on the next declaration instead.
|
|
250
|
+
|
|
251
|
+
Bad — appending after line 7 (`}`) happens to land in the gap today, but the anchor is still the previous function's closer rather than a stable declaration boundary:
|
|
199
252
|
```
|
|
200
253
|
{
|
|
201
|
-
path: "
|
|
254
|
+
path: "util.ts",
|
|
202
255
|
edits: [{
|
|
203
256
|
op: "append",
|
|
204
|
-
pos: {{hlineref
|
|
257
|
+
pos: {{hlineref 7 "}"}},
|
|
205
258
|
lines: [
|
|
206
|
-
"
|
|
207
|
-
"
|
|
208
|
-
"
|
|
209
|
-
""
|
|
259
|
+
"",
|
|
260
|
+
"function gamma() {",
|
|
261
|
+
"\tvalidate();",
|
|
262
|
+
"}"
|
|
210
263
|
]
|
|
211
264
|
}]
|
|
212
265
|
}
|
|
213
266
|
```
|
|
214
|
-
Good —
|
|
267
|
+
Good — prepend before the next declaration so the new sibling is anchored on a declaration header, not a block tail:
|
|
215
268
|
```
|
|
216
269
|
{
|
|
217
|
-
path: "
|
|
270
|
+
path: "util.ts",
|
|
218
271
|
edits: [{
|
|
219
272
|
op: "prepend",
|
|
220
|
-
pos: {{hlineref
|
|
273
|
+
pos: {{hlineref 9 "function beta() {"}},
|
|
221
274
|
lines: [
|
|
222
|
-
"function
|
|
223
|
-
"
|
|
275
|
+
"function gamma() {",
|
|
276
|
+
"\tvalidate();",
|
|
224
277
|
"}",
|
|
225
278
|
""
|
|
226
279
|
]
|
|
@@ -228,6 +281,7 @@ Good — anchor on the unique declaration line:
|
|
|
228
281
|
}
|
|
229
282
|
```
|
|
230
283
|
</example>
|
|
284
|
+
</examples>
|
|
231
285
|
|
|
232
286
|
<critical>
|
|
233
287
|
- Edit payload: `{ path, edits[] }`. Each entry: `op`, `lines`, optional `pos`/`end`. No extra keys.
|
|
@@ -235,4 +289,6 @@ Good — anchor on the unique declaration line:
|
|
|
235
289
|
- You **MUST** re-read the file after each edit call before issuing another on the same file. Tags shift after every edit, so reusing old tags produces mismatches.
|
|
236
290
|
- You **MUST NOT** use this tool to reformat, reindent, or adjust whitespace — run the project's formatter instead. If the only difference is whitespace, it is formatting; leave it alone.
|
|
237
291
|
- `lines` entries **MUST** be literal file content with indentation copied exactly from the `read` output. If the file uses tabs, use `\t` in JSON (a real tab character). Using `\\t` (backslash + t) writes the literal two-character string `\t` into the file.
|
|
292
|
+
- For `append`/`prepend`, `lines` **MUST NOT** repeat surrounding delimiters or existing sibling code. Insert only the new content.
|
|
293
|
+
- Before any range `replace`, you **MUST** check whether the replacement's last line duplicates the original line immediately after `end` (most often a closing `}`, `]`, or `)`). If it does, extend the range to consume that old boundary instead of leaving two closers behind.
|
|
238
294
|
</critical>
|
package/src/sdk.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
Agent,
|
|
3
|
+
type AgentEvent,
|
|
4
|
+
type AgentMessage,
|
|
5
|
+
type AgentTool,
|
|
6
|
+
INTENT_FIELD,
|
|
7
|
+
type ThinkingLevel,
|
|
8
|
+
} from "@oh-my-pi/pi-agent-core";
|
|
9
|
+
import type { Message, Model } from "@oh-my-pi/pi-ai";
|
|
3
10
|
|
|
4
11
|
import { prewarmOpenAICodexResponses } from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
5
12
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
@@ -72,6 +79,7 @@ import {
|
|
|
72
79
|
loadProjectContextFiles as loadContextFilesInternal,
|
|
73
80
|
} from "./system-prompt";
|
|
74
81
|
import { AgentOutputManager } from "./task/output-manager";
|
|
82
|
+
import { resolveThinkingLevelForModel, toReasoningEffort } from "./thinking";
|
|
75
83
|
import {
|
|
76
84
|
BashTool,
|
|
77
85
|
BUILTIN_TOOLS,
|
|
@@ -117,10 +125,10 @@ export interface CreateAgentSessionOptions {
|
|
|
117
125
|
/** Raw model pattern string (e.g. from --model CLI flag) to resolve after extensions load.
|
|
118
126
|
* Used when model lookup is deferred because extension-provided models aren't registered yet. */
|
|
119
127
|
modelPattern?: string;
|
|
120
|
-
/** Thinking
|
|
128
|
+
/** Thinking selector. Default: from settings, else unset */
|
|
121
129
|
thinkingLevel?: ThinkingLevel;
|
|
122
130
|
/** Models available for cycling (Ctrl+P in interactive mode) */
|
|
123
|
-
scopedModels?: Array<{ model: Model; thinkingLevel
|
|
131
|
+
scopedModels?: Array<{ model: Model; thinkingLevel?: ThinkingLevel }>;
|
|
124
132
|
|
|
125
133
|
/** System prompt. String replaces default, function receives default and returns final. */
|
|
126
134
|
systemPrompt?: string | ((defaultPrompt: string) => string);
|
|
@@ -456,12 +464,13 @@ function createCustomToolsExtension(tools: CustomTool[]): ExtensionFactory {
|
|
|
456
464
|
runOnSession({ reason: "shutdown", previousSessionFile: undefined }, ctx),
|
|
457
465
|
);
|
|
458
466
|
api.on("auto_compaction_start", async (event, ctx) =>
|
|
459
|
-
runOnSession({ reason: "auto_compaction_start", trigger: event.reason }, ctx),
|
|
467
|
+
runOnSession({ reason: "auto_compaction_start", trigger: event.reason, action: event.action }, ctx),
|
|
460
468
|
);
|
|
461
469
|
api.on("auto_compaction_end", async (event, ctx) =>
|
|
462
470
|
runOnSession(
|
|
463
471
|
{
|
|
464
472
|
reason: "auto_compaction_end",
|
|
473
|
+
action: event.action,
|
|
465
474
|
result: event.result,
|
|
466
475
|
aborted: event.aborted,
|
|
467
476
|
willRetry: event.willRetry,
|
|
@@ -696,7 +705,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
696
705
|
|
|
697
706
|
// If session has data and includes a thinking entry, restore it
|
|
698
707
|
if (thinkingLevel === undefined && hasExistingSession && hasThinkingEntry) {
|
|
699
|
-
thinkingLevel = existingSession.thinkingLevel as ThinkingLevel;
|
|
708
|
+
thinkingLevel = existingSession.thinkingLevel as ThinkingLevel | undefined;
|
|
700
709
|
}
|
|
701
710
|
|
|
702
711
|
if (thinkingLevel === undefined && !hasExplicitModel && !hasThinkingEntry && defaultRoleSpec.explicitThinkingLevel) {
|
|
@@ -705,14 +714,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
705
714
|
|
|
706
715
|
// Fall back to settings default
|
|
707
716
|
if (thinkingLevel === undefined) {
|
|
708
|
-
thinkingLevel = settings.get("defaultThinkingLevel")
|
|
717
|
+
thinkingLevel = settings.get("defaultThinkingLevel");
|
|
709
718
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
if (!model || !model.reasoning) {
|
|
713
|
-
thinkingLevel = "off";
|
|
714
|
-
} else if (thinkingLevel === "xhigh" && !supportsXhigh(model)) {
|
|
715
|
-
thinkingLevel = "high";
|
|
719
|
+
if (model) {
|
|
720
|
+
thinkingLevel = resolveThinkingLevelForModel(model, thinkingLevel);
|
|
716
721
|
}
|
|
717
722
|
|
|
718
723
|
let skills: Skill[];
|
|
@@ -1343,12 +1348,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1343
1348
|
const openaiWebsocketSetting = settings.get("providers.openaiWebsockets") ?? "auto";
|
|
1344
1349
|
const preferOpenAICodexWebsockets =
|
|
1345
1350
|
openaiWebsocketSetting === "on" ? true : openaiWebsocketSetting === "off" ? false : undefined;
|
|
1351
|
+
const serviceTierSetting = settings.get("serviceTier");
|
|
1346
1352
|
|
|
1347
1353
|
agent = new Agent({
|
|
1348
1354
|
initialState: {
|
|
1349
1355
|
systemPrompt,
|
|
1350
1356
|
model,
|
|
1351
|
-
thinkingLevel,
|
|
1357
|
+
thinkingLevel: toReasoningEffort(thinkingLevel),
|
|
1352
1358
|
tools: initialTools,
|
|
1353
1359
|
},
|
|
1354
1360
|
convertToLlm: convertToLlmFinal,
|
|
@@ -1368,6 +1374,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1368
1374
|
minP: settings.get("minP") >= 0 ? settings.get("minP") : undefined,
|
|
1369
1375
|
presencePenalty: settings.get("presencePenalty") >= 0 ? settings.get("presencePenalty") : undefined,
|
|
1370
1376
|
repetitionPenalty: settings.get("repetitionPenalty") >= 0 ? settings.get("repetitionPenalty") : undefined,
|
|
1377
|
+
serviceTier: serviceTierSetting === "none" ? undefined : serviceTierSetting,
|
|
1371
1378
|
kimiApiFormat: settings.get("providers.kimiApiFormat") ?? "anthropic",
|
|
1372
1379
|
preferWebsockets: preferOpenAICodexWebsockets,
|
|
1373
1380
|
getToolContext: tc => toolContextStore.getContext(tc),
|
|
@@ -1418,6 +1425,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1418
1425
|
|
|
1419
1426
|
session = new AgentSession({
|
|
1420
1427
|
agent,
|
|
1428
|
+
thinkingLevel,
|
|
1421
1429
|
sessionManager,
|
|
1422
1430
|
settings,
|
|
1423
1431
|
scopedModels: options.scopedModels,
|