@bastani/pi-ai 0.9.20-alpha.8 → 0.9.20
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 +68 -0
- package/README.md +172 -24
- package/dist/api/anthropic-messages.d.ts.map +1 -1
- package/dist/api/anthropic-messages.js +9 -3
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/api/azure-openai-responses.d.ts.map +1 -1
- package/dist/api/azure-openai-responses.js +4 -1
- package/dist/api/azure-openai-responses.js.map +1 -1
- package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
- package/dist/api/bedrock-converse-stream.js +5 -3
- package/dist/api/bedrock-converse-stream.js.map +1 -1
- package/dist/api/cloudflare-workers-ai-system-one.d.ts +4 -0
- package/dist/api/cloudflare-workers-ai-system-one.d.ts.map +1 -0
- package/dist/api/cloudflare-workers-ai-system-one.js +43 -0
- package/dist/api/cloudflare-workers-ai-system-one.js.map +1 -0
- package/dist/api/cloudflare-workers-ai-system-one.lazy.d.ts +3 -0
- package/dist/api/cloudflare-workers-ai-system-one.lazy.d.ts.map +1 -0
- package/dist/api/cloudflare-workers-ai-system-one.lazy.js +4 -0
- package/dist/api/cloudflare-workers-ai-system-one.lazy.js.map +1 -0
- package/dist/api/cloudflare.d.ts +2 -0
- package/dist/api/cloudflare.d.ts.map +1 -1
- package/dist/api/cloudflare.js +2 -0
- package/dist/api/cloudflare.js.map +1 -1
- package/dist/api/constrained-sampling.d.ts +8 -3
- package/dist/api/constrained-sampling.d.ts.map +1 -1
- package/dist/api/constrained-sampling.js +29 -11
- package/dist/api/constrained-sampling.js.map +1 -1
- package/dist/api/google-generative-ai.d.ts.map +1 -1
- package/dist/api/google-generative-ai.js +1 -0
- package/dist/api/google-generative-ai.js.map +1 -1
- package/dist/api/google-vertex.d.ts.map +1 -1
- package/dist/api/google-vertex.js +1 -0
- package/dist/api/google-vertex.js.map +1 -1
- package/dist/api/mistral-conversations.d.ts.map +1 -1
- package/dist/api/mistral-conversations.js +3 -2
- package/dist/api/mistral-conversations.js.map +1 -1
- package/dist/api/openai-codex-responses.d.ts.map +1 -1
- package/dist/api/openai-codex-responses.js +20 -4
- package/dist/api/openai-codex-responses.js.map +1 -1
- package/dist/api/openai-completions.d.ts.map +1 -1
- package/dist/api/openai-completions.js +1 -0
- package/dist/api/openai-completions.js.map +1 -1
- package/dist/api/openai-responses-shared.d.ts +2 -1
- package/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/dist/api/openai-responses-shared.js +1 -0
- package/dist/api/openai-responses-shared.js.map +1 -1
- package/dist/api/openai-responses.d.ts.map +1 -1
- package/dist/api/openai-responses.js +1 -0
- package/dist/api/openai-responses.js.map +1 -1
- package/dist/api/openrouter-images.d.ts +2 -1
- package/dist/api/openrouter-images.d.ts.map +1 -1
- package/dist/api/openrouter-images.js +1 -0
- package/dist/api/openrouter-images.js.map +1 -1
- package/dist/api/openrouter-images.lazy.d.ts.map +1 -1
- package/dist/api/openrouter-images.lazy.js.map +1 -1
- package/dist/api/pi-messages.d.ts.map +1 -1
- package/dist/api/pi-messages.js +1 -0
- package/dist/api/pi-messages.js.map +1 -1
- package/dist/api/simple-options.d.ts.map +1 -1
- package/dist/api/simple-options.js +1 -0
- package/dist/api/simple-options.js.map +1 -1
- package/dist/api/system-one-shared.d.ts +23 -0
- package/dist/api/system-one-shared.d.ts.map +1 -0
- package/dist/api/system-one-shared.js +170 -0
- package/dist/api/system-one-shared.js.map +1 -0
- package/dist/api/typesafe-system-one.d.ts +4 -0
- package/dist/api/typesafe-system-one.d.ts.map +1 -0
- package/dist/api/typesafe-system-one.js +19 -0
- package/dist/api/typesafe-system-one.js.map +1 -0
- package/dist/api/typesafe-system-one.lazy.d.ts +3 -0
- package/dist/api/typesafe-system-one.lazy.d.ts.map +1 -0
- package/dist/api/typesafe-system-one.lazy.js +4 -0
- package/dist/api/typesafe-system-one.lazy.js.map +1 -0
- package/dist/auth/resolve.d.ts +2 -8
- package/dist/auth/resolve.d.ts.map +1 -1
- package/dist/auth/resolve.js +3 -19
- package/dist/auth/resolve.js.map +1 -1
- package/dist/env-api-keys.d.ts.map +1 -1
- package/dist/env-api-keys.js +1 -0
- package/dist/env-api-keys.js.map +1 -1
- package/dist/image-models.d.ts +19 -8
- package/dist/image-models.d.ts.map +1 -1
- package/dist/image-models.js +14 -13
- package/dist/image-models.js.map +1 -1
- package/dist/images-api-registry.d.ts +7 -7
- package/dist/images-api-registry.d.ts.map +1 -1
- package/dist/images-api-registry.js.map +1 -1
- package/dist/images.d.ts +7 -2
- package/dist/images.d.ts.map +1 -1
- package/dist/images.js +5 -0
- package/dist/images.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/model-catalog.d.ts +25 -9
- package/dist/model-catalog.d.ts.map +1 -1
- package/dist/model-catalog.js +14 -2
- package/dist/model-catalog.js.map +1 -1
- package/dist/models-store.d.ts +3 -2
- package/dist/models-store.d.ts.map +1 -1
- package/dist/models-store.js.map +1 -1
- package/dist/models.d.ts +95 -28
- package/dist/models.d.ts.map +1 -1
- package/dist/models.generated.d.ts +131 -41
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +131 -41
- package/dist/models.generated.js.map +1 -1
- package/dist/models.js +155 -28
- package/dist/models.js.map +1 -1
- package/dist/providers/all.d.ts +19 -13
- package/dist/providers/all.d.ts.map +1 -1
- package/dist/providers/all.js +25 -21
- package/dist/providers/all.js.map +1 -1
- package/dist/providers/amazon-bedrock.models.d.ts +4 -2
- package/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
- package/dist/providers/amazon-bedrock.models.js +4 -2
- package/dist/providers/amazon-bedrock.models.js.map +1 -1
- package/dist/providers/ant-ling.models.d.ts +4 -2
- package/dist/providers/ant-ling.models.d.ts.map +1 -1
- package/dist/providers/ant-ling.models.js +4 -2
- package/dist/providers/ant-ling.models.js.map +1 -1
- package/dist/providers/anthropic.models.d.ts +4 -2
- package/dist/providers/anthropic.models.d.ts.map +1 -1
- package/dist/providers/anthropic.models.js +4 -2
- package/dist/providers/anthropic.models.js.map +1 -1
- package/dist/providers/azure-openai-responses.models.d.ts +4 -2
- package/dist/providers/azure-openai-responses.models.d.ts.map +1 -1
- package/dist/providers/azure-openai-responses.models.js +4 -2
- package/dist/providers/azure-openai-responses.models.js.map +1 -1
- package/dist/providers/baseten.models.d.ts +4 -2
- package/dist/providers/baseten.models.d.ts.map +1 -1
- package/dist/providers/baseten.models.js +4 -2
- package/dist/providers/baseten.models.js.map +1 -1
- package/dist/providers/cerebras.models.d.ts +4 -2
- package/dist/providers/cerebras.models.d.ts.map +1 -1
- package/dist/providers/cerebras.models.js +4 -2
- package/dist/providers/cerebras.models.js.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.models.d.ts +4 -2
- package/dist/providers/cloudflare-ai-gateway.models.d.ts.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.models.js +4 -2
- package/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
- package/dist/providers/cloudflare-stream.d.ts +6 -2
- package/dist/providers/cloudflare-stream.d.ts.map +1 -1
- package/dist/providers/cloudflare-stream.js +6 -0
- package/dist/providers/cloudflare-stream.js.map +1 -1
- package/dist/providers/cloudflare-workers-ai.d.ts.map +1 -1
- package/dist/providers/cloudflare-workers-ai.js +10 -3
- package/dist/providers/cloudflare-workers-ai.js.map +1 -1
- package/dist/providers/cloudflare-workers-ai.models.d.ts +4 -2
- package/dist/providers/cloudflare-workers-ai.models.d.ts.map +1 -1
- package/dist/providers/cloudflare-workers-ai.models.js +4 -2
- package/dist/providers/cloudflare-workers-ai.models.js.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/amazon-bedrock.json +1 -1
- package/dist/providers/data/ant-ling.json +1 -1
- package/dist/providers/data/anthropic.json +1 -1
- package/dist/providers/data/azure-openai-responses.json +1 -1
- package/dist/providers/data/baseten.json +1 -1
- package/dist/providers/data/cerebras.json +1 -1
- package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/dist/providers/data/deepseek.json +1 -1
- package/dist/providers/data/fireworks.json +1 -1
- package/dist/providers/data/github-copilot.json +1 -1
- package/dist/providers/data/google-vertex.json +1 -1
- package/dist/providers/data/google.json +1 -1
- package/dist/providers/data/groq.json +1 -1
- package/dist/providers/data/huggingface.json +1 -1
- package/dist/providers/data/kimi-coding.json +1 -1
- package/dist/providers/data/meta.json +1 -1
- package/dist/providers/data/minimax-cn.json +1 -1
- package/dist/providers/data/minimax.json +1 -1
- package/dist/providers/data/mistral.json +1 -1
- package/dist/providers/data/moonshotai-cn.json +1 -1
- package/dist/providers/data/moonshotai.json +1 -1
- package/dist/providers/data/nvidia.json +1 -1
- package/dist/providers/data/openai-codex.json +1 -1
- package/dist/providers/data/openai.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/qwen-token-plan-cn.json +1 -1
- package/dist/providers/data/qwen-token-plan-individual.json +1 -1
- package/dist/providers/data/qwen-token-plan.json +1 -1
- package/dist/providers/data/radius.json +1 -1
- package/dist/providers/data/together.json +1 -1
- package/dist/providers/data/typesafe.json +1 -0
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/providers/data/xai.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
- package/dist/providers/data/xiaomi.json +1 -1
- package/dist/providers/data/zai-coding-cn.json +1 -1
- package/dist/providers/data/zai.json +1 -1
- package/dist/providers/deepseek.models.d.ts +4 -2
- package/dist/providers/deepseek.models.d.ts.map +1 -1
- package/dist/providers/deepseek.models.js +4 -2
- package/dist/providers/deepseek.models.js.map +1 -1
- package/dist/providers/fireworks.models.d.ts +4 -2
- package/dist/providers/fireworks.models.d.ts.map +1 -1
- package/dist/providers/fireworks.models.js +4 -2
- package/dist/providers/fireworks.models.js.map +1 -1
- package/dist/providers/github-copilot.models.d.ts +4 -2
- package/dist/providers/github-copilot.models.d.ts.map +1 -1
- package/dist/providers/github-copilot.models.js +4 -2
- package/dist/providers/github-copilot.models.js.map +1 -1
- package/dist/providers/google-vertex.models.d.ts +4 -2
- package/dist/providers/google-vertex.models.d.ts.map +1 -1
- package/dist/providers/google-vertex.models.js +4 -2
- package/dist/providers/google-vertex.models.js.map +1 -1
- package/dist/providers/google.models.d.ts +4 -2
- package/dist/providers/google.models.d.ts.map +1 -1
- package/dist/providers/google.models.js +4 -2
- package/dist/providers/google.models.js.map +1 -1
- package/dist/providers/groq.models.d.ts +4 -2
- package/dist/providers/groq.models.d.ts.map +1 -1
- package/dist/providers/groq.models.js +4 -2
- package/dist/providers/groq.models.js.map +1 -1
- package/dist/providers/huggingface.models.d.ts +4 -2
- package/dist/providers/huggingface.models.d.ts.map +1 -1
- package/dist/providers/huggingface.models.js +4 -2
- package/dist/providers/huggingface.models.js.map +1 -1
- package/dist/providers/images/register-builtins.d.ts +1 -1
- package/dist/providers/images/register-builtins.d.ts.map +1 -1
- package/dist/providers/images/register-builtins.js.map +1 -1
- package/dist/providers/kimi-coding.models.d.ts +4 -2
- package/dist/providers/kimi-coding.models.d.ts.map +1 -1
- package/dist/providers/kimi-coding.models.js +4 -2
- package/dist/providers/kimi-coding.models.js.map +1 -1
- package/dist/providers/meta.models.d.ts +4 -2
- package/dist/providers/meta.models.d.ts.map +1 -1
- package/dist/providers/meta.models.js +4 -2
- package/dist/providers/meta.models.js.map +1 -1
- package/dist/providers/minimax-cn.models.d.ts +4 -2
- package/dist/providers/minimax-cn.models.d.ts.map +1 -1
- package/dist/providers/minimax-cn.models.js +4 -2
- package/dist/providers/minimax-cn.models.js.map +1 -1
- package/dist/providers/minimax.models.d.ts +4 -2
- package/dist/providers/minimax.models.d.ts.map +1 -1
- package/dist/providers/minimax.models.js +4 -2
- package/dist/providers/minimax.models.js.map +1 -1
- package/dist/providers/mistral.models.d.ts +4 -2
- package/dist/providers/mistral.models.d.ts.map +1 -1
- package/dist/providers/mistral.models.js +4 -2
- package/dist/providers/mistral.models.js.map +1 -1
- package/dist/providers/moonshotai-cn.models.d.ts +4 -2
- package/dist/providers/moonshotai-cn.models.d.ts.map +1 -1
- package/dist/providers/moonshotai-cn.models.js +4 -2
- package/dist/providers/moonshotai-cn.models.js.map +1 -1
- package/dist/providers/moonshotai.models.d.ts +4 -2
- package/dist/providers/moonshotai.models.d.ts.map +1 -1
- package/dist/providers/moonshotai.models.js +4 -2
- package/dist/providers/moonshotai.models.js.map +1 -1
- package/dist/providers/nvidia.models.d.ts +4 -2
- package/dist/providers/nvidia.models.d.ts.map +1 -1
- package/dist/providers/nvidia.models.js +4 -2
- package/dist/providers/nvidia.models.js.map +1 -1
- package/dist/providers/openai-codex.models.d.ts +4 -2
- package/dist/providers/openai-codex.models.d.ts.map +1 -1
- package/dist/providers/openai-codex.models.js +4 -2
- package/dist/providers/openai-codex.models.js.map +1 -1
- package/dist/providers/openai.models.d.ts +4 -2
- package/dist/providers/openai.models.d.ts.map +1 -1
- package/dist/providers/openai.models.js +4 -2
- package/dist/providers/openai.models.js.map +1 -1
- package/dist/providers/opencode-go.models.d.ts +4 -2
- package/dist/providers/opencode-go.models.d.ts.map +1 -1
- package/dist/providers/opencode-go.models.js +4 -2
- package/dist/providers/opencode-go.models.js.map +1 -1
- package/dist/providers/opencode.models.d.ts +4 -2
- package/dist/providers/opencode.models.d.ts.map +1 -1
- package/dist/providers/opencode.models.js +4 -2
- package/dist/providers/opencode.models.js.map +1 -1
- package/dist/providers/openrouter.d.ts.map +1 -1
- package/dist/providers/openrouter.js +11 -2
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/openrouter.models.d.ts +4 -2
- package/dist/providers/openrouter.models.d.ts.map +1 -1
- package/dist/providers/openrouter.models.js +4 -2
- package/dist/providers/openrouter.models.js.map +1 -1
- package/dist/providers/qwen-token-plan-cn.models.d.ts +4 -2
- package/dist/providers/qwen-token-plan-cn.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-cn.models.js +4 -2
- package/dist/providers/qwen-token-plan-cn.models.js.map +1 -1
- package/dist/providers/qwen-token-plan-individual.models.d.ts +4 -2
- package/dist/providers/qwen-token-plan-individual.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-individual.models.js +4 -2
- package/dist/providers/qwen-token-plan-individual.models.js.map +1 -1
- package/dist/providers/qwen-token-plan.models.d.ts +4 -2
- package/dist/providers/qwen-token-plan.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan.models.js +4 -2
- package/dist/providers/qwen-token-plan.models.js.map +1 -1
- package/dist/providers/radius.models.d.ts +4 -2
- package/dist/providers/radius.models.d.ts.map +1 -1
- package/dist/providers/radius.models.js +4 -2
- package/dist/providers/radius.models.js.map +1 -1
- package/dist/providers/together.models.d.ts +4 -2
- package/dist/providers/together.models.d.ts.map +1 -1
- package/dist/providers/together.models.js +4 -2
- package/dist/providers/together.models.js.map +1 -1
- package/dist/providers/typesafe.d.ts +3 -0
- package/dist/providers/typesafe.d.ts.map +1 -0
- package/dist/providers/typesafe.js +18 -0
- package/dist/providers/typesafe.js.map +1 -0
- package/dist/providers/typesafe.models.d.ts +5 -0
- package/dist/providers/typesafe.models.d.ts.map +1 -0
- package/dist/providers/typesafe.models.js +8 -0
- package/dist/providers/typesafe.models.js.map +1 -0
- package/dist/providers/vercel-ai-gateway.models.d.ts +4 -2
- package/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
- package/dist/providers/vercel-ai-gateway.models.js +4 -2
- package/dist/providers/vercel-ai-gateway.models.js.map +1 -1
- package/dist/providers/xai.models.d.ts +4 -2
- package/dist/providers/xai.models.d.ts.map +1 -1
- package/dist/providers/xai.models.js +4 -2
- package/dist/providers/xai.models.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-ams.models.d.ts +4 -2
- package/dist/providers/xiaomi-token-plan-ams.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-ams.models.js +4 -2
- package/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-cn.models.d.ts +4 -2
- package/dist/providers/xiaomi-token-plan-cn.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-cn.models.js +4 -2
- package/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-sgp.models.d.ts +4 -2
- package/dist/providers/xiaomi-token-plan-sgp.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-sgp.models.js +4 -2
- package/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
- package/dist/providers/xiaomi.models.d.ts +4 -2
- package/dist/providers/xiaomi.models.d.ts.map +1 -1
- package/dist/providers/xiaomi.models.js +4 -2
- package/dist/providers/xiaomi.models.js.map +1 -1
- package/dist/providers/zai-coding-cn.models.d.ts +4 -2
- package/dist/providers/zai-coding-cn.models.d.ts.map +1 -1
- package/dist/providers/zai-coding-cn.models.js +4 -2
- package/dist/providers/zai-coding-cn.models.js.map +1 -1
- package/dist/providers/zai.models.d.ts +4 -2
- package/dist/providers/zai.models.d.ts.map +1 -1
- package/dist/providers/zai.models.js +4 -2
- package/dist/providers/zai.models.js.map +1 -1
- package/dist/types.d.ts +109 -26
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/headers.d.ts +1 -1
- package/dist/utils/headers.d.ts.map +1 -1
- package/dist/utils/headers.js +10 -8
- package/dist/utils/headers.js.map +1 -1
- package/dist/utils/model-operations.d.ts +11 -0
- package/dist/utils/model-operations.d.ts.map +1 -0
- package/dist/utils/model-operations.js +47 -0
- package/dist/utils/model-operations.js.map +1 -0
- package/dist/utils/models-error.d.ts +8 -0
- package/dist/utils/models-error.d.ts.map +1 -0
- package/dist/utils/models-error.js +19 -0
- package/dist/utils/models-error.js.map +1 -0
- package/package.json +1 -2
- package/dist/image-models.generated.d.ts +0 -830
- package/dist/image-models.generated.d.ts.map +0 -1
- package/dist/image-models.generated.js +0 -832
- package/dist/image-models.generated.js.map +0 -1
- package/dist/images-models.d.ts +0 -95
- package/dist/images-models.d.ts.map +0 -1
- package/dist/images-models.js +0 -143
- package/dist/images-models.js.map +0 -1
- package/dist/providers/openrouter-images.d.ts +0 -3
- package/dist/providers/openrouter-images.d.ts.map +0 -1
- package/dist/providers/openrouter-images.js +0 -22
- package/dist/providers/openrouter-images.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-responses.d.ts","sourceRoot":"","sources":["../../src/api/openai-responses.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AAE7F,OAAO,KAAK,EAQX,mBAAmB,EACnB,cAAc,EACd,aAAa,EAGb,MAAM,aAAa,CAAC;AAiGrB,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC5D,eAAe,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;IAC1E,gBAAgB,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,IAAI,CAAC;IAC1D,WAAW,CAAC,EAAE,6BAA6B,CAAC,cAAc,CAAC,CAAC;IAC5D,UAAU,CAAC,EAAE,6BAA6B,CAAC,aAAa,CAAC,CAAC;CAC1D;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,kBAAkB,EAAE,sBAAsB,CAoH7E,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,kBAAkB,EAAE,mBAAmB,CAkBhF,CAAC","sourcesContent":["import OpenAI from \"openai\";\nimport type { ResponseCreateParamsStreaming } from \"openai/resources/responses/responses.js\";\nimport { clampThinkingLevel } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tCacheRetention,\n\tModel,\n\tOpenAIResponsesCompat,\n\tProviderEnv,\n\tProviderHeaders,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tTranscriptContext,\n\tUsage,\n} from \"../types.ts\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.ts\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { headersToRecord } from \"../utils/headers.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\nimport { getProviderEnvValue } from \"../utils/provider-env.ts\";\nimport { retryProviderRequest } from \"../utils/provider-retry.ts\";\nimport { createStreamDeadline, withStreamDeadline } from \"../utils/stream-deadline.ts\";\nimport { getDeclaredTools, resolveTranscript, resolveTranscriptTools } from \"../utils/transcript.ts\";\nimport { createGrammarToolInputProperties } from \"./constrained-sampling.ts\";\nimport {\n\tbuildCopilotDynamicHeaders,\n\thasCopilotVisionInput,\n\tpreserveCopilotIntegrationHeader,\n} from \"./github-copilot-headers.ts\";\nimport { clampOpenAIPromptCacheKey } from \"./openai-prompt-cache.ts\";\nimport {\n\tassertPayloadPreservesFastRoute,\n\tconvertResponsesMessages,\n\tconvertResponsesTools,\n\tprocessResponsesStream,\n\tresolveRequestedServiceTier,\n} from \"./openai-responses-shared.ts\";\nimport { buildBaseOptions } from \"./simple-options.ts\";\n\nconst OPENAI_TOOL_CALL_PROVIDERS = new Set([\"openai\", \"openai-codex\", \"opencode\"]);\n// OpenAI Responses rejects max_output_tokens below 16: https://github.com/earendil-works/pi/issues/6265\nconst OPENAI_RESPONSES_MIN_OUTPUT_TOKENS = 16;\n\nfunction hasHeader(headers: ProviderHeaders | undefined, name: string): boolean {\n\tif (!headers) return false;\n\tconst expected = name.toLowerCase();\n\tfor (const [key, value] of Object.entries(headers)) {\n\t\tif (key.toLowerCase() === expected && value !== null && value.trim().length > 0) return true;\n\t}\n\treturn false;\n}\n\nfunction getClientApiKey(provider: string, apiKey: string | undefined, headers: ProviderHeaders | undefined): string {\n\tif (apiKey) return apiKey;\n\tif (hasHeader(headers, \"authorization\") || hasHeader(headers, \"cf-aig-authorization\")) return \"unused\";\n\tthrow new Error(`No API key for provider: ${provider}`);\n}\n\nfunction detectSessionAffinityFormat(model: Pick<Model<\"openai-responses\">, \"provider\" | \"baseUrl\">) {\n\treturn model.provider === \"openrouter\" || model.baseUrl.includes(\"openrouter.ai\") ? \"openrouter\" : \"openai\";\n}\n\n/**\n * Resolve cache retention preference.\n * Defaults to \"short\" and uses PI_CACHE_RETENTION for backward compatibility.\n */\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\nfunction getCompat(model: Model<\"openai-responses\">): Required<OpenAIResponsesCompat> {\n\treturn {\n\t\tsupportsDeveloperRole: model.compat?.supportsDeveloperRole ?? true,\n\t\tsupportsMidConvoSystemMessages: model.compat?.supportsMidConvoSystemMessages ?? false,\n\t\tsessionAffinityFormat: model.compat?.sessionAffinityFormat ?? detectSessionAffinityFormat(model),\n\t\tsupportsLongCacheRetention: model.compat?.supportsLongCacheRetention ?? true,\n\t\tsupportsStrictMode: model.compat?.supportsStrictMode ?? false,\n\t\tsupportsOpenAIGrammarTools: model.compat?.supportsOpenAIGrammarTools ?? false,\n\t\tsupportsAdditionalTools: model.compat?.supportsAdditionalTools ?? false,\n\t\tsupportsToolSearch: model.compat?.supportsToolSearch ?? false,\n\t\tsupportsExplicitPromptCacheMode: model.compat?.supportsExplicitPromptCacheMode ?? false,\n\t\tsupportsMaxOutputTokens: model.compat?.supportsMaxOutputTokens ?? true,\n\t};\n}\n\nfunction getPromptCacheRetention(\n\tcompat: Required<OpenAIResponsesCompat>,\n\tcacheRetention: CacheRetention,\n): \"24h\" | undefined {\n\treturn cacheRetention === \"long\" && compat.supportsLongCacheRetention && !compat.supportsExplicitPromptCacheMode\n\t\t? \"24h\"\n\t\t: undefined;\n}\n\nfunction getPromptCacheOptions(\n\tcompat: Required<OpenAIResponsesCompat>,\n\tcacheRetention: CacheRetention,\n): { mode?: \"explicit\"; ttl?: \"30m\" } | undefined {\n\tif (!compat.supportsExplicitPromptCacheMode) return undefined;\n\tif (cacheRetention === \"none\") return { mode: \"explicit\" };\n\tif (cacheRetention === \"long\" && compat.supportsLongCacheRetention) return { ttl: \"30m\" };\n\treturn undefined;\n}\n\n// OpenAI Responses-specific options\nexport interface OpenAIResponsesOptions extends StreamOptions {\n\treasoningEffort?: \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\treasoningSummary?: \"auto\" | \"detailed\" | \"concise\" | null;\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\ttoolChoice?: ResponseCreateParamsStreaming[\"tool_choice\"];\n}\n\n/**\n * Generate function for OpenAI Responses API\n */\nexport const stream: StreamFunction<\"openai-responses\", OpenAIResponsesOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions?: OpenAIResponsesOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\tconst normalizedContext = resolveTranscript(context, getCompat(model).supportsMidConvoSystemMessages);\n\n\t// Start async processing\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"pending\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tconst streamDeadline = createStreamDeadline(options?.streamDeadlineMs, options?.signal);\n\n\t\ttry {\n\t\t\t// Create OpenAI client\n\t\t\tconst apiKey = getClientApiKey(model.provider, options?.apiKey, options?.headers);\n\t\t\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\t\t\tconst cacheSessionId = cacheRetention === \"none\" ? undefined : options?.sessionId;\n\t\t\tconst compat = getCompat(model);\n\t\t\tconst grammarToolInputProperties = createGrammarToolInputProperties(\n\t\t\t\tgetDeclaredTools(normalizedContext.messages),\n\t\t\t\tcompat.supportsOpenAIGrammarTools,\n\t\t\t);\n\t\t\tconst client = createClient(\n\t\t\t\tmodel,\n\t\t\t\tnormalizedContext,\n\t\t\t\tapiKey,\n\t\t\t\toptions?.headers,\n\t\t\t\toptions?.fetch,\n\t\t\t\tcacheSessionId,\n\t\t\t\toptions?.apiKey,\n\t\t\t);\n\t\t\tlet params = buildParams(model, normalizedContext, options, compat, grammarToolInputProperties);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as ResponseCreateParamsStreaming;\n\t\t\t}\n\t\t\tassertPayloadPreservesFastRoute(model, params);\n\t\t\tconst requestOptions = {\n\t\t\t\t...(streamDeadline.signal ? { signal: streamDeadline.signal } : {}),\n\t\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\t\tmaxRetries: 0,\n\t\t\t};\n\t\t\tconst { data: openaiStream, response } = await retryProviderRequest(\n\t\t\t\t() => client.responses.create(params, requestOptions).withResponse(),\n\t\t\t\t{\n\t\t\t\t\tmaxRetries: options?.maxRetries,\n\t\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\t\t\t\tsignal: streamDeadline.signal,\n\t\t\t\t},\n\t\t\t);\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\tawait processResponsesStream(\n\t\t\t\twithStreamDeadline(openaiStream, streamDeadline.deadlineMs, streamDeadline.abort),\n\t\t\t\toutput,\n\t\t\t\tstream,\n\t\t\t\tmodel,\n\t\t\t\t{\n\t\t\t\t\tserviceTier: resolveRequestedServiceTier(model, options?.serviceTier),\n\t\t\t\t\tgrammarToolInputProperties,\n\t\t\t\t\tapplyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"pending\") {\n\t\t\t\tthrow new Error(\"OpenAI Responses stream ended without a stop reason\");\n\t\t\t}\n\t\t\tif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(output.errorMessage || \"An unknown error occurred\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t// Streaming scratch buffers are only used during parsing; never persist them.\n\t\t\t\tdelete (block as { partialJson?: string }).partialJson;\n\t\t\t\tdelete (block as { customInput?: unknown }).customInput;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = formatProviderError(\n\t\t\t\tnormalizeProviderError(error),\n\t\t\t\t`${model.provider === \"openai\" ? \"OpenAI\" : model.provider} API error`,\n\t\t\t);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tstreamDeadline.cleanup();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimple: StreamFunction<\"openai-responses\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tgetClientApiKey(model.provider, options?.apiKey, options?.headers);\n\n\tconst base = {\n\t\t...buildBaseOptions(model, context, options, options?.apiKey),\n\t\ttoolChoice: options?.toolChoice,\n\t} satisfies OpenAIResponsesOptions;\n\tconst clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;\n\tconst reasoningEffort = clampedReasoning === \"off\" ? undefined : clampedReasoning;\n\n\treturn stream(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t} satisfies OpenAIResponsesOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\tapiKey: string,\n\toptionsHeaders?: ProviderHeaders,\n\tfetch?: typeof globalThis.fetch,\n\tsessionId?: string,\n\tcopilotApiKey?: string,\n) {\n\tconst compat = getCompat(model);\n\tconst headers: ProviderHeaders = { \"User-Agent\": getPiUserAgent(), ...model.headers };\n\tif (model.provider === \"github-copilot\") {\n\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\tconst copilotHeaders = preserveCopilotIntegrationHeader(\n\t\t\tmodel.headers,\n\t\t\tbuildCopilotDynamicHeaders({\n\t\t\t\tmessages: context.messages,\n\t\t\t\thasImages,\n\t\t\t\tapiKey: copilotApiKey,\n\t\t\t}),\n\t\t);\n\t\tObject.assign(headers, copilotHeaders);\n\t}\n\n\tif (sessionId) {\n\t\tif (compat.sessionAffinityFormat === \"openrouter\") {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t} else {\n\t\t\tif (compat.sessionAffinityFormat === \"openai\") {\n\t\t\t\theaders.session_id = sessionId;\n\t\t\t}\n\t\t\theaders[\"x-client-request-id\"] = sessionId;\n\t\t}\n\t}\n\n\t// Merge options headers last so they can override defaults\n\tif (optionsHeaders) {\n\t\tObject.assign(headers, optionsHeaders);\n\t}\n\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tfetch,\n\t\tdefaultHeaders: headers,\n\t});\n}\n\nfunction buildParams(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions: OpenAIResponsesOptions | undefined,\n\tcompat: Required<OpenAIResponsesCompat> = getCompat(model),\n\tgrammarToolInputProperties: ReadonlyMap<string, string> = createGrammarToolInputProperties(\n\t\tgetDeclaredTools(context.messages),\n\t\tcompat.supportsOpenAIGrammarTools,\n\t),\n) {\n\tconst transcriptTools = resolveTranscriptTools(\n\t\tcontext.messages,\n\t\tcompat.supportsAdditionalTools || compat.supportsToolSearch,\n\t);\n\tconst messages = convertResponsesMessages(model, context, OPENAI_TOOL_CALL_PROVIDERS, {\n\t\tgrammarToolInputProperties,\n\t\tsupportsMidConvoSystemMessages: compat.supportsMidConvoSystemMessages,\n\t\tsupportsAdditionalTools: compat.supportsAdditionalTools,\n\t\tsupportsToolSearch: compat.supportsToolSearch,\n\t\ttoolOptions: {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t},\n\t});\n\n\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\tconst params: ResponseCreateParamsStreaming & {\n\t\tprompt_cache_options?: { mode?: \"explicit\"; ttl?: \"30m\" };\n\t} = {\n\t\t// A fast variant keeps its canonical `-fast` id on the model object — that is the identity the\n\t\t// caller selected and records — while routing to the base upstream model plus a service tier.\n\t\tmodel: model.fastRoute?.upstreamModelId ?? model.id,\n\t\tinput: messages,\n\t\tstream: true,\n\t\tprompt_cache_key: cacheRetention === \"none\" ? undefined : clampOpenAIPromptCacheKey(options?.sessionId),\n\t\tprompt_cache_retention: getPromptCacheRetention(compat, cacheRetention),\n\t\tprompt_cache_options: getPromptCacheOptions(compat, cacheRetention),\n\t\tstore: false,\n\t};\n\n\tif (options?.maxTokens && compat.supportsMaxOutputTokens) {\n\t\tparams.max_output_tokens = Math.max(options.maxTokens, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS);\n\t}\n\n\tif (options?.temperature !== undefined) {\n\t\tparams.temperature = options?.temperature;\n\t}\n\n\t// A fast variant carries its own tier, so a caller that only hands over the model still routes fast.\n\tconst requestedServiceTier = resolveRequestedServiceTier(model, options?.serviceTier);\n\tif (requestedServiceTier !== undefined) {\n\t\tparams.service_tier = requestedServiceTier;\n\t}\n\n\tif (transcriptTools.requestTools.length > 0) {\n\t\tparams.tools = convertResponsesTools(transcriptTools.requestTools, {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t});\n\t}\n\n\tif (options?.toolChoice !== undefined) {\n\t\tparams.tool_choice = options.toolChoice;\n\t}\n\n\tif (model.reasoning) {\n\t\tif (options?.reasoningEffort || options?.reasoningSummary) {\n\t\t\tconst effort = options?.reasoningEffort\n\t\t\t\t? (model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort)\n\t\t\t\t: \"medium\";\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: effort as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t\tsummary: options?.reasoningSummary || \"auto\",\n\t\t\t};\n\t\t\tparams.include = [\"reasoning.encrypted_content\"];\n\t\t} else if (model.provider !== \"github-copilot\" && model.thinkingLevelMap?.off !== null) {\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: (model.thinkingLevelMap?.off ?? \"none\") as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t};\n\t\t}\n\t\tif (model.provider === \"xai\") params.include = [\"reasoning.encrypted_content\"];\n\t}\n\n\t// Last so custom keys override the named request fields.\n\tif (options?.samplingParams) {\n\t\tObject.assign(params, options.samplingParams);\n\t}\n\n\treturn params;\n}\n\nfunction getServiceTierCostMultiplier(\n\tmodel: Pick<Model<\"openai-responses\">, \"fastRoute\" | \"id\">,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n): number {\n\t// Price against the model that was actually billed upstream, so a `-fast` variant of a\n\t// per-model rate (gpt-5.5) is not silently charged the generic multiplier.\n\tconst pricedModelId = model.fastRoute?.baseModelId ?? model.id;\n\tswitch (serviceTier) {\n\t\tcase \"flex\":\n\t\t\treturn 0.5;\n\t\tcase \"priority\":\n\t\t\treturn pricedModelId === \"gpt-5.5\" ? 2.5 : 2;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nfunction applyServiceTierPricing(\n\tusage: Usage,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\tmodel: Pick<Model<\"openai-responses\">, \"fastRoute\" | \"id\">,\n) {\n\tconst multiplier = getServiceTierCostMultiplier(model, serviceTier);\n\tif (multiplier === 1) return;\n\n\tusage.cost.input *= multiplier;\n\tusage.cost.output *= multiplier;\n\tusage.cost.cacheRead *= multiplier;\n\tusage.cost.cacheWrite *= multiplier;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"openai-responses.d.ts","sourceRoot":"","sources":["../../src/api/openai-responses.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AAE7F,OAAO,KAAK,EAQX,mBAAmB,EACnB,cAAc,EACd,aAAa,EAGb,MAAM,aAAa,CAAC;AAiGrB,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC5D,eAAe,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;IAC1E,gBAAgB,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,IAAI,CAAC;IAC1D,WAAW,CAAC,EAAE,6BAA6B,CAAC,cAAc,CAAC,CAAC;IAC5D,UAAU,CAAC,EAAE,6BAA6B,CAAC,aAAa,CAAC,CAAC;CAC1D;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,kBAAkB,EAAE,sBAAsB,CAqH7E,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,kBAAkB,EAAE,mBAAmB,CAkBhF,CAAC","sourcesContent":["import OpenAI from \"openai\";\nimport type { ResponseCreateParamsStreaming } from \"openai/resources/responses/responses.js\";\nimport { clampThinkingLevel } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tCacheRetention,\n\tModel,\n\tOpenAIResponsesCompat,\n\tProviderEnv,\n\tProviderHeaders,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tTranscriptContext,\n\tUsage,\n} from \"../types.ts\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.ts\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { headersToRecord } from \"../utils/headers.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\nimport { getProviderEnvValue } from \"../utils/provider-env.ts\";\nimport { retryProviderRequest } from \"../utils/provider-retry.ts\";\nimport { createStreamDeadline, withStreamDeadline } from \"../utils/stream-deadline.ts\";\nimport { getDeclaredTools, resolveTranscript, resolveTranscriptTools } from \"../utils/transcript.ts\";\nimport { createGrammarToolInputProperties } from \"./constrained-sampling.ts\";\nimport {\n\tbuildCopilotDynamicHeaders,\n\thasCopilotVisionInput,\n\tpreserveCopilotIntegrationHeader,\n} from \"./github-copilot-headers.ts\";\nimport { clampOpenAIPromptCacheKey } from \"./openai-prompt-cache.ts\";\nimport {\n\tassertPayloadPreservesFastRoute,\n\tconvertResponsesMessages,\n\tconvertResponsesTools,\n\tprocessResponsesStream,\n\tresolveRequestedServiceTier,\n} from \"./openai-responses-shared.ts\";\nimport { buildBaseOptions } from \"./simple-options.ts\";\n\nconst OPENAI_TOOL_CALL_PROVIDERS = new Set([\"openai\", \"openai-codex\", \"opencode\"]);\n// OpenAI Responses rejects max_output_tokens below 16: https://github.com/earendil-works/pi/issues/6265\nconst OPENAI_RESPONSES_MIN_OUTPUT_TOKENS = 16;\n\nfunction hasHeader(headers: ProviderHeaders | undefined, name: string): boolean {\n\tif (!headers) return false;\n\tconst expected = name.toLowerCase();\n\tfor (const [key, value] of Object.entries(headers)) {\n\t\tif (key.toLowerCase() === expected && value !== null && value.trim().length > 0) return true;\n\t}\n\treturn false;\n}\n\nfunction getClientApiKey(provider: string, apiKey: string | undefined, headers: ProviderHeaders | undefined): string {\n\tif (apiKey) return apiKey;\n\tif (hasHeader(headers, \"authorization\") || hasHeader(headers, \"cf-aig-authorization\")) return \"unused\";\n\tthrow new Error(`No API key for provider: ${provider}`);\n}\n\nfunction detectSessionAffinityFormat(model: Pick<Model<\"openai-responses\">, \"provider\" | \"baseUrl\">) {\n\treturn model.provider === \"openrouter\" || model.baseUrl.includes(\"openrouter.ai\") ? \"openrouter\" : \"openai\";\n}\n\n/**\n * Resolve cache retention preference.\n * Defaults to \"short\" and uses PI_CACHE_RETENTION for backward compatibility.\n */\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\nfunction getCompat(model: Model<\"openai-responses\">): Required<OpenAIResponsesCompat> {\n\treturn {\n\t\tsupportsDeveloperRole: model.compat?.supportsDeveloperRole ?? true,\n\t\tsupportsMidConvoSystemMessages: model.compat?.supportsMidConvoSystemMessages ?? false,\n\t\tsessionAffinityFormat: model.compat?.sessionAffinityFormat ?? detectSessionAffinityFormat(model),\n\t\tsupportsLongCacheRetention: model.compat?.supportsLongCacheRetention ?? true,\n\t\tsupportsStrictMode: model.compat?.supportsStrictMode ?? false,\n\t\tsupportsOpenAIGrammarTools: model.compat?.supportsOpenAIGrammarTools ?? false,\n\t\tsupportsAdditionalTools: model.compat?.supportsAdditionalTools ?? false,\n\t\tsupportsToolSearch: model.compat?.supportsToolSearch ?? false,\n\t\tsupportsExplicitPromptCacheMode: model.compat?.supportsExplicitPromptCacheMode ?? false,\n\t\tsupportsMaxOutputTokens: model.compat?.supportsMaxOutputTokens ?? true,\n\t};\n}\n\nfunction getPromptCacheRetention(\n\tcompat: Required<OpenAIResponsesCompat>,\n\tcacheRetention: CacheRetention,\n): \"24h\" | undefined {\n\treturn cacheRetention === \"long\" && compat.supportsLongCacheRetention && !compat.supportsExplicitPromptCacheMode\n\t\t? \"24h\"\n\t\t: undefined;\n}\n\nfunction getPromptCacheOptions(\n\tcompat: Required<OpenAIResponsesCompat>,\n\tcacheRetention: CacheRetention,\n): { mode?: \"explicit\"; ttl?: \"30m\" } | undefined {\n\tif (!compat.supportsExplicitPromptCacheMode) return undefined;\n\tif (cacheRetention === \"none\") return { mode: \"explicit\" };\n\tif (cacheRetention === \"long\" && compat.supportsLongCacheRetention) return { ttl: \"30m\" };\n\treturn undefined;\n}\n\n// OpenAI Responses-specific options\nexport interface OpenAIResponsesOptions extends StreamOptions {\n\treasoningEffort?: \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\treasoningSummary?: \"auto\" | \"detailed\" | \"concise\" | null;\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\ttoolChoice?: ResponseCreateParamsStreaming[\"tool_choice\"];\n}\n\n/**\n * Generate function for OpenAI Responses API\n */\nexport const stream: StreamFunction<\"openai-responses\", OpenAIResponsesOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions?: OpenAIResponsesOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\tconst normalizedContext = resolveTranscript(context, getCompat(model).supportsMidConvoSystemMessages);\n\n\t// Start async processing\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"pending\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tconst streamDeadline = createStreamDeadline(options?.streamDeadlineMs, options?.signal);\n\n\t\ttry {\n\t\t\t// Create OpenAI client\n\t\t\tconst apiKey = getClientApiKey(model.provider, options?.apiKey, options?.headers);\n\t\t\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\t\t\tconst cacheSessionId = cacheRetention === \"none\" ? undefined : options?.sessionId;\n\t\t\tconst compat = getCompat(model);\n\t\t\tconst grammarToolInputProperties = createGrammarToolInputProperties(\n\t\t\t\tgetDeclaredTools(normalizedContext.messages),\n\t\t\t\tcompat.supportsOpenAIGrammarTools,\n\t\t\t);\n\t\t\tconst client = createClient(\n\t\t\t\tmodel,\n\t\t\t\tnormalizedContext,\n\t\t\t\tapiKey,\n\t\t\t\toptions?.headers,\n\t\t\t\toptions?.fetch,\n\t\t\t\tcacheSessionId,\n\t\t\t\toptions?.apiKey,\n\t\t\t);\n\t\t\tlet params = buildParams(model, normalizedContext, options, compat, grammarToolInputProperties);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as ResponseCreateParamsStreaming;\n\t\t\t}\n\t\t\tassertPayloadPreservesFastRoute(model, params);\n\t\t\tconst requestOptions = {\n\t\t\t\t...(streamDeadline.signal ? { signal: streamDeadline.signal } : {}),\n\t\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\t\tmaxRetries: 0,\n\t\t\t};\n\t\t\tconst { data: openaiStream, response } = await retryProviderRequest(\n\t\t\t\t() => client.responses.create(params, requestOptions).withResponse(),\n\t\t\t\t{\n\t\t\t\t\tmaxRetries: options?.maxRetries,\n\t\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\t\t\t\tsignal: streamDeadline.signal,\n\t\t\t\t},\n\t\t\t);\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\tawait processResponsesStream(\n\t\t\t\twithStreamDeadline(openaiStream, streamDeadline.deadlineMs, streamDeadline.abort),\n\t\t\t\toutput,\n\t\t\t\tstream,\n\t\t\t\tmodel,\n\t\t\t\t{\n\t\t\t\t\tonProviderStreamEvent: options?.onProviderStreamEvent,\n\t\t\t\t\tserviceTier: resolveRequestedServiceTier(model, options?.serviceTier),\n\t\t\t\t\tgrammarToolInputProperties,\n\t\t\t\t\tapplyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"pending\") {\n\t\t\t\tthrow new Error(\"OpenAI Responses stream ended without a stop reason\");\n\t\t\t}\n\t\t\tif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(output.errorMessage || \"An unknown error occurred\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t// Streaming scratch buffers are only used during parsing; never persist them.\n\t\t\t\tdelete (block as { partialJson?: string }).partialJson;\n\t\t\t\tdelete (block as { customInput?: unknown }).customInput;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = formatProviderError(\n\t\t\t\tnormalizeProviderError(error),\n\t\t\t\t`${model.provider === \"openai\" ? \"OpenAI\" : model.provider} API error`,\n\t\t\t);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tstreamDeadline.cleanup();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimple: StreamFunction<\"openai-responses\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tgetClientApiKey(model.provider, options?.apiKey, options?.headers);\n\n\tconst base = {\n\t\t...buildBaseOptions(model, context, options, options?.apiKey),\n\t\ttoolChoice: options?.toolChoice,\n\t} satisfies OpenAIResponsesOptions;\n\tconst clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;\n\tconst reasoningEffort = clampedReasoning === \"off\" ? undefined : clampedReasoning;\n\n\treturn stream(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t} satisfies OpenAIResponsesOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\tapiKey: string,\n\toptionsHeaders?: ProviderHeaders,\n\tfetch?: typeof globalThis.fetch,\n\tsessionId?: string,\n\tcopilotApiKey?: string,\n) {\n\tconst compat = getCompat(model);\n\tconst headers: ProviderHeaders = { \"User-Agent\": getPiUserAgent(), ...model.headers };\n\tif (model.provider === \"github-copilot\") {\n\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\tconst copilotHeaders = preserveCopilotIntegrationHeader(\n\t\t\tmodel.headers,\n\t\t\tbuildCopilotDynamicHeaders({\n\t\t\t\tmessages: context.messages,\n\t\t\t\thasImages,\n\t\t\t\tapiKey: copilotApiKey,\n\t\t\t}),\n\t\t);\n\t\tObject.assign(headers, copilotHeaders);\n\t}\n\n\tif (sessionId) {\n\t\tif (compat.sessionAffinityFormat === \"openrouter\") {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t} else {\n\t\t\tif (compat.sessionAffinityFormat === \"openai\") {\n\t\t\t\theaders.session_id = sessionId;\n\t\t\t}\n\t\t\theaders[\"x-client-request-id\"] = sessionId;\n\t\t}\n\t}\n\n\t// Merge options headers last so they can override defaults\n\tif (optionsHeaders) {\n\t\tObject.assign(headers, optionsHeaders);\n\t}\n\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tfetch,\n\t\tdefaultHeaders: headers,\n\t});\n}\n\nfunction buildParams(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions: OpenAIResponsesOptions | undefined,\n\tcompat: Required<OpenAIResponsesCompat> = getCompat(model),\n\tgrammarToolInputProperties: ReadonlyMap<string, string> = createGrammarToolInputProperties(\n\t\tgetDeclaredTools(context.messages),\n\t\tcompat.supportsOpenAIGrammarTools,\n\t),\n) {\n\tconst transcriptTools = resolveTranscriptTools(\n\t\tcontext.messages,\n\t\tcompat.supportsAdditionalTools || compat.supportsToolSearch,\n\t);\n\tconst messages = convertResponsesMessages(model, context, OPENAI_TOOL_CALL_PROVIDERS, {\n\t\tgrammarToolInputProperties,\n\t\tsupportsMidConvoSystemMessages: compat.supportsMidConvoSystemMessages,\n\t\tsupportsAdditionalTools: compat.supportsAdditionalTools,\n\t\tsupportsToolSearch: compat.supportsToolSearch,\n\t\ttoolOptions: {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t},\n\t});\n\n\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\tconst params: ResponseCreateParamsStreaming & {\n\t\tprompt_cache_options?: { mode?: \"explicit\"; ttl?: \"30m\" };\n\t} = {\n\t\t// A fast variant keeps its canonical `-fast` id on the model object — that is the identity the\n\t\t// caller selected and records — while routing to the base upstream model plus a service tier.\n\t\tmodel: model.fastRoute?.upstreamModelId ?? model.id,\n\t\tinput: messages,\n\t\tstream: true,\n\t\tprompt_cache_key: cacheRetention === \"none\" ? undefined : clampOpenAIPromptCacheKey(options?.sessionId),\n\t\tprompt_cache_retention: getPromptCacheRetention(compat, cacheRetention),\n\t\tprompt_cache_options: getPromptCacheOptions(compat, cacheRetention),\n\t\tstore: false,\n\t};\n\n\tif (options?.maxTokens && compat.supportsMaxOutputTokens) {\n\t\tparams.max_output_tokens = Math.max(options.maxTokens, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS);\n\t}\n\n\tif (options?.temperature !== undefined) {\n\t\tparams.temperature = options?.temperature;\n\t}\n\n\t// A fast variant carries its own tier, so a caller that only hands over the model still routes fast.\n\tconst requestedServiceTier = resolveRequestedServiceTier(model, options?.serviceTier);\n\tif (requestedServiceTier !== undefined) {\n\t\tparams.service_tier = requestedServiceTier;\n\t}\n\n\tif (transcriptTools.requestTools.length > 0) {\n\t\tparams.tools = convertResponsesTools(transcriptTools.requestTools, {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t});\n\t}\n\n\tif (options?.toolChoice !== undefined) {\n\t\tparams.tool_choice = options.toolChoice;\n\t}\n\n\tif (model.reasoning) {\n\t\tif (options?.reasoningEffort || options?.reasoningSummary) {\n\t\t\tconst effort = options?.reasoningEffort\n\t\t\t\t? (model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort)\n\t\t\t\t: \"medium\";\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: effort as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t\tsummary: options?.reasoningSummary || \"auto\",\n\t\t\t};\n\t\t\tparams.include = [\"reasoning.encrypted_content\"];\n\t\t} else if (model.provider !== \"github-copilot\" && model.thinkingLevelMap?.off !== null) {\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: (model.thinkingLevelMap?.off ?? \"none\") as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t};\n\t\t}\n\t\tif (model.provider === \"xai\") params.include = [\"reasoning.encrypted_content\"];\n\t}\n\n\t// Last so custom keys override the named request fields.\n\tif (options?.samplingParams) {\n\t\tObject.assign(params, options.samplingParams);\n\t}\n\n\treturn params;\n}\n\nfunction getServiceTierCostMultiplier(\n\tmodel: Pick<Model<\"openai-responses\">, \"fastRoute\" | \"id\">,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n): number {\n\t// Price against the model that was actually billed upstream, so a `-fast` variant of a\n\t// per-model rate (gpt-5.5) is not silently charged the generic multiplier.\n\tconst pricedModelId = model.fastRoute?.baseModelId ?? model.id;\n\tswitch (serviceTier) {\n\t\tcase \"flex\":\n\t\t\treturn 0.5;\n\t\tcase \"priority\":\n\t\t\treturn pricedModelId === \"gpt-5.5\" ? 2.5 : 2;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nfunction applyServiceTierPricing(\n\tusage: Usage,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\tmodel: Pick<Model<\"openai-responses\">, \"fastRoute\" | \"id\">,\n) {\n\tconst multiplier = getServiceTierCostMultiplier(model, serviceTier);\n\tif (multiplier === 1) return;\n\n\tusage.cost.input *= multiplier;\n\tusage.cost.output *= multiplier;\n\tusage.cost.cacheRead *= multiplier;\n\tusage.cost.cacheWrite *= multiplier;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n}\n"]}
|
|
@@ -130,6 +130,7 @@ export const stream = (model, context, options) => {
|
|
|
130
130
|
await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);
|
|
131
131
|
stream.push({ type: "start", partial: output });
|
|
132
132
|
await processResponsesStream(withStreamDeadline(openaiStream, streamDeadline.deadlineMs, streamDeadline.abort), output, stream, model, {
|
|
133
|
+
onProviderStreamEvent: options?.onProviderStreamEvent,
|
|
133
134
|
serviceTier: resolveRequestedServiceTier(model, options?.serviceTier),
|
|
134
135
|
grammarToolInputProperties,
|
|
135
136
|
applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-responses.js","sourceRoot":"","sources":["../../src/api/openai-responses.ts"],"names":[],"mappings":"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","sourcesContent":["import OpenAI from \"openai\";\nimport type { ResponseCreateParamsStreaming } from \"openai/resources/responses/responses.js\";\nimport { clampThinkingLevel } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tCacheRetention,\n\tModel,\n\tOpenAIResponsesCompat,\n\tProviderEnv,\n\tProviderHeaders,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tTranscriptContext,\n\tUsage,\n} from \"../types.ts\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.ts\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { headersToRecord } from \"../utils/headers.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\nimport { getProviderEnvValue } from \"../utils/provider-env.ts\";\nimport { retryProviderRequest } from \"../utils/provider-retry.ts\";\nimport { createStreamDeadline, withStreamDeadline } from \"../utils/stream-deadline.ts\";\nimport { getDeclaredTools, resolveTranscript, resolveTranscriptTools } from \"../utils/transcript.ts\";\nimport { createGrammarToolInputProperties } from \"./constrained-sampling.ts\";\nimport {\n\tbuildCopilotDynamicHeaders,\n\thasCopilotVisionInput,\n\tpreserveCopilotIntegrationHeader,\n} from \"./github-copilot-headers.ts\";\nimport { clampOpenAIPromptCacheKey } from \"./openai-prompt-cache.ts\";\nimport {\n\tassertPayloadPreservesFastRoute,\n\tconvertResponsesMessages,\n\tconvertResponsesTools,\n\tprocessResponsesStream,\n\tresolveRequestedServiceTier,\n} from \"./openai-responses-shared.ts\";\nimport { buildBaseOptions } from \"./simple-options.ts\";\n\nconst OPENAI_TOOL_CALL_PROVIDERS = new Set([\"openai\", \"openai-codex\", \"opencode\"]);\n// OpenAI Responses rejects max_output_tokens below 16: https://github.com/earendil-works/pi/issues/6265\nconst OPENAI_RESPONSES_MIN_OUTPUT_TOKENS = 16;\n\nfunction hasHeader(headers: ProviderHeaders | undefined, name: string): boolean {\n\tif (!headers) return false;\n\tconst expected = name.toLowerCase();\n\tfor (const [key, value] of Object.entries(headers)) {\n\t\tif (key.toLowerCase() === expected && value !== null && value.trim().length > 0) return true;\n\t}\n\treturn false;\n}\n\nfunction getClientApiKey(provider: string, apiKey: string | undefined, headers: ProviderHeaders | undefined): string {\n\tif (apiKey) return apiKey;\n\tif (hasHeader(headers, \"authorization\") || hasHeader(headers, \"cf-aig-authorization\")) return \"unused\";\n\tthrow new Error(`No API key for provider: ${provider}`);\n}\n\nfunction detectSessionAffinityFormat(model: Pick<Model<\"openai-responses\">, \"provider\" | \"baseUrl\">) {\n\treturn model.provider === \"openrouter\" || model.baseUrl.includes(\"openrouter.ai\") ? \"openrouter\" : \"openai\";\n}\n\n/**\n * Resolve cache retention preference.\n * Defaults to \"short\" and uses PI_CACHE_RETENTION for backward compatibility.\n */\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\nfunction getCompat(model: Model<\"openai-responses\">): Required<OpenAIResponsesCompat> {\n\treturn {\n\t\tsupportsDeveloperRole: model.compat?.supportsDeveloperRole ?? true,\n\t\tsupportsMidConvoSystemMessages: model.compat?.supportsMidConvoSystemMessages ?? false,\n\t\tsessionAffinityFormat: model.compat?.sessionAffinityFormat ?? detectSessionAffinityFormat(model),\n\t\tsupportsLongCacheRetention: model.compat?.supportsLongCacheRetention ?? true,\n\t\tsupportsStrictMode: model.compat?.supportsStrictMode ?? false,\n\t\tsupportsOpenAIGrammarTools: model.compat?.supportsOpenAIGrammarTools ?? false,\n\t\tsupportsAdditionalTools: model.compat?.supportsAdditionalTools ?? false,\n\t\tsupportsToolSearch: model.compat?.supportsToolSearch ?? false,\n\t\tsupportsExplicitPromptCacheMode: model.compat?.supportsExplicitPromptCacheMode ?? false,\n\t\tsupportsMaxOutputTokens: model.compat?.supportsMaxOutputTokens ?? true,\n\t};\n}\n\nfunction getPromptCacheRetention(\n\tcompat: Required<OpenAIResponsesCompat>,\n\tcacheRetention: CacheRetention,\n): \"24h\" | undefined {\n\treturn cacheRetention === \"long\" && compat.supportsLongCacheRetention && !compat.supportsExplicitPromptCacheMode\n\t\t? \"24h\"\n\t\t: undefined;\n}\n\nfunction getPromptCacheOptions(\n\tcompat: Required<OpenAIResponsesCompat>,\n\tcacheRetention: CacheRetention,\n): { mode?: \"explicit\"; ttl?: \"30m\" } | undefined {\n\tif (!compat.supportsExplicitPromptCacheMode) return undefined;\n\tif (cacheRetention === \"none\") return { mode: \"explicit\" };\n\tif (cacheRetention === \"long\" && compat.supportsLongCacheRetention) return { ttl: \"30m\" };\n\treturn undefined;\n}\n\n// OpenAI Responses-specific options\nexport interface OpenAIResponsesOptions extends StreamOptions {\n\treasoningEffort?: \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\treasoningSummary?: \"auto\" | \"detailed\" | \"concise\" | null;\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\ttoolChoice?: ResponseCreateParamsStreaming[\"tool_choice\"];\n}\n\n/**\n * Generate function for OpenAI Responses API\n */\nexport const stream: StreamFunction<\"openai-responses\", OpenAIResponsesOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions?: OpenAIResponsesOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\tconst normalizedContext = resolveTranscript(context, getCompat(model).supportsMidConvoSystemMessages);\n\n\t// Start async processing\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"pending\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tconst streamDeadline = createStreamDeadline(options?.streamDeadlineMs, options?.signal);\n\n\t\ttry {\n\t\t\t// Create OpenAI client\n\t\t\tconst apiKey = getClientApiKey(model.provider, options?.apiKey, options?.headers);\n\t\t\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\t\t\tconst cacheSessionId = cacheRetention === \"none\" ? undefined : options?.sessionId;\n\t\t\tconst compat = getCompat(model);\n\t\t\tconst grammarToolInputProperties = createGrammarToolInputProperties(\n\t\t\t\tgetDeclaredTools(normalizedContext.messages),\n\t\t\t\tcompat.supportsOpenAIGrammarTools,\n\t\t\t);\n\t\t\tconst client = createClient(\n\t\t\t\tmodel,\n\t\t\t\tnormalizedContext,\n\t\t\t\tapiKey,\n\t\t\t\toptions?.headers,\n\t\t\t\toptions?.fetch,\n\t\t\t\tcacheSessionId,\n\t\t\t\toptions?.apiKey,\n\t\t\t);\n\t\t\tlet params = buildParams(model, normalizedContext, options, compat, grammarToolInputProperties);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as ResponseCreateParamsStreaming;\n\t\t\t}\n\t\t\tassertPayloadPreservesFastRoute(model, params);\n\t\t\tconst requestOptions = {\n\t\t\t\t...(streamDeadline.signal ? { signal: streamDeadline.signal } : {}),\n\t\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\t\tmaxRetries: 0,\n\t\t\t};\n\t\t\tconst { data: openaiStream, response } = await retryProviderRequest(\n\t\t\t\t() => client.responses.create(params, requestOptions).withResponse(),\n\t\t\t\t{\n\t\t\t\t\tmaxRetries: options?.maxRetries,\n\t\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\t\t\t\tsignal: streamDeadline.signal,\n\t\t\t\t},\n\t\t\t);\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\tawait processResponsesStream(\n\t\t\t\twithStreamDeadline(openaiStream, streamDeadline.deadlineMs, streamDeadline.abort),\n\t\t\t\toutput,\n\t\t\t\tstream,\n\t\t\t\tmodel,\n\t\t\t\t{\n\t\t\t\t\tserviceTier: resolveRequestedServiceTier(model, options?.serviceTier),\n\t\t\t\t\tgrammarToolInputProperties,\n\t\t\t\t\tapplyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"pending\") {\n\t\t\t\tthrow new Error(\"OpenAI Responses stream ended without a stop reason\");\n\t\t\t}\n\t\t\tif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(output.errorMessage || \"An unknown error occurred\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t// Streaming scratch buffers are only used during parsing; never persist them.\n\t\t\t\tdelete (block as { partialJson?: string }).partialJson;\n\t\t\t\tdelete (block as { customInput?: unknown }).customInput;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = formatProviderError(\n\t\t\t\tnormalizeProviderError(error),\n\t\t\t\t`${model.provider === \"openai\" ? \"OpenAI\" : model.provider} API error`,\n\t\t\t);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tstreamDeadline.cleanup();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimple: StreamFunction<\"openai-responses\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tgetClientApiKey(model.provider, options?.apiKey, options?.headers);\n\n\tconst base = {\n\t\t...buildBaseOptions(model, context, options, options?.apiKey),\n\t\ttoolChoice: options?.toolChoice,\n\t} satisfies OpenAIResponsesOptions;\n\tconst clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;\n\tconst reasoningEffort = clampedReasoning === \"off\" ? undefined : clampedReasoning;\n\n\treturn stream(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t} satisfies OpenAIResponsesOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\tapiKey: string,\n\toptionsHeaders?: ProviderHeaders,\n\tfetch?: typeof globalThis.fetch,\n\tsessionId?: string,\n\tcopilotApiKey?: string,\n) {\n\tconst compat = getCompat(model);\n\tconst headers: ProviderHeaders = { \"User-Agent\": getPiUserAgent(), ...model.headers };\n\tif (model.provider === \"github-copilot\") {\n\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\tconst copilotHeaders = preserveCopilotIntegrationHeader(\n\t\t\tmodel.headers,\n\t\t\tbuildCopilotDynamicHeaders({\n\t\t\t\tmessages: context.messages,\n\t\t\t\thasImages,\n\t\t\t\tapiKey: copilotApiKey,\n\t\t\t}),\n\t\t);\n\t\tObject.assign(headers, copilotHeaders);\n\t}\n\n\tif (sessionId) {\n\t\tif (compat.sessionAffinityFormat === \"openrouter\") {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t} else {\n\t\t\tif (compat.sessionAffinityFormat === \"openai\") {\n\t\t\t\theaders.session_id = sessionId;\n\t\t\t}\n\t\t\theaders[\"x-client-request-id\"] = sessionId;\n\t\t}\n\t}\n\n\t// Merge options headers last so they can override defaults\n\tif (optionsHeaders) {\n\t\tObject.assign(headers, optionsHeaders);\n\t}\n\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tfetch,\n\t\tdefaultHeaders: headers,\n\t});\n}\n\nfunction buildParams(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions: OpenAIResponsesOptions | undefined,\n\tcompat: Required<OpenAIResponsesCompat> = getCompat(model),\n\tgrammarToolInputProperties: ReadonlyMap<string, string> = createGrammarToolInputProperties(\n\t\tgetDeclaredTools(context.messages),\n\t\tcompat.supportsOpenAIGrammarTools,\n\t),\n) {\n\tconst transcriptTools = resolveTranscriptTools(\n\t\tcontext.messages,\n\t\tcompat.supportsAdditionalTools || compat.supportsToolSearch,\n\t);\n\tconst messages = convertResponsesMessages(model, context, OPENAI_TOOL_CALL_PROVIDERS, {\n\t\tgrammarToolInputProperties,\n\t\tsupportsMidConvoSystemMessages: compat.supportsMidConvoSystemMessages,\n\t\tsupportsAdditionalTools: compat.supportsAdditionalTools,\n\t\tsupportsToolSearch: compat.supportsToolSearch,\n\t\ttoolOptions: {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t},\n\t});\n\n\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\tconst params: ResponseCreateParamsStreaming & {\n\t\tprompt_cache_options?: { mode?: \"explicit\"; ttl?: \"30m\" };\n\t} = {\n\t\t// A fast variant keeps its canonical `-fast` id on the model object — that is the identity the\n\t\t// caller selected and records — while routing to the base upstream model plus a service tier.\n\t\tmodel: model.fastRoute?.upstreamModelId ?? model.id,\n\t\tinput: messages,\n\t\tstream: true,\n\t\tprompt_cache_key: cacheRetention === \"none\" ? undefined : clampOpenAIPromptCacheKey(options?.sessionId),\n\t\tprompt_cache_retention: getPromptCacheRetention(compat, cacheRetention),\n\t\tprompt_cache_options: getPromptCacheOptions(compat, cacheRetention),\n\t\tstore: false,\n\t};\n\n\tif (options?.maxTokens && compat.supportsMaxOutputTokens) {\n\t\tparams.max_output_tokens = Math.max(options.maxTokens, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS);\n\t}\n\n\tif (options?.temperature !== undefined) {\n\t\tparams.temperature = options?.temperature;\n\t}\n\n\t// A fast variant carries its own tier, so a caller that only hands over the model still routes fast.\n\tconst requestedServiceTier = resolveRequestedServiceTier(model, options?.serviceTier);\n\tif (requestedServiceTier !== undefined) {\n\t\tparams.service_tier = requestedServiceTier;\n\t}\n\n\tif (transcriptTools.requestTools.length > 0) {\n\t\tparams.tools = convertResponsesTools(transcriptTools.requestTools, {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t});\n\t}\n\n\tif (options?.toolChoice !== undefined) {\n\t\tparams.tool_choice = options.toolChoice;\n\t}\n\n\tif (model.reasoning) {\n\t\tif (options?.reasoningEffort || options?.reasoningSummary) {\n\t\t\tconst effort = options?.reasoningEffort\n\t\t\t\t? (model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort)\n\t\t\t\t: \"medium\";\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: effort as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t\tsummary: options?.reasoningSummary || \"auto\",\n\t\t\t};\n\t\t\tparams.include = [\"reasoning.encrypted_content\"];\n\t\t} else if (model.provider !== \"github-copilot\" && model.thinkingLevelMap?.off !== null) {\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: (model.thinkingLevelMap?.off ?? \"none\") as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t};\n\t\t}\n\t\tif (model.provider === \"xai\") params.include = [\"reasoning.encrypted_content\"];\n\t}\n\n\t// Last so custom keys override the named request fields.\n\tif (options?.samplingParams) {\n\t\tObject.assign(params, options.samplingParams);\n\t}\n\n\treturn params;\n}\n\nfunction getServiceTierCostMultiplier(\n\tmodel: Pick<Model<\"openai-responses\">, \"fastRoute\" | \"id\">,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n): number {\n\t// Price against the model that was actually billed upstream, so a `-fast` variant of a\n\t// per-model rate (gpt-5.5) is not silently charged the generic multiplier.\n\tconst pricedModelId = model.fastRoute?.baseModelId ?? model.id;\n\tswitch (serviceTier) {\n\t\tcase \"flex\":\n\t\t\treturn 0.5;\n\t\tcase \"priority\":\n\t\t\treturn pricedModelId === \"gpt-5.5\" ? 2.5 : 2;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nfunction applyServiceTierPricing(\n\tusage: Usage,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\tmodel: Pick<Model<\"openai-responses\">, \"fastRoute\" | \"id\">,\n) {\n\tconst multiplier = getServiceTierCostMultiplier(model, serviceTier);\n\tif (multiplier === 1) return;\n\n\tusage.cost.input *= multiplier;\n\tusage.cost.output *= multiplier;\n\tusage.cost.cacheRead *= multiplier;\n\tusage.cost.cacheWrite *= multiplier;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"openai-responses.js","sourceRoot":"","sources":["../../src/api/openai-responses.ts"],"names":[],"mappings":"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","sourcesContent":["import OpenAI from \"openai\";\nimport type { ResponseCreateParamsStreaming } from \"openai/resources/responses/responses.js\";\nimport { clampThinkingLevel } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tCacheRetention,\n\tModel,\n\tOpenAIResponsesCompat,\n\tProviderEnv,\n\tProviderHeaders,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tTranscriptContext,\n\tUsage,\n} from \"../types.ts\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.ts\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { headersToRecord } from \"../utils/headers.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\nimport { getProviderEnvValue } from \"../utils/provider-env.ts\";\nimport { retryProviderRequest } from \"../utils/provider-retry.ts\";\nimport { createStreamDeadline, withStreamDeadline } from \"../utils/stream-deadline.ts\";\nimport { getDeclaredTools, resolveTranscript, resolveTranscriptTools } from \"../utils/transcript.ts\";\nimport { createGrammarToolInputProperties } from \"./constrained-sampling.ts\";\nimport {\n\tbuildCopilotDynamicHeaders,\n\thasCopilotVisionInput,\n\tpreserveCopilotIntegrationHeader,\n} from \"./github-copilot-headers.ts\";\nimport { clampOpenAIPromptCacheKey } from \"./openai-prompt-cache.ts\";\nimport {\n\tassertPayloadPreservesFastRoute,\n\tconvertResponsesMessages,\n\tconvertResponsesTools,\n\tprocessResponsesStream,\n\tresolveRequestedServiceTier,\n} from \"./openai-responses-shared.ts\";\nimport { buildBaseOptions } from \"./simple-options.ts\";\n\nconst OPENAI_TOOL_CALL_PROVIDERS = new Set([\"openai\", \"openai-codex\", \"opencode\"]);\n// OpenAI Responses rejects max_output_tokens below 16: https://github.com/earendil-works/pi/issues/6265\nconst OPENAI_RESPONSES_MIN_OUTPUT_TOKENS = 16;\n\nfunction hasHeader(headers: ProviderHeaders | undefined, name: string): boolean {\n\tif (!headers) return false;\n\tconst expected = name.toLowerCase();\n\tfor (const [key, value] of Object.entries(headers)) {\n\t\tif (key.toLowerCase() === expected && value !== null && value.trim().length > 0) return true;\n\t}\n\treturn false;\n}\n\nfunction getClientApiKey(provider: string, apiKey: string | undefined, headers: ProviderHeaders | undefined): string {\n\tif (apiKey) return apiKey;\n\tif (hasHeader(headers, \"authorization\") || hasHeader(headers, \"cf-aig-authorization\")) return \"unused\";\n\tthrow new Error(`No API key for provider: ${provider}`);\n}\n\nfunction detectSessionAffinityFormat(model: Pick<Model<\"openai-responses\">, \"provider\" | \"baseUrl\">) {\n\treturn model.provider === \"openrouter\" || model.baseUrl.includes(\"openrouter.ai\") ? \"openrouter\" : \"openai\";\n}\n\n/**\n * Resolve cache retention preference.\n * Defaults to \"short\" and uses PI_CACHE_RETENTION for backward compatibility.\n */\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\nfunction getCompat(model: Model<\"openai-responses\">): Required<OpenAIResponsesCompat> {\n\treturn {\n\t\tsupportsDeveloperRole: model.compat?.supportsDeveloperRole ?? true,\n\t\tsupportsMidConvoSystemMessages: model.compat?.supportsMidConvoSystemMessages ?? false,\n\t\tsessionAffinityFormat: model.compat?.sessionAffinityFormat ?? detectSessionAffinityFormat(model),\n\t\tsupportsLongCacheRetention: model.compat?.supportsLongCacheRetention ?? true,\n\t\tsupportsStrictMode: model.compat?.supportsStrictMode ?? false,\n\t\tsupportsOpenAIGrammarTools: model.compat?.supportsOpenAIGrammarTools ?? false,\n\t\tsupportsAdditionalTools: model.compat?.supportsAdditionalTools ?? false,\n\t\tsupportsToolSearch: model.compat?.supportsToolSearch ?? false,\n\t\tsupportsExplicitPromptCacheMode: model.compat?.supportsExplicitPromptCacheMode ?? false,\n\t\tsupportsMaxOutputTokens: model.compat?.supportsMaxOutputTokens ?? true,\n\t};\n}\n\nfunction getPromptCacheRetention(\n\tcompat: Required<OpenAIResponsesCompat>,\n\tcacheRetention: CacheRetention,\n): \"24h\" | undefined {\n\treturn cacheRetention === \"long\" && compat.supportsLongCacheRetention && !compat.supportsExplicitPromptCacheMode\n\t\t? \"24h\"\n\t\t: undefined;\n}\n\nfunction getPromptCacheOptions(\n\tcompat: Required<OpenAIResponsesCompat>,\n\tcacheRetention: CacheRetention,\n): { mode?: \"explicit\"; ttl?: \"30m\" } | undefined {\n\tif (!compat.supportsExplicitPromptCacheMode) return undefined;\n\tif (cacheRetention === \"none\") return { mode: \"explicit\" };\n\tif (cacheRetention === \"long\" && compat.supportsLongCacheRetention) return { ttl: \"30m\" };\n\treturn undefined;\n}\n\n// OpenAI Responses-specific options\nexport interface OpenAIResponsesOptions extends StreamOptions {\n\treasoningEffort?: \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\treasoningSummary?: \"auto\" | \"detailed\" | \"concise\" | null;\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\ttoolChoice?: ResponseCreateParamsStreaming[\"tool_choice\"];\n}\n\n/**\n * Generate function for OpenAI Responses API\n */\nexport const stream: StreamFunction<\"openai-responses\", OpenAIResponsesOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions?: OpenAIResponsesOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\tconst normalizedContext = resolveTranscript(context, getCompat(model).supportsMidConvoSystemMessages);\n\n\t// Start async processing\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"pending\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tconst streamDeadline = createStreamDeadline(options?.streamDeadlineMs, options?.signal);\n\n\t\ttry {\n\t\t\t// Create OpenAI client\n\t\t\tconst apiKey = getClientApiKey(model.provider, options?.apiKey, options?.headers);\n\t\t\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\t\t\tconst cacheSessionId = cacheRetention === \"none\" ? undefined : options?.sessionId;\n\t\t\tconst compat = getCompat(model);\n\t\t\tconst grammarToolInputProperties = createGrammarToolInputProperties(\n\t\t\t\tgetDeclaredTools(normalizedContext.messages),\n\t\t\t\tcompat.supportsOpenAIGrammarTools,\n\t\t\t);\n\t\t\tconst client = createClient(\n\t\t\t\tmodel,\n\t\t\t\tnormalizedContext,\n\t\t\t\tapiKey,\n\t\t\t\toptions?.headers,\n\t\t\t\toptions?.fetch,\n\t\t\t\tcacheSessionId,\n\t\t\t\toptions?.apiKey,\n\t\t\t);\n\t\t\tlet params = buildParams(model, normalizedContext, options, compat, grammarToolInputProperties);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as ResponseCreateParamsStreaming;\n\t\t\t}\n\t\t\tassertPayloadPreservesFastRoute(model, params);\n\t\t\tconst requestOptions = {\n\t\t\t\t...(streamDeadline.signal ? { signal: streamDeadline.signal } : {}),\n\t\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\t\tmaxRetries: 0,\n\t\t\t};\n\t\t\tconst { data: openaiStream, response } = await retryProviderRequest(\n\t\t\t\t() => client.responses.create(params, requestOptions).withResponse(),\n\t\t\t\t{\n\t\t\t\t\tmaxRetries: options?.maxRetries,\n\t\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\t\t\t\tsignal: streamDeadline.signal,\n\t\t\t\t},\n\t\t\t);\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\tawait processResponsesStream(\n\t\t\t\twithStreamDeadline(openaiStream, streamDeadline.deadlineMs, streamDeadline.abort),\n\t\t\t\toutput,\n\t\t\t\tstream,\n\t\t\t\tmodel,\n\t\t\t\t{\n\t\t\t\t\tonProviderStreamEvent: options?.onProviderStreamEvent,\n\t\t\t\t\tserviceTier: resolveRequestedServiceTier(model, options?.serviceTier),\n\t\t\t\t\tgrammarToolInputProperties,\n\t\t\t\t\tapplyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"pending\") {\n\t\t\t\tthrow new Error(\"OpenAI Responses stream ended without a stop reason\");\n\t\t\t}\n\t\t\tif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(output.errorMessage || \"An unknown error occurred\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t// Streaming scratch buffers are only used during parsing; never persist them.\n\t\t\t\tdelete (block as { partialJson?: string }).partialJson;\n\t\t\t\tdelete (block as { customInput?: unknown }).customInput;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = formatProviderError(\n\t\t\t\tnormalizeProviderError(error),\n\t\t\t\t`${model.provider === \"openai\" ? \"OpenAI\" : model.provider} API error`,\n\t\t\t);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tstreamDeadline.cleanup();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimple: StreamFunction<\"openai-responses\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tgetClientApiKey(model.provider, options?.apiKey, options?.headers);\n\n\tconst base = {\n\t\t...buildBaseOptions(model, context, options, options?.apiKey),\n\t\ttoolChoice: options?.toolChoice,\n\t} satisfies OpenAIResponsesOptions;\n\tconst clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;\n\tconst reasoningEffort = clampedReasoning === \"off\" ? undefined : clampedReasoning;\n\n\treturn stream(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t} satisfies OpenAIResponsesOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\tapiKey: string,\n\toptionsHeaders?: ProviderHeaders,\n\tfetch?: typeof globalThis.fetch,\n\tsessionId?: string,\n\tcopilotApiKey?: string,\n) {\n\tconst compat = getCompat(model);\n\tconst headers: ProviderHeaders = { \"User-Agent\": getPiUserAgent(), ...model.headers };\n\tif (model.provider === \"github-copilot\") {\n\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\tconst copilotHeaders = preserveCopilotIntegrationHeader(\n\t\t\tmodel.headers,\n\t\t\tbuildCopilotDynamicHeaders({\n\t\t\t\tmessages: context.messages,\n\t\t\t\thasImages,\n\t\t\t\tapiKey: copilotApiKey,\n\t\t\t}),\n\t\t);\n\t\tObject.assign(headers, copilotHeaders);\n\t}\n\n\tif (sessionId) {\n\t\tif (compat.sessionAffinityFormat === \"openrouter\") {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t} else {\n\t\t\tif (compat.sessionAffinityFormat === \"openai\") {\n\t\t\t\theaders.session_id = sessionId;\n\t\t\t}\n\t\t\theaders[\"x-client-request-id\"] = sessionId;\n\t\t}\n\t}\n\n\t// Merge options headers last so they can override defaults\n\tif (optionsHeaders) {\n\t\tObject.assign(headers, optionsHeaders);\n\t}\n\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tfetch,\n\t\tdefaultHeaders: headers,\n\t});\n}\n\nfunction buildParams(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: TranscriptContext,\n\toptions: OpenAIResponsesOptions | undefined,\n\tcompat: Required<OpenAIResponsesCompat> = getCompat(model),\n\tgrammarToolInputProperties: ReadonlyMap<string, string> = createGrammarToolInputProperties(\n\t\tgetDeclaredTools(context.messages),\n\t\tcompat.supportsOpenAIGrammarTools,\n\t),\n) {\n\tconst transcriptTools = resolveTranscriptTools(\n\t\tcontext.messages,\n\t\tcompat.supportsAdditionalTools || compat.supportsToolSearch,\n\t);\n\tconst messages = convertResponsesMessages(model, context, OPENAI_TOOL_CALL_PROVIDERS, {\n\t\tgrammarToolInputProperties,\n\t\tsupportsMidConvoSystemMessages: compat.supportsMidConvoSystemMessages,\n\t\tsupportsAdditionalTools: compat.supportsAdditionalTools,\n\t\tsupportsToolSearch: compat.supportsToolSearch,\n\t\ttoolOptions: {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t},\n\t});\n\n\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\tconst params: ResponseCreateParamsStreaming & {\n\t\tprompt_cache_options?: { mode?: \"explicit\"; ttl?: \"30m\" };\n\t} = {\n\t\t// A fast variant keeps its canonical `-fast` id on the model object — that is the identity the\n\t\t// caller selected and records — while routing to the base upstream model plus a service tier.\n\t\tmodel: model.fastRoute?.upstreamModelId ?? model.id,\n\t\tinput: messages,\n\t\tstream: true,\n\t\tprompt_cache_key: cacheRetention === \"none\" ? undefined : clampOpenAIPromptCacheKey(options?.sessionId),\n\t\tprompt_cache_retention: getPromptCacheRetention(compat, cacheRetention),\n\t\tprompt_cache_options: getPromptCacheOptions(compat, cacheRetention),\n\t\tstore: false,\n\t};\n\n\tif (options?.maxTokens && compat.supportsMaxOutputTokens) {\n\t\tparams.max_output_tokens = Math.max(options.maxTokens, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS);\n\t}\n\n\tif (options?.temperature !== undefined) {\n\t\tparams.temperature = options?.temperature;\n\t}\n\n\t// A fast variant carries its own tier, so a caller that only hands over the model still routes fast.\n\tconst requestedServiceTier = resolveRequestedServiceTier(model, options?.serviceTier);\n\tif (requestedServiceTier !== undefined) {\n\t\tparams.service_tier = requestedServiceTier;\n\t}\n\n\tif (transcriptTools.requestTools.length > 0) {\n\t\tparams.tools = convertResponsesTools(transcriptTools.requestTools, {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t});\n\t}\n\n\tif (options?.toolChoice !== undefined) {\n\t\tparams.tool_choice = options.toolChoice;\n\t}\n\n\tif (model.reasoning) {\n\t\tif (options?.reasoningEffort || options?.reasoningSummary) {\n\t\t\tconst effort = options?.reasoningEffort\n\t\t\t\t? (model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort)\n\t\t\t\t: \"medium\";\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: effort as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t\tsummary: options?.reasoningSummary || \"auto\",\n\t\t\t};\n\t\t\tparams.include = [\"reasoning.encrypted_content\"];\n\t\t} else if (model.provider !== \"github-copilot\" && model.thinkingLevelMap?.off !== null) {\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: (model.thinkingLevelMap?.off ?? \"none\") as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t};\n\t\t}\n\t\tif (model.provider === \"xai\") params.include = [\"reasoning.encrypted_content\"];\n\t}\n\n\t// Last so custom keys override the named request fields.\n\tif (options?.samplingParams) {\n\t\tObject.assign(params, options.samplingParams);\n\t}\n\n\treturn params;\n}\n\nfunction getServiceTierCostMultiplier(\n\tmodel: Pick<Model<\"openai-responses\">, \"fastRoute\" | \"id\">,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n): number {\n\t// Price against the model that was actually billed upstream, so a `-fast` variant of a\n\t// per-model rate (gpt-5.5) is not silently charged the generic multiplier.\n\tconst pricedModelId = model.fastRoute?.baseModelId ?? model.id;\n\tswitch (serviceTier) {\n\t\tcase \"flex\":\n\t\t\treturn 0.5;\n\t\tcase \"priority\":\n\t\t\treturn pricedModelId === \"gpt-5.5\" ? 2.5 : 2;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nfunction applyServiceTierPricing(\n\tusage: Usage,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\tmodel: Pick<Model<\"openai-responses\">, \"fastRoute\" | \"id\">,\n) {\n\tconst multiplier = getServiceTierCostMultiplier(model, serviceTier);\n\tif (multiplier === 1) return;\n\n\tusage.cost.input *= multiplier;\n\tusage.cost.output *= multiplier;\n\tusage.cost.cacheRead *= multiplier;\n\tusage.cost.cacheWrite *= multiplier;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { ImagesFunction, ImagesOptions } from "../types.ts";
|
|
2
|
-
|
|
2
|
+
/** Image generation over OpenRouter's chat completions endpoint. */
|
|
3
|
+
export declare const generateImages: ImagesFunction<ImagesOptions>;
|
|
3
4
|
//# sourceMappingURL=openrouter-images.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openrouter-images.d.ts","sourceRoot":"","sources":["../../src/api/openrouter-images.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"openrouter-images.d.ts","sourceRoot":"","sources":["../../src/api/openrouter-images.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAMX,cAAc,EACd,aAAa,EAGb,MAAM,aAAa,CAAC;AAsBrB,oEAAoE;AACpE,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,aAAa,CA2ExD,CAAC","sourcesContent":["import OpenAI from \"openai\";\nimport type {\n\tChatCompletion,\n\tChatCompletionContentPart,\n\tChatCompletionContentPartImage,\n\tChatCompletionContentPartText,\n\tChatCompletionCreateParamsNonStreaming,\n} from \"openai/resources/chat/completions.js\";\nimport type {\n\tAssistantImages,\n\tImageApi,\n\tImageContent,\n\tImageModel,\n\tImagesContext,\n\tImagesFunction,\n\tImagesOptions,\n\tProviderHeaders,\n\tTextContent,\n} from \"../types.ts\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.ts\";\nimport { headersToRecord, providerHeadersToRecord } from \"../utils/headers.ts\";\nimport { retryProviderRequest } from \"../utils/provider-retry.ts\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.ts\";\n\ninterface OpenRouterGeneratedImage {\n\timage_url?: string | { url?: string };\n}\n\ntype OpenRouterImageGenerationMessage = ChatCompletion[\"choices\"][number][\"message\"] & {\n\timages?: OpenRouterGeneratedImage[];\n};\n\ntype OpenRouterImageGenerationChoice = ChatCompletion[\"choices\"][number] & {\n\tmessage: OpenRouterImageGenerationMessage;\n};\n\ntype OpenRouterImageGenerationResponse = ChatCompletion & {\n\tchoices: OpenRouterImageGenerationChoice[];\n};\n\n/** Image generation over OpenRouter's chat completions endpoint. */\nexport const generateImages: ImagesFunction<ImagesOptions> = async (\n\tmodel: ImageModel<ImageApi>,\n\tcontext: ImagesContext,\n\toptions?: ImagesOptions,\n) => {\n\tconst output: AssistantImages = {\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\toutput: [],\n\t\tstopReason: \"stop\",\n\t\ttimestamp: Date.now(),\n\t};\n\n\ttry {\n\t\tconst apiKey = options?.apiKey;\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t\t}\n\t\tconst client = createClient(model, apiKey, options?.headers, options?.fetch);\n\t\tlet params = buildParams(model, context);\n\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\tif (nextParams !== undefined) {\n\t\t\tparams = nextParams as typeof params;\n\t\t}\n\t\tconst requestOptions = {\n\t\t\t...(options?.signal ? { signal: options.signal } : {}),\n\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\tmaxRetries: 0,\n\t\t};\n\t\tconst { data: response, response: rawResponse } = await retryProviderRequest(\n\t\t\t() =>\n\t\t\t\tclient.chat.completions\n\t\t\t\t\t.create(params as unknown as ChatCompletionCreateParamsNonStreaming, requestOptions)\n\t\t\t\t\t.withResponse(),\n\t\t\t{\n\t\t\t\tmaxRetries: options?.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\t\t\tsignal: options?.signal,\n\t\t\t},\n\t\t);\n\t\tawait options?.onResponse?.({ status: rawResponse.status, headers: headersToRecord(rawResponse.headers) }, model);\n\n\t\tconst imageResponse = response as OpenRouterImageGenerationResponse;\n\t\toutput.responseId = imageResponse.id;\n\t\tif (imageResponse.usage) {\n\t\t\toutput.usage = parseUsage(imageResponse.usage, model);\n\t\t}\n\n\t\tconst choice = imageResponse.choices[0];\n\t\tif (choice) {\n\t\t\tconst content = choice.message.content;\n\t\t\tif (typeof content === \"string\" && content.length > 0) {\n\t\t\t\toutput.output.push({ type: \"text\", text: content } satisfies TextContent);\n\t\t\t}\n\n\t\t\tfor (const image of choice.message.images ?? []) {\n\t\t\t\tconst imageUrl = typeof image.image_url === \"string\" ? image.image_url : image.image_url?.url;\n\t\t\t\tif (!imageUrl?.startsWith(\"data:\")) continue;\n\t\t\t\tconst matches = imageUrl.match(/^data:([^;]+);base64,(.+)$/);\n\t\t\t\tif (!matches) continue;\n\t\t\t\toutput.output.push({\n\t\t\t\t\ttype: \"image\",\n\t\t\t\t\tmimeType: matches[1],\n\t\t\t\t\tdata: matches[2],\n\t\t\t\t} satisfies ImageContent);\n\t\t\t}\n\t\t}\n\n\t\treturn output;\n\t} catch (error) {\n\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\toutput.errorMessage = formatProviderError(normalizeProviderError(error));\n\t\treturn output;\n\t}\n};\n\nfunction createClient(\n\tmodel: ImageModel<ImageApi>,\n\tapiKey: string,\n\toptionsHeaders?: ProviderHeaders,\n\tfetch?: typeof globalThis.fetch,\n): OpenAI {\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tfetch,\n\t\tdefaultHeaders: providerHeadersToRecord({ ...model.headers, ...optionsHeaders }),\n\t});\n}\n\ntype OpenRouterImagesCreateParams = Omit<ChatCompletionCreateParamsNonStreaming, \"modalities\"> & {\n\tmodalities: Array<\"image\" | \"text\">;\n};\n\nfunction buildParams(model: ImageModel<ImageApi>, context: ImagesContext): OpenRouterImagesCreateParams {\n\tconst content: ChatCompletionContentPart[] = context.input.map((item): ChatCompletionContentPart => {\n\t\tif (item.type === \"text\") {\n\t\t\treturn {\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: sanitizeSurrogates(item.text),\n\t\t\t} satisfies ChatCompletionContentPartText;\n\t\t}\n\t\treturn {\n\t\t\ttype: \"image_url\",\n\t\t\timage_url: {\n\t\t\t\turl: `data:${item.mimeType};base64,${item.data}`,\n\t\t\t},\n\t\t} satisfies ChatCompletionContentPartImage;\n\t});\n\n\treturn {\n\t\tmodel: model.id,\n\t\tmessages: [\n\t\t\t{\n\t\t\t\trole: \"user\" as const,\n\t\t\t\tcontent,\n\t\t\t},\n\t\t],\n\t\tstream: false,\n\t\tmodalities: model.output.includes(\"text\") ? [\"image\", \"text\"] : [\"image\"],\n\t};\n}\n\nfunction parseUsage(\n\trawUsage: {\n\t\tprompt_tokens?: number;\n\t\tcompletion_tokens?: number;\n\t\tprompt_tokens_details?: { cached_tokens?: number; cache_write_tokens?: number };\n\t},\n\tmodel: ImageModel<ImageApi>,\n) {\n\tconst promptTokens = rawUsage.prompt_tokens || 0;\n\tconst reportedCachedTokens = rawUsage.prompt_tokens_details?.cached_tokens || 0;\n\tconst cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;\n\tconst cacheReadTokens =\n\t\tcacheWriteTokens > 0 ? Math.max(0, reportedCachedTokens - cacheWriteTokens) : reportedCachedTokens;\n\tconst input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);\n\tconst output = rawUsage.completion_tokens || 0;\n\tconst usage = {\n\t\tinput,\n\t\toutput,\n\t\tcacheRead: cacheReadTokens,\n\t\tcacheWrite: cacheWriteTokens,\n\t\ttotalTokens: input + output + cacheReadTokens + cacheWriteTokens,\n\t\tcost: {\n\t\t\tinput: (model.cost.input / 1000000) * input,\n\t\t\toutput: (model.cost.output / 1000000) * output,\n\t\t\tcacheRead: (model.cost.cacheRead / 1000000) * cacheReadTokens,\n\t\t\tcacheWrite: (model.cost.cacheWrite / 1000000) * cacheWriteTokens,\n\t\t\ttotal: 0,\n\t\t},\n\t};\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n\treturn usage;\n}\n"]}
|
|
@@ -3,6 +3,7 @@ import { formatProviderError, normalizeProviderError } from "../utils/error-body
|
|
|
3
3
|
import { headersToRecord, providerHeadersToRecord } from "../utils/headers.js";
|
|
4
4
|
import { retryProviderRequest } from "../utils/provider-retry.js";
|
|
5
5
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
6
|
+
/** Image generation over OpenRouter's chat completions endpoint. */
|
|
6
7
|
export const generateImages = async (model, context, options) => {
|
|
7
8
|
const output = {
|
|
8
9
|
api: model.api,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openrouter-images.js","sourceRoot":"","sources":["../../src/api/openrouter-images.ts"],"names":[],"mappings":"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","sourcesContent":["import OpenAI from \"openai\";\nimport type {\n\tChatCompletion,\n\tChatCompletionContentPart,\n\tChatCompletionContentPartImage,\n\tChatCompletionContentPartText,\n\tChatCompletionCreateParamsNonStreaming,\n} from \"openai/resources/chat/completions.js\";\nimport type {\n\tAssistantImages,\n\tImageContent,\n\tImagesContext,\n\tImagesFunction,\n\tImagesModel,\n\tImagesOptions,\n\tProviderHeaders,\n\tTextContent,\n} from \"../types.ts\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.ts\";\nimport { headersToRecord, providerHeadersToRecord } from \"../utils/headers.ts\";\nimport { retryProviderRequest } from \"../utils/provider-retry.ts\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.ts\";\n\ninterface OpenRouterGeneratedImage {\n\timage_url?: string | { url?: string };\n}\n\ntype OpenRouterImageGenerationMessage = ChatCompletion[\"choices\"][number][\"message\"] & {\n\timages?: OpenRouterGeneratedImage[];\n};\n\ntype OpenRouterImageGenerationChoice = ChatCompletion[\"choices\"][number] & {\n\tmessage: OpenRouterImageGenerationMessage;\n};\n\ntype OpenRouterImageGenerationResponse = ChatCompletion & {\n\tchoices: OpenRouterImageGenerationChoice[];\n};\n\nexport const generateImages: ImagesFunction<\"openrouter-images\", ImagesOptions> = async (\n\tmodel: ImagesModel<\"openrouter-images\">,\n\tcontext: ImagesContext,\n\toptions?: ImagesOptions,\n) => {\n\tconst output: AssistantImages = {\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\toutput: [],\n\t\tstopReason: \"stop\",\n\t\ttimestamp: Date.now(),\n\t};\n\n\ttry {\n\t\tconst apiKey = options?.apiKey;\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t\t}\n\t\tconst client = createClient(model, apiKey, options?.headers, options?.fetch);\n\t\tlet params = buildParams(model, context);\n\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\tif (nextParams !== undefined) {\n\t\t\tparams = nextParams as typeof params;\n\t\t}\n\t\tconst requestOptions = {\n\t\t\t...(options?.signal ? { signal: options.signal } : {}),\n\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\tmaxRetries: 0,\n\t\t};\n\t\tconst { data: response, response: rawResponse } = await retryProviderRequest(\n\t\t\t() =>\n\t\t\t\tclient.chat.completions\n\t\t\t\t\t.create(params as unknown as ChatCompletionCreateParamsNonStreaming, requestOptions)\n\t\t\t\t\t.withResponse(),\n\t\t\t{\n\t\t\t\tmaxRetries: options?.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\t\t\tsignal: options?.signal,\n\t\t\t},\n\t\t);\n\t\tawait options?.onResponse?.({ status: rawResponse.status, headers: headersToRecord(rawResponse.headers) }, model);\n\n\t\tconst imageResponse = response as OpenRouterImageGenerationResponse;\n\t\toutput.responseId = imageResponse.id;\n\t\tif (imageResponse.usage) {\n\t\t\toutput.usage = parseUsage(imageResponse.usage, model);\n\t\t}\n\n\t\tconst choice = imageResponse.choices[0];\n\t\tif (choice) {\n\t\t\tconst content = choice.message.content;\n\t\t\tif (typeof content === \"string\" && content.length > 0) {\n\t\t\t\toutput.output.push({ type: \"text\", text: content } satisfies TextContent);\n\t\t\t}\n\n\t\t\tfor (const image of choice.message.images ?? []) {\n\t\t\t\tconst imageUrl = typeof image.image_url === \"string\" ? image.image_url : image.image_url?.url;\n\t\t\t\tif (!imageUrl?.startsWith(\"data:\")) continue;\n\t\t\t\tconst matches = imageUrl.match(/^data:([^;]+);base64,(.+)$/);\n\t\t\t\tif (!matches) continue;\n\t\t\t\toutput.output.push({\n\t\t\t\t\ttype: \"image\",\n\t\t\t\t\tmimeType: matches[1],\n\t\t\t\t\tdata: matches[2],\n\t\t\t\t} satisfies ImageContent);\n\t\t\t}\n\t\t}\n\n\t\treturn output;\n\t} catch (error) {\n\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\toutput.errorMessage = formatProviderError(normalizeProviderError(error));\n\t\treturn output;\n\t}\n};\n\nfunction createClient(\n\tmodel: ImagesModel<\"openrouter-images\">,\n\tapiKey: string,\n\toptionsHeaders?: ProviderHeaders,\n\tfetch?: typeof globalThis.fetch,\n): OpenAI {\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tfetch,\n\t\tdefaultHeaders: providerHeadersToRecord({ ...model.headers, ...optionsHeaders }),\n\t});\n}\n\ntype OpenRouterImagesCreateParams = Omit<ChatCompletionCreateParamsNonStreaming, \"modalities\"> & {\n\tmodalities: Array<\"image\" | \"text\">;\n};\n\nfunction buildParams(model: ImagesModel<\"openrouter-images\">, context: ImagesContext): OpenRouterImagesCreateParams {\n\tconst content: ChatCompletionContentPart[] = context.input.map((item): ChatCompletionContentPart => {\n\t\tif (item.type === \"text\") {\n\t\t\treturn {\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: sanitizeSurrogates(item.text),\n\t\t\t} satisfies ChatCompletionContentPartText;\n\t\t}\n\t\treturn {\n\t\t\ttype: \"image_url\",\n\t\t\timage_url: {\n\t\t\t\turl: `data:${item.mimeType};base64,${item.data}`,\n\t\t\t},\n\t\t} satisfies ChatCompletionContentPartImage;\n\t});\n\n\treturn {\n\t\tmodel: model.id,\n\t\tmessages: [\n\t\t\t{\n\t\t\t\trole: \"user\" as const,\n\t\t\t\tcontent,\n\t\t\t},\n\t\t],\n\t\tstream: false,\n\t\tmodalities: model.output.includes(\"text\") ? [\"image\", \"text\"] : [\"image\"],\n\t};\n}\n\nfunction parseUsage(\n\trawUsage: {\n\t\tprompt_tokens?: number;\n\t\tcompletion_tokens?: number;\n\t\tprompt_tokens_details?: { cached_tokens?: number; cache_write_tokens?: number };\n\t},\n\tmodel: ImagesModel<\"openrouter-images\">,\n) {\n\tconst promptTokens = rawUsage.prompt_tokens || 0;\n\tconst reportedCachedTokens = rawUsage.prompt_tokens_details?.cached_tokens || 0;\n\tconst cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;\n\tconst cacheReadTokens =\n\t\tcacheWriteTokens > 0 ? Math.max(0, reportedCachedTokens - cacheWriteTokens) : reportedCachedTokens;\n\tconst input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);\n\tconst output = rawUsage.completion_tokens || 0;\n\tconst usage = {\n\t\tinput,\n\t\toutput,\n\t\tcacheRead: cacheReadTokens,\n\t\tcacheWrite: cacheWriteTokens,\n\t\ttotalTokens: input + output + cacheReadTokens + cacheWriteTokens,\n\t\tcost: {\n\t\t\tinput: (model.cost.input / 1000000) * input,\n\t\t\toutput: (model.cost.output / 1000000) * output,\n\t\t\tcacheRead: (model.cost.cacheRead / 1000000) * cacheReadTokens,\n\t\t\tcacheWrite: (model.cost.cacheWrite / 1000000) * cacheWriteTokens,\n\t\t\ttotal: 0,\n\t\t},\n\t};\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n\treturn usage;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"openrouter-images.js","sourceRoot":"","sources":["../../src/api/openrouter-images.ts"],"names":[],"mappings":"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","sourcesContent":["import OpenAI from \"openai\";\nimport type {\n\tChatCompletion,\n\tChatCompletionContentPart,\n\tChatCompletionContentPartImage,\n\tChatCompletionContentPartText,\n\tChatCompletionCreateParamsNonStreaming,\n} from \"openai/resources/chat/completions.js\";\nimport type {\n\tAssistantImages,\n\tImageApi,\n\tImageContent,\n\tImageModel,\n\tImagesContext,\n\tImagesFunction,\n\tImagesOptions,\n\tProviderHeaders,\n\tTextContent,\n} from \"../types.ts\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.ts\";\nimport { headersToRecord, providerHeadersToRecord } from \"../utils/headers.ts\";\nimport { retryProviderRequest } from \"../utils/provider-retry.ts\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.ts\";\n\ninterface OpenRouterGeneratedImage {\n\timage_url?: string | { url?: string };\n}\n\ntype OpenRouterImageGenerationMessage = ChatCompletion[\"choices\"][number][\"message\"] & {\n\timages?: OpenRouterGeneratedImage[];\n};\n\ntype OpenRouterImageGenerationChoice = ChatCompletion[\"choices\"][number] & {\n\tmessage: OpenRouterImageGenerationMessage;\n};\n\ntype OpenRouterImageGenerationResponse = ChatCompletion & {\n\tchoices: OpenRouterImageGenerationChoice[];\n};\n\n/** Image generation over OpenRouter's chat completions endpoint. */\nexport const generateImages: ImagesFunction<ImagesOptions> = async (\n\tmodel: ImageModel<ImageApi>,\n\tcontext: ImagesContext,\n\toptions?: ImagesOptions,\n) => {\n\tconst output: AssistantImages = {\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\toutput: [],\n\t\tstopReason: \"stop\",\n\t\ttimestamp: Date.now(),\n\t};\n\n\ttry {\n\t\tconst apiKey = options?.apiKey;\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t\t}\n\t\tconst client = createClient(model, apiKey, options?.headers, options?.fetch);\n\t\tlet params = buildParams(model, context);\n\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\tif (nextParams !== undefined) {\n\t\t\tparams = nextParams as typeof params;\n\t\t}\n\t\tconst requestOptions = {\n\t\t\t...(options?.signal ? { signal: options.signal } : {}),\n\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\tmaxRetries: 0,\n\t\t};\n\t\tconst { data: response, response: rawResponse } = await retryProviderRequest(\n\t\t\t() =>\n\t\t\t\tclient.chat.completions\n\t\t\t\t\t.create(params as unknown as ChatCompletionCreateParamsNonStreaming, requestOptions)\n\t\t\t\t\t.withResponse(),\n\t\t\t{\n\t\t\t\tmaxRetries: options?.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\t\t\tsignal: options?.signal,\n\t\t\t},\n\t\t);\n\t\tawait options?.onResponse?.({ status: rawResponse.status, headers: headersToRecord(rawResponse.headers) }, model);\n\n\t\tconst imageResponse = response as OpenRouterImageGenerationResponse;\n\t\toutput.responseId = imageResponse.id;\n\t\tif (imageResponse.usage) {\n\t\t\toutput.usage = parseUsage(imageResponse.usage, model);\n\t\t}\n\n\t\tconst choice = imageResponse.choices[0];\n\t\tif (choice) {\n\t\t\tconst content = choice.message.content;\n\t\t\tif (typeof content === \"string\" && content.length > 0) {\n\t\t\t\toutput.output.push({ type: \"text\", text: content } satisfies TextContent);\n\t\t\t}\n\n\t\t\tfor (const image of choice.message.images ?? []) {\n\t\t\t\tconst imageUrl = typeof image.image_url === \"string\" ? image.image_url : image.image_url?.url;\n\t\t\t\tif (!imageUrl?.startsWith(\"data:\")) continue;\n\t\t\t\tconst matches = imageUrl.match(/^data:([^;]+);base64,(.+)$/);\n\t\t\t\tif (!matches) continue;\n\t\t\t\toutput.output.push({\n\t\t\t\t\ttype: \"image\",\n\t\t\t\t\tmimeType: matches[1],\n\t\t\t\t\tdata: matches[2],\n\t\t\t\t} satisfies ImageContent);\n\t\t\t}\n\t\t}\n\n\t\treturn output;\n\t} catch (error) {\n\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\toutput.errorMessage = formatProviderError(normalizeProviderError(error));\n\t\treturn output;\n\t}\n};\n\nfunction createClient(\n\tmodel: ImageModel<ImageApi>,\n\tapiKey: string,\n\toptionsHeaders?: ProviderHeaders,\n\tfetch?: typeof globalThis.fetch,\n): OpenAI {\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tfetch,\n\t\tdefaultHeaders: providerHeadersToRecord({ ...model.headers, ...optionsHeaders }),\n\t});\n}\n\ntype OpenRouterImagesCreateParams = Omit<ChatCompletionCreateParamsNonStreaming, \"modalities\"> & {\n\tmodalities: Array<\"image\" | \"text\">;\n};\n\nfunction buildParams(model: ImageModel<ImageApi>, context: ImagesContext): OpenRouterImagesCreateParams {\n\tconst content: ChatCompletionContentPart[] = context.input.map((item): ChatCompletionContentPart => {\n\t\tif (item.type === \"text\") {\n\t\t\treturn {\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: sanitizeSurrogates(item.text),\n\t\t\t} satisfies ChatCompletionContentPartText;\n\t\t}\n\t\treturn {\n\t\t\ttype: \"image_url\",\n\t\t\timage_url: {\n\t\t\t\turl: `data:${item.mimeType};base64,${item.data}`,\n\t\t\t},\n\t\t} satisfies ChatCompletionContentPartImage;\n\t});\n\n\treturn {\n\t\tmodel: model.id,\n\t\tmessages: [\n\t\t\t{\n\t\t\t\trole: \"user\" as const,\n\t\t\t\tcontent,\n\t\t\t},\n\t\t],\n\t\tstream: false,\n\t\tmodalities: model.output.includes(\"text\") ? [\"image\", \"text\"] : [\"image\"],\n\t};\n}\n\nfunction parseUsage(\n\trawUsage: {\n\t\tprompt_tokens?: number;\n\t\tcompletion_tokens?: number;\n\t\tprompt_tokens_details?: { cached_tokens?: number; cache_write_tokens?: number };\n\t},\n\tmodel: ImageModel<ImageApi>,\n) {\n\tconst promptTokens = rawUsage.prompt_tokens || 0;\n\tconst reportedCachedTokens = rawUsage.prompt_tokens_details?.cached_tokens || 0;\n\tconst cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;\n\tconst cacheReadTokens =\n\t\tcacheWriteTokens > 0 ? Math.max(0, reportedCachedTokens - cacheWriteTokens) : reportedCachedTokens;\n\tconst input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);\n\tconst output = rawUsage.completion_tokens || 0;\n\tconst usage = {\n\t\tinput,\n\t\toutput,\n\t\tcacheRead: cacheReadTokens,\n\t\tcacheWrite: cacheWriteTokens,\n\t\ttotalTokens: input + output + cacheReadTokens + cacheWriteTokens,\n\t\tcost: {\n\t\t\tinput: (model.cost.input / 1000000) * input,\n\t\t\toutput: (model.cost.output / 1000000) * output,\n\t\t\tcacheRead: (model.cost.cacheRead / 1000000) * cacheReadTokens,\n\t\t\tcacheWrite: (model.cost.cacheWrite / 1000000) * cacheWriteTokens,\n\t\t\ttotal: 0,\n\t\t},\n\t};\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n\treturn usage;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openrouter-images.lazy.d.ts","sourceRoot":"","sources":["../../src/api/openrouter-images.lazy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"openrouter-images.lazy.d.ts","sourceRoot":"","sources":["../../src/api/openrouter-images.lazy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,eAAO,MAAM,mBAAmB,sBAG9B,CAAC","sourcesContent":["import type { ProviderImages } from \"../types.ts\";\n\nexport const openrouterImagesApi = (): ProviderImages => ({\n\tgenerateImages: async (model, context, options) =>\n\t\t(await import(\"./openrouter-images.ts\")).generateImages(model, context, options),\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openrouter-images.lazy.js","sourceRoot":"","sources":["../../src/api/openrouter-images.lazy.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAmB,EAAE,CAAC,CAAC;IACzD,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CACjD,CAAC,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,cAAc,
|
|
1
|
+
{"version":3,"file":"openrouter-images.lazy.js","sourceRoot":"","sources":["../../src/api/openrouter-images.lazy.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAmB,EAAE,CAAC,CAAC;IACzD,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CACjD,CAAC,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC;CACjF,CAAC,CAAC","sourcesContent":["import type { ProviderImages } from \"../types.ts\";\n\nexport const openrouterImagesApi = (): ProviderImages => ({\n\tgenerateImages: async (model, context, options) =>\n\t\t(await import(\"./openrouter-images.ts\")).generateImages(model, context, options),\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pi-messages.d.ts","sourceRoot":"","sources":["../../src/api/pi-messages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * pi-messages API implementation.\n *\n * Streams pi's own message protocol directly to a backend: the request is a\n * single POST of `{ model, context, options }` to `<baseUrl>/messages`, the\n * response is an SSE stream of serialized assistant-message events plus a\n * terminal `done`/`error` event. This is the wire protocol spoken by the\n * Radius gateway, but any backend implementing it can be used, e.g. via a\n * models.json custom provider with `\"api\": \"pi-messages\"`.\n */\n\nimport type {\n\tAssistantMessage,\n\tAssistantMessageEvent,\n\tCacheRetention,\n\tJsonObject,\n\tJsonValue,\n\tModel,\n\tProviderEnv,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tThinkingLevel,\n\tToolCall,\n\tTranscriptContext,\n} from \"../types.ts\";\nimport { appendAssistantMessageDiagnostic, createAssistantMessageDiagnostic } from \"../utils/diagnostics.ts\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { headersToRecord, providerHeadersToRecord } from \"../utils/headers.ts\";\nimport { parseStreamingJson } from \"../utils/json-parse.ts\";\nimport { getProviderEnvValue } from \"../utils/provider-env.ts\";\nimport { createStreamDeadline, withStreamDeadline } from \"../utils/stream-deadline.ts\";\n\nexport interface PiMessagesOptions extends StreamOptions {\n\treasoning?: ThinkingLevel;\n\ttoolChoice?: \"auto\" | \"none\" | \"required\" | { type: \"function\"; function: { name: string } };\n\t/** Ask the backend for debug metadata (e.g. routing response headers). */\n\tdebug?: boolean;\n}\n\ntype PiMessagesUsage = AssistantMessage[\"usage\"];\ntype PiMessagesStopReason = AssistantMessage[\"stopReason\"];\n\n/** Impact summary of a server-side message rewrite (e.g. a gateway policy). */\nexport type PiMessagesRewriteImpact = {\n\tpolicyId: string;\n\tpolicyVersion: number;\n\tchanged: boolean;\n\ttokenCountChange: number;\n\tmessageCountChange: number;\n\tsystemPromptChanged: boolean;\n};\n\n/** Serialized assistant-message event as sent by a pi-messages backend. */\nexport type PiMessagesEvent =\n\t| { type: \"start\" }\n\t| { type: \"text_start\"; contentIndex: number }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string }\n\t| { type: \"text_end\"; contentIndex: number; content: string; contentSignature?: string }\n\t| { type: \"thinking_start\"; contentIndex: number }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string }\n\t| {\n\t\t\ttype: \"thinking_end\";\n\t\t\tcontentIndex: number;\n\t\t\tcontent: string;\n\t\t\tcontentSignature?: string;\n\t\t\tredacted?: boolean;\n\t }\n\t| { type: \"toolcall_start\"; contentIndex: number; id: string; toolName: string }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string }\n\t| { type: \"toolcall_end\"; contentIndex: number; toolCall: ToolCall }\n\t| {\n\t\t\ttype: \"done\";\n\t\t\treason: Extract<PiMessagesStopReason, \"stop\" | \"length\" | \"toolUse\">;\n\t\t\tusage: PiMessagesUsage;\n\t\t\tresponseId?: string;\n\t\t\tproviderThinkingLevel?: string;\n\t\t\trewrite?: PiMessagesRewriteImpact;\n\t }\n\t| {\n\t\t\ttype: \"error\";\n\t\t\treason: Extract<PiMessagesStopReason, \"aborted\" | \"error\">;\n\t\t\tusage: PiMessagesUsage;\n\t\t\terrorMessage?: string;\n\t\t\tresponseId?: string;\n\t\t\tproviderThinkingLevel?: string;\n\t\t\trewrite?: PiMessagesRewriteImpact;\n\t };\n\ntype PiMessagesErrorBody = {\n\terror?: {\n\t\tmessage?: unknown;\n\t\tcode?: unknown;\n\t\tdetails?: unknown;\n\t\t[key: string]: unknown;\n\t};\n};\n\nexport class PiMessagesResponseError extends Error {\n\tcode?: string;\n\treadonly diagnosticDetails: JsonObject;\n\n\tconstructor(message: string, code: string | undefined, diagnosticDetails: JsonObject) {\n\t\tsuper(message);\n\t\tthis.name = \"PiMessagesResponseError\";\n\t\tthis.code = code;\n\t\tthis.diagnosticDetails = diagnosticDetails;\n\t}\n}\n\nfunction parsePiMessagesErrorBody(body: string): PiMessagesErrorBody | undefined {\n\ttry {\n\t\tconst parsed = JSON.parse(body) as PiMessagesErrorBody | null;\n\t\tconst error = parsed?.error;\n\t\treturn parsed && typeof error === \"object\" && error !== null && !Array.isArray(error) ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction truncateDiagnosticString(value: string): string {\n\tconst maxLength = 8192;\n\treturn value.length > maxLength ? `${value.slice(0, maxLength)}…` : value;\n}\n\nfunction formatPiMessagesResponseError(\n\tresponse: Response,\n\tbody: string,\n\terrorBody: PiMessagesErrorBody | undefined,\n): string {\n\tconst message = typeof errorBody?.error?.message === \"string\" ? errorBody.error.message : undefined;\n\tconst code = typeof errorBody?.error?.code === \"string\" ? errorBody.error.code : undefined;\n\tconst suffix = message ?? body;\n\tconst codeSuffix = code ? ` (${code})` : \"\";\n\treturn `${response.status} ${response.statusText}: ${suffix}${codeSuffix}`;\n}\n\nfunction createPiMessagesResponseError(\n\tmodel: Model<\"pi-messages\">,\n\turl: URL,\n\tresponse: Response,\n\tbody: string,\n): PiMessagesResponseError {\n\tconst errorBody = parsePiMessagesErrorBody(body);\n\tconst code = typeof errorBody?.error?.code === \"string\" ? errorBody.error.code : undefined;\n\treturn new PiMessagesResponseError(formatPiMessagesResponseError(response, body, errorBody), code, {\n\t\tversion: 1,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\turl: url.toString(),\n\t\tstatus: response.status,\n\t\tstatusText: response.statusText,\n\t\t...(errorBody?.error === undefined ? {} : { error: errorBody.error as JsonValue }),\n\t\t...(errorBody ? {} : { body: truncateDiagnosticString(body) }),\n\t\ttimestampMs: Date.now(),\n\t});\n}\n\nfunction createEmptyUsage(): PiMessagesUsage {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotalTokens: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\nfunction appendRewriteDiagnostic(message: AssistantMessage, rewrite: PiMessagesRewriteImpact | undefined): void {\n\tif (!rewrite) {\n\t\treturn;\n\t}\n\tappendAssistantMessageDiagnostic(message, {\n\t\ttype: \"pi_messages_rewrite\",\n\t\ttimestamp: Date.now(),\n\t\tdetails: { ...rewrite },\n\t});\n}\n\nfunction createEventConverter(model: Model<\"pi-messages\">) {\n\tconst partial: AssistantMessage = {\n\t\trole: \"assistant\",\n\t\tcontent: [],\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\tusage: createEmptyUsage(),\n\t\tstopReason: \"pending\",\n\t\ttimestamp: Date.now(),\n\t};\n\tconst toolJson = new Map<number, string>();\n\n\treturn (event: PiMessagesEvent): AssistantMessageEvent => {\n\t\tswitch (event.type) {\n\t\t\tcase \"done\":\n\t\t\t\tObject.assign(partial, {\n\t\t\t\t\tstopReason: event.reason,\n\t\t\t\t\tusage: event.usage,\n\t\t\t\t\tresponseId: event.responseId,\n\t\t\t\t});\n\t\t\t\tif (event.providerThinkingLevel !== undefined) {\n\t\t\t\t\tpartial.providerThinkingLevel = event.providerThinkingLevel;\n\t\t\t\t}\n\t\t\t\tappendRewriteDiagnostic(partial, event.rewrite);\n\t\t\t\treturn { type: \"done\", reason: event.reason, message: partial };\n\t\t\tcase \"error\":\n\t\t\t\tObject.assign(partial, {\n\t\t\t\t\tstopReason: event.reason,\n\t\t\t\t\tusage: event.usage,\n\t\t\t\t\terrorMessage: event.errorMessage,\n\t\t\t\t\tresponseId: event.responseId,\n\t\t\t\t});\n\t\t\t\tif (event.providerThinkingLevel !== undefined) {\n\t\t\t\t\tpartial.providerThinkingLevel = event.providerThinkingLevel;\n\t\t\t\t}\n\t\t\t\tappendRewriteDiagnostic(partial, event.rewrite);\n\t\t\t\treturn { type: \"error\", reason: event.reason, error: partial };\n\t\t\tcase \"start\":\n\t\t\t\tbreak;\n\t\t\tcase \"text_start\":\n\t\t\t\tpartial.content[event.contentIndex] = { type: \"text\", text: \"\" };\n\t\t\t\tbreak;\n\t\t\tcase \"text_delta\":\n\t\t\t\t(partial.content[event.contentIndex] as { text: string }).text += event.delta;\n\t\t\t\tbreak;\n\t\t\tcase \"text_end\":\n\t\t\t\tObject.assign(partial.content[event.contentIndex]!, {\n\t\t\t\t\ttext: event.content,\n\t\t\t\t\ttextSignature: event.contentSignature,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"thinking_start\":\n\t\t\t\tpartial.content[event.contentIndex] = { type: \"thinking\", thinking: \"\" };\n\t\t\t\tbreak;\n\t\t\tcase \"thinking_delta\":\n\t\t\t\t(partial.content[event.contentIndex] as { thinking: string }).thinking += event.delta;\n\t\t\t\tbreak;\n\t\t\tcase \"thinking_end\":\n\t\t\t\tObject.assign(partial.content[event.contentIndex]!, {\n\t\t\t\t\tthinking: event.content,\n\t\t\t\t\tthinkingSignature: event.contentSignature,\n\t\t\t\t\tredacted: event.redacted,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"toolcall_start\":\n\t\t\t\tpartial.content[event.contentIndex] = {\n\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\tid: event.id,\n\t\t\t\t\tname: event.toolName,\n\t\t\t\t\targuments: {},\n\t\t\t\t};\n\t\t\t\ttoolJson.set(event.contentIndex, \"\");\n\t\t\t\tbreak;\n\t\t\tcase \"toolcall_delta\": {\n\t\t\t\tconst json = `${toolJson.get(event.contentIndex) ?? \"\"}${event.delta}`;\n\t\t\t\ttoolJson.set(event.contentIndex, json);\n\t\t\t\t(partial.content[event.contentIndex] as ToolCall).arguments =\n\t\t\t\t\tparseStreamingJson<ToolCall[\"arguments\"]>(json);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"toolcall_end\":\n\t\t\t\tObject.assign(partial.content[event.contentIndex]!, event.toolCall);\n\t\t\t\ttoolJson.delete(event.contentIndex);\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\t\ttoolCall: partial.content[event.contentIndex] as ToolCall,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t}\n\n\t\treturn { ...event, partial } as AssistantMessageEvent;\n\t};\n}\n\nasync function* readPiMessagesEvents(\n\tstream: ReadableStream<Uint8Array>,\n\tsignal?: AbortSignal,\n): AsyncGenerator<PiMessagesEvent> {\n\tconst decoder = new TextDecoder();\n\tconst reader = stream.getReader();\n\tlet buffer = \"\";\n\tconst onAbort = () => {\n\t\tvoid reader.cancel().catch(() => {});\n\t};\n\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\ttry {\n\t\twhile (true) {\n\t\t\tif (signal?.aborted) throw signal.reason ?? new Error(\"Request was aborted\");\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (signal?.aborted) throw signal.reason ?? new Error(\"Request was aborted\");\n\t\t\tbuffer += done ? decoder.decode() : decoder.decode(value, { stream: true });\n\t\t\tbuffer = buffer.replace(/\\r\\n/g, \"\\n\");\n\n\t\t\tlet split = buffer.indexOf(\"\\n\\n\");\n\t\t\twhile (split !== -1) {\n\t\t\t\tconst event = parsePiMessagesEvent(buffer.slice(0, split));\n\t\t\t\tif (event) {\n\t\t\t\t\tyield event;\n\t\t\t\t}\n\t\t\t\tbuffer = buffer.slice(split + 2);\n\t\t\t\tsplit = buffer.indexOf(\"\\n\\n\");\n\t\t\t}\n\n\t\t\tif (done) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (buffer.trim()) {\n\t\t\tconst event = parsePiMessagesEvent(buffer);\n\t\t\tif (event) {\n\t\t\t\tyield event;\n\t\t\t}\n\t\t}\n\t} finally {\n\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\ttry {\n\t\t\tawait reader.cancel();\n\t\t} catch {}\n\t\treader.releaseLock();\n\t}\n}\n\nfunction parsePiMessagesEvent(raw: string): PiMessagesEvent | undefined {\n\tconst data = raw\n\t\t.split(\"\\n\")\n\t\t.find((line) => line.startsWith(\"data:\"))\n\t\t?.slice(5)\n\t\t.trim();\n\n\treturn data && data !== \"[DONE]\" ? (JSON.parse(data) as PiMessagesEvent) : undefined;\n}\n\nfunction createErrorEvent(model: Model<\"pi-messages\">, error: unknown, aborted: boolean): AssistantMessageEvent {\n\tconst reason = aborted ? \"aborted\" : \"error\";\n\tconst assistantMessage: AssistantMessage = {\n\t\trole: \"assistant\",\n\t\tcontent: [],\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\tusage: createEmptyUsage(),\n\t\tstopReason: reason,\n\t\terrorMessage: error instanceof Error ? error.message : String(error),\n\t\ttimestamp: Date.now(),\n\t};\n\n\tif (!aborted && error instanceof PiMessagesResponseError) {\n\t\tappendAssistantMessageDiagnostic(\n\t\t\tassistantMessage,\n\t\t\tcreateAssistantMessageDiagnostic(\"pi_messages_response_failure\", error, error.diagnosticDetails),\n\t\t);\n\t}\n\n\treturn { type: \"error\", reason, error: assistantMessage };\n}\n\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention | undefined {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\t// Backend defaults apply when unset; only the legacy env opt-in is mapped.\n\treturn getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\" ? \"long\" : undefined;\n}\n\nexport const stream: StreamFunction<\"pi-messages\", PiMessagesOptions> = (\n\tmodel: Model<\"pi-messages\">,\n\tcontext: TranscriptContext,\n\toptions?: PiMessagesOptions,\n): AssistantMessageEventStream => {\n\tconst eventStream = new AssistantMessageEventStream();\n\tconst convertEvent = createEventConverter(model);\n\n\tvoid (async () => {\n\t\tconst streamDeadline = createStreamDeadline(options?.streamDeadlineMs, options?.signal);\n\t\ttry {\n\t\t\tconst apiKey = options?.apiKey;\n\t\t\tif (!apiKey) {\n\t\t\t\tthrow new Error(`No API key provided for provider \"${model.provider}\"`);\n\t\t\t}\n\n\t\t\tconst url = new URL(`${model.baseUrl.replace(/\\/+$/u, \"\")}/messages`);\n\t\t\tif (options?.debug) {\n\t\t\t\turl.searchParams.set(\"debug\", \"1\");\n\t\t\t}\n\n\t\t\tlet payload: unknown = {\n\t\t\t\tmodel: model.id,\n\t\t\t\tcontext,\n\t\t\t\toptions: {\n\t\t\t\t\ttemperature: options?.temperature,\n\t\t\t\t\tmaxTokens: options?.maxTokens,\n\t\t\t\t\treasoning: options?.reasoning,\n\t\t\t\t\tcacheRetention: resolveCacheRetention(options?.cacheRetention, options?.env),\n\t\t\t\t\tsessionId: options?.sessionId,\n\t\t\t\t\ttoolChoice: options?.toolChoice,\n\t\t\t\t},\n\t\t\t};\n\t\t\tconst nextPayload = await options?.onPayload?.(payload, model);\n\t\t\tif (nextPayload !== undefined) {\n\t\t\t\tpayload = nextPayload;\n\t\t\t}\n\n\t\t\tconst response = await (options?.fetch ?? globalThis.fetch)(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tauthorization: `Bearer ${apiKey}`,\n\t\t\t\t\taccept: \"text/event-stream\",\n\t\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\t\t...providerHeadersToRecord({ ...model.headers, ...options?.headers }),\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\tsignal: streamDeadline.signal,\n\t\t\t});\n\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst body = await response.text();\n\t\t\t\tthrow createPiMessagesResponseError(model, url, response, body);\n\t\t\t}\n\t\t\tif (!response.body) {\n\t\t\t\tthrow new Error(`${model.provider} response has no body`);\n\t\t\t}\n\n\t\t\tfor await (const piEvent of withStreamDeadline(\n\t\t\t\treadPiMessagesEvents(response.body, streamDeadline.signal),\n\t\t\t\tstreamDeadline.deadlineMs,\n\t\t\t\tstreamDeadline.abort,\n\t\t\t)) {\n\t\t\t\tconst event = convertEvent(piEvent);\n\t\t\t\teventStream.push(event);\n\t\t\t\tif (event.type === \"done\" || event.type === \"error\") {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow new Error(`${model.provider} stream ended without a terminal event`);\n\t\t} catch (error) {\n\t\t\teventStream.push(createErrorEvent(model, error, options?.signal?.aborted ?? false));\n\t\t} finally {\n\t\t\tstreamDeadline.cleanup();\n\t\t}\n\t})();\n\n\treturn eventStream;\n};\n\nexport const streamSimple: StreamFunction<\"pi-messages\", SimpleStreamOptions> = (\n\tmodel: Model<\"pi-messages\">,\n\tcontext: TranscriptContext,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst extra = options as PiMessagesOptions | undefined;\n\treturn stream(model, context, {\n\t\t...options,\n\t\treasoning: options?.reasoning,\n\t\ttoolChoice: options?.toolChoice,\n\t\tdebug: extra?.debug,\n\t});\n};\n"]}
|
|
1
|
+
{"version":3,"file":"pi-messages.d.ts","sourceRoot":"","sources":["../../src/api/pi-messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACX,gBAAgB,EAGhB,UAAU,EAIV,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,aAAa,EACb,QAAQ,EAER,MAAM,aAAa,CAAC;AAQrB,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACvD,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAC7F,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,KAAK,eAAe,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;AACjD,KAAK,oBAAoB,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;AAE3D,+EAA+E;AAC/E,MAAM,MAAM,uBAAuB,GAAG;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,eAAe,GACxB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/D;IACA,IAAI,EAAE,cAAc,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;CAClB,GACD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAClE;IACA,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC,oBAAoB,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC;IACrE,KAAK,EAAE,eAAe,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,EAAE,uBAAuB,CAAC;CACjC,GACD;IACA,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC,oBAAoB,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC;IAC3D,KAAK,EAAE,eAAe,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,EAAE,uBAAuB,CAAC;CACjC,CAAC;AAWL,qBAAa,uBAAwB,SAAQ,KAAK;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,iBAAiB,EAAE,UAAU,CAAC;IAEvC,YAAY,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,iBAAiB,EAAE,UAAU,EAKnF;CACD;AAoQD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,aAAa,EAAE,iBAAiB,CAkFnE,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,aAAa,EAAE,mBAAmB,CAY3E,CAAC","sourcesContent":["/**\n * pi-messages API implementation.\n *\n * Streams pi's own message protocol directly to a backend: the request is a\n * single POST of `{ model, context, options }` to `<baseUrl>/messages`, the\n * response is an SSE stream of serialized assistant-message events plus a\n * terminal `done`/`error` event. This is the wire protocol spoken by the\n * Radius gateway, but any backend implementing it can be used, e.g. via a\n * models.json custom provider with `\"api\": \"pi-messages\"`.\n */\n\nimport type {\n\tAssistantMessage,\n\tAssistantMessageEvent,\n\tCacheRetention,\n\tJsonObject,\n\tJsonValue,\n\tModel,\n\tProviderEnv,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tThinkingLevel,\n\tToolCall,\n\tTranscriptContext,\n} from \"../types.ts\";\nimport { appendAssistantMessageDiagnostic, createAssistantMessageDiagnostic } from \"../utils/diagnostics.ts\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { headersToRecord, providerHeadersToRecord } from \"../utils/headers.ts\";\nimport { parseStreamingJson } from \"../utils/json-parse.ts\";\nimport { getProviderEnvValue } from \"../utils/provider-env.ts\";\nimport { createStreamDeadline, withStreamDeadline } from \"../utils/stream-deadline.ts\";\n\nexport interface PiMessagesOptions extends StreamOptions {\n\treasoning?: ThinkingLevel;\n\ttoolChoice?: \"auto\" | \"none\" | \"required\" | { type: \"function\"; function: { name: string } };\n\t/** Ask the backend for debug metadata (e.g. routing response headers). */\n\tdebug?: boolean;\n}\n\ntype PiMessagesUsage = AssistantMessage[\"usage\"];\ntype PiMessagesStopReason = AssistantMessage[\"stopReason\"];\n\n/** Impact summary of a server-side message rewrite (e.g. a gateway policy). */\nexport type PiMessagesRewriteImpact = {\n\tpolicyId: string;\n\tpolicyVersion: number;\n\tchanged: boolean;\n\ttokenCountChange: number;\n\tmessageCountChange: number;\n\tsystemPromptChanged: boolean;\n};\n\n/** Serialized assistant-message event as sent by a pi-messages backend. */\nexport type PiMessagesEvent =\n\t| { type: \"start\" }\n\t| { type: \"text_start\"; contentIndex: number }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string }\n\t| { type: \"text_end\"; contentIndex: number; content: string; contentSignature?: string }\n\t| { type: \"thinking_start\"; contentIndex: number }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string }\n\t| {\n\t\t\ttype: \"thinking_end\";\n\t\t\tcontentIndex: number;\n\t\t\tcontent: string;\n\t\t\tcontentSignature?: string;\n\t\t\tredacted?: boolean;\n\t }\n\t| { type: \"toolcall_start\"; contentIndex: number; id: string; toolName: string }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string }\n\t| { type: \"toolcall_end\"; contentIndex: number; toolCall: ToolCall }\n\t| {\n\t\t\ttype: \"done\";\n\t\t\treason: Extract<PiMessagesStopReason, \"stop\" | \"length\" | \"toolUse\">;\n\t\t\tusage: PiMessagesUsage;\n\t\t\tresponseId?: string;\n\t\t\tproviderThinkingLevel?: string;\n\t\t\trewrite?: PiMessagesRewriteImpact;\n\t }\n\t| {\n\t\t\ttype: \"error\";\n\t\t\treason: Extract<PiMessagesStopReason, \"aborted\" | \"error\">;\n\t\t\tusage: PiMessagesUsage;\n\t\t\terrorMessage?: string;\n\t\t\tresponseId?: string;\n\t\t\tproviderThinkingLevel?: string;\n\t\t\trewrite?: PiMessagesRewriteImpact;\n\t };\n\ntype PiMessagesErrorBody = {\n\terror?: {\n\t\tmessage?: unknown;\n\t\tcode?: unknown;\n\t\tdetails?: unknown;\n\t\t[key: string]: unknown;\n\t};\n};\n\nexport class PiMessagesResponseError extends Error {\n\tcode?: string;\n\treadonly diagnosticDetails: JsonObject;\n\n\tconstructor(message: string, code: string | undefined, diagnosticDetails: JsonObject) {\n\t\tsuper(message);\n\t\tthis.name = \"PiMessagesResponseError\";\n\t\tthis.code = code;\n\t\tthis.diagnosticDetails = diagnosticDetails;\n\t}\n}\n\nfunction parsePiMessagesErrorBody(body: string): PiMessagesErrorBody | undefined {\n\ttry {\n\t\tconst parsed = JSON.parse(body) as PiMessagesErrorBody | null;\n\t\tconst error = parsed?.error;\n\t\treturn parsed && typeof error === \"object\" && error !== null && !Array.isArray(error) ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction truncateDiagnosticString(value: string): string {\n\tconst maxLength = 8192;\n\treturn value.length > maxLength ? `${value.slice(0, maxLength)}…` : value;\n}\n\nfunction formatPiMessagesResponseError(\n\tresponse: Response,\n\tbody: string,\n\terrorBody: PiMessagesErrorBody | undefined,\n): string {\n\tconst message = typeof errorBody?.error?.message === \"string\" ? errorBody.error.message : undefined;\n\tconst code = typeof errorBody?.error?.code === \"string\" ? errorBody.error.code : undefined;\n\tconst suffix = message ?? body;\n\tconst codeSuffix = code ? ` (${code})` : \"\";\n\treturn `${response.status} ${response.statusText}: ${suffix}${codeSuffix}`;\n}\n\nfunction createPiMessagesResponseError(\n\tmodel: Model<\"pi-messages\">,\n\turl: URL,\n\tresponse: Response,\n\tbody: string,\n): PiMessagesResponseError {\n\tconst errorBody = parsePiMessagesErrorBody(body);\n\tconst code = typeof errorBody?.error?.code === \"string\" ? errorBody.error.code : undefined;\n\treturn new PiMessagesResponseError(formatPiMessagesResponseError(response, body, errorBody), code, {\n\t\tversion: 1,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\turl: url.toString(),\n\t\tstatus: response.status,\n\t\tstatusText: response.statusText,\n\t\t...(errorBody?.error === undefined ? {} : { error: errorBody.error as JsonValue }),\n\t\t...(errorBody ? {} : { body: truncateDiagnosticString(body) }),\n\t\ttimestampMs: Date.now(),\n\t});\n}\n\nfunction createEmptyUsage(): PiMessagesUsage {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotalTokens: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\nfunction appendRewriteDiagnostic(message: AssistantMessage, rewrite: PiMessagesRewriteImpact | undefined): void {\n\tif (!rewrite) {\n\t\treturn;\n\t}\n\tappendAssistantMessageDiagnostic(message, {\n\t\ttype: \"pi_messages_rewrite\",\n\t\ttimestamp: Date.now(),\n\t\tdetails: { ...rewrite },\n\t});\n}\n\nfunction createEventConverter(model: Model<\"pi-messages\">) {\n\tconst partial: AssistantMessage = {\n\t\trole: \"assistant\",\n\t\tcontent: [],\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\tusage: createEmptyUsage(),\n\t\tstopReason: \"pending\",\n\t\ttimestamp: Date.now(),\n\t};\n\tconst toolJson = new Map<number, string>();\n\n\treturn (event: PiMessagesEvent): AssistantMessageEvent => {\n\t\tswitch (event.type) {\n\t\t\tcase \"done\":\n\t\t\t\tObject.assign(partial, {\n\t\t\t\t\tstopReason: event.reason,\n\t\t\t\t\tusage: event.usage,\n\t\t\t\t\tresponseId: event.responseId,\n\t\t\t\t});\n\t\t\t\tif (event.providerThinkingLevel !== undefined) {\n\t\t\t\t\tpartial.providerThinkingLevel = event.providerThinkingLevel;\n\t\t\t\t}\n\t\t\t\tappendRewriteDiagnostic(partial, event.rewrite);\n\t\t\t\treturn { type: \"done\", reason: event.reason, message: partial };\n\t\t\tcase \"error\":\n\t\t\t\tObject.assign(partial, {\n\t\t\t\t\tstopReason: event.reason,\n\t\t\t\t\tusage: event.usage,\n\t\t\t\t\terrorMessage: event.errorMessage,\n\t\t\t\t\tresponseId: event.responseId,\n\t\t\t\t});\n\t\t\t\tif (event.providerThinkingLevel !== undefined) {\n\t\t\t\t\tpartial.providerThinkingLevel = event.providerThinkingLevel;\n\t\t\t\t}\n\t\t\t\tappendRewriteDiagnostic(partial, event.rewrite);\n\t\t\t\treturn { type: \"error\", reason: event.reason, error: partial };\n\t\t\tcase \"start\":\n\t\t\t\tbreak;\n\t\t\tcase \"text_start\":\n\t\t\t\tpartial.content[event.contentIndex] = { type: \"text\", text: \"\" };\n\t\t\t\tbreak;\n\t\t\tcase \"text_delta\":\n\t\t\t\t(partial.content[event.contentIndex] as { text: string }).text += event.delta;\n\t\t\t\tbreak;\n\t\t\tcase \"text_end\":\n\t\t\t\tObject.assign(partial.content[event.contentIndex]!, {\n\t\t\t\t\ttext: event.content,\n\t\t\t\t\ttextSignature: event.contentSignature,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"thinking_start\":\n\t\t\t\tpartial.content[event.contentIndex] = { type: \"thinking\", thinking: \"\" };\n\t\t\t\tbreak;\n\t\t\tcase \"thinking_delta\":\n\t\t\t\t(partial.content[event.contentIndex] as { thinking: string }).thinking += event.delta;\n\t\t\t\tbreak;\n\t\t\tcase \"thinking_end\":\n\t\t\t\tObject.assign(partial.content[event.contentIndex]!, {\n\t\t\t\t\tthinking: event.content,\n\t\t\t\t\tthinkingSignature: event.contentSignature,\n\t\t\t\t\tredacted: event.redacted,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"toolcall_start\":\n\t\t\t\tpartial.content[event.contentIndex] = {\n\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\tid: event.id,\n\t\t\t\t\tname: event.toolName,\n\t\t\t\t\targuments: {},\n\t\t\t\t};\n\t\t\t\ttoolJson.set(event.contentIndex, \"\");\n\t\t\t\tbreak;\n\t\t\tcase \"toolcall_delta\": {\n\t\t\t\tconst json = `${toolJson.get(event.contentIndex) ?? \"\"}${event.delta}`;\n\t\t\t\ttoolJson.set(event.contentIndex, json);\n\t\t\t\t(partial.content[event.contentIndex] as ToolCall).arguments =\n\t\t\t\t\tparseStreamingJson<ToolCall[\"arguments\"]>(json);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"toolcall_end\":\n\t\t\t\tObject.assign(partial.content[event.contentIndex]!, event.toolCall);\n\t\t\t\ttoolJson.delete(event.contentIndex);\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\t\ttoolCall: partial.content[event.contentIndex] as ToolCall,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t}\n\n\t\treturn { ...event, partial } as AssistantMessageEvent;\n\t};\n}\n\nasync function* readPiMessagesEvents(\n\tstream: ReadableStream<Uint8Array>,\n\tsignal?: AbortSignal,\n): AsyncGenerator<PiMessagesEvent> {\n\tconst decoder = new TextDecoder();\n\tconst reader = stream.getReader();\n\tlet buffer = \"\";\n\tconst onAbort = () => {\n\t\tvoid reader.cancel().catch(() => {});\n\t};\n\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\ttry {\n\t\twhile (true) {\n\t\t\tif (signal?.aborted) throw signal.reason ?? new Error(\"Request was aborted\");\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (signal?.aborted) throw signal.reason ?? new Error(\"Request was aborted\");\n\t\t\tbuffer += done ? decoder.decode() : decoder.decode(value, { stream: true });\n\t\t\tbuffer = buffer.replace(/\\r\\n/g, \"\\n\");\n\n\t\t\tlet split = buffer.indexOf(\"\\n\\n\");\n\t\t\twhile (split !== -1) {\n\t\t\t\tconst event = parsePiMessagesEvent(buffer.slice(0, split));\n\t\t\t\tif (event) {\n\t\t\t\t\tyield event;\n\t\t\t\t}\n\t\t\t\tbuffer = buffer.slice(split + 2);\n\t\t\t\tsplit = buffer.indexOf(\"\\n\\n\");\n\t\t\t}\n\n\t\t\tif (done) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (buffer.trim()) {\n\t\t\tconst event = parsePiMessagesEvent(buffer);\n\t\t\tif (event) {\n\t\t\t\tyield event;\n\t\t\t}\n\t\t}\n\t} finally {\n\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\ttry {\n\t\t\tawait reader.cancel();\n\t\t} catch {}\n\t\treader.releaseLock();\n\t}\n}\n\nfunction parsePiMessagesEvent(raw: string): PiMessagesEvent | undefined {\n\tconst data = raw\n\t\t.split(\"\\n\")\n\t\t.find((line) => line.startsWith(\"data:\"))\n\t\t?.slice(5)\n\t\t.trim();\n\n\treturn data && data !== \"[DONE]\" ? (JSON.parse(data) as PiMessagesEvent) : undefined;\n}\n\nfunction createErrorEvent(model: Model<\"pi-messages\">, error: unknown, aborted: boolean): AssistantMessageEvent {\n\tconst reason = aborted ? \"aborted\" : \"error\";\n\tconst assistantMessage: AssistantMessage = {\n\t\trole: \"assistant\",\n\t\tcontent: [],\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\tusage: createEmptyUsage(),\n\t\tstopReason: reason,\n\t\terrorMessage: error instanceof Error ? error.message : String(error),\n\t\ttimestamp: Date.now(),\n\t};\n\n\tif (!aborted && error instanceof PiMessagesResponseError) {\n\t\tappendAssistantMessageDiagnostic(\n\t\t\tassistantMessage,\n\t\t\tcreateAssistantMessageDiagnostic(\"pi_messages_response_failure\", error, error.diagnosticDetails),\n\t\t);\n\t}\n\n\treturn { type: \"error\", reason, error: assistantMessage };\n}\n\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention | undefined {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\t// Backend defaults apply when unset; only the legacy env opt-in is mapped.\n\treturn getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\" ? \"long\" : undefined;\n}\n\nexport const stream: StreamFunction<\"pi-messages\", PiMessagesOptions> = (\n\tmodel: Model<\"pi-messages\">,\n\tcontext: TranscriptContext,\n\toptions?: PiMessagesOptions,\n): AssistantMessageEventStream => {\n\tconst eventStream = new AssistantMessageEventStream();\n\tconst convertEvent = createEventConverter(model);\n\n\tvoid (async () => {\n\t\tconst streamDeadline = createStreamDeadline(options?.streamDeadlineMs, options?.signal);\n\t\ttry {\n\t\t\tconst apiKey = options?.apiKey;\n\t\t\tif (!apiKey) {\n\t\t\t\tthrow new Error(`No API key provided for provider \"${model.provider}\"`);\n\t\t\t}\n\n\t\t\tconst url = new URL(`${model.baseUrl.replace(/\\/+$/u, \"\")}/messages`);\n\t\t\tif (options?.debug) {\n\t\t\t\turl.searchParams.set(\"debug\", \"1\");\n\t\t\t}\n\n\t\t\tlet payload: unknown = {\n\t\t\t\tmodel: model.id,\n\t\t\t\tcontext,\n\t\t\t\toptions: {\n\t\t\t\t\ttemperature: options?.temperature,\n\t\t\t\t\tmaxTokens: options?.maxTokens,\n\t\t\t\t\treasoning: options?.reasoning,\n\t\t\t\t\tcacheRetention: resolveCacheRetention(options?.cacheRetention, options?.env),\n\t\t\t\t\tsessionId: options?.sessionId,\n\t\t\t\t\ttoolChoice: options?.toolChoice,\n\t\t\t\t},\n\t\t\t};\n\t\t\tconst nextPayload = await options?.onPayload?.(payload, model);\n\t\t\tif (nextPayload !== undefined) {\n\t\t\t\tpayload = nextPayload;\n\t\t\t}\n\n\t\t\tconst response = await (options?.fetch ?? globalThis.fetch)(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tauthorization: `Bearer ${apiKey}`,\n\t\t\t\t\taccept: \"text/event-stream\",\n\t\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\t\t...providerHeadersToRecord({ ...model.headers, ...options?.headers }),\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\tsignal: streamDeadline.signal,\n\t\t\t});\n\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst body = await response.text();\n\t\t\t\tthrow createPiMessagesResponseError(model, url, response, body);\n\t\t\t}\n\t\t\tif (!response.body) {\n\t\t\t\tthrow new Error(`${model.provider} response has no body`);\n\t\t\t}\n\n\t\t\tfor await (const piEvent of withStreamDeadline(\n\t\t\t\treadPiMessagesEvents(response.body, streamDeadline.signal),\n\t\t\t\tstreamDeadline.deadlineMs,\n\t\t\t\tstreamDeadline.abort,\n\t\t\t)) {\n\t\t\t\tawait options?.onProviderStreamEvent?.(piEvent, model);\n\t\t\t\tconst event = convertEvent(piEvent);\n\t\t\t\teventStream.push(event);\n\t\t\t\tif (event.type === \"done\" || event.type === \"error\") {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow new Error(`${model.provider} stream ended without a terminal event`);\n\t\t} catch (error) {\n\t\t\teventStream.push(createErrorEvent(model, error, options?.signal?.aborted ?? false));\n\t\t} finally {\n\t\t\tstreamDeadline.cleanup();\n\t\t}\n\t})();\n\n\treturn eventStream;\n};\n\nexport const streamSimple: StreamFunction<\"pi-messages\", SimpleStreamOptions> = (\n\tmodel: Model<\"pi-messages\">,\n\tcontext: TranscriptContext,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst extra = options as PiMessagesOptions | undefined;\n\treturn stream(model, context, {\n\t\t...options,\n\t\treasoning: options?.reasoning,\n\t\ttoolChoice: options?.toolChoice,\n\t\tdebug: extra?.debug,\n\t});\n};\n"]}
|
package/dist/api/pi-messages.js
CHANGED
|
@@ -302,6 +302,7 @@ export const stream = (model, context, options) => {
|
|
|
302
302
|
throw new Error(`${model.provider} response has no body`);
|
|
303
303
|
}
|
|
304
304
|
for await (const piEvent of withStreamDeadline(readPiMessagesEvents(response.body, streamDeadline.signal), streamDeadline.deadlineMs, streamDeadline.abort)) {
|
|
305
|
+
await options?.onProviderStreamEvent?.(piEvent, model);
|
|
305
306
|
const event = convertEvent(piEvent);
|
|
306
307
|
eventStream.push(event);
|
|
307
308
|
if (event.type === "done" || event.type === "error") {
|