Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/providers/codex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,12 @@ function shouldSkipCodexSandboxConfig(
}

function shouldDisableCodexWebsockets(): boolean {
const envRaw = Deno.env.get(CODEX_DISABLE_WEBSOCKETS_ENV);
return Boolean(envRaw && parseTruthy(envRaw));
// Newer Codex releases reserve built-in provider IDs, so overriding
// `model_providers.openai.supports_websockets` now prevents app-server
// startup. Keep the env var harmless while the old transport workaround ages
// out.
Deno.env.get(CODEX_DISABLE_WEBSOCKETS_ENV);
return false;
}

function tomlString(value: string): string {
Expand Down
4 changes: 2 additions & 2 deletions src/providers/codex_app_server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Deno.test("codex app-server refresh host failures are returned as RPC errors", a
}
});

Deno.test("codex config can disable OpenAI websocket responses", () => {
Deno.test("codex websocket disable env does not override built-in OpenAI provider", () => {
const previous = Deno.env.get("GAMBIT_CODEX_DISABLE_WEBSOCKETS");
Deno.env.set("GAMBIT_CODEX_DISABLE_WEBSOCKETS", "1");

Expand All @@ -44,7 +44,7 @@ Deno.test("codex config can disable OpenAI websocket responses", () => {

assertEquals(
args.includes("model_providers.openai.supports_websockets=false"),
true,
false,
);
} finally {
if (previous === undefined) {
Expand Down
171 changes: 171 additions & 0 deletions src/runtime_host_service.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { assertEquals } from "@std/assert";
import { assertThrows } from "@std/assert/throws";
import { join } from "@std/path";
import {
callRuntimeHostServiceRaw,
CREATE_WRITEBACK_PREVIEW_HOST_SERVICE_METHOD,
DRAFT_COWORKER_TASK_HOST_SERVICE_METHOD,
validateRuntimeHostServiceMethodAndParams,
} from "./runtime_host_service.ts";

async function readJsonLine(conn: Deno.Conn): Promise<Record<string, unknown>> {
const reader = conn.readable.getReader();
const decoder = new TextDecoder();
let text = "";
try {
while (true) {
const { value, done } = await reader.read();
if (done) break;
text += decoder.decode(value, { stream: true });
const newlineIndex = text.indexOf("\n");
if (newlineIndex >= 0) {
return JSON.parse(text.slice(0, newlineIndex));
}
}
} finally {
reader.releaseLock();
}
throw new Error("expected JSON line");
}

Deno.test("runtime host-service raw calls return non-Codex host results unchanged", async () => {
const root = await Deno.makeTempDir({ dir: "/tmp", prefix: "rhs-" });
const socketPath = join(root, "host-services.sock");
const listener = Deno.listen({ path: socketPath, transport: "unix" });
const server = (async () => {
const conn = await listener.accept();
try {
const request = await readJsonLine(conn);
const writer = conn.writable.getWriter();
await writer.write(
new TextEncoder().encode(
`${
JSON.stringify({
error: null,
id: request.id,
result: {
payload: { taskId: "workspace-delegation-smoke" },
status: 200,
},
})
}\n`,
),
);
writer.releaseLock();
} finally {
conn.close();
listener.close();
}
})();

try {
const result = await callRuntimeHostServiceRaw({
method: DRAFT_COWORKER_TASK_HOST_SERVICE_METHOD,
params: {
targetCoworker: "assistant-to-chief-of-staff",
title: "Workspace delegation smoke",
purpose: "Verify host-owned task drafting.",
request: "Report the current working directory.",
},
socketPath,
token: "test-token",
});

assertEquals(result, {
payload: { taskId: "workspace-delegation-smoke" },
status: 200,
});
} finally {
await server;
await Deno.remove(root, { recursive: true }).catch(() => undefined);
}
});

Deno.test("runtime host-service raw calls support TCP endpoints", async () => {
const listener = Deno.listen({ hostname: "127.0.0.1", port: 0 });
const address = listener.addr;
if (address.transport !== "tcp") {
throw new Error("expected TCP listener");
}
const server = (async () => {
const conn = await listener.accept();
try {
const request = await readJsonLine(conn);
const writer = conn.writable.getWriter();
await writer.write(
new TextEncoder().encode(
`${
JSON.stringify({
error: null,
id: request.id,
result: {
payload: { taskId: "tcp-workspace-delegation-smoke" },
status: 200,
},
})
}\n`,
),
);
writer.releaseLock();
} finally {
conn.close();
listener.close();
}
})();

try {
const result = await callRuntimeHostServiceRaw({
method: DRAFT_COWORKER_TASK_HOST_SERVICE_METHOD,
params: {
targetCoworker: "assistant-to-chief-of-staff",
title: "TCP workspace delegation smoke",
purpose: "Verify host-owned task drafting over TCP.",
request: "Report the current working directory.",
},
socketPath: `tcp://127.0.0.1:${address.port}`,
token: "test-token",
});

assertEquals(result, {
payload: { taskId: "tcp-workspace-delegation-smoke" },
status: 200,
});
} finally {
await server;
}
});

Deno.test("runtime host-service validates create writeback preview params", () => {
assertEquals(
validateRuntimeHostServiceMethodAndParams({
method: CREATE_WRITEBACK_PREVIEW_HOST_SERVICE_METHOD,
params: {
changedPaths: ["notes/smoke.md"],
summary: "Preview the runtime note.",
workspaceRoot:
"/runtime/cache/chief-session-workspaces/session-123/merged/coworkers/agents/assistant-to-chief-of-staff",
},
}),
{
method: CREATE_WRITEBACK_PREVIEW_HOST_SERVICE_METHOD,
params: {
changedPaths: ["notes/smoke.md"],
summary: "Preview the runtime note.",
workspaceRoot:
"/runtime/cache/chief-session-workspaces/session-123/merged/coworkers/agents/assistant-to-chief-of-staff",
},
},
);

assertThrows(
() =>
validateRuntimeHostServiceMethodAndParams({
method: CREATE_WRITEBACK_PREVIEW_HOST_SERVICE_METHOD,
params: {
summary: "Preview the runtime note.",
},
}),
Error,
"workspaceRoot",
);
});
Loading
Loading