pi-ui-extend 0.1.38 → 0.1.39

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.
Files changed (43) hide show
  1. package/dist/app/app.d.ts +0 -1
  2. package/dist/app/app.js +22 -21
  3. package/dist/app/input/input-controller.d.ts +1 -0
  4. package/dist/app/input/input-controller.js +40 -12
  5. package/dist/app/model/model-usage-status.js +4 -2
  6. package/dist/app/session/request-history.js +2 -0
  7. package/dist/app/session/session-event-controller.d.ts +13 -0
  8. package/dist/app/session/session-event-controller.js +27 -0
  9. package/dist/app/session/tabs-controller.d.ts +8 -0
  10. package/dist/app/session/tabs-controller.js +37 -6
  11. package/dist/app/workspace/workspace-actions-controller.d.ts +1 -0
  12. package/dist/app/workspace/workspace-actions-controller.js +2 -1
  13. package/dist/bundled-extensions/terminal-bell/index.js +1 -1
  14. package/dist/markdown-format.js +14 -25
  15. package/dist/terminal-width.d.ts +14 -0
  16. package/dist/terminal-width.js +31 -2
  17. package/dist/theme.js +2 -2
  18. package/external/pi-tools-suite/README.md +34 -9
  19. package/external/pi-tools-suite/package.json +3 -3
  20. package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +35 -21
  21. package/external/pi-tools-suite/src/async-subagents/commands.ts +1 -1
  22. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +2 -2
  23. package/external/pi-tools-suite/src/async-subagents/core/config.ts +70 -12
  24. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +1 -1
  25. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +1 -1
  26. package/external/pi-tools-suite/src/async-subagents/core/types.ts +1 -1
  27. package/external/pi-tools-suite/src/async-subagents/index.ts +6 -6
  28. package/external/pi-tools-suite/src/async-subagents/lib.ts +1 -1
  29. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +4 -2
  30. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +2 -2
  31. package/external/pi-tools-suite/src/{glm-coding-discipline → coding-discipline}/index.ts +17 -8
  32. package/external/pi-tools-suite/src/config.ts +1 -1
  33. package/external/pi-tools-suite/src/dcp/auto-compress.ts +368 -0
  34. package/external/pi-tools-suite/src/dcp/compress-tool.ts +3 -0
  35. package/external/pi-tools-suite/src/dcp/config.ts +23 -0
  36. package/external/pi-tools-suite/src/dcp/index.ts +112 -7
  37. package/external/pi-tools-suite/src/dcp/prompts.ts +8 -0
  38. package/external/pi-tools-suite/src/dcp/state.ts +41 -0
  39. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +30 -22
  40. package/external/pi-tools-suite/src/index.ts +2 -1
  41. package/external/pi-tools-suite/src/session-name/index.ts +37 -0
  42. package/external/pi-tools-suite/src/tool-descriptions.ts +16 -4
  43. package/package.json +4 -4
@@ -218,6 +218,24 @@ export interface DcpState {
218
218
  nextNudgeAnchorId: number
219
219
  /** Diagnostic/telemetry snapshot for the latest emitted reminder. */
220
220
  lastNudge?: DcpLastNudge
221
+ /**
222
+ * The context window observed on the previous `context` event, used to
223
+ * detect a mid-session model/window downgrade (e.g. switch from a 1M model
224
+ * to a 275K model). When the window shrinks and inherited tokens already
225
+ * exceed `minContextPercent`, the context handler forces a pre-emptive
226
+ * strong nudge so the model is told to compress before the window fills.
227
+ * `undefined` until the first context event records a window.
228
+ */
229
+ lastContextWindow?: number
230
+ /**
231
+ * How many consecutive `context-strong` nudges have been emitted without a
232
+ * subsequent successful `compress` (model- or DCP-initiated). When this
233
+ * reaches `compress.autoCompress.patience` while context is above the
234
+ * emergency threshold, the auto-compress fallback creates a block without
235
+ * waiting for the model. Reset to 0 on any successful compression, when
236
+ * pressure drops below the emergency threshold, or on a window change.
237
+ */
238
+ consecutiveIgnoredStrongNudges: number
221
239
  }
222
240
 
223
241
  // ---------------------------------------------------------------------------
