@gajae-code/ai 0.1.1
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 +2644 -0
- package/README.md +1181 -0
- package/dist/types/api-registry.d.ts +30 -0
- package/dist/types/auth-broker/client.d.ts +66 -0
- package/dist/types/auth-broker/index.d.ts +5 -0
- package/dist/types/auth-broker/refresher.d.ts +25 -0
- package/dist/types/auth-broker/remote-store.d.ts +96 -0
- package/dist/types/auth-broker/server.d.ts +32 -0
- package/dist/types/auth-broker/types.d.ts +105 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +412 -0
- package/dist/types/auth-gateway/http.d.ts +39 -0
- package/dist/types/auth-gateway/index.d.ts +3 -0
- package/dist/types/auth-gateway/server.d.ts +17 -0
- package/dist/types/auth-gateway/types.d.ts +115 -0
- package/dist/types/auth-storage.d.ts +641 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/index.d.ts +49 -0
- package/dist/types/model-cache.d.ts +17 -0
- package/dist/types/model-manager.d.ts +62 -0
- package/dist/types/model-thinking.d.ts +71 -0
- package/dist/types/models.d.ts +12 -0
- package/dist/types/provider-details.d.ts +24 -0
- package/dist/types/provider-models/bundled-references.d.ts +4 -0
- package/dist/types/provider-models/descriptors.d.ts +48 -0
- package/dist/types/provider-models/google.d.ts +20 -0
- package/dist/types/provider-models/index.d.ts +5 -0
- package/dist/types/provider-models/ollama.d.ts +7 -0
- package/dist/types/provider-models/openai-compat.d.ts +237 -0
- package/dist/types/provider-models/special.d.ts +16 -0
- package/dist/types/providers/amazon-bedrock.d.ts +36 -0
- package/dist/types/providers/anthropic-messages-server-schema.d.ts +450 -0
- package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
- package/dist/types/providers/anthropic.d.ts +188 -0
- package/dist/types/providers/aws-credentials.d.ts +43 -0
- package/dist/types/providers/aws-eventstream.d.ts +38 -0
- package/dist/types/providers/aws-sigv4.d.ts +55 -0
- package/dist/types/providers/azure-openai-responses.d.ts +15 -0
- package/dist/types/providers/cursor/gen/agent_pb.d.ts +13022 -0
- package/dist/types/providers/cursor.d.ts +42 -0
- package/dist/types/providers/error-message.d.ts +27 -0
- package/dist/types/providers/github-copilot-headers.d.ts +40 -0
- package/dist/types/providers/gitlab-duo.d.ts +27 -0
- package/dist/types/providers/google-auth.d.ts +24 -0
- package/dist/types/providers/google-gemini-cli.d.ts +72 -0
- package/dist/types/providers/google-gemini-headers.d.ts +18 -0
- package/dist/types/providers/google-shared.d.ts +163 -0
- package/dist/types/providers/google-types.d.ts +138 -0
- package/dist/types/providers/google-vertex.d.ts +7 -0
- package/dist/types/providers/google.d.ts +4 -0
- package/dist/types/providers/grammar.d.ts +1 -0
- package/dist/types/providers/kimi.d.ts +27 -0
- package/dist/types/providers/mock.d.ts +175 -0
- package/dist/types/providers/ollama.d.ts +6 -0
- package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
- package/dist/types/providers/openai-chat-server-schema.d.ts +814 -0
- package/dist/types/providers/openai-chat-server.d.ts +16 -0
- package/dist/types/providers/openai-codex/constants.d.ts +26 -0
- package/dist/types/providers/openai-codex/request-transformer.d.ts +49 -0
- package/dist/types/providers/openai-codex/response-handler.d.ts +17 -0
- package/dist/types/providers/openai-codex-responses.d.ts +67 -0
- package/dist/types/providers/openai-completions-compat.d.ts +25 -0
- package/dist/types/providers/openai-completions.d.ts +33 -0
- package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
- package/dist/types/providers/openai-responses-server.d.ts +17 -0
- package/dist/types/providers/openai-responses-shared.d.ts +89 -0
- package/dist/types/providers/openai-responses.d.ts +32 -0
- package/dist/types/providers/pi-native-client.d.ts +13 -0
- package/dist/types/providers/pi-native-server.d.ts +68 -0
- package/dist/types/providers/register-builtins.d.ts +31 -0
- package/dist/types/providers/synthetic.d.ts +26 -0
- package/dist/types/providers/transform-messages.d.ts +12 -0
- package/dist/types/providers/vision-guard.d.ts +8 -0
- package/dist/types/rate-limit-utils.d.ts +19 -0
- package/dist/types/stream.d.ts +24 -0
- package/dist/types/types.d.ts +746 -0
- package/dist/types/usage/claude.d.ts +3 -0
- package/dist/types/usage/gemini.d.ts +2 -0
- package/dist/types/usage/github-copilot.d.ts +7 -0
- package/dist/types/usage/google-antigravity.d.ts +2 -0
- package/dist/types/usage/kimi.d.ts +2 -0
- package/dist/types/usage/minimax-code.d.ts +2 -0
- package/dist/types/usage/openai-codex.d.ts +3 -0
- package/dist/types/usage/shared.d.ts +1 -0
- package/dist/types/usage/zai.d.ts +2 -0
- package/dist/types/usage.d.ts +258 -0
- package/dist/types/utils/abort.d.ts +19 -0
- package/dist/types/utils/anthropic-auth.d.ts +31 -0
- package/dist/types/utils/discovery/antigravity.d.ts +61 -0
- package/dist/types/utils/discovery/codex.d.ts +38 -0
- package/dist/types/utils/discovery/cursor.d.ts +23 -0
- package/dist/types/utils/discovery/gemini.d.ts +25 -0
- package/dist/types/utils/discovery/index.d.ts +4 -0
- package/dist/types/utils/discovery/openai-compatible.d.ts +72 -0
- package/dist/types/utils/event-stream.d.ts +28 -0
- package/dist/types/utils/fireworks-model-id.d.ts +10 -0
- package/dist/types/utils/foundry.d.ts +1 -0
- package/dist/types/utils/h2-fetch.d.ts +22 -0
- package/dist/types/utils/http-inspector.d.ts +31 -0
- package/dist/types/utils/idle-iterator.d.ts +67 -0
- package/dist/types/utils/json-parse.d.ts +10 -0
- package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +18 -0
- package/dist/types/utils/oauth/anthropic.d.ts +22 -0
- package/dist/types/utils/oauth/api-key-login.d.ts +35 -0
- package/dist/types/utils/oauth/api-key-validation.d.ts +27 -0
- package/dist/types/utils/oauth/callback-server.d.ts +57 -0
- package/dist/types/utils/oauth/cerebras.d.ts +1 -0
- package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
- package/dist/types/utils/oauth/cursor.d.ts +15 -0
- package/dist/types/utils/oauth/deepseek.d.ts +10 -0
- package/dist/types/utils/oauth/firepass.d.ts +1 -0
- package/dist/types/utils/oauth/fireworks.d.ts +1 -0
- package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
- package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
- package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
- package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
- package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
- package/dist/types/utils/oauth/huggingface.d.ts +19 -0
- package/dist/types/utils/oauth/index.d.ts +38 -0
- package/dist/types/utils/oauth/kagi.d.ts +17 -0
- package/dist/types/utils/oauth/kilo.d.ts +5 -0
- package/dist/types/utils/oauth/kimi.d.ts +21 -0
- package/dist/types/utils/oauth/litellm.d.ts +18 -0
- package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
- package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
- package/dist/types/utils/oauth/moonshot.d.ts +1 -0
- package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
- package/dist/types/utils/oauth/nvidia.d.ts +18 -0
- package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
- package/dist/types/utils/oauth/ollama.d.ts +18 -0
- package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
- package/dist/types/utils/oauth/opencode.d.ts +18 -0
- package/dist/types/utils/oauth/parallel.d.ts +17 -0
- package/dist/types/utils/oauth/perplexity.d.ts +9 -0
- package/dist/types/utils/oauth/pkce.d.ts +8 -0
- package/dist/types/utils/oauth/qianfan.d.ts +17 -0
- package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
- package/dist/types/utils/oauth/synthetic.d.ts +1 -0
- package/dist/types/utils/oauth/tavily.d.ts +17 -0
- package/dist/types/utils/oauth/together.d.ts +1 -0
- package/dist/types/utils/oauth/types.d.ts +44 -0
- package/dist/types/utils/oauth/venice.d.ts +18 -0
- package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
- package/dist/types/utils/oauth/vllm.d.ts +16 -0
- package/dist/types/utils/oauth/xiaomi.d.ts +19 -0
- package/dist/types/utils/oauth/zai.d.ts +18 -0
- package/dist/types/utils/oauth/zenmux.d.ts +1 -0
- package/dist/types/utils/overflow.d.ts +54 -0
- package/dist/types/utils/parse-bind.d.ts +23 -0
- package/dist/types/utils/provider-response.d.ts +3 -0
- package/dist/types/utils/retry-after.d.ts +3 -0
- package/dist/types/utils/retry.d.ts +26 -0
- package/dist/types/utils/schema/adapt.d.ts +24 -0
- package/dist/types/utils/schema/compatibility.d.ts +30 -0
- package/dist/types/utils/schema/dereference.d.ts +11 -0
- package/dist/types/utils/schema/draft.d.ts +10 -0
- package/dist/types/utils/schema/equality.d.ts +4 -0
- package/dist/types/utils/schema/fields.d.ts +49 -0
- package/dist/types/utils/schema/index.d.ts +13 -0
- package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
- package/dist/types/utils/schema/meta-validator.d.ts +2 -0
- package/dist/types/utils/schema/normalize.d.ts +93 -0
- package/dist/types/utils/schema/spill.d.ts +8 -0
- package/dist/types/utils/schema/stamps.d.ts +25 -0
- package/dist/types/utils/schema/types.d.ts +4 -0
- package/dist/types/utils/schema/wire.d.ts +54 -0
- package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
- package/dist/types/utils/sse-debug.d.ts +10 -0
- package/dist/types/utils/tool-call-healing.d.ts +71 -0
- package/dist/types/utils/tool-choice.d.ts +50 -0
- package/dist/types/utils/validation.d.ts +17 -0
- package/dist/types/utils.d.ts +28 -0
- package/package.json +146 -0
- package/src/api-registry.ts +96 -0
- package/src/auth-broker/client.ts +358 -0
- package/src/auth-broker/index.ts +5 -0
- package/src/auth-broker/refresher.ts +127 -0
- package/src/auth-broker/remote-store.ts +623 -0
- package/src/auth-broker/server.ts +644 -0
- package/src/auth-broker/types.ts +127 -0
- package/src/auth-broker/wire-schemas.ts +200 -0
- package/src/auth-gateway/http.ts +194 -0
- package/src/auth-gateway/index.ts +3 -0
- package/src/auth-gateway/server.ts +717 -0
- package/src/auth-gateway/types.ts +134 -0
- package/src/auth-storage.ts +4104 -0
- package/src/cli.ts +262 -0
- package/src/index.ts +54 -0
- package/src/model-cache.ts +129 -0
- package/src/model-manager.ts +450 -0
- package/src/model-thinking.ts +691 -0
- package/src/models.json +73853 -0
- package/src/models.json.d.ts +9 -0
- package/src/models.ts +56 -0
- package/src/prompts/turn-aborted-guidance.md +4 -0
- package/src/provider-details.ts +90 -0
- package/src/provider-models/bundled-references.ts +38 -0
- package/src/provider-models/descriptors.ts +308 -0
- package/src/provider-models/google.ts +91 -0
- package/src/provider-models/index.ts +5 -0
- package/src/provider-models/ollama.ts +153 -0
- package/src/provider-models/openai-compat.ts +2275 -0
- package/src/provider-models/special.ts +67 -0
- package/src/providers/amazon-bedrock.ts +849 -0
- package/src/providers/anthropic-messages-server-schema.ts +229 -0
- package/src/providers/anthropic-messages-server.ts +677 -0
- package/src/providers/anthropic.ts +2696 -0
- package/src/providers/aws-credentials.ts +501 -0
- package/src/providers/aws-eventstream.ts +185 -0
- package/src/providers/aws-sigv4.ts +218 -0
- package/src/providers/azure-openai-responses.ts +337 -0
- package/src/providers/cursor/gen/agent_pb.ts +15274 -0
- package/src/providers/cursor/proto/agent.proto +3526 -0
- package/src/providers/cursor/proto/buf.gen.yaml +6 -0
- package/src/providers/cursor/proto/buf.yaml +17 -0
- package/src/providers/cursor.ts +2561 -0
- package/src/providers/error-message.ts +21 -0
- package/src/providers/github-copilot-headers.ts +140 -0
- package/src/providers/gitlab-duo.ts +372 -0
- package/src/providers/google-auth.ts +252 -0
- package/src/providers/google-gemini-cli.ts +795 -0
- package/src/providers/google-gemini-headers.ts +41 -0
- package/src/providers/google-shared.ts +902 -0
- package/src/providers/google-types.ts +167 -0
- package/src/providers/google-vertex.ts +88 -0
- package/src/providers/google.ts +41 -0
- package/src/providers/grammar.ts +70 -0
- package/src/providers/kimi.ts +52 -0
- package/src/providers/mock.ts +500 -0
- package/src/providers/ollama.ts +544 -0
- package/src/providers/openai-anthropic-shim.ts +138 -0
- package/src/providers/openai-chat-server-schema.ts +243 -0
- package/src/providers/openai-chat-server.ts +628 -0
- package/src/providers/openai-codex/constants.ts +43 -0
- package/src/providers/openai-codex/request-transformer.ts +161 -0
- package/src/providers/openai-codex/response-handler.ts +81 -0
- package/src/providers/openai-codex-responses.ts +2598 -0
- package/src/providers/openai-completions-compat.ts +279 -0
- package/src/providers/openai-completions.ts +1853 -0
- package/src/providers/openai-responses-server-schema.ts +290 -0
- package/src/providers/openai-responses-server.ts +1183 -0
- package/src/providers/openai-responses-shared.ts +800 -0
- package/src/providers/openai-responses.ts +621 -0
- package/src/providers/pi-native-client.ts +228 -0
- package/src/providers/pi-native-server.ts +210 -0
- package/src/providers/register-builtins.ts +412 -0
- package/src/providers/synthetic.ts +50 -0
- package/src/providers/transform-messages.ts +309 -0
- package/src/providers/vision-guard.ts +31 -0
- package/src/rate-limit-utils.ts +84 -0
- package/src/stream.ts +895 -0
- package/src/types.ts +884 -0
- package/src/usage/claude.ts +431 -0
- package/src/usage/gemini.ts +250 -0
- package/src/usage/github-copilot.ts +421 -0
- package/src/usage/google-antigravity.ts +201 -0
- package/src/usage/kimi.ts +271 -0
- package/src/usage/minimax-code.ts +31 -0
- package/src/usage/openai-codex.ts +503 -0
- package/src/usage/shared.ts +10 -0
- package/src/usage/zai.ts +247 -0
- package/src/usage.ts +183 -0
- package/src/utils/abort.ts +51 -0
- package/src/utils/anthropic-auth.ts +87 -0
- package/src/utils/discovery/antigravity.ts +261 -0
- package/src/utils/discovery/codex.ts +371 -0
- package/src/utils/discovery/cursor.ts +306 -0
- package/src/utils/discovery/gemini.ts +248 -0
- package/src/utils/discovery/index.ts +4 -0
- package/src/utils/discovery/openai-compatible.ts +224 -0
- package/src/utils/event-stream.ts +142 -0
- package/src/utils/fireworks-model-id.ts +30 -0
- package/src/utils/foundry.ts +8 -0
- package/src/utils/h2-fetch.ts +60 -0
- package/src/utils/http-inspector.ts +176 -0
- package/src/utils/idle-iterator.ts +250 -0
- package/src/utils/json-parse.ts +148 -0
- package/src/utils/oauth/alibaba-coding-plan.ts +59 -0
- package/src/utils/oauth/anthropic.ts +200 -0
- package/src/utils/oauth/api-key-login.ts +87 -0
- package/src/utils/oauth/api-key-validation.ts +92 -0
- package/src/utils/oauth/callback-server.ts +276 -0
- package/src/utils/oauth/cerebras.ts +16 -0
- package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
- package/src/utils/oauth/cursor.ts +157 -0
- package/src/utils/oauth/deepseek.ts +53 -0
- package/src/utils/oauth/firepass.ts +24 -0
- package/src/utils/oauth/fireworks.ts +15 -0
- package/src/utils/oauth/github-copilot.ts +362 -0
- package/src/utils/oauth/gitlab-duo.ts +123 -0
- package/src/utils/oauth/google-antigravity.ts +200 -0
- package/src/utils/oauth/google-gemini-cli.ts +256 -0
- package/src/utils/oauth/google-oauth-shared.ts +110 -0
- package/src/utils/oauth/huggingface.ts +62 -0
- package/src/utils/oauth/index.ts +444 -0
- package/src/utils/oauth/kagi.ts +47 -0
- package/src/utils/oauth/kilo.ts +87 -0
- package/src/utils/oauth/kimi.ts +254 -0
- package/src/utils/oauth/litellm.ts +47 -0
- package/src/utils/oauth/lm-studio.ts +38 -0
- package/src/utils/oauth/minimax-code.ts +78 -0
- package/src/utils/oauth/moonshot.ts +16 -0
- package/src/utils/oauth/nanogpt.ts +15 -0
- package/src/utils/oauth/nvidia.ts +70 -0
- package/src/utils/oauth/oauth.html +199 -0
- package/src/utils/oauth/ollama-cloud.ts +28 -0
- package/src/utils/oauth/ollama.ts +47 -0
- package/src/utils/oauth/openai-codex.ts +299 -0
- package/src/utils/oauth/opencode.ts +49 -0
- package/src/utils/oauth/parallel.ts +46 -0
- package/src/utils/oauth/perplexity.ts +206 -0
- package/src/utils/oauth/pkce.ts +18 -0
- package/src/utils/oauth/qianfan.ts +58 -0
- package/src/utils/oauth/qwen-portal.ts +60 -0
- package/src/utils/oauth/synthetic.ts +16 -0
- package/src/utils/oauth/tavily.ts +46 -0
- package/src/utils/oauth/together.ts +16 -0
- package/src/utils/oauth/types.ts +94 -0
- package/src/utils/oauth/venice.ts +59 -0
- package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
- package/src/utils/oauth/vllm.ts +40 -0
- package/src/utils/oauth/xiaomi.ts +137 -0
- package/src/utils/oauth/zai.ts +60 -0
- package/src/utils/oauth/zenmux.ts +15 -0
- package/src/utils/overflow.ts +137 -0
- package/src/utils/parse-bind.ts +54 -0
- package/src/utils/provider-response.ts +30 -0
- package/src/utils/retry-after.ts +110 -0
- package/src/utils/retry.ts +54 -0
- package/src/utils/schema/CONSTRAINTS.md +164 -0
- package/src/utils/schema/adapt.ts +36 -0
- package/src/utils/schema/compatibility.ts +435 -0
- package/src/utils/schema/dereference.ts +98 -0
- package/src/utils/schema/draft.ts +341 -0
- package/src/utils/schema/equality.ts +97 -0
- package/src/utils/schema/fields.ts +190 -0
- package/src/utils/schema/index.ts +13 -0
- package/src/utils/schema/json-schema-validator.ts +577 -0
- package/src/utils/schema/meta-validator.ts +167 -0
- package/src/utils/schema/normalize.ts +1588 -0
- package/src/utils/schema/spill.ts +43 -0
- package/src/utils/schema/stamps.ts +97 -0
- package/src/utils/schema/types.ts +11 -0
- package/src/utils/schema/wire.ts +213 -0
- package/src/utils/schema/zod-decontaminate.ts +331 -0
- package/src/utils/sse-debug.ts +289 -0
- package/src/utils/tool-call-healing.ts +271 -0
- package/src/utils/tool-choice.ts +99 -0
- package/src/utils/validation.ts +1019 -0
- package/src/utils.ts +166 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Signature V4 signing for HTTP requests. WebCrypto-only — no node:crypto.
|
|
3
|
+
*
|
|
4
|
+
* Matches `@smithy/signature-v4` for our usage: header-based signing with a
|
|
5
|
+
* full SHA-256 payload hash (Bedrock requires `applyChecksum: true`).
|
|
6
|
+
*
|
|
7
|
+
* Returns the set of headers to attach to the request:
|
|
8
|
+
* - `host`
|
|
9
|
+
* - `x-amz-date`
|
|
10
|
+
* - `x-amz-content-sha256`
|
|
11
|
+
* - `x-amz-security-token` (only when credentials carry a sessionToken)
|
|
12
|
+
* - `authorization`
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export interface AwsCredentials {
|
|
16
|
+
accessKeyId: string;
|
|
17
|
+
secretAccessKey: string;
|
|
18
|
+
sessionToken?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface SignParams {
|
|
22
|
+
method: string;
|
|
23
|
+
/** Hostname only — used to build the `host` header and the canonical request. */
|
|
24
|
+
host: string;
|
|
25
|
+
/** URI path component, e.g. `/model/anthropic.Anthropic model/converse-stream`. */
|
|
26
|
+
path: string;
|
|
27
|
+
/** Optional pre-built query string (without leading `?`). */
|
|
28
|
+
query?: string;
|
|
29
|
+
/** Extra headers to sign in addition to `host`/`x-amz-*`. Names are case-insensitive. */
|
|
30
|
+
headers?: Record<string, string>;
|
|
31
|
+
body: Uint8Array;
|
|
32
|
+
region: string;
|
|
33
|
+
service: string;
|
|
34
|
+
credentials: AwsCredentials;
|
|
35
|
+
/** Override clock for deterministic tests. */
|
|
36
|
+
date?: Date;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const ALGORITHM = "AWS4-HMAC-SHA256";
|
|
40
|
+
const KEY_TYPE = "aws4_request";
|
|
41
|
+
// Headers the SDK never includes in the signature. Lowercased.
|
|
42
|
+
const UNSIGNABLE: Record<string, true> = {
|
|
43
|
+
authorization: true,
|
|
44
|
+
"cache-control": true,
|
|
45
|
+
connection: true,
|
|
46
|
+
expect: true,
|
|
47
|
+
from: true,
|
|
48
|
+
"keep-alive": true,
|
|
49
|
+
"max-forwards": true,
|
|
50
|
+
pragma: true,
|
|
51
|
+
referer: true,
|
|
52
|
+
te: true,
|
|
53
|
+
trailer: true,
|
|
54
|
+
"transfer-encoding": true,
|
|
55
|
+
upgrade: true,
|
|
56
|
+
"user-agent": true,
|
|
57
|
+
"x-amzn-trace-id": true,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/** Coerce a possibly-ArrayBufferLike-backed `Uint8Array` into one over a fresh
|
|
61
|
+
* `ArrayBuffer`, which is what `crypto.subtle.{digest,sign,importKey}` requires
|
|
62
|
+
* under the strict TS DOM typings. No-op when already strict.
|
|
63
|
+
*/
|
|
64
|
+
function asStrict(bytes: Uint8Array): Uint8Array<ArrayBuffer> {
|
|
65
|
+
if (bytes.buffer instanceof ArrayBuffer && bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength) {
|
|
66
|
+
return bytes as Uint8Array<ArrayBuffer>;
|
|
67
|
+
}
|
|
68
|
+
const copy = new Uint8Array(bytes.byteLength);
|
|
69
|
+
copy.set(bytes);
|
|
70
|
+
return copy;
|
|
71
|
+
}
|
|
72
|
+
const subtle = globalThis.crypto.subtle;
|
|
73
|
+
|
|
74
|
+
const HEX = "0123456789abcdef";
|
|
75
|
+
export function toHex(bytes: Uint8Array): string {
|
|
76
|
+
let out = "";
|
|
77
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
78
|
+
const b = bytes[i];
|
|
79
|
+
out += HEX[b >> 4] + HEX[b & 15];
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export async function sha256(data: Uint8Array | string): Promise<Uint8Array> {
|
|
85
|
+
const bytes = typeof data === "string" ? new TextEncoder().encode(data) : asStrict(data);
|
|
86
|
+
const digest = await subtle.digest("SHA-256", bytes);
|
|
87
|
+
return new Uint8Array(digest);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function sha256Hex(data: Uint8Array | string): Promise<string> {
|
|
91
|
+
return toHex(await sha256(data));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function hmac(key: Uint8Array, data: string | Uint8Array): Promise<Uint8Array> {
|
|
95
|
+
const cryptoKey = await subtle.importKey("raw", asStrict(key), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
96
|
+
const bytes = typeof data === "string" ? new TextEncoder().encode(data) : asStrict(data);
|
|
97
|
+
const sig = await subtle.sign("HMAC", cryptoKey, bytes);
|
|
98
|
+
return new Uint8Array(sig);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Derive a signing key: HMAC chain `kSecret → kDate → kRegion → kService → kSigning`.
|
|
103
|
+
*/
|
|
104
|
+
export async function getSigningKey(
|
|
105
|
+
secretAccessKey: string,
|
|
106
|
+
shortDate: string,
|
|
107
|
+
region: string,
|
|
108
|
+
service: string,
|
|
109
|
+
): Promise<Uint8Array> {
|
|
110
|
+
const kDate = await hmac(new TextEncoder().encode(`AWS4${secretAccessKey}`), shortDate);
|
|
111
|
+
const kRegion = await hmac(kDate, region);
|
|
112
|
+
const kService = await hmac(kRegion, service);
|
|
113
|
+
return hmac(kService, KEY_TYPE);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** `YYYYMMDDTHHMMSSZ` + 8-char `YYYYMMDD`. */
|
|
117
|
+
export function formatAmzDate(d: Date): { longDate: string; shortDate: string } {
|
|
118
|
+
const iso = d.toISOString();
|
|
119
|
+
// `2025-05-17T12:34:56.789Z` -> `20250517T123456Z`
|
|
120
|
+
const longDate = `${iso.slice(0, 4)}${iso.slice(5, 7)}${iso.slice(8, 10)}T${iso.slice(11, 13)}${iso.slice(14, 16)}${iso.slice(17, 19)}Z`;
|
|
121
|
+
return { longDate, shortDate: longDate.slice(0, 8) };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Canonicalize a request path per RFC 3986: each segment is %-encoded but `/`
|
|
126
|
+
* stays literal. Matches the smithy default (`uriEscapePath: true`, then revert
|
|
127
|
+
* the double-encoding of `/`). Bedrock paths use no reserved characters in
|
|
128
|
+
* practice, but model IDs can include `:` and `.`.
|
|
129
|
+
*/
|
|
130
|
+
function canonicalPath(path: string): string {
|
|
131
|
+
const segments = path.split("/");
|
|
132
|
+
const escaped = segments.map(seg => (seg.length === 0 ? "" : encodeRfc3986(seg)));
|
|
133
|
+
return escaped.join("/");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function encodeRfc3986(str: string): string {
|
|
137
|
+
return encodeURIComponent(str).replace(/[!'()*]/g, c => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function canonicalQuery(query: string | undefined): string {
|
|
141
|
+
if (!query) return "";
|
|
142
|
+
const pairs: Array<[string, string]> = [];
|
|
143
|
+
for (const part of query.split("&")) {
|
|
144
|
+
if (!part) continue;
|
|
145
|
+
const eq = part.indexOf("=");
|
|
146
|
+
const k = eq === -1 ? part : part.slice(0, eq);
|
|
147
|
+
const v = eq === -1 ? "" : part.slice(eq + 1);
|
|
148
|
+
pairs.push([decodeURIComponent(k), decodeURIComponent(v)]);
|
|
149
|
+
}
|
|
150
|
+
pairs.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0));
|
|
151
|
+
return pairs.map(([k, v]) => `${encodeRfc3986(k)}=${encodeRfc3986(v)}`).join("&");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface SignedHeaders {
|
|
155
|
+
host: string;
|
|
156
|
+
"x-amz-date": string;
|
|
157
|
+
"x-amz-content-sha256": string;
|
|
158
|
+
authorization: string;
|
|
159
|
+
"x-amz-security-token"?: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export async function signRequest(params: SignParams): Promise<SignedHeaders> {
|
|
163
|
+
const { method, host, path, query, body, region, service, credentials } = params;
|
|
164
|
+
const date = params.date ?? new Date();
|
|
165
|
+
const { longDate, shortDate } = formatAmzDate(date);
|
|
166
|
+
const payloadHash = await sha256Hex(body);
|
|
167
|
+
|
|
168
|
+
// Assemble the headers that will be signed. Always include host, x-amz-date,
|
|
169
|
+
// x-amz-content-sha256, plus x-amz-security-token when present, plus
|
|
170
|
+
// caller-provided signable headers (e.g. content-type, accept).
|
|
171
|
+
const signed: Record<string, string> = {
|
|
172
|
+
host,
|
|
173
|
+
"x-amz-date": longDate,
|
|
174
|
+
"x-amz-content-sha256": payloadHash,
|
|
175
|
+
};
|
|
176
|
+
if (credentials.sessionToken) signed["x-amz-security-token"] = credentials.sessionToken;
|
|
177
|
+
const extraHeaders = params.headers;
|
|
178
|
+
if (extraHeaders) {
|
|
179
|
+
for (const k in extraHeaders) {
|
|
180
|
+
const lk = k.toLowerCase();
|
|
181
|
+
if (UNSIGNABLE[lk]) continue;
|
|
182
|
+
if (lk.startsWith("proxy-") || lk.startsWith("sec-")) continue;
|
|
183
|
+
signed[lk] = extraHeaders[k].trim().replace(/\s+/g, " ");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const sortedNames = Object.keys(signed).sort();
|
|
188
|
+
const canonicalHeaders = `${sortedNames.map(n => `${n}:${signed[n]}`).join("\n")}\n`;
|
|
189
|
+
const signedHeadersStr = sortedNames.join(";");
|
|
190
|
+
|
|
191
|
+
const canonicalRequest = [
|
|
192
|
+
method.toUpperCase(),
|
|
193
|
+
canonicalPath(path),
|
|
194
|
+
canonicalQuery(query),
|
|
195
|
+
canonicalHeaders,
|
|
196
|
+
signedHeadersStr,
|
|
197
|
+
payloadHash,
|
|
198
|
+
].join("\n");
|
|
199
|
+
|
|
200
|
+
const scope = `${shortDate}/${region}/${service}/${KEY_TYPE}`;
|
|
201
|
+
const stringToSign = [ALGORITHM, longDate, scope, await sha256Hex(canonicalRequest)].join("\n");
|
|
202
|
+
|
|
203
|
+
const signingKey = await getSigningKey(credentials.secretAccessKey, shortDate, region, service);
|
|
204
|
+
const signature = toHex(await hmac(signingKey, stringToSign));
|
|
205
|
+
|
|
206
|
+
const authorization =
|
|
207
|
+
`${ALGORITHM} Credential=${credentials.accessKeyId}/${scope}, ` +
|
|
208
|
+
`SignedHeaders=${signedHeadersStr}, Signature=${signature}`;
|
|
209
|
+
|
|
210
|
+
const out: SignedHeaders = {
|
|
211
|
+
host,
|
|
212
|
+
"x-amz-date": longDate,
|
|
213
|
+
"x-amz-content-sha256": payloadHash,
|
|
214
|
+
authorization,
|
|
215
|
+
};
|
|
216
|
+
if (credentials.sessionToken) out["x-amz-security-token"] = credentials.sessionToken;
|
|
217
|
+
return out;
|
|
218
|
+
}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { $env, extractHttpStatusFromError } from "@gajae-code/utils";
|
|
2
|
+
import { AzureOpenAI } from "openai";
|
|
3
|
+
import type {
|
|
4
|
+
Tool as OpenAITool,
|
|
5
|
+
ResponseCreateParamsStreaming,
|
|
6
|
+
ResponseInput,
|
|
7
|
+
} from "openai/resources/responses/responses";
|
|
8
|
+
import { getEnvApiKey } from "../stream";
|
|
9
|
+
import type {
|
|
10
|
+
AssistantMessage,
|
|
11
|
+
Context,
|
|
12
|
+
Model,
|
|
13
|
+
ServiceTier,
|
|
14
|
+
StreamFunction,
|
|
15
|
+
StreamOptions,
|
|
16
|
+
Tool,
|
|
17
|
+
ToolChoice,
|
|
18
|
+
} from "../types";
|
|
19
|
+
import { normalizeSystemPrompts } from "../utils";
|
|
20
|
+
import { createAbortSourceTracker } from "../utils/abort";
|
|
21
|
+
import { AssistantMessageEventStream } from "../utils/event-stream";
|
|
22
|
+
import { finalizeErrorMessage, type RawHttpRequestDump } from "../utils/http-inspector";
|
|
23
|
+
import {
|
|
24
|
+
createWatchdog,
|
|
25
|
+
getOpenAIStreamIdleTimeoutMs,
|
|
26
|
+
getStreamFirstEventTimeoutMs,
|
|
27
|
+
iterateWithIdleTimeout,
|
|
28
|
+
} from "../utils/idle-iterator";
|
|
29
|
+
import { sanitizeSchemaForOpenAIResponses, toolWireSchema } from "../utils/schema";
|
|
30
|
+
import { wrapFetchForSseDebug } from "../utils/sse-debug";
|
|
31
|
+
import { mapToOpenAIResponsesToolChoice } from "../utils/tool-choice";
|
|
32
|
+
import { normalizeOpenAIResponsesPromptCacheKey, supportsDeveloperRole } from "./openai-responses";
|
|
33
|
+
import {
|
|
34
|
+
appendResponsesToolResultMessages,
|
|
35
|
+
applyCommonResponsesSamplingParams,
|
|
36
|
+
applyResponsesReasoningParams,
|
|
37
|
+
convertResponsesAssistantMessage,
|
|
38
|
+
convertResponsesInputContent,
|
|
39
|
+
createInitialResponsesAssistantMessage,
|
|
40
|
+
normalizeResponsesToolCallIdForTransform,
|
|
41
|
+
processResponsesStream,
|
|
42
|
+
} from "./openai-responses-shared";
|
|
43
|
+
import { transformMessages } from "./transform-messages";
|
|
44
|
+
|
|
45
|
+
const DEFAULT_AZURE_API_VERSION = "v1";
|
|
46
|
+
const AZURE_OPENAI_RESPONSES_FIRST_EVENT_TIMEOUT_MESSAGE =
|
|
47
|
+
"Azure OpenAI responses stream timed out while waiting for the first event";
|
|
48
|
+
|
|
49
|
+
function parseDeploymentNameMap(value: string | undefined): Map<string, string> {
|
|
50
|
+
const map = new Map<string, string>();
|
|
51
|
+
if (!value) return map;
|
|
52
|
+
for (const entry of value.split(",")) {
|
|
53
|
+
const trimmed = entry.trim();
|
|
54
|
+
if (!trimmed) continue;
|
|
55
|
+
const [modelId, deploymentName] = trimmed.split("=", 2);
|
|
56
|
+
if (!modelId || !deploymentName) continue;
|
|
57
|
+
map.set(modelId.trim(), deploymentName.trim());
|
|
58
|
+
}
|
|
59
|
+
return map;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function resolveDeploymentName(model: Model<"azure-openai-responses">, options?: AzureOpenAIResponsesOptions): string {
|
|
63
|
+
if (options?.azureDeploymentName) {
|
|
64
|
+
return options.azureDeploymentName;
|
|
65
|
+
}
|
|
66
|
+
const mappedDeployment = parseDeploymentNameMap($env.AZURE_OPENAI_DEPLOYMENT_NAME_MAP).get(model.id);
|
|
67
|
+
return mappedDeployment ?? model.id;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Azure OpenAI Responses-specific options
|
|
71
|
+
export interface AzureOpenAIResponsesOptions extends StreamOptions {
|
|
72
|
+
reasoning?: "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
73
|
+
reasoningSummary?: "auto" | "detailed" | "concise" | null;
|
|
74
|
+
azureApiVersion?: string;
|
|
75
|
+
azureResourceName?: string;
|
|
76
|
+
azureBaseUrl?: string;
|
|
77
|
+
azureDeploymentName?: string;
|
|
78
|
+
toolChoice?: ToolChoice;
|
|
79
|
+
serviceTier?: ServiceTier;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
type AzureOpenAIResponsesSamplingParams = ResponseCreateParamsStreaming & {
|
|
83
|
+
top_p?: number;
|
|
84
|
+
top_k?: number;
|
|
85
|
+
min_p?: number;
|
|
86
|
+
presence_penalty?: number;
|
|
87
|
+
repetition_penalty?: number;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Generate function for Azure OpenAI Responses API
|
|
92
|
+
*/
|
|
93
|
+
export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses"> = (
|
|
94
|
+
model: Model<"azure-openai-responses">,
|
|
95
|
+
context: Context,
|
|
96
|
+
options?: AzureOpenAIResponsesOptions,
|
|
97
|
+
): AssistantMessageEventStream => {
|
|
98
|
+
const stream = new AssistantMessageEventStream();
|
|
99
|
+
|
|
100
|
+
// Start async processing
|
|
101
|
+
(async () => {
|
|
102
|
+
const startTime = Date.now();
|
|
103
|
+
let firstTokenTime: number | undefined;
|
|
104
|
+
const deploymentName = resolveDeploymentName(model, options);
|
|
105
|
+
|
|
106
|
+
const output: AssistantMessage = createInitialResponsesAssistantMessage(
|
|
107
|
+
"azure-openai-responses",
|
|
108
|
+
model.provider,
|
|
109
|
+
model.id,
|
|
110
|
+
);
|
|
111
|
+
let rawRequestDump: RawHttpRequestDump | undefined;
|
|
112
|
+
const abortTracker = createAbortSourceTracker(options?.signal);
|
|
113
|
+
const firstEventTimeoutAbortError = new Error(AZURE_OPENAI_RESPONSES_FIRST_EVENT_TIMEOUT_MESSAGE);
|
|
114
|
+
const { requestAbortController, requestSignal } = abortTracker;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
// Create Azure OpenAI client
|
|
118
|
+
const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
|
|
119
|
+
const client = createClient(model, apiKey, options);
|
|
120
|
+
const { baseUrl } = resolveAzureConfig(model, options);
|
|
121
|
+
const params = buildParams(model, context, options, deploymentName, baseUrl);
|
|
122
|
+
const idleTimeoutMs = getOpenAIStreamIdleTimeoutMs();
|
|
123
|
+
options?.onPayload?.(params);
|
|
124
|
+
rawRequestDump = {
|
|
125
|
+
provider: model.provider,
|
|
126
|
+
api: output.api,
|
|
127
|
+
model: model.id,
|
|
128
|
+
method: "POST",
|
|
129
|
+
url: `${baseUrl}/responses`,
|
|
130
|
+
body: params,
|
|
131
|
+
};
|
|
132
|
+
const openaiStream = await client.responses.create(params, { signal: requestSignal });
|
|
133
|
+
const firstEventWatchdog = createWatchdog(
|
|
134
|
+
options?.streamFirstEventTimeoutMs ?? getStreamFirstEventTimeoutMs(idleTimeoutMs),
|
|
135
|
+
() => abortTracker.abortLocally(firstEventTimeoutAbortError),
|
|
136
|
+
);
|
|
137
|
+
stream.push({ type: "start", partial: output });
|
|
138
|
+
|
|
139
|
+
await processResponsesStream(
|
|
140
|
+
iterateWithIdleTimeout(openaiStream, {
|
|
141
|
+
watchdog: firstEventWatchdog,
|
|
142
|
+
idleTimeoutMs,
|
|
143
|
+
errorMessage: "Azure OpenAI responses stream stalled while waiting for the next event",
|
|
144
|
+
onIdle: () => requestAbortController.abort(),
|
|
145
|
+
}),
|
|
146
|
+
output,
|
|
147
|
+
stream,
|
|
148
|
+
model,
|
|
149
|
+
{
|
|
150
|
+
onFirstToken: () => {
|
|
151
|
+
if (!firstTokenTime) firstTokenTime = Date.now();
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const firstEventTimeoutError = abortTracker.getLocalAbortReason();
|
|
157
|
+
if (firstEventTimeoutError) {
|
|
158
|
+
throw firstEventTimeoutError;
|
|
159
|
+
}
|
|
160
|
+
if (abortTracker.wasCallerAbort()) {
|
|
161
|
+
throw new Error("Request was aborted");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (output.stopReason === "aborted" || output.stopReason === "error") {
|
|
165
|
+
throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
output.duration = Date.now() - startTime;
|
|
169
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
170
|
+
stream.push({ type: "done", reason: output.stopReason, message: output });
|
|
171
|
+
stream.end();
|
|
172
|
+
} catch (error) {
|
|
173
|
+
for (const block of output.content) delete (block as { index?: number }).index;
|
|
174
|
+
const firstEventTimeoutError = abortTracker.getLocalAbortReason();
|
|
175
|
+
output.stopReason = abortTracker.wasCallerAbort() ? "aborted" : "error";
|
|
176
|
+
output.errorStatus = extractHttpStatusFromError(error);
|
|
177
|
+
output.errorMessage = firstEventTimeoutError?.message ?? (await finalizeErrorMessage(error, rawRequestDump));
|
|
178
|
+
output.duration = Date.now() - startTime;
|
|
179
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
180
|
+
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
181
|
+
stream.end();
|
|
182
|
+
}
|
|
183
|
+
})();
|
|
184
|
+
|
|
185
|
+
return stream;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
function normalizeAzureBaseUrl(baseUrl: string): string {
|
|
189
|
+
return baseUrl.replace(/\/+$/, "");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function buildDefaultBaseUrl(resourceName: string): string {
|
|
193
|
+
return `https://${resourceName}.openai.azure.com/openai/v1`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function resolveAzureConfig(
|
|
197
|
+
model: Model<"azure-openai-responses">,
|
|
198
|
+
options?: AzureOpenAIResponsesOptions,
|
|
199
|
+
): { baseUrl: string; apiVersion: string } {
|
|
200
|
+
const apiVersion = options?.azureApiVersion || $env.AZURE_OPENAI_API_VERSION || DEFAULT_AZURE_API_VERSION;
|
|
201
|
+
|
|
202
|
+
const baseUrl = options?.azureBaseUrl?.trim() || $env.AZURE_OPENAI_BASE_URL?.trim() || undefined;
|
|
203
|
+
const resourceName = options?.azureResourceName || $env.AZURE_OPENAI_RESOURCE_NAME;
|
|
204
|
+
|
|
205
|
+
let resolvedBaseUrl = baseUrl;
|
|
206
|
+
|
|
207
|
+
if (!resolvedBaseUrl && resourceName) {
|
|
208
|
+
resolvedBaseUrl = buildDefaultBaseUrl(resourceName);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!resolvedBaseUrl && model.baseUrl) {
|
|
212
|
+
resolvedBaseUrl = model.baseUrl;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (!resolvedBaseUrl) {
|
|
216
|
+
throw new Error(
|
|
217
|
+
"Azure OpenAI base URL is required. Set AZURE_OPENAI_BASE_URL or AZURE_OPENAI_RESOURCE_NAME, or pass azureBaseUrl, azureResourceName, or model.baseUrl.",
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
baseUrl: normalizeAzureBaseUrl(resolvedBaseUrl),
|
|
223
|
+
apiVersion,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function createClient(model: Model<"azure-openai-responses">, apiKey: string, options?: AzureOpenAIResponsesOptions) {
|
|
228
|
+
if (!apiKey) {
|
|
229
|
+
const envKey = $env.AZURE_OPENAI_API_KEY;
|
|
230
|
+
if (!envKey) {
|
|
231
|
+
throw new Error(
|
|
232
|
+
"Azure OpenAI API key is required. Set AZURE_OPENAI_API_KEY environment variable or pass it as an argument.",
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
apiKey = envKey;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const headers = { ...(model.headers ?? {}) };
|
|
239
|
+
|
|
240
|
+
if (options?.headers) {
|
|
241
|
+
Object.assign(headers, options.headers);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const { baseUrl, apiVersion } = resolveAzureConfig(model, options);
|
|
245
|
+
|
|
246
|
+
const baseFetch = options?.fetch ?? fetch;
|
|
247
|
+
const onSseEvent = options?.onSseEvent;
|
|
248
|
+
return new AzureOpenAI({
|
|
249
|
+
apiKey,
|
|
250
|
+
apiVersion,
|
|
251
|
+
dangerouslyAllowBrowser: true,
|
|
252
|
+
maxRetries: 5,
|
|
253
|
+
defaultHeaders: headers,
|
|
254
|
+
baseURL: baseUrl,
|
|
255
|
+
fetch: onSseEvent ? wrapFetchForSseDebug(baseFetch, event => onSseEvent(event, model)) : baseFetch,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function buildParams(
|
|
260
|
+
model: Model<"azure-openai-responses">,
|
|
261
|
+
context: Context,
|
|
262
|
+
options: AzureOpenAIResponsesOptions | undefined,
|
|
263
|
+
deploymentName: string,
|
|
264
|
+
resolvedBaseUrl?: string,
|
|
265
|
+
) {
|
|
266
|
+
const messages = convertMessages(model, context, true, resolvedBaseUrl);
|
|
267
|
+
|
|
268
|
+
const params: AzureOpenAIResponsesSamplingParams = {
|
|
269
|
+
model: deploymentName,
|
|
270
|
+
input: messages,
|
|
271
|
+
stream: true,
|
|
272
|
+
prompt_cache_key: normalizeOpenAIResponsesPromptCacheKey(options?.sessionId),
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
applyCommonResponsesSamplingParams(params, options, model.provider);
|
|
276
|
+
|
|
277
|
+
if (context.tools) {
|
|
278
|
+
params.tools = convertTools(context.tools);
|
|
279
|
+
if (options?.toolChoice) {
|
|
280
|
+
params.tool_choice = mapToOpenAIResponsesToolChoice(options.toolChoice);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
applyResponsesReasoningParams(params, model, options, messages);
|
|
285
|
+
|
|
286
|
+
return params;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function convertMessages(
|
|
290
|
+
model: Model<"azure-openai-responses">,
|
|
291
|
+
context: Context,
|
|
292
|
+
strictResponsesPairing: boolean,
|
|
293
|
+
resolvedBaseUrl?: string,
|
|
294
|
+
): ResponseInput {
|
|
295
|
+
const messages: ResponseInput = [];
|
|
296
|
+
const transformedMessages = transformMessages(context.messages, model, normalizeResponsesToolCallIdForTransform);
|
|
297
|
+
const knownCallIds = new Set<string>();
|
|
298
|
+
|
|
299
|
+
const systemPrompts = normalizeSystemPrompts(context.systemPrompt);
|
|
300
|
+
if (systemPrompts.length > 0) {
|
|
301
|
+
const role = model.reasoning && supportsDeveloperRole(resolvedBaseUrl ?? model) ? "developer" : "system";
|
|
302
|
+
for (const systemPrompt of systemPrompts) {
|
|
303
|
+
messages.push({ role, content: systemPrompt });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
let msgIndex = 0;
|
|
308
|
+
for (const msg of transformedMessages) {
|
|
309
|
+
if (msg.role === "user" || msg.role === "developer") {
|
|
310
|
+
const content = convertResponsesInputContent(msg.content, model.input.includes("image"));
|
|
311
|
+
if (!content) continue;
|
|
312
|
+
messages.push({
|
|
313
|
+
role: "user",
|
|
314
|
+
content: msg.role === "developer" && typeof msg.content === "string" ? msg.content.toWellFormed() : content,
|
|
315
|
+
});
|
|
316
|
+
} else if (msg.role === "assistant") {
|
|
317
|
+
const outputItems = convertResponsesAssistantMessage(msg as AssistantMessage, model, msgIndex, knownCallIds);
|
|
318
|
+
if (outputItems.length === 0) continue;
|
|
319
|
+
messages.push(...outputItems);
|
|
320
|
+
} else if (msg.role === "toolResult") {
|
|
321
|
+
appendResponsesToolResultMessages(messages, msg, model, strictResponsesPairing, knownCallIds);
|
|
322
|
+
}
|
|
323
|
+
msgIndex++;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return messages;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function convertTools(tools: Tool[]): OpenAITool[] {
|
|
330
|
+
return tools.map(tool => ({
|
|
331
|
+
type: "function",
|
|
332
|
+
name: tool.name,
|
|
333
|
+
description: tool.description || "",
|
|
334
|
+
parameters: sanitizeSchemaForOpenAIResponses(toolWireSchema(tool)),
|
|
335
|
+
strict: false,
|
|
336
|
+
}));
|
|
337
|
+
}
|