@odla-ai/ai 0.2.1 → 0.3.0
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/LICENSE +21 -0
- package/README.md +68 -11
- package/dist/{anthropic-JXDXR7O7.js → anthropic-2NPMHJZT.js} +67 -51
- package/dist/anthropic-2NPMHJZT.js.map +1 -0
- package/dist/chunk-OX4TA4ZH.js +16 -0
- package/dist/chunk-OX4TA4ZH.js.map +1 -0
- package/dist/{chunk-LANGYP65.js → chunk-PXXCN2EU.js} +65 -46
- package/dist/chunk-PXXCN2EU.js.map +1 -0
- package/dist/chunk-U7F6VJCV.js +9 -0
- package/dist/chunk-U7F6VJCV.js.map +1 -0
- package/dist/{google-3TFOFIQO.js → google-3XV2VWVB.js} +50 -31
- package/dist/google-3XV2VWVB.js.map +1 -0
- package/dist/index.cjs +867 -132
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +194 -74
- package/dist/index.d.ts +194 -74
- package/dist/index.js +578 -57
- package/dist/index.js.map +1 -1
- package/dist/{openai-XZRXMKCC.js → openai-NTQCF577.js} +54 -36
- package/dist/openai-NTQCF577.js.map +1 -0
- package/llms.txt +35 -12
- package/package.json +12 -5
- package/dist/anthropic-JXDXR7O7.js.map +0 -1
- package/dist/chunk-LANGYP65.js.map +0 -1
- package/dist/google-3TFOFIQO.js.map +0 -1
- package/dist/openai-XZRXMKCC.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cory Ondrejka
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# @odla-ai/ai
|
|
2
2
|
|
|
3
|
+
> ⚠️ **Early access — pre-1.0.** Agents work from bounded runbooks; humans
|
|
4
|
+
> approve credentials, production changes, releases, and merges. APIs and exact
|
|
5
|
+
> package availability can change. Review the documented guarantees and
|
|
6
|
+
> limitations; this software is MIT-licensed and provided without warranty.
|
|
7
|
+
|
|
3
8
|
One general-purpose interface for AI inference across **Anthropic (Claude)**,
|
|
4
9
|
**OpenAI (GPT)**, and **Google (Gemini)** — text, image, and audio — plus a
|
|
5
10
|
tool-use **agent engine** and an **eval harness**. It's the place every odla app
|
|
@@ -13,8 +18,9 @@ reaches for when it needs AI.
|
|
|
13
18
|
- **Capability-checked.** Every request is validated against the model before
|
|
14
19
|
dispatch, so "audio to Claude" fails fast with a clear error instead of an
|
|
15
20
|
opaque provider 400.
|
|
16
|
-
- **
|
|
17
|
-
lazy
|
|
21
|
+
- **Server runtimes.** Node 20+ and Cloudflare Workers. Provider adapters are
|
|
22
|
+
runtime-lazy, but all three provider SDKs are package dependencies. Do not put
|
|
23
|
+
long-lived provider keys in browser code; use your own authenticated proxy.
|
|
18
24
|
|
|
19
25
|
```bash
|
|
20
26
|
npm install @odla-ai/ai
|
|
@@ -72,9 +78,17 @@ const { value } = await ai.extract<{ sentiment: "positive" | "negative" | "neutr
|
|
|
72
78
|
},
|
|
73
79
|
},
|
|
74
80
|
});
|
|
75
|
-
// value.sentiment === "positive"
|
|
81
|
+
// value.sentiment === "positive" (parsed and validated before it is returned)
|
|
76
82
|
```
|
|
77
83
|
|
|
84
|
+
`extract` and local agent tools validate provider arguments before returning or
|
|
85
|
+
executing them. The dependency-free validator supports the common tool-schema
|
|
86
|
+
subset: local `$ref`/`$defs`, `type`, `enum`, `const`, composition, object
|
|
87
|
+
properties/required/additional properties, arrays, and string/number constraints.
|
|
88
|
+
Unknown or unsupported schema keywords outside that documented subset fail
|
|
89
|
+
closed. `extract()` throws `ToolInputError`; local agent tools return an error
|
|
90
|
+
`tool_result` and their handlers do not execute.
|
|
91
|
+
|
|
78
92
|
### Web search
|
|
79
93
|
|
|
80
94
|
```ts
|
|
@@ -141,6 +155,28 @@ console.log(run.toolCalls); // [{ toolUse, output }]
|
|
|
141
155
|
console.log(run.usage); // accumulated across turns
|
|
142
156
|
```
|
|
143
157
|
|
|
158
|
+
Provider calls and tool handlers receive a combined cancellation signal. Runs
|
|
159
|
+
can also stop before additional effects when a run-wide budget is exhausted:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
const run = await runAgent(ai, calculator, {
|
|
163
|
+
input: "Reconcile these records",
|
|
164
|
+
signal: request.signal,
|
|
165
|
+
deadline: Date.now() + 30_000,
|
|
166
|
+
budget: { maxInputTokens: 20_000, maxOutputTokens: 4_000, maxToolCalls: 8 },
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Token limits are post-turn ceilings because provider input usage is known only
|
|
171
|
+
after a response. `maxInputTokens` and `maxTotalTokens` therefore cannot
|
|
172
|
+
tokenizer-bound the first prompt; they stop later turns and tool effects once
|
|
173
|
+
reported usage reaches the ceiling. `maxOutputTokens` and the remaining total
|
|
174
|
+
budget cap each request's `maxTokens` before dispatch. Limits must be integers
|
|
175
|
+
(`maxToolCalls` may be zero; token limits must be positive). When a limit blocks
|
|
176
|
+
tools, the loop records a matching error `tool_result` for every requested tool
|
|
177
|
+
before persisting memory, so retries never inherit an unmatched effect request.
|
|
178
|
+
`stoppedReason` is `"budget_exhausted"` when a limit prevents further work.
|
|
179
|
+
|
|
144
180
|
Tools can declare taint constraints (`outputTaint` / `acceptsTaint`) for a
|
|
145
181
|
lightweight CaMeL-style prompt-injection gate, and personas can carry a pluggable
|
|
146
182
|
`MemoryScope`.
|
|
@@ -224,20 +260,23 @@ The agent handshake (an agent never takes a platform secret):
|
|
|
224
260
|
import { requestToken, init as odlaInit } from "@odla-ai/db";
|
|
225
261
|
import { provisionAgentApp, odlaDbKeyResolver, OdlaDbMemory, persistRun, runAgent, init } from "@odla-ai/ai";
|
|
226
262
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
263
|
+
const ODLA_PLATFORM = "https://odla.ai";
|
|
264
|
+
const ODLA_DB_URL = "https://db.odla.ai";
|
|
265
|
+
|
|
266
|
+
// 1. Device authorization — the human approves a short code at odla.ai;
|
|
267
|
+
// the agent receives a scoped, revocable platform token.
|
|
268
|
+
const { token } = await requestToken({ endpoint: ODLA_PLATFORM, onCode: ({ userCode }) => console.log(userCode) });
|
|
230
269
|
|
|
231
270
|
// 2. Provision: create app, mint an app key, push the agent schema, and store the
|
|
232
271
|
// user's BYO provider keys as odla-db secrets (encrypted at rest).
|
|
233
272
|
const { appId, appKey } = await provisionAgentApp({
|
|
234
|
-
endpoint:
|
|
273
|
+
endpoint: ODLA_PLATFORM,
|
|
235
274
|
token, // operator/dev token — needed to WRITE secrets
|
|
236
275
|
providerKeys: { openai: OPENAI_KEY, anthropic: ANTHROPIC_KEY },
|
|
237
276
|
});
|
|
238
277
|
|
|
239
278
|
// 3. Runtime: read keys from secrets with the app key, persist memory + run traces.
|
|
240
|
-
const db = odlaInit({ appId, adminToken: appKey, endpoint:
|
|
279
|
+
const db = odlaInit({ appId, adminToken: appKey, endpoint: ODLA_DB_URL });
|
|
241
280
|
const ai = init({ resolveKey: odlaDbKeyResolver(db) }); // keys come from odla-db secrets
|
|
242
281
|
|
|
243
282
|
const persona = { name: "assistant", model: "gpt-5", memory: new OdlaDbMemory({ db, sessionId: "user-42" }) };
|
|
@@ -274,11 +313,28 @@ const { ai, provider, model } = await initFromPlatform({
|
|
|
274
313
|
|
|
275
314
|
The config comes from the anonymous `public-config` endpoint and is cached
|
|
276
315
|
(~60s by default), so switching provider or model in Studio takes effect
|
|
277
|
-
without a redeploy
|
|
278
|
-
|
|
316
|
+
without a redeploy. The configured provider is enforced: its facade catalog is
|
|
317
|
+
filtered to that provider, and a mismatched configured/default/call model fails
|
|
318
|
+
with `ConfigError`. If Studio has no default model, each call must name a model
|
|
319
|
+
for that provider. Tenant-bound facades are never shared globally. Provider
|
|
320
|
+
keys and SDK clients have finite 60-second in-isolate caches; rotation replaces
|
|
321
|
+
the previous credential generation rather than retaining it. Set
|
|
322
|
+
`keyResolverOptions: { ttlMs, cacheVersion }` to shorten or immediately
|
|
323
|
+
invalidate it after rotation. **Never put provider keys in an app
|
|
279
324
|
Worker's wrangler vars/secrets** — the worker's only secret is its odla-db
|
|
280
325
|
app key.
|
|
281
326
|
|
|
327
|
+
### 0.3 migration notes
|
|
328
|
+
|
|
329
|
+
- Tool/extraction JSON Schemas now fail closed. `extract()` throws
|
|
330
|
+
`ToolInputError`; `runAgent()` records an error `tool_result` and does not run
|
|
331
|
+
a local handler when its arguments do not validate.
|
|
332
|
+
- Platform calls cannot cross the provider selected in Studio.
|
|
333
|
+
- `CancelledError` (`cancelled`) and `DeadlineExceededError`
|
|
334
|
+
(`deadline_exceeded`) distinguish caller limits from provider failures.
|
|
335
|
+
- Invalid run budgets now throw `ConfigError`; budget stops persist paired tool
|
|
336
|
+
results and may therefore add one final user/tool-result turn to memory.
|
|
337
|
+
|
|
282
338
|
## Models & capabilities
|
|
283
339
|
|
|
284
340
|
The catalog maps a canonical model id → provider, native id, and capabilities.
|
|
@@ -302,7 +358,8 @@ models; extend or override it via `buildCatalog` / `init({ catalog })`.
|
|
|
302
358
|
|
|
303
359
|
Every error is an `OdlaAIError` subclass carrying a stable `code` — branch on
|
|
304
360
|
`err.code`, not message text: `ConfigError`, `AuthError`, `RateLimitError`,
|
|
305
|
-
`CapabilityError`, `ContextWindowError`, `InvalidRequestError`, `
|
|
361
|
+
`CapabilityError`, `ContextWindowError`, `InvalidRequestError`, `ToolInputError`,
|
|
362
|
+
`CancelledError`, `DeadlineExceededError`, `ProviderError`.
|
|
306
363
|
|
|
307
364
|
## Develop
|
|
308
365
|
|
|
@@ -1,59 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
toolInput
|
|
3
|
+
} from "./chunk-OX4TA4ZH.js";
|
|
1
4
|
import {
|
|
2
5
|
addUsage,
|
|
3
6
|
emptyUsage,
|
|
4
7
|
mapProviderError,
|
|
5
|
-
normalizeError
|
|
6
|
-
|
|
8
|
+
normalizeError,
|
|
9
|
+
signalWithDeadline
|
|
10
|
+
} from "./chunk-PXXCN2EU.js";
|
|
7
11
|
|
|
8
12
|
// src/providers/anthropic.ts
|
|
9
13
|
import Anthropic from "@anthropic-ai/sdk";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
client;
|
|
13
|
-
/** `client` may be injected (tests, custom transport); otherwise built from key. */
|
|
14
|
-
constructor(apiKey, client) {
|
|
15
|
-
this.client = client ?? new Anthropic({ apiKey });
|
|
16
|
-
}
|
|
17
|
-
async create(spec, req) {
|
|
18
|
-
try {
|
|
19
|
-
let messages = toAnthropicMessages(req);
|
|
20
|
-
const content = [];
|
|
21
|
-
const usage = emptyUsage();
|
|
22
|
-
let stopReason = "end_turn";
|
|
23
|
-
let id = "";
|
|
24
|
-
for (let i = 0; i < 8; i++) {
|
|
25
|
-
const res = await this.client.messages.create(
|
|
26
|
-
buildParams(spec, req, messages)
|
|
27
|
-
);
|
|
28
|
-
id = res.id;
|
|
29
|
-
addUsage(usage, mapUsage(res.usage));
|
|
30
|
-
content.push(...mapContent(res.content));
|
|
31
|
-
stopReason = mapStop(res.stop_reason);
|
|
32
|
-
if (res.stop_reason === "pause_turn") {
|
|
33
|
-
messages = [...messages, { role: "assistant", content: res.content }];
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
|
-
return { id, model: req.model, provider: "anthropic", role: "assistant", content, stopReason, usage };
|
|
39
|
-
} catch (err) {
|
|
40
|
-
mapProviderError(err, "anthropic");
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
async *stream(spec, req) {
|
|
44
|
-
try {
|
|
45
|
-
const events = this.client.messages.stream(
|
|
46
|
-
buildParams(spec, req, toAnthropicMessages(req))
|
|
47
|
-
);
|
|
48
|
-
for await (const raw of events) {
|
|
49
|
-
const ev = mapStreamEvent(raw, req);
|
|
50
|
-
if (ev) yield ev;
|
|
51
|
-
}
|
|
52
|
-
} catch (err) {
|
|
53
|
-
yield { type: "error", error: normalizeError(err, "anthropic").toShape() };
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
};
|
|
14
|
+
|
|
15
|
+
// src/providers/anthropic/request.ts
|
|
57
16
|
function buildParams(spec, req, messages) {
|
|
58
17
|
const params = {
|
|
59
18
|
model: spec.nativeId,
|
|
@@ -141,12 +100,14 @@ function mapToolChoice(tc) {
|
|
|
141
100
|
if (tc === "none") return { type: "none" };
|
|
142
101
|
return { type: "tool", name: tc.name };
|
|
143
102
|
}
|
|
103
|
+
|
|
104
|
+
// src/providers/anthropic/response.ts
|
|
144
105
|
function mapContent(blocks) {
|
|
145
106
|
const out = [];
|
|
146
107
|
for (const b of blocks) {
|
|
147
108
|
if (b.type === "text") out.push({ type: "text", text: b.text });
|
|
148
109
|
else if (b.type === "tool_use") {
|
|
149
|
-
out.push({ type: "tool_use", id: b.id, name: b.name, input: b.input ?? {} });
|
|
110
|
+
out.push({ type: "tool_use", id: b.id, name: b.name, input: toolInput(b.input ?? {}, "anthropic", b.name) });
|
|
150
111
|
} else if (b.type === "thinking") {
|
|
151
112
|
out.push({ type: "thinking", thinking: b.thinking, signature: b.signature });
|
|
152
113
|
}
|
|
@@ -172,6 +133,8 @@ function mapStop(reason) {
|
|
|
172
133
|
return "end_turn";
|
|
173
134
|
}
|
|
174
135
|
}
|
|
136
|
+
|
|
137
|
+
// src/providers/anthropic/stream.ts
|
|
175
138
|
function mapStreamEvent(raw, req) {
|
|
176
139
|
switch (raw.type) {
|
|
177
140
|
case "message_start":
|
|
@@ -213,7 +176,60 @@ function mapStartBlock(cb) {
|
|
|
213
176
|
if (cb.type === "thinking") return { type: "thinking", thinking: cb.thinking, signature: cb.signature };
|
|
214
177
|
return void 0;
|
|
215
178
|
}
|
|
179
|
+
|
|
180
|
+
// src/providers/anthropic.ts
|
|
181
|
+
var AnthropicProvider = class {
|
|
182
|
+
id = "anthropic";
|
|
183
|
+
client;
|
|
184
|
+
/** `client` may be injected (tests, custom transport); otherwise built from key. */
|
|
185
|
+
constructor(apiKey, client) {
|
|
186
|
+
this.client = client ?? new Anthropic({ apiKey });
|
|
187
|
+
}
|
|
188
|
+
async create(spec, req) {
|
|
189
|
+
const signal = signalWithDeadline(req.signal, req.deadline);
|
|
190
|
+
try {
|
|
191
|
+
let messages = toAnthropicMessages(req);
|
|
192
|
+
const content = [];
|
|
193
|
+
const usage = emptyUsage();
|
|
194
|
+
let stopReason = "end_turn";
|
|
195
|
+
let id = "";
|
|
196
|
+
for (let i = 0; i < 8; i++) {
|
|
197
|
+
const res = await this.client.messages.create(
|
|
198
|
+
buildParams(spec, req, messages),
|
|
199
|
+
{ signal }
|
|
200
|
+
);
|
|
201
|
+
id = res.id;
|
|
202
|
+
addUsage(usage, mapUsage(res.usage));
|
|
203
|
+
content.push(...mapContent(res.content));
|
|
204
|
+
stopReason = mapStop(res.stop_reason);
|
|
205
|
+
if (res.stop_reason === "pause_turn") {
|
|
206
|
+
messages = [...messages, { role: "assistant", content: res.content }];
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
return { id, model: req.model, provider: "anthropic", role: "assistant", content, stopReason, usage };
|
|
212
|
+
} catch (err) {
|
|
213
|
+
mapProviderError(err, "anthropic", signal);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async *stream(spec, req) {
|
|
217
|
+
const signal = signalWithDeadline(req.signal, req.deadline);
|
|
218
|
+
try {
|
|
219
|
+
const events = this.client.messages.stream(
|
|
220
|
+
buildParams(spec, req, toAnthropicMessages(req)),
|
|
221
|
+
{ signal }
|
|
222
|
+
);
|
|
223
|
+
for await (const raw of events) {
|
|
224
|
+
const ev = mapStreamEvent(raw, req);
|
|
225
|
+
if (ev) yield ev;
|
|
226
|
+
}
|
|
227
|
+
} catch (err) {
|
|
228
|
+
yield { type: "error", error: normalizeError(err, "anthropic", signal).toShape() };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
216
232
|
export {
|
|
217
233
|
AnthropicProvider
|
|
218
234
|
};
|
|
219
|
-
//# sourceMappingURL=anthropic-
|
|
235
|
+
//# sourceMappingURL=anthropic-2NPMHJZT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/anthropic.ts","../src/providers/anthropic/request.ts","../src/providers/anthropic/response.ts","../src/providers/anthropic/stream.ts"],"sourcesContent":["// Anthropic (Claude) adapter. The canonical shape is Anthropic-flavored, so this\n// is the lowest-translation adapter. Ported from odla-kg's claude.ts patterns:\n// forced tool-call via tool_choice, web_search_20260209 with pause_turn\n// continuation, adaptive thinking + output_config.effort (never budget_tokens).\n//\n// The installed @anthropic-ai/sdk (0.70.x) doesn't yet type adaptive thinking,\n// output_config, or web_search_20260209 — those newer request fields are built\n// into a loose params object in ./anthropic/request and cast at the call site\n// (the wire accepts them), exactly as odla-kg does for the web-search tool literal.\n\nimport Anthropic from \"@anthropic-ai/sdk\";\nimport type { ModelSpec } from \"../shape/capabilities\";\nimport type { Provider } from \"./types\";\nimport { mapProviderError, normalizeError } from \"./errors\";\nimport { addUsage, emptyUsage, type OracleContentBlock, type OracleEvent, type OracleRequest, type OracleResponse, type OracleStopReason } from \"../shape/index\";\nimport { buildParams, toAnthropicMessages } from \"./anthropic/request\";\nimport { mapContent, mapStop, mapUsage } from \"./anthropic/response\";\nimport { mapStreamEvent } from \"./anthropic/stream\";\nimport { signalWithDeadline } from \"../client/abort\";\n\nexport class AnthropicProvider implements Provider {\n readonly id = \"anthropic\" as const;\n private client: Anthropic;\n\n /** `client` may be injected (tests, custom transport); otherwise built from key. */\n constructor(apiKey: string, client?: Anthropic) {\n this.client = client ?? new Anthropic({ apiKey });\n }\n\n async create(spec: ModelSpec, req: OracleRequest): Promise<OracleResponse> {\n const signal = signalWithDeadline(req.signal, req.deadline);\n try {\n let messages = toAnthropicMessages(req);\n const content: OracleContentBlock[] = [];\n const usage = emptyUsage();\n let stopReason: OracleStopReason = \"end_turn\";\n let id = \"\";\n\n // Loop only to resolve server-side tools (pause_turn), max 8 hops. Client\n // tool_use / end_turn / etc. return immediately.\n for (let i = 0; i < 8; i++) {\n const res = await this.client.messages.create(\n buildParams(spec, req, messages) as unknown as Anthropic.MessageCreateParamsNonStreaming,\n { signal },\n );\n id = res.id;\n addUsage(usage, mapUsage(res.usage));\n content.push(...mapContent(res.content));\n stopReason = mapStop(res.stop_reason);\n if (res.stop_reason === \"pause_turn\") {\n messages = [...messages, { role: \"assistant\", content: res.content }];\n continue;\n }\n break;\n }\n\n return { id, model: req.model, provider: \"anthropic\", role: \"assistant\", content, stopReason, usage };\n } catch (err) {\n mapProviderError(err, \"anthropic\", signal);\n }\n }\n\n async *stream(spec: ModelSpec, req: OracleRequest): AsyncIterable<OracleEvent> {\n const signal = signalWithDeadline(req.signal, req.deadline);\n try {\n const events = this.client.messages.stream(\n buildParams(spec, req, toAnthropicMessages(req)) as unknown as Anthropic.MessageStreamParams,\n { signal },\n );\n for await (const raw of events) {\n const ev = mapStreamEvent(raw, req);\n if (ev) yield ev;\n }\n } catch (err) {\n yield { type: \"error\", error: normalizeError(err, \"anthropic\", signal).toShape() };\n }\n }\n}\n","// Anthropic request mapping. The canonical shape is Anthropic-flavored, so this\n// is the lowest-translation adapter.\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport type { ModelSpec } from \"../../shape/capabilities\";\nimport type { OracleContentBlock, OracleRequest, TextBlock, ToolChoice } from \"../../shape/index\";\n\nexport function buildParams(\n spec: ModelSpec,\n req: OracleRequest,\n messages: Anthropic.MessageParam[],\n): Record<string, unknown> {\n const params: Record<string, unknown> = {\n model: spec.nativeId,\n max_tokens: req.maxTokens,\n messages,\n };\n\n const system = toAnthropicSystem(req.system);\n if (system !== undefined) params.system = system;\n\n const tools = buildTools(req);\n if (tools) params.tools = tools;\n\n const toolChoice = mapToolChoice(req.toolChoice);\n if (toolChoice) params.tool_choice = toolChoice;\n\n if (req.stopSequences && req.stopSequences.length > 0) params.stop_sequences = req.stopSequences;\n\n // Sampling params are rejected on the frontier models (they carry effort);\n // only the non-effort tier (Haiku) accepts temperature.\n if (req.temperature !== undefined && !spec.capabilities.effort) params.temperature = req.temperature;\n\n if (req.thinking === \"adaptive\" && spec.capabilities.thinking) params.thinking = { type: \"adaptive\" };\n\n const outputConfig: Record<string, unknown> = {};\n if (req.effort && spec.capabilities.effort) outputConfig.effort = req.effort;\n if (req.responseFormat && spec.capabilities.structuredOutput) {\n outputConfig.format = { type: \"json_schema\", schema: req.responseFormat.schema };\n }\n if (Object.keys(outputConfig).length > 0) params.output_config = outputConfig;\n\n if (req.providerExtras) Object.assign(params, req.providerExtras);\n return params;\n}\n\nfunction toAnthropicSystem(system: OracleRequest[\"system\"]): string | Anthropic.TextBlockParam[] | undefined {\n if (system === undefined) return undefined;\n if (typeof system === \"string\") return system;\n return system.map((b: TextBlock) => ({\n type: \"text\" as const,\n text: b.text,\n ...(b.cacheControl ? { cache_control: { type: \"ephemeral\" as const } } : {}),\n }));\n}\n\nexport function toAnthropicMessages(req: OracleRequest): Anthropic.MessageParam[] {\n return req.messages.map((m) => ({\n role: m.role,\n content: typeof m.content === \"string\" ? m.content : m.content.map(anthropicBlock),\n }));\n}\n\nfunction anthropicBlock(b: OracleContentBlock): Anthropic.ContentBlockParam {\n switch (b.type) {\n case \"text\":\n return {\n type: \"text\",\n text: b.text,\n ...(b.cacheControl ? { cache_control: { type: \"ephemeral\" } } : {}),\n };\n case \"image\":\n return {\n type: \"image\",\n source:\n b.source.type === \"base64\"\n ? { type: \"base64\", media_type: b.source.mediaType, data: b.source.data }\n : { type: \"url\", url: b.source.url },\n } as Anthropic.ContentBlockParam;\n case \"document\":\n return {\n type: \"document\",\n source:\n b.source.type === \"base64\"\n ? { type: \"base64\", media_type: \"application/pdf\", data: b.source.data }\n : { type: \"url\", url: b.source.url },\n } as Anthropic.ContentBlockParam;\n case \"tool_use\":\n return { type: \"tool_use\", id: b.id, name: b.name, input: b.input };\n case \"tool_result\":\n return {\n type: \"tool_result\",\n tool_use_id: b.toolUseId,\n content:\n typeof b.content === \"string\"\n ? b.content\n : (b.content.map(anthropicBlock) as Anthropic.ToolResultBlockParam[\"content\"]),\n ...(b.isError ? { is_error: true } : {}),\n };\n case \"thinking\":\n return { type: \"thinking\", thinking: b.thinking, signature: b.signature ?? \"\" };\n case \"audio\":\n // Guarded by validateRequest; defensive in case validation is bypassed.\n throw new Error(\"Anthropic does not support audio input\");\n }\n}\n\nfunction buildTools(req: OracleRequest): unknown[] | undefined {\n const tools: unknown[] = [];\n for (const t of req.tools ?? []) {\n tools.push({ name: t.name, description: t.description, input_schema: t.inputSchema });\n }\n if (req.webSearch) tools.push({ type: \"web_search_20260209\", name: \"web_search\" });\n return tools.length > 0 ? tools : undefined;\n}\n\nfunction mapToolChoice(tc: ToolChoice | undefined): unknown | undefined {\n if (tc === undefined) return undefined;\n if (tc === \"auto\") return { type: \"auto\" };\n if (tc === \"any\") return { type: \"any\" };\n if (tc === \"none\") return { type: \"none\" };\n return { type: \"tool\", name: tc.name };\n}\n","// Anthropic response mapping. mapUsage / mapStop are also used by the stream\n// mapper (kept here so the entry ↔ stream edge stays one-directional).\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport type { OracleContentBlock, OracleStopReason, OracleUsage } from \"../../shape/index\";\nimport { toolInput } from \"../tool-input\";\n\nexport function mapContent(blocks: Anthropic.ContentBlock[]): OracleContentBlock[] {\n const out: OracleContentBlock[] = [];\n for (const b of blocks) {\n if (b.type === \"text\") out.push({ type: \"text\", text: b.text });\n else if (b.type === \"tool_use\") {\n out.push({ type: \"tool_use\", id: b.id, name: b.name, input: toolInput(b.input ?? {}, \"anthropic\", b.name) });\n } else if (b.type === \"thinking\") {\n out.push({ type: \"thinking\", thinking: b.thinking, signature: b.signature });\n }\n // server_tool_use / web_search_tool_result blocks are dropped — the answer\n // text lives in text blocks.\n }\n return out;\n}\n\nexport function mapUsage(u: Anthropic.Usage): OracleUsage {\n const usage: OracleUsage = { inputTokens: u.input_tokens ?? 0, outputTokens: u.output_tokens ?? 0 };\n if (u.cache_creation_input_tokens != null) usage.cacheCreationTokens = u.cache_creation_input_tokens;\n if (u.cache_read_input_tokens != null) usage.cacheReadTokens = u.cache_read_input_tokens;\n return usage;\n}\n\nexport function mapStop(reason: string | null | undefined): OracleStopReason {\n switch (reason) {\n case \"end_turn\":\n case \"max_tokens\":\n case \"stop_sequence\":\n case \"tool_use\":\n case \"pause_turn\":\n case \"refusal\":\n return reason;\n default:\n return \"end_turn\";\n }\n}\n","// Anthropic stream mapping. The SDK's raw events pass through nearly 1:1.\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport type { OracleContentBlock, OracleEvent, OracleRequest } from \"../../shape/index\";\nimport { mapStop, mapUsage } from \"./response\";\n\nexport function mapStreamEvent(raw: Anthropic.RawMessageStreamEvent, req: OracleRequest): OracleEvent | undefined {\n switch (raw.type) {\n case \"message_start\":\n return {\n type: \"message_start\",\n message: {\n id: raw.message.id,\n model: req.model,\n provider: \"anthropic\",\n role: \"assistant\",\n content: [],\n usage: mapUsage(raw.message.usage),\n },\n };\n case \"content_block_start\": {\n const block = mapStartBlock(raw.content_block);\n return block ? { type: \"content_block_start\", index: raw.index, contentBlock: block } : undefined;\n }\n case \"content_block_delta\": {\n const d = raw.delta;\n if (d.type === \"text_delta\") return { type: \"content_block_delta\", index: raw.index, delta: { type: \"text_delta\", text: d.text } };\n if (d.type === \"thinking_delta\") return { type: \"content_block_delta\", index: raw.index, delta: { type: \"thinking_delta\", thinking: d.thinking } };\n if (d.type === \"input_json_delta\") return { type: \"content_block_delta\", index: raw.index, delta: { type: \"input_json_delta\", partialJson: d.partial_json } };\n return undefined;\n }\n case \"content_block_stop\":\n return { type: \"content_block_stop\", index: raw.index };\n case \"message_delta\":\n return { type: \"message_delta\", delta: { stopReason: mapStop(raw.delta.stop_reason) }, usage: mapUsage(raw.usage as Anthropic.Usage) };\n case \"message_stop\":\n return { type: \"message_stop\" };\n default:\n return undefined;\n }\n}\n\nfunction mapStartBlock(cb: Anthropic.ContentBlock): OracleContentBlock | undefined {\n if (cb.type === \"text\") return { type: \"text\", text: cb.text };\n if (cb.type === \"tool_use\") return { type: \"tool_use\", id: cb.id, name: cb.name, input: {} };\n if (cb.type === \"thinking\") return { type: \"thinking\", thinking: cb.thinking, signature: cb.signature };\n return undefined;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ToolInputError
|
|
3
|
+
} from "./chunk-PXXCN2EU.js";
|
|
4
|
+
|
|
5
|
+
// src/providers/tool-input.ts
|
|
6
|
+
function toolInput(value, provider, name) {
|
|
7
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
throw new ToolInputError(`[${provider}] tool "${name}" returned arguments that are not a JSON object.`, { tool: name });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
toolInput
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=chunk-OX4TA4ZH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/tool-input.ts"],"sourcesContent":["import { ToolInputError, type ProviderId } from \"../shape/index\";\n\n/** Normalize a provider's decoded function arguments without manufacturing an\n * empty object from malformed data. Schema validation happens at the facade or\n * agent boundary, but structural corruption fails here. */\nexport function toolInput(value: unknown, provider: ProviderId, name: string): Record<string, unknown> {\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n throw new ToolInputError(`[${provider}] tool \"${name}\" returned arguments that are not a JSON object.`, { tool: name });\n}\n"],"mappings":";;;;;AAKO,SAAS,UAAU,OAAgB,UAAsB,MAAuC;AACrG,MAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AACxE,WAAO;AAAA,EACT;AACA,QAAM,IAAI,eAAe,IAAI,QAAQ,WAAW,IAAI,oDAAoD,EAAE,MAAM,KAAK,CAAC;AACxH;","names":[]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/shape/
|
|
1
|
+
// src/shape/usage.ts
|
|
2
2
|
function emptyUsage() {
|
|
3
3
|
return { inputTokens: 0, outputTokens: 0 };
|
|
4
4
|
}
|
|
@@ -12,6 +12,8 @@ function addUsage(into, more) {
|
|
|
12
12
|
into.cacheReadTokens = (into.cacheReadTokens ?? 0) + more.cacheReadTokens;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
// src/shape/errors.ts
|
|
15
17
|
var OdlaAIError = class extends Error {
|
|
16
18
|
code;
|
|
17
19
|
providerStatus;
|
|
@@ -62,41 +64,28 @@ var InvalidRequestError = class extends OdlaAIError {
|
|
|
62
64
|
super("invalid_request", message, opts);
|
|
63
65
|
}
|
|
64
66
|
};
|
|
67
|
+
var ToolInputError = class extends OdlaAIError {
|
|
68
|
+
tool;
|
|
69
|
+
constructor(message, opts) {
|
|
70
|
+
super("tool_input_invalid", message, { cause: opts?.cause });
|
|
71
|
+
this.tool = opts?.tool;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var CancelledError = class extends OdlaAIError {
|
|
75
|
+
constructor(message = "AI request was cancelled.", opts) {
|
|
76
|
+
super("cancelled", message, opts);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var DeadlineExceededError = class extends OdlaAIError {
|
|
80
|
+
constructor(message = "AI request deadline was exceeded.", opts) {
|
|
81
|
+
super("deadline_exceeded", message, opts);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
65
84
|
var ProviderError = class extends OdlaAIError {
|
|
66
85
|
constructor(message, opts) {
|
|
67
86
|
super("provider_error", message, opts);
|
|
68
87
|
}
|
|
69
88
|
};
|
|
70
|
-
function isTextBlock(b) {
|
|
71
|
-
return b.type === "text";
|
|
72
|
-
}
|
|
73
|
-
function isImageBlock(b) {
|
|
74
|
-
return b.type === "image";
|
|
75
|
-
}
|
|
76
|
-
function isAudioBlock(b) {
|
|
77
|
-
return b.type === "audio";
|
|
78
|
-
}
|
|
79
|
-
function isDocumentBlock(b) {
|
|
80
|
-
return b.type === "document";
|
|
81
|
-
}
|
|
82
|
-
function isToolUseBlock(b) {
|
|
83
|
-
return b.type === "tool_use";
|
|
84
|
-
}
|
|
85
|
-
function isToolResultBlock(b) {
|
|
86
|
-
return b.type === "tool_result";
|
|
87
|
-
}
|
|
88
|
-
function isThinkingBlock(b) {
|
|
89
|
-
return b.type === "thinking";
|
|
90
|
-
}
|
|
91
|
-
function blocksOf(content) {
|
|
92
|
-
return typeof content === "string" ? [{ type: "text", text: content }] : content;
|
|
93
|
-
}
|
|
94
|
-
function extractText(content) {
|
|
95
|
-
return content.filter(isTextBlock).map((b) => b.text).join("");
|
|
96
|
-
}
|
|
97
|
-
function extractToolUses(content) {
|
|
98
|
-
return content.filter(isToolUseBlock);
|
|
99
|
-
}
|
|
100
89
|
|
|
101
90
|
// src/providers/errors.ts
|
|
102
91
|
function statusOf(err) {
|
|
@@ -125,8 +114,10 @@ function messageOf(err) {
|
|
|
125
114
|
if (typeof err === "string") return err;
|
|
126
115
|
return "unknown provider error";
|
|
127
116
|
}
|
|
128
|
-
function normalizeError(err, provider) {
|
|
117
|
+
function normalizeError(err, provider, signal) {
|
|
129
118
|
if (err instanceof OdlaAIError) return err;
|
|
119
|
+
const cancellation = cancellationError(signal?.aborted ? signal.reason : err);
|
|
120
|
+
if (signal?.aborted || cancellation) return cancellation ?? new CancelledError(void 0, { cause: err });
|
|
130
121
|
const status = statusOf(err);
|
|
131
122
|
const message = messageOf(err);
|
|
132
123
|
const tagged = `[${provider}] ${message}`;
|
|
@@ -142,8 +133,41 @@ function normalizeError(err, provider) {
|
|
|
142
133
|
}
|
|
143
134
|
return new ProviderError(tagged, { providerStatus: status, cause: err });
|
|
144
135
|
}
|
|
145
|
-
function mapProviderError(err, provider) {
|
|
146
|
-
throw normalizeError(err, provider);
|
|
136
|
+
function mapProviderError(err, provider, signal) {
|
|
137
|
+
throw normalizeError(err, provider, signal);
|
|
138
|
+
}
|
|
139
|
+
function cancellationError(reason) {
|
|
140
|
+
if (reason instanceof DeadlineExceededError || reason instanceof CancelledError) return reason;
|
|
141
|
+
if (!reason || typeof reason !== "object") return void 0;
|
|
142
|
+
const rec = reason;
|
|
143
|
+
if (rec.name === "TimeoutError") return new DeadlineExceededError(void 0, { cause: reason });
|
|
144
|
+
if (rec.name === "AbortError" || rec.name === "APIUserAbortError" || rec.code === "ABORT_ERR") {
|
|
145
|
+
return new CancelledError(void 0, { cause: reason });
|
|
146
|
+
}
|
|
147
|
+
return void 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/client/abort.ts
|
|
151
|
+
function signalWithDeadline(signal, deadline) {
|
|
152
|
+
if (deadline === void 0) return signal;
|
|
153
|
+
if (!Number.isSafeInteger(deadline)) throw new ConfigError("deadline must be a finite integer Unix timestamp in milliseconds.");
|
|
154
|
+
const remaining = deadline - Date.now();
|
|
155
|
+
if (remaining <= 0) {
|
|
156
|
+
const expired = new AbortController();
|
|
157
|
+
expired.abort(new DeadlineExceededError());
|
|
158
|
+
return signal ? AbortSignal.any([signal, expired.signal]) : expired.signal;
|
|
159
|
+
}
|
|
160
|
+
const timeout = AbortSignal.timeout(remaining);
|
|
161
|
+
return signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
162
|
+
}
|
|
163
|
+
function throwIfAborted(signal) {
|
|
164
|
+
if (!signal?.aborted) return;
|
|
165
|
+
const reason = signal.reason;
|
|
166
|
+
if (reason instanceof DeadlineExceededError || reason instanceof CancelledError) throw reason;
|
|
167
|
+
if (reason && typeof reason === "object" && reason.name === "TimeoutError") {
|
|
168
|
+
throw new DeadlineExceededError(void 0, { cause: reason });
|
|
169
|
+
}
|
|
170
|
+
throw new CancelledError(void 0, { cause: reason });
|
|
147
171
|
}
|
|
148
172
|
|
|
149
173
|
export {
|
|
@@ -156,18 +180,13 @@ export {
|
|
|
156
180
|
CapabilityError,
|
|
157
181
|
ContextWindowError,
|
|
158
182
|
InvalidRequestError,
|
|
183
|
+
ToolInputError,
|
|
184
|
+
CancelledError,
|
|
185
|
+
DeadlineExceededError,
|
|
159
186
|
ProviderError,
|
|
160
|
-
isTextBlock,
|
|
161
|
-
isImageBlock,
|
|
162
|
-
isAudioBlock,
|
|
163
|
-
isDocumentBlock,
|
|
164
|
-
isToolUseBlock,
|
|
165
|
-
isToolResultBlock,
|
|
166
|
-
isThinkingBlock,
|
|
167
|
-
blocksOf,
|
|
168
|
-
extractText,
|
|
169
|
-
extractToolUses,
|
|
170
187
|
normalizeError,
|
|
171
|
-
mapProviderError
|
|
188
|
+
mapProviderError,
|
|
189
|
+
signalWithDeadline,
|
|
190
|
+
throwIfAborted
|
|
172
191
|
};
|
|
173
|
-
//# sourceMappingURL=chunk-
|
|
192
|
+
//# sourceMappingURL=chunk-PXXCN2EU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shape/usage.ts","../src/shape/errors.ts","../src/providers/errors.ts","../src/client/abort.ts"],"sourcesContent":["// Token usage accounting. The one runtime island with no dependencies.\n\nexport interface OracleUsage {\n inputTokens: number;\n outputTokens: number;\n cacheCreationTokens?: number;\n cacheReadTokens?: number;\n}\n\n/** A fresh zeroed usage tally (0 input/output tokens, no cache fields) — the seed for accumulation. */\nexport function emptyUsage(): OracleUsage {\n return { inputTokens: 0, outputTokens: 0 };\n}\n\n/** Accumulate `more` into `into`, in place. Cache fields sum when present. */\nexport function addUsage(into: OracleUsage, more: OracleUsage): void {\n into.inputTokens += more.inputTokens;\n into.outputTokens += more.outputTokens;\n if (more.cacheCreationTokens !== undefined) {\n into.cacheCreationTokens = (into.cacheCreationTokens ?? 0) + more.cacheCreationTokens;\n }\n if (more.cacheReadTokens !== undefined) {\n into.cacheReadTokens = (into.cacheReadTokens ?? 0) + more.cacheReadTokens;\n }\n}\n","// The normalized error taxonomy and the class hierarchy every adapter throws.\n\n/** The closed taxonomy of normalized error codes carried by every OdlaAIError\n * and by the streaming `error` event. */\nexport type OracleErrorType =\n | \"invalid_request\"\n | \"auth\"\n | \"rate_limit\"\n | \"context_window\"\n | \"cancelled\"\n | \"deadline_exceeded\"\n | \"tool_input_invalid\"\n | \"capability_unsupported\"\n | \"config\"\n | \"provider_error\";\n\n/** The plain-data error shape used inside the streaming `error` event. */\nexport interface OracleErrorShape {\n code: OracleErrorType;\n message: string;\n /** HTTP status from the upstream provider, when applicable. */\n providerStatus?: number;\n /** Seconds until a retry might succeed (rate limit / overload). */\n retryAfter?: number;\n}\n\n/** Base class for every error odla-ai throws. Carries a stable string `code`\n * (the odla ecosystem convention — see odla-db's AuthError/RuleError) so\n * callers branch on `err.code`, never on message text. */\nexport class OdlaAIError extends Error {\n readonly code: OracleErrorType;\n readonly providerStatus?: number;\n readonly retryAfter?: number;\n\n constructor(\n code: OracleErrorType,\n message: string,\n opts?: { providerStatus?: number; retryAfter?: number; cause?: unknown },\n ) {\n super(message, opts?.cause !== undefined ? { cause: opts.cause } : undefined);\n this.name = new.target.name;\n this.code = code;\n this.providerStatus = opts?.providerStatus;\n this.retryAfter = opts?.retryAfter;\n }\n\n toShape(): OracleErrorShape {\n return {\n code: this.code,\n message: this.message,\n providerStatus: this.providerStatus,\n retryAfter: this.retryAfter,\n };\n }\n}\n\n/** A provider/model is not configured — e.g. no API key for its provider, or an\n * unknown canonical model id. The library analog of odla-db's 501 gating. */\nexport class ConfigError extends OdlaAIError {\n constructor(message: string) {\n super(\"config\", message);\n }\n}\n\n/** Authentication with the provider failed (bad/missing key). */\nexport class AuthError extends OdlaAIError {\n constructor(message: string, opts?: { providerStatus?: number; cause?: unknown }) {\n super(\"auth\", message, opts);\n }\n}\n\n/** The provider rate-limited or is overloaded; check `retryAfter`. */\nexport class RateLimitError extends OdlaAIError {\n constructor(message: string, opts?: { providerStatus?: number; retryAfter?: number; cause?: unknown }) {\n super(\"rate_limit\", message, opts);\n }\n}\n\n/** The request asked a model to do something it cannot — audio to Claude, tools\n * to a text-only model, web search where unsupported, etc. Raised before any\n * network call by `validateRequest`. */\nexport class CapabilityError extends OdlaAIError {\n constructor(message: string) {\n super(\"capability_unsupported\", message);\n }\n}\n\n/** The request exceeded the model's context window. */\nexport class ContextWindowError extends OdlaAIError {\n constructor(message: string, opts?: { providerStatus?: number; cause?: unknown }) {\n super(\"context_window\", message, opts);\n }\n}\n\n/** The request was malformed / rejected as invalid by the provider. */\nexport class InvalidRequestError extends OdlaAIError {\n constructor(message: string, opts?: { providerStatus?: number; cause?: unknown }) {\n super(\"invalid_request\", message, opts);\n }\n}\n\n/** A provider returned tool arguments that are malformed or do not satisfy the\n * declared JSON Schema. Tool handlers are never invoked for this error. */\nexport class ToolInputError extends OdlaAIError {\n readonly tool?: string;\n\n constructor(message: string, opts?: { tool?: string; cause?: unknown }) {\n super(\"tool_input_invalid\", message, { cause: opts?.cause });\n this.tool = opts?.tool;\n }\n}\n\n/** The caller cancelled a request. This is not an upstream failure and should\n * not be retried unless the caller explicitly starts a new operation. */\nexport class CancelledError extends OdlaAIError {\n constructor(message = \"AI request was cancelled.\", opts?: { cause?: unknown }) {\n super(\"cancelled\", message, opts);\n }\n}\n\n/** The request's absolute deadline elapsed. Callers may choose a new deadline,\n * but should not classify this as a provider outage. */\nexport class DeadlineExceededError extends OdlaAIError {\n constructor(message = \"AI request deadline was exceeded.\", opts?: { cause?: unknown }) {\n super(\"deadline_exceeded\", message, opts);\n }\n}\n\n/** Any other upstream provider failure (5xx, transport, unexpected shape). */\nexport class ProviderError extends OdlaAIError {\n constructor(message: string, opts?: { providerStatus?: number; cause?: unknown }) {\n super(\"provider_error\", message, opts);\n }\n}\n","// Normalize a thrown provider-SDK error into the odla-ai error taxonomy. Kept\n// dependency-light: it duck-types the HTTP status / retry-after off the error\n// object rather than importing each SDK's error classes, so it works uniformly\n// across @anthropic-ai/sdk, openai, and @google/genai.\n\nimport {\n AuthError,\n CancelledError,\n ContextWindowError,\n DeadlineExceededError,\n InvalidRequestError,\n OdlaAIError,\n ProviderError,\n RateLimitError,\n type ProviderId,\n} from \"../shape/index\";\n\nfunction statusOf(err: unknown): number | undefined {\n if (err && typeof err === \"object\") {\n const rec = err as Record<string, unknown>;\n for (const k of [\"status\", \"statusCode\", \"code\"]) {\n const v = rec[k];\n if (typeof v === \"number\") return v;\n }\n }\n return undefined;\n}\n\nfunction retryAfterOf(err: unknown): number | undefined {\n if (err && typeof err === \"object\") {\n const headers = (err as { headers?: unknown }).headers;\n if (headers && typeof headers === \"object\") {\n const raw = (headers as Record<string, unknown>)[\"retry-after\"];\n const n = typeof raw === \"string\" ? Number(raw) : typeof raw === \"number\" ? raw : NaN;\n if (Number.isFinite(n)) return n;\n }\n }\n return undefined;\n}\n\nfunction messageOf(err: unknown): string {\n if (err instanceof Error) return err.message;\n if (typeof err === \"string\") return err;\n return \"unknown provider error\";\n}\n\n/** Map any provider error to an OdlaAIError, returning it (does not throw).\n * Re-returns an OdlaAIError unchanged (already normalized). */\nexport function normalizeError(err: unknown, provider: ProviderId, signal?: AbortSignal): OdlaAIError {\n if (err instanceof OdlaAIError) return err;\n const cancellation = cancellationError(signal?.aborted ? signal.reason : err);\n if (signal?.aborted || cancellation) return cancellation ?? new CancelledError(undefined, { cause: err });\n\n const status = statusOf(err);\n const message = messageOf(err);\n const tagged = `[${provider}] ${message}`;\n\n if (status === 401 || status === 403) return new AuthError(tagged, { providerStatus: status, cause: err });\n if (status === 429) {\n return new RateLimitError(tagged, { providerStatus: status, retryAfter: retryAfterOf(err), cause: err });\n }\n if (status === 400 || status === 422) {\n if (/context|token limit|too long|maximum context/i.test(message)) {\n return new ContextWindowError(tagged, { providerStatus: status, cause: err });\n }\n return new InvalidRequestError(tagged, { providerStatus: status, cause: err });\n }\n return new ProviderError(tagged, { providerStatus: status, cause: err });\n}\n\n/**\n * Normalize and throw. The `never` return lets call sites write\n * `catch (e) { mapProviderError(e, id); }` with no fallthrough.\n */\nexport function mapProviderError(err: unknown, provider: ProviderId, signal?: AbortSignal): never {\n throw normalizeError(err, provider, signal);\n}\n\nfunction cancellationError(reason: unknown): CancelledError | DeadlineExceededError | undefined {\n if (reason instanceof DeadlineExceededError || reason instanceof CancelledError) return reason;\n if (!reason || typeof reason !== \"object\") return undefined;\n const rec = reason as { name?: unknown; code?: unknown; message?: unknown };\n if (rec.name === \"TimeoutError\") return new DeadlineExceededError(undefined, { cause: reason });\n if (rec.name === \"AbortError\" || rec.name === \"APIUserAbortError\" || rec.code === \"ABORT_ERR\") {\n return new CancelledError(undefined, { cause: reason });\n }\n return undefined;\n}\n","import { CancelledError, ConfigError, DeadlineExceededError } from \"../shape/errors\";\n\n/** Combine a caller signal with an absolute deadline. Kept provider-neutral so\n * every adapter and the agent loop observes the same cancellation contract. */\nexport function signalWithDeadline(signal?: AbortSignal, deadline?: number): AbortSignal | undefined {\n if (deadline === undefined) return signal;\n if (!Number.isSafeInteger(deadline)) throw new ConfigError(\"deadline must be a finite integer Unix timestamp in milliseconds.\");\n const remaining = deadline - Date.now();\n if (remaining <= 0) {\n const expired = new AbortController();\n expired.abort(new DeadlineExceededError());\n return signal ? AbortSignal.any([signal, expired.signal]) : expired.signal;\n }\n const timeout = AbortSignal.timeout(remaining);\n return signal ? AbortSignal.any([signal, timeout]) : timeout;\n}\n\n/** Fail synchronously before beginning a local side effect when a run was\n * cancelled or its deadline elapsed. Handlers must still observe the signal\n * while in flight; this closes the already-aborted race at invocation time. */\nexport function throwIfAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) return;\n const reason = signal.reason;\n if (reason instanceof DeadlineExceededError || reason instanceof CancelledError) throw reason;\n if (reason && typeof reason === \"object\" && (reason as { name?: unknown }).name === \"TimeoutError\") {\n throw new DeadlineExceededError(undefined, { cause: reason });\n }\n throw new CancelledError(undefined, { cause: reason });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/blocks.ts"],"sourcesContent":["import type { OracleContentBlock } from \"../shape/index\";\n\n/** Render content blocks to a plain string for providers/fields that only accept\n * text: text blocks pass through, everything else becomes a `[type]` placeholder.\n * Shared by the openai and google request mappers (tool_result fallback). */\nexport function stringifyBlocks(blocks: OracleContentBlock[]): string {\n return blocks.map((b) => (b.type === \"text\" ? b.text : `[${b.type}]`)).join(\"\");\n}\n"],"mappings":";AAKO,SAAS,gBAAgB,QAAsC;AACpE,SAAO,OAAO,IAAI,CAAC,MAAO,EAAE,SAAS,SAAS,EAAE,OAAO,IAAI,EAAE,IAAI,GAAI,EAAE,KAAK,EAAE;AAChF;","names":[]}
|