@vedmalex/ai-connect 0.2.1 → 0.5.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 +130 -67
- package/dist/browser/index.js +114 -104
- package/dist/browser/index.js.map +2 -2
- package/dist/bun/index.js +338 -412
- package/dist/bun/index.js.map +3 -3
- package/dist/bun/local.js +330 -374
- package/dist/bun/local.js.map +3 -3
- package/dist/node/index.js +338 -412
- package/dist/node/index.js.map +3 -3
- package/dist/node/local.js +330 -374
- package/dist/node/local.js.map +3 -3
- package/dist/types/acp-presets.d.ts.map +1 -1
- package/dist/types/acp.d.ts.map +1 -1
- package/dist/types/catalog.d.ts.map +1 -1
- package/dist/types/cli-presets.d.ts.map +1 -1
- package/dist/types/cli.d.ts +8 -1
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/default-handlers.d.ts +3 -1
- package/dist/types/default-handlers.d.ts.map +1 -1
- package/dist/types/local-handlers.d.ts.map +1 -1
- package/dist/types/model-reference.d.ts +19 -1
- package/dist/types/model-reference.d.ts.map +1 -1
- package/dist/types/types.d.ts +86 -5
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/node/index.js
CHANGED
|
@@ -219,11 +219,7 @@ function normalizeTransport(providerId, input) {
|
|
|
219
219
|
...selector.whereEquals !== void 0 ? { whereEquals: selector.whereEquals } : {}
|
|
220
220
|
};
|
|
221
221
|
};
|
|
222
|
-
const
|
|
223
|
-
if (!descriptor.cli?.parser) {
|
|
224
|
-
return void 0;
|
|
225
|
-
}
|
|
226
|
-
const cliParser = descriptor.cli.parser;
|
|
222
|
+
const normalizeCliParser = (cliParser) => {
|
|
227
223
|
if (cliParser.kind === "json") {
|
|
228
224
|
assert(
|
|
229
225
|
cliParser.textPath.trim().length > 0,
|
|
@@ -236,13 +232,22 @@ function normalizeTransport(providerId, input) {
|
|
|
236
232
|
...cliParser.usagePath?.trim() ? { usagePath: cliParser.usagePath.trim() } : {}
|
|
237
233
|
};
|
|
238
234
|
}
|
|
235
|
+
if (cliParser.kind === "text") {
|
|
236
|
+
return {
|
|
237
|
+
kind: "text",
|
|
238
|
+
// Default trim=true, stripAnsi=false; only persist explicit overrides.
|
|
239
|
+
...cliParser.trim === false ? { trim: false } : {},
|
|
240
|
+
...cliParser.stripAnsi === true ? { stripAnsi: true } : {}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
239
243
|
return {
|
|
240
244
|
kind: "jsonl",
|
|
241
245
|
text: normalizeSelector(cliParser.text, "text"),
|
|
242
246
|
...cliParser.error ? { error: normalizeSelector(cliParser.error, "error") } : {},
|
|
243
247
|
...cliParser.usage ? { usage: normalizeSelector(cliParser.usage, "usage") } : {}
|
|
244
248
|
};
|
|
245
|
-
}
|
|
249
|
+
};
|
|
250
|
+
const parser = descriptor.cli?.parser ? normalizeCliParser(descriptor.cli.parser) : void 0;
|
|
246
251
|
const normalized = {
|
|
247
252
|
...descriptor.cli.preset ? { preset: descriptor.cli.preset } : {},
|
|
248
253
|
...descriptor.cli.argsTemplate ? {
|
|
@@ -254,11 +259,13 @@ function normalizeTransport(providerId, input) {
|
|
|
254
259
|
if (!descriptor.cli?.discovery) {
|
|
255
260
|
return void 0;
|
|
256
261
|
}
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
+
const explicitVia = descriptor.cli.discovery.via;
|
|
263
|
+
if (explicitVia !== void 0) {
|
|
264
|
+
assert(
|
|
265
|
+
explicitVia === "none" || explicitVia === "acp" || explicitVia === "command" || explicitVia === "static",
|
|
266
|
+
`Unsupported CLI discovery mode "${String(explicitVia)}" for provider "${providerId}".`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
262
269
|
const launch = descriptor.cli.discovery.acp?.launch ? (() => {
|
|
263
270
|
const contextMode = descriptor.cli.discovery?.acp?.launch?.contextMode ?? "workspace";
|
|
264
271
|
const skillsMode = descriptor.cli.discovery?.acp?.launch?.skillsMode ?? "default";
|
|
@@ -279,7 +286,7 @@ function normalizeTransport(providerId, input) {
|
|
|
279
286
|
methodId: descriptor.cli.discovery.acp.auth.methodId.trim(),
|
|
280
287
|
params: descriptor.cli.discovery.acp.auth.params ?? {}
|
|
281
288
|
} : void 0;
|
|
282
|
-
const acp =
|
|
289
|
+
const acp = descriptor.cli.discovery.acp ? {
|
|
283
290
|
...descriptor.cli.discovery.acp?.providerId?.trim() ? { providerId: descriptor.cli.discovery.acp.providerId.trim() } : {},
|
|
284
291
|
...descriptor.cli.discovery.acp?.transportId?.trim() ? {
|
|
285
292
|
transportId: descriptor.cli.discovery.acp.transportId.trim()
|
|
@@ -287,9 +294,55 @@ function normalizeTransport(providerId, input) {
|
|
|
287
294
|
...auth ? { auth } : {},
|
|
288
295
|
...launch ? { launch } : {}
|
|
289
296
|
} : void 0;
|
|
297
|
+
const commandInput = descriptor.cli.discovery.command;
|
|
298
|
+
const command = commandInput ? (() => {
|
|
299
|
+
assert(
|
|
300
|
+
Array.isArray(commandInput.argsTemplate) && commandInput.argsTemplate.length > 0,
|
|
301
|
+
`CLI discovery command.argsTemplate must be a non-empty array for provider "${providerId}".`
|
|
302
|
+
);
|
|
303
|
+
const cmdParserInput = commandInput.parser ?? { kind: "text" };
|
|
304
|
+
const cmdParser = cmdParserInput.kind === "text" ? {
|
|
305
|
+
kind: "text",
|
|
306
|
+
...cmdParserInput.trim === false ? { trim: false } : {},
|
|
307
|
+
...cmdParserInput.stripAnsi === true ? { stripAnsi: true } : {}
|
|
308
|
+
} : { kind: cmdParserInput.kind };
|
|
309
|
+
if (cmdParser.kind !== "text") {
|
|
310
|
+
assert(
|
|
311
|
+
Boolean(commandInput.models?.idPath?.trim()),
|
|
312
|
+
`CLI discovery command.models.idPath is required for a ${cmdParser.kind} parser for provider "${providerId}".`
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
const m = commandInput.models;
|
|
316
|
+
const models = m?.idPath?.trim() ? {
|
|
317
|
+
...m.path?.trim() ? { path: m.path.trim() } : {},
|
|
318
|
+
idPath: m.idPath.trim(),
|
|
319
|
+
...m.namePath?.trim() ? { namePath: m.namePath.trim() } : {},
|
|
320
|
+
...m.descriptionPath?.trim() ? { descriptionPath: m.descriptionPath.trim() } : {},
|
|
321
|
+
...m.contextLengthPath?.trim() ? { contextLengthPath: m.contextLengthPath.trim() } : {}
|
|
322
|
+
} : void 0;
|
|
323
|
+
return {
|
|
324
|
+
...commandInput.command?.trim() ? { command: commandInput.command.trim() } : {},
|
|
325
|
+
argsTemplate: commandInput.argsTemplate.map((part) => String(part)),
|
|
326
|
+
parser: cmdParser,
|
|
327
|
+
...models ? { models } : {}
|
|
328
|
+
};
|
|
329
|
+
})() : void 0;
|
|
330
|
+
assert(
|
|
331
|
+
explicitVia !== "command" || command !== void 0,
|
|
332
|
+
`CLI discovery via:"command" requires a discovery.command block for provider "${providerId}".`
|
|
333
|
+
);
|
|
334
|
+
const fallback = descriptor.cli.discovery.fallback;
|
|
335
|
+
if (fallback !== void 0) {
|
|
336
|
+
assert(
|
|
337
|
+
fallback === "static" || fallback === "none",
|
|
338
|
+
`Unsupported CLI discovery fallback "${String(fallback)}" for provider "${providerId}".`
|
|
339
|
+
);
|
|
340
|
+
}
|
|
290
341
|
return {
|
|
291
|
-
via,
|
|
292
|
-
...acp ? { acp } : {}
|
|
342
|
+
...explicitVia !== void 0 ? { via: explicitVia } : {},
|
|
343
|
+
...acp ? { acp } : {},
|
|
344
|
+
...command ? { command } : {},
|
|
345
|
+
...fallback !== void 0 ? { fallback } : {}
|
|
293
346
|
};
|
|
294
347
|
})();
|
|
295
348
|
return {
|
|
@@ -330,7 +383,7 @@ function normalizeTransport(providerId, input) {
|
|
|
330
383
|
};
|
|
331
384
|
}
|
|
332
385
|
if (descriptor.kind === "cli") {
|
|
333
|
-
const inferredId2 = providerId === "anthropic" ? "claude-cli" : providerId === "openclaude" ? "openclaude-cli" : providerId === "openai" ? "codex-cli" : providerId === "
|
|
386
|
+
const inferredId2 = providerId === "anthropic" ? "claude-cli" : providerId === "openclaude" ? "openclaude-cli" : providerId === "openai" ? "codex-cli" : providerId === "pi" ? "pi-cli" : "cli";
|
|
334
387
|
return {
|
|
335
388
|
kind: "cli",
|
|
336
389
|
id: descriptor.id?.trim() || inferredId2,
|
|
@@ -347,7 +400,7 @@ function normalizeTransport(providerId, input) {
|
|
|
347
400
|
...descriptor.baseUrl?.trim() ? { baseUrl: descriptor.baseUrl.trim() } : {}
|
|
348
401
|
};
|
|
349
402
|
}
|
|
350
|
-
const inferredId = providerId === "anthropic" ? "claude-code-acp" : providerId === "openai" ? "codex-acp" :
|
|
403
|
+
const inferredId = providerId === "anthropic" ? "claude-code-acp" : providerId === "openai" ? "codex-acp" : "acp";
|
|
351
404
|
const normalizedLaunch = descriptor.launch ? (() => {
|
|
352
405
|
const contextMode = descriptor.launch?.contextMode ?? "workspace";
|
|
353
406
|
const skillsMode = descriptor.launch?.skillsMode ?? "default";
|
|
@@ -1585,18 +1638,14 @@ var MODEL_REFERENCE = {
|
|
|
1585
1638
|
key: "gemini-3.1-flash-lite",
|
|
1586
1639
|
contextLength: 1048576
|
|
1587
1640
|
},
|
|
1641
|
+
"gemini-3.1-pro": { key: "gemini-3.1-pro", contextLength: 1048576 },
|
|
1588
1642
|
"gemini-3-pro": { key: "gemini-3-pro", contextLength: 2097152 },
|
|
1589
1643
|
"auto-gemini-3": { key: "auto-gemini-3", contextLength: 1048576 },
|
|
1590
1644
|
"gemini-2.5-flash": { key: "gemini-2.5-flash", contextLength: 1048576 },
|
|
1591
1645
|
"gemini-2.5-pro": { key: "gemini-2.5-pro", contextLength: 2097152 },
|
|
1592
1646
|
"gemini-2.0-flash": { key: "gemini-2.0-flash", contextLength: 1048576 },
|
|
1593
1647
|
"gemini-1.5-flash": { key: "gemini-1.5-flash", contextLength: 1048576 },
|
|
1594
|
-
"gemini-1.5-pro": { key: "gemini-1.5-pro", contextLength: 2097152 }
|
|
1595
|
-
// --- Qwen (catalog: qwen3-coder-plus) ---
|
|
1596
|
-
"qwen3-coder-plus": { key: "qwen3-coder-plus", contextLength: 1048576 },
|
|
1597
|
-
"qwen3-coder": { key: "qwen3-coder", contextLength: 262144 },
|
|
1598
|
-
"qwen-max": { key: "qwen-max", contextLength: 32768 },
|
|
1599
|
-
"qwen-plus": { key: "qwen-plus", contextLength: 131072 }
|
|
1648
|
+
"gemini-1.5-pro": { key: "gemini-1.5-pro", contextLength: 2097152 }
|
|
1600
1649
|
};
|
|
1601
1650
|
function normalizeModelKey(model) {
|
|
1602
1651
|
let key = model.trim().toLowerCase();
|
|
@@ -1730,6 +1779,25 @@ function resolveModelContextWindow(input) {
|
|
|
1730
1779
|
const fallback = isUsableContextLength(input.defaultContextWindow) ? input.defaultContextWindow : DEFAULT_CONTEXT_WINDOW;
|
|
1731
1780
|
return { contextWindow: fallback, source: "default" };
|
|
1732
1781
|
}
|
|
1782
|
+
function fillConfiguredContextLength(route, models) {
|
|
1783
|
+
if (!isUsableContextLength(route.contextWindow)) {
|
|
1784
|
+
return models;
|
|
1785
|
+
}
|
|
1786
|
+
const configured = route.contextWindow;
|
|
1787
|
+
return models.map((entry) => {
|
|
1788
|
+
if (isUsableContextLength(entry.contextLength)) {
|
|
1789
|
+
return entry;
|
|
1790
|
+
}
|
|
1791
|
+
if (route.model !== void 0 && entry.modelId !== route.model) {
|
|
1792
|
+
return entry;
|
|
1793
|
+
}
|
|
1794
|
+
return {
|
|
1795
|
+
...entry,
|
|
1796
|
+
contextLength: configured,
|
|
1797
|
+
metadata: { ...entry.metadata ?? {}, contextWindowSource: "configured" }
|
|
1798
|
+
};
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1733
1801
|
function modelContextCacheKey(input) {
|
|
1734
1802
|
if (typeof input === "string") {
|
|
1735
1803
|
return { key: `::${input}`, model: input };
|
|
@@ -4726,18 +4794,19 @@ function canonicalGeminiImageModelId(modelId) {
|
|
|
4726
4794
|
}
|
|
4727
4795
|
function buildModelCatalog(route, availableModels, currentModelId) {
|
|
4728
4796
|
const requestedModelId = route.model;
|
|
4729
|
-
const
|
|
4797
|
+
const filledModels = fillConfiguredContextLength(route, availableModels);
|
|
4798
|
+
const requestedModelAdvertised = filledModels.some(
|
|
4730
4799
|
(model) => model.modelId === requestedModelId
|
|
4731
4800
|
);
|
|
4732
4801
|
const canonicalModelId = route.provider === "gemini" ? canonicalGeminiImageModelId(requestedModelId) : void 0;
|
|
4733
|
-
const resolvedModelId = requestedModelAdvertised ? requestedModelId : canonicalModelId &&
|
|
4802
|
+
const resolvedModelId = requestedModelAdvertised ? requestedModelId : canonicalModelId && filledModels.some((model) => model.modelId === canonicalModelId) ? canonicalModelId : void 0;
|
|
4734
4803
|
return {
|
|
4735
4804
|
requestedModelId,
|
|
4736
4805
|
requestedModelAdvertised,
|
|
4737
4806
|
...canonicalModelId ? { canonicalModelId } : {},
|
|
4738
4807
|
...resolvedModelId ? { resolvedModelId } : {},
|
|
4739
4808
|
...currentModelId ? { currentModelId } : {},
|
|
4740
|
-
availableModels
|
|
4809
|
+
availableModels: filledModels
|
|
4741
4810
|
};
|
|
4742
4811
|
}
|
|
4743
4812
|
function parseOpenAiModelCatalog(route, payload) {
|
|
@@ -6270,54 +6339,26 @@ function createDefaultRouteHandlers(options = {}) {
|
|
|
6270
6339
|
var AI_CONNECT_DEFAULT_ACP_COMMANDS = {
|
|
6271
6340
|
"anthropic:claude-code-acp": "npx -y @agentclientprotocol/claude-agent-acp@^0.25.0",
|
|
6272
6341
|
"openai:codex-acp": "npx @zed-industries/codex-acp@^0.11.1",
|
|
6273
|
-
"gemini:gemini-acp": "gemini --acp",
|
|
6274
|
-
"qwen:qwen-acp": "qwen --acp",
|
|
6275
6342
|
"opencode:opencode-acp": "opencode acp"
|
|
6276
6343
|
};
|
|
6277
6344
|
|
|
6278
6345
|
// src/cli-presets.ts
|
|
6279
6346
|
var AI_CONNECT_DEFAULT_CLI_PRESETS = {
|
|
6280
|
-
|
|
6281
|
-
id: "
|
|
6282
|
-
label: "
|
|
6283
|
-
command: "
|
|
6284
|
-
transportId: "
|
|
6285
|
-
options: {
|
|
6286
|
-
preset: "gemini",
|
|
6287
|
-
argsTemplate: ["-p", "{prompt}", "--output-format", "json", "--model", "{model}"],
|
|
6288
|
-
discovery: {
|
|
6289
|
-
via: "acp",
|
|
6290
|
-
acp: {
|
|
6291
|
-
transportId: "gemini-acp"
|
|
6292
|
-
}
|
|
6293
|
-
},
|
|
6294
|
-
parser: {
|
|
6295
|
-
kind: "json",
|
|
6296
|
-
textPath: "response",
|
|
6297
|
-
usagePath: "stats",
|
|
6298
|
-
errorPath: "error"
|
|
6299
|
-
}
|
|
6300
|
-
}
|
|
6301
|
-
},
|
|
6302
|
-
qwen: {
|
|
6303
|
-
id: "qwen",
|
|
6304
|
-
label: "Qwen CLI",
|
|
6305
|
-
command: "qwen",
|
|
6306
|
-
transportId: "qwen-cli",
|
|
6347
|
+
pi: {
|
|
6348
|
+
id: "pi",
|
|
6349
|
+
label: "pi (coding agent)",
|
|
6350
|
+
command: "pi",
|
|
6351
|
+
transportId: "pi-cli",
|
|
6307
6352
|
options: {
|
|
6308
|
-
preset: "
|
|
6309
|
-
|
|
6353
|
+
preset: "pi",
|
|
6354
|
+
// pi print mode emits the answer as plain text on stdout (no JSON wrapper),
|
|
6355
|
+
// and has no ACP mode — so it uses the raw `text` parser and no discovery sidecar.
|
|
6356
|
+
argsTemplate: ["--print", "--model", "{model}", "{prompt}"],
|
|
6310
6357
|
discovery: {
|
|
6311
|
-
via: "
|
|
6312
|
-
acp: {
|
|
6313
|
-
transportId: "qwen-acp"
|
|
6314
|
-
}
|
|
6358
|
+
via: "none"
|
|
6315
6359
|
},
|
|
6316
6360
|
parser: {
|
|
6317
|
-
kind: "
|
|
6318
|
-
textPath: "__preset__:qwen.result",
|
|
6319
|
-
usagePath: "__preset__:qwen.stats",
|
|
6320
|
-
errorPath: "__preset__:qwen.error"
|
|
6361
|
+
kind: "text"
|
|
6321
6362
|
}
|
|
6322
6363
|
}
|
|
6323
6364
|
},
|
|
@@ -6401,8 +6442,7 @@ var AI_CONNECT_DEFAULT_CLI_COMMANDS = {
|
|
|
6401
6442
|
"anthropic:openclaude-cli": AI_CONNECT_DEFAULT_CLI_PRESETS.openclaude.command,
|
|
6402
6443
|
"openclaude:openclaude-cli": AI_CONNECT_DEFAULT_CLI_PRESETS.openclaude.command,
|
|
6403
6444
|
"openai:codex-cli": AI_CONNECT_DEFAULT_CLI_PRESETS.codex.command,
|
|
6404
|
-
"
|
|
6405
|
-
"qwen:qwen-cli": AI_CONNECT_DEFAULT_CLI_PRESETS.qwen.command
|
|
6445
|
+
"pi:pi-cli": AI_CONNECT_DEFAULT_CLI_PRESETS.pi.command
|
|
6406
6446
|
};
|
|
6407
6447
|
function getCliTransportPreset(presetId) {
|
|
6408
6448
|
return AI_CONNECT_DEFAULT_CLI_PRESETS[presetId];
|
|
@@ -6524,52 +6564,22 @@ var TEXT_PROVIDER_CATALOG = [
|
|
|
6524
6564
|
runtime: "universal",
|
|
6525
6565
|
defaultModel: "gemini-3.1-flash-lite",
|
|
6526
6566
|
defaultBaseUrl: ""
|
|
6527
|
-
},
|
|
6528
|
-
{
|
|
6529
|
-
providerId: "gemini",
|
|
6530
|
-
providerLabel: "Gemini",
|
|
6531
|
-
transportKind: "cli",
|
|
6532
|
-
transportId: "gemini-cli",
|
|
6533
|
-
transportLabel: "Gemini CLI",
|
|
6534
|
-
runtime: "local",
|
|
6535
|
-
defaultModel: "gemini-2.5-flash",
|
|
6536
|
-
defaultCommand: AI_CONNECT_DEFAULT_CLI_COMMANDS["gemini:gemini-cli"]
|
|
6537
|
-
},
|
|
6538
|
-
{
|
|
6539
|
-
providerId: "gemini",
|
|
6540
|
-
providerLabel: "Gemini",
|
|
6541
|
-
transportKind: "acp",
|
|
6542
|
-
transportId: "gemini-acp",
|
|
6543
|
-
transportLabel: "Gemini ACP",
|
|
6544
|
-
runtime: "local",
|
|
6545
|
-
defaultModel: "auto-gemini-3",
|
|
6546
|
-
defaultCommand: AI_CONNECT_DEFAULT_ACP_COMMANDS["gemini:gemini-acp"]
|
|
6547
6567
|
}
|
|
6548
6568
|
]
|
|
6549
6569
|
},
|
|
6550
6570
|
{
|
|
6551
|
-
providerId: "
|
|
6552
|
-
label: "
|
|
6571
|
+
providerId: "pi",
|
|
6572
|
+
label: "pi",
|
|
6553
6573
|
transports: [
|
|
6554
6574
|
{
|
|
6555
|
-
providerId: "
|
|
6556
|
-
providerLabel: "
|
|
6575
|
+
providerId: "pi",
|
|
6576
|
+
providerLabel: "pi",
|
|
6557
6577
|
transportKind: "cli",
|
|
6558
|
-
transportId: "
|
|
6559
|
-
transportLabel: "
|
|
6560
|
-
runtime: "local",
|
|
6561
|
-
defaultModel: "qwen3-coder-plus",
|
|
6562
|
-
defaultCommand: AI_CONNECT_DEFAULT_CLI_COMMANDS["qwen:qwen-cli"]
|
|
6563
|
-
},
|
|
6564
|
-
{
|
|
6565
|
-
providerId: "qwen",
|
|
6566
|
-
providerLabel: "Qwen",
|
|
6567
|
-
transportKind: "acp",
|
|
6568
|
-
transportId: "qwen-acp",
|
|
6569
|
-
transportLabel: "Qwen ACP",
|
|
6578
|
+
transportId: "pi-cli",
|
|
6579
|
+
transportLabel: "pi CLI",
|
|
6570
6580
|
runtime: "local",
|
|
6571
|
-
defaultModel: "
|
|
6572
|
-
defaultCommand:
|
|
6581
|
+
defaultModel: "gemini-3.1-pro-low",
|
|
6582
|
+
defaultCommand: AI_CONNECT_DEFAULT_CLI_COMMANDS["pi:pi-cli"]
|
|
6573
6583
|
}
|
|
6574
6584
|
]
|
|
6575
6585
|
},
|
|
@@ -6742,15 +6752,6 @@ function resolveHomeDir(env) {
|
|
|
6742
6752
|
function resolveXdgConfigHome(env) {
|
|
6743
6753
|
return env.XDG_CONFIG_HOME ?? path.join(resolveHomeDir(env), ".config");
|
|
6744
6754
|
}
|
|
6745
|
-
function resolveGeminiCliHome(env) {
|
|
6746
|
-
return env.GEMINI_CLI_HOME ?? resolveHomeDir(env);
|
|
6747
|
-
}
|
|
6748
|
-
function resolveGeminiDir(env) {
|
|
6749
|
-
return path.join(resolveGeminiCliHome(env), ".gemini");
|
|
6750
|
-
}
|
|
6751
|
-
function resolveQwenDir(env) {
|
|
6752
|
-
return path.join(resolveHomeDir(env), ".qwen");
|
|
6753
|
-
}
|
|
6754
6755
|
function resolveCodexHome(env) {
|
|
6755
6756
|
return env.CODEX_HOME ?? path.join(resolveHomeDir(env), ".codex");
|
|
6756
6757
|
}
|
|
@@ -6796,118 +6797,6 @@ async function removeIfExists(targetPath) {
|
|
|
6796
6797
|
}
|
|
6797
6798
|
});
|
|
6798
6799
|
}
|
|
6799
|
-
async function readJsonFile(filePath) {
|
|
6800
|
-
try {
|
|
6801
|
-
const raw = await fs.readFile(filePath, "utf8");
|
|
6802
|
-
const parsed = JSON.parse(raw);
|
|
6803
|
-
return isRecord2(parsed) ? parsed : void 0;
|
|
6804
|
-
} catch (error) {
|
|
6805
|
-
if (error instanceof SyntaxError || error.code === "ENOENT") {
|
|
6806
|
-
return void 0;
|
|
6807
|
-
}
|
|
6808
|
-
throw error;
|
|
6809
|
-
}
|
|
6810
|
-
}
|
|
6811
|
-
function mergeRecordValues(current, next) {
|
|
6812
|
-
const merged = { ...current };
|
|
6813
|
-
for (const [key, value] of Object.entries(next)) {
|
|
6814
|
-
const existing = merged[key];
|
|
6815
|
-
if (isRecord2(existing) && isRecord2(value)) {
|
|
6816
|
-
merged[key] = mergeRecordValues(existing, value);
|
|
6817
|
-
continue;
|
|
6818
|
-
}
|
|
6819
|
-
merged[key] = value;
|
|
6820
|
-
}
|
|
6821
|
-
return merged;
|
|
6822
|
-
}
|
|
6823
|
-
async function writeJsonFile(filePath, value) {
|
|
6824
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
6825
|
-
await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}
|
|
6826
|
-
`, "utf8");
|
|
6827
|
-
}
|
|
6828
|
-
async function prepareGeminiLaunchRuntime(base, launch) {
|
|
6829
|
-
if (launch.contextMode === "workspace" && launch.skillsMode === "default") {
|
|
6830
|
-
return {
|
|
6831
|
-
...base,
|
|
6832
|
-
launch
|
|
6833
|
-
};
|
|
6834
|
-
}
|
|
6835
|
-
const sandbox = await createSandboxPaths("ai-connect-gemini-acp-");
|
|
6836
|
-
const originalGeminiDir = resolveGeminiDir(base.env);
|
|
6837
|
-
const sandboxGeminiDir = path.join(sandbox.root, ".gemini");
|
|
6838
|
-
const settingsPath = path.join(sandboxGeminiDir, "settings.json");
|
|
6839
|
-
const systemSettingsPath = path.join(sandbox.config, "gemini-settings.json");
|
|
6840
|
-
const systemDefaultsPath = path.join(
|
|
6841
|
-
sandbox.config,
|
|
6842
|
-
"gemini-system-defaults.json"
|
|
6843
|
-
);
|
|
6844
|
-
const isolatedCwd = launch.contextMode === "clean" || launch.skillsMode === "disabled" ? sandbox.root : base.cwd;
|
|
6845
|
-
await Promise.all(
|
|
6846
|
-
[
|
|
6847
|
-
"oauth_creds.json",
|
|
6848
|
-
"google_accounts.json",
|
|
6849
|
-
"mcp-oauth-tokens.json",
|
|
6850
|
-
"a2a-oauth-tokens.json",
|
|
6851
|
-
"installation_id"
|
|
6852
|
-
].map(
|
|
6853
|
-
(fileName) => maybeCopyFile(
|
|
6854
|
-
path.join(originalGeminiDir, fileName),
|
|
6855
|
-
path.join(sandboxGeminiDir, fileName)
|
|
6856
|
-
)
|
|
6857
|
-
)
|
|
6858
|
-
);
|
|
6859
|
-
const settings = mergeRecordValues(
|
|
6860
|
-
await readJsonFile(settingsPath) ?? {},
|
|
6861
|
-
{
|
|
6862
|
-
context: {
|
|
6863
|
-
fileName: "AI_CONNECT_CONTEXT_DISABLED.md",
|
|
6864
|
-
includeDirectoryTree: false,
|
|
6865
|
-
memoryBoundaryMarkers: [],
|
|
6866
|
-
includeDirectories: [],
|
|
6867
|
-
loadMemoryFromIncludeDirectories: false,
|
|
6868
|
-
discoveryMaxDirs: 0
|
|
6869
|
-
},
|
|
6870
|
-
admin: {
|
|
6871
|
-
mcp: {
|
|
6872
|
-
enabled: false,
|
|
6873
|
-
config: {},
|
|
6874
|
-
requiredConfig: {}
|
|
6875
|
-
},
|
|
6876
|
-
...launch.skillsMode === "disabled" ? {
|
|
6877
|
-
skills: {
|
|
6878
|
-
enabled: false
|
|
6879
|
-
}
|
|
6880
|
-
} : {}
|
|
6881
|
-
},
|
|
6882
|
-
...launch.skillsMode === "disabled" ? {
|
|
6883
|
-
skills: {
|
|
6884
|
-
enabled: false,
|
|
6885
|
-
disabled: []
|
|
6886
|
-
}
|
|
6887
|
-
} : {}
|
|
6888
|
-
}
|
|
6889
|
-
);
|
|
6890
|
-
await Promise.all([
|
|
6891
|
-
writeJsonFile(settingsPath, settings),
|
|
6892
|
-
writeJsonFile(systemSettingsPath, {}),
|
|
6893
|
-
writeJsonFile(systemDefaultsPath, {})
|
|
6894
|
-
]);
|
|
6895
|
-
return {
|
|
6896
|
-
commandLine: base.commandLine,
|
|
6897
|
-
cwd: isolatedCwd,
|
|
6898
|
-
env: {
|
|
6899
|
-
...base.env,
|
|
6900
|
-
HOME: sandbox.root,
|
|
6901
|
-
GEMINI_CLI_HOME: sandbox.root,
|
|
6902
|
-
GEMINI_CLI_SYSTEM_SETTINGS_PATH: systemSettingsPath,
|
|
6903
|
-
GEMINI_CLI_SYSTEM_DEFAULTS_PATH: systemDefaultsPath
|
|
6904
|
-
},
|
|
6905
|
-
launch,
|
|
6906
|
-
cleanup: async () => {
|
|
6907
|
-
await removeIfExists(sandbox.root);
|
|
6908
|
-
}
|
|
6909
|
-
};
|
|
6910
|
-
}
|
|
6911
6800
|
async function prepareOpenCodeLaunchRuntime(base, launch) {
|
|
6912
6801
|
if (launch.contextMode === "workspace" && launch.skillsMode === "default") {
|
|
6913
6802
|
return {
|
|
@@ -6956,70 +6845,6 @@ async function prepareOpenCodeLaunchRuntime(base, launch) {
|
|
|
6956
6845
|
}
|
|
6957
6846
|
};
|
|
6958
6847
|
}
|
|
6959
|
-
async function prepareQwenLaunchRuntime(base, launch) {
|
|
6960
|
-
if (launch.contextMode === "workspace" && launch.skillsMode === "default") {
|
|
6961
|
-
return {
|
|
6962
|
-
...base,
|
|
6963
|
-
launch
|
|
6964
|
-
};
|
|
6965
|
-
}
|
|
6966
|
-
const sandbox = await createSandboxPaths("ai-connect-qwen-acp-");
|
|
6967
|
-
const originalQwenDir = resolveQwenDir(base.env);
|
|
6968
|
-
const sandboxQwenDir = path.join(sandbox.home, ".qwen");
|
|
6969
|
-
const settingsPath = path.join(sandboxQwenDir, "settings.json");
|
|
6970
|
-
const systemSettingsPath = path.join(sandbox.config, "qwen-settings.json");
|
|
6971
|
-
const systemDefaultsPath = path.join(
|
|
6972
|
-
sandbox.config,
|
|
6973
|
-
"qwen-system-defaults.json"
|
|
6974
|
-
);
|
|
6975
|
-
await Promise.all(
|
|
6976
|
-
[
|
|
6977
|
-
"oauth_creds.json",
|
|
6978
|
-
"mcp-oauth-tokens.json",
|
|
6979
|
-
"installation_id",
|
|
6980
|
-
".env",
|
|
6981
|
-
"settings.json"
|
|
6982
|
-
].map(
|
|
6983
|
-
(fileName) => maybeCopyFile(
|
|
6984
|
-
path.join(originalQwenDir, fileName),
|
|
6985
|
-
path.join(sandboxQwenDir, fileName)
|
|
6986
|
-
)
|
|
6987
|
-
)
|
|
6988
|
-
);
|
|
6989
|
-
const settings = mergeRecordValues(
|
|
6990
|
-
await readJsonFile(settingsPath) ?? {},
|
|
6991
|
-
{
|
|
6992
|
-
context: {
|
|
6993
|
-
fileName: ["AI_CONNECT_CONTEXT_DISABLED.md"],
|
|
6994
|
-
includeDirectories: [],
|
|
6995
|
-
loadFromIncludeDirectories: false
|
|
6996
|
-
},
|
|
6997
|
-
model: {
|
|
6998
|
-
skipStartupContext: true
|
|
6999
|
-
}
|
|
7000
|
-
}
|
|
7001
|
-
);
|
|
7002
|
-
await Promise.all([
|
|
7003
|
-
writeJsonFile(settingsPath, settings),
|
|
7004
|
-
writeJsonFile(systemSettingsPath, {}),
|
|
7005
|
-
writeJsonFile(systemDefaultsPath, {})
|
|
7006
|
-
]);
|
|
7007
|
-
const isolatedCwd = launch.contextMode === "clean" || launch.skillsMode === "disabled" ? sandbox.root : base.cwd;
|
|
7008
|
-
return {
|
|
7009
|
-
commandLine: base.commandLine,
|
|
7010
|
-
cwd: isolatedCwd,
|
|
7011
|
-
env: {
|
|
7012
|
-
...base.env,
|
|
7013
|
-
HOME: sandbox.home,
|
|
7014
|
-
QWEN_CODE_SYSTEM_SETTINGS_PATH: systemSettingsPath,
|
|
7015
|
-
QWEN_CODE_SYSTEM_DEFAULTS_PATH: systemDefaultsPath
|
|
7016
|
-
},
|
|
7017
|
-
launch,
|
|
7018
|
-
cleanup: async () => {
|
|
7019
|
-
await removeIfExists(sandbox.root);
|
|
7020
|
-
}
|
|
7021
|
-
};
|
|
7022
|
-
}
|
|
7023
6848
|
async function prepareCodexLaunchRuntime(base, launch) {
|
|
7024
6849
|
if (launch.contextMode === "workspace" && launch.skillsMode === "default") {
|
|
7025
6850
|
return {
|
|
@@ -7137,15 +6962,9 @@ async function prepareAcpLaunchRuntime(route, options, commandLine, cwdOverride)
|
|
|
7137
6962
|
...options?.env ?? {}
|
|
7138
6963
|
}
|
|
7139
6964
|
};
|
|
7140
|
-
if (route.transport.id === "gemini-acp") {
|
|
7141
|
-
return prepareGeminiLaunchRuntime(base, launch);
|
|
7142
|
-
}
|
|
7143
6965
|
if (route.transport.id === "opencode-acp") {
|
|
7144
6966
|
return prepareOpenCodeLaunchRuntime(base, launch);
|
|
7145
6967
|
}
|
|
7146
|
-
if (route.transport.id === "qwen-acp") {
|
|
7147
|
-
return prepareQwenLaunchRuntime(base, launch);
|
|
7148
|
-
}
|
|
7149
6968
|
if (route.transport.id === "codex-acp") {
|
|
7150
6969
|
return prepareCodexLaunchRuntime(base, launch);
|
|
7151
6970
|
}
|
|
@@ -7726,10 +7545,6 @@ function buildAcpLifecycle(route, authRequest, mode) {
|
|
|
7726
7545
|
steps.push("authenticate");
|
|
7727
7546
|
}
|
|
7728
7547
|
steps.push("session/new");
|
|
7729
|
-
if (mode === "prompt" && route.transport.id === "gemini-acp") {
|
|
7730
|
-
steps.push("session/set_model");
|
|
7731
|
-
keys.push("session/set_model.modelId");
|
|
7732
|
-
}
|
|
7733
7548
|
if (mode === "prompt") {
|
|
7734
7549
|
steps.push("session/prompt");
|
|
7735
7550
|
}
|
|
@@ -7865,16 +7680,6 @@ var AcpConnection = class {
|
|
|
7865
7680
|
);
|
|
7866
7681
|
}
|
|
7867
7682
|
const sessionId = session.sessionId;
|
|
7868
|
-
if (context.route.transport.id === "gemini-acp") {
|
|
7869
|
-
await measurePhase(
|
|
7870
|
-
transport.phases ?? [],
|
|
7871
|
-
"session/set_model",
|
|
7872
|
-
async () => this.request("session/set_model", {
|
|
7873
|
-
sessionId,
|
|
7874
|
-
modelId: context.route.model
|
|
7875
|
-
})
|
|
7876
|
-
);
|
|
7877
|
-
}
|
|
7878
7683
|
this.activePrompt = {
|
|
7879
7684
|
sessionId,
|
|
7880
7685
|
text: "",
|
|
@@ -7966,6 +7771,10 @@ var AcpConnection = class {
|
|
|
7966
7771
|
`ACP route "${context.route.id}" did not return an ACP model catalog in session/new.`
|
|
7967
7772
|
);
|
|
7968
7773
|
}
|
|
7774
|
+
catalog.availableModels = fillConfiguredContextLength(
|
|
7775
|
+
context.route,
|
|
7776
|
+
catalog.availableModels
|
|
7777
|
+
);
|
|
7969
7778
|
return catalog;
|
|
7970
7779
|
} finally {
|
|
7971
7780
|
this.bumpIdleTimer();
|
|
@@ -8383,9 +8192,6 @@ var AcpConnection = class {
|
|
|
8383
8192
|
});
|
|
8384
8193
|
}
|
|
8385
8194
|
};
|
|
8386
|
-
function isGeminiAcpFallbackCandidate(route, commandLine) {
|
|
8387
|
-
return route.transport.id === "gemini-acp" && commandLine.includes("--acp") && !commandLine.includes("--experimental-acp");
|
|
8388
|
-
}
|
|
8389
8195
|
function cacheKeyForConnection(route, runtime, options) {
|
|
8390
8196
|
const envEntries = Object.entries(options.env).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key}=${value}`).join("");
|
|
8391
8197
|
return [
|
|
@@ -8632,18 +8438,7 @@ function createAcpTransportManager(options) {
|
|
|
8632
8438
|
}
|
|
8633
8439
|
async function drivePrompt(context, onDelta) {
|
|
8634
8440
|
const commandLine = resolveAcpCommand(context.route, options);
|
|
8635
|
-
|
|
8636
|
-
return await runWithCommand(context, commandLine, onDelta);
|
|
8637
|
-
} catch (error) {
|
|
8638
|
-
if (!isGeminiAcpFallbackCandidate(context.route, commandLine)) {
|
|
8639
|
-
throw error;
|
|
8640
|
-
}
|
|
8641
|
-
return await runWithCommand(
|
|
8642
|
-
context,
|
|
8643
|
-
commandLine.replace("--acp", "--experimental-acp"),
|
|
8644
|
-
onDelta
|
|
8645
|
-
);
|
|
8646
|
-
}
|
|
8441
|
+
return await runWithCommand(context, commandLine, onDelta);
|
|
8647
8442
|
}
|
|
8648
8443
|
return {
|
|
8649
8444
|
async runPrompt(context) {
|
|
@@ -8712,17 +8507,7 @@ function createAcpTransportManager(options) {
|
|
|
8712
8507
|
},
|
|
8713
8508
|
async discoverModels(context) {
|
|
8714
8509
|
const commandLine = resolveAcpCommand(context.route, options);
|
|
8715
|
-
|
|
8716
|
-
return await discoverWithCommand(context, commandLine);
|
|
8717
|
-
} catch (error) {
|
|
8718
|
-
if (!isGeminiAcpFallbackCandidate(context.route, commandLine)) {
|
|
8719
|
-
throw error;
|
|
8720
|
-
}
|
|
8721
|
-
return await discoverWithCommand(
|
|
8722
|
-
context,
|
|
8723
|
-
commandLine.replace("--acp", "--experimental-acp")
|
|
8724
|
-
);
|
|
8725
|
-
}
|
|
8510
|
+
return await discoverWithCommand(context, commandLine);
|
|
8726
8511
|
},
|
|
8727
8512
|
async dispose() {
|
|
8728
8513
|
const values = [...connectionPools.values()].flat();
|
|
@@ -8747,14 +8532,6 @@ import fs2 from "node:fs/promises";
|
|
|
8747
8532
|
import os2 from "node:os";
|
|
8748
8533
|
import path2 from "node:path";
|
|
8749
8534
|
var CLI_PRESET_ACP_DISCOVERY_DEFAULTS = {
|
|
8750
|
-
gemini: {
|
|
8751
|
-
transportId: "gemini-acp",
|
|
8752
|
-
providerId: "gemini"
|
|
8753
|
-
},
|
|
8754
|
-
qwen: {
|
|
8755
|
-
transportId: "qwen-acp",
|
|
8756
|
-
providerId: "qwen"
|
|
8757
|
-
},
|
|
8758
8535
|
claude: {
|
|
8759
8536
|
transportId: "claude-code-acp",
|
|
8760
8537
|
providerId: "anthropic"
|
|
@@ -8861,10 +8638,8 @@ function buildCliCwd(context, options) {
|
|
|
8861
8638
|
}
|
|
8862
8639
|
function defaultCliPresetIdForRoute(route) {
|
|
8863
8640
|
switch (route.transport.id) {
|
|
8864
|
-
case "
|
|
8865
|
-
return "
|
|
8866
|
-
case "qwen-cli":
|
|
8867
|
-
return "qwen";
|
|
8641
|
+
case "pi-cli":
|
|
8642
|
+
return "pi";
|
|
8868
8643
|
case "claude-cli":
|
|
8869
8644
|
return "claude";
|
|
8870
8645
|
case "openclaude-cli":
|
|
@@ -8907,14 +8682,26 @@ function normalizeCliDiscoveryAcpSource(route, discovery) {
|
|
|
8907
8682
|
};
|
|
8908
8683
|
}
|
|
8909
8684
|
function resolveCliDiscoverySource(route) {
|
|
8910
|
-
const
|
|
8911
|
-
|
|
8912
|
-
|
|
8685
|
+
const discovery = route.transport.cli?.discovery;
|
|
8686
|
+
const hasModels = (route.advertisedModels?.length ?? 0) > 0;
|
|
8687
|
+
const hasAcpDefault = Boolean(defaultCliDiscoveryTransportIdForRoute(route));
|
|
8688
|
+
const via = discovery?.via ?? (discovery?.command ? "command" : hasAcpDefault ? "acp" : hasModels ? "static" : "none");
|
|
8689
|
+
switch (via) {
|
|
8690
|
+
case "none":
|
|
8691
|
+
return { via: "none" };
|
|
8692
|
+
case "static":
|
|
8693
|
+
return { via: "static" };
|
|
8694
|
+
case "command": {
|
|
8695
|
+
const command = discovery?.command;
|
|
8696
|
+
if (!command) {
|
|
8697
|
+
return { via: "none" };
|
|
8698
|
+
}
|
|
8699
|
+
const fallback = discovery?.fallback ?? (hasModels ? "static" : "none");
|
|
8700
|
+
return { via: "command", command, fallback };
|
|
8701
|
+
}
|
|
8702
|
+
default:
|
|
8703
|
+
return normalizeCliDiscoveryAcpSource(route, discovery?.acp);
|
|
8913
8704
|
}
|
|
8914
|
-
return normalizeCliDiscoveryAcpSource(
|
|
8915
|
-
route,
|
|
8916
|
-
route.transport.cli?.discovery?.acp
|
|
8917
|
-
);
|
|
8918
8705
|
}
|
|
8919
8706
|
function createCliDiscoveryAcpRoute(route) {
|
|
8920
8707
|
const discovery = resolveCliDiscoverySource(route);
|
|
@@ -9023,6 +8810,42 @@ async function buildCliInvocation(context, options) {
|
|
|
9023
8810
|
parameterKeys
|
|
9024
8811
|
};
|
|
9025
8812
|
}
|
|
8813
|
+
function buildCliDiscoveryInvocation(route, command, options) {
|
|
8814
|
+
const commandLine = command.command?.trim() ? command.command : resolveCliCommand(route, options);
|
|
8815
|
+
const resolved = splitCommandLine2(commandLine);
|
|
8816
|
+
const parameterKeys = [];
|
|
8817
|
+
const args = [
|
|
8818
|
+
...resolved.args,
|
|
8819
|
+
...command.argsTemplate.map((part) => {
|
|
8820
|
+
if (part === "{model}") {
|
|
8821
|
+
parameterKeys.push("model");
|
|
8822
|
+
return route.model;
|
|
8823
|
+
}
|
|
8824
|
+
if (part.startsWith("--")) {
|
|
8825
|
+
parameterKeys.push(part);
|
|
8826
|
+
}
|
|
8827
|
+
return part;
|
|
8828
|
+
})
|
|
8829
|
+
];
|
|
8830
|
+
return {
|
|
8831
|
+
command: resolved.command,
|
|
8832
|
+
args,
|
|
8833
|
+
cwd: path2.resolve(options?.cwd ?? process.cwd()),
|
|
8834
|
+
env: buildCliEnvironment(options),
|
|
8835
|
+
parameterKeys
|
|
8836
|
+
};
|
|
8837
|
+
}
|
|
8838
|
+
function buildStaticCliCatalog(route) {
|
|
8839
|
+
const models = route.advertisedModels.map((id) => ({
|
|
8840
|
+
modelId: id,
|
|
8841
|
+
name: id
|
|
8842
|
+
}));
|
|
8843
|
+
return buildModelCatalog(
|
|
8844
|
+
route,
|
|
8845
|
+
models,
|
|
8846
|
+
currentModelIdForRoute(route, route.advertisedModels)
|
|
8847
|
+
);
|
|
8848
|
+
}
|
|
9026
8849
|
function statsToUsage(stats) {
|
|
9027
8850
|
if (!stats || typeof stats !== "object") {
|
|
9028
8851
|
return void 0;
|
|
@@ -9060,6 +8883,9 @@ function getValueByPath(value, dotPath) {
|
|
|
9060
8883
|
}
|
|
9061
8884
|
return current;
|
|
9062
8885
|
}
|
|
8886
|
+
function splitJsonlLines(stdout) {
|
|
8887
|
+
return stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => JSON.parse(line));
|
|
8888
|
+
}
|
|
9063
8889
|
function normalizeErrorMessage(value) {
|
|
9064
8890
|
if (typeof value === "string" && value.trim()) {
|
|
9065
8891
|
return value.trim();
|
|
@@ -9107,7 +8933,7 @@ function parseGenericJsonCli(stdout, parser) {
|
|
|
9107
8933
|
};
|
|
9108
8934
|
}
|
|
9109
8935
|
function parseGenericJsonlCli(stdout, parser) {
|
|
9110
|
-
const entries = stdout
|
|
8936
|
+
const entries = splitJsonlLines(stdout);
|
|
9111
8937
|
const errorValue = parser.error ? findJsonlSelection(entries, parser.error) : void 0;
|
|
9112
8938
|
const errorMessage = normalizeErrorMessage(errorValue);
|
|
9113
8939
|
if (errorMessage) {
|
|
@@ -9128,59 +8954,69 @@ function parseGenericJsonlCli(stdout, parser) {
|
|
|
9128
8954
|
data: entries
|
|
9129
8955
|
};
|
|
9130
8956
|
}
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
8957
|
+
var ANSI_ESCAPE_PATTERN = /\[[0-?]*[ -/]*[@-~]/g;
|
|
8958
|
+
function parseTextCli(stdout, parser) {
|
|
8959
|
+
let text = stdout;
|
|
8960
|
+
if (parser.stripAnsi) {
|
|
8961
|
+
text = text.replace(ANSI_ESCAPE_PATTERN, "");
|
|
9135
8962
|
}
|
|
9136
|
-
if (
|
|
8963
|
+
if (parser.trim !== false) {
|
|
8964
|
+
text = text.trim();
|
|
8965
|
+
}
|
|
8966
|
+
if (!text) {
|
|
9137
8967
|
throw new AiConnectError(
|
|
9138
8968
|
"temporary_unavailable",
|
|
9139
|
-
"
|
|
8969
|
+
"CLI text parser produced no output."
|
|
9140
8970
|
);
|
|
9141
8971
|
}
|
|
9142
|
-
|
|
8972
|
+
return { text, data: stdout };
|
|
8973
|
+
}
|
|
8974
|
+
function modelInfoFromRecord(record, selector) {
|
|
8975
|
+
const rawId = getValueByPath(record, selector.idPath);
|
|
8976
|
+
const modelId = typeof rawId === "string" ? rawId.trim() : "";
|
|
8977
|
+
if (!modelId) {
|
|
8978
|
+
return void 0;
|
|
8979
|
+
}
|
|
8980
|
+
const rawName = selector.namePath ? getValueByPath(record, selector.namePath) : void 0;
|
|
8981
|
+
const name = typeof rawName === "string" && rawName.trim().length > 0 ? rawName : modelId;
|
|
8982
|
+
const rawDescription = selector.descriptionPath ? getValueByPath(record, selector.descriptionPath) : void 0;
|
|
8983
|
+
const description = typeof rawDescription === "string" && rawDescription.trim().length > 0 ? rawDescription : void 0;
|
|
8984
|
+
const rawContext = selector.contextLengthPath ? getValueByPath(record, selector.contextLengthPath) : void 0;
|
|
8985
|
+
const contextLength = typeof rawContext === "number" && Number.isFinite(rawContext) && rawContext > 0 ? Math.floor(rawContext) : void 0;
|
|
9143
8986
|
return {
|
|
9144
|
-
|
|
9145
|
-
|
|
9146
|
-
|
|
8987
|
+
modelId,
|
|
8988
|
+
name,
|
|
8989
|
+
...description ? { description } : {},
|
|
8990
|
+
...contextLength !== void 0 ? { contextLength } : {}
|
|
9147
8991
|
};
|
|
9148
8992
|
}
|
|
9149
|
-
function
|
|
9150
|
-
|
|
9151
|
-
|
|
9152
|
-
|
|
9153
|
-
"
|
|
9154
|
-
|
|
9155
|
-
);
|
|
9156
|
-
}
|
|
9157
|
-
const resultMessage = payload.find(
|
|
9158
|
-
(entry) => entry && typeof entry === "object" && entry.type === "result"
|
|
9159
|
-
);
|
|
9160
|
-
if (!resultMessage) {
|
|
9161
|
-
throw new AiConnectError(
|
|
9162
|
-
"temporary_unavailable",
|
|
9163
|
-
"Qwen CLI JSON output did not contain a result message."
|
|
9164
|
-
);
|
|
8993
|
+
function parseCliModelList(stdout, parser, selector) {
|
|
8994
|
+
if (parser.kind === "text") {
|
|
8995
|
+
let text = stdout;
|
|
8996
|
+
if (parser.stripAnsi) {
|
|
8997
|
+
text = text.replace(ANSI_ESCAPE_PATTERN, "");
|
|
8998
|
+
}
|
|
8999
|
+
return text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => ({ modelId: line, name: line }));
|
|
9165
9000
|
}
|
|
9166
|
-
if (
|
|
9001
|
+
if (!selector) {
|
|
9167
9002
|
throw new AiConnectError(
|
|
9168
|
-
"
|
|
9169
|
-
|
|
9003
|
+
"validation_error",
|
|
9004
|
+
`CLI ${parser.kind} discovery parser requires a models selector with idPath.`
|
|
9170
9005
|
);
|
|
9171
9006
|
}
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9007
|
+
const records = parser.kind === "jsonl" ? splitJsonlLines(stdout) : (() => {
|
|
9008
|
+
const payload = JSON.parse(stdout);
|
|
9009
|
+
const arr = selector.path ? getValueByPath(payload, selector.path) : payload;
|
|
9010
|
+
return Array.isArray(arr) ? arr : [];
|
|
9011
|
+
})();
|
|
9012
|
+
const models = [];
|
|
9013
|
+
for (const record of records) {
|
|
9014
|
+
const info = modelInfoFromRecord(record, selector);
|
|
9015
|
+
if (info) {
|
|
9016
|
+
models.push(info);
|
|
9017
|
+
}
|
|
9177
9018
|
}
|
|
9178
|
-
|
|
9179
|
-
return {
|
|
9180
|
-
text: resultMessage.result,
|
|
9181
|
-
...usage ? { usage } : {},
|
|
9182
|
-
data: payload
|
|
9183
|
-
};
|
|
9019
|
+
return models;
|
|
9184
9020
|
}
|
|
9185
9021
|
function parseClaudeCli(stdout) {
|
|
9186
9022
|
const payload = JSON.parse(stdout);
|
|
@@ -9199,8 +9035,7 @@ function parseClaudeCli(stdout) {
|
|
|
9199
9035
|
};
|
|
9200
9036
|
}
|
|
9201
9037
|
function parseCodexCli(stdout, outputFileContent) {
|
|
9202
|
-
const
|
|
9203
|
-
const events = lines.map((line) => JSON.parse(line));
|
|
9038
|
+
const events = splitJsonlLines(stdout);
|
|
9204
9039
|
let text = outputFileContent?.trim() || void 0;
|
|
9205
9040
|
let usage;
|
|
9206
9041
|
for (const event of events) {
|
|
@@ -9258,13 +9093,18 @@ function parseCliResult(route, result, outputFileContent) {
|
|
|
9258
9093
|
`CLI route "${route.id}" declared a parser override but normalization did not preserve it.`
|
|
9259
9094
|
);
|
|
9260
9095
|
}
|
|
9261
|
-
|
|
9096
|
+
switch (parser.kind) {
|
|
9097
|
+
case "text":
|
|
9098
|
+
return parseTextCli(result.stdout, parser);
|
|
9099
|
+
case "json":
|
|
9100
|
+
return parseGenericJsonCli(stdout, parser);
|
|
9101
|
+
default:
|
|
9102
|
+
return parseGenericJsonlCli(stdout, parser);
|
|
9103
|
+
}
|
|
9262
9104
|
}
|
|
9263
9105
|
switch (cliOptions.preset) {
|
|
9264
|
-
case "
|
|
9265
|
-
return
|
|
9266
|
-
case "qwen":
|
|
9267
|
-
return parseQwenCli(stdout);
|
|
9106
|
+
case "pi":
|
|
9107
|
+
return parseTextCli(stdout, { kind: "text" });
|
|
9268
9108
|
case "claude":
|
|
9269
9109
|
case "openclaude":
|
|
9270
9110
|
return parseClaudeCli(stdout);
|
|
@@ -9361,6 +9201,88 @@ async function cleanupCliInvocation(invocation) {
|
|
|
9361
9201
|
}
|
|
9362
9202
|
function createCliTransportManager(options) {
|
|
9363
9203
|
return {
|
|
9204
|
+
async discoverModels(context) {
|
|
9205
|
+
const source = resolveCliDiscoverySource(context.route);
|
|
9206
|
+
if (source.via === "none") {
|
|
9207
|
+
throw new AiConnectError(
|
|
9208
|
+
"not_supported",
|
|
9209
|
+
`CLI transport "${context.route.transport.id}" does not support model discovery (no list command, no ACP sidecar, and no configured models[]).`
|
|
9210
|
+
);
|
|
9211
|
+
}
|
|
9212
|
+
if (source.via === "acp") {
|
|
9213
|
+
throw new AiConnectError(
|
|
9214
|
+
"not_supported",
|
|
9215
|
+
`CLI route "${context.route.id}" resolves discovery via acp; dispatch to the acp discovery route instead.`
|
|
9216
|
+
);
|
|
9217
|
+
}
|
|
9218
|
+
if (source.via === "static") {
|
|
9219
|
+
return buildStaticCliCatalog(context.route);
|
|
9220
|
+
}
|
|
9221
|
+
const phases = [];
|
|
9222
|
+
const invocation = buildCliDiscoveryInvocation(
|
|
9223
|
+
context.route,
|
|
9224
|
+
source.command,
|
|
9225
|
+
options
|
|
9226
|
+
);
|
|
9227
|
+
context.telemetry?.captureTransport({
|
|
9228
|
+
protocol: "cli",
|
|
9229
|
+
endpoint: invocation.command,
|
|
9230
|
+
method: "process",
|
|
9231
|
+
bodyKeys: ["argv"],
|
|
9232
|
+
parameterKeys: invocation.parameterKeys,
|
|
9233
|
+
phases,
|
|
9234
|
+
stream: false
|
|
9235
|
+
});
|
|
9236
|
+
try {
|
|
9237
|
+
let models;
|
|
9238
|
+
try {
|
|
9239
|
+
const execution = await executeCliInvocation(
|
|
9240
|
+
invocation,
|
|
9241
|
+
options?.timeoutMs ?? 6e4,
|
|
9242
|
+
phases,
|
|
9243
|
+
context.abort.signal
|
|
9244
|
+
);
|
|
9245
|
+
if (execution.exitCode !== 0 || !execution.stdout.trim()) {
|
|
9246
|
+
throw new AiConnectError(
|
|
9247
|
+
"temporary_unavailable",
|
|
9248
|
+
execution.stderr.trim() || `CLI discovery command for "${context.route.transport.id}" exited with code ${execution.exitCode ?? "null"}.`
|
|
9249
|
+
);
|
|
9250
|
+
}
|
|
9251
|
+
models = parseCliModelList(
|
|
9252
|
+
execution.stdout,
|
|
9253
|
+
source.command.parser,
|
|
9254
|
+
source.command.models
|
|
9255
|
+
);
|
|
9256
|
+
} catch (error) {
|
|
9257
|
+
if (error instanceof AiConnectError && error.code === "aborted") {
|
|
9258
|
+
throw error;
|
|
9259
|
+
}
|
|
9260
|
+
if (source.fallback === "static") {
|
|
9261
|
+
return buildStaticCliCatalog(context.route);
|
|
9262
|
+
}
|
|
9263
|
+
throw error;
|
|
9264
|
+
}
|
|
9265
|
+
if (models.length === 0) {
|
|
9266
|
+
if (source.fallback === "static") {
|
|
9267
|
+
return buildStaticCliCatalog(context.route);
|
|
9268
|
+
}
|
|
9269
|
+
throw new AiConnectError(
|
|
9270
|
+
"temporary_unavailable",
|
|
9271
|
+
`CLI discovery command for "${context.route.transport.id}" returned no models.`
|
|
9272
|
+
);
|
|
9273
|
+
}
|
|
9274
|
+
return buildModelCatalog(
|
|
9275
|
+
context.route,
|
|
9276
|
+
models,
|
|
9277
|
+
currentModelIdForRoute(
|
|
9278
|
+
context.route,
|
|
9279
|
+
models.map((model) => model.modelId)
|
|
9280
|
+
)
|
|
9281
|
+
);
|
|
9282
|
+
} finally {
|
|
9283
|
+
await cleanupCliInvocation(invocation);
|
|
9284
|
+
}
|
|
9285
|
+
},
|
|
9364
9286
|
async runPrompt(context) {
|
|
9365
9287
|
const invocation = await buildCliInvocation(context, options);
|
|
9366
9288
|
const phases = [];
|
|
@@ -9880,17 +9802,21 @@ function createLocalRouteHandlers(options = {}) {
|
|
|
9880
9802
|
return cliTransport.runPrompt(context);
|
|
9881
9803
|
},
|
|
9882
9804
|
async discoverModels(context) {
|
|
9883
|
-
const
|
|
9884
|
-
if (
|
|
9885
|
-
|
|
9886
|
-
|
|
9887
|
-
|
|
9888
|
-
|
|
9805
|
+
const source = resolveCliDiscoverySource(context.route);
|
|
9806
|
+
if (source.via === "acp") {
|
|
9807
|
+
const discoveryRoute = createCliDiscoveryAcpRoute(context.route);
|
|
9808
|
+
if (!discoveryRoute) {
|
|
9809
|
+
throw new AiConnectError(
|
|
9810
|
+
"not_supported",
|
|
9811
|
+
`CLI route "${context.route.id}" does not define a model discovery backend.`
|
|
9812
|
+
);
|
|
9813
|
+
}
|
|
9814
|
+
return acpTransport.discoverModels({
|
|
9815
|
+
...context,
|
|
9816
|
+
route: discoveryRoute
|
|
9817
|
+
});
|
|
9889
9818
|
}
|
|
9890
|
-
return
|
|
9891
|
-
...context,
|
|
9892
|
-
route: discoveryRoute
|
|
9893
|
-
});
|
|
9819
|
+
return cliTransport.discoverModels(context);
|
|
9894
9820
|
},
|
|
9895
9821
|
async verify({ route, runtime }) {
|
|
9896
9822
|
try {
|