@nextclaw/nextclaw-ncp-runtime-codex-sdk 0.1.35 → 0.1.37

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.
Files changed (49) hide show
  1. package/dist/codex-cli-env.js +2 -0
  2. package/dist/codex-cli-env.js.map +1 -0
  3. package/dist/codex-input.utils.d.ts +2 -1
  4. package/dist/codex-input.utils.d.ts.map +1 -0
  5. package/dist/codex-input.utils.js +2 -0
  6. package/dist/codex-input.utils.js.map +1 -0
  7. package/dist/codex-model-provider.d.ts +2 -1
  8. package/dist/codex-model-provider.d.ts.map +1 -0
  9. package/dist/codex-model-provider.js +2 -0
  10. package/dist/codex-model-provider.js.map +1 -0
  11. package/dist/codex-openai-responses-bridge-assistant-output.utils.js +2 -0
  12. package/dist/codex-openai-responses-bridge-assistant-output.utils.js.map +1 -0
  13. package/dist/codex-openai-responses-bridge-message-content.utils.js +2 -0
  14. package/dist/codex-openai-responses-bridge-message-content.utils.js.map +1 -0
  15. package/dist/codex-openai-responses-bridge-shared.utils.d.ts +2 -1
  16. package/dist/codex-openai-responses-bridge-shared.utils.d.ts.map +1 -0
  17. package/dist/codex-openai-responses-bridge-shared.utils.js +2 -0
  18. package/dist/codex-openai-responses-bridge-shared.utils.js.map +1 -0
  19. package/dist/completed-assistant-message.utils.js +2 -0
  20. package/dist/completed-assistant-message.utils.js.map +1 -0
  21. package/dist/index.d.ts +2 -1
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +2 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/services/codex-live-output-event-merge.service.js +2 -0
  26. package/dist/services/codex-live-output-event-merge.service.js.map +1 -0
  27. package/dist/services/codex-live-output-stream.service.d.ts +2 -1
  28. package/dist/services/codex-live-output-stream.service.d.ts.map +1 -0
  29. package/dist/services/codex-live-output-stream.service.js +2 -0
  30. package/dist/services/codex-live-output-stream.service.js.map +1 -0
  31. package/dist/services/codex-ncp-run-event-emitter.service.js +2 -0
  32. package/dist/services/codex-ncp-run-event-emitter.service.js.map +1 -0
  33. package/dist/utils/codex-openai-responses-bridge-request.utils.js +2 -0
  34. package/dist/utils/codex-openai-responses-bridge-request.utils.js.map +1 -0
  35. package/dist/utils/codex-openai-responses-bridge-stream.utils.js +2 -0
  36. package/dist/utils/codex-openai-responses-bridge-stream.utils.js.map +1 -0
  37. package/dist/utils/codex-openai-responses-bridge.utils.d.ts +2 -1
  38. package/dist/utils/codex-openai-responses-bridge.utils.d.ts.map +1 -0
  39. package/dist/utils/codex-openai-responses-bridge.utils.js +2 -0
  40. package/dist/utils/codex-openai-responses-bridge.utils.js.map +1 -0
  41. package/dist/utils/codex-openai-responses-stream-writer.utils.d.ts +2 -1
  42. package/dist/utils/codex-openai-responses-stream-writer.utils.d.ts.map +1 -0
  43. package/dist/utils/codex-openai-responses-stream-writer.utils.js +2 -0
  44. package/dist/utils/codex-openai-responses-stream-writer.utils.js.map +1 -0
  45. package/dist/utils/codex-openai-sse-chunks.utils.js +2 -0
  46. package/dist/utils/codex-openai-sse-chunks.utils.js.map +1 -0
  47. package/dist/utils/codex-sdk-ncp-event-mapper.utils.js +2 -0
  48. package/dist/utils/codex-sdk-ncp-event-mapper.utils.js.map +1 -0
  49. package/package.json +3 -3
@@ -24,3 +24,5 @@ function buildCodexCliEnv(config) {
24
24
  }
25
25
  //#endregion
26
26
  export { buildCodexCliEnv };
27
+
28
+ //# sourceMappingURL=codex-cli-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-cli-env.js","names":[],"sources":["../src/codex-cli-env.ts"],"sourcesContent":["import type { CodexSdkNcpAgentRuntimeConfig } from \"./index.js\";\n\nfunction readString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n return value;\n}\n\nfunction copyProcessEnv(): Record<string, string> {\n const env: Record<string, string> = {};\n for (const [key, value] of Object.entries(process.env)) {\n const normalized = readString(value);\n if (normalized === undefined) {\n continue;\n }\n env[key] = normalized;\n }\n return env;\n}\n\nexport function buildCodexCliEnv(\n config: CodexSdkNcpAgentRuntimeConfig,\n): Record<string, string> | undefined {\n const env = copyProcessEnv();\n\n for (const [key, value] of Object.entries(config.env ?? {})) {\n if (typeof value !== \"string\") {\n continue;\n }\n env[key] = value;\n }\n\n if (config.apiKey.trim()) {\n env.OPENAI_API_KEY = config.apiKey;\n }\n if (config.apiBase?.trim()) {\n env.OPENAI_BASE_URL = config.apiBase.trim();\n }\n\n return Object.keys(env).length > 0 ? env : undefined;\n}\n"],"mappings":";AAEA,SAAS,WAAW,OAAoC;AACtD,KAAI,OAAO,UAAU,SACnB;AAEF,QAAO;;AAGT,SAAS,iBAAyC;CAChD,MAAM,MAA8B,EAAE;AACtC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,IAAI,EAAE;EACtD,MAAM,aAAa,WAAW,MAAM;AACpC,MAAI,eAAe,KAAA,EACjB;AAEF,MAAI,OAAO;;AAEb,QAAO;;AAGT,SAAgB,iBACd,QACoC;CACpC,MAAM,MAAM,gBAAgB;AAE5B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,OAAO,EAAE,CAAC,EAAE;AAC3D,MAAI,OAAO,UAAU,SACnB;AAEF,MAAI,OAAO;;AAGb,KAAI,OAAO,OAAO,MAAM,CACtB,KAAI,iBAAiB,OAAO;AAE9B,KAAI,OAAO,SAAS,MAAM,CACxB,KAAI,kBAAkB,OAAO,QAAQ,MAAM;AAG7C,QAAO,OAAO,KAAK,IAAI,CAAC,SAAS,IAAI,MAAM,KAAA"}
@@ -20,4 +20,5 @@ declare function buildCodexInputBuilder(runtimeAgent: RuntimeAgentPromptBuilder,
20
20
  resolveAssetContentPath?: CodexAssetContentPathResolver;
21
21
  }): (input: NcpAgentRunInput) => Promise<CodexThreadInput>;
22
22
  //#endregion
23
- export { CodexAssetContentPathResolver, CodexThreadInput, buildCodexInputBuilder };
23
+ export { CodexAssetContentPathResolver, CodexThreadInput, buildCodexInputBuilder };
24
+ //# sourceMappingURL=codex-input.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-input.utils.d.ts","names":[],"sources":["../src/codex-input.utils.ts"],"mappings":";;;;KAKY,gBAAA,GAAmB,UAAA,CAAW,MAAA;AAAA,KAG9B,6BAAA,IACV,QAAA,aACG,OAAA;AAAA,KAmKA,yBAAA;EACH,sBAAA,GAAyB,MAAA;IACvB,SAAA;IACA,aAAA;IACA,UAAA;IACA,QAAA,GAAW,MAAA;IACX,WAAA;EAAA;AAAA;AAAA,iBAWY,sBAAA,CACd,YAAA,EAAc,yBAAA,EACd,MAAA;EACE,SAAA;EACA,aAAA;EACA,eAAA,GAAkB,MAAA;EAClB,uBAAA,GAA0B,6BAAA;AAAA,KAGd,KAAA,EAAO,gBAAA,KAAmB,OAAA,CAAQ,gBAAA"}
@@ -122,3 +122,5 @@ async function buildCodexTurnInputFromRunInput(input, options = {}) {
122
122
  }
123
123
  //#endregion
124
124
  export { buildCodexInputBuilder, buildCodexTurnInputFromRunInput };
125
+
126
+ //# sourceMappingURL=codex-input.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-input.utils.js","names":[],"sources":["../src/codex-input.utils.ts"],"sourcesContent":["import { isAbsolute } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Thread } from \"@openai/codex-sdk\";\nimport type { NcpAgentRunInput, NcpMessagePart } from \"@nextclaw/ncp\";\n\nexport type CodexThreadInput = Parameters<Thread[\"runStreamed\"]>[0];\ntype CodexUserInput = Exclude<CodexThreadInput, string>[number];\n\nexport type CodexAssetContentPathResolver = (\n assetUri: string,\n) => Promise<string | null> | string | null;\n\nfunction readOptionalString(value: unknown): string | null {\n if (typeof value !== \"string\") {\n return null;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n}\n\nfunction isImageMimeType(value: string | null): boolean {\n return value?.startsWith(\"image/\") ?? false;\n}\n\nfunction readLatestUserMessageParts(input: NcpAgentRunInput): NcpMessagePart[] {\n for (let index = input.messages.length - 1; index >= 0; index -= 1) {\n const message = input.messages[index];\n if (message?.role !== \"user\") {\n continue;\n }\n if (message.parts.length > 0) {\n return message.parts;\n }\n }\n return [];\n}\n\nfunction formatAssetReferenceBlock(part: Extract<NcpMessagePart, { type: \"file\" }>): string {\n const fileName = readOptionalString(part.name) ?? \"asset\";\n const mimeType = readOptionalString(part.mimeType) ?? \"application/octet-stream\";\n const assetUri = readOptionalString(part.assetUri);\n const url = readOptionalString(part.url);\n const sizeText =\n typeof part.sizeBytes === \"number\" && Number.isFinite(part.sizeBytes)\n ? String(part.sizeBytes)\n : null;\n\n return [\n `[Asset: ${fileName}]`,\n `[MIME: ${mimeType}]`,\n ...(assetUri ? [`[Asset URI: ${assetUri}]`] : []),\n ...(sizeText ? [`[Size Bytes: ${sizeText}]`] : []),\n ...(url ? [`[Preview URL: ${url}]`] : []),\n \"[Instruction: This file is not embedded in the prompt. If you need to inspect or transform it, use asset_export to copy it to a normal file path first.]\",\n ].join(\"\\n\");\n}\n\nfunction formatImageAttachmentHint(part: Extract<NcpMessagePart, { type: \"file\" }>): string {\n const fileName = readOptionalString(part.name) ?? \"asset\";\n const mimeType = readOptionalString(part.mimeType) ?? \"application/octet-stream\";\n const assetUri = readOptionalString(part.assetUri);\n const sizeText =\n typeof part.sizeBytes === \"number\" && Number.isFinite(part.sizeBytes)\n ? String(part.sizeBytes)\n : null;\n\n return [\n `[Attached Image: ${fileName}]`,\n `[MIME: ${mimeType}]`,\n ...(assetUri ? [`[Asset URI: ${assetUri}]`] : []),\n ...(sizeText ? [`[Size Bytes: ${sizeText}]`] : []),\n assetUri\n ? \"[Instruction: This image is embedded in the prompt. If you need to transform or process the original file with tools, use the asset URI.]\"\n : \"[Instruction: This image is embedded in the prompt.]\",\n ].join(\"\\n\");\n}\n\nfunction resolveFileUrlToPath(value: string | null): string | null {\n if (!value) {\n return null;\n }\n\n if (value.startsWith(\"file://\")) {\n try {\n return fileURLToPath(value);\n } catch {\n return null;\n }\n }\n\n return isAbsolute(value) ? value : null;\n}\n\nasync function resolveLocalImagePath(\n part: Extract<NcpMessagePart, { type: \"file\" }>,\n resolveAssetContentPath: CodexAssetContentPathResolver | undefined,\n): Promise<string | null> {\n if (!isImageMimeType(readOptionalString(part.mimeType))) {\n return null;\n }\n\n const assetUri = readOptionalString(part.assetUri);\n if (assetUri && resolveAssetContentPath) {\n const resolvedPath = readOptionalString(await resolveAssetContentPath(assetUri));\n if (resolvedPath) {\n return resolvedPath;\n }\n }\n\n return resolveFileUrlToPath(readOptionalString(part.url));\n}\n\nasync function buildCodexPromptContent(\n parts: NcpMessagePart[],\n resolveAssetContentPath: CodexAssetContentPathResolver | undefined,\n): Promise<{\n promptText: string;\n userInputs: CodexUserInput[];\n}> {\n const promptBlocks: string[] = [];\n const userInputs: CodexUserInput[] = [];\n\n for (const part of parts) {\n if ((part.type === \"text\" || part.type === \"rich-text\") && part.text.trim().length > 0) {\n promptBlocks.push(part.text);\n continue;\n }\n\n if (part.type !== \"file\") {\n continue;\n }\n\n const localImagePath = await resolveLocalImagePath(part, resolveAssetContentPath);\n if (localImagePath) {\n promptBlocks.push(formatImageAttachmentHint(part));\n userInputs.push({\n type: \"local_image\",\n path: localImagePath,\n });\n continue;\n }\n\n promptBlocks.push(formatAssetReferenceBlock(part));\n }\n\n return {\n promptText: promptBlocks.join(\"\\n\\n\").trim(),\n userInputs,\n };\n}\n\nexport function buildCodexThreadInput(\n promptText: string,\n userInputs: CodexUserInput[],\n): CodexThreadInput {\n const normalizedPrompt = promptText.trim();\n if (userInputs.length === 0) {\n return normalizedPrompt;\n }\n\n return [\n ...(normalizedPrompt\n ? [\n {\n type: \"text\" as const,\n text: normalizedPrompt,\n },\n ]\n : []),\n ...userInputs,\n ];\n}\n\ntype RuntimeAgentPromptBuilder = {\n buildRuntimeUserPrompt: (params: {\n workspace?: string;\n hostWorkspace?: string;\n sessionKey?: string;\n metadata?: Record<string, unknown>;\n userMessage: string;\n }) => string;\n};\n\nfunction readMetadata(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n return value as Record<string, unknown>;\n}\n\nexport function buildCodexInputBuilder(\n runtimeAgent: RuntimeAgentPromptBuilder,\n params: {\n workspace: string;\n hostWorkspace?: string;\n sessionMetadata?: Record<string, unknown>;\n resolveAssetContentPath?: CodexAssetContentPathResolver;\n },\n) {\n return async (input: NcpAgentRunInput): Promise<CodexThreadInput> => {\n const { promptText, userInputs } = await buildCodexPromptContent(\n readLatestUserMessageParts(input),\n params.resolveAssetContentPath,\n );\n const metadata = {\n ...readMetadata(params.sessionMetadata),\n ...readMetadata(input.metadata),\n };\n const prompt = runtimeAgent.buildRuntimeUserPrompt({\n workspace: params.workspace,\n hostWorkspace: params.hostWorkspace,\n sessionKey: input.sessionId,\n metadata,\n userMessage: promptText,\n });\n return buildCodexThreadInput(prompt, userInputs);\n };\n}\n\nexport async function buildCodexTurnInputFromRunInput(\n input: NcpAgentRunInput,\n options: {\n resolveAssetContentPath?: CodexAssetContentPathResolver;\n } = {},\n): Promise<CodexThreadInput> {\n const { promptText, userInputs } = await buildCodexPromptContent(\n readLatestUserMessageParts(input),\n options.resolveAssetContentPath,\n );\n return buildCodexThreadInput(promptText, userInputs);\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  //#region src/codex-model-provider.d.ts
2
2
  declare function buildCodexBridgeModelProviderId(externalModelProvider: string): string;
3
3
  //#endregion
4
- export { buildCodexBridgeModelProviderId };
4
+ export { buildCodexBridgeModelProviderId };
5
+ //# sourceMappingURL=codex-model-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-model-provider.d.ts","names":[],"sources":["../src/codex-model-provider.ts"],"mappings":";iBAyDgB,+BAAA,CACd,qBAAA"}
@@ -6,3 +6,5 @@ function buildCodexBridgeModelProviderId(externalModelProvider) {
6
6
  }
7
7
  //#endregion
8
8
  export { buildCodexBridgeModelProviderId };
