@f5xc-salesdemos/xcsh 16.0.0 → 17.0.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 +7 -7
- package/src/async/index.ts +1 -0
- package/src/async/job-manager.ts +43 -10
- package/src/async/support.ts +5 -0
- package/src/cli/list-models.ts +96 -57
- package/src/commit/agentic/tools/analyze-file.ts +1 -2
- package/src/commit/model-selection.ts +16 -13
- package/src/config/model-equivalence.ts +675 -0
- package/src/config/model-registry.ts +252 -176
- package/src/config/model-resolver.ts +314 -89
- package/src/config/settings-schema.ts +67 -70
- package/src/config/settings.ts +9 -2
- package/src/dap/session.ts +1 -1
- package/src/debug/log-formatting.ts +2 -2
- package/src/edit/index.ts +254 -89
- package/src/edit/modes/chunk.ts +342 -58
- package/src/edit/modes/hashline.ts +51 -26
- package/src/edit/modes/patch.ts +16 -10
- package/src/edit/modes/replace.ts +15 -7
- package/src/edit/renderer.ts +248 -94
- package/src/export/html/template.css +82 -0
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +614 -97
- package/src/extensibility/custom-tools/types.ts +0 -4
- package/src/extensibility/extensions/loader.ts +24 -4
- package/src/extensibility/extensions/runner.ts +2 -7
- package/src/extensibility/extensions/types.ts +9 -5
- package/src/internal-urls/docs-index.generated.ts +2 -2
- package/src/internal-urls/jobs-protocol.ts +2 -1
- package/src/ipy/executor.ts +449 -55
- package/src/ipy/kernel.ts +39 -13
- package/src/lsp/client.ts +59 -3
- package/src/lsp/index.ts +12 -9
- package/src/lsp/types.ts +6 -0
- package/src/lsp/utils.ts +26 -0
- package/src/main.ts +20 -18
- package/src/memories/index.ts +7 -6
- package/src/modes/acp/acp-agent.ts +6 -3
- package/src/modes/components/diff.ts +1 -1
- package/src/modes/components/model-selector.ts +224 -67
- package/src/modes/components/status-line/segments.ts +12 -0
- package/src/modes/components/status-line-segment-editor.ts +1 -0
- package/src/modes/components/tool-execution.ts +145 -75
- package/src/modes/components/welcome-checks.ts +23 -3
- package/src/modes/controllers/command-controller.ts +42 -1
- package/src/modes/controllers/extension-ui-controller.ts +31 -8
- package/src/modes/controllers/input-controller.ts +9 -3
- package/src/modes/controllers/selector-controller.ts +39 -133
- package/src/modes/interactive-mode.ts +7 -0
- package/src/modes/print-mode.ts +4 -0
- package/src/modes/prompt-action-autocomplete.ts +3 -5
- package/src/modes/rpc/rpc-mode.ts +8 -2
- package/src/modes/shared.ts +2 -2
- package/src/modes/theme/mermaid-cache.ts +5 -7
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/priority.json +8 -0
- package/src/prompts/agents/designer.md +1 -2
- package/src/prompts/tools/bash.md +16 -1
- package/src/prompts/tools/cancel-job.md +1 -1
- package/src/prompts/tools/chunk-edit.md +196 -169
- package/src/prompts/tools/hashline.md +11 -11
- package/src/prompts/tools/patch.md +10 -5
- package/src/prompts/tools/{await.md → poll.md} +1 -1
- package/src/prompts/tools/read-chunk.md +16 -4
- package/src/prompts/tools/read.md +9 -0
- package/src/prompts/tools/task.md +2 -2
- package/src/prompts/tools/vim.md +98 -0
- package/src/prompts/tools/write.md +1 -0
- package/src/sdk.ts +764 -829
- package/src/session/agent-session.ts +206 -47
- package/src/session/compaction/compaction.ts +1 -1
- package/src/session/session-manager.ts +50 -4
- package/src/session/session-storage.ts +3 -0
- package/src/slash-commands/builtin-registry.ts +17 -0
- package/src/task/executor.ts +7 -1
- package/src/task/index.ts +3 -5
- package/src/task/types.ts +2 -2
- package/src/tools/bash.ts +247 -138
- package/src/tools/browser.ts +84 -21
- package/src/tools/cancel-job.ts +2 -1
- package/src/tools/fetch.ts +1 -1
- package/src/tools/find.ts +46 -97
- package/src/tools/gemini-image.ts +1 -0
- package/src/tools/grep.ts +77 -8
- package/src/tools/index.ts +50 -21
- package/src/tools/inspect-image.ts +1 -1
- package/src/tools/{await-tool.ts → poll-tool.ts} +38 -31
- package/src/tools/python.ts +35 -4
- package/src/tools/read.ts +218 -1
- package/src/tools/render-utils.ts +1 -1
- package/src/tools/sqlite-reader.ts +623 -0
- package/src/tools/submit-result.ts +5 -2
- package/src/tools/todo-write.ts +8 -2
- package/src/tools/vim.ts +971 -0
- package/src/tools/write.ts +189 -3
- package/src/utils/commit-message-generator.ts +1 -0
- package/src/utils/edit-mode.ts +2 -1
- package/src/utils/git.ts +24 -1
- package/src/utils/image-resize.ts +73 -37
- package/src/utils/session-color.ts +55 -0
- package/src/utils/title-generator.ts +16 -7
- package/src/vim/buffer.ts +309 -0
- package/src/vim/commands.ts +382 -0
- package/src/vim/engine.ts +2426 -0
- package/src/vim/parser.ts +151 -0
- package/src/vim/render.ts +252 -0
- package/src/vim/types.ts +197 -0
- package/src/web/search/providers/codex.ts +21 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5xc-salesdemos/xcsh",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "17.0.1",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5xc-salesdemos/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
48
48
|
"@mozilla/readability": "^0.6",
|
|
49
|
-
"@f5xc-salesdemos/xcsh-stats": "
|
|
50
|
-
"@f5xc-salesdemos/pi-agent-core": "
|
|
51
|
-
"@f5xc-salesdemos/pi-ai": "
|
|
52
|
-
"@f5xc-salesdemos/pi-natives": "
|
|
53
|
-
"@f5xc-salesdemos/pi-tui": "
|
|
54
|
-
"@f5xc-salesdemos/pi-utils": "
|
|
49
|
+
"@f5xc-salesdemos/xcsh-stats": "17.0.1",
|
|
50
|
+
"@f5xc-salesdemos/pi-agent-core": "17.0.1",
|
|
51
|
+
"@f5xc-salesdemos/pi-ai": "17.0.1",
|
|
52
|
+
"@f5xc-salesdemos/pi-natives": "17.0.1",
|
|
53
|
+
"@f5xc-salesdemos/pi-tui": "17.0.1",
|
|
54
|
+
"@f5xc-salesdemos/pi-utils": "17.0.1",
|
|
55
55
|
"@sinclair/typebox": "^0.34",
|
|
56
56
|
"@xterm/headless": "^6.0",
|
|
57
57
|
"ajv": "^8.18",
|
package/src/async/index.ts
CHANGED
package/src/async/job-manager.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { logger
|
|
1
|
+
import { logger } from "@f5xc-salesdemos/pi-utils";
|
|
2
2
|
|
|
3
3
|
const DELIVERY_RETRY_BASE_MS = 500;
|
|
4
4
|
const DELIVERY_RETRY_MAX_MS = 30_000;
|
|
@@ -48,6 +48,7 @@ export class AsyncJobManager {
|
|
|
48
48
|
readonly #jobs = new Map<string, AsyncJob>();
|
|
49
49
|
readonly #deliveries: AsyncJobDelivery[] = [];
|
|
50
50
|
readonly #suppressedDeliveries = new Set<string>();
|
|
51
|
+
readonly #watchedJobs = new Set<string>();
|
|
51
52
|
readonly #evictionTimers = new Map<string, NodeJS.Timeout>();
|
|
52
53
|
readonly #onJobComplete: AsyncJobManagerOptions["onJobComplete"];
|
|
53
54
|
readonly #maxRunningJobs: number;
|
|
@@ -184,6 +185,25 @@ export class AsyncJobManager {
|
|
|
184
185
|
return this.#deliveries.length > 0;
|
|
185
186
|
}
|
|
186
187
|
|
|
188
|
+
watchJobs(jobIds: string[]): number {
|
|
189
|
+
const uniqueJobIds = Array.from(new Set(jobIds.map(id => id.trim()).filter(id => id.length > 0)));
|
|
190
|
+
for (const jobId of uniqueJobIds) {
|
|
191
|
+
this.#watchedJobs.add(jobId);
|
|
192
|
+
}
|
|
193
|
+
return uniqueJobIds.length;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
unwatchJobs(jobIds: string[]): number {
|
|
197
|
+
const uniqueJobIds = Array.from(new Set(jobIds.map(id => id.trim()).filter(id => id.length > 0)));
|
|
198
|
+
let removed = 0;
|
|
199
|
+
for (const jobId of uniqueJobIds) {
|
|
200
|
+
if (this.#watchedJobs.delete(jobId)) {
|
|
201
|
+
removed += 1;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return removed;
|
|
205
|
+
}
|
|
206
|
+
|
|
187
207
|
acknowledgeDeliveries(jobIds: string[]): number {
|
|
188
208
|
const uniqueJobIds = Array.from(new Set(jobIds.map(id => id.trim()).filter(id => id.length > 0)));
|
|
189
209
|
if (uniqueJobIds.length === 0) return 0;
|
|
@@ -196,7 +216,7 @@ export class AsyncJobManager {
|
|
|
196
216
|
this.#deliveries.splice(
|
|
197
217
|
0,
|
|
198
218
|
this.#deliveries.length,
|
|
199
|
-
...this.#deliveries.filter(delivery => !this
|
|
219
|
+
...this.#deliveries.filter(delivery => !this.isDeliverySuppressed(delivery.jobId)),
|
|
200
220
|
);
|
|
201
221
|
return before - this.#deliveries.length;
|
|
202
222
|
}
|
|
@@ -254,12 +274,21 @@ export class AsyncJobManager {
|
|
|
254
274
|
this.#jobs.clear();
|
|
255
275
|
this.#deliveries.length = 0;
|
|
256
276
|
this.#suppressedDeliveries.clear();
|
|
277
|
+
this.#watchedJobs.clear();
|
|
257
278
|
return drained;
|
|
258
279
|
}
|
|
259
280
|
|
|
260
281
|
#resolveJobId(preferredId?: string): string {
|
|
261
|
-
|
|
262
|
-
|
|
282
|
+
preferredId = preferredId?.trim();
|
|
283
|
+
if (!preferredId) {
|
|
284
|
+
let candidate = 1;
|
|
285
|
+
while (true) {
|
|
286
|
+
const id = `bg_${candidate}`;
|
|
287
|
+
if (!this.#jobs.has(id)) {
|
|
288
|
+
return id;
|
|
289
|
+
}
|
|
290
|
+
candidate += 1;
|
|
291
|
+
}
|
|
263
292
|
}
|
|
264
293
|
|
|
265
294
|
const base = preferredId.trim();
|
|
@@ -278,6 +307,7 @@ export class AsyncJobManager {
|
|
|
278
307
|
if (this.#retentionMs <= 0) {
|
|
279
308
|
this.#jobs.delete(jobId);
|
|
280
309
|
this.#suppressedDeliveries.delete(jobId);
|
|
310
|
+
this.#watchedJobs.delete(jobId);
|
|
281
311
|
return;
|
|
282
312
|
}
|
|
283
313
|
const existing = this.#evictionTimers.get(jobId);
|
|
@@ -288,6 +318,7 @@ export class AsyncJobManager {
|
|
|
288
318
|
this.#evictionTimers.delete(jobId);
|
|
289
319
|
this.#jobs.delete(jobId);
|
|
290
320
|
this.#suppressedDeliveries.delete(jobId);
|
|
321
|
+
this.#watchedJobs.delete(jobId);
|
|
291
322
|
}, this.#retentionMs);
|
|
292
323
|
timer.unref();
|
|
293
324
|
this.#evictionTimers.set(jobId, timer);
|
|
@@ -300,12 +331,13 @@ export class AsyncJobManager {
|
|
|
300
331
|
this.#evictionTimers.clear();
|
|
301
332
|
}
|
|
302
333
|
|
|
303
|
-
|
|
304
|
-
return this.#suppressedDeliveries.has(jobId);
|
|
334
|
+
isDeliverySuppressed(jobId: string): boolean {
|
|
335
|
+
return this.#suppressedDeliveries.has(jobId) || this.#watchedJobs.has(jobId);
|
|
305
336
|
}
|
|
306
337
|
|
|
307
338
|
#enqueueDelivery(jobId: string, text: string): void {
|
|
308
|
-
if
|
|
339
|
+
// Skip delivery if already acknowledged
|
|
340
|
+
if (this.isDeliverySuppressed(jobId)) {
|
|
309
341
|
return;
|
|
310
342
|
}
|
|
311
343
|
this.#deliveries.push({
|
|
@@ -337,7 +369,7 @@ export class AsyncJobManager {
|
|
|
337
369
|
async #runDeliveryLoop(): Promise<void> {
|
|
338
370
|
while (this.#deliveries.length > 0) {
|
|
339
371
|
const delivery = this.#deliveries[0];
|
|
340
|
-
if (this
|
|
372
|
+
if (this.isDeliverySuppressed(delivery.jobId)) {
|
|
341
373
|
this.#deliveries.shift();
|
|
342
374
|
continue;
|
|
343
375
|
}
|
|
@@ -348,7 +380,8 @@ export class AsyncJobManager {
|
|
|
348
380
|
if (this.#deliveries[0] !== delivery) {
|
|
349
381
|
continue;
|
|
350
382
|
}
|
|
351
|
-
|
|
383
|
+
// Check again after sleep
|
|
384
|
+
if (this.isDeliverySuppressed(delivery.jobId)) {
|
|
352
385
|
this.#deliveries.shift();
|
|
353
386
|
continue;
|
|
354
387
|
}
|
|
@@ -361,7 +394,7 @@ export class AsyncJobManager {
|
|
|
361
394
|
delivery.lastError = error instanceof Error ? error.message : String(error);
|
|
362
395
|
delivery.nextAttemptAt = Date.now() + this.#getRetryDelay(delivery.attempt);
|
|
363
396
|
this.#deliveries.shift();
|
|
364
|
-
if (!this
|
|
397
|
+
if (!this.isDeliverySuppressed(delivery.jobId)) {
|
|
365
398
|
this.#deliveries.push(delivery);
|
|
366
399
|
}
|
|
367
400
|
logger.warn("Async job completion delivery failed", {
|
package/src/cli/list-models.ts
CHANGED
|
@@ -6,6 +6,45 @@ import { formatNumber } from "@f5xc-salesdemos/pi-utils";
|
|
|
6
6
|
import type { ModelRegistry } from "../config/model-registry";
|
|
7
7
|
import { fuzzyFilter } from "../utils/fuzzy";
|
|
8
8
|
|
|
9
|
+
interface ProviderRow {
|
|
10
|
+
provider: string;
|
|
11
|
+
model: string;
|
|
12
|
+
context: string;
|
|
13
|
+
maxOut: string;
|
|
14
|
+
thinking: string;
|
|
15
|
+
images: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface CanonicalRow {
|
|
19
|
+
canonical: string;
|
|
20
|
+
selected: string;
|
|
21
|
+
variants: string;
|
|
22
|
+
context: string;
|
|
23
|
+
maxOut: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function writeLine(line = ""): void {
|
|
27
|
+
process.stdout.write(`${line}\n`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function renderTable<T extends Record<string, string>>(rows: T[], headers: T): void {
|
|
31
|
+
const widths = Object.fromEntries(
|
|
32
|
+
Object.keys(headers).map(key => [key, Math.max(headers[key]!.length, ...rows.map(row => row[key]!.length))]),
|
|
33
|
+
) as Record<keyof T, number>;
|
|
34
|
+
|
|
35
|
+
const headerLine = Object.keys(headers)
|
|
36
|
+
.map(key => headers[key as keyof T]!.padEnd(widths[key as keyof T]))
|
|
37
|
+
.join(" ");
|
|
38
|
+
writeLine(headerLine);
|
|
39
|
+
|
|
40
|
+
for (const row of rows) {
|
|
41
|
+
const line = Object.keys(headers)
|
|
42
|
+
.map(key => row[key as keyof T]!.padEnd(widths[key as keyof T]))
|
|
43
|
+
.join(" ");
|
|
44
|
+
writeLine(line);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
9
48
|
/**
|
|
10
49
|
* List available models, optionally filtered by search pattern
|
|
11
50
|
*/
|
|
@@ -13,77 +52,77 @@ export async function listModels(modelRegistry: ModelRegistry, searchPattern?: s
|
|
|
13
52
|
const models = modelRegistry.getAvailable();
|
|
14
53
|
|
|
15
54
|
if (models.length === 0) {
|
|
16
|
-
|
|
55
|
+
writeLine("No models available. Set API keys in environment variables.");
|
|
17
56
|
return;
|
|
18
57
|
}
|
|
19
58
|
|
|
20
|
-
// Apply fuzzy filter if search pattern provided
|
|
21
59
|
let filteredModels: Model<Api>[] = models;
|
|
22
60
|
if (searchPattern) {
|
|
23
|
-
filteredModels = fuzzyFilter(models, searchPattern,
|
|
61
|
+
filteredModels = fuzzyFilter(models, searchPattern, model => `${model.provider} ${model.id}`);
|
|
24
62
|
}
|
|
25
63
|
|
|
26
|
-
|
|
27
|
-
|
|
64
|
+
const filteredCanonical = modelRegistry
|
|
65
|
+
.getCanonicalModels({ availableOnly: true, candidates: filteredModels })
|
|
66
|
+
.map(record => {
|
|
67
|
+
const selected = modelRegistry.resolveCanonicalModel(record.id, {
|
|
68
|
+
availableOnly: true,
|
|
69
|
+
candidates: filteredModels,
|
|
70
|
+
});
|
|
71
|
+
if (!selected) return undefined;
|
|
72
|
+
return {
|
|
73
|
+
canonical: record.id,
|
|
74
|
+
selected: `${selected.provider}/${selected.id}`,
|
|
75
|
+
variants: String(record.variants.length),
|
|
76
|
+
context: formatNumber(selected.contextWindow),
|
|
77
|
+
maxOut: formatNumber(selected.maxTokens),
|
|
78
|
+
} satisfies CanonicalRow;
|
|
79
|
+
})
|
|
80
|
+
.filter((row): row is CanonicalRow => row !== undefined)
|
|
81
|
+
.sort((left, right) => left.canonical.localeCompare(right.canonical));
|
|
82
|
+
|
|
83
|
+
if (filteredModels.length === 0 && filteredCanonical.length === 0) {
|
|
84
|
+
writeLine(`No models matching "${searchPattern}"`);
|
|
28
85
|
return;
|
|
29
86
|
}
|
|
30
87
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const providerCmp = a.provider.localeCompare(b.provider);
|
|
88
|
+
filteredModels.sort((left, right) => {
|
|
89
|
+
const providerCmp = left.provider.localeCompare(right.provider);
|
|
34
90
|
if (providerCmp !== 0) return providerCmp;
|
|
35
|
-
return
|
|
91
|
+
return left.id.localeCompare(right.id);
|
|
36
92
|
});
|
|
37
93
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}));
|
|
94
|
+
const providerRows = filteredModels.map(model => ({
|
|
95
|
+
provider: model.provider,
|
|
96
|
+
model: model.id,
|
|
97
|
+
context: formatNumber(model.contextWindow),
|
|
98
|
+
maxOut: formatNumber(model.maxTokens),
|
|
99
|
+
thinking: model.thinking ? getSupportedEfforts(model).join(",") : model.reasoning ? "yes" : "-",
|
|
100
|
+
images: model.input.includes("image") ? "yes" : "no",
|
|
101
|
+
})) satisfies ProviderRow[];
|
|
47
102
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
maxOut: Math.max(headers.maxOut.length, ...rows.map(r => r.maxOut.length)),
|
|
62
|
-
thinking: Math.max(headers.thinking.length, ...rows.map(r => r.thinking.length)),
|
|
63
|
-
images: Math.max(headers.images.length, ...rows.map(r => r.images.length)),
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
// Print header
|
|
67
|
-
const headerLine = [
|
|
68
|
-
headers.provider.padEnd(widths.provider),
|
|
69
|
-
headers.model.padEnd(widths.model),
|
|
70
|
-
headers.context.padEnd(widths.context),
|
|
71
|
-
headers.maxOut.padEnd(widths.maxOut),
|
|
72
|
-
headers.thinking.padEnd(widths.thinking),
|
|
73
|
-
headers.images.padEnd(widths.images),
|
|
74
|
-
].join(" ");
|
|
75
|
-
console.log(headerLine);
|
|
103
|
+
if (filteredCanonical.length > 0) {
|
|
104
|
+
writeLine("Canonical models");
|
|
105
|
+
renderTable(filteredCanonical, {
|
|
106
|
+
canonical: "canonical",
|
|
107
|
+
selected: "selected",
|
|
108
|
+
variants: "variants",
|
|
109
|
+
context: "context",
|
|
110
|
+
maxOut: "max-out",
|
|
111
|
+
});
|
|
112
|
+
if (providerRows.length > 0) {
|
|
113
|
+
writeLine();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
76
116
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
console.log(line);
|
|
117
|
+
if (providerRows.length > 0) {
|
|
118
|
+
writeLine("Provider models");
|
|
119
|
+
renderTable(providerRows, {
|
|
120
|
+
provider: "provider",
|
|
121
|
+
model: "model",
|
|
122
|
+
context: "context",
|
|
123
|
+
maxOut: "max-out",
|
|
124
|
+
thinking: "thinking",
|
|
125
|
+
images: "images",
|
|
126
|
+
});
|
|
88
127
|
}
|
|
89
128
|
}
|
|
@@ -43,7 +43,6 @@ function buildToolSession(
|
|
|
43
43
|
settings: options.settings,
|
|
44
44
|
authStorage: options.authStorage,
|
|
45
45
|
modelRegistry: options.modelRegistry,
|
|
46
|
-
searchDb: ctx.searchDb,
|
|
47
46
|
};
|
|
48
47
|
}
|
|
49
48
|
|
|
@@ -79,7 +78,7 @@ export function createAnalyzeFileTool(options: {
|
|
|
79
78
|
});
|
|
80
79
|
const taskParams: TaskParams = {
|
|
81
80
|
agent: "quick_task",
|
|
82
|
-
schema: analyzeFileOutputSchema,
|
|
81
|
+
schema: JSON.stringify(analyzeFileOutputSchema),
|
|
83
82
|
tasks,
|
|
84
83
|
};
|
|
85
84
|
return taskTool.execute(toolCallId, taskParams, signal, onUpdate);
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@f5xc-salesdemos/pi-agent-core";
|
|
2
2
|
import type { Api, Model } from "@f5xc-salesdemos/pi-ai";
|
|
3
3
|
import { MODEL_ROLE_IDS } from "../config/model-registry";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
type ModelLookupRegistry,
|
|
6
|
+
parseModelPattern,
|
|
7
|
+
resolveModelRoleValue,
|
|
8
|
+
resolveRoleSelection,
|
|
9
|
+
} from "../config/model-resolver";
|
|
5
10
|
import type { Settings } from "../config/settings";
|
|
6
11
|
import MODEL_PRIO from "../priority.json" with { type: "json" };
|
|
7
12
|
|
|
@@ -11,19 +16,20 @@ export interface ResolvedCommitModel {
|
|
|
11
16
|
thinkingLevel?: ThinkingLevel;
|
|
12
17
|
}
|
|
13
18
|
|
|
19
|
+
type CommitModelRegistry = ModelLookupRegistry & {
|
|
20
|
+
getApiKey: (model: Model<Api>) => Promise<string | undefined>;
|
|
21
|
+
};
|
|
22
|
+
|
|
14
23
|
export async function resolvePrimaryModel(
|
|
15
24
|
override: string | undefined,
|
|
16
25
|
settings: Settings,
|
|
17
|
-
modelRegistry:
|
|
18
|
-
getAvailable: () => Model<Api>[];
|
|
19
|
-
getApiKey: (model: Model<Api>) => Promise<string | undefined>;
|
|
20
|
-
},
|
|
26
|
+
modelRegistry: CommitModelRegistry,
|
|
21
27
|
): Promise<ResolvedCommitModel> {
|
|
22
28
|
const available = modelRegistry.getAvailable();
|
|
23
29
|
const matchPreferences = { usageOrder: settings.getStorage()?.getModelUsageOrder() };
|
|
24
30
|
const resolved = override
|
|
25
|
-
? resolveModelRoleValue(override, available, { settings, matchPreferences })
|
|
26
|
-
: resolveRoleSelection(["commit", "smol", ...MODEL_ROLE_IDS], settings, available);
|
|
31
|
+
? resolveModelRoleValue(override, available, { settings, matchPreferences, modelRegistry })
|
|
32
|
+
: resolveRoleSelection(["commit", "smol", ...MODEL_ROLE_IDS], settings, available, modelRegistry);
|
|
27
33
|
const model = resolved?.model;
|
|
28
34
|
if (!model) {
|
|
29
35
|
throw new Error("No model available for commit generation");
|
|
@@ -37,15 +43,12 @@ export async function resolvePrimaryModel(
|
|
|
37
43
|
|
|
38
44
|
export async function resolveSmolModel(
|
|
39
45
|
settings: Settings,
|
|
40
|
-
modelRegistry:
|
|
41
|
-
getAvailable: () => Model<Api>[];
|
|
42
|
-
getApiKey: (model: Model<Api>) => Promise<string | undefined>;
|
|
43
|
-
},
|
|
46
|
+
modelRegistry: CommitModelRegistry,
|
|
44
47
|
fallbackModel: Model<Api>,
|
|
45
48
|
fallbackApiKey: string,
|
|
46
49
|
): Promise<ResolvedCommitModel> {
|
|
47
50
|
const available = modelRegistry.getAvailable();
|
|
48
|
-
const resolvedSmol = resolveRoleSelection(["smol"], settings, available);
|
|
51
|
+
const resolvedSmol = resolveRoleSelection(["smol"], settings, available, modelRegistry);
|
|
49
52
|
if (resolvedSmol?.model) {
|
|
50
53
|
const apiKey = await modelRegistry.getApiKey(resolvedSmol.model);
|
|
51
54
|
if (apiKey) return { model: resolvedSmol.model, apiKey, thinkingLevel: resolvedSmol.thinkingLevel };
|
|
@@ -53,7 +56,7 @@ export async function resolveSmolModel(
|
|
|
53
56
|
|
|
54
57
|
const matchPreferences = { usageOrder: settings.getStorage()?.getModelUsageOrder() };
|
|
55
58
|
for (const pattern of MODEL_PRIO.smol) {
|
|
56
|
-
const candidate = parseModelPattern(pattern, available, matchPreferences).model;
|
|
59
|
+
const candidate = parseModelPattern(pattern, available, matchPreferences, { modelRegistry }).model;
|
|
57
60
|
if (!candidate) continue;
|
|
58
61
|
const apiKey = await modelRegistry.getApiKey(candidate);
|
|
59
62
|
if (apiKey) return { model: candidate, apiKey };
|