pi-ui-extend 0.1.55 → 0.1.57
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/README.md +206 -259
- package/dist/app/constants.d.ts +2 -2
- package/dist/app/constants.js +2 -2
- package/dist/app/popup/menu-items-controller.js +3 -0
- package/dist/app/rendering/status-line-renderer.js +1 -0
- package/dist/app/session/session-event-controller.js +4 -0
- package/dist/app/session/tabs-controller.js +3 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/default-pix-config.js +1 -1
- package/dist/schemas/pix-schema.js +1 -1
- package/dist/theme.d.ts +1 -0
- package/dist/theme.js +2 -0
- package/external/pi-tools-suite/README.md +5 -5
- package/external/pi-tools-suite/package.json +3 -3
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +18 -18
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +5 -5
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +53 -19
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +2 -2
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +2 -2
- package/external/pi-tools-suite/src/codex-reasoning-fix/index.ts +12 -13
- package/external/pi-tools-suite/src/dcp/index.ts +11 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +15 -15
- package/external/pi-tools-suite/src/index.ts +4 -2
- package/external/pi-tools-suite/src/todo/index.ts +24 -28
- package/external/pi-tools-suite/src/todo/state/state-reducer.ts +1 -1
- package/external/pi-tools-suite/src/todo/tool/types.ts +2 -2
- package/package.json +5 -4
- package/schemas/pix.json +4 -0
|
@@ -598,6 +598,7 @@ function thinkingRankThemeColor(label, rank, count, colors) {
|
|
|
598
598
|
colors.warning,
|
|
599
599
|
colors.error,
|
|
600
600
|
colors.thinkingXHigh,
|
|
601
|
+
colors.thinkingMax,
|
|
601
602
|
];
|
|
602
603
|
const palette = count > baseColors.length ? [colors.statusForeground, ...baseColors] : baseColors;
|
|
603
604
|
const fallbackRank = DEFAULT_THINKING_LEVEL_LABELS.indexOf(label);
|
|
@@ -225,6 +225,10 @@ export class AppSessionEventController {
|
|
|
225
225
|
this.clearCurrentAssistantState();
|
|
226
226
|
this.finalizeAbandonedToolEntries();
|
|
227
227
|
this.currentUserEntryId = undefined;
|
|
228
|
+
this.host.setSessionActivity(this.host.runtime()?.session.isStreaming ? "running" : "idle");
|
|
229
|
+
this.host.setSessionStatus(this.host.runtime()?.session);
|
|
230
|
+
break;
|
|
231
|
+
case "agent_settled":
|
|
228
232
|
this.host.setSessionActivity("idle");
|
|
229
233
|
this.host.setSessionStatus(this.host.runtime()?.session);
|
|
230
234
|
this.host.flushAutoUserMessages();
|
|
@@ -900,11 +900,13 @@ export class AppTabsController {
|
|
|
900
900
|
return event.type === "session_info_changed"
|
|
901
901
|
|| event.type === "agent_start"
|
|
902
902
|
|| event.type === "agent_end"
|
|
903
|
+
|| event.type === "agent_settled"
|
|
903
904
|
|| event.type === "compaction_start"
|
|
904
905
|
|| event.type === "compaction_end";
|
|
905
906
|
}
|
|
906
907
|
shouldScheduleDelayedSyncForRuntimeEvent(event) {
|
|
907
908
|
return event.type === "agent_end"
|
|
909
|
+
|| event.type === "agent_settled"
|
|
908
910
|
|| event.type === "turn_end"
|
|
909
911
|
|| event.type === "compaction_end";
|
|
910
912
|
}
|
|
@@ -916,6 +918,7 @@ export class AppTabsController {
|
|
|
916
918
|
|| event.type === "tool_execution_update"
|
|
917
919
|
|| event.type === "tool_execution_end"
|
|
918
920
|
|| event.type === "agent_end"
|
|
921
|
+
|| event.type === "agent_settled"
|
|
919
922
|
|| event.type === "turn_end"
|
|
920
923
|
|| event.type === "compaction_end";
|
|
921
924
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export type AutocompleteConfig = {
|
|
|
41
41
|
};
|
|
42
42
|
export type DefaultModelConfig = {
|
|
43
43
|
modelRef: string;
|
|
44
|
-
thinking?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
44
|
+
thinking?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
45
45
|
};
|
|
46
46
|
export type ModelColorsConfig = {
|
|
47
47
|
rules: Record<string, string>;
|
package/dist/config.js
CHANGED
|
@@ -53,7 +53,7 @@ const DEFAULT_TOOL_RENDERER = {
|
|
|
53
53
|
const DEFAULT_OUTPUT_FILTERS = {
|
|
54
54
|
patterns: [],
|
|
55
55
|
};
|
|
56
|
-
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
56
|
+
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
57
57
|
const DEFAULT_PROMPT_ENHANCER = {
|
|
58
58
|
modelRef: "zai/glm-5-turbo",
|
|
59
59
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const DEFAULT_PIX_CONFIG_JSONC = String.raw `{
|
|
2
2
|
"$schema": "https://unpkg.com/pi-ui-extend/schemas/pix.json",
|
|
3
3
|
// pix renderer configuration
|
|
4
|
-
"defaultModel": { "modelRef": "openai-codex/gpt-5.
|
|
4
|
+
"defaultModel": { "modelRef": "openai-codex/gpt-5.6-sol", "thinking": "medium" },
|
|
5
5
|
// Disable AGENTS.md / CLAUDE.md discovery for this project when set in <cwd>/.pi/pix.jsonc.
|
|
6
6
|
"ignoreContextFiles": false,
|
|
7
7
|
// Maximum pi session JSONL files to retain per project. 0 disables automatic deletion.
|
|
@@ -9,7 +9,7 @@ import { Type } from "typebox";
|
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
10
|
// Shared primitives
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
12
|
-
const DefaultThinkingSelection = Type.Union(["off", "minimal", "low", "medium", "high", "xhigh"].map((v) => Type.Literal(v)), { description: "Default model thinking budget level." });
|
|
12
|
+
const DefaultThinkingSelection = Type.Union(["off", "minimal", "low", "medium", "high", "xhigh", "max"].map((v) => Type.Literal(v)), { description: "Default model thinking budget level." });
|
|
13
13
|
// ---------------------------------------------------------------------------
|
|
14
14
|
// Tool renderer
|
|
15
15
|
// ---------------------------------------------------------------------------
|
package/dist/theme.d.ts
CHANGED
package/dist/theme.js
CHANGED
|
@@ -48,6 +48,7 @@ export const THEMES = {
|
|
|
48
48
|
thinkingForeground: "#64748b",
|
|
49
49
|
userForeground: "#d97706",
|
|
50
50
|
thinkingXHigh: "#ff8a86",
|
|
51
|
+
thinkingMax: "#ff5f8f",
|
|
51
52
|
modelOpenAI: "#c8b45a",
|
|
52
53
|
statusDotBase: "#30363d",
|
|
53
54
|
statusDotRunningDim: "#30363d",
|
|
@@ -103,6 +104,7 @@ export const THEMES = {
|
|
|
103
104
|
thinkingForeground: "#6b5491",
|
|
104
105
|
userForeground: "#854d0e",
|
|
105
106
|
thinkingXHigh: "#cf333d",
|
|
107
|
+
thinkingMax: "#b91c57",
|
|
106
108
|
modelOpenAI: "#75671f",
|
|
107
109
|
statusDotBase: "#334155",
|
|
108
110
|
statusDotRunningDim: "#334155",
|
|
@@ -265,19 +265,19 @@ The canonical use case is an **`oracle`** role that consults a flagship model fr
|
|
|
265
265
|
```jsonc
|
|
266
266
|
"oracle": {
|
|
267
267
|
"description": "Cross-provider second opinion: consult a flagship from a different provider than the parent to pressure-test a hard decision. Read-only; advise, do not edit.",
|
|
268
|
-
"model": "openai-codex/gpt-5.
|
|
268
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
269
269
|
"fallbackModels": ["zai/glm-5.2"],
|
|
270
270
|
"thinking": "xhigh",
|
|
271
271
|
"modelByParent": {
|
|
272
|
-
"zai/*": { "model": "openai-codex/gpt-5.
|
|
272
|
+
"zai/*": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.2"] },
|
|
273
273
|
"openai-codex/*": "zai/glm-5.2",
|
|
274
|
-
"antigravity/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.
|
|
275
|
-
"anthropic/*": { "model": "openai-codex/gpt-5.
|
|
274
|
+
"antigravity/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.6-sol"] },
|
|
275
|
+
"anthropic/*": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.2"] }
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
278
|
```
|
|
279
279
|
|
|
280
|
-
With this config a GLM parent (`zai/*`) spawns the oracle on `gpt-5.
|
|
280
|
+
With this config a GLM parent (`zai/*`) spawns the oracle on `gpt-5.6-sol`, a GPT parent (`openai-codex/*`) spawns it on `glm-5.2`, and so on — automatically, at spawn time, with no `task.model` needed. The parent model ref is read from the spawn context (`ctx.model`) and passed into resolution. Pattern matching is case-insensitive `*` glob (same engine as `vision.blindModelPatterns`). When no key matches (or no parent model is known), the role falls back to its static `model` + `fallbackModels`. An explicit `task.model` or `ASYNC_SUBAGENTS_FORCE_CURRENT_MODEL=1` still overrides the match.
|
|
281
281
|
|
|
282
282
|
Sub-agents run with `--no-session` by default to avoid writing duplicate Pi session JSONL files for fire-and-forget background work. Set `ASYNC_SUBAGENTS_ENABLE_SESSIONS=1` to restore persisted per-agent sessions under each agent's `sessions/` directory; this also registers the session-navigation slash commands (`/sub-open`, `/sub-back`, `/sub-where`) needed for switching and deeper post-mortem navigation.
|
|
283
283
|
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"vscode-languageserver-protocol": "^3.17.5"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@earendil-works/pi-ai": "0.80.
|
|
42
|
-
"@earendil-works/pi-coding-agent": "0.80.
|
|
43
|
-
"@earendil-works/pi-tui": "0.80.
|
|
41
|
+
"@earendil-works/pi-ai": "0.80.6",
|
|
42
|
+
"@earendil-works/pi-coding-agent": "0.80.6",
|
|
43
|
+
"@earendil-works/pi-tui": "0.80.6",
|
|
44
44
|
"typebox": "*"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
@@ -56,9 +56,9 @@
|
|
|
56
56
|
// profile model, so a role like an "oracle" can always pick a flagship from a
|
|
57
57
|
// DIFFERENT provider than the parent. Example:
|
|
58
58
|
// "modelByParent": {
|
|
59
|
-
// "zai/*": { "model": "openai-codex/gpt-5.
|
|
59
|
+
// "zai/*": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.2"] },
|
|
60
60
|
// "openai-codex/*": "zai/glm-5.2",
|
|
61
|
-
// "antigravity/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.
|
|
61
|
+
// "antigravity/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.6-sol"] }
|
|
62
62
|
// }
|
|
63
63
|
|
|
64
64
|
// Role auto-selection when subagentType is omitted is handled by a small LLM
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
// "extraArgs": ["optional", "global", "pi", "args"],
|
|
97
97
|
// "timeoutMs": 1800000,
|
|
98
98
|
// "types": {
|
|
99
|
-
// "roleName": { "model": "provider/model", "fallbackModels": ["provider/backup"], "thinking": "off|low|medium|high|xhigh", "timeoutMs": 1800000 }
|
|
99
|
+
// "roleName": { "model": "provider/model", "fallbackModels": ["provider/backup"], "thinking": "off|low|medium|high|xhigh|max", "timeoutMs": 1800000 }
|
|
100
100
|
// }
|
|
101
101
|
// }
|
|
102
102
|
// }
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
},
|
|
125
125
|
|
|
126
126
|
"gpt": {
|
|
127
|
-
"description": "Prefer enabled GPT-family models: spark/mini for cheap roles, gpt-5.
|
|
127
|
+
"description": "Prefer enabled GPT-family models: spark/mini for cheap roles, gpt-5.6-sol for heavy roles; fallback cross-provider on quota.",
|
|
128
128
|
"types": {
|
|
129
129
|
"quick": { "model": "openai-codex/gpt-5.3-codex-spark", "fallbackModels": ["zai/glm-4.5-air"], "thinking": "off" },
|
|
130
130
|
"scan": { "model": "openai-codex/gpt-5.3-codex-spark", "fallbackModels": ["zai/glm-4.5-air"], "thinking": "off" },
|
|
@@ -132,9 +132,9 @@
|
|
|
132
132
|
"docs": { "model": "openai-codex/gpt-5.3-codex-spark", "fallbackModels": ["zai/glm-4.5-air"], "thinking": "low" },
|
|
133
133
|
"frontend": { "model": "openai-codex/gpt-5.4-mini", "fallbackModels": ["antigravity/gemini-3-flash-preview", "zai/glm-5.2"], "thinking": "medium" },
|
|
134
134
|
"tests": { "model": "openai-codex/gpt-5.4-mini", "fallbackModels": ["zai/glm-5-turbo"], "thinking": "medium" },
|
|
135
|
-
"review": { "model": "openai-codex/gpt-5.
|
|
136
|
-
"implement": { "model": "openai-codex/gpt-5.
|
|
137
|
-
"deep": { "model": "openai-codex/gpt-5.
|
|
135
|
+
"review": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.2"], "thinking": "high" },
|
|
136
|
+
"implement": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.2"], "thinking": "high" },
|
|
137
|
+
"deep": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.2"], "thinking": "high" }
|
|
138
138
|
}
|
|
139
139
|
},
|
|
140
140
|
|
|
@@ -147,9 +147,9 @@
|
|
|
147
147
|
"docs": { "model": "antigravity/gemini-2.5-flash", "fallbackModels": ["openai-codex/gpt-5.3-codex-spark", "zai/glm-4.5-air"], "thinking": "medium" },
|
|
148
148
|
"frontend": { "model": "antigravity/gemini-3.1-pro-preview-customtools", "fallbackModels": ["openai-codex/gpt-5.4-mini", "zai/glm-5.2"], "thinking": "low" },
|
|
149
149
|
"tests": { "model": "antigravity/antigravity-claude-sonnet-4-6", "fallbackModels": ["openai-codex/gpt-5.4-mini", "zai/glm-5-turbo"], "thinking": "high" },
|
|
150
|
-
"review": { "model": "antigravity/antigravity-claude-sonnet-4-6", "fallbackModels": ["openai-codex/gpt-5.
|
|
151
|
-
"implement": { "model": "openai-codex/gpt-5.
|
|
152
|
-
"deep": { "model": "antigravity/antigravity-claude-opus-4-6-thinking", "fallbackModels": ["openai-codex/gpt-5.
|
|
150
|
+
"review": { "model": "antigravity/antigravity-claude-sonnet-4-6", "fallbackModels": ["openai-codex/gpt-5.6-sol", "zai/glm-5.2"], "thinking": "high" },
|
|
151
|
+
"implement": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.2"], "thinking": "high" },
|
|
152
|
+
"deep": { "model": "antigravity/antigravity-claude-opus-4-6-thinking", "fallbackModels": ["openai-codex/gpt-5.6-sol", "zai/glm-5.2"], "thinking": "high" }
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
},
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
|
|
204
204
|
"review": {
|
|
205
205
|
"description": "Use for review/audit of existing code or changes: correctness, security, performance, maintainability, API risks, quality. Do not implement new code.",
|
|
206
|
-
"model": "openai-codex/gpt-5.
|
|
206
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
207
207
|
"fallbackModels": ["zai/glm-5.2"],
|
|
208
208
|
"thinking": "high",
|
|
209
209
|
"tools": ["read", "grep"]
|
|
@@ -211,29 +211,29 @@
|
|
|
211
211
|
|
|
212
212
|
"implement": {
|
|
213
213
|
"description": "Use when the sub-agent should make or plan code changes for a feature, bug fix, or refactor.",
|
|
214
|
-
"model": "openai-codex/gpt-5.
|
|
214
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
215
215
|
"fallbackModels": ["zai/glm-5.2"],
|
|
216
216
|
"thinking": "high"
|
|
217
217
|
},
|
|
218
218
|
|
|
219
219
|
"deep": {
|
|
220
220
|
"description": "Use for broad hard reasoning: architecture, system design, cross-module impact, complex tradeoffs.",
|
|
221
|
-
"model": "openai-codex/gpt-5.
|
|
221
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
222
222
|
"fallbackModels": ["zai/glm-5.2"],
|
|
223
223
|
"thinking": "high"
|
|
224
224
|
},
|
|
225
225
|
|
|
226
226
|
"oracle": {
|
|
227
227
|
"description": "Oracle: cross-provider flagship second opinion for hard or high-stakes uncertainty. Use sparingly to pressure-test architecture, plans, root-cause hypotheses, risk/security calls, or final recommendations when independent disagreement is valuable. Read-only; advise, do not edit.",
|
|
228
|
-
"model": "openai-codex/gpt-5.
|
|
228
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
229
229
|
"fallbackModels": ["zai/glm-5.2"],
|
|
230
230
|
"thinking": "xhigh",
|
|
231
231
|
"tools": ["read", "grep", "bash"],
|
|
232
232
|
"modelByParent": {
|
|
233
|
-
"zai/*": { "model": "openai-codex/gpt-5.
|
|
234
|
-
"openai-codex/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.
|
|
235
|
-
"antigravity/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.
|
|
236
|
-
"anthropic/*": { "model": "openai-codex/gpt-5.
|
|
233
|
+
"zai/*": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.2"] },
|
|
234
|
+
"openai-codex/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.6-sol"] },
|
|
235
|
+
"antigravity/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.6-sol"] },
|
|
236
|
+
"anthropic/*": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.2"] }
|
|
237
237
|
},
|
|
238
238
|
"promptAppend": "You are an oracle: a flagship model from a different provider giving a second opinion to the parent agent. Give a concise, decisive recommendation with key tradeoffs and risks. Disagree when warranted; do not rubber-stamp. Do not edit unless explicitly asked."
|
|
239
239
|
}
|
|
@@ -219,13 +219,13 @@ const BUILTIN_CONFIG: SubagentConfig = {
|
|
|
219
219
|
},
|
|
220
220
|
oracle: {
|
|
221
221
|
description: "Oracle: cross-provider flagship second opinion for hard or high-stakes uncertainty. Use sparingly to pressure-test architecture, plans, root-cause hypotheses, risk/security calls, or final recommendations when independent disagreement is valuable. Read-only; advise, do not edit.",
|
|
222
|
-
model: "openai-codex/gpt-5.
|
|
222
|
+
model: "openai-codex/gpt-5.6-sol",
|
|
223
223
|
fallbackModels: ["zai/glm-5.2"],
|
|
224
224
|
modelByParent: {
|
|
225
|
-
"zai/*": { model: "openai-codex/gpt-5.
|
|
226
|
-
"openai-codex/*": { model: "zai/glm-5.2", fallbackModels: ["openai-codex/gpt-5.
|
|
227
|
-
"antigravity/*": { model: "zai/glm-5.2", fallbackModels: ["openai-codex/gpt-5.
|
|
228
|
-
"anthropic/*": { model: "openai-codex/gpt-5.
|
|
225
|
+
"zai/*": { model: "openai-codex/gpt-5.6-sol", fallbackModels: ["zai/glm-5.2"] },
|
|
226
|
+
"openai-codex/*": { model: "zai/glm-5.2", fallbackModels: ["openai-codex/gpt-5.6-sol"] },
|
|
227
|
+
"antigravity/*": { model: "zai/glm-5.2", fallbackModels: ["openai-codex/gpt-5.6-sol"] },
|
|
228
|
+
"anthropic/*": { model: "openai-codex/gpt-5.6-sol", fallbackModels: ["zai/glm-5.2"] },
|
|
229
229
|
},
|
|
230
230
|
thinking: "xhigh",
|
|
231
231
|
tools: ["read", "grep", "bash"],
|
|
@@ -24,8 +24,9 @@ export interface SpawnAgentOptions {
|
|
|
24
24
|
export const DEFAULT_AGENT_TIMEOUT_MS = 30 * 60 * 1000;
|
|
25
25
|
const AGENT_TIMEOUT_EXIT_CODE = 124;
|
|
26
26
|
const AGENT_TIMEOUT_KILL_GRACE_MS = 5_000;
|
|
27
|
-
const
|
|
28
|
-
const
|
|
27
|
+
const AGENT_SETTLED_TERMINATE_GRACE_MS = 50;
|
|
28
|
+
const AGENT_SETTLED_COMPLETION_FALLBACK_MS = 1_000;
|
|
29
|
+
const AGENT_END_BACKCOMPAT_SETTLE_FALLBACK_MS = 100;
|
|
29
30
|
const EXIT_STDIO_FLUSH_GRACE_MS = 10;
|
|
30
31
|
|
|
31
32
|
export function shouldPersistSubagentSessions(env: NodeJS.ProcessEnv = process.env): boolean {
|
|
@@ -142,8 +143,9 @@ export function spawnAgent(
|
|
|
142
143
|
let shouldKeepStderr = false;
|
|
143
144
|
let timeoutTimer: NodeJS.Timeout | undefined;
|
|
144
145
|
let timeoutKillTimer: NodeJS.Timeout | undefined;
|
|
145
|
-
let
|
|
146
|
-
let
|
|
146
|
+
let agentSettledKillTimer: NodeJS.Timeout | undefined;
|
|
147
|
+
let agentSettledCompletionFallbackTimer: NodeJS.Timeout | undefined;
|
|
148
|
+
let agentEndBackcompatFallbackTimer: NodeJS.Timeout | undefined;
|
|
147
149
|
let exitFinalizationTimer: NodeJS.Timeout | undefined;
|
|
148
150
|
const suppressedRpcEventCounts = new Map<string, number>();
|
|
149
151
|
|
|
@@ -153,8 +155,9 @@ export function spawnAgent(
|
|
|
153
155
|
completionNotified = true;
|
|
154
156
|
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
155
157
|
if (timeoutKillTimer) clearTimeout(timeoutKillTimer);
|
|
156
|
-
if (
|
|
157
|
-
if (
|
|
158
|
+
if (agentSettledKillTimer) clearTimeout(agentSettledKillTimer);
|
|
159
|
+
if (agentSettledCompletionFallbackTimer) clearTimeout(agentSettledCompletionFallbackTimer);
|
|
160
|
+
if (agentEndBackcompatFallbackTimer) clearTimeout(agentEndBackcompatFallbackTimer);
|
|
158
161
|
if (exitFinalizationTimer) clearTimeout(exitFinalizationTimer);
|
|
159
162
|
if (!fs.existsSync(agentDir)) {
|
|
160
163
|
onComplete?.({
|
|
@@ -216,18 +219,22 @@ export function spawnAgent(
|
|
|
216
219
|
notifyComplete(exitCode);
|
|
217
220
|
};
|
|
218
221
|
|
|
219
|
-
const
|
|
220
|
-
if (
|
|
221
|
-
|
|
222
|
-
|
|
222
|
+
const scheduleAgentSettledTermination = () => {
|
|
223
|
+
if (agentEndBackcompatFallbackTimer) {
|
|
224
|
+
clearTimeout(agentEndBackcompatFallbackTimer);
|
|
225
|
+
agentEndBackcompatFallbackTimer = undefined;
|
|
226
|
+
}
|
|
227
|
+
if (agentSettledKillTimer) return;
|
|
228
|
+
agentSettledKillTimer = setTimeout(() => {
|
|
229
|
+
agentSettledKillTimer = undefined;
|
|
223
230
|
try {
|
|
224
231
|
terminateChildProcess(proc, "SIGTERM");
|
|
225
232
|
} catch {
|
|
226
233
|
/* process may have exited before the graceful termination timer fired */
|
|
227
234
|
}
|
|
228
|
-
},
|
|
229
|
-
|
|
230
|
-
|
|
235
|
+
}, AGENT_SETTLED_TERMINATE_GRACE_MS);
|
|
236
|
+
agentSettledKillTimer.unref?.();
|
|
237
|
+
agentSettledCompletionFallbackTimer = setTimeout(() => {
|
|
231
238
|
if (completionNotified) return;
|
|
232
239
|
try {
|
|
233
240
|
terminateChildProcess(proc, "SIGKILL");
|
|
@@ -239,8 +246,23 @@ export function spawnAgent(
|
|
|
239
246
|
proc.stderr?.destroy();
|
|
240
247
|
proc.unref();
|
|
241
248
|
finalizeCompletion(0, null);
|
|
242
|
-
},
|
|
243
|
-
|
|
249
|
+
}, AGENT_SETTLED_COMPLETION_FALLBACK_MS);
|
|
250
|
+
agentSettledCompletionFallbackTimer.unref?.();
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const clearAgentEndBackcompatFallback = () => {
|
|
254
|
+
if (!agentEndBackcompatFallbackTimer) return;
|
|
255
|
+
clearTimeout(agentEndBackcompatFallbackTimer);
|
|
256
|
+
agentEndBackcompatFallbackTimer = undefined;
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const scheduleAgentEndBackcompatFallback = () => {
|
|
260
|
+
if (agentEndBackcompatFallbackTimer || agentSettledKillTimer) return;
|
|
261
|
+
agentEndBackcompatFallbackTimer = setTimeout(() => {
|
|
262
|
+
agentEndBackcompatFallbackTimer = undefined;
|
|
263
|
+
scheduleAgentSettledTermination();
|
|
264
|
+
}, AGENT_END_BACKCOMPAT_SETTLE_FALLBACK_MS);
|
|
265
|
+
agentEndBackcompatFallbackTimer.unref?.();
|
|
244
266
|
};
|
|
245
267
|
|
|
246
268
|
const timeoutMs = options.timeoutMs ?? DEFAULT_AGENT_TIMEOUT_MS;
|
|
@@ -283,6 +305,15 @@ export function spawnAgent(
|
|
|
283
305
|
}
|
|
284
306
|
try {
|
|
285
307
|
const event = JSON.parse(line) as RpcEventRecord;
|
|
308
|
+
if (
|
|
309
|
+
event.type === "agent_start"
|
|
310
|
+
|| event.type === "message_start"
|
|
311
|
+
|| event.type === "tool_execution_start"
|
|
312
|
+
|| event.type === "compaction_start"
|
|
313
|
+
|| event.type === "auto_retry_start"
|
|
314
|
+
) {
|
|
315
|
+
clearAgentEndBackcompatFallback();
|
|
316
|
+
}
|
|
286
317
|
const storedEvent = compactRpcEventForTranscript(event, Buffer.byteLength(line, "utf8"));
|
|
287
318
|
if (storedEvent) transcriptStream.write(serializeJsonLine(storedEvent));
|
|
288
319
|
onRpcEvent?.(event);
|
|
@@ -309,7 +340,10 @@ export function spawnAgent(
|
|
|
309
340
|
const result = extractAgentEndResult(event);
|
|
310
341
|
if (result.trim())
|
|
311
342
|
fs.writeFileSync(path.join(agentDir, "result.md"), result, "utf-8");
|
|
312
|
-
|
|
343
|
+
scheduleAgentEndBackcompatFallback();
|
|
344
|
+
}
|
|
345
|
+
if (event.type === "agent_settled") {
|
|
346
|
+
scheduleAgentSettledTermination();
|
|
313
347
|
}
|
|
314
348
|
} catch (error) {
|
|
315
349
|
stderrStream.write(`Invalid RPC JSON line: ${String(error)}\n${previewLine(line)}\n`);
|
|
@@ -334,7 +368,7 @@ export function spawnAgent(
|
|
|
334
368
|
lastAgentEndError = "Sub-agent produced an oversized agent_end RPC event before a final result could be captured.";
|
|
335
369
|
fs.writeFileSync(path.join(agentDir, "result.md"), lastAgentEndError, "utf-8");
|
|
336
370
|
}
|
|
337
|
-
|
|
371
|
+
scheduleAgentEndBackcompatFallback();
|
|
338
372
|
return true;
|
|
339
373
|
}
|
|
340
374
|
return false;
|
|
@@ -378,8 +412,8 @@ export function spawnAgent(
|
|
|
378
412
|
// Keep stdin open while the RPC prompt is running. pi RPC mode treats stdin
|
|
379
413
|
// EOF as a shutdown request, while the prompt command itself is handled
|
|
380
414
|
// asynchronously after preflight. Closing stdin here can therefore terminate
|
|
381
|
-
// the child before message_end/agent_end events are emitted,
|
|
382
|
-
// with no result.md. The child is terminated explicitly after
|
|
415
|
+
// the child before message_end/agent_end/agent_settled events are emitted,
|
|
416
|
+
// producing exit 0 with no result.md. The child is terminated explicitly after agent_settled,
|
|
383
417
|
// timeout, stop, or process error.
|
|
384
418
|
|
|
385
419
|
const pid = proc.pid!;
|
|
@@ -169,7 +169,7 @@ const AgentTaskSchema = Type.Object({
|
|
|
169
169
|
scope: Type.Optional(Type.String({ description: "Relevant files/areas for this task" })),
|
|
170
170
|
subagentType: Type.Optional(Type.String({ description: "Logical sub-agent type/profile from config. Usually omit this so the router selects from the current config; set only for an explicit user-requested role, deterministic tests, or another concrete override." })),
|
|
171
171
|
model: Type.Optional(Type.String({ description: "Explicit model override for this sub-agent. Prefer subagentType for reusable routing." })),
|
|
172
|
-
thinking: Type.Optional(Type.String({ description: "Per-agent thinking level override (off, minimal, low, medium, high, xhigh)." })),
|
|
172
|
+
thinking: Type.Optional(Type.String({ description: "Per-agent thinking level override (off, minimal, low, medium, high, xhigh, max)." })),
|
|
173
173
|
promptAppend: Type.Optional(Type.String({ description: "Extra prompt instructions appended after the generated/type prompt." })),
|
|
174
174
|
promptOverride: Type.Optional(Type.String({ description: "Full prompt replacement for this sub-agent. Prefer configuring this per subagentType." })),
|
|
175
175
|
focus: Type.Optional(Type.String({ description: "Optional focus/attention instructions for attached images or scoped inspection." })),
|
|
@@ -194,7 +194,7 @@ export function registerSpawnTool(
|
|
|
194
194
|
tasks: Type.Array(AgentTaskSchema, { description: "Agent tasks to spawn" }),
|
|
195
195
|
runDir: Type.Optional(Type.String({ description: "Existing run directory. Creates new one if omitted." })),
|
|
196
196
|
slug: Type.Optional(Type.String({ description: "Slug for new run directory name" })),
|
|
197
|
-
thinking: Type.Optional(Type.String({ description: "Thinking level for sub-agents (off, minimal, low, medium, high, xhigh)" })),
|
|
197
|
+
thinking: Type.Optional(Type.String({ description: "Thinking level for sub-agents (off, minimal, low, medium, high, xhigh, max)" })),
|
|
198
198
|
extraArgs: Type.Optional(Type.Array(Type.String(), { description: "Additional pi CLI args for sub-agents" })),
|
|
199
199
|
timeoutSeconds: Type.Optional(Type.Number({ description: "Wall-clock timeout in seconds for every spawned agent in this call. Task-level timeoutSeconds overrides this." })),
|
|
200
200
|
watchSeconds: Type.Optional(Type.Number({ description: "Live update watch window after spawning (default/max 300s; 0 returns immediately)", default: DEFAULT_SPAWN_WATCH_SECONDS })),
|
|
@@ -21,7 +21,7 @@ const AgentTaskSchema = Type.Object({
|
|
|
21
21
|
scope: Type.Optional(Type.String({ description: "Relevant files/areas for this task" })),
|
|
22
22
|
subagentType: Type.Optional(Type.String({ description: "Logical sub-agent type/profile from config. Usually omit this so the router selects from the current config; set only for an explicit user-requested role, deterministic tests, or another concrete override." })),
|
|
23
23
|
model: Type.Optional(Type.String({ description: "Explicit model override for this sub-agent. Prefer subagentType for reusable routing." })),
|
|
24
|
-
thinking: Type.Optional(Type.String({ description: "Per-agent thinking level override (off, minimal, low, medium, high, xhigh)." })),
|
|
24
|
+
thinking: Type.Optional(Type.String({ description: "Per-agent thinking level override (off, minimal, low, medium, high, xhigh, max)." })),
|
|
25
25
|
promptAppend: Type.Optional(Type.String({ description: "Extra prompt instructions appended after the generated/type prompt." })),
|
|
26
26
|
promptOverride: Type.Optional(Type.String({ description: "Full prompt replacement for this sub-agent. Prefer configuring this per subagentType." })),
|
|
27
27
|
focus: Type.Optional(Type.String({ description: "Optional focus/attention instructions for attached images or scoped inspection." })),
|
|
@@ -92,7 +92,7 @@ export function registerSubagentsTool(
|
|
|
92
92
|
tasks: Type.Optional(Type.Array(AgentTaskSchema, { description: "spawn: agent tasks to launch" })),
|
|
93
93
|
runDir: Type.Optional(Type.String({ description: "spawn/status/wait/result/stop: run directory path. spawn creates one when omitted; status/wait/stop default to the latest project run; result can resolve runDir by agentId through .pi/subagents/registry.json." })),
|
|
94
94
|
slug: Type.Optional(Type.String({ description: "spawn: slug for a newly created run directory" })),
|
|
95
|
-
thinking: Type.Optional(Type.String({ description: "spawn: thinking level for sub-agents (off, minimal, low, medium, high, xhigh)" })),
|
|
95
|
+
thinking: Type.Optional(Type.String({ description: "spawn: thinking level for sub-agents (off, minimal, low, medium, high, xhigh, max)" })),
|
|
96
96
|
extraArgs: Type.Optional(Type.Array(Type.String(), { description: "spawn: additional pi CLI args for sub-agents" })),
|
|
97
97
|
timeoutSeconds: Type.Optional(Type.Number({ description: "spawn: wall-clock timeout in seconds for every spawned agent in this call; task timeoutSeconds overrides this." })),
|
|
98
98
|
watchSeconds: Type.Optional(Type.Number({ description: "spawn: live update watch window (default/max 300s; 0 detaches immediately)", default: DEFAULT_SPAWN_WATCH_SECONDS })),
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
* rejects HTTP 400 `Unknown parameter: 'input[N].content'` when non-message
|
|
4
4
|
* items (reasoning, function_call_output) carry a spurious `content` field.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* (incl. 0.79.10) is affected.
|
|
6
|
+
* Stray fields can come from replayed pi-ai items or from another extension
|
|
7
|
+
* that modifies the provider payload. The sanitizer therefore must be the
|
|
8
|
+
* LAST `before_provider_request` handler registered by pi-tools-suite.
|
|
10
9
|
*
|
|
11
10
|
* The fix must run at the transport layer because the provider has TWO paths:
|
|
12
11
|
*
|
|
@@ -16,16 +15,13 @@
|
|
|
16
15
|
* strip `content` from every non-message input item of each
|
|
17
16
|
* `response.create` frame, on the exact bytes leaving the socket.
|
|
18
17
|
*
|
|
19
|
-
* 2. SSE/fetch fallback path: once a websocket attempt fails
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* `
|
|
23
|
-
*
|
|
24
|
-
* offending item, so we also wrap `globalThis.fetch` once and strip the same
|
|
25
|
-
* spurious `content` from the request body on the exact bytes leaving the
|
|
26
|
-
* HTTP client.
|
|
18
|
+
* 2. SSE/fetch fallback path: once a websocket attempt fails, subsequent
|
|
19
|
+
* requests use the FULL body. pi-ai >= 0.80.6 zstd-compresses that body
|
|
20
|
+
* before fetch, so a fetch wrapper cannot inspect it. The final
|
|
21
|
+
* `before_provider_request` sanitizer is the primary guard for this path;
|
|
22
|
+
* the fetch wrapper remains a best-effort fallback for uncompressed bodies.
|
|
27
23
|
*
|
|
28
|
-
*
|
|
24
|
+
* Module registration order is part of this workaround's correctness.
|
|
29
25
|
*
|
|
30
26
|
* Remove this whole module once an upstream pi-ai release carries the fix.
|
|
31
27
|
*/
|
|
@@ -182,6 +178,9 @@ export function stripContentFromWireFrame(frame: unknown): { frame: Record<strin
|
|
|
182
178
|
}
|
|
183
179
|
|
|
184
180
|
export default function codexReasoningFix(pi: ExtensionAPI): void {
|
|
181
|
+
// src/index.ts deliberately registers this module last. A later payload
|
|
182
|
+
// modifier could otherwise reintroduce invalid content after sanitization,
|
|
183
|
+
// and compressed SSE bodies are too late to repair in the fetch wrapper.
|
|
185
184
|
pi.on("before_provider_request", async (event: ProviderRequestEvent, _ctx: ProviderRequestContext) => {
|
|
186
185
|
const result = stripReasoningContentFromPayload(event.payload);
|
|
187
186
|
return result === event.payload ? undefined : result;
|
|
@@ -132,6 +132,17 @@ function appendDcpControlToMessages(messages: unknown, text: string): unknown {
|
|
|
132
132
|
for (let index = messages.length - 1; index >= 0; index--) {
|
|
133
133
|
const message = messages[index] as any
|
|
134
134
|
if (!message || typeof message !== "object") continue
|
|
135
|
+
// Responses items such as reasoning/function_call_output do not accept a
|
|
136
|
+
// `content` field. Keep a function output at the tail by appending to its
|
|
137
|
+
// valid `output` string; otherwise scan back to an actual message item.
|
|
138
|
+
if (typeof message.type === "string" && message.type !== "message" && message.role === undefined) {
|
|
139
|
+
if (message.type === "function_call_output" && typeof message.output === "string") {
|
|
140
|
+
return messages.map((candidate: any, candidateIndex) => candidateIndex === index
|
|
141
|
+
? { ...candidate, output: `${candidate.output}\n\n${block}` }
|
|
142
|
+
: candidate)
|
|
143
|
+
}
|
|
144
|
+
continue
|
|
145
|
+
}
|
|
135
146
|
if (message.role === "system" || message.role === "developer") continue
|
|
136
147
|
targetIndex = index
|
|
137
148
|
break
|
|
@@ -141,7 +141,7 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
|
|
|
141
141
|
}
|
|
142
142
|
},
|
|
143
143
|
"gpt": {
|
|
144
|
-
"description": "Prefer enabled GPT-family models: spark/mini for cheap roles, gpt-5.
|
|
144
|
+
"description": "Prefer enabled GPT-family models: spark/mini for cheap roles, gpt-5.6-sol for heavy roles; fallback cross-provider on quota.",
|
|
145
145
|
"types": {
|
|
146
146
|
"quick": {
|
|
147
147
|
"model": "openai-codex/gpt-5.3-codex-spark",
|
|
@@ -174,17 +174,17 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
|
|
|
174
174
|
"thinking": "medium"
|
|
175
175
|
},
|
|
176
176
|
"review": {
|
|
177
|
-
"model": "openai-codex/gpt-5.
|
|
177
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
178
178
|
"fallbackModels": ["zai/glm-5.2"],
|
|
179
179
|
"thinking": "high"
|
|
180
180
|
},
|
|
181
181
|
"implement": {
|
|
182
|
-
"model": "openai-codex/gpt-5.
|
|
182
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
183
183
|
"fallbackModels": ["zai/glm-5.2"],
|
|
184
184
|
"thinking": "high"
|
|
185
185
|
},
|
|
186
186
|
"deep": {
|
|
187
|
-
"model": "openai-codex/gpt-5.
|
|
187
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
188
188
|
"fallbackModels": ["zai/glm-5.2"],
|
|
189
189
|
"thinking": "high"
|
|
190
190
|
}
|
|
@@ -225,17 +225,17 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
|
|
|
225
225
|
},
|
|
226
226
|
"review": {
|
|
227
227
|
"model": "antigravity/antigravity-claude-sonnet-4-6",
|
|
228
|
-
"fallbackModels": ["openai-codex/gpt-5.
|
|
228
|
+
"fallbackModels": ["openai-codex/gpt-5.6-sol", "zai/glm-5.2"],
|
|
229
229
|
"thinking": "high"
|
|
230
230
|
},
|
|
231
231
|
"implement": {
|
|
232
|
-
"model": "openai-codex/gpt-5.
|
|
232
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
233
233
|
"fallbackModels": ["zai/glm-5.2"],
|
|
234
234
|
"thinking": "high"
|
|
235
235
|
},
|
|
236
236
|
"deep": {
|
|
237
237
|
"model": "antigravity/antigravity-claude-opus-4-6-thinking",
|
|
238
|
-
"fallbackModels": ["openai-codex/gpt-5.
|
|
238
|
+
"fallbackModels": ["openai-codex/gpt-5.6-sol", "zai/glm-5.2"],
|
|
239
239
|
"thinking": "high"
|
|
240
240
|
}
|
|
241
241
|
}
|
|
@@ -280,34 +280,34 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
|
|
|
280
280
|
},
|
|
281
281
|
"review": {
|
|
282
282
|
"description": "Use for review/audit of existing code or changes: correctness, security, performance, maintainability, API risks, quality. Do not implement new code.",
|
|
283
|
-
"model": "openai-codex/gpt-5.
|
|
283
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
284
284
|
"fallbackModels": ["zai/glm-5.2"],
|
|
285
285
|
"thinking": "high",
|
|
286
286
|
"tools": ["read", "grep"]
|
|
287
287
|
},
|
|
288
288
|
"implement": {
|
|
289
289
|
"description": "Use when the sub-agent should make or plan code changes for a feature, bug fix, or refactor.",
|
|
290
|
-
"model": "openai-codex/gpt-5.
|
|
290
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
291
291
|
"fallbackModels": ["zai/glm-5.2"],
|
|
292
292
|
"thinking": "high"
|
|
293
293
|
},
|
|
294
294
|
"deep": {
|
|
295
295
|
"description": "Use for broad hard reasoning: architecture, system design, cross-module impact, complex tradeoffs.",
|
|
296
|
-
"model": "openai-codex/gpt-5.
|
|
296
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
297
297
|
"fallbackModels": ["zai/glm-5.2"],
|
|
298
298
|
"thinking": "high"
|
|
299
299
|
},
|
|
300
300
|
"oracle": {
|
|
301
301
|
"description": "Oracle: cross-provider flagship second opinion for hard or high-stakes uncertainty. Use sparingly to pressure-test architecture, plans, root-cause hypotheses, risk/security calls, or final recommendations when independent disagreement is valuable. Read-only; advise, do not edit.",
|
|
302
|
-
"model": "openai-codex/gpt-5.
|
|
302
|
+
"model": "openai-codex/gpt-5.6-sol",
|
|
303
303
|
"fallbackModels": ["zai/glm-5.2"],
|
|
304
304
|
"thinking": "xhigh",
|
|
305
305
|
"tools": ["read", "grep", "bash"],
|
|
306
306
|
"modelByParent": {
|
|
307
|
-
"zai/*": { "model": "openai-codex/gpt-5.
|
|
308
|
-
"openai-codex/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.
|
|
309
|
-
"antigravity/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.
|
|
310
|
-
"anthropic/*": { "model": "openai-codex/gpt-5.
|
|
307
|
+
"zai/*": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.2"] },
|
|
308
|
+
"openai-codex/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.6-sol"] },
|
|
309
|
+
"antigravity/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.6-sol"] },
|
|
310
|
+
"anthropic/*": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.2"] }
|
|
311
311
|
},
|
|
312
312
|
"promptAppend": "You are an oracle: a flagship model from a different provider giving a second opinion to the parent agent. Give a concise, decisive recommendation with key tradeoffs and risks. Disagree when warranted; do not rubber-stamp. Do not edit unless explicitly asked."
|
|
313
313
|
}
|