@@ -247,6 +265,8 @@ export function createState(): DcpState {
247
265
  nudgeAnchors: [],
248
266
  nextNudgeAnchorId: 1,
249
267
  lastNudge: undefined,
268
+ lastContextWindow: undefined,
269
+ consecutiveIgnoredStrongNudges: 0,
250
270
  }
251
271
  }
252
272
 
@@ -276,6 +296,8 @@ export function resetState(state: DcpState): void {
276
296
  state.nudgeAnchors = []
277
297
  state.nextNudgeAnchorId = 1
278
298
  state.lastNudge = undefined
299
+ state.lastContextWindow = undefined
300
+ state.consecutiveIgnoredStrongNudges = 0
279
301
  }
280
302
 
281
303
  /**
@@ -412,6 +434,17 @@ export interface SerializedDcpState {
412
434
  nudgeCounter?: number
413
435
  /** Persisted since v?.?. Diagnostic turn of the last emitted nudge. */
414
436
  lastNudgeTurn?: number
437
+ /**
438
+ * Persisted so a mid-session window downgrade (model switch to a smaller
439
+ * context window) is still detectable after a pi process restart / resume.
440
+ */
441
+ lastContextWindow?: number
442
+ /**
443
+ * Persisted so the auto-compress fallback's patience counter survives a pi
444
+ * process restart / resume, preventing a stuck "model ignores strong nudges"
445
+ * state from being silently cleared by a reload.
446
+ */
447
+ consecutiveIgnoredStrongNudges?: number
415
448
  /** Hash of the last persisted serialized state, used for dedup. */
416
449
  _stateHash?: string
417
450
  }
@@ -583,6 +616,8 @@ export function serializeState(state: DcpState): SerializedDcpState {
583
616
  currentTurn: state.currentTurn,
584
617
  nudgeCounter: state.nudgeCounter,
585
618
  lastNudgeTurn: state.lastNudgeTurn,
619
+ lastContextWindow: state.lastContextWindow,
620
+ consecutiveIgnoredStrongNudges: state.consecutiveIgnoredStrongNudges,
586
621
  }
587
622
  }
588
623
 
@@ -743,6 +778,12 @@ export function restoreState(state: DcpState, data: unknown): void {
743
778
  if (typeof saved.currentTurn === "number" && Number.isFinite(saved.currentTurn) && saved.currentTurn >= 0) {
744
779
  state.currentTurn = Math.floor(saved.currentTurn)
745
780
  }
781
+ if (typeof saved.lastContextWindow === "number" && Number.isFinite(saved.lastContextWindow) && saved.lastContextWindow > 0) {
782
+ state.lastContextWindow = saved.lastContextWindow
783
+ }
784
+ if (typeof saved.consecutiveIgnoredStrongNudges === "number" && Number.isFinite(saved.consecutiveIgnoredStrongNudges) && saved.consecutiveIgnoredStrongNudges >= 0) {
785
+ state.consecutiveIgnoredStrongNudges = Math.floor(saved.consecutiveIgnoredStrongNudges)
786
+ }
746
787
  }
747
788
 
748
789
  // ---------------------------------------------------------------------------
@@ -8,7 +8,8 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
8
8
  // When true, todo items may carry a per-task thinking level and the todo
9
9
  // module will switch/restore Pi's thinking level as in-progress tasks change.
10
10
  "todoThinking": true,
11
- // Vision-capable model used by GLM's lookup tool. Remove or set to null to disable lookup.
11
+ // Vision-capable model used by the coding-discipline lookup tool for blind-model
12
+ // screenshot/image questions. Remove or set to null to disable lookup.
12
13
  "lookupModel": "openai-codex/gpt-5.4-mini",
13
14
  "terminalBell": { "sound": true },
14
15
  // comment-checker: nudges the agent to remove AI-slop code comments it just
@@ -38,10 +39,10 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
38
39
  "debugLog": { "maxBytes": 5242880, "maxBackups": 3 },
39
40
  "manualMode": { "enabled": false, "automaticStrategies": true },
