@code-yeongyu/senpi 2026.5.29 → 2026.6.3
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.
- package/CHANGELOG.md +131 -1
- package/README.md +12 -2
- package/dist/cli/args.d.ts +3 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +28 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -1
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +9 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +36 -13
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +3 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +9 -3
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +5 -3
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +21 -3
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +14 -6
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +2 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +29 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +82 -21
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +2 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/provider-attribution.d.ts +4 -0
- package/dist/core/provider-attribution.d.ts.map +1 -0
- package/dist/core/provider-attribution.js +73 -0
- package/dist/core/provider-attribution.js.map +1 -0
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +1 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts +9 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +134 -11
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/sdk.d.ts +2 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +18 -40
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +6 -7
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +167 -96
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +15 -11
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +0 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/thinking-levels.d.ts.map +1 -1
- package/dist/core/thinking-levels.js +6 -2
- package/dist/core/thinking-levels.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +7 -10
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +5 -7
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +6 -7
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +5 -2
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +17 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +5 -6
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +76 -16
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +118 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +1 -3
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +2 -4
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +25 -1
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +64 -6
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +10 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +1 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +4 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +1 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/deprecation.d.ts +4 -0
- package/dist/utils/deprecation.d.ts.map +1 -0
- package/dist/utils/deprecation.js +13 -0
- package/dist/utils/deprecation.js.map +1 -0
- package/dist/utils/json.d.ts +3 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +7 -0
- package/dist/utils/json.js.map +1 -0
- package/docs/custom-provider.md +13 -10
- package/docs/extensions.md +47 -17
- package/docs/models.md +25 -12
- package/docs/providers.md +15 -5
- package/docs/quickstart.md +1 -0
- package/docs/rpc.md +3 -2
- package/docs/sdk.md +6 -0
- package/docs/session-format.md +1 -1
- package/docs/sessions.md +8 -0
- package/docs/settings.md +4 -2
- package/docs/terminal-setup.md +2 -0
- package/docs/tui.md +12 -3
- package/docs/usage.md +10 -1
- package/examples/extensions/README.md +1 -0
- package/examples/extensions/custom-header.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +54 -3
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/doom-overlay/index.ts +1 -1
- package/examples/extensions/git-merge-and-resolve.ts +115 -0
- package/examples/extensions/handoff.ts +1 -1
- package/examples/extensions/input-transform-streaming.ts +39 -0
- package/examples/extensions/interactive-shell.ts +1 -1
- package/examples/extensions/overlay-qa-tests.ts +152 -81
- package/examples/extensions/qna.ts +1 -1
- package/examples/extensions/question.ts +1 -1
- package/examples/extensions/questionnaire.ts +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/snake.ts +1 -1
- package/examples/extensions/space-invaders.ts +1 -1
- package/examples/extensions/summarize.ts +1 -1
- package/examples/extensions/tic-tac-toe.ts +1 -1
- package/examples/extensions/todo.ts +1 -1
- package/examples/extensions/tools.ts +5 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +15 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts +5 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +81 -18
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +14 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +22 -8
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/README.md +5 -3
- package/node_modules/@earendil-works/pi-ai/dist/cli.js +0 -0
- package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +1294 -412
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +1278 -652
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.js +9 -4
- package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +89 -21
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +27 -14
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +5 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.js +5 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +2 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js +2 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +118 -52
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +27 -17
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +5 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +5 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/transform-messages.d.ts +7 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/transform-messages.js +8 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/stream.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/stream.js +18 -4
- package/node_modules/@earendil-works/pi-ai/dist/stream.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +21 -5
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js +34 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts +9 -7
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +8 -7
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts +10 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +179 -79
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-tui/README.md +15 -3
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +9 -53
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/input.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/input.js +6 -54
- package/node_modules/@earendil-works/pi-tui/dist/components/input.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +34 -7
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +33 -10
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js +173 -39
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts +18 -3
- package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/tui.js +166 -22
- package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +1 -0
- package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.js +11 -3
- package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts +25 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js +96 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js.map +1 -0
- package/node_modules/@earendil-works/pi-tui/package.json +2 -2
- package/npm-shrinkwrap.json +56 -56
- package/package.json +5 -5
|
@@ -15,9 +15,9 @@ if (typeof process !== "undefined" && (process.versions?.node || process.version
|
|
|
15
15
|
_os = m;
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
|
-
import { getEnvApiKey } from "../env-api-keys.js";
|
|
19
18
|
import { clampThinkingLevel, supportsXhigh } from "../models.js";
|
|
20
19
|
import { registerSessionResourceCleanup } from "../session-resources.js";
|
|
20
|
+
import { combineAbortSignals } from "../utils/abort-signals.js";
|
|
21
21
|
import { appendAssistantMessageDiagnostic, createAssistantMessageDiagnostic, formatThrownValue, } from "../utils/diagnostics.js";
|
|
22
22
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
23
23
|
import { headersToRecord } from "../utils/headers.js";
|
|
@@ -32,6 +32,8 @@ const JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
|
32
32
|
const DEFAULT_MAX_RETRIES = 0;
|
|
33
33
|
const BASE_DELAY_MS = 1000;
|
|
34
34
|
const DEFAULT_MAX_RETRY_DELAY_MS = 60_000;
|
|
35
|
+
const DEFAULT_SSE_HEADER_TIMEOUT_MS = 10_000;
|
|
36
|
+
const DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS = 15_000;
|
|
35
37
|
const CODEX_TOOL_CALL_PROVIDERS = new Set(["openai", "openai-codex", "opencode"]);
|
|
36
38
|
const WEBSOCKET_MESSAGE_TOO_BIG_CLOSE_CODE = 1009;
|
|
37
39
|
const CODEX_RESPONSE_STATUSES = new Set([
|
|
@@ -96,6 +98,27 @@ function sleep(ms, signal) {
|
|
|
96
98
|
});
|
|
97
99
|
});
|
|
98
100
|
}
|
|
101
|
+
function normalizeTimeoutMs(value) {
|
|
102
|
+
if (value === undefined)
|
|
103
|
+
return undefined;
|
|
104
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
105
|
+
throw new Error(`Invalid timeoutMs: ${String(value)}`);
|
|
106
|
+
}
|
|
107
|
+
return Math.floor(value);
|
|
108
|
+
}
|
|
109
|
+
function createSSEHeaderTimeout() {
|
|
110
|
+
const controller = new AbortController();
|
|
111
|
+
let error;
|
|
112
|
+
const timeout = setTimeout(() => {
|
|
113
|
+
error = new Error(`Codex SSE response headers timed out after ${DEFAULT_SSE_HEADER_TIMEOUT_MS}ms`);
|
|
114
|
+
controller.abort(error);
|
|
115
|
+
}, DEFAULT_SSE_HEADER_TIMEOUT_MS);
|
|
116
|
+
return {
|
|
117
|
+
signal: controller.signal,
|
|
118
|
+
clear: () => clearTimeout(timeout),
|
|
119
|
+
error: () => error,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
99
122
|
// ============================================================================
|
|
100
123
|
// Main Stream Function
|
|
101
124
|
// ============================================================================
|
|
@@ -120,7 +143,7 @@ export const streamOpenAICodexResponses = (model, context, options) => {
|
|
|
120
143
|
timestamp: Date.now(),
|
|
121
144
|
};
|
|
122
145
|
try {
|
|
123
|
-
const apiKey = options?.apiKey
|
|
146
|
+
const apiKey = options?.apiKey;
|
|
124
147
|
if (!apiKey) {
|
|
125
148
|
throw new Error(`No API key for provider: ${model.provider}`);
|
|
126
149
|
}
|
|
@@ -134,6 +157,8 @@ export const streamOpenAICodexResponses = (model, context, options) => {
|
|
|
134
157
|
const sseHeaders = buildSSEHeaders(model.headers, options?.headers, accountId, apiKey, options?.sessionId);
|
|
135
158
|
const websocketHeaders = buildWebSocketHeaders(model.headers, options?.headers, accountId, apiKey, websocketRequestId);
|
|
136
159
|
const bodyJson = JSON.stringify(body);
|
|
160
|
+
const idleTimeoutMs = normalizeTimeoutMs(options?.timeoutMs);
|
|
161
|
+
const websocketConnectTimeoutMs = normalizeTimeoutMs(options?.websocketConnectTimeoutMs);
|
|
137
162
|
const transport = options?.transport || "auto";
|
|
138
163
|
const websocketDisabledForSession = transport !== "sse" && isWebSocketSseFallbackActive(options?.sessionId);
|
|
139
164
|
if (websocketDisabledForSession) {
|
|
@@ -144,7 +169,7 @@ export const streamOpenAICodexResponses = (model, context, options) => {
|
|
|
144
169
|
try {
|
|
145
170
|
await processWebSocketStream(resolveCodexWebSocketUrl(model.baseUrl), body, websocketHeaders, output, stream, model, () => {
|
|
146
171
|
websocketStarted = true;
|
|
147
|
-
}, options);
|
|
172
|
+
}, idleTimeoutMs, websocketConnectTimeoutMs, options);
|
|
148
173
|
if (options?.signal?.aborted) {
|
|
149
174
|
throw new Error("Request was aborted");
|
|
150
175
|
}
|
|
@@ -184,12 +209,24 @@ export const streamOpenAICodexResponses = (model, context, options) => {
|
|
|
184
209
|
throw new Error("Request was aborted");
|
|
185
210
|
}
|
|
186
211
|
try {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
212
|
+
const headerTimeout = createSSEHeaderTimeout();
|
|
213
|
+
const combinedSignal = combineAbortSignals([options?.signal, headerTimeout.signal]);
|
|
214
|
+
try {
|
|
215
|
+
response = await fetch(resolveCodexUrl(model.baseUrl), {
|
|
216
|
+
method: "POST",
|
|
217
|
+
headers: sseHeaders,
|
|
218
|
+
body: bodyJson,
|
|
219
|
+
signal: combinedSignal.signal,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
const timeoutError = headerTimeout.error();
|
|
224
|
+
throw timeoutError && !options?.signal?.aborted ? timeoutError : error;
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
combinedSignal.cleanup();
|
|
228
|
+
headerTimeout.clear();
|
|
229
|
+
}
|
|
193
230
|
await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);
|
|
194
231
|
if (response.ok) {
|
|
195
232
|
break;
|
|
@@ -257,7 +294,7 @@ export const streamOpenAICodexResponses = (model, context, options) => {
|
|
|
257
294
|
return stream;
|
|
258
295
|
};
|
|
259
296
|
export const streamSimpleOpenAICodexResponses = (model, context, options) => {
|
|
260
|
-
const apiKey = options?.apiKey
|
|
297
|
+
const apiKey = options?.apiKey;
|
|
261
298
|
if (!apiKey) {
|
|
262
299
|
throw new Error(`No API key for provider: ${model.provider}`);
|
|
263
300
|
}
|
|
@@ -277,6 +314,7 @@ function buildRequestBody(model, context, options) {
|
|
|
277
314
|
const messages = convertResponsesMessages(model, context, CODEX_TOOL_CALL_PROVIDERS, {
|
|
278
315
|
includeSystemPrompt: false,
|
|
279
316
|
preserveThinking: reasoningRequested,
|
|
317
|
+
preserveTextSignatures: true,
|
|
280
318
|
});
|
|
281
319
|
const body = {
|
|
282
320
|
model: model.id,
|
|
@@ -360,7 +398,7 @@ function resolveCodexWebSocketUrl(baseUrl) {
|
|
|
360
398
|
// Response Processing
|
|
361
399
|
// ============================================================================
|
|
362
400
|
async function processStream(response, output, stream, model, options) {
|
|
363
|
-
await processResponsesStream(mapCodexEvents(parseSSE(response)), output, stream, model, {
|
|
401
|
+
await processResponsesStream(mapCodexEvents(parseSSE(response, options?.signal)), output, stream, model, {
|
|
364
402
|
serviceTier: options?.serviceTier,
|
|
365
403
|
resolveServiceTier: resolveCodexServiceTier,
|
|
366
404
|
applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),
|
|
@@ -428,15 +466,25 @@ function normalizeCodexStatus(status) {
|
|
|
428
466
|
// ============================================================================
|
|
429
467
|
// SSE Parsing
|
|
430
468
|
// ============================================================================
|
|
431
|
-
async function* parseSSE(response) {
|
|
469
|
+
async function* parseSSE(response, signal) {
|
|
432
470
|
if (!response.body)
|
|
433
471
|
return;
|
|
434
472
|
const reader = response.body.getReader();
|
|
435
473
|
const decoder = new TextDecoder();
|
|
436
474
|
let buffer = "";
|
|
475
|
+
const onAbort = () => {
|
|
476
|
+
void reader.cancel().catch(() => { });
|
|
477
|
+
};
|
|
478
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
437
479
|
try {
|
|
438
480
|
while (true) {
|
|
481
|
+
if (signal?.aborted) {
|
|
482
|
+
throw new Error("Request was aborted");
|
|
483
|
+
}
|
|
439
484
|
const { done, value } = await reader.read();
|
|
485
|
+
if (signal?.aborted) {
|
|
486
|
+
throw new Error("Request was aborted");
|
|
487
|
+
}
|
|
440
488
|
if (done)
|
|
441
489
|
break;
|
|
442
490
|
buffer += decoder.decode(value, { stream: true });
|
|
@@ -467,6 +515,7 @@ async function* parseSSE(response) {
|
|
|
467
515
|
}
|
|
468
516
|
}
|
|
469
517
|
finally {
|
|
518
|
+
signal?.removeEventListener("abort", onAbort);
|
|
470
519
|
try {
|
|
471
520
|
await reader.cancel();
|
|
472
521
|
}
|
|
@@ -642,7 +691,7 @@ function scheduleSessionWebSocketExpiry(sessionId, entry) {
|
|
|
642
691
|
websocketSessionCache.delete(sessionId);
|
|
643
692
|
}, SESSION_WEBSOCKET_CACHE_TTL_MS);
|
|
644
693
|
}
|
|
645
|
-
async function connectWebSocket(url, headers, signal) {
|
|
694
|
+
async function connectWebSocket(url, headers, signal, connectTimeoutMs = DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS) {
|
|
646
695
|
const WebSocketCtor = await getWebSocketConstructor();
|
|
647
696
|
if (!WebSocketCtor) {
|
|
648
697
|
throw new Error("WebSocket transport is not available in this runtime");
|
|
@@ -651,6 +700,7 @@ async function connectWebSocket(url, headers, signal) {
|
|
|
651
700
|
delete wsHeaders["OpenAI-Beta"];
|
|
652
701
|
return new Promise((resolve, reject) => {
|
|
653
702
|
let settled = false;
|
|
703
|
+
let timeout;
|
|
654
704
|
let socket;
|
|
655
705
|
try {
|
|
656
706
|
socket = new WebSocketCtor(url, { headers: wsHeaders });
|
|
@@ -659,62 +709,63 @@ async function connectWebSocket(url, headers, signal) {
|
|
|
659
709
|
reject(error instanceof Error ? error : new Error(String(error)));
|
|
660
710
|
return;
|
|
661
711
|
}
|
|
662
|
-
const
|
|
663
|
-
if (
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
712
|
+
const cleanup = () => {
|
|
713
|
+
if (timeout) {
|
|
714
|
+
clearTimeout(timeout);
|
|
715
|
+
timeout = undefined;
|
|
716
|
+
}
|
|
717
|
+
socket.removeEventListener("open", onOpen);
|
|
718
|
+
socket.removeEventListener("error", onError);
|
|
719
|
+
socket.removeEventListener("close", onClose);
|
|
720
|
+
signal?.removeEventListener("abort", onAbort);
|
|
668
721
|
};
|
|
669
|
-
const
|
|
670
|
-
const error = extractWebSocketError(event);
|
|
722
|
+
const fail = (error, closeReason) => {
|
|
671
723
|
if (settled)
|
|
672
724
|
return;
|
|
673
725
|
settled = true;
|
|
674
726
|
cleanup();
|
|
727
|
+
if (closeReason) {
|
|
728
|
+
closeWebSocketSilently(socket, 1000, closeReason);
|
|
729
|
+
}
|
|
675
730
|
reject(error);
|
|
676
731
|
};
|
|
677
|
-
const
|
|
678
|
-
const error = extractWebSocketCloseError(event);
|
|
732
|
+
const onOpen = () => {
|
|
679
733
|
if (settled)
|
|
680
734
|
return;
|
|
681
735
|
settled = true;
|
|
682
736
|
cleanup();
|
|
683
|
-
|
|
737
|
+
resolve(socket);
|
|
684
738
|
};
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
return;
|
|
688
|
-
settled = true;
|
|
689
|
-
cleanup();
|
|
690
|
-
socket.close(1000, "aborted");
|
|
691
|
-
reject(new Error("Request was aborted"));
|
|
739
|
+
const onError = (event) => {
|
|
740
|
+
fail(extractWebSocketError(event));
|
|
692
741
|
};
|
|
693
|
-
const
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
742
|
+
const onClose = (event) => {
|
|
743
|
+
fail(extractWebSocketCloseError(event));
|
|
744
|
+
};
|
|
745
|
+
const onAbort = () => {
|
|
746
|
+
fail(new Error("Request was aborted"), "aborted");
|
|
698
747
|
};
|
|
699
748
|
socket.addEventListener("open", onOpen);
|
|
700
749
|
socket.addEventListener("error", onError);
|
|
701
750
|
socket.addEventListener("close", onClose);
|
|
702
751
|
signal?.addEventListener("abort", onAbort);
|
|
752
|
+
if (connectTimeoutMs > 0) {
|
|
753
|
+
timeout = setTimeout(() => {
|
|
754
|
+
fail(new Error(`WebSocket connect timeout after ${connectTimeoutMs}ms`), "connect_timeout");
|
|
755
|
+
}, connectTimeoutMs);
|
|
756
|
+
}
|
|
757
|
+
if (signal?.aborted) {
|
|
758
|
+
onAbort();
|
|
759
|
+
}
|
|
703
760
|
});
|
|
704
761
|
}
|
|
705
|
-
async function acquireWebSocket(url, headers, sessionId, signal) {
|
|
762
|
+
async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutMs) {
|
|
706
763
|
if (!sessionId) {
|
|
707
|
-
const socket = await connectWebSocket(url, headers, signal);
|
|
764
|
+
const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs);
|
|
708
765
|
return {
|
|
709
766
|
socket,
|
|
710
767
|
reused: false,
|
|
711
|
-
release: (
|
|
712
|
-
if (keep === false) {
|
|
713
|
-
closeWebSocketSilently(socket);
|
|
714
|
-
return;
|
|
715
|
-
}
|
|
716
|
-
closeWebSocketSilently(socket);
|
|
717
|
-
},
|
|
768
|
+
release: () => closeWebSocketSilently(socket),
|
|
718
769
|
};
|
|
719
770
|
}
|
|
720
771
|
const cached = websocketSessionCache.get(sessionId);
|
|
@@ -741,7 +792,7 @@ async function acquireWebSocket(url, headers, sessionId, signal) {
|
|
|
741
792
|
};
|
|
742
793
|
}
|
|
743
794
|
if (cached.busy) {
|
|
744
|
-
const socket = await connectWebSocket(url, headers, signal);
|
|
795
|
+
const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs);
|
|
745
796
|
return {
|
|
746
797
|
socket,
|
|
747
798
|
reused: false,
|
|
@@ -755,7 +806,7 @@ async function acquireWebSocket(url, headers, sessionId, signal) {
|
|
|
755
806
|
websocketSessionCache.delete(sessionId);
|
|
756
807
|
}
|
|
757
808
|
}
|
|
758
|
-
const socket = await connectWebSocket(url, headers, signal);
|
|
809
|
+
const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs);
|
|
759
810
|
const entry = { socket, busy: true };
|
|
760
811
|
websocketSessionCache.set(sessionId, entry);
|
|
761
812
|
return {
|
|
@@ -831,7 +882,7 @@ async function decodeWebSocketData(data) {
|
|
|
831
882
|
}
|
|
832
883
|
return null;
|
|
833
884
|
}
|
|
834
|
-
async function* parseWebSocket(socket, signal) {
|
|
885
|
+
async function* parseWebSocket(socket, signal, idleTimeoutMs) {
|
|
835
886
|
const queue = [];
|
|
836
887
|
let pending = null;
|
|
837
888
|
let done = false;
|
|
@@ -909,8 +960,23 @@ async function* parseWebSocket(socket, signal) {
|
|
|
909
960
|
}
|
|
910
961
|
if (done)
|
|
911
962
|
break;
|
|
912
|
-
|
|
963
|
+
let timeout;
|
|
964
|
+
await new Promise((resolve, reject) => {
|
|
913
965
|
pending = resolve;
|
|
966
|
+
if (idleTimeoutMs !== undefined && idleTimeoutMs > 0) {
|
|
967
|
+
timeout = setTimeout(() => {
|
|
968
|
+
const error = new Error(`WebSocket idle timeout after ${idleTimeoutMs}ms`);
|
|
969
|
+
failed = error;
|
|
970
|
+
done = true;
|
|
971
|
+
pending = null;
|
|
972
|
+
closeWebSocketSilently(socket, 1000, "idle_timeout");
|
|
973
|
+
reject(error);
|
|
974
|
+
}, idleTimeoutMs);
|
|
975
|
+
}
|
|
976
|
+
}).finally(() => {
|
|
977
|
+
if (timeout) {
|
|
978
|
+
clearTimeout(timeout);
|
|
979
|
+
}
|
|
914
980
|
});
|
|
915
981
|
}
|
|
916
982
|
if (failed) {
|
|
@@ -979,8 +1045,8 @@ async function* startWebSocketOutputOnFirstEvent(events, output, stream, onStart
|
|
|
979
1045
|
yield event;
|
|
980
1046
|
}
|
|
981
1047
|
}
|
|
982
|
-
async function processWebSocketStream(url, body, headers, output, stream, model, onStart, options) {
|
|
983
|
-
const { socket, entry, reused, release } = await acquireWebSocket(url, headers, options?.sessionId, options?.signal);
|
|
1048
|
+
async function processWebSocketStream(url, body, headers, output, stream, model, onStart, idleTimeoutMs, websocketConnectTimeoutMs, options) {
|
|
1049
|
+
const { socket, entry, reused, release } = await acquireWebSocket(url, headers, options?.sessionId, options?.signal, websocketConnectTimeoutMs);
|
|
984
1050
|
let keepConnection = true;
|
|
985
1051
|
const useCachedContext = options?.transport === "websocket-cached" || options?.transport === "auto";
|
|
986
1052
|
// ChatGPT Codex Responses rejects `store: true` ("Store must be set to false").
|
|
@@ -1012,7 +1078,7 @@ async function processWebSocketStream(url, body, headers, output, stream, model,
|
|
|
1012
1078
|
}
|
|
1013
1079
|
try {
|
|
1014
1080
|
socket.send(JSON.stringify({ type: "response.create", ...requestBody }));
|
|
1015
|
-
await processResponsesStream(startWebSocketOutputOnFirstEvent(mapCodexEvents(parseWebSocket(socket, options?.signal)), output, stream, onStart), output, stream, model, {
|
|
1081
|
+
await processResponsesStream(startWebSocketOutputOnFirstEvent(mapCodexEvents(parseWebSocket(socket, options?.signal, idleTimeoutMs)), output, stream, onStart), output, stream, model, {
|
|
1016
1082
|
serviceTier: options?.serviceTier,
|
|
1017
1083
|
resolveServiceTier: resolveCodexServiceTier,
|
|
1018
1084
|
applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),
|