9
+
10
+ //# sourceMappingURL=codex-model-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-model-provider.js","names":[],"sources":["../src/codex-model-provider.ts"],"sourcesContent":["function readOptionalString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction isValidExternalModelProvider(value: string): boolean {\n return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(value);\n}\n\nexport function resolveExternalModelProvider(params: {\n explicitModelProvider?: unknown;\n providerName?: string | null;\n providerDisplayName?: string | null;\n runtimeEntryId: string;\n}): string {\n const {\n explicitModelProvider: rawExplicitModelProvider,\n providerName: rawProviderName,\n providerDisplayName: rawProviderDisplayName,\n runtimeEntryId,\n } = params;\n const explicitModelProvider = readOptionalString(rawExplicitModelProvider);\n if (explicitModelProvider) {\n return explicitModelProvider;\n }\n\n const providerName = readOptionalString(rawProviderName);\n if (providerName) {\n return providerName;\n }\n\n const providerDisplayName = readOptionalString(rawProviderDisplayName);\n if (providerDisplayName && isValidExternalModelProvider(providerDisplayName)) {\n return providerDisplayName;\n }\n\n throw new Error(\n `[codex] custom provider \"${providerName ?? \"unknown\"}\" requires an external model provider id. ` +\n `Set agents.runtimes.entries.${runtimeEntryId}.config.modelProvider or use a provider display name with only letters, numbers, \".\", \"_\" or \"-\".`,\n );\n}\n\nexport function buildUserFacingModelRoute(params: {\n externalModelProvider: string;\n providerLocalModel: string;\n resolvedModel: string;\n}): string {\n const providerLocalModel = params.providerLocalModel.trim();\n if (!providerLocalModel) {\n return params.resolvedModel.trim();\n }\n return `${params.externalModelProvider}/${providerLocalModel}`;\n}\n\nexport function buildCodexBridgeModelProviderId(\n externalModelProvider: string,\n): string {\n const normalized = externalModelProvider.trim();\n if (!normalized) {\n return \"nextclaw-codex-bridge\";\n }\n return `nextclaw-codex-bridge-${normalized}`;\n}\n"],"mappings":";AAyDA,SAAgB,gCACd,uBACQ;CACR,MAAM,aAAa,sBAAsB,MAAM;AAC/C,KAAI,CAAC,WACH,QAAO;AAET,QAAO,yBAAyB"}
@@ -104,3 +104,5 @@ function buildAssistantOutputItems(params) {
104
104
  }
105
105
  //#endregion
106
106
  export { buildAssistantOutputItems };
107
+
108
+ //# sourceMappingURL=codex-openai-responses-bridge-assistant-output.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-openai-responses-bridge-assistant-output.utils.js","names":[],"sources":["../src/codex-openai-responses-bridge-assistant-output.utils.ts"],"sourcesContent":["import type { ServerResponse } from \"node:http\";\nimport { normalizeAssistantText } from \"@nextclaw/ncp\";\nimport {\n nextSequenceNumber,\n readArray,\n readRecord,\n readRawString,\n readString,\n writeSseEvent,\n type OpenAiChatCompletionChoiceMessage,\n type OpenResponsesOutputItem,\n type StreamSequenceState,\n} from \"./codex-openai-responses-bridge-shared.utils.js\";\n\nfunction extractAssistantText(content: unknown): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (!Array.isArray(content)) {\n return \"\";\n }\n return content\n .map((entry) => {\n const record = readRecord(entry);\n if (!record) {\n return \"\";\n }\n const type = readString(record.type);\n if (type === \"text\" || type === \"output_text\") {\n return readString(record.text) ?? \"\";\n }\n return \"\";\n })\n .filter(Boolean)\n .join(\"\");\n}\n\ntype ReasoningExtraction = {\n present: boolean;\n text: string;\n};\n\nfunction readReasoningRecordText(value: unknown): string {\n const record = readRecord(value);\n if (!record) {\n return \"\";\n }\n return (\n readRawString(record.text) ??\n readRawString(record.content) ??\n readRawString(record.reasoning) ??\n readRawString(record.reasoning_content) ??\n readRawString(record.thinking) ??\n \"\"\n );\n}\n\nfunction extractReasoningDetailsText(value: unknown): ReasoningExtraction | undefined {\n const rawString = readRawString(value);\n if (rawString !== undefined) {\n return {\n present: true,\n text: rawString,\n };\n }\n\n const record = readRecord(value);\n if (record) {\n return {\n present: true,\n text: readReasoningRecordText(record),\n };\n }\n\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const text = readArray(value)\n .map((entry) => readReasoningRecordText(entry))\n .join(\"\");\n return {\n present: true,\n text,\n };\n}\n\nfunction extractContentReasoningText(content: unknown): string {\n if (!Array.isArray(content)) {\n return \"\";\n }\n return content\n .map((entry) => {\n const record = readRecord(entry);\n if (!record) {\n return \"\";\n }\n const type = readString(record.type);\n if (\n type === \"reasoning\" ||\n type === \"reasoning_text\" ||\n type === \"thinking\" ||\n type === \"thinking_text\"\n ) {\n return readReasoningRecordText(record);\n }\n return \"\";\n })\n .join(\"\");\n}\n\nfunction extractExplicitReasoning(\n message: OpenAiChatCompletionChoiceMessage | undefined,\n): ReasoningExtraction | undefined {\n const candidates = [\n message?.reasoning_content,\n message?.reasoning,\n message?.thinking,\n message?.reasoning_details,\n ];\n\n for (const candidate of candidates) {\n const extracted = extractReasoningDetailsText(candidate);\n if (extracted) {\n return extracted;\n }\n }\n\n const contentReasoning = extractContentReasoningText(message?.content);\n return contentReasoning\n ? {\n present: true,\n text: contentReasoning,\n }\n : undefined;\n}\n\nfunction extractAssistantOutput(message: OpenAiChatCompletionChoiceMessage | undefined): {\n text: string;\n reasoning: string;\n reasoningPresent: boolean;\n} {\n const rawText = extractAssistantText(message?.content);\n const normalized = normalizeAssistantText(rawText, \"think-tags\");\n const explicitReasoning = extractExplicitReasoning(message);\n const reasoning = explicitReasoning?.text ?? readString(normalized.reasoning) ?? \"\";\n const reasoningPresent = explicitReasoning?.present === true || Boolean(normalized.reasoning);\n const text =\n explicitReasoning?.present === true\n ? readString(normalized.text) ?? readString(rawText) ?? \"\"\n : normalized.reasoning\n ? readString(normalized.text) ?? \"\"\n : readString(rawText) ?? \"\";\n\n return {\n text,\n reasoning,\n reasoningPresent,\n };\n}\n\nfunction buildInProgressReasoningItem(item: OpenResponsesOutputItem): OpenResponsesOutputItem {\n return {\n ...structuredClone(item),\n status: \"in_progress\",\n content: [],\n summary: [],\n };\n}\n\nexport function buildAssistantOutputItems(params: {\n message: OpenAiChatCompletionChoiceMessage | undefined;\n responseId: string;\n}): OpenResponsesOutputItem[] {\n const { reasoning, reasoningPresent, text } = extractAssistantOutput(params.message);\n const outputItems: OpenResponsesOutputItem[] = [];\n\n if (reasoningPresent) {\n outputItems.push({\n type: \"reasoning\",\n id: `${params.responseId}:reasoning:0`,\n summary: [\n {\n type: \"summary_text\",\n text: reasoning,\n },\n ],\n content: [\n {\n type: \"reasoning_text\",\n text: reasoning,\n },\n ],\n status: \"completed\",\n });\n }\n\n if (text) {\n outputItems.push({\n type: \"message\",\n id: `${params.responseId}:message:${outputItems.length}`,\n role: \"assistant\",\n status: \"completed\",\n content: [\n {\n type: \"output_text\",\n text,\n annotations: [],\n },\n ],\n });\n }\n\n return outputItems;\n}\n\nexport function writeReasoningOutputItemEvents(params: {\n response: ServerResponse;\n item: OpenResponsesOutputItem;\n outputIndex: number;\n sequenceState: StreamSequenceState;\n}): void {\n const itemId = readString(params.item.id);\n const content = readArray(params.item.content);\n const textPart = content.find((entry) => readString(readRecord(entry)?.type) === \"reasoning_text\");\n const text = readString(readRecord(textPart)?.text) ?? \"\";\n const summary = readArray(params.item.summary);\n const summaryIndex = summary.findIndex((entry) => readString(readRecord(entry)?.type) === \"summary_text\");\n const summaryText =\n summaryIndex >= 0 ? readString(readRecord(summary[summaryIndex])?.text) ?? \"\" : \"\";\n\n writeSseEvent(params.response, \"response.output_item.added\", {\n type: \"response.output_item.added\",\n sequence_number: nextSequenceNumber(params.sequenceState),\n output_index: params.outputIndex,\n item: buildInProgressReasoningItem(params.item),\n });\n\n if (itemId && summaryText) {\n writeSseEvent(params.response, \"response.reasoning_summary_part.added\", {\n type: \"response.reasoning_summary_part.added\",\n sequence_number: nextSequenceNumber(params.sequenceState),\n output_index: params.outputIndex,\n item_id: itemId,\n summary_index: summaryIndex,\n part: {\n type: \"summary_text\",\n text: \"\",\n },\n });\n writeSseEvent(params.response, \"response.reasoning_summary_text.delta\", {\n type: \"response.reasoning_summary_text.delta\",\n sequence_number: nextSequenceNumber(params.sequenceState),\n output_index: params.outputIndex,\n item_id: itemId,\n summary_index: summaryIndex,\n delta: summaryText,\n });\n writeSseEvent(params.response, \"response.reasoning_summary_text.done\", {\n type: \"response.reasoning_summary_text.done\",\n sequence_number: nextSequenceNumber(params.sequenceState),\n output_index: params.outputIndex,\n item_id: itemId,\n summary_index: summaryIndex,\n text: summaryText,\n });\n writeSseEvent(params.response, \"response.reasoning_summary_part.done\", {\n type: \"response.reasoning_summary_part.done\",\n sequence_number: nextSequenceNumber(params.sequenceState),\n output_index: params.outputIndex,\n item_id: itemId,\n summary_index: summaryIndex,\n part: {\n type: \"summary_text\",\n text: summaryText,\n },\n });\n }\n\n if (itemId && text) {\n writeSseEvent(params.response, \"response.reasoning_text.delta\", {\n type: \"response.reasoning_text.delta\",\n sequence_number: nextSequenceNumber(params.sequenceState),\n output_index: params.outputIndex,\n item_id: itemId,\n content_index: 0,\n delta: text,\n });\n }\n\n if (itemId) {\n writeSseEvent(params.response, \"response.reasoning_text.done\", {\n type: \"response.reasoning_text.done\",\n sequence_number: nextSequenceNumber(params.sequenceState),\n output_index: params.outputIndex,\n item_id: itemId,\n content_index: 0,\n text,\n });\n }\n\n writeSseEvent(params.response, \"response.output_item.done\", {\n type: \"response.output_item.done\",\n sequence_number: nextSequenceNumber(params.sequenceState),\n output_index: params.outputIndex,\n item: params.item,\n });\n}\n"],"mappings":"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"}
@@ -77,3 +77,5 @@ function readAssistantMessageText(content) {
77
77
  }
78
78
  //#endregion
79
79
  export { buildChatContent, mergeChatContent, normalizeToolOutput, readAssistantMessageText };
80
+
81
+ //# sourceMappingURL=codex-openai-responses-bridge-message-content.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-openai-responses-bridge-message-content.utils.js","names":[],"sources":["../src/codex-openai-responses-bridge-message-content.utils.ts"],"sourcesContent":["import { readRecord, readString } from \"./codex-openai-responses-bridge-shared.utils.js\";\n\nexport type OpenAiChatContent = string | Array<Record<string, unknown>> | null;\n\nfunction normalizeTextPart(value: unknown): string {\n const record = readRecord(value);\n if (!record) {\n return \"\";\n }\n const type = readString(record.type);\n if (type !== \"input_text\" && type !== \"output_text\") {\n return \"\";\n }\n return readString(record.text) ?? \"\";\n}\n\nfunction normalizeImageUrl(value: unknown): string | null {\n const record = readRecord(value);\n if (!record || readString(record.type) !== \"input_image\") {\n return null;\n }\n const source = readRecord(record.source);\n if (!source) {\n return null;\n }\n if (readString(source.type) === \"url\") {\n return readString(source.url) ?? null;\n }\n if (readString(source.type) === \"base64\") {\n const mediaType = readString(source.media_type) ?? \"application/octet-stream\";\n const data = readString(source.data);\n if (!data) {\n return null;\n }\n return `data:${mediaType};base64,${data}`;\n }\n return null;\n}\n\nexport function normalizeToolOutput(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (Array.isArray(value)) {\n const text = value.map((entry) => normalizeTextPart(entry)).filter(Boolean).join(\"\");\n if (text) {\n return text;\n }\n }\n try {\n return JSON.stringify(value ?? \"\");\n } catch {\n return String(value ?? \"\");\n }\n}\n\nexport function buildChatContent(content: unknown): OpenAiChatContent {\n if (typeof content === \"string\") {\n return content;\n }\n if (!Array.isArray(content)) {\n return null;\n }\n\n const chatContent: Array<Record<string, unknown>> = [];\n for (const entry of content) {\n const text = normalizeTextPart(entry);\n if (text) {\n chatContent.push({\n type: \"text\",\n text,\n });\n continue;\n }\n\n const imageUrl = normalizeImageUrl(entry);\n if (imageUrl) {\n chatContent.push({\n type: \"image_url\",\n image_url: {\n url: imageUrl,\n },\n });\n }\n }\n\n if (chatContent.length === 0) {\n return null;\n }\n const textOnly = chatContent.every((entry) => entry.type === \"text\");\n if (textOnly) {\n return chatContent\n .map((entry) => readString(entry.text) ?? \"\")\n .join(\"\\n\");\n }\n return chatContent;\n}\n\nexport function mergeChatContent(\n left: OpenAiChatContent,\n right: OpenAiChatContent,\n): OpenAiChatContent {\n if (left === null) {\n return right;\n }\n if (right === null) {\n return left;\n }\n if (typeof left === \"string\" && typeof right === \"string\") {\n return [left, right].filter((value) => value.length > 0).join(\"\\n\\n\");\n }\n const normalizedLeft =\n typeof left === \"string\"\n ? [\n {\n type: \"text\",\n text: left,\n },\n ]\n : left;\n const normalizedRight =\n typeof right === \"string\"\n ? [\n {\n type: \"text\",\n text: right,\n },\n ]\n : right;\n return [...normalizedLeft, ...normalizedRight];\n}\n\nexport function readAssistantMessageText(content: OpenAiChatContent): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (!Array.isArray(content)) {\n return \"\";\n }\n return content\n .filter((entry) => entry.type === \"text\")\n .map((entry) => readString(entry.text) ?? \"\")\n .join(\"\\n\");\n}\n"],"mappings":";;AAIA,SAAS,kBAAkB,OAAwB;CACjD,MAAM,SAAS,WAAW,MAAM;AAChC,KAAI,CAAC,OACH,QAAO;CAET,MAAM,OAAO,WAAW,OAAO,KAAK;AACpC,KAAI,SAAS,gBAAgB,SAAS,cACpC,QAAO;AAET,QAAO,WAAW,OAAO,KAAK,IAAI;;AAGpC,SAAS,kBAAkB,OAA+B;CACxD,MAAM,SAAS,WAAW,MAAM;AAChC,KAAI,CAAC,UAAU,WAAW,OAAO,KAAK,KAAK,cACzC,QAAO;CAET,MAAM,SAAS,WAAW,OAAO,OAAO;AACxC,KAAI,CAAC,OACH,QAAO;AAET,KAAI,WAAW,OAAO,KAAK,KAAK,MAC9B,QAAO,WAAW,OAAO,IAAI,IAAI;AAEnC,KAAI,WAAW,OAAO,KAAK,KAAK,UAAU;EACxC,MAAM,YAAY,WAAW,OAAO,WAAW,IAAI;EACnD,MAAM,OAAO,WAAW,OAAO,KAAK;AACpC,MAAI,CAAC,KACH,QAAO;AAET,SAAO,QAAQ,UAAU,UAAU;;AAErC,QAAO;;AAGT,SAAgB,oBAAoB,OAAwB;AAC1D,KAAI,OAAO,UAAU,SACnB,QAAO;AAET,KAAI,MAAM,QAAQ,MAAM,EAAE;EACxB,MAAM,OAAO,MAAM,KAAK,UAAU,kBAAkB,MAAM,CAAC,CAAC,OAAO,QAAQ,CAAC,KAAK,GAAG;AACpF,MAAI,KACF,QAAO;;AAGX,KAAI;AACF,SAAO,KAAK,UAAU,SAAS,GAAG;SAC5B;AACN,SAAO,OAAO,SAAS,GAAG;;;AAI9B,SAAgB,iBAAiB,SAAqC;AACpE,KAAI,OAAO,YAAY,SACrB,QAAO;AAET,KAAI,CAAC,MAAM,QAAQ,QAAQ,CACzB,QAAO;CAGT,MAAM,cAA8C,EAAE;AACtD,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,OAAO,kBAAkB,MAAM;AACrC,MAAI,MAAM;AACR,eAAY,KAAK;IACf,MAAM;IACN;IACD,CAAC;AACF;;EAGF,MAAM,WAAW,kBAAkB,MAAM;AACzC,MAAI,SACF,aAAY,KAAK;GACf,MAAM;GACN,WAAW,EACT,KAAK,UACN;GACF,CAAC;;AAIN,KAAI,YAAY,WAAW,EACzB,QAAO;AAGT,KADiB,YAAY,OAAO,UAAU,MAAM,SAAS,OAAO,CAElE,QAAO,YACJ,KAAK,UAAU,WAAW,MAAM,KAAK,IAAI,GAAG,CAC5C,KAAK,KAAK;AAEf,QAAO;;AAGT,SAAgB,iBACd,MACA,OACmB;AACnB,KAAI,SAAS,KACX,QAAO;AAET,KAAI,UAAU,KACZ,QAAO;AAET,KAAI,OAAO,SAAS,YAAY,OAAO,UAAU,SAC/C,QAAO,CAAC,MAAM,MAAM,CAAC,QAAQ,UAAU,MAAM,SAAS,EAAE,CAAC,KAAK,OAAO;CAEvE,MAAM,iBACJ,OAAO,SAAS,WACZ,CACE;EACE,MAAM;EACN,MAAM;EACP,CACF,GACD;CACN,MAAM,kBACJ,OAAO,UAAU,WACb,CACE;EACE,MAAM;EACN,MAAM;EACP,CACF,GACD;AACN,QAAO,CAAC,GAAG,gBAAgB,GAAG,gBAAgB;;AAGhD,SAAgB,yBAAyB,SAAoC;AAC3E,KAAI,OAAO,YAAY,SACrB,QAAO;AAET,KAAI,CAAC,MAAM,QAAQ,QAAQ,CACzB,QAAO;AAET,QAAO,QACJ,QAAQ,UAAU,MAAM,SAAS,OAAO,CACxC,KAAK,UAAU,WAAW,MAAM,KAAK,IAAI,GAAG,CAC5C,KAAK,KAAK"}
@@ -11,4 +11,5 @@ type CodexOpenAiResponsesBridgeResult = {
11
11
  baseUrl: string;
12
12
  };
