@oh-my-pi/pi-coding-agent 16.2.9 → 16.2.12
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/CHANGELOG.md +60 -0
- package/dist/cli.js +3464 -3306
- package/dist/types/cli/bench-cli.d.ts +0 -5
- package/dist/types/cli/dry-balance-cli.d.ts +0 -5
- package/dist/types/cli/models-cli.d.ts +1 -1
- package/dist/types/config/inline-tool-descriptors-mode.d.ts +1 -2
- package/dist/types/config/model-registry.d.ts +1 -23
- package/dist/types/config/model-resolver.d.ts +10 -15
- package/dist/types/config/models-config-schema.d.ts +0 -6
- package/dist/types/config/models-config.d.ts +0 -6
- package/dist/types/config/settings-schema.d.ts +31 -1
- package/dist/types/eval/py/__tests__/runner-shell-output.test.d.ts +1 -0
- package/dist/types/extensibility/extensions/runner.d.ts +15 -0
- package/dist/types/extensibility/skills.d.ts +29 -0
- package/dist/types/lsp/client.d.ts +9 -3
- package/dist/types/modes/components/todo-reminder.d.ts +3 -1
- package/dist/types/modes/interactive-mode.d.ts +0 -1
- package/dist/types/modes/skill-command.d.ts +1 -1
- package/dist/types/modes/types.d.ts +0 -1
- package/dist/types/stt/asr-client.d.ts +7 -3
- package/dist/types/task/spawn-policy.d.ts +17 -0
- package/dist/types/task/spawn-policy.test.d.ts +1 -0
- package/dist/types/task/types.d.ts +8 -2
- package/dist/types/tools/__tests__/eval-description.test.d.ts +1 -0
- package/dist/types/tools/browser/cmux/cmux-tab.d.ts +2 -2
- package/dist/types/tools/browser/registry.d.ts +2 -0
- package/dist/types/tools/browser/run-cancellation.d.ts +4 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +30 -1
- package/dist/types/tools/eval.d.ts +3 -6
- package/dist/types/tools/write.d.ts +1 -1
- package/dist/types/utils/image-vision-fallback.d.ts +1 -1
- package/package.json +14 -13
- package/scripts/bundle-dist.ts +23 -4
- package/scripts/generate-docs-index.ts +116 -24
- package/src/advisor/__tests__/advisor.test.ts +1 -1
- package/src/async/job-manager.ts +27 -3
- package/src/auto-thinking/classifier.ts +1 -1
- package/src/cli/bench-cli.ts +3 -12
- package/src/cli/dry-balance-cli.ts +1 -6
- package/src/cli/grep-cli.ts +1 -1
- package/src/cli/models-cli.ts +3 -81
- package/src/commands/models.ts +1 -2
- package/src/commit/model-selection.ts +4 -4
- package/src/config/inline-tool-descriptors-mode.ts +1 -2
- package/src/config/model-discovery.ts +150 -82
- package/src/config/model-registry.ts +11 -225
- package/src/config/model-resolver.ts +23 -135
- package/src/config/models-config-schema.ts +0 -22
- package/src/config/prompt-templates.ts +20 -0
- package/src/config/settings-schema.ts +35 -1
- package/src/config/settings.ts +60 -24
- package/src/eval/__tests__/agent-bridge.test.ts +17 -3
- package/src/eval/agent-bridge.ts +7 -9
- package/src/eval/completion-bridge.ts +1 -1
- package/src/eval/py/__tests__/runner-shell-output.test.ts +157 -0
- package/src/eval/py/runner.py +169 -18
- package/src/extensibility/extensions/model-api.ts +1 -3
- package/src/extensibility/extensions/runner.ts +62 -5
- package/src/extensibility/skills.ts +77 -0
- package/src/internal-urls/docs-index.generated.txt +2 -2
- package/src/lsp/client.ts +162 -45
- package/src/lsp/config.ts +17 -3
- package/src/lsp/index.ts +31 -21
- package/src/main.ts +0 -1
- package/src/mcp/transports/http.ts +19 -17
- package/src/mcp/transports/stdio.test.ts +51 -1
- package/src/mcp/transports/stdio.ts +19 -9
- package/src/memories/index.ts +0 -1
- package/src/mnemopi/backend.ts +1 -1
- package/src/modes/acp/acp-agent.ts +6 -9
- package/src/modes/components/model-selector.ts +32 -186
- package/src/modes/components/todo-reminder.ts +5 -1
- package/src/modes/controllers/event-controller.ts +1 -16
- package/src/modes/controllers/selector-controller.ts +57 -36
- package/src/modes/interactive-mode.ts +0 -6
- package/src/modes/rpc/rpc-mode.ts +5 -8
- package/src/modes/skill-command.ts +8 -20
- package/src/modes/types.ts +0 -1
- package/src/prompts/system/subagent-system-prompt.md +2 -2
- package/src/prompts/system/tool-call-loop-redirect.md +8 -0
- package/src/prompts/tools/eval.md +2 -2
- package/src/prompts/tools/task.md +1 -1
- package/src/sdk.ts +2 -9
- package/src/session/agent-session.ts +89 -8
- package/src/session/session-context.ts +2 -1
- package/src/session/session-manager.ts +2 -1
- package/src/session/unexpected-stop-classifier.ts +1 -1
- package/src/stt/asr-client.ts +87 -27
- package/src/stt/downloader.ts +8 -2
- package/src/task/executor.ts +1 -3
- package/src/task/index.ts +37 -32
- package/src/task/spawn-policy.test.ts +63 -0
- package/src/task/spawn-policy.ts +58 -0
- package/src/task/types.ts +77 -6
- package/src/tools/__tests__/eval-description.test.ts +19 -0
- package/src/tools/ast-grep.ts +34 -12
- package/src/tools/browser/cmux/cmux-tab.ts +66 -24
- package/src/tools/browser/registry.ts +25 -0
- package/src/tools/browser/run-cancellation.ts +47 -0
- package/src/tools/browser/tab-supervisor.ts +120 -7
- package/src/tools/browser/tab-worker.ts +22 -10
- package/src/tools/browser.ts +1 -0
- package/src/tools/eval.ts +15 -10
- package/src/tools/grep.ts +11 -8
- package/src/tools/inspect-image.ts +1 -1
- package/src/tools/write.ts +49 -9
- package/src/utils/commit-message-generator.ts +0 -1
- package/src/utils/git.ts +22 -1
- package/src/utils/image-vision-fallback.ts +2 -3
- package/src/utils/title-generator.ts +1 -1
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
OPENAI_COMPAT_DISCOVERY_DEFAULT_CONTEXT_WINDOW,
|
|
20
20
|
OPENAI_COMPAT_DISCOVERY_DEFAULT_MAX_TOKENS,
|
|
21
21
|
} from "@oh-my-pi/pi-catalog/provider-models/openai-compat";
|
|
22
|
-
import type { ModelSpec } from "@oh-my-pi/pi-catalog/types";
|
|
22
|
+
import type { ModelSpec, OpenAICompat } from "@oh-my-pi/pi-catalog/types";
|
|
23
23
|
import { isRecord } from "@oh-my-pi/pi-utils";
|
|
24
24
|
import type { ProviderDiscovery } from "./models-config-schema";
|
|
25
25
|
|
|
@@ -35,6 +35,31 @@ import type { ProviderDiscovery } from "./models-config-schema";
|
|
|
35
35
|
export const DISCOVERY_DEFAULT_CONTEXT_WINDOW = OPENAI_COMPAT_DISCOVERY_DEFAULT_CONTEXT_WINDOW;
|
|
36
36
|
export const DISCOVERY_DEFAULT_MAX_TOKENS = OPENAI_COMPAT_DISCOVERY_DEFAULT_MAX_TOKENS;
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Run `fn` with an abort signal that fires after `timeoutMs`, clearing the
|
|
40
|
+
* backing timer the instant the operation settles.
|
|
41
|
+
*
|
|
42
|
+
* Unlike the built-in abort-signal timeout API, the timer never outlives the
|
|
43
|
+
* request: on the success path it is cancelled before `fn` resolves, so the
|
|
44
|
+
* signal is never aborted and no pending callback lingers on the heap. A leaked
|
|
45
|
+
* abort-signal timeout (e.g. discovery against a mocked fetch that resolves
|
|
46
|
+
* instantly) fires seconds later and sets its abort `reason` — which crashed
|
|
47
|
+
* Bun's concurrent GC while it marked the signal's wrapped reason during an
|
|
48
|
+
* unrelated allocation (`JSAbortSignal::visitAdditionalChildren`).
|
|
49
|
+
*/
|
|
50
|
+
async function withTimeoutSignal<T>(timeoutMs: number, fn: (signal: AbortSignal) => Promise<T>): Promise<T> {
|
|
51
|
+
const controller = new AbortController();
|
|
52
|
+
const timer = setTimeout(
|
|
53
|
+
() => controller.abort(new DOMException("The operation timed out.", "TimeoutError")),
|
|
54
|
+
timeoutMs,
|
|
55
|
+
);
|
|
56
|
+
try {
|
|
57
|
+
return await fn(controller.signal);
|
|
58
|
+
} finally {
|
|
59
|
+
clearTimeout(timer);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
38
63
|
const DEFAULT_OLLAMA_BASE_URL = "http://127.0.0.1:11434";
|
|
39
64
|
const OLLAMA_HOST_DEFAULT_PORT = "11434";
|
|
40
65
|
|
|
@@ -288,16 +313,18 @@ async function discoverOllamaModelMetadata(
|
|
|
288
313
|
): Promise<OllamaDiscoveredModelMetadata | null> {
|
|
289
314
|
const showUrl = `${endpoint}/api/show`;
|
|
290
315
|
try {
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
316
|
+
const payload = await withTimeoutSignal(150, async signal => {
|
|
317
|
+
const response = await ctx.fetch(showUrl, {
|
|
318
|
+
method: "POST",
|
|
319
|
+
headers: { ...(headers ?? {}), "Content-Type": "application/json" },
|
|
320
|
+
body: JSON.stringify({ model: modelId }),
|
|
321
|
+
signal,
|
|
322
|
+
});
|
|
323
|
+
if (!response.ok) {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
return (await response.json()) as unknown;
|
|
296
327
|
});
|
|
297
|
-
if (!response.ok) {
|
|
298
|
-
return null;
|
|
299
|
-
}
|
|
300
|
-
const payload = (await response.json()) as unknown;
|
|
301
328
|
if (!isRecord(payload)) {
|
|
302
329
|
return null;
|
|
303
330
|
}
|
|
@@ -339,14 +366,16 @@ export async function discoverOllamaModels(
|
|
|
339
366
|
const endpoint = normalizeOllamaBaseUrl(providerConfig.baseUrl);
|
|
340
367
|
const tagsUrl = `${endpoint}/api/tags`;
|
|
341
368
|
const headers = { ...(providerConfig.headers ?? {}) };
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
369
|
+
const payload = await withTimeoutSignal(250, async signal => {
|
|
370
|
+
const response = await ctx.fetch(tagsUrl, {
|
|
371
|
+
headers,
|
|
372
|
+
signal,
|
|
373
|
+
});
|
|
374
|
+
if (!response.ok) {
|
|
375
|
+
throw new Error(`HTTP ${response.status} from ${tagsUrl}`);
|
|
376
|
+
}
|
|
377
|
+
return (await response.json()) as { models?: Array<{ name?: string; model?: string }> };
|
|
345
378
|
});
|
|
346
|
-
if (!response.ok) {
|
|
347
|
-
throw new Error(`HTTP ${response.status} from ${tagsUrl}`);
|
|
348
|
-
}
|
|
349
|
-
const payload = (await response.json()) as { models?: Array<{ name?: string; model?: string }> };
|
|
350
379
|
const entries = (payload.models ?? []).flatMap(item => {
|
|
351
380
|
const id = item.model || item.name;
|
|
352
381
|
return id ? [{ id, name: item.name || id }] : [];
|
|
@@ -384,14 +413,16 @@ async function discoverLlamaCppServerMetadata(
|
|
|
384
413
|
): Promise<LlamaCppDiscoveredServerMetadata | null> {
|
|
385
414
|
const propsUrl = `${toLlamaCppNativeBaseUrl(baseUrl)}/props`;
|
|
386
415
|
try {
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
416
|
+
const payload = await withTimeoutSignal(150, async signal => {
|
|
417
|
+
const response = await ctx.fetch(propsUrl, {
|
|
418
|
+
headers,
|
|
419
|
+
signal,
|
|
420
|
+
});
|
|
421
|
+
if (!response.ok) {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
return (await response.json()) as unknown;
|
|
390
425
|
});
|
|
391
|
-
if (!response.ok) {
|
|
392
|
-
return null;
|
|
393
|
-
}
|
|
394
|
-
const payload = (await response.json()) as unknown;
|
|
395
426
|
if (!isRecord(payload)) {
|
|
396
427
|
return null;
|
|
397
428
|
}
|
|
@@ -415,24 +446,26 @@ export async function discoverLlamaCppModels(
|
|
|
415
446
|
const baseHeaders: Record<string, string> = { ...(providerConfig.headers ?? {}) };
|
|
416
447
|
let headers = baseHeaders;
|
|
417
448
|
const attempt = async (h: Record<string, string>) => {
|
|
418
|
-
const [
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
449
|
+
const [payload, metadata] = await Promise.all([
|
|
450
|
+
withTimeoutSignal(250, async signal => {
|
|
451
|
+
const response = await ctx.fetch(modelsUrl, {
|
|
452
|
+
headers: h,
|
|
453
|
+
signal,
|
|
454
|
+
});
|
|
455
|
+
if (!response.ok) {
|
|
456
|
+
throw new Error(`HTTP ${response.status} from ${modelsUrl}`);
|
|
457
|
+
}
|
|
458
|
+
headers = h;
|
|
459
|
+
return (await response.json()) as unknown;
|
|
422
460
|
}),
|
|
423
461
|
discoverLlamaCppServerMetadata(ctx, baseUrl, h),
|
|
424
462
|
]);
|
|
425
|
-
|
|
426
|
-
throw new Error(`HTTP ${response.status} from ${modelsUrl}`);
|
|
427
|
-
}
|
|
428
|
-
headers = h;
|
|
429
|
-
return [response, metadata] as const;
|
|
463
|
+
return [payload, metadata] as const;
|
|
430
464
|
};
|
|
431
465
|
const apiKey = await ctx.getBearerApiKeyResolver(providerConfig.provider);
|
|
432
|
-
const [
|
|
466
|
+
const [payload, serverMetadata] = apiKey
|
|
433
467
|
? await withAuth(apiKey, key => attempt({ ...baseHeaders, Authorization: `Bearer ${key}` }))
|
|
434
468
|
: await attempt(baseHeaders);
|
|
435
|
-
const payload = (await response.json()) as unknown;
|
|
436
469
|
const models = parseLlamaCppModelList(payload);
|
|
437
470
|
const discovered: Model<Api>[] = [];
|
|
438
471
|
for (const item of models) {
|
|
@@ -476,17 +509,22 @@ export async function discoverLlamaCppModelRuntimeMetadata(
|
|
|
476
509
|
const modelsUrl = `${baseUrl}/models`;
|
|
477
510
|
const baseHeaders: Record<string, string> = { ...(model.headers ?? {}) };
|
|
478
511
|
const attempt = async (headers: Record<string, string>) => {
|
|
479
|
-
const [
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
512
|
+
const [entries, serverMetadata] = await Promise.all([
|
|
513
|
+
withTimeoutSignal(250, async signal => {
|
|
514
|
+
const response = await ctx.fetch(modelsUrl, {
|
|
515
|
+
headers,
|
|
516
|
+
signal,
|
|
517
|
+
});
|
|
518
|
+
if (!response.ok) {
|
|
519
|
+
return undefined;
|
|
520
|
+
}
|
|
521
|
+
return parseLlamaCppModelList(await response.json());
|
|
483
522
|
}),
|
|
484
523
|
discoverLlamaCppServerMetadata(ctx, baseUrl, headers),
|
|
485
524
|
]);
|
|
486
|
-
if (!
|
|
525
|
+
if (!entries) {
|
|
487
526
|
return undefined;
|
|
488
527
|
}
|
|
489
|
-
const entries = parseLlamaCppModelList(await response.json());
|
|
490
528
|
const entry = entries.find(entry => entry.id === model.id);
|
|
491
529
|
if (!entry) {
|
|
492
530
|
return undefined;
|
|
@@ -524,55 +562,83 @@ export async function discoverOpenAIModelsList(
|
|
|
524
562
|
providerConfig.discovery.type === "lm-studio"
|
|
525
563
|
? fetchLmStudioNativeModelMetadata(baseUrl, ctx.fetch, { headers: h })
|
|
526
564
|
: Promise.resolve(null);
|
|
527
|
-
const [
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
565
|
+
const [payload, nativeMetadata] = await Promise.all([
|
|
566
|
+
withTimeoutSignal(10_000, async signal => {
|
|
567
|
+
const res = await ctx.fetch(modelsUrl, {
|
|
568
|
+
headers: h,
|
|
569
|
+
signal,
|
|
570
|
+
});
|
|
571
|
+
if (!res.ok) {
|
|
572
|
+
throw new Error(`HTTP ${res.status} from ${modelsUrl}`);
|
|
573
|
+
}
|
|
574
|
+
headers = h;
|
|
575
|
+
return (await res.json()) as {
|
|
576
|
+
data?: Array<{ id?: string; max_model_len?: unknown; context_length?: unknown }>;
|
|
577
|
+
};
|
|
531
578
|
}),
|
|
532
579
|
nativeMetadataPromise,
|
|
533
580
|
]);
|
|
534
|
-
|
|
535
|
-
throw new Error(`HTTP ${res.status} from ${modelsUrl}`);
|
|
536
|
-
}
|
|
537
|
-
headers = h;
|
|
538
|
-
return [res, nativeMetadata] as const;
|
|
581
|
+
return [payload, nativeMetadata] as const;
|
|
539
582
|
};
|
|
540
583
|
const apiKey = await ctx.getBearerApiKeyResolver(providerConfig.provider);
|
|
541
|
-
const [
|
|
584
|
+
const [payload, nativeMetadata] = apiKey
|
|
542
585
|
? await withAuth(apiKey, key => attempt({ ...baseHeaders, Authorization: `Bearer ${key}` }))
|
|
543
586
|
: await attempt(baseHeaders);
|
|
544
|
-
const payload = (await response.json()) as {
|
|
545
|
-
data?: Array<{ id?: string; max_model_len?: unknown; context_length?: unknown }>;
|
|
546
|
-
};
|
|
547
587
|
const models = payload.data ?? [];
|
|
588
|
+
const references = getBundledModelReferenceIndex();
|
|
548
589
|
const discovered: Model<Api>[] = [];
|
|
549
590
|
for (const item of models) {
|
|
550
591
|
const id = item.id;
|
|
551
592
|
if (!id) continue;
|
|
552
593
|
const nativeMetadataForModel = nativeMetadata?.get(id);
|
|
594
|
+
// Thin OpenAI-compatible proxies frequently omit `context_length`/
|
|
595
|
+
// `max_model_len` on `/v1/models`, leaving discovered models pinned at
|
|
596
|
+
// the 128K default even when the underlying model is e.g. a proxied
|
|
597
|
+
// Claude with a 1M window. Resolve the id against the bundled catalog
|
|
598
|
+
// (same pattern as `discoverProxyModels` and `discoverLiteLLMModels`) so
|
|
599
|
+
// intrinsic metadata — context/output limits, display name, modality,
|
|
600
|
+
// reasoning support — flows through when the provider is silent. Local
|
|
601
|
+
// runtime state and provider-reported values still win; proxy-specific
|
|
602
|
+
// headers/baseUrl/cost stay local.
|
|
603
|
+
const reference = resolveModelReference(id, references) as ModelSpec<Api> | undefined;
|
|
604
|
+
const referenceCompat = reference?.compat as OpenAICompat | undefined;
|
|
553
605
|
const contextWindow =
|
|
554
606
|
toPositiveNumberOrUndefined(item.max_model_len) ??
|
|
555
607
|
toPositiveNumberOrUndefined(item.context_length) ??
|
|
556
608
|
nativeMetadataForModel?.contextWindow ??
|
|
609
|
+
reference?.contextWindow ??
|
|
557
610
|
DISCOVERY_DEFAULT_CONTEXT_WINDOW;
|
|
558
611
|
discovered.push(
|
|
559
612
|
buildModel({
|
|
560
613
|
id,
|
|
561
|
-
name: id,
|
|
614
|
+
name: reference?.name ?? id,
|
|
562
615
|
api: providerConfig.api,
|
|
563
616
|
provider: providerConfig.provider,
|
|
564
617
|
baseUrl,
|
|
565
|
-
reasoning: false,
|
|
566
|
-
|
|
618
|
+
reasoning: reference?.reasoning ?? false,
|
|
619
|
+
thinking: reference?.thinking,
|
|
620
|
+
input: nativeMetadataForModel?.input ?? reference?.input ?? ["text"],
|
|
567
621
|
...(providerConfig.discovery.type === "lm-studio" ? { imageInputDecoder: "stb" as const } : {}),
|
|
622
|
+
// Proxy/gateway pricing is provider-specific and rarely matches
|
|
623
|
+
// upstream bundled catalogs, so keep costs local-unknown even
|
|
624
|
+
// when we successfully recover the upstream model identity.
|
|
568
625
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
569
626
|
contextWindow,
|
|
570
|
-
|
|
627
|
+
// Cap the reference's output limit at the discovered context
|
|
628
|
+
// window so an ID collision with a larger bundled model can
|
|
629
|
+
// never request more tokens than the local runtime advertises.
|
|
630
|
+
maxTokens: Math.min(reference?.maxTokens ?? discoveryDefaultMaxTokens(providerConfig.api), contextWindow),
|
|
571
631
|
headers,
|
|
572
632
|
compat: {
|
|
573
633
|
supportsStore: false,
|
|
574
634
|
supportsDeveloperRole: false,
|
|
575
|
-
supportsReasoningEffort: false,
|
|
635
|
+
supportsReasoningEffort: referenceCompat?.supportsReasoningEffort ?? false,
|
|
636
|
+
...(referenceCompat?.reasoningEffortMap
|
|
637
|
+
? { reasoningEffortMap: referenceCompat.reasoningEffortMap }
|
|
638
|
+
: {}),
|
|
639
|
+
...(referenceCompat?.omitReasoningEffort !== undefined
|
|
640
|
+
? { omitReasoningEffort: referenceCompat.omitReasoningEffort }
|
|
641
|
+
: {}),
|
|
576
642
|
},
|
|
577
643
|
} as ModelSpec<Api>),
|
|
578
644
|
);
|
|
@@ -600,15 +666,17 @@ export async function discoverLiteLLMModels(
|
|
|
600
666
|
}
|
|
601
667
|
return response;
|
|
602
668
|
};
|
|
603
|
-
const models = await
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
669
|
+
const models = await withTimeoutSignal(10_000, signal =>
|
|
670
|
+
fetchLiteLLMRichModels({
|
|
671
|
+
api: providerConfig.api,
|
|
672
|
+
provider: providerConfig.provider,
|
|
673
|
+
baseUrl,
|
|
674
|
+
headers: h,
|
|
675
|
+
fetch: authAwareFetch,
|
|
676
|
+
referenceResolver: resolveReference,
|
|
677
|
+
signal,
|
|
678
|
+
}),
|
|
679
|
+
);
|
|
612
680
|
if (authError && models === null) {
|
|
613
681
|
throw authError;
|
|
614
682
|
}
|
|
@@ -657,24 +725,24 @@ export async function discoverProxyModels(
|
|
|
657
725
|
|
|
658
726
|
const baseHeaders: Record<string, string> = { ...(providerConfig.headers ?? {}) };
|
|
659
727
|
let headers = baseHeaders;
|
|
660
|
-
const attempt = async (h: Record<string, string>) =>
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
728
|
+
const attempt = async (h: Record<string, string>) =>
|
|
729
|
+
withTimeoutSignal(10_000, async signal => {
|
|
730
|
+
const res = await ctx.fetch(modelsUrl, {
|
|
731
|
+
headers: h,
|
|
732
|
+
signal,
|
|
733
|
+
});
|
|
734
|
+
if (!res.ok) {
|
|
735
|
+
throw new Error(`HTTP ${res.status} from ${modelsUrl}`);
|
|
736
|
+
}
|
|
737
|
+
headers = h;
|
|
738
|
+
return (await res.json()) as {
|
|
739
|
+
data?: Array<{ id?: string; name?: string; supported_endpoint_types?: string[]; context_length?: number }>;
|
|
740
|
+
};
|
|
664
741
|
});
|
|
665
|
-
if (!res.ok) {
|
|
666
|
-
throw new Error(`HTTP ${res.status} from ${modelsUrl}`);
|
|
667
|
-
}
|
|
668
|
-
headers = h;
|
|
669
|
-
return res;
|
|
670
|
-
};
|
|
671
742
|
const apiKey = await ctx.getBearerApiKeyResolver(providerConfig.provider);
|
|
672
|
-
const
|
|
743
|
+
const payload = apiKey
|
|
673
744
|
? await withAuth(apiKey, key => attempt({ ...baseHeaders, Authorization: `Bearer ${key}` }))
|
|
674
745
|
: await attempt(baseHeaders);
|
|
675
|
-
const payload = (await response.json()) as {
|
|
676
|
-
data?: Array<{ id?: string; name?: string; supported_endpoint_types?: string[]; context_length?: number }>;
|
|
677
|
-
};
|
|
678
746
|
const items = payload.data ?? [];
|
|
679
747
|
const discovered: Model<Api>[] = [];
|
|
680
748
|
for (const item of items) {
|