@bitkyc08/opencodex 2.42.0 ā 2.43.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/AGENTS_INSTALL.md +2 -2
- package/README.md +31 -0
- package/bin/ocx.mjs +10 -1
- package/gui/dist/assets/index-DS1NE4Jn.css +1 -0
- package/gui/dist/assets/index-Djowl68T.js +112 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/anthropic-image-codec.ts +304 -0
- package/src/adapters/anthropic-image-normalize.ts +8 -298
- package/src/adapters/anthropic.ts +30 -7
- package/src/adapters/command-code.ts +7 -5
- package/src/adapters/cursor/desktop-executor-contract.ts +15 -0
- package/src/adapters/cursor/images.ts +36 -6
- package/src/adapters/cursor/live-transport.ts +7 -2
- package/src/adapters/cursor/native-exec-desktop.ts +2 -15
- package/src/adapters/cursor/protobuf-request.ts +13 -3
- package/src/adapters/cursor/tool-definitions.ts +5 -670
- package/src/adapters/cursor/tool-guidance.ts +236 -0
- package/src/adapters/cursor/tool-naming.ts +252 -0
- package/src/adapters/cursor/tool-schemas.ts +195 -0
- package/src/adapters/cursor/types.ts +6 -3
- package/src/adapters/exec-tool-result-normalize.ts +1 -1
- package/src/adapters/google-errors.ts +9 -1
- package/src/adapters/google.ts +1 -0
- package/src/adapters/kiro-calibration.ts +181 -0
- package/src/adapters/kiro.ts +135 -3
- package/src/adapters/openai-responses.ts +216 -26
- package/src/adapters/responses-code-mode.ts +59 -0
- package/src/adapters/tool-catalog-nudge.ts +1 -1
- package/src/adapters/xai-schema-analysis.ts +86 -0
- package/src/adapters/xai-tool-schema.ts +2 -87
- package/src/adapters/xai-web-search.ts +1 -1
- package/src/bridge.ts +22 -10
- package/src/chat/inbound.ts +11 -3
- package/src/claude/inbound-content-options.ts +60 -0
- package/src/claude/inbound-model-options.ts +142 -0
- package/src/claude/inbound-records.ts +7 -0
- package/src/claude/inbound.ts +10 -202
- package/src/claude/model-info.ts +45 -0
- package/src/cli/account-auth.ts +21 -6
- package/src/cli/capabilities.ts +13 -2
- package/src/cli/claude.ts +232 -39
- package/src/cli/config-command.ts +9 -1
- package/src/cli/dispatch.ts +5 -1
- package/src/cli/doctor.ts +10 -0
- package/src/cli/effort.ts +372 -0
- package/src/cli/export-command.ts +3 -9
- package/src/cli/help.ts +1 -0
- package/src/cli/index.ts +13 -0
- package/src/cli/init.ts +4 -0
- package/src/cli/model-selection-guidance.ts +30 -0
- package/src/cli/models-runtime.ts +3 -2
- package/src/cli/models.ts +8 -3
- package/src/cli/opencode.ts +4 -1
- package/src/cli/provider-runtime.ts +65 -0
- package/src/cli/provider.ts +8 -0
- package/src/cli/registry.ts +16 -2
- package/src/cli/runtime-api.ts +3 -1
- package/src/cli/star-prompt.ts +22 -6
- package/src/cli/status-probes.ts +168 -0
- package/src/cli/status.ts +5 -168
- package/src/clients/config-export/constants.ts +69 -0
- package/src/clients/config-export/contracts.ts +154 -0
- package/src/clients/config-export/dsh.ts +132 -0
- package/src/clients/config-export/fast-models.ts +29 -0
- package/src/clients/config-export/mcode.ts +83 -0
- package/src/clients/config-export/model-metadata.ts +108 -0
- package/src/clients/config-export/omp.ts +104 -0
- package/src/clients/config-export/zcode.ts +92 -0
- package/src/clients/config-export.ts +18 -710
- package/src/codex/account-lifecycle.ts +20 -3
- package/src/codex/account-usability.ts +2 -0
- package/src/codex/auth-api.ts +170 -23
- package/src/codex/auth-context.ts +328 -24
- package/src/codex/catalog/effort.ts +30 -4
- package/src/codex/catalog/metadata.ts +39 -9
- package/src/codex/catalog/native-models.ts +53 -12
- package/src/codex/catalog/parsing.ts +119 -5
- package/src/codex/catalog/provider-fetch.ts +150 -20
- package/src/codex/catalog/reserve.ts +52 -0
- package/src/codex/catalog/sync.ts +89 -16
- package/src/codex/convergence-types.ts +1 -0
- package/src/codex/convergence.ts +2 -0
- package/src/codex/data/upstream-models.json +1 -1
- package/src/codex/forward-transport-headers.ts +25 -0
- package/src/codex/inject.ts +3 -28
- package/src/codex/legacy-config-keys.ts +68 -0
- package/src/codex/log-guard/inspect-schema.ts +137 -0
- package/src/codex/log-guard/inspect.ts +2 -134
- package/src/codex/loopback-target.ts +54 -0
- package/src/codex/main-account-cache.ts +63 -1
- package/src/codex/main-account-hard-lock.ts +52 -0
- package/src/codex/main-account.ts +3 -1
- package/src/codex/management-convergence.ts +3 -0
- package/src/codex/model-entitlements.ts +54 -4
- package/src/codex/project-config-warnings.ts +92 -2
- package/src/codex/prompt-layers/encoding.ts +80 -0
- package/src/codex/prompt-layers/paths.ts +54 -0
- package/src/codex/prompt-layers/revision.ts +55 -0
- package/src/codex/prompt-layers/toml-edit.ts +163 -0
- package/src/codex/prompt-layers/toml-read.ts +181 -0
- package/src/codex/prompt-layers.ts +14 -520
- package/src/codex/quota-auto-refresh-state.ts +16 -0
- package/src/codex/quota-auto-refresh.ts +219 -0
- package/src/codex/quota-types.ts +51 -0
- package/src/codex/quota.ts +252 -93
- package/src/codex/reserve-availability.ts +177 -0
- package/src/codex/routing.ts +28 -9
- package/src/codex/shim.ts +53 -11
- package/src/codex/subagent-model-fallback.ts +23 -3
- package/src/combos/failover.ts +125 -7
- package/src/combos/identifiers.ts +89 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/resolve.ts +80 -9
- package/src/combos/types.ts +20 -93
- package/src/config/subagent-models.ts +24 -0
- package/src/config.ts +156 -13
- package/src/generated/compatibility-version.json +454 -166
- package/src/generated/model-metadata.ts +1 -1
- package/src/integrations/journal.ts +65 -4
- package/src/integrations/store.ts +5 -0
- package/src/lab/events/limits.ts +4 -0
- package/src/lib/destination-policy.ts +31 -2
- package/src/lib/errors.ts +39 -0
- package/src/lib/provider-outbound.ts +69 -3
- package/src/lib/proxy-env.ts +22 -0
- package/src/lib/redact-folding.ts +176 -0
- package/src/lib/redact.ts +2 -175
- package/src/lib/state-store-sweeper.ts +20 -6
- package/src/lib/token-estimate.ts +94 -27
- package/src/lib/windows-user-principal.ts +53 -5
- package/src/oauth/anthropic-routing.ts +99 -3
- package/src/oauth/generic-account-failover.ts +36 -13
- package/src/oauth/index.ts +127 -26
- package/src/oauth/login-cli.ts +5 -0
- package/src/oauth/meta-muse.ts +117 -15
- package/src/oauth/pool-settings-capability.ts +15 -4
- package/src/providers/api-keys.ts +8 -10
- package/src/providers/default-aliases.ts +39 -0
- package/src/providers/derive.ts +10 -2
- package/src/providers/fastwire.ts +36 -7
- package/src/providers/initial-model-selection-runtime.ts +90 -0
- package/src/providers/initial-model-selection.ts +120 -0
- package/src/providers/key-failover.ts +134 -54
- package/src/providers/key-store.ts +11 -1
- package/src/providers/label.ts +1 -1
- package/src/providers/model-discovery.ts +76 -0
- package/src/providers/model-rename-startup.ts +72 -8
- package/src/providers/openai-sidecar.ts +17 -5
- package/src/providers/openai-tiers-destination.ts +102 -0
- package/src/providers/openai-tiers.ts +2 -99
- package/src/providers/opencode-go-transport.ts +41 -0
- package/src/providers/quota-key-accounts.ts +141 -0
- package/src/providers/quota-types.ts +9 -0
- package/src/providers/quota.ts +535 -104
- package/src/providers/registry.ts +60 -17
- package/src/providers/xai-responses-opt-in.ts +31 -5
- package/src/quota/reset-activation.ts +81 -0
- package/src/quota/reset-detector.ts +305 -0
- package/src/quota/reset-notify-config.ts +162 -0
- package/src/quota/reset-observer.ts +125 -0
- package/src/quota/reset-poller.ts +160 -0
- package/src/quota/reset-seen-store.ts +385 -0
- package/src/quota/reset-sinks.ts +199 -0
- package/src/quota/window-mapping.ts +106 -0
- package/src/responses/apply-patch-envelope.ts +46 -0
- package/src/responses/code-mode-helper-compat.ts +39 -1
- package/src/responses/custom-tool-compat.ts +10 -4
- package/src/responses/hosted-tool-policy.ts +12 -4
- package/src/responses/parser-content.ts +133 -0
- package/src/responses/parser-text-format.ts +24 -0
- package/src/responses/parser-tools.ts +188 -0
- package/src/responses/parser.ts +3 -326
- package/src/responses/state.ts +124 -28
- package/src/router.ts +48 -13
- package/src/routing/analytics.ts +1 -0
- package/src/routing/capability.ts +17 -4
- package/src/server/auth-cors.ts +7 -1
- package/src/server/background-lifecycle.ts +23 -1
- package/src/server/chat-completions.ts +25 -3
- package/src/server/claude-messages.ts +62 -5
- package/src/server/effort-row.ts +1 -1
- package/src/server/fast-row.ts +295 -0
- package/src/server/gui-static.ts +30 -4
- package/src/server/index.ts +107 -21
- package/src/server/management/agent-settings-routes.ts +2 -2
- package/src/server/management/combo-routes.ts +37 -9
- package/src/server/management/config-routes.ts +93 -2
- package/src/server/management/integration-routes.ts +108 -0
- package/src/server/management/model-routes.ts +13 -3
- package/src/server/management/model-rows.ts +20 -1
- package/src/server/management/native-integration-routes.ts +4 -1
- package/src/server/management/oauth-account-routes.ts +38 -10
- package/src/server/management/provider-routes.ts +34 -3
- package/src/server/management/quota-reset-routes.ts +57 -0
- package/src/server/management/route-registry.ts +7 -4
- package/src/server/management/shared.ts +19 -5
- package/src/server/management/system-routes.ts +3 -2
- package/src/server/management-api.ts +14 -2
- package/src/server/ports.ts +12 -2
- package/src/server/relay-eager.ts +38 -23
- package/src/server/relay.ts +4 -0
- package/src/server/request-log.ts +6 -0
- package/src/server/responses/codex-ws-correlation.ts +65 -0
- package/src/server/responses/codex-ws-exchange.ts +261 -0
- package/src/server/responses/codex-ws-metadata.ts +134 -0
- package/src/server/responses/codex-ws-pool.ts +162 -0
- package/src/server/responses/codex-ws-request.ts +87 -0
- package/src/server/responses/codex-ws-session.ts +93 -0
- package/src/server/responses/codex-ws-wire.ts +144 -0
- package/src/server/responses/collaboration.ts +41 -1
- package/src/server/responses/compact.ts +105 -12
- package/src/server/responses/core.ts +476 -57
- package/src/server/responses/fetch-helpers.ts +10 -3
- package/src/server/responses/input-admission.ts +16 -9
- package/src/server/responses/responses-field-backfill.ts +1 -1
- package/src/server/responses/ws-upstream.ts +34 -318
- package/src/server/responses-custom-tool-repair.ts +20 -4
- package/src/server/responses-undeclared-tool-guard.ts +100 -8
- package/src/server/safe-response-headers.ts +23 -0
- package/src/server/search.ts +9 -0
- package/src/server/subagent-models-startup.ts +27 -0
- package/src/server/system-env-shell.ts +238 -0
- package/src/server/system-env.ts +7 -234
- package/src/server/ws-bridge.ts +3 -25
- package/src/server/xai-responses-startup.ts +21 -0
- package/src/service-manager-probe.ts +1 -1
- package/src/service.ts +55 -16
- package/src/types/config.ts +108 -12
- package/src/types/provider.ts +36 -7
- package/src/types/tools.ts +26 -1
- package/src/types.ts +2 -0
- package/src/update/notify.ts +8 -2
- package/src/usage/cost.ts +38 -28
- package/src/usage/expected-prices.ts +34 -15
- package/src/usage/log.ts +2 -0
- package/src/usage/model-identity.ts +26 -0
- package/src/usage/summary.ts +15 -1
- package/src/vision/describe.ts +6 -0
- package/src/vision/image-rewrite.ts +108 -0
- package/src/vision/index.ts +19 -306
- package/src/vision/plan.ts +205 -0
- package/src/web-search/executor.ts +6 -0
- package/src/web-search/index.ts +8 -1
- package/gui/dist/assets/index-BU1tE0sr.js +0 -112
- package/gui/dist/assets/index-DL9-iS6J.css +0 -1
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { loadConfig, saveConfig } from "../config";
|
|
2
|
+
import {
|
|
3
|
+
CODEX_REASONING_LEVELS,
|
|
4
|
+
configuredReasoningEfforts,
|
|
5
|
+
isDeclaredReasoningEffort,
|
|
6
|
+
mapReasoningEffort,
|
|
7
|
+
reasoningEffortMapFor,
|
|
8
|
+
} from "../reasoning-effort";
|
|
9
|
+
import { findLiveProxy } from "../server/proxy-liveness";
|
|
10
|
+
import { modelInList, type OcxConfig } from "../types";
|
|
11
|
+
import {
|
|
12
|
+
CliUsageError,
|
|
13
|
+
printData,
|
|
14
|
+
rejectArgs,
|
|
15
|
+
runCliAction,
|
|
16
|
+
runtimeRequest,
|
|
17
|
+
takeFlag,
|
|
18
|
+
takeOption,
|
|
19
|
+
type RuntimeApiDeps,
|
|
20
|
+
} from "./runtime-api";
|
|
21
|
+
|
|
22
|
+
export const EFFORT_USAGE = `Usage:
|
|
23
|
+
ocx effort [status] [--json]
|
|
24
|
+
ocx effort <low|medium|high|xhigh|max|ultra|none|minimal|-> [--json]
|
|
25
|
+
ocx effort set [--main <level|->] [--subagent <level|->] [--injection <level|->] [--json]
|
|
26
|
+
ocx effort clear [--json]
|
|
27
|
+
ocx effort model <provider/model|model> [--json]
|
|
28
|
+
|
|
29
|
+
Note: 'ocx effort clear' resets main and subagent caps but keeps delegation
|
|
30
|
+
injection effort. Use 'ocx effort set --injection -' to clear injection effort.`;
|
|
31
|
+
|
|
32
|
+
function clearable(value: string | undefined): string | null | undefined {
|
|
33
|
+
return value === "-" ? null : value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function validateEffortLevel(level: string | null | undefined, label: string): string | null | undefined {
|
|
37
|
+
if (level === undefined || level === null) return level;
|
|
38
|
+
const trimmed = level.trim();
|
|
39
|
+
if (trimmed === "-" || trimmed === "") return null;
|
|
40
|
+
if (!isDeclaredReasoningEffort(trimmed)) {
|
|
41
|
+
throw new CliUsageError(
|
|
42
|
+
`unknown reasoning effort "${trimmed}" for ${label} (allowed: ${CODEX_REASONING_LEVELS.map(l => l.effort).join(", ")}, none, minimal, -)`,
|
|
43
|
+
EFFORT_USAGE,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return trimmed;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface EffortCapsResponse {
|
|
50
|
+
effortCap: string | null;
|
|
51
|
+
subagentEffortCap: string | null;
|
|
52
|
+
efforts: string[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface InjectionResponse {
|
|
56
|
+
effort?: string | null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function getLiveStatus(deps: RuntimeApiDeps): Promise<{
|
|
60
|
+
effortCap: string | null;
|
|
61
|
+
subagentEffortCap: string | null;
|
|
62
|
+
injectionEffort: string | null;
|
|
63
|
+
efforts: string[];
|
|
64
|
+
source: "runtime";
|
|
65
|
+
}> {
|
|
66
|
+
// Propagate API failures once live mode is selected ā do not swallow 401/500 into null (#3528 review).
|
|
67
|
+
const [caps, injection] = await Promise.all([
|
|
68
|
+
runtimeRequest<EffortCapsResponse>("/api/effort-caps", {}, deps),
|
|
69
|
+
runtimeRequest<InjectionResponse>("/api/injection-model", {}, deps),
|
|
70
|
+
]);
|
|
71
|
+
return {
|
|
72
|
+
effortCap: caps.effortCap ?? null,
|
|
73
|
+
subagentEffortCap: caps.subagentEffortCap ?? null,
|
|
74
|
+
injectionEffort: injection?.effort ?? null,
|
|
75
|
+
efforts: caps.efforts ?? CODEX_REASONING_LEVELS.map(l => l.effort),
|
|
76
|
+
source: "runtime",
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function getOfflineStatus(): {
|
|
81
|
+
effortCap: string | null;
|
|
82
|
+
subagentEffortCap: string | null;
|
|
83
|
+
injectionEffort: string | null;
|
|
84
|
+
efforts: string[];
|
|
85
|
+
source: "config";
|
|
86
|
+
} {
|
|
87
|
+
const config = loadConfig();
|
|
88
|
+
return {
|
|
89
|
+
effortCap: config.effortCap ?? null,
|
|
90
|
+
subagentEffortCap: config.subagentEffortCap ?? null,
|
|
91
|
+
injectionEffort: config.injectionEffort ?? null,
|
|
92
|
+
efforts: CODEX_REASONING_LEVELS.map(l => l.effort),
|
|
93
|
+
source: "config",
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function status(wantsJson: boolean, deps: RuntimeApiDeps): Promise<void> {
|
|
98
|
+
let data: {
|
|
99
|
+
effortCap: string | null;
|
|
100
|
+
subagentEffortCap: string | null;
|
|
101
|
+
injectionEffort: string | null;
|
|
102
|
+
efforts: string[];
|
|
103
|
+
source: "runtime" | "config";
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const liveFinder = deps.findLiveProxy ?? findLiveProxy;
|
|
107
|
+
const live = await liveFinder().catch(() => null);
|
|
108
|
+
const isLive = Boolean(live || deps.baseUrl);
|
|
109
|
+
|
|
110
|
+
if (isLive) {
|
|
111
|
+
// Once live proxy / baseUrl is selected, propagate API failures; do not silently substitute local config (#3528 review).
|
|
112
|
+
data = await getLiveStatus(deps);
|
|
113
|
+
} else {
|
|
114
|
+
data = getOfflineStatus();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const lines = [
|
|
118
|
+
`Reasoning effort status (${data.source === "runtime" ? "live proxy" : "offline config"}):`,
|
|
119
|
+
` Main agent effort cap: ${data.effortCap ?? "(unset ā no cap)"}`,
|
|
120
|
+
` Subagent effort cap: ${data.subagentEffortCap ?? "(unset ā no cap)"}`,
|
|
121
|
+
` Subagent injection effort: ${data.injectionEffort ?? "(unset ā inherits parent session)"}`,
|
|
122
|
+
"",
|
|
123
|
+
"Supported Codex reasoning effort ladder:",
|
|
124
|
+
...CODEX_REASONING_LEVELS.map(l => ` - ${l.effort.padEnd(8)} ${l.description}`),
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
printData(data, wantsJson, lines);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function setEffort(
|
|
131
|
+
options: {
|
|
132
|
+
main?: string | null;
|
|
133
|
+
subagent?: string | null;
|
|
134
|
+
injection?: string | null;
|
|
135
|
+
},
|
|
136
|
+
wantsJson: boolean,
|
|
137
|
+
deps: RuntimeApiDeps,
|
|
138
|
+
): Promise<void> {
|
|
139
|
+
const validatedMain = validateEffortLevel(options.main, "--main");
|
|
140
|
+
const validatedSubagent = validateEffortLevel(options.subagent, "--subagent");
|
|
141
|
+
const validatedInjection = validateEffortLevel(options.injection, "--injection");
|
|
142
|
+
|
|
143
|
+
if (validatedMain === undefined && validatedSubagent === undefined && validatedInjection === undefined) {
|
|
144
|
+
throw new CliUsageError("at least one effort option (--main, --subagent, or --injection) is required", EFFORT_USAGE);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Probe live proxy BEFORE any mutation attempt
|
|
148
|
+
const liveFinder = deps.findLiveProxy ?? findLiveProxy;
|
|
149
|
+
const live = await liveFinder().catch(() => null);
|
|
150
|
+
const isLive = Boolean(live || deps.baseUrl);
|
|
151
|
+
|
|
152
|
+
if (isLive) {
|
|
153
|
+
// Live update path: once live proxy / baseUrl is selected, HTTP 4xx/5xx or transport
|
|
154
|
+
// errors must never fall through to silent offline config writes (#3528 review).
|
|
155
|
+
const capsBody: Record<string, unknown> = {};
|
|
156
|
+
if (validatedMain !== undefined) capsBody.effortCap = validatedMain;
|
|
157
|
+
if (validatedSubagent !== undefined) capsBody.subagentEffortCap = validatedSubagent;
|
|
158
|
+
|
|
159
|
+
let capsCommitted = false;
|
|
160
|
+
let injectionCommitted = false;
|
|
161
|
+
|
|
162
|
+
if (Object.keys(capsBody).length > 0) {
|
|
163
|
+
await runtimeRequest<EffortCapsResponse>("/api/effort-caps", {
|
|
164
|
+
method: "PUT",
|
|
165
|
+
body: JSON.stringify(capsBody),
|
|
166
|
+
}, deps);
|
|
167
|
+
capsCommitted = true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (validatedInjection !== undefined) {
|
|
171
|
+
try {
|
|
172
|
+
await runtimeRequest<InjectionResponse>("/api/injection-model", {
|
|
173
|
+
method: "PUT",
|
|
174
|
+
body: JSON.stringify({ effort: validatedInjection }),
|
|
175
|
+
}, deps);
|
|
176
|
+
injectionCommitted = true;
|
|
177
|
+
} catch (err) {
|
|
178
|
+
if (capsCommitted) {
|
|
179
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
180
|
+
throw new Error(`effort caps were updated on live proxy, but injection effort failed: ${errMsg}`);
|
|
181
|
+
}
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Accurately reflect live state: query fresh live status so unchanged caps are never serialized as null.
|
|
187
|
+
// If the read fails after a successful PUT, wrap with explicit partial-application error (#3528 review).
|
|
188
|
+
let finalStatus: { effortCap: string | null; subagentEffortCap: string | null; injectionEffort: string | null; efforts: string[] };
|
|
189
|
+
try {
|
|
190
|
+
finalStatus = await getLiveStatus(deps);
|
|
191
|
+
} catch (err) {
|
|
192
|
+
if (capsCommitted || injectionCommitted) {
|
|
193
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
194
|
+
throw new Error(`live state was updated, but verifying live status failed: ${errMsg}`);
|
|
195
|
+
}
|
|
196
|
+
throw err;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const result = {
|
|
200
|
+
ok: true,
|
|
201
|
+
effortCap: finalStatus.effortCap,
|
|
202
|
+
subagentEffortCap: finalStatus.subagentEffortCap,
|
|
203
|
+
injectionEffort: finalStatus.injectionEffort,
|
|
204
|
+
source: "runtime" as const,
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
printData(result, wantsJson, [
|
|
208
|
+
"Effort caps updated on live proxy:",
|
|
209
|
+
...(validatedMain !== undefined ? [` Main agent effort cap: ${validatedMain ?? "(cleared)"}`] : []),
|
|
210
|
+
...(validatedSubagent !== undefined ? [` Subagent effort cap: ${validatedSubagent ?? "(cleared)"}`] : []),
|
|
211
|
+
...(validatedInjection !== undefined ? [` Subagent injection effort: ${validatedInjection ?? "(cleared)"}`] : []),
|
|
212
|
+
]);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Offline persistence path: only reached when no live proxy was found before mutation
|
|
217
|
+
const config = loadConfig();
|
|
218
|
+
if (validatedMain !== undefined) {
|
|
219
|
+
if (validatedMain === null) delete config.effortCap;
|
|
220
|
+
else config.effortCap = validatedMain;
|
|
221
|
+
}
|
|
222
|
+
if (validatedSubagent !== undefined) {
|
|
223
|
+
if (validatedSubagent === null) delete config.subagentEffortCap;
|
|
224
|
+
else config.subagentEffortCap = validatedSubagent;
|
|
225
|
+
}
|
|
226
|
+
if (validatedInjection !== undefined) {
|
|
227
|
+
if (validatedInjection === null) delete config.injectionEffort;
|
|
228
|
+
else config.injectionEffort = validatedInjection;
|
|
229
|
+
}
|
|
230
|
+
saveConfig(config);
|
|
231
|
+
|
|
232
|
+
const result = {
|
|
233
|
+
ok: true,
|
|
234
|
+
effortCap: config.effortCap ?? null,
|
|
235
|
+
subagentEffortCap: config.subagentEffortCap ?? null,
|
|
236
|
+
injectionEffort: config.injectionEffort ?? null,
|
|
237
|
+
source: "config" as const,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
printData(result, wantsJson, [
|
|
241
|
+
"[offline] Effort caps updated in config.json (proxy is not running; changes will take effect on next start):",
|
|
242
|
+
...(validatedMain !== undefined ? [` Main agent effort cap: ${validatedMain ?? "(cleared)"}`] : []),
|
|
243
|
+
...(validatedSubagent !== undefined ? [` Subagent effort cap: ${validatedSubagent ?? "(cleared)"}`] : []),
|
|
244
|
+
...(validatedInjection !== undefined ? [` Subagent injection effort: ${validatedInjection ?? "(cleared)"}`] : []),
|
|
245
|
+
]);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function inspectModelEffort(modelTarget: string, wantsJson: boolean): void {
|
|
249
|
+
// Reject leading or trailing slash selectors before lookup (#3528 review)
|
|
250
|
+
if (modelTarget.startsWith("/") || modelTarget.endsWith("/")) {
|
|
251
|
+
throw new CliUsageError(
|
|
252
|
+
`invalid model selector "${modelTarget}" (must be <provider/model> or <model> without leading or trailing slashes)`,
|
|
253
|
+
EFFORT_USAGE,
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const config = loadConfig();
|
|
258
|
+
let providerName = "";
|
|
259
|
+
let modelId = modelTarget;
|
|
260
|
+
|
|
261
|
+
const slashIndex = modelTarget.indexOf("/");
|
|
262
|
+
if (slashIndex > 0) {
|
|
263
|
+
providerName = modelTarget.slice(0, slashIndex);
|
|
264
|
+
modelId = modelTarget.slice(slashIndex + 1);
|
|
265
|
+
} else {
|
|
266
|
+
providerName = config.defaultProvider || "openai";
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const provider = config.providers[providerName];
|
|
270
|
+
if (!provider) {
|
|
271
|
+
throw new CliUsageError(
|
|
272
|
+
`Provider "${providerName}" is not configured. Configured providers: ${Object.keys(config.providers).join(", ")}`,
|
|
273
|
+
EFFORT_USAGE,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const isReasoningDisabled = modelInList(provider.noReasoningModels, modelId);
|
|
278
|
+
const efforts = configuredReasoningEfforts(provider, modelId);
|
|
279
|
+
const wireMap = reasoningEffortMapFor(provider, modelId);
|
|
280
|
+
|
|
281
|
+
// Derive sample ladder directly from canonical CODEX_REASONING_LEVELS (#3528 review)
|
|
282
|
+
const mappedExamples: Record<string, string | undefined> = {};
|
|
283
|
+
for (const { effort } of CODEX_REASONING_LEVELS) {
|
|
284
|
+
mappedExamples[effort] = mapReasoningEffort(provider, modelId, effort);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const result = {
|
|
288
|
+
provider: providerName,
|
|
289
|
+
model: modelId,
|
|
290
|
+
reasoningDisabled: isReasoningDisabled,
|
|
291
|
+
supportedEfforts: efforts ?? null,
|
|
292
|
+
wireMap: wireMap ?? null,
|
|
293
|
+
mappedTiers: mappedExamples,
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const lines = [
|
|
297
|
+
`Reasoning effort configuration for ${providerName}/${modelId}:`,
|
|
298
|
+
` Reasoning disabled: ${isReasoningDisabled ? "yes (noReasoningModels)" : "no"}`,
|
|
299
|
+
` Supported ladder: ${efforts ? efforts.join(", ") : "(default / unconstrained)"}`,
|
|
300
|
+
` Wire mapping overrides: ${wireMap ? JSON.stringify(wireMap) : "(standard provider mapping)"}`,
|
|
301
|
+
" Sample wire translations:",
|
|
302
|
+
...Object.entries(mappedExamples).map(([req, wire]) => ` ${req.padEnd(8)} -> ${wire ?? "(omitted/unsupported)"}`),
|
|
303
|
+
];
|
|
304
|
+
|
|
305
|
+
printData(result, wantsJson, lines);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export async function handleEffortCommand(argv: string[], deps: RuntimeApiDeps = {}): Promise<number> {
|
|
309
|
+
return runCliAction(async () => {
|
|
310
|
+
const args = [...argv];
|
|
311
|
+
const wantsJson = takeFlag(args, "--json");
|
|
312
|
+
|
|
313
|
+
if (args.length === 0) {
|
|
314
|
+
await status(wantsJson, deps);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const rawFirst = args[0]!;
|
|
319
|
+
const first = rawFirst.toLowerCase();
|
|
320
|
+
|
|
321
|
+
if (first === "status") {
|
|
322
|
+
args.shift();
|
|
323
|
+
rejectArgs(args, EFFORT_USAGE);
|
|
324
|
+
await status(wantsJson, deps);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (first === "clear" || first === "unset") {
|
|
329
|
+
args.shift();
|
|
330
|
+
rejectArgs(args, EFFORT_USAGE);
|
|
331
|
+
await setEffort({ main: null, subagent: null }, wantsJson, deps);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (first === "set") {
|
|
336
|
+
args.shift();
|
|
337
|
+
const main = clearable(takeOption(args, "--main"));
|
|
338
|
+
const subagent = clearable(takeOption(args, "--subagent"));
|
|
339
|
+
const injection = clearable(takeOption(args, "--injection"));
|
|
340
|
+
rejectArgs(args, EFFORT_USAGE);
|
|
341
|
+
await setEffort({ main, subagent, injection }, wantsJson, deps);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (first === "model") {
|
|
346
|
+
args.shift();
|
|
347
|
+
const target = args.shift();
|
|
348
|
+
if (!target) throw new CliUsageError("model identifier (<provider/model> or <model>) is required", EFFORT_USAGE);
|
|
349
|
+
rejectArgs(args, EFFORT_USAGE);
|
|
350
|
+
inspectModelEffort(target, wantsJson);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Shorthand: check if first argument is an effort level or "-"
|
|
355
|
+
if (first === "-" || isDeclaredReasoningEffort(first)) {
|
|
356
|
+
args.shift();
|
|
357
|
+
rejectArgs(args, EFFORT_USAGE);
|
|
358
|
+
await setEffort({ main: first === "-" ? null : first }, wantsJson, deps);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Shorthand model inspection: preserve raw casing and check slash boundaries (#3528 review)
|
|
363
|
+
if (rawFirst.includes("/")) {
|
|
364
|
+
args.shift();
|
|
365
|
+
rejectArgs(args, EFFORT_USAGE);
|
|
366
|
+
inspectModelEffort(rawFirst, wantsJson);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
throw new CliUsageError(`unknown effort command or level "${rawFirst}"`, EFFORT_USAGE);
|
|
371
|
+
});
|
|
372
|
+
}
|
|
@@ -68,13 +68,6 @@ type ExportProxyModelRow = OpencodeProxyModelRow & {
|
|
|
68
68
|
defaultReasoningEffort?: string;
|
|
69
69
|
};
|
|
70
70
|
|
|
71
|
-
/** Same authoritativeness rule the serializers apply, for the degraded-count line. */
|
|
72
|
-
function hasContextLimit(model: ExportModel): boolean {
|
|
73
|
-
return typeof model.contextWindow === "number"
|
|
74
|
-
&& Number.isFinite(model.contextWindow)
|
|
75
|
-
&& model.contextWindow > 0;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
71
|
/**
|
|
79
72
|
* Export rows from proxy `/api/models` rows.
|
|
80
73
|
*
|
|
@@ -106,6 +99,7 @@ export function exportModelsFromProxyRows(
|
|
|
106
99
|
id: entry.id ?? entry.namespaced,
|
|
107
100
|
};
|
|
108
101
|
if (entry.native) model.native = true;
|
|
102
|
+
if (entry.fastRowAvailable !== undefined) model.fastRowAvailable = entry.fastRowAvailable;
|
|
109
103
|
if (entry.displayName) model.displayName = entry.displayName;
|
|
110
104
|
if (entry.contextWindow !== undefined) model.contextWindow = entry.contextWindow;
|
|
111
105
|
if (entry.reasoningEfforts && entry.reasoningEfforts.length > 0) {
|
|
@@ -195,7 +189,7 @@ export async function handleExportCommand(argv: string[], deps: ExportCommandDep
|
|
|
195
189
|
// stderr, so `--json` stdout stays a standalone JSON document.
|
|
196
190
|
if (out !== undefined && wantsJson) console.error(`Wrote ${out}`);
|
|
197
191
|
|
|
198
|
-
const
|
|
192
|
+
const { modelCount, modelsWithoutLimits } = spec.summarize(clientConfig);
|
|
199
193
|
// `--json` keeps emitting the DOCUMENT at the top level as JSON for scripts;
|
|
200
194
|
// `--out` is the path that writes the selected client's native format.
|
|
201
195
|
// Format metadata rides in the human lines below.
|
|
@@ -206,7 +200,7 @@ export async function handleExportCommand(argv: string[], deps: ExportCommandDep
|
|
|
206
200
|
`Destination: ${spec.destination(process.env)}`,
|
|
207
201
|
"Merge this generated configuration into that file; do not replace it.",
|
|
208
202
|
`Before launching: ${spec.exportHint}`,
|
|
209
|
-
`${
|
|
203
|
+
`${modelCount} model${modelCount === 1 ? "" : "s"}; ${modelsWithoutLimits} omit context limits (the client applies its own defaults).`,
|
|
210
204
|
]);
|
|
211
205
|
});
|
|
212
206
|
}
|
package/src/cli/help.ts
CHANGED
|
@@ -66,6 +66,7 @@ Usage:
|
|
|
66
66
|
ocx alias <sub> Short names for providers and models (list, set, rm, defaults)
|
|
67
67
|
ocx combo <sub> Combo routing strategies and failover
|
|
68
68
|
ocx agent <sub> Subagents, injection, effort caps, and sidecars
|
|
69
|
+
ocx effort [sub] Inspect and configure reasoning effort caps and defaults
|
|
69
70
|
ocx observe <sub> Logs, usage, storage, memory, and debug data
|
|
70
71
|
ocx inspect <sub> Effective config, catalog, analytics, pacing, client-config
|
|
71
72
|
ocx route <sub> Routing features (combo, policy)
|
package/src/cli/index.ts
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
|
|
5
|
+
// Best-effort recovery for runtime execution and spawned children if launched
|
|
6
|
+
// from an unlinked/deleted working directory (runs after hoisted ESM module imports).
|
|
7
|
+
try {
|
|
8
|
+
process.cwd();
|
|
9
|
+
} catch {
|
|
10
|
+
try {
|
|
11
|
+
process.chdir(homedir());
|
|
12
|
+
} catch {
|
|
13
|
+
/* best-effort */
|
|
14
|
+
}
|
|
15
|
+
}
|
|
3
16
|
import { currentExternalCodexModelProvider, restoreNativeCodex, restoreNativeCodexAsync, shouldInjectApiAuthHeader } from "../codex/inject";
|
|
4
17
|
import { stripGrokConfig } from "../grok/inject";
|
|
5
18
|
import { STOP_HISTORY_INCOMPLETE_EXIT_CODE } from "../update/stop-contract.mjs";
|
package/src/cli/init.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import * as readline from "node:readline";
|
|
2
|
+
import { modelSelectionGuidance } from "./model-selection-guidance";
|
|
3
|
+
import { initializeProviderModelSelection } from "../providers/initial-model-selection";
|
|
2
4
|
import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
3
5
|
import { injectCodexConfig } from "../codex/inject";
|
|
4
6
|
import { classifyOpenAiTierBackup, getConfigPath, getDefaultConfig, isValidProviderName, preserveOpenAiTierRollbackSnapshot, saveConfig } from "../config";
|
|
@@ -160,6 +162,7 @@ export async function runInit(): Promise<void> {
|
|
|
160
162
|
const portStr = await prompt.ask("\nProxy port [10100]: ");
|
|
161
163
|
const port = parseInt(portStr, 10) || 10100;
|
|
162
164
|
|
|
165
|
+
initializeProviderModelSelection(providerName, providerConfig);
|
|
163
166
|
const config: OcxConfig = {
|
|
164
167
|
...getDefaultConfig(),
|
|
165
168
|
port,
|
|
@@ -198,6 +201,7 @@ export async function runInit(): Promise<void> {
|
|
|
198
201
|
}
|
|
199
202
|
|
|
200
203
|
console.log(`\nš Setup complete! Run 'ocx start' to start the proxy.`);
|
|
204
|
+
for (const line of modelSelectionGuidance(providerName)) console.log(line);
|
|
201
205
|
} catch (error) {
|
|
202
206
|
const message = error instanceof Error ? error.message : String(error);
|
|
203
207
|
if (/stdin (closed|reached EOF)/i.test(message)) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Existing model-management commands; use the exact ID from `live`, including native IDs. */
|
|
2
|
+
export function modelSelectionNextSteps(provider: string, afterLogin = false) {
|
|
3
|
+
const name = provider === "codex" || provider === "chatgpt" ? "openai" : provider;
|
|
4
|
+
return {
|
|
5
|
+
provider: name,
|
|
6
|
+
afterLogin,
|
|
7
|
+
requiresRunningProxy: true,
|
|
8
|
+
commands: {
|
|
9
|
+
list: `ocx models live --provider ${name}`,
|
|
10
|
+
enable: 'ocx models enable "<model-id-from-list>"',
|
|
11
|
+
disable: 'ocx models disable "<model-id-from-list>"',
|
|
12
|
+
enableNative: 'ocx models enable "<model-id-from-list>" --native',
|
|
13
|
+
disableNative: 'ocx models disable "<model-id-from-list>" --native',
|
|
14
|
+
enableAll: `ocx models provider ${name} on`,
|
|
15
|
+
disableAll: `ocx models provider ${name} off`,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function modelSelectionGuidance(provider: string, afterLogin = false): string[] {
|
|
21
|
+
const next = modelSelectionNextSteps(provider, afterLogin);
|
|
22
|
+
return [
|
|
23
|
+
afterLogin ? "After login completes, manage model switches with:" : "Manage model switches (the provider stays active):",
|
|
24
|
+
" Start the proxy first if needed: ocx start",
|
|
25
|
+
" Replace <model-id-from-list> with an exact ID printed by the list command.",
|
|
26
|
+
" For rows marked native, use the --native variants (including IDs containing /).",
|
|
27
|
+
...Object.values(next.commands).map(command => ` ${command}`),
|
|
28
|
+
" If initial discovery is still pending, check the provider connection and retry: ocx sync",
|
|
29
|
+
];
|
|
30
|
+
}
|
|
@@ -36,6 +36,7 @@ type ModelRow = {
|
|
|
36
36
|
namespaced?: string;
|
|
37
37
|
native?: boolean;
|
|
38
38
|
disabled?: boolean;
|
|
39
|
+
initialSelectionPending?: boolean;
|
|
39
40
|
custom?: boolean;
|
|
40
41
|
customId?: string;
|
|
41
42
|
displayName?: string;
|
|
@@ -49,7 +50,7 @@ async function live(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
|
49
50
|
const rows = await runtimeRequest<ModelRow[]>("/api/models", {}, deps);
|
|
50
51
|
const filtered = provider ? rows.filter(row => row.provider === provider) : rows;
|
|
51
52
|
printData(filtered, wantsJson, filtered.map(row => {
|
|
52
|
-
const flags = [row.native ? "native" : "routed", row.custom ? "custom" : "", row.disabled ? "disabled" : "enabled"].filter(Boolean);
|
|
53
|
+
const flags = [row.native ? "native" : "routed", row.custom ? "custom" : "", row.initialSelectionPending ? "initial discovery pending" : row.disabled ? "disabled" : "enabled"].filter(Boolean);
|
|
53
54
|
return `${row.namespaced ?? `${row.provider}/${row.id}`} [${flags.join(", ")}]`;
|
|
54
55
|
}));
|
|
55
56
|
}
|
|
@@ -323,7 +324,7 @@ async function shadow(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
|
323
324
|
|
|
324
325
|
export async function handleModelsRuntimeCommand(sub: string, argv: string[], deps: RuntimeApiDeps = {}): Promise<number | null> {
|
|
325
326
|
// The dispatch below and MODELS_RUNTIME_SUBCOMMANDS must name the same set;
|
|
326
|
-
// tests/cli-models-runtime-dispatch.test.ts fails if they drift (#3094).
|
|
327
|
+
// tests/cli/cli-models-runtime-dispatch.test.ts fails if they drift (#3094).
|
|
327
328
|
if (!isModelsRuntimeSubcommand(sub)) return null;
|
|
328
329
|
let action: (() => Promise<void>) | undefined;
|
|
329
330
|
if (sub === "live") action = () => live(argv, deps);
|
package/src/cli/models.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { createInterface } from "node:readline/promises";
|
|
6
6
|
import { syncModelsToCodex } from "../codex/sync";
|
|
7
|
+
import { configuredContextWindow } from "../codex/catalog/provider-fetch";
|
|
7
8
|
import { hasOwnProvider, isValidProviderName, loadConfig, saveConfig } from "../config";
|
|
8
9
|
import {
|
|
9
10
|
canonicalizeReasoningEfforts,
|
|
@@ -86,6 +87,11 @@ interface ModelEntry {
|
|
|
86
87
|
reasoningEfforts: string[] | null;
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Collect static configured models for all providers or one selected provider.
|
|
92
|
+
* Keep each provider's default model first and resolve metadata through shared helpers.
|
|
93
|
+
* Live-discovered models are not fetched by this listing.
|
|
94
|
+
*/
|
|
89
95
|
function collectModels(config: OcxConfig, providerFilter?: string): ModelEntry[] {
|
|
90
96
|
const entries: ModelEntry[] = [];
|
|
91
97
|
const providers = providerFilter
|
|
@@ -95,10 +101,9 @@ function collectModels(config: OcxConfig, providerFilter?: string): ModelEntry[]
|
|
|
95
101
|
for (const [provName, prov] of Object.entries(providers)) {
|
|
96
102
|
if (!prov) continue;
|
|
97
103
|
const seen = new Set<string>();
|
|
98
|
-
const contextWindows = prov.modelContextWindows ?? {};
|
|
99
104
|
const inputModalities = prov.modelInputModalities ?? {};
|
|
100
|
-
const globalContext = prov.contextWindow ?? null;
|
|
101
105
|
|
|
106
|
+
/** Append one model with resolved metadata, ignoring duplicates within this provider. */
|
|
102
107
|
const addModel = (model: string, isDefault: boolean) => {
|
|
103
108
|
if (seen.has(model)) return;
|
|
104
109
|
seen.add(model);
|
|
@@ -124,7 +129,7 @@ function collectModels(config: OcxConfig, providerFilter?: string): ModelEntry[]
|
|
|
124
129
|
provider: provName,
|
|
125
130
|
model,
|
|
126
131
|
isDefault,
|
|
127
|
-
contextWindow:
|
|
132
|
+
contextWindow: configuredContextWindow(prov, model) ?? null,
|
|
128
133
|
inputModalities: modalities,
|
|
129
134
|
reasoningEfforts: efforts,
|
|
130
135
|
});
|
package/src/cli/opencode.ts
CHANGED
|
@@ -88,6 +88,8 @@ export interface OpencodeRoutedModel {
|
|
|
88
88
|
|
|
89
89
|
/** Row shape from authenticated GET /api/models on the running proxy. */
|
|
90
90
|
export interface OpencodeProxyModelRow {
|
|
91
|
+
/** Hub-resolved availability, independent of the launcher's local Fast setting. */
|
|
92
|
+
fastRowAvailable?: boolean;
|
|
91
93
|
provider?: string;
|
|
92
94
|
id?: string;
|
|
93
95
|
namespaced?: string;
|
|
@@ -389,6 +391,7 @@ export function opencodeCatalogFromProxyRows(
|
|
|
389
391
|
id: row.id,
|
|
390
392
|
contextWindow: row.contextWindow,
|
|
391
393
|
displayName: row.displayNameSource === "fallback" ? undefined : row.displayName,
|
|
394
|
+
...(typeof row.fastRowAvailable === "boolean" ? { fastRowAvailable: row.fastRowAvailable } : {}),
|
|
392
395
|
...(Array.isArray(row.reasoningEfforts) && row.reasoningEfforts.length > 0
|
|
393
396
|
? { reasoningEfforts: [...row.reasoningEfforts] }
|
|
394
397
|
: {}),
|
|
@@ -648,7 +651,7 @@ export async function cmdOpencode(args: string[]): Promise<number> {
|
|
|
648
651
|
const catalog = opencodeCatalogFromProxyRows(proxyModels, config);
|
|
649
652
|
const blocks = buildOpencodeProviderBlocksFromCatalog(live.port, catalog, live.hostname, config);
|
|
650
653
|
const baseUrl = blocks.v1.options.baseURL;
|
|
651
|
-
const modelCount =
|
|
654
|
+
const modelCount = Object.keys(blocks.v1.models).length;
|
|
652
655
|
console.error(`ā
opencode wired to ${baseUrl} ā ${modelCount} model(s) under provider \`${OPENCODE_PROVIDER_ID}\`.`);
|
|
653
656
|
console.error(" Your existing opencode config files are left untouched; only the runtime provider blocks are injected.");
|
|
654
657
|
const providerOverride = opencodeProviderOverridePath(process.cwd());
|