@providerprotocol/ai 0.0.21 → 0.0.23
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/README.md +188 -6
- package/dist/anthropic/index.d.ts +1 -1
- package/dist/anthropic/index.js +115 -39
- package/dist/anthropic/index.js.map +1 -1
- package/dist/{chunk-Y3GBJNA2.js → chunk-55X3W2MN.js} +4 -3
- package/dist/chunk-55X3W2MN.js.map +1 -0
- package/dist/chunk-73IIE3QT.js +120 -0
- package/dist/chunk-73IIE3QT.js.map +1 -0
- package/dist/{chunk-M4BMM5IB.js → chunk-MF5ETY5O.js} +13 -4
- package/dist/chunk-MF5ETY5O.js.map +1 -0
- package/dist/{chunk-SKY2JLA7.js → chunk-MKDLXV4O.js} +1 -1
- package/dist/chunk-MKDLXV4O.js.map +1 -0
- package/dist/{chunk-Z7RBRCRN.js → chunk-NWS5IKNR.js} +37 -11
- package/dist/chunk-NWS5IKNR.js.map +1 -0
- package/dist/{chunk-EDENPF3E.js → chunk-QNJO7DSD.js} +152 -53
- package/dist/chunk-QNJO7DSD.js.map +1 -0
- package/dist/{chunk-Z4ILICF5.js → chunk-SBCATNHA.js} +43 -14
- package/dist/chunk-SBCATNHA.js.map +1 -0
- package/dist/chunk-Z6DKC37J.js +50 -0
- package/dist/chunk-Z6DKC37J.js.map +1 -0
- package/dist/google/index.d.ts +22 -7
- package/dist/google/index.js +286 -85
- package/dist/google/index.js.map +1 -1
- package/dist/http/index.d.ts +3 -3
- package/dist/http/index.js +4 -4
- package/dist/index.d.ts +10 -6
- package/dist/index.js +331 -204
- package/dist/index.js.map +1 -1
- package/dist/ollama/index.d.ts +5 -2
- package/dist/ollama/index.js +87 -28
- package/dist/ollama/index.js.map +1 -1
- package/dist/openai/index.d.ts +1 -1
- package/dist/openai/index.js +226 -81
- package/dist/openai/index.js.map +1 -1
- package/dist/openrouter/index.d.ts +1 -1
- package/dist/openrouter/index.js +199 -64
- package/dist/openrouter/index.js.map +1 -1
- package/dist/{provider-DGQHYE6I.d.ts → provider-DR1yins0.d.ts} +159 -53
- package/dist/proxy/index.d.ts +2 -2
- package/dist/proxy/index.js +178 -17
- package/dist/proxy/index.js.map +1 -1
- package/dist/{retry-Pcs3hnbu.d.ts → retry-DJiqAslw.d.ts} +11 -2
- package/dist/{stream-Di9acos2.d.ts → stream-BuTrqt_j.d.ts} +103 -41
- package/dist/xai/index.d.ts +1 -1
- package/dist/xai/index.js +189 -75
- package/dist/xai/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-EDENPF3E.js.map +0 -1
- package/dist/chunk-M4BMM5IB.js.map +0 -1
- package/dist/chunk-SKY2JLA7.js.map +0 -1
- package/dist/chunk-Y3GBJNA2.js.map +0 -1
- package/dist/chunk-Z4ILICF5.js.map +0 -1
- package/dist/chunk-Z7RBRCRN.js.map +0 -1
package/README.md
CHANGED
|
@@ -44,6 +44,31 @@ for await (const event of stream) {
|
|
|
44
44
|
const turn = await stream.turn;
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
**Stream Control:**
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
const stream = claude.stream('Write a long story');
|
|
51
|
+
|
|
52
|
+
// Abort the stream at any time
|
|
53
|
+
setTimeout(() => stream.abort(), 5000);
|
|
54
|
+
|
|
55
|
+
for await (const event of stream) {
|
|
56
|
+
// Process events until abort
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Stream Events:**
|
|
61
|
+
|
|
62
|
+
| Event | Description |
|
|
63
|
+
|-------|-------------|
|
|
64
|
+
| `text_delta` | Incremental text output |
|
|
65
|
+
| `reasoning_delta` | Incremental reasoning/thinking output |
|
|
66
|
+
| `tool_call_delta` | Tool call arguments being streamed |
|
|
67
|
+
| `tool_execution_start` | Tool execution has started |
|
|
68
|
+
| `tool_execution_end` | Tool execution has completed |
|
|
69
|
+
| `message_start` / `message_stop` | Message boundaries |
|
|
70
|
+
| `content_block_start` / `content_block_stop` | Content block boundaries |
|
|
71
|
+
|
|
47
72
|
### Multi-turn Conversations
|
|
48
73
|
|
|
49
74
|
```typescript
|
|
@@ -104,6 +129,60 @@ const img = await Image.fromPath('./photo.png');
|
|
|
104
129
|
const turn = await claude.generate([img, 'What is in this image?']);
|
|
105
130
|
```
|
|
106
131
|
|
|
132
|
+
## Anthropic Beta Features
|
|
133
|
+
|
|
134
|
+
Anthropic provides beta features through the `betas` export. Enable them at the model level:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { anthropic, betas } from '@providerprotocol/ai/anthropic';
|
|
138
|
+
import { llm } from '@providerprotocol/ai';
|
|
139
|
+
|
|
140
|
+
// Native structured outputs with guaranteed JSON schema conformance
|
|
141
|
+
const model = llm({
|
|
142
|
+
model: anthropic('claude-sonnet-4-20250514', {
|
|
143
|
+
betas: [betas.structuredOutputs],
|
|
144
|
+
}),
|
|
145
|
+
structure: {
|
|
146
|
+
type: 'object',
|
|
147
|
+
properties: { answer: { type: 'string' } },
|
|
148
|
+
required: ['answer'],
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Extended thinking with interleaved tool calls
|
|
153
|
+
const thinker = llm({
|
|
154
|
+
model: anthropic('claude-sonnet-4-20250514', {
|
|
155
|
+
betas: [betas.interleavedThinking],
|
|
156
|
+
}),
|
|
157
|
+
params: {
|
|
158
|
+
thinking: { type: 'enabled', budget_tokens: 10000 },
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Available Beta Features:**
|
|
164
|
+
|
|
165
|
+
| Beta | Description |
|
|
166
|
+
|------|-------------|
|
|
167
|
+
| `structuredOutputs` | Guaranteed JSON schema conformance for responses |
|
|
168
|
+
| `interleavedThinking` | Claude can think between tool calls |
|
|
169
|
+
| `devFullThinking` | Developer mode for full thinking visibility |
|
|
170
|
+
| `effort` | Control response thoroughness vs efficiency (Opus 4.5) |
|
|
171
|
+
| `computerUse` | Mouse, keyboard, screenshot control (Claude 4) |
|
|
172
|
+
| `codeExecution` | Python/Bash sandbox execution |
|
|
173
|
+
| `tokenEfficientTools` | Up to 70% token reduction for tool calls |
|
|
174
|
+
| `fineGrainedToolStreaming` | Stream tool args without buffering |
|
|
175
|
+
| `output128k` | 128K token output length |
|
|
176
|
+
| `context1m` | 1 million token context window (Sonnet 4) |
|
|
177
|
+
| `promptCaching` | Reduced latency and costs via caching |
|
|
178
|
+
| `extendedCacheTtl` | 1-hour cache TTL (vs 5-minute default) |
|
|
179
|
+
| `advancedToolUse` | Tool Search, Programmatic Tool Calling |
|
|
180
|
+
| `mcpClient` | Connect to remote MCP servers |
|
|
181
|
+
| `filesApi` | Upload and manage files |
|
|
182
|
+
| `pdfs` | PDF document support |
|
|
183
|
+
| `messageBatches` | Async batch processing at 50% cost |
|
|
184
|
+
| `skills` | Agent Skills (PowerPoint, Excel, Word, PDF) |
|
|
185
|
+
|
|
107
186
|
## Embeddings
|
|
108
187
|
|
|
109
188
|
```typescript
|
|
@@ -198,6 +277,51 @@ const instance = llm({
|
|
|
198
277
|
});
|
|
199
278
|
```
|
|
200
279
|
|
|
280
|
+
### System Prompts
|
|
281
|
+
|
|
282
|
+
System prompts can be a simple string or a provider-specific array for advanced features:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// Simple string (all providers)
|
|
286
|
+
const simple = llm({
|
|
287
|
+
model: anthropic('claude-sonnet-4-20250514'),
|
|
288
|
+
system: 'You are a helpful assistant.',
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// Anthropic cache_control format
|
|
292
|
+
import { anthropic, betas } from '@providerprotocol/ai/anthropic';
|
|
293
|
+
|
|
294
|
+
const cached = llm({
|
|
295
|
+
model: anthropic('claude-sonnet-4-20250514', {
|
|
296
|
+
betas: [betas.promptCaching],
|
|
297
|
+
}),
|
|
298
|
+
system: [
|
|
299
|
+
{ type: 'text', text: 'Large context document...', cache_control: { type: 'ephemeral' } },
|
|
300
|
+
{ type: 'text', text: 'Instructions...' },
|
|
301
|
+
],
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Provider Config Options
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
interface ProviderConfig {
|
|
309
|
+
apiKey?: string | (() => Promise<string>) | KeyStrategy; // API key, async getter, or strategy
|
|
310
|
+
baseUrl?: string; // Custom API endpoint
|
|
311
|
+
timeout?: number; // Per-attempt timeout (ms)
|
|
312
|
+
retryStrategy?: RetryStrategy; // Retry behavior
|
|
313
|
+
headers?: Record<string, string>; // Custom headers (merged with provider defaults)
|
|
314
|
+
fetch?: typeof fetch; // Custom fetch implementation
|
|
315
|
+
apiVersion?: string; // API version override
|
|
316
|
+
retryAfterMaxSeconds?: number; // Cap for Retry-After header (default: 3600)
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Notes:**
|
|
321
|
+
- `timeout` applies per attempt; total time can exceed this with retries
|
|
322
|
+
- `headers` are merged with model-level headers (explicit config takes precedence)
|
|
323
|
+
- `retryAfterMaxSeconds` prevents honoring excessively long Retry-After values
|
|
324
|
+
|
|
201
325
|
### Key Strategies
|
|
202
326
|
|
|
203
327
|
```typescript
|
|
@@ -227,8 +351,13 @@ import {
|
|
|
227
351
|
RetryAfterStrategy,
|
|
228
352
|
} from '@providerprotocol/ai/http';
|
|
229
353
|
|
|
230
|
-
// Exponential: 1s, 2s, 4s...
|
|
231
|
-
new ExponentialBackoff({
|
|
354
|
+
// Exponential: 1s, 2s, 4s...
|
|
355
|
+
new ExponentialBackoff({
|
|
356
|
+
maxAttempts: 5,
|
|
357
|
+
baseDelay: 1000,
|
|
358
|
+
maxDelay: 30000,
|
|
359
|
+
jitter: true, // Randomize delays to prevent thundering herd (default: true)
|
|
360
|
+
})
|
|
232
361
|
|
|
233
362
|
// Linear: 1s, 2s, 3s...
|
|
234
363
|
new LinearBackoff({ maxAttempts: 3, delay: 1000 })
|
|
@@ -243,6 +372,8 @@ new RetryAfterStrategy({ maxAttempts: 3, fallbackDelay: 5000 })
|
|
|
243
372
|
new NoRetry()
|
|
244
373
|
```
|
|
245
374
|
|
|
375
|
+
**Retryable Errors:** `RATE_LIMITED`, `NETWORK_ERROR`, `TIMEOUT`, `PROVIDER_ERROR`
|
|
376
|
+
|
|
246
377
|
## Tool Execution Control
|
|
247
378
|
|
|
248
379
|
```typescript
|
|
@@ -294,6 +425,12 @@ try {
|
|
|
294
425
|
await claude.generate('Hello');
|
|
295
426
|
} catch (error) {
|
|
296
427
|
if (error instanceof UPPError) {
|
|
428
|
+
console.log(error.code); // 'RATE_LIMITED'
|
|
429
|
+
console.log(error.provider); // 'anthropic'
|
|
430
|
+
console.log(error.modality); // 'llm'
|
|
431
|
+
console.log(error.statusCode); // 429
|
|
432
|
+
console.log(error.cause); // Original error (if any)
|
|
433
|
+
|
|
297
434
|
switch (error.code) {
|
|
298
435
|
case 'RATE_LIMITED':
|
|
299
436
|
// Wait and retry
|
|
@@ -385,7 +522,7 @@ Server adapters for Express, Fastify, and Nuxt/H3:
|
|
|
385
522
|
|
|
386
523
|
```typescript
|
|
387
524
|
// Express
|
|
388
|
-
import { express as expressAdapter } from '@providerprotocol/ai/proxy
|
|
525
|
+
import { express as expressAdapter, parseBody } from '@providerprotocol/ai/proxy';
|
|
389
526
|
app.post('/ai', authMiddleware, async (req, res) => {
|
|
390
527
|
const { messages, system, params } = parseBody(req.body);
|
|
391
528
|
if (params?.stream) {
|
|
@@ -396,7 +533,7 @@ app.post('/ai', authMiddleware, async (req, res) => {
|
|
|
396
533
|
});
|
|
397
534
|
|
|
398
535
|
// Fastify
|
|
399
|
-
import { fastify as fastifyAdapter } from '@providerprotocol/ai/proxy
|
|
536
|
+
import { fastify as fastifyAdapter, parseBody } from '@providerprotocol/ai/proxy';
|
|
400
537
|
app.post('/ai', async (request, reply) => {
|
|
401
538
|
const { messages, system, params } = parseBody(request.body);
|
|
402
539
|
if (params?.stream) {
|
|
@@ -406,7 +543,7 @@ app.post('/ai', async (request, reply) => {
|
|
|
406
543
|
});
|
|
407
544
|
|
|
408
545
|
// Nuxt/H3 (server/api/ai.post.ts)
|
|
409
|
-
import { h3 as h3Adapter } from '@providerprotocol/ai/proxy
|
|
546
|
+
import { h3 as h3Adapter, parseBody } from '@providerprotocol/ai/proxy';
|
|
410
547
|
export default defineEventHandler(async (event) => {
|
|
411
548
|
const { messages, system, params } = parseBody(await readBody(event));
|
|
412
549
|
if (params?.stream) {
|
|
@@ -441,23 +578,68 @@ xai('grok-3-fast', { api: 'responses' })
|
|
|
441
578
|
xai('grok-3-fast', { api: 'messages' })
|
|
442
579
|
```
|
|
443
580
|
|
|
581
|
+
## Alternative Import Style
|
|
582
|
+
|
|
583
|
+
Use the `ai` namespace for a grouped import style:
|
|
584
|
+
|
|
585
|
+
```typescript
|
|
586
|
+
import { ai } from '@providerprotocol/ai';
|
|
587
|
+
import { openai } from '@providerprotocol/ai/openai';
|
|
588
|
+
|
|
589
|
+
const model = ai.llm({ model: openai('gpt-4o') });
|
|
590
|
+
const embedder = ai.embedding({ model: openai('text-embedding-3-small') });
|
|
591
|
+
const dalle = ai.image({ model: openai('dall-e-3') });
|
|
592
|
+
```
|
|
593
|
+
|
|
444
594
|
## TypeScript
|
|
445
595
|
|
|
446
596
|
Full type safety with no `any` types. All provider parameters are typed:
|
|
447
597
|
|
|
448
598
|
```typescript
|
|
449
599
|
import type {
|
|
600
|
+
// Core types
|
|
450
601
|
Turn,
|
|
451
602
|
Message,
|
|
452
603
|
Tool,
|
|
453
|
-
UPPError,
|
|
454
604
|
TokenUsage,
|
|
605
|
+
|
|
606
|
+
// Streaming
|
|
455
607
|
StreamEvent,
|
|
608
|
+
StreamResult,
|
|
609
|
+
|
|
610
|
+
// Modality results
|
|
456
611
|
EmbeddingResult,
|
|
457
612
|
ImageResult,
|
|
613
|
+
|
|
614
|
+
// Errors
|
|
615
|
+
UPPError,
|
|
616
|
+
ErrorCode,
|
|
617
|
+
|
|
618
|
+
// Configuration
|
|
619
|
+
ProviderConfig,
|
|
620
|
+
KeyStrategy,
|
|
621
|
+
RetryStrategy,
|
|
622
|
+
LLMCapabilities,
|
|
458
623
|
} from '@providerprotocol/ai';
|
|
459
624
|
```
|
|
460
625
|
|
|
626
|
+
### Custom Providers
|
|
627
|
+
|
|
628
|
+
Build custom providers with `createProvider`:
|
|
629
|
+
|
|
630
|
+
```typescript
|
|
631
|
+
import { createProvider } from '@providerprotocol/ai';
|
|
632
|
+
|
|
633
|
+
const myProvider = createProvider({
|
|
634
|
+
name: 'my-provider',
|
|
635
|
+
version: '1.0.0',
|
|
636
|
+
handlers: {
|
|
637
|
+
llm: myLLMHandler,
|
|
638
|
+
embedding: myEmbeddingHandler,
|
|
639
|
+
},
|
|
640
|
+
});
|
|
641
|
+
```
|
|
642
|
+
|
|
461
643
|
## License
|
|
462
644
|
|
|
463
645
|
MIT
|
package/dist/anthropic/index.js
CHANGED
|
@@ -1,22 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseJsonResponse
|
|
3
|
+
} from "../chunk-Z6DKC37J.js";
|
|
4
|
+
import {
|
|
5
|
+
StreamEventType
|
|
6
|
+
} from "../chunk-73IIE3QT.js";
|
|
1
7
|
import {
|
|
2
8
|
AssistantMessage,
|
|
3
9
|
createProvider,
|
|
10
|
+
generateId,
|
|
4
11
|
isAssistantMessage,
|
|
5
12
|
isToolResultMessage,
|
|
6
13
|
isUserMessage
|
|
7
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-MF5ETY5O.js";
|
|
8
15
|
import {
|
|
9
16
|
parseSSEStream
|
|
10
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-NWS5IKNR.js";
|
|
11
18
|
import {
|
|
12
19
|
resolveApiKey
|
|
13
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-55X3W2MN.js";
|
|
14
21
|
import {
|
|
22
|
+
ErrorCode,
|
|
23
|
+
ModalityType,
|
|
15
24
|
UPPError,
|
|
16
25
|
doFetch,
|
|
17
26
|
doStreamFetch,
|
|
18
|
-
normalizeHttpError
|
|
19
|
-
|
|
27
|
+
normalizeHttpError,
|
|
28
|
+
toError
|
|
29
|
+
} from "../chunk-QNJO7DSD.js";
|
|
20
30
|
|
|
21
31
|
// src/providers/anthropic/types.ts
|
|
22
32
|
var betas = {
|
|
@@ -151,8 +161,9 @@ function transformRequest(request, modelId, useNativeStructuredOutput = false) {
|
|
|
151
161
|
model: modelId,
|
|
152
162
|
messages: request.messages.map(transformMessage)
|
|
153
163
|
};
|
|
154
|
-
|
|
155
|
-
|
|
164
|
+
const normalizedSystem = normalizeSystem(request.system);
|
|
165
|
+
if (normalizedSystem !== void 0) {
|
|
166
|
+
anthropicRequest.system = normalizedSystem;
|
|
156
167
|
}
|
|
157
168
|
const allTools = [];
|
|
158
169
|
if (request.tools && request.tools.length > 0) {
|
|
@@ -184,7 +195,8 @@ function transformRequest(request, modelId, useNativeStructuredOutput = false) {
|
|
|
184
195
|
input_schema: {
|
|
185
196
|
type: "object",
|
|
186
197
|
properties: request.structure.properties,
|
|
187
|
-
required: request.structure.required
|
|
198
|
+
required: request.structure.required,
|
|
199
|
+
...request.structure.additionalProperties !== void 0 ? { additionalProperties: request.structure.additionalProperties } : {}
|
|
188
200
|
}
|
|
189
201
|
};
|
|
190
202
|
anthropicRequest.tools = [...anthropicRequest.tools ?? [], structuredTool];
|
|
@@ -193,6 +205,57 @@ function transformRequest(request, modelId, useNativeStructuredOutput = false) {
|
|
|
193
205
|
}
|
|
194
206
|
return anthropicRequest;
|
|
195
207
|
}
|
|
208
|
+
function normalizeSystem(system) {
|
|
209
|
+
if (system === void 0 || system === null) return void 0;
|
|
210
|
+
if (typeof system === "string") return system;
|
|
211
|
+
if (!Array.isArray(system)) {
|
|
212
|
+
throw new UPPError(
|
|
213
|
+
"System prompt must be a string or an array of text blocks",
|
|
214
|
+
ErrorCode.InvalidRequest,
|
|
215
|
+
"anthropic",
|
|
216
|
+
ModalityType.LLM
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
const blocks = [];
|
|
220
|
+
for (const block of system) {
|
|
221
|
+
if (!block || typeof block !== "object") {
|
|
222
|
+
throw new UPPError(
|
|
223
|
+
'System prompt array must contain objects with type "text"',
|
|
224
|
+
ErrorCode.InvalidRequest,
|
|
225
|
+
"anthropic",
|
|
226
|
+
ModalityType.LLM
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
const candidate = block;
|
|
230
|
+
if (candidate.type !== "text" || typeof candidate.text !== "string") {
|
|
231
|
+
throw new UPPError(
|
|
232
|
+
'Anthropic system blocks must be of type "text" with a string text field',
|
|
233
|
+
ErrorCode.InvalidRequest,
|
|
234
|
+
"anthropic",
|
|
235
|
+
ModalityType.LLM
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
if (candidate.cache_control !== void 0 && !isValidCacheControl(candidate.cache_control)) {
|
|
239
|
+
throw new UPPError(
|
|
240
|
+
"Invalid cache_control for Anthropic system prompt",
|
|
241
|
+
ErrorCode.InvalidRequest,
|
|
242
|
+
"anthropic",
|
|
243
|
+
ModalityType.LLM
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
blocks.push(block);
|
|
247
|
+
}
|
|
248
|
+
return blocks.length > 0 ? blocks : void 0;
|
|
249
|
+
}
|
|
250
|
+
function isValidCacheControl(value) {
|
|
251
|
+
if (!value || typeof value !== "object") return false;
|
|
252
|
+
const candidate = value;
|
|
253
|
+
if (candidate.type !== "ephemeral") return false;
|
|
254
|
+
if (candidate.ttl !== void 0 && candidate.ttl !== "5m" && candidate.ttl !== "1h") {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
196
259
|
function filterValidContent(content) {
|
|
197
260
|
return content.filter((c) => c && typeof c.type === "string");
|
|
198
261
|
}
|
|
@@ -312,7 +375,8 @@ function transformTool(tool) {
|
|
|
312
375
|
input_schema: {
|
|
313
376
|
type: "object",
|
|
314
377
|
properties: tool.parameters.properties,
|
|
315
|
-
required: tool.parameters.required
|
|
378
|
+
required: tool.parameters.required,
|
|
379
|
+
...tool.parameters.additionalProperties !== void 0 ? { additionalProperties: tool.parameters.additionalProperties } : {}
|
|
316
380
|
},
|
|
317
381
|
...cacheControl ? { cache_control: cacheControl } : {}
|
|
318
382
|
};
|
|
@@ -396,6 +460,7 @@ function createStreamState() {
|
|
|
396
460
|
};
|
|
397
461
|
}
|
|
398
462
|
function transformStreamEvent(event, state) {
|
|
463
|
+
const events = [];
|
|
399
464
|
switch (event.type) {
|
|
400
465
|
case "message_start":
|
|
401
466
|
state.messageId = event.message.id;
|
|
@@ -403,7 +468,8 @@ function transformStreamEvent(event, state) {
|
|
|
403
468
|
state.inputTokens = event.message.usage.input_tokens;
|
|
404
469
|
state.cacheReadTokens = event.message.usage.cache_read_input_tokens ?? 0;
|
|
405
470
|
state.cacheWriteTokens = event.message.usage.cache_creation_input_tokens ?? 0;
|
|
406
|
-
|
|
471
|
+
events.push({ type: StreamEventType.MessageStart, index: 0, delta: {} });
|
|
472
|
+
break;
|
|
407
473
|
case "content_block_start":
|
|
408
474
|
if (event.content_block.type === "text") {
|
|
409
475
|
state.content[event.index] = { type: "text", text: "" };
|
|
@@ -436,56 +502,63 @@ function transformStreamEvent(event, state) {
|
|
|
436
502
|
fileContent: resultBlock.content?.content ?? ""
|
|
437
503
|
};
|
|
438
504
|
}
|
|
439
|
-
|
|
505
|
+
events.push({ type: StreamEventType.ContentBlockStart, index: event.index, delta: {} });
|
|
506
|
+
break;
|
|
440
507
|
case "content_block_delta": {
|
|
441
508
|
const delta = event.delta;
|
|
442
509
|
if (delta.type === "text_delta") {
|
|
443
510
|
if (state.content[event.index]) {
|
|
444
511
|
state.content[event.index].text = (state.content[event.index].text ?? "") + delta.text;
|
|
445
512
|
}
|
|
446
|
-
|
|
447
|
-
type:
|
|
513
|
+
events.push({
|
|
514
|
+
type: StreamEventType.TextDelta,
|
|
448
515
|
index: event.index,
|
|
449
516
|
delta: { text: delta.text }
|
|
450
|
-
};
|
|
517
|
+
});
|
|
518
|
+
break;
|
|
451
519
|
}
|
|
452
520
|
if (delta.type === "input_json_delta") {
|
|
453
521
|
if (state.content[event.index]) {
|
|
454
522
|
state.content[event.index].input = (state.content[event.index].input ?? "") + delta.partial_json;
|
|
455
523
|
}
|
|
456
|
-
|
|
457
|
-
type:
|
|
524
|
+
events.push({
|
|
525
|
+
type: StreamEventType.ToolCallDelta,
|
|
458
526
|
index: event.index,
|
|
459
527
|
delta: {
|
|
460
528
|
argumentsJson: delta.partial_json,
|
|
461
529
|
toolCallId: state.content[event.index]?.id,
|
|
462
530
|
toolName: state.content[event.index]?.name
|
|
463
531
|
}
|
|
464
|
-
};
|
|
532
|
+
});
|
|
533
|
+
break;
|
|
465
534
|
}
|
|
466
535
|
if (delta.type === "thinking_delta") {
|
|
467
|
-
|
|
468
|
-
type:
|
|
536
|
+
events.push({
|
|
537
|
+
type: StreamEventType.ReasoningDelta,
|
|
469
538
|
index: event.index,
|
|
470
539
|
delta: { text: delta.thinking }
|
|
471
|
-
};
|
|
540
|
+
});
|
|
541
|
+
break;
|
|
472
542
|
}
|
|
473
|
-
|
|
543
|
+
break;
|
|
474
544
|
}
|
|
475
545
|
case "content_block_stop":
|
|
476
|
-
|
|
546
|
+
events.push({ type: StreamEventType.ContentBlockStop, index: event.index, delta: {} });
|
|
547
|
+
break;
|
|
477
548
|
case "message_delta":
|
|
478
549
|
state.stopReason = event.delta.stop_reason;
|
|
479
550
|
state.outputTokens = event.usage.output_tokens;
|
|
480
|
-
return
|
|
551
|
+
return [];
|
|
481
552
|
case "message_stop":
|
|
482
|
-
|
|
553
|
+
events.push({ type: StreamEventType.MessageStop, index: 0, delta: {} });
|
|
554
|
+
break;
|
|
483
555
|
case "ping":
|
|
484
556
|
case "error":
|
|
485
|
-
return
|
|
557
|
+
return [];
|
|
486
558
|
default:
|
|
487
|
-
|
|
559
|
+
break;
|
|
488
560
|
}
|
|
561
|
+
return events;
|
|
489
562
|
}
|
|
490
563
|
function buildResponseFromState(state, useNativeStructuredOutput = false) {
|
|
491
564
|
const textContent = [];
|
|
@@ -529,11 +602,12 @@ ${block.fileContent}\`\`\`
|
|
|
529
602
|
` });
|
|
530
603
|
}
|
|
531
604
|
}
|
|
605
|
+
const messageId = state.messageId || generateId();
|
|
532
606
|
const message = new AssistantMessage(
|
|
533
607
|
textContent,
|
|
534
608
|
toolCalls.length > 0 ? toolCalls : void 0,
|
|
535
609
|
{
|
|
536
|
-
id:
|
|
610
|
+
id: messageId,
|
|
537
611
|
metadata: {
|
|
538
612
|
anthropic: {
|
|
539
613
|
stop_reason: state.stopReason,
|
|
@@ -588,9 +662,9 @@ function createLLMHandler() {
|
|
|
588
662
|
if (!providerRef) {
|
|
589
663
|
throw new UPPError(
|
|
590
664
|
"Provider reference not set. Handler must be used with createProvider().",
|
|
591
|
-
|
|
665
|
+
ErrorCode.InvalidRequest,
|
|
592
666
|
"anthropic",
|
|
593
|
-
|
|
667
|
+
ModalityType.LLM
|
|
594
668
|
);
|
|
595
669
|
}
|
|
596
670
|
const model = {
|
|
@@ -636,7 +710,7 @@ function createLLMHandler() {
|
|
|
636
710
|
"anthropic",
|
|
637
711
|
"llm"
|
|
638
712
|
);
|
|
639
|
-
const data = await response
|
|
713
|
+
const data = await parseJsonResponse(response, "anthropic", "llm");
|
|
640
714
|
return transformResponse(data, useNativeStructuredOutput);
|
|
641
715
|
},
|
|
642
716
|
stream(request) {
|
|
@@ -665,7 +739,8 @@ function createLLMHandler() {
|
|
|
665
739
|
const headers = {
|
|
666
740
|
"Content-Type": "application/json",
|
|
667
741
|
"x-api-key": apiKey,
|
|
668
|
-
"anthropic-version": request.config.apiVersion ?? ANTHROPIC_VERSION
|
|
742
|
+
"anthropic-version": request.config.apiVersion ?? ANTHROPIC_VERSION,
|
|
743
|
+
Accept: "text/event-stream"
|
|
669
744
|
};
|
|
670
745
|
if (request.config.headers) {
|
|
671
746
|
for (const [key, value] of Object.entries(request.config.headers)) {
|
|
@@ -694,9 +769,9 @@ function createLLMHandler() {
|
|
|
694
769
|
if (!response.body) {
|
|
695
770
|
const error = new UPPError(
|
|
696
771
|
"No response body for streaming request",
|
|
697
|
-
|
|
772
|
+
ErrorCode.ProviderError,
|
|
698
773
|
"anthropic",
|
|
699
|
-
|
|
774
|
+
ModalityType.LLM
|
|
700
775
|
);
|
|
701
776
|
responseReject(error);
|
|
702
777
|
throw error;
|
|
@@ -707,23 +782,24 @@ function createLLMHandler() {
|
|
|
707
782
|
if (event.type === "error") {
|
|
708
783
|
const error = new UPPError(
|
|
709
784
|
event.error.message,
|
|
710
|
-
|
|
785
|
+
ErrorCode.ProviderError,
|
|
711
786
|
"anthropic",
|
|
712
|
-
|
|
787
|
+
ModalityType.LLM
|
|
713
788
|
);
|
|
714
789
|
responseReject(error);
|
|
715
790
|
throw error;
|
|
716
791
|
}
|
|
717
|
-
const
|
|
718
|
-
|
|
792
|
+
const uppEvents = transformStreamEvent(event, state);
|
|
793
|
+
for (const uppEvent of uppEvents) {
|
|
719
794
|
yield uppEvent;
|
|
720
795
|
}
|
|
721
796
|
}
|
|
722
797
|
}
|
|
723
798
|
responseResolve(buildResponseFromState(state, useNativeStructuredOutput));
|
|
724
799
|
} catch (error) {
|
|
725
|
-
|
|
726
|
-
|
|
800
|
+
const err = toError(error);
|
|
801
|
+
responseReject(err);
|
|
802
|
+
throw err;
|
|
727
803
|
}
|
|
728
804
|
}
|
|
729
805
|
return {
|