13
13
  //#endregion
14
- export { CodexOpenAiResponsesBridgeConfig, CodexOpenAiResponsesBridgeResult };
14
+ export { CodexOpenAiResponsesBridgeConfig, CodexOpenAiResponsesBridgeResult };
15
+ //# sourceMappingURL=codex-openai-responses-bridge-shared.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-openai-responses-bridge-shared.utils.d.ts","names":[],"sources":["../src/codex-openai-responses-bridge-shared.utils.ts"],"mappings":";KAAY,gCAAA;EACV,eAAA;EACA,cAAA;EACA,oBAAA,GAAuB,MAAA;EACvB,YAAA;EACA,aAAA;EACA,sBAAA;AAAA;AAAA,KAGU,gCAAA;EACV,OAAA;AAAA"}
@@ -34,3 +34,5 @@ function nextSequenceNumber(state) {
34
34
  }
35
35
  //#endregion
36
36
  export { nextSequenceNumber, readArray, readBoolean, readNumber, readRawString, readRecord, readString, withTrailingSlash, writeSseEvent };
37
+
38
+ //# sourceMappingURL=codex-openai-responses-bridge-shared.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-openai-responses-bridge-shared.utils.js","names":[],"sources":["../src/codex-openai-responses-bridge-shared.utils.ts"],"sourcesContent":["export type CodexOpenAiResponsesBridgeConfig = {\n upstreamApiBase: string;\n upstreamApiKey?: string;\n upstreamExtraHeaders?: Record<string, string>;\n defaultModel?: string;\n modelPrefixes?: string[];\n upstreamReasoningSplit?: boolean;\n};\n\nexport type CodexOpenAiResponsesBridgeResult = {\n baseUrl: string;\n};\n\nexport type BridgeEntry = {\n promise: Promise<CodexOpenAiResponsesBridgeResult>;\n};\n\nexport type OpenResponsesItemRecord = Record<string, unknown>;\n\nexport type OpenAiChatCompletionChoiceMessage = {\n content?: unknown;\n reasoning?: unknown;\n reasoning_content?: unknown;\n reasoning_details?: unknown;\n thinking?: unknown;\n tool_calls?: unknown;\n};\n\nexport type OpenAiChatCompletionResponse = {\n choices?: Array<{\n message?: OpenAiChatCompletionChoiceMessage;\n }>;\n usage?: Record<string, unknown> & {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n };\n error?: {\n message?: unknown;\n };\n};\n\nexport type OpenResponsesOutputItem = Record<string, unknown>;\n\nexport type StreamSequenceState = {\n value: number;\n};\n\nexport function readString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nexport function readRawString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nexport function readBoolean(value: unknown): boolean | undefined {\n return typeof value === \"boolean\" ? value : undefined;\n}\n\nexport function readNumber(value: unknown): number | undefined {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n return undefined;\n }\n return value;\n}\n\nexport function readRecord(value: unknown): Record<string, unknown> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n return value as Record<string, unknown>;\n}\n\nexport function readArray(value: unknown): unknown[] {\n return Array.isArray(value) ? value : [];\n}\n\nexport function withTrailingSlash(value: string): string {\n return value.endsWith(\"/\") ? value : `${value}/`;\n}\n\nexport function writeSseEvent(\n response: { write: (chunk: string) => void },\n eventType: string,\n payload: Record<string, unknown>,\n): void {\n response.write(`event: ${eventType}\\n`);\n response.write(`data: ${JSON.stringify(payload)}\\n\\n`);\n}\n\nexport function nextSequenceNumber(state: StreamSequenceState): number {\n const nextValue = state.value;\n state.value += 1;\n return nextValue;\n}\n"],"mappings":";AAgDA,SAAgB,WAAW,OAAoC;AAC7D,KAAI,OAAO,UAAU,SACnB;AAGF,QADgB,MAAM,MAAM,IACV,KAAA;;AAGpB,SAAgB,cAAc,OAAoC;AAChE,QAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;;AAG7C,SAAgB,YAAY,OAAqC;AAC/D,QAAO,OAAO,UAAU,YAAY,QAAQ,KAAA;;AAG9C,SAAgB,WAAW,OAAoC;AAC7D,KAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,MAAM,CACtD;AAEF,QAAO;;AAGT,SAAgB,WAAW,OAAqD;AAC9E,KAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,MAAM,CAC7D;AAEF,QAAO;;AAGT,SAAgB,UAAU,OAA2B;AACnD,QAAO,MAAM,QAAQ,MAAM,GAAG,QAAQ,EAAE;;AAG1C,SAAgB,kBAAkB,OAAuB;AACvD,QAAO,MAAM,SAAS,IAAI,GAAG,QAAQ,GAAG,MAAM;;AAGhD,SAAgB,cACd,UACA,WACA,SACM;AACN,UAAS,MAAM,UAAU,UAAU,IAAI;AACvC,UAAS,MAAM,SAAS,KAAK,UAAU,QAAQ,CAAC,MAAM;;AAGxD,SAAgB,mBAAmB,OAAoC;CACrE,MAAM,YAAY,MAAM;AACxB,OAAM,SAAS;AACf,QAAO"}
@@ -23,3 +23,5 @@ function buildCompletedAssistantMessage(params) {
23
23
  }
24
24
  //#endregion
25
25
  export { buildCompletedAssistantMessage };
26
+
27
+ //# sourceMappingURL=completed-assistant-message.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completed-assistant-message.utils.js","names":[],"sources":["../src/completed-assistant-message.utils.ts"],"sourcesContent":["import type {\n NcpAgentConversationStateManager,\n NcpMessage,\n} from \"@nextclaw/ncp\";\n\nexport function buildCompletedAssistantMessage(params: {\n stateManager?: NcpAgentConversationStateManager;\n sessionId: string;\n messageId: string;\n}): NcpMessage {\n const { stateManager, sessionId, messageId } = params;\n const snapshot = stateManager?.getSnapshot();\n const existingMessage = snapshot?.messages.find(\n (message) => message.id === messageId && message.role === \"assistant\",\n );\n if (existingMessage) {\n return {\n ...structuredClone(existingMessage),\n status: \"final\",\n };\n }\n\n const streamingMessage = snapshot?.streamingMessage;\n if (\n streamingMessage?.id === messageId &&\n streamingMessage.role === \"assistant\"\n ) {\n return {\n ...structuredClone(streamingMessage),\n status: \"final\",\n };\n }\n\n return {\n id: messageId,\n sessionId,\n role: \"assistant\",\n status: \"final\",\n parts: [],\n timestamp: new Date().toISOString(),\n };\n}\n"],"mappings":";AAKA,SAAgB,+BAA+B,QAIhC;CACb,MAAM,EAAE,cAAc,WAAW,cAAc;CAC/C,MAAM,WAAW,cAAc,aAAa;CAC5C,MAAM,kBAAkB,UAAU,SAAS,MACxC,YAAY,QAAQ,OAAO,aAAa,QAAQ,SAAS,YAC3D;AACD,KAAI,gBACF,QAAO;EACL,GAAG,gBAAgB,gBAAgB;EACnC,QAAQ;EACT;CAGH,MAAM,mBAAmB,UAAU;AACnC,KACE,kBAAkB,OAAO,aACzB,iBAAiB,SAAS,YAE1B,QAAO;EACL,GAAG,gBAAgB,iBAAiB;EACpC,QAAQ;EACT;AAGH,QAAO;EACL,IAAI;EACJ;EACA,MAAM;EACN,QAAQ;EACR,OAAO,EAAE;EACT,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC"}
package/dist/index.d.ts CHANGED
@@ -42,4 +42,5 @@ declare class CodexSdkNcpAgentRuntime implements NcpAgentRuntime {
42
42
  private updateThreadId;
43
43
  }
44
44
  //#endregion
45
- export { type CodexAssetContentPathResolver, type CodexLiveOutputChannel, type CodexLiveOutputEvent, CodexLiveOutputStream, type CodexOpenAiResponsesBridgeResult, type CodexOpenAiResponsesBridgeRuntimeConfig, CodexSdkNcpAgentRuntime, CodexSdkNcpAgentRuntimeConfig, buildCodexBridgeModelProviderId, buildCodexInputBuilder, ensureCodexOpenAiResponsesBridge };
45
+ export { type CodexAssetContentPathResolver, type CodexLiveOutputChannel, type CodexLiveOutputEvent, CodexLiveOutputStream, type CodexOpenAiResponsesBridgeResult, type CodexOpenAiResponsesBridgeRuntimeConfig, CodexSdkNcpAgentRuntime, CodexSdkNcpAgentRuntimeConfig, buildCodexBridgeModelProviderId, buildCodexInputBuilder, ensureCodexOpenAiResponsesBridge };
46
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;KA+CY,6BAAA;EACV,SAAA;EACA,MAAA;EACA,OAAA;EACA,KAAA;EACA,QAAA;EACA,iBAAA;EACA,GAAA,GAAM,MAAA;EACN,SAAA,GAAY,YAAA;EACZ,aAAA,GAAgB,aAAA;EAChB,eAAA,GAAkB,MAAA;EAClB,kBAAA,IAAsB,YAAA,EAAc,MAAA;EACpC,YAAA,IAAgB,KAAA,EAAO,gBAAA,KAAqB,OAAA,CAAQ,gBAAA,IAAoB,gBAAA;EACxE,gBAAA,GAAmB,qBAAA;EACnB,uBAAA,GAA0B,6BAAA;EAC1B,YAAA,GAAe,gCAAA;AAAA;AAAA,cAkCJ,uBAAA,YAAmC,eAAA;EAAA,iBAQjB,MAAA;EAAA,QAPrB,YAAA;EAAA,iBACS,YAAA;EAAA,iBACA,2BAAA;EAAA,QACT,MAAA;EAAA,QACA,QAAA;EAAA,iBACS,eAAA;cAEY,MAAA,EAAQ,6BAAA;EAQrC,GAAA,GACE,IAAA,EAAM,uBAAA,EACN,KAAA,EAAO,gBAAA,EACP,OAAA,GAAU,kBAAA,KACT,cAAA,CAAe,gBAAA;EAAA,QAmCV,QAAA;EAAA,QAgBA,aAAA;EAAA,QAcA,cAAA;EAAA,QASA,gBAAA;EAAA,QAiDA,iBAAA;EAAA,QAkFA,cAAA;AAAA"}
package/dist/index.js CHANGED
@@ -171,3 +171,5 @@ var CodexSdkNcpAgentRuntime = class {
171
171
  };
172
172
  //#endregion
173
173
  export { CodexLiveOutputStream, CodexSdkNcpAgentRuntime, buildCodexBridgeModelProviderId, buildCodexInputBuilder, ensureCodexOpenAiResponsesBridge };
