@oh-my-pi/pi-coding-agent 15.10.11 → 15.11.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 +103 -2
- package/dist/cli.js +5790 -5731
- package/dist/types/async/index.d.ts +0 -1
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/gallery-fixtures/types.d.ts +5 -0
- package/dist/types/cli-commands.d.ts +12 -0
- package/dist/types/commands/launch.d.ts +4 -0
- package/dist/types/config/api-key-resolver.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +6 -1
- package/dist/types/config/model-registry.d.ts +1 -0
- package/dist/types/config/model-resolver.d.ts +18 -0
- package/dist/types/config/settings-schema.d.ts +85 -34
- package/dist/types/config/settings.d.ts +7 -0
- package/dist/types/edit/hashline/noop-loop-guard.d.ts +72 -0
- package/dist/types/eval/py/executor.d.ts +5 -0
- package/dist/types/eval/py/kernel.d.ts +6 -1
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/exec/bash-executor.d.ts +2 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/runner.d.ts +3 -2
- package/dist/types/extensibility/extensions/types.d.ts +3 -0
- package/dist/types/extensibility/shared-events.d.ts +2 -2
- package/dist/types/internal-urls/history-protocol.d.ts +14 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/types.d.ts +1 -1
- package/dist/types/irc/bus.d.ts +66 -0
- package/dist/types/memory-backend/index.d.ts +1 -0
- package/dist/types/memory-backend/runtime.d.ts +4 -0
- package/dist/types/memory-backend/types.d.ts +66 -1
- package/dist/types/modes/components/agent-hub.d.ts +30 -0
- package/dist/types/modes/components/compaction-summary-message.d.ts +10 -4
- package/dist/types/modes/components/custom-editor.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/components/ttsr-notification.d.ts +5 -1
- package/dist/types/modes/components/welcome.d.ts +3 -9
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/index.d.ts +3 -3
- package/dist/types/modes/interactive-mode.d.ts +10 -4
- package/dist/types/modes/oauth-manual-input.d.ts +7 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +39 -2
- package/dist/types/modes/rpc/rpc-mode.d.ts +31 -2
- package/dist/types/modes/rpc/rpc-subagents.d.ts +24 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +75 -1
- package/dist/types/modes/setup-wizard/index.d.ts +5 -1
- package/dist/types/modes/setup-wizard/lazy.d.ts +2 -0
- package/dist/types/modes/theme/theme.d.ts +2 -1
- package/dist/types/modes/types.d.ts +5 -2
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -1
- package/dist/types/registry/agent-lifecycle.d.ts +51 -0
- package/dist/types/registry/agent-registry.d.ts +16 -5
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/secrets/obfuscator.d.ts +8 -2
- package/dist/types/session/agent-session.d.ts +49 -32
- package/dist/types/session/messages.d.ts +2 -4
- package/dist/types/session/session-history-format.d.ts +12 -0
- package/dist/types/session/session-manager.d.ts +21 -3
- package/dist/types/session/streaming-output.d.ts +46 -0
- package/dist/types/slash-commands/acp-builtins.d.ts +16 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -0
- package/dist/types/slash-commands/types.d.ts +1 -1
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +12 -2
- package/dist/types/task/index.d.ts +13 -6
- package/dist/types/task/output-manager.d.ts +0 -7
- package/dist/types/task/repair-args.d.ts +8 -7
- package/dist/types/task/types.d.ts +63 -51
- package/dist/types/thinking.d.ts +4 -0
- package/dist/types/tiny/title-client.d.ts +11 -0
- package/dist/types/tiny/title-protocol.d.ts +1 -0
- package/dist/types/tools/browser/tab-worker.d.ts +3 -1
- package/dist/types/tools/find.d.ts +0 -11
- package/dist/types/tools/grouped-file-output.d.ts +0 -49
- package/dist/types/tools/index.d.ts +7 -3
- package/dist/types/tools/irc.d.ts +76 -38
- package/dist/types/tools/job.d.ts +7 -1
- package/dist/types/utils/git.d.ts +15 -2
- package/dist/types/utils/title-generator.d.ts +3 -2
- package/examples/extensions/with-deps/package.json +1 -0
- package/package.json +11 -10
- package/scripts/bundle-dist.ts +28 -19
- package/src/async/index.ts +0 -1
- package/src/auto-thinking/classifier.ts +1 -0
- package/src/cli/args.ts +3 -0
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli/gallery-fixtures/agentic.ts +230 -115
- package/src/cli/gallery-fixtures/types.ts +5 -0
- package/src/cli-commands.ts +29 -0
- package/src/cli.ts +28 -15
- package/src/commands/launch.ts +4 -0
- package/src/commit/agentic/tools/analyze-file.ts +38 -19
- package/src/commit/model-selection.ts +3 -2
- package/src/config/api-key-resolver.ts +8 -6
- package/src/config/keybindings.ts +6 -1
- package/src/config/model-registry.ts +97 -30
- package/src/config/model-resolver.ts +60 -0
- package/src/config/settings-schema.ts +99 -55
- package/src/config/settings.ts +68 -3
- package/src/edit/hashline/execute.ts +39 -2
- package/src/edit/hashline/noop-loop-guard.ts +99 -0
- package/src/eval/__tests__/agent-bridge.test.ts +5 -3
- package/src/eval/agent-bridge.ts +3 -16
- package/src/eval/completion-bridge.ts +1 -0
- package/src/eval/js/shared/prelude.txt +1 -1
- package/src/eval/py/executor.ts +29 -7
- package/src/eval/py/index.ts +6 -1
- package/src/eval/py/kernel.ts +31 -11
- package/src/eval/py/prelude.py +5 -6
- package/src/eval/py/runtime.ts +37 -0
- package/src/exec/bash-executor.ts +82 -3
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +38 -13
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/get-commands-handler.ts +2 -1
- package/src/extensibility/extensions/runner.ts +6 -1
- package/src/extensibility/extensions/types.ts +3 -0
- package/src/extensibility/shared-events.ts +2 -2
- package/src/hindsight/bank.ts +17 -2
- package/src/internal-urls/docs-index.generated.ts +11 -11
- package/src/internal-urls/history-protocol.ts +113 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/router.ts +3 -1
- package/src/internal-urls/types.ts +1 -1
- package/src/irc/bus.ts +292 -0
- package/src/main.ts +26 -66
- package/src/memories/index.ts +2 -0
- package/src/memory-backend/index.ts +1 -0
- package/src/memory-backend/local-backend.ts +9 -0
- package/src/memory-backend/off-backend.ts +9 -0
- package/src/memory-backend/runtime.ts +66 -0
- package/src/memory-backend/types.ts +81 -1
- package/src/mnemopi/backend.ts +151 -4
- package/src/modes/acp/acp-agent.ts +119 -11
- package/src/modes/components/{session-observer-overlay.ts → agent-hub.ts} +586 -367
- package/src/modes/components/assistant-message.ts +19 -21
- package/src/modes/components/compaction-summary-message.ts +68 -32
- package/src/modes/components/custom-editor.ts +10 -0
- package/src/modes/components/footer.ts +3 -1
- package/src/modes/components/status-line/component.ts +118 -34
- package/src/modes/components/tool-execution.ts +31 -1
- package/src/modes/components/ttsr-notification.ts +72 -30
- package/src/modes/components/welcome.ts +9 -33
- package/src/modes/controllers/command-controller.ts +1 -1
- package/src/modes/controllers/event-controller.ts +65 -0
- package/src/modes/controllers/extension-ui-controller.ts +8 -8
- package/src/modes/controllers/input-controller.ts +19 -2
- package/src/modes/controllers/mcp-command-controller.ts +38 -3
- package/src/modes/controllers/selector-controller.ts +21 -17
- package/src/modes/index.ts +3 -21
- package/src/modes/interactive-mode.ts +47 -22
- package/src/modes/oauth-manual-input.ts +30 -3
- package/src/modes/rpc/rpc-client.ts +154 -3
- package/src/modes/rpc/rpc-mode.ts +97 -12
- package/src/modes/rpc/rpc-subagents.ts +265 -0
- package/src/modes/rpc/rpc-types.ts +81 -1
- package/src/modes/setup-wizard/index.ts +12 -2
- package/src/modes/setup-wizard/lazy.ts +16 -0
- package/src/modes/theme/theme.ts +18 -5
- package/src/modes/types.ts +5 -5
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +51 -49
- package/src/prompts/system/irc-incoming.md +3 -4
- package/src/prompts/system/orchestrate-notice.md +2 -2
- package/src/prompts/system/subagent-system-prompt.md +0 -5
- package/src/prompts/system/system-prompt.md +1 -0
- package/src/prompts/system/workflow-notice.md +2 -2
- package/src/prompts/tools/eval.md +3 -3
- package/src/prompts/tools/irc.md +29 -19
- package/src/prompts/tools/read.md +2 -2
- package/src/prompts/tools/task-summary.md +5 -16
- package/src/prompts/tools/task.md +38 -29
- package/src/registry/agent-lifecycle.ts +218 -0
- package/src/registry/agent-registry.ts +16 -5
- package/src/sdk.ts +37 -10
- package/src/secrets/index.ts +8 -1
- package/src/secrets/obfuscator.ts +39 -18
- package/src/session/agent-session.ts +422 -291
- package/src/session/messages.ts +11 -78
- package/src/session/session-history-format.ts +246 -0
- package/src/session/session-manager.ts +59 -5
- package/src/session/streaming-output.ts +226 -10
- package/src/slash-commands/acp-builtins.ts +24 -0
- package/src/slash-commands/builtin-registry.ts +20 -0
- package/src/slash-commands/types.ts +1 -1
- package/src/system-prompt.ts +14 -0
- package/src/task/executor.ts +851 -461
- package/src/task/index.ts +721 -796
- package/src/task/output-manager.ts +0 -11
- package/src/task/render.ts +148 -63
- package/src/task/repair-args.ts +21 -9
- package/src/task/types.ts +82 -66
- package/src/thinking.ts +7 -0
- package/src/tiny/title-client.ts +34 -5
- package/src/tiny/title-protocol.ts +1 -1
- package/src/tiny/worker.ts +6 -4
- package/src/tools/ask.ts +4 -2
- package/src/tools/bash.ts +61 -10
- package/src/tools/browser/tab-worker.ts +26 -7
- package/src/tools/browser.ts +28 -1
- package/src/tools/find.ts +2 -27
- package/src/tools/grouped-file-output.ts +1 -118
- package/src/tools/image-gen.ts +11 -4
- package/src/tools/index.ts +17 -13
- package/src/tools/inspect-image.ts +1 -0
- package/src/tools/irc.ts +596 -171
- package/src/tools/job.ts +41 -7
- package/src/tools/read.ts +57 -1
- package/src/tools/renderers.ts +2 -0
- package/src/tools/resolve.ts +4 -1
- package/src/utils/commit-message-generator.ts +1 -0
- package/src/utils/git.ts +267 -13
- package/src/utils/title-generator.ts +24 -5
- package/dist/types/async/support.d.ts +0 -2
- package/dist/types/modes/components/session-observer-overlay.d.ts +0 -11
- package/dist/types/task/simple-mode.d.ts +0 -8
- package/src/async/support.ts +0 -5
- package/src/task/simple-mode.ts +0 -27
|
@@ -5,6 +5,8 @@ export interface ApiKeyResolverOptions {
|
|
|
5
5
|
sessionId?: string;
|
|
6
6
|
/** Provider base URL hint forwarded to the auth-storage cascade. */
|
|
7
7
|
baseUrl?: string;
|
|
8
|
+
/** Provider model id forwarded to model-scoped usage ranking/backoff. */
|
|
9
|
+
modelId?: string;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
/**
|
|
@@ -16,7 +18,7 @@ export interface ApiKeyResolverRegistry {
|
|
|
16
18
|
getApiKeyForProvider(
|
|
17
19
|
provider: string,
|
|
18
20
|
sessionId?: string,
|
|
19
|
-
options?: { baseUrl?: string; forceRefresh?: boolean; signal?: AbortSignal },
|
|
21
|
+
options?: { baseUrl?: string; modelId?: string; forceRefresh?: boolean; signal?: AbortSignal },
|
|
20
22
|
): Promise<string | undefined>;
|
|
21
23
|
authStorage: Pick<AuthStorage, "rotateSessionCredential">;
|
|
22
24
|
/**
|
|
@@ -39,10 +41,10 @@ export function createApiKeyResolver(
|
|
|
39
41
|
provider: string,
|
|
40
42
|
options: ApiKeyResolverOptions = {},
|
|
41
43
|
): ApiKeyResolver {
|
|
42
|
-
const { sessionId, baseUrl } = options;
|
|
44
|
+
const { sessionId, baseUrl, modelId } = options;
|
|
43
45
|
return async ({ lastChance, error, signal }) => {
|
|
44
46
|
if (error === undefined) {
|
|
45
|
-
return registry.getApiKeyForProvider(provider, sessionId, { baseUrl });
|
|
47
|
+
return registry.getApiKeyForProvider(provider, sessionId, { baseUrl, modelId });
|
|
46
48
|
}
|
|
47
49
|
if (lastChance) {
|
|
48
50
|
// Account constraint (401 / usage / account-rate-limit): rotate to a
|
|
@@ -50,9 +52,9 @@ export function createApiKeyResolver(
|
|
|
50
52
|
// sibling exists we switch immediately; the precise no-sibling backoff
|
|
51
53
|
// is owned by `markUsageLimitReached` (default + server usage-report
|
|
52
54
|
// reset) and the outer whole-turn retry layer.
|
|
53
|
-
await registry.authStorage.rotateSessionCredential(provider, sessionId, { error, signal });
|
|
54
|
-
return registry.getApiKeyForProvider(provider, sessionId, { baseUrl });
|
|
55
|
+
await registry.authStorage.rotateSessionCredential(provider, sessionId, { error, modelId, signal });
|
|
56
|
+
return registry.getApiKeyForProvider(provider, sessionId, { baseUrl, modelId });
|
|
55
57
|
}
|
|
56
|
-
return registry.getApiKeyForProvider(provider, sessionId, { baseUrl, forceRefresh: true, signal });
|
|
58
|
+
return registry.getApiKeyForProvider(provider, sessionId, { baseUrl, modelId, forceRefresh: true, signal });
|
|
57
59
|
};
|
|
58
60
|
}
|
|
@@ -36,6 +36,7 @@ interface AppKeybindings {
|
|
|
36
36
|
"app.clipboard.pasteTextRaw": true;
|
|
37
37
|
"app.clipboard.copyLine": true;
|
|
38
38
|
"app.clipboard.copyPrompt": true;
|
|
39
|
+
"app.agents.hub": true;
|
|
39
40
|
"app.session.new": true;
|
|
40
41
|
"app.session.tree": true;
|
|
41
42
|
"app.session.fork": true;
|
|
@@ -166,9 +167,13 @@ export const KEYBINDINGS = {
|
|
|
166
167
|
defaultKeys: [],
|
|
167
168
|
description: "Resume session",
|
|
168
169
|
},
|
|
170
|
+
"app.agents.hub": {
|
|
171
|
+
defaultKeys: "alt+a",
|
|
172
|
+
description: "Open the agent hub",
|
|
173
|
+
},
|
|
169
174
|
"app.session.observe": {
|
|
170
175
|
defaultKeys: "ctrl+s",
|
|
171
|
-
description: "
|
|
176
|
+
description: "Open the agent hub",
|
|
172
177
|
},
|
|
173
178
|
"app.session.togglePath": {
|
|
174
179
|
defaultKeys: "ctrl+p",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
1
2
|
import * as path from "node:path";
|
|
2
3
|
import { registerCustomApi, unregisterCustomApis } from "@oh-my-pi/pi-ai/api-registry";
|
|
3
4
|
import type { Api, Context, Model, ModelSpec, SimpleStreamOptions, ThinkingConfig } from "@oh-my-pi/pi-ai/types";
|
|
@@ -226,14 +227,50 @@ interface CustomModelsResult {
|
|
|
226
227
|
found: boolean;
|
|
227
228
|
}
|
|
228
229
|
|
|
230
|
+
const commandValueCache = new Map<string, string>();
|
|
231
|
+
|
|
232
|
+
function isCommandConfigValue(valueConfig: string | undefined): valueConfig is string {
|
|
233
|
+
return valueConfig?.startsWith("!") === true;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function resolveCommandConfig(command: string): string | undefined {
|
|
237
|
+
const cached = commandValueCache.get(command);
|
|
238
|
+
if (cached !== undefined) return cached;
|
|
239
|
+
try {
|
|
240
|
+
const stdout = execSync(command, { encoding: "utf8", timeout: 10_000, windowsHide: true });
|
|
241
|
+
const trimmed = stdout.trim();
|
|
242
|
+
if (trimmed.length === 0) return undefined;
|
|
243
|
+
commandValueCache.set(command, trimmed);
|
|
244
|
+
return trimmed;
|
|
245
|
+
} catch {
|
|
246
|
+
return undefined;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
interface CommandApiKeyResolution {
|
|
251
|
+
configured: boolean;
|
|
252
|
+
value?: string;
|
|
253
|
+
}
|
|
229
254
|
/**
|
|
230
|
-
* Resolve
|
|
231
|
-
*
|
|
255
|
+
* Resolve a models.yml secret/config value to an actual value.
|
|
256
|
+
* `!cmd` runs a shell command and returns trimmed stdout, otherwise env vars are
|
|
257
|
+
* checked first and the input falls back to a literal value.
|
|
232
258
|
*/
|
|
233
|
-
function
|
|
234
|
-
|
|
259
|
+
function resolveConfigValue(valueConfig: string): string | undefined {
|
|
260
|
+
if (valueConfig.startsWith("!")) return resolveCommandConfig(valueConfig.slice(1).trim());
|
|
261
|
+
const envValue = Bun.env[valueConfig];
|
|
235
262
|
if (envValue) return envValue;
|
|
236
|
-
return
|
|
263
|
+
return valueConfig;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function resolveConfigHeaders(headers: Record<string, string> | undefined): Record<string, string> | undefined {
|
|
267
|
+
if (!headers) return undefined;
|
|
268
|
+
const resolved: Record<string, string> = {};
|
|
269
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
270
|
+
const next = resolveConfigValue(value);
|
|
271
|
+
if (next) resolved[key] = next;
|
|
272
|
+
}
|
|
273
|
+
return Object.keys(resolved).length > 0 ? resolved : undefined;
|
|
237
274
|
}
|
|
238
275
|
|
|
239
276
|
function extractGoogleOAuthToken(value: string | undefined): string | undefined {
|
|
@@ -394,7 +431,8 @@ function mergeCustomModelHeaders(
|
|
|
394
431
|
authHeader: boolean | undefined,
|
|
395
432
|
apiKeyConfig: string | undefined,
|
|
396
433
|
): Record<string, string> | undefined {
|
|
397
|
-
|
|
434
|
+
const resolvedModelHeaders = resolveConfigHeaders(modelHeaders);
|
|
435
|
+
return mergeAuthHeader({ ...providerHeaders, ...resolvedModelHeaders }, authHeader, apiKeyConfig);
|
|
398
436
|
}
|
|
399
437
|
|
|
400
438
|
function mergeAuthHeader(
|
|
@@ -406,7 +444,7 @@ function mergeAuthHeader(
|
|
|
406
444
|
if (!authHeader || !apiKeyConfig) {
|
|
407
445
|
return nextHeaders;
|
|
408
446
|
}
|
|
409
|
-
const resolvedKey =
|
|
447
|
+
const resolvedKey = resolveConfigValue(apiKeyConfig);
|
|
410
448
|
return resolvedKey ? { ...nextHeaders, Authorization: `Bearer ${resolvedKey}` } : nextHeaders;
|
|
411
449
|
}
|
|
412
450
|
|
|
@@ -559,6 +597,28 @@ export class ModelRegistry {
|
|
|
559
597
|
#rebuildSuspended: number = 0;
|
|
560
598
|
#fetch: FetchImpl;
|
|
561
599
|
|
|
600
|
+
#resolveCommandBackedApiKey(provider: string): CommandApiKeyResolution {
|
|
601
|
+
const keyConfig = this.#customProviderApiKeys.get(provider);
|
|
602
|
+
if (!isCommandConfigValue(keyConfig)) return { configured: false };
|
|
603
|
+
const value = resolveConfigValue(keyConfig);
|
|
604
|
+
if (value) {
|
|
605
|
+
this.authStorage.setConfigApiKey(provider, value);
|
|
606
|
+
return { configured: true, value };
|
|
607
|
+
}
|
|
608
|
+
this.authStorage.removeConfigApiKey(provider);
|
|
609
|
+
return { configured: true };
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
#installProviderApiKey(provider: string, keyConfig: string): void {
|
|
613
|
+
this.#customProviderApiKeys.set(provider, keyConfig);
|
|
614
|
+
const resolved = resolveConfigValue(keyConfig);
|
|
615
|
+
if (resolved) {
|
|
616
|
+
this.authStorage.setConfigApiKey(provider, resolved);
|
|
617
|
+
} else if (isCommandConfigValue(keyConfig)) {
|
|
618
|
+
this.authStorage.removeConfigApiKey(provider);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
562
622
|
/**
|
|
563
623
|
* @param authStorage - Auth storage for API key resolution
|
|
564
624
|
*
|
|
@@ -579,10 +639,8 @@ export class ModelRegistry {
|
|
|
579
639
|
// Set up fallback resolver for custom provider API keys
|
|
580
640
|
this.authStorage.setFallbackResolver(provider => {
|
|
581
641
|
const keyConfig = this.#customProviderApiKeys.get(provider);
|
|
582
|
-
if (keyConfig)
|
|
583
|
-
|
|
584
|
-
}
|
|
585
|
-
return undefined;
|
|
642
|
+
if (!keyConfig) return undefined;
|
|
643
|
+
return resolveConfigValue(keyConfig);
|
|
586
644
|
});
|
|
587
645
|
// Load models synchronously in constructor.
|
|
588
646
|
this.#loadModels();
|
|
@@ -673,7 +731,7 @@ export class ModelRegistry {
|
|
|
673
731
|
// Restore runtime API keys before #loadModels — survives because
|
|
674
732
|
// #loadModels only calls .set() on #customProviderApiKeys, never reassigns it.
|
|
675
733
|
for (const [k, v] of this.#runtimeProviderApiKeys) {
|
|
676
|
-
this.#
|
|
734
|
+
this.#installProviderApiKey(k, v);
|
|
677
735
|
}
|
|
678
736
|
this.#providerOverrides.clear();
|
|
679
737
|
this.#modelOverrides.clear();
|
|
@@ -975,10 +1033,11 @@ export class ModelRegistry {
|
|
|
975
1033
|
const configuredProviders = new Set(Object.keys(value.providers ?? {}));
|
|
976
1034
|
|
|
977
1035
|
for (const [providerName, providerConfig] of providerEntries) {
|
|
1036
|
+
const resolvedProviderHeaders = resolveConfigHeaders(providerConfig.headers);
|
|
978
1037
|
// Always set overrides when baseUrl/headers/apiKey/authHeader/compat/disableStrictTools/transport are present
|
|
979
1038
|
if (
|
|
980
1039
|
providerConfig.baseUrl ||
|
|
981
|
-
|
|
1040
|
+
resolvedProviderHeaders ||
|
|
982
1041
|
providerConfig.apiKey ||
|
|
983
1042
|
providerConfig.authHeader !== undefined ||
|
|
984
1043
|
providerConfig.compat ||
|
|
@@ -988,7 +1047,7 @@ export class ModelRegistry {
|
|
|
988
1047
|
const disableStrictCompat = providerConfig.disableStrictTools ? { disableStrictTools: true } : undefined;
|
|
989
1048
|
overrides.set(providerName, {
|
|
990
1049
|
baseUrl: providerConfig.baseUrl,
|
|
991
|
-
headers:
|
|
1050
|
+
headers: resolvedProviderHeaders,
|
|
992
1051
|
apiKey: providerConfig.apiKey,
|
|
993
1052
|
authHeader: providerConfig.authHeader,
|
|
994
1053
|
compat: mergeCompat(providerConfig.compat, disableStrictCompat),
|
|
@@ -1010,7 +1069,7 @@ export class ModelRegistry {
|
|
|
1010
1069
|
// fallback for entries that don't advertise one.
|
|
1011
1070
|
api: (providerConfig.api ?? "openai-completions") as Api,
|
|
1012
1071
|
baseUrl: providerConfig.baseUrl,
|
|
1013
|
-
headers:
|
|
1072
|
+
headers: resolvedProviderHeaders,
|
|
1014
1073
|
compat: mergeCompat(providerConfig.compat, disableStrictCompat),
|
|
1015
1074
|
discovery: providerConfig.discovery,
|
|
1016
1075
|
optional: false,
|
|
@@ -1022,16 +1081,17 @@ export class ModelRegistry {
|
|
|
1022
1081
|
// bearer in models.yml (e.g. for an auth-gateway baseUrl), that bearer
|
|
1023
1082
|
// must authenticate the outbound request.
|
|
1024
1083
|
if (providerConfig.apiKey) {
|
|
1025
|
-
this.#
|
|
1026
|
-
const resolved = resolveApiKeyConfig(providerConfig.apiKey);
|
|
1027
|
-
if (resolved) this.authStorage.setConfigApiKey(providerName, resolved);
|
|
1084
|
+
this.#installProviderApiKey(providerName, providerConfig.apiKey);
|
|
1028
1085
|
}
|
|
1029
1086
|
|
|
1030
1087
|
// Parse per-model overrides
|
|
1031
1088
|
if (providerConfig.modelOverrides) {
|
|
1032
1089
|
const perModel = new Map<string, ModelOverride>();
|
|
1033
1090
|
for (const [modelId, override] of Object.entries(providerConfig.modelOverrides)) {
|
|
1034
|
-
perModel.set(
|
|
1091
|
+
perModel.set(
|
|
1092
|
+
modelId,
|
|
1093
|
+
override.headers ? { ...override, headers: resolveConfigHeaders(override.headers) } : override,
|
|
1094
|
+
);
|
|
1035
1095
|
}
|
|
1036
1096
|
allModelOverrides.set(providerName, perModel);
|
|
1037
1097
|
}
|
|
@@ -1179,7 +1239,7 @@ export class ModelRegistry {
|
|
|
1179
1239
|
return {
|
|
1180
1240
|
fetch: this.#fetch,
|
|
1181
1241
|
getBearerApiKey: async provider => {
|
|
1182
|
-
const apiKey = await this.
|
|
1242
|
+
const apiKey = await this.getApiKeyForProvider(provider);
|
|
1183
1243
|
return apiKey && apiKey !== DEFAULT_LOCAL_TOKEN && apiKey !== kNoAuth ? apiKey : undefined;
|
|
1184
1244
|
},
|
|
1185
1245
|
};
|
|
@@ -1443,10 +1503,9 @@ export class ModelRegistry {
|
|
|
1443
1503
|
for (const [providerName, providerConfig] of Object.entries(config.providers ?? {})) {
|
|
1444
1504
|
const modelDefs = providerConfig.models ?? [];
|
|
1445
1505
|
if (modelDefs.length === 0) continue; // Override-only, no custom models
|
|
1506
|
+
const resolvedProviderHeaders = resolveConfigHeaders(providerConfig.headers);
|
|
1446
1507
|
if (providerConfig.apiKey) {
|
|
1447
|
-
this.#
|
|
1448
|
-
const resolved = resolveApiKeyConfig(providerConfig.apiKey);
|
|
1449
|
-
if (resolved) this.authStorage.setConfigApiKey(providerName, resolved);
|
|
1508
|
+
this.#installProviderApiKey(providerName, providerConfig.apiKey);
|
|
1450
1509
|
}
|
|
1451
1510
|
for (const modelDef of modelDefs) {
|
|
1452
1511
|
const providerCompat = providerConfig.disableStrictTools
|
|
@@ -1456,7 +1515,7 @@ export class ModelRegistry {
|
|
|
1456
1515
|
providerName,
|
|
1457
1516
|
providerConfig.baseUrl!,
|
|
1458
1517
|
providerConfig.api as Api | undefined,
|
|
1459
|
-
|
|
1518
|
+
resolvedProviderHeaders,
|
|
1460
1519
|
providerConfig.apiKey,
|
|
1461
1520
|
providerConfig.authHeader,
|
|
1462
1521
|
providerCompat,
|
|
@@ -1626,7 +1685,10 @@ export class ModelRegistry {
|
|
|
1626
1685
|
* as providers with stored credentials. See issue #993.
|
|
1627
1686
|
*/
|
|
1628
1687
|
hasConfiguredAuth(model: Model<Api>): boolean {
|
|
1629
|
-
|
|
1688
|
+
const commandKey = this.#resolveCommandBackedApiKey(model.provider);
|
|
1689
|
+
return (
|
|
1690
|
+
commandKey.configured || this.#keylessProviders.has(model.provider) || this.authStorage.hasAuth(model.provider)
|
|
1691
|
+
);
|
|
1630
1692
|
}
|
|
1631
1693
|
|
|
1632
1694
|
getDiscoverableProviders(): string[] {
|
|
@@ -1658,6 +1720,8 @@ export class ModelRegistry {
|
|
|
1658
1720
|
* Get API key for a model.
|
|
1659
1721
|
*/
|
|
1660
1722
|
async getApiKey(model: Model<Api>, sessionId?: string): Promise<string | undefined> {
|
|
1723
|
+
const commandKey = this.#resolveCommandBackedApiKey(model.provider);
|
|
1724
|
+
if (commandKey.configured) return commandKey.value;
|
|
1661
1725
|
if (this.#keylessProviders.has(model.provider) && !this.authStorage.hasAuth(model.provider)) {
|
|
1662
1726
|
return kNoAuth;
|
|
1663
1727
|
}
|
|
@@ -1674,13 +1738,16 @@ export class ModelRegistry {
|
|
|
1674
1738
|
async getApiKeyForProvider(
|
|
1675
1739
|
provider: string,
|
|
1676
1740
|
sessionId?: string,
|
|
1677
|
-
options?: { baseUrl?: string; forceRefresh?: boolean; signal?: AbortSignal },
|
|
1741
|
+
options?: { baseUrl?: string; modelId?: string; forceRefresh?: boolean; signal?: AbortSignal },
|
|
1678
1742
|
): Promise<string | undefined> {
|
|
1743
|
+
const commandKey = this.#resolveCommandBackedApiKey(provider);
|
|
1744
|
+
if (commandKey.configured) return commandKey.value;
|
|
1679
1745
|
if (this.#keylessProviders.has(provider) && !this.authStorage.hasAuth(provider)) {
|
|
1680
1746
|
return kNoAuth;
|
|
1681
1747
|
}
|
|
1682
1748
|
return this.authStorage.getApiKey(provider, sessionId, {
|
|
1683
1749
|
baseUrl: options?.baseUrl,
|
|
1750
|
+
modelId: options?.modelId,
|
|
1684
1751
|
forceRefresh: options?.forceRefresh,
|
|
1685
1752
|
signal: options?.signal,
|
|
1686
1753
|
});
|
|
@@ -1696,6 +1763,8 @@ export class ModelRegistry {
|
|
|
1696
1763
|
}
|
|
1697
1764
|
|
|
1698
1765
|
async #peekApiKeyForProvider(provider: string): Promise<string | undefined> {
|
|
1766
|
+
const commandKey = this.#resolveCommandBackedApiKey(provider);
|
|
1767
|
+
if (commandKey.configured) return commandKey.value;
|
|
1699
1768
|
if (this.#keylessProviders.has(provider) && !this.authStorage.hasAuth(provider)) {
|
|
1700
1769
|
return kNoAuth;
|
|
1701
1770
|
}
|
|
@@ -1819,11 +1888,9 @@ export class ModelRegistry {
|
|
|
1819
1888
|
}
|
|
1820
1889
|
|
|
1821
1890
|
if (config.apiKey) {
|
|
1822
|
-
this.#
|
|
1891
|
+
this.#installProviderApiKey(providerName, config.apiKey);
|
|
1823
1892
|
// Persist runtime API keys so they survive #reloadStaticModels() cycles
|
|
1824
1893
|
this.#runtimeProviderApiKeys.set(providerName, config.apiKey);
|
|
1825
|
-
const resolved = resolveApiKeyConfig(config.apiKey);
|
|
1826
|
-
if (resolved) this.authStorage.setConfigApiKey(providerName, resolved);
|
|
1827
1894
|
}
|
|
1828
1895
|
|
|
1829
1896
|
if (config.models && config.models.length > 0) {
|
|
@@ -1892,7 +1959,7 @@ export class ModelRegistry {
|
|
|
1892
1959
|
cacheTtlMs: 24 * 60 * 60 * 1000,
|
|
1893
1960
|
dynamicModelsAuthoritative: true,
|
|
1894
1961
|
fetchDynamicModels: async () => {
|
|
1895
|
-
const apiKey = await this
|
|
1962
|
+
const apiKey = await this.#peekApiKeyForProvider(providerName);
|
|
1896
1963
|
const resolvedKey = isAuthenticated(apiKey) ? apiKey : undefined;
|
|
1897
1964
|
const modelDefs = await fetcher(resolvedKey);
|
|
1898
1965
|
const results: Model<Api>[] = [];
|
|
@@ -1058,6 +1058,66 @@ export async function resolveAllowedModels(
|
|
|
1058
1058
|
return available.filter(model => allowed.has(`${model.provider}/${model.id}`));
|
|
1059
1059
|
}
|
|
1060
1060
|
|
|
1061
|
+
/**
|
|
1062
|
+
* Synchronous subset of {@link resolveAllowedModels} for contexts where async is unavailable
|
|
1063
|
+
* (e.g. `getAvailableModels()` which is called from the ACP model-list advertisement, RPC
|
|
1064
|
+
* `get_available_models`, and the `/model` slash command). Uses the same effective
|
|
1065
|
+
* `enabledModels` scope semantics as startup resolution:
|
|
1066
|
+
*
|
|
1067
|
+
* - Glob selectors match `provider/modelId` and bare model id
|
|
1068
|
+
* - Exact canonical ids expand to all available concrete variants
|
|
1069
|
+
* - Exact `provider/modelId`, bare ids, provider-scoped fuzzy, and substring selectors
|
|
1070
|
+
* resolve through the shared model-pattern matcher
|
|
1071
|
+
* - Optional `:thinkingLevel` suffixes are stripped only when valid
|
|
1072
|
+
*
|
|
1073
|
+
* When no pattern resolves to any model (misconfiguration / typo) an empty list is returned,
|
|
1074
|
+
* consistent with the empty-list contract of {@link resolveAllowedModels}. Callers that render
|
|
1075
|
+
* a UI picker should treat an empty list as "hide the picker entry", matching how the SDK
|
|
1076
|
+
* surfaces the same misconfiguration during session initialization.
|
|
1077
|
+
*/
|
|
1078
|
+
export function filterAvailableModelsByEnabledPatterns(
|
|
1079
|
+
available: Model<Api>[],
|
|
1080
|
+
patterns: readonly string[],
|
|
1081
|
+
registry: Pick<ModelRegistry, "getCanonicalVariants">,
|
|
1082
|
+
): Model<Api>[] {
|
|
1083
|
+
if (patterns.length === 0) return available;
|
|
1084
|
+
|
|
1085
|
+
const context = buildPreferenceContext(available, undefined);
|
|
1086
|
+
const allowed = new Set<string>();
|
|
1087
|
+
const addAllowed = (model: Model<Api>) => {
|
|
1088
|
+
allowed.add(`${model.provider}/${model.id}`);
|
|
1089
|
+
};
|
|
1090
|
+
|
|
1091
|
+
for (const pattern of patterns) {
|
|
1092
|
+
if (pattern.includes("*") || pattern.includes("?") || pattern.includes("[")) {
|
|
1093
|
+
const { base: globPattern } = splitThinkingSuffix(pattern);
|
|
1094
|
+
const glob = new Bun.Glob(globPattern.toLowerCase());
|
|
1095
|
+
for (const model of available) {
|
|
1096
|
+
const fullId = `${model.provider}/${model.id}`.toLowerCase();
|
|
1097
|
+
if (glob.match(fullId) || glob.match(model.id.toLowerCase())) {
|
|
1098
|
+
addAllowed(model);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
continue;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
const exactCanonical = resolveExactCanonicalScopePattern(pattern, registry, available);
|
|
1105
|
+
if (exactCanonical) {
|
|
1106
|
+
for (const model of exactCanonical.models) {
|
|
1107
|
+
addAllowed(model);
|
|
1108
|
+
}
|
|
1109
|
+
continue;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
const { model } = parseModelPatternWithContext(pattern, available, context, { modelRegistry: registry });
|
|
1113
|
+
if (model) {
|
|
1114
|
+
addAllowed(model);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
return allowed.size === 0 ? [] : available.filter(model => allowed.has(`${model.provider}/${model.id}`));
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1061
1121
|
export interface ResolveCliModelResult {
|
|
1062
1122
|
model: Model<Api> | undefined;
|
|
1063
1123
|
selector?: string;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { THINKING_EFFORTS } from "@oh-my-pi/pi-ai";
|
|
2
|
-
import { TASK_SIMPLE_MODES } from "../task/simple-mode";
|
|
3
2
|
import { AUTO_THINKING, getConfiguredThinkingLevelMetadata, getThinkingLevelMetadata } from "../thinking";
|
|
4
3
|
import {
|
|
5
4
|
TINY_MODEL_DEVICE_DEFAULT,
|
|
@@ -151,7 +150,7 @@ export type AnyUiMetadata = UiBase & {
|
|
|
151
150
|
|
|
152
151
|
interface BooleanDef {
|
|
153
152
|
type: "boolean";
|
|
154
|
-
default: boolean;
|
|
153
|
+
default: boolean | undefined;
|
|
155
154
|
ui?: UiBoolean;
|
|
156
155
|
}
|
|
157
156
|
|
|
@@ -1177,13 +1176,13 @@ export const SETTINGS_SCHEMA = {
|
|
|
1177
1176
|
|
|
1178
1177
|
"compaction.strategy": {
|
|
1179
1178
|
type: "enum",
|
|
1180
|
-
values: ["context-full", "handoff", "shake", "off"] as const,
|
|
1179
|
+
values: ["context-full", "handoff", "shake", "snapcompact", "off"] as const,
|
|
1181
1180
|
default: "context-full",
|
|
1182
1181
|
ui: {
|
|
1183
1182
|
tab: "context",
|
|
1184
1183
|
label: "Compaction Strategy",
|
|
1185
1184
|
description:
|
|
1186
|
-
"Choose in-place context-full maintenance, auto-handoff, surgical shake (drop heavy content), or disable auto maintenance (off)",
|
|
1185
|
+
"Choose in-place context-full maintenance, auto-handoff, surgical shake (drop heavy content), snapcompact (archive history as dense images), or disable auto maintenance (off)",
|
|
1187
1186
|
options: [
|
|
1188
1187
|
{
|
|
1189
1188
|
value: "context-full",
|
|
@@ -1196,6 +1195,11 @@ export const SETTINGS_SCHEMA = {
|
|
|
1196
1195
|
label: "Shake",
|
|
1197
1196
|
description: "Drop heavy content (tool results + large blocks) in place; recover via artifact",
|
|
1198
1197
|
},
|
|
1198
|
+
{
|
|
1199
|
+
value: "snapcompact",
|
|
1200
|
+
label: "Snapcompact",
|
|
1201
|
+
description: "Archive history onto dense bitmap images the model reads back; no LLM call",
|
|
1202
|
+
},
|
|
1199
1203
|
{
|
|
1200
1204
|
value: "off",
|
|
1201
1205
|
label: "Off",
|
|
@@ -1326,6 +1330,17 @@ export const SETTINGS_SCHEMA = {
|
|
|
1326
1330
|
],
|
|
1327
1331
|
},
|
|
1328
1332
|
},
|
|
1333
|
+
|
|
1334
|
+
"compaction.supersedeReads": {
|
|
1335
|
+
type: "boolean",
|
|
1336
|
+
default: true,
|
|
1337
|
+
ui: {
|
|
1338
|
+
tab: "context",
|
|
1339
|
+
label: "Supersede Stale Reads",
|
|
1340
|
+
description: "Prune older read results when the same file is read again (cache-aware, runs every turn)",
|
|
1341
|
+
},
|
|
1342
|
+
},
|
|
1343
|
+
|
|
1329
1344
|
// Branch summaries
|
|
1330
1345
|
"branchSummary.enabled": {
|
|
1331
1346
|
type: "boolean",
|
|
@@ -2067,6 +2082,20 @@ export const SETTINGS_SCHEMA = {
|
|
|
2067
2082
|
type: "number",
|
|
2068
2083
|
default: 4 * 1024 * 1024,
|
|
2069
2084
|
},
|
|
2085
|
+
"shellMinimizer.sourceOutlineLevel": {
|
|
2086
|
+
type: "enum",
|
|
2087
|
+
values: ["default", "aggressive"] as const,
|
|
2088
|
+
default: "default",
|
|
2089
|
+
ui: {
|
|
2090
|
+
tab: "editing",
|
|
2091
|
+
label: "Shell Minimizer Source Outline",
|
|
2092
|
+
description: "Source outline mode for cat/read of source files: default or aggressive",
|
|
2093
|
+
},
|
|
2094
|
+
},
|
|
2095
|
+
"shellMinimizer.legacyFilters": {
|
|
2096
|
+
type: "boolean",
|
|
2097
|
+
default: undefined,
|
|
2098
|
+
},
|
|
2070
2099
|
|
|
2071
2100
|
// Eval (per-backend toggles; add more as new backends ship, e.g. eval.ts)
|
|
2072
2101
|
"eval.py": {
|
|
@@ -2100,6 +2129,16 @@ export const SETTINGS_SCHEMA = {
|
|
|
2100
2129
|
description: "Whether to keep IPython kernel alive across calls",
|
|
2101
2130
|
},
|
|
2102
2131
|
},
|
|
2132
|
+
"python.interpreter": {
|
|
2133
|
+
type: "string",
|
|
2134
|
+
default: "",
|
|
2135
|
+
ui: {
|
|
2136
|
+
tab: "editing",
|
|
2137
|
+
label: "Python Interpreter",
|
|
2138
|
+
description:
|
|
2139
|
+
"Optional path to an exact Python executable. When set, automatic Python runtime discovery is skipped.",
|
|
2140
|
+
},
|
|
2141
|
+
},
|
|
2103
2142
|
|
|
2104
2143
|
// ────────────────────────────────────────────────────────────────────────
|
|
2105
2144
|
// Tools
|
|
@@ -2265,24 +2304,13 @@ export const SETTINGS_SCHEMA = {
|
|
|
2265
2304
|
},
|
|
2266
2305
|
},
|
|
2267
2306
|
|
|
2268
|
-
"irc.enabled": {
|
|
2269
|
-
type: "boolean",
|
|
2270
|
-
default: true,
|
|
2271
|
-
ui: {
|
|
2272
|
-
tab: "tools",
|
|
2273
|
-
label: "IRC",
|
|
2274
|
-
description: "Enable agent-to-agent IRC messaging via the irc tool",
|
|
2275
|
-
},
|
|
2276
|
-
},
|
|
2277
|
-
|
|
2278
2307
|
"irc.timeoutMs": {
|
|
2279
2308
|
type: "number",
|
|
2280
2309
|
default: 120_000,
|
|
2281
2310
|
ui: {
|
|
2282
2311
|
tab: "tools",
|
|
2283
2312
|
label: "IRC Timeout",
|
|
2284
|
-
description:
|
|
2285
|
-
"Drop IRC messages whose recipient does not respond within this many milliseconds (0 disables the timeout)",
|
|
2313
|
+
description: "Default timeout for irc wait (and send await:true) in milliseconds; 0 disables the timeout",
|
|
2286
2314
|
options: [
|
|
2287
2315
|
{ value: "0", label: "Disabled" },
|
|
2288
2316
|
{ value: "30000", label: "30 seconds" },
|
|
@@ -2477,7 +2505,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
2477
2505
|
ui: {
|
|
2478
2506
|
tab: "tools",
|
|
2479
2507
|
label: "Async Execution",
|
|
2480
|
-
description: "Enable async bash commands
|
|
2508
|
+
description: "Enable async bash commands",
|
|
2481
2509
|
},
|
|
2482
2510
|
},
|
|
2483
2511
|
|
|
@@ -2723,31 +2751,14 @@ export const SETTINGS_SCHEMA = {
|
|
|
2723
2751
|
},
|
|
2724
2752
|
},
|
|
2725
2753
|
|
|
2726
|
-
"task.
|
|
2727
|
-
type: "
|
|
2728
|
-
|
|
2729
|
-
default: "schema-free",
|
|
2754
|
+
"task.batch": {
|
|
2755
|
+
type: "boolean",
|
|
2756
|
+
default: true,
|
|
2730
2757
|
ui: {
|
|
2731
2758
|
tab: "tasks",
|
|
2732
|
-
label: "Task
|
|
2733
|
-
description:
|
|
2734
|
-
|
|
2735
|
-
{
|
|
2736
|
-
value: "default",
|
|
2737
|
-
label: "Default",
|
|
2738
|
-
description: "Shared context and custom task schema are available",
|
|
2739
|
-
},
|
|
2740
|
-
{
|
|
2741
|
-
value: "schema-free",
|
|
2742
|
-
label: "Schema-free",
|
|
2743
|
-
description: "Shared context stays available, but custom task schema is disabled",
|
|
2744
|
-
},
|
|
2745
|
-
{
|
|
2746
|
-
value: "independent",
|
|
2747
|
-
label: "Independent",
|
|
2748
|
-
description: "No shared context or custom task schema; each task must stand alone",
|
|
2749
|
-
},
|
|
2750
|
-
],
|
|
2759
|
+
label: "Batch Task Calls",
|
|
2760
|
+
description:
|
|
2761
|
+
"Switch the task tool to its batch shape: one call carries { agent, context, tasks[] } — one subagent per item (with per-item isolation) and a required shared context prepended to every assignment. Each spawn still runs as an independent background agent with the normal idle/parked lifecycle. Disable to restore the flat single-spawn schema.",
|
|
2751
2762
|
},
|
|
2752
2763
|
},
|
|
2753
2764
|
|
|
@@ -2817,6 +2828,34 @@ export const SETTINGS_SCHEMA = {
|
|
|
2817
2828
|
},
|
|
2818
2829
|
},
|
|
2819
2830
|
|
|
2831
|
+
"task.agentIdleTtlMs": {
|
|
2832
|
+
type: "number",
|
|
2833
|
+
default: 420_000,
|
|
2834
|
+
ui: {
|
|
2835
|
+
tab: "tasks",
|
|
2836
|
+
label: "Agent Idle TTL",
|
|
2837
|
+
description:
|
|
2838
|
+
"How long an idle subagent stays live in memory before being parked to disk (ms). Parked agents are revived automatically when messaged or resumed. 0 keeps idle agents live until exit.",
|
|
2839
|
+
},
|
|
2840
|
+
},
|
|
2841
|
+
|
|
2842
|
+
"task.softRequestBudget": {
|
|
2843
|
+
type: "number",
|
|
2844
|
+
default: 90,
|
|
2845
|
+
ui: {
|
|
2846
|
+
tab: "tasks",
|
|
2847
|
+
label: "Soft Subagent Request Budget",
|
|
2848
|
+
description:
|
|
2849
|
+
"Soft per-subagent request budget (assistant requests per run). Crossing it injects one steering notice asking the subagent to wrap up; at 1.5x the budget the run is aborted gracefully, salvaging partial output. 0 disables the guard. Bundled explore/quick_task agents use a lower built-in budget.",
|
|
2850
|
+
options: [
|
|
2851
|
+
{ value: "0", label: "Disabled" },
|
|
2852
|
+
{ value: "40", label: "40 requests" },
|
|
2853
|
+
{ value: "90", label: "90 requests", description: "Default" },
|
|
2854
|
+
{ value: "150", label: "150 requests" },
|
|
2855
|
+
],
|
|
2856
|
+
},
|
|
2857
|
+
},
|
|
2858
|
+
|
|
2820
2859
|
"task.disabledAgents": {
|
|
2821
2860
|
type: "array",
|
|
2822
2861
|
default: [] as string[],
|
|
@@ -3257,21 +3296,23 @@ type Schema = typeof SETTINGS_SCHEMA;
|
|
|
3257
3296
|
export type SettingPath = keyof Schema;
|
|
3258
3297
|
|
|
3259
3298
|
/** Infer the value type for a setting path */
|
|
3260
|
-
export type SettingValue<P extends SettingPath> = Schema[P] extends { type: "boolean" }
|
|
3261
|
-
? boolean
|
|
3262
|
-
: Schema[P] extends { type: "
|
|
3263
|
-
?
|
|
3264
|
-
: Schema[P] extends { type: "
|
|
3265
|
-
?
|
|
3266
|
-
: Schema[P] extends { type: "
|
|
3267
|
-
?
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
: Schema[P] extends { type: "
|
|
3299
|
+
export type SettingValue<P extends SettingPath> = Schema[P] extends { type: "boolean"; default: undefined }
|
|
3300
|
+
? boolean | undefined
|
|
3301
|
+
: Schema[P] extends { type: "boolean" }
|
|
3302
|
+
? boolean
|
|
3303
|
+
: Schema[P] extends { type: "string" }
|
|
3304
|
+
? string | undefined
|
|
3305
|
+
: Schema[P] extends { type: "number" }
|
|
3306
|
+
? number
|
|
3307
|
+
: Schema[P] extends { type: "enum"; values: infer V }
|
|
3308
|
+
? V extends readonly string[]
|
|
3309
|
+
? V[number]
|
|
3310
|
+
: never
|
|
3311
|
+
: Schema[P] extends { type: "array"; default: infer D }
|
|
3273
3312
|
? D
|
|
3274
|
-
:
|
|
3313
|
+
: Schema[P] extends { type: "record"; default: infer D }
|
|
3314
|
+
? D
|
|
3315
|
+
: never;
|
|
3275
3316
|
|
|
3276
3317
|
/** Get the default value for a setting path */
|
|
3277
3318
|
export function getDefault<P extends SettingPath>(path: P): SettingValue<P> {
|
|
@@ -3327,7 +3368,7 @@ export type TreeFilterMode = SettingValue<"treeFilterMode">;
|
|
|
3327
3368
|
|
|
3328
3369
|
export interface CompactionSettings {
|
|
3329
3370
|
enabled: boolean;
|
|
3330
|
-
strategy: "context-full" | "handoff" | "shake" | "off";
|
|
3371
|
+
strategy: "context-full" | "handoff" | "shake" | "snapcompact" | "off";
|
|
3331
3372
|
thresholdPercent: number;
|
|
3332
3373
|
thresholdTokens: number;
|
|
3333
3374
|
reserveTokens: number;
|
|
@@ -3339,6 +3380,7 @@ export interface CompactionSettings {
|
|
|
3339
3380
|
idleEnabled: boolean;
|
|
3340
3381
|
idleThresholdTokens: number;
|
|
3341
3382
|
idleTimeoutSeconds: number;
|
|
3383
|
+
supersedeReads: boolean;
|
|
3342
3384
|
}
|
|
3343
3385
|
|
|
3344
3386
|
export interface ContextPromotionSettings {
|
|
@@ -3461,6 +3503,8 @@ export interface ShellMinimizerSettings {
|
|
|
3461
3503
|
only: string[];
|
|
3462
3504
|
except: string[];
|
|
3463
3505
|
maxCaptureBytes: number;
|
|
3506
|
+
sourceOutlineLevel: "default" | "aggressive";
|
|
3507
|
+
legacyFilters: boolean | undefined;
|
|
3464
3508
|
}
|
|
3465
3509
|
|
|
3466
3510
|
/** Map group prefix -> typed settings interface */
|