/** * CodexAdapterLive - Scoped live implementation for the Codex provider adapter. * * Wraps `CodexAppServerManager` behind the `CodexAdapter` service contract and * maps manager failures into the shared `ProviderAdapterError` algebra. * * @module CodexAdapterLive */import { type CanonicalItemType, type CanonicalRequestType, type ProviderEvent, type ProviderRuntimeEvent, type ProviderUserInputAnswers, RuntimeItemId, RuntimeRequestId, RuntimeTaskId, ProviderApprovalDecision, ProviderItemId, ThreadId, TurnId,} from "@t3tools/contracts";import { Effect, FileSystem, Layer, Queue, Schema, ServiceMap, Stream } from "effect"; import { ProviderAdapterProcessError, ProviderAdapterRequestError, ProviderAdapterSessionClosedError, ProviderAdapterSessionNotFoundError, ProviderAdapterValidationError, type ProviderAdapterError,} from "../Errors.ts";import { CodexAdapter, type CodexAdapterShape } from "../Services/CodexAdapter.ts";import { CodexAppServerManager, type CodexAppServerStartSessionInput,} from "../../codexAppServerManager.ts";import { resolveAttachmentPath } from "../../attachmentStore.ts";import { ServerConfig } from "../../config.ts";import { type EventNdjsonLogger, makeEventNdjsonLogger } from "./EventNdjsonLogger.ts"; const PROVIDER = "codex" as const; export interface CodexAdapterLiveOptions { readonly manager?: CodexAppServerManager; readonly makeManager?: (services?: ServiceMap.ServiceMap<never>) => CodexAppServerManager; readonly nativeEventLogPath?: string; readonly nativeEventLogger?: EventNdjsonLogger;} function toMessage(cause: unknown, fallback: string): string { if (cause instanceof Error && cause.message.length > 0) { return cause.message; } return fallback;} function toSessionError( threadId: ThreadId, cause: unknown,): ProviderAdapterSessionNotFoundError | ProviderAdapterSessionClosedError | undefined { const normalized = toMessage(cause, "").toLowerCase(); if (normalized.includes("unknown session") || normalized.includes("unknown provider session")) { return new ProviderAdapterSessionNotFoundError({ provider: PROVIDER, threadId, cause, }); } if (normalized.includes("session is closed")) { return new ProviderAdapterSessionClosedError({ provider: PROVIDER, threadId, cause, }); } return undefined;} function toRequestError(threadId: ThreadId, method: string, cause: unknown): ProviderAdapterError { const sessionError = toSessionError(threadId, cause); if (sessionError) { return sessionError; } return new ProviderAdapterRequestError({ provider: PROVIDER, method, detail: toMessage(cause, `${method} failed`), cause, });} function asObject(value: unknown): Record<string, unknown> | undefined { if (!value || typeof value !== "object") { return undefined; } return value as Record<string, unknown>;} function asString(value: unknown): string | undefined { return typeof value === "string" ? value : undefined;} function asArray(value: unknown): unknown[] | undefined { return Array.isArray(value) ? value : undefined;} function asNumber(value: unknown): number | undefined { return typeof value === "number" && Number.isFinite(value) ? value : undefined;} function toTurnStatus(value: unknown): "completed" | "failed" | "cancelled" | "interrupted" { switch (value) { case "completed": case "failed": case "cancelled": case "interrupted": return value; default: return "completed"; }} function normalizeItemType(raw: unknown): string { const type = asString(raw); if (!type) return "item"; return type .replace(/([a-z0-9])([A-Z])/g, "$1 $2") .replace(/[._/-]/g, " ") .replace(/\s+/g, " ") .trim() .toLowerCase();} function toCanonicalItemType(raw: unknown): CanonicalItemType { const type = normalizeItemType(raw); if (type.includes("user")) return "user_message"; if (type.includes("agent message") || type.includes("assistant")) return "assistant_message"; if (type.includes("reasoning") || type.includes("thought")) return "reasoning"; if (type.includes("plan") || type.includes("todo")) return "plan"; if (type.includes("command")) return "command_execution"; if (type.includes("file change") || type.includes("patch") || type.includes("edit")) return "file_change"; if (type.includes("mcp")) return "mcp_tool_call"; if (type.includes("dynamic tool")) return "dynamic_tool_call"; if (type.includes("collab")) return "collab_agent_tool_call"; if (type.includes("web search")) return "web_search"; if (type.includes("image")) return "image_view"; if (type.includes("review entered")) return "review_entered"; if (type.includes("review exited")) return "review_exited"; if (type.includes("compact")) return "context_compaction"; if (type.includes("error")) return "error"; return "unknown";} function itemTitle(itemType: CanonicalItemType): string | undefined { switch (itemType) { case "assistant_message": return "Assistant message"; case "user_message": return "User message"; case "reasoning": return "Reasoning"; case "plan": return "Plan"; case "command_execution": return "Command run"; case "file_change": return "File change"; case "mcp_tool_call": return "MCP tool call"; case "dynamic_tool_call": return "Tool call"; case "web_search": return "Web search"; case "image_view": return "Image view"; case "error": return "Error"; default: return undefined; }} function itemDetail( item: Record<string, unknown>, payload: Record<string, unknown>,): string | undefined { const nestedResult = asObject(item.result); const candidates = [ asString(item.command), asString(item.title), asString(item.summary), asString(item.text), asString(item.path), asString(item.prompt), asString(nestedResult?.command), asString(payload.command), asString(payload.message), asString(payload.prompt), ]; for (const candidate of candidates) { if (!candidate) continue; const trimmed = candidate.trim(); if (trimmed.length === 0) continue; return trimmed; } return undefined;} function toRequestTypeFromMethod(method: string): CanonicalRequestType { switch (method) { case "item/commandExecution/requestApproval": return "command_execution_approval"; case "item/fileRead/requestApproval": return "file_read_approval"; case "item/fileChange/requestApproval": return "file_change_approval"; case "applyPatchApproval": return "apply_patch_approval"; case "execCommandApproval": return "exec_command_approval"; case "item/tool/requestUserInput": return "tool_user_input"; case "item/tool/call": return "dynamic_tool_call"; case "account/chatgptAuthTokens/refresh": return "auth_tokens_refresh"; default: return "unknown"; }} function toRequestTypeFromKind(kind: unknown): CanonicalRequestType { switch (kind) { case "command": return "command_execution_approval"; case "file-read": return "file_read_approval"; case "file-change": return "file_change_approval"; default: return "unknown"; }} function toRequestTypeFromResolvedPayload( payload: Record<string, unknown> | undefined,): CanonicalRequestType { const request = asObject(payload?.request); const method = asString(request?.method) ?? asString(payload?.method); if (method) { return toRequestTypeFromMethod(method); } const requestKind = asString(request?.kind) ?? asString(payload?.requestKind); if (requestKind) { return toRequestTypeFromKind(requestKind); } return "unknown";} function toCanonicalUserInputAnswers( answers: ProviderUserInputAnswers | undefined,): ProviderUserInputAnswers { if (!answers) { return {}; } return Object.fromEntries( Object.entries(answers).flatMap(([questionId, value]) => { if (typeof value === "string") { return [[questionId, value] as const]; } if (Array.isArray(value)) { const normalized = value.filter((entry): entry is string => typeof entry === "string"); return [[questionId, normalized.length === 1 ? normalized[0] : normalized] as const]; } const answerObject = asObject(value); const answerList = asArray(answerObject?.answers)?.filter( (entry): entry is string => typeof entry === "string", ); if (!answerList) { return []; } return [[questionId, answerList.length === 1 ? answerList[0] : answerList] as const]; }), );} function toUserInputQuestions(payload: Record<string, unknown> | undefined) { const questions = asArray(payload?.questions); if (!questions) { return undefined; } const parsedQuestions = questions .map((entry) => { const question = asObject(entry); if (!question) return undefined; const options = asArray(question.options) ?.map((option) => { const optionRecord = asObject(option); if (!optionRecord) return undefined; const label = asString(optionRecord.label)?.trim(); const description = asString(optionRecord.description)?.trim(); if (!label || !description) { return undefined; } return { label, description }; }) .filter((option): option is { label: string; description: string } => option !== undefined); const id = asString(question.id)?.trim(); const header = asString(question.header)?.trim(); const prompt = asString(question.question)?.trim(); if (!id || !header || !prompt || !options || options.length === 0) { return undefined; } return { id, header, question: prompt, options, }; }) .filter( ( question, ): question is { id: string; header: string; question: string; options: Array<{ label: string; description: string }>; } => question !== undefined, ); return parsedQuestions.length > 0 ? parsedQuestions : undefined;} function toThreadState( value: unknown,): "active" | "idle" | "archived" | "closed" | "compacted" | "error" { switch (value) { case "idle": return "idle"; case "archived": return "archived"; case "closed": return "closed"; case "compacted": return "compacted"; case "error": case "failed": return "error"; default: return "active"; }} function contentStreamKindFromMethod( method: string,): | "assistant_text" | "reasoning_text" | "reasoning_summary_text" | "plan_text" | "command_output" | "file_change_output" { switch (method) { case "item/agentMessage/delta": return "assistant_text"; case "item/reasoning/textDelta": return "reasoning_text"; case "item/reasoning/summaryTextDelta": return "reasoning_summary_text"; case "item/commandExecution/outputDelta": return "command_output"; case "item/fileChange/outputDelta": return "file_change_output"; default: return "assistant_text"; }} const PROPOSED_PLAN_BLOCK_REGEX = /<proposed_plan>\s*([\s\S]*?)\s*<\/proposed_plan>/i; function extractProposedPlanMarkdown(text: string | undefined): string | undefined { const match = text ? PROPOSED_PLAN_BLOCK_REGEX.exec(text) : null; const planMarkdown = match?.[1]?.trim(); return planMarkdown && planMarkdown.length > 0 ? planMarkdown : undefined;} function asRuntimeItemId(itemId: ProviderItemId): RuntimeItemId { return RuntimeItemId.makeUnsafe(itemId);} function asRuntimeRequestId(requestId: string): RuntimeRequestId { return RuntimeRequestId.makeUnsafe(requestId);} function asRuntimeTaskId(taskId: string): RuntimeTaskId { return RuntimeTaskId.makeUnsafe(taskId);} function codexEventMessage(payload: Record<string, unknown> | undefined): Record<string, unknown> | undefined { return asObject(payload?.msg);} function codexEventBase( event: ProviderEvent, canonicalThreadId: ThreadId,): Omit<ProviderRuntimeEvent, "type" | "payload"> { const payload = asObject(event.payload); const msg = codexEventMessage(payload); const turnId = asString(msg?.turn_id) ?? asString(msg?.turnId); const itemId = asString(msg?.item_id) ?? asString(msg?.itemId); const requestId = asString(msg?.request_id) ?? asString(msg?.requestId); const base = runtimeEventBase(event, canonicalThreadId); const providerRefs = base.providerRefs ? { ...base.providerRefs, ...(turnId ? { providerTurnId: turnId } : {}), ...(itemId ? { providerItemId: ProviderItemId.makeUnsafe(itemId) } : {}), ...(requestId ? { providerRequestId: requestId } : {}), } : { ...(turnId ? { providerTurnId: turnId } : {}), ...(itemId ? { providerItemId: ProviderItemId.makeUnsafe(itemId) } : {}), ...(requestId ? { providerRequestId: requestId } : {}), }; return { ...base, ...(turnId ? { turnId: TurnId.makeUnsafe(turnId) } : {}), ...(itemId ? { itemId: asRuntimeItemId(ProviderItemId.makeUnsafe(itemId)) } : {}), ...(requestId ? { requestId: asRuntimeRequestId(requestId) } : {}), ...(Object.keys(providerRefs).length > 0 ? { providerRefs } : {}), };} function eventRawSource(event: ProviderEvent): NonNullable<ProviderRuntimeEvent["raw"]>["source"] { return event.kind === "request" ? "codex.app-server.request" : "codex.app-server.notification";} function providerRefsFromEvent( event: ProviderEvent,): ProviderRuntimeEvent["providerRefs"] | undefined { const refs: Record<string, string> = {}; if (event.turnId) refs.providerTurnId = event.turnId; if (event.itemId) refs.providerItemId = event.itemId; if (event.requestId) refs.providerRequestId = event.requestId; return Object.keys(refs).length > 0 ? (refs as ProviderRuntimeEvent["providerRefs"]) : undefined;} function runtimeEventBase( event: ProviderEvent, canonicalThreadId: ThreadId,): Omit<ProviderRuntimeEvent, "type" | "payload"> { const refs = providerRefsFromEvent(event); return { eventId: event.id, provider: event.provider, threadId: canonicalThreadId, createdAt: event.createdAt, ...(event.turnId ? { turnId: event.turnId } : {}), ...(event.itemId ? { itemId: asRuntimeItemId(event.itemId) } : {}), ...(event.requestId ? { requestId: asRuntimeRequestId(event.requestId) } : {}), ...(refs ? { providerRefs: refs } : {}), raw: { source: eventRawSource(event), method: event.method, payload: event.payload ?? {}, }, };} function mapItemLifecycle( event: ProviderEvent, canonicalThreadId: ThreadId, lifecycle: "item.started" | "item.updated" | "item.completed",): ProviderRuntimeEvent | undefined { const payload = asObject(event.payload); const item = asObject(payload?.item); const source = item ?? payload; if (!source) { return undefined; } const itemType = toCanonicalItemType(source.type ?? source.kind); if (itemType === "unknown" && lifecycle !== "item.updated") { return undefined; } const detail = itemDetail(source, payload ?? {}); const status = lifecycle === "item.started" ? "inProgress" : lifecycle === "item.completed"Lines 1–500 of 1517. Load more
/** * CodexAdapterLive - Scoped live implementation for the Codex provider adapter. * * Wraps `CodexAppServerManager` behind the `CodexAdapter` service contract and * maps manager failures into the shared `ProviderAdapterError` algebra. * * @module CodexAdapterLive */ import { type CanonicalItemType, type CanonicalRequestType, type ProviderEvent, type ProviderRuntimeEvent, type ProviderUserInputAnswers, RuntimeItemId, RuntimeRequestId, RuntimeTaskId, ProviderApprovalDecision, ProviderItemId, ThreadId, TurnId, } from "@t3tools/contracts"; import { Effect, FileSystem, Layer, Queue, Schema, ServiceMap, Stream } from "effect"; import { ProviderAdapterProcessError, ProviderAdapterRequestError, ProviderAdapterSessionClosedError, ProviderAdapterSessionNotFoundError, ProviderAdapterValidationError, type ProviderAdapterError, } from "../Errors.ts"; import { CodexAdapter, type CodexAdapterShape } from "../Services/CodexAdapter.ts"; import { CodexAppServerManager, type CodexAppServerStartSessionInput, } from "../../codexAppServerManager.ts"; import { resolveAttachmentPath } from "../../attachmentStore.ts"; import { ServerConfig } from "../../config.ts"; import { type EventNdjsonLogger, makeEventNdjsonLogger } from "./EventNdjsonLogger.ts"; const PROVIDER = "codex" as const; export interface CodexAdapterLiveOptions { readonly manager?: CodexAppServerManager; readonly makeManager?: (services?: ServiceMap.ServiceMap<never>) => CodexAppServerManager; readonly nativeEventLogPath?: string; readonly nativeEventLogger?: EventNdjsonLogger; } function toMessage(cause: unknown, fallback: string): string { if (cause instanceof Error && cause.message.length > 0) { return cause.message; } return fallback; } function toSessionError( threadId: ThreadId, cause: unknown, ): ProviderAdapterSessionNotFoundError | ProviderAdapterSessionClosedError | undefined { const normalized = toMessage(cause, "").toLowerCase(); if (normalized.includes("unknown session") || normalized.includes("unknown provider session")) { return new ProviderAdapterSessionNotFoundError({ provider: PROVIDER, threadId, cause, }); } if (normalized.includes("session is closed")) { return new ProviderAdapterSessionClosedError({ provider: PROVIDER, threadId, cause, }); } return undefined; } function toRequestError(threadId: ThreadId, method: string, cause: unknown): ProviderAdapterError { const sessionError = toSessionError(threadId, cause); if (sessionError) { return sessionError; } return new ProviderAdapterRequestError({ provider: PROVIDER, method, detail: toMessage(cause, `${method} failed`), cause, }); } function asObject(value: unknown): Record<string, unknown> | undefined { if (!value || typeof value !== "object") { return undefined; } return value as Record<string, unknown>; } function asString(value: unknown): string | undefined { return typeof value === "string" ? value : undefined; } function asArray(value: unknown): unknown[] | undefined { return Array.isArray(value) ? value : undefined; } function asNumber(value: unknown): number | undefined { return typeof value === "number" && Number.isFinite(value) ? value : undefined; } function toTurnStatus(value: unknown): "completed" | "failed" | "cancelled" | "interrupted" { switch (value) { case "completed": case "failed": case "cancelled": case "interrupted": return value; default: return "completed"; } } function normalizeItemType(raw: unknown): string { const type = asString(raw); if (!type) return "item"; return type .replace(/([a-z0-9])([A-Z])/g, "$1 $2") .replace(/[._/-]/g, " ") .replace(/\s+/g, " ") .trim() .toLowerCase(); } function toCanonicalItemType(raw: unknown): CanonicalItemType { const type = normalizeItemType(raw); if (type.includes("user")) return "user_message"; if (type.includes("agent message") || type.includes("assistant")) return "assistant_message"; if (type.includes("reasoning") || type.includes("thought")) return "reasoning"; if (type.includes("plan") || type.includes("todo")) return "plan"; if (type.includes("command")) return "command_execution"; if (type.includes("file change") || type.includes("patch") || type.includes("edit")) return "file_change"; if (type.includes("mcp")) return "mcp_tool_call"; if (type.includes("dynamic tool")) return "dynamic_tool_call"; if (type.includes("collab")) return "collab_agent_tool_call"; if (type.includes("web search")) return "web_search"; if (type.includes("image")) return "image_view"; if (type.includes("review entered")) return "review_entered"; if (type.includes("review exited")) return "review_exited"; if (type.includes("compact")) return "context_compaction"; if (type.includes("error")) return "error"; return "unknown"; } function itemTitle(itemType: CanonicalItemType): string | undefined { switch (itemType) { case "assistant_message": return "Assistant message"; case "user_message": return "User message"; case "reasoning": return "Reasoning"; case "plan": return "Plan"; case "command_execution": return "Command run"; case "file_change": return "File change"; case "mcp_tool_call": return "MCP tool call"; case "dynamic_tool_call": return "Tool call"; case "web_search": return "Web search"; case "image_view": return "Image view"; case "error": return "Error"; default: return undefined; } } function itemDetail( item: Record<string, unknown>, payload: Record<string, unknown>, ): string | undefined { const nestedResult = asObject(item.result); const candidates = [ asString(item.command), asString(item.title), asString(item.summary), asString(item.text), asString(item.path), asString(item.prompt), asString(nestedResult?.command), asString(payload.command), asString(payload.message), asString(payload.prompt), ]; for (const candidate of candidates) { if (!candidate) continue; const trimmed = candidate.trim(); if (trimmed.length === 0) continue; return trimmed; } return undefined; } function toRequestTypeFromMethod(method: string): CanonicalRequestType { switch (method) { case "item/commandExecution/requestApproval": return "command_execution_approval"; case "item/fileRead/requestApproval": return "file_read_approval"; case "item/fileChange/requestApproval": return "file_change_approval"; case "applyPatchApproval": return "apply_patch_approval"; case "execCommandApproval": return "exec_command_approval"; case "item/tool/requestUserInput": return "tool_user_input"; case "item/tool/call": return "dynamic_tool_call"; case "account/chatgptAuthTokens/refresh": return "auth_tokens_refresh"; default: return "unknown"; } } function toRequestTypeFromKind(kind: unknown): CanonicalRequestType { switch (kind) { case "command": return "command_execution_approval"; case "file-read": return "file_read_approval"; case "file-change": return "file_change_approval"; default: return "unknown"; } } function toRequestTypeFromResolvedPayload( payload: Record<string, unknown> | undefined, ): CanonicalRequestType { const request = asObject(payload?.request); const method = asString(request?.method) ?? asString(payload?.method); if (method) { return toRequestTypeFromMethod(method); } const requestKind = asString(request?.kind) ?? asString(payload?.requestKind); if (requestKind) { return toRequestTypeFromKind(requestKind); } return "unknown"; } function toCanonicalUserInputAnswers( answers: ProviderUserInputAnswers | undefined, ): ProviderUserInputAnswers { if (!answers) { return {}; } return Object.fromEntries( Object.entries(answers).flatMap(([questionId, value]) => { if (typeof value === "string") { return [[questionId, value] as const]; } if (Array.isArray(value)) { const normalized = value.filter((entry): entry is string => typeof entry === "string"); return [[questionId, normalized.length === 1 ? normalized[0] : normalized] as const]; } const answerObject = asObject(value); const answerList = asArray(answerObject?.answers)?.filter( (entry): entry is string => typeof entry === "string", ); if (!answerList) { return []; } return [[questionId, answerList.length === 1 ? answerList[0] : answerList] as const]; }), ); } function toUserInputQuestions(payload: Record<string, unknown> | undefined) { const questions = asArray(payload?.questions); if (!questions) { return undefined; } const parsedQuestions = questions .map((entry) => { const question = asObject(entry); if (!question) return undefined; const options = asArray(question.options) ?.map((option) => { const optionRecord = asObject(option); if (!optionRecord) return undefined; const label = asString(optionRecord.label)?.trim(); const description = asString(optionRecord.description)?.trim(); if (!label || !description) { return undefined; } return { label, description }; }) .filter((option): option is { label: string; description: string } => option !== undefined); const id = asString(question.id)?.trim(); const header = asString(question.header)?.trim(); const prompt = asString(question.question)?.trim(); if (!id || !header || !prompt || !options || options.length === 0) { return undefined; } return { id, header, question: prompt, options, }; }) .filter( ( question, ): question is { id: string; header: string; question: string; options: Array<{ label: string; description: string }>; } => question !== undefined, ); return parsedQuestions.length > 0 ? parsedQuestions : undefined; } function toThreadState( value: unknown, ): "active" | "idle" | "archived" | "closed" | "compacted" | "error" { switch (value) { case "idle": return "idle"; case "archived": return "archived"; case "closed": return "closed"; case "compacted": return "compacted"; case "error": case "failed": return "error"; default: return "active"; } } function contentStreamKindFromMethod( method: string, ): | "assistant_text" | "reasoning_text" | "reasoning_summary_text" | "plan_text" | "command_output" | "file_change_output" { switch (method) { case "item/agentMessage/delta": return "assistant_text"; case "item/reasoning/textDelta": return "reasoning_text"; case "item/reasoning/summaryTextDelta": return "reasoning_summary_text"; case "item/commandExecution/outputDelta": return "command_output"; case "item/fileChange/outputDelta": return "file_change_output"; default: return "assistant_text"; } } const PROPOSED_PLAN_BLOCK_REGEX = /<proposed_plan>\s*([\s\S]*?)\s*<\/proposed_plan>/i; function extractProposedPlanMarkdown(text: string | undefined): string | undefined { const match = text ? PROPOSED_PLAN_BLOCK_REGEX.exec(text) : null; const planMarkdown = match?.[1]?.trim(); return planMarkdown && planMarkdown.length > 0 ? planMarkdown : undefined; } function asRuntimeItemId(itemId: ProviderItemId): RuntimeItemId { return RuntimeItemId.makeUnsafe(itemId); } function asRuntimeRequestId(requestId: string): RuntimeRequestId { return RuntimeRequestId.makeUnsafe(requestId); } function asRuntimeTaskId(taskId: string): RuntimeTaskId { return RuntimeTaskId.makeUnsafe(taskId); } function codexEventMessage(payload: Record<string, unknown> | undefined): Record<string, unknown> | undefined { return asObject(payload?.msg); } function codexEventBase( event: ProviderEvent, canonicalThreadId: ThreadId, ): Omit<ProviderRuntimeEvent, "type" | "payload"> { const payload = asObject(event.payload); const msg = codexEventMessage(payload); const turnId = asString(msg?.turn_id) ?? asString(msg?.turnId); const itemId = asString(msg?.item_id) ?? asString(msg?.itemId); const requestId = asString(msg?.request_id) ?? asString(msg?.requestId); const base = runtimeEventBase(event, canonicalThreadId); const providerRefs = base.providerRefs ? { ...base.providerRefs, ...(turnId ? { providerTurnId: turnId } : {}), ...(itemId ? { providerItemId: ProviderItemId.makeUnsafe(itemId) } : {}), ...(requestId ? { providerRequestId: requestId } : {}), } : { ...(turnId ? { providerTurnId: turnId } : {}), ...(itemId ? { providerItemId: ProviderItemId.makeUnsafe(itemId) } : {}), ...(requestId ? { providerRequestId: requestId } : {}), }; return { ...base, ...(turnId ? { turnId: TurnId.makeUnsafe(turnId) } : {}), ...(itemId ? { itemId: asRuntimeItemId(ProviderItemId.makeUnsafe(itemId)) } : {}), ...(requestId ? { requestId: asRuntimeRequestId(requestId) } : {}), ...(Object.keys(providerRefs).length > 0 ? { providerRefs } : {}), }; } function eventRawSource(event: ProviderEvent): NonNullable<ProviderRuntimeEvent["raw"]>["source"] { return event.kind === "request" ? "codex.app-server.request" : "codex.app-server.notification"; } function providerRefsFromEvent( event: ProviderEvent, ): ProviderRuntimeEvent["providerRefs"] | undefined { const refs: Record<string, string> = {}; if (event.turnId) refs.providerTurnId = event.turnId; if (event.itemId) refs.providerItemId = event.itemId; if (event.requestId) refs.providerRequestId = event.requestId; return Object.keys(refs).length > 0 ? (refs as ProviderRuntimeEvent["providerRefs"]) : undefined; } function runtimeEventBase( event: ProviderEvent, canonicalThreadId: ThreadId, ): Omit<ProviderRuntimeEvent, "type" | "payload"> { const refs = providerRefsFromEvent(event); return { eventId: event.id, provider: event.provider, threadId: canonicalThreadId, createdAt: event.createdAt, ...(event.turnId ? { turnId: event.turnId } : {}), ...(event.itemId ? { itemId: asRuntimeItemId(event.itemId) } : {}), ...(event.requestId ? { requestId: asRuntimeRequestId(event.requestId) } : {}), ...(refs ? { providerRefs: refs } : {}), raw: { source: eventRawSource(event), method: event.method, payload: event.payload ?? {}, }, }; } function mapItemLifecycle( event: ProviderEvent, canonicalThreadId: ThreadId, lifecycle: "item.started" | "item.updated" | "item.completed", ): ProviderRuntimeEvent | undefined { const payload = asObject(event.payload); const item = asObject(payload?.item); const source = item ?? payload; if (!source) { return undefined; } const itemType = toCanonicalItemType(source.type ?? source.kind); if (itemType === "unknown" && lifecycle !== "item.updated") { return undefined; } const detail = itemDetail(source, payload ?? {}); const status = lifecycle === "item.started" ? "inProgress" : lifecycle === "item.completed"