@fgv/ts-extras 5.1.0-37 → 5.1.0-39
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/packlets/ai-assist/apiClient.js +66 -111
- package/dist/packlets/ai-assist/apiClient.js.map +1 -1
- package/dist/packlets/ai-assist/converters.js +16 -3
- package/dist/packlets/ai-assist/converters.js.map +1 -1
- package/dist/packlets/ai-assist/embeddingClient.js +5 -6
- package/dist/packlets/ai-assist/embeddingClient.js.map +1 -1
- package/dist/packlets/ai-assist/imageOptionsResolver.js +0 -19
- package/dist/packlets/ai-assist/imageOptionsResolver.js.map +1 -1
- package/dist/packlets/ai-assist/index.js +2 -2
- package/dist/packlets/ai-assist/index.js.map +1 -1
- package/dist/packlets/ai-assist/model.js +139 -7
- package/dist/packlets/ai-assist/model.js.map +1 -1
- package/dist/packlets/ai-assist/registry.js +58 -51
- package/dist/packlets/ai-assist/registry.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +38 -11
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +187 -36
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/common.js +13 -0
- package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js +12 -4
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +6 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +10 -3
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js +5 -2
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
- package/dist/packlets/ai-assist/streamingClient.js +16 -16
- package/dist/packlets/ai-assist/streamingClient.js.map +1 -1
- package/dist/packlets/crypto-utils/converters.js +18 -0
- package/dist/packlets/crypto-utils/converters.js.map +1 -1
- package/dist/packlets/crypto-utils/index.browser.js +2 -2
- package/dist/packlets/crypto-utils/index.browser.js.map +1 -1
- package/dist/packlets/crypto-utils/index.js +2 -2
- package/dist/packlets/crypto-utils/index.js.map +1 -1
- package/dist/packlets/crypto-utils/keystore/keyStore.js +19 -4
- package/dist/packlets/crypto-utils/keystore/keyStore.js.map +1 -1
- package/dist/packlets/crypto-utils/keystore/model.js.map +1 -1
- package/dist/packlets/crypto-utils/model.js.map +1 -1
- package/dist/packlets/crypto-utils/spkiHelpers.js +104 -25
- package/dist/packlets/crypto-utils/spkiHelpers.js.map +1 -1
- package/dist/ts-extras.d.ts +377 -132
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/packlets/ai-assist/apiClient.d.ts +12 -2
- package/lib/packlets/ai-assist/apiClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/apiClient.js +65 -110
- package/lib/packlets/ai-assist/apiClient.js.map +1 -1
- package/lib/packlets/ai-assist/converters.d.ts +8 -2
- package/lib/packlets/ai-assist/converters.d.ts.map +1 -1
- package/lib/packlets/ai-assist/converters.js +17 -4
- package/lib/packlets/ai-assist/converters.js.map +1 -1
- package/lib/packlets/ai-assist/embeddingClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/embeddingClient.js +4 -5
- package/lib/packlets/ai-assist/embeddingClient.js.map +1 -1
- package/lib/packlets/ai-assist/imageOptionsResolver.d.ts +0 -8
- package/lib/packlets/ai-assist/imageOptionsResolver.d.ts.map +1 -1
- package/lib/packlets/ai-assist/imageOptionsResolver.js +0 -19
- package/lib/packlets/ai-assist/imageOptionsResolver.js.map +1 -1
- package/lib/packlets/ai-assist/index.d.ts +3 -3
- package/lib/packlets/ai-assist/index.d.ts.map +1 -1
- package/lib/packlets/ai-assist/index.js +6 -1
- package/lib/packlets/ai-assist/index.js.map +1 -1
- package/lib/packlets/ai-assist/model.d.ts +181 -98
- package/lib/packlets/ai-assist/model.d.ts.map +1 -1
- package/lib/packlets/ai-assist/model.js +143 -8
- package/lib/packlets/ai-assist/model.js.map +1 -1
- package/lib/packlets/ai-assist/registry.d.ts.map +1 -1
- package/lib/packlets/ai-assist/registry.js +58 -51
- package/lib/packlets/ai-assist/registry.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +37 -10
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +82 -3
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +187 -35
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +24 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.js +14 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts +10 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js +12 -4
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +6 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +10 -3
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js +5 -2
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.d.ts +1 -1
- package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.js +15 -15
- package/lib/packlets/ai-assist/streamingClient.js.map +1 -1
- package/lib/packlets/crypto-utils/converters.d.ts +9 -1
- package/lib/packlets/crypto-utils/converters.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/converters.js +19 -1
- package/lib/packlets/crypto-utils/converters.js.map +1 -1
- package/lib/packlets/crypto-utils/index.browser.d.ts +1 -1
- package/lib/packlets/crypto-utils/index.browser.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/index.browser.js +6 -2
- package/lib/packlets/crypto-utils/index.browser.js.map +1 -1
- package/lib/packlets/crypto-utils/index.d.ts +1 -1
- package/lib/packlets/crypto-utils/index.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/index.js +6 -2
- package/lib/packlets/crypto-utils/index.js.map +1 -1
- package/lib/packlets/crypto-utils/keystore/keyStore.d.ts +9 -2
- package/lib/packlets/crypto-utils/keystore/keyStore.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/keystore/keyStore.js +19 -4
- package/lib/packlets/crypto-utils/keystore/keyStore.js.map +1 -1
- package/lib/packlets/crypto-utils/keystore/model.d.ts +7 -0
- package/lib/packlets/crypto-utils/keystore/model.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/keystore/model.js.map +1 -1
- package/lib/packlets/crypto-utils/model.d.ts +11 -1
- package/lib/packlets/crypto-utils/model.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/model.js.map +1 -1
- package/lib/packlets/crypto-utils/spkiHelpers.d.ts +59 -2
- package/lib/packlets/crypto-utils/spkiHelpers.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/spkiHelpers.js +108 -25
- package/lib/packlets/crypto-utils/spkiHelpers.js.map +1 -1
- package/package.json +7 -7
|
@@ -51,7 +51,20 @@ const BUILTIN_PROVIDERS = [
|
|
|
51
51
|
needsSecret: true,
|
|
52
52
|
apiFormat: 'anthropic',
|
|
53
53
|
baseUrl: 'https://api.anthropic.com/v1',
|
|
54
|
-
defaultModel:
|
|
54
|
+
defaultModel: {
|
|
55
|
+
base: '@anthropic:sonnet', // claude-sonnet-5 (was 'claude-sonnet-4-5-20250929')
|
|
56
|
+
advanced: '@anthropic:opus' // claude-opus-4-8
|
|
57
|
+
// no frontier key → a frontier request cascades advanced → opus (see resolveModel)
|
|
58
|
+
},
|
|
59
|
+
aliases: {
|
|
60
|
+
'@anthropic:sonnet': 'claude-sonnet-5', // base tier
|
|
61
|
+
'@anthropic:opus': 'claude-opus-4-8', // advanced tier
|
|
62
|
+
'@anthropic:haiku': 'claude-haiku-4-5-20251001', // NON-tier alias; modelOverride only
|
|
63
|
+
'@anthropic:fable': 'claude-fable-5' // NON-tier alias; modelOverride only
|
|
64
|
+
// NOTE: no thinking/image/embedding keys — Anthropic completions are all text; base
|
|
65
|
+
// (sonnet-5) and advanced (opus-4-8) are both thinking-capable, so a thinking-context
|
|
66
|
+
// call flat-falls to base safely.
|
|
67
|
+
},
|
|
55
68
|
supportedTools: ['web_search'],
|
|
56
69
|
corsRestricted: false,
|
|
57
70
|
streamingCorsRestricted: false,
|
|
@@ -66,9 +79,22 @@ const BUILTIN_PROVIDERS = [
|
|
|
66
79
|
apiFormat: 'gemini',
|
|
67
80
|
baseUrl: 'https://generativelanguage.googleapis.com/v1beta',
|
|
68
81
|
defaultModel: {
|
|
69
|
-
base: 'gemini
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
base: '@google-gemini:flash',
|
|
83
|
+
advanced: '@google-gemini:pro', // reuses the existing @google-gemini:pro alias (no new alias entry)
|
|
84
|
+
image: '@google-gemini:flash-image',
|
|
85
|
+
embedding: '@google-gemini:embedding'
|
|
86
|
+
// no frontier key → a frontier request cascades advanced → pro (see resolveModel)
|
|
87
|
+
},
|
|
88
|
+
aliases: {
|
|
89
|
+
// NOTE: the base flash line is at 3.5 while pro / flash-lite / flash-image are at 3.1 — this is
|
|
90
|
+
// NOT a typo. The targets come verbatim from Google's official deprecation table: the flash base
|
|
91
|
+
// line advanced to 3.5 while the other roles are on the 3.1 generation. The per-role version
|
|
92
|
+
// split is exactly why the alias layer exists — consumers never see these numbers.
|
|
93
|
+
'@google-gemini:flash': 'gemini-3.5-flash', // base (was gemini-2.5-flash, shutdown 2026-10-16)
|
|
94
|
+
'@google-gemini:pro': 'gemini-3.1-pro-preview', // advanced-tier role (wired to the 'advanced' defaultModel key); also the frontier cascade target (was gemini-2.5-pro, 2026-10-16)
|
|
95
|
+
'@google-gemini:flash-lite': 'gemini-3.1-flash-lite', // cheaper thinking-capable line; available via modelOverride only (was gemini-2.5-flash-lite, 2026-10-16)
|
|
96
|
+
'@google-gemini:flash-image': 'gemini-3.1-flash-image-preview', // image (was gemini-2.5-flash-image, 2026-10-02)
|
|
97
|
+
'@google-gemini:embedding': 'gemini-embedding-001' // NOT deprecated — aliased for uniformity only
|
|
72
98
|
},
|
|
73
99
|
supportedTools: ['web_search'],
|
|
74
100
|
corsRestricted: false,
|
|
@@ -85,26 +111,6 @@ const BUILTIN_PROVIDERS = [
|
|
|
85
111
|
}
|
|
86
112
|
],
|
|
87
113
|
imageGeneration: [
|
|
88
|
-
{
|
|
89
|
-
// Imagen 4 Ultra: max 1 image
|
|
90
|
-
modelPrefix: 'imagen-4.0-ultra-',
|
|
91
|
-
format: 'gemini-imagen',
|
|
92
|
-
acceptsImageReferenceInput: false,
|
|
93
|
-
supportsQualityParam: false,
|
|
94
|
-
maxCount: 1,
|
|
95
|
-
outputParamStyle: 'none',
|
|
96
|
-
defaultOutputMimeType: 'image/png'
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
// All other Imagen 4 models: max 4 images
|
|
100
|
-
modelPrefix: 'imagen-',
|
|
101
|
-
format: 'gemini-imagen',
|
|
102
|
-
acceptsImageReferenceInput: false,
|
|
103
|
-
supportsQualityParam: false,
|
|
104
|
-
maxCount: 4,
|
|
105
|
-
outputParamStyle: 'none',
|
|
106
|
-
defaultOutputMimeType: 'image/png'
|
|
107
|
-
},
|
|
108
114
|
{
|
|
109
115
|
// Gemini Flash Image: chat-style generateContent
|
|
110
116
|
modelPrefix: '',
|
|
@@ -168,12 +174,31 @@ const BUILTIN_PROVIDERS = [
|
|
|
168
174
|
needsSecret: true,
|
|
169
175
|
apiFormat: 'openai',
|
|
170
176
|
baseUrl: 'https://api.openai.com/v1',
|
|
171
|
-
defaultModel: {
|
|
177
|
+
defaultModel: {
|
|
178
|
+
base: '@openai:mini', // gpt-5.4-mini (was 'gpt-4o' — EOL-behind)
|
|
179
|
+
advanced: '@openai:flagship', // gpt-5.5
|
|
180
|
+
// gpt-5.5-pro is a Responses-API-only model (400s on chat completions). The completion
|
|
181
|
+
// and streaming dispatch route Responses-only models to the Responses API via the
|
|
182
|
+
// `responsesOnlyModelPrefixes` marker below, so `frontier` is invokable again.
|
|
183
|
+
frontier: '@openai:pro', // gpt-5.5-pro (Responses-API-only; routed via responsesOnlyModelPrefixes)
|
|
184
|
+
image: '@openai:image', // gpt-image-1.5 (was 'dall-e-3' — EOL 2026-05-12)
|
|
185
|
+
embedding: '@openai:embedding' // text-embedding-3-small (unchanged, aliased for uniformity)
|
|
186
|
+
},
|
|
187
|
+
aliases: {
|
|
188
|
+
'@openai:mini': 'gpt-5.4-mini', // base tier
|
|
189
|
+
'@openai:flagship': 'gpt-5.5', // advanced tier
|
|
190
|
+
'@openai:pro': 'gpt-5.5-pro', // frontier tier; Responses-API-only (routed via responsesOnlyModelPrefixes)
|
|
191
|
+
'@openai:nano': 'gpt-5.4-nano', // NON-tier alias; modelOverride only
|
|
192
|
+
'@openai:image': 'gpt-image-1.5', // image (matches the gpt-image- capability prefix)
|
|
193
|
+
'@openai:embedding': 'text-embedding-3-small' // NOT deprecated — aliased for uniformity
|
|
194
|
+
// NOTE: gpt-5.1 deliberately absent — retired March 2026.
|
|
195
|
+
},
|
|
172
196
|
supportedTools: ['web_search'],
|
|
173
197
|
corsRestricted: false,
|
|
174
198
|
streamingCorsRestricted: false,
|
|
175
199
|
acceptsImageInput: true,
|
|
176
200
|
thinkingMode: 'optional',
|
|
201
|
+
responsesOnlyModelPrefixes: ['gpt-5.5-pro'],
|
|
177
202
|
embedding: [
|
|
178
203
|
{
|
|
179
204
|
modelPrefix: 'text-embedding-3',
|
|
@@ -198,27 +223,6 @@ const BUILTIN_PROVIDERS = [
|
|
|
198
223
|
outputParamStyle: 'output-format',
|
|
199
224
|
defaultOutputMimeType: 'image/png'
|
|
200
225
|
},
|
|
201
|
-
{
|
|
202
|
-
modelPrefix: 'dall-e-3',
|
|
203
|
-
format: 'openai-images',
|
|
204
|
-
acceptsImageReferenceInput: false,
|
|
205
|
-
acceptedSizes: ['1024x1024', '1792x1024', '1024x1792'],
|
|
206
|
-
supportsQualityParam: true,
|
|
207
|
-
acceptedQualities: ['standard', 'hd'],
|
|
208
|
-
maxCount: 1,
|
|
209
|
-
outputParamStyle: 'response-format',
|
|
210
|
-
defaultOutputMimeType: 'image/png'
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
modelPrefix: 'dall-e-2',
|
|
214
|
-
format: 'openai-images',
|
|
215
|
-
acceptsImageReferenceInput: false,
|
|
216
|
-
acceptedSizes: ['256x256', '512x512', '1024x1024'],
|
|
217
|
-
supportsQualityParam: false,
|
|
218
|
-
maxCount: 10,
|
|
219
|
-
outputParamStyle: 'response-format',
|
|
220
|
-
defaultOutputMimeType: 'image/png'
|
|
221
|
-
},
|
|
222
226
|
{
|
|
223
227
|
modelPrefix: '',
|
|
224
228
|
format: 'openai-images',
|
|
@@ -251,8 +255,6 @@ const BUILTIN_PROVIDERS = [
|
|
|
251
255
|
baseUrl: 'https://api.x.ai/v1',
|
|
252
256
|
defaultModel: {
|
|
253
257
|
base: 'grok-4.3',
|
|
254
|
-
tools: 'grok-4.3',
|
|
255
|
-
thinking: 'grok-4.3',
|
|
256
258
|
image: 'grok-imagine-image-quality'
|
|
257
259
|
},
|
|
258
260
|
supportedTools: ['web_search'],
|
|
@@ -394,7 +396,6 @@ export function resolveEmbeddingCapability(descriptor, modelId) {
|
|
|
394
396
|
export const DEFAULT_MODEL_CAPABILITY_CONFIG = {
|
|
395
397
|
perProvider: {
|
|
396
398
|
openai: [
|
|
397
|
-
{ idPattern: /^dall-e/, capabilities: ['image-generation'] },
|
|
398
399
|
{ idPattern: /^gpt-image/, capabilities: ['image-generation'] },
|
|
399
400
|
{ idPattern: /^text-embedding/, capabilities: ['embedding'] },
|
|
400
401
|
{ idPattern: /^gpt-5/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },
|
|
@@ -415,12 +416,18 @@ export const DEFAULT_MODEL_CAPABILITY_CONFIG = {
|
|
|
415
416
|
{ idPattern: /^imagen/, capabilities: ['image-generation'] },
|
|
416
417
|
{ idPattern: /^gemini-.*-image/, capabilities: ['image-generation'] },
|
|
417
418
|
{ idPattern: /embedding/, capabilities: ['embedding'] },
|
|
419
|
+
{ idPattern: /^gemini-3/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },
|
|
418
420
|
{ idPattern: /^gemini-2\.5/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },
|
|
419
421
|
{ idPattern: /^gemini-/, capabilities: ['chat', 'tools', 'vision'] }
|
|
420
422
|
],
|
|
421
423
|
anthropic: [
|
|
422
|
-
|
|
423
|
-
|
|
424
|
+
// Broadened from /^claude-opus-4/ and /^claude-sonnet-4/ so the sonnet-5+ / opus-5+ lines
|
|
425
|
+
// are detected as thinking-capable. Detection accumulates across matching rules, so this is
|
|
426
|
+
// purely additive: every existing opus-4 / sonnet-4 id still matches. The sonnet broadening
|
|
427
|
+
// is required (claude-sonnet-5 otherwise hits only /^claude-/ and loses thinking); the opus
|
|
428
|
+
// broadening is future-proofing (claude-opus-4-8 already matches /^claude-opus-4/).
|
|
429
|
+
{ idPattern: /^claude-opus-/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },
|
|
430
|
+
{ idPattern: /^claude-sonnet-/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },
|
|
424
431
|
{ idPattern: /^claude-/, capabilities: ['chat', 'tools', 'vision'] }
|
|
425
432
|
],
|
|
426
433
|
groq: [{ idPattern: /./, capabilities: ['chat'] }],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/registry.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Centralized provider registry — single source of truth for all AI provider metadata.\n * @packageDocumentation\n */\n\nimport { fail, Result, succeed } from '@fgv/ts-utils';\n\nimport {\n type AiProviderId,\n type IAiEmbeddingModelCapability,\n type IAiImageModelCapability,\n type IAiModelCapabilityConfig,\n type IAiProviderDescriptor\n} from './model';\n\n// ============================================================================\n// Built-in providers\n// ============================================================================\n\n/**\n * All known AI provider descriptors. Copy-paste first, then alphabetical.\n * @internal\n */\nconst BUILTIN_PROVIDERS: ReadonlyArray<IAiProviderDescriptor> = [\n {\n id: 'copy-paste',\n label: 'Copy / Paste',\n buttonLabel: 'AI Assist | Copy',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: '',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported'\n },\n {\n id: 'anthropic',\n label: 'Anthropic Claude',\n buttonLabel: 'AI Assist | Claude',\n needsSecret: true,\n apiFormat: 'anthropic',\n baseUrl: 'https://api.anthropic.com/v1',\n defaultModel: 'claude-sonnet-4-5-20250929',\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional'\n },\n {\n id: 'google-gemini',\n label: 'Google Gemini',\n buttonLabel: 'AI Assist | Gemini',\n needsSecret: true,\n apiFormat: 'gemini',\n baseUrl: 'https://generativelanguage.googleapis.com/v1beta',\n defaultModel: {\n base: 'gemini-2.5-flash',\n image: 'gemini-2.5-flash-image',\n embedding: 'gemini-embedding-001'\n },\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n embedding: [\n {\n modelPrefix: '',\n format: 'gemini-embeddings',\n supportsDimensions: true,\n supportsTaskType: true,\n defaultDimensions: 3072\n }\n ],\n imageGeneration: [\n {\n // Imagen 4 Ultra: max 1 image\n modelPrefix: 'imagen-4.0-ultra-',\n format: 'gemini-imagen',\n acceptsImageReferenceInput: false,\n supportsQualityParam: false,\n maxCount: 1,\n outputParamStyle: 'none',\n defaultOutputMimeType: 'image/png'\n },\n {\n // All other Imagen 4 models: max 4 images\n modelPrefix: 'imagen-',\n format: 'gemini-imagen',\n acceptsImageReferenceInput: false,\n supportsQualityParam: false,\n maxCount: 4,\n outputParamStyle: 'none',\n defaultOutputMimeType: 'image/png'\n },\n {\n // Gemini Flash Image: chat-style generateContent\n modelPrefix: '',\n format: 'gemini-image-out',\n acceptsImageReferenceInput: true,\n supportsQualityParam: false,\n maxCount: 1,\n outputParamStyle: 'none',\n defaultOutputMimeType: 'image/jpeg'\n }\n ]\n },\n {\n id: 'groq',\n label: 'Groq',\n buttonLabel: 'AI Assist | Groq',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.groq.com/openai/v1',\n defaultModel: 'llama-3.3-70b-versatile',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported'\n },\n {\n id: 'mistral',\n label: 'Mistral',\n buttonLabel: 'AI Assist | Mistral',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.mistral.ai/v1',\n defaultModel: { base: 'mistral-large-latest', embedding: 'mistral-embed' },\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'ollama',\n label: 'Ollama (self-hosted)',\n buttonLabel: 'AI Assist | Ollama',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: 'http://localhost:11434/v1',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'openai',\n label: 'OpenAI',\n buttonLabel: 'AI Assist | OpenAI',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.openai.com/v1',\n defaultModel: { base: 'gpt-4o', image: 'dall-e-3', embedding: 'text-embedding-3-small' },\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n embedding: [\n {\n modelPrefix: 'text-embedding-3',\n format: 'openai-embeddings',\n supportsDimensions: true,\n maxBatchSize: 2048\n },\n {\n modelPrefix: '',\n format: 'openai-embeddings'\n }\n ],\n imageGeneration: [\n {\n modelPrefix: 'gpt-image-',\n format: 'openai-images',\n acceptsImageReferenceInput: true,\n acceptedSizes: ['1024x1024', '1536x1024', '1024x1536', 'auto'],\n supportsQualityParam: true,\n acceptedQualities: ['low', 'medium', 'high', 'auto'],\n maxCount: 10,\n outputParamStyle: 'output-format',\n defaultOutputMimeType: 'image/png'\n },\n {\n modelPrefix: 'dall-e-3',\n format: 'openai-images',\n acceptsImageReferenceInput: false,\n acceptedSizes: ['1024x1024', '1792x1024', '1024x1792'],\n supportsQualityParam: true,\n acceptedQualities: ['standard', 'hd'],\n maxCount: 1,\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/png'\n },\n {\n modelPrefix: 'dall-e-2',\n format: 'openai-images',\n acceptsImageReferenceInput: false,\n acceptedSizes: ['256x256', '512x512', '1024x1024'],\n supportsQualityParam: false,\n maxCount: 10,\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/png'\n },\n {\n modelPrefix: '',\n format: 'openai-images',\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/png'\n }\n ]\n },\n {\n id: 'openai-compat',\n label: 'OpenAI-compatible (self-hosted)',\n buttonLabel: 'AI Assist | OpenAI-compat',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: '',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'xai-grok',\n label: 'xAI Grok',\n buttonLabel: 'AI Assist | Grok',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.x.ai/v1',\n defaultModel: {\n base: 'grok-4.3',\n tools: 'grok-4.3',\n thinking: 'grok-4.3',\n image: 'grok-imagine-image-quality'\n },\n supportedTools: ['web_search'],\n corsRestricted: true,\n streamingCorsRestricted: true,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n imageGeneration: [\n {\n // grok-imagine models use JSON edits with image_url objects (different wire format)\n modelPrefix: 'grok-imagine-',\n format: 'xai-images-edits',\n acceptsImageReferenceInput: true,\n supportsQualityParam: false,\n maxCount: 10,\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/jpeg'\n },\n {\n // catch-all for other xai image models\n modelPrefix: '',\n format: 'xai-images',\n acceptsImageReferenceInput: false,\n supportsQualityParam: false,\n maxCount: 10,\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/jpeg'\n }\n ]\n }\n];\n\n/**\n * Index for O(1) lookup by id.\n * @internal\n */\nconst PROVIDER_BY_ID: ReadonlyMap<string, IAiProviderDescriptor> = new Map(\n BUILTIN_PROVIDERS.map((d) => [d.id, d])\n);\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * All valid provider ID values, in the same order as the registry.\n * @public\n */\nexport const allProviderIds: ReadonlyArray<AiProviderId> = BUILTIN_PROVIDERS.map((d) => d.id);\n\n/**\n * Get all known provider descriptors. Copy-paste first, then alphabetical.\n * @returns All built-in provider descriptors\n * @public\n */\nexport function getProviderDescriptors(): ReadonlyArray<IAiProviderDescriptor> {\n return BUILTIN_PROVIDERS;\n}\n\n/**\n * Get a provider descriptor by id.\n * @param id - The provider identifier\n * @returns The descriptor, or a failure if the provider is unknown\n * @public\n */\nexport function getProviderDescriptor(id: string): Result<IAiProviderDescriptor> {\n const descriptor = PROVIDER_BY_ID.get(id);\n if (!descriptor) {\n return fail(`unknown AI provider: ${id}`);\n }\n return succeed(descriptor);\n}\n\n/**\n * Whether a provider declares any image-generation capability at all.\n *\n * @param descriptor - The provider descriptor\n * @returns `true` when {@link IAiProviderDescriptor.imageGeneration} has at\n * least one entry; `false` otherwise.\n * @public\n */\nexport function supportsImageGeneration(descriptor: IAiProviderDescriptor): boolean {\n return (descriptor.imageGeneration?.length ?? 0) > 0;\n}\n\n/**\n * Resolve the image-generation capability that applies to a given model id\n * for a provider. Returns the entry from\n * {@link IAiProviderDescriptor.imageGeneration} whose `modelPrefix` is the\n * longest prefix of `modelId`. Ties are broken by first-encountered, so rule\n * order does not matter for correctness — only for tie-breaking among rules\n * with identical-length prefixes (an unusual case).\n *\n * @param descriptor - The provider descriptor\n * @param modelId - The resolved image model id\n * @returns The matching capability, or `undefined` when no rule matches or\n * the provider declares no image-generation capabilities.\n * @public\n */\nexport function resolveImageCapability(\n descriptor: IAiProviderDescriptor,\n modelId: string\n): IAiImageModelCapability | undefined {\n return (descriptor.imageGeneration ?? [])\n .filter((cap) => modelId.startsWith(cap.modelPrefix))\n .reduce<IAiImageModelCapability | undefined>(\n (best, cap) => (best && best.modelPrefix.length >= cap.modelPrefix.length ? best : cap),\n undefined\n );\n}\n\n/**\n * Whether a provider declares any embedding capability at all.\n *\n * @param descriptor - The provider descriptor\n * @returns `true` when {@link IAiProviderDescriptor.embedding} has at least one\n * entry; `false` otherwise.\n * @public\n */\nexport function supportsEmbedding(descriptor: IAiProviderDescriptor): boolean {\n return (descriptor.embedding?.length ?? 0) > 0;\n}\n\n/**\n * Resolve the embedding capability that applies to a given model id for a\n * provider. Returns the entry from {@link IAiProviderDescriptor.embedding} whose\n * `modelPrefix` is the longest prefix of `modelId`. Ties are broken by\n * first-encountered.\n *\n * @param descriptor - The provider descriptor\n * @param modelId - The resolved embedding model id\n * @returns The matching capability, or `undefined` when no rule matches or the\n * provider declares no embedding capabilities.\n * @public\n */\nexport function resolveEmbeddingCapability(\n descriptor: IAiProviderDescriptor,\n modelId: string\n): IAiEmbeddingModelCapability | undefined {\n return (descriptor.embedding ?? [])\n .filter((cap) => modelId.startsWith(cap.modelPrefix))\n .reduce<IAiEmbeddingModelCapability | undefined>(\n (best, cap) => (best && best.modelPrefix.length >= cap.modelPrefix.length ? best : cap),\n undefined\n );\n}\n\n// ============================================================================\n// Default model capability config\n// ============================================================================\n\n/**\n * Default capability config used by `callProviderListModels` when callers\n * don't supply their own. Patterns are intentionally narrow — false\n * positives are worse than missing a model. Caller can override per call\n * via {@link IProviderListModelsParams.capabilityConfig}.\n *\n * @public\n */\nexport const DEFAULT_MODEL_CAPABILITY_CONFIG: IAiModelCapabilityConfig = {\n perProvider: {\n openai: [\n { idPattern: /^dall-e/, capabilities: ['image-generation'] },\n { idPattern: /^gpt-image/, capabilities: ['image-generation'] },\n { idPattern: /^text-embedding/, capabilities: ['embedding'] },\n { idPattern: /^gpt-5/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^gpt-4/, capabilities: ['chat', 'tools', 'vision'] },\n { idPattern: /^gpt-3\\.5/, capabilities: ['chat'] },\n { idPattern: /^o\\d/, capabilities: ['chat', 'tools', 'thinking'] }\n ],\n 'xai-grok': [\n { idPattern: /-image/, capabilities: ['image-generation'] },\n { idPattern: /^grok-4\\.3/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-4$/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-4/, capabilities: ['chat', 'tools', 'vision'] },\n { idPattern: /^grok-3-mini/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-3/, capabilities: ['chat', 'tools'] },\n { idPattern: /^grok-2/, capabilities: ['chat', 'vision'] }\n ],\n 'google-gemini': [\n { idPattern: /^imagen/, capabilities: ['image-generation'] },\n { idPattern: /^gemini-.*-image/, capabilities: ['image-generation'] },\n { idPattern: /embedding/, capabilities: ['embedding'] },\n { idPattern: /^gemini-2\\.5/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^gemini-/, capabilities: ['chat', 'tools', 'vision'] }\n ],\n anthropic: [\n { idPattern: /^claude-opus-4/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^claude-sonnet-4/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^claude-/, capabilities: ['chat', 'tools', 'vision'] }\n ],\n groq: [{ idPattern: /./, capabilities: ['chat'] }],\n mistral: [\n { idPattern: /embed/, capabilities: ['embedding'] },\n { idPattern: /./, capabilities: ['chat'] }\n ],\n // Self-hosted OpenAI-compatible servers (Ollama, LM Studio, llama.cpp) serve\n // arbitrary, caller-chosen models whose ids we can't enumerate ahead of time.\n // The catch-all `/./` intentionally departs from the \"narrow patterns\" rule\n // above: assume `chat` for everything and let the caller override via\n // `capabilityConfig` when they know their deployment serves image/embedding models.\n ollama: [{ idPattern: /./, capabilities: ['chat'] }],\n 'openai-compat': [{ idPattern: /./, capabilities: ['chat'] }]\n }\n};\n"]}
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/registry.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Centralized provider registry — single source of truth for all AI provider metadata.\n * @packageDocumentation\n */\n\nimport { fail, Result, succeed } from '@fgv/ts-utils';\n\nimport {\n type AiProviderId,\n type IAiEmbeddingModelCapability,\n type IAiImageModelCapability,\n type IAiModelCapabilityConfig,\n type IAiProviderDescriptor\n} from './model';\n\n// ============================================================================\n// Built-in providers\n// ============================================================================\n\n/**\n * All known AI provider descriptors. Copy-paste first, then alphabetical.\n * @internal\n */\nconst BUILTIN_PROVIDERS: ReadonlyArray<IAiProviderDescriptor> = [\n {\n id: 'copy-paste',\n label: 'Copy / Paste',\n buttonLabel: 'AI Assist | Copy',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: '',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported'\n },\n {\n id: 'anthropic',\n label: 'Anthropic Claude',\n buttonLabel: 'AI Assist | Claude',\n needsSecret: true,\n apiFormat: 'anthropic',\n baseUrl: 'https://api.anthropic.com/v1',\n defaultModel: {\n base: '@anthropic:sonnet', // claude-sonnet-5 (was 'claude-sonnet-4-5-20250929')\n advanced: '@anthropic:opus' // claude-opus-4-8\n // no frontier key → a frontier request cascades advanced → opus (see resolveModel)\n },\n aliases: {\n '@anthropic:sonnet': 'claude-sonnet-5', // base tier\n '@anthropic:opus': 'claude-opus-4-8', // advanced tier\n '@anthropic:haiku': 'claude-haiku-4-5-20251001', // NON-tier alias; modelOverride only\n '@anthropic:fable': 'claude-fable-5' // NON-tier alias; modelOverride only\n // NOTE: no thinking/image/embedding keys — Anthropic completions are all text; base\n // (sonnet-5) and advanced (opus-4-8) are both thinking-capable, so a thinking-context\n // call flat-falls to base safely.\n },\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional'\n },\n {\n id: 'google-gemini',\n label: 'Google Gemini',\n buttonLabel: 'AI Assist | Gemini',\n needsSecret: true,\n apiFormat: 'gemini',\n baseUrl: 'https://generativelanguage.googleapis.com/v1beta',\n defaultModel: {\n base: '@google-gemini:flash',\n advanced: '@google-gemini:pro', // reuses the existing @google-gemini:pro alias (no new alias entry)\n image: '@google-gemini:flash-image',\n embedding: '@google-gemini:embedding'\n // no frontier key → a frontier request cascades advanced → pro (see resolveModel)\n },\n aliases: {\n // NOTE: the base flash line is at 3.5 while pro / flash-lite / flash-image are at 3.1 — this is\n // NOT a typo. The targets come verbatim from Google's official deprecation table: the flash base\n // line advanced to 3.5 while the other roles are on the 3.1 generation. The per-role version\n // split is exactly why the alias layer exists — consumers never see these numbers.\n '@google-gemini:flash': 'gemini-3.5-flash', // base (was gemini-2.5-flash, shutdown 2026-10-16)\n '@google-gemini:pro': 'gemini-3.1-pro-preview', // advanced-tier role (wired to the 'advanced' defaultModel key); also the frontier cascade target (was gemini-2.5-pro, 2026-10-16)\n '@google-gemini:flash-lite': 'gemini-3.1-flash-lite', // cheaper thinking-capable line; available via modelOverride only (was gemini-2.5-flash-lite, 2026-10-16)\n '@google-gemini:flash-image': 'gemini-3.1-flash-image-preview', // image (was gemini-2.5-flash-image, 2026-10-02)\n '@google-gemini:embedding': 'gemini-embedding-001' // NOT deprecated — aliased for uniformity only\n },\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n embedding: [\n {\n modelPrefix: '',\n format: 'gemini-embeddings',\n supportsDimensions: true,\n supportsTaskType: true,\n defaultDimensions: 3072\n }\n ],\n imageGeneration: [\n {\n // Gemini Flash Image: chat-style generateContent\n modelPrefix: '',\n format: 'gemini-image-out',\n acceptsImageReferenceInput: true,\n supportsQualityParam: false,\n maxCount: 1,\n outputParamStyle: 'none',\n defaultOutputMimeType: 'image/jpeg'\n }\n ]\n },\n {\n id: 'groq',\n label: 'Groq',\n buttonLabel: 'AI Assist | Groq',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.groq.com/openai/v1',\n defaultModel: 'llama-3.3-70b-versatile',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported'\n },\n {\n id: 'mistral',\n label: 'Mistral',\n buttonLabel: 'AI Assist | Mistral',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.mistral.ai/v1',\n defaultModel: { base: 'mistral-large-latest', embedding: 'mistral-embed' },\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'ollama',\n label: 'Ollama (self-hosted)',\n buttonLabel: 'AI Assist | Ollama',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: 'http://localhost:11434/v1',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'openai',\n label: 'OpenAI',\n buttonLabel: 'AI Assist | OpenAI',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.openai.com/v1',\n defaultModel: {\n base: '@openai:mini', // gpt-5.4-mini (was 'gpt-4o' — EOL-behind)\n advanced: '@openai:flagship', // gpt-5.5\n // gpt-5.5-pro is a Responses-API-only model (400s on chat completions). The completion\n // and streaming dispatch route Responses-only models to the Responses API via the\n // `responsesOnlyModelPrefixes` marker below, so `frontier` is invokable again.\n frontier: '@openai:pro', // gpt-5.5-pro (Responses-API-only; routed via responsesOnlyModelPrefixes)\n image: '@openai:image', // gpt-image-1.5 (was 'dall-e-3' — EOL 2026-05-12)\n embedding: '@openai:embedding' // text-embedding-3-small (unchanged, aliased for uniformity)\n },\n aliases: {\n '@openai:mini': 'gpt-5.4-mini', // base tier\n '@openai:flagship': 'gpt-5.5', // advanced tier\n '@openai:pro': 'gpt-5.5-pro', // frontier tier; Responses-API-only (routed via responsesOnlyModelPrefixes)\n '@openai:nano': 'gpt-5.4-nano', // NON-tier alias; modelOverride only\n '@openai:image': 'gpt-image-1.5', // image (matches the gpt-image- capability prefix)\n '@openai:embedding': 'text-embedding-3-small' // NOT deprecated — aliased for uniformity\n // NOTE: gpt-5.1 deliberately absent — retired March 2026.\n },\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n responsesOnlyModelPrefixes: ['gpt-5.5-pro'],\n embedding: [\n {\n modelPrefix: 'text-embedding-3',\n format: 'openai-embeddings',\n supportsDimensions: true,\n maxBatchSize: 2048\n },\n {\n modelPrefix: '',\n format: 'openai-embeddings'\n }\n ],\n imageGeneration: [\n {\n modelPrefix: 'gpt-image-',\n format: 'openai-images',\n acceptsImageReferenceInput: true,\n acceptedSizes: ['1024x1024', '1536x1024', '1024x1536', 'auto'],\n supportsQualityParam: true,\n acceptedQualities: ['low', 'medium', 'high', 'auto'],\n maxCount: 10,\n outputParamStyle: 'output-format',\n defaultOutputMimeType: 'image/png'\n },\n {\n modelPrefix: '',\n format: 'openai-images',\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/png'\n }\n ]\n },\n {\n id: 'openai-compat',\n label: 'OpenAI-compatible (self-hosted)',\n buttonLabel: 'AI Assist | OpenAI-compat',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: '',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'xai-grok',\n label: 'xAI Grok',\n buttonLabel: 'AI Assist | Grok',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.x.ai/v1',\n defaultModel: {\n base: 'grok-4.3',\n image: 'grok-imagine-image-quality'\n },\n supportedTools: ['web_search'],\n corsRestricted: true,\n streamingCorsRestricted: true,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n imageGeneration: [\n {\n // grok-imagine models use JSON edits with image_url objects (different wire format)\n modelPrefix: 'grok-imagine-',\n format: 'xai-images-edits',\n acceptsImageReferenceInput: true,\n supportsQualityParam: false,\n maxCount: 10,\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/jpeg'\n },\n {\n // catch-all for other xai image models\n modelPrefix: '',\n format: 'xai-images',\n acceptsImageReferenceInput: false,\n supportsQualityParam: false,\n maxCount: 10,\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/jpeg'\n }\n ]\n }\n];\n\n/**\n * Index for O(1) lookup by id.\n * @internal\n */\nconst PROVIDER_BY_ID: ReadonlyMap<string, IAiProviderDescriptor> = new Map(\n BUILTIN_PROVIDERS.map((d) => [d.id, d])\n);\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * All valid provider ID values, in the same order as the registry.\n * @public\n */\nexport const allProviderIds: ReadonlyArray<AiProviderId> = BUILTIN_PROVIDERS.map((d) => d.id);\n\n/**\n * Get all known provider descriptors. Copy-paste first, then alphabetical.\n * @returns All built-in provider descriptors\n * @public\n */\nexport function getProviderDescriptors(): ReadonlyArray<IAiProviderDescriptor> {\n return BUILTIN_PROVIDERS;\n}\n\n/**\n * Get a provider descriptor by id.\n * @param id - The provider identifier\n * @returns The descriptor, or a failure if the provider is unknown\n * @public\n */\nexport function getProviderDescriptor(id: string): Result<IAiProviderDescriptor> {\n const descriptor = PROVIDER_BY_ID.get(id);\n if (!descriptor) {\n return fail(`unknown AI provider: ${id}`);\n }\n return succeed(descriptor);\n}\n\n/**\n * Whether a provider declares any image-generation capability at all.\n *\n * @param descriptor - The provider descriptor\n * @returns `true` when {@link IAiProviderDescriptor.imageGeneration} has at\n * least one entry; `false` otherwise.\n * @public\n */\nexport function supportsImageGeneration(descriptor: IAiProviderDescriptor): boolean {\n return (descriptor.imageGeneration?.length ?? 0) > 0;\n}\n\n/**\n * Resolve the image-generation capability that applies to a given model id\n * for a provider. Returns the entry from\n * {@link IAiProviderDescriptor.imageGeneration} whose `modelPrefix` is the\n * longest prefix of `modelId`. Ties are broken by first-encountered, so rule\n * order does not matter for correctness — only for tie-breaking among rules\n * with identical-length prefixes (an unusual case).\n *\n * @param descriptor - The provider descriptor\n * @param modelId - The resolved image model id\n * @returns The matching capability, or `undefined` when no rule matches or\n * the provider declares no image-generation capabilities.\n * @public\n */\nexport function resolveImageCapability(\n descriptor: IAiProviderDescriptor,\n modelId: string\n): IAiImageModelCapability | undefined {\n return (descriptor.imageGeneration ?? [])\n .filter((cap) => modelId.startsWith(cap.modelPrefix))\n .reduce<IAiImageModelCapability | undefined>(\n (best, cap) => (best && best.modelPrefix.length >= cap.modelPrefix.length ? best : cap),\n undefined\n );\n}\n\n/**\n * Whether a provider declares any embedding capability at all.\n *\n * @param descriptor - The provider descriptor\n * @returns `true` when {@link IAiProviderDescriptor.embedding} has at least one\n * entry; `false` otherwise.\n * @public\n */\nexport function supportsEmbedding(descriptor: IAiProviderDescriptor): boolean {\n return (descriptor.embedding?.length ?? 0) > 0;\n}\n\n/**\n * Resolve the embedding capability that applies to a given model id for a\n * provider. Returns the entry from {@link IAiProviderDescriptor.embedding} whose\n * `modelPrefix` is the longest prefix of `modelId`. Ties are broken by\n * first-encountered.\n *\n * @param descriptor - The provider descriptor\n * @param modelId - The resolved embedding model id\n * @returns The matching capability, or `undefined` when no rule matches or the\n * provider declares no embedding capabilities.\n * @public\n */\nexport function resolveEmbeddingCapability(\n descriptor: IAiProviderDescriptor,\n modelId: string\n): IAiEmbeddingModelCapability | undefined {\n return (descriptor.embedding ?? [])\n .filter((cap) => modelId.startsWith(cap.modelPrefix))\n .reduce<IAiEmbeddingModelCapability | undefined>(\n (best, cap) => (best && best.modelPrefix.length >= cap.modelPrefix.length ? best : cap),\n undefined\n );\n}\n\n// ============================================================================\n// Default model capability config\n// ============================================================================\n\n/**\n * Default capability config used by `callProviderListModels` when callers\n * don't supply their own. Patterns are intentionally narrow — false\n * positives are worse than missing a model. Caller can override per call\n * via {@link IProviderListModelsParams.capabilityConfig}.\n *\n * @public\n */\nexport const DEFAULT_MODEL_CAPABILITY_CONFIG: IAiModelCapabilityConfig = {\n perProvider: {\n openai: [\n { idPattern: /^gpt-image/, capabilities: ['image-generation'] },\n { idPattern: /^text-embedding/, capabilities: ['embedding'] },\n { idPattern: /^gpt-5/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^gpt-4/, capabilities: ['chat', 'tools', 'vision'] },\n { idPattern: /^gpt-3\\.5/, capabilities: ['chat'] },\n { idPattern: /^o\\d/, capabilities: ['chat', 'tools', 'thinking'] }\n ],\n 'xai-grok': [\n { idPattern: /-image/, capabilities: ['image-generation'] },\n { idPattern: /^grok-4\\.3/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-4$/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-4/, capabilities: ['chat', 'tools', 'vision'] },\n { idPattern: /^grok-3-mini/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-3/, capabilities: ['chat', 'tools'] },\n { idPattern: /^grok-2/, capabilities: ['chat', 'vision'] }\n ],\n 'google-gemini': [\n { idPattern: /^imagen/, capabilities: ['image-generation'] },\n { idPattern: /^gemini-.*-image/, capabilities: ['image-generation'] },\n { idPattern: /embedding/, capabilities: ['embedding'] },\n { idPattern: /^gemini-3/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^gemini-2\\.5/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^gemini-/, capabilities: ['chat', 'tools', 'vision'] }\n ],\n anthropic: [\n // Broadened from /^claude-opus-4/ and /^claude-sonnet-4/ so the sonnet-5+ / opus-5+ lines\n // are detected as thinking-capable. Detection accumulates across matching rules, so this is\n // purely additive: every existing opus-4 / sonnet-4 id still matches. The sonnet broadening\n // is required (claude-sonnet-5 otherwise hits only /^claude-/ and loses thinking); the opus\n // broadening is future-proofing (claude-opus-4-8 already matches /^claude-opus-4/).\n { idPattern: /^claude-opus-/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^claude-sonnet-/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^claude-/, capabilities: ['chat', 'tools', 'vision'] }\n ],\n groq: [{ idPattern: /./, capabilities: ['chat'] }],\n mistral: [\n { idPattern: /embed/, capabilities: ['embedding'] },\n { idPattern: /./, capabilities: ['chat'] }\n ],\n // Self-hosted OpenAI-compatible servers (Ollama, LM Studio, llama.cpp) serve\n // arbitrary, caller-chosen models whose ids we can't enumerate ahead of time.\n // The catch-all `/./` intentionally departs from the \"narrow patterns\" rule\n // above: assume `chat` for everything and let the caller override via\n // `capabilityConfig` when they know their deployment serves image/embedding models.\n ollama: [{ idPattern: /./, capabilities: ['chat'] }],\n 'openai-compat': [{ idPattern: /./, capabilities: ['chat'] }]\n }\n};\n"]}
|
|
@@ -54,7 +54,7 @@ import { buildAnthropicMessages } from '../chatRequestBuilders';
|
|
|
54
54
|
import { parseSseEventJson, readSseEvents } from '../sseParser';
|
|
55
55
|
import { toAnthropicTools } from '../toolFormats';
|
|
56
56
|
import { anthropicEffortToBudgetTokens } from '../thinkingOptionsResolver';
|
|
57
|
-
import { UNRECOGNIZED_EVENT_WARN_TAG, formatUnrecognizedEventPayloadPreview, openSseConnection, validateEventPayload } from './common';
|
|
57
|
+
import { MALFORMED_TOOL_USE_WARN_TAG, UNRECOGNIZED_EVENT_WARN_TAG, formatUnrecognizedEventPayloadPreview, openSseConnection, validateEventPayload } from './common';
|
|
58
58
|
const anthropicContentBlockInner = Validators.object({
|
|
59
59
|
type: Validators.string.optional(),
|
|
60
60
|
name: Validators.string.optional(),
|
|
@@ -158,14 +158,28 @@ function translateAnthropicStream(response, accumulationBuffer, logger) {
|
|
|
158
158
|
else if (block.type === 'text') {
|
|
159
159
|
accumulationBuffer.set(index, { type: 'text', text: '' });
|
|
160
160
|
}
|
|
161
|
-
else if (block.type === 'tool_use'
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
161
|
+
else if (block.type === 'tool_use') {
|
|
162
|
+
// A tool_use block_start MUST carry a non-empty id and name: the id is the
|
|
163
|
+
// sole correlation key for the follow-up tool_result, and dropping the block
|
|
164
|
+
// silently (then ignoring its input_json_delta chunks at the delta handler
|
|
165
|
+
// below) is exactly how an orphaned block leaves the harness without a clean
|
|
166
|
+
// id and corrupts the continuation. Surface it loudly instead of dropping it.
|
|
167
|
+
if (block.id && block.name) {
|
|
168
|
+
accumulationBuffer.set(index, {
|
|
169
|
+
type: 'tool_use',
|
|
170
|
+
id: block.id,
|
|
171
|
+
name: block.name,
|
|
172
|
+
argsBuffer: ''
|
|
173
|
+
});
|
|
174
|
+
yield yield __await({ type: 'client-tool-call-start', toolName: block.name, callId: block.id });
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
logger === null || logger === void 0 ? void 0 : logger.warn(`${MALFORMED_TOOL_USE_WARN_TAG} Anthropic streaming adapter: tool_use content_block_start ` +
|
|
178
|
+
`at index ${index} is missing a usable id and/or name ` +
|
|
179
|
+
`(id=${JSON.stringify(block.id)}, name=${JSON.stringify(block.name)}). ` +
|
|
180
|
+
`No client tool call will be issued for this block; its argument deltas are dropped. ` +
|
|
181
|
+
`This usually indicates provider drift or a truncated stream.`);
|
|
182
|
+
}
|
|
169
183
|
}
|
|
170
184
|
else if (block.type === 'server_tool_use' && block.name === 'web_search') {
|
|
171
185
|
yield yield __await({ type: 'tool-event', toolType: 'web_search', phase: 'started' });
|
|
@@ -310,8 +324,21 @@ export async function callAnthropicStream(config, prompt, messagesBefore, temper
|
|
|
310
324
|
head: messagesBefore,
|
|
311
325
|
rawTail: continuationMessages
|
|
312
326
|
});
|
|
313
|
-
|
|
314
|
-
|
|
327
|
+
const body = {
|
|
328
|
+
model: config.model,
|
|
329
|
+
system: prompt.system,
|
|
330
|
+
messages,
|
|
331
|
+
max_tokens: 4096,
|
|
332
|
+
stream: true
|
|
333
|
+
};
|
|
334
|
+
// Temperature is sent only when explicitly provided (Claude-5 rejects any temperature). When
|
|
335
|
+
// thinking is active it is also rejected — the completion/streaming paths validate this upstream,
|
|
336
|
+
// and the effort gate here is the safety net for the (unguarded) client-tool path.
|
|
337
|
+
if ((resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.anthropicEffort) === undefined) {
|
|
338
|
+
if (temperature !== undefined) {
|
|
339
|
+
body.temperature = temperature;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
315
342
|
if ((resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.anthropicEffort) !== undefined) {
|
|
316
343
|
body.thinking = {
|
|
317
344
|
type: 'enabled',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../../src/packlets/ai-assist/streamingAdapters/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Streaming adapter for the Anthropic Messages API. Handles server tool\n * use (e.g. `web_search`) as unified `tool-event` markers and client-defined\n * tool calls (type `tool_use`) with B4 thinking-block accumulation.\n *\n * The ordered accumulation buffer preserves all content blocks from the\n * assistant turn in their original stream positions. The C3 continuation\n * builder reads this buffer to reconstruct the assistant turn for the\n * follow-up request.\n *\n * @packageDocumentation\n */\n\nimport { type Logging, Result, succeed, type Validator, Validators } from '@fgv/ts-utils';\nimport { type JsonObject } from '@fgv/ts-json-base';\n\nimport { buildAnthropicMessages } from '../chatRequestBuilders';\nimport { AiPrompt, type AiToolConfig, type IAiStreamEvent, type IChatMessage } from '../model';\nimport { parseSseEventJson, readSseEvents } from '../sseParser';\nimport { toAnthropicTools } from '../toolFormats';\nimport { anthropicEffortToBudgetTokens, type IResolvedThinkingConfig } from '../thinkingOptionsResolver';\nimport {\n IStreamApiConfig,\n UNRECOGNIZED_EVENT_WARN_TAG,\n formatUnrecognizedEventPayloadPreview,\n openSseConnection,\n validateEventPayload\n} from './common';\n\n// ============================================================================\n// Accumulated block types (internal — used by C3 continuation builder)\n// ============================================================================\n\n/**\n * An accumulated `thinking` block from the assistant turn. The `thinking` text\n * and `signature` are both concatenated across their respective delta events.\n * The full block is passed to the C3 continuation builder for round-trip preservation.\n * @internal\n */\nexport interface IAccumulatedThinkingBlock {\n readonly type: 'thinking';\n thinking: string;\n signature: string;\n}\n\n/**\n * An accumulated `redacted_thinking` block from the assistant turn. The `data`\n * field is opaque and arrives complete in the `content_block_start` event — no\n * delta events follow. Passed through unmodified to the C3 continuation builder.\n * @internal\n */\nexport interface IAccumulatedRedactedThinkingBlock {\n readonly type: 'redacted_thinking';\n readonly data: string;\n}\n\n/**\n * An accumulated `text` block from the assistant turn.\n * @internal\n */\nexport interface IAccumulatedTextBlock {\n readonly type: 'text';\n text: string;\n}\n\n/**\n * An accumulated `tool_use` block from the assistant turn (client-defined tool call).\n * The `argsBuffer` is the concatenation of all `input_json_delta` chunks.\n * @internal\n */\nexport interface IAccumulatedToolUseBlock {\n readonly type: 'tool_use';\n readonly id: string;\n readonly name: string;\n argsBuffer: string;\n}\n\n/**\n * Discriminated union of all accumulated Anthropic content block types.\n * The ordered accumulation buffer is a `Map<number, IAccumulatedBlock>` keyed\n * by the SSE `index` field from `content_block_start` events.\n * @internal\n */\nexport type IAccumulatedBlock =\n | IAccumulatedThinkingBlock\n | IAccumulatedRedactedThinkingBlock\n | IAccumulatedTextBlock\n | IAccumulatedToolUseBlock;\n\n// ============================================================================\n// Event payload shapes\n// ============================================================================\n\n/**\n * Payload of a `content_block_start` SSE event with the `index` field.\n * The `index` field is optional for backward compatibility with providers that\n * omit it; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockStartPayload {\n readonly index?: number;\n readonly content_block: {\n readonly type?: string;\n readonly name?: string;\n readonly id?: string;\n readonly data?: string;\n };\n}\n\n/**\n * Payload of a `content_block_delta` SSE event. Various delta types are\n * discriminated on `delta.type`:\n * - `text_delta`: text content\n * - `input_json_delta`: tool argument accumulation\n * - `thinking_delta`: thinking text accumulation\n * - `signature_delta`: thinking signature accumulation (MUST be appended, not overwritten)\n *\n * The `index` field is optional; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockDeltaPayload {\n readonly index?: number;\n readonly delta: {\n readonly type?: string;\n readonly text?: string;\n readonly partial_json?: string;\n readonly thinking?: string;\n readonly signature?: string;\n };\n}\n\n/**\n * Payload of a `content_block_stop` SSE event.\n * The `index` field is optional; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockStopPayload {\n readonly index?: number;\n}\n\n/**\n * Payload of a `message_delta` SSE event carrying the final stop reason.\n * @internal\n */\ninterface IAnthropicMessageDeltaPayload {\n readonly delta: { readonly stop_reason?: string };\n}\n\n/**\n * Payload of an `error` SSE event.\n * @internal\n */\ninterface IAnthropicErrorPayload {\n readonly error?: { readonly message?: string };\n}\n\nconst anthropicContentBlockInner: Validator<{\n type?: string;\n name?: string;\n id?: string;\n data?: string;\n}> = Validators.object<{ type?: string; name?: string; id?: string; data?: string }>(\n {\n type: Validators.string.optional(),\n name: Validators.string.optional(),\n id: Validators.string.optional(),\n data: Validators.string.optional()\n },\n { options: { optionalFields: ['type', 'name', 'id', 'data'] } }\n);\n\nconst anthropicContentBlockStartPayload: Validator<IAnthropicContentBlockStartPayload> =\n Validators.object<IAnthropicContentBlockStartPayload>(\n {\n index: Validators.number.optional(),\n content_block: anthropicContentBlockInner\n },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicContentBlockDeltaInner: Validator<{\n type?: string;\n text?: string;\n partial_json?: string;\n thinking?: string;\n signature?: string;\n}> = Validators.object<{\n type?: string;\n text?: string;\n partial_json?: string;\n thinking?: string;\n signature?: string;\n}>(\n {\n type: Validators.string.optional(),\n text: Validators.string.optional(),\n partial_json: Validators.string.optional(),\n thinking: Validators.string.optional(),\n signature: Validators.string.optional()\n },\n { options: { optionalFields: ['type', 'text', 'partial_json', 'thinking', 'signature'] } }\n);\n\nconst anthropicContentBlockDeltaPayload: Validator<IAnthropicContentBlockDeltaPayload> =\n Validators.object<IAnthropicContentBlockDeltaPayload>(\n {\n index: Validators.number.optional(),\n delta: anthropicContentBlockDeltaInner\n },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicContentBlockStopPayload: Validator<IAnthropicContentBlockStopPayload> =\n Validators.object<IAnthropicContentBlockStopPayload>(\n { index: Validators.number.optional() },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicMessageDeltaInner: Validator<{ stop_reason?: string }> = Validators.object<{\n stop_reason?: string;\n}>({ stop_reason: Validators.string.optional() }, { options: { optionalFields: ['stop_reason'] } });\n\nconst anthropicMessageDeltaPayload: Validator<IAnthropicMessageDeltaPayload> =\n Validators.object<IAnthropicMessageDeltaPayload>({\n delta: anthropicMessageDeltaInner\n });\n\nconst anthropicErrorInner: Validator<{ message?: string }> = Validators.object<{ message?: string }>(\n { message: Validators.string.optional() },\n { options: { optionalFields: ['message'] } }\n);\n\nconst anthropicErrorPayload: Validator<IAnthropicErrorPayload> = Validators.object<IAnthropicErrorPayload>(\n { error: anthropicErrorInner.optional() },\n { options: { optionalFields: ['error'] } }\n);\n\n// ============================================================================\n// Stream translator\n// ============================================================================\n\n/**\n * Recognized Anthropic Messages API SSE event names. Anything not in this set surfaces a\n * one-time `logger.warn` per stream — same rationale as the OpenAI Responses adapter's\n * `RECOGNIZED_OPENAI_RESPONSES_EVENTS` allowlist in `openaiResponses.ts`. Add to this set\n * when a new event type is observed and confirmed safe to ignore.\n *\n * @internal\n */\nconst RECOGNIZED_ANTHROPIC_EVENTS: ReadonlySet<string> = new Set<string>([\n // ---- handled by the translator ----\n 'content_block_start',\n 'content_block_delta',\n 'content_block_stop',\n 'message_delta',\n 'message_stop',\n 'error',\n // ---- lifecycle / heartbeats: intentionally silent ----\n 'message_start',\n 'ping'\n]);\n\n/**\n * Translates an Anthropic Messages API SSE stream into unified events.\n *\n * Maintains an ordered accumulation buffer (keyed by SSE `index`) for all\n * content blocks: `thinking`, `redacted_thinking`, `text`, and `tool_use`.\n * The buffer is available on the returned generator via `.accumulationBuffer`.\n *\n * Unrecognized event names are reported once per stream via `logger?.warn` —\n * see {@link RECOGNIZED_ANTHROPIC_EVENTS}.\n *\n * @internal\n */\nasync function* translateAnthropicStream(\n response: Response,\n accumulationBuffer: Map<number, IAccumulatedBlock>,\n logger?: Logging.ILogger\n): AsyncGenerator<IAiStreamEvent> {\n let fullText = '';\n let truncated = false;\n let stopped = false;\n // Track unrecognized event names we have already warned about, so a hot stream of\n // an unknown event type produces exactly one log line per name per stream.\n const warnedEvents = new Set<string>();\n\n try {\n /* c8 ignore next - body is non-null at this point per openSseConnection */\n if (!response.body) return;\n for await (const message of readSseEvents(response.body)) {\n const eventName = message.event;\n\n if (eventName === 'content_block_start') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockStartPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n const { index: rawIndex, content_block: block } = payload;\n const index = rawIndex ?? 0;\n\n if (block.type === 'thinking') {\n accumulationBuffer.set(index, { type: 'thinking', thinking: '', signature: '' });\n } else if (block.type === 'redacted_thinking') {\n accumulationBuffer.set(index, {\n type: 'redacted_thinking',\n /* c8 ignore next 1 - defensive: Anthropic always provides data for redacted_thinking */\n data: block.data ?? ''\n });\n } else if (block.type === 'text') {\n accumulationBuffer.set(index, { type: 'text', text: '' });\n } else if (block.type === 'tool_use' && block.id && block.name) {\n accumulationBuffer.set(index, {\n type: 'tool_use',\n id: block.id,\n name: block.name,\n argsBuffer: ''\n });\n yield { type: 'client-tool-call-start', toolName: block.name, callId: block.id };\n } else if (block.type === 'server_tool_use' && block.name === 'web_search') {\n yield { type: 'tool-event', toolType: 'web_search', phase: 'started' };\n } else if (block.type === 'web_search_tool_result') {\n yield { type: 'tool-event', toolType: 'web_search', phase: 'completed' };\n }\n } else if (eventName === 'content_block_delta') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockDeltaPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n const { index: rawDeltaIndex, delta } = payload;\n const index = rawDeltaIndex ?? 0;\n const block = accumulationBuffer.get(index);\n\n if (delta.type === 'text_delta' && typeof delta.text === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'text') {\n block.text += delta.text;\n }\n if (delta.text.length > 0) {\n fullText += delta.text;\n yield { type: 'text-delta', delta: delta.text };\n }\n } else if (delta.type === 'input_json_delta' && typeof delta.partial_json === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'tool_use') {\n block.argsBuffer += delta.partial_json;\n }\n } else if (delta.type === 'thinking_delta' && typeof delta.thinking === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'thinking') {\n block.thinking += delta.thinking;\n }\n } else if (delta.type === 'signature_delta' && typeof delta.signature === 'string') {\n // CRITICAL (E5): signature must be APPENDED, not overwritten.\n // The signature is base64 arriving in multiple chunks.\n // Overwriting produces a truncated signature that Anthropic rejects with HTTP 400.\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'thinking') {\n block.signature += delta.signature;\n }\n }\n } else if (eventName === 'content_block_stop') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockStopPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n /* c8 ignore next 1 - defensive: payload.index ?? 0 null branch is unreachable */\n const block = accumulationBuffer.get(payload.index ?? 0);\n /* c8 ignore next 1 - defensive: block always exists when block_stop follows block_start */\n if (block?.type === 'tool_use') {\n let args: JsonObject;\n try {\n /* c8 ignore next 1 - defensive: argsBuffer || '{}' empty-string branch unreachable in tests */\n const parsed = JSON.parse(block.argsBuffer || '{}') as unknown;\n /* c8 ignore start - defensive: non-object/malformed parse defaults to empty object */\n args =\n parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as JsonObject)\n : {};\n } catch {\n args = {};\n }\n /* c8 ignore stop */\n yield { type: 'client-tool-call-done', toolName: block.name, callId: block.id, args };\n }\n } else if (eventName === 'message_delta') {\n const payload = validateEventPayload(parseSseEventJson(message.data), anthropicMessageDeltaPayload);\n /* c8 ignore next 1 - defensive: payload?.delta null branch unreachable after validation */\n if (payload?.delta.stop_reason === 'max_tokens') {\n truncated = true;\n }\n } else if (eventName === 'message_stop') {\n stopped = true;\n } else if (eventName === 'error') {\n const payload = validateEventPayload(parseSseEventJson(message.data), anthropicErrorPayload);\n yield {\n type: 'error',\n /* c8 ignore next 1 - defensive: payload?.error null branch unreachable after validation */\n message: payload?.error?.message ?? 'Anthropic stream returned an error event'\n };\n return;\n } else if (\n typeof eventName === 'string' &&\n !RECOGNIZED_ANTHROPIC_EVENTS.has(eventName) &&\n !warnedEvents.has(eventName)\n ) {\n // Empirical drift instrument: an unrecognized Anthropic event surfaces as a one-time\n // warning per stream. Update RECOGNIZED_ANTHROPIC_EVENTS once the new event is either\n // handled or confirmed safe to ignore.\n warnedEvents.add(eventName);\n logger?.warn(\n `${UNRECOGNIZED_EVENT_WARN_TAG} Anthropic streaming adapter: unrecognized SSE event ` +\n `'${eventName}'. ` +\n `payload preview: ${formatUnrecognizedEventPayloadPreview(message.data)}. ` +\n `This may indicate provider drift — if the new event carries data the adapter ` +\n `should surface, add a handler; otherwise add the name to ` +\n `RECOGNIZED_ANTHROPIC_EVENTS.`\n );\n }\n }\n } catch (err: unknown) /* c8 ignore start - defensive: stream errors are always Error instances */ {\n yield { type: 'error', message: err instanceof Error ? err.message : String(err) };\n return;\n } /* c8 ignore stop */\n\n if (stopped) {\n yield { type: 'done', truncated, fullText };\n } else {\n yield { type: 'error', message: 'Anthropic stream ended without a message_stop event' };\n }\n}\n\n// ============================================================================\n// Per-format request caller\n// ============================================================================\n\n/**\n * Issues a streaming Anthropic Messages request and returns the\n * unified-event iterable on success.\n *\n * @internal\n */\nexport async function callAnthropicStream(\n config: IStreamApiConfig,\n prompt: AiPrompt,\n messagesBefore: ReadonlyArray<IChatMessage> | undefined,\n temperature: number,\n tools: ReadonlyArray<AiToolConfig> | undefined,\n logger?: Logging.ILogger,\n signal?: AbortSignal,\n resolvedThinking?: IResolvedThinkingConfig,\n accumulationBuffer?: Map<number, IAccumulatedBlock>,\n continuationMessages?: ReadonlyArray<JsonObject>\n): Promise<Result<AsyncIterable<IAiStreamEvent>>> {\n const url = `${config.baseUrl}/messages`;\n const messages = buildAnthropicMessages(prompt, {\n head: messagesBefore,\n rawTail: continuationMessages\n });\n // When thinking is active, temperature is rejected by Anthropic (validated upstream).\n const body: Record<string, unknown> = {\n model: config.model,\n system: prompt.system,\n messages,\n max_tokens: 4096,\n ...(resolvedThinking?.anthropicEffort === undefined ? { temperature } : {}),\n stream: true\n };\n if (resolvedThinking?.anthropicEffort !== undefined) {\n body.thinking = {\n type: 'enabled',\n budget_tokens: anthropicEffortToBudgetTokens(resolvedThinking.anthropicEffort)\n };\n }\n if (resolvedThinking?.otherParams !== undefined) {\n Object.assign(body, resolvedThinking.otherParams);\n }\n if (tools && tools.length > 0) {\n body.tools = toAnthropicTools(tools);\n }\n const headers: Record<string, string> = {\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n 'anthropic-dangerous-direct-browser-access': 'true'\n };\n /* c8 ignore next 4 - optional logger diagnostic output */\n if (logger) {\n const toolTypes = tools && tools.length > 0 ? tools.map((t) => t.type).join(',') : 'none';\n logger.info(`Anthropic streaming: model=${config.model}, tools=${toolTypes}`);\n }\n const buffer = accumulationBuffer ?? new Map<number, IAccumulatedBlock>();\n const conn = await openSseConnection(url, headers, body, logger, signal);\n return conn.onSuccess((response) => succeed(translateAnthropicStream(response, buffer, logger)));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../../src/packlets/ai-assist/streamingAdapters/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Streaming adapter for the Anthropic Messages API. Handles server tool\n * use (e.g. `web_search`) as unified `tool-event` markers and client-defined\n * tool calls (type `tool_use`) with B4 thinking-block accumulation.\n *\n * The ordered accumulation buffer preserves all content blocks from the\n * assistant turn in their original stream positions. The C3 continuation\n * builder reads this buffer to reconstruct the assistant turn for the\n * follow-up request.\n *\n * @packageDocumentation\n */\n\nimport { type Logging, Result, succeed, type Validator, Validators } from '@fgv/ts-utils';\nimport { type JsonObject } from '@fgv/ts-json-base';\n\nimport { buildAnthropicMessages } from '../chatRequestBuilders';\nimport { AiPrompt, type AiToolConfig, type IAiStreamEvent, type IChatMessage } from '../model';\nimport { parseSseEventJson, readSseEvents } from '../sseParser';\nimport { toAnthropicTools } from '../toolFormats';\nimport { anthropicEffortToBudgetTokens, type IResolvedThinkingConfig } from '../thinkingOptionsResolver';\nimport {\n IStreamApiConfig,\n MALFORMED_TOOL_USE_WARN_TAG,\n UNRECOGNIZED_EVENT_WARN_TAG,\n formatUnrecognizedEventPayloadPreview,\n openSseConnection,\n validateEventPayload\n} from './common';\n\n// ============================================================================\n// Accumulated block types (internal — used by C3 continuation builder)\n// ============================================================================\n\n/**\n * An accumulated `thinking` block from the assistant turn. The `thinking` text\n * and `signature` are both concatenated across their respective delta events.\n * The full block is passed to the C3 continuation builder for round-trip preservation.\n * @internal\n */\nexport interface IAccumulatedThinkingBlock {\n readonly type: 'thinking';\n thinking: string;\n signature: string;\n}\n\n/**\n * An accumulated `redacted_thinking` block from the assistant turn. The `data`\n * field is opaque and arrives complete in the `content_block_start` event — no\n * delta events follow. Passed through unmodified to the C3 continuation builder.\n * @internal\n */\nexport interface IAccumulatedRedactedThinkingBlock {\n readonly type: 'redacted_thinking';\n readonly data: string;\n}\n\n/**\n * An accumulated `text` block from the assistant turn.\n * @internal\n */\nexport interface IAccumulatedTextBlock {\n readonly type: 'text';\n text: string;\n}\n\n/**\n * An accumulated `tool_use` block from the assistant turn (client-defined tool call).\n * The `argsBuffer` is the concatenation of all `input_json_delta` chunks.\n * @internal\n */\nexport interface IAccumulatedToolUseBlock {\n readonly type: 'tool_use';\n readonly id: string;\n readonly name: string;\n argsBuffer: string;\n}\n\n/**\n * Discriminated union of all accumulated Anthropic content block types.\n * The ordered accumulation buffer is a `Map<number, IAccumulatedBlock>` keyed\n * by the SSE `index` field from `content_block_start` events.\n * @internal\n */\nexport type IAccumulatedBlock =\n | IAccumulatedThinkingBlock\n | IAccumulatedRedactedThinkingBlock\n | IAccumulatedTextBlock\n | IAccumulatedToolUseBlock;\n\n// ============================================================================\n// Event payload shapes\n// ============================================================================\n\n/**\n * Payload of a `content_block_start` SSE event with the `index` field.\n * The `index` field is optional for backward compatibility with providers that\n * omit it; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockStartPayload {\n readonly index?: number;\n readonly content_block: {\n readonly type?: string;\n readonly name?: string;\n readonly id?: string;\n readonly data?: string;\n };\n}\n\n/**\n * Payload of a `content_block_delta` SSE event. Various delta types are\n * discriminated on `delta.type`:\n * - `text_delta`: text content\n * - `input_json_delta`: tool argument accumulation\n * - `thinking_delta`: thinking text accumulation\n * - `signature_delta`: thinking signature accumulation (MUST be appended, not overwritten)\n *\n * The `index` field is optional; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockDeltaPayload {\n readonly index?: number;\n readonly delta: {\n readonly type?: string;\n readonly text?: string;\n readonly partial_json?: string;\n readonly thinking?: string;\n readonly signature?: string;\n };\n}\n\n/**\n * Payload of a `content_block_stop` SSE event.\n * The `index` field is optional; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockStopPayload {\n readonly index?: number;\n}\n\n/**\n * Payload of a `message_delta` SSE event carrying the final stop reason.\n * @internal\n */\ninterface IAnthropicMessageDeltaPayload {\n readonly delta: { readonly stop_reason?: string };\n}\n\n/**\n * Payload of an `error` SSE event.\n * @internal\n */\ninterface IAnthropicErrorPayload {\n readonly error?: { readonly message?: string };\n}\n\nconst anthropicContentBlockInner: Validator<{\n type?: string;\n name?: string;\n id?: string;\n data?: string;\n}> = Validators.object<{ type?: string; name?: string; id?: string; data?: string }>(\n {\n type: Validators.string.optional(),\n name: Validators.string.optional(),\n id: Validators.string.optional(),\n data: Validators.string.optional()\n },\n { options: { optionalFields: ['type', 'name', 'id', 'data'] } }\n);\n\nconst anthropicContentBlockStartPayload: Validator<IAnthropicContentBlockStartPayload> =\n Validators.object<IAnthropicContentBlockStartPayload>(\n {\n index: Validators.number.optional(),\n content_block: anthropicContentBlockInner\n },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicContentBlockDeltaInner: Validator<{\n type?: string;\n text?: string;\n partial_json?: string;\n thinking?: string;\n signature?: string;\n}> = Validators.object<{\n type?: string;\n text?: string;\n partial_json?: string;\n thinking?: string;\n signature?: string;\n}>(\n {\n type: Validators.string.optional(),\n text: Validators.string.optional(),\n partial_json: Validators.string.optional(),\n thinking: Validators.string.optional(),\n signature: Validators.string.optional()\n },\n { options: { optionalFields: ['type', 'text', 'partial_json', 'thinking', 'signature'] } }\n);\n\nconst anthropicContentBlockDeltaPayload: Validator<IAnthropicContentBlockDeltaPayload> =\n Validators.object<IAnthropicContentBlockDeltaPayload>(\n {\n index: Validators.number.optional(),\n delta: anthropicContentBlockDeltaInner\n },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicContentBlockStopPayload: Validator<IAnthropicContentBlockStopPayload> =\n Validators.object<IAnthropicContentBlockStopPayload>(\n { index: Validators.number.optional() },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicMessageDeltaInner: Validator<{ stop_reason?: string }> = Validators.object<{\n stop_reason?: string;\n}>({ stop_reason: Validators.string.optional() }, { options: { optionalFields: ['stop_reason'] } });\n\nconst anthropicMessageDeltaPayload: Validator<IAnthropicMessageDeltaPayload> =\n Validators.object<IAnthropicMessageDeltaPayload>({\n delta: anthropicMessageDeltaInner\n });\n\nconst anthropicErrorInner: Validator<{ message?: string }> = Validators.object<{ message?: string }>(\n { message: Validators.string.optional() },\n { options: { optionalFields: ['message'] } }\n);\n\nconst anthropicErrorPayload: Validator<IAnthropicErrorPayload> = Validators.object<IAnthropicErrorPayload>(\n { error: anthropicErrorInner.optional() },\n { options: { optionalFields: ['error'] } }\n);\n\n// ============================================================================\n// Stream translator\n// ============================================================================\n\n/**\n * Recognized Anthropic Messages API SSE event names. Anything not in this set surfaces a\n * one-time `logger.warn` per stream — same rationale as the OpenAI Responses adapter's\n * `RECOGNIZED_OPENAI_RESPONSES_EVENTS` allowlist in `openaiResponses.ts`. Add to this set\n * when a new event type is observed and confirmed safe to ignore.\n *\n * @internal\n */\nconst RECOGNIZED_ANTHROPIC_EVENTS: ReadonlySet<string> = new Set<string>([\n // ---- handled by the translator ----\n 'content_block_start',\n 'content_block_delta',\n 'content_block_stop',\n 'message_delta',\n 'message_stop',\n 'error',\n // ---- lifecycle / heartbeats: intentionally silent ----\n 'message_start',\n 'ping'\n]);\n\n/**\n * Translates an Anthropic Messages API SSE stream into unified events.\n *\n * Maintains an ordered accumulation buffer (keyed by SSE `index`) for all\n * content blocks: `thinking`, `redacted_thinking`, `text`, and `tool_use`.\n * The buffer is available on the returned generator via `.accumulationBuffer`.\n *\n * Unrecognized event names are reported once per stream via `logger?.warn` —\n * see {@link RECOGNIZED_ANTHROPIC_EVENTS}.\n *\n * @internal\n */\nasync function* translateAnthropicStream(\n response: Response,\n accumulationBuffer: Map<number, IAccumulatedBlock>,\n logger?: Logging.ILogger\n): AsyncGenerator<IAiStreamEvent> {\n let fullText = '';\n let truncated = false;\n let stopped = false;\n // Track unrecognized event names we have already warned about, so a hot stream of\n // an unknown event type produces exactly one log line per name per stream.\n const warnedEvents = new Set<string>();\n\n try {\n /* c8 ignore next - body is non-null at this point per openSseConnection */\n if (!response.body) return;\n for await (const message of readSseEvents(response.body)) {\n const eventName = message.event;\n\n if (eventName === 'content_block_start') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockStartPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n const { index: rawIndex, content_block: block } = payload;\n const index = rawIndex ?? 0;\n\n if (block.type === 'thinking') {\n accumulationBuffer.set(index, { type: 'thinking', thinking: '', signature: '' });\n } else if (block.type === 'redacted_thinking') {\n accumulationBuffer.set(index, {\n type: 'redacted_thinking',\n /* c8 ignore next 1 - defensive: Anthropic always provides data for redacted_thinking */\n data: block.data ?? ''\n });\n } else if (block.type === 'text') {\n accumulationBuffer.set(index, { type: 'text', text: '' });\n } else if (block.type === 'tool_use') {\n // A tool_use block_start MUST carry a non-empty id and name: the id is the\n // sole correlation key for the follow-up tool_result, and dropping the block\n // silently (then ignoring its input_json_delta chunks at the delta handler\n // below) is exactly how an orphaned block leaves the harness without a clean\n // id and corrupts the continuation. Surface it loudly instead of dropping it.\n if (block.id && block.name) {\n accumulationBuffer.set(index, {\n type: 'tool_use',\n id: block.id,\n name: block.name,\n argsBuffer: ''\n });\n yield { type: 'client-tool-call-start', toolName: block.name, callId: block.id };\n } else {\n logger?.warn(\n `${MALFORMED_TOOL_USE_WARN_TAG} Anthropic streaming adapter: tool_use content_block_start ` +\n `at index ${index} is missing a usable id and/or name ` +\n `(id=${JSON.stringify(block.id)}, name=${JSON.stringify(block.name)}). ` +\n `No client tool call will be issued for this block; its argument deltas are dropped. ` +\n `This usually indicates provider drift or a truncated stream.`\n );\n }\n } else if (block.type === 'server_tool_use' && block.name === 'web_search') {\n yield { type: 'tool-event', toolType: 'web_search', phase: 'started' };\n } else if (block.type === 'web_search_tool_result') {\n yield { type: 'tool-event', toolType: 'web_search', phase: 'completed' };\n }\n } else if (eventName === 'content_block_delta') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockDeltaPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n const { index: rawDeltaIndex, delta } = payload;\n const index = rawDeltaIndex ?? 0;\n const block = accumulationBuffer.get(index);\n\n if (delta.type === 'text_delta' && typeof delta.text === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'text') {\n block.text += delta.text;\n }\n if (delta.text.length > 0) {\n fullText += delta.text;\n yield { type: 'text-delta', delta: delta.text };\n }\n } else if (delta.type === 'input_json_delta' && typeof delta.partial_json === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'tool_use') {\n block.argsBuffer += delta.partial_json;\n }\n } else if (delta.type === 'thinking_delta' && typeof delta.thinking === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'thinking') {\n block.thinking += delta.thinking;\n }\n } else if (delta.type === 'signature_delta' && typeof delta.signature === 'string') {\n // CRITICAL (E5): signature must be APPENDED, not overwritten.\n // The signature is base64 arriving in multiple chunks.\n // Overwriting produces a truncated signature that Anthropic rejects with HTTP 400.\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'thinking') {\n block.signature += delta.signature;\n }\n }\n } else if (eventName === 'content_block_stop') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockStopPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n /* c8 ignore next 1 - defensive: payload.index ?? 0 null branch is unreachable */\n const block = accumulationBuffer.get(payload.index ?? 0);\n /* c8 ignore next 1 - defensive: block always exists when block_stop follows block_start */\n if (block?.type === 'tool_use') {\n let args: JsonObject;\n try {\n /* c8 ignore next 1 - defensive: argsBuffer || '{}' empty-string branch unreachable in tests */\n const parsed = JSON.parse(block.argsBuffer || '{}') as unknown;\n /* c8 ignore start - defensive: non-object/malformed parse defaults to empty object */\n args =\n parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as JsonObject)\n : {};\n } catch {\n args = {};\n }\n /* c8 ignore stop */\n yield { type: 'client-tool-call-done', toolName: block.name, callId: block.id, args };\n }\n } else if (eventName === 'message_delta') {\n const payload = validateEventPayload(parseSseEventJson(message.data), anthropicMessageDeltaPayload);\n /* c8 ignore next 1 - defensive: payload?.delta null branch unreachable after validation */\n if (payload?.delta.stop_reason === 'max_tokens') {\n truncated = true;\n }\n } else if (eventName === 'message_stop') {\n stopped = true;\n } else if (eventName === 'error') {\n const payload = validateEventPayload(parseSseEventJson(message.data), anthropicErrorPayload);\n yield {\n type: 'error',\n /* c8 ignore next 1 - defensive: payload?.error null branch unreachable after validation */\n message: payload?.error?.message ?? 'Anthropic stream returned an error event'\n };\n return;\n } else if (\n typeof eventName === 'string' &&\n !RECOGNIZED_ANTHROPIC_EVENTS.has(eventName) &&\n !warnedEvents.has(eventName)\n ) {\n // Empirical drift instrument: an unrecognized Anthropic event surfaces as a one-time\n // warning per stream. Update RECOGNIZED_ANTHROPIC_EVENTS once the new event is either\n // handled or confirmed safe to ignore.\n warnedEvents.add(eventName);\n logger?.warn(\n `${UNRECOGNIZED_EVENT_WARN_TAG} Anthropic streaming adapter: unrecognized SSE event ` +\n `'${eventName}'. ` +\n `payload preview: ${formatUnrecognizedEventPayloadPreview(message.data)}. ` +\n `This may indicate provider drift — if the new event carries data the adapter ` +\n `should surface, add a handler; otherwise add the name to ` +\n `RECOGNIZED_ANTHROPIC_EVENTS.`\n );\n }\n }\n } catch (err: unknown) /* c8 ignore start - defensive: stream errors are always Error instances */ {\n yield { type: 'error', message: err instanceof Error ? err.message : String(err) };\n return;\n } /* c8 ignore stop */\n\n if (stopped) {\n yield { type: 'done', truncated, fullText };\n } else {\n yield { type: 'error', message: 'Anthropic stream ended without a message_stop event' };\n }\n}\n\n// ============================================================================\n// Per-format request caller\n// ============================================================================\n\n/**\n * Issues a streaming Anthropic Messages request and returns the\n * unified-event iterable on success.\n *\n * @internal\n */\nexport async function callAnthropicStream(\n config: IStreamApiConfig,\n prompt: AiPrompt,\n messagesBefore: ReadonlyArray<IChatMessage> | undefined,\n temperature: number | undefined,\n tools: ReadonlyArray<AiToolConfig> | undefined,\n logger?: Logging.ILogger,\n signal?: AbortSignal,\n resolvedThinking?: IResolvedThinkingConfig,\n accumulationBuffer?: Map<number, IAccumulatedBlock>,\n continuationMessages?: ReadonlyArray<JsonObject>\n): Promise<Result<AsyncIterable<IAiStreamEvent>>> {\n const url = `${config.baseUrl}/messages`;\n const messages = buildAnthropicMessages(prompt, {\n head: messagesBefore,\n rawTail: continuationMessages\n });\n const body: Record<string, unknown> = {\n model: config.model,\n system: prompt.system,\n messages,\n max_tokens: 4096,\n stream: true\n };\n // Temperature is sent only when explicitly provided (Claude-5 rejects any temperature). When\n // thinking is active it is also rejected — the completion/streaming paths validate this upstream,\n // and the effort gate here is the safety net for the (unguarded) client-tool path.\n if (resolvedThinking?.anthropicEffort === undefined) {\n if (temperature !== undefined) {\n body.temperature = temperature;\n }\n }\n if (resolvedThinking?.anthropicEffort !== undefined) {\n body.thinking = {\n type: 'enabled',\n budget_tokens: anthropicEffortToBudgetTokens(resolvedThinking.anthropicEffort)\n };\n }\n if (resolvedThinking?.otherParams !== undefined) {\n Object.assign(body, resolvedThinking.otherParams);\n }\n if (tools && tools.length > 0) {\n body.tools = toAnthropicTools(tools);\n }\n const headers: Record<string, string> = {\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n 'anthropic-dangerous-direct-browser-access': 'true'\n };\n /* c8 ignore next 4 - optional logger diagnostic output */\n if (logger) {\n const toolTypes = tools && tools.length > 0 ? tools.map((t) => t.type).join(',') : 'none';\n logger.info(`Anthropic streaming: model=${config.model}, tools=${toolTypes}`);\n }\n const buffer = accumulationBuffer ?? new Map<number, IAccumulatedBlock>();\n const conn = await openSseConnection(url, headers, body, logger, signal);\n return conn.onSuccess((response) => succeed(translateAnthropicStream(response, buffer, logger)));\n}\n"]}
|