174
+
175
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport type { Codex as CodexClient, CodexOptions, Thread, ThreadOptions } from \"@openai/codex-sdk\";\nimport {\n type NcpAgentConversationStateManager,\n type NcpAgentRunInput,\n type NcpAgentRunOptions,\n type NcpAgentRuntime,\n type NcpEndpointEvent,\n} from \"@nextclaw/ncp\";\nimport type {\n CodexLiveOutputChannel,\n CodexLiveOutputStream,\n} from \"./services/codex-live-output-stream.service.js\";\nimport { CodexLiveOutputEventMergeService } from \"./services/codex-live-output-event-merge.service.js\";\nimport { CodexNcpRunEventEmitter } from \"./services/codex-ncp-run-event-emitter.service.js\";\nimport {\n type ItemTextSnapshot,\n mapCodexItemEvent,\n type ToolSnapshot,\n} from \"./utils/codex-sdk-ncp-event-mapper.utils.js\";\nimport { buildCodexCliEnv } from \"./codex-cli-env.js\";\nimport {\n buildCodexTurnInputFromRunInput,\n type CodexAssetContentPathResolver,\n type CodexThreadInput,\n} from \"./codex-input.utils.js\";\nexport { buildCodexInputBuilder } from \"./codex-input.utils.js\";\nexport type { CodexAssetContentPathResolver } from \"./codex-input.utils.js\";\nexport { buildCodexBridgeModelProviderId } from \"./codex-model-provider.js\";\nexport { ensureCodexOpenAiResponsesBridge } from \"./utils/codex-openai-responses-bridge.utils.js\";\nexport type { CodexOpenAiResponsesBridgeRuntimeConfig } from \"./utils/codex-openai-responses-bridge.utils.js\";\nexport type { CodexOpenAiResponsesBridgeResult } from \"./codex-openai-responses-bridge-shared.utils.js\";\nexport { CodexLiveOutputStream } from \"./services/codex-live-output-stream.service.js\";\nexport type {\n CodexLiveOutputChannel,\n CodexLiveOutputEvent,\n} from \"./services/codex-live-output-stream.service.js\";\n\ntype CodexCtor = new (options: CodexOptions) => CodexClient;\n\ntype CodexLoader = {\n loadCodexConstructor: () => Promise<CodexCtor>;\n};\n\nconst require = createRequire(import.meta.url);\nconst codexLoader = require(\"../codex-sdk-loader.cjs\") as CodexLoader;\n\nexport type CodexSdkNcpAgentRuntimeConfig = {\n sessionId: string;\n apiKey: string;\n apiBase?: string;\n model?: string;\n threadId?: string | null;\n codexPathOverride?: string;\n env?: Record<string, string>;\n cliConfig?: CodexOptions[\"config\"];\n threadOptions?: ThreadOptions;\n sessionMetadata?: Record<string, unknown>;\n setSessionMetadata?: (nextMetadata: Record<string, unknown>) => void;\n inputBuilder?: (input: NcpAgentRunInput) => Promise<CodexThreadInput> | CodexThreadInput;\n liveOutputStream?: CodexLiveOutputStream;\n resolveAssetContentPath?: CodexAssetContentPathResolver;\n stateManager?: NcpAgentConversationStateManager;\n};\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction toAbortError(reason: unknown): Error {\n if (reason instanceof Error) {\n return reason;\n }\n const message = typeof reason === \"string\" && reason.trim() ? reason.trim() : \"operation aborted\";\n const error = new Error(message);\n error.name = \"AbortError\";\n return error;\n}\n\nfunction normalizeThreadOptions(\n options: ThreadOptions | undefined,\n model: string | undefined,\n): ThreadOptions {\n return {\n ...options,\n skipGitRepoCheck: options?.skipGitRepoCheck ?? true,\n ...(model ? { model } : {}),\n };\n}\n\nfunction isItemLifecycleEvent(\n event: Parameters<typeof mapCodexItemEvent>[0][\"event\"] | { type: string },\n): event is Parameters<typeof mapCodexItemEvent>[0][\"event\"] {\n return event.type === \"item.started\" || event.type === \"item.updated\" || event.type === \"item.completed\";\n}\n\nexport class CodexSdkNcpAgentRuntime implements NcpAgentRuntime {\n private codexPromise: Promise<CodexClient> | null = null;\n private readonly eventEmitter: CodexNcpRunEventEmitter;\n private readonly liveOutputEventMergeService = new CodexLiveOutputEventMergeService();\n private thread: Thread | null = null;\n private threadId: string | null;\n private readonly sessionMetadata: Record<string, unknown>;\n\n constructor(private readonly config: CodexSdkNcpAgentRuntimeConfig) {\n this.eventEmitter = new CodexNcpRunEventEmitter(config.stateManager);\n this.threadId = config.threadId?.trim() || null;\n this.sessionMetadata = {\n ...(config.sessionMetadata ? structuredClone(config.sessionMetadata) : {}),\n };\n }\n\n run = async function* (\n this: CodexSdkNcpAgentRuntime,\n input: NcpAgentRunInput,\n options?: NcpAgentRunOptions,\n ): AsyncGenerator<NcpEndpointEvent> {\n const signal = options?.signal;\n const messageId = createId(\"codex-message\");\n const runId = (input as NcpAgentRunInput & { runId?: string }).runId ?? createId(\"codex-run\");\n const itemTextById = new Map<string, ItemTextSnapshot>();\n const toolStateById = new Map<string, ToolSnapshot>();\n\n yield* this.eventEmitter.emitRunStarted(input.sessionId, messageId, runId);\n yield* this.eventEmitter.emitReadyMetadata(input.sessionId, messageId, runId);\n\n const thread = await this.resolveThread();\n const turnInput = await this.buildTurnInput(input);\n this.config.liveOutputStream?.reset();\n const streamed = await thread.runStreamed(turnInput, {\n ...(signal ? { signal } : {}),\n });\n\n try {\n yield* this.streamTurnEvents({\n sessionId: input.sessionId,\n messageId,\n runId,\n streamed,\n signal,\n itemTextById,\n toolStateById,\n });\n } catch (error) {\n if (signal?.aborted) {\n throw toAbortError(signal.reason);\n }\n throw error;\n }\n };\n\n private getCodex = async (): Promise<CodexClient> => {\n if (!this.codexPromise) {\n const env = buildCodexCliEnv(this.config);\n this.codexPromise = codexLoader.loadCodexConstructor().then((Ctor) =>\n new Ctor({\n apiKey: this.config.apiKey,\n baseUrl: this.config.apiBase,\n ...(this.config.codexPathOverride ? { codexPathOverride: this.config.codexPathOverride } : {}),\n ...(env ? { env } : {}),\n ...(this.config.cliConfig ? { config: this.config.cliConfig } : {}),\n }),\n );\n }\n return this.codexPromise;\n };\n\n private resolveThread = async (): Promise<Thread> => {\n if (this.thread) {\n return this.thread;\n }\n\n const codex = await this.getCodex();\n const threadOptions = normalizeThreadOptions(this.config.threadOptions, this.config.model);\n\n this.thread = this.threadId\n ? codex.resumeThread(this.threadId, threadOptions)\n : codex.startThread(threadOptions);\n return this.thread;\n };\n\n private buildTurnInput = async (input: NcpAgentRunInput): Promise<CodexThreadInput> => {\n if (this.config.inputBuilder) {\n return await this.config.inputBuilder(input);\n }\n return await buildCodexTurnInputFromRunInput(input, {\n resolveAssetContentPath: this.config.resolveAssetContentPath,\n });\n };\n\n private streamTurnEvents = async function* (\n this: CodexSdkNcpAgentRuntime,\n params: {\n sessionId: string;\n messageId: string;\n runId: string;\n streamed: Awaited<ReturnType<Thread[\"runStreamed\"]>>;\n signal?: AbortSignal;\n itemTextById: Map<string, ItemTextSnapshot>;\n toolStateById: Map<string, ToolSnapshot>;\n },\n ): AsyncGenerator<NcpEndpointEvent> {\n const { itemTextById, messageId, runId, sessionId, signal, streamed, toolStateById } =\n params;\n const liveOutputStream = this.config.liveOutputStream;\n if (liveOutputStream) {\n yield* this.liveOutputEventMergeService.stream({\n ...params,\n liveOutputStream,\n emitEvent: (event) => this.eventEmitter.emitEvent(event),\n emitRunCompleted: (sessionId, messageId, runId) =>\n this.eventEmitter.emitRunCompleted(sessionId, messageId, runId),\n handleThreadEvent: (handlerParams) => this.handleThreadEvent(handlerParams),\n });\n return;\n }\n\n let finished = false;\n for await (const event of streamed.events) {\n const shouldFinish = yield* this.handleThreadEvent({\n sessionId,\n messageId,\n runId,\n event,\n signal,\n itemTextById,\n toolStateById,\n });\n if (shouldFinish) {\n finished = true;\n return;\n }\n }\n\n if (!finished) {\n yield* this.eventEmitter.emitRunCompleted(sessionId, messageId, runId);\n }\n };\n\n private handleThreadEvent = async function* (\n this: CodexSdkNcpAgentRuntime,\n params: {\n sessionId: string;\n messageId: string;\n runId: string;\n event: Awaited<ReturnType<Thread[\"runStreamed\"]>>[\"events\"] extends AsyncGenerator<infer T> ? T : never;\n signal?: AbortSignal;\n itemTextById: Map<string, ItemTextSnapshot>;\n suppressLiveChannels?: Set<CodexLiveOutputChannel>;\n toolStateById: Map<string, ToolSnapshot>;\n },\n ): AsyncGenerator<NcpEndpointEvent, boolean> {\n const {\n event,\n itemTextById,\n messageId,\n runId,\n sessionId,\n signal,\n suppressLiveChannels,\n toolStateById,\n } = params;\n if (signal?.aborted) {\n throw toAbortError(signal.reason);\n }\n\n if (event.type === \"thread.started\") {\n this.updateThreadId(event.thread_id);\n return false;\n }\n\n if (event.type === \"turn.failed\") {\n yield* this.eventEmitter.emitRunError(\n sessionId,\n messageId,\n runId,\n event.error.message,\n );\n return true;\n }\n\n if (event.type === \"error\") {\n yield* this.eventEmitter.emitRunError(\n sessionId,\n messageId,\n runId,\n event.message,\n );\n return true;\n }\n\n if (isItemLifecycleEvent(event)) {\n const suppressedChannel =\n event.item.type === \"agent_message\"\n ? \"text\"\n : event.item.type === \"reasoning\"\n ? \"reasoning\"\n : null;\n if (suppressedChannel && suppressLiveChannels?.has(suppressedChannel)) {\n return false;\n }\n for await (const mappedEvent of mapCodexItemEvent({\n sessionId,\n messageId,\n event,\n itemTextById,\n toolStateById,\n })) {\n yield* this.eventEmitter.emitEvent(mappedEvent);\n }\n return false;\n }\n\n if (event.type === \"turn.completed\") {\n yield* this.eventEmitter.emitRunCompleted(sessionId, messageId, runId);\n return true;\n }\n\n return false;\n };\n\n private updateThreadId = (nextThreadId: string): void => {\n const normalizedThreadId = nextThreadId.trim();\n if (!normalizedThreadId || normalizedThreadId === this.threadId) {\n return;\n }\n this.threadId = normalizedThreadId;\n const nextMetadata = {\n ...this.sessionMetadata,\n session_type: \"codex\",\n codex_thread_id: normalizedThreadId,\n };\n this.sessionMetadata.codex_thread_id = normalizedThreadId;\n this.sessionMetadata.session_type = \"codex\";\n this.config.setSessionMetadata?.(nextMetadata);\n };\n}\n"],"mappings":"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"}
@@ -99,3 +99,5 @@ var CodexLiveOutputEventMergeService = class {
99
99
  };
100
100
  //#endregion
101
101
  export { CodexLiveOutputEventMergeService };
102
+
103
+ //# sourceMappingURL=codex-live-output-event-merge.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-live-output-event-merge.service.js","names":[],"sources":["../../src/services/codex-live-output-event-merge.service.ts"],"sourcesContent":["import type { Thread } from \"@openai/codex-sdk\";\nimport { type NcpEndpointEvent, NcpEventType } from \"@nextclaw/ncp\";\nimport type {\n ItemTextSnapshot,\n ToolSnapshot,\n} from \"@/utils/codex-sdk-ncp-event-mapper.utils.js\";\nimport type {\n CodexLiveOutputChannel,\n CodexLiveOutputStream,\n} from \"./codex-live-output-stream.service.js\";\n\ntype StreamedTurn = Awaited<ReturnType<Thread[\"runStreamed\"]>>;\ntype ThreadEvent = StreamedTurn[\"events\"] extends AsyncGenerator<infer T> ? T : never;\n\nexport type CodexThreadEventHandlerParams = {\n sessionId: string;\n messageId: string;\n runId: string;\n event: ThreadEvent;\n signal?: AbortSignal;\n itemTextById: Map<string, ItemTextSnapshot>;\n suppressLiveChannels?: Set<CodexLiveOutputChannel>;\n toolStateById: Map<string, ToolSnapshot>;\n};\n\nexport type CodexLiveOutputEventMergeParams = {\n sessionId: string;\n messageId: string;\n runId: string;\n streamed: StreamedTurn;\n signal?: AbortSignal;\n itemTextById: Map<string, ItemTextSnapshot>;\n liveOutputStream: CodexLiveOutputStream;\n toolStateById: Map<string, ToolSnapshot>;\n emitEvent: (event: NcpEndpointEvent) => AsyncGenerator<NcpEndpointEvent>;\n emitRunCompleted: (\n sessionId: string,\n messageId: string,\n runId: string,\n ) => AsyncGenerator<NcpEndpointEvent>;\n handleThreadEvent: (\n params: CodexThreadEventHandlerParams,\n ) => AsyncGenerator<NcpEndpointEvent, boolean>;\n};\n\nexport class CodexLiveOutputEventMergeService {\n stream = async function* (\n this: CodexLiveOutputEventMergeService,\n params: CodexLiveOutputEventMergeParams,\n ): AsyncGenerator<NcpEndpointEvent> {\n const {\n emitEvent,\n emitRunCompleted,\n handleThreadEvent,\n itemTextById,\n liveOutputStream,\n messageId,\n runId,\n sessionId,\n signal,\n streamed,\n toolStateById,\n } = params;\n const liveChannels = new Set<CodexLiveOutputChannel>();\n const codexIterator = streamed.events[Symbol.asyncIterator]();\n const liveIterator = this.streamLiveOutputEvents({\n emitEvent,\n liveChannels,\n liveOutputStream,\n messageId,\n sessionId,\n signal,\n })[Symbol.asyncIterator]();\n let finished = false;\n let codexDone = false;\n let liveDone = false;\n let codexNext = codexIterator.next();\n let liveNext = liveIterator.next();\n\n while (!codexDone || !liveDone) {\n const pending = [\n ...(!codexDone\n ? [codexNext.then((next) => ({ source: \"codex\" as const, next }))]\n : []),\n ...(!liveDone\n ? [liveNext.then((next) => ({ source: \"live\" as const, next }))]\n : []),\n ];\n const result = await Promise.race(pending);\n\n if (result.source === \"live\") {\n if (result.next.done) {\n liveDone = true;\n } else {\n yield result.next.value;\n liveNext = liveIterator.next();\n }\n continue;\n }\n\n if (result.next.done) {\n codexDone = true;\n continue;\n }\n\n const shouldFinish = yield* handleThreadEvent({\n event: result.next.value,\n itemTextById,\n messageId,\n runId,\n sessionId,\n signal,\n suppressLiveChannels: liveChannels,\n toolStateById,\n });\n if (shouldFinish) {\n finished = true;\n break;\n }\n codexNext = codexIterator.next();\n }\n\n await liveIterator.return?.(undefined);\n if (!finished) {\n yield* emitRunCompleted(sessionId, messageId, runId);\n }\n };\n\n private streamLiveOutputEvents = async function* (\n this: CodexLiveOutputEventMergeService,\n params: {\n sessionId: string;\n messageId: string;\n signal?: AbortSignal;\n liveChannels: Set<CodexLiveOutputChannel>;\n liveOutputStream: CodexLiveOutputStream;\n emitEvent: (event: NcpEndpointEvent) => AsyncGenerator<NcpEndpointEvent>;\n },\n ): AsyncGenerator<NcpEndpointEvent> {\n const {\n emitEvent,\n liveChannels,\n liveOutputStream,\n messageId,\n sessionId,\n signal,\n } = params;\n const startedChannels = new Set<CodexLiveOutputChannel>();\n for await (const event of liveOutputStream.events(signal)) {\n if (event.type === \"delta\") {\n liveChannels.add(event.channel);\n if (!startedChannels.has(event.channel)) {\n startedChannels.add(event.channel);\n yield* emitEvent({\n type: event.channel === \"reasoning\"\n ? NcpEventType.MessageReasoningStart\n : NcpEventType.MessageTextStart,\n payload: { sessionId, messageId },\n });\n }\n yield* emitEvent({\n type: event.channel === \"reasoning\"\n ? NcpEventType.MessageReasoningDelta\n : NcpEventType.MessageTextDelta,\n payload: { sessionId, messageId, delta: event.delta },\n });\n continue;\n }\n\n if (event.type === \"end\") {\n if (startedChannels.has(event.channel)) {\n yield* emitEvent({\n type: event.channel === \"reasoning\"\n ? NcpEventType.MessageReasoningEnd\n : NcpEventType.MessageTextEnd,\n payload: { sessionId, messageId },\n });\n }\n continue;\n }\n\n return;\n }\n };\n}\n"],"mappings":";;AA6CA,IAAa,mCAAb,MAA8C;CAC5C,SAAS,iBAEP,QACkC;EAClC,MAAM,EACJ,WACA,kBACA,mBACA,cACA,kBACA,WACA,OACA,WACA,QACA,UACA,kBACE;EACJ,MAAM,+BAAe,IAAI,KAA6B;EACtD,MAAM,gBAAgB,SAAS,OAAO,OAAO,gBAAgB;EAC7D,MAAM,eAAe,KAAK,uBAAuB;GAC/C;GACA;GACA;GACA;GACA;GACA;GACD,CAAC,CAAC,OAAO,gBAAgB;EAC1B,IAAI,WAAW;EACf,IAAI,YAAY;EAChB,IAAI,WAAW;EACf,IAAI,YAAY,cAAc,MAAM;EACpC,IAAI,WAAW,aAAa,MAAM;AAElC,SAAO,CAAC,aAAa,CAAC,UAAU;GAC9B,MAAM,UAAU,CACd,GAAI,CAAC,YACD,CAAC,UAAU,MAAM,UAAU;IAAE,QAAQ;IAAkB;IAAM,EAAE,CAAC,GAChE,EAAE,EACN,GAAI,CAAC,WACD,CAAC,SAAS,MAAM,UAAU;IAAE,QAAQ;IAAiB;IAAM,EAAE,CAAC,GAC9D,EAAE,CACP;GACD,MAAM,SAAS,MAAM,QAAQ,KAAK,QAAQ;AAE1C,OAAI,OAAO,WAAW,QAAQ;AAC5B,QAAI,OAAO,KAAK,KACd,YAAW;SACN;AACL,WAAM,OAAO,KAAK;AAClB,gBAAW,aAAa,MAAM;;AAEhC;;AAGF,OAAI,OAAO,KAAK,MAAM;AACpB,gBAAY;AACZ;;AAaF,OAVqB,OAAO,kBAAkB;IAC5C,OAAO,OAAO,KAAK;IACnB;IACA;IACA;IACA;IACA;IACA,sBAAsB;IACtB;IACD,CAAC,EACgB;AAChB,eAAW;AACX;;AAEF,eAAY,cAAc,MAAM;;AAGlC,QAAM,aAAa,SAAS,KAAA,EAAU;AACtC,MAAI,CAAC,SACH,QAAO,iBAAiB,WAAW,WAAW,MAAM;;CAIxD,yBAAiC,iBAE/B,QAQkC;EAClC,MAAM,EACJ,WACA,cACA,kBACA,WACA,WACA,WACE;EACJ,MAAM,kCAAkB,IAAI,KAA6B;AACzD,aAAW,MAAM,SAAS,iBAAiB,OAAO,OAAO,EAAE;AACzD,OAAI,MAAM,SAAS,SAAS;AAC1B,iBAAa,IAAI,MAAM,QAAQ;AAC/B,QAAI,CAAC,gBAAgB,IAAI,MAAM,QAAQ,EAAE;AACvC,qBAAgB,IAAI,MAAM,QAAQ;AAClC,YAAO,UAAU;MACf,MAAM,MAAM,YAAY,cACpB,aAAa,wBACb,aAAa;MACjB,SAAS;OAAE;OAAW;OAAW;MAClC,CAAC;;AAEJ,WAAO,UAAU;KACf,MAAM,MAAM,YAAY,cACpB,aAAa,wBACb,aAAa;KACjB,SAAS;MAAE;MAAW;MAAW,OAAO,MAAM;MAAO;KACtD,CAAC;AACF;;AAGF,OAAI,MAAM,SAAS,OAAO;AACxB,QAAI,gBAAgB,IAAI,MAAM,QAAQ,CACpC,QAAO,UAAU;KACf,MAAM,MAAM,YAAY,cACpB,aAAa,sBACb,aAAa;KACjB,SAAS;MAAE;MAAW;MAAW;KAClC,CAAC;AAEJ;;AAGF"}
@@ -28,4 +28,5 @@ declare class CodexLiveOutputStream {
28
28
  private push;
29
29
  }
30
30
  //#endregion
