Skip to content

Commit f310c6d

Browse files
committed
fix: enable websocket transport by default
1 parent fe51e44 commit f310c6d

7 files changed

Lines changed: 71 additions & 13 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# 133.00 — WebSocket Default-On Release
2+
3+
## Decision
4+
5+
After Phase 132 hardened the Responses WebSocket bridge and the user verified local Codex behavior,
6+
WebSocket advertisement is restored to default-on for `1.9.1`.
7+
8+
## Behavior
9+
10+
- Missing `websockets` now means enabled.
11+
- Fresh `~/.opencodex/config.json` writes `"websockets": true`.
12+
- Explicit `"websockets": false` still suppresses provider/catalog `supports_websockets`.
13+
14+
## Changed
15+
16+
- `/Users/jun/Developer/new/700_projects/opencodex/src/config.ts`
17+
- `/Users/jun/Developer/new/700_projects/opencodex/src/types.ts`
18+
- `/Users/jun/Developer/new/700_projects/opencodex/tests/codex-inject.test.ts`
19+
- `/Users/jun/Developer/new/700_projects/opencodex/tests/codex-catalog.test.ts`
20+
21+
## Verification Plan
22+
23+
- `bun test tests/codex-inject.test.ts tests/codex-catalog.test.ts`
24+
- `bun test tests`
25+
- `bun x tsc --noEmit`
26+
- `ocx start` smoke:
27+
- `/healthz` returns HTTP 200.
28+
- `/v1/models?client_version=0.141.0` advertises `supports_websockets` by default.
29+
- `ocx stop` leaves the proxy stopped before release.
30+
31+
## Verification Results
32+
33+
- `bun test tests/codex-inject.test.ts tests/codex-catalog.test.ts`
34+
- 17 pass, 0 fail, 107 assertions.
35+
- `bun test tests`
36+
- 85 pass, 0 fail, 277 assertions.
37+
- `bun x tsc --noEmit`
38+
- passed with exit 0.
39+
- Local source smoke via `bun src/cli.ts start`
40+
- `/healthz` returned HTTP 200.
41+
- `/v1/models?client_version=0.141.0` returned `supports_websockets: true` for:
42+
- `gpt-5.5`
43+
- `opencode-go/kimi-k2.7-code`
44+
- `opencode-go/minimax-m3`
45+
- Context values stayed correct for the checked routed models:
46+
- `opencode-go/kimi-k2.7-code`: `262144`, auto compact `235929`
47+
- `opencode-go/minimax-m3`: `512000`, auto compact `460800`
48+
- `ocx stop` stopped the proxy and final `ocx status` returned `Proxy not running`.

