@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
|
@@ -7,6 +7,68 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module types/content
|
|
9
9
|
*/
|
|
10
|
+
/**
|
|
11
|
+
* Content block type constants.
|
|
12
|
+
*
|
|
13
|
+
* Use these constants instead of raw strings for type-safe content handling:
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { ContentBlockType } from 'upp';
|
|
18
|
+
*
|
|
19
|
+
* if (block.type === ContentBlockType.Text) {
|
|
20
|
+
* console.log(block.text);
|
|
21
|
+
* } else if (block.type === ContentBlockType.Image) {
|
|
22
|
+
* console.log(block.mimeType);
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
declare const ContentBlockType: {
|
|
27
|
+
/** Text content */
|
|
28
|
+
readonly Text: "text";
|
|
29
|
+
/** Image content */
|
|
30
|
+
readonly Image: "image";
|
|
31
|
+
/** Audio content */
|
|
32
|
+
readonly Audio: "audio";
|
|
33
|
+
/** Video content */
|
|
34
|
+
readonly Video: "video";
|
|
35
|
+
/** Binary/arbitrary data content */
|
|
36
|
+
readonly Binary: "binary";
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Content block type discriminator union.
|
|
40
|
+
*
|
|
41
|
+
* This type is derived from {@link ContentBlockType} constants.
|
|
42
|
+
*/
|
|
43
|
+
type ContentBlockType = (typeof ContentBlockType)[keyof typeof ContentBlockType];
|
|
44
|
+
/**
|
|
45
|
+
* Image source type constants.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* import { ImageSourceType } from 'upp';
|
|
50
|
+
*
|
|
51
|
+
* if (source.type === ImageSourceType.Base64) {
|
|
52
|
+
* // Handle base64 encoded image
|
|
53
|
+
* } else if (source.type === ImageSourceType.Url) {
|
|
54
|
+
* // Handle URL reference
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
declare const ImageSourceType: {
|
|
59
|
+
/** Base64-encoded image data */
|
|
60
|
+
readonly Base64: "base64";
|
|
61
|
+
/** URL reference to image */
|
|
62
|
+
readonly Url: "url";
|
|
63
|
+
/** Raw bytes image data */
|
|
64
|
+
readonly Bytes: "bytes";
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Image source type discriminator union.
|
|
68
|
+
*
|
|
69
|
+
* This type is derived from {@link ImageSourceType} constants.
|
|
70
|
+
*/
|
|
71
|
+
type ImageSourceType = (typeof ImageSourceType)[keyof typeof ImageSourceType];
|
|
10
72
|
/**
|
|
11
73
|
* Image source variants for ImageBlock.
|
|
12
74
|
*
|
|
@@ -282,70 +344,100 @@ declare function isBinaryBlock(block: ContentBlock): block is BinaryBlock;
|
|
|
282
344
|
* @module types/errors
|
|
283
345
|
*/
|
|
284
346
|
/**
|
|
285
|
-
*
|
|
347
|
+
* Error code constants for cross-provider error handling.
|
|
286
348
|
*
|
|
287
|
-
*
|
|
288
|
-
* regardless of which AI provider generated them.
|
|
349
|
+
* Use these constants instead of raw strings for type-safe error handling:
|
|
289
350
|
*
|
|
290
351
|
* @example
|
|
291
352
|
* ```typescript
|
|
353
|
+
* import { ErrorCode } from 'upp';
|
|
354
|
+
*
|
|
292
355
|
* try {
|
|
293
356
|
* await llm.generate('Hello');
|
|
294
357
|
* } catch (error) {
|
|
295
358
|
* if (error instanceof UPPError) {
|
|
296
359
|
* switch (error.code) {
|
|
297
|
-
* case
|
|
360
|
+
* case ErrorCode.RateLimited:
|
|
298
361
|
* await delay(error.retryAfter);
|
|
299
362
|
* break;
|
|
300
|
-
* case
|
|
363
|
+
* case ErrorCode.AuthenticationFailed:
|
|
301
364
|
* throw new Error('Invalid API key');
|
|
302
365
|
* }
|
|
303
366
|
* }
|
|
304
367
|
* }
|
|
305
368
|
* ```
|
|
306
369
|
*/
|
|
307
|
-
|
|
308
|
-
/** API key is invalid or expired */
|
|
309
|
-
|
|
310
|
-
/** Rate limit exceeded, retry after delay */
|
|
311
|
-
|
|
312
|
-
/** Input exceeds model's context window */
|
|
313
|
-
|
|
314
|
-
/** Requested model does not exist */
|
|
315
|
-
|
|
316
|
-
/** Request parameters are malformed */
|
|
317
|
-
|
|
318
|
-
/** Provider returned an unexpected response format */
|
|
319
|
-
|
|
320
|
-
/** Content was blocked by safety filters */
|
|
321
|
-
|
|
322
|
-
/** Account quota or credits exhausted */
|
|
323
|
-
|
|
324
|
-
/** Provider-specific error not covered by other codes */
|
|
325
|
-
|
|
326
|
-
/** Network connectivity issue */
|
|
327
|
-
|
|
328
|
-
/** Request exceeded timeout limit */
|
|
329
|
-
|
|
330
|
-
/** Request was cancelled via AbortSignal */
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
370
|
+
declare const ErrorCode: {
|
|
371
|
+
/** API key is invalid or expired */
|
|
372
|
+
readonly AuthenticationFailed: "AUTHENTICATION_FAILED";
|
|
373
|
+
/** Rate limit exceeded, retry after delay */
|
|
374
|
+
readonly RateLimited: "RATE_LIMITED";
|
|
375
|
+
/** Input exceeds model's context window */
|
|
376
|
+
readonly ContextLengthExceeded: "CONTEXT_LENGTH_EXCEEDED";
|
|
377
|
+
/** Requested model does not exist */
|
|
378
|
+
readonly ModelNotFound: "MODEL_NOT_FOUND";
|
|
379
|
+
/** Request parameters are malformed */
|
|
380
|
+
readonly InvalidRequest: "INVALID_REQUEST";
|
|
381
|
+
/** Provider returned an unexpected response format */
|
|
382
|
+
readonly InvalidResponse: "INVALID_RESPONSE";
|
|
383
|
+
/** Content was blocked by safety filters */
|
|
384
|
+
readonly ContentFiltered: "CONTENT_FILTERED";
|
|
385
|
+
/** Account quota or credits exhausted */
|
|
386
|
+
readonly QuotaExceeded: "QUOTA_EXCEEDED";
|
|
387
|
+
/** Provider-specific error not covered by other codes */
|
|
388
|
+
readonly ProviderError: "PROVIDER_ERROR";
|
|
389
|
+
/** Network connectivity issue */
|
|
390
|
+
readonly NetworkError: "NETWORK_ERROR";
|
|
391
|
+
/** Request exceeded timeout limit */
|
|
392
|
+
readonly Timeout: "TIMEOUT";
|
|
393
|
+
/** Request was cancelled via AbortSignal */
|
|
394
|
+
readonly Cancelled: "CANCELLED";
|
|
395
|
+
};
|
|
396
|
+
/**
|
|
397
|
+
* Error code discriminator union.
|
|
398
|
+
*
|
|
399
|
+
* This type is derived from {@link ErrorCode} constants. Use `ErrorCode.RateLimited`
|
|
400
|
+
* for constants or `type MyCode = ErrorCode` for type annotations.
|
|
401
|
+
*/
|
|
402
|
+
type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
403
|
+
/**
|
|
404
|
+
* Modality type discriminator union.
|
|
405
|
+
*
|
|
406
|
+
* This type is derived from {@link ModalityType} constants. The name `Modality`
|
|
407
|
+
* is kept for backward compatibility; `ModalityType` works as both the const
|
|
408
|
+
* object and this type.
|
|
409
|
+
*/
|
|
410
|
+
type Modality = (typeof ModalityType)[keyof typeof ModalityType];
|
|
411
|
+
/**
|
|
412
|
+
* Modality type constants.
|
|
413
|
+
*
|
|
414
|
+
* Use these constants for type-safe modality handling:
|
|
415
|
+
*
|
|
416
|
+
* @example
|
|
417
|
+
* ```typescript
|
|
418
|
+
* import { ModalityType } from 'upp';
|
|
419
|
+
*
|
|
420
|
+
* if (provider.modality === ModalityType.LLM) {
|
|
421
|
+
* // Handle LLM provider
|
|
422
|
+
* }
|
|
423
|
+
* ```
|
|
424
|
+
*/
|
|
425
|
+
declare const ModalityType: {
|
|
426
|
+
/** Large language model for text generation */
|
|
427
|
+
readonly LLM: "llm";
|
|
428
|
+
/** Text/image embedding model */
|
|
429
|
+
readonly Embedding: "embedding";
|
|
430
|
+
/** Image generation model */
|
|
431
|
+
readonly Image: "image";
|
|
432
|
+
/** Audio processing/generation model */
|
|
433
|
+
readonly Audio: "audio";
|
|
434
|
+
/** Video processing/generation model */
|
|
435
|
+
readonly Video: "video";
|
|
436
|
+
};
|
|
437
|
+
/**
|
|
438
|
+
* Type alias for Modality, allowing `ModalityType` to work as both const and type.
|
|
439
|
+
*/
|
|
440
|
+
type ModalityType = Modality;
|
|
349
441
|
/**
|
|
350
442
|
* Unified Provider Protocol Error.
|
|
351
443
|
*
|
|
@@ -354,26 +446,30 @@ type Modality =
|
|
|
354
446
|
*
|
|
355
447
|
* @example
|
|
356
448
|
* ```typescript
|
|
449
|
+
* import { ErrorCode, ModalityType } from 'upp';
|
|
450
|
+
*
|
|
357
451
|
* throw new UPPError(
|
|
358
452
|
* 'API key is invalid',
|
|
359
|
-
*
|
|
453
|
+
* ErrorCode.AuthenticationFailed,
|
|
360
454
|
* 'openai',
|
|
361
|
-
*
|
|
455
|
+
* ModalityType.LLM,
|
|
362
456
|
* 401
|
|
363
457
|
* );
|
|
364
458
|
* ```
|
|
365
459
|
*
|
|
366
460
|
* @example
|
|
367
461
|
* ```typescript
|
|
462
|
+
* import { ErrorCode, ModalityType } from 'upp';
|
|
463
|
+
*
|
|
368
464
|
* // Wrapping a provider error
|
|
369
465
|
* try {
|
|
370
466
|
* await openai.chat.completions.create({ ... });
|
|
371
467
|
* } catch (err) {
|
|
372
468
|
* throw new UPPError(
|
|
373
469
|
* 'OpenAI request failed',
|
|
374
|
-
*
|
|
470
|
+
* ErrorCode.ProviderError,
|
|
375
471
|
* 'openai',
|
|
376
|
-
*
|
|
472
|
+
* ModalityType.LLM,
|
|
377
473
|
* err.status,
|
|
378
474
|
* err
|
|
379
475
|
* );
|
|
@@ -593,6 +689,8 @@ declare class Image {
|
|
|
593
689
|
interface ImageModelInput {
|
|
594
690
|
readonly modelId: string;
|
|
595
691
|
readonly provider: ProviderIdentity;
|
|
692
|
+
/** Optional provider configuration merged into requests */
|
|
693
|
+
readonly providerConfig?: Partial<ProviderConfig>;
|
|
596
694
|
}
|
|
597
695
|
/**
|
|
598
696
|
* Options for creating an image instance with the image() function.
|
|
@@ -1000,7 +1098,10 @@ interface ProviderConfig {
|
|
|
1000
1098
|
apiKey?: string | (() => string | Promise<string>) | KeyStrategy;
|
|
1001
1099
|
/** Override the base API URL (for proxies, local models) */
|
|
1002
1100
|
baseUrl?: string;
|
|
1003
|
-
/**
|
|
1101
|
+
/**
|
|
1102
|
+
* Request timeout in milliseconds.
|
|
1103
|
+
* Applied per attempt; total wall time can exceed this when retries are enabled.
|
|
1104
|
+
*/
|
|
1004
1105
|
timeout?: number;
|
|
1005
1106
|
/** Custom fetch implementation (for logging, caching, custom TLS) */
|
|
1006
1107
|
fetch?: typeof fetch;
|
|
@@ -1025,6 +1126,11 @@ interface ProviderConfig {
|
|
|
1025
1126
|
* ```
|
|
1026
1127
|
*/
|
|
1027
1128
|
headers?: Record<string, string | undefined>;
|
|
1129
|
+
/**
|
|
1130
|
+
* Maximum Retry-After delay in seconds when honoring server headers.
|
|
1131
|
+
* Defaults to 3600 seconds (1 hour).
|
|
1132
|
+
*/
|
|
1133
|
+
retryAfterMaxSeconds?: number;
|
|
1028
1134
|
}
|
|
1029
1135
|
/**
|
|
1030
1136
|
* A reference to a model, created by a provider factory.
|
|
@@ -1316,4 +1422,4 @@ type ImageProvider<TParams = unknown, TOptions = unknown> = Provider<TOptions> &
|
|
|
1316
1422
|
readonly __params?: TParams;
|
|
1317
1423
|
};
|
|
1318
1424
|
|
|
1319
|
-
export { type
|
|
1425
|
+
export { type ImageResponse as $, type AssistantContent as A, type BoundEmbeddingModel as B, type ContentBlock as C, type EmbeddingRequest as D, type EmbeddingInput as E, type EmbeddingResponse as F, type EmbeddingVector as G, type ImageInput as H, type ImageOptions as I, type ImageEditInput as J, type KeyStrategy as K, type LLMProvider as L, type ModelReference as M, type ImageGenerateOptions as N, type GeneratedImage as O, type ProviderIdentity as P, type ImageUsage as Q, type RetryStrategy as R, type ImageResult as S, type TextBlock as T, type UserContent as U, type VideoBlock as V, type ImageStreamEvent as W, type ImageStreamResult as X, type ImageCapabilities as Y, type ImageRequest as Z, type ImageEditRequest as _, type ProviderConfig as a, type ImageProviderStreamResult as a0, type BoundImageModel as a1, type ImageHandler$1 as a2, type ImageModelInput as a3, type EmbeddingUsage as b, type ImageInstance as c, type LLMHandler as d, type EmbeddingHandler as e, type ImageHandler as f, type Provider as g, Image as h, UPPError as i, ErrorCode as j, ModalityType as k, type Modality as l, type ImageBlock as m, type AudioBlock as n, type BinaryBlock as o, type ImageSource as p, ContentBlockType as q, ImageSourceType as r, isTextBlock as s, text as t, isImageBlock as u, isAudioBlock as v, isVideoBlock as w, isBinaryBlock as x, type EmbeddingProvider as y, type ImageProvider as z };
|
package/dist/proxy/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { g as Provider, M as ModelReference } from '../provider-
|
|
2
|
-
import { M as Message, b as MessageJSON, T as Turn,
|
|
1
|
+
import { g as Provider, M as ModelReference } from '../provider-DR1yins0.js';
|
|
2
|
+
import { M as Message, b as MessageJSON, T as Turn, I as TurnJSON, f as StreamEvent, S as StreamResult, J as JSONSchema, k as ToolMetadata, c as Tool } from '../stream-BuTrqt_j.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @fileoverview Proxy provider types.
|
package/dist/proxy/index.js
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
2
|
emptyUsage
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-MKDLXV4O.js";
|
|
4
|
+
import {
|
|
5
|
+
parseJsonResponse
|
|
6
|
+
} from "../chunk-Z6DKC37J.js";
|
|
4
7
|
import {
|
|
5
8
|
AssistantMessage,
|
|
6
9
|
ToolResultMessage,
|
|
7
10
|
UserMessage,
|
|
8
11
|
createProvider
|
|
9
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-MF5ETY5O.js";
|
|
10
13
|
import {
|
|
14
|
+
ErrorCode,
|
|
15
|
+
ModalityType,
|
|
11
16
|
UPPError,
|
|
12
17
|
doFetch,
|
|
13
18
|
doStreamFetch,
|
|
14
|
-
normalizeHttpError
|
|
15
|
-
|
|
19
|
+
normalizeHttpError,
|
|
20
|
+
toError
|
|
21
|
+
} from "../chunk-QNJO7DSD.js";
|
|
16
22
|
|
|
17
23
|
// src/providers/proxy/serialization.ts
|
|
18
24
|
function serializeMessage(m) {
|
|
@@ -50,7 +56,12 @@ function deserializeMessage(json) {
|
|
|
50
56
|
case "tool_result":
|
|
51
57
|
return new ToolResultMessage(json.results ?? [], options);
|
|
52
58
|
default:
|
|
53
|
-
throw new
|
|
59
|
+
throw new UPPError(
|
|
60
|
+
`Unknown message type: ${json.type}`,
|
|
61
|
+
ErrorCode.InvalidResponse,
|
|
62
|
+
"proxy",
|
|
63
|
+
ModalityType.LLM
|
|
64
|
+
);
|
|
54
65
|
}
|
|
55
66
|
}
|
|
56
67
|
function serializeTurn(turn) {
|
|
@@ -109,9 +120,9 @@ function createLLMHandler(options) {
|
|
|
109
120
|
if (!providerRef) {
|
|
110
121
|
throw new UPPError(
|
|
111
122
|
"Provider reference not set. Handler must be used with createProvider().",
|
|
112
|
-
|
|
123
|
+
ErrorCode.InvalidRequest,
|
|
113
124
|
"proxy",
|
|
114
|
-
|
|
125
|
+
ModalityType.LLM
|
|
115
126
|
);
|
|
116
127
|
}
|
|
117
128
|
const model = {
|
|
@@ -139,7 +150,7 @@ function createLLMHandler(options) {
|
|
|
139
150
|
"proxy",
|
|
140
151
|
"llm"
|
|
141
152
|
);
|
|
142
|
-
const data = await response
|
|
153
|
+
const data = await parseJsonResponse(response, "proxy", "llm");
|
|
143
154
|
return turnJSONToLLMResponse(data);
|
|
144
155
|
},
|
|
145
156
|
stream(request) {
|
|
@@ -175,9 +186,9 @@ function createLLMHandler(options) {
|
|
|
175
186
|
if (!response.body) {
|
|
176
187
|
throw new UPPError(
|
|
177
188
|
"Response body is null",
|
|
178
|
-
|
|
189
|
+
ErrorCode.ProviderError,
|
|
179
190
|
"proxy",
|
|
180
|
-
|
|
191
|
+
ModalityType.LLM
|
|
181
192
|
);
|
|
182
193
|
}
|
|
183
194
|
const reader = response.body.getReader();
|
|
@@ -191,8 +202,36 @@ function createLLMHandler(options) {
|
|
|
191
202
|
buffer = lines.pop() ?? "";
|
|
192
203
|
for (const line of lines) {
|
|
193
204
|
if (!line.trim() || line.startsWith(":")) continue;
|
|
194
|
-
if (line.startsWith("data:
|
|
195
|
-
|
|
205
|
+
if (line.startsWith("data:")) {
|
|
206
|
+
let data = line.slice(5);
|
|
207
|
+
if (data.startsWith(" ")) {
|
|
208
|
+
data = data.slice(1);
|
|
209
|
+
}
|
|
210
|
+
if (data === "[DONE]") continue;
|
|
211
|
+
try {
|
|
212
|
+
const parsed = JSON.parse(data);
|
|
213
|
+
if ("messages" in parsed && "usage" in parsed && "cycles" in parsed) {
|
|
214
|
+
resolveResponse(turnJSONToLLMResponse(parsed));
|
|
215
|
+
} else {
|
|
216
|
+
yield deserializeStreamEvent(parsed);
|
|
217
|
+
}
|
|
218
|
+
} catch {
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const remaining = decoder.decode();
|
|
224
|
+
if (remaining) {
|
|
225
|
+
buffer += remaining;
|
|
226
|
+
const lines = buffer.split("\n");
|
|
227
|
+
buffer = lines.pop() ?? "";
|
|
228
|
+
for (const line of lines) {
|
|
229
|
+
if (!line.trim() || line.startsWith(":")) continue;
|
|
230
|
+
if (line.startsWith("data:")) {
|
|
231
|
+
let data = line.slice(5);
|
|
232
|
+
if (data.startsWith(" ")) {
|
|
233
|
+
data = data.slice(1);
|
|
234
|
+
}
|
|
196
235
|
if (data === "[DONE]") continue;
|
|
197
236
|
try {
|
|
198
237
|
const parsed = JSON.parse(data);
|
|
@@ -207,7 +246,7 @@ function createLLMHandler(options) {
|
|
|
207
246
|
}
|
|
208
247
|
}
|
|
209
248
|
} catch (error) {
|
|
210
|
-
rejectResponse(
|
|
249
|
+
rejectResponse(toError(error));
|
|
211
250
|
throw error;
|
|
212
251
|
}
|
|
213
252
|
};
|
|
@@ -249,13 +288,117 @@ function mergeHeaders(requestHeaders, defaultHeaders) {
|
|
|
249
288
|
function turnJSONToLLMResponse(data) {
|
|
250
289
|
const messages = data.messages.map(deserializeMessage);
|
|
251
290
|
const lastAssistant = messages.filter((m) => m.type === "assistant").pop();
|
|
291
|
+
const stopReason = deriveStopReason(lastAssistant);
|
|
252
292
|
return {
|
|
253
293
|
message: lastAssistant ?? new AssistantMessage(""),
|
|
254
294
|
usage: data.usage ?? emptyUsage(),
|
|
255
|
-
stopReason
|
|
295
|
+
stopReason,
|
|
256
296
|
data: data.data
|
|
257
297
|
};
|
|
258
298
|
}
|
|
299
|
+
function deriveStopReason(message) {
|
|
300
|
+
if (!message) {
|
|
301
|
+
return "end_turn";
|
|
302
|
+
}
|
|
303
|
+
if (message.toolCalls && message.toolCalls.length > 0) {
|
|
304
|
+
return "tool_use";
|
|
305
|
+
}
|
|
306
|
+
const metadata = message.metadata;
|
|
307
|
+
const openaiMeta = metadata?.openai;
|
|
308
|
+
if (openaiMeta?.status) {
|
|
309
|
+
if (openaiMeta.status === "failed") {
|
|
310
|
+
return "error";
|
|
311
|
+
}
|
|
312
|
+
if (openaiMeta.status === "completed") {
|
|
313
|
+
return "end_turn";
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (openaiMeta?.finish_reason) {
|
|
317
|
+
return mapCompletionStopReason(openaiMeta.finish_reason);
|
|
318
|
+
}
|
|
319
|
+
const openrouterMeta = metadata?.openrouter;
|
|
320
|
+
if (openrouterMeta?.finish_reason) {
|
|
321
|
+
return mapCompletionStopReason(openrouterMeta.finish_reason);
|
|
322
|
+
}
|
|
323
|
+
const xaiMeta = metadata?.xai;
|
|
324
|
+
if (xaiMeta?.status) {
|
|
325
|
+
if (xaiMeta.status === "failed") {
|
|
326
|
+
return "error";
|
|
327
|
+
}
|
|
328
|
+
if (xaiMeta.status === "completed") {
|
|
329
|
+
return "end_turn";
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (xaiMeta?.finish_reason) {
|
|
333
|
+
return mapCompletionStopReason(xaiMeta.finish_reason);
|
|
334
|
+
}
|
|
335
|
+
const anthropicMeta = metadata?.anthropic;
|
|
336
|
+
if (anthropicMeta?.stop_reason) {
|
|
337
|
+
return mapAnthropicStopReason(anthropicMeta.stop_reason);
|
|
338
|
+
}
|
|
339
|
+
const googleMeta = metadata?.google;
|
|
340
|
+
if (googleMeta?.finishReason) {
|
|
341
|
+
return mapGoogleStopReason(googleMeta.finishReason);
|
|
342
|
+
}
|
|
343
|
+
const ollamaMeta = metadata?.ollama;
|
|
344
|
+
if (ollamaMeta?.done_reason) {
|
|
345
|
+
return mapOllamaStopReason(ollamaMeta.done_reason);
|
|
346
|
+
}
|
|
347
|
+
return "end_turn";
|
|
348
|
+
}
|
|
349
|
+
function mapCompletionStopReason(reason) {
|
|
350
|
+
switch (reason) {
|
|
351
|
+
case "stop":
|
|
352
|
+
return "end_turn";
|
|
353
|
+
case "length":
|
|
354
|
+
return "max_tokens";
|
|
355
|
+
case "tool_calls":
|
|
356
|
+
return "tool_use";
|
|
357
|
+
case "content_filter":
|
|
358
|
+
return "content_filter";
|
|
359
|
+
default:
|
|
360
|
+
return "end_turn";
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function mapAnthropicStopReason(reason) {
|
|
364
|
+
switch (reason) {
|
|
365
|
+
case "tool_use":
|
|
366
|
+
return "tool_use";
|
|
367
|
+
case "max_tokens":
|
|
368
|
+
return "max_tokens";
|
|
369
|
+
case "end_turn":
|
|
370
|
+
return "end_turn";
|
|
371
|
+
case "stop_sequence":
|
|
372
|
+
return "end_turn";
|
|
373
|
+
default:
|
|
374
|
+
return "end_turn";
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function mapGoogleStopReason(reason) {
|
|
378
|
+
switch (reason) {
|
|
379
|
+
case "STOP":
|
|
380
|
+
return "end_turn";
|
|
381
|
+
case "MAX_TOKENS":
|
|
382
|
+
return "max_tokens";
|
|
383
|
+
case "SAFETY":
|
|
384
|
+
return "content_filter";
|
|
385
|
+
case "RECITATION":
|
|
386
|
+
return "content_filter";
|
|
387
|
+
case "OTHER":
|
|
388
|
+
return "end_turn";
|
|
389
|
+
default:
|
|
390
|
+
return "end_turn";
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function mapOllamaStopReason(reason) {
|
|
394
|
+
if (reason === "length") {
|
|
395
|
+
return "max_tokens";
|
|
396
|
+
}
|
|
397
|
+
if (reason === "stop") {
|
|
398
|
+
return "end_turn";
|
|
399
|
+
}
|
|
400
|
+
return "end_turn";
|
|
401
|
+
}
|
|
259
402
|
|
|
260
403
|
// src/providers/proxy/server/express.ts
|
|
261
404
|
function sendJSON(turn, res) {
|
|
@@ -417,6 +560,24 @@ function parseBody(body) {
|
|
|
417
560
|
if (!Array.isArray(data.messages)) {
|
|
418
561
|
throw new Error("Request body must have a messages array");
|
|
419
562
|
}
|
|
563
|
+
for (const message of data.messages) {
|
|
564
|
+
if (!message || typeof message !== "object") {
|
|
565
|
+
throw new Error("Each message must be an object");
|
|
566
|
+
}
|
|
567
|
+
const msg = message;
|
|
568
|
+
if (typeof msg.id !== "string") {
|
|
569
|
+
throw new Error("Each message must have a string id");
|
|
570
|
+
}
|
|
571
|
+
if (typeof msg.type !== "string") {
|
|
572
|
+
throw new Error("Each message must have a string type");
|
|
573
|
+
}
|
|
574
|
+
if (typeof msg.timestamp !== "string") {
|
|
575
|
+
throw new Error("Each message must have a string timestamp");
|
|
576
|
+
}
|
|
577
|
+
if ((msg.type === "user" || msg.type === "assistant") && !Array.isArray(msg.content)) {
|
|
578
|
+
throw new Error("User and assistant messages must have a content array");
|
|
579
|
+
}
|
|
580
|
+
}
|
|
420
581
|
return {
|
|
421
582
|
messages: data.messages.map(deserializeMessage),
|
|
422
583
|
system: data.system,
|
|
@@ -466,7 +627,7 @@ function toSSE(stream) {
|
|
|
466
627
|
}
|
|
467
628
|
});
|
|
468
629
|
}
|
|
469
|
-
function
|
|
630
|
+
function toError2(message, status = 500) {
|
|
470
631
|
return new Response(JSON.stringify({ error: message }), {
|
|
471
632
|
status,
|
|
472
633
|
headers: { "Content-Type": "application/json" }
|
|
@@ -486,7 +647,7 @@ var webapi = {
|
|
|
486
647
|
parseBody,
|
|
487
648
|
toJSON,
|
|
488
649
|
toSSE,
|
|
489
|
-
toError,
|
|
650
|
+
toError: toError2,
|
|
490
651
|
bindTools
|
|
491
652
|
};
|
|
492
653
|
|
|
@@ -529,7 +690,7 @@ export {
|
|
|
529
690
|
serializeStreamEvent,
|
|
530
691
|
serializeTurn,
|
|
531
692
|
server,
|
|
532
|
-
toError,
|
|
693
|
+
toError2 as toError,
|
|
533
694
|
toJSON,
|
|
534
695
|
toSSE,
|
|
535
696
|
webapi
|