31
- export { CodexLiveOutputChannel, CodexLiveOutputEvent, CodexLiveOutputStream };
31
+ export { CodexLiveOutputChannel, CodexLiveOutputEvent, CodexLiveOutputStream };
32
+ //# sourceMappingURL=codex-live-output-stream.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-live-output-stream.service.d.ts","names":[],"sources":["../../src/services/codex-live-output-stream.service.ts"],"mappings":";KAAY,sBAAA;AAAA,KAEA,oBAAA;EACN,IAAA;EAAe,OAAA,EAAS,sBAAA;EAAwB,KAAA;AAAA;EAChD,IAAA;EAAa,OAAA,EAAS,sBAAA;AAAA;EACtB,IAAA;AAAA;AAAA,cAEO,qBAAA;EAAA,QACH,WAAA;EAAA,QACA,OAAA;EAAA,QACA,IAAA;EAAA,QACA,cAAA;EAAA,QACA,SAAA;EAER,KAAA;EAOA,gBAAA,GAAoB,KAAA;EAIpB,eAAA;EAIA,WAAA,GAAe,KAAA;EAIf,UAAA;EAIA,MAAA;EAQA,MAAA,GACE,IAAA,EAAM,qBAAA,EACN,MAAA,GAAS,WAAA,KACR,cAAA,CAAe,oBAAA;EAAA,QAyBV,SAAA;EAAA,QAOA,OAAA;EAAA,QAkBA,IAAA;AAAA"}
@@ -79,3 +79,5 @@ var CodexLiveOutputStream = class {
79
79
  };
80
80
  //#endregion
81
81
  export { CodexLiveOutputStream };
82
+
83
+ //# sourceMappingURL=codex-live-output-stream.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-live-output-stream.service.js","names":[],"sources":["../../src/services/codex-live-output-stream.service.ts"],"sourcesContent":["export type CodexLiveOutputChannel = \"reasoning\" | \"text\";\n\nexport type CodexLiveOutputEvent =\n | { type: \"delta\"; channel: CodexLiveOutputChannel; delta: string }\n | { type: \"end\"; channel: CodexLiveOutputChannel }\n | { type: \"done\" };\n\nexport class CodexLiveOutputStream {\n private eventsQueue: CodexLiveOutputEvent[] = [];\n private waiters: Array<() => void> = [];\n private done = false;\n private reasoningEnded = false;\n private textEnded = false;\n\n reset = (): void => {\n this.eventsQueue = [];\n this.done = false;\n this.reasoningEnded = false;\n this.textEnded = false;\n };\n\n onReasoningDelta = (delta: string): void => {\n this.pushDelta(\"reasoning\", delta);\n };\n\n onReasoningDone = (): void => {\n this.pushEnd(\"reasoning\");\n };\n\n onTextDelta = (delta: string): void => {\n this.pushDelta(\"text\", delta);\n };\n\n onTextDone = (): void => {\n this.pushEnd(\"text\");\n };\n\n onDone = (): void => {\n if (this.done) {\n return;\n }\n this.done = true;\n this.push({ type: \"done\" });\n };\n\n events = async function* (\n this: CodexLiveOutputStream,\n signal?: AbortSignal,\n ): AsyncGenerator<CodexLiveOutputEvent> {\n while (!signal?.aborted) {\n const event = this.eventsQueue.shift();\n if (event) {\n yield event;\n if (event.type === \"done\") {\n return;\n }\n continue;\n }\n\n await new Promise<void>((resolve) => {\n const abort = () => {\n signal?.removeEventListener(\"abort\", abort);\n resolve();\n };\n this.waiters.push(() => {\n signal?.removeEventListener(\"abort\", abort);\n resolve();\n });\n signal?.addEventListener(\"abort\", abort, { once: true });\n });\n }\n };\n\n private pushDelta = (channel: CodexLiveOutputChannel, delta: string): void => {\n if (!delta || this.done) {\n return;\n }\n this.push({ type: \"delta\", channel, delta });\n };\n\n private pushEnd = (channel: CodexLiveOutputChannel): void => {\n if (this.done) {\n return;\n }\n if (channel === \"reasoning\") {\n if (this.reasoningEnded) {\n return;\n }\n this.reasoningEnded = true;\n } else {\n if (this.textEnded) {\n return;\n }\n this.textEnded = true;\n }\n this.push({ type: \"end\", channel });\n };\n\n private push = (event: CodexLiveOutputEvent): void => {\n this.eventsQueue.push(event);\n const waiters = this.waiters.splice(0);\n for (const waiter of waiters) {\n waiter();\n }\n };\n}\n"],"mappings":";AAOA,IAAa,wBAAb,MAAmC;CACjC,cAA8C,EAAE;CAChD,UAAqC,EAAE;CACvC,OAAe;CACf,iBAAyB;CACzB,YAAoB;CAEpB,cAAoB;AAClB,OAAK,cAAc,EAAE;AACrB,OAAK,OAAO;AACZ,OAAK,iBAAiB;AACtB,OAAK,YAAY;;CAGnB,oBAAoB,UAAwB;AAC1C,OAAK,UAAU,aAAa,MAAM;;CAGpC,wBAA8B;AAC5B,OAAK,QAAQ,YAAY;;CAG3B,eAAe,UAAwB;AACrC,OAAK,UAAU,QAAQ,MAAM;;CAG/B,mBAAyB;AACvB,OAAK,QAAQ,OAAO;;CAGtB,eAAqB;AACnB,MAAI,KAAK,KACP;AAEF,OAAK,OAAO;AACZ,OAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;;CAG7B,SAAS,iBAEP,QACsC;AACtC,SAAO,CAAC,QAAQ,SAAS;GACvB,MAAM,QAAQ,KAAK,YAAY,OAAO;AACtC,OAAI,OAAO;AACT,UAAM;AACN,QAAI,MAAM,SAAS,OACjB;AAEF;;AAGF,SAAM,IAAI,SAAe,YAAY;IACnC,MAAM,cAAc;AAClB,aAAQ,oBAAoB,SAAS,MAAM;AAC3C,cAAS;;AAEX,SAAK,QAAQ,WAAW;AACtB,aAAQ,oBAAoB,SAAS,MAAM;AAC3C,cAAS;MACT;AACF,YAAQ,iBAAiB,SAAS,OAAO,EAAE,MAAM,MAAM,CAAC;KACxD;;;CAIN,aAAqB,SAAiC,UAAwB;AAC5E,MAAI,CAAC,SAAS,KAAK,KACjB;AAEF,OAAK,KAAK;GAAE,MAAM;GAAS;GAAS;GAAO,CAAC;;CAG9C,WAAmB,YAA0C;AAC3D,MAAI,KAAK,KACP;AAEF,MAAI,YAAY,aAAa;AAC3B,OAAI,KAAK,eACP;AAEF,QAAK,iBAAiB;SACjB;AACL,OAAI,KAAK,UACP;AAEF,QAAK,YAAY;;AAEnB,OAAK,KAAK;GAAE,MAAM;GAAO;GAAS,CAAC;;CAGrC,QAAgB,UAAsC;AACpD,OAAK,YAAY,KAAK,MAAM;EAC5B,MAAM,UAAU,KAAK,QAAQ,OAAO,EAAE;AACtC,OAAK,MAAM,UAAU,QACnB,SAAQ"}
@@ -82,3 +82,5 @@ var CodexNcpRunEventEmitter = class {
82
82
  };
83
83
  //#endregion
84
84
  export { CodexNcpRunEventEmitter };
85
+
86
+ //# sourceMappingURL=codex-ncp-run-event-emitter.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-ncp-run-event-emitter.service.js","names":[],"sources":["../../src/services/codex-ncp-run-event-emitter.service.ts"],"sourcesContent":["import {\n type NcpAgentConversationStateManager,\n type NcpEndpointEvent,\n NcpEventType,\n} from \"@nextclaw/ncp\";\nimport { buildCompletedAssistantMessage } from \"@/completed-assistant-message.utils.js\";\n\nexport class CodexNcpRunEventEmitter {\n constructor(private readonly stateManager?: NcpAgentConversationStateManager) {}\n\n emitEvent = async function* (\n this: CodexNcpRunEventEmitter,\n event: NcpEndpointEvent,\n ): AsyncGenerator<NcpEndpointEvent> {\n await this.stateManager?.dispatch(event);\n yield event;\n };\n\n emitRunStarted = async function* (\n this: CodexNcpRunEventEmitter,\n sessionId: string,\n messageId: string,\n runId: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n yield* this.emitEvent({\n type: NcpEventType.RunStarted,\n payload: { sessionId, messageId, runId },\n });\n };\n\n emitReadyMetadata = async function* (\n this: CodexNcpRunEventEmitter,\n sessionId: string,\n messageId: string,\n runId: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n yield* this.emitEvent({\n type: NcpEventType.RunMetadata,\n payload: {\n sessionId,\n messageId,\n runId,\n metadata: { kind: \"ready\", runId, sessionId, supportsAbort: true },\n },\n });\n };\n\n emitRunError = async function* (\n this: CodexNcpRunEventEmitter,\n sessionId: string,\n messageId: string,\n runId: string,\n error: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n yield* this.emitEvent({\n type: NcpEventType.RunError,\n payload: { sessionId, messageId, runId, error },\n });\n };\n\n emitRunCompleted = async function* (\n this: CodexNcpRunEventEmitter,\n sessionId: string,\n messageId: string,\n runId: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n yield* this.emitEvent({\n type: NcpEventType.RunMetadata,\n payload: {\n sessionId,\n messageId,\n runId,\n metadata: { kind: \"final\", sessionId },\n },\n });\n yield* this.emitEvent({\n type: NcpEventType.MessageCompleted,\n payload: {\n sessionId,\n message: buildCompletedAssistantMessage({\n stateManager: this.stateManager,\n sessionId,\n messageId,\n }),\n },\n });\n yield* this.emitEvent({\n type: NcpEventType.RunFinished,\n payload: { sessionId, messageId, runId },\n });\n };\n}\n"],"mappings":";;;AAOA,IAAa,0BAAb,MAAqC;CACnC,YAAY,cAAkE;AAAjD,OAAA,eAAA;;CAE7B,YAAY,iBAEV,OACkC;AAClC,QAAM,KAAK,cAAc,SAAS,MAAM;AACxC,QAAM;;CAGR,iBAAiB,iBAEf,WACA,WACA,OACkC;AAClC,SAAO,KAAK,UAAU;GACpB,MAAM,aAAa;GACnB,SAAS;IAAE;IAAW;IAAW;IAAO;GACzC,CAAC;;CAGJ,oBAAoB,iBAElB,WACA,WACA,OACkC;AAClC,SAAO,KAAK,UAAU;GACpB,MAAM,aAAa;GACnB,SAAS;IACP;IACA;IACA;IACA,UAAU;KAAE,MAAM;KAAS;KAAO;KAAW,eAAe;KAAM;IACnE;GACF,CAAC;;CAGJ,eAAe,iBAEb,WACA,WACA,OACA,OACkC;AAClC,SAAO,KAAK,UAAU;GACpB,MAAM,aAAa;GACnB,SAAS;IAAE;IAAW;IAAW;IAAO;IAAO;GAChD,CAAC;;CAGJ,mBAAmB,iBAEjB,WACA,WACA,OACkC;AAClC,SAAO,KAAK,UAAU;GACpB,MAAM,aAAa;GACnB,SAAS;IACP;IACA;IACA;IACA,UAAU;KAAE,MAAM;KAAS;KAAW;IACvC;GACF,CAAC;AACF,SAAO,KAAK,UAAU;GACpB,MAAM,aAAa;GACnB,SAAS;IACP;IACA,SAAS,+BAA+B;KACtC,cAAc,KAAK;KACnB;KACA;KACD,CAAC;IACH;GACF,CAAC;AACF,SAAO,KAAK,UAAU;GACpB,MAAM,aAAa;GACnB,SAAS;IAAE;IAAW;IAAW;IAAO;GACzC,CAAC"}
@@ -216,3 +216,5 @@ function buildOpenAiCompatibleUpstreamRequest(params) {
216
216
  }
217
217
  //#endregion
218
218
  export { buildOpenAiCompatibleUpstreamRequest, callOpenAiCompatibleUpstream };
