@vedmalex/ai-connect 0.2.1 → 0.4.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 +135 -67
- package/dist/browser/index.js +90 -17
- package/dist/browser/index.js.map +2 -2
- package/dist/bun/index.js +322 -38
- package/dist/bun/index.js.map +2 -2
- package/dist/bun/local.js +322 -38
- package/dist/bun/local.js.map +2 -2
- package/dist/node/index.js +322 -38
- package/dist/node/index.js.map +2 -2
- package/dist/node/local.js +322 -38
- package/dist/node/local.js.map +2 -2
- package/dist/types/acp.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 +85 -4
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/bun/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 {
|
|
@@ -1730,6 +1783,25 @@ function resolveModelContextWindow(input) {
|
|
|
1730
1783
|
const fallback = isUsableContextLength(input.defaultContextWindow) ? input.defaultContextWindow : DEFAULT_CONTEXT_WINDOW;
|
|
1731
1784
|
return { contextWindow: fallback, source: "default" };
|
|
1732
1785
|
}
|
|
1786
|
+
function fillConfiguredContextLength(route, models) {
|
|
1787
|
+
if (!isUsableContextLength(route.contextWindow)) {
|
|
1788
|
+
return models;
|
|
1789
|
+
}
|
|
1790
|
+
const configured = route.contextWindow;
|
|
1791
|
+
return models.map((entry) => {
|
|
1792
|
+
if (isUsableContextLength(entry.contextLength)) {
|
|
1793
|
+
return entry;
|
|
1794
|
+
}
|
|
1795
|
+
if (route.model !== void 0 && entry.modelId !== route.model) {
|
|
1796
|
+
return entry;
|
|
1797
|
+
}
|
|
1798
|
+
return {
|
|
1799
|
+
...entry,
|
|
1800
|
+
contextLength: configured,
|
|
1801
|
+
metadata: { ...entry.metadata ?? {}, contextWindowSource: "configured" }
|
|
1802
|
+
};
|
|
1803
|
+
});
|
|
1804
|
+
}
|
|
1733
1805
|
function modelContextCacheKey(input) {
|
|
1734
1806
|
if (typeof input === "string") {
|
|
1735
1807
|
return { key: `::${input}`, model: input };
|
|
@@ -4726,18 +4798,19 @@ function canonicalGeminiImageModelId(modelId) {
|
|
|
4726
4798
|
}
|
|
4727
4799
|
function buildModelCatalog(route, availableModels, currentModelId) {
|
|
4728
4800
|
const requestedModelId = route.model;
|
|
4729
|
-
const
|
|
4801
|
+
const filledModels = fillConfiguredContextLength(route, availableModels);
|
|
4802
|
+
const requestedModelAdvertised = filledModels.some(
|
|
4730
4803
|
(model) => model.modelId === requestedModelId
|
|
4731
4804
|
);
|
|
4732
4805
|
const canonicalModelId = route.provider === "gemini" ? canonicalGeminiImageModelId(requestedModelId) : void 0;
|
|
4733
|
-
const resolvedModelId = requestedModelAdvertised ? requestedModelId : canonicalModelId &&
|
|
4806
|
+
const resolvedModelId = requestedModelAdvertised ? requestedModelId : canonicalModelId && filledModels.some((model) => model.modelId === canonicalModelId) ? canonicalModelId : void 0;
|
|
4734
4807
|
return {
|
|
4735
4808
|
requestedModelId,
|
|
4736
4809
|
requestedModelAdvertised,
|
|
4737
4810
|
...canonicalModelId ? { canonicalModelId } : {},
|
|
4738
4811
|
...resolvedModelId ? { resolvedModelId } : {},
|
|
4739
4812
|
...currentModelId ? { currentModelId } : {},
|
|
4740
|
-
availableModels
|
|
4813
|
+
availableModels: filledModels
|
|
4741
4814
|
};
|
|
4742
4815
|
}
|
|
4743
4816
|
function parseOpenAiModelCatalog(route, payload) {
|
|
@@ -7966,6 +8039,10 @@ var AcpConnection = class {
|
|
|
7966
8039
|
`ACP route "${context.route.id}" did not return an ACP model catalog in session/new.`
|
|
7967
8040
|
);
|
|
7968
8041
|
}
|
|
8042
|
+
catalog.availableModels = fillConfiguredContextLength(
|
|
8043
|
+
context.route,
|
|
8044
|
+
catalog.availableModels
|
|
8045
|
+
);
|
|
7969
8046
|
return catalog;
|
|
7970
8047
|
} finally {
|
|
7971
8048
|
this.bumpIdleTimer();
|
|
@@ -8907,14 +8984,26 @@ function normalizeCliDiscoveryAcpSource(route, discovery) {
|
|
|
8907
8984
|
};
|
|
8908
8985
|
}
|
|
8909
8986
|
function resolveCliDiscoverySource(route) {
|
|
8910
|
-
const
|
|
8911
|
-
|
|
8912
|
-
|
|
8987
|
+
const discovery = route.transport.cli?.discovery;
|
|
8988
|
+
const hasModels = (route.advertisedModels?.length ?? 0) > 0;
|
|
8989
|
+
const hasAcpDefault = Boolean(defaultCliDiscoveryTransportIdForRoute(route));
|
|
8990
|
+
const via = discovery?.via ?? (discovery?.command ? "command" : hasAcpDefault ? "acp" : hasModels ? "static" : "none");
|
|
8991
|
+
switch (via) {
|
|
8992
|
+
case "none":
|
|
8993
|
+
return { via: "none" };
|
|
8994
|
+
case "static":
|
|
8995
|
+
return { via: "static" };
|
|
8996
|
+
case "command": {
|
|
8997
|
+
const command = discovery?.command;
|
|
8998
|
+
if (!command) {
|
|
8999
|
+
return { via: "none" };
|
|
9000
|
+
}
|
|
9001
|
+
const fallback = discovery?.fallback ?? (hasModels ? "static" : "none");
|
|
9002
|
+
return { via: "command", command, fallback };
|
|
9003
|
+
}
|
|
9004
|
+
default:
|
|
9005
|
+
return normalizeCliDiscoveryAcpSource(route, discovery?.acp);
|
|
8913
9006
|
}
|
|
8914
|
-
return normalizeCliDiscoveryAcpSource(
|
|
8915
|
-
route,
|
|
8916
|
-
route.transport.cli?.discovery?.acp
|
|
8917
|
-
);
|
|
8918
9007
|
}
|
|
8919
9008
|
function createCliDiscoveryAcpRoute(route) {
|
|
8920
9009
|
const discovery = resolveCliDiscoverySource(route);
|
|
@@ -9023,6 +9112,42 @@ async function buildCliInvocation(context, options) {
|
|
|
9023
9112
|
parameterKeys
|
|
9024
9113
|
};
|
|
9025
9114
|
}
|
|
9115
|
+
function buildCliDiscoveryInvocation(route, command, options) {
|
|
9116
|
+
const commandLine = command.command?.trim() ? command.command : resolveCliCommand(route, options);
|
|
9117
|
+
const resolved = splitCommandLine2(commandLine);
|
|
9118
|
+
const parameterKeys = [];
|
|
9119
|
+
const args = [
|
|
9120
|
+
...resolved.args,
|
|
9121
|
+
...command.argsTemplate.map((part) => {
|
|
9122
|
+
if (part === "{model}") {
|
|
9123
|
+
parameterKeys.push("model");
|
|
9124
|
+
return route.model;
|
|
9125
|
+
}
|
|
9126
|
+
if (part.startsWith("--")) {
|
|
9127
|
+
parameterKeys.push(part);
|
|
9128
|
+
}
|
|
9129
|
+
return part;
|
|
9130
|
+
})
|
|
9131
|
+
];
|
|
9132
|
+
return {
|
|
9133
|
+
command: resolved.command,
|
|
9134
|
+
args,
|
|
9135
|
+
cwd: path2.resolve(options?.cwd ?? process.cwd()),
|
|
9136
|
+
env: buildCliEnvironment(options),
|
|
9137
|
+
parameterKeys
|
|
9138
|
+
};
|
|
9139
|
+
}
|
|
9140
|
+
function buildStaticCliCatalog(route) {
|
|
9141
|
+
const models = route.advertisedModels.map((id) => ({
|
|
9142
|
+
modelId: id,
|
|
9143
|
+
name: id
|
|
9144
|
+
}));
|
|
9145
|
+
return buildModelCatalog(
|
|
9146
|
+
route,
|
|
9147
|
+
models,
|
|
9148
|
+
currentModelIdForRoute(route, route.advertisedModels)
|
|
9149
|
+
);
|
|
9150
|
+
}
|
|
9026
9151
|
function statsToUsage(stats) {
|
|
9027
9152
|
if (!stats || typeof stats !== "object") {
|
|
9028
9153
|
return void 0;
|
|
@@ -9060,6 +9185,9 @@ function getValueByPath(value, dotPath) {
|
|
|
9060
9185
|
}
|
|
9061
9186
|
return current;
|
|
9062
9187
|
}
|
|
9188
|
+
function splitJsonlLines(stdout) {
|
|
9189
|
+
return stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => JSON.parse(line));
|
|
9190
|
+
}
|
|
9063
9191
|
function normalizeErrorMessage(value) {
|
|
9064
9192
|
if (typeof value === "string" && value.trim()) {
|
|
9065
9193
|
return value.trim();
|
|
@@ -9107,7 +9235,7 @@ function parseGenericJsonCli(stdout, parser) {
|
|
|
9107
9235
|
};
|
|
9108
9236
|
}
|
|
9109
9237
|
function parseGenericJsonlCli(stdout, parser) {
|
|
9110
|
-
const entries = stdout
|
|
9238
|
+
const entries = splitJsonlLines(stdout);
|
|
9111
9239
|
const errorValue = parser.error ? findJsonlSelection(entries, parser.error) : void 0;
|
|
9112
9240
|
const errorMessage = normalizeErrorMessage(errorValue);
|
|
9113
9241
|
if (errorMessage) {
|
|
@@ -9128,6 +9256,70 @@ function parseGenericJsonlCli(stdout, parser) {
|
|
|
9128
9256
|
data: entries
|
|
9129
9257
|
};
|
|
9130
9258
|
}
|
|
9259
|
+
var ANSI_ESCAPE_PATTERN = /\[[0-?]*[ -/]*[@-~]/g;
|
|
9260
|
+
function parseTextCli(stdout, parser) {
|
|
9261
|
+
let text = stdout;
|
|
9262
|
+
if (parser.stripAnsi) {
|
|
9263
|
+
text = text.replace(ANSI_ESCAPE_PATTERN, "");
|
|
9264
|
+
}
|
|
9265
|
+
if (parser.trim !== false) {
|
|
9266
|
+
text = text.trim();
|
|
9267
|
+
}
|
|
9268
|
+
if (!text) {
|
|
9269
|
+
throw new AiConnectError(
|
|
9270
|
+
"temporary_unavailable",
|
|
9271
|
+
"CLI text parser produced no output."
|
|
9272
|
+
);
|
|
9273
|
+
}
|
|
9274
|
+
return { text, data: stdout };
|
|
9275
|
+
}
|
|
9276
|
+
function modelInfoFromRecord(record, selector) {
|
|
9277
|
+
const rawId = getValueByPath(record, selector.idPath);
|
|
9278
|
+
const modelId = typeof rawId === "string" ? rawId.trim() : "";
|
|
9279
|
+
if (!modelId) {
|
|
9280
|
+
return void 0;
|
|
9281
|
+
}
|
|
9282
|
+
const rawName = selector.namePath ? getValueByPath(record, selector.namePath) : void 0;
|
|
9283
|
+
const name = typeof rawName === "string" && rawName.trim().length > 0 ? rawName : modelId;
|
|
9284
|
+
const rawDescription = selector.descriptionPath ? getValueByPath(record, selector.descriptionPath) : void 0;
|
|
9285
|
+
const description = typeof rawDescription === "string" && rawDescription.trim().length > 0 ? rawDescription : void 0;
|
|
9286
|
+
const rawContext = selector.contextLengthPath ? getValueByPath(record, selector.contextLengthPath) : void 0;
|
|
9287
|
+
const contextLength = typeof rawContext === "number" && Number.isFinite(rawContext) && rawContext > 0 ? Math.floor(rawContext) : void 0;
|
|
9288
|
+
return {
|
|
9289
|
+
modelId,
|
|
9290
|
+
name,
|
|
9291
|
+
...description ? { description } : {},
|
|
9292
|
+
...contextLength !== void 0 ? { contextLength } : {}
|
|
9293
|
+
};
|
|
9294
|
+
}
|
|
9295
|
+
function parseCliModelList(stdout, parser, selector) {
|
|
9296
|
+
if (parser.kind === "text") {
|
|
9297
|
+
let text = stdout;
|
|
9298
|
+
if (parser.stripAnsi) {
|
|
9299
|
+
text = text.replace(ANSI_ESCAPE_PATTERN, "");
|
|
9300
|
+
}
|
|
9301
|
+
return text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => ({ modelId: line, name: line }));
|
|
9302
|
+
}
|
|
9303
|
+
if (!selector) {
|
|
9304
|
+
throw new AiConnectError(
|
|
9305
|
+
"validation_error",
|
|
9306
|
+
`CLI ${parser.kind} discovery parser requires a models selector with idPath.`
|
|
9307
|
+
);
|
|
9308
|
+
}
|
|
9309
|
+
const records = parser.kind === "jsonl" ? splitJsonlLines(stdout) : (() => {
|
|
9310
|
+
const payload = JSON.parse(stdout);
|
|
9311
|
+
const arr = selector.path ? getValueByPath(payload, selector.path) : payload;
|
|
9312
|
+
return Array.isArray(arr) ? arr : [];
|
|
9313
|
+
})();
|
|
9314
|
+
const models = [];
|
|
9315
|
+
for (const record of records) {
|
|
9316
|
+
const info = modelInfoFromRecord(record, selector);
|
|
9317
|
+
if (info) {
|
|
9318
|
+
models.push(info);
|
|
9319
|
+
}
|
|
9320
|
+
}
|
|
9321
|
+
return models;
|
|
9322
|
+
}
|
|
9131
9323
|
function parseGeminiCli(stdout) {
|
|
9132
9324
|
const payload = JSON.parse(stdout);
|
|
9133
9325
|
if (typeof payload.error === "string") {
|
|
@@ -9199,8 +9391,7 @@ function parseClaudeCli(stdout) {
|
|
|
9199
9391
|
};
|
|
9200
9392
|
}
|
|
9201
9393
|
function parseCodexCli(stdout, outputFileContent) {
|
|
9202
|
-
const
|
|
9203
|
-
const events = lines.map((line) => JSON.parse(line));
|
|
9394
|
+
const events = splitJsonlLines(stdout);
|
|
9204
9395
|
let text = outputFileContent?.trim() || void 0;
|
|
9205
9396
|
let usage;
|
|
9206
9397
|
for (const event of events) {
|
|
@@ -9258,7 +9449,14 @@ function parseCliResult(route, result, outputFileContent) {
|
|
|
9258
9449
|
`CLI route "${route.id}" declared a parser override but normalization did not preserve it.`
|
|
9259
9450
|
);
|
|
9260
9451
|
}
|
|
9261
|
-
|
|
9452
|
+
switch (parser.kind) {
|
|
9453
|
+
case "text":
|
|
9454
|
+
return parseTextCli(result.stdout, parser);
|
|
9455
|
+
case "json":
|
|
9456
|
+
return parseGenericJsonCli(stdout, parser);
|
|
9457
|
+
default:
|
|
9458
|
+
return parseGenericJsonlCli(stdout, parser);
|
|
9459
|
+
}
|
|
9262
9460
|
}
|
|
9263
9461
|
switch (cliOptions.preset) {
|
|
9264
9462
|
case "gemini":
|
|
@@ -9361,6 +9559,88 @@ async function cleanupCliInvocation(invocation) {
|
|
|
9361
9559
|
}
|
|
9362
9560
|
function createCliTransportManager(options) {
|
|
9363
9561
|
return {
|
|
9562
|
+
async discoverModels(context) {
|
|
9563
|
+
const source = resolveCliDiscoverySource(context.route);
|
|
9564
|
+
if (source.via === "none") {
|
|
9565
|
+
throw new AiConnectError(
|
|
9566
|
+
"not_supported",
|
|
9567
|
+
`CLI transport "${context.route.transport.id}" does not support model discovery (no list command, no ACP sidecar, and no configured models[]).`
|
|
9568
|
+
);
|
|
9569
|
+
}
|
|
9570
|
+
if (source.via === "acp") {
|
|
9571
|
+
throw new AiConnectError(
|
|
9572
|
+
"not_supported",
|
|
9573
|
+
`CLI route "${context.route.id}" resolves discovery via acp; dispatch to the acp discovery route instead.`
|
|
9574
|
+
);
|
|
9575
|
+
}
|
|
9576
|
+
if (source.via === "static") {
|
|
9577
|
+
return buildStaticCliCatalog(context.route);
|
|
9578
|
+
}
|
|
9579
|
+
const phases = [];
|
|
9580
|
+
const invocation = buildCliDiscoveryInvocation(
|
|
9581
|
+
context.route,
|
|
9582
|
+
source.command,
|
|
9583
|
+
options
|
|
9584
|
+
);
|
|
9585
|
+
context.telemetry?.captureTransport({
|
|
9586
|
+
protocol: "cli",
|
|
9587
|
+
endpoint: invocation.command,
|
|
9588
|
+
method: "process",
|
|
9589
|
+
bodyKeys: ["argv"],
|
|
9590
|
+
parameterKeys: invocation.parameterKeys,
|
|
9591
|
+
phases,
|
|
9592
|
+
stream: false
|
|
9593
|
+
});
|
|
9594
|
+
try {
|
|
9595
|
+
let models;
|
|
9596
|
+
try {
|
|
9597
|
+
const execution = await executeCliInvocation(
|
|
9598
|
+
invocation,
|
|
9599
|
+
options?.timeoutMs ?? 6e4,
|
|
9600
|
+
phases,
|
|
9601
|
+
context.abort.signal
|
|
9602
|
+
);
|
|
9603
|
+
if (execution.exitCode !== 0 || !execution.stdout.trim()) {
|
|
9604
|
+
throw new AiConnectError(
|
|
9605
|
+
"temporary_unavailable",
|
|
9606
|
+
execution.stderr.trim() || `CLI discovery command for "${context.route.transport.id}" exited with code ${execution.exitCode ?? "null"}.`
|
|
9607
|
+
);
|
|
9608
|
+
}
|
|
9609
|
+
models = parseCliModelList(
|
|
9610
|
+
execution.stdout,
|
|
9611
|
+
source.command.parser,
|
|
9612
|
+
source.command.models
|
|
9613
|
+
);
|
|
9614
|
+
} catch (error) {
|
|
9615
|
+
if (error instanceof AiConnectError && error.code === "aborted") {
|
|
9616
|
+
throw error;
|
|
9617
|
+
}
|
|
9618
|
+
if (source.fallback === "static") {
|
|
9619
|
+
return buildStaticCliCatalog(context.route);
|
|
9620
|
+
}
|
|
9621
|
+
throw error;
|
|
9622
|
+
}
|
|
9623
|
+
if (models.length === 0) {
|
|
9624
|
+
if (source.fallback === "static") {
|
|
9625
|
+
return buildStaticCliCatalog(context.route);
|
|
9626
|
+
}
|
|
9627
|
+
throw new AiConnectError(
|
|
9628
|
+
"temporary_unavailable",
|
|
9629
|
+
`CLI discovery command for "${context.route.transport.id}" returned no models.`
|
|
9630
|
+
);
|
|
9631
|
+
}
|
|
9632
|
+
return buildModelCatalog(
|
|
9633
|
+
context.route,
|
|
9634
|
+
models,
|
|
9635
|
+
currentModelIdForRoute(
|
|
9636
|
+
context.route,
|
|
9637
|
+
models.map((model) => model.modelId)
|
|
9638
|
+
)
|
|
9639
|
+
);
|
|
9640
|
+
} finally {
|
|
9641
|
+
await cleanupCliInvocation(invocation);
|
|
9642
|
+
}
|
|
9643
|
+
},
|
|
9364
9644
|
async runPrompt(context) {
|
|
9365
9645
|
const invocation = await buildCliInvocation(context, options);
|
|
9366
9646
|
const phases = [];
|
|
@@ -9880,17 +10160,21 @@ function createLocalRouteHandlers(options = {}) {
|
|
|
9880
10160
|
return cliTransport.runPrompt(context);
|
|
9881
10161
|
},
|
|
9882
10162
|
async discoverModels(context) {
|
|
9883
|
-
const
|
|
9884
|
-
if (
|
|
9885
|
-
|
|
9886
|
-
|
|
9887
|
-
|
|
9888
|
-
|
|
10163
|
+
const source = resolveCliDiscoverySource(context.route);
|
|
10164
|
+
if (source.via === "acp") {
|
|
10165
|
+
const discoveryRoute = createCliDiscoveryAcpRoute(context.route);
|
|
10166
|
+
if (!discoveryRoute) {
|
|
10167
|
+
throw new AiConnectError(
|
|
10168
|
+
"not_supported",
|
|
10169
|
+
`CLI route "${context.route.id}" does not define a model discovery backend.`
|
|
10170
|
+
);
|
|
10171
|
+
}
|
|
10172
|
+
return acpTransport.discoverModels({
|
|
10173
|
+
...context,
|
|
10174
|
+
route: discoveryRoute
|
|
10175
|
+
});
|
|
9889
10176
|
}
|
|
9890
|
-
return
|
|
9891
|
-
...context,
|
|
9892
|
-
route: discoveryRoute
|
|
9893
|
-
});
|
|
10177
|
+
return cliTransport.discoverModels(context);
|
|
9894
10178
|
},
|
|
9895
10179
|
async verify({ route, runtime }) {
|
|
9896
10180
|
try {
|