pi-ui-extend 0.1.55 → 0.1.56

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.
@@ -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.5", "thinking": "medium" },
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
@@ -47,6 +47,7 @@ export type Theme = {
47
47
  thinkingForeground: string;
48
48
  userForeground: string;
49
49
  thinkingXHigh: string;
50
+ thinkingMax: string;
50
51
  modelOpenAI: string;
51
52
  statusDotBase: string;
52
53
  statusDotRunningDim: string;
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.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.5", "fallbackModels": ["zai/glm-5.2"] },
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.5"] },
275
- "anthropic/*": { "model": "openai-codex/gpt-5.5", "fallbackModels": ["zai/glm-5.2"] }
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.5`, 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.
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.3",
42
- "@earendil-works/pi-coding-agent": "0.80.3",
43
- "@earendil-works/pi-tui": "0.80.3",
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.5", "fallbackModels": ["zai/glm-5.2"] },
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.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.5 for heavy roles; fallback cross-provider on quota.",
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.5", "fallbackModels": ["zai/glm-5.2"], "thinking": "high" },
136
- "implement": { "model": "openai-codex/gpt-5.5", "fallbackModels": ["zai/glm-5.2"], "thinking": "high" },
137
- "deep": { "model": "openai-codex/gpt-5.5", "fallbackModels": ["zai/glm-5.2"], "thinking": "high" }
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.5", "zai/glm-5.2"], "thinking": "high" },
151
- "implement": { "model": "openai-codex/gpt-5.5", "fallbackModels": ["zai/glm-5.2"], "thinking": "high" },
152
- "deep": { "model": "antigravity/antigravity-claude-opus-4-6-thinking", "fallbackModels": ["openai-codex/gpt-5.5", "zai/glm-5.2"], "thinking": "high" }
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.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.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.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.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.5", "fallbackModels": ["zai/glm-5.2"] },
234
- "openai-codex/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.5"] },
235
- "antigravity/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.5"] },
236
- "anthropic/*": { "model": "openai-codex/gpt-5.5", "fallbackModels": ["zai/glm-5.2"] }
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.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.5", fallbackModels: ["zai/glm-5.2"] },
226
- "openai-codex/*": { model: "zai/glm-5.2", fallbackModels: ["openai-codex/gpt-5.5"] },
227
- "antigravity/*": { model: "zai/glm-5.2", fallbackModels: ["openai-codex/gpt-5.5"] },
228
- "anthropic/*": { model: "openai-codex/gpt-5.5", fallbackModels: ["zai/glm-5.2"] },
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 AGENT_END_TERMINATE_GRACE_MS = 50;
28
- const AGENT_END_COMPLETION_FALLBACK_MS = 1_000;
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 agentEndKillTimer: NodeJS.Timeout | undefined;
146
- let agentEndCompletionFallbackTimer: NodeJS.Timeout | undefined;
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 (agentEndKillTimer) clearTimeout(agentEndKillTimer);
157
- if (agentEndCompletionFallbackTimer) clearTimeout(agentEndCompletionFallbackTimer);
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 scheduleAgentEndTermination = () => {
220
- if (agentEndKillTimer) return;
221
- agentEndKillTimer = setTimeout(() => {
222
- agentEndKillTimer = undefined;
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
- }, AGENT_END_TERMINATE_GRACE_MS);
229
- agentEndKillTimer.unref?.();
230
- agentEndCompletionFallbackTimer = setTimeout(() => {
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
- }, AGENT_END_COMPLETION_FALLBACK_MS);
243
- agentEndCompletionFallbackTimer.unref?.();
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
- scheduleAgentEndTermination();
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
- scheduleAgentEndTermination();
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, producing exit 0
382
- // with no result.md. The child is terminated explicitly after agent_end,
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 })),
@@ -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.5 for heavy roles; fallback cross-provider on quota.",
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.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.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.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.5", "zai/glm-5.2"],
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.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.5", "zai/glm-5.2"],
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.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.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.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.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.5", "fallbackModels": ["zai/glm-5.2"] },
308
- "openai-codex/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.5"] },
309
- "antigravity/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.5"] },
310
- "anthropic/*": { "model": "openai-codex/gpt-5.5", "fallbackModels": ["zai/glm-5.2"] }
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
  }
@@ -27,7 +27,7 @@ const TODO_NUDGE_INITIAL_DELAY_MS = 0;
27
27
  const TODO_NUDGE_IDLE_RETRY_DELAY_MS = 100;
28
28
  const TODO_NUDGE_MAX_IDLE_ATTEMPTS = 40;
29
29
  const ASK_USER_TOOL_NAMES = new Set(["ask_user", "ask_user_question", "question"]);
30
- const TODO_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const;
30
+ const TODO_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"] as const;
31
31
  const TODO_THINKING_RESTORE_METADATA_KEY = "__piTodoRestoreThinking";
32
32
 
33
33
  function isStaleExtensionContextError(error: unknown): boolean {
@@ -30,7 +30,7 @@ function uniqueNumbers(values: number[] | undefined): number[] {
30
30
  }
31
31
 
32
32
  function isTodoThinkingLevel(value: unknown): value is TodoThinkingLevel {
33
- return value === "off" || value === "minimal" || value === "low" || value === "medium" || value === "high" || value === "xhigh";
33
+ return value === "off" || value === "minimal" || value === "low" || value === "medium" || value === "high" || value === "xhigh" || value === "max";
34
34
  }
35
35
 
36
36
  function findTask(state: TaskState, id: number): Task | undefined {
@@ -24,7 +24,7 @@ export const MSG_NO_TODOS = "No todos yet. Ask the agent to add some!";
24
24
  // ---------------------------------------------------------------------------
25
25
 
26
26
  export type TaskStatus = "pending" | "in_progress" | "deferred" | "completed" | "deleted";
27
- export type TodoThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
27
+ export type TodoThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
28
28
 
29
29
  export type TaskAction = "create" | "update" | "batch_create" | "batch_update" | "list" | "get" | "delete" | "clear" | "export" | "import";
30
30
 
@@ -104,7 +104,7 @@ export const TodoParamsSchema = Type.Object({
104
104
  }),
105
105
  ),
106
106
  thinking: Type.Optional(
107
- StringEnum(["off", "minimal", "low", "medium", "high", "xhigh"] as const, {
107
+ StringEnum(["off", "minimal", "low", "medium", "high", "xhigh", "max"] as const, {
108
108
  description: "Per-task thinking level used when todoThinking is enabled and this task is in_progress",
109
109
  }),
110
110
  ),
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "pi-ui-extend",
3
- "version": "0.1.55",
3
+ "version": "0.1.56",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
7
+ "pi-ui-extend": "./bin/pix.mjs",
7
8
  "pix": "./bin/pix.mjs"
8
9
  },
9
10
  "exports": {
@@ -64,9 +65,9 @@
64
65
  "prepublishOnly": "npm run check && npm run build:pix && npm run generate-schemas"
65
66
  },
66
67
  "dependencies": {
67
- "@earendil-works/pi-ai": "0.80.3",
68
- "@earendil-works/pi-coding-agent": "0.80.3",
69
- "@earendil-works/pi-tui": "0.80.3",
68
+ "@earendil-works/pi-ai": "0.80.6",
69
+ "@earendil-works/pi-coding-agent": "0.80.6",
70
+ "@earendil-works/pi-tui": "0.80.6",
70
71
  "@mariozechner/clipboard": "^0.3.9",
71
72
  "jsonc-parser": "3.3.1",
72
73
  "typebox": "1.1.38",