219
+
220
+ //# sourceMappingURL=codex-openai-responses-bridge-request.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-openai-responses-bridge-request.utils.js","names":[],"sources":["../../src/utils/codex-openai-responses-bridge-request.utils.ts"],"sourcesContent":["import {\n readArray,\n readBoolean,\n readNumber,\n readRecord,\n readString,\n withTrailingSlash,\n type CodexOpenAiResponsesBridgeConfig,\n type OpenAiChatCompletionResponse,\n type OpenResponsesItemRecord,\n} from \"../codex-openai-responses-bridge-shared.utils.js\";\nimport {\n buildChatContent,\n mergeChatContent,\n normalizeToolOutput,\n readAssistantMessageText,\n type OpenAiChatContent,\n} from \"../codex-openai-responses-bridge-message-content.utils.js\";\nfunction stripModelPrefix(model: string, prefixes: string[]): string {\n const normalizedModel = model.trim();\n for (const prefix of prefixes) {\n const normalizedPrefix = prefix.trim().toLowerCase();\n if (!normalizedPrefix) {\n continue;\n }\n const candidatePrefix = `${normalizedPrefix}/`;\n if (normalizedModel.toLowerCase().startsWith(candidatePrefix)) {\n return normalizedModel.slice(candidatePrefix.length);\n }\n }\n return normalizedModel;\n}\nfunction resolveUpstreamModel(\n requestedModel: unknown,\n config: CodexOpenAiResponsesBridgeConfig,\n): string {\n const prefixes = (config.modelPrefixes ?? []).filter((value) => value.trim().length > 0);\n const model =\n stripModelPrefix(readString(requestedModel) ?? \"\", prefixes) ||\n stripModelPrefix(config.defaultModel ?? \"\", prefixes);\n if (!model) {\n throw new Error(\"Codex bridge could not resolve an upstream model.\");\n }\n return model;\n}\nfunction buildOpenAiMessages(input: unknown, instructions: unknown): Array<Record<string, unknown>> {\n return new OpenAiMessagesBuilder(input, instructions).build();\n}\n\nclass OpenAiMessagesBuilder {\n private readonly messages: Array<Record<string, unknown>> = [];\n private readonly assistantTextParts: string[] = [];\n private readonly assistantToolCalls: Array<Record<string, unknown>> = [];\n private assistantReasoningContent = { present: false, value: \"\" };\n private systemContent: OpenAiChatContent;\n\n constructor(\n private readonly input: unknown,\n instructions: unknown,\n ) {\n this.systemContent = readString(instructions) ?? null;\n }\n\n build = (): Array<Record<string, unknown>> => {\n if (typeof this.input === \"string\") {\n this.messages.push({\n role: \"user\",\n content: this.input,\n });\n return this.withSystemMessage();\n }\n\n for (const rawItem of readArray(this.input)) {\n const item = readRecord(rawItem) as OpenResponsesItemRecord | undefined;\n if (!item) {\n continue;\n }\n this.appendItem(item);\n }\n\n this.flushAssistant();\n return this.withSystemMessage();\n };\n\n private appendItem = (item: OpenResponsesItemRecord): void => {\n const type = readString(item.type);\n if (type === \"message\") {\n this.appendMessageInputItem(item);\n } else if (type === \"reasoning\") {\n this.appendReasoningItem(item);\n } else if (type === \"function_call\") {\n this.appendFunctionCallItem(item);\n } else if (type === \"function_call_output\") {\n this.appendFunctionCallOutputItem(item);\n }\n };\n\n private appendMessageInputItem = (item: OpenResponsesItemRecord): void => {\n const role = readString(item.role);\n const content = buildChatContent(item.content);\n if (role === \"assistant\") {\n const text = readAssistantMessageText(content);\n if (text.trim()) {\n this.assistantTextParts.push(text);\n }\n return;\n }\n\n this.flushAssistant();\n const normalizedRole = role === \"developer\" ? \"system\" : role;\n if (normalizedRole === \"system\") {\n this.systemContent = mergeChatContent(this.systemContent, content);\n } else if (normalizedRole === \"user\" && content !== null) {\n this.messages.push({\n role: \"user\",\n content,\n });\n }\n };\n\n private appendReasoningItem = (item: OpenResponsesItemRecord): void => {\n const content = readArray(item.content);\n const reasoningText = content\n .map((entry) => {\n const record = readRecord(entry);\n if (!record || readString(record.type) !== \"reasoning_text\") {\n return \"\";\n }\n return typeof record.text === \"string\" ? record.text : \"\";\n })\n .join(\"\");\n this.assistantReasoningContent = { present: true, value: reasoningText };\n };\n\n private appendFunctionCallItem = (item: OpenResponsesItemRecord): void => {\n const name = readString(item.name);\n const argumentsText = readString(item.arguments) ?? \"{}\";\n if (!name) {\n return;\n }\n const callId =\n readString(item.call_id) ??\n readString(item.id) ??\n `call_${this.assistantToolCalls.length}`;\n this.assistantToolCalls.push({\n id: callId,\n type: \"function\",\n function: {\n name,\n arguments: argumentsText,\n },\n });\n };\n\n private appendFunctionCallOutputItem = (item: OpenResponsesItemRecord): void => {\n this.flushAssistant();\n const callId = readString(item.call_id);\n if (!callId) {\n return;\n }\n this.messages.push({\n role: \"tool\",\n tool_call_id: callId,\n content: normalizeToolOutput(item.output),\n });\n };\n\n private flushAssistant = (): void => {\n if (\n this.assistantTextParts.length === 0 &&\n this.assistantToolCalls.length === 0 &&\n !this.assistantReasoningContent.present\n ) {\n return;\n }\n this.messages.push({\n role: \"assistant\",\n content: this.assistantTextParts.join(\"\\n\").trim() || null,\n ...(this.assistantReasoningContent.present\n ? {\n reasoning_content: this.assistantReasoningContent.value,\n }\n : {}),\n ...(this.assistantToolCalls.length > 0\n ? {\n tool_calls: structuredClone(this.assistantToolCalls),\n }\n : {}),\n });\n this.assistantTextParts.length = 0;\n this.assistantToolCalls.length = 0;\n this.assistantReasoningContent = { present: false, value: \"\" };\n };\n\n private withSystemMessage = (): Array<Record<string, unknown>> =>\n this.systemContent === null\n ? this.messages\n : [\n {\n role: \"system\",\n content: this.systemContent,\n },\n ...this.messages,\n ];\n}\n\nfunction toOpenAiTools(value: unknown): Array<Record<string, unknown>> | undefined {\n const tools: Array<Record<string, unknown>> = [];\n for (const entry of readArray(value)) {\n const tool = readRecord(entry);\n const type = readString(tool?.type);\n const fn = readRecord(tool?.function);\n const name = readString(fn?.name) ?? readString(tool?.name);\n if (type !== \"function\" || !name) {\n continue;\n }\n const description =\n (fn ? readString(fn.description) : undefined) ?? readString(tool?.description);\n const parameters =\n (fn ? readRecord(fn.parameters) : undefined) ?? readRecord(tool?.parameters);\n const strict =\n (fn ? readBoolean(fn.strict) : undefined) ?? readBoolean(tool?.strict);\n tools.push({\n type: \"function\",\n function: {\n name,\n ...(description ? { description } : {}),\n parameters: parameters ?? {\n type: \"object\",\n properties: {},\n },\n ...(strict !== undefined ? { strict } : {}),\n },\n });\n }\n return tools.length > 0 ? tools : undefined;\n}\n\nfunction toOpenAiToolChoice(value: unknown): Record<string, unknown> | string | undefined {\n if (value === \"auto\" || value === \"none\" || value === \"required\") {\n return value;\n }\n const record = readRecord(value);\n const fn = readRecord(record?.function);\n const name = readString(fn?.name) ?? readString(record?.name);\n if (readString(record?.type) === \"function\" && name) {\n return {\n type: \"function\",\n function: {\n name,\n },\n };\n }\n return undefined;\n}\n\nexport async function callOpenAiCompatibleUpstream(params: {\n config: CodexOpenAiResponsesBridgeConfig;\n body: Record<string, unknown>;\n}): Promise<{\n model: string;\n response: OpenAiChatCompletionResponse;\n}> {\n const { model, request } = buildOpenAiCompatibleUpstreamRequest({\n config: params.config,\n body: params.body,\n stream: false,\n });\n const upstreamResponse = await fetch(request.url, request.init);\n const rawText = await upstreamResponse.text();\n let parsed: OpenAiChatCompletionResponse;\n try {\n parsed = JSON.parse(rawText) as OpenAiChatCompletionResponse;\n } catch {\n throw new Error(`Bridge upstream returned invalid JSON: ${rawText.slice(0, 240)}`);\n }\n\n if (!upstreamResponse.ok) {\n throw new Error(\n readString(parsed.error?.message) ??\n rawText.slice(0, 240) ??\n `HTTP ${upstreamResponse.status}`,\n );\n }\n\n return {\n model,\n response: parsed,\n };\n}\n\nexport function buildOpenAiCompatibleUpstreamRequest(params: {\n config: CodexOpenAiResponsesBridgeConfig;\n body: Record<string, unknown>;\n stream: boolean;\n}): {\n model: string;\n request: {\n url: string;\n init: RequestInit;\n };\n} {\n const { body, config, stream } = params;\n const model = resolveUpstreamModel(body.model, config);\n const upstreamUrl = new URL(\n \"chat/completions\",\n withTrailingSlash(config.upstreamApiBase),\n );\n const tools = toOpenAiTools(body.tools);\n const toolChoice = toOpenAiToolChoice(body.tool_choice);\n return {\n model,\n request: {\n url: upstreamUrl.toString(),\n init: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(config.upstreamApiKey\n ? {\n Authorization: `Bearer ${config.upstreamApiKey}`,\n }\n : {}),\n ...(config.upstreamExtraHeaders ?? {}),\n },\n body: JSON.stringify({\n model,\n messages: buildOpenAiMessages(body.input, body.instructions),\n ...(tools ? { tools } : {}),\n ...(toolChoice ? { tool_choice: toolChoice } : {}),\n ...(config.upstreamReasoningSplit ? { reasoning_split: true } : {}),\n ...(stream ? { stream: true, stream_options: { include_usage: true } } : {}),\n ...(typeof body.max_output_tokens === \"number\"\n ? {\n max_tokens: Math.max(\n 1,\n Math.trunc(readNumber(body.max_output_tokens) ?? 1),\n ),\n }\n : {}),\n }),\n },\n },\n };\n}\n"],"mappings":"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"}
@@ -129,3 +129,5 @@ function buildBridgeResponsePayload(params) {
129
129
  }
130
130
  //#endregion
131
131
  export { buildBridgeResponsePayload, buildResponseResource, buildUsage, writeStreamError };
132
+
133
+ //# sourceMappingURL=codex-openai-responses-bridge-stream.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-openai-responses-bridge-stream.utils.js","names":[],"sources":["../../src/utils/codex-openai-responses-bridge-stream.utils.ts"],"sourcesContent":["import type { ServerResponse } from \"node:http\";\nimport { buildAssistantOutputItems } from \"../codex-openai-responses-bridge-assistant-output.utils.js\";\nimport {\n readArray,\n readNumber,\n readRecord,\n readString,\n writeSseEvent,\n type OpenAiChatCompletionResponse,\n type OpenResponsesOutputItem,\n} from \"../codex-openai-responses-bridge-shared.utils.js\";\n\nfunction buildOpenResponsesOutputItems(\n response: OpenAiChatCompletionResponse,\n responseId: string,\n): OpenResponsesOutputItem[] {\n const message = response.choices?.[0]?.message;\n if (!message) {\n return [];\n }\n\n const outputItems = buildAssistantOutputItems({\n message,\n responseId,\n });\n\n const toolCalls = readArray(message.tool_calls);\n toolCalls.forEach((entry, index) => {\n const toolCall = readRecord(entry);\n const fn = readRecord(toolCall?.function);\n const name = readString(fn?.name);\n const argumentsText = readString(fn?.arguments) ?? \"{}\";\n if (!name) {\n return;\n }\n const callId =\n readString(toolCall?.id) ??\n `${responseId}:call:${index}`;\n outputItems.push({\n type: \"function_call\",\n id: `${responseId}:function:${index}`,\n call_id: callId,\n name,\n arguments: argumentsText,\n status: \"completed\",\n });\n });\n\n return outputItems;\n}\n\nfunction normalizeUsageValue(value: unknown): number | Record<string, unknown> | null {\n const numericValue = readNumber(value);\n if (numericValue !== undefined) {\n return Math.max(0, Math.trunc(numericValue));\n }\n const record = readRecord(value);\n if (!record) {\n return null;\n }\n const next: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(record)) {\n const normalizedEntry = normalizeUsageValue(entry);\n if (normalizedEntry !== null) {\n next[key] = normalizedEntry;\n }\n }\n return Object.keys(next).length > 0 ? next : null;\n}\n\nfunction normalizeUsageRecord(rawUsage: unknown): Record<string, unknown> {\n const usage = readRecord(rawUsage);\n if (!usage) {\n return {};\n }\n const next: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(usage)) {\n const normalizedValue = normalizeUsageValue(value);\n if (normalizedValue === null) {\n continue;\n }\n if (key === \"prompt_tokens\") {\n next.input_tokens = normalizedValue;\n continue;\n }\n if (key === \"completion_tokens\") {\n next.output_tokens = normalizedValue;\n continue;\n }\n if (key === \"prompt_tokens_details\") {\n next.input_tokens_details = normalizedValue;\n continue;\n }\n if (key === \"completion_tokens_details\") {\n next.output_tokens_details = normalizedValue;\n continue;\n }\n next[key] = normalizedValue;\n }\n return next;\n}\n\nexport function buildUsage(response: OpenAiChatCompletionResponse): Record<string, unknown> {\n const promptTokens = Math.max(0, Math.trunc(readNumber(response.usage?.prompt_tokens) ?? 0));\n const completionTokens = Math.max(\n 0,\n Math.trunc(readNumber(response.usage?.completion_tokens) ?? 0),\n );\n const totalTokens = Math.max(\n 0,\n Math.trunc(readNumber(response.usage?.total_tokens) ?? promptTokens + completionTokens),\n );\n return {\n ...normalizeUsageRecord(response.usage),\n input_tokens: promptTokens,\n output_tokens: completionTokens,\n total_tokens: totalTokens,\n };\n}\n\nexport function buildResponseResource(params: {\n responseId: string;\n model: string;\n outputItems: OpenResponsesOutputItem[];\n usage: Record<string, unknown>;\n status?: \"in_progress\" | \"completed\";\n}): Record<string, unknown> {\n const { model, outputItems, responseId, status, usage } = params;\n return {\n id: responseId,\n object: \"response\",\n created_at: Math.floor(Date.now() / 1000),\n status: status ?? \"completed\",\n model,\n output: outputItems,\n usage,\n error: null,\n };\n}\n\nexport function writeStreamError(response: ServerResponse, message: string): void {\n new StreamErrorWriter(response, message).write();\n}\n\nclass StreamErrorWriter {\n constructor(\n private readonly response: ServerResponse,\n private readonly message: string,\n ) {}\n\n write = (): void => {\n this.response.statusCode = 200;\n this.response.setHeader(\"content-type\", \"text/event-stream; charset=utf-8\");\n this.response.setHeader(\"cache-control\", \"no-cache, no-transform\");\n this.response.setHeader(\"connection\", \"keep-alive\");\n writeSseEvent(this.response, \"error\", {\n type: \"error\",\n error: {\n code: \"invalid_request_error\",\n message: this.message,\n },\n });\n this.response.end();\n };\n}\n\nexport function buildBridgeResponsePayload(params: {\n responseId: string;\n model: string;\n response: OpenAiChatCompletionResponse;\n}): {\n outputItems: OpenResponsesOutputItem[];\n usage: Record<string, unknown>;\n responseResource: Record<string, unknown>;\n} {\n const { model, response, responseId } = params;\n const outputItems = buildOpenResponsesOutputItems(response, responseId);\n const usage = buildUsage(response);\n return {\n outputItems,\n usage,\n responseResource: buildResponseResource({\n responseId,\n model,\n outputItems,\n usage,\n }),\n };\n}\n"],"mappings":";;;AAYA,SAAS,8BACP,UACA,YAC2B;CAC3B,MAAM,UAAU,SAAS,UAAU,IAAI;AACvC,KAAI,CAAC,QACH,QAAO,EAAE;CAGX,MAAM,cAAc,0BAA0B;EAC5C;EACA;EACD,CAAC;AAEgB,WAAU,QAAQ,WAAW,CACrC,SAAS,OAAO,UAAU;EAClC,MAAM,WAAW,WAAW,MAAM;EAClC,MAAM,KAAK,WAAW,UAAU,SAAS;EACzC,MAAM,OAAO,WAAW,IAAI,KAAK;EACjC,MAAM,gBAAgB,WAAW,IAAI,UAAU,IAAI;AACnD,MAAI,CAAC,KACH;EAEF,MAAM,SACJ,WAAW,UAAU,GAAG,IACxB,GAAG,WAAW,QAAQ;AACxB,cAAY,KAAK;GACf,MAAM;GACN,IAAI,GAAG,WAAW,YAAY;GAC9B,SAAS;GACT;GACA,WAAW;GACX,QAAQ;GACT,CAAC;GACF;AAEF,QAAO;;AAGT,SAAS,oBAAoB,OAAyD;CACpF,MAAM,eAAe,WAAW,MAAM;AACtC,KAAI,iBAAiB,KAAA,EACnB,QAAO,KAAK,IAAI,GAAG,KAAK,MAAM,aAAa,CAAC;CAE9C,MAAM,SAAS,WAAW,MAAM;AAChC,KAAI,CAAC,OACH,QAAO;CAET,MAAM,OAAgC,EAAE;AACxC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,EAAE;EACjD,MAAM,kBAAkB,oBAAoB,MAAM;AAClD,MAAI,oBAAoB,KACtB,MAAK,OAAO;;AAGhB,QAAO,OAAO,KAAK,KAAK,CAAC,SAAS,IAAI,OAAO;;AAG/C,SAAS,qBAAqB,UAA4C;CACxE,MAAM,QAAQ,WAAW,SAAS;AAClC,KAAI,CAAC,MACH,QAAO,EAAE;CAEX,MAAM,OAAgC,EAAE;AACxC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,EAAE;EAChD,MAAM,kBAAkB,oBAAoB,MAAM;AAClD,MAAI,oBAAoB,KACtB;AAEF,MAAI,QAAQ,iBAAiB;AAC3B,QAAK,eAAe;AACpB;;AAEF,MAAI,QAAQ,qBAAqB;AAC/B,QAAK,gBAAgB;AACrB;;AAEF,MAAI,QAAQ,yBAAyB;AACnC,QAAK,uBAAuB;AAC5B;;AAEF,MAAI,QAAQ,6BAA6B;AACvC,QAAK,wBAAwB;AAC7B;;AAEF,OAAK,OAAO;;AAEd,QAAO;;AAGT,SAAgB,WAAW,UAAiE;CAC1F,MAAM,eAAe,KAAK,IAAI,GAAG,KAAK,MAAM,WAAW,SAAS,OAAO,cAAc,IAAI,EAAE,CAAC;CAC5F,MAAM,mBAAmB,KAAK,IAC5B,GACA,KAAK,MAAM,WAAW,SAAS,OAAO,kBAAkB,IAAI,EAAE,CAC/D;CACD,MAAM,cAAc,KAAK,IACvB,GACA,KAAK,MAAM,WAAW,SAAS,OAAO,aAAa,IAAI,eAAe,iBAAiB,CACxF;AACD,QAAO;EACL,GAAG,qBAAqB,SAAS,MAAM;EACvC,cAAc;EACd,eAAe;EACf,cAAc;EACf;;AAGH,SAAgB,sBAAsB,QAMV;CAC1B,MAAM,EAAE,OAAO,aAAa,YAAY,QAAQ,UAAU;AAC1D,QAAO;EACL,IAAI;EACJ,QAAQ;EACR,YAAY,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;EACzC,QAAQ,UAAU;EAClB;EACA,QAAQ;EACR;EACA,OAAO;EACR;;AAGH,SAAgB,iBAAiB,UAA0B,SAAuB;AAChF,KAAI,kBAAkB,UAAU,QAAQ,CAAC,OAAO;;AAGlD,IAAM,oBAAN,MAAwB;CACtB,YACE,UACA,SACA;AAFiB,OAAA,WAAA;AACA,OAAA,UAAA;;CAGnB,cAAoB;AAClB,OAAK,SAAS,aAAa;AAC3B,OAAK,SAAS,UAAU,gBAAgB,mCAAmC;AAC3E,OAAK,SAAS,UAAU,iBAAiB,yBAAyB;AAClE,OAAK,SAAS,UAAU,cAAc,aAAa;AACnD,gBAAc,KAAK,UAAU,SAAS;GACpC,MAAM;GACN,OAAO;IACL,MAAM;IACN,SAAS,KAAK;IACf;GACF,CAAC;AACF,OAAK,SAAS,KAAK;;;AAIvB,SAAgB,2BAA2B,QAQzC;CACA,MAAM,EAAE,OAAO,UAAU,eAAe;CACxC,MAAM,cAAc,8BAA8B,UAAU,WAAW;CACvE,MAAM,QAAQ,WAAW,SAAS;AAClC,QAAO;EACL;EACA;EACA,kBAAkB,sBAAsB;GACtC;GACA;GACA;GACA;GACD,CAAC;EACH"}
@@ -7,4 +7,5 @@ type CodexOpenAiResponsesBridgeRuntimeConfig = CodexOpenAiResponsesBridgeConfig
7
7
  };
8
8
  declare function ensureCodexOpenAiResponsesBridge(config: CodexOpenAiResponsesBridgeRuntimeConfig): Promise<CodexOpenAiResponsesBridgeResult>;
9
9
  //#endregion
