@sayknow-cli/ai 0.3.6 → 0.3.8
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/dist/types/api-registry.d.ts +30 -0
- package/dist/types/auth-broker/client.d.ts +67 -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 +99 -0
- package/dist/types/auth-broker/server.d.ts +32 -0
- package/dist/types/auth-broker/types.d.ts +110 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +443 -0
- package/dist/types/auth-gateway/http.d.ts +40 -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 +679 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/index.d.ts +51 -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 +74 -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 +251 -0
- package/dist/types/provider-models/special.d.ts +19 -0
- package/dist/types/providers/amazon-bedrock.d.ts +60 -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 +208 -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/composer-discipline.d.ts +26 -0
- package/dist/types/providers/cursor/gen/agent_pb.d.ts +13022 -0
- package/dist/types/providers/cursor.d.ts +44 -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 +75 -0
- package/dist/types/providers/google-gemini-headers.d.ts +40 -0
- package/dist/types/providers/google-shared.d.ts +173 -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 +177 -0
- package/dist/types/providers/ollama.d.ts +41 -0
- package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
- package/dist/types/providers/openai-bounded-rate-limits.d.ts +3 -0
- package/dist/types/providers/openai-chat-server-schema.d.ts +815 -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 +50 -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 +27 -0
- package/dist/types/providers/openai-completions.d.ts +33 -0
- package/dist/types/providers/openai-request-transform.d.ts +4 -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 +104 -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 +14 -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 +43 -0
- package/dist/types/types.d.ts +830 -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/grok-cli.d.ts +10 -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 +74 -0
- package/dist/types/utils/event-stream.d.ts +33 -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 +35 -0
- package/dist/types/utils/idle-iterator.d.ts +67 -0
- package/dist/types/utils/json-parse.d.ts +18 -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 +60 -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/deepinfra.d.ts +1 -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/fugu.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/glm-zcode.d.ts +71 -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 +39 -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 +45 -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/xai.d.ts +30 -0
- package/dist/types/utils/oauth/xiaomi.d.ts +25 -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 +64 -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-budget.d.ts +1 -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 +14 -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/root-combinator.d.ts +12 -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-capability.d.ts +41 -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 +35 -0
- package/package.json +26 -25
- package/src/auth-broker/remote-store.ts +17 -2
- package/src/auth-broker/wire-schemas.ts +1 -0
- package/src/auth-storage.ts +80 -7
- package/src/providers/amazon-bedrock.ts +2 -2
- package/src/providers/anthropic-messages-server.ts +2 -1
- package/src/providers/anthropic.ts +107 -11
- package/src/providers/azure-openai-responses.ts +2 -1
- package/src/providers/google-shared.ts +3 -3
- package/src/providers/openai-bounded-rate-limits.ts +57 -0
- package/src/providers/openai-chat-server.ts +3 -2
- package/src/providers/openai-codex/request-transformer.ts +5 -0
- package/src/providers/openai-completions-compat.ts +26 -13
- package/src/providers/openai-responses-server.ts +6 -3
- package/src/providers/openai-responses-shared.ts +3 -3
- package/src/providers/openai-responses.ts +5 -1
- package/src/rate-limit-utils.ts +9 -2
- package/src/utils.ts +49 -1
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@sayknow-cli/ai",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.8",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
|
-
"homepage": "https://
|
|
6
|
+
"homepage": "https://sayknow-cli.com",
|
|
7
7
|
"author": "jaybeyond",
|
|
8
8
|
"contributors": [
|
|
9
9
|
"Mario Zechner"
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"api"
|
|
28
28
|
],
|
|
29
29
|
"main": "./src/index.ts",
|
|
30
|
-
"types": "./
|
|
30
|
+
"types": "./dist/types/index.d.ts",
|
|
31
31
|
"bin": {
|
|
32
32
|
"pi-ai": "./src/cli.ts"
|
|
33
33
|
},
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@anthropic-ai/sdk": "^0.94.0",
|
|
45
45
|
"@bufbuild/protobuf": "^2.12.0",
|
|
46
|
-
"@sayknow-cli/utils": "0.3.
|
|
46
|
+
"@sayknow-cli/utils": "0.3.8",
|
|
47
47
|
"openai": "^6.36.0",
|
|
48
48
|
"partial-json": "^0.1.7",
|
|
49
49
|
"zod": "4.4.3"
|
|
@@ -57,87 +57,88 @@
|
|
|
57
57
|
"files": [
|
|
58
58
|
"src",
|
|
59
59
|
"README.md",
|
|
60
|
-
"CHANGELOG.md"
|
|
60
|
+
"CHANGELOG.md",
|
|
61
|
+
"dist/types"
|
|
61
62
|
],
|
|
62
63
|
"exports": {
|
|
63
64
|
".": {
|
|
64
|
-
"types": "./
|
|
65
|
+
"types": "./dist/types/index.d.ts",
|
|
65
66
|
"import": "./src/index.ts"
|
|
66
67
|
},
|
|
67
68
|
"./*": {
|
|
68
|
-
"types": "./
|
|
69
|
+
"types": "./dist/types/*.d.ts",
|
|
69
70
|
"import": "./src/*.ts"
|
|
70
71
|
},
|
|
71
72
|
"./auth-broker": {
|
|
72
|
-
"types": "./
|
|
73
|
+
"types": "./dist/types/auth-broker/index.d.ts",
|
|
73
74
|
"import": "./src/auth-broker/index.ts"
|
|
74
75
|
},
|
|
75
76
|
"./auth-broker/*": {
|
|
76
|
-
"types": "./
|
|
77
|
+
"types": "./dist/types/auth-broker/*.d.ts",
|
|
77
78
|
"import": "./src/auth-broker/*.ts"
|
|
78
79
|
},
|
|
79
80
|
"./auth-gateway": {
|
|
80
|
-
"types": "./
|
|
81
|
+
"types": "./dist/types/auth-gateway/index.d.ts",
|
|
81
82
|
"import": "./src/auth-gateway/index.ts"
|
|
82
83
|
},
|
|
83
84
|
"./auth-gateway/*": {
|
|
84
|
-
"types": "./
|
|
85
|
+
"types": "./dist/types/auth-gateway/*.d.ts",
|
|
85
86
|
"import": "./src/auth-gateway/*.ts"
|
|
86
87
|
},
|
|
87
88
|
"./models.json": {
|
|
88
|
-
"types": "./
|
|
89
|
+
"types": "./dist/types/models.json.d.d.ts",
|
|
89
90
|
"import": "./src/models.json"
|
|
90
91
|
},
|
|
91
92
|
"./provider-models": {
|
|
92
|
-
"types": "./
|
|
93
|
+
"types": "./dist/types/provider-models/index.d.ts",
|
|
93
94
|
"import": "./src/provider-models/index.ts"
|
|
94
95
|
},
|
|
95
96
|
"./provider-models/*": {
|
|
96
|
-
"types": "./
|
|
97
|
+
"types": "./dist/types/provider-models/*.d.ts",
|
|
97
98
|
"import": "./src/provider-models/*.ts"
|
|
98
99
|
},
|
|
99
100
|
"./providers/*": {
|
|
100
|
-
"types": "./
|
|
101
|
+
"types": "./dist/types/providers/*.d.ts",
|
|
101
102
|
"import": "./src/providers/*.ts"
|
|
102
103
|
},
|
|
103
104
|
"./providers/cursor/gen/*": {
|
|
104
|
-
"types": "./
|
|
105
|
+
"types": "./dist/types/providers/cursor/gen/*.d.ts",
|
|
105
106
|
"import": "./src/providers/cursor/gen/*.ts"
|
|
106
107
|
},
|
|
107
108
|
"./providers/openai-codex/*": {
|
|
108
|
-
"types": "./
|
|
109
|
+
"types": "./dist/types/providers/openai-codex/*.d.ts",
|
|
109
110
|
"import": "./src/providers/openai-codex/*.ts"
|
|
110
111
|
},
|
|
111
112
|
"./usage/*": {
|
|
112
|
-
"types": "./
|
|
113
|
+
"types": "./dist/types/usage/*.d.ts",
|
|
113
114
|
"import": "./src/usage/*.ts"
|
|
114
115
|
},
|
|
115
116
|
"./utils/*": {
|
|
116
|
-
"types": "./
|
|
117
|
+
"types": "./dist/types/utils/*.d.ts",
|
|
117
118
|
"import": "./src/utils/*.ts"
|
|
118
119
|
},
|
|
119
120
|
"./utils/discovery": {
|
|
120
|
-
"types": "./
|
|
121
|
+
"types": "./dist/types/utils/discovery/index.d.ts",
|
|
121
122
|
"import": "./src/utils/discovery/index.ts"
|
|
122
123
|
},
|
|
123
124
|
"./utils/discovery/*": {
|
|
124
|
-
"types": "./
|
|
125
|
+
"types": "./dist/types/utils/discovery/*.d.ts",
|
|
125
126
|
"import": "./src/utils/discovery/*.ts"
|
|
126
127
|
},
|
|
127
128
|
"./utils/oauth": {
|
|
128
|
-
"types": "./
|
|
129
|
+
"types": "./dist/types/utils/oauth/index.d.ts",
|
|
129
130
|
"import": "./src/utils/oauth/index.ts"
|
|
130
131
|
},
|
|
131
132
|
"./utils/oauth/*": {
|
|
132
|
-
"types": "./
|
|
133
|
+
"types": "./dist/types/utils/oauth/*.d.ts",
|
|
133
134
|
"import": "./src/utils/oauth/*.ts"
|
|
134
135
|
},
|
|
135
136
|
"./utils/schema": {
|
|
136
|
-
"types": "./
|
|
137
|
+
"types": "./dist/types/utils/schema/index.d.ts",
|
|
137
138
|
"import": "./src/utils/schema/index.ts"
|
|
138
139
|
},
|
|
139
140
|
"./utils/schema/*": {
|
|
140
|
-
"types": "./
|
|
141
|
+
"types": "./dist/types/utils/schema/*.d.ts",
|
|
141
142
|
"import": "./src/utils/schema/*.ts"
|
|
142
143
|
},
|
|
143
144
|
"./*.js": "./src/*.ts"
|
|
@@ -86,6 +86,7 @@ export class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
86
86
|
#cache: Map<string, CacheEntry> = new Map();
|
|
87
87
|
#usageCache?: UsageCacheEntry;
|
|
88
88
|
#usageInflight?: Promise<UsageReport[] | null>;
|
|
89
|
+
#usageCacheEpoch = 0;
|
|
89
90
|
#closed = false;
|
|
90
91
|
/**
|
|
91
92
|
* `true` once the SSE consumer received its first frame and hasn't dropped
|
|
@@ -465,6 +466,19 @@ export class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
465
466
|
}
|
|
466
467
|
}
|
|
467
468
|
|
|
469
|
+
deleteCachePrefix(prefix: string): void {
|
|
470
|
+
for (const key of this.#cache.keys()) {
|
|
471
|
+
if (key.startsWith(prefix)) this.#cache.delete(key);
|
|
472
|
+
}
|
|
473
|
+
if (prefix.startsWith("usage_cache:")) this.#invalidateUsageCache();
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
#invalidateUsageCache(): void {
|
|
477
|
+
this.#usageCache = undefined;
|
|
478
|
+
this.#usageInflight = undefined;
|
|
479
|
+
this.#usageCacheEpoch += 1;
|
|
480
|
+
}
|
|
481
|
+
|
|
468
482
|
/**
|
|
469
483
|
* Store-level hook consumed by `AuthStorage` — routes refresh through the
|
|
470
484
|
* broker so the actual refresh token never leaves the broker host. Returns
|
|
@@ -561,10 +575,11 @@ export class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
561
575
|
return Promise.resolve(cached.reports);
|
|
562
576
|
}
|
|
563
577
|
if (this.#usageInflight) return this.#usageInflight;
|
|
578
|
+
const epoch = this.#usageCacheEpoch;
|
|
564
579
|
const inflight = this.#client
|
|
565
580
|
.fetchUsage()
|
|
566
581
|
.then(body => {
|
|
567
|
-
this.#usageCache = { reports: body.reports, fetchedAt: Date.now() };
|
|
582
|
+
if (this.#usageCacheEpoch === epoch) this.#usageCache = { reports: body.reports, fetchedAt: Date.now() };
|
|
568
583
|
return body.reports;
|
|
569
584
|
})
|
|
570
585
|
.catch(error => {
|
|
@@ -572,7 +587,7 @@ export class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
572
587
|
return null;
|
|
573
588
|
})
|
|
574
589
|
.finally(() => {
|
|
575
|
-
this.#usageInflight = undefined;
|
|
590
|
+
if (this.#usageCacheEpoch === epoch) this.#usageInflight = undefined;
|
|
576
591
|
});
|
|
577
592
|
this.#usageInflight = inflight;
|
|
578
593
|
return inflight;
|
|
@@ -187,6 +187,7 @@ export const credentialDisableResponseSchema = z
|
|
|
187
187
|
// ─── Upload ────────────────────────────────────────────────────────────────
|
|
188
188
|
const credentialIfAbsentReasonSchema = z.enum([
|
|
189
189
|
"inserted",
|
|
190
|
+
"updated-existing",
|
|
190
191
|
"skipped-existing",
|
|
191
192
|
"skipped-existing-runtime",
|
|
192
193
|
"skipped-existing-config",
|
package/src/auth-storage.ts
CHANGED
|
@@ -32,6 +32,7 @@ import { kimiUsageProvider } from "./usage/kimi";
|
|
|
32
32
|
import { codexRankingStrategy, openaiCodexUsageProvider } from "./usage/openai-codex";
|
|
33
33
|
import { zaiUsageProvider } from "./usage/zai";
|
|
34
34
|
import { getOAuthApiKey, getOAuthProvider, refreshOAuthToken, resolveOAuthStorageProvider } from "./utils/oauth";
|
|
35
|
+
import { loginDeepInfra } from "./utils/oauth/deepinfra";
|
|
35
36
|
import { loginDeepSeek } from "./utils/oauth/deepseek";
|
|
36
37
|
import { loginOpenAICodexDevice } from "./utils/oauth/openai-codex";
|
|
37
38
|
import type { OAuthController, OAuthCredentials, OAuthProvider, OAuthProviderId } from "./utils/oauth/types";
|
|
@@ -153,6 +154,7 @@ export interface AuthCredentialSnapshotEntry {
|
|
|
153
154
|
|
|
154
155
|
export type AuthCredentialIfAbsentReason =
|
|
155
156
|
| "inserted"
|
|
157
|
+
| "updated-existing"
|
|
156
158
|
| "skipped-existing"
|
|
157
159
|
| "skipped-existing-runtime"
|
|
158
160
|
| "skipped-existing-config"
|
|
@@ -209,6 +211,7 @@ export interface AuthCredentialStore {
|
|
|
209
211
|
deleteAuthCredentialsForProvider(provider: string, disabledCause: string): void;
|
|
210
212
|
getCache(key: string, options?: { includeExpired?: boolean }): string | null;
|
|
211
213
|
setCache(key: string, value: string, expiresAtSec: number): void;
|
|
214
|
+
deleteCachePrefix?(prefix: string): void;
|
|
212
215
|
cleanExpiredCache(): void;
|
|
213
216
|
/**
|
|
214
217
|
* Optional store-supplied OAuth refresh. When present, `AuthStorage` uses
|
|
@@ -471,6 +474,7 @@ interface UsageCache {
|
|
|
471
474
|
get<T>(key: string): UsageCacheEntry<T> | undefined;
|
|
472
475
|
getStale<T>(key: string): UsageCacheEntry<T> | undefined;
|
|
473
476
|
set<T>(key: string, entry: UsageCacheEntry<T>): void;
|
|
477
|
+
deletePrefix?(prefix: string): void;
|
|
474
478
|
cleanup?(): void;
|
|
475
479
|
}
|
|
476
480
|
|
|
@@ -661,6 +665,10 @@ class AuthStorageUsageCache implements UsageCache {
|
|
|
661
665
|
this.store.setCache(`${USAGE_CACHE_PREFIX}${key}`, payload, Math.floor(durableExpiresAt / 1000));
|
|
662
666
|
}
|
|
663
667
|
|
|
668
|
+
deletePrefix(prefix: string): void {
|
|
669
|
+
this.store.deleteCachePrefix?.(`${USAGE_CACHE_PREFIX}${prefix}`);
|
|
670
|
+
}
|
|
671
|
+
|
|
664
672
|
cleanup(): void {
|
|
665
673
|
this.store.cleanExpiredCache();
|
|
666
674
|
}
|
|
@@ -1296,8 +1304,6 @@ export class AuthStorage {
|
|
|
1296
1304
|
return this.#snapshotSkipResult(storageProvider, "skipped-existing-runtime");
|
|
1297
1305
|
if (this.#configOverrides.has(storageProvider))
|
|
1298
1306
|
return this.#snapshotSkipResult(storageProvider, "skipped-existing-config");
|
|
1299
|
-
if (this.#getCredentialsForProvider(storageProvider).length > 0)
|
|
1300
|
-
return this.#snapshotSkipResult(storageProvider, "skipped-existing");
|
|
1301
1307
|
if (getEnvApiKey(storageProvider)) return this.#snapshotSkipResult(storageProvider, "skipped-existing-env");
|
|
1302
1308
|
if (this.#fallbackResolver?.(storageProvider))
|
|
1303
1309
|
return this.#snapshotSkipResult(storageProvider, "skipped-existing-fallback");
|
|
@@ -1310,6 +1316,7 @@ export class AuthStorage {
|
|
|
1310
1316
|
result.entries.map(entry => ({ id: entry.id, credential: entry.credential })),
|
|
1311
1317
|
);
|
|
1312
1318
|
this.#resetProviderAssignments(storageProvider);
|
|
1319
|
+
if (result.inserted) this.#invalidateUsageCacheForProvider(storageProvider);
|
|
1313
1320
|
return {
|
|
1314
1321
|
inserted: result.inserted,
|
|
1315
1322
|
reason: result.reason,
|
|
@@ -1327,6 +1334,13 @@ export class AuthStorage {
|
|
|
1327
1334
|
stored.map(record => ({ id: record.id, credential: record.credential })),
|
|
1328
1335
|
);
|
|
1329
1336
|
this.#resetProviderAssignments(provider);
|
|
1337
|
+
this.#invalidateUsageCacheForProvider(provider);
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
#invalidateUsageCacheForProvider(provider: string): void {
|
|
1341
|
+
this.#usageRequestInFlight.clear();
|
|
1342
|
+
this.#usageReportsInFlight.clear();
|
|
1343
|
+
this.#usageCache.deletePrefix?.(`report:${provider}:`);
|
|
1330
1344
|
}
|
|
1331
1345
|
|
|
1332
1346
|
/**
|
|
@@ -1593,6 +1607,11 @@ export class AuthStorage {
|
|
|
1593
1607
|
await saveApiKeyCredential(apiKey);
|
|
1594
1608
|
return;
|
|
1595
1609
|
}
|
|
1610
|
+
case "deepinfra": {
|
|
1611
|
+
const apiKey = await loginDeepInfra(ctrl);
|
|
1612
|
+
await saveApiKeyCredential(apiKey);
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1596
1615
|
case "xai": {
|
|
1597
1616
|
const { loginXai } = await import("./utils/oauth/xai");
|
|
1598
1617
|
credentials = await loginXai({
|
|
@@ -3699,6 +3718,7 @@ export class SqliteAuthCredentialStore implements AuthCredentialStore {
|
|
|
3699
3718
|
#getCacheStmt: Statement;
|
|
3700
3719
|
#getCacheIncludingExpiredStmt: Statement;
|
|
3701
3720
|
#upsertCacheStmt: Statement;
|
|
3721
|
+
#deleteCachePrefixStmt: Statement;
|
|
3702
3722
|
#deleteExpiredCacheStmt: Statement;
|
|
3703
3723
|
#closed = false;
|
|
3704
3724
|
|
|
@@ -3738,6 +3758,7 @@ export class SqliteAuthCredentialStore implements AuthCredentialStore {
|
|
|
3738
3758
|
this.#upsertCacheStmt = this.#db.prepare(
|
|
3739
3759
|
"INSERT INTO cache (key, value, expires_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value, expires_at = excluded.expires_at",
|
|
3740
3760
|
);
|
|
3761
|
+
this.#deleteCachePrefixStmt = this.#db.prepare("DELETE FROM cache WHERE substr(key, 1, ?) = ?");
|
|
3741
3762
|
this.#deleteExpiredCacheStmt = this.#db.prepare(`DELETE FROM cache WHERE expires_at <= ${SQLITE_NOW_EPOCH}`);
|
|
3742
3763
|
}
|
|
3743
3764
|
|
|
@@ -4096,16 +4117,58 @@ export class SqliteAuthCredentialStore implements AuthCredentialStore {
|
|
|
4096
4117
|
}
|
|
4097
4118
|
|
|
4098
4119
|
const writeIfAbsent = this.#db.transaction(
|
|
4099
|
-
(
|
|
4120
|
+
(
|
|
4121
|
+
providerName: string,
|
|
4122
|
+
item: AuthCredential,
|
|
4123
|
+
record: SerializedCredentialRecord,
|
|
4124
|
+
): AuthCredentialIfAbsentResult => {
|
|
4100
4125
|
const existingRows = this.#listActiveByProviderStmt.all(providerName) as AuthRow[];
|
|
4101
|
-
const existing:
|
|
4126
|
+
const existing: Array<{
|
|
4127
|
+
id: number;
|
|
4128
|
+
credential: AuthCredential;
|
|
4129
|
+
identityKey: string | null;
|
|
4130
|
+
}> = [];
|
|
4102
4131
|
for (const row of existingRows) {
|
|
4103
4132
|
const activeCredential = deserializeCredential(row);
|
|
4104
4133
|
if (!activeCredential) continue;
|
|
4105
|
-
existing.push(
|
|
4134
|
+
existing.push({
|
|
4135
|
+
id: row.id,
|
|
4136
|
+
credential: activeCredential,
|
|
4137
|
+
identityKey: resolveRowCredentialIdentityKey(providerName, row),
|
|
4138
|
+
});
|
|
4106
4139
|
}
|
|
4107
4140
|
if (existing.length > 0) {
|
|
4108
|
-
|
|
4141
|
+
let targetId: number | null = null;
|
|
4142
|
+
for (const row of existing) {
|
|
4143
|
+
if (!matchesReplacementCredential(providerName, row.credential, row.identityKey, item)) continue;
|
|
4144
|
+
if (targetId === null) {
|
|
4145
|
+
targetId = row.id;
|
|
4146
|
+
this.#updateStmt.run(record.credentialType, record.data, record.identityKey, row.id);
|
|
4147
|
+
} else {
|
|
4148
|
+
this.#deleteStmt.run("replaced by newer credential", row.id);
|
|
4149
|
+
}
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4152
|
+
if (targetId !== null) {
|
|
4153
|
+
return {
|
|
4154
|
+
inserted: true,
|
|
4155
|
+
reason: "updated-existing",
|
|
4156
|
+
provider: providerName,
|
|
4157
|
+
entries: this.listAuthCredentials(providerName),
|
|
4158
|
+
};
|
|
4159
|
+
}
|
|
4160
|
+
|
|
4161
|
+
return {
|
|
4162
|
+
inserted: false,
|
|
4163
|
+
reason: "skipped-existing",
|
|
4164
|
+
provider: providerName,
|
|
4165
|
+
entries: existing.map(row => ({
|
|
4166
|
+
id: row.id,
|
|
4167
|
+
provider: providerName,
|
|
4168
|
+
credential: row.credential,
|
|
4169
|
+
disabledCause: null,
|
|
4170
|
+
})),
|
|
4171
|
+
};
|
|
4109
4172
|
}
|
|
4110
4173
|
|
|
4111
4174
|
this.#insertStmt.get(providerName, record.credentialType, record.data, record.identityKey);
|
|
@@ -4118,7 +4181,9 @@ export class SqliteAuthCredentialStore implements AuthCredentialStore {
|
|
|
4118
4181
|
},
|
|
4119
4182
|
);
|
|
4120
4183
|
|
|
4121
|
-
|
|
4184
|
+
const result = writeIfAbsent.immediate(provider, credential, serialized);
|
|
4185
|
+
if (result.inserted) this.#purgeSupersededDisabledRows(provider, result.entries);
|
|
4186
|
+
return result;
|
|
4122
4187
|
}
|
|
4123
4188
|
|
|
4124
4189
|
/**
|
|
@@ -4215,6 +4280,13 @@ export class SqliteAuthCredentialStore implements AuthCredentialStore {
|
|
|
4215
4280
|
}
|
|
4216
4281
|
}
|
|
4217
4282
|
|
|
4283
|
+
deleteCachePrefix(prefix: string): void {
|
|
4284
|
+
if (prefix.length === 0) return;
|
|
4285
|
+
try {
|
|
4286
|
+
this.#deleteCachePrefixStmt.run(prefix.length, prefix);
|
|
4287
|
+
} catch {}
|
|
4288
|
+
}
|
|
4289
|
+
|
|
4218
4290
|
cleanExpiredCache(): void {
|
|
4219
4291
|
try {
|
|
4220
4292
|
this.#deleteExpiredCacheStmt.run();
|
|
@@ -4305,6 +4377,7 @@ export class SqliteAuthCredentialStore implements AuthCredentialStore {
|
|
|
4305
4377
|
this.#getCacheStmt.finalize();
|
|
4306
4378
|
this.#getCacheIncludingExpiredStmt.finalize();
|
|
4307
4379
|
this.#upsertCacheStmt.finalize();
|
|
4380
|
+
this.#deleteCachePrefixStmt.finalize();
|
|
4308
4381
|
this.#deleteExpiredCacheStmt.finalize();
|
|
4309
4382
|
this.#db.close();
|
|
4310
4383
|
}
|
|
@@ -28,7 +28,7 @@ import type {
|
|
|
28
28
|
ToolChoice,
|
|
29
29
|
ToolResultMessage,
|
|
30
30
|
} from "../types";
|
|
31
|
-
import { normalizeToolCallId, resolveCacheRetention } from "../utils";
|
|
31
|
+
import { normalizeToolCallId, resolveCacheRetention, sanitizeJsonStrings } from "../utils";
|
|
32
32
|
import { AssistantMessageEventStream } from "../utils/event-stream";
|
|
33
33
|
import { appendRawHttpRequestDumpFor400, type RawHttpRequestDump, withHttpStatus } from "../utils/http-inspector";
|
|
34
34
|
import { parseStreamingJson } from "../utils/json-parse";
|
|
@@ -701,7 +701,7 @@ function convertMessages(
|
|
|
701
701
|
toolUse: {
|
|
702
702
|
toolUseId: normalizeToolCallId(c.id),
|
|
703
703
|
name: c.name,
|
|
704
|
-
input: c.arguments,
|
|
704
|
+
input: sanitizeJsonStrings(c.arguments),
|
|
705
705
|
},
|
|
706
706
|
});
|
|
707
707
|
break;
|
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
ToolResultMessage,
|
|
14
14
|
UserMessage,
|
|
15
15
|
} from "../types";
|
|
16
|
+
import { sanitizeJsonStrings } from "../utils";
|
|
16
17
|
import {
|
|
17
18
|
type AnthropicAssistantContentBlock,
|
|
18
19
|
type AnthropicMessage,
|
|
@@ -433,7 +434,7 @@ function encodeContentBlocks(message: AssistantMessage): Record<string, unknown>
|
|
|
433
434
|
blocks.push({ type: "redacted_thinking", data: c.data });
|
|
434
435
|
break;
|
|
435
436
|
case "toolCall":
|
|
436
|
-
blocks.push({ type: "tool_use", id: c.id, name: c.name, input: c.arguments ?? {} });
|
|
437
|
+
blocks.push({ type: "tool_use", id: c.id, name: c.name, input: sanitizeJsonStrings(c.arguments ?? {}) });
|
|
437
438
|
break;
|
|
438
439
|
}
|
|
439
440
|
}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from "@sayknow-cli/utils";
|
|
22
22
|
import { hasOpus47ApiRestrictions, mapEffortToAnthropicAdaptiveEffort } from "../model-thinking";
|
|
23
23
|
import { calculateCost } from "../models";
|
|
24
|
+
import { isUsageLimitError } from "../rate-limit-utils";
|
|
24
25
|
import { getEnvApiKey, OUTPUT_FALLBACK_BUFFER } from "../stream";
|
|
25
26
|
import type {
|
|
26
27
|
Api,
|
|
@@ -52,6 +53,7 @@ import {
|
|
|
52
53
|
normalizeSystemPrompts,
|
|
53
54
|
normalizeToolCallId,
|
|
54
55
|
resolveCacheRetention,
|
|
56
|
+
sanitizeJsonStrings,
|
|
55
57
|
} from "../utils";
|
|
56
58
|
import { createAbortSourceTracker } from "../utils/abort";
|
|
57
59
|
import { AssistantMessageEventStream } from "../utils/event-stream";
|
|
@@ -62,6 +64,7 @@ import { parseJsonWithRepair, parseStreamingJson } from "../utils/json-parse";
|
|
|
62
64
|
import { parseGitHubCopilotApiKey } from "../utils/oauth/github-copilot";
|
|
63
65
|
import { notifyProviderResponse } from "../utils/provider-response";
|
|
64
66
|
import { isCopilotTransientModelError } from "../utils/retry";
|
|
67
|
+
import { getRetryAfterMsFromHeaders } from "../utils/retry-after";
|
|
65
68
|
import { resolveRetryBudget } from "../utils/retry-budget";
|
|
66
69
|
import {
|
|
67
70
|
COMBINATOR_KEYS,
|
|
@@ -724,6 +727,7 @@ export type AnthropicClientOptionsArgs = {
|
|
|
724
727
|
onSseEvent?: AnthropicOptions["onSseEvent"];
|
|
725
728
|
fetch?: FetchImpl;
|
|
726
729
|
requestMaxRetries?: number;
|
|
730
|
+
maxRetryDelayMs?: number;
|
|
727
731
|
};
|
|
728
732
|
|
|
729
733
|
export type AnthropicClientOptionsResult = {
|
|
@@ -877,6 +881,101 @@ function mergeHeaders(...headerSources: (Record<string, string> | undefined)[]):
|
|
|
877
881
|
return merged;
|
|
878
882
|
}
|
|
879
883
|
|
|
884
|
+
const ANTHROPIC_RETRY_DELAY_CAP_MS = 60_000;
|
|
885
|
+
const ANTHROPIC_RATE_LIMIT_HEADER_PREFIX = "anthropic-ratelimit-";
|
|
886
|
+
|
|
887
|
+
function getSafeAnthropicHeaderEvidence(headers: Headers): string[] {
|
|
888
|
+
const evidence: string[] = [];
|
|
889
|
+
for (const [name, value] of headers) {
|
|
890
|
+
const lowerName = name.toLowerCase();
|
|
891
|
+
if (
|
|
892
|
+
lowerName === "retry-after" ||
|
|
893
|
+
lowerName === "retry-after-ms" ||
|
|
894
|
+
lowerName.startsWith(ANTHROPIC_RATE_LIMIT_HEADER_PREFIX)
|
|
895
|
+
) {
|
|
896
|
+
evidence.push(`${lowerName}=${value}`);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
return evidence.sort();
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
function getStringProperty(source: unknown, key: string): string | undefined {
|
|
903
|
+
if (!isRecord(source)) return undefined;
|
|
904
|
+
const value = source[key];
|
|
905
|
+
return typeof value === "string" ? value : undefined;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
function appendAnthropicRateLimitEvidence(bodyText: string, headers: Headers): string {
|
|
909
|
+
const evidence = getSafeAnthropicHeaderEvidence(headers);
|
|
910
|
+
if (evidence.length === 0) return bodyText;
|
|
911
|
+
|
|
912
|
+
const suffix = ` Anthropic rate-limit evidence: ${evidence.join(", ")}`;
|
|
913
|
+
try {
|
|
914
|
+
const parsed = JSON.parse(bodyText) as unknown;
|
|
915
|
+
if (isRecord(parsed)) {
|
|
916
|
+
const error = parsed.error;
|
|
917
|
+
if (isRecord(error) && typeof error.message === "string" && !error.message.includes(suffix)) {
|
|
918
|
+
return JSON.stringify({ ...parsed, error: { ...error, message: `${error.message}${suffix}` } });
|
|
919
|
+
}
|
|
920
|
+
if (typeof parsed.message === "string" && !parsed.message.includes(suffix)) {
|
|
921
|
+
return JSON.stringify({ ...parsed, message: `${parsed.message}${suffix}` });
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
} catch {}
|
|
925
|
+
|
|
926
|
+
return bodyText.includes(suffix) ? bodyText : `${bodyText}${suffix}`;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
function isAnthropicUsageExhaustionResponse(
|
|
930
|
+
bodyText: string,
|
|
931
|
+
headers: Headers,
|
|
932
|
+
retryAfterMs: number | undefined,
|
|
933
|
+
retryDelayCapMs: number,
|
|
934
|
+
): boolean {
|
|
935
|
+
const overageReason = headers.get("anthropic-ratelimit-unified-overage-disabled-reason")?.toLowerCase();
|
|
936
|
+
if (overageReason === "out_of_credits") return true;
|
|
937
|
+
if (retryAfterMs !== undefined && retryAfterMs > retryDelayCapMs) return true;
|
|
938
|
+
|
|
939
|
+
try {
|
|
940
|
+
const parsed = JSON.parse(bodyText) as unknown;
|
|
941
|
+
const error = isRecord(parsed) ? parsed.error : undefined;
|
|
942
|
+
const type = getStringProperty(error, "type") ?? getStringProperty(parsed, "type");
|
|
943
|
+
const message = getStringProperty(error, "message") ?? getStringProperty(parsed, "message") ?? bodyText;
|
|
944
|
+
return (
|
|
945
|
+
/rate_limit_error/i.test(type ?? "") &&
|
|
946
|
+
(/request would exceed your account.?s rate limit/i.test(message) || /out_of_credits/i.test(message))
|
|
947
|
+
);
|
|
948
|
+
} catch {
|
|
949
|
+
return /request would exceed your account.?s rate limit|out_of_credits/i.test(bodyText);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
function wrapAnthropicFetchForBoundedRateLimits(baseFetch: FetchImpl, maxRetryDelayMs: number | undefined): FetchImpl {
|
|
954
|
+
const retryDelayCapMs = maxRetryDelayMs ?? ANTHROPIC_RETRY_DELAY_CAP_MS;
|
|
955
|
+
return Object.assign(
|
|
956
|
+
async (input: string | URL | Request, init?: RequestInit): Promise<Response> => {
|
|
957
|
+
const response = await baseFetch(input, init);
|
|
958
|
+
if (response.status !== 429 || retryDelayCapMs === 0) return response;
|
|
959
|
+
|
|
960
|
+
const headers = new Headers(response.headers);
|
|
961
|
+
const retryAfterMs = getRetryAfterMsFromHeaders(headers);
|
|
962
|
+
const bodyText = await response
|
|
963
|
+
.clone()
|
|
964
|
+
.text()
|
|
965
|
+
.catch(() => "");
|
|
966
|
+
if (!isAnthropicUsageExhaustionResponse(bodyText, headers, retryAfterMs, retryDelayCapMs)) return response;
|
|
967
|
+
|
|
968
|
+
headers.set("x-should-retry", "false");
|
|
969
|
+
return new Response(appendAnthropicRateLimitEvidence(bodyText, headers), {
|
|
970
|
+
status: response.status,
|
|
971
|
+
statusText: response.statusText,
|
|
972
|
+
headers,
|
|
973
|
+
});
|
|
974
|
+
},
|
|
975
|
+
baseFetch.preconnect ? { preconnect: baseFetch.preconnect } : {},
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
|
|
880
979
|
// The Anthropic SDK logs malformed SSE frames directly before rethrowing them.
|
|
881
980
|
// We surface the resulting provider error ourselves, so keep the SDK quiet.
|
|
882
981
|
const ANTHROPIC_SDK_LOG_LEVEL = "off" as const;
|
|
@@ -1042,6 +1141,7 @@ export function isProviderRetryableError(error: unknown, provider?: string): boo
|
|
|
1042
1141
|
if (!(error instanceof Error)) return false;
|
|
1043
1142
|
if (provider === "github-copilot" && isCopilotTransientModelError(error)) return true;
|
|
1044
1143
|
const msg = error.message.toLowerCase();
|
|
1144
|
+
if (isUsageLimitError(error.message)) return false;
|
|
1045
1145
|
if (
|
|
1046
1146
|
isUnexpectedSocketCloseMessage(msg) ||
|
|
1047
1147
|
/rate.?limit|too many requests|overloaded|service.?unavailable|internal_error|stream error.*received from peer|1302|timed?\s*out while waiting for the first event|timeout waiting for first/i.test(
|
|
@@ -1166,6 +1266,7 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
1166
1266
|
onSseEvent: options?.onSseEvent,
|
|
1167
1267
|
fetch: options?.fetch,
|
|
1168
1268
|
requestMaxRetries: options?.requestMaxRetries,
|
|
1269
|
+
maxRetryDelayMs: options?.maxRetryDelayMs,
|
|
1169
1270
|
});
|
|
1170
1271
|
client = created.client;
|
|
1171
1272
|
isOAuthToken = created.isOAuthToken;
|
|
@@ -1723,11 +1824,8 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
|
|
|
1723
1824
|
const foundryCustomHeaders = resolveAnthropicCustomHeaders(model);
|
|
1724
1825
|
const tlsFetchOptions = buildClaudeCodeTlsFetchOptions(model, baseUrl);
|
|
1725
1826
|
const baseFetch = args.fetch ?? fetch;
|
|
1726
|
-
const
|
|
1727
|
-
|
|
1728
|
-
: args.fetch
|
|
1729
|
-
? baseFetch
|
|
1730
|
-
: undefined;
|
|
1827
|
+
const boundedFetch = wrapAnthropicFetchForBoundedRateLimits(baseFetch, args.maxRetryDelayMs);
|
|
1828
|
+
const debugFetch = onSseEvent ? wrapFetchForSseDebug(boundedFetch, event => onSseEvent(event, model)) : boundedFetch;
|
|
1731
1829
|
if (model.provider === "github-copilot") {
|
|
1732
1830
|
const copilotApiKey = parseGitHubCopilotApiKey(apiKey).accessToken;
|
|
1733
1831
|
const betaFeatures = [...extraBetas];
|
|
@@ -1755,7 +1853,7 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
|
|
|
1755
1853
|
dangerouslyAllowBrowser: true,
|
|
1756
1854
|
defaultHeaders,
|
|
1757
1855
|
logLevel: ANTHROPIC_SDK_LOG_LEVEL,
|
|
1758
|
-
|
|
1856
|
+
fetch: debugFetch,
|
|
1759
1857
|
...(tlsFetchOptions ? { fetchOptions: tlsFetchOptions } : {}),
|
|
1760
1858
|
};
|
|
1761
1859
|
}
|
|
@@ -1789,7 +1887,7 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
|
|
|
1789
1887
|
dangerouslyAllowBrowser: true,
|
|
1790
1888
|
defaultHeaders,
|
|
1791
1889
|
logLevel: ANTHROPIC_SDK_LOG_LEVEL,
|
|
1792
|
-
|
|
1890
|
+
fetch: debugFetch,
|
|
1793
1891
|
};
|
|
1794
1892
|
}
|
|
1795
1893
|
|
|
@@ -1802,7 +1900,7 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
|
|
|
1802
1900
|
dangerouslyAllowBrowser: true,
|
|
1803
1901
|
defaultHeaders,
|
|
1804
1902
|
logLevel: ANTHROPIC_SDK_LOG_LEVEL,
|
|
1805
|
-
|
|
1903
|
+
fetch: debugFetch,
|
|
1806
1904
|
...(tlsFetchOptions ? { fetchOptions: tlsFetchOptions } : {}),
|
|
1807
1905
|
};
|
|
1808
1906
|
}
|
|
@@ -2183,8 +2281,6 @@ function buildParams(
|
|
|
2183
2281
|
params.output_config = { effort } as typeof params.output_config;
|
|
2184
2282
|
}
|
|
2185
2283
|
}
|
|
2186
|
-
} else if (options?.thinkingEnabled === false) {
|
|
2187
|
-
params.thinking = { type: "disabled" };
|
|
2188
2284
|
}
|
|
2189
2285
|
}
|
|
2190
2286
|
|
|
@@ -2394,7 +2490,7 @@ export function convertAnthropicMessages(
|
|
|
2394
2490
|
type: "tool_use",
|
|
2395
2491
|
id: block.id,
|
|
2396
2492
|
name: isOAuthToken ? applyClaudeToolPrefix(block.name) : block.name,
|
|
2397
|
-
input: block.arguments ?? {},
|
|
2493
|
+
input: sanitizeJsonStrings(block.arguments ?? {}),
|
|
2398
2494
|
});
|
|
2399
2495
|
}
|
|
2400
2496
|
}
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
markToolChoiceIncapability,
|
|
36
36
|
resolveToolChoice,
|
|
37
37
|
} from "../utils/tool-choice-capability";
|
|
38
|
+
import { wrapOpenAIFetchForBoundedRateLimits } from "./openai-bounded-rate-limits";
|
|
38
39
|
import { normalizeOpenAIResponsesPromptCacheKey, supportsDeveloperRole } from "./openai-responses";
|
|
39
40
|
import {
|
|
40
41
|
appendResponsesToolResultMessages,
|
|
@@ -272,7 +273,7 @@ function createClient(model: Model<"azure-openai-responses">, apiKey: string, op
|
|
|
272
273
|
|
|
273
274
|
const { baseUrl, apiVersion } = resolveAzureConfig(model, options);
|
|
274
275
|
|
|
275
|
-
const baseFetch = options?.fetch ?? fetch;
|
|
276
|
+
const baseFetch = wrapOpenAIFetchForBoundedRateLimits(options?.fetch ?? fetch, options?.maxRetryDelayMs);
|
|
276
277
|
const onSseEvent = options?.onSseEvent;
|
|
277
278
|
return new AzureOpenAI({
|
|
278
279
|
apiKey,
|
|
@@ -18,7 +18,7 @@ import type {
|
|
|
18
18
|
Tool,
|
|
19
19
|
ToolCall,
|
|
20
20
|
} from "../types";
|
|
21
|
-
import { normalizeSystemPrompts } from "../utils";
|
|
21
|
+
import { normalizeSystemPrompts, sanitizeJsonStrings } from "../utils";
|
|
22
22
|
import { AssistantMessageEventStream } from "../utils/event-stream";
|
|
23
23
|
import { finalizeErrorMessage, type RawHttpRequestDump, withHttpStatus } from "../utils/http-inspector";
|
|
24
24
|
import { normalizeSchemaForCCA, normalizeSchemaForGoogle, toolWireSchema } from "../utils/schema";
|
|
@@ -237,7 +237,7 @@ export function convertMessages<T extends GoogleApiType>(model: Model<T>, contex
|
|
|
237
237
|
const part: Part = {
|
|
238
238
|
functionCall: {
|
|
239
239
|
name: block.name,
|
|
240
|
-
args: block.arguments ?? {},
|
|
240
|
+
args: sanitizeJsonStrings(block.arguments ?? {}) as Record<string, unknown>,
|
|
241
241
|
...(requiresToolCallId(model.id) ? { id: block.id } : {}),
|
|
242
242
|
},
|
|
243
243
|
};
|
|
@@ -467,7 +467,7 @@ export function pushToolCallEvents(
|
|
|
467
467
|
stream.push({
|
|
468
468
|
type: "toolcall_delta",
|
|
469
469
|
contentIndex,
|
|
470
|
-
delta: JSON.stringify(toolCall.arguments),
|
|
470
|
+
delta: JSON.stringify(sanitizeJsonStrings(toolCall.arguments)),
|
|
471
471
|
partial: output,
|
|
472
472
|
});
|
|
473
473
|
stream.push({ type: "toolcall_end", contentIndex, toolCall, partial: output });
|