src/codex-catalog.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ function deriveEntry(template: RawEntry | null, slug: string, desc: string, prio
206206
* catalog sync and the proxy `/v1/models?client_version` branch.
207207
* Native gpt slugs stay bare; routed models are namespaced `<provider>/<model>`.
208208
*/
209-
export function buildCatalogEntries(template: RawEntry | null, gptSlugs: string[], goModels: CatalogModel[], featured?: string[], wsEnabled = false): RawEntry[] {
209+
export function buildCatalogEntries(template: RawEntry | null, gptSlugs: string[], goModels: CatalogModel[], featured?: string[], wsEnabled = true): RawEntry[] {
210210
// Codex's models-manager sorts by `priority` ASC and advertises the first 5 picker-visible
211211
// models to spawn_agent (sort_by_key(priority) + MAX_MODEL_OVERRIDES_IN_SPAWN_AGENT=5). Catalog
212212
// ARRAY order is discarded — so "featuring" a model = giving it the LOWEST priority (0..N-1) so

src/codex-inject.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const OCX_SECTION_MARKER = "# Auto-injected by opencodex";
1414
* whatever `[table]` happened to be open last (e.g. `[plugins."chrome@openai-bundled"]`), so Codex
1515
* never saw a global model_provider and silently fell back to the `openai` (ChatGPT) provider.
1616
*/
17-
export function buildProviderTableBlock(port: number, supportsWebsockets = false): string {
17+
export function buildProviderTableBlock(port: number, supportsWebsockets = true): string {
1818
const lines = [
1919
"",
2020
OCX_SECTION_MARKER,

src/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export function saveConfig(config: OcxConfig): void {
5858
}
5959

6060
export function websocketsEnabled(config: Pick<OcxConfig, "websockets">): boolean {
61-
return config.websockets === true;
61+
return config.websockets !== false;
6262
}
6363

6464
export function getDefaultConfig(): OcxConfig {
@@ -76,7 +76,7 @@ export function getDefaultConfig(): OcxConfig {
7676
},
7777
defaultProvider: "openai",
7878
subagentModels: [...DEFAULT_SUBAGENT_MODELS],
79-
websockets: false,
79+
websockets: true,
8080
};
8181
}
8282

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ export interface OcxConfig {
175175
subagentModels?: string[];
176176
/** Routed model ids ("<provider>/<model>") hidden from Codex (excluded from the catalog + /v1/models). */
177177
disabledModels?: string[];
178-
/** Advertise supports_websockets so Codex opens the WS endpoint. Default false; set true to opt into WS. */
178+
/** Advertise supports_websockets so Codex opens the WS endpoint. Default true; set false to force HTTPS/SSE. */
179179
websockets?: boolean;
180180
/** Freshness window (ms) for the per-provider live `/models` cache. Defaults to 5 min. */
181181
modelCacheTtlMs?: number;

tests/codex-catalog.test.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ describe("Codex catalog routed normalization", () => {
6262
expect(routed).not.toHaveProperty("tool_mode");
6363
expect(routed).not.toHaveProperty("multi_agent_version");
6464
expect(routed).not.toHaveProperty("use_responses_lite");
65-
expect(routed).not.toHaveProperty("supports_websockets");
65+
expect(routed?.supports_websockets).toBe(true);
6666
expect(routed).not.toHaveProperty("additional_speed_tiers");
6767
expect(routed).not.toHaveProperty("service_tier");
6868
expect(routed).not.toHaveProperty("service_tiers");
@@ -99,24 +99,28 @@ describe("Codex catalog routed normalization", () => {
9999
expect(native?.tool_mode).toBe("code");
100100
expect(native?.multi_agent_version).toBe("v2");
101101
expect(native?.use_responses_lite).toBe(true);
102-
// Phase 132: websocket advertisement is explicit opt-in, not inherited from templates.
103-
expect(native).not.toHaveProperty("supports_websockets");
102+
// Phase 133: websocket advertisement is default-on after Phase 132 hardening.
103+
expect(native?.supports_websockets).toBe(true);
104104
expect(native?.web_search_tool_type).toBe("text_and_image");
105105
expect(native?.supports_search_tool).toBe(true);
106106
expect(native?.service_tier).toBe("priority");
107107
expect(native?.service_tiers).toEqual([{ id: "priority" }]);
108108
});
109109

110-
test("buildCatalogEntries advertises supports_websockets only on explicit opt-in", () => {
110+
test("buildCatalogEntries advertises supports_websockets by default with explicit opt-out", () => {
111111
const goModels = [{ provider: "anthropic", id: "claude-sonnet-4-6", owned_by: "anthropic" }];
112112

113-
const off = buildCatalogEntries(nativeTemplate(), ["gpt-5.5"], goModels);
114-
expect(off.find(e => e.slug === "gpt-5.5")).not.toHaveProperty("supports_websockets");
115-
expect(off.find(e => e.slug === "anthropic/claude-sonnet-4-6")).not.toHaveProperty("supports_websockets");
113+
const defaultOn = buildCatalogEntries(nativeTemplate(), ["gpt-5.5"], goModels);
114+
expect(defaultOn.find(e => e.slug === "gpt-5.5")?.supports_websockets).toBe(true);
115+
expect(defaultOn.find(e => e.slug === "anthropic/claude-sonnet-4-6")?.supports_websockets).toBe(true);
116116

117117
const on = buildCatalogEntries(nativeTemplate(), ["gpt-5.5"], goModels, undefined, true);
118118
expect(on.find(e => e.slug === "gpt-5.5")?.supports_websockets).toBe(true);
119119
expect(on.find(e => e.slug === "anthropic/claude-sonnet-4-6")?.supports_websockets).toBe(true);
120+
121+
const off = buildCatalogEntries(nativeTemplate(), ["gpt-5.5"], goModels, undefined, false);
122+
expect(off.find(e => e.slug === "gpt-5.5")).not.toHaveProperty("supports_websockets");
123+
expect(off.find(e => e.slug === "anthropic/claude-sonnet-4-6")).not.toHaveProperty("supports_websockets");
120124
});
121125

122126
test("fallback routed entries still receive explicit search metadata", () => {

tests/codex-inject.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ import { describe, expect, test } from "bun:test";
22
import { buildProviderTableBlock, stripOpencodexConfig } from "../src/codex-inject";
33

44
describe("Codex config injection", () => {
5-
test("omits provider-level Responses WebSocket support by default", () => {
5+
test("advertises provider-level Responses WebSocket support by default", () => {
66
const block = buildProviderTableBlock(10100);
77

88
expect(block).toContain("[model_providers.opencodex]");
99
expect(block).toContain('wire_api = "responses"');
1010
expect(block).toContain("requires_openai_auth = true");
11+
expect(block).toContain("supports_websockets = true");
12+
});
13+
14+
test("can suppress provider-level Responses WebSocket support for explicit opt-out", () => {
15+
const block = buildProviderTableBlock(10100, false);
16+
1117
expect(block).not.toContain("supports_websockets");
1218
});
1319

0 commit comments

Comments
 (0)