10
- export { CodexOpenAiResponsesBridgeRuntimeConfig, ensureCodexOpenAiResponsesBridge };
10
+ export { CodexOpenAiResponsesBridgeRuntimeConfig, ensureCodexOpenAiResponsesBridge };
11
+ //# sourceMappingURL=codex-openai-responses-bridge.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-openai-responses-bridge.utils.d.ts","names":[],"sources":["../../src/utils/codex-openai-responses-bridge.utils.ts"],"mappings":";;;;KAsBY,uCAAA,GAA0C,gCAAA;EACpD,cAAA,GAAiB,kCAAA;AAAA;AAAA,iBAoKG,gCAAA,CACpB,MAAA,EAAQ,uCAAA,GACP,OAAA,CAAQ,gCAAA"}
@@ -136,3 +136,5 @@ async function ensureCodexOpenAiResponsesBridge(config) {
136
136
  }
137
137
  //#endregion
138
138
  export { ensureCodexOpenAiResponsesBridge };
139
+
140
+ //# sourceMappingURL=codex-openai-responses-bridge.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-openai-responses-bridge.utils.js","names":[],"sources":["../../src/utils/codex-openai-responses-bridge.utils.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport {\n buildOpenAiCompatibleUpstreamRequest,\n callOpenAiCompatibleUpstream,\n} from \"./codex-openai-responses-bridge-request.utils.js\";\nimport {\n buildBridgeResponsePayload,\n writeStreamError,\n} from \"./codex-openai-responses-bridge-stream.utils.js\";\nimport { writeResponsesUpstreamStream } from \"./codex-openai-responses-stream-writer.utils.js\";\nimport {\n readBoolean,\n readRecord,\n type BridgeEntry,\n type CodexOpenAiResponsesBridgeConfig,\n type CodexOpenAiResponsesBridgeResult,\n} from \"../codex-openai-responses-bridge-shared.utils.js\";\nimport type { CodexOpenAiResponsesOutputObserver } from \"./codex-openai-responses-stream-writer.utils.js\";\n\nconst bridgeCache = new Map<string, BridgeEntry>();\n\nexport type CodexOpenAiResponsesBridgeRuntimeConfig = CodexOpenAiResponsesBridgeConfig & {\n outputObserver?: CodexOpenAiResponsesOutputObserver;\n};\n\nfunction toBridgeCacheKey(config: CodexOpenAiResponsesBridgeConfig): string {\n return JSON.stringify({\n upstreamApiBase: config.upstreamApiBase,\n upstreamApiKey: config.upstreamApiKey ?? \"\",\n upstreamExtraHeaders: config.upstreamExtraHeaders ?? {},\n defaultModel: config.defaultModel ?? \"\",\n modelPrefixes: (config.modelPrefixes ?? []).map((prefix) => prefix.trim().toLowerCase()),\n upstreamReasoningSplit: config.upstreamReasoningSplit === true,\n });\n}\n\nasync function readJsonBody(request: IncomingMessage): Promise<Record<string, unknown> | null> {\n const chunks: Buffer[] = [];\n for await (const chunk of request) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n const rawText = Buffer.concat(chunks).toString(\"utf8\").trim();\n if (!rawText) {\n return {};\n }\n try {\n return readRecord(JSON.parse(rawText)) ?? null;\n } catch {\n return null;\n }\n}\n\nasync function handleResponsesRequest(\n request: IncomingMessage,\n response: ServerResponse,\n config: CodexOpenAiResponsesBridgeRuntimeConfig,\n): Promise<void> {\n await new CodexResponsesBridgeRequestHandler(request, response, config).handle();\n}\n\nclass JsonResponseWriter {\n constructor(private readonly response: ServerResponse) {}\n\n write = (statusCode: number, body: Record<string, unknown>): void => {\n this.response.statusCode = statusCode;\n this.response.setHeader(\"content-type\", \"application/json\");\n this.response.end(JSON.stringify(body));\n };\n}\n\nclass CodexResponsesBridgeRequestHandler {\n private readonly jsonWriter: JsonResponseWriter;\n\n constructor(\n private readonly request: IncomingMessage,\n private readonly response: ServerResponse,\n private readonly config: CodexOpenAiResponsesBridgeRuntimeConfig,\n ) {\n this.jsonWriter = new JsonResponseWriter(response);\n }\n\n handle = async (): Promise<void> => {\n const body = await readJsonBody(this.request);\n if (!body) {\n this.writeErrorJson(400, \"Invalid JSON payload.\");\n return;\n }\n\n try {\n if (readBoolean(body.stream) !== false) {\n await this.writeStreamingResponse(body);\n return;\n }\n await this.writeJsonResponse(body);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"Codex OpenAI bridge request failed.\";\n if (readBoolean(body.stream) !== false) {\n writeStreamError(this.response, message);\n return;\n }\n this.writeErrorJson(400, message);\n }\n };\n\n private writeStreamingResponse = async (body: Record<string, unknown>): Promise<void> => {\n const responseId = randomUUID();\n const upstream = buildOpenAiCompatibleUpstreamRequest({\n config: this.config,\n body,\n stream: true,\n });\n const upstreamResponse = await fetch(upstream.request.url, upstream.request.init);\n if (!upstreamResponse.ok) {\n throw new Error((await upstreamResponse.text()).slice(0, 240));\n }\n await writeResponsesUpstreamStream({\n response: this.response,\n responseId,\n model: upstream.model,\n outputObserver: this.config.outputObserver,\n upstreamResponse,\n });\n };\n\n private writeJsonResponse = async (body: Record<string, unknown>): Promise<void> => {\n const responseId = randomUUID();\n const upstream = await callOpenAiCompatibleUpstream({\n config: this.config,\n body,\n });\n const { responseResource } = buildBridgeResponsePayload({\n responseId,\n model: upstream.model,\n response: upstream.response,\n });\n\n this.jsonWriter.write(200, responseResource);\n };\n\n private writeErrorJson = (statusCode: number, message: string): void => {\n this.jsonWriter.write(statusCode, {\n error: {\n message,\n },\n });\n };\n}\n\nasync function createCodexOpenAiResponsesBridge(\n config: CodexOpenAiResponsesBridgeRuntimeConfig,\n): Promise<CodexOpenAiResponsesBridgeResult> {\n const server = createServer((request, response) => {\n const pathname = request.url\n ? new URL(request.url, \"http://127.0.0.1\").pathname\n : \"/\";\n if (\n request.method === \"POST\" &&\n (pathname === \"/responses\" || pathname === \"/v1/responses\")\n ) {\n void handleResponsesRequest(request, response, config);\n return;\n }\n\n new JsonResponseWriter(response).write(404, {\n error: {\n message: `Unsupported Codex bridge path: ${pathname}`,\n },\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(0, \"127.0.0.1\", () => resolve());\n });\n\n const address = server.address();\n if (!address || typeof address === \"string\") {\n throw new Error(\"Codex bridge failed to bind a loopback port.\");\n }\n\n return {\n baseUrl: `http://127.0.0.1:${address.port}`,\n };\n}\n\nexport async function ensureCodexOpenAiResponsesBridge(\n config: CodexOpenAiResponsesBridgeRuntimeConfig,\n): Promise<CodexOpenAiResponsesBridgeResult> {\n if (config.outputObserver) {\n return await createCodexOpenAiResponsesBridge(config);\n }\n\n const key = toBridgeCacheKey(config);\n const existing = bridgeCache.get(key);\n if (existing) {\n return await existing.promise;\n }\n\n const promise = createCodexOpenAiResponsesBridge(config);\n bridgeCache.set(key, { promise });\n try {\n return await promise;\n } catch (error) {\n bridgeCache.delete(key);\n throw error;\n }\n}\n"],"mappings":"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"}
@@ -7,4 +7,5 @@ type CodexOpenAiResponsesOutputObserver = {
7
7
  onTextDone: () => void;
8
8
  };
9
9
  //#endregion
10
- export { CodexOpenAiResponsesOutputObserver };
10
+ export { CodexOpenAiResponsesOutputObserver };
11
+ //# sourceMappingURL=codex-openai-responses-stream-writer.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-openai-responses-stream-writer.utils.d.ts","names":[],"sources":["../../src/utils/codex-openai-responses-stream-writer.utils.ts"],"mappings":";KA0CY,kCAAA;EACV,MAAA;EACA,gBAAA,GAAmB,KAAA;EACnB,eAAA;EACA,WAAA,GAAc,KAAA;EACd,UAAA;AAAA"}
@@ -322,3 +322,5 @@ var CodexResponsesOpenAiStreamWriter = class {
322
322
  };
323
323
  //#endregion
324
324
  export { writeResponsesUpstreamStream };
325
+
326
+ //# sourceMappingURL=codex-openai-responses-stream-writer.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-openai-responses-stream-writer.utils.js","names":[],"sources":["../../src/utils/codex-openai-responses-stream-writer.utils.ts"],"sourcesContent":["import type { ServerResponse } from \"node:http\";\nimport {\n buildResponseResource,\n buildUsage,\n} from \"./codex-openai-responses-bridge-stream.utils.js\";\nimport {\n nextSequenceNumber,\n readArray,\n readNumber,\n readRecord,\n readString,\n writeSseEvent,\n type OpenResponsesOutputItem,\n type StreamSequenceState,\n} from \"../codex-openai-responses-bridge-shared.utils.js\";\nimport {\n extractContentText,\n extractReasoningText,\n readOpenAiSseChunks,\n type OpenAiStreamChunk,\n} from \"./codex-openai-sse-chunks.utils.js\";\n\ntype TextStreamState = {\n outputIndex: number;\n itemId: string;\n text: string;\n};\n\ntype ReasoningStreamState = {\n outputIndex: number;\n itemId: string;\n text: string;\n};\n\ntype ToolCallStreamState = {\n outputIndex: number;\n itemId: string;\n callId: string;\n name: string;\n argumentsText: string;\n};\n\nexport type CodexOpenAiResponsesOutputObserver = {\n onDone: () => void;\n onReasoningDelta: (delta: string) => void;\n onReasoningDone: () => void;\n onTextDelta: (delta: string) => void;\n onTextDone: () => void;\n};\n\nexport async function writeResponsesUpstreamStream(params: {\n response: ServerResponse;\n responseId: string;\n model: string;\n outputObserver?: CodexOpenAiResponsesOutputObserver;\n upstreamResponse: Response;\n}): Promise<void> {\n await new CodexResponsesOpenAiStreamWriter(params).write();\n}\n\nclass CodexResponsesOpenAiStreamWriter {\n private readonly sequenceState: StreamSequenceState = { value: 0 };\n private readonly outputItems: OpenResponsesOutputItem[] = [];\n private readonly toolCalls = new Map<number, ToolCallStreamState>();\n private outputCount = 0;\n private textState: TextStreamState | null = null;\n private reasoningState: ReasoningStreamState | null = null;\n private usage: Record<string, unknown> = {};\n\n constructor(\n private readonly params: {\n response: ServerResponse;\n responseId: string;\n model: string;\n outputObserver?: CodexOpenAiResponsesOutputObserver;\n upstreamResponse: Response;\n },\n ) {}\n\n write = async (): Promise<void> => {\n this.writeHeaders();\n this.writeCreatedEvent();\n for await (const chunk of readOpenAiSseChunks(this.params.upstreamResponse)) {\n this.handleChunk(chunk);\n }\n this.finishReasoning();\n this.finishText();\n this.finishToolCalls();\n this.writeCompletedEvent();\n this.params.outputObserver?.onDone();\n this.params.response.end();\n };\n\n private nextOutputIndex = (): number => {\n const value = this.outputCount;\n this.outputCount += 1;\n return value;\n };\n\n private writeEvent = (eventType: string, payload: Record<string, unknown>): void => {\n writeSseEvent(this.params.response, eventType, {\n ...payload,\n sequence_number: nextSequenceNumber(this.sequenceState),\n });\n };\n\n private writeHeaders = (): void => {\n this.params.response.statusCode = 200;\n this.params.response.setHeader(\"content-type\", \"text/event-stream; charset=utf-8\");\n this.params.response.setHeader(\"cache-control\", \"no-cache, no-transform\");\n this.params.response.setHeader(\"connection\", \"keep-alive\");\n };\n\n private writeCreatedEvent = (): void => {\n this.writeEvent(\"response.created\", {\n type: \"response.created\",\n response: buildResponseResource({\n responseId: this.params.responseId,\n model: this.params.model,\n outputItems: [],\n usage: buildUsage({ usage: {} }),\n status: \"in_progress\",\n }),\n });\n };\n\n private ensureTextState = (): TextStreamState => {\n if (this.textState) {\n return this.textState;\n }\n this.textState = {\n outputIndex: this.nextOutputIndex(),\n itemId: `${this.params.responseId}:message:${this.outputCount}`,\n text: \"\",\n };\n this.writeEvent(\"response.output_item.added\", {\n type: \"response.output_item.added\",\n output_index: this.textState.outputIndex,\n item: {\n type: \"message\",\n id: this.textState.itemId,\n role: \"assistant\",\n status: \"in_progress\",\n content: [],\n },\n });\n this.writeEvent(\"response.content_part.added\", {\n type: \"response.content_part.added\",\n output_index: this.textState.outputIndex,\n item_id: this.textState.itemId,\n content_index: 0,\n part: { type: \"output_text\", text: \"\", annotations: [] },\n });\n return this.textState;\n };\n\n private ensureReasoningState = (): ReasoningStreamState => {\n if (this.reasoningState) {\n return this.reasoningState;\n }\n this.reasoningState = {\n outputIndex: this.nextOutputIndex(),\n itemId: `${this.params.responseId}:reasoning:${this.outputCount}`,\n text: \"\",\n };\n this.writeEvent(\"response.output_item.added\", {\n type: \"response.output_item.added\",\n output_index: this.reasoningState.outputIndex,\n item: {\n type: \"reasoning\",\n id: this.reasoningState.itemId,\n status: \"in_progress\",\n content: [],\n summary: [],\n },\n });\n this.writeEvent(\"response.reasoning_summary_part.added\", {\n type: \"response.reasoning_summary_part.added\",\n output_index: this.reasoningState.outputIndex,\n item_id: this.reasoningState.itemId,\n summary_index: 0,\n part: { type: \"summary_text\", text: \"\" },\n });\n return this.reasoningState;\n };\n\n private ensureToolCallState = (\n index: number,\n delta: Record<string, unknown>,\n ): ToolCallStreamState => {\n const existing = this.toolCalls.get(index);\n if (existing) {\n return existing;\n }\n const fn = readRecord(delta.function);\n const state = {\n outputIndex: this.nextOutputIndex(),\n itemId: `${this.params.responseId}:function:${this.outputCount}`,\n callId: readString(delta.id) ?? `${this.params.responseId}:call:${index}`,\n name: readString(fn?.name) ?? \"tool\",\n argumentsText: \"\",\n };\n this.toolCalls.set(index, state);\n this.writeEvent(\"response.output_item.added\", {\n type: \"response.output_item.added\",\n output_index: state.outputIndex,\n item: {\n type: \"function_call\",\n id: state.itemId,\n call_id: state.callId,\n name: state.name,\n arguments: \"\",\n status: \"in_progress\",\n },\n });\n return state;\n };\n\n private handleChunk = (chunk: OpenAiStreamChunk): void => {\n this.usage = chunk.usage ?? this.usage;\n const delta = chunk.choices?.[0]?.delta;\n this.writeReasoningDelta(extractReasoningText(delta));\n this.writeTextDelta(extractContentText(delta?.content));\n for (const rawToolCall of readArray(delta?.tool_calls)) {\n this.writeToolCallDelta(readRecord(rawToolCall));\n }\n };\n\n private writeReasoningDelta = (reasoningDelta: string): void => {\n if (!reasoningDelta) {\n return;\n }\n const state = this.ensureReasoningState();\n state.text += reasoningDelta;\n this.params.outputObserver?.onReasoningDelta(reasoningDelta);\n this.writeEvent(\"response.reasoning_summary_text.delta\", {\n type: \"response.reasoning_summary_text.delta\",\n output_index: state.outputIndex,\n item_id: state.itemId,\n summary_index: 0,\n delta: reasoningDelta,\n });\n this.writeEvent(\"response.reasoning_text.delta\", {\n type: \"response.reasoning_text.delta\",\n output_index: state.outputIndex,\n item_id: state.itemId,\n content_index: 0,\n delta: reasoningDelta,\n });\n };\n\n private writeTextDelta = (textDelta: string): void => {\n if (!textDelta) {\n return;\n }\n const state = this.ensureTextState();\n state.text += textDelta;\n this.params.outputObserver?.onTextDelta(textDelta);\n this.writeEvent(\"response.output_text.delta\", {\n type: \"response.output_text.delta\",\n output_index: state.outputIndex,\n item_id: state.itemId,\n content_index: 0,\n delta: textDelta,\n });\n };\n\n private writeToolCallDelta = (toolCall: Record<string, unknown> | undefined): void => {\n const toolIndex = Math.trunc(readNumber(toolCall?.index) ?? this.toolCalls.size);\n const fn = readRecord(toolCall?.function);\n const state = this.ensureToolCallState(toolIndex, toolCall ?? {});\n state.name = readString(fn?.name) ?? state.name;\n const argumentsDelta = readString(fn?.arguments) ?? \"\";\n state.argumentsText += argumentsDelta;\n if (!argumentsDelta) {\n return;\n }\n this.writeEvent(\"response.function_call_arguments.delta\", {\n type: \"response.function_call_arguments.delta\",\n output_index: state.outputIndex,\n item_id: state.itemId,\n delta: argumentsDelta,\n });\n };\n\n private finishReasoning = (): void => {\n if (!this.reasoningState) {\n return;\n }\n const item = {\n type: \"reasoning\",\n id: this.reasoningState.itemId,\n summary: [{ type: \"summary_text\", text: this.reasoningState.text }],\n content: [{ type: \"reasoning_text\", text: this.reasoningState.text }],\n status: \"completed\",\n };\n this.outputItems[this.reasoningState.outputIndex] = item;\n this.writeEvent(\"response.reasoning_summary_text.done\", {\n type: \"response.reasoning_summary_text.done\",\n output_index: this.reasoningState.outputIndex,\n item_id: this.reasoningState.itemId,\n summary_index: 0,\n text: this.reasoningState.text,\n });\n this.writeEvent(\"response.reasoning_summary_part.done\", {\n type: \"response.reasoning_summary_part.done\",\n output_index: this.reasoningState.outputIndex,\n item_id: this.reasoningState.itemId,\n summary_index: 0,\n part: { type: \"summary_text\", text: this.reasoningState.text },\n });\n this.writeEvent(\"response.reasoning_text.done\", {\n type: \"response.reasoning_text.done\",\n output_index: this.reasoningState.outputIndex,\n item_id: this.reasoningState.itemId,\n content_index: 0,\n text: this.reasoningState.text,\n });\n this.writeEvent(\"response.output_item.done\", {\n type: \"response.output_item.done\",\n output_index: this.reasoningState.outputIndex,\n item,\n });\n this.params.outputObserver?.onReasoningDone();\n };\n\n private finishText = (): void => {\n if (!this.textState) {\n return;\n }\n const item = {\n type: \"message\",\n id: this.textState.itemId,\n role: \"assistant\",\n status: \"completed\",\n content: [{ type: \"output_text\", text: this.textState.text, annotations: [] }],\n };\n this.outputItems[this.textState.outputIndex] = item;\n this.writeEvent(\"response.output_text.done\", {\n type: \"response.output_text.done\",\n output_index: this.textState.outputIndex,\n item_id: this.textState.itemId,\n content_index: 0,\n text: this.textState.text,\n });\n this.writeEvent(\"response.content_part.done\", {\n type: \"response.content_part.done\",\n output_index: this.textState.outputIndex,\n item_id: this.textState.itemId,\n content_index: 0,\n part: { type: \"output_text\", text: this.textState.text, annotations: [] },\n });\n this.writeEvent(\"response.output_item.done\", {\n type: \"response.output_item.done\",\n output_index: this.textState.outputIndex,\n item,\n });\n this.params.outputObserver?.onTextDone();\n };\n\n private finishToolCalls = (): void => {\n for (const state of [...this.toolCalls.values()].sort((a, b) => a.outputIndex - b.outputIndex)) {\n const item = {\n type: \"function_call\",\n id: state.itemId,\n call_id: state.callId,\n name: state.name,\n arguments: state.argumentsText,\n status: \"completed\",\n };\n this.outputItems[state.outputIndex] = item;\n this.writeEvent(\"response.function_call_arguments.done\", {\n type: \"response.function_call_arguments.done\",\n output_index: state.outputIndex,\n item_id: state.itemId,\n arguments: state.argumentsText,\n });\n this.writeEvent(\"response.output_item.done\", {\n type: \"response.output_item.done\",\n output_index: state.outputIndex,\n item,\n });\n }\n };\n\n private writeCompletedEvent = (): void => {\n this.writeEvent(\"response.completed\", {\n type: \"response.completed\",\n response: buildResponseResource({\n responseId: this.params.responseId,\n model: this.params.model,\n outputItems: this.outputItems.filter(Boolean),\n usage: buildUsage({ usage: this.usage }),\n }),\n });\n };\n}\n"],"mappings":"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"}
@@ -28,3 +28,5 @@ async function* readOpenAiSseChunks(upstreamResponse) {
28
28
  }