40
41
  "modelOverrides": {
41
- "openai-codex/gpt-5.5": {
42
+ "openai-codex/gpt-5*": {
42
43
  "compress": {
43
- "minContextPercent": "28%",
44
- "maxContextPercent": "48%"
44
+ "minContextPercent": "26%",
45
+ "maxContextPercent": "46%"
45
46
  }
46
47
  },
47
48
  "openai-codex/gpt-5.4-mini": {
@@ -92,8 +93,15 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
92
93
  "maxContextPercent": "55%",
93
94
  "nudgeFrequency": 1,
94
95
  "iterationNudgeThreshold": 4,
96
+ "nudgeForce": "strong",
95
97
  "autoCandidates": { "minContextPercent": 0.2 },
96
- "messageMode": { "minContextPercent": 0.2 }
98
+ "messageMode": { "minContextPercent": 0.2 },
99
+ "autoCompress": {
100
+ "enabled": false,
101
+ "patience": 2,
102
+ "summarizerModel": ["zai/glm-5.2", "zai/glm-4.5-air"],
103
+ "timeoutMs": 20000
104
+ }
97
105
  }
98
106
  },
99
107
  "asyncSubagents": {
@@ -101,7 +109,7 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
101
109
  "routing": { "enabled": true, "model": "zai/glm-4.5-air", "maxTaskChars": 1200, "maxTokens": 512, "maxRetries": 1, "timeoutMs": 12000, "debug": false },
102
110
  "presets": {
103
111
  "cheap": {
104
- "description": "Use cheap GLM/Gemini Flash models for text/code roles; keep vision on the enabled GPT vision model.",
112
+ "description": "Use cheap GLM/Gemini Flash models for text/code roles.",
105
113
  "types": {
106
114
  "quick": { "model": "zai/glm-4.5-air", "thinking": "off" },
107
115
  "scan": { "model": "zai/glm-4.5-air", "thinking": "off" },
@@ -115,8 +123,7 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
115
123
  "tests": { "model": "zai/glm-5-turbo", "thinking": "medium" },
116
124
  "review": { "model": "zai/glm-5.2", "thinking": "high" },
117
125
  "implement": { "model": "zai/glm-5.2", "thinking": "high" },
118
- "deep": { "model": "zai/glm-5.2", "thinking": "high" },
119
- "vision": { "model": "openai-codex/gpt-5.4-mini", "thinking": "off" }
126
+ "deep": { "model": "zai/glm-5.2", "thinking": "high" }
120
127
  }
121
128
  },
122
129
  "gpt": {
@@ -166,8 +173,7 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
166
173
  "model": "openai-codex/gpt-5.5",
167
174
  "fallbackModels": ["zai/glm-5.2"],
168
175
  "thinking": "high"
169
- },
170
- "vision": { "model": "openai-codex/gpt-5.4-mini", "thinking": "off" }
176
+ }
171
177
  }
172
178
  },
173
179
  "deep": {
@@ -217,8 +223,7 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
217
223
  "model": "antigravity/antigravity-claude-opus-4-6-thinking",
218
224
  "fallbackModels": ["openai-codex/gpt-5.5", "zai/glm-5.2"],
219
225
  "thinking": "high"
220
- },
221
- "vision": { "model": "openai-codex/gpt-5.4-mini", "thinking": "off" }
226
+ }
222
227
  }
223
228
  }
224
229
  },
@@ -278,16 +283,19 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
278
283
  "fallbackModels": ["zai/glm-5.2"],
279
284
  "thinking": "high"
280
285
  },
281
- "vision": {
282
- "description": "Use only when task has imagePaths, screenshots, or asks to inspect visible UI/image content for a text-only parent.",
283
- "model": "openai-codex/gpt-5.4-mini",
284
- "thinking": "off",
285
- "promptAppend": [
286
- "You are a vision helper for a parent model that may not be able to see images.",
287
- "Inspect any attached images and any image paths mentioned in the task/scope. Describe concrete visible details, UI state, text, layout, errors, and uncertainties.",
288
- "If focus instructions are provided, prioritize them, but still mention other important visible findings.",
289
- "Do not make code changes. Return a compact visual description that the parent agent can rely on."
290
- ]
286
+ "oracle": {
287
+ "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.",
288
+ "model": "openai-codex/gpt-5.5",
289
+ "fallbackModels": ["zai/glm-5.2"],
290
+ "thinking": "xhigh",
291
+ "tools": ["read", "grep", "bash"],
292
+ "modelByParent": {
293
+ "zai/*": { "model": "openai-codex/gpt-5.5", "fallbackModels": ["zai/glm-5.2"] },
294
+ "openai-codex/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.5"] },
295
+ "antigravity/*": { "model": "zai/glm-5.2", "fallbackModels": ["openai-codex/gpt-5.5"] },
296
+ "anthropic/*": { "model": "openai-codex/gpt-5.5", "fallbackModels": ["zai/glm-5.2"] }
297
+ },
298
+ "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."
291
299
  }
