@oh-my-pi/pi-coding-agent 16.2.11 → 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 +31 -0
- package/dist/cli.js +3005 -2848
- 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/lsp/client.d.ts +9 -3
- package/dist/types/modes/controllers/tool-args-reveal.d.ts +0 -5
- 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 +12 -12
- package/src/advisor/__tests__/advisor.test.ts +1 -1
- 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/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 +32 -6
- 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/lsp/client.ts +162 -45
- 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/components/model-selector.ts +32 -186
- package/src/modes/controllers/event-controller.ts +8 -39
- package/src/modes/controllers/selector-controller.ts +0 -1
- package/src/modes/controllers/tool-args-reveal.ts +0 -12
- 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/task/index.ts +23 -27
- 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/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/inspect-image.ts +1 -1
- package/src/tools/write.ts +49 -9
- package/src/utils/commit-message-generator.ts +0 -1
- package/src/utils/image-vision-fallback.ts +2 -3
- package/src/utils/title-generator.ts +1 -1
package/src/cli/bench-cli.ts
CHANGED
|
@@ -14,12 +14,12 @@ import type {
|
|
|
14
14
|
SimpleStreamOptions,
|
|
15
15
|
} from "@oh-my-pi/pi-ai";
|
|
16
16
|
import { resolveModelServiceTier, streamSimple } from "@oh-my-pi/pi-ai";
|
|
17
|
-
import { buildModelProviderPriorityRank
|
|
17
|
+
import { buildModelProviderPriorityRank } from "@oh-my-pi/pi-catalog/identity";
|
|
18
18
|
import { replaceTabs, truncateToWidth } from "@oh-my-pi/pi-tui";
|
|
19
19
|
import { formatDuration, getProjectDir } from "@oh-my-pi/pi-utils";
|
|
20
20
|
import chalk from "chalk";
|
|
21
21
|
import type { ApiKeyResolverModel } from "../config/api-key-resolver";
|
|
22
|
-
import {
|
|
22
|
+
import { ModelRegistry } from "../config/model-registry";
|
|
23
23
|
import {
|
|
24
24
|
formatModelSelectorValue,
|
|
25
25
|
formatModelString,
|
|
@@ -55,9 +55,6 @@ export interface BenchModelRegistry {
|
|
|
55
55
|
getAll(): Model<Api>[];
|
|
56
56
|
getApiKey(model: Model<Api>, sessionId?: string): Promise<string | undefined>;
|
|
57
57
|
resolver(model: ApiKeyResolverModel, sessionId?: string): ApiKeyResolver;
|
|
58
|
-
resolveCanonicalModel?(canonicalId: string, options?: CanonicalModelQueryOptions): Model<Api> | undefined;
|
|
59
|
-
getCanonicalVariants?(canonicalId: string, options?: CanonicalModelQueryOptions): CanonicalModelVariant[];
|
|
60
|
-
getCanonicalId?(model: Model<Api>): string | undefined;
|
|
61
58
|
hasConfiguredAuth?(model: Model<Api>): boolean;
|
|
62
59
|
}
|
|
63
60
|
|
|
@@ -440,13 +437,7 @@ function resolveAuthenticatedAlternative(
|
|
|
440
437
|
seen.add(key);
|
|
441
438
|
if (modelRegistry.hasConfiguredAuth?.(candidate)) authenticated.push(candidate);
|
|
442
439
|
};
|
|
443
|
-
//
|
|
444
|
-
// ids differ (e.g. fireworks `gpt-oss-20b` <-> openrouter `openai/gpt-oss-20b`).
|
|
445
|
-
const canonicalId = modelRegistry.getCanonicalId?.(model);
|
|
446
|
-
if (canonicalId) {
|
|
447
|
-
for (const variant of modelRegistry.getCanonicalVariants?.(canonicalId) ?? []) consider(variant.model);
|
|
448
|
-
}
|
|
449
|
-
// Same-id fallback for entries outside the canonical index.
|
|
440
|
+
// Same-id fallback for equivalent entries under providers with configured auth.
|
|
450
441
|
for (const candidate of modelRegistry.getAll()) {
|
|
451
442
|
if (candidate.id === model.id) consider(candidate);
|
|
452
443
|
}
|
|
@@ -12,11 +12,10 @@ import type {
|
|
|
12
12
|
SimpleStreamOptions,
|
|
13
13
|
} from "@oh-my-pi/pi-ai";
|
|
14
14
|
import { streamSimple } from "@oh-my-pi/pi-ai";
|
|
15
|
-
import type { CanonicalModelVariant } from "@oh-my-pi/pi-catalog/identity";
|
|
16
15
|
import { replaceTabs, truncateToWidth } from "@oh-my-pi/pi-tui";
|
|
17
16
|
import { formatDuration, getProjectDir } from "@oh-my-pi/pi-utils";
|
|
18
17
|
import chalk from "chalk";
|
|
19
|
-
import {
|
|
18
|
+
import { ModelRegistry } from "../config/model-registry";
|
|
20
19
|
import {
|
|
21
20
|
formatModelString,
|
|
22
21
|
getModelMatchPreferences,
|
|
@@ -74,9 +73,6 @@ export interface DryBalanceModelRegistry {
|
|
|
74
73
|
getAll(): Model<Api>[];
|
|
75
74
|
getAvailable(): Model<Api>[];
|
|
76
75
|
getApiKey(model: Model<Api>, sessionId?: string): Promise<string | undefined>;
|
|
77
|
-
getCanonicalVariants(canonicalId: string, options?: CanonicalModelQueryOptions): CanonicalModelVariant[];
|
|
78
|
-
resolveCanonicalModel?(canonicalId: string, options?: CanonicalModelQueryOptions): Model<Api> | undefined;
|
|
79
|
-
getCanonicalId?(model: Model<Api>): string | undefined;
|
|
80
76
|
}
|
|
81
77
|
|
|
82
78
|
export interface DryBalanceRuntime {
|
|
@@ -566,7 +562,6 @@ async function resolveDryBalanceModel(
|
|
|
566
562
|
const defaultRoleSpec = resolveModelRoleValue(settings?.getModelRole("default"), allowedModels, {
|
|
567
563
|
settings,
|
|
568
564
|
matchPreferences: preferences,
|
|
569
|
-
modelRegistry,
|
|
570
565
|
});
|
|
571
566
|
if (defaultRoleSpec.model) {
|
|
572
567
|
return { model: defaultRoleSpec.model, warning: defaultRoleSpec.warning };
|
package/src/cli/models-cli.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `omp models` — list, search, and refresh available models.
|
|
3
3
|
*
|
|
4
4
|
* Subcommands:
|
|
5
|
-
* - `ls` (default): list every available model
|
|
5
|
+
* - `ls` (default): list every available model grouped by provider.
|
|
6
6
|
* - `find <substring>`: list models whose provider, id, or name contains the substring.
|
|
7
7
|
* - `refresh`: force an online catalog re-fetch (ignoring the model cache TTL),
|
|
8
8
|
* then list. This is the supported replacement for `rm -rf ~/.omp/models.db`
|
|
@@ -21,7 +21,7 @@ import { discoverAndLoadExtensions, loadExtensions } from "../extensibility/exte
|
|
|
21
21
|
import { discoverAuthStorage } from "../sdk";
|
|
22
22
|
import { EventBus } from "../utils/event-bus";
|
|
23
23
|
|
|
24
|
-
export type ModelsAction = "ls" | "find" | "refresh"
|
|
24
|
+
export type ModelsAction = "ls" | "find" | "refresh";
|
|
25
25
|
|
|
26
26
|
export interface ModelsCommandArgs {
|
|
27
27
|
action: ModelsAction;
|
|
@@ -48,7 +48,6 @@ const KNOWN_ACTIONS: Record<string, ModelsAction> = {
|
|
|
48
48
|
list: "ls",
|
|
49
49
|
find: "find",
|
|
50
50
|
refresh: "refresh",
|
|
51
|
-
canonical: "canonical",
|
|
52
51
|
};
|
|
53
52
|
|
|
54
53
|
/** Resolve the two positional args into an action + filter (provider names fall through to `ls`). */
|
|
@@ -77,22 +76,10 @@ interface ModelJson {
|
|
|
77
76
|
cost: Model<Api>["cost"];
|
|
78
77
|
}
|
|
79
78
|
|
|
80
|
-
interface CanonicalJson {
|
|
81
|
-
id: string;
|
|
82
|
-
selected: string;
|
|
83
|
-
variants: number;
|
|
84
|
-
contextWindow: number | null;
|
|
85
|
-
maxTokens: number | null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
79
|
interface ModelsJson {
|
|
89
80
|
models: ModelJson[];
|
|
90
81
|
}
|
|
91
82
|
|
|
92
|
-
interface CanonicalModelsJson {
|
|
93
|
-
canonical: CanonicalJson[];
|
|
94
|
-
}
|
|
95
|
-
|
|
96
83
|
function writeLine(line = ""): void {
|
|
97
84
|
process.stdout.write(`${line}\n`);
|
|
98
85
|
}
|
|
@@ -253,67 +240,6 @@ function renderProviderModels(
|
|
|
253
240
|
}
|
|
254
241
|
}
|
|
255
242
|
|
|
256
|
-
/** `omp models canonical`: the coalesced canonical view (one row per canonical id). */
|
|
257
|
-
function renderCanonicalModels(modelRegistry: ModelRegistry, pattern: string | undefined, json: boolean): void {
|
|
258
|
-
const selections = modelRegistry.getCanonicalModelSelections({ availableOnly: true });
|
|
259
|
-
const needle = pattern?.toLowerCase();
|
|
260
|
-
const filtered = needle
|
|
261
|
-
? selections.filter(
|
|
262
|
-
({ record, model }) =>
|
|
263
|
-
record.id.toLowerCase().includes(needle) ||
|
|
264
|
-
`${model.provider}/${model.id}`.toLowerCase().includes(needle),
|
|
265
|
-
)
|
|
266
|
-
: selections;
|
|
267
|
-
|
|
268
|
-
if (json) {
|
|
269
|
-
const output: CanonicalModelsJson = {
|
|
270
|
-
canonical: filtered
|
|
271
|
-
.map(({ record, model }) => ({
|
|
272
|
-
id: record.id,
|
|
273
|
-
selected: `${model.provider}/${model.id}`,
|
|
274
|
-
variants: record.variants.length,
|
|
275
|
-
contextWindow: model.contextWindow,
|
|
276
|
-
maxTokens: model.maxTokens,
|
|
277
|
-
}))
|
|
278
|
-
.sort((left, right) => left.id.localeCompare(right.id)),
|
|
279
|
-
};
|
|
280
|
-
writeLine(JSON.stringify(output));
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (selections.length === 0) {
|
|
285
|
-
writeLine("No models available. Set API keys in environment variables.");
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
if (filtered.length === 0) {
|
|
289
|
-
writeLine(`No canonical models matching "${pattern}"`);
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const rows = filtered
|
|
294
|
-
.slice()
|
|
295
|
-
.sort((left, right) => left.record.id.localeCompare(right.record.id))
|
|
296
|
-
.map(({ record, model }) => [
|
|
297
|
-
record.id,
|
|
298
|
-
`${model.provider}/${model.id}`,
|
|
299
|
-
String(record.variants.length),
|
|
300
|
-
formatLimit(model.contextWindow),
|
|
301
|
-
formatLimit(model.maxTokens),
|
|
302
|
-
]);
|
|
303
|
-
for (const line of boxTable(
|
|
304
|
-
[
|
|
305
|
-
{ header: "canonical" },
|
|
306
|
-
{ header: "selected" },
|
|
307
|
-
{ header: "variants", align: "right" },
|
|
308
|
-
{ header: "context", align: "right" },
|
|
309
|
-
{ header: "max-out", align: "right" },
|
|
310
|
-
],
|
|
311
|
-
rows,
|
|
312
|
-
)) {
|
|
313
|
-
writeLine(line);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
243
|
/**
|
|
318
244
|
* Options for {@link runModelsListing}: render the catalog from a caller-supplied
|
|
319
245
|
* registry. Loads extensions (CLI `-e` paths and configured `settings.extensions`)
|
|
@@ -376,11 +302,7 @@ export async function runModelsListing(options: RunModelsListingOptions): Promis
|
|
|
376
302
|
// Discover runtime (extension) provider catalogs now that they are registered.
|
|
377
303
|
await modelRegistry.refreshRuntimeProviders(action === "refresh" ? "online" : "online-if-uncached");
|
|
378
304
|
|
|
379
|
-
|
|
380
|
-
renderCanonicalModels(modelRegistry, pattern, json);
|
|
381
|
-
} else {
|
|
382
|
-
renderProviderModels(modelRegistry, action, pattern, json);
|
|
383
|
-
}
|
|
305
|
+
renderProviderModels(modelRegistry, action, pattern, json);
|
|
384
306
|
}
|
|
385
307
|
|
|
386
308
|
/**
|
package/src/commands/models.ts
CHANGED
|
@@ -10,7 +10,7 @@ export default class Models extends Command {
|
|
|
10
10
|
|
|
11
11
|
static args = {
|
|
12
12
|
action: Args.string({
|
|
13
|
-
description: "ls (default) | find | refresh |
|
|
13
|
+
description: "ls (default) | find | refresh | <provider>",
|
|
14
14
|
required: false,
|
|
15
15
|
}),
|
|
16
16
|
pattern: Args.string({
|
|
@@ -40,7 +40,6 @@ export default class Models extends Command {
|
|
|
40
40
|
`# List one provider's models (any provider name works)\n ${APP_NAME} models openai-codex`,
|
|
41
41
|
`# Find models by substring\n ${APP_NAME} models find minimax`,
|
|
42
42
|
`# Force a fresh catalog fetch (replaces rm -rf ~/.omp/models.db)\n ${APP_NAME} models refresh`,
|
|
43
|
-
`# Show the coalesced canonical model view\n ${APP_NAME} models canonical`,
|
|
44
43
|
`# Machine-readable output\n ${APP_NAME} models --json`,
|
|
45
44
|
];
|
|
46
45
|
|
|
@@ -36,8 +36,8 @@ export async function resolvePrimaryModel(
|
|
|
36
36
|
const available = modelRegistry.getAvailable();
|
|
37
37
|
const matchPreferences = getModelMatchPreferences(settings);
|
|
38
38
|
const resolved = override
|
|
39
|
-
? resolveModelRoleValue(override, available, { settings, matchPreferences
|
|
40
|
-
: resolveRoleSelection(["commit", "smol", ...MODEL_ROLE_IDS], settings, available
|
|
39
|
+
? resolveModelRoleValue(override, available, { settings, matchPreferences })
|
|
40
|
+
: resolveRoleSelection(["commit", "smol", ...MODEL_ROLE_IDS], settings, available);
|
|
41
41
|
const model = resolved?.model;
|
|
42
42
|
if (!model) {
|
|
43
43
|
throw new Error("No model available for commit generation");
|
|
@@ -60,7 +60,7 @@ export async function resolveSmolModel(
|
|
|
60
60
|
fallbackApiKey: ApiKey,
|
|
61
61
|
): Promise<ResolvedCommitModel> {
|
|
62
62
|
const available = modelRegistry.getAvailable();
|
|
63
|
-
const resolvedSmol = resolveRoleSelection(["smol"], settings, available
|
|
63
|
+
const resolvedSmol = resolveRoleSelection(["smol"], settings, available);
|
|
64
64
|
if (resolvedSmol?.model) {
|
|
65
65
|
const apiKey = await modelRegistry.getApiKey(resolvedSmol.model);
|
|
66
66
|
if (apiKey) {
|
|
@@ -74,7 +74,7 @@ export async function resolveSmolModel(
|
|
|
74
74
|
|
|
75
75
|
const matchPreferences = getModelMatchPreferences(settings);
|
|
76
76
|
for (const pattern of MODEL_PRIO.smol) {
|
|
77
|
-
const candidate = parseModelPattern(pattern, available, matchPreferences
|
|
77
|
+
const candidate = parseModelPattern(pattern, available, matchPreferences).model;
|
|
78
78
|
if (!candidate) continue;
|
|
79
79
|
const apiKey = await modelRegistry.getApiKey(candidate);
|
|
80
80
|
if (apiKey) {
|
|
@@ -9,8 +9,7 @@ import { modelFamilyToken } from "@oh-my-pi/pi-catalog/identity";
|
|
|
9
9
|
* Gemini benefits from descriptors in-prompt; other providers keep them in the
|
|
10
10
|
* tool schemas. `on`/`off` are explicit user overrides.
|
|
11
11
|
*
|
|
12
|
-
* @param modelId
|
|
13
|
-
* `ModelRegistry.getCanonicalId` before calling so `auto` classifies correctly.
|
|
12
|
+
* @param modelId Model id (e.g. `gemini-3-pro`) used to classify `auto`.
|
|
14
13
|
*/
|
|
15
14
|
export function shouldInlineToolDescriptors(
|
|
16
15
|
setting: "auto" | "on" | "off" | undefined,
|
|
@@ -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
|
|
|
@@ -585,34 +585,60 @@ export async function discoverOpenAIModelsList(
|
|
|
585
585
|
? await withAuth(apiKey, key => attempt({ ...baseHeaders, Authorization: `Bearer ${key}` }))
|
|
586
586
|
: await attempt(baseHeaders);
|
|
587
587
|
const models = payload.data ?? [];
|
|
588
|
+
const references = getBundledModelReferenceIndex();
|
|
588
589
|
const discovered: Model<Api>[] = [];
|
|
589
590
|
for (const item of models) {
|
|
590
591
|
const id = item.id;
|
|
591
592
|
if (!id) continue;
|
|
592
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;
|
|
593
605
|
const contextWindow =
|
|
594
606
|
toPositiveNumberOrUndefined(item.max_model_len) ??
|
|
595
607
|
toPositiveNumberOrUndefined(item.context_length) ??
|
|
596
608
|
nativeMetadataForModel?.contextWindow ??
|
|
609
|
+
reference?.contextWindow ??
|
|
597
610
|
DISCOVERY_DEFAULT_CONTEXT_WINDOW;
|
|
598
611
|
discovered.push(
|
|
599
612
|
buildModel({
|
|
600
613
|
id,
|
|
601
|
-
name: id,
|
|
614
|
+
name: reference?.name ?? id,
|
|
602
615
|
api: providerConfig.api,
|
|
603
616
|
provider: providerConfig.provider,
|
|
604
617
|
baseUrl,
|
|
605
|
-
reasoning: false,
|
|
606
|
-
|
|
618
|
+
reasoning: reference?.reasoning ?? false,
|
|
619
|
+
thinking: reference?.thinking,
|
|
620
|
+
input: nativeMetadataForModel?.input ?? reference?.input ?? ["text"],
|
|
607
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.
|
|
608
625
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
609
626
|
contextWindow,
|
|
610
|
-
|
|
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),
|
|
611
631
|
headers,
|
|
612
632
|
compat: {
|
|
613
633
|
supportsStore: false,
|
|
614
634
|
supportsDeveloperRole: false,
|
|
615
|
-
supportsReasoningEffort: false,
|
|
635
|
+
supportsReasoningEffort: referenceCompat?.supportsReasoningEffort ?? false,
|
|
636
|
+
...(referenceCompat?.reasoningEffortMap
|
|
637
|
+
? { reasoningEffortMap: referenceCompat.reasoningEffortMap }
|
|
638
|
+
: {}),
|
|
639
|
+
...(referenceCompat?.omitReasoningEffort !== undefined
|
|
640
|
+
? { omitReasoningEffort: referenceCompat.omitReasoningEffort }
|
|
641
|
+
: {}),
|
|
616
642
|
},
|
|
617
643
|
} as ModelSpec<Api>),
|
|
618
644
|
);
|