29
29
  //#endregion
30
30
  export { extractContentText, extractReasoningText, readOpenAiSseChunks };
31
+
32
+ //# sourceMappingURL=codex-openai-sse-chunks.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-openai-sse-chunks.utils.js","names":[],"sources":["../../src/utils/codex-openai-sse-chunks.utils.ts"],"sourcesContent":["import {\n readArray,\n readRawString,\n readRecord,\n} from \"../codex-openai-responses-bridge-shared.utils.js\";\n\nexport type OpenAiStreamChoiceDelta = Record<string, unknown> & {\n tool_calls?: unknown;\n};\n\nexport type OpenAiStreamChunk = {\n choices?: Array<{\n delta?: OpenAiStreamChoiceDelta;\n finish_reason?: unknown;\n }>;\n usage?: Record<string, unknown>;\n};\n\nexport function extractContentText(content: unknown): string {\n if (typeof content === \"string\") {\n return content;\n }\n return readArray(content)\n .map((entry) => {\n const record = readRecord(entry);\n return readRawString(record?.text) ?? readRawString(record?.content) ?? \"\";\n })\n .join(\"\");\n}\n\nexport function extractReasoningText(delta: OpenAiStreamChoiceDelta | undefined): string {\n return (\n readRawString(delta?.reasoning_content) ??\n readRawString(delta?.reasoning) ??\n readRawString(delta?.thinking) ??\n \"\"\n );\n}\n\nexport async function* readOpenAiSseChunks(\n upstreamResponse: Response,\n): AsyncGenerator<OpenAiStreamChunk> {\n const stream = upstreamResponse.body;\n if (!stream) {\n return;\n }\n const decoder = new TextDecoder();\n let buffer = \"\";\n for await (const rawChunk of stream as unknown as AsyncIterable<Uint8Array>) {\n buffer += decoder.decode(rawChunk, { stream: true }).replaceAll(\"\\r\\n\", \"\\n\");\n const blocks = buffer.split(\"\\n\\n\");\n buffer = blocks.pop() ?? \"\";\n for (const block of blocks) {\n const data = block\n .split(\"\\n\")\n .filter((line) => line.startsWith(\"data:\"))\n .map((line) => line.slice(5).trimStart())\n .join(\"\\n\")\n .trim();\n if (!data || data === \"[DONE]\") {\n continue;\n }\n yield JSON.parse(data) as OpenAiStreamChunk;\n }\n }\n}\n"],"mappings":";;AAkBA,SAAgB,mBAAmB,SAA0B;AAC3D,KAAI,OAAO,YAAY,SACrB,QAAO;AAET,QAAO,UAAU,QAAQ,CACtB,KAAK,UAAU;EACd,MAAM,SAAS,WAAW,MAAM;AAChC,SAAO,cAAc,QAAQ,KAAK,IAAI,cAAc,QAAQ,QAAQ,IAAI;GACxE,CACD,KAAK,GAAG;;AAGb,SAAgB,qBAAqB,OAAoD;AACvF,QACE,cAAc,OAAO,kBAAkB,IACvC,cAAc,OAAO,UAAU,IAC/B,cAAc,OAAO,SAAS,IAC9B;;AAIJ,gBAAuB,oBACrB,kBACmC;CACnC,MAAM,SAAS,iBAAiB;AAChC,KAAI,CAAC,OACH;CAEF,MAAM,UAAU,IAAI,aAAa;CACjC,IAAI,SAAS;AACb,YAAW,MAAM,YAAY,QAAgD;AAC3E,YAAU,QAAQ,OAAO,UAAU,EAAE,QAAQ,MAAM,CAAC,CAAC,WAAW,QAAQ,KAAK;EAC7E,MAAM,SAAS,OAAO,MAAM,OAAO;AACnC,WAAS,OAAO,KAAK,IAAI;AACzB,OAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,OAAO,MACV,MAAM,KAAK,CACX,QAAQ,SAAS,KAAK,WAAW,QAAQ,CAAC,CAC1C,KAAK,SAAS,KAAK,MAAM,EAAE,CAAC,WAAW,CAAC,CACxC,KAAK,KAAK,CACV,MAAM;AACT,OAAI,CAAC,QAAQ,SAAS,SACpB;AAEF,SAAM,KAAK,MAAM,KAAK"}
@@ -181,3 +181,5 @@ async function* mapCodexItemEvent(params) {
181
181
  }
182
182
  //#endregion
183
183
  export { mapCodexItemEvent };
184
+
185
+ //# sourceMappingURL=codex-sdk-ncp-event-mapper.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-sdk-ncp-event-mapper.utils.js","names":[],"sources":["../../src/utils/codex-sdk-ncp-event-mapper.utils.ts"],"sourcesContent":["import type { ThreadEvent, ThreadItem } from \"@openai/codex-sdk\";\nimport { type NcpEndpointEvent, NcpEventType } from \"@nextclaw/ncp\";\n\ntype ToolLikeItem = Extract<\n ThreadItem,\n { type: \"mcp_tool_call\" | \"command_execution\" | \"web_search\" | \"file_change\" | \"todo_list\" }\n>;\n\nexport type ItemTextSnapshot = {\n text: string;\n started: boolean;\n};\n\nexport type ToolSnapshot = {\n started: boolean;\n argsEmitted: boolean;\n ended: boolean;\n};\n\nconst TEXT_DELTA_CHUNK_SIZE = 32;\nconst TOOL_LIKE_ITEM_TYPES = new Set<ThreadItem[\"type\"]>([\n \"mcp_tool_call\",\n \"command_execution\",\n \"web_search\",\n \"file_change\",\n \"todo_list\",\n]);\n\nfunction buildToolDescriptor(item: ToolLikeItem): { toolName: string; args: unknown } {\n switch (item.type) {\n case \"mcp_tool_call\":\n return {\n toolName: item.server ? `mcp:${item.server}.${item.tool}` : `mcp:${item.tool}`,\n args: item.arguments,\n };\n case \"command_execution\":\n return { toolName: \"command_execution\", args: { command: item.command } };\n case \"web_search\":\n return { toolName: \"web_search\", args: { query: item.query } };\n case \"file_change\":\n return { toolName: \"file_change\", args: { changes: item.changes } };\n case \"todo_list\":\n return { toolName: \"todo_list\", args: { items: item.items } };\n }\n}\n\nfunction buildToolResult(item: ToolLikeItem): unknown {\n switch (item.type) {\n case \"mcp_tool_call\":\n return item.status === \"failed\"\n ? { ok: false, error: item.error ?? { message: \"MCP tool call failed.\" } }\n : {\n ok: item.status === \"completed\",\n status: item.status,\n result: item.result ?? null,\n };\n case \"command_execution\":\n return {\n status: item.status,\n command: item.command,\n aggregated_output: item.aggregated_output,\n ...(typeof item.exit_code === \"number\" ? { exit_code: item.exit_code } : {}),\n };\n case \"web_search\":\n return { status: \"completed\", query: item.query };\n case \"file_change\":\n return { status: item.status, changes: item.changes };\n case \"todo_list\":\n return { status: \"completed\", items: item.items };\n }\n}\n\nfunction stringifyToolArgs(args: unknown): string {\n try {\n return JSON.stringify(args ?? {});\n } catch {\n return JSON.stringify({\n __serialization_error__: \"tool arguments are not JSON serializable\",\n });\n }\n}\n\nfunction isToolLikeItem(item: ThreadItem): item is ToolLikeItem {\n return TOOL_LIKE_ITEM_TYPES.has(item.type);\n}\n\nfunction splitTextDelta(delta: string): string[] {\n return Array.from(\n { length: Math.ceil(delta.length / TEXT_DELTA_CHUNK_SIZE) },\n (_, index) =>\n delta.slice(index * TEXT_DELTA_CHUNK_SIZE, (index + 1) * TEXT_DELTA_CHUNK_SIZE),\n );\n}\n\nfunction* mapTextSnapshotDelta(params: {\n currentText: string;\n deltaType: typeof NcpEventType.MessageTextDelta | typeof NcpEventType.MessageReasoningDelta;\n endType: typeof NcpEventType.MessageTextEnd | typeof NcpEventType.MessageReasoningEnd;\n eventType: \"item.started\" | \"item.updated\" | \"item.completed\";\n itemId: string;\n itemTextById: Map<string, ItemTextSnapshot>;\n messageId: string;\n sessionId: string;\n startType: typeof NcpEventType.MessageTextStart | typeof NcpEventType.MessageReasoningStart;\n}): Generator<NcpEndpointEvent> {\n const { currentText, itemId, itemTextById, messageId, sessionId } = params;\n const previous = itemTextById.get(itemId) ?? { text: \"\", started: false };\n if (!previous.started) {\n yield {\n type: params.startType,\n payload: { sessionId, messageId },\n };\n }\n if (currentText.length > previous.text.length) {\n const delta = currentText.slice(previous.text.length);\n for (const chunk of splitTextDelta(delta)) {\n yield {\n type: params.deltaType,\n payload: { sessionId, messageId, delta: chunk },\n };\n }\n }\n itemTextById.set(itemId, { text: currentText, started: true });\n if (params.eventType === \"item.completed\") {\n yield {\n type: params.endType,\n payload: { sessionId, messageId },\n };\n }\n}\n\nexport async function* mapCodexItemEvent(params: {\n sessionId: string;\n messageId: string;\n event: Extract<ThreadEvent, { type: \"item.started\" | \"item.updated\" | \"item.completed\" }>;\n itemTextById: Map<string, ItemTextSnapshot>;\n toolStateById: Map<string, ToolSnapshot>;\n}): AsyncGenerator<NcpEndpointEvent> {\n const { sessionId, messageId, event, itemTextById, toolStateById } = params;\n const { item } = event;\n\n if (item.type === \"agent_message\" || item.type === \"reasoning\") {\n const isReasoning = item.type === \"reasoning\";\n yield* mapTextSnapshotDelta({\n currentText: item.text ?? \"\",\n deltaType: isReasoning\n ? NcpEventType.MessageReasoningDelta\n : NcpEventType.MessageTextDelta,\n endType: isReasoning ? NcpEventType.MessageReasoningEnd : NcpEventType.MessageTextEnd,\n eventType: event.type,\n itemId: item.id,\n itemTextById,\n messageId,\n sessionId,\n startType: isReasoning\n ? NcpEventType.MessageReasoningStart\n : NcpEventType.MessageTextStart,\n });\n return;\n }\n\n if (!isToolLikeItem(item)) {\n return;\n }\n\n const previous = toolStateById.get(item.id) ?? {\n started: false,\n argsEmitted: false,\n ended: false,\n };\n const descriptor = buildToolDescriptor(item);\n\n if (!previous.started) {\n yield {\n type: NcpEventType.MessageToolCallStart,\n payload: {\n sessionId,\n messageId,\n toolCallId: item.id,\n toolName: descriptor.toolName,\n },\n };\n previous.started = true;\n }\n\n if (!previous.argsEmitted) {\n yield {\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId,\n toolCallId: item.id,\n args: stringifyToolArgs(descriptor.args),\n },\n };\n previous.argsEmitted = true;\n }\n\n if (!previous.ended) {\n yield {\n type: NcpEventType.MessageToolCallEnd,\n payload: {\n sessionId,\n toolCallId: item.id,\n },\n };\n previous.ended = true;\n }\n\n if (event.type === \"item.updated\" || event.type === \"item.completed\") {\n yield {\n type: NcpEventType.MessageToolCallResult,\n payload: {\n sessionId,\n toolCallId: item.id,\n content: buildToolResult(item),\n },\n };\n }\n\n toolStateById.set(item.id, previous);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/nextclaw-ncp-runtime-codex-sdk",
3
- "version": "0.1.35",
3
+ "version": "0.1.37",
4
4
  "private": false,
5
5
  "description": "Optional NCP runtime adapter backed by OpenAI Codex SDK.",
6
6
  "type": "module",
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "dependencies": {
19
19
  "@openai/codex-sdk": "^0.130.0",
20
- "@nextclaw/ncp": "0.5.14"
20
+ "@nextclaw/ncp": "0.5.16"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/node": "^20.17.6",
@@ -25,7 +25,7 @@
25
25
  "vitest": "^4.1.2"
26
26
  },
27
27
  "scripts": {
28
- "build": "tsdown src/index.ts --dts --clean --target es2022 --no-fixedExtension --unbundle",
28
+ "build": "tsdown src/index.ts --dts.sourcemap --clean --target es2022 --no-fixedExtension --unbundle",
29
29
  "lint": "eslint .",
30
30
  "test": "vitest run src/utils/codex-model-provider.utils.test.ts src/utils/codex-sdk-ncp-event-mapper.utils.test.ts src/services/codex-live-output-stream.service.test.ts src/utils/codex-openai-sse-chunks.utils.test.ts",
31
31
  "tsc": "tsc -p tsconfig.json"