@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,205 @@
|
|
|
1
|
+
import type { OcxConfig, OcxContentPart, OcxParsedRequest, OcxProviderConfig } from "../types";
|
|
2
|
+
import type { VisionReasoningEffort } from "../reasoning-effort";
|
|
3
|
+
import type { VisionSettings } from "./describe";
|
|
4
|
+
import type { ResolvedOpenAiForwardSidecar } from "../providers/openai-sidecar";
|
|
5
|
+
import type { CodexAuthPolicyConfig } from "../codex/auth-context";
|
|
6
|
+
import { isCodexReserveRequestEligible } from "../codex/loopback-target";
|
|
7
|
+
import type { DataPlaneAdmission } from "../server/auth-cors";
|
|
8
|
+
import { isModelVisionSidecarConsumer as isModelTextOnly, modelAcceptsImageInput } from "./eligibility";
|
|
9
|
+
import { normalizeVisionReasoningForModel } from "./reasoning";
|
|
10
|
+
import { resolveSidecarAuth } from "../sidecar/auth";
|
|
11
|
+
import { DEFAULT_VISION_TIMEOUT_MS, MAX_VISION_TIMEOUT_MS, MIN_VISION_TIMEOUT_MS } from "./timeout-bounds";
|
|
12
|
+
import { carriesImages } from "./image-rewrite";
|
|
13
|
+
|
|
14
|
+
const DEFAULT_VISION_MODEL = "gpt-5.4-mini";
|
|
15
|
+
const DEFAULT_ANTHROPIC_VISION_MODEL = "claude-sonnet-5";
|
|
16
|
+
const DEFAULT_REASONING: VisionReasoningEffort = "low";
|
|
17
|
+
export const DEFAULT_MAX_DESCRIPTIONS_PER_TURN = 8;
|
|
18
|
+
|
|
19
|
+
/** Runtime config is permissive: zero is intentional; malformed values fall back to the bounded default. */
|
|
20
|
+
export function resolveMaxDescriptionsPerTurn(value: unknown): number {
|
|
21
|
+
if (value === 0) return 0;
|
|
22
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0
|
|
23
|
+
? value
|
|
24
|
+
: DEFAULT_MAX_DESCRIPTIONS_PER_TURN;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function isValidVisionTimeoutMs(value: unknown): value is number {
|
|
28
|
+
return typeof value === "number"
|
|
29
|
+
&& Number.isInteger(value)
|
|
30
|
+
&& value >= MIN_VISION_TIMEOUT_MS
|
|
31
|
+
&& value <= MAX_VISION_TIMEOUT_MS;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Runtime config is permissive: malformed or out-of-range values fall back to the default. */
|
|
35
|
+
export function resolveVisionTimeoutMs(value: unknown): number {
|
|
36
|
+
return isValidVisionTimeoutMs(value) ? value : DEFAULT_VISION_TIMEOUT_MS;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface AnthropicVisionProvider {
|
|
40
|
+
providerName: string;
|
|
41
|
+
provider: OcxProviderConfig;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* First enabled Anthropic OAuth provider whose active stored account is not marked for reauth.
|
|
46
|
+
* Delegates to the shared sidecar auth module (#2188) — same predicate as web-search.
|
|
47
|
+
*/
|
|
48
|
+
export function findAnthropicVisionProvider(config: OcxConfig): AnthropicVisionProvider | undefined {
|
|
49
|
+
const auth = resolveSidecarAuth(config);
|
|
50
|
+
if (!auth.isAnthropicAuth || !auth.anthropicProviderName || !auth.anthropicProvider) return undefined;
|
|
51
|
+
return { providerName: auth.anthropicProviderName, provider: auth.anthropicProvider };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function resolveVisionBackend(
|
|
55
|
+
explicit: "openai" | "anthropic" | "routed" | undefined,
|
|
56
|
+
anthropicSidecar: AnthropicVisionProvider | undefined,
|
|
57
|
+
): "openai" | "anthropic" {
|
|
58
|
+
if (explicit === "openai" || explicit === "anthropic") return explicit;
|
|
59
|
+
// "routed" collapses to the legacy default order until its describe executor
|
|
60
|
+
// lands (roadmap 170 → 180 revised): a persisted routed backend without a
|
|
61
|
+
// dispatchable arm degrades exactly like unset rather than crashing. wp3
|
|
62
|
+
// replaces this collapse with the real routed arm in planVisionSidecar.
|
|
63
|
+
return anthropicSidecar ? "anthropic" : "openai";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Native model used by the OpenAI vision helper, including its bounded default. */
|
|
67
|
+
export function resolveOpenAiVisionModel(config: Pick<OcxConfig, "visionSidecar">): string {
|
|
68
|
+
const configured = config.visionSidecar?.model;
|
|
69
|
+
// Namespaced routed ids never reach the forward executor (see
|
|
70
|
+
// resolveEffectiveVisionModel).
|
|
71
|
+
return configured && !configured.includes("/") ? configured : DEFAULT_VISION_MODEL;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Effective describer model for the backend `planVisionSidecar` selected. */
|
|
75
|
+
export function resolveEffectiveVisionModel(
|
|
76
|
+
config: Pick<OcxConfig, "visionSidecar">,
|
|
77
|
+
backend: "openai" | "anthropic",
|
|
78
|
+
): string {
|
|
79
|
+
const configured = config.visionSidecar?.model;
|
|
80
|
+
// A namespaced "provider/model" id belongs to the routed backend only; the
|
|
81
|
+
// forward/OAuth executors POST the model string verbatim, so it falls back
|
|
82
|
+
// to the side's default here (PUT coherence rejects new writes of this
|
|
83
|
+
// shape, but a legacy or hand-edited config must not break the executor).
|
|
84
|
+
const usable = configured && !configured.includes("/") ? configured : undefined;
|
|
85
|
+
return backend === "anthropic"
|
|
86
|
+
? usable || DEFAULT_ANTHROPIC_VISION_MODEL
|
|
87
|
+
: usable || DEFAULT_VISION_MODEL;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function messagesHaveImage(parsed: OcxParsedRequest): boolean {
|
|
91
|
+
return parsed.context.messages.some(m =>
|
|
92
|
+
carriesImages(m.role) && Array.isArray(m.content) && (m.content as OcxContentPart[]).some(p => p.type === "image"));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function shouldResolveOpenAiVisionSidecar(
|
|
96
|
+
config: OcxConfig,
|
|
97
|
+
provider: OcxProviderConfig,
|
|
98
|
+
modelId: string,
|
|
99
|
+
parsed: OcxParsedRequest,
|
|
100
|
+
): boolean {
|
|
101
|
+
if (!isModelTextOnly(provider, modelId) || !messagesHaveImage(parsed)) return false;
|
|
102
|
+
const cfg = config.visionSidecar ?? {};
|
|
103
|
+
if (cfg.enabled === false) return false;
|
|
104
|
+
return resolveVisionBackend(cfg.backend, findAnthropicVisionProvider(config)) === "openai";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface VisionPlan {
|
|
108
|
+
backend: "openai" | "anthropic" | "routed";
|
|
109
|
+
forwardSidecar?: ResolvedOpenAiForwardSidecar;
|
|
110
|
+
anthropicSidecar?: AnthropicVisionProvider;
|
|
111
|
+
/** Namespaced "provider/model" describer for the routed backend (roadmap 180). */
|
|
112
|
+
routedModel?: string;
|
|
113
|
+
/** Loopback dispatch inputs for the routed backend. */
|
|
114
|
+
routedConfig?: Pick<OcxConfig, "port" | "apiKeys">;
|
|
115
|
+
settings: VisionSettings;
|
|
116
|
+
maxDescriptionsPerTurn: number;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Decide whether the vision sidecar should pre-describe images for this request, returning the plan
|
|
121
|
+
* if so. Active when: the routed model is in `provider.noVisionModels`, the request actually carries
|
|
122
|
+
* an image, the sidecar isn't disabled, and the selected backend has usable auth. Returns undefined
|
|
123
|
+
* otherwise (the caller strips images before sending to a text-only model).
|
|
124
|
+
*/
|
|
125
|
+
export function planVisionSidecar(
|
|
126
|
+
config: OcxConfig,
|
|
127
|
+
provider: OcxProviderConfig,
|
|
128
|
+
modelId: string,
|
|
129
|
+
parsed: OcxParsedRequest,
|
|
130
|
+
openAiSidecar?: ResolvedOpenAiForwardSidecar,
|
|
131
|
+
options: { admission?: Pick<DataPlaneAdmission, "source">; codexAuthPolicy?: CodexAuthPolicyConfig } = {},
|
|
132
|
+
): VisionPlan | undefined {
|
|
133
|
+
if (!isModelTextOnly(provider, modelId)) return undefined;
|
|
134
|
+
if (!messagesHaveImage(parsed)) return undefined;
|
|
135
|
+
const cfg = config.visionSidecar ?? {};
|
|
136
|
+
if (cfg.enabled === false) return undefined;
|
|
137
|
+
|
|
138
|
+
// Routed arm (roadmap 180 revised): explicit backend + NAMESPACED explicit
|
|
139
|
+
// model only — never inferred from credential availability. Plan-time
|
|
140
|
+
// fence: the target must not be provably blind, and must not itself be a
|
|
141
|
+
// model this planner would re-enter for (belt; the terminal marker on the
|
|
142
|
+
// loopback request is the braces).
|
|
143
|
+
if (cfg.backend === "routed") {
|
|
144
|
+
const routedModel = cfg.model;
|
|
145
|
+
const sep = routedModel ? routedModel.indexOf("/") : -1;
|
|
146
|
+
if (routedModel && sep > 0) {
|
|
147
|
+
const targetProvider = routedModel.slice(0, sep);
|
|
148
|
+
const targetId = routedModel.slice(sep + 1);
|
|
149
|
+
const targetProviderConfig = config.providers?.[targetProvider];
|
|
150
|
+
const targetVisible = modelAcceptsImageInput(config, { provider: targetProvider, id: targetId }) !== false
|
|
151
|
+
&& !(targetProviderConfig && isModelTextOnly(targetProviderConfig, targetId));
|
|
152
|
+
if (targetVisible) {
|
|
153
|
+
return {
|
|
154
|
+
backend: "routed",
|
|
155
|
+
routedModel,
|
|
156
|
+
routedConfig: { port: config.port, ...(config.apiKeys ? { apiKeys: config.apiKeys } : {}) },
|
|
157
|
+
settings: {
|
|
158
|
+
model: routedModel,
|
|
159
|
+
reasoning: DEFAULT_REASONING,
|
|
160
|
+
timeoutMs: resolveVisionTimeoutMs(cfg.timeoutMs),
|
|
161
|
+
},
|
|
162
|
+
maxDescriptionsPerTurn: resolveMaxDescriptionsPerTurn(cfg.maxDescriptionsPerTurn),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Misconfigured routed backend (bare id, unknown provider, or provably
|
|
167
|
+
// blind target): fall through to the legacy default order below rather
|
|
168
|
+
// than dispatching a describe that cannot work.
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const anthropicSidecar = findAnthropicVisionProvider(config);
|
|
172
|
+
const backend = resolveVisionBackend(cfg.backend, anthropicSidecar);
|
|
173
|
+
// A namespaced routed model must never reach the forward/OAuth executors
|
|
174
|
+
// (they POST the string verbatim); the effective-model resolver falls back
|
|
175
|
+
// to each side's default in that case.
|
|
176
|
+
const model = resolveEffectiveVisionModel(config, backend);
|
|
177
|
+
const maxDescriptionsPerTurn = resolveMaxDescriptionsPerTurn(cfg.maxDescriptionsPerTurn);
|
|
178
|
+
|
|
179
|
+
if (backend === "anthropic") {
|
|
180
|
+
if (!anthropicSidecar) return undefined;
|
|
181
|
+
return {
|
|
182
|
+
backend,
|
|
183
|
+
anthropicSidecar,
|
|
184
|
+
settings: {
|
|
185
|
+
model,
|
|
186
|
+
reasoning: normalizeVisionReasoningForModel(model, cfg.reasoning) ?? DEFAULT_REASONING,
|
|
187
|
+
timeoutMs: resolveVisionTimeoutMs(cfg.timeoutMs),
|
|
188
|
+
},
|
|
189
|
+
maxDescriptionsPerTurn,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (!openAiSidecar) return undefined;
|
|
194
|
+
return {
|
|
195
|
+
backend,
|
|
196
|
+
forwardSidecar: openAiSidecar,
|
|
197
|
+
settings: {
|
|
198
|
+
...(isCodexReserveRequestEligible(options.codexAuthPolicy ?? config, options.admission) ? { reserveCompatibility: true } : {}),
|
|
199
|
+
model,
|
|
200
|
+
reasoning: normalizeVisionReasoningForModel(model, cfg.reasoning) ?? DEFAULT_REASONING,
|
|
201
|
+
timeoutMs: resolveVisionTimeoutMs(cfg.timeoutMs),
|
|
202
|
+
},
|
|
203
|
+
maxDescriptionsPerTurn,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
@@ -7,11 +7,14 @@ import { applyUpstreamRecoveryInit, fetchWithResetRetry } from "../lib/upstream-
|
|
|
7
7
|
import { withUpstreamHttpVersion } from "../lib/upstream-http-version";
|
|
8
8
|
import { parseSidecarSSE, type WebSearchResult } from "./parse";
|
|
9
9
|
import type { CodexUpstreamOutcome } from "../codex/routing";
|
|
10
|
+
import { NATIVE_RESERVE_MODEL } from "../codex/catalog/native-models";
|
|
10
11
|
|
|
11
12
|
export interface SidecarSettings {
|
|
12
13
|
model: string;
|
|
13
14
|
reasoning: string;
|
|
14
15
|
timeoutMs: number;
|
|
16
|
+
/** Effective Desktop authless compatibility does not grant auxiliary model use. */
|
|
17
|
+
reserveCompatibility?: boolean;
|
|
15
18
|
/**
|
|
16
19
|
* True when the routed (downstream) model is text-only. The search model CAN see images, so it's
|
|
17
20
|
* told to verbalize any relevant image results and include their URLs — otherwise a non-vision model
|
|
@@ -49,6 +52,9 @@ export async function runWebSearch(
|
|
|
49
52
|
abortSignal?: AbortSignal,
|
|
50
53
|
recordOutcome?: SidecarOutcomeRecorder,
|
|
51
54
|
): Promise<SidecarOutcome> {
|
|
55
|
+
if (settings.reserveCompatibility && settings.model === NATIVE_RESERVE_MODEL) {
|
|
56
|
+
return { text: "", sources: [], error: "Luna Reserve compatibility is only available as a conversation model, not a search helper. Choose another search helper model." };
|
|
57
|
+
}
|
|
52
58
|
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
53
59
|
if (forwardProvider.headers) Object.assign(headers, forwardProvider.headers);
|
|
54
60
|
for (const h of FORWARD_HEADERS) {
|
package/src/web-search/index.ts
CHANGED
|
@@ -2,6 +2,9 @@ import type { OcxConfig, OcxParsedRequest, OcxProviderConfig } from "../types";
|
|
|
2
2
|
import { modelInList, toolChoiceToolPredicate } from "../types";
|
|
3
3
|
import { isModelTextOnly } from "../vision";
|
|
4
4
|
import type { SidecarSettings } from "./executor";
|
|
5
|
+
import type { CodexAuthPolicyConfig } from "../codex/auth-context";
|
|
6
|
+
import { isCodexReserveRequestEligible } from "../codex/loopback-target";
|
|
7
|
+
import type { DataPlaneAdmission } from "../server/auth-cors";
|
|
5
8
|
import type { ResolvedOpenAiForwardSidecar } from "../providers/openai-sidecar";
|
|
6
9
|
import { resolveSidecarAuth } from "../sidecar/auth";
|
|
7
10
|
import { getAccountSet } from "../oauth/store";
|
|
@@ -215,6 +218,7 @@ export function planWebSearch(
|
|
|
215
218
|
provider: OcxProviderConfig,
|
|
216
219
|
modelId: string,
|
|
217
220
|
openAiSidecar?: ResolvedOpenAiForwardSidecar,
|
|
221
|
+
options: { admission?: Pick<DataPlaneAdmission, "source">; codexAuthPolicy?: CodexAuthPolicyConfig } = {},
|
|
218
222
|
): SidecarPlan | undefined {
|
|
219
223
|
if (!parsed._webSearch || isPassthrough) return undefined;
|
|
220
224
|
if (!toolChoiceToolPredicate(parsed.options.toolChoice)(buildWebSearchTool())) return undefined;
|
|
@@ -322,7 +326,10 @@ export function planWebSearch(
|
|
|
322
326
|
backend: "openai",
|
|
323
327
|
forwardSidecar: openAiSidecar,
|
|
324
328
|
hostedTool: parsed._webSearch,
|
|
325
|
-
settings: {
|
|
329
|
+
settings: {
|
|
330
|
+
model: cfg.model ?? DEFAULT_SIDECAR_MODEL, reasoning, timeoutMs, describeImages,
|
|
331
|
+
...(isCodexReserveRequestEligible(options.codexAuthPolicy ?? config, options.admission) ? { reserveCompatibility: true } : {}),
|
|
332
|
+
},
|
|
326
333
|
maxSearches,
|
|
327
334
|
routedModelStallTimeoutMs,
|
|
328
335
|
stallTimeoutSec,
|