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
36 changes: 36 additions & 0 deletions apps/server/src/provider/Layers/CodexAdapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => {
turnId: asTurnId("turn-1"),
itemId: asItemId("msg_1"),
payload: {
completedAtMs: 1_778_000_000_000,
threadId: "thread-1",
turnId: "turn-1",
item: {
Expand Down Expand Up @@ -494,6 +495,7 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => {
turnId: asTurnId("turn-1"),
itemId: asItemId("plan_1"),
payload: {
completedAtMs: 1_778_000_000_000,
threadId: "thread-1",
turnId: "turn-1",
item: {
Expand Down Expand Up @@ -660,6 +662,40 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => {
}),
);

it.effect("maps realtime started notifications with upstream realtime session ids", () =>
Effect.gen(function* () {
const { adapter, runtime } = yield* startLifecycleRuntime();
const firstEventFiber = yield* Stream.runHead(adapter.streamEvents).pipe(Effect.forkChild);

yield* runtime.emit({
id: asEventId("evt-realtime-started"),
kind: "notification",
provider: ProviderDriverKind.make("codex"),
threadId: asThreadId("thread-1"),
createdAt: new Date().toISOString(),
method: "thread/realtime/started",
payload: {
threadId: "thread-1",
realtimeSessionId: "realtime-session-1",
version: "v2",
},
} satisfies ProviderEvent);

const firstEvent = yield* Fiber.join(firstEventFiber);

assert.equal(firstEvent._tag, "Some");
if (firstEvent._tag !== "Some") {
return;
}
assert.equal(firstEvent.value.type, "thread.realtime.started");
if (firstEvent.value.type !== "thread.realtime.started") {
return;
}
assert.equal(firstEvent.value.threadId, "thread-1");
assert.equal(firstEvent.value.payload.realtimeSessionId, "realtime-session-1");
}),
);

it.effect("maps fatal websocket stderr notifications to runtime.error", () =>
Effect.gen(function* () {
const { adapter, runtime } = yield* startLifecycleRuntime();
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/provider/Layers/CodexAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1151,7 +1151,7 @@ function mapToRuntimeEvents(
type: "thread.realtime.started",
...runtimeEventBase(event, canonicalThreadId),
payload: {
realtimeSessionId: payload.sessionId ?? undefined,
realtimeSessionId: payload.realtimeSessionId ?? undefined,
},
},
];
Expand Down
2 changes: 2 additions & 0 deletions apps/server/src/provider/Layers/CodexProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ const REASONING_EFFORT_LABELS: Record<CodexSchema.V2ModelListResponse__Reasoning
function codexAccountAuthLabel(account: CodexSchema.V2GetAccountResponse["account"]) {
if (!account) return undefined;
if (account.type === "apiKey") return "OpenAI API Key";
if (account.type === "amazonBedrock") return "Amazon Bedrock";
if (account.type !== "chatgpt") return undefined;

switch (account.planType) {
case "free":
Expand Down
11 changes: 6 additions & 5 deletions apps/server/src/provider/Layers/CodexSessionRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export type CodexTurnStartParamsWithCollaborationMode =
const formatSchemaIssue = SchemaIssue.makeFormatterDefault();

export type CodexResumeCursor = typeof CodexResumeCursorSchema.Type;
type CodexServiceTier = NonNullable<EffectCodexSchema.V2ThreadStartParams["serviceTier"]>;
type CodexThreadItem =
| EffectCodexSchema.V2ThreadReadResponse["thread"]["turns"][number]["items"][number]
| EffectCodexSchema.V2ThreadRollbackResponse["thread"]["turns"][number]["items"][number];
Expand All @@ -83,7 +84,7 @@ export interface CodexSessionRuntimeOptions {
readonly cwd: string;
readonly runtimeMode: RuntimeMode;
readonly model?: string;
readonly serviceTier?: EffectCodexSchema.V2ThreadStartParams__ServiceTier | undefined;
readonly serviceTier?: CodexServiceTier | undefined;
readonly resumeCursor?: CodexResumeCursor;
}

Expand All @@ -94,7 +95,7 @@ export interface CodexSessionRuntimeSendTurnInput {
readonly url: string;
}>;
readonly model?: string;
readonly serviceTier?: EffectCodexSchema.V2TurnStartParams__ServiceTier | undefined;
readonly serviceTier?: CodexServiceTier | undefined;
readonly effort?: EffectCodexSchema.V2TurnStartParams__ReasoningEffort | undefined;
readonly interactionMode?: ProviderInteractionMode;
}
Expand Down Expand Up @@ -268,7 +269,7 @@ function buildThreadStartParams(input: {
readonly cwd: string;
readonly runtimeMode: RuntimeMode;
readonly model: string | undefined;
readonly serviceTier: EffectCodexSchema.V2ThreadStartParams__ServiceTier | undefined;
readonly serviceTier: CodexServiceTier | undefined;
}): EffectCodexSchema.V2ThreadStartParams {
const config = runtimeModeToThreadConfig(input.runtimeMode);
return {
Expand Down Expand Up @@ -331,7 +332,7 @@ export function buildTurnStartParams(input: {
readonly url: string;
}>;
readonly model?: string;
readonly serviceTier?: EffectCodexSchema.V2TurnStartParams__ServiceTier;
readonly serviceTier?: CodexServiceTier;
readonly effort?: EffectCodexSchema.V2TurnStartParams__ReasoningEffort;
readonly interactionMode?: ProviderInteractionMode;
}): Effect.Effect<
Expand Down Expand Up @@ -417,7 +418,7 @@ export const openCodexThread = (input: {
readonly runtimeMode: RuntimeMode;
readonly cwd: string;
readonly requestedModel: string | undefined;
readonly serviceTier: EffectCodexSchema.V2ThreadStartParams__ServiceTier | undefined;
readonly serviceTier: CodexServiceTier | undefined;
readonly resumeThreadId: string | undefined;
}): Effect.Effect<CodexThreadOpenResponse, CodexErrors.CodexAppServerError> => {
const resumeThreadId = input.resumeThreadId;
Expand Down
20 changes: 20 additions & 0 deletions apps/server/src/provider/Layers/ProviderRegistry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,26 @@ it.layer(Layer.mergeAll(NodeServices.layer, ServerSettingsService.layerTest(), T
}),
);

it.effect("returns an Amazon Bedrock label for codex Bedrock auth", () =>
Effect.gen(function* () {
const status = yield* checkCodexProviderStatus(defaultCodexSettings, () =>
Effect.succeed(
makeCodexProbeSnapshot({
account: {
account: { type: "amazonBedrock" },
requiresOpenaiAuth: false,
},
}),
),
);

assert.strictEqual(status.status, "ready");
assert.strictEqual(status.auth.status, "authenticated");
assert.strictEqual(status.auth.type, "amazonBedrock");
assert.strictEqual(status.auth.label, "Amazon Bedrock");
}),
);

it.effect("returns unavailable when codex is missing", () =>
Effect.gen(function* () {
const status = yield* checkCodexProviderStatus(defaultCodexSettings, () =>
Expand Down
2 changes: 1 addition & 1 deletion packages/effect-codex-app-server/scripts/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from "effect/unstable/http";
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";

const UPSTREAM_REF = "be75785504ff152fa6333e380a2d50642f42fba0";
const UPSTREAM_REF = "07b695190f30a450e4921f71f77473e564395c59";
const USER_AGENT = "effect-codex-app-server-generator";
const GITHUB_API_BASE =
"https://api.github.com/repos/openai/codex/contents/codex-rs/app-server-protocol";
Expand Down
Loading
Loading