@oh-my-pi/pi-coding-agent 17.1.8 → 17.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +92 -0
- package/dist/{CHANGELOG-vt8ene9g.md → CHANGELOG-be1f2t8h.md} +92 -0
- package/dist/cli.js +9986 -9776
- package/dist/{template-dys3vk5b.js → template-8vdv6xb4.js} +1 -1
- package/dist/types/advisor/runtime.d.ts +8 -2
- package/dist/types/advisor/transcript-recorder.d.ts +15 -0
- package/dist/types/auto-thinking/classifier.d.ts +9 -2
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/session-picker.d.ts +14 -7
- package/dist/types/collab/guest.d.ts +21 -2
- package/dist/types/commands/launch.d.ts +6 -0
- package/dist/types/config/settings-schema.d.ts +63 -8
- package/dist/types/cursor-bridge-tools.d.ts +54 -0
- package/dist/types/cursor.d.ts +193 -8
- package/dist/types/edit/edit-clipboard.d.ts +19 -0
- package/dist/types/edit/hashline/diff.d.ts +9 -1
- package/dist/types/edit/index.d.ts +8 -1
- package/dist/types/edit/streaming.d.ts +8 -1
- package/dist/types/extensibility/extensions/runner.d.ts +19 -2
- package/dist/types/extensibility/extensions/types.d.ts +25 -1
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +2 -0
- package/dist/types/internal-urls/local-protocol.d.ts +3 -2
- package/dist/types/launch/terminal-output-worker-client.d.ts +5 -0
- package/dist/types/launch/terminal-output-worker-protocol.d.ts +14 -0
- package/dist/types/launch/terminal-output-worker.d.ts +1 -0
- package/dist/types/lsp/client.d.ts +2 -0
- package/dist/types/main.d.ts +2 -0
- package/dist/types/mcp/manager.d.ts +33 -4
- package/dist/types/modes/components/codex-reset-fireworks.d.ts +51 -0
- package/dist/types/modes/components/read-tool-group.d.ts +12 -0
- package/dist/types/modes/components/session-selector.d.ts +6 -0
- package/dist/types/modes/components/status-line/component.d.ts +23 -0
- package/dist/types/modes/components/tool-execution.d.ts +16 -7
- package/dist/types/modes/components/usage-row.d.ts +2 -0
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +26 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
- package/dist/types/modes/interactive-mode.d.ts +4 -2
- package/dist/types/modes/rpc/rpc-client.d.ts +7 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +16 -0
- package/dist/types/modes/theme/theme.d.ts +12 -1
- package/dist/types/modes/types.d.ts +2 -1
- package/dist/types/sdk.d.ts +1 -0
- package/dist/types/session/agent-session-events.d.ts +2 -0
- package/dist/types/session/agent-session-types.d.ts +36 -1
- package/dist/types/session/agent-session.d.ts +4 -2
- package/dist/types/session/claude-session-store.d.ts +13 -0
- package/dist/types/session/codex-session-store.d.ts +14 -0
- package/dist/types/session/credential-pin.d.ts +58 -0
- package/dist/types/session/foreign-session-import.d.ts +15 -0
- package/dist/types/session/foreign-session-jsonl.d.ts +9 -0
- package/dist/types/session/foreign-session-store.d.ts +23 -0
- package/dist/types/session/session-advisors.d.ts +47 -2
- package/dist/types/session/session-entries.d.ts +19 -1
- package/dist/types/session/session-handoff.d.ts +4 -1
- package/dist/types/session/session-loader.d.ts +2 -0
- package/dist/types/session/session-maintenance.d.ts +1 -1
- package/dist/types/session/session-manager.d.ts +21 -0
- package/dist/types/session/session-tools.d.ts +25 -1
- package/dist/types/session/turn-recovery.d.ts +10 -4
- package/dist/types/system-prompt.d.ts +2 -1
- package/dist/types/task/executor.d.ts +11 -2
- package/dist/types/task/render.d.ts +7 -0
- package/dist/types/thinking.d.ts +18 -6
- package/dist/types/tools/acp-bridge.d.ts +28 -5
- package/dist/types/tools/grep.d.ts +17 -1
- package/dist/types/tools/hub/launch.d.ts +5 -1
- package/dist/types/tools/index.d.ts +4 -1
- package/dist/types/tools/path-utils.d.ts +19 -0
- package/dist/types/tools/read.d.ts +2 -0
- package/dist/types/tools/xdev.d.ts +2 -1
- package/dist/types/utils/changelog.d.ts +19 -0
- package/dist/types/utils/git.d.ts +10 -0
- package/dist/types/utils/jj.d.ts +11 -4
- package/dist/types/web/search/types.d.ts +2 -2
- package/package.json +12 -12
- package/src/advisor/runtime.ts +138 -12
- package/src/advisor/transcript-recorder.ts +56 -0
- package/src/auto-thinking/classifier.ts +48 -10
- package/src/cli/args.ts +6 -0
- package/src/cli/flag-tables.ts +2 -0
- package/src/cli/gallery-fixtures/fs.ts +25 -0
- package/src/cli/session-picker.ts +34 -17
- package/src/cli/ttsr-cli.ts +19 -1
- package/src/cli.ts +9 -0
- package/src/collab/guest.ts +37 -4
- package/src/collab/host.ts +1 -0
- package/src/commands/launch.ts +6 -0
- package/src/config/model-registry.ts +103 -25
- package/src/config/settings-schema.ts +65 -6
- package/src/config/settings.ts +25 -0
- package/src/cursor-bridge-tools.ts +81 -0
- package/src/cursor.ts +463 -12
- package/src/edit/edit-clipboard.ts +23 -0
- package/src/edit/hashline/diff.ts +49 -10
- package/src/edit/hashline/execute.ts +38 -6
- package/src/edit/hashline/filesystem.ts +27 -3
- package/src/edit/index.ts +12 -2
- package/src/edit/renderer.ts +4 -4
- package/src/edit/streaming.ts +17 -2
- package/src/export/html/template.js +1 -1
- package/src/extensibility/extensions/runner.ts +70 -0
- package/src/extensibility/extensions/types.ts +30 -0
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +12 -13
- package/src/internal-urls/local-protocol.ts +3 -2
- package/src/internal-urls/mcp-protocol.ts +4 -1
- package/src/launch/terminal-output-worker-client.ts +53 -0
- package/src/launch/terminal-output-worker-protocol.ts +11 -0
- package/src/launch/terminal-output-worker.ts +23 -0
- package/src/lsp/client.ts +18 -3
- package/src/lsp/index.ts +4 -0
- package/src/lsp/render.ts +1 -1
- package/src/main.ts +127 -56
- package/src/mcp/manager.ts +120 -18
- package/src/modes/acp/acp-agent.ts +15 -9
- package/src/modes/components/chat-transcript-builder.ts +30 -11
- package/src/modes/components/codex-reset-fireworks.ts +369 -0
- package/src/modes/components/read-tool-group.ts +159 -17
- package/src/modes/components/session-selector.ts +19 -3
- package/src/modes/components/status-line/component.ts +381 -54
- package/src/modes/components/tool-execution.ts +78 -31
- package/src/modes/components/usage-row.ts +10 -5
- package/src/modes/controllers/event-controller.ts +26 -4
- package/src/modes/controllers/mcp-command-controller.ts +68 -3
- package/src/modes/controllers/selector-controller.ts +94 -36
- package/src/modes/controllers/tan-command-controller.ts +14 -0
- package/src/modes/interactive-mode.ts +31 -17
- package/src/modes/rpc/rpc-client.ts +18 -0
- package/src/modes/rpc/rpc-mode.ts +16 -1
- package/src/modes/rpc/rpc-types.ts +11 -0
- package/src/modes/theme/theme.ts +151 -6
- package/src/modes/types.ts +2 -1
- package/src/modes/utils/ui-helpers.ts +38 -21
- package/src/prompts/system/auto-thinking-difficulty.md +4 -2
- package/src/prompts/system/plan-mode-active.md +2 -2
- package/src/prompts/system/system-prompt.md +3 -0
- package/src/prompts/system/xdev-mount-notice.md +1 -1
- package/src/prompts/tools/bash.md +15 -17
- package/src/prompts/tools/checkpoint.md +1 -1
- package/src/prompts/tools/glob.md +7 -6
- package/src/prompts/tools/grep.md +7 -6
- package/src/sdk.ts +178 -15
- package/src/session/agent-session-events.ts +1 -0
- package/src/session/agent-session-types.ts +40 -1
- package/src/session/agent-session.ts +302 -175
- package/src/session/claude-session-store.ts +426 -0
- package/src/session/codex-session-store.ts +673 -0
- package/src/session/credential-pin.ts +93 -0
- package/src/session/foreign-session-import.ts +52 -0
- package/src/session/foreign-session-jsonl.ts +29 -0
- package/src/session/foreign-session-store.ts +26 -0
- package/src/session/model-controls.ts +11 -3
- package/src/session/session-advisors.ts +140 -16
- package/src/session/session-entries.ts +21 -1
- package/src/session/session-handoff.ts +20 -3
- package/src/session/session-loader.ts +25 -9
- package/src/session/session-maintenance.ts +59 -11
- package/src/session/session-manager.ts +61 -0
- package/src/session/session-tools.ts +107 -5
- package/src/session/settings-stream-fn.ts +1 -0
- package/src/session/turn-recovery.ts +97 -51
- package/src/slash-commands/builtin-registry.ts +131 -3
- package/src/system-prompt.ts +3 -2
- package/src/task/executor.ts +17 -4
- package/src/task/render.ts +20 -4
- package/src/thinking.ts +29 -10
- package/src/tools/acp-bridge.ts +52 -8
- package/src/tools/browser.ts +5 -0
- package/src/tools/checkpoint.ts +0 -13
- package/src/tools/grep.ts +64 -8
- package/src/tools/hub/launch.ts +10 -15
- package/src/tools/index.ts +28 -4
- package/src/tools/path-utils.ts +88 -0
- package/src/tools/read.ts +3 -0
- package/src/tools/write.ts +9 -3
- package/src/tools/xdev.ts +39 -14
- package/src/utils/changelog.ts +144 -4
- package/src/utils/git.ts +61 -14
- package/src/utils/jj.ts +19 -13
- package/src/web/search/providers/codex.ts +34 -0
- package/src/web/search/types.ts +1 -1
|
@@ -6,16 +6,26 @@ import type { SessionInfo } from "../session/session-listing";
|
|
|
6
6
|
import { SessionManager } from "../session/session-manager";
|
|
7
7
|
import { FileSessionStorage } from "../session/session-storage";
|
|
8
8
|
|
|
9
|
+
/** Presentation and capability controls for the standalone session picker. */
|
|
10
|
+
export interface SessionPickerOptions {
|
|
11
|
+
allSessions?: SessionInfo[];
|
|
12
|
+
title?: string;
|
|
13
|
+
scopeLabel?: string | false;
|
|
14
|
+
showCwd?: boolean;
|
|
15
|
+
allowDelete?: boolean;
|
|
16
|
+
allowGlobalScope?: boolean;
|
|
17
|
+
historySearch?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
9
20
|
/**
|
|
10
21
|
* Show the TUI session selector and return the selected session, or null if
|
|
11
|
-
* cancelled.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* is loaded lazily via `SessionManager.listAll`.
|
|
22
|
+
* cancelled. The default OMP picker supports deletion, transcript-history
|
|
23
|
+
* search, and an all-projects scope; foreign import pickers disable those
|
|
24
|
+
* source-owned capabilities.
|
|
15
25
|
*/
|
|
16
26
|
export async function selectSession(
|
|
17
27
|
sessions: SessionInfo[],
|
|
18
|
-
options
|
|
28
|
+
options: SessionPickerOptions = {},
|
|
19
29
|
): Promise<SessionInfo | null> {
|
|
20
30
|
const { promise, resolve } = Promise.withResolvers<SessionInfo | null>();
|
|
21
31
|
const ui = new TUI(new ProcessTerminal());
|
|
@@ -26,11 +36,13 @@ export async function selectSession(
|
|
|
26
36
|
// session-list prefix never sees. Best-effort: a missing/locked history.db
|
|
27
37
|
// must not break the picker.
|
|
28
38
|
let historyMatcher: ((query: string) => string[]) | undefined;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
if (options.historySearch !== false) {
|
|
40
|
+
try {
|
|
41
|
+
const history = HistoryStorage.open();
|
|
42
|
+
historyMatcher = (query: string) => history.matchingSessionIds(query);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
logger.warn("History storage unavailable for session ranking", { error: String(error) });
|
|
45
|
+
}
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
const showSelector = () => {
|
|
@@ -58,16 +70,21 @@ export async function selectSession(
|
|
|
58
70
|
}
|
|
59
71
|
},
|
|
60
72
|
{
|
|
61
|
-
onDelete:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
onDelete:
|
|
74
|
+
options.allowDelete === false
|
|
75
|
+
? undefined
|
|
76
|
+
: async (session: SessionInfo) => {
|
|
77
|
+
await storage.deleteSessionWithArtifacts(session.path);
|
|
78
|
+
return true;
|
|
79
|
+
},
|
|
66
80
|
historyMatcher,
|
|
67
|
-
loadAllSessions: () => SessionManager.listAll(storage),
|
|
68
|
-
allSessions: options
|
|
81
|
+
loadAllSessions: options.allowGlobalScope === false ? undefined : () => SessionManager.listAll(storage),
|
|
82
|
+
allSessions: options.allSessions,
|
|
69
83
|
getTerminalRows: () => ui.terminal.rows,
|
|
70
84
|
fillHeight: true,
|
|
85
|
+
title: options.title,
|
|
86
|
+
scopeLabel: options.scopeLabel,
|
|
87
|
+
showCwd: options.showCwd,
|
|
71
88
|
},
|
|
72
89
|
);
|
|
73
90
|
return selector;
|
package/src/cli/ttsr-cli.ts
CHANGED
|
@@ -94,12 +94,18 @@ interface TestReport {
|
|
|
94
94
|
evaluated: number;
|
|
95
95
|
triggered: RuleMatchDetail[];
|
|
96
96
|
notTriggered: RuleMatchDetail[];
|
|
97
|
+
/**
|
|
98
|
+
* Set when a file path was supplied but the match source was inferred as
|
|
99
|
+
* `text` (extension absent from {@link SOURCE_FILE_EXT}), so callers can
|
|
100
|
+
* surface why a source file was evaluated against a prose context.
|
|
101
|
+
*/
|
|
102
|
+
inferenceNote?: string;
|
|
97
103
|
}
|
|
98
104
|
|
|
99
105
|
const STDIN_MARKER = "-";
|
|
100
106
|
/** Extensions treated as source files for default tool-context inference. */
|
|
101
107
|
const SOURCE_FILE_EXT =
|
|
102
|
-
/^\.(ts|tsx|js|jsx|mjs|cjs|rs|py|go|java|kt|swift|c|cc|cpp|h|hpp|rb|php|lua|css|scss|html|json|ya?ml|toml|md|mdc)$/i;
|
|
108
|
+
/^\.(ts|tsx|js|jsx|mjs|cjs|rs|py|go|java|kt|swift|c|cc|cpp|h|hpp|rb|php|lua|css|scss|html|json|ya?ml|toml|md|mdc|cs|razor|cshtml|fs|fsx|vb|sh|bash|sql|zig|dart|scala|ex|exs|proto|tf)$/i;
|
|
103
109
|
|
|
104
110
|
const BINARY_PROBE_BYTES = 8192;
|
|
105
111
|
const DEFAULT_MAX_SCAN_BYTES = 5 * 1024 * 1024;
|
|
@@ -342,6 +348,14 @@ async function runTest(args: TtsrTestArgs, json: boolean, cwd: string): Promise<
|
|
|
342
348
|
args.source ?? (filePath && SOURCE_FILE_EXT.test(path.extname(filePath)) ? "tool" : "text");
|
|
343
349
|
const tool = args.tool ?? (source === "tool" ? "edit" : undefined);
|
|
344
350
|
|
|
351
|
+
// A supplied source file whose extension is unknown falls through to the
|
|
352
|
+
// text (prose) context, where tool-scoped rules can never match. Surface
|
|
353
|
+
// that so a false negative reads as a context mismatch, not a bad regex.
|
|
354
|
+
const inferenceNote =
|
|
355
|
+
!args.source && filePath && source === "text"
|
|
356
|
+
? `inferred --source text from '${path.extname(filePath) || filePath}' (not in the source-file extension set); pass --source tool --tool edit to evaluate tool-scoped rules`
|
|
357
|
+
: undefined;
|
|
358
|
+
|
|
345
359
|
const context: TtsrMatchContext = {
|
|
346
360
|
source,
|
|
347
361
|
toolName: tool,
|
|
@@ -373,6 +387,7 @@ async function runTest(args: TtsrTestArgs, json: boolean, cwd: string): Promise<
|
|
|
373
387
|
evaluated: rules.length,
|
|
374
388
|
triggered,
|
|
375
389
|
notTriggered,
|
|
390
|
+
inferenceNote,
|
|
376
391
|
};
|
|
377
392
|
|
|
378
393
|
if (json) {
|
|
@@ -390,6 +405,9 @@ function renderTestReport(report: TestReport, verbose: boolean, isolated: boolea
|
|
|
390
405
|
`${chalk.bold("TTSR test")} — source=${chalk.cyan(ctxLabel)}${pathLabel} snippet=${chalk.dim(`${report.snippetBytes}b`)}\n`,
|
|
391
406
|
);
|
|
392
407
|
process.stdout.write(`${chalk.dim(` "${report.snippetPreview}"`)}\n\n`);
|
|
408
|
+
if (report.inferenceNote) {
|
|
409
|
+
process.stdout.write(`${chalk.yellow(`note: ${report.inferenceNote}`)}\n\n`);
|
|
410
|
+
}
|
|
393
411
|
|
|
394
412
|
if (report.triggered.length === 0) {
|
|
395
413
|
process.stdout.write(`${chalk.red("No rules triggered.")} (evaluated ${report.evaluated})\n`);
|
package/src/cli.ts
CHANGED
|
@@ -32,6 +32,7 @@ import { extractProfileFlags } from "./cli/profile-bootstrap";
|
|
|
32
32
|
import { startJsEvalProcess } from "./eval/js/process-entry";
|
|
33
33
|
import type { WorkerInbound as JsWorkerInbound, WorkerOutbound as JsWorkerOutbound } from "./eval/js/worker-protocol";
|
|
34
34
|
import { DAEMON_BROKER_WORKER_ARG } from "./launch/protocol";
|
|
35
|
+
import { TERMINAL_OUTPUT_WORKER_ARG } from "./launch/terminal-output-worker-protocol";
|
|
35
36
|
import { COMPUTER_WORKER_ARG } from "./tools/computer/protocol";
|
|
36
37
|
import { smokeTestComputerWorker } from "./tools/computer/supervisor";
|
|
37
38
|
import { startComputerWorker } from "./tools/computer/worker-entry";
|
|
@@ -88,6 +89,7 @@ async function runSmokeTest(): Promise<void> {
|
|
|
88
89
|
const { smokeTestJsEvalWorker } = await import("./eval/js/context-manager");
|
|
89
90
|
// Other smoke dependencies stay lazy so normal CLI startup does not load their worker clients.
|
|
90
91
|
const { smokeTestDaemonBroker } = await import("./launch/client");
|
|
92
|
+
const { smokeTestTerminalOutputWorker } = await import("./launch/terminal-output-worker-client");
|
|
91
93
|
await smokeTestSyncWorker();
|
|
92
94
|
|
|
93
95
|
const statsServer = await startServer(0);
|
|
@@ -109,6 +111,7 @@ async function runSmokeTest(): Promise<void> {
|
|
|
109
111
|
await smokeTestTtsWorker();
|
|
110
112
|
await smokeTestMnemopiEmbedWorker();
|
|
111
113
|
await smokeTestDaemonBroker();
|
|
114
|
+
await smokeTestTerminalOutputWorker();
|
|
112
115
|
process.stdout.write("smoke-test: ok\n");
|
|
113
116
|
}
|
|
114
117
|
|
|
@@ -195,6 +198,12 @@ async function runWorkerEntrypoint(arg: string | undefined): Promise<boolean> {
|
|
|
195
198
|
await runIpcSubprocessWorker(startMnemopiEmbedWorker);
|
|
196
199
|
return true;
|
|
197
200
|
}
|
|
201
|
+
if (arg === TERMINAL_OUTPUT_WORKER_ARG) {
|
|
202
|
+
if (parentPort) installWorkerInbox(parentPort);
|
|
203
|
+
// This selector is the isolation boundary; a static import would evaluate xterm in normal CLI startup.
|
|
204
|
+
await import("./launch/terminal-output-worker");
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
198
207
|
if (arg === DAEMON_BROKER_WORKER_ARG) {
|
|
199
208
|
// Worker selectors must dispatch before the normal command graph loads.
|
|
200
209
|
const { startDaemonBrokerFromEnvironment } = await import("./launch/broker");
|
package/src/collab/guest.ts
CHANGED
|
@@ -85,14 +85,15 @@ interface PendingSnapshot {
|
|
|
85
85
|
/** Minimal context surface the idle-state reconciler mutates. */
|
|
86
86
|
export interface GuestIdleReconcilerCtx {
|
|
87
87
|
statusLine: { markActivityEnd: () => void };
|
|
88
|
+
statusContainer: Pick<InteractiveModeContext["statusContainer"], "disposeChildren">;
|
|
88
89
|
loadingAnimation: { stop: () => void } | undefined;
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
/**
|
|
92
93
|
* Close the guest UI state held open by an earlier `agent_start` whose
|
|
93
94
|
* matching `agent_end` never reached us — most often because a reconnect
|
|
94
|
-
* dropped the event mid-stream.
|
|
95
|
-
* `state
|
|
95
|
+
* dropped the event mid-stream. Reached via {@link reconcileGuestSnapshotHostState}
|
|
96
|
+
* (the live `state`-frame and welcome/resync reconciler) when the host reports `isStreaming === false`:
|
|
96
97
|
* folds the in-flight active-time window into the per-session meter (so
|
|
97
98
|
* `time_spent` stops ticking) and stops the `Working…` loader if one is
|
|
98
99
|
* still animating. No-op when the host is still streaming.
|
|
@@ -106,17 +107,49 @@ export function reconcileGuestIdleHostState(ctx: GuestIdleReconcilerCtx, isStrea
|
|
|
106
107
|
if (ctx.loadingAnimation) {
|
|
107
108
|
ctx.loadingAnimation.stop();
|
|
108
109
|
ctx.loadingAnimation = undefined;
|
|
110
|
+
ctx.statusContainer.disposeChildren();
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
/** Reconcile a welcome/resync snapshot's host activity state into the guest meter. */
|
|
113
115
|
export interface GuestSnapshotActivityReconcilerCtx extends GuestIdleReconcilerCtx {
|
|
114
116
|
statusLine: GuestIdleReconcilerCtx["statusLine"] & { markActivityStart: () => void };
|
|
117
|
+
/**
|
|
118
|
+
* Start (or re-attach) the live "Working…" loader. Mirrors
|
|
119
|
+
* `InteractiveModeContext.ensureLoadingAnimation`, which is what
|
|
120
|
+
* `EventController` calls on `agent_start`. Required so a guest that
|
|
121
|
+
* missed an earlier `agent_start` (a reconnect dropped it mid-stream)
|
|
122
|
+
* starts its spinner when the host later reports it is streaming.
|
|
123
|
+
*/
|
|
124
|
+
ensureLoadingAnimation: InteractiveModeContext["ensureLoadingAnimation"];
|
|
125
|
+
autoCompactionLoader: InteractiveModeContext["autoCompactionLoader"];
|
|
126
|
+
retryLoader: InteractiveModeContext["retryLoader"];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Status-area state which cannot outlive removal of its child components. */
|
|
130
|
+
export interface GuestTransientStatusCtx {
|
|
131
|
+
statusContainer: Pick<InteractiveModeContext["statusContainer"], "clear">;
|
|
132
|
+
autoCompactionLoader: InteractiveModeContext["autoCompactionLoader"];
|
|
133
|
+
retryLoader: InteractiveModeContext["retryLoader"];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Stop and forget status-area loaders before detaching their components. */
|
|
137
|
+
export function clearGuestTransientStatus(ctx: GuestTransientStatusCtx): void {
|
|
138
|
+
if (ctx.autoCompactionLoader) {
|
|
139
|
+
ctx.autoCompactionLoader.stop();
|
|
140
|
+
ctx.autoCompactionLoader = undefined;
|
|
141
|
+
}
|
|
142
|
+
if (ctx.retryLoader) {
|
|
143
|
+
ctx.retryLoader.stop();
|
|
144
|
+
ctx.retryLoader = undefined;
|
|
145
|
+
}
|
|
146
|
+
ctx.statusContainer.clear();
|
|
115
147
|
}
|
|
116
148
|
|
|
117
149
|
export function reconcileGuestSnapshotHostState(ctx: GuestSnapshotActivityReconcilerCtx, isStreaming: boolean): void {
|
|
118
150
|
if (isStreaming) {
|
|
119
151
|
ctx.statusLine.markActivityStart();
|
|
152
|
+
if (!ctx.autoCompactionLoader && !ctx.retryLoader) ctx.ensureLoadingAnimation();
|
|
120
153
|
return;
|
|
121
154
|
}
|
|
122
155
|
reconcileGuestIdleHostState(ctx, false);
|
|
@@ -482,7 +515,7 @@ export class CollabGuestLink {
|
|
|
482
515
|
this.#applyHostState(frame.state);
|
|
483
516
|
setSessionTerminalTitle(frame.state.sessionName, frame.state.cwd);
|
|
484
517
|
this.#updateStatusSegment();
|
|
485
|
-
|
|
518
|
+
reconcileGuestSnapshotHostState(this.#ctx, frame.state.isStreaming);
|
|
486
519
|
this.#ctx.statusLine.invalidate();
|
|
487
520
|
this.#ctx.ui.requestRender();
|
|
488
521
|
break;
|
|
@@ -681,7 +714,7 @@ export class CollabGuestLink {
|
|
|
681
714
|
|
|
682
715
|
#clearTransientUi(): void {
|
|
683
716
|
this.#clearUiRequests();
|
|
684
|
-
this.#ctx
|
|
717
|
+
clearGuestTransientStatus(this.#ctx);
|
|
685
718
|
this.#ctx.pendingMessagesContainer.clear();
|
|
686
719
|
this.#ctx.compactionQueuedMessages = [];
|
|
687
720
|
this.#ctx.streamingComponent = undefined;
|
package/src/collab/host.ts
CHANGED
package/src/commands/launch.ts
CHANGED
|
@@ -99,6 +99,12 @@ export default class Index extends Command {
|
|
|
99
99
|
char: "r",
|
|
100
100
|
description: "Resume a session (by ID prefix, path, or picker if omitted)",
|
|
101
101
|
}),
|
|
102
|
+
"from-claude": Flags.boolean({
|
|
103
|
+
description: "Import a Claude Code session into OMP",
|
|
104
|
+
}),
|
|
105
|
+
"from-codex": Flags.boolean({
|
|
106
|
+
description: "Import a Codex session into OMP",
|
|
107
|
+
}),
|
|
102
108
|
"session-dir": Flags.string({
|
|
103
109
|
description: "Directory for session storage and lookup",
|
|
104
110
|
}),
|
|
@@ -539,6 +539,12 @@ interface ModelPatch {
|
|
|
539
539
|
*/
|
|
540
540
|
type ModelTransportPolicy = "merge" | "replace";
|
|
541
541
|
|
|
542
|
+
/**
|
|
543
|
+
* Credential-aware model projection supplied by an extension provider. Receives
|
|
544
|
+
* the fully composed catalog and returns the list the host should serve.
|
|
545
|
+
*/
|
|
546
|
+
type ModifyModelsHook = (models: Model<Api>[], credentials: OAuthCredentials) => Model<Api>[];
|
|
547
|
+
|
|
542
548
|
function applyModelPatch(base: Model<Api>, patch: ModelPatch, transport: ModelTransportPolicy): Model<Api> {
|
|
543
549
|
const result = { ...base };
|
|
544
550
|
if (patch.name !== undefined) result.name = patch.name;
|
|
@@ -779,6 +785,7 @@ export type ResolvedRequestAuth =
|
|
|
779
785
|
*/
|
|
780
786
|
export class ModelRegistry {
|
|
781
787
|
#models: Model<Api>[] = [];
|
|
788
|
+
#unprojectedModels: Model<Api>[] = [];
|
|
782
789
|
#hasFullSnapshot = false;
|
|
783
790
|
#cachedStandardModels: Model<Api>[] = [];
|
|
784
791
|
#cachedDiscoverableModels: Model<Api>[] = [];
|
|
@@ -805,6 +812,13 @@ export class ModelRegistry {
|
|
|
805
812
|
#runtimeModelOverlays: CustomModelOverlay[] = [];
|
|
806
813
|
#runtimeProviderApiKeys: Map<string, string> = new Map();
|
|
807
814
|
#runtimeProviderOverrides: Map<string, ProviderOverride> = new Map();
|
|
815
|
+
// Credential-aware model projections registered via
|
|
816
|
+
// `registerProvider({ oauth: { modifyModels } })`. Persisted for the same
|
|
817
|
+
// reason as #runtimeModelOverlays: the overlays hold the *pre-projection*
|
|
818
|
+
// definitions, so without re-applying the projection every static reload
|
|
819
|
+
// would silently revert the provider to its unprojected catalog.
|
|
820
|
+
#runtimeModelModifiers: Map<string, ModifyModelsHook> = new Map();
|
|
821
|
+
#lastModelModifierWarnings: Map<string, string> = new Map();
|
|
808
822
|
#runtimeProvidersBySource: Map<string, Set<string>> = new Map();
|
|
809
823
|
#runtimeProviderSourceByName: Map<string, string> = new Map();
|
|
810
824
|
// Runtime model managers registered by extensions via fetchDynamicModels.
|
|
@@ -1002,6 +1016,15 @@ export class ModelRegistry {
|
|
|
1002
1016
|
if (patch.contextWindow === undefined && patch.maxTokens === undefined && patch.input === undefined) {
|
|
1003
1017
|
return current;
|
|
1004
1018
|
}
|
|
1019
|
+
const unprojected = resolveProviderModelReference(current.provider, current.id, this.#unprojectedModels);
|
|
1020
|
+
if (unprojected) {
|
|
1021
|
+
const patchedBase = applyModelPatch(unprojected, patch, "merge");
|
|
1022
|
+
this.#unprojectedModels = this.#unprojectedModels.map(candidate =>
|
|
1023
|
+
candidate.provider === unprojected.provider && candidate.id === unprojected.id ? patchedBase : candidate,
|
|
1024
|
+
);
|
|
1025
|
+
this.#models = this.#applyRuntimeModelModifiers(this.#unprojectedModels);
|
|
1026
|
+
return resolveProviderModelReference(current.provider, current.id, this.#models) ?? patchedBase;
|
|
1027
|
+
}
|
|
1005
1028
|
const patched = applyModelPatch(current, patch, "merge");
|
|
1006
1029
|
this.#models = this.#models.map(candidate =>
|
|
1007
1030
|
candidate.provider === current.provider && candidate.id === current.id ? patched : candidate,
|
|
@@ -1102,6 +1125,7 @@ export class ModelRegistry {
|
|
|
1102
1125
|
|
|
1103
1126
|
#resetStaticComposition(): void {
|
|
1104
1127
|
this.#models = [];
|
|
1128
|
+
this.#unprojectedModels = [];
|
|
1105
1129
|
this.#hasFullSnapshot = false;
|
|
1106
1130
|
this.#internedStaticModels.clear();
|
|
1107
1131
|
this.#providerLookupSnapshots.clear();
|
|
@@ -1126,7 +1150,46 @@ export class ModelRegistry {
|
|
|
1126
1150
|
});
|
|
1127
1151
|
}
|
|
1128
1152
|
|
|
1129
|
-
|
|
1153
|
+
/**
|
|
1154
|
+
* Re-apply the credential-aware projections registered by extension providers.
|
|
1155
|
+
*
|
|
1156
|
+
* Runtime overlays hold the pre-projection definitions, so the registry keeps
|
|
1157
|
+
* those definitions separate from `#models` and reruns the ordered hooks after
|
|
1158
|
+
* every catalog rebuild. Otherwise an offline refresh silently restores the
|
|
1159
|
+
* provider's placeholder catalog.
|
|
1160
|
+
*
|
|
1161
|
+
* A throwing hook falls back to the catalog produced by earlier hooks instead
|
|
1162
|
+
* of failing the whole composition; one bad extension must not empty the
|
|
1163
|
+
* registry. The failure is logged (deduped per provider) so it is not silent.
|
|
1164
|
+
* Each hook receives a deep clone because the public contract permits
|
|
1165
|
+
* mutation of both the array and its model records before returning.
|
|
1166
|
+
*/
|
|
1167
|
+
#applyRuntimeModelModifiers(models: Model<Api>[]): Model<Api>[] {
|
|
1168
|
+
if (this.#runtimeModelModifiers.size === 0) return models;
|
|
1169
|
+
let projected = models;
|
|
1170
|
+
for (const [providerName, modifyModels] of this.#runtimeModelModifiers) {
|
|
1171
|
+
const credential = this.authStorage.getOAuthCredential(providerName);
|
|
1172
|
+
if (!credential) continue;
|
|
1173
|
+
try {
|
|
1174
|
+
projected = modifyModels(structuredClone(projected), credential);
|
|
1175
|
+
} catch (error) {
|
|
1176
|
+
this.#warnModelModifierFailure(providerName, error instanceof Error ? error.message : String(error));
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
return projected;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
/**
|
|
1183
|
+
* Dedup key is separate from `#lastDiscoveryWarnings` so a repeated modifier
|
|
1184
|
+
* failure cannot mask a subsequent discovery failure for the same provider.
|
|
1185
|
+
*/
|
|
1186
|
+
#warnModelModifierFailure(provider: string, error: string): void {
|
|
1187
|
+
if (this.#lastModelModifierWarnings.get(provider) === error) return;
|
|
1188
|
+
this.#lastModelModifierWarnings.set(provider, error);
|
|
1189
|
+
logger.warn("extension model projection failed; serving unprojected catalog", { provider, error });
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
#composeUnprojectedStaticModels(providerFilter?: ReadonlySet<string>): Model<Api>[] {
|
|
1130
1193
|
const select = <T extends { provider: string }>(models: readonly T[]): T[] =>
|
|
1131
1194
|
providerFilter ? models.filter(model => providerFilter.has(model.provider)) : [...models];
|
|
1132
1195
|
let builtInModels = this.#applyHardcodedModelPolicies(
|
|
@@ -1141,17 +1204,24 @@ export class ModelRegistry {
|
|
|
1141
1204
|
);
|
|
1142
1205
|
const withConfigModels = this.#mergeCustomModels(resolvedDefaults, select(this.#customModelOverlays));
|
|
1143
1206
|
const combined = this.#mergeCustomModels(withConfigModels, select(this.#runtimeModelOverlays));
|
|
1144
|
-
// Custom/config providers bypass the model-manager merge point —
|
|
1145
|
-
// collapse effort-tier variants here so X/X-thinking twins fold.
|
|
1146
1207
|
const withModelOverrides = this.#applyModelOverrides(collapseBuiltModelVariants(combined), this.#modelOverrides);
|
|
1147
|
-
return this.#
|
|
1148
|
-
|
|
1149
|
-
|
|
1208
|
+
return this.#applyLlamaCppQwenThinkingToModels(this.#applyRuntimeProviderOverrides(withModelOverrides));
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
#composeStaticModels(providerFilter?: ReadonlySet<string>): Model<Api>[] {
|
|
1212
|
+
// A modifier is a whole-catalog transform. Build and project the full catalog
|
|
1213
|
+
// before narrowing a lazy lookup, matching getAll() followed by filtering.
|
|
1214
|
+
const projectFullCatalog = providerFilter !== undefined && this.#runtimeModelModifiers.size > 0;
|
|
1215
|
+
const unprojected = this.#composeUnprojectedStaticModels(projectFullCatalog ? undefined : providerFilter);
|
|
1216
|
+
const projected = this.#applyRuntimeModelModifiers(unprojected);
|
|
1217
|
+
const selected = projectFullCatalog ? projected.filter(model => providerFilter.has(model.provider)) : projected;
|
|
1218
|
+
return this.#internStaticModels(selected);
|
|
1150
1219
|
}
|
|
1151
1220
|
|
|
1152
1221
|
#ensureFullSnapshot(): Model<Api>[] {
|
|
1153
1222
|
if (!this.#hasFullSnapshot) {
|
|
1154
|
-
this.#
|
|
1223
|
+
this.#unprojectedModels = this.#composeUnprojectedStaticModels();
|
|
1224
|
+
this.#models = this.#internStaticModels(this.#applyRuntimeModelModifiers(this.#unprojectedModels));
|
|
1155
1225
|
this.#hasFullSnapshot = true;
|
|
1156
1226
|
this.#providerLookupSnapshots.clear();
|
|
1157
1227
|
}
|
|
@@ -1605,7 +1675,7 @@ export class ModelRegistry {
|
|
|
1605
1675
|
discovered.map(model =>
|
|
1606
1676
|
mergeDiscoveredModel(
|
|
1607
1677
|
model,
|
|
1608
|
-
|
|
1678
|
+
resolveProviderModelReference(model.provider, model.id, this.#unprojectedModels),
|
|
1609
1679
|
this.#providerOverrides.get(model.provider),
|
|
1610
1680
|
),
|
|
1611
1681
|
),
|
|
@@ -1615,13 +1685,17 @@ export class ModelRegistry {
|
|
|
1615
1685
|
authoritativeProviders.add(provider);
|
|
1616
1686
|
}
|
|
1617
1687
|
const baseModels =
|
|
1618
|
-
authoritativeProviders.size > 0
|
|
1688
|
+
authoritativeProviders.size > 0
|
|
1689
|
+
? dropProviderModels(this.#unprojectedModels, authoritativeProviders)
|
|
1690
|
+
: this.#unprojectedModels;
|
|
1619
1691
|
const resolved = this.#mergeResolvedModels(baseModels, discoveredModels);
|
|
1620
1692
|
const withConfigModels = this.#mergeCustomModels(resolved, this.#customModelOverlays);
|
|
1621
|
-
// Merge runtime extension models so they survive online discovery completion
|
|
1622
1693
|
const combined = this.#mergeCustomModels(withConfigModels, this.#runtimeModelOverlays);
|
|
1623
1694
|
const withModelOverrides = this.#applyModelOverrides(collapseBuiltModelVariants(combined), this.#modelOverrides);
|
|
1624
|
-
this.#
|
|
1695
|
+
this.#unprojectedModels = this.#applyLlamaCppQwenThinkingToModels(
|
|
1696
|
+
this.#applyRuntimeProviderOverrides(withModelOverrides),
|
|
1697
|
+
);
|
|
1698
|
+
this.#models = this.#applyRuntimeModelModifiers(this.#unprojectedModels);
|
|
1625
1699
|
}
|
|
1626
1700
|
|
|
1627
1701
|
#configuredDiscoveryCacheProviderId(providerConfig: DiscoveryProviderConfig): string {
|
|
@@ -2393,6 +2467,8 @@ export class ModelRegistry {
|
|
|
2393
2467
|
this.#runtimeProviderOverrides.delete(providerName);
|
|
2394
2468
|
this.#runtimeModelOverlays = this.#runtimeModelOverlays.filter(overlay => overlay.provider !== providerName);
|
|
2395
2469
|
this.#runtimeModelManagers.delete(providerName);
|
|
2470
|
+
this.#runtimeModelModifiers.delete(providerName);
|
|
2471
|
+
this.#lastModelModifierWarnings.delete(providerName);
|
|
2396
2472
|
this.authStorage.removeConfigApiKey(providerName);
|
|
2397
2473
|
}
|
|
2398
2474
|
|
|
@@ -2529,13 +2605,15 @@ export class ModelRegistry {
|
|
|
2529
2605
|
this.#runtimeModelOverlays = this.#runtimeModelOverlays.filter(m => m.provider !== providerName);
|
|
2530
2606
|
this.#runtimeModelOverlays.push(...newOverlays);
|
|
2531
2607
|
|
|
2532
|
-
//
|
|
2533
|
-
|
|
2608
|
+
// Update the unprojected snapshot, then rerun every whole-catalog
|
|
2609
|
+
// projection exactly once. Incremental projection is not safe because one
|
|
2610
|
+
// provider's hook may inspect or suppress another provider's models.
|
|
2611
|
+
const nextModels = this.#unprojectedModels.filter(model => model.provider !== providerName);
|
|
2534
2612
|
for (const overlay of newOverlays) {
|
|
2535
2613
|
nextModels.push(finalizeCustomModel(overlay, { useDefaults: true }));
|
|
2536
2614
|
}
|
|
2537
2615
|
const runtimeTransportOverride = this.#runtimeProviderOverrides.get(providerName);
|
|
2538
|
-
|
|
2616
|
+
this.#unprojectedModels = runtimeTransportOverride
|
|
2539
2617
|
? nextModels.map(model => {
|
|
2540
2618
|
if (model.provider !== providerName) return model;
|
|
2541
2619
|
return this.#applyProviderTransportOverrideToModel(model, runtimeTransportOverride);
|
|
@@ -2543,14 +2621,12 @@ export class ModelRegistry {
|
|
|
2543
2621
|
: nextModels;
|
|
2544
2622
|
|
|
2545
2623
|
if (config.oauth?.modifyModels) {
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
return;
|
|
2550
|
-
}
|
|
2624
|
+
this.#runtimeModelModifiers.set(providerName, config.oauth.modifyModels);
|
|
2625
|
+
} else {
|
|
2626
|
+
this.#runtimeModelModifiers.delete(providerName);
|
|
2551
2627
|
}
|
|
2552
|
-
|
|
2553
|
-
this.#
|
|
2628
|
+
this.#models = this.#applyRuntimeModelModifiers(this.#unprojectedModels);
|
|
2629
|
+
this.#providerLookupSnapshots.clear();
|
|
2554
2630
|
return;
|
|
2555
2631
|
}
|
|
2556
2632
|
|
|
@@ -2619,12 +2695,14 @@ export class ModelRegistry {
|
|
|
2619
2695
|
transportOverride,
|
|
2620
2696
|
);
|
|
2621
2697
|
this.#runtimeProviderOverrides.set(providerName, nextRuntimeOverride);
|
|
2622
|
-
this.#
|
|
2623
|
-
this.#
|
|
2624
|
-
if (
|
|
2625
|
-
return this.#applyProviderTransportOverrideToModel(
|
|
2698
|
+
this.#unprojectedModels = this.#applyLlamaCppQwenThinkingToModels(
|
|
2699
|
+
this.#unprojectedModels.map(model => {
|
|
2700
|
+
if (model.provider !== providerName) return model;
|
|
2701
|
+
return this.#applyProviderTransportOverrideToModel(model, transportOverride);
|
|
2626
2702
|
}),
|
|
2627
2703
|
);
|
|
2704
|
+
this.#models = this.#applyRuntimeModelModifiers(this.#unprojectedModels);
|
|
2705
|
+
this.#providerLookupSnapshots.clear();
|
|
2628
2706
|
}
|
|
2629
2707
|
}
|
|
2630
2708
|
|
|
@@ -927,6 +927,18 @@ export const SETTINGS_SCHEMA = {
|
|
|
927
927
|
},
|
|
928
928
|
},
|
|
929
929
|
|
|
930
|
+
"tui.codexResetFireworks": {
|
|
931
|
+
type: "boolean",
|
|
932
|
+
default: false,
|
|
933
|
+
ui: {
|
|
934
|
+
tab: "appearance",
|
|
935
|
+
group: "Display",
|
|
936
|
+
label: "Codex Reset Fireworks",
|
|
937
|
+
description:
|
|
938
|
+
"Celebrate unscheduled Codex weekly usage resets and newly banked saved resets with a top-third fireworks overlay that remains until Escape",
|
|
939
|
+
},
|
|
940
|
+
},
|
|
941
|
+
|
|
930
942
|
"tui.titleState": {
|
|
931
943
|
type: "boolean",
|
|
932
944
|
default: true,
|
|
@@ -1811,14 +1823,32 @@ export const SETTINGS_SCHEMA = {
|
|
|
1811
1823
|
},
|
|
1812
1824
|
},
|
|
1813
1825
|
|
|
1814
|
-
|
|
1815
|
-
type: "
|
|
1816
|
-
|
|
1826
|
+
"startup.changelogMode": {
|
|
1827
|
+
type: "enum",
|
|
1828
|
+
values: ["summary", "expanded", "hidden"] as const,
|
|
1829
|
+
default: "summary",
|
|
1817
1830
|
ui: {
|
|
1818
1831
|
tab: "interaction",
|
|
1819
1832
|
group: "Startup & Updates",
|
|
1820
|
-
label: "
|
|
1821
|
-
description: "
|
|
1833
|
+
label: "Startup Changelog",
|
|
1834
|
+
description: "Choose whether update notes start as a summary, full details, or stay hidden",
|
|
1835
|
+
options: [
|
|
1836
|
+
{
|
|
1837
|
+
value: "summary",
|
|
1838
|
+
label: "Summary",
|
|
1839
|
+
description: "Show release and change counts with a /changelog hint",
|
|
1840
|
+
},
|
|
1841
|
+
{
|
|
1842
|
+
value: "expanded",
|
|
1843
|
+
label: "Expanded",
|
|
1844
|
+
description: "Show the recent release notes in full",
|
|
1845
|
+
},
|
|
1846
|
+
{
|
|
1847
|
+
value: "hidden",
|
|
1848
|
+
label: "Hidden",
|
|
1849
|
+
description: "Do not show release notes on startup",
|
|
1850
|
+
},
|
|
1851
|
+
],
|
|
1822
1852
|
},
|
|
1823
1853
|
},
|
|
1824
1854
|
|
|
@@ -4054,6 +4084,18 @@ export const SETTINGS_SCHEMA = {
|
|
|
4054
4084
|
},
|
|
4055
4085
|
},
|
|
4056
4086
|
|
|
4087
|
+
"browser.cdpUrl": {
|
|
4088
|
+
type: "string",
|
|
4089
|
+
default: undefined,
|
|
4090
|
+
ui: {
|
|
4091
|
+
tab: "tools",
|
|
4092
|
+
group: "Grep & Browser",
|
|
4093
|
+
label: "Browser CDP URL",
|
|
4094
|
+
description:
|
|
4095
|
+
"Default HTTP CDP discovery endpoint (for example http://127.0.0.1:9222) to attach to instead of launching a browser. Explicit app.cdp_url or app.path on the tool call take precedence.",
|
|
4096
|
+
},
|
|
4097
|
+
},
|
|
4098
|
+
|
|
4057
4099
|
"browser.headless": {
|
|
4058
4100
|
type: "boolean",
|
|
4059
4101
|
default: true,
|
|
@@ -4592,7 +4634,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
4592
4634
|
group: "Subagents",
|
|
4593
4635
|
label: "Soft Subagent Request Budget",
|
|
4594
4636
|
description:
|
|
4595
|
-
"Soft per-subagent request budget (assistant requests per run). Crossing it injects a wrap-up steering notice (see task.softRequestBudgetNotice); at 1.5x the budget the run is force-stopped and the agent must yield its partial findings. 0 disables the guard. Bundled scout/sonic agents
|
|
4637
|
+
"Soft per-subagent request budget (assistant requests per run). Crossing it injects a wrap-up steering notice (see task.softRequestBudgetNotice); at 1.5x the budget the run is force-stopped and the agent must yield its partial findings. 0 disables the guard. Bundled scout/sonic agents cap out at a lower built-in budget, so a value below that cap still applies to them.",
|
|
4596
4638
|
options: [
|
|
4597
4639
|
{ value: "0", label: "Disabled" },
|
|
4598
4640
|
{ value: "90", label: "90 requests" },
|
|
@@ -5064,6 +5106,23 @@ export const SETTINGS_SCHEMA = {
|
|
|
5064
5106
|
options: AUTO_THINKING_MODEL_OPTIONS,
|
|
5065
5107
|
},
|
|
5066
5108
|
},
|
|
5109
|
+
"providers.autoThinkingMaxEffort": {
|
|
5110
|
+
type: "enum",
|
|
5111
|
+
values: ["xhigh", "max"] as const,
|
|
5112
|
+
default: "xhigh",
|
|
5113
|
+
ui: {
|
|
5114
|
+
tab: "model",
|
|
5115
|
+
group: "Thinking",
|
|
5116
|
+
label: "Auto Thinking Ceiling",
|
|
5117
|
+
description:
|
|
5118
|
+
"Highest effort the `auto` classifier may resolve. `xhigh` keeps the classifier one tier below the top, so only an explicit `ultrathink` reaches `max`; `max` lets a turn the classifier judges exceptional bill the top tier on models that expose it.",
|
|
5119
|
+
condition: "autoThinkingActive",
|
|
5120
|
+
options: [
|
|
5121
|
+
{ value: "xhigh", label: "xhigh", description: "Classifier stops at xhigh (default)" },
|
|
5122
|
+
{ value: "max", label: "max", description: "Classifier may resolve max where the model supports it" },
|
|
5123
|
+
],
|
|
5124
|
+
},
|
|
5125
|
+
},
|
|
5067
5126
|
"features.unexpectedStopDetection": {
|
|
5068
5127
|
type: "boolean",
|
|
5069
5128
|
default: false,
|
package/src/config/settings.ts
CHANGED
|
@@ -1346,6 +1346,31 @@ export class Settings {
|
|
|
1346
1346
|
}
|
|
1347
1347
|
delete raw.lastChangelogVersion;
|
|
1348
1348
|
|
|
1349
|
+
// collapseChangelog (boolean) -> startup.changelogMode (enum). Preserve
|
|
1350
|
+
// every explicit legacy choice while giving new installs the schema's
|
|
1351
|
+
// "summary" default: true -> summary, false -> expanded. A separately
|
|
1352
|
+
// configured new mode always wins.
|
|
1353
|
+
const startupObj = isRecord(raw.startup) ? (raw.startup as Record<string, unknown>) : undefined;
|
|
1354
|
+
const legacyCollapseChangelog = typeof raw.collapseChangelog === "boolean" ? raw.collapseChangelog : undefined;
|
|
1355
|
+
const flatChangelogMode = raw["startup.changelogMode"];
|
|
1356
|
+
const normalizedFlatChangelogMode =
|
|
1357
|
+
flatChangelogMode === "summary" || flatChangelogMode === "expanded" || flatChangelogMode === "hidden"
|
|
1358
|
+
? flatChangelogMode
|
|
1359
|
+
: undefined;
|
|
1360
|
+
if (legacyCollapseChangelog !== undefined || normalizedFlatChangelogMode !== undefined) {
|
|
1361
|
+
if (!startupObj) {
|
|
1362
|
+
raw.startup = {};
|
|
1363
|
+
}
|
|
1364
|
+
const target = raw.startup as Record<string, unknown>;
|
|
1365
|
+
if (target.changelogMode === undefined) {
|
|
1366
|
+
target.changelogMode =
|
|
1367
|
+
normalizedFlatChangelogMode ??
|
|
1368
|
+
(legacyCollapseChangelog !== undefined ? (legacyCollapseChangelog ? "summary" : "expanded") : undefined);
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
delete raw.collapseChangelog;
|
|
1372
|
+
delete raw["startup.changelogMode"];
|
|
1373
|
+
|
|
1349
1374
|
// ask.timeout: ms -> seconds (if value > 1000, it's old ms format)
|
|
1350
1375
|
if (raw.ask && typeof (raw.ask as Record<string, unknown>).timeout === "number") {
|
|
1351
1376
|
const oldValue = (raw.ask as Record<string, unknown>).timeout as number;
|