@providerprotocol/ai 0.0.11 → 0.0.13
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/anthropic/index.d.ts +51 -15
- package/dist/anthropic/index.js +54 -19
- package/dist/anthropic/index.js.map +1 -1
- package/dist/{chunk-SUNYWHTH.js → chunk-MOU4U3PO.js} +55 -3
- package/dist/chunk-MOU4U3PO.js.map +1 -0
- package/dist/{chunk-Y6Q7JCNP.js → chunk-MSR5P65T.js} +1 -1
- package/dist/chunk-MSR5P65T.js.map +1 -0
- package/dist/{chunk-W4BB4BG2.js → chunk-SVYROCLD.js} +31 -11
- package/dist/chunk-SVYROCLD.js.map +1 -0
- package/dist/chunk-U4JJC2YX.js +234 -0
- package/dist/chunk-U4JJC2YX.js.map +1 -0
- package/dist/{chunk-X5G4EHL7.js → chunk-Z7RBRCRN.js} +1 -1
- package/dist/chunk-Z7RBRCRN.js.map +1 -0
- package/dist/google/index.d.ts +376 -7
- package/dist/google/index.js +127 -15
- package/dist/google/index.js.map +1 -1
- package/dist/http/index.d.ts +222 -25
- package/dist/http/index.js +3 -3
- package/dist/index.d.ts +1482 -198
- package/dist/index.js +233 -49
- package/dist/index.js.map +1 -1
- package/dist/ollama/index.d.ts +92 -20
- package/dist/ollama/index.js +17 -7
- package/dist/ollama/index.js.map +1 -1
- package/dist/openai/index.d.ts +340 -61
- package/dist/openai/index.js +57 -15
- package/dist/openai/index.js.map +1 -1
- package/dist/openrouter/index.d.ts +107 -51
- package/dist/openrouter/index.js +36 -8
- package/dist/openrouter/index.js.map +1 -1
- package/dist/provider-mKkz7Q9U.d.ts +488 -0
- package/dist/retry-Dh70lgr0.d.ts +508 -0
- package/dist/xai/index.d.ts +97 -22
- package/dist/xai/index.js +55 -19
- package/dist/xai/index.js.map +1 -1
- package/package.json +8 -12
- package/dist/chunk-CUCRF5W6.js +0 -136
- package/dist/chunk-CUCRF5W6.js.map +0 -1
- package/dist/chunk-SUNYWHTH.js.map +0 -1
- package/dist/chunk-W4BB4BG2.js.map +0 -1
- package/dist/chunk-X5G4EHL7.js.map +0 -1
- package/dist/chunk-Y6Q7JCNP.js.map +0 -1
- package/dist/provider-CUJWjgNl.d.ts +0 -192
- package/dist/retry-I2661_rv.d.ts +0 -118
- package/src/anthropic/index.ts +0 -3
- package/src/core/image.ts +0 -188
- package/src/core/llm.ts +0 -650
- package/src/core/provider.ts +0 -92
- package/src/google/index.ts +0 -3
- package/src/http/errors.ts +0 -112
- package/src/http/fetch.ts +0 -210
- package/src/http/index.ts +0 -31
- package/src/http/keys.ts +0 -136
- package/src/http/retry.ts +0 -205
- package/src/http/sse.ts +0 -136
- package/src/index.ts +0 -32
- package/src/ollama/index.ts +0 -3
- package/src/openai/index.ts +0 -39
- package/src/openrouter/index.ts +0 -11
- package/src/providers/anthropic/index.ts +0 -17
- package/src/providers/anthropic/llm.ts +0 -196
- package/src/providers/anthropic/transform.ts +0 -434
- package/src/providers/anthropic/types.ts +0 -213
- package/src/providers/google/index.ts +0 -17
- package/src/providers/google/llm.ts +0 -203
- package/src/providers/google/transform.ts +0 -447
- package/src/providers/google/types.ts +0 -214
- package/src/providers/ollama/index.ts +0 -43
- package/src/providers/ollama/llm.ts +0 -272
- package/src/providers/ollama/transform.ts +0 -434
- package/src/providers/ollama/types.ts +0 -260
- package/src/providers/openai/index.ts +0 -186
- package/src/providers/openai/llm.completions.ts +0 -201
- package/src/providers/openai/llm.responses.ts +0 -211
- package/src/providers/openai/transform.completions.ts +0 -561
- package/src/providers/openai/transform.responses.ts +0 -708
- package/src/providers/openai/types.ts +0 -1249
- package/src/providers/openrouter/index.ts +0 -177
- package/src/providers/openrouter/llm.completions.ts +0 -201
- package/src/providers/openrouter/llm.responses.ts +0 -211
- package/src/providers/openrouter/transform.completions.ts +0 -538
- package/src/providers/openrouter/transform.responses.ts +0 -742
- package/src/providers/openrouter/types.ts +0 -717
- package/src/providers/xai/index.ts +0 -223
- package/src/providers/xai/llm.completions.ts +0 -201
- package/src/providers/xai/llm.messages.ts +0 -195
- package/src/providers/xai/llm.responses.ts +0 -211
- package/src/providers/xai/transform.completions.ts +0 -565
- package/src/providers/xai/transform.messages.ts +0 -448
- package/src/providers/xai/transform.responses.ts +0 -678
- package/src/providers/xai/types.ts +0 -938
- package/src/types/content.ts +0 -133
- package/src/types/errors.ts +0 -85
- package/src/types/index.ts +0 -105
- package/src/types/llm.ts +0 -211
- package/src/types/messages.ts +0 -205
- package/src/types/provider.ts +0 -195
- package/src/types/schema.ts +0 -58
- package/src/types/stream.ts +0 -188
- package/src/types/thread.ts +0 -226
- package/src/types/tool.ts +0 -88
- package/src/types/turn.ts +0 -118
- package/src/utils/id.ts +0 -28
- package/src/xai/index.ts +0 -41
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@providerprotocol/ai",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "UPP: Unified Provider Protocol for AI inference",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://providerprotocol.org",
|
|
@@ -14,56 +14,47 @@
|
|
|
14
14
|
"exports": {
|
|
15
15
|
".": {
|
|
16
16
|
"types": "./dist/index.d.ts",
|
|
17
|
-
"bun": "./src/index.ts",
|
|
18
17
|
"import": "./dist/index.js",
|
|
19
18
|
"default": "./dist/index.js"
|
|
20
19
|
},
|
|
21
20
|
"./anthropic": {
|
|
22
21
|
"types": "./dist/anthropic/index.d.ts",
|
|
23
|
-
"bun": "./src/anthropic/index.ts",
|
|
24
22
|
"import": "./dist/anthropic/index.js",
|
|
25
23
|
"default": "./dist/anthropic/index.js"
|
|
26
24
|
},
|
|
27
25
|
"./openai": {
|
|
28
26
|
"types": "./dist/openai/index.d.ts",
|
|
29
|
-
"bun": "./src/openai/index.ts",
|
|
30
27
|
"import": "./dist/openai/index.js",
|
|
31
28
|
"default": "./dist/openai/index.js"
|
|
32
29
|
},
|
|
33
30
|
"./google": {
|
|
34
31
|
"types": "./dist/google/index.d.ts",
|
|
35
|
-
"bun": "./src/google/index.ts",
|
|
36
32
|
"import": "./dist/google/index.js",
|
|
37
33
|
"default": "./dist/google/index.js"
|
|
38
34
|
},
|
|
39
35
|
"./ollama": {
|
|
40
36
|
"types": "./dist/ollama/index.d.ts",
|
|
41
|
-
"bun": "./src/ollama/index.ts",
|
|
42
37
|
"import": "./dist/ollama/index.js",
|
|
43
38
|
"default": "./dist/ollama/index.js"
|
|
44
39
|
},
|
|
45
40
|
"./openrouter": {
|
|
46
41
|
"types": "./dist/openrouter/index.d.ts",
|
|
47
|
-
"bun": "./src/openrouter/index.ts",
|
|
48
42
|
"import": "./dist/openrouter/index.js",
|
|
49
43
|
"default": "./dist/openrouter/index.js"
|
|
50
44
|
},
|
|
51
45
|
"./xai": {
|
|
52
46
|
"types": "./dist/xai/index.d.ts",
|
|
53
|
-
"bun": "./src/xai/index.ts",
|
|
54
47
|
"import": "./dist/xai/index.js",
|
|
55
48
|
"default": "./dist/xai/index.js"
|
|
56
49
|
},
|
|
57
50
|
"./http": {
|
|
58
51
|
"types": "./dist/http/index.d.ts",
|
|
59
|
-
"bun": "./src/http/index.ts",
|
|
60
52
|
"import": "./dist/http/index.js",
|
|
61
53
|
"default": "./dist/http/index.js"
|
|
62
54
|
}
|
|
63
55
|
},
|
|
64
56
|
"files": [
|
|
65
57
|
"dist",
|
|
66
|
-
"src",
|
|
67
58
|
"README.md"
|
|
68
59
|
],
|
|
69
60
|
"scripts": {
|
|
@@ -72,14 +63,19 @@
|
|
|
72
63
|
"test": "bun test",
|
|
73
64
|
"test:unit": "bun test tests/unit",
|
|
74
65
|
"test:live": "bun test tests/live",
|
|
75
|
-
"typecheck": "tsc --noEmit"
|
|
66
|
+
"typecheck": "tsc --noEmit",
|
|
67
|
+
"docgen": "typedoc --entryPoints src/index.ts --entryPoints src/anthropic/index.ts --entryPoints src/openai/index.ts --entryPoints src/google/index.ts --entryPoints src/ollama/index.ts --entryPoints src/openrouter/index.ts --entryPoints src/xai/index.ts --entryPoints src/http/index.ts --out docs --plugin typedoc-plugin-markdown",
|
|
68
|
+
"docs:sort": "bun run scripts/sort-docs.ts",
|
|
69
|
+
"docs": "bun run docgen && bun run docs:sort"
|
|
76
70
|
},
|
|
77
71
|
"publishConfig": {
|
|
78
72
|
"access": "public"
|
|
79
73
|
},
|
|
80
74
|
"devDependencies": {
|
|
81
75
|
"@types/bun": "latest",
|
|
82
|
-
"tsup": "^8.5.1"
|
|
76
|
+
"tsup": "^8.5.1",
|
|
77
|
+
"typedoc": "^0.28.15",
|
|
78
|
+
"typedoc-plugin-markdown": "^4.9.0"
|
|
83
79
|
},
|
|
84
80
|
"peerDependencies": {
|
|
85
81
|
"typescript": "^5"
|
package/dist/chunk-CUCRF5W6.js
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
// src/http/retry.ts
|
|
2
|
-
var ExponentialBackoff = class {
|
|
3
|
-
maxAttempts;
|
|
4
|
-
baseDelay;
|
|
5
|
-
maxDelay;
|
|
6
|
-
jitter;
|
|
7
|
-
constructor(options = {}) {
|
|
8
|
-
this.maxAttempts = options.maxAttempts ?? 3;
|
|
9
|
-
this.baseDelay = options.baseDelay ?? 1e3;
|
|
10
|
-
this.maxDelay = options.maxDelay ?? 3e4;
|
|
11
|
-
this.jitter = options.jitter ?? true;
|
|
12
|
-
}
|
|
13
|
-
onRetry(error, attempt) {
|
|
14
|
-
if (attempt > this.maxAttempts) {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
if (!this.isRetryable(error)) {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
let delay = this.baseDelay * Math.pow(2, attempt - 1);
|
|
21
|
-
delay = Math.min(delay, this.maxDelay);
|
|
22
|
-
if (this.jitter) {
|
|
23
|
-
delay = delay * (0.5 + Math.random());
|
|
24
|
-
}
|
|
25
|
-
return Math.floor(delay);
|
|
26
|
-
}
|
|
27
|
-
isRetryable(error) {
|
|
28
|
-
return error.code === "RATE_LIMITED" || error.code === "NETWORK_ERROR" || error.code === "TIMEOUT" || error.code === "PROVIDER_ERROR";
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
var LinearBackoff = class {
|
|
32
|
-
maxAttempts;
|
|
33
|
-
delay;
|
|
34
|
-
constructor(options = {}) {
|
|
35
|
-
this.maxAttempts = options.maxAttempts ?? 3;
|
|
36
|
-
this.delay = options.delay ?? 1e3;
|
|
37
|
-
}
|
|
38
|
-
onRetry(error, attempt) {
|
|
39
|
-
if (attempt > this.maxAttempts) {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
if (!this.isRetryable(error)) {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
return this.delay * attempt;
|
|
46
|
-
}
|
|
47
|
-
isRetryable(error) {
|
|
48
|
-
return error.code === "RATE_LIMITED" || error.code === "NETWORK_ERROR" || error.code === "TIMEOUT" || error.code === "PROVIDER_ERROR";
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
var NoRetry = class {
|
|
52
|
-
onRetry() {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
var TokenBucket = class {
|
|
57
|
-
tokens;
|
|
58
|
-
maxTokens;
|
|
59
|
-
refillRate;
|
|
60
|
-
// tokens per second
|
|
61
|
-
lastRefill;
|
|
62
|
-
maxAttempts;
|
|
63
|
-
constructor(options = {}) {
|
|
64
|
-
this.maxTokens = options.maxTokens ?? 10;
|
|
65
|
-
this.refillRate = options.refillRate ?? 1;
|
|
66
|
-
this.maxAttempts = options.maxAttempts ?? 3;
|
|
67
|
-
this.tokens = this.maxTokens;
|
|
68
|
-
this.lastRefill = Date.now();
|
|
69
|
-
}
|
|
70
|
-
beforeRequest() {
|
|
71
|
-
this.refill();
|
|
72
|
-
if (this.tokens >= 1) {
|
|
73
|
-
this.tokens -= 1;
|
|
74
|
-
return 0;
|
|
75
|
-
}
|
|
76
|
-
const msPerToken = 1e3 / this.refillRate;
|
|
77
|
-
return Math.ceil(msPerToken);
|
|
78
|
-
}
|
|
79
|
-
onRetry(error, attempt) {
|
|
80
|
-
if (attempt > this.maxAttempts) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
if (error.code !== "RATE_LIMITED") {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
const msPerToken = 1e3 / this.refillRate;
|
|
87
|
-
return Math.ceil(msPerToken * 2);
|
|
88
|
-
}
|
|
89
|
-
reset() {
|
|
90
|
-
this.tokens = this.maxTokens;
|
|
91
|
-
this.lastRefill = Date.now();
|
|
92
|
-
}
|
|
93
|
-
refill() {
|
|
94
|
-
const now = Date.now();
|
|
95
|
-
const elapsed = (now - this.lastRefill) / 1e3;
|
|
96
|
-
const newTokens = elapsed * this.refillRate;
|
|
97
|
-
this.tokens = Math.min(this.maxTokens, this.tokens + newTokens);
|
|
98
|
-
this.lastRefill = now;
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
var RetryAfterStrategy = class {
|
|
102
|
-
maxAttempts;
|
|
103
|
-
fallbackDelay;
|
|
104
|
-
lastRetryAfter;
|
|
105
|
-
constructor(options = {}) {
|
|
106
|
-
this.maxAttempts = options.maxAttempts ?? 3;
|
|
107
|
-
this.fallbackDelay = options.fallbackDelay ?? 5e3;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Set the Retry-After value from response headers
|
|
111
|
-
* Call this before onRetry when you have a Retry-After header
|
|
112
|
-
*/
|
|
113
|
-
setRetryAfter(seconds) {
|
|
114
|
-
this.lastRetryAfter = seconds * 1e3;
|
|
115
|
-
}
|
|
116
|
-
onRetry(error, attempt) {
|
|
117
|
-
if (attempt > this.maxAttempts) {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
if (error.code !== "RATE_LIMITED") {
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
const delay = this.lastRetryAfter ?? this.fallbackDelay;
|
|
124
|
-
this.lastRetryAfter = void 0;
|
|
125
|
-
return delay;
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
export {
|
|
130
|
-
ExponentialBackoff,
|
|
131
|
-
LinearBackoff,
|
|
132
|
-
NoRetry,
|
|
133
|
-
TokenBucket,
|
|
134
|
-
RetryAfterStrategy
|
|
135
|
-
};
|
|
136
|
-
//# sourceMappingURL=chunk-CUCRF5W6.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/http/retry.ts"],"sourcesContent":["import type { RetryStrategy } from '../types/provider.ts';\nimport type { UPPError } from '../types/errors.ts';\n\n/**\n * Exponential backoff retry strategy\n */\nexport class ExponentialBackoff implements RetryStrategy {\n private maxAttempts: number;\n private baseDelay: number;\n private maxDelay: number;\n private jitter: boolean;\n\n constructor(options: {\n maxAttempts?: number;\n baseDelay?: number;\n maxDelay?: number;\n jitter?: boolean;\n } = {}) {\n this.maxAttempts = options.maxAttempts ?? 3;\n this.baseDelay = options.baseDelay ?? 1000;\n this.maxDelay = options.maxDelay ?? 30000;\n this.jitter = options.jitter ?? true;\n }\n\n onRetry(error: UPPError, attempt: number): number | null {\n if (attempt > this.maxAttempts) {\n return null;\n }\n\n // Only retry on retryable errors\n if (!this.isRetryable(error)) {\n return null;\n }\n\n // Calculate delay with exponential backoff\n let delay = this.baseDelay * Math.pow(2, attempt - 1);\n delay = Math.min(delay, this.maxDelay);\n\n // Add jitter\n if (this.jitter) {\n delay = delay * (0.5 + Math.random());\n }\n\n return Math.floor(delay);\n }\n\n private isRetryable(error: UPPError): boolean {\n return (\n error.code === 'RATE_LIMITED' ||\n error.code === 'NETWORK_ERROR' ||\n error.code === 'TIMEOUT' ||\n error.code === 'PROVIDER_ERROR'\n );\n }\n}\n\n/**\n * Linear backoff retry strategy\n */\nexport class LinearBackoff implements RetryStrategy {\n private maxAttempts: number;\n private delay: number;\n\n constructor(options: {\n maxAttempts?: number;\n delay?: number;\n } = {}) {\n this.maxAttempts = options.maxAttempts ?? 3;\n this.delay = options.delay ?? 1000;\n }\n\n onRetry(error: UPPError, attempt: number): number | null {\n if (attempt > this.maxAttempts) {\n return null;\n }\n\n // Only retry on retryable errors\n if (!this.isRetryable(error)) {\n return null;\n }\n\n return this.delay * attempt;\n }\n\n private isRetryable(error: UPPError): boolean {\n return (\n error.code === 'RATE_LIMITED' ||\n error.code === 'NETWORK_ERROR' ||\n error.code === 'TIMEOUT' ||\n error.code === 'PROVIDER_ERROR'\n );\n }\n}\n\n/**\n * No retry strategy - fail immediately\n */\nexport class NoRetry implements RetryStrategy {\n onRetry(): null {\n return null;\n }\n}\n\n/**\n * Token bucket rate limiter with retry\n */\nexport class TokenBucket implements RetryStrategy {\n private tokens: number;\n private maxTokens: number;\n private refillRate: number; // tokens per second\n private lastRefill: number;\n private maxAttempts: number;\n\n constructor(options: {\n maxTokens?: number;\n refillRate?: number;\n maxAttempts?: number;\n } = {}) {\n this.maxTokens = options.maxTokens ?? 10;\n this.refillRate = options.refillRate ?? 1;\n this.maxAttempts = options.maxAttempts ?? 3;\n this.tokens = this.maxTokens;\n this.lastRefill = Date.now();\n }\n\n beforeRequest(): number {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n return 0;\n }\n\n // Calculate time until next token\n const msPerToken = 1000 / this.refillRate;\n return Math.ceil(msPerToken);\n }\n\n onRetry(error: UPPError, attempt: number): number | null {\n if (attempt > this.maxAttempts) {\n return null;\n }\n\n if (error.code !== 'RATE_LIMITED') {\n return null;\n }\n\n // Wait for token bucket to refill\n const msPerToken = 1000 / this.refillRate;\n return Math.ceil(msPerToken * 2); // Wait for 2 tokens\n }\n\n reset(): void {\n this.tokens = this.maxTokens;\n this.lastRefill = Date.now();\n }\n\n private refill(): void {\n const now = Date.now();\n const elapsed = (now - this.lastRefill) / 1000;\n const newTokens = elapsed * this.refillRate;\n\n this.tokens = Math.min(this.maxTokens, this.tokens + newTokens);\n this.lastRefill = now;\n }\n}\n\n/**\n * Retry strategy that respects Retry-After headers\n */\nexport class RetryAfterStrategy implements RetryStrategy {\n private maxAttempts: number;\n private fallbackDelay: number;\n private lastRetryAfter?: number;\n\n constructor(options: {\n maxAttempts?: number;\n fallbackDelay?: number;\n } = {}) {\n this.maxAttempts = options.maxAttempts ?? 3;\n this.fallbackDelay = options.fallbackDelay ?? 5000;\n }\n\n /**\n * Set the Retry-After value from response headers\n * Call this before onRetry when you have a Retry-After header\n */\n setRetryAfter(seconds: number): void {\n this.lastRetryAfter = seconds * 1000;\n }\n\n onRetry(error: UPPError, attempt: number): number | null {\n if (attempt > this.maxAttempts) {\n return null;\n }\n\n if (error.code !== 'RATE_LIMITED') {\n return null;\n }\n\n const delay = this.lastRetryAfter ?? this.fallbackDelay;\n this.lastRetryAfter = undefined;\n return delay;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types/errors.ts","../src/http/keys.ts","../src/http/errors.ts","../src/http/fetch.ts"],"sourcesContent":["/**\n * UPP Error Codes\n * Normalized error codes for cross-provider error handling\n */\nexport type ErrorCode =\n | 'AUTHENTICATION_FAILED'\n | 'RATE_LIMITED'\n | 'CONTEXT_LENGTH_EXCEEDED'\n | 'MODEL_NOT_FOUND'\n | 'INVALID_REQUEST'\n | 'INVALID_RESPONSE'\n | 'CONTENT_FILTERED'\n | 'QUOTA_EXCEEDED'\n | 'PROVIDER_ERROR'\n | 'NETWORK_ERROR'\n | 'TIMEOUT'\n | 'CANCELLED';\n\n/**\n * Modality types supported by UPP\n */\nexport type Modality = 'llm' | 'embedding' | 'image' | 'audio' | 'video';\n\n/**\n * Unified Provider Protocol Error\n * All provider errors are normalized to this type\n */\nexport class UPPError extends Error {\n readonly code: ErrorCode;\n readonly provider: string;\n readonly modality: Modality;\n readonly statusCode?: number;\n override readonly cause?: Error;\n\n override readonly name = 'UPPError';\n\n constructor(\n message: string,\n code: ErrorCode,\n provider: string,\n modality: Modality,\n statusCode?: number,\n cause?: Error\n ) {\n super(message);\n this.code = code;\n this.provider = provider;\n this.modality = modality;\n this.statusCode = statusCode;\n this.cause = cause;\n\n // Maintain proper stack trace in V8 environments\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, UPPError);\n }\n }\n\n /**\n * Create a string representation of the error\n */\n override toString(): string {\n let str = `UPPError [${this.code}]: ${this.message}`;\n str += ` (provider: ${this.provider}, modality: ${this.modality}`;\n if (this.statusCode) {\n str += `, status: ${this.statusCode}`;\n }\n str += ')';\n return str;\n }\n\n /**\n * Convert to JSON for serialization\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n provider: this.provider,\n modality: this.modality,\n statusCode: this.statusCode,\n cause: this.cause?.message,\n };\n }\n}\n","import type { ProviderConfig, KeyStrategy } from '../types/provider.ts';\nimport { UPPError, type Modality } from '../types/errors.ts';\n\n/**\n * Round-robin through a list of API keys\n */\nexport class RoundRobinKeys implements KeyStrategy {\n private keys: string[];\n private index = 0;\n\n constructor(keys: string[]) {\n if (keys.length === 0) {\n throw new Error('RoundRobinKeys requires at least one key');\n }\n this.keys = keys;\n }\n\n getKey(): string {\n const key = this.keys[this.index]!;\n this.index = (this.index + 1) % this.keys.length;\n return key;\n }\n}\n\n/**\n * Weighted random selection of API keys\n */\nexport class WeightedKeys implements KeyStrategy {\n private entries: Array<{ key: string; weight: number }>;\n private totalWeight: number;\n\n constructor(keys: Array<{ key: string; weight: number }>) {\n if (keys.length === 0) {\n throw new Error('WeightedKeys requires at least one key');\n }\n this.entries = keys;\n this.totalWeight = keys.reduce((sum, k) => sum + k.weight, 0);\n }\n\n getKey(): string {\n const random = Math.random() * this.totalWeight;\n let cumulative = 0;\n\n for (const entry of this.entries) {\n cumulative += entry.weight;\n if (random <= cumulative) {\n return entry.key;\n }\n }\n\n // Fallback to last key (shouldn't happen)\n return this.entries[this.entries.length - 1]!.key;\n }\n}\n\n/**\n * Dynamic key selection based on custom logic\n */\nexport class DynamicKey implements KeyStrategy {\n private selector: () => string | Promise<string>;\n\n constructor(selector: () => string | Promise<string>) {\n this.selector = selector;\n }\n\n async getKey(): Promise<string> {\n return this.selector();\n }\n}\n\n/**\n * Check if a value is a KeyStrategy\n */\nfunction isKeyStrategy(value: unknown): value is KeyStrategy {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'getKey' in value &&\n typeof (value as KeyStrategy).getKey === 'function'\n );\n}\n\n/**\n * Resolve API key from ProviderConfig\n * Falls back to environment variable if provided and config.apiKey is not set\n * Throws UPPError with AUTHENTICATION_FAILED if no key is available\n *\n * @param config - Provider configuration\n * @param envVar - Environment variable name to check as fallback\n * @param provider - Provider name for error messages\n * @param modality - Modality for error messages\n */\nexport async function resolveApiKey(\n config: ProviderConfig,\n envVar?: string,\n provider = 'unknown',\n modality: Modality = 'llm'\n): Promise<string> {\n const { apiKey } = config;\n\n // If apiKey is provided in config\n if (apiKey !== undefined) {\n // String\n if (typeof apiKey === 'string') {\n return apiKey;\n }\n\n // Function\n if (typeof apiKey === 'function') {\n return apiKey();\n }\n\n // KeyStrategy\n if (isKeyStrategy(apiKey)) {\n return apiKey.getKey();\n }\n }\n\n // Try environment variable\n if (envVar) {\n const envValue = process.env[envVar];\n if (envValue) {\n return envValue;\n }\n }\n\n // No key found\n throw new UPPError(\n envVar\n ? `API key not found. Set ${envVar} environment variable or provide apiKey in config.`\n : 'API key not found. Provide apiKey in config.',\n 'AUTHENTICATION_FAILED',\n provider,\n modality\n );\n}\n","import { UPPError, type ErrorCode, type Modality } from '../types/errors.ts';\n\n/**\n * Map HTTP status codes to UPP error codes\n */\nexport function statusToErrorCode(status: number): ErrorCode {\n switch (status) {\n case 400:\n return 'INVALID_REQUEST';\n case 401:\n case 403:\n return 'AUTHENTICATION_FAILED';\n case 404:\n return 'MODEL_NOT_FOUND';\n case 408:\n return 'TIMEOUT';\n case 413:\n return 'CONTEXT_LENGTH_EXCEEDED';\n case 429:\n return 'RATE_LIMITED';\n case 500:\n case 502:\n case 503:\n case 504:\n return 'PROVIDER_ERROR';\n default:\n return 'PROVIDER_ERROR';\n }\n}\n\n/**\n * Normalize HTTP error responses to UPPError\n * Maps HTTP status codes to appropriate ErrorCode values\n * Extracts error message from response body when available\n */\nexport async function normalizeHttpError(\n response: Response,\n provider: string,\n modality: Modality\n): Promise<UPPError> {\n const code = statusToErrorCode(response.status);\n let message = `HTTP ${response.status}: ${response.statusText}`;\n\n try {\n const body = await response.text();\n if (body) {\n try {\n const json = JSON.parse(body);\n // Common error message locations across providers\n const extractedMessage =\n json.error?.message ||\n json.message ||\n json.error?.error?.message ||\n json.detail;\n\n if (extractedMessage) {\n message = extractedMessage;\n }\n } catch {\n // Body is not JSON, use raw text if short\n if (body.length < 200) {\n message = body;\n }\n }\n }\n } catch {\n // Failed to read body, use default message\n }\n\n return new UPPError(message, code, provider, modality, response.status);\n}\n\n/**\n * Create a network error\n */\nexport function networkError(\n error: Error,\n provider: string,\n modality: Modality\n): UPPError {\n return new UPPError(\n `Network error: ${error.message}`,\n 'NETWORK_ERROR',\n provider,\n modality,\n undefined,\n error\n );\n}\n\n/**\n * Create a timeout error\n */\nexport function timeoutError(\n timeout: number,\n provider: string,\n modality: Modality\n): UPPError {\n return new UPPError(\n `Request timed out after ${timeout}ms`,\n 'TIMEOUT',\n provider,\n modality\n );\n}\n\n/**\n * Create a cancelled error\n */\nexport function cancelledError(provider: string, modality: Modality): UPPError {\n return new UPPError('Request was cancelled', 'CANCELLED', provider, modality);\n}\n","import type { ProviderConfig } from '../types/provider.ts';\nimport type { Modality } from '../types/errors.ts';\nimport { UPPError } from '../types/errors.ts';\nimport {\n normalizeHttpError,\n networkError,\n timeoutError,\n cancelledError,\n} from './errors.ts';\n\n/**\n * Default timeout in milliseconds\n */\nconst DEFAULT_TIMEOUT = 120000; // 2 minutes\n\n/**\n * Execute fetch with retry, timeout, and error normalization\n *\n * @param url - Request URL\n * @param init - Fetch init options\n * @param config - Provider config\n * @param provider - Provider name for error messages\n * @param modality - Modality for error messages\n */\nexport async function doFetch(\n url: string,\n init: RequestInit,\n config: ProviderConfig,\n provider: string,\n modality: Modality\n): Promise<Response> {\n const fetchFn = config.fetch ?? fetch;\n const timeout = config.timeout ?? DEFAULT_TIMEOUT;\n const strategy = config.retryStrategy;\n\n // Pre-request delay (e.g., token bucket)\n if (strategy?.beforeRequest) {\n const delay = await strategy.beforeRequest();\n if (delay > 0) {\n await sleep(delay);\n }\n }\n\n let lastError: UPPError | undefined;\n let attempt = 0;\n\n while (true) {\n attempt++;\n\n try {\n const response = await fetchWithTimeout(\n fetchFn,\n url,\n init,\n timeout,\n provider,\n modality\n );\n\n // Check for HTTP errors\n if (!response.ok) {\n const error = await normalizeHttpError(response, provider, modality);\n\n // Check for Retry-After header\n const retryAfter = response.headers.get('Retry-After');\n if (retryAfter && strategy) {\n const seconds = parseInt(retryAfter, 10);\n if (!isNaN(seconds) && 'setRetryAfter' in strategy) {\n (strategy as { setRetryAfter: (s: number) => void }).setRetryAfter(\n seconds\n );\n }\n }\n\n // Try to retry\n if (strategy) {\n const delay = await strategy.onRetry(error, attempt);\n if (delay !== null) {\n await sleep(delay);\n lastError = error;\n continue;\n }\n }\n\n throw error;\n }\n\n // Success - reset strategy state\n strategy?.reset?.();\n\n return response;\n } catch (error) {\n // Already a UPPError, handle retry\n if (error instanceof UPPError) {\n if (strategy) {\n const delay = await strategy.onRetry(error, attempt);\n if (delay !== null) {\n await sleep(delay);\n lastError = error;\n continue;\n }\n }\n throw error;\n }\n\n // Network error\n const uppError = networkError(error as Error, provider, modality);\n\n if (strategy) {\n const delay = await strategy.onRetry(uppError, attempt);\n if (delay !== null) {\n await sleep(delay);\n lastError = uppError;\n continue;\n }\n }\n\n throw uppError;\n }\n }\n}\n\n/**\n * Fetch with timeout\n */\nasync function fetchWithTimeout(\n fetchFn: typeof fetch,\n url: string,\n init: RequestInit,\n timeout: number,\n provider: string,\n modality: Modality\n): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n // Merge abort signals if one was provided\n const existingSignal = init.signal;\n if (existingSignal) {\n existingSignal.addEventListener('abort', () => controller.abort());\n }\n\n try {\n const response = await fetchFn(url, {\n ...init,\n signal: controller.signal,\n });\n return response;\n } catch (error) {\n if ((error as Error).name === 'AbortError') {\n // Check if it was the user's signal or our timeout\n if (existingSignal?.aborted) {\n throw cancelledError(provider, modality);\n }\n throw timeoutError(timeout, provider, modality);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\n/**\n * Sleep for a given number of milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Streaming fetch - returns response without checking ok status\n * Used when we need to read the stream for SSE\n */\nexport async function doStreamFetch(\n url: string,\n init: RequestInit,\n config: ProviderConfig,\n provider: string,\n modality: Modality\n): Promise<Response> {\n const fetchFn = config.fetch ?? fetch;\n const timeout = config.timeout ?? DEFAULT_TIMEOUT;\n const strategy = config.retryStrategy;\n\n // Pre-request delay\n if (strategy?.beforeRequest) {\n const delay = await strategy.beforeRequest();\n if (delay > 0) {\n await sleep(delay);\n }\n }\n\n // For streaming, we don't retry - the consumer handles errors\n try {\n const response = await fetchWithTimeout(\n fetchFn,\n url,\n init,\n timeout,\n provider,\n modality\n );\n return response;\n } catch (error) {\n if (error instanceof UPPError) {\n throw error;\n }\n throw networkError(error as Error, provider, modality);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/id.ts","../src/types/messages.ts"],"sourcesContent":["/**\n * Generate a unique ID\n * Uses crypto.randomUUID if available, falls back to a simple implementation\n */\nexport function generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback for environments without crypto.randomUUID\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Generate a short ID (for tool call IDs, etc.)\n */\nexport function generateShortId(prefix = ''): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n let result = prefix;\n for (let i = 0; i < 12; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n}\n","import { generateId } from '../utils/id.ts';\nimport type {\n ContentBlock,\n TextBlock,\n ImageBlock,\n AudioBlock,\n VideoBlock,\n UserContent,\n AssistantContent,\n} from './content.ts';\nimport type { ToolCall, ToolResult } from './tool.ts';\n\n/**\n * Message type discriminator\n */\nexport type MessageType = 'user' | 'assistant' | 'tool_result';\n\n/**\n * Provider-namespaced metadata\n * Each provider uses its own namespace\n */\nexport interface MessageMetadata {\n [provider: string]: Record<string, unknown> | undefined;\n}\n\n/**\n * Options for message construction\n */\nexport interface MessageOptions {\n id?: string;\n metadata?: MessageMetadata;\n}\n\n/**\n * Base message class\n * All messages inherit from this\n */\nexport abstract class Message {\n /** Unique message identifier */\n readonly id: string;\n\n /** Timestamp */\n readonly timestamp: Date;\n\n /** Provider-specific metadata, namespaced by provider */\n readonly metadata?: MessageMetadata;\n\n /** Message type discriminator */\n abstract readonly type: MessageType;\n\n /** Raw content - implemented by subclasses */\n protected abstract getContent(): ContentBlock[];\n\n constructor(options?: MessageOptions) {\n this.id = options?.id ?? generateId();\n this.timestamp = new Date();\n this.metadata = options?.metadata;\n }\n\n /**\n * Convenience accessor for text content\n * Concatenates all text blocks with '\\n\\n'\n */\n get text(): string {\n return this.getContent()\n .filter((block): block is TextBlock => block.type === 'text')\n .map((block) => block.text)\n .join('\\n\\n');\n }\n\n /**\n * Convenience accessor for image content blocks\n */\n get images(): ImageBlock[] {\n return this.getContent().filter((block): block is ImageBlock => block.type === 'image');\n }\n\n /**\n * Convenience accessor for audio content blocks\n */\n get audio(): AudioBlock[] {\n return this.getContent().filter((block): block is AudioBlock => block.type === 'audio');\n }\n\n /**\n * Convenience accessor for video content blocks\n */\n get video(): VideoBlock[] {\n return this.getContent().filter((block): block is VideoBlock => block.type === 'video');\n }\n}\n\n/**\n * User input message\n */\nexport class UserMessage extends Message {\n readonly type = 'user' as const;\n readonly content: UserContent[];\n\n /**\n * @param content - String (converted to TextBlock) or array of content blocks\n */\n constructor(content: string | UserContent[], options?: MessageOptions) {\n super(options);\n if (typeof content === 'string') {\n this.content = [{ type: 'text', text: content }];\n } else {\n this.content = content;\n }\n }\n\n protected getContent(): ContentBlock[] {\n return this.content;\n }\n}\n\n/**\n * Assistant response message\n * May contain text, media, and/or tool calls\n */\nexport class AssistantMessage extends Message {\n readonly type = 'assistant' as const;\n readonly content: AssistantContent[];\n\n /** Tool calls requested by the model (if any) */\n readonly toolCalls?: ToolCall[];\n\n /**\n * @param content - String (converted to TextBlock) or array of content blocks\n * @param toolCalls - Tool calls requested by the model\n * @param options - Message ID and metadata\n */\n constructor(\n content: string | AssistantContent[],\n toolCalls?: ToolCall[],\n options?: MessageOptions\n ) {\n super(options);\n if (typeof content === 'string') {\n this.content = [{ type: 'text', text: content }];\n } else {\n this.content = content;\n }\n this.toolCalls = toolCalls;\n }\n\n protected getContent(): ContentBlock[] {\n return this.content;\n }\n\n /** Check if this message requests tool execution */\n get hasToolCalls(): boolean {\n return this.toolCalls !== undefined && this.toolCalls.length > 0;\n }\n}\n\n/**\n * Result of tool execution (sent back to model)\n */\nexport class ToolResultMessage extends Message {\n readonly type = 'tool_result' as const;\n readonly results: ToolResult[];\n\n /**\n * @param results - Array of tool execution results\n * @param options - Message ID and metadata\n */\n constructor(results: ToolResult[], options?: MessageOptions) {\n super(options);\n this.results = results;\n }\n\n protected getContent(): ContentBlock[] {\n // Tool results don't have traditional content blocks\n // Return text representations of results\n return this.results.map((result) => ({\n type: 'text' as const,\n text:\n typeof result.result === 'string'\n ? result.result\n : JSON.stringify(result.result),\n }));\n }\n}\n\n/**\n * Type guard for UserMessage\n */\nexport function isUserMessage(msg: Message): msg is UserMessage {\n return msg.type === 'user';\n}\n\n/**\n * Type guard for AssistantMessage\n */\nexport function isAssistantMessage(msg: Message): msg is AssistantMessage {\n return msg.type === 'assistant';\n}\n\n/**\n * Type guard for ToolResultMessage\n */\nexport function isToolResultMessage(msg: Message): msg is ToolResultMessage {\n return msg.type === 'tool_result';\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/http/sse.ts"],"sourcesContent":["/**\n * Server-Sent Events (SSE) stream parser\n */\n\n/**\n * Parse a Server-Sent Events stream into JSON objects\n * Handles standard SSE format with \"data:\" prefix\n * Yields parsed JSON for each event\n * Terminates on \"[DONE]\" message (OpenAI style)\n *\n * @param body - ReadableStream from fetch response\n */\nexport async function* parseSSEStream(\n body: ReadableStream<Uint8Array>\n): AsyncGenerator<unknown, void, unknown> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n // Process any remaining data in buffer\n if (buffer.trim()) {\n const event = parseSSEEvent(buffer);\n if (event !== null && event !== undefined) {\n yield event;\n }\n }\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete events (separated by double newlines or \\r\\n\\r\\n)\n const events = buffer.split(/\\r?\\n\\r?\\n/);\n\n // Keep the last partial event in the buffer\n buffer = events.pop() ?? '';\n\n for (const eventText of events) {\n if (!eventText.trim()) continue;\n\n const event = parseSSEEvent(eventText);\n if (event === 'DONE') {\n return;\n }\n if (event !== null && event !== undefined) {\n yield event;\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Parse a single SSE event\n * Returns 'DONE' for [DONE] terminator\n * Returns null for empty or unparseable events\n * Returns parsed JSON otherwise\n */\nfunction parseSSEEvent(eventText: string): unknown | 'DONE' | null {\n const lines = eventText.split('\\n');\n let data = '';\n let eventType = '';\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n if (trimmedLine.startsWith('event:')) {\n eventType = trimmedLine.slice(6).trim();\n } else if (trimmedLine.startsWith('data:')) {\n // Append data (some providers send multi-line data)\n const lineData = trimmedLine.slice(5).trim();\n data += (data ? '\\n' : '') + lineData;\n } else if (trimmedLine.startsWith(':')) {\n // Comment line, ignore (often used for keep-alive)\n continue;\n } else if (trimmedLine.startsWith('{') || trimmedLine.startsWith('[')) {\n // Some providers (like Google) may send raw JSON without data: prefix\n data += (data ? '\\n' : '') + trimmedLine;\n }\n }\n\n if (!data) {\n return null;\n }\n\n // Check for OpenAI-style termination\n if (data === '[DONE]') {\n return 'DONE';\n }\n\n try {\n const parsed = JSON.parse(data);\n\n // If we have an event type, include it\n if (eventType) {\n return { _eventType: eventType, ...parsed };\n }\n\n return parsed;\n } catch {\n // Failed to parse JSON - could be a ping or malformed event\n return null;\n }\n}\n\n/**\n * Create a simple SSE reader that handles basic text streaming\n * For providers that just stream text deltas\n */\nexport async function* parseSimpleTextStream(\n body: ReadableStream<Uint8Array>\n): AsyncGenerator<string, void, unknown> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) break;\n\n const text = decoder.decode(value, { stream: true });\n if (text) {\n yield text;\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n"],"mappings":";AAYA,gBAAuB,eACrB,MACwC;AACxC,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AAEb,MAAI;AACF,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAE1C,UAAI,MAAM;AAER,YAAI,OAAO,KAAK,GAAG;AACjB,gBAAM,QAAQ,cAAc,MAAM;AAClC,cAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,kBAAM;AAAA,UACR;AAAA,QACF;AACA;AAAA,MACF;AAEA,gBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAGhD,YAAM,SAAS,OAAO,MAAM,YAAY;AAGxC,eAAS,OAAO,IAAI,KAAK;AAEzB,iBAAW,aAAa,QAAQ;AAC9B,YAAI,CAAC,UAAU,KAAK,EAAG;AAEvB,cAAM,QAAQ,cAAc,SAAS;AACrC,YAAI,UAAU,QAAQ;AACpB;AAAA,QACF;AACA,YAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;AAQA,SAAS,cAAc,WAA4C;AACjE,QAAM,QAAQ,UAAU,MAAM,IAAI;AAClC,MAAI,OAAO;AACX,MAAI,YAAY;AAEhB,aAAW,QAAQ,OAAO;AACxB,UAAM,cAAc,KAAK,KAAK;AAC9B,QAAI,YAAY,WAAW,QAAQ,GAAG;AACpC,kBAAY,YAAY,MAAM,CAAC,EAAE,KAAK;AAAA,IACxC,WAAW,YAAY,WAAW,OAAO,GAAG;AAE1C,YAAM,WAAW,YAAY,MAAM,CAAC,EAAE,KAAK;AAC3C,eAAS,OAAO,OAAO,MAAM;AAAA,IAC/B,WAAW,YAAY,WAAW,GAAG,GAAG;AAEtC;AAAA,IACF,WAAW,YAAY,WAAW,GAAG,KAAK,YAAY,WAAW,GAAG,GAAG;AAErE,eAAS,OAAO,OAAO,MAAM;AAAA,IAC/B;AAAA,EACF;AAEA,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAGA,MAAI,SAAS,UAAU;AACrB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,IAAI;AAG9B,QAAI,WAAW;AACb,aAAO,EAAE,YAAY,WAAW,GAAG,OAAO;AAAA,IAC5C;AAEA,WAAO;AAAA,EACT,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAMA,gBAAuB,sBACrB,MACuC;AACvC,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,IAAI,YAAY;AAEhC,MAAI;AACF,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAE1C,UAAI,KAAM;AAEV,YAAM,OAAO,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AACnD,UAAI,MAAM;AACR,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/provider.ts"],"sourcesContent":["import type {\n Provider,\n ModelReference,\n LLMHandler,\n EmbeddingHandler,\n ImageHandler,\n LLMProvider,\n EmbeddingProvider,\n ImageProvider,\n} from '../types/provider.ts';\n\n/**\n * Options for creating a provider\n */\nexport interface CreateProviderOptions {\n name: string;\n version: string;\n modalities: {\n llm?: LLMHandler;\n embedding?: EmbeddingHandler;\n image?: ImageHandler;\n };\n}\n\n/**\n * Create a provider factory function\n *\n * @typeParam TOptions - Provider-specific options type (defaults to unknown)\n * @param options - Provider configuration\n * @returns Provider function with modalities attached\n *\n * @example\n * ```ts\n * // Basic provider without options\n * const anthropic = createProvider({\n * name: 'anthropic',\n * version: '1.0.0',\n * modalities: { llm: createLLMHandler() },\n * });\n *\n * // Provider with custom options (typically needs custom factory)\n * interface MyProviderOptions { api?: 'v1' | 'v2' }\n * const myProvider = createProvider<MyProviderOptions>({\n * name: 'my-provider',\n * version: '1.0.0',\n * modalities: { llm: createLLMHandler() },\n * });\n * ```\n */\nexport function createProvider<TOptions = unknown>(\n options: CreateProviderOptions\n): Provider<TOptions> {\n // Create the base function that accepts optional provider-specific options\n const fn = function (modelId: string, _options?: TOptions): ModelReference<TOptions> {\n return { modelId, provider };\n };\n\n // Define properties, including overriding the read-only 'name' property\n Object.defineProperties(fn, {\n name: {\n value: options.name,\n writable: false,\n configurable: true,\n },\n version: {\n value: options.version,\n writable: false,\n configurable: true,\n },\n modalities: {\n value: options.modalities,\n writable: false,\n configurable: true,\n },\n });\n\n const provider = fn as Provider<TOptions>;\n\n // Inject provider reference into handlers so bind() can return\n // models with the correct provider reference (spec compliance)\n if (options.modalities.llm?._setProvider) {\n options.modalities.llm._setProvider(provider as unknown as LLMProvider);\n }\n if (options.modalities.embedding?._setProvider) {\n options.modalities.embedding._setProvider(provider as unknown as EmbeddingProvider);\n }\n if (options.modalities.image?._setProvider) {\n options.modalities.image._setProvider(provider as unknown as ImageProvider);\n }\n\n return provider;\n}\n"],"mappings":";AAiDO,SAAS,eACd,SACoB;AAEpB,QAAM,KAAK,SAAU,SAAiB,UAA+C;AACnF,WAAO,EAAE,SAAS,SAAS;AAAA,EAC7B;AAGA,SAAO,iBAAiB,IAAI;AAAA,IAC1B,MAAM;AAAA,MACJ,OAAO,QAAQ;AAAA,MACf,UAAU;AAAA,MACV,cAAc;AAAA,IAChB;AAAA,IACA,SAAS;AAAA,MACP,OAAO,QAAQ;AAAA,MACf,UAAU;AAAA,MACV,cAAc;AAAA,IAChB;AAAA,IACA,YAAY;AAAA,MACV,OAAO,QAAQ;AAAA,MACf,UAAU;AAAA,MACV,cAAc;AAAA,IAChB;AAAA,EACF,CAAC;AAED,QAAM,WAAW;AAIjB,MAAI,QAAQ,WAAW,KAAK,cAAc;AACxC,YAAQ,WAAW,IAAI,aAAa,QAAkC;AAAA,EACxE;AACA,MAAI,QAAQ,WAAW,WAAW,cAAc;AAC9C,YAAQ,WAAW,UAAU,aAAa,QAAwC;AAAA,EACpF;AACA,MAAI,QAAQ,WAAW,OAAO,cAAc;AAC1C,YAAQ,WAAW,MAAM,aAAa,QAAoC;AAAA,EAC5E;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* UPP Error Codes
|
|
3
|
-
* Normalized error codes for cross-provider error handling
|
|
4
|
-
*/
|
|
5
|
-
type ErrorCode = 'AUTHENTICATION_FAILED' | 'RATE_LIMITED' | 'CONTEXT_LENGTH_EXCEEDED' | 'MODEL_NOT_FOUND' | 'INVALID_REQUEST' | 'INVALID_RESPONSE' | 'CONTENT_FILTERED' | 'QUOTA_EXCEEDED' | 'PROVIDER_ERROR' | 'NETWORK_ERROR' | 'TIMEOUT' | 'CANCELLED';
|
|
6
|
-
/**
|
|
7
|
-
* Modality types supported by UPP
|
|
8
|
-
*/
|
|
9
|
-
type Modality = 'llm' | 'embedding' | 'image' | 'audio' | 'video';
|
|
10
|
-
/**
|
|
11
|
-
* Unified Provider Protocol Error
|
|
12
|
-
* All provider errors are normalized to this type
|
|
13
|
-
*/
|
|
14
|
-
declare class UPPError extends Error {
|
|
15
|
-
readonly code: ErrorCode;
|
|
16
|
-
readonly provider: string;
|
|
17
|
-
readonly modality: Modality;
|
|
18
|
-
readonly statusCode?: number;
|
|
19
|
-
readonly cause?: Error;
|
|
20
|
-
readonly name = "UPPError";
|
|
21
|
-
constructor(message: string, code: ErrorCode, provider: string, modality: Modality, statusCode?: number, cause?: Error);
|
|
22
|
-
/**
|
|
23
|
-
* Create a string representation of the error
|
|
24
|
-
*/
|
|
25
|
-
toString(): string;
|
|
26
|
-
/**
|
|
27
|
-
* Convert to JSON for serialization
|
|
28
|
-
*/
|
|
29
|
-
toJSON(): Record<string, unknown>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* API key strategy interface for managing multiple keys
|
|
34
|
-
*/
|
|
35
|
-
interface KeyStrategy {
|
|
36
|
-
/** Get the next API key to use */
|
|
37
|
-
getKey(): string | Promise<string>;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Retry strategy interface
|
|
41
|
-
*/
|
|
42
|
-
interface RetryStrategy {
|
|
43
|
-
/**
|
|
44
|
-
* Called when a request fails with a retryable error.
|
|
45
|
-
* @param error - The error that occurred
|
|
46
|
-
* @param attempt - The attempt number (1 = first retry)
|
|
47
|
-
* @returns Delay in ms before retrying, or null to stop retrying
|
|
48
|
-
*/
|
|
49
|
-
onRetry(error: UPPError, attempt: number): number | null | Promise<number | null>;
|
|
50
|
-
/**
|
|
51
|
-
* Called before each request. Can be used to implement pre-emptive rate limiting.
|
|
52
|
-
* Returns delay in ms to wait before making the request, or 0 to proceed immediately.
|
|
53
|
-
*/
|
|
54
|
-
beforeRequest?(): number | Promise<number>;
|
|
55
|
-
/**
|
|
56
|
-
* Reset the strategy state (e.g., after a successful request)
|
|
57
|
-
*/
|
|
58
|
-
reset?(): void;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Provider configuration for infrastructure/connection settings
|
|
62
|
-
*/
|
|
63
|
-
interface ProviderConfig {
|
|
64
|
-
/**
|
|
65
|
-
* API key - string, async function, or key strategy
|
|
66
|
-
* @example 'sk-xxx'
|
|
67
|
-
* @example () => fetchKeyFromVault()
|
|
68
|
-
* @example new RoundRobinKeys(['sk-1', 'sk-2'])
|
|
69
|
-
*/
|
|
70
|
-
apiKey?: string | (() => string | Promise<string>) | KeyStrategy;
|
|
71
|
-
/** Override the base API URL (for proxies, local models) */
|
|
72
|
-
baseUrl?: string;
|
|
73
|
-
/** Request timeout in milliseconds */
|
|
74
|
-
timeout?: number;
|
|
75
|
-
/** Custom fetch implementation (for logging, caching, custom TLS) */
|
|
76
|
-
fetch?: typeof fetch;
|
|
77
|
-
/** API version override */
|
|
78
|
-
apiVersion?: string;
|
|
79
|
-
/** Retry strategy for handling failures and rate limits */
|
|
80
|
-
retryStrategy?: RetryStrategy;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* A reference to a model, created by a provider factory
|
|
84
|
-
*
|
|
85
|
-
* @typeParam TOptions - Provider-specific options type
|
|
86
|
-
*/
|
|
87
|
-
interface ModelReference<TOptions = unknown> {
|
|
88
|
-
/** The model identifier */
|
|
89
|
-
readonly modelId: string;
|
|
90
|
-
/** The provider that created this reference */
|
|
91
|
-
readonly provider: Provider<TOptions>;
|
|
92
|
-
}
|
|
93
|
-
interface LLMHandler<TParams = any> {
|
|
94
|
-
/** Bind model ID to create executable model */
|
|
95
|
-
bind(modelId: string): BoundLLMModel<TParams>;
|
|
96
|
-
/**
|
|
97
|
-
* Internal: Set the parent provider reference.
|
|
98
|
-
* Called by createProvider() after the provider is constructed.
|
|
99
|
-
* This allows bind() to return models with the correct provider reference.
|
|
100
|
-
* @internal
|
|
101
|
-
*/
|
|
102
|
-
_setProvider?(provider: LLMProvider<TParams>): void;
|
|
103
|
-
}
|
|
104
|
-
interface EmbeddingHandler<TParams = any> {
|
|
105
|
-
/** Supported input types */
|
|
106
|
-
readonly supportedInputs: ('text' | 'image')[];
|
|
107
|
-
/** Bind model ID to create executable model */
|
|
108
|
-
bind(modelId: string): BoundEmbeddingModel<TParams>;
|
|
109
|
-
/**
|
|
110
|
-
* Internal: Set the parent provider reference.
|
|
111
|
-
* @internal
|
|
112
|
-
*/
|
|
113
|
-
_setProvider?(provider: EmbeddingProvider<TParams>): void;
|
|
114
|
-
}
|
|
115
|
-
interface ImageHandler<TParams = any> {
|
|
116
|
-
/** Bind model ID to create executable model */
|
|
117
|
-
bind(modelId: string): BoundImageModel<TParams>;
|
|
118
|
-
/**
|
|
119
|
-
* Internal: Set the parent provider reference.
|
|
120
|
-
* @internal
|
|
121
|
-
*/
|
|
122
|
-
_setProvider?(provider: ImageProvider<TParams>): void;
|
|
123
|
-
}
|
|
124
|
-
interface BoundLLMModel<TParams = any> {
|
|
125
|
-
readonly modelId: string;
|
|
126
|
-
readonly provider: LLMProvider<TParams>;
|
|
127
|
-
}
|
|
128
|
-
interface BoundEmbeddingModel<TParams = any> {
|
|
129
|
-
readonly modelId: string;
|
|
130
|
-
readonly provider: EmbeddingProvider<TParams>;
|
|
131
|
-
readonly maxBatchSize: number;
|
|
132
|
-
readonly maxInputLength: number;
|
|
133
|
-
readonly dimensions: number;
|
|
134
|
-
}
|
|
135
|
-
interface BoundImageModel<TParams = any> {
|
|
136
|
-
readonly modelId: string;
|
|
137
|
-
readonly provider: ImageProvider<TParams>;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* A provider factory function with metadata and modality handlers.
|
|
141
|
-
*
|
|
142
|
-
* @typeParam TOptions - Provider-specific options passed to the factory function
|
|
143
|
-
*/
|
|
144
|
-
interface Provider<TOptions = unknown> {
|
|
145
|
-
/** Create a model reference, optionally with provider-specific options */
|
|
146
|
-
(modelId: string, options?: TOptions): ModelReference<TOptions>;
|
|
147
|
-
/** Provider name */
|
|
148
|
-
readonly name: string;
|
|
149
|
-
/** Provider version */
|
|
150
|
-
readonly version: string;
|
|
151
|
-
/** Supported modalities */
|
|
152
|
-
readonly modalities: {
|
|
153
|
-
llm?: LLMHandler;
|
|
154
|
-
embedding?: EmbeddingHandler;
|
|
155
|
-
image?: ImageHandler;
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Provider with LLM modality
|
|
160
|
-
*
|
|
161
|
-
* @typeParam TParams - Model-specific parameters type
|
|
162
|
-
* @typeParam TOptions - Provider-specific options type
|
|
163
|
-
*/
|
|
164
|
-
type LLMProvider<TParams = any, TOptions = unknown> = Provider<TOptions> & {
|
|
165
|
-
readonly modalities: {
|
|
166
|
-
llm: LLMHandler<TParams>;
|
|
167
|
-
};
|
|
168
|
-
};
|
|
169
|
-
/**
|
|
170
|
-
* Provider with Embedding modality
|
|
171
|
-
*
|
|
172
|
-
* @typeParam TParams - Model-specific parameters type
|
|
173
|
-
* @typeParam TOptions - Provider-specific options type
|
|
174
|
-
*/
|
|
175
|
-
type EmbeddingProvider<TParams = any, TOptions = unknown> = Provider<TOptions> & {
|
|
176
|
-
readonly modalities: {
|
|
177
|
-
embedding: EmbeddingHandler<TParams>;
|
|
178
|
-
};
|
|
179
|
-
};
|
|
180
|
-
/**
|
|
181
|
-
* Provider with Image modality
|
|
182
|
-
*
|
|
183
|
-
* @typeParam TParams - Model-specific parameters type
|
|
184
|
-
* @typeParam TOptions - Provider-specific options type
|
|
185
|
-
*/
|
|
186
|
-
type ImageProvider<TParams = any, TOptions = unknown> = Provider<TOptions> & {
|
|
187
|
-
readonly modalities: {
|
|
188
|
-
image: ImageHandler<TParams>;
|
|
189
|
-
};
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
export { type BoundEmbeddingModel as B, type EmbeddingHandler as E, type ImageHandler as I, type KeyStrategy as K, type LLMProvider as L, type ModelReference as M, type ProviderConfig as P, type RetryStrategy as R, UPPError as U, type LLMHandler as a, type Provider as b, type ErrorCode as c, type Modality as d, type EmbeddingProvider as e, type ImageProvider as f, type BoundImageModel as g };
|
package/dist/retry-I2661_rv.d.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { K as KeyStrategy, P as ProviderConfig, d as Modality, R as RetryStrategy, U as UPPError } from './provider-CUJWjgNl.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Round-robin through a list of API keys
|
|
5
|
-
*/
|
|
6
|
-
declare class RoundRobinKeys implements KeyStrategy {
|
|
7
|
-
private keys;
|
|
8
|
-
private index;
|
|
9
|
-
constructor(keys: string[]);
|
|
10
|
-
getKey(): string;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Weighted random selection of API keys
|
|
14
|
-
*/
|
|
15
|
-
declare class WeightedKeys implements KeyStrategy {
|
|
16
|
-
private entries;
|
|
17
|
-
private totalWeight;
|
|
18
|
-
constructor(keys: Array<{
|
|
19
|
-
key: string;
|
|
20
|
-
weight: number;
|
|
21
|
-
}>);
|
|
22
|
-
getKey(): string;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Dynamic key selection based on custom logic
|
|
26
|
-
*/
|
|
27
|
-
declare class DynamicKey implements KeyStrategy {
|
|
28
|
-
private selector;
|
|
29
|
-
constructor(selector: () => string | Promise<string>);
|
|
30
|
-
getKey(): Promise<string>;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Resolve API key from ProviderConfig
|
|
34
|
-
* Falls back to environment variable if provided and config.apiKey is not set
|
|
35
|
-
* Throws UPPError with AUTHENTICATION_FAILED if no key is available
|
|
36
|
-
*
|
|
37
|
-
* @param config - Provider configuration
|
|
38
|
-
* @param envVar - Environment variable name to check as fallback
|
|
39
|
-
* @param provider - Provider name for error messages
|
|
40
|
-
* @param modality - Modality for error messages
|
|
41
|
-
*/
|
|
42
|
-
declare function resolveApiKey(config: ProviderConfig, envVar?: string, provider?: string, modality?: Modality): Promise<string>;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Exponential backoff retry strategy
|
|
46
|
-
*/
|
|
47
|
-
declare class ExponentialBackoff implements RetryStrategy {
|
|
48
|
-
private maxAttempts;
|
|
49
|
-
private baseDelay;
|
|
50
|
-
private maxDelay;
|
|
51
|
-
private jitter;
|
|
52
|
-
constructor(options?: {
|
|
53
|
-
maxAttempts?: number;
|
|
54
|
-
baseDelay?: number;
|
|
55
|
-
maxDelay?: number;
|
|
56
|
-
jitter?: boolean;
|
|
57
|
-
});
|
|
58
|
-
onRetry(error: UPPError, attempt: number): number | null;
|
|
59
|
-
private isRetryable;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Linear backoff retry strategy
|
|
63
|
-
*/
|
|
64
|
-
declare class LinearBackoff implements RetryStrategy {
|
|
65
|
-
private maxAttempts;
|
|
66
|
-
private delay;
|
|
67
|
-
constructor(options?: {
|
|
68
|
-
maxAttempts?: number;
|
|
69
|
-
delay?: number;
|
|
70
|
-
});
|
|
71
|
-
onRetry(error: UPPError, attempt: number): number | null;
|
|
72
|
-
private isRetryable;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* No retry strategy - fail immediately
|
|
76
|
-
*/
|
|
77
|
-
declare class NoRetry implements RetryStrategy {
|
|
78
|
-
onRetry(): null;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Token bucket rate limiter with retry
|
|
82
|
-
*/
|
|
83
|
-
declare class TokenBucket implements RetryStrategy {
|
|
84
|
-
private tokens;
|
|
85
|
-
private maxTokens;
|
|
86
|
-
private refillRate;
|
|
87
|
-
private lastRefill;
|
|
88
|
-
private maxAttempts;
|
|
89
|
-
constructor(options?: {
|
|
90
|
-
maxTokens?: number;
|
|
91
|
-
refillRate?: number;
|
|
92
|
-
maxAttempts?: number;
|
|
93
|
-
});
|
|
94
|
-
beforeRequest(): number;
|
|
95
|
-
onRetry(error: UPPError, attempt: number): number | null;
|
|
96
|
-
reset(): void;
|
|
97
|
-
private refill;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Retry strategy that respects Retry-After headers
|
|
101
|
-
*/
|
|
102
|
-
declare class RetryAfterStrategy implements RetryStrategy {
|
|
103
|
-
private maxAttempts;
|
|
104
|
-
private fallbackDelay;
|
|
105
|
-
private lastRetryAfter?;
|
|
106
|
-
constructor(options?: {
|
|
107
|
-
maxAttempts?: number;
|
|
108
|
-
fallbackDelay?: number;
|
|
109
|
-
});
|
|
110
|
-
/**
|
|
111
|
-
* Set the Retry-After value from response headers
|
|
112
|
-
* Call this before onRetry when you have a Retry-After header
|
|
113
|
-
*/
|
|
114
|
-
setRetryAfter(seconds: number): void;
|
|
115
|
-
onRetry(error: UPPError, attempt: number): number | null;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export { DynamicKey as D, ExponentialBackoff as E, LinearBackoff as L, NoRetry as N, RoundRobinKeys as R, TokenBucket as T, WeightedKeys as W, RetryAfterStrategy as a, resolveApiKey as r };
|
package/src/anthropic/index.ts
DELETED