@vedmalex/ai-connect 0.2.0 → 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/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 parser = (() => {
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 via = descriptor.cli.discovery.via ?? "none";
258
- assert(
259
- via === "none" || via === "acp",
260
- `Unsupported CLI discovery mode "${String(via)}" for provider "${providerId}".`
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 = via === "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 };
@@ -2175,6 +2247,7 @@ function normalizeResult(route, output, attempts) {
2175
2247
  attempts,
2176
2248
  ...output.toolCalls ? { toolCalls: output.toolCalls } : {},
2177
2249
  ...output.text !== void 0 ? { text: output.text } : {},
2250
+ ...output.reasoning !== void 0 ? { reasoning: output.reasoning } : {},
2178
2251
  ...output.data !== void 0 ? { data: output.data } : {},
2179
2252
  ...output.usage !== void 0 ? { usage: output.usage } : {}
2180
2253
  };
@@ -4725,18 +4798,19 @@ function canonicalGeminiImageModelId(modelId) {
4725
4798
  }
4726
4799
  function buildModelCatalog(route, availableModels, currentModelId) {
4727
4800
  const requestedModelId = route.model;
4728
- const requestedModelAdvertised = availableModels.some(
4801
+ const filledModels = fillConfiguredContextLength(route, availableModels);
4802
+ const requestedModelAdvertised = filledModels.some(
4729
4803
  (model) => model.modelId === requestedModelId
4730
4804
  );
4731
4805
  const canonicalModelId = route.provider === "gemini" ? canonicalGeminiImageModelId(requestedModelId) : void 0;
4732
- const resolvedModelId = requestedModelAdvertised ? requestedModelId : canonicalModelId && availableModels.some((model) => model.modelId === canonicalModelId) ? canonicalModelId : void 0;
4806
+ const resolvedModelId = requestedModelAdvertised ? requestedModelId : canonicalModelId && filledModels.some((model) => model.modelId === canonicalModelId) ? canonicalModelId : void 0;
4733
4807
  return {
4734
4808
  requestedModelId,
4735
4809
  requestedModelAdvertised,
4736
4810
  ...canonicalModelId ? { canonicalModelId } : {},
4737
4811
  ...resolvedModelId ? { resolvedModelId } : {},
4738
4812
  ...currentModelId ? { currentModelId } : {},
4739
- availableModels
4813
+ availableModels: filledModels
4740
4814
  };
4741
4815
  }
4742
4816
  function parseOpenAiModelCatalog(route, payload) {
@@ -5551,6 +5625,9 @@ function extractText(value) {
5551
5625
  return [part];
5552
5626
  }
5553
5627
  if (part && typeof part === "object") {
5628
+ if (part.thought === true) {
5629
+ return [];
5630
+ }
5554
5631
  const candidate = part.text;
5555
5632
  if (typeof candidate === "string") {
5556
5633
  return [candidate];
@@ -5561,6 +5638,22 @@ function extractText(value) {
5561
5638
  }
5562
5639
  return "";
5563
5640
  }
5641
+ function extractThoughts(value) {
5642
+ if (!Array.isArray(value)) {
5643
+ return void 0;
5644
+ }
5645
+ const thoughts = value.flatMap((part) => {
5646
+ if (part && typeof part === "object" && part.thought === true) {
5647
+ const candidate = part.text;
5648
+ if (typeof candidate === "string") {
5649
+ return [candidate];
5650
+ }
5651
+ }
5652
+ return [];
5653
+ });
5654
+ const joined = thoughts.join("\n").trim();
5655
+ return joined.length > 0 ? joined : void 0;
5656
+ }
5564
5657
  function imageAttachmentsFromPayload(payload, ...sources) {
5565
5658
  return extractImagePayloads(payload, ...sources).map(
5566
5659
  (item) => preparePortableFile(item)
@@ -6103,8 +6196,11 @@ async function runGemini(fetchImpl, context) {
6103
6196
  throw classifyApiError(provider, response, payload);
6104
6197
  }
6105
6198
  const data = payload;
6199
+ const geminiThoughts = extractThoughts(data.candidates?.[0]?.content?.parts);
6106
6200
  return {
6107
6201
  text: extractText(data.candidates?.[0]?.content?.parts),
6202
+ // The model's `{ thought: true }` parts, separated from the answer (consumers route this to a thinking UI).
6203
+ ...geminiThoughts ? { reasoning: geminiThoughts } : {},
6108
6204
  data,
6109
6205
  ...geminiToolCallsFromPayload(data).length > 0 ? { toolCalls: geminiToolCallsFromPayload(data) } : {},
6110
6206
  ...(() => {
@@ -7943,6 +8039,10 @@ var AcpConnection = class {
7943
8039
  `ACP route "${context.route.id}" did not return an ACP model catalog in session/new.`
7944
8040
  );
7945
8041
  }
8042
+ catalog.availableModels = fillConfiguredContextLength(
8043
+ context.route,
8044
+ catalog.availableModels
8045
+ );
7946
8046
  return catalog;
7947
8047
  } finally {
7948
8048
  this.bumpIdleTimer();
@@ -8884,14 +8984,26 @@ function normalizeCliDiscoveryAcpSource(route, discovery) {
8884
8984
  };
8885
8985
  }
8886
8986
  function resolveCliDiscoverySource(route) {
8887
- const via = route.transport.cli?.discovery?.via ?? (defaultCliDiscoveryTransportIdForRoute(route) ? "acp" : "none");
8888
- if (via === "none") {
8889
- return { via: "none" };
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);
8890
9006
  }
8891
- return normalizeCliDiscoveryAcpSource(
8892
- route,
8893
- route.transport.cli?.discovery?.acp
8894
- );
8895
9007
  }
8896
9008
  function createCliDiscoveryAcpRoute(route) {
8897
9009
  const discovery = resolveCliDiscoverySource(route);
@@ -9000,6 +9112,42 @@ async function buildCliInvocation(context, options) {
9000
9112
  parameterKeys
9001
9113
  };
9002
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
+ }
9003
9151
  function statsToUsage(stats) {
9004
9152
  if (!stats || typeof stats !== "object") {
9005
9153
  return void 0;
@@ -9037,6 +9185,9 @@ function getValueByPath(value, dotPath) {
9037
9185
  }
9038
9186
  return current;
9039
9187
  }
9188
+ function splitJsonlLines(stdout) {
9189
+ return stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => JSON.parse(line));
9190
+ }
9040
9191
  function normalizeErrorMessage(value) {
9041
9192
  if (typeof value === "string" && value.trim()) {
9042
9193
  return value.trim();
@@ -9084,7 +9235,7 @@ function parseGenericJsonCli(stdout, parser) {
9084
9235
  };
9085
9236
  }
9086
9237
  function parseGenericJsonlCli(stdout, parser) {
9087
- const entries = stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => JSON.parse(line));
9238
+ const entries = splitJsonlLines(stdout);
9088
9239
  const errorValue = parser.error ? findJsonlSelection(entries, parser.error) : void 0;
9089
9240
  const errorMessage = normalizeErrorMessage(errorValue);
9090
9241
  if (errorMessage) {
@@ -9105,6 +9256,70 @@ function parseGenericJsonlCli(stdout, parser) {
9105
9256
  data: entries
9106
9257
  };
9107
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
+ }
9108
9323
  function parseGeminiCli(stdout) {
9109
9324
  const payload = JSON.parse(stdout);
9110
9325
  if (typeof payload.error === "string") {
@@ -9176,8 +9391,7 @@ function parseClaudeCli(stdout) {
9176
9391
  };
9177
9392
  }
9178
9393
  function parseCodexCli(stdout, outputFileContent) {
9179
- const lines = stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
9180
- const events = lines.map((line) => JSON.parse(line));
9394
+ const events = splitJsonlLines(stdout);
9181
9395
  let text = outputFileContent?.trim() || void 0;
9182
9396
  let usage;
9183
9397
  for (const event of events) {
@@ -9235,7 +9449,14 @@ function parseCliResult(route, result, outputFileContent) {
9235
9449
  `CLI route "${route.id}" declared a parser override but normalization did not preserve it.`
9236
9450
  );
9237
9451
  }
9238
- return parser.kind === "json" ? parseGenericJsonCli(stdout, parser) : parseGenericJsonlCli(stdout, parser);
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
+ }
9239
9460
  }
9240
9461
  switch (cliOptions.preset) {
9241
9462
  case "gemini":
@@ -9338,6 +9559,88 @@ async function cleanupCliInvocation(invocation) {
9338
9559
  }
9339
9560
  function createCliTransportManager(options) {
9340
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
+ },
9341
9644
  async runPrompt(context) {
9342
9645
  const invocation = await buildCliInvocation(context, options);
9343
9646
  const phases = [];
@@ -9857,17 +10160,21 @@ function createLocalRouteHandlers(options = {}) {
9857
10160
  return cliTransport.runPrompt(context);
9858
10161
  },
9859
10162
  async discoverModels(context) {
9860
- const discoveryRoute = createCliDiscoveryAcpRoute(context.route);
9861
- if (!discoveryRoute) {
9862
- throw new AiConnectError(
9863
- "not_supported",
9864
- `CLI route "${context.route.id}" does not define a model discovery backend.`
9865
- );
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
+ });
9866
10176
  }
9867
- return acpTransport.discoverModels({
9868
- ...context,
9869
- route: discoveryRoute
9870
- });
10177
+ return cliTransport.discoverModels(context);
9871
10178
  },
9872
10179
  async verify({ route, runtime }) {
9873
10180
  try {