@f5-sales-demo/xcsh 22.4.11 → 22.5.1
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/package.json +8 -8
- package/src/cli/update-cli.ts +9 -0
- package/src/config/auto-config.ts +25 -1
- package/src/config/model-catalog.ts +1 -0
- package/src/config/model-registry.ts +153 -4
- package/src/config/settings-schema.ts +5 -6
- package/src/extensibility/custom-tools/types.ts +3 -0
- package/src/extensibility/extensions/types.ts +3 -1
- 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 +3 -3
- package/src/modes/controllers/login-model.ts +10 -10
- package/src/prompts/tools/classify.md +1 -0
- package/src/routing/subscription-profiles.ts +3 -3
- package/src/sdk.ts +5 -1
- package/src/session/agent-session.ts +9 -1
- package/src/tools/async-tool.ts +47 -0
- package/src/tools/classify.ts +64 -0
- package/src/tools/gemini-image.ts +42 -133
- package/src/tools/index.ts +7 -1
- package/src/tools/search-tool-bm25.ts +14 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "22.
|
|
4
|
+
"version": "22.5.1",
|
|
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": "22.
|
|
71
|
-
"@f5-sales-demo/pi-ai": "22.
|
|
72
|
-
"@f5-sales-demo/pi-natives": "22.
|
|
73
|
-
"@f5-sales-demo/pi-resource-management": "22.
|
|
74
|
-
"@f5-sales-demo/pi-tui": "22.
|
|
75
|
-
"@f5-sales-demo/pi-utils": "22.
|
|
76
|
-
"@f5-sales-demo/xcsh-stats": "22.
|
|
70
|
+
"@f5-sales-demo/pi-agent-core": "22.5.1",
|
|
71
|
+
"@f5-sales-demo/pi-ai": "22.5.1",
|
|
72
|
+
"@f5-sales-demo/pi-natives": "22.5.1",
|
|
73
|
+
"@f5-sales-demo/pi-resource-management": "22.5.1",
|
|
74
|
+
"@f5-sales-demo/pi-tui": "22.5.1",
|
|
75
|
+
"@f5-sales-demo/pi-utils": "22.5.1",
|
|
76
|
+
"@f5-sales-demo/xcsh-stats": "22.5.1",
|
|
77
77
|
"@mozilla/readability": "^0.6",
|
|
78
78
|
"@resvg/resvg-wasm": "2.6.2",
|
|
79
79
|
"@sinclair/typebox": "0.34.52",
|
package/src/cli/update-cli.ts
CHANGED
|
@@ -243,6 +243,15 @@ export async function runUpdateCommand(
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
const comparison = compareVersions(release.version, deps.currentVersion);
|
|
246
|
+
if (comparison < 0) {
|
|
247
|
+
deps.stdout(
|
|
248
|
+
chalk.yellow(
|
|
249
|
+
`Discovered release ${release.version} is older than installed ${deps.currentVersion}; no update performed.`,
|
|
250
|
+
),
|
|
251
|
+
);
|
|
252
|
+
if (opts.check) deps.stdout(formatUpdateRecommendation(recommendation));
|
|
253
|
+
return 0;
|
|
254
|
+
}
|
|
246
255
|
if (comparison > 0) deps.stdout(chalk.cyan(`New version available: ${release.version}`));
|
|
247
256
|
else if (opts.force) deps.stdout(chalk.yellow(`Forcing update recommendation for ${release.version}`));
|
|
248
257
|
else deps.stdout(chalk.green("✓ Already up to date"));
|
|
@@ -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 = 12;
|
|
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";
|
|
@@ -119,6 +119,7 @@ export function generateModelsYml(baseUrl: string, options?: GenerateModelsYmlOp
|
|
|
119
119
|
" modelAllowlist:",
|
|
120
120
|
" - gpt-6-luna",
|
|
121
121
|
" - gpt-5.6-terra",
|
|
122
|
+
" - gpt-6.1-sol",
|
|
122
123
|
" - gpt-6-sol",
|
|
123
124
|
" - gpt-6-astra",
|
|
124
125
|
" - gpt-5.6-luna",
|
|
@@ -133,6 +134,10 @@ export function generateModelsYml(baseUrl: string, options?: GenerateModelsYmlOp
|
|
|
133
134
|
" name: GPT-5.6 Terra",
|
|
134
135
|
" api: openai-responses",
|
|
135
136
|
` baseUrl: "${responsesBaseUrl}"`,
|
|
137
|
+
" - id: gpt-6.1-sol",
|
|
138
|
+
" name: GPT-6.1 Sol",
|
|
139
|
+
" api: openai-responses",
|
|
140
|
+
` baseUrl: "${responsesBaseUrl}"`,
|
|
136
141
|
" - id: gpt-6-sol",
|
|
137
142
|
" name: GPT-6 Sol",
|
|
138
143
|
" api: openai-responses",
|
|
@@ -198,6 +203,25 @@ export function generateModelsYml(baseUrl: string, options?: GenerateModelsYmlOp
|
|
|
198
203
|
" maxTokens: 128000",
|
|
199
204
|
" compat:",
|
|
200
205
|
" supportsTemperature: false",
|
|
206
|
+
" gpt-6.1-sol:",
|
|
207
|
+
" reasoning: true",
|
|
208
|
+
" input:",
|
|
209
|
+
" - text",
|
|
210
|
+
" - image",
|
|
211
|
+
" cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }",
|
|
212
|
+
" thinking:",
|
|
213
|
+
" mode: effort",
|
|
214
|
+
" defaultLevel: medium",
|
|
215
|
+
" supportedLevels:",
|
|
216
|
+
" - { effort: low, description: Light reasoning }",
|
|
217
|
+
" - { effort: medium, description: Balanced reasoning }",
|
|
218
|
+
" - { effort: high, description: Deep reasoning }",
|
|
219
|
+
" - { effort: xhigh, description: Very deep reasoning }",
|
|
220
|
+
" - { effort: max, description: Maximum reasoning }",
|
|
221
|
+
" contextWindow: 922000",
|
|
222
|
+
" maxTokens: 128000",
|
|
223
|
+
" compat:",
|
|
224
|
+
" supportsTemperature: false",
|
|
201
225
|
" gpt-6-sol:",
|
|
202
226
|
" reasoning: true",
|
|
203
227
|
" input:",
|
|
@@ -12,6 +12,7 @@ function compareVersions(left: string, right: string): number {
|
|
|
12
12
|
|
|
13
13
|
/** Present the exact model-interaction contract when each provider advertises the model. */
|
|
14
14
|
const CODEX_INTERACTION_MODEL_IDS = new Set([
|
|
15
|
+
"gpt-6.1-sol",
|
|
15
16
|
"gpt-6-astra",
|
|
16
17
|
"gpt-6-sol",
|
|
17
18
|
"gpt-6-luna",
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import {
|
|
3
|
+
type AnyModel,
|
|
3
4
|
type Api,
|
|
4
5
|
type AssistantMessageEventStream,
|
|
5
6
|
applyCodexInteractionMetadata,
|
|
6
7
|
applyGeneratedModelPolicies,
|
|
8
|
+
type ClassifierModel,
|
|
7
9
|
type CodexContextTier,
|
|
8
10
|
type Context,
|
|
9
11
|
createModelManager,
|
|
12
|
+
createOperationCatalog,
|
|
10
13
|
DEFAULT_LOCAL_TOKEN,
|
|
11
14
|
enrichModelThinking,
|
|
12
15
|
getBundledModels,
|
|
@@ -14,6 +17,7 @@ import {
|
|
|
14
17
|
googleAntigravityModelManagerOptions,
|
|
15
18
|
googleGeminiCliModelManagerOptions,
|
|
16
19
|
googleVertexModelManagerOptions,
|
|
20
|
+
type ImageModel,
|
|
17
21
|
type Model,
|
|
18
22
|
type ModelManagerOptions,
|
|
19
23
|
type ModelRefreshStrategy,
|
|
@@ -31,7 +35,7 @@ import {
|
|
|
31
35
|
unregisterCustomApis,
|
|
32
36
|
unregisterOAuthProviders,
|
|
33
37
|
} from "@f5-sales-demo/pi-ai";
|
|
34
|
-
import { $env, $envExact, isRecord, logger } from "@f5-sales-demo/pi-utils";
|
|
38
|
+
import { $env, $envExact, getModelDbPath, isRecord, logger } from "@f5-sales-demo/pi-utils";
|
|
35
39
|
import { type Static, Type } from "@sinclair/typebox";
|
|
36
40
|
import { type ConfigError, ConfigFile } from "../config";
|
|
37
41
|
import { hasLiteLLMEnv, probeAndUpgradeLiteLLMConfig, startupHealthCheck } from "../config/auto-config";
|
|
@@ -147,6 +151,8 @@ const ReasoningEffortMapSchema = Type.Object({
|
|
|
147
151
|
medium: Type.Optional(Type.String()),
|
|
148
152
|
high: Type.Optional(Type.String()),
|
|
149
153
|
xhigh: Type.Optional(Type.String()),
|
|
154
|
+
max: Type.Optional(Type.String()),
|
|
155
|
+
ultra: Type.Optional(Type.String()),
|
|
150
156
|
});
|
|
151
157
|
|
|
152
158
|
const OpenAICompatSchema = Type.Object({
|
|
@@ -157,6 +163,7 @@ const OpenAICompatSchema = Type.Object({
|
|
|
157
163
|
reasoningEffortMap: Type.Optional(ReasoningEffortMapSchema),
|
|
158
164
|
maxTokensField: Type.Optional(Type.Union([Type.Literal("max_completion_tokens"), Type.Literal("max_tokens")])),
|
|
159
165
|
supportsUsageInStreaming: Type.Optional(Type.Boolean()),
|
|
166
|
+
supportsFinishReason: Type.Optional(Type.Boolean()),
|
|
160
167
|
requiresToolResultName: Type.Optional(Type.Boolean()),
|
|
161
168
|
requiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),
|
|
162
169
|
requiresThinkingAsText: Type.Optional(Type.Boolean()),
|
|
@@ -167,12 +174,77 @@ const OpenAICompatSchema = Type.Object({
|
|
|
167
174
|
Type.Literal("zai"),
|
|
168
175
|
Type.Literal("qwen"),
|
|
169
176
|
Type.Literal("qwen-chat-template"),
|
|
177
|
+
Type.Literal("ant-ling"),
|
|
178
|
+
Type.Literal("baseten"),
|
|
179
|
+
Type.Literal("deepseek"),
|
|
180
|
+
Type.Literal("together"),
|
|
181
|
+
Type.Literal("chat-template"),
|
|
182
|
+
Type.Literal("string-thinking"),
|
|
170
183
|
]),
|
|
171
184
|
),
|
|
172
185
|
openRouterRouting: Type.Optional(OpenRouterRoutingSchema),
|
|
186
|
+
chatTemplateKwargs: Type.Optional(
|
|
187
|
+
Type.Record(
|
|
188
|
+
Type.String(),
|
|
189
|
+
Type.Union([
|
|
190
|
+
Type.String(),
|
|
191
|
+
Type.Number(),
|
|
192
|
+
Type.Boolean(),
|
|
193
|
+
Type.Null(),
|
|
194
|
+
Type.Object({
|
|
195
|
+
$var: Type.Union([
|
|
196
|
+
Type.Literal("thinking.enabled"),
|
|
197
|
+
Type.Literal("thinking.effort"),
|
|
198
|
+
Type.Literal("thinking.budget"),
|
|
199
|
+
]),
|
|
200
|
+
omitWhenOff: Type.Optional(Type.Boolean()),
|
|
201
|
+
}),
|
|
202
|
+
]),
|
|
203
|
+
),
|
|
204
|
+
),
|
|
205
|
+
chatTemplateArgs: Type.Optional(
|
|
206
|
+
Type.Record(
|
|
207
|
+
Type.String(),
|
|
208
|
+
Type.Union([
|
|
209
|
+
Type.String(),
|
|
210
|
+
Type.Number(),
|
|
211
|
+
Type.Boolean(),
|
|
212
|
+
Type.Null(),
|
|
213
|
+
Type.Object({
|
|
214
|
+
$var: Type.Union([
|
|
215
|
+
Type.Literal("thinking.enabled"),
|
|
216
|
+
Type.Literal("thinking.effort"),
|
|
217
|
+
Type.Literal("thinking.budget"),
|
|
218
|
+
]),
|
|
219
|
+
omitWhenOff: Type.Optional(Type.Boolean()),
|
|
220
|
+
}),
|
|
221
|
+
]),
|
|
222
|
+
),
|
|
223
|
+
),
|
|
224
|
+
thinkingTokenBudgetField: Type.Optional(
|
|
225
|
+
Type.Union([
|
|
226
|
+
Type.Literal("thinking_token_budget"),
|
|
227
|
+
Type.Literal("thinking_budget"),
|
|
228
|
+
Type.Literal("thinking_budget_tokens"),
|
|
229
|
+
]),
|
|
230
|
+
),
|
|
231
|
+
supportsThinkingTokenBudget: Type.Optional(Type.Boolean()),
|
|
232
|
+
sendSessionAffinityHeaders: Type.Optional(Type.Boolean()),
|
|
233
|
+
allowEmptySignature: Type.Optional(Type.Boolean()),
|
|
234
|
+
supportsCacheControlOnTools: Type.Optional(Type.Boolean()),
|
|
235
|
+
forceAdaptiveThinking: Type.Optional(Type.Boolean()),
|
|
173
236
|
vercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),
|
|
174
237
|
extraBody: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
|
|
175
238
|
supportsStrictMode: Type.Optional(Type.Boolean()),
|
|
239
|
+
supportsMidConvoSystemMessages: Type.Optional(Type.Boolean()),
|
|
240
|
+
supportsMidConvoToolChanges: Type.Optional(Type.Boolean()),
|
|
241
|
+
supportsOpenAIGrammarTools: Type.Optional(Type.Boolean()),
|
|
242
|
+
supportsAdditionalTools: Type.Optional(Type.Boolean()),
|
|
243
|
+
supportsToolSearch: Type.Optional(Type.Boolean()),
|
|
244
|
+
supportsExplicitPromptCacheMode: Type.Optional(Type.Boolean()),
|
|
245
|
+
supportsCachedReasoningUpdates: Type.Optional(Type.Boolean()),
|
|
246
|
+
supportsWebSocketSteering: Type.Optional(Type.Boolean()),
|
|
247
|
+
supportsMaxOutputTokens: Type.Optional(Type.Boolean()),
|
|
176
248
|
toolStrictMode: Type.Optional(Type.Union([Type.Literal("all_strict"), Type.Literal("none")])),
|
|
177
249
|
});
|
|
178
250
|
|
|
@@ -184,6 +256,7 @@ const EffortSchema = Type.Union([
|
|
|
184
256
|
Type.Literal("high"),
|
|
185
257
|
Type.Literal("xhigh"),
|
|
186
258
|
Type.Literal("max"),
|
|
259
|
+
Type.Literal("ultra"),
|
|
187
260
|
]);
|
|
188
261
|
|
|
189
262
|
const ThinkingControlModeSchema = Type.Union([
|
|
@@ -213,6 +286,8 @@ const ModelDefinitionSchema = Type.Object({
|
|
|
213
286
|
name: Type.Optional(Type.String({ minLength: 1 })),
|
|
214
287
|
api: Type.Optional(
|
|
215
288
|
Type.Union([
|
|
289
|
+
Type.Literal("pi-messages"),
|
|
290
|
+
Type.Literal("mistral-conversations"),
|
|
216
291
|
Type.Literal("openai-completions"),
|
|
217
292
|
Type.Literal("openai-responses"),
|
|
218
293
|
Type.Literal("openai-codex-responses"),
|
|
@@ -232,10 +307,22 @@ const ModelDefinitionSchema = Type.Object({
|
|
|
232
307
|
output: Type.Number(),
|
|
233
308
|
cacheRead: Type.Number(),
|
|
234
309
|
cacheWrite: Type.Number(),
|
|
310
|
+
tiers: Type.Optional(
|
|
311
|
+
Type.Array(
|
|
312
|
+
Type.Object({
|
|
313
|
+
inputTokensAbove: Type.Number(),
|
|
314
|
+
input: Type.Number(),
|
|
315
|
+
output: Type.Number(),
|
|
316
|
+
cacheRead: Type.Number(),
|
|
317
|
+
cacheWrite: Type.Number(),
|
|
318
|
+
}),
|
|
319
|
+
),
|
|
320
|
+
),
|
|
235
321
|
}),
|
|
236
322
|
),
|
|
237
323
|
premiumMultiplier: Type.Optional(Type.Number()),
|
|
238
324
|
contextWindow: Type.Optional(Type.Number()),
|
|
325
|
+
maxInputTokens: Type.Optional(Type.Number()),
|
|
239
326
|
maxTokens: Type.Optional(Type.Number()),
|
|
240
327
|
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
241
328
|
compat: Type.Optional(OpenAICompatSchema),
|
|
@@ -254,10 +341,22 @@ const ModelOverrideSchema = Type.Object({
|
|
|
254
341
|
output: Type.Optional(Type.Number()),
|
|
255
342
|
cacheRead: Type.Optional(Type.Number()),
|
|
256
343
|
cacheWrite: Type.Optional(Type.Number()),
|
|
344
|
+
tiers: Type.Optional(
|
|
345
|
+
Type.Array(
|
|
346
|
+
Type.Object({
|
|
347
|
+
inputTokensAbove: Type.Number(),
|
|
348
|
+
input: Type.Number(),
|
|
349
|
+
output: Type.Number(),
|
|
350
|
+
cacheRead: Type.Number(),
|
|
351
|
+
cacheWrite: Type.Number(),
|
|
352
|
+
}),
|
|
353
|
+
),
|
|
354
|
+
),
|
|
257
355
|
}),
|
|
258
356
|
),
|
|
259
357
|
premiumMultiplier: Type.Optional(Type.Number()),
|
|
260
358
|
contextWindow: Type.Optional(Type.Number()),
|
|
359
|
+
maxInputTokens: Type.Optional(Type.Number()),
|
|
261
360
|
maxTokens: Type.Optional(Type.Number()),
|
|
262
361
|
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
263
362
|
compat: Type.Optional(OpenAICompatSchema),
|
|
@@ -329,6 +428,7 @@ interface ProviderValidationModel {
|
|
|
329
428
|
id: string;
|
|
330
429
|
api?: Api;
|
|
331
430
|
contextWindow?: number;
|
|
431
|
+
maxInputTokens?: number;
|
|
332
432
|
maxTokens?: number;
|
|
333
433
|
}
|
|
334
434
|
|
|
@@ -543,10 +643,12 @@ type OllamaDiscoveredModelMetadata = {
|
|
|
543
643
|
reasoning: boolean;
|
|
544
644
|
input: ("text" | "image")[];
|
|
545
645
|
contextWindow?: number;
|
|
646
|
+
maxInputTokens?: number;
|
|
546
647
|
};
|
|
547
648
|
|
|
548
649
|
type LlamaCppDiscoveredServerMetadata = {
|
|
549
650
|
contextWindow?: number;
|
|
651
|
+
maxInputTokens?: number;
|
|
550
652
|
input?: ("text" | "image")[];
|
|
551
653
|
};
|
|
552
654
|
|
|
@@ -699,6 +801,7 @@ function applyModelOverride(model: Model<Api>, override: ModelOverride): Model<A
|
|
|
699
801
|
if (override.thinking !== undefined) result.thinking = override.thinking as ThinkingConfig;
|
|
700
802
|
if (override.input !== undefined) result.input = override.input as ("text" | "image")[];
|
|
701
803
|
if (override.contextWindow !== undefined) result.contextWindow = override.contextWindow;
|
|
804
|
+
if (override.maxInputTokens !== undefined) result.maxInputTokens = override.maxInputTokens;
|
|
702
805
|
if (override.maxTokens !== undefined) result.maxTokens = override.maxTokens;
|
|
703
806
|
if (override.contextPromotionTarget !== undefined) result.contextPromotionTarget = override.contextPromotionTarget;
|
|
704
807
|
if (override.premiumMultiplier !== undefined) result.premiumMultiplier = override.premiumMultiplier;
|
|
@@ -708,6 +811,7 @@ function applyModelOverride(model: Model<Api>, override: ModelOverride): Model<A
|
|
|
708
811
|
output: override.cost.output ?? model.cost.output,
|
|
709
812
|
cacheRead: override.cost.cacheRead ?? model.cost.cacheRead,
|
|
710
813
|
cacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,
|
|
814
|
+
tiers: override.cost.tiers ?? model.cost.tiers,
|
|
711
815
|
};
|
|
712
816
|
}
|
|
713
817
|
if (override.headers) {
|
|
@@ -725,8 +829,9 @@ interface CustomModelDefinitionLike {
|
|
|
725
829
|
reasoning?: boolean;
|
|
726
830
|
thinking?: ThinkingConfig;
|
|
727
831
|
input?: ("text" | "image")[];
|
|
728
|
-
cost?:
|
|
832
|
+
cost?: import("@f5-sales-demo/pi-ai").ModelCost;
|
|
729
833
|
contextWindow?: number;
|
|
834
|
+
maxInputTokens?: number;
|
|
730
835
|
maxTokens?: number;
|
|
731
836
|
headers?: Record<string, string>;
|
|
732
837
|
compat?: Model<Api>["compat"];
|
|
@@ -747,8 +852,9 @@ type CustomModelOverlay = {
|
|
|
747
852
|
reasoning?: boolean;
|
|
748
853
|
thinking?: ThinkingConfig;
|
|
749
854
|
input?: ("text" | "image")[];
|
|
750
|
-
cost?:
|
|
855
|
+
cost?: import("@f5-sales-demo/pi-ai").ModelCost;
|
|
751
856
|
contextWindow?: number;
|
|
857
|
+
maxInputTokens?: number;
|
|
752
858
|
maxTokens?: number;
|
|
753
859
|
headers?: Record<string, string>;
|
|
754
860
|
compat?: Model<Api>["compat"];
|
|
@@ -795,6 +901,7 @@ function buildCustomModelOverlay(
|
|
|
795
901
|
input: modelDef.input as ("text" | "image")[] | undefined,
|
|
796
902
|
cost: modelDef.cost,
|
|
797
903
|
contextWindow: modelDef.contextWindow,
|
|
904
|
+
maxInputTokens: modelDef.maxInputTokens,
|
|
798
905
|
maxTokens: modelDef.maxTokens,
|
|
799
906
|
headers: mergeCustomModelHeaders(providerHeaders, modelDef.headers, authHeader, providerApiKey),
|
|
800
907
|
compat: mergeCompat(providerCompat, modelDef.compat),
|
|
@@ -825,6 +932,7 @@ function finalizeCustomModel(model: CustomModelOverlay, options: CustomModelBuil
|
|
|
825
932
|
thinking: resolvedModel.thinking,
|
|
826
933
|
input: input as ("text" | "image")[],
|
|
827
934
|
cost,
|
|
935
|
+
maxInputTokens: resolvedModel.maxInputTokens,
|
|
828
936
|
contextWindow: resolvedModel.contextWindow ?? (options.useDefaults ? 128000 : undefined),
|
|
829
937
|
maxTokens: resolvedModel.maxTokens ?? (options.useDefaults ? 16384 : undefined),
|
|
830
938
|
headers: resolvedModel.headers,
|
|
@@ -854,6 +962,7 @@ function getDisabledProviderIdsFromSettings(): Set<string> {
|
|
|
854
962
|
* Model registry - loads and manages models, resolves API keys via AuthStorage.
|
|
855
963
|
*/
|
|
856
964
|
export class ModelRegistry {
|
|
965
|
+
#operationCatalog: ReturnType<typeof createOperationCatalog>;
|
|
857
966
|
#models: Model<Api>[] = [];
|
|
858
967
|
#canonicalIndex: CanonicalModelIndex = { records: [], byId: new Map(), bySelector: new Map() };
|
|
859
968
|
#customProviderApiKeys: Map<string, string> = new Map();
|
|
@@ -907,6 +1016,9 @@ export class ModelRegistry {
|
|
|
907
1016
|
) {
|
|
908
1017
|
this.#modelsConfigFile = ModelsConfigFile.relocate(modelsPath);
|
|
909
1018
|
this.#cacheDbPath = modelsPath ? path.join(path.dirname(modelsPath), "models.db") : undefined;
|
|
1019
|
+
this.#operationCatalog = createOperationCatalog({
|
|
1020
|
+
cacheDbPath: this.#cacheDbPath ?? getModelDbPath(),
|
|
1021
|
+
});
|
|
910
1022
|
// Set up fallback resolver for custom provider API keys
|
|
911
1023
|
this.authStorage.setFallbackResolver(provider => {
|
|
912
1024
|
const keyConfig = this.#customProviderApiKeys.get(provider);
|
|
@@ -2066,6 +2178,7 @@ export class ModelRegistry {
|
|
|
2066
2178
|
const items: Array<{
|
|
2067
2179
|
id: string;
|
|
2068
2180
|
contextWindow?: number;
|
|
2181
|
+
maxInputTokens?: number;
|
|
2069
2182
|
context_window?: unknown;
|
|
2070
2183
|
max_input_tokens?: unknown;
|
|
2071
2184
|
max_output_tokens?: unknown;
|
|
@@ -2233,6 +2346,42 @@ export class ModelRegistry {
|
|
|
2233
2346
|
return this.#models;
|
|
2234
2347
|
}
|
|
2235
2348
|
|
|
2349
|
+
getImageModels(provider: string): ImageModel[] {
|
|
2350
|
+
return this.#operationCatalog
|
|
2351
|
+
.getImageModels(provider)
|
|
2352
|
+
.map(model => ({ ...model, baseUrl: this.#providerOverrides.get(provider)?.baseUrl ?? model.baseUrl }));
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
getClassifierModels(provider: string): ClassifierModel[] {
|
|
2356
|
+
return this.#operationCatalog
|
|
2357
|
+
.getClassifierModels(provider)
|
|
2358
|
+
.map(model => ({ ...model, baseUrl: this.#providerOverrides.get(provider)?.baseUrl ?? model.baseUrl }));
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
getAnyModels(provider: string): AnyModel[] {
|
|
2362
|
+
return [
|
|
2363
|
+
...this.#models.filter(model => model.provider === provider),
|
|
2364
|
+
...this.getImageModels(provider),
|
|
2365
|
+
...this.getClassifierModels(provider),
|
|
2366
|
+
];
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
async refreshOperationModels(provider: string, signal?: AbortSignal): Promise<void> {
|
|
2370
|
+
const apiKey = await this.getApiKeyForProvider(provider);
|
|
2371
|
+
await this.#operationCatalog.refresh(provider, {
|
|
2372
|
+
apiKey,
|
|
2373
|
+
signal,
|
|
2374
|
+
baseUrl: this.getProviderBaseUrl(provider),
|
|
2375
|
+
...(provider === "llama.cpp"
|
|
2376
|
+
? {
|
|
2377
|
+
modelIds: this.getAll()
|
|
2378
|
+
.filter(model => model.provider === provider)
|
|
2379
|
+
.map(model => model.id),
|
|
2380
|
+
}
|
|
2381
|
+
: {}),
|
|
2382
|
+
});
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2236
2385
|
#isModelAvailable(model: Model<Api>): boolean {
|
|
2237
2386
|
const disabledProviders = getDisabledProviderIdsFromSettings();
|
|
2238
2387
|
return (
|
|
@@ -2711,7 +2860,7 @@ export interface ProviderConfigInput {
|
|
|
2711
2860
|
reasoning: boolean;
|
|
2712
2861
|
thinking?: ThinkingConfig;
|
|
2713
2862
|
input: ("text" | "image")[];
|
|
2714
|
-
cost:
|
|
2863
|
+
cost: import("@f5-sales-demo/pi-ai").ModelCost;
|
|
2715
2864
|
contextWindow: number;
|
|
2716
2865
|
maxTokens: number;
|
|
2717
2866
|
headers?: Record<string, string>;
|
|
@@ -161,22 +161,21 @@ const DEFAULT_CYCLE_ORDER: string[] = ["smol", "default", "slow"];
|
|
|
161
161
|
/**
|
|
162
162
|
* Binary-baked default model role. Ships in the binary so a fresh install needs
|
|
163
163
|
* NO `~/.xcsh/agent/config.yml` — `/login` only supplies the (PII) proxy URL + key.
|
|
164
|
-
* GPT-
|
|
165
|
-
* Chat Completions route on LiteLLM. Keep the effort explicit in the role so returning
|
|
164
|
+
* GPT-6.1 Sol Medium is the default through the OpenAI Responses route on LiteLLM. Keep the effort explicit in the role so returning
|
|
166
165
|
* from a lower-effort role cannot inherit that role's effort.
|
|
167
166
|
*/
|
|
168
|
-
export const DEFAULT_MODEL_ROLE = "litellm/gpt-
|
|
167
|
+
export const DEFAULT_MODEL_ROLE = "litellm/gpt-6.1-sol:medium";
|
|
169
168
|
/** Fast role for lightweight work (commit messages, titles, memory summaries). */
|
|
170
169
|
const SMOL_MODEL_ROLE = "litellm/gpt-6-luna:low";
|
|
171
170
|
/**
|
|
172
171
|
* Baked role map for the current internal LiteLLM catalog. Sol handles slow and
|
|
173
|
-
* planning work, while Luna
|
|
172
|
+
* planning and default work, while Luna covers lightweight work.
|
|
174
173
|
*/
|
|
175
174
|
export const DEFAULT_MODEL_ROLES: Record<string, string> = {
|
|
176
175
|
default: DEFAULT_MODEL_ROLE,
|
|
177
176
|
smol: SMOL_MODEL_ROLE,
|
|
178
|
-
slow: "litellm/gpt-6-sol:high",
|
|
179
|
-
plan: "litellm/gpt-6-sol:high",
|
|
177
|
+
slow: "litellm/gpt-6.1-sol:high",
|
|
178
|
+
plan: "litellm/gpt-6.1-sol:high",
|
|
180
179
|
};
|
|
181
180
|
const EMPTY_MODEL_TAGS_RECORD: ModelTagsSettings = {};
|
|
182
181
|
export const DEFAULT_BASH_INTERCEPTOR_RULES: BashInterceptorRule[] = [
|
|
@@ -184,6 +184,9 @@ export interface CustomTool<TParams extends TSchema = TSchema, TDetails = any> {
|
|
|
184
184
|
hidden?: boolean;
|
|
185
185
|
/** If true, tool may stage deferred changes that require explicit resolve/discard. */
|
|
186
186
|
deferrable?: boolean;
|
|
187
|
+
/** Opt-in execution through the host's background job lifecycle. */
|
|
188
|
+
async?: boolean;
|
|
189
|
+
constrainedSampling?: import("@f5-sales-demo/pi-ai").Tool["constrainedSampling"];
|
|
187
190
|
/**
|
|
188
191
|
* Execute the tool.
|
|
189
192
|
* @param toolCallId - Unique ID for this tool call
|
|
@@ -313,6 +313,8 @@ export interface ToolSessionEvent {
|
|
|
313
313
|
* Tool definition for registerTool().
|
|
314
314
|
*/
|
|
315
315
|
export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = unknown> {
|
|
316
|
+
async?: boolean;
|
|
317
|
+
constrainedSampling?: import("@f5-sales-demo/pi-ai").Tool["constrainedSampling"];
|
|
316
318
|
/** Tool name (used in LLM tool calls) */
|
|
317
319
|
name: string;
|
|
318
320
|
/** Human-readable label for UI */
|
|
@@ -1323,7 +1325,7 @@ export interface ProviderModelConfig {
|
|
|
1323
1325
|
/** Supported input types. */
|
|
1324
1326
|
input: ("text" | "image")[];
|
|
1325
1327
|
/** Cost per million tokens. */
|
|
1326
|
-
cost:
|
|
1328
|
+
cost: import("@f5-sales-demo/pi-ai").ModelCost;
|
|
1327
1329
|
/** Premium Copilot requests charged per user-initiated request. */
|
|
1328
1330
|
premiumMultiplier?: number;
|
|
1329
1331
|
/** Maximum context window size in tokens. */
|