292
300
  }
293
301
  },
@@ -10,11 +10,12 @@ type ExtensionModule = {
10
10
  };
11
11
 
12
12
  const MODULES: Array<{ name: string; load: () => Promise<ExtensionModule> }> = [
13
- { name: "glm-coding-discipline", load: () => import("./glm-coding-discipline/index") },
13
+ { name: "coding-discipline", load: () => import("./coding-discipline/index") },
14
14
  { name: "ast-grep", load: () => import("./ast-grep/index") },
15
15
  { name: "async-subagents", load: () => import("./async-subagents/index") },
16
16
  { name: "lsp", load: () => import("./lsp/index") },
17
17
  { name: "comment-checker", load: () => import("./comment-checker/index") },
18
+ { name: "session-name", load: () => import("./session-name/index") },
18
19
  { name: "repo-discovery", load: () => import("./repo-discovery/index") },
19
20
  { name: "antigravity-auth", load: () => import("./antigravity-auth/index") },
20
21
  { name: "opencode-import", load: () => import("./opencode-import/index") },
@@ -0,0 +1,37 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { Type } from "typebox";
3
+
4
+ import { SESSION_NAME_TOOL_DESCRIPTION } from "../tool-descriptions.js";
5
+
6
+ type SessionNameParams = {
7
+ name?: string;
8
+ };
9
+
10
+ function formatCurrentName(name: string | undefined): string {
11
+ return name ? `Current session name: ${name}` : "No session name is set.";
12
+ }
13
+
14
+ export default function sessionName(pi: ExtensionAPI): void {
15
+ pi.registerTool({
16
+ ...SESSION_NAME_TOOL_DESCRIPTION,
17
+ parameters: Type.Object({
18
+ name: Type.Optional(Type.String({ description: "New session name to set. Omit to read the current session name." })),
19
+ }),
20
+ async execute(_toolCallId: string, params: SessionNameParams) {
21
+ const nextName = params.name?.trim();
22
+
23
+ if (!nextName) {
24
+ return {
25
+ content: [{ type: "text", text: formatCurrentName(pi.getSessionName()) }],
26
+ details: { changed: false, sessionName: pi.getSessionName() ?? null },
27
+ };
28
+ }
29
+
30
+ pi.setSessionName(nextName);
31
+ return {
32
+ content: [{ type: "text", text: `Session name set: ${nextName}` }],
33
+ details: { changed: true, sessionName: nextName },
34
+ };
35
+ },
36
+ });
37
+ }
@@ -73,7 +73,7 @@ export function asyncSubagentToolDescriptions(options: ToolDescriptionSetOptions
73
73
  description: [
74
74
  "Manage isolated async sub-agents for large, parallel, context-heavy work.",
75
75
  "Presets from async-subagents config and /subagent-preset choose role model/thinking/args; AGENTS_PRESET or /subagent-preset session <name> overrides the current session; /subagent-preset init creates a sample config.",
76
- "Omit subagentType so the router chooses a configured role unless the user or task requires a role, vision, or deterministic override.",
76
+ "Omit subagentType so the router chooses a configured role unless the user or task requires a role or deterministic override.",
77
77
  repoDiscovery
78
78
  ? "Use for broad independent tracks, review axes, or hypotheses even though repo_* tools are available."
79
79
  : "Use first for broad codebase discovery split into tracks, review axes, or incident-triage hypotheses when repo_* tools are unavailable.",
@@ -82,7 +82,7 @@ export function asyncSubagentToolDescriptions(options: ToolDescriptionSetOptions
82
82
  ].join(" "),
83
83
  promptSnippet:
84
84
  "Use subagents action='spawn' for multiple independent agents, explicit delegate/parallelize/split work requests, or one large review/debug track that should stay out of the parent context. " +
85
- "Usually omit subagentType so the router chooses; set it only for user-named roles, vision/image handling, deterministic tests, or another concrete override. Avoid trivial reads/edits and do not call status/wait immediately after spawn just for progress. " +
85
+ "Usually omit subagentType so the router chooses; set it only for user-named roles, deterministic tests, or another concrete override. Avoid trivial reads/edits and do not call status/wait immediately after spawn just for progress. " +
86
86
  (repoDiscovery
87
87
  ? "For one semantic code-discovery question, use repo_search; for independent tracks/hypotheses/review axes, delegate even when repo_* tools exist. Read result only after completion when findings are needed."
88
88
  : "For one focused code-discovery question, use direct read/grep. Without repo_* tools, spawn several focused scan/quick agents first for broad multi-track discovery, incident triage, release readiness, risk strategy, or parallel reviews. Read result only after completion when findings are needed."),
@@ -97,8 +97,9 @@ export function asyncSubagentToolDescriptions(options: ToolDescriptionSetOptions
97
97
  : "For incident triage, release readiness, or risk/test strategy with separate hypotheses or review tracks and no repo_* tools, call action='spawn' as the first discovery step; direct read/grep can follow.",
98
98
  "Do not use subagents for exact-string lookups, known-file edits, typo/text replacements, obvious one-file changes, or interactive user input; use the cheapest direct path.",
99
99
  "Spawn multiple focused agents in one action='spawn' call for independent questions; for synthetic tests or bounded probes, pass timeoutSeconds slightly above expected runtime.",
100
- "For spawn, leave subagentType unset so the router chooses from configured roles. Set it only for user-named roles, vision/image handling, deterministic tests, or another concrete override.",
101
- "Use subagentType='vision' with imagePaths and optional focus when images/screenshots/diagrams need visual inspection.",
100
+ "For spawn, leave subagentType unset so the router chooses from configured roles. Set it only for user-named roles, deterministic tests, or another concrete override.",
101
+ "Use subagentType='oracle' sparingly for cross-provider second opinions on high-stakes uncertainty or final plan/risk checks.",
102
+ "For screenshot/image inspection by blind models, use lookup; subagents only receive imagePaths when a broader delegated track genuinely needs them.",
102
103
  "If the user asks to start, run, launch, or test parallel sub-agents, call action='spawn' and then stop; completion/failure notifications will wake the parent so do not immediately call action='status' or action='wait' just to see whether agents finished.",
103
104
  "Use status for non-blocking progress/recovery, wait only when requested or needed, and result only after completion; registry mappings can recover latest runDir/agentId after reload.",
104
105
  "Result output is compact with artifact links; inspect raw artifacts only when full details are necessary.",
@@ -251,6 +252,17 @@ export const TODO_TOOL_DESCRIPTION: ToolDescription = {
251
252
  ],
252
253
  };
253
254
 
255
+ export const SESSION_NAME_TOOL_DESCRIPTION: ToolDescription = {
256
+ name: "session_name",
257
+ label: "Session Name",
258
+ description: "Show or set the current session name so the agent can retitle the active session without relying on slash-command parsing.",
259
+ promptSnippet: "Use session_name to rename the current session directly when the task calls for updating the session title.",
260
+ promptGuidelines: [
261
+ "Pass a short, user-meaningful name when renaming the current session.",
262
+ "Call without a name only when you need to read the current session name.",
263
+ ],
264
+ };
265
+
254
266
  export const WEB_SEARCH_TOOL_DESCRIPTIONS = {
255
267
  webSearch: {
256
268
  name: "web_search",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-ui-extend",
3
- "version": "0.1.38",
3
+ "version": "0.1.39",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -64,9 +64,9 @@
64
64
  "prepublishOnly": "npm run check && npm run build:pix && npm run generate-schemas"
65
65
  },
66
66
  "dependencies": {
67
- "@earendil-works/pi-ai": "^0.79.6",
68
- "@earendil-works/pi-coding-agent": "^0.79.6",
69
- "@earendil-works/pi-tui": "^0.79.6",
67
+ "@earendil-works/pi-ai": "0.79.7",
68
+ "@earendil-works/pi-coding-agent": "0.79.7",
69
+ "@earendil-works/pi-tui": "0.79.7",
70
70
  "@mariozechner/clipboard": "^0.3.9",
71
71
  "jsonc-parser": "3.3.1",
72
72
  "typebox": "1.1.38",