@jini-ai/agent-runtime 0.1.0
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/LICENSE +201 -0
- package/README.md +43 -0
- package/dist/acp-model-probe.d.ts +48 -0
- package/dist/acp-model-probe.d.ts.map +1 -0
- package/dist/acp-model-probe.js +15 -0
- package/dist/acp-model-probe.js.map +1 -0
- package/dist/agent-protocol/acp/account-failure.d.ts +54 -0
- package/dist/agent-protocol/acp/account-failure.d.ts.map +1 -0
- package/dist/agent-protocol/acp/account-failure.js +37 -0
- package/dist/agent-protocol/acp/account-failure.js.map +1 -0
- package/dist/agent-protocol/acp/constants.d.ts +26 -0
- package/dist/agent-protocol/acp/constants.d.ts.map +1 -0
- package/dist/agent-protocol/acp/constants.js +39 -0
- package/dist/agent-protocol/acp/constants.js.map +1 -0
- package/dist/agent-protocol/acp/index.d.ts +14 -0
- package/dist/agent-protocol/acp/index.d.ts.map +1 -0
- package/dist/agent-protocol/acp/index.js +14 -0
- package/dist/agent-protocol/acp/index.js.map +1 -0
- package/dist/agent-protocol/acp/json.d.ts +82 -0
- package/dist/agent-protocol/acp/json.d.ts.map +1 -0
- package/dist/agent-protocol/acp/json.js +144 -0
- package/dist/agent-protocol/acp/json.js.map +1 -0
- package/dist/agent-protocol/acp/models.d.ts +112 -0
- package/dist/agent-protocol/acp/models.d.ts.map +1 -0
- package/dist/agent-protocol/acp/models.js +293 -0
- package/dist/agent-protocol/acp/models.js.map +1 -0
- package/dist/agent-protocol/acp/rpc.d.ts +107 -0
- package/dist/agent-protocol/acp/rpc.d.ts.map +1 -0
- package/dist/agent-protocol/acp/rpc.js +162 -0
- package/dist/agent-protocol/acp/rpc.js.map +1 -0
- package/dist/agent-protocol/acp/session-params.d.ts +55 -0
- package/dist/agent-protocol/acp/session-params.d.ts.map +1 -0
- package/dist/agent-protocol/acp/session-params.js +81 -0
- package/dist/agent-protocol/acp/session-params.js.map +1 -0
- package/dist/agent-protocol/acp/session.d.ts +101 -0
- package/dist/agent-protocol/acp/session.d.ts.map +1 -0
- package/dist/agent-protocol/acp/session.js +832 -0
- package/dist/agent-protocol/acp/session.js.map +1 -0
- package/dist/agent-protocol/acp/text-suppression.d.ts +73 -0
- package/dist/agent-protocol/acp/text-suppression.d.ts.map +1 -0
- package/dist/agent-protocol/acp/text-suppression.js +229 -0
- package/dist/agent-protocol/acp/text-suppression.js.map +1 -0
- package/dist/agent-protocol/acp/types.d.ts +27 -0
- package/dist/agent-protocol/acp/types.d.ts.map +1 -0
- package/dist/agent-protocol/acp/types.js +2 -0
- package/dist/agent-protocol/acp/types.js.map +1 -0
- package/dist/agent-protocol/acp/updates.d.ts +166 -0
- package/dist/agent-protocol/acp/updates.d.ts.map +1 -0
- package/dist/agent-protocol/acp/updates.js +268 -0
- package/dist/agent-protocol/acp/updates.js.map +1 -0
- package/dist/agent-protocol/core/index.d.ts +6 -0
- package/dist/agent-protocol/core/index.d.ts.map +1 -0
- package/dist/agent-protocol/core/index.js +6 -0
- package/dist/agent-protocol/core/index.js.map +1 -0
- package/dist/agent-protocol/core/json-line-stream.d.ts +42 -0
- package/dist/agent-protocol/core/json-line-stream.d.ts.map +1 -0
- package/dist/agent-protocol/core/json-line-stream.js +333 -0
- package/dist/agent-protocol/core/json-line-stream.js.map +1 -0
- package/dist/agent-protocol/index.d.ts +8 -0
- package/dist/agent-protocol/index.d.ts.map +1 -0
- package/dist/agent-protocol/index.js +8 -0
- package/dist/agent-protocol/index.js.map +1 -0
- package/dist/agent-protocol/pi-rpc/events.d.ts +26 -0
- package/dist/agent-protocol/pi-rpc/events.d.ts.map +1 -0
- package/dist/agent-protocol/pi-rpc/events.js +167 -0
- package/dist/agent-protocol/pi-rpc/events.js.map +1 -0
- package/dist/agent-protocol/pi-rpc/index.d.ts +11 -0
- package/dist/agent-protocol/pi-rpc/index.d.ts.map +1 -0
- package/dist/agent-protocol/pi-rpc/index.js +11 -0
- package/dist/agent-protocol/pi-rpc/index.js.map +1 -0
- package/dist/agent-protocol/pi-rpc/internal.d.ts +45 -0
- package/dist/agent-protocol/pi-rpc/internal.d.ts.map +1 -0
- package/dist/agent-protocol/pi-rpc/internal.js +41 -0
- package/dist/agent-protocol/pi-rpc/internal.js.map +1 -0
- package/dist/agent-protocol/pi-rpc/models.d.ts +21 -0
- package/dist/agent-protocol/pi-rpc/models.d.ts.map +1 -0
- package/dist/agent-protocol/pi-rpc/models.js +48 -0
- package/dist/agent-protocol/pi-rpc/models.js.map +1 -0
- package/dist/agent-protocol/pi-rpc/session.d.ts +106 -0
- package/dist/agent-protocol/pi-rpc/session.d.ts.map +1 -0
- package/dist/agent-protocol/pi-rpc/session.js +371 -0
- package/dist/agent-protocol/pi-rpc/session.js.map +1 -0
- package/dist/amr-model-cache.d.ts +40 -0
- package/dist/amr-model-cache.d.ts.map +1 -0
- package/dist/amr-model-cache.js +79 -0
- package/dist/amr-model-cache.js.map +1 -0
- package/dist/amr-profile-resolver.d.ts +21 -0
- package/dist/amr-profile-resolver.d.ts.map +1 -0
- package/dist/amr-profile-resolver.js +4 -0
- package/dist/amr-profile-resolver.js.map +1 -0
- package/dist/artifact-taxonomy.d.ts +27 -0
- package/dist/artifact-taxonomy.d.ts.map +1 -0
- package/dist/artifact-taxonomy.js +5 -0
- package/dist/artifact-taxonomy.js.map +1 -0
- package/dist/auth.d.ts +25 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +332 -0
- package/dist/auth.js.map +1 -0
- package/dist/capabilities.d.ts +9 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +2 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/claude-stream.d.ts +37 -0
- package/dist/claude-stream.d.ts.map +1 -0
- package/dist/claude-stream.js +660 -0
- package/dist/claude-stream.js.map +1 -0
- package/dist/copilot-stream.d.ts +37 -0
- package/dist/copilot-stream.d.ts.map +1 -0
- package/dist/copilot-stream.js +136 -0
- package/dist/copilot-stream.js.map +1 -0
- package/dist/defs/aider.d.ts +13 -0
- package/dist/defs/aider.d.ts.map +1 -0
- package/dist/defs/aider.js +63 -0
- package/dist/defs/aider.js.map +1 -0
- package/dist/defs/amp.d.ts +12 -0
- package/dist/defs/amp.d.ts.map +1 -0
- package/dist/defs/amp.js +56 -0
- package/dist/defs/amp.js.map +1 -0
- package/dist/defs/amr.d.ts +37 -0
- package/dist/defs/amr.d.ts.map +1 -0
- package/dist/defs/amr.js +303 -0
- package/dist/defs/amr.js.map +1 -0
- package/dist/defs/antigravity.d.ts +25 -0
- package/dist/defs/antigravity.d.ts.map +1 -0
- package/dist/defs/antigravity.js +213 -0
- package/dist/defs/antigravity.js.map +1 -0
- package/dist/defs/claude.d.ts +30 -0
- package/dist/defs/claude.d.ts.map +1 -0
- package/dist/defs/claude.js +130 -0
- package/dist/defs/claude.js.map +1 -0
- package/dist/defs/codebuddy.d.ts +26 -0
- package/dist/defs/codebuddy.d.ts.map +1 -0
- package/dist/defs/codebuddy.js +124 -0
- package/dist/defs/codebuddy.js.map +1 -0
- package/dist/defs/codex.d.ts +30 -0
- package/dist/defs/codex.d.ts.map +1 -0
- package/dist/defs/codex.js +196 -0
- package/dist/defs/codex.js.map +1 -0
- package/dist/defs/copilot.d.ts +12 -0
- package/dist/defs/copilot.d.ts.map +1 -0
- package/dist/defs/copilot.js +88 -0
- package/dist/defs/copilot.js.map +1 -0
- package/dist/defs/cursor-agent.d.ts +27 -0
- package/dist/defs/cursor-agent.d.ts.map +1 -0
- package/dist/defs/cursor-agent.js +93 -0
- package/dist/defs/cursor-agent.js.map +1 -0
- package/dist/defs/deepseek.d.ts +12 -0
- package/dist/defs/deepseek.d.ts.map +1 -0
- package/dist/defs/deepseek.js +53 -0
- package/dist/defs/deepseek.js.map +1 -0
- package/dist/defs/devin.d.ts +12 -0
- package/dist/defs/devin.d.ts.map +1 -0
- package/dist/defs/devin.js +45 -0
- package/dist/defs/devin.js.map +1 -0
- package/dist/defs/grok-build.d.ts +26 -0
- package/dist/defs/grok-build.d.ts.map +1 -0
- package/dist/defs/grok-build.js +105 -0
- package/dist/defs/grok-build.js.map +1 -0
- package/dist/defs/hermes.d.ts +13 -0
- package/dist/defs/hermes.d.ts.map +1 -0
- package/dist/defs/hermes.js +51 -0
- package/dist/defs/hermes.js.map +1 -0
- package/dist/defs/index.d.ts +33 -0
- package/dist/defs/index.d.ts.map +1 -0
- package/dist/defs/index.js +33 -0
- package/dist/defs/index.js.map +1 -0
- package/dist/defs/kilo.d.ts +12 -0
- package/dist/defs/kilo.d.ts.map +1 -0
- package/dist/defs/kilo.js +20 -0
- package/dist/defs/kilo.js.map +1 -0
- package/dist/defs/kimi.d.ts +13 -0
- package/dist/defs/kimi.d.ts.map +1 -0
- package/dist/defs/kimi.js +26 -0
- package/dist/defs/kimi.js.map +1 -0
- package/dist/defs/kiro.d.ts +12 -0
- package/dist/defs/kiro.d.ts.map +1 -0
- package/dist/defs/kiro.js +20 -0
- package/dist/defs/kiro.js.map +1 -0
- package/dist/defs/mimo.d.ts +13 -0
- package/dist/defs/mimo.d.ts.map +1 -0
- package/dist/defs/mimo.js +26 -0
- package/dist/defs/mimo.js.map +1 -0
- package/dist/defs/opencode.d.ts +27 -0
- package/dist/defs/opencode.d.ts.map +1 -0
- package/dist/defs/opencode.js +89 -0
- package/dist/defs/opencode.js.map +1 -0
- package/dist/defs/pi.d.ts +18 -0
- package/dist/defs/pi.d.ts.map +1 -0
- package/dist/defs/pi.js +94 -0
- package/dist/defs/pi.js.map +1 -0
- package/dist/defs/qoder.d.ts +11 -0
- package/dist/defs/qoder.d.ts.map +1 -0
- package/dist/defs/qoder.js +50 -0
- package/dist/defs/qoder.js.map +1 -0
- package/dist/defs/qwen.d.ts +11 -0
- package/dist/defs/qwen.d.ts.map +1 -0
- package/dist/defs/qwen.js +28 -0
- package/dist/defs/qwen.js.map +1 -0
- package/dist/defs/reasonix.d.ts +20 -0
- package/dist/defs/reasonix.d.ts.map +1 -0
- package/dist/defs/reasonix.js +60 -0
- package/dist/defs/reasonix.js.map +1 -0
- package/dist/defs/shared.d.ts +23 -0
- package/dist/defs/shared.d.ts.map +1 -0
- package/dist/defs/shared.js +58 -0
- package/dist/defs/shared.js.map +1 -0
- package/dist/defs/trae-cli.d.ts +14 -0
- package/dist/defs/trae-cli.d.ts.map +1 -0
- package/dist/defs/trae-cli.js +22 -0
- package/dist/defs/trae-cli.js.map +1 -0
- package/dist/defs/vibe.d.ts +12 -0
- package/dist/defs/vibe.d.ts.map +1 -0
- package/dist/defs/vibe.js +20 -0
- package/dist/defs/vibe.js.map +1 -0
- package/dist/detection.d.ts +14 -0
- package/dist/detection.d.ts.map +1 -0
- package/dist/detection.js +266 -0
- package/dist/detection.js.map +1 -0
- package/dist/diagnostics.d.ts +8 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +95 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/env.d.ts +19 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +95 -0
- package/dist/env.js.map +1 -0
- package/dist/executables.d.ts +24 -0
- package/dist/executables.d.ts.map +1 -0
- package/dist/executables.js +349 -0
- package/dist/executables.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/dist/invocation.d.ts +6 -0
- package/dist/invocation.d.ts.map +1 -0
- package/dist/invocation.js +47 -0
- package/dist/invocation.js.map +1 -0
- package/dist/json-event-stream.d.ts +9 -0
- package/dist/json-event-stream.d.ts.map +1 -0
- package/dist/json-event-stream.js +856 -0
- package/dist/json-event-stream.js.map +1 -0
- package/dist/launch.d.ts +12 -0
- package/dist/launch.d.ts.map +1 -0
- package/dist/launch.js +221 -0
- package/dist/launch.js.map +1 -0
- package/dist/mcp.d.ts +44 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +12 -0
- package/dist/mcp.js.map +1 -0
- package/dist/metadata.d.ts +24 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +100 -0
- package/dist/metadata.js.map +1 -0
- package/dist/mmd-routes.d.ts +12 -0
- package/dist/mmd-routes.d.ts.map +1 -0
- package/dist/mmd-routes.js +146 -0
- package/dist/mmd-routes.js.map +1 -0
- package/dist/model-registry.d.ts +120 -0
- package/dist/model-registry.d.ts.map +1 -0
- package/dist/model-registry.js +77 -0
- package/dist/model-registry.js.map +1 -0
- package/dist/models.d.ts +16 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +93 -0
- package/dist/models.js.map +1 -0
- package/dist/opencode-log.d.ts +16 -0
- package/dist/opencode-log.d.ts.map +1 -0
- package/dist/opencode-log.js +163 -0
- package/dist/opencode-log.js.map +1 -0
- package/dist/paths.d.ts +3 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +29 -0
- package/dist/paths.js.map +1 -0
- package/dist/pi-models.d.ts +13 -0
- package/dist/pi-models.d.ts.map +1 -0
- package/dist/pi-models.js +36 -0
- package/dist/pi-models.js.map +1 -0
- package/dist/prompt-augmenter.d.ts +60 -0
- package/dist/prompt-augmenter.d.ts.map +1 -0
- package/dist/prompt-augmenter.js +26 -0
- package/dist/prompt-augmenter.js.map +1 -0
- package/dist/prompt-budget.d.ts +20 -0
- package/dist/prompt-budget.d.ts.map +1 -0
- package/dist/prompt-budget.js +226 -0
- package/dist/prompt-budget.js.map +1 -0
- package/dist/prompt-file.d.ts +7 -0
- package/dist/prompt-file.d.ts.map +1 -0
- package/dist/prompt-file.js +27 -0
- package/dist/prompt-file.js.map +1 -0
- package/dist/providers/aihubmix.d.ts +99 -0
- package/dist/providers/aihubmix.d.ts.map +1 -0
- package/dist/providers/aihubmix.js +239 -0
- package/dist/providers/aihubmix.js.map +1 -0
- package/dist/providers/anthropic-messages.d.ts +116 -0
- package/dist/providers/anthropic-messages.d.ts.map +1 -0
- package/dist/providers/anthropic-messages.js +313 -0
- package/dist/providers/anthropic-messages.js.map +1 -0
- package/dist/providers/azure-chat.d.ts +99 -0
- package/dist/providers/azure-chat.d.ts.map +1 -0
- package/dist/providers/azure-chat.js +164 -0
- package/dist/providers/azure-chat.js.map +1 -0
- package/dist/providers/connection-guard.d.ts +67 -0
- package/dist/providers/connection-guard.d.ts.map +1 -0
- package/dist/providers/connection-guard.js +211 -0
- package/dist/providers/connection-guard.js.map +1 -0
- package/dist/providers/elevenlabs.d.ts +28 -0
- package/dist/providers/elevenlabs.d.ts.map +1 -0
- package/dist/providers/elevenlabs.js +138 -0
- package/dist/providers/elevenlabs.js.map +1 -0
- package/dist/providers/google-messages.d.ts +108 -0
- package/dist/providers/google-messages.d.ts.map +1 -0
- package/dist/providers/google-messages.js +284 -0
- package/dist/providers/google-messages.js.map +1 -0
- package/dist/providers/google.d.ts +20 -0
- package/dist/providers/google.d.ts.map +1 -0
- package/dist/providers/google.js +42 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/index.d.ts +39 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +39 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/model-catalog.d.ts +32 -0
- package/dist/providers/model-catalog.d.ts.map +1 -0
- package/dist/providers/model-catalog.js +394 -0
- package/dist/providers/model-catalog.js.map +1 -0
- package/dist/providers/oauth-callback-server.d.ts +35 -0
- package/dist/providers/oauth-callback-server.d.ts.map +1 -0
- package/dist/providers/oauth-callback-server.js +217 -0
- package/dist/providers/oauth-callback-server.js.map +1 -0
- package/dist/providers/oauth-credentials.d.ts +29 -0
- package/dist/providers/oauth-credentials.d.ts.map +1 -0
- package/dist/providers/oauth-credentials.js +70 -0
- package/dist/providers/oauth-credentials.js.map +1 -0
- package/dist/providers/oauth-provider.d.ts +95 -0
- package/dist/providers/oauth-provider.d.ts.map +1 -0
- package/dist/providers/oauth-provider.js +130 -0
- package/dist/providers/oauth-provider.js.map +1 -0
- package/dist/providers/oauth-tokens.d.ts +35 -0
- package/dist/providers/oauth-tokens.d.ts.map +1 -0
- package/dist/providers/oauth-tokens.js +136 -0
- package/dist/providers/oauth-tokens.js.map +1 -0
- package/dist/providers/ollama-chat.d.ts +106 -0
- package/dist/providers/ollama-chat.d.ts.map +1 -0
- package/dist/providers/ollama-chat.js +292 -0
- package/dist/providers/ollama-chat.js.map +1 -0
- package/dist/providers/openai-chat.d.ts +147 -0
- package/dist/providers/openai-chat.d.ts.map +1 -0
- package/dist/providers/openai-chat.js +302 -0
- package/dist/providers/openai-chat.js.map +1 -0
- package/dist/providers/pkce.d.ts +81 -0
- package/dist/providers/pkce.d.ts.map +1 -0
- package/dist/providers/pkce.js +176 -0
- package/dist/providers/pkce.js.map +1 -0
- package/dist/providers/sse-decode.d.ts +47 -0
- package/dist/providers/sse-decode.d.ts.map +1 -0
- package/dist/providers/sse-decode.js +109 -0
- package/dist/providers/sse-decode.js.map +1 -0
- package/dist/providers/token-params.d.ts +29 -0
- package/dist/providers/token-params.d.ts.map +1 -0
- package/dist/providers/token-params.js +41 -0
- package/dist/providers/token-params.js.map +1 -0
- package/dist/providers/turn-end-guard.d.ts +37 -0
- package/dist/providers/turn-end-guard.d.ts.map +1 -0
- package/dist/providers/turn-end-guard.js +42 -0
- package/dist/providers/turn-end-guard.js.map +1 -0
- package/dist/providers/types.d.ts +36 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +13 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/qoder-stream.d.ts +19 -0
- package/dist/qoder-stream.d.ts.map +1 -0
- package/dist/qoder-stream.js +167 -0
- package/dist/qoder-stream.js.map +1 -0
- package/dist/registry.d.ts +5 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +58 -0
- package/dist/registry.js.map +1 -0
- package/dist/resolution.d.ts +2 -0
- package/dist/resolution.d.ts.map +1 -0
- package/dist/resolution.js +19 -0
- package/dist/resolution.js.map +1 -0
- package/dist/role-marker-guard.d.ts +53 -0
- package/dist/role-marker-guard.d.ts.map +1 -0
- package/dist/role-marker-guard.js +280 -0
- package/dist/role-marker-guard.js.map +1 -0
- package/dist/telemetry-sink.d.ts +35 -0
- package/dist/telemetry-sink.d.ts.map +1 -0
- package/dist/telemetry-sink.js +5 -0
- package/dist/telemetry-sink.js.map +1 -0
- package/dist/terminal-launch.d.ts +11 -0
- package/dist/terminal-launch.d.ts.map +1 -0
- package/dist/terminal-launch.js +123 -0
- package/dist/terminal-launch.js.map +1 -0
- package/dist/types.d.ts +185 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module providers/openai-chat
|
|
3
|
+
*
|
|
4
|
+
* OpenAI Chat Completions API wire adapter + tool-loop turn-runner. Built
|
|
5
|
+
* fresh against OpenAI's real, current public API docs/reference
|
|
6
|
+
* (`developers.openai.com/api/docs/guides/function-calling` for the
|
|
7
|
+
* `tools`/`tool_calls`/tool-result-message shapes; the streaming delta
|
|
8
|
+
* accumulation shape below matches the long-stable, widely-documented
|
|
9
|
+
* `chat.completion.chunk` SSE format every OpenAI-compatible gateway this
|
|
10
|
+
* package's `providers/model-catalog.ts` already targets — `openai`/
|
|
11
|
+
* `senseaudio`/`aihubmix` protocols — implements identically), per this
|
|
12
|
+
* repo's "verify against real API docs, don't guess from memory"
|
|
13
|
+
* convention. Only the *shape* (a turn-runner with a tool-execution loop)
|
|
14
|
+
* is modeled on OD's `apps/daemon/src/routes/chat.ts`'s `runTurn` per
|
|
15
|
+
* `ADS-memory/reports/proposals/PROP-http-route-packs-chat-model-proxy-
|
|
16
|
+
* 2026-07-21.md` — this task did not have direct access to that file.
|
|
17
|
+
* Sibling of `anthropic-messages.ts`; see that module's header for the
|
|
18
|
+
* shared design rationale (package placement, `extraHeaders` fix for the
|
|
19
|
+
* confirmed OpenRouter product-identity leak, the `turn-end-guard.ts` fix
|
|
20
|
+
* for the confirmed duplicate-`end`-event bug — both apply identically
|
|
21
|
+
* here).
|
|
22
|
+
*
|
|
23
|
+
* **Token-limit fix**: an earlier version of this module sent no
|
|
24
|
+
* `max_tokens`/`max_completion_tokens` field at all — a live comparison
|
|
25
|
+
* against a running Open Design daemon found OD always sends one (defaulting
|
|
26
|
+
* to 8192), model-aware between the legacy and newer field name. This
|
|
27
|
+
* module now wires in `./token-params.js#buildOpenAIChatTokenParam` — that
|
|
28
|
+
* module already existed, itself a verbatim port of OD's real
|
|
29
|
+
* `apps/daemon/src/integrations/openai-chat-token-params.ts`, but was never
|
|
30
|
+
* actually called from here until this fix. `azure-chat.ts` reuses the same
|
|
31
|
+
* module's `buildLegacyMaxTokensParam` (always the legacy `max_tokens`
|
|
32
|
+
* field, not model-aware) — matching OD's own azure handler, which never
|
|
33
|
+
* uses the model-aware picker (Azure deployment names are caller-defined
|
|
34
|
+
* strings, not necessarily matching OpenAI's own model-naming scheme).
|
|
35
|
+
*/
|
|
36
|
+
import { createRoleMarkerGuard } from '../role-marker-guard.js';
|
|
37
|
+
import { redactSecrets, validateBaseUrl } from './connection-guard.js';
|
|
38
|
+
import { decodeSseStream } from './sse-decode.js';
|
|
39
|
+
import { buildOpenAIChatTokenParam } from './token-params.js';
|
|
40
|
+
import { createTurnEndGuard } from './turn-end-guard.js';
|
|
41
|
+
const DEFAULT_OPENAI_BASE_URL = 'https://api.openai.com';
|
|
42
|
+
const DEFAULT_MAX_TOOL_TURNS = 8;
|
|
43
|
+
const DONE_SENTINEL = '[DONE]';
|
|
44
|
+
/** Matches OD's own default (`apps/daemon/src/routes/chat.ts`'s openai/azure handlers both fall back to this when the caller doesn't supply one) — a real, explicit bound is always sent, never an unbounded request. */
|
|
45
|
+
export const DEFAULT_OPENAI_MAX_TOKENS = 8192;
|
|
46
|
+
function isRecord(value) {
|
|
47
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
48
|
+
}
|
|
49
|
+
function openAiRequestUrl(baseUrl) {
|
|
50
|
+
const base = (baseUrl ?? DEFAULT_OPENAI_BASE_URL).replace(/\/+$/, '');
|
|
51
|
+
return /\/v\d+(\/|$)/.test(base) ? `${base}/chat/completions` : `${base}/v1/chat/completions`;
|
|
52
|
+
}
|
|
53
|
+
function openAiHeaders(options) {
|
|
54
|
+
return {
|
|
55
|
+
'content-type': 'application/json',
|
|
56
|
+
authorization: `Bearer ${options.apiKey}`,
|
|
57
|
+
...(options.extraHeaders ?? {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function openAiRequestBody(options, messages) {
|
|
61
|
+
const effectiveMaxTokens = typeof options.maxTokens === 'number' && options.maxTokens > 0 ? options.maxTokens : DEFAULT_OPENAI_MAX_TOKENS;
|
|
62
|
+
return {
|
|
63
|
+
model: options.model,
|
|
64
|
+
stream: true,
|
|
65
|
+
stream_options: { include_usage: true },
|
|
66
|
+
messages,
|
|
67
|
+
...buildOpenAIChatTokenParam(options.model, effectiveMaxTokens),
|
|
68
|
+
...(options.temperature !== undefined ? { temperature: options.temperature } : {}),
|
|
69
|
+
...(options.tools && options.tools.length > 0 ? { tools: options.tools } : {}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function extractOpenAiErrorDetail(rawText) {
|
|
73
|
+
try {
|
|
74
|
+
const parsed = JSON.parse(rawText);
|
|
75
|
+
if (isRecord(parsed) && isRecord(parsed.error) && typeof parsed.error.message === 'string') {
|
|
76
|
+
return parsed.error.message;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Non-JSON error body — fall through to the raw text below.
|
|
81
|
+
}
|
|
82
|
+
return rawText.trim().slice(0, 500);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Runs exactly one OpenAI-compatible (Chat Completions JSON wire format)
|
|
86
|
+
* streaming HTTP request and reduces its SSE events into a single outcome.
|
|
87
|
+
* Extracted so this ~150-line SSE-reduction loop has exactly one
|
|
88
|
+
* implementation shared by every OpenAI-compatible provider turn-runner in
|
|
89
|
+
* this package: `runOpenAiToolTurn` itself (below), plus
|
|
90
|
+
* `azure-chat.ts#runAzureToolTurn` and `ollama-chat.ts#runOllamaToolTurn` —
|
|
91
|
+
* both target byte-identical chat-completions JSON, differing only in URL
|
|
92
|
+
* and auth. Callers own their own base-URL SSRF validation
|
|
93
|
+
* (`validateBaseUrl`) and URL/header/body construction *before* calling
|
|
94
|
+
* this function — it only knows how to run *a* request against whatever
|
|
95
|
+
* URL/headers/body it is handed, and has no opinion on any provider's
|
|
96
|
+
* defaults. Mirrors `anthropic-messages.ts#runSingleAnthropicRequest`'s
|
|
97
|
+
* `emitEnd` contract — see that function's doc.
|
|
98
|
+
*/
|
|
99
|
+
export async function runOpenAiCompatibleRequest(init) {
|
|
100
|
+
const { onEvent, emitEnd, hasEnded } = init;
|
|
101
|
+
let response;
|
|
102
|
+
try {
|
|
103
|
+
response = (await fetch(init.url, {
|
|
104
|
+
method: 'POST',
|
|
105
|
+
headers: init.headers,
|
|
106
|
+
body: JSON.stringify(init.body),
|
|
107
|
+
...(init.signal ? { signal: init.signal } : {}),
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
112
|
+
onEvent({ type: 'error', message: redactSecrets(message, init.redactSecretsList) });
|
|
113
|
+
emitEnd('error');
|
|
114
|
+
return { finishReason: null, toolCalls: [], text: '' };
|
|
115
|
+
}
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const rawText = await response.text();
|
|
118
|
+
if (init.retryableBody) {
|
|
119
|
+
const retryBody = init.retryableBody(response.status, rawText);
|
|
120
|
+
if (retryBody) {
|
|
121
|
+
const { retryableBody: _retryableBody, ...retryInit } = init;
|
|
122
|
+
return runOpenAiCompatibleRequest({ ...retryInit, body: retryBody });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
onEvent({
|
|
126
|
+
type: 'error',
|
|
127
|
+
message: redactSecrets(extractOpenAiErrorDetail(rawText), init.redactSecretsList),
|
|
128
|
+
code: String(response.status),
|
|
129
|
+
});
|
|
130
|
+
emitEnd('error');
|
|
131
|
+
return { finishReason: null, toolCalls: [], text: '' };
|
|
132
|
+
}
|
|
133
|
+
if (!response.body) {
|
|
134
|
+
onEvent({ type: 'error', message: `${init.providerLabel} response had no body` });
|
|
135
|
+
emitEnd('error');
|
|
136
|
+
return { finishReason: null, toolCalls: [], text: '' };
|
|
137
|
+
}
|
|
138
|
+
onEvent({ type: 'status', label: 'requesting' });
|
|
139
|
+
const guard = createRoleMarkerGuard(init.guardMessageId);
|
|
140
|
+
const toolCalls = new Map();
|
|
141
|
+
let fullText = '';
|
|
142
|
+
let finishReason = null;
|
|
143
|
+
let usage = null;
|
|
144
|
+
for await (const frame of decodeSseStream(response.body)) {
|
|
145
|
+
// No `hasEnded()` re-check at the top of this loop: the only in-loop call to `emitEnd`
|
|
146
|
+
// (contamination, below) is immediately followed by `break`, and every other call site is a
|
|
147
|
+
// pre-loop early `return` — traced across all five call sites in this function, same proof as
|
|
148
|
+
// `anthropic-messages.ts#runSingleAnthropicRequest`. `hasEnded()` is still consulted once,
|
|
149
|
+
// after this loop, to decide whether pending tool_use events should still be emitted (a
|
|
150
|
+
// contaminating delta can arrive on a *later* chunk than the one that set `finish_reason`).
|
|
151
|
+
if (frame.data === DONE_SENTINEL)
|
|
152
|
+
break;
|
|
153
|
+
let data;
|
|
154
|
+
try {
|
|
155
|
+
data = JSON.parse(frame.data);
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
continue; // tolerate a malformed/empty keep-alive frame
|
|
159
|
+
}
|
|
160
|
+
if (!isRecord(data))
|
|
161
|
+
continue;
|
|
162
|
+
if (isRecord(data.usage)) {
|
|
163
|
+
usage = data.usage;
|
|
164
|
+
onEvent({ type: 'usage', usage });
|
|
165
|
+
}
|
|
166
|
+
const choices = Array.isArray(data.choices) ? data.choices : [];
|
|
167
|
+
const choice = choices[0];
|
|
168
|
+
if (!isRecord(choice))
|
|
169
|
+
continue;
|
|
170
|
+
if (typeof choice.finish_reason === 'string') {
|
|
171
|
+
finishReason = choice.finish_reason;
|
|
172
|
+
}
|
|
173
|
+
const delta = isRecord(choice.delta) ? choice.delta : null;
|
|
174
|
+
if (!delta)
|
|
175
|
+
continue;
|
|
176
|
+
if (typeof delta.content === 'string' && delta.content.length > 0) {
|
|
177
|
+
// No `guard.contaminated` pre-check here: the only way it becomes true is the
|
|
178
|
+
// `emitEnd('contaminated'); break;` a few lines below, which exits this loop immediately —
|
|
179
|
+
// see `anthropic-messages.ts#runSingleAnthropicRequest`'s identical reachability proof.
|
|
180
|
+
const safe = guard.feedText(delta.content);
|
|
181
|
+
if (safe.length > 0) {
|
|
182
|
+
fullText += safe;
|
|
183
|
+
onEvent({ type: 'text_delta', delta: safe });
|
|
184
|
+
}
|
|
185
|
+
if (guard.contaminated) {
|
|
186
|
+
const warn = guard.warningEvent();
|
|
187
|
+
if (warn)
|
|
188
|
+
onEvent(warn);
|
|
189
|
+
emitEnd('contaminated');
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (Array.isArray(delta.tool_calls)) {
|
|
194
|
+
for (const rawCall of delta.tool_calls) {
|
|
195
|
+
if (!isRecord(rawCall) || typeof rawCall.index !== 'number')
|
|
196
|
+
continue;
|
|
197
|
+
let pending = toolCalls.get(rawCall.index);
|
|
198
|
+
if (!pending) {
|
|
199
|
+
const id = typeof rawCall.id === 'string' ? rawCall.id : `call_${rawCall.index}`;
|
|
200
|
+
const fn = isRecord(rawCall.function) ? rawCall.function : {};
|
|
201
|
+
const name = typeof fn.name === 'string' ? fn.name : '';
|
|
202
|
+
pending = { id, name, argsJson: '' };
|
|
203
|
+
toolCalls.set(rawCall.index, pending);
|
|
204
|
+
}
|
|
205
|
+
const fn = isRecord(rawCall.function) ? rawCall.function : null;
|
|
206
|
+
if (fn && typeof fn.arguments === 'string') {
|
|
207
|
+
pending.argsJson += fn.arguments;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const resolvedToolCalls = Array.from(toolCalls.values()).map((call) => {
|
|
213
|
+
let input = {};
|
|
214
|
+
if (call.argsJson.trim()) {
|
|
215
|
+
try {
|
|
216
|
+
input = JSON.parse(call.argsJson);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
input = {};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return { id: call.id, name: call.name, input };
|
|
223
|
+
});
|
|
224
|
+
if (finishReason === 'tool_calls' && !hasEnded()) {
|
|
225
|
+
for (const call of resolvedToolCalls) {
|
|
226
|
+
onEvent({ type: 'tool_use', id: call.id, name: call.name, input: call.input });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return { finishReason, toolCalls: resolvedToolCalls, text: fullText };
|
|
230
|
+
}
|
|
231
|
+
/** Validates `options.baseUrl`, then delegates to {@link runOpenAiCompatibleRequest} with OpenAI's own URL/header/body builders. Thin wrapper kept so `runOpenAiToolTurn`'s per-iteration call site stays unchanged by the extraction. */
|
|
232
|
+
async function runSingleOpenAiRequest(options, messages, emitEnd, hasEnded) {
|
|
233
|
+
const baseUrlCheck = validateBaseUrl(options.baseUrl ?? DEFAULT_OPENAI_BASE_URL);
|
|
234
|
+
if (baseUrlCheck.error) {
|
|
235
|
+
options.onEvent({ type: 'error', message: baseUrlCheck.error });
|
|
236
|
+
emitEnd('error');
|
|
237
|
+
return { finishReason: null, toolCalls: [], text: '' };
|
|
238
|
+
}
|
|
239
|
+
return runOpenAiCompatibleRequest({
|
|
240
|
+
url: openAiRequestUrl(options.baseUrl),
|
|
241
|
+
headers: openAiHeaders(options),
|
|
242
|
+
body: openAiRequestBody(options, messages),
|
|
243
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
244
|
+
redactSecretsList: [options.apiKey],
|
|
245
|
+
guardMessageId: 'openai-turn',
|
|
246
|
+
providerLabel: 'OpenAI',
|
|
247
|
+
onEvent: options.onEvent,
|
|
248
|
+
emitEnd,
|
|
249
|
+
hasEnded,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Runs a full OpenAI Chat Completions turn, including the tool-execution
|
|
254
|
+
* loop when `options.executeTool` is supplied and the model requests a
|
|
255
|
+
* function call. See `anthropic-messages.ts#runAnthropicToolTurn`'s doc for
|
|
256
|
+
* the shared event-stream/`ended`-flag contract this mirrors exactly.
|
|
257
|
+
*/
|
|
258
|
+
export async function runOpenAiToolTurn(options) {
|
|
259
|
+
const maxToolTurns = options.maxToolTurns ?? DEFAULT_MAX_TOOL_TURNS;
|
|
260
|
+
const endGuard = createTurnEndGuard(options.onEvent, (reason) => ({ type: 'end', reason }));
|
|
261
|
+
const emitEnd = endGuard.emitEnd;
|
|
262
|
+
let messages = options.messages.slice();
|
|
263
|
+
let toolTurns = 0;
|
|
264
|
+
let lastFinishReason = null;
|
|
265
|
+
while (true) {
|
|
266
|
+
const outcome = await runSingleOpenAiRequest(options, messages, emitEnd, endGuard.hasEnded);
|
|
267
|
+
lastFinishReason = outcome.finishReason;
|
|
268
|
+
if (endGuard.hasEnded())
|
|
269
|
+
break;
|
|
270
|
+
if (outcome.finishReason !== 'tool_calls' || outcome.toolCalls.length === 0) {
|
|
271
|
+
emitEnd('stop');
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
if (!options.executeTool) {
|
|
275
|
+
emitEnd('stop');
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
if (toolTurns >= maxToolTurns) {
|
|
279
|
+
emitEnd('max_tool_turns');
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
toolTurns += 1;
|
|
283
|
+
const assistantToolCalls = outcome.toolCalls.map((call) => ({
|
|
284
|
+
id: call.id,
|
|
285
|
+
type: 'function',
|
|
286
|
+
function: { name: call.name, arguments: JSON.stringify(call.input) },
|
|
287
|
+
}));
|
|
288
|
+
const toolResultMessages = [];
|
|
289
|
+
for (const call of outcome.toolCalls) {
|
|
290
|
+
const result = await options.executeTool(call);
|
|
291
|
+
options.onEvent({ type: 'tool_result', toolUseId: call.id, content: result.content, isError: false });
|
|
292
|
+
toolResultMessages.push({ role: 'tool', content: result.content, tool_call_id: call.id });
|
|
293
|
+
}
|
|
294
|
+
messages = [
|
|
295
|
+
...messages,
|
|
296
|
+
{ role: 'assistant', content: outcome.text || null, tool_calls: assistantToolCalls },
|
|
297
|
+
...toolResultMessages,
|
|
298
|
+
];
|
|
299
|
+
}
|
|
300
|
+
return { finishReason: lastFinishReason, toolTurns };
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=openai-chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-chat.js","sourceRoot":"","sources":["../../src/providers/openai-chat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** RFC 8414 / OIDC discovery document fields a PKCE client needs. */
|
|
2
|
+
export interface AuthorizationServerMetadata {
|
|
3
|
+
issuer: string;
|
|
4
|
+
authorization_endpoint: string;
|
|
5
|
+
token_endpoint: string;
|
|
6
|
+
}
|
|
7
|
+
/** RFC 6749 §5.1 token endpoint response (subset). */
|
|
8
|
+
export interface OAuthTokenResponse {
|
|
9
|
+
access_token: string;
|
|
10
|
+
token_type?: string;
|
|
11
|
+
expires_in?: number;
|
|
12
|
+
refresh_token?: string;
|
|
13
|
+
scope?: string;
|
|
14
|
+
}
|
|
15
|
+
/** In-flight authorization request, stashed in memory while the user approves in their browser. */
|
|
16
|
+
export interface PendingAuthState {
|
|
17
|
+
serverId: string;
|
|
18
|
+
authServerIssuer: string;
|
|
19
|
+
tokenEndpoint: string;
|
|
20
|
+
clientId: string;
|
|
21
|
+
clientSecret?: string;
|
|
22
|
+
redirectUri: string;
|
|
23
|
+
codeVerifier: string;
|
|
24
|
+
scope?: string;
|
|
25
|
+
resource?: string;
|
|
26
|
+
createdAt: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function generateCodeVerifier(): string;
|
|
29
|
+
export declare function deriveCodeChallenge(verifier: string): string;
|
|
30
|
+
export declare function generateState(): string;
|
|
31
|
+
export interface AuthorizeUrlInput {
|
|
32
|
+
authServer: AuthorizationServerMetadata;
|
|
33
|
+
clientId: string;
|
|
34
|
+
redirectUri: string;
|
|
35
|
+
state: string;
|
|
36
|
+
codeChallenge: string;
|
|
37
|
+
scope?: string;
|
|
38
|
+
resource?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function buildAuthorizeUrl(input: AuthorizeUrlInput): string;
|
|
41
|
+
export interface ExchangeCodeInput {
|
|
42
|
+
tokenEndpoint: string;
|
|
43
|
+
clientId: string;
|
|
44
|
+
clientSecret?: string;
|
|
45
|
+
redirectUri: string;
|
|
46
|
+
code: string;
|
|
47
|
+
codeVerifier: string;
|
|
48
|
+
resource?: string;
|
|
49
|
+
}
|
|
50
|
+
export declare function exchangeCodeForToken(input: ExchangeCodeInput, fetchImpl?: typeof fetch): Promise<OAuthTokenResponse>;
|
|
51
|
+
export interface RefreshTokenInput {
|
|
52
|
+
tokenEndpoint: string;
|
|
53
|
+
clientId: string;
|
|
54
|
+
clientSecret?: string;
|
|
55
|
+
refreshToken: string;
|
|
56
|
+
scope?: string;
|
|
57
|
+
resource?: string;
|
|
58
|
+
}
|
|
59
|
+
export declare function refreshAccessToken(input: RefreshTokenInput, fetchImpl?: typeof fetch): Promise<OAuthTokenResponse>;
|
|
60
|
+
/**
|
|
61
|
+
* In-memory pending-authorization cache keyed by the OAuth `state`
|
|
62
|
+
* parameter. Bridges the "begin" (mint state + verifier) and "complete"
|
|
63
|
+
* (browser returns code + state) halves of the dance; persistence isn't
|
|
64
|
+
* needed because the caller completes auth in the same process, and state
|
|
65
|
+
* is single-use.
|
|
66
|
+
*/
|
|
67
|
+
export declare class PendingAuthCache {
|
|
68
|
+
private readonly ttlMs;
|
|
69
|
+
private store;
|
|
70
|
+
private timer;
|
|
71
|
+
constructor(ttlMs?: number);
|
|
72
|
+
put(state: string, value: PendingAuthState): void;
|
|
73
|
+
/** One-shot consume — any successful callback removes the state so a replay can't reuse it. */
|
|
74
|
+
consume(state: string): PendingAuthState | null;
|
|
75
|
+
size(): number;
|
|
76
|
+
/** Stops the background sweeper. Production lets the timer ride on the host process lifetime. */
|
|
77
|
+
stop(): void;
|
|
78
|
+
private startSweeper;
|
|
79
|
+
private sweep;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=pkce.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../src/providers/pkce.ts"],"names":[],"mappings":"AA0BA,qEAAqE;AACrE,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,mGAAmG;AACnG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAYD,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,2BAA2B,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAclE;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,iBAAiB,EACxB,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,kBAAkB,CAAC,CAS7B;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,iBAAiB,EACxB,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,kBAAkB,CAAC,CAQ7B;AA6CD;;;;;;GAMG;AACH,qBAAa,gBAAgB;IAIf,OAAO,CAAC,QAAQ,CAAC,KAAK;IAHlC,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,KAAK,CAA+C;gBAE/B,KAAK,GAAE,MAAuB;IAE3D,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAKjD,+FAA+F;IAC/F,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAQ/C,IAAI,IAAI,MAAM;IAId,iGAAiG;IACjG,IAAI,IAAI,IAAI;IAOZ,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,KAAK;CAUd"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module providers/pkce
|
|
3
|
+
*
|
|
4
|
+
* Generic OAuth 2.0 Authorization Code + PKCE (RFC 7636) client primitives —
|
|
5
|
+
* verifier/challenge/state generation, authorize-URL building, and the
|
|
6
|
+
* code-exchange/refresh token-endpoint calls.
|
|
7
|
+
*
|
|
8
|
+
* Vendored from the minimal subset of OD's `apps/daemon/src/mcp-oauth.ts`
|
|
9
|
+
* (a 601-line "daemon-side OAuth 2.1 client for HTTP/SSE MCP servers") that
|
|
10
|
+
* `integrations/xai-oauth.ts` actually depends on: PKCE generation,
|
|
11
|
+
* `buildAuthorizeUrl`, `exchangeCodeForToken`, `refreshAccessToken`, and the
|
|
12
|
+
* in-memory `PendingAuthCache`. The origin file's protected-resource /
|
|
13
|
+
* authorization-server RFC 9728+8414 *discovery* and Dynamic Client
|
|
14
|
+
* Registration (RFC 7591) machinery — `discoverProtectedResource`,
|
|
15
|
+
* `discoverAuthServer`, `registerClient`, `getOrRegisterClient`, `beginAuth`
|
|
16
|
+
* — is a distinct, separately-scoped MCP-server-OAuth-discovery subsystem
|
|
17
|
+
* that `xai-oauth.ts` never calls (xAI's OAuth server is hardcoded, no MCP
|
|
18
|
+
* discovery involved) and is not part of this task's 13-file scope; not
|
|
19
|
+
* ported, mirroring the same reasoning `@jini-ai/agent-runtime`'s
|
|
20
|
+
* `acp-model-probe.ts` used to exclude the ACP transport (a distinct
|
|
21
|
+
* subsystem named as its own future extraction target). No product-identity
|
|
22
|
+
* strings in the vendored subset — ported verbatim apart from doc-comment
|
|
23
|
+
* wording.
|
|
24
|
+
*/
|
|
25
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
26
|
+
const VERIFIER_LEN = 64; // RFC 7636 §4.1: 43-128 chars
|
|
27
|
+
function base64url(buf) {
|
|
28
|
+
return buf
|
|
29
|
+
.toString('base64')
|
|
30
|
+
.replace(/\+/g, '-')
|
|
31
|
+
.replace(/\//g, '_')
|
|
32
|
+
.replace(/=+$/g, '');
|
|
33
|
+
}
|
|
34
|
+
export function generateCodeVerifier() {
|
|
35
|
+
return base64url(randomBytes(VERIFIER_LEN));
|
|
36
|
+
}
|
|
37
|
+
export function deriveCodeChallenge(verifier) {
|
|
38
|
+
return base64url(createHash('sha256').update(verifier).digest());
|
|
39
|
+
}
|
|
40
|
+
export function generateState() {
|
|
41
|
+
return base64url(randomBytes(32));
|
|
42
|
+
}
|
|
43
|
+
export function buildAuthorizeUrl(input) {
|
|
44
|
+
const u = new URL(input.authServer.authorization_endpoint);
|
|
45
|
+
u.searchParams.set('response_type', 'code');
|
|
46
|
+
u.searchParams.set('client_id', input.clientId);
|
|
47
|
+
u.searchParams.set('redirect_uri', input.redirectUri);
|
|
48
|
+
u.searchParams.set('state', input.state);
|
|
49
|
+
u.searchParams.set('code_challenge', input.codeChallenge);
|
|
50
|
+
u.searchParams.set('code_challenge_method', 'S256');
|
|
51
|
+
if (input.scope)
|
|
52
|
+
u.searchParams.set('scope', input.scope);
|
|
53
|
+
// RFC 8707 resource indicator — narrows the issued token to the resource
|
|
54
|
+
// actually being requested. Most authoritative servers require it;
|
|
55
|
+
// harmless when ignored.
|
|
56
|
+
if (input.resource)
|
|
57
|
+
u.searchParams.set('resource', input.resource);
|
|
58
|
+
return u.toString();
|
|
59
|
+
}
|
|
60
|
+
export async function exchangeCodeForToken(input, fetchImpl = fetch) {
|
|
61
|
+
const form = new URLSearchParams();
|
|
62
|
+
form.set('grant_type', 'authorization_code');
|
|
63
|
+
form.set('code', input.code);
|
|
64
|
+
form.set('redirect_uri', input.redirectUri);
|
|
65
|
+
form.set('client_id', input.clientId);
|
|
66
|
+
form.set('code_verifier', input.codeVerifier);
|
|
67
|
+
if (input.resource)
|
|
68
|
+
form.set('resource', input.resource);
|
|
69
|
+
return tokenRequest(input.tokenEndpoint, form, input.clientSecret, fetchImpl);
|
|
70
|
+
}
|
|
71
|
+
export async function refreshAccessToken(input, fetchImpl = fetch) {
|
|
72
|
+
const form = new URLSearchParams();
|
|
73
|
+
form.set('grant_type', 'refresh_token');
|
|
74
|
+
form.set('refresh_token', input.refreshToken);
|
|
75
|
+
form.set('client_id', input.clientId);
|
|
76
|
+
if (input.scope)
|
|
77
|
+
form.set('scope', input.scope);
|
|
78
|
+
if (input.resource)
|
|
79
|
+
form.set('resource', input.resource);
|
|
80
|
+
return tokenRequest(input.tokenEndpoint, form, input.clientSecret, fetchImpl);
|
|
81
|
+
}
|
|
82
|
+
async function tokenRequest(tokenEndpoint, form, clientSecret, fetchImpl) {
|
|
83
|
+
const headers = {
|
|
84
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
85
|
+
accept: 'application/json',
|
|
86
|
+
};
|
|
87
|
+
if (clientSecret) {
|
|
88
|
+
// RFC 6749 §2.3.1 — confidential clients use HTTP Basic with the
|
|
89
|
+
// client_id already in the form. Public clients (PKCE-only) skip this.
|
|
90
|
+
const basic = Buffer.from(`${form.get('client_id')}:${clientSecret}`).toString('base64');
|
|
91
|
+
headers['authorization'] = `Basic ${basic}`;
|
|
92
|
+
}
|
|
93
|
+
const res = await fetchImpl(tokenEndpoint, {
|
|
94
|
+
method: 'POST',
|
|
95
|
+
headers,
|
|
96
|
+
body: form.toString(),
|
|
97
|
+
});
|
|
98
|
+
if (!res.ok) {
|
|
99
|
+
const txt = await safeText(res);
|
|
100
|
+
throw new Error(`token endpoint rejected request: HTTP ${res.status} ${res.statusText} ${txt}`);
|
|
101
|
+
}
|
|
102
|
+
const json = (await res.json());
|
|
103
|
+
if (!json.access_token) {
|
|
104
|
+
throw new Error('token endpoint response missing access_token');
|
|
105
|
+
}
|
|
106
|
+
return json;
|
|
107
|
+
}
|
|
108
|
+
async function safeText(res) {
|
|
109
|
+
try {
|
|
110
|
+
const t = await res.text();
|
|
111
|
+
return t.slice(0, 500);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* In-memory pending-authorization cache keyed by the OAuth `state`
|
|
119
|
+
* parameter. Bridges the "begin" (mint state + verifier) and "complete"
|
|
120
|
+
* (browser returns code + state) halves of the dance; persistence isn't
|
|
121
|
+
* needed because the caller completes auth in the same process, and state
|
|
122
|
+
* is single-use.
|
|
123
|
+
*/
|
|
124
|
+
export class PendingAuthCache {
|
|
125
|
+
ttlMs;
|
|
126
|
+
store = new Map();
|
|
127
|
+
timer = null;
|
|
128
|
+
constructor(ttlMs = 10 * 60 * 1000) {
|
|
129
|
+
this.ttlMs = ttlMs;
|
|
130
|
+
}
|
|
131
|
+
put(state, value) {
|
|
132
|
+
this.store.set(state, value);
|
|
133
|
+
this.startSweeper();
|
|
134
|
+
}
|
|
135
|
+
/** One-shot consume — any successful callback removes the state so a replay can't reuse it. */
|
|
136
|
+
consume(state) {
|
|
137
|
+
const v = this.store.get(state);
|
|
138
|
+
if (!v)
|
|
139
|
+
return null;
|
|
140
|
+
this.store.delete(state);
|
|
141
|
+
if (Date.now() - v.createdAt > this.ttlMs)
|
|
142
|
+
return null;
|
|
143
|
+
return v;
|
|
144
|
+
}
|
|
145
|
+
size() {
|
|
146
|
+
return this.store.size;
|
|
147
|
+
}
|
|
148
|
+
/** Stops the background sweeper. Production lets the timer ride on the host process lifetime. */
|
|
149
|
+
stop() {
|
|
150
|
+
if (this.timer) {
|
|
151
|
+
clearInterval(this.timer);
|
|
152
|
+
this.timer = null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
startSweeper() {
|
|
156
|
+
if (this.timer)
|
|
157
|
+
return;
|
|
158
|
+
this.timer = setInterval(() => this.sweep(), Math.min(this.ttlMs, 60_000));
|
|
159
|
+
// unref so the cache doesn't keep the event loop alive in tests.
|
|
160
|
+
if (typeof this.timer === 'object' && this.timer && typeof this.timer.unref === 'function') {
|
|
161
|
+
this.timer.unref();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
sweep() {
|
|
165
|
+
const now = Date.now();
|
|
166
|
+
for (const [k, v] of this.store) {
|
|
167
|
+
if (now - v.createdAt > this.ttlMs)
|
|
168
|
+
this.store.delete(k);
|
|
169
|
+
}
|
|
170
|
+
if (this.store.size === 0 && this.timer) {
|
|
171
|
+
clearInterval(this.timer);
|
|
172
|
+
this.timer = null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=pkce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/providers/pkce.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module providers/sse-decode
|
|
3
|
+
*
|
|
4
|
+
* Minimal, tolerant Server-Sent-Events *frame decoder* for an INBOUND
|
|
5
|
+
* provider stream — the response body a call to the Anthropic Messages API
|
|
6
|
+
* or the OpenAI Chat Completions API sends back when `stream: true` is
|
|
7
|
+
* requested. This is deliberately not `@jini-ai/http`'s `sse.ts`: that module
|
|
8
|
+
* is the OUTBOUND channel a route uses to push events to a browser client
|
|
9
|
+
* (bounded queue, backpressure, `Last-Event-ID` replay). This module has
|
|
10
|
+
* none of that — it only turns a raw byte/text stream into `{event, data}`
|
|
11
|
+
* frames per the SSE wire format (`text/event-stream`, RFC-ish: fields
|
|
12
|
+
* separated by `\n`, records separated by a blank line), so a provider-
|
|
13
|
+
* specific turn-runner (`anthropic-messages.ts`, `openai-chat.ts`) can
|
|
14
|
+
* `JSON.parse` each frame's `data` field without re-deriving line/record
|
|
15
|
+
* framing itself.
|
|
16
|
+
*
|
|
17
|
+
* New file, not a port — chat.ts's origin used the Node `fetch` global's
|
|
18
|
+
* response body directly with ad hoc inline buffering per call site; this
|
|
19
|
+
* factors that concern into one shared, independently-tested primitive so
|
|
20
|
+
* both provider turn-runners consume the same framing logic (the same
|
|
21
|
+
* "shared mechanism, one implementation" discipline `@jini-ai/http`'s
|
|
22
|
+
* `sse.ts`/`origin-validation.ts` already apply to their own domains).
|
|
23
|
+
*/
|
|
24
|
+
/** One decoded SSE record. `event` is `null` when the record had no `event:` line (OpenAI's Chat Completions stream never sends one; every `data:` line is implicitly a plain message). `data` is the joined value of every `data:` line in the record (multi-line `data:` fields are joined with `\n`, per the SSE spec). */
|
|
25
|
+
export interface DecodedSseEvent {
|
|
26
|
+
readonly event: string | null;
|
|
27
|
+
readonly data: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Decodes an inbound byte/text stream into SSE records. Accepts either
|
|
31
|
+
* `Uint8Array` chunks (a real `fetch` response body) or `string` chunks (test
|
|
32
|
+
* fixtures, or any caller that already has decoded text) in the same
|
|
33
|
+
* iterable — this keeps unit tests free of any need to construct a real web
|
|
34
|
+
* `ReadableStream`, matching this package's existing `fetch`-mocking
|
|
35
|
+
* convention (`vi.stubGlobal('fetch', ...)`, see `model-catalog.test.ts`).
|
|
36
|
+
*
|
|
37
|
+
* Tolerant per the SSE spec: accepts both `\n` and `\r\n` line endings,
|
|
38
|
+
* ignores comment lines (leading `:`) and unrecognized field names (`id`/
|
|
39
|
+
* `retry` are parsed by real SSE clients for reconnect bookkeeping, which is
|
|
40
|
+
* meaningless for a single proxied request/response pair, so this decoder
|
|
41
|
+
* intentionally drops them), and flushes a trailing unterminated record —
|
|
42
|
+
* even one whose very last line has no trailing `\n` at all — once the
|
|
43
|
+
* source iterable ends, so a provider closing the connection immediately
|
|
44
|
+
* after its last byte never silently loses that last record.
|
|
45
|
+
*/
|
|
46
|
+
export declare function decodeSseStream(source: AsyncIterable<Uint8Array | string>): AsyncGenerator<DecodedSseEvent>;
|
|
47
|
+
//# sourceMappingURL=sse-decode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse-decode.d.ts","sourceRoot":"","sources":["../../src/providers/sse-decode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,8TAA8T;AAC9T,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAuB,eAAe,CACpC,MAAM,EAAE,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC,GACzC,cAAc,CAAC,eAAe,CAAC,CAkEjC"}
|