@f5-sales-demo/xcsh 21.49.4 → 22.0.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/README.md +0 -3
- package/package.json +8 -8
- package/src/browser/headless-bridge.ts +0 -2
- package/src/browser/host-profiles.ts +1 -1
- package/src/capability/extension.ts +2 -4
- package/src/capability/types.ts +6 -6
- package/src/cli/args.ts +0 -11
- package/src/cli/flag-spec.ts +0 -2
- package/src/commit/agentic/agent.ts +0 -1
- package/src/commit/agentic/index.ts +2 -2
- package/src/commit/pipeline.ts +2 -2
- package/src/config/auto-config.ts +29 -4
- package/src/config/model-catalog.ts +13 -5
- package/src/config/model-registry.ts +74 -45
- package/src/config/model-resolver.ts +14 -0
- package/src/config/settings-schema.ts +14 -66
- package/src/context/profile.ts +2 -2
- package/src/cursor.ts +5 -26
- package/src/discovery/builtin.ts +1 -130
- package/src/discovery/claude-plugins.ts +1 -88
- package/src/discovery/claude.ts +0 -80
- package/src/discovery/codex.ts +11 -148
- package/src/discovery/cursor.ts +1 -84
- package/src/discovery/gemini.ts +0 -89
- package/src/discovery/helpers.ts +1 -1
- package/src/discovery/index.ts +0 -4
- package/src/discovery/opencode.ts +1 -106
- package/src/discovery/windsurf.ts +1 -82
- package/src/extensibility/custom-tools/types.ts +0 -4
- package/src/extensibility/extensions/types.ts +0 -4
- package/src/extensibility/plugins/marketplace/builtin-marketplace-snapshot.ts +1 -1
- package/src/extensibility/plugins/marketplace/builtin-marketplace.provenance.json +1 -1
- package/src/extensibility/plugins/marketplace/types.ts +0 -1
- package/src/internal-urls/api-catalog-discovery.ts +32 -4
- package/src/internal-urls/api-catalog-qmd-index.generated.ts +2 -2
- package/src/internal-urls/build-info.generated.ts +8 -8
- package/src/internal-urls/docs-index.generated.ts +14 -16
- package/src/internal-urls/index.ts +1 -2
- package/src/internal-urls/router.ts +1 -1
- package/src/internal-urls/types.ts +2 -2
- package/src/lifecycle/native-acceptance-driver.ts +0 -1
- package/src/lifecycle/native-acceptance.ts +1 -2
- package/src/locales/ar.json +1 -65
- package/src/locales/de.json +1 -65
- package/src/locales/en.json +1 -99
- package/src/locales/es.json +1 -65
- package/src/locales/fr.json +1 -65
- package/src/locales/hi.json +1 -65
- package/src/locales/it.json +1 -65
- package/src/locales/ja.json +1 -65
- package/src/locales/ko.json +1 -65
- package/src/locales/pt-br.json +1 -65
- package/src/locales/th.json +1 -65
- package/src/locales/zh-cn.json +1 -65
- package/src/locales/zh-tw.json +1 -65
- package/src/main.ts +5 -22
- package/src/memories/index.ts +3 -3
- package/src/modes/acp/acp-agent.ts +14 -146
- package/src/modes/components/agent-dashboard.ts +0 -1
- package/src/modes/components/extensions/extension-dashboard.ts +1 -2
- package/src/modes/components/extensions/state-manager.ts +0 -46
- package/src/modes/components/extensions/types.ts +0 -1
- package/src/modes/components/footer.ts +3 -1
- package/src/modes/components/model-selector.ts +1 -0
- package/src/modes/components/settings-defs.ts +1 -2
- package/src/modes/components/status-line.ts +2 -2
- package/src/modes/controllers/command-controller.ts +0 -14
- package/src/modes/controllers/selector-controller.ts +4 -12
- package/src/modes/interactive-mode.ts +3 -20
- package/src/modes/theme/theme.ts +0 -6
- package/src/modes/types.ts +0 -6
- package/src/prompts/internal-urls/about.md +1 -1
- package/src/prompts/system/progressive-system-prompt.md +1 -1
- package/src/prompts/system/system-prompt.md +0 -9
- package/src/prompts/tools/search-tool-bm25-progressive.md +3 -6
- package/src/qmd-smoke.ts +189 -24
- package/src/remote-control/host.ts +1 -1
- package/src/remote-control/interactions.ts +1 -1
- package/src/remote-control/managed-sessions.ts +1 -1
- package/src/remote-control/protocol-methods.json +0 -10
- package/src/remote-control/router.ts +1 -2
- package/src/remote-control/session.ts +4 -4
- package/src/remote-control/voice-timeline.ts +2 -2
- package/src/sdk.ts +12 -254
- package/src/session/active-model.ts +2 -2
- package/src/session/agent-session.ts +35 -330
- package/src/session/compaction/branch-summarization.ts +2 -2
- package/src/session/compaction/compaction.ts +21 -4
- package/src/session/session-manager.ts +0 -40
- package/src/slash-commands/builtin-registry.ts +3 -85
- package/src/system-prompt.ts +0 -9
- package/src/task/executor.ts +2 -118
- package/src/task/index.ts +0 -4
- package/src/thinking.ts +5 -0
- package/src/{mcp → tools}/discoverable-tool-metadata.ts +14 -84
- package/src/tools/index.ts +7 -28
- package/src/tools/path-utils.ts +2 -10
- package/src/tools/read.ts +2 -2
- package/src/tools/search-tool-bm25.ts +28 -72
- package/src/tools/vim.ts +1 -1
- package/src/web/search/index.ts +2 -5
- package/src/web/search/provider.ts +0 -3
- package/src/web/search/providers/exa.ts +4 -84
- package/src/web/search/types.ts +0 -2
- package/src/capability/mcp.ts +0 -74
- package/src/config/mcp-schema.json +0 -230
- package/src/discovery/mcp-json.ts +0 -171
- package/src/discovery/vscode.ts +0 -105
- package/src/exa/factory.ts +0 -61
- package/src/exa/index.ts +0 -27
- package/src/exa/mcp-client.ts +0 -293
- package/src/exa/render.ts +0 -232
- package/src/exa/researcher.ts +0 -47
- package/src/exa/search.ts +0 -86
- package/src/exa/types.ts +0 -166
- package/src/exa/websets.ts +0 -247
- package/src/internal-urls/mcp-protocol.ts +0 -156
- package/src/mcp/client.ts +0 -482
- package/src/mcp/config-writer.ts +0 -225
- package/src/mcp/config.ts +0 -365
- package/src/mcp/index.ts +0 -29
- package/src/mcp/json-rpc.ts +0 -84
- package/src/mcp/loader.ts +0 -124
- package/src/mcp/manager.ts +0 -1173
- package/src/mcp/oauth-discovery.ts +0 -349
- package/src/mcp/oauth-flow.ts +0 -398
- package/src/mcp/policy.ts +0 -24
- package/src/mcp/render.ts +0 -161
- package/src/mcp/runtime-controller.ts +0 -95
- package/src/mcp/smithery-auth.ts +0 -105
- package/src/mcp/smithery-connect.ts +0 -145
- package/src/mcp/smithery-registry.ts +0 -477
- package/src/mcp/tool-bridge.ts +0 -449
- package/src/mcp/tool-cache.ts +0 -117
- package/src/mcp/transports/http.ts +0 -475
- package/src/mcp/transports/index.ts +0 -6
- package/src/mcp/transports/stdio.ts +0 -325
- package/src/mcp/types.ts +0 -428
- package/src/modes/components/mcp-add-wizard.ts +0 -1346
- package/src/modes/controllers/mcp-command-controller.ts +0 -2502
- package/src/prompts/tools/search-tool-bm25.md +0 -38
- package/src/web/search/providers/zai.ts +0 -311
package/README.md
CHANGED
|
@@ -10,9 +10,6 @@ For installation, setup, provider configuration, model roles, slash commands, an
|
|
|
10
10
|
Package-specific references:
|
|
11
11
|
|
|
12
12
|
- [CHANGELOG](./CHANGELOG.md)
|
|
13
|
-
- [MCP configuration guide](../../docs/mcp-config.md)
|
|
14
|
-
- [MCP runtime lifecycle](../../docs/mcp-runtime-lifecycle.md)
|
|
15
|
-
- [MCP server/tool authoring](../../docs/mcp-server-tool-authoring.md)
|
|
16
13
|
- [Remote-control implementation](./src/remote-control/IMPLEMENTATION.md)
|
|
17
14
|
- [Remote-control acceptance](./src/remote-control/ACCEPTANCE.md)
|
|
18
15
|
- [CONTRIBUTING](../../CONTRIBUTING.md)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "22.0.0",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -67,13 +67,13 @@
|
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@agentclientprotocol/sdk": "1.4.0",
|
|
70
|
-
"@f5-sales-demo/pi-agent-core": "
|
|
71
|
-
"@f5-sales-demo/pi-ai": "
|
|
72
|
-
"@f5-sales-demo/pi-natives": "
|
|
73
|
-
"@f5-sales-demo/pi-resource-management": "
|
|
74
|
-
"@f5-sales-demo/pi-tui": "
|
|
75
|
-
"@f5-sales-demo/pi-utils": "
|
|
76
|
-
"@f5-sales-demo/xcsh-stats": "
|
|
70
|
+
"@f5-sales-demo/pi-agent-core": "22.0.0",
|
|
71
|
+
"@f5-sales-demo/pi-ai": "22.0.0",
|
|
72
|
+
"@f5-sales-demo/pi-natives": "22.0.0",
|
|
73
|
+
"@f5-sales-demo/pi-resource-management": "22.0.0",
|
|
74
|
+
"@f5-sales-demo/pi-tui": "22.0.0",
|
|
75
|
+
"@f5-sales-demo/pi-utils": "22.0.0",
|
|
76
|
+
"@f5-sales-demo/xcsh-stats": "22.0.0",
|
|
77
77
|
"@mozilla/readability": "^0.6",
|
|
78
78
|
"@resvg/resvg-wasm": "2.6.2",
|
|
79
79
|
"@sinclair/typebox": "0.34.52",
|
|
@@ -180,7 +180,6 @@ export async function startHeadlessChatBridge(
|
|
|
180
180
|
hasUI: false,
|
|
181
181
|
toolNames: [...new Set([...BROWSER_TOOL_NAMES, ...EXTENSION_AGENT_TOOL_NAMES])],
|
|
182
182
|
customTools: createExtensionBridgeTools(bridge),
|
|
183
|
-
enableMCP: false,
|
|
184
183
|
enableLsp: false,
|
|
185
184
|
disableExtensionDiscovery: true,
|
|
186
185
|
...(process.env.XCSH_BENCH_EXTENSION
|
|
@@ -201,7 +200,6 @@ export async function startHeadlessChatBridge(
|
|
|
201
200
|
sessionManager: SessionManager.inMemory(cwd),
|
|
202
201
|
toolNames: [...OFFICE_TOOL_NAMES],
|
|
203
202
|
customTools: [],
|
|
204
|
-
enableMCP: false,
|
|
205
203
|
enableLsp: false,
|
|
206
204
|
disableExtensionDiscovery: true,
|
|
207
205
|
bundledExtensions: ["sandbox-guard"],
|
|
@@ -102,7 +102,7 @@ SAFETY — NEVER DO THESE:
|
|
|
102
102
|
const OFFICE_NATIVE_TOOLS_NOTE = `
|
|
103
103
|
NATIVE TOOLS: Beyond the document host tools, you have xcsh's full local toolset — \`bash\` (run shell commands, including CLIs like \`az\`, \`gh\`, \`terraform\`, \`git\` when installed and authenticated), file tools (\`read\`/\`write\`/\`edit\`), and \`grep\` — plus any skills available in this workspace. Reach for them when the task genuinely needs them (pull live data with a CLI, read a local file the user points you at). Prefer the document host tools for document work. Your file tools and shell are confined to the folder xcsh was launched from.
|
|
104
104
|
|
|
105
|
-
This pane
|
|
105
|
+
This pane exposes no plugin-provided tools — the tools listed above (plus the document host tools) are everything you can call. To use a cloud or SCM CLI, invoke it directly with \`bash\` (e.g. \`az account show\`, \`gh repo view\`).
|
|
106
106
|
|
|
107
107
|
Plugin RESOURCES are a different thing and they ARE available to you: an installed plugin's skills, slash commands, schemas, templates and engines. Read them through \`xcsh://plugin/<name>\` (summary), \`xcsh://plugin/<name>/<key>\` (a declared resource such as \`schema\`), or \`xcsh://plugin/<name>/file/<path>\` (any file in the plugin), and run a plugin's engine with \`bash\` (e.g. \`bun xcsh://plugin/<name>/file/engine/cli.ts <command>\`). When a plugin declares a deterministic engine, use it — never recompute by hand what the engine computes.
|
|
108
108
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Extensions Capability
|
|
3
3
|
*
|
|
4
|
-
* Gemini-style extensions that provide
|
|
4
|
+
* Gemini-style extensions that provide tools and context.
|
|
5
5
|
*/
|
|
6
6
|
import { defineCapability } from ".";
|
|
7
|
-
import type { MCPServer } from "./mcp";
|
|
8
7
|
import type { SourceMeta } from "./types";
|
|
9
8
|
|
|
10
9
|
/**
|
|
@@ -13,7 +12,6 @@ import type { SourceMeta } from "./types";
|
|
|
13
12
|
export interface ExtensionManifest {
|
|
14
13
|
name?: string;
|
|
15
14
|
description?: string;
|
|
16
|
-
mcpServers?: Record<string, Omit<MCPServer, "name" | "_source">>;
|
|
17
15
|
tools?: unknown[];
|
|
18
16
|
context?: unknown;
|
|
19
17
|
}
|
|
@@ -37,7 +35,7 @@ export interface Extension {
|
|
|
37
35
|
export const extensionCapability = defineCapability<Extension>({
|
|
38
36
|
id: "extensions",
|
|
39
37
|
displayName: "Extensions",
|
|
40
|
-
description: "Gemini-style extensions providing
|
|
38
|
+
description: "Gemini-style extensions providing tools and context",
|
|
41
39
|
key: ext => ext.name,
|
|
42
40
|
validate: ext => {
|
|
43
41
|
if (!ext.name) return "Missing extension name";
|
package/src/capability/types.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Core types for the capability-based config discovery system.
|
|
3
3
|
*
|
|
4
4
|
* This architecture inverts control: instead of callers knowing about paths like
|
|
5
|
-
* `.xcsh`, `.codex`, `.gemini`, they simply ask for
|
|
6
|
-
* a unified array of
|
|
5
|
+
* `.xcsh`, `.codex`, `.gemini`, they simply ask for a capability and get back
|
|
6
|
+
* a unified array of items.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -33,7 +33,7 @@ export interface LoadResult<T> {
|
|
|
33
33
|
* A provider that can load items for a capability.
|
|
34
34
|
*/
|
|
35
35
|
export interface Provider<T> {
|
|
36
|
-
/** Unique provider ID (e.g., "xcsh", "
|
|
36
|
+
/** Unique provider ID (e.g., "xcsh", "codex", "agents-md") */
|
|
37
37
|
id: string;
|
|
38
38
|
|
|
39
39
|
/** Human-readable name for UI display (e.g., "xcsh", "OpenAI Codex") */
|
|
@@ -47,7 +47,7 @@ export interface Provider<T> {
|
|
|
47
47
|
* Suggested ranges:
|
|
48
48
|
* 100+ : Primary providers (xcsh, pi)
|
|
49
49
|
* 50-99: Tool-specific providers (claude, codex, gemini)
|
|
50
|
-
* 1-49 : Shared standards (
|
|
50
|
+
* 1-49 : Shared standards (agents-md)
|
|
51
51
|
*/
|
|
52
52
|
priority: number;
|
|
53
53
|
|
|
@@ -110,10 +110,10 @@ export interface CapabilityResult<T> {
|
|
|
110
110
|
* Definition of a capability.
|
|
111
111
|
*/
|
|
112
112
|
export interface Capability<T> {
|
|
113
|
-
/** Capability ID (e.g., "
|
|
113
|
+
/** Capability ID (e.g., "skills", "context-files") */
|
|
114
114
|
id: string;
|
|
115
115
|
|
|
116
|
-
/** Human-readable name for UI display (e.g., "
|
|
116
|
+
/** Human-readable name for UI display (e.g., "Skills", "Context Files") */
|
|
117
117
|
displayName: string;
|
|
118
118
|
|
|
119
119
|
/** Short description for settings/status UI */
|
package/src/cli/args.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { type Effort, THINKING_EFFORTS } from "@f5-sales-demo/pi-ai";
|
|
5
5
|
import { APP_NAME, CONFIG_DIR_NAME, logger } from "@f5-sales-demo/pi-utils";
|
|
6
|
-
import { CliUsageError } from "@f5-sales-demo/pi-utils/cli";
|
|
7
6
|
import chalk from "chalk";
|
|
8
7
|
import { parseEffort } from "../thinking";
|
|
9
8
|
import {
|
|
@@ -50,8 +49,6 @@ export interface Args {
|
|
|
50
49
|
models?: string[];
|
|
51
50
|
tools?: string[];
|
|
52
51
|
noTools?: boolean;
|
|
53
|
-
mcp?: boolean;
|
|
54
|
-
noMcp?: boolean;
|
|
55
52
|
noLsp?: boolean;
|
|
56
53
|
noPty?: boolean;
|
|
57
54
|
hooks?: string[];
|
|
@@ -161,12 +158,6 @@ const APPLY: Record<LaunchFlagName, (result: Args, value: string | true) => void
|
|
|
161
158
|
"no-tools": r => {
|
|
162
159
|
r.noTools = true;
|
|
163
160
|
},
|
|
164
|
-
mcp: r => {
|
|
165
|
-
r.mcp = true;
|
|
166
|
-
},
|
|
167
|
-
"no-mcp": r => {
|
|
168
|
-
r.noMcp = true;
|
|
169
|
-
},
|
|
170
161
|
"no-lsp": r => {
|
|
171
162
|
r.noLsp = true;
|
|
172
163
|
},
|
|
@@ -404,8 +395,6 @@ export function parseArgs(args: string[], extensionFlags?: ExtensionFlagRegistry
|
|
|
404
395
|
result.unrecognizedFlags.push({ token, name: name ?? token.replace(/^-+/, "") });
|
|
405
396
|
}
|
|
406
397
|
|
|
407
|
-
if (result.mcp && result.noMcp) throw new CliUsageError("--mcp cannot be combined with --no-mcp");
|
|
408
|
-
if (result.mcp && result.noTools) throw new CliUsageError("--mcp cannot be combined with --no-tools");
|
|
409
398
|
return result;
|
|
410
399
|
}
|
|
411
400
|
|
package/src/cli/flag-spec.ts
CHANGED
|
@@ -79,8 +79,6 @@ export const LAUNCH_FLAGS = defineFlags({
|
|
|
79
79
|
"provider-session-id": { arity: "value", description: "Resume a provider-side session", hidden: true },
|
|
80
80
|
models: { arity: "value", description: "Comma-separated model patterns for Ctrl+P cycling" },
|
|
81
81
|
"no-tools": { arity: "boolean", description: "Disable all built-in tools" },
|
|
82
|
-
mcp: { arity: "boolean", description: "Enable MCP servers for this run" },
|
|
83
|
-
"no-mcp": { arity: "boolean", description: "Disable MCP server discovery and tools" },
|
|
84
82
|
"no-lsp": { arity: "boolean", description: "Disable LSP tools, formatting, and diagnostics" },
|
|
85
83
|
"no-pty": { arity: "boolean", description: "Disable PTY-based interactive bash execution" },
|
|
86
84
|
tools: { arity: "value", description: "Comma-separated list of tools to enable (default: all)" },
|
|
@@ -31,8 +31,8 @@ export async function runAgenticCommit(args: CommitCommandArgs): Promise<void> {
|
|
|
31
31
|
process.stdout.write("● Resolving model...\n");
|
|
32
32
|
const modelRegistry = new ModelRegistry(authStorage, undefined, {
|
|
33
33
|
getProviderOrder: () => settings.get("modelProviderOrder"),
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
getOpenAIContextTier: () => settings.get("providers.openaiContextTier"),
|
|
35
|
+
getLiteLLMContextTier: () => settings.get("providers.litellmContextTier"),
|
|
36
36
|
});
|
|
37
37
|
await modelRegistry.refresh();
|
|
38
38
|
const stagedFilesPromise = (async () => {
|
package/src/commit/pipeline.ts
CHANGED
|
@@ -44,8 +44,8 @@ async function runLegacyCommitCommand(args: CommitCommandArgs): Promise<void> {
|
|
|
44
44
|
const authStorage = await discoverAuthStorage();
|
|
45
45
|
const modelRegistry = new ModelRegistry(authStorage, undefined, {
|
|
46
46
|
getProviderOrder: () => settings.get("modelProviderOrder"),
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
getOpenAIContextTier: () => settings.get("providers.openaiContextTier"),
|
|
48
|
+
getLiteLLMContextTier: () => settings.get("providers.litellmContextTier"),
|
|
49
49
|
});
|
|
50
50
|
await modelRegistry.refresh();
|
|
51
51
|
|
|
@@ -20,7 +20,7 @@ import { hardenAgentConfigFileSync, writeAgentConfigFileSync } from "./agent-con
|
|
|
20
20
|
import { DEFAULT_MODEL_ROLE } from "./settings-schema";
|
|
21
21
|
|
|
22
22
|
/** Current config schema version. Bump when the generated format changes. */
|
|
23
|
-
export const CURRENT_CONFIG_VERSION =
|
|
23
|
+
export const CURRENT_CONFIG_VERSION = 11;
|
|
24
24
|
const LITELLM_CONFIG_DIR_MODE = 0o700;
|
|
25
25
|
const LITELLM_MODELS_FILE_MODE = 0o600;
|
|
26
26
|
const GENERATED_LITELLM_MARKER = "# Auto-generated by xcsh for LiteLLM proxy";
|
|
@@ -123,6 +123,7 @@ export function generateModelsYml(baseUrl: string, options?: GenerateModelsYmlOp
|
|
|
123
123
|
" - gpt-6-astra",
|
|
124
124
|
" - gpt-5.6-luna",
|
|
125
125
|
" - gpt-5.6-sol",
|
|
126
|
+
" - gpt-5.5",
|
|
126
127
|
" models:",
|
|
127
128
|
" - id: gpt-6-luna",
|
|
128
129
|
" name: GPT-6 Luna",
|
|
@@ -130,7 +131,8 @@ export function generateModelsYml(baseUrl: string, options?: GenerateModelsYmlOp
|
|
|
130
131
|
` baseUrl: "${responsesBaseUrl}"`,
|
|
131
132
|
" - id: gpt-5.6-terra",
|
|
132
133
|
" name: GPT-5.6 Terra",
|
|
133
|
-
" api: openai-
|
|
134
|
+
" api: openai-responses",
|
|
135
|
+
` baseUrl: "${responsesBaseUrl}"`,
|
|
134
136
|
" - id: gpt-6-sol",
|
|
135
137
|
" name: GPT-6 Sol",
|
|
136
138
|
" api: openai-responses",
|
|
@@ -141,10 +143,16 @@ export function generateModelsYml(baseUrl: string, options?: GenerateModelsYmlOp
|
|
|
141
143
|
` baseUrl: "${responsesBaseUrl}"`,
|
|
142
144
|
" - id: gpt-5.6-luna",
|
|
143
145
|
" name: GPT-5.6 Luna",
|
|
144
|
-
" api: openai-
|
|
146
|
+
" api: openai-responses",
|
|
147
|
+
` baseUrl: "${responsesBaseUrl}"`,
|
|
145
148
|
" - id: gpt-5.6-sol",
|
|
146
149
|
" name: GPT-5.6 Sol",
|
|
147
|
-
" api: openai-
|
|
150
|
+
" api: openai-responses",
|
|
151
|
+
` baseUrl: "${responsesBaseUrl}"`,
|
|
152
|
+
" - id: gpt-5.5",
|
|
153
|
+
" name: GPT-5.5",
|
|
154
|
+
" api: openai-responses",
|
|
155
|
+
` baseUrl: "${responsesBaseUrl}"`,
|
|
148
156
|
" picker:",
|
|
149
157
|
" groupId: litellm",
|
|
150
158
|
" groupLabel: LiteLLM",
|
|
@@ -251,6 +259,23 @@ export function generateModelsYml(baseUrl: string, options?: GenerateModelsYmlOp
|
|
|
251
259
|
" supportsTemperature: false",
|
|
252
260
|
" gpt-5.6-luna:",
|
|
253
261
|
" reasoning: true",
|
|
262
|
+
" input:",
|
|
263
|
+
" - text",
|
|
264
|
+
" - image",
|
|
265
|
+
" contextWindow: 1050000",
|
|
266
|
+
" maxTokens: 128000",
|
|
267
|
+
" compat:",
|
|
268
|
+
" supportsTemperature: false",
|
|
269
|
+
" cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }",
|
|
270
|
+
" gpt-5.5:",
|
|
271
|
+
" reasoning: true",
|
|
272
|
+
" input:",
|
|
273
|
+
" - text",
|
|
274
|
+
" - image",
|
|
275
|
+
" contextWindow: 1050000",
|
|
276
|
+
" maxTokens: 128000",
|
|
277
|
+
" compat:",
|
|
278
|
+
" supportsTemperature: false",
|
|
254
279
|
" cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }",
|
|
255
280
|
];
|
|
256
281
|
|
|
@@ -10,9 +10,16 @@ function compareVersions(left: string, right: string): number {
|
|
|
10
10
|
return 0;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
const
|
|
15
|
-
|
|
13
|
+
/** Present the exact model-interaction contract when each provider advertises the model. */
|
|
14
|
+
const CODEX_INTERACTION_MODEL_IDS = new Set([
|
|
15
|
+
"gpt-6-astra",
|
|
16
|
+
"gpt-6-sol",
|
|
17
|
+
"gpt-6-luna",
|
|
18
|
+
"gpt-5.6-sol",
|
|
19
|
+
"gpt-5.6-terra",
|
|
20
|
+
"gpt-5.6-luna",
|
|
21
|
+
"gpt-5.5",
|
|
22
|
+
]);
|
|
16
23
|
|
|
17
24
|
/** Shared catalog boundary for the TUI and attached human interfaces. */
|
|
18
25
|
export function filterCurrentBrowserModels(models: readonly Model[]): Model[] {
|
|
@@ -39,9 +46,10 @@ export function filterCurrentBrowserModels(models: readonly Model[]): Model[] {
|
|
|
39
46
|
return models.filter(model => {
|
|
40
47
|
const gpt = model.id.match(/^gpt-(\d+(?:\.\d+)?)(?:-|$)/i);
|
|
41
48
|
if (gpt?.[1]) {
|
|
49
|
+
if (model.provider === "openai-codex" || model.provider === "litellm") {
|
|
50
|
+
return CODEX_INTERACTION_MODEL_IDS.has(model.id.toLowerCase());
|
|
51
|
+
}
|
|
42
52
|
if (compareVersions(gpt[1], "5.6") < 0) return false;
|
|
43
|
-
if (model.provider === "openai-codex") return DEFAULT_OPENAI_CODEX_MODEL_IDS.has(model.id.toLowerCase());
|
|
44
|
-
if (model.provider === "litellm") return CURRENT_LITELLM_OPENAI_MODEL_IDS.has(model.id.toLowerCase());
|
|
45
53
|
}
|
|
46
54
|
const claude = model.id.match(/^claude-(opus|sonnet|haiku)-(\d+)(?:[.-](\d+))?(?:-|$)/i);
|
|
47
55
|
if (claude?.[1] && claude[2]) {
|
|
@@ -2,7 +2,9 @@ import * as path from "node:path";
|
|
|
2
2
|
import {
|
|
3
3
|
type Api,
|
|
4
4
|
type AssistantMessageEventStream,
|
|
5
|
+
applyCodexInteractionMetadata,
|
|
5
6
|
applyGeneratedModelPolicies,
|
|
7
|
+
type CodexContextTier,
|
|
6
8
|
type Context,
|
|
7
9
|
createModelManager,
|
|
8
10
|
DEFAULT_LOCAL_TOKEN,
|
|
@@ -23,6 +25,7 @@ import {
|
|
|
23
25
|
readModelCache,
|
|
24
26
|
registerCustomApi,
|
|
25
27
|
registerOAuthProvider,
|
|
28
|
+
resolveCodexContextBudget,
|
|
26
29
|
type SimpleStreamOptions,
|
|
27
30
|
type ThinkingConfig,
|
|
28
31
|
unregisterCustomApis,
|
|
@@ -50,17 +53,14 @@ export type { CanonicalModelIndex, CanonicalModelRecord, CanonicalModelVariant,
|
|
|
50
53
|
|
|
51
54
|
export const kNoAuth = NO_AUTH_API_KEY;
|
|
52
55
|
|
|
53
|
-
const OPENAI_CODEX_STANDARD_CONTEXT_WINDOW = 272_000;
|
|
54
|
-
const OPENAI_CODEX_MAX_CONTEXT_WINDOW = 1_050_000;
|
|
55
|
-
const OPENAI_CODEX_MAX_CONTEXT_MODEL_IDS = new Set(["gpt-6-luna", "gpt-6-sol"]);
|
|
56
|
-
const LITELLM_STANDARD_CONTEXT_WINDOW = 272_000;
|
|
57
|
-
const LITELLM_MAX_CONTEXT_WINDOW = 1_050_000;
|
|
58
|
-
const LITELLM_MAX_CONTEXT_MODEL_IDS = new Set(["gpt-6-luna", "gpt-5.6-terra", "gpt-6-sol", "gpt-6-astra"]);
|
|
59
|
-
|
|
60
56
|
export function isAuthenticated(apiKey: string | undefined | null): apiKey is string {
|
|
61
57
|
return Boolean(apiKey) && apiKey !== kNoAuth;
|
|
62
58
|
}
|
|
63
59
|
|
|
60
|
+
function positiveInteger(value: unknown): number | undefined {
|
|
61
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : undefined;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
64
|
export type ModelRole = "default" | "smol" | "slow" | "vision" | "plan" | "designer" | "commit" | "task";
|
|
65
65
|
|
|
66
66
|
export interface ModelRoleInfo {
|
|
@@ -878,8 +878,8 @@ export class ModelRegistry {
|
|
|
878
878
|
#lastDiscoveryWarnings: Map<string, string> = new Map();
|
|
879
879
|
#hasProbed = false;
|
|
880
880
|
#refreshQueue: Promise<void> = Promise.resolve();
|
|
881
|
-
#
|
|
882
|
-
#
|
|
881
|
+
#openAIContextTier: CodexContextTier = "standard";
|
|
882
|
+
#litellmContextTier: CodexContextTier = "standard";
|
|
883
883
|
|
|
884
884
|
#enqueueRefresh(operation: () => Promise<void>): Promise<void> {
|
|
885
885
|
const pending = this.#refreshQueue.then(operation);
|
|
@@ -901,8 +901,8 @@ export class ModelRegistry {
|
|
|
901
901
|
modelsPath?: string,
|
|
902
902
|
private readonly options: {
|
|
903
903
|
getProviderOrder?: () => readonly string[];
|
|
904
|
-
|
|
905
|
-
|
|
904
|
+
getOpenAIContextTier?: () => CodexContextTier;
|
|
905
|
+
getLiteLLMContextTier?: () => CodexContextTier;
|
|
906
906
|
} = {},
|
|
907
907
|
) {
|
|
908
908
|
this.#modelsConfigFile = ModelsConfigFile.relocate(modelsPath);
|
|
@@ -1055,8 +1055,8 @@ export class ModelRegistry {
|
|
|
1055
1055
|
}
|
|
1056
1056
|
|
|
1057
1057
|
#loadModels() {
|
|
1058
|
-
this.#
|
|
1059
|
-
this.#
|
|
1058
|
+
this.#openAIContextTier = this.options.getOpenAIContextTier?.() ?? this.#openAIContextTier;
|
|
1059
|
+
this.#litellmContextTier = this.options.getLiteLLMContextTier?.() ?? this.#litellmContextTier;
|
|
1060
1060
|
// Load custom models from models.json first (to know which providers to override)
|
|
1061
1061
|
const {
|
|
1062
1062
|
models: customModels = [],
|
|
@@ -1090,42 +1090,39 @@ export class ModelRegistry {
|
|
|
1090
1090
|
const combined = this.#mergeCustomModels(withConfigModels, this.#runtimeModelOverlays);
|
|
1091
1091
|
|
|
1092
1092
|
this.#models = this.#applyProviderModelAllowlists(this.#applyModelOverrides(combined, this.#modelOverrides));
|
|
1093
|
-
this.#
|
|
1094
|
-
this.#
|
|
1093
|
+
this.#applyOpenAIContextTier();
|
|
1094
|
+
this.#applyLiteLLMContextTier();
|
|
1095
1095
|
this.#rebuildCanonicalIndex();
|
|
1096
1096
|
}
|
|
1097
1097
|
|
|
1098
|
-
#
|
|
1099
|
-
const contextWindow = this.#openAICodexMaxContext
|
|
1100
|
-
? OPENAI_CODEX_MAX_CONTEXT_WINDOW
|
|
1101
|
-
: OPENAI_CODEX_STANDARD_CONTEXT_WINDOW;
|
|
1098
|
+
#applyContextTier(provider: "openai-codex" | "litellm", tier: CodexContextTier): void {
|
|
1102
1099
|
for (const model of this.#models) {
|
|
1103
|
-
if (model.provider
|
|
1104
|
-
|
|
1105
|
-
|
|
1100
|
+
if (model.provider !== provider) continue;
|
|
1101
|
+
Object.assign(model, applyCodexInteractionMetadata(model));
|
|
1102
|
+
const budget = resolveCodexContextBudget(model.id, tier, model.providerContextWindow);
|
|
1103
|
+
if (budget) Object.assign(model, budget);
|
|
1106
1104
|
}
|
|
1107
1105
|
}
|
|
1108
1106
|
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1107
|
+
#applyOpenAIContextTier(): void {
|
|
1108
|
+
this.#applyContextTier("openai-codex", this.#openAIContextTier);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/** Update subscription context limits without rebuilding the registry. */
|
|
1112
|
+
setOpenAIContextTier(tier: CodexContextTier): void {
|
|
1113
|
+
this.#openAIContextTier = tier;
|
|
1114
|
+
this.#applyOpenAIContextTier();
|
|
1113
1115
|
this.#rebuildCanonicalIndex();
|
|
1114
1116
|
}
|
|
1115
1117
|
|
|
1116
|
-
#
|
|
1117
|
-
|
|
1118
|
-
for (const model of this.#models) {
|
|
1119
|
-
if (model.provider === "litellm" && LITELLM_MAX_CONTEXT_MODEL_IDS.has(model.id)) {
|
|
1120
|
-
model.contextWindow = contextWindow;
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1118
|
+
#applyLiteLLMContextTier(): void {
|
|
1119
|
+
this.#applyContextTier("litellm", this.#litellmContextTier);
|
|
1123
1120
|
}
|
|
1124
1121
|
|
|
1125
1122
|
/** Update current internal OpenAI context limits without changing subscription models. */
|
|
1126
|
-
|
|
1127
|
-
this.#
|
|
1128
|
-
this.#
|
|
1123
|
+
setLiteLLMContextTier(tier: CodexContextTier): void {
|
|
1124
|
+
this.#litellmContextTier = tier;
|
|
1125
|
+
this.#applyLiteLLMContextTier();
|
|
1129
1126
|
this.#rebuildCanonicalIndex();
|
|
1130
1127
|
}
|
|
1131
1128
|
|
|
@@ -1198,6 +1195,13 @@ export class ModelRegistry {
|
|
|
1198
1195
|
return merged;
|
|
1199
1196
|
}
|
|
1200
1197
|
|
|
1198
|
+
#filterOverlaysBySuccessfulDiscovery(models: CustomModelOverlay[]): CustomModelOverlay[] {
|
|
1199
|
+
return models.filter(model => {
|
|
1200
|
+
const discovery = this.#providerDiscoveryStates.get(model.provider);
|
|
1201
|
+
return discovery?.status !== "ok" || discovery.models.includes(model.id);
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1201
1205
|
#applyProviderModelAllowlists(models: Model<Api>[]): Model<Api>[] {
|
|
1202
1206
|
return models.filter(model => {
|
|
1203
1207
|
const allowlist = this.#modelAllowlists.get(model.provider);
|
|
@@ -1420,9 +1424,15 @@ export class ModelRegistry {
|
|
|
1420
1424
|
]);
|
|
1421
1425
|
const discovered = [...configuredDiscovered, ...builtInDiscovered];
|
|
1422
1426
|
// Replace only catalogs which completed successfully, including an empty response.
|
|
1427
|
+
const successfulDiscoveryProviders = providerFilter
|
|
1428
|
+
? [...providerFilter].filter(provider => this.#providerDiscoveryStates.get(provider)?.status === "ok")
|
|
1429
|
+
: [...this.#providerDiscoveryStates.values()]
|
|
1430
|
+
.filter(state => state.status === "ok")
|
|
1431
|
+
.map(state => state.provider);
|
|
1423
1432
|
const refreshed = new Set([
|
|
1424
1433
|
...selectedDiscoverableProviders.map(provider => provider.provider),
|
|
1425
1434
|
...discovered.map(model => model.provider),
|
|
1435
|
+
...successfulDiscoveryProviders,
|
|
1426
1436
|
]);
|
|
1427
1437
|
const discoveredModels = this.#applyHardcodedModelPolicies(
|
|
1428
1438
|
discovered.map(model => {
|
|
@@ -1452,12 +1462,18 @@ export class ModelRegistry {
|
|
|
1452
1462
|
model => !refreshed.has(model.provider) || this.#providerDiscoveryStates.get(model.provider)?.status !== "ok",
|
|
1453
1463
|
);
|
|
1454
1464
|
const resolved = this.#mergeResolvedModels(this.#models, discoveredModels);
|
|
1455
|
-
const withConfigModels = this.#mergeCustomModels(
|
|
1465
|
+
const withConfigModels = this.#mergeCustomModels(
|
|
1466
|
+
resolved,
|
|
1467
|
+
this.#filterOverlaysBySuccessfulDiscovery(this.#customModelOverlays),
|
|
1468
|
+
);
|
|
1456
1469
|
// Merge runtime extension models so they survive online discovery completion
|
|
1457
|
-
const combined = this.#mergeCustomModels(
|
|
1470
|
+
const combined = this.#mergeCustomModels(
|
|
1471
|
+
withConfigModels,
|
|
1472
|
+
this.#filterOverlaysBySuccessfulDiscovery(this.#runtimeModelOverlays),
|
|
1473
|
+
);
|
|
1458
1474
|
this.#models = this.#applyProviderModelAllowlists(this.#applyModelOverrides(combined, this.#modelOverrides));
|
|
1459
|
-
this.#
|
|
1460
|
-
this.#
|
|
1475
|
+
this.#applyOpenAIContextTier();
|
|
1476
|
+
this.#applyLiteLLMContextTier();
|
|
1461
1477
|
this.#rebuildCanonicalIndex();
|
|
1462
1478
|
}
|
|
1463
1479
|
|
|
@@ -2047,7 +2063,13 @@ export class ModelRegistry {
|
|
|
2047
2063
|
throw new Error(`HTTP ${response.status} from ${modelsUrl}`);
|
|
2048
2064
|
}
|
|
2049
2065
|
const payload = await response.json();
|
|
2050
|
-
const items: Array<{
|
|
2066
|
+
const items: Array<{
|
|
2067
|
+
id: string;
|
|
2068
|
+
contextWindow?: number;
|
|
2069
|
+
context_window?: unknown;
|
|
2070
|
+
max_input_tokens?: unknown;
|
|
2071
|
+
max_output_tokens?: unknown;
|
|
2072
|
+
}> =
|
|
2051
2073
|
providerConfig.provider === "vllm"
|
|
2052
2074
|
? parseVllmModelsPayload(payload)
|
|
2053
2075
|
: ((payload as { data?: Array<{ id: string }> }).data ?? []);
|
|
@@ -2055,6 +2077,10 @@ export class ModelRegistry {
|
|
|
2055
2077
|
for (const item of items) {
|
|
2056
2078
|
const id = item.id;
|
|
2057
2079
|
if (!id) continue;
|
|
2080
|
+
const advertisedContextWindow =
|
|
2081
|
+
positiveInteger(item.context_window) ?? positiveInteger(item.max_input_tokens) ?? item.contextWindow;
|
|
2082
|
+
const advertisedOutputLimit = positiveInteger(item.max_output_tokens);
|
|
2083
|
+
const contextWindow = advertisedContextWindow ?? 128000;
|
|
2058
2084
|
discovered.push(
|
|
2059
2085
|
enrichModelThinking({
|
|
2060
2086
|
id,
|
|
@@ -2065,11 +2091,13 @@ export class ModelRegistry {
|
|
|
2065
2091
|
reasoning: false,
|
|
2066
2092
|
input: ["text"],
|
|
2067
2093
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
2068
|
-
contextWindow
|
|
2094
|
+
contextWindow,
|
|
2069
2095
|
maxTokens:
|
|
2070
|
-
|
|
2096
|
+
advertisedOutputLimit ??
|
|
2097
|
+
(advertisedContextWindow === undefined
|
|
2071
2098
|
? 8192
|
|
2072
|
-
: Math.max(1, Math.min(8192, Math.floor(
|
|
2099
|
+
: Math.max(1, Math.min(8192, Math.floor(advertisedContextWindow / 4)))),
|
|
2100
|
+
providerContextWindow: advertisedContextWindow,
|
|
2073
2101
|
headers,
|
|
2074
2102
|
}),
|
|
2075
2103
|
);
|
|
@@ -2150,7 +2178,8 @@ export class ModelRegistry {
|
|
|
2150
2178
|
// bundled corrections. Reapply generated-model policy before a cached entry
|
|
2151
2179
|
// replaces its bundled peer; explicit user overrides still run afterward.
|
|
2152
2180
|
applyGeneratedModelPolicies(models, { preserveDiscoveredThinking });
|
|
2153
|
-
return models.map(
|
|
2181
|
+
return models.map(rawModel => {
|
|
2182
|
+
const model = applyCodexInteractionMetadata(rawModel);
|
|
2154
2183
|
if (model.id !== "gpt-5.4" || model.provider === "github-copilot") {
|
|
2155
2184
|
return model;
|
|
2156
2185
|
}
|
|
@@ -1116,6 +1116,20 @@ export function resolveCliModel(options: {
|
|
|
1116
1116
|
error: undefined,
|
|
1117
1117
|
};
|
|
1118
1118
|
}
|
|
1119
|
+
const thinkingSeparator = pattern.lastIndexOf(":");
|
|
1120
|
+
const exactModelId =
|
|
1121
|
+
thinkingSeparator !== -1 && parseThinkingLevel(pattern.slice(thinkingSeparator + 1))
|
|
1122
|
+
? pattern.slice(0, thinkingSeparator)
|
|
1123
|
+
: pattern;
|
|
1124
|
+
if (resolveProviderModelReference(provider, exactModelId, allModels)) {
|
|
1125
|
+
return {
|
|
1126
|
+
model: undefined,
|
|
1127
|
+
selector: undefined,
|
|
1128
|
+
thinkingLevel: undefined,
|
|
1129
|
+
warning: undefined,
|
|
1130
|
+
error: `Model "${provider}/${exactModelId}" is unavailable. Configure or sign in to provider "${provider}".`,
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1119
1133
|
}
|
|
1120
1134
|
|
|
1121
1135
|
const candidates = provider ? availableModels.filter(model => model.provider === provider) : availableModels;
|