@odla-ai/ai 0.1.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/README.md +290 -0
- package/dist/anthropic-JXDXR7O7.js +219 -0
- package/dist/anthropic-JXDXR7O7.js.map +1 -0
- package/dist/chunk-LANGYP65.js +173 -0
- package/dist/chunk-LANGYP65.js.map +1 -0
- package/dist/google-3TFOFIQO.js +206 -0
- package/dist/google-3TFOFIQO.js.map +1 -0
- package/dist/index.cjs +2002 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +991 -0
- package/dist/index.d.ts +991 -0
- package/dist/index.js +1122 -0
- package/dist/index.js.map +1 -0
- package/dist/openai-Y3OAONAU.js +257 -0
- package/dist/openai-Y3OAONAU.js.map +1 -0
- package/llms.txt +111 -0
- package/package.json +76 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,991 @@
|
|
|
1
|
+
/** Every provider odla-ai can route to. Apps should not branch on this for
|
|
2
|
+
* portability, but it is carried on responses/events for observability. */
|
|
3
|
+
type ProviderId = "anthropic" | "openai" | "google";
|
|
4
|
+
interface TextBlock {
|
|
5
|
+
type: "text";
|
|
6
|
+
text: string;
|
|
7
|
+
/** Anthropic prompt-caching marker. Other providers ignore it. */
|
|
8
|
+
cacheControl?: {
|
|
9
|
+
type: "ephemeral";
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
type ImageMediaType = "image/jpeg" | "image/png" | "image/gif" | "image/webp";
|
|
13
|
+
type ImageSource = {
|
|
14
|
+
type: "base64";
|
|
15
|
+
mediaType: ImageMediaType;
|
|
16
|
+
data: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: "url";
|
|
19
|
+
url: string;
|
|
20
|
+
};
|
|
21
|
+
interface ImageBlock {
|
|
22
|
+
type: "image";
|
|
23
|
+
source: ImageSource;
|
|
24
|
+
}
|
|
25
|
+
type AudioMediaType = "audio/wav" | "audio/mp3" | "audio/mpeg" | "audio/ogg" | "audio/flac" | "audio/aac" | "audio/webm";
|
|
26
|
+
type AudioSource = {
|
|
27
|
+
type: "base64";
|
|
28
|
+
mediaType: AudioMediaType;
|
|
29
|
+
data: string;
|
|
30
|
+
} | {
|
|
31
|
+
type: "url";
|
|
32
|
+
url: string;
|
|
33
|
+
};
|
|
34
|
+
/** Audio input. Supported by OpenAI (audio models) and Google (Gemini); NOT by
|
|
35
|
+
* Anthropic — a request carrying an AudioBlock to a Claude model is rejected up
|
|
36
|
+
* front by capability validation, never sent. */
|
|
37
|
+
interface AudioBlock {
|
|
38
|
+
type: "audio";
|
|
39
|
+
source: AudioSource;
|
|
40
|
+
}
|
|
41
|
+
type DocumentSource = {
|
|
42
|
+
type: "base64";
|
|
43
|
+
mediaType: "application/pdf";
|
|
44
|
+
data: string;
|
|
45
|
+
} | {
|
|
46
|
+
type: "url";
|
|
47
|
+
url: string;
|
|
48
|
+
};
|
|
49
|
+
/** A document (PDF) input. Supported by Anthropic and Google. */
|
|
50
|
+
interface DocumentBlock {
|
|
51
|
+
type: "document";
|
|
52
|
+
source: DocumentSource;
|
|
53
|
+
}
|
|
54
|
+
interface ToolUseBlock {
|
|
55
|
+
type: "tool_use";
|
|
56
|
+
/** Correlates a `tool_result` with this call. Translated from OpenAI's
|
|
57
|
+
* `tool_calls[].id` by the openai adapter. */
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
/** Already-parsed object. OpenAI's JSON-string `arguments` is parsed before it
|
|
61
|
+
* reaches this shape — callers never JSON.parse a tool's arguments. */
|
|
62
|
+
input: Record<string, unknown>;
|
|
63
|
+
}
|
|
64
|
+
interface ToolResultBlock {
|
|
65
|
+
type: "tool_result";
|
|
66
|
+
toolUseId: string;
|
|
67
|
+
/** String for plain-text results (most tools); a content-block array for tools
|
|
68
|
+
* that return structured / multi-modal content. */
|
|
69
|
+
content: string | OracleContentBlock[];
|
|
70
|
+
isError?: boolean;
|
|
71
|
+
}
|
|
72
|
+
interface ThinkingBlock {
|
|
73
|
+
type: "thinking";
|
|
74
|
+
/** Extended-thinking text (Anthropic). Empty when `display` is omitted. */
|
|
75
|
+
thinking: string;
|
|
76
|
+
signature?: string;
|
|
77
|
+
}
|
|
78
|
+
type OracleContentBlock = TextBlock | ImageBlock | AudioBlock | DocumentBlock | ToolUseBlock | ToolResultBlock | ThinkingBlock;
|
|
79
|
+
type OracleRole = "user" | "assistant";
|
|
80
|
+
interface OracleMessage {
|
|
81
|
+
role: OracleRole;
|
|
82
|
+
/** A plain string (shorthand for a single TextBlock) or an explicit array for
|
|
83
|
+
* multi-modal / tool turns. */
|
|
84
|
+
content: string | OracleContentBlock[];
|
|
85
|
+
}
|
|
86
|
+
interface OracleTool {
|
|
87
|
+
name: string;
|
|
88
|
+
description: string;
|
|
89
|
+
/** JSON Schema for the tool's arguments. */
|
|
90
|
+
inputSchema: Record<string, unknown>;
|
|
91
|
+
}
|
|
92
|
+
/** How the model may use tools this turn. `{ type: "tool", name }` forces one
|
|
93
|
+
* specific tool — the mechanism behind `extract<T>()`. */
|
|
94
|
+
type ToolChoice = "auto" | "any" | "none" | {
|
|
95
|
+
type: "tool";
|
|
96
|
+
name: string;
|
|
97
|
+
};
|
|
98
|
+
/** Whether the model reasons before answering. Maps to Anthropic adaptive
|
|
99
|
+
* thinking; emulated or ignored on providers without a native equivalent. */
|
|
100
|
+
type ThinkingMode = "off" | "adaptive";
|
|
101
|
+
/** Reasoning/spend depth. Maps to Anthropic `output_config.effort`; the openai
|
|
102
|
+
* and google adapters map it to their nearest reasoning-effort knob. */
|
|
103
|
+
type Effort = "low" | "medium" | "high" | "xhigh" | "max";
|
|
104
|
+
/** Constrain the response to valid JSON matching a schema (structured output). */
|
|
105
|
+
interface ResponseFormat {
|
|
106
|
+
type: "json_schema";
|
|
107
|
+
name?: string;
|
|
108
|
+
schema: Record<string, unknown>;
|
|
109
|
+
}
|
|
110
|
+
interface OracleRequest {
|
|
111
|
+
/** Canonical model id from the catalog; resolved to a provider + native id. */
|
|
112
|
+
model: string;
|
|
113
|
+
/** System prompt. Top-level for Anthropic/Google; the openai adapter folds it
|
|
114
|
+
* into a leading system message. */
|
|
115
|
+
system?: string | TextBlock[];
|
|
116
|
+
messages: OracleMessage[];
|
|
117
|
+
tools?: OracleTool[];
|
|
118
|
+
toolChoice?: ToolChoice;
|
|
119
|
+
maxTokens: number;
|
|
120
|
+
temperature?: number;
|
|
121
|
+
stopSequences?: string[];
|
|
122
|
+
/** Reasoning mode. Only applied on models whose capabilities allow it. */
|
|
123
|
+
thinking?: ThinkingMode;
|
|
124
|
+
/** Reasoning/spend depth. Only applied on models whose capabilities allow it. */
|
|
125
|
+
effort?: Effort;
|
|
126
|
+
responseFormat?: ResponseFormat;
|
|
127
|
+
/** Enable the provider's server-side web-search tool for this request. */
|
|
128
|
+
webSearch?: boolean;
|
|
129
|
+
/** Provider-specific escape hatch, passed through opaquely. Using it gives up
|
|
130
|
+
* portability across providers. */
|
|
131
|
+
providerExtras?: Record<string, unknown>;
|
|
132
|
+
}
|
|
133
|
+
interface OracleUsage {
|
|
134
|
+
inputTokens: number;
|
|
135
|
+
outputTokens: number;
|
|
136
|
+
cacheCreationTokens?: number;
|
|
137
|
+
cacheReadTokens?: number;
|
|
138
|
+
}
|
|
139
|
+
declare function emptyUsage(): OracleUsage;
|
|
140
|
+
/** Accumulate `more` into `into`, in place. Cache fields sum when present. */
|
|
141
|
+
declare function addUsage(into: OracleUsage, more: OracleUsage): void;
|
|
142
|
+
type OracleStopReason = "end_turn" | "max_tokens" | "stop_sequence" | "tool_use" | "pause_turn" | "refusal" | "error";
|
|
143
|
+
interface OracleResponse {
|
|
144
|
+
id: string;
|
|
145
|
+
model: string;
|
|
146
|
+
/** The provider that actually answered — for observability, not branching. */
|
|
147
|
+
provider: ProviderId;
|
|
148
|
+
role: "assistant";
|
|
149
|
+
content: OracleContentBlock[];
|
|
150
|
+
stopReason: OracleStopReason;
|
|
151
|
+
usage: OracleUsage;
|
|
152
|
+
}
|
|
153
|
+
/** A discriminated union of SSE events with the same vocabulary regardless of
|
|
154
|
+
* provider. The anthropic adapter passes these through nearly 1:1; the openai
|
|
155
|
+
* and google adapters map their native streams onto this shape. */
|
|
156
|
+
type OracleEvent = MessageStartEvent | ContentBlockStartEvent | ContentBlockDeltaEvent | ContentBlockStopEvent | MessageDeltaEvent | MessageStopEvent | OracleErrorEvent;
|
|
157
|
+
interface MessageStartEvent {
|
|
158
|
+
type: "message_start";
|
|
159
|
+
message: {
|
|
160
|
+
id: string;
|
|
161
|
+
model: string;
|
|
162
|
+
provider: ProviderId;
|
|
163
|
+
role: "assistant";
|
|
164
|
+
content: [];
|
|
165
|
+
usage: OracleUsage;
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
interface ContentBlockStartEvent {
|
|
169
|
+
type: "content_block_start";
|
|
170
|
+
index: number;
|
|
171
|
+
contentBlock: OracleContentBlock;
|
|
172
|
+
}
|
|
173
|
+
type ContentBlockDelta = {
|
|
174
|
+
type: "text_delta";
|
|
175
|
+
text: string;
|
|
176
|
+
} | {
|
|
177
|
+
type: "thinking_delta";
|
|
178
|
+
thinking: string;
|
|
179
|
+
} | {
|
|
180
|
+
type: "input_json_delta";
|
|
181
|
+
partialJson: string;
|
|
182
|
+
};
|
|
183
|
+
interface ContentBlockDeltaEvent {
|
|
184
|
+
type: "content_block_delta";
|
|
185
|
+
index: number;
|
|
186
|
+
delta: ContentBlockDelta;
|
|
187
|
+
}
|
|
188
|
+
interface ContentBlockStopEvent {
|
|
189
|
+
type: "content_block_stop";
|
|
190
|
+
index: number;
|
|
191
|
+
}
|
|
192
|
+
interface MessageDeltaEvent {
|
|
193
|
+
type: "message_delta";
|
|
194
|
+
delta: {
|
|
195
|
+
stopReason?: OracleStopReason;
|
|
196
|
+
};
|
|
197
|
+
usage: OracleUsage;
|
|
198
|
+
}
|
|
199
|
+
interface MessageStopEvent {
|
|
200
|
+
type: "message_stop";
|
|
201
|
+
}
|
|
202
|
+
interface OracleErrorEvent {
|
|
203
|
+
type: "error";
|
|
204
|
+
error: OracleErrorShape;
|
|
205
|
+
}
|
|
206
|
+
/** The closed taxonomy of normalized error codes carried by every OdlaAIError
|
|
207
|
+
* and by the streaming `error` event. */
|
|
208
|
+
type OracleErrorType = "invalid_request" | "auth" | "rate_limit" | "context_window" | "tool_input_invalid" | "capability_unsupported" | "config" | "provider_error";
|
|
209
|
+
/** The plain-data error shape used inside the streaming `error` event. */
|
|
210
|
+
interface OracleErrorShape {
|
|
211
|
+
code: OracleErrorType;
|
|
212
|
+
message: string;
|
|
213
|
+
/** HTTP status from the upstream provider, when applicable. */
|
|
214
|
+
providerStatus?: number;
|
|
215
|
+
/** Seconds until a retry might succeed (rate limit / overload). */
|
|
216
|
+
retryAfter?: number;
|
|
217
|
+
}
|
|
218
|
+
/** Base class for every error odla-ai throws. Carries a stable string `code`
|
|
219
|
+
* (the odla ecosystem convention — see odla-db's AuthError/RuleError) so
|
|
220
|
+
* callers branch on `err.code`, never on message text. */
|
|
221
|
+
declare class OdlaAIError extends Error {
|
|
222
|
+
readonly code: OracleErrorType;
|
|
223
|
+
readonly providerStatus?: number;
|
|
224
|
+
readonly retryAfter?: number;
|
|
225
|
+
constructor(code: OracleErrorType, message: string, opts?: {
|
|
226
|
+
providerStatus?: number;
|
|
227
|
+
retryAfter?: number;
|
|
228
|
+
cause?: unknown;
|
|
229
|
+
});
|
|
230
|
+
toShape(): OracleErrorShape;
|
|
231
|
+
}
|
|
232
|
+
/** A provider/model is not configured — e.g. no API key for its provider, or an
|
|
233
|
+
* unknown canonical model id. The library analog of odla-db's 501 gating. */
|
|
234
|
+
declare class ConfigError extends OdlaAIError {
|
|
235
|
+
constructor(message: string);
|
|
236
|
+
}
|
|
237
|
+
/** Authentication with the provider failed (bad/missing key). */
|
|
238
|
+
declare class AuthError extends OdlaAIError {
|
|
239
|
+
constructor(message: string, opts?: {
|
|
240
|
+
providerStatus?: number;
|
|
241
|
+
cause?: unknown;
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/** The provider rate-limited or is overloaded; check `retryAfter`. */
|
|
245
|
+
declare class RateLimitError extends OdlaAIError {
|
|
246
|
+
constructor(message: string, opts?: {
|
|
247
|
+
providerStatus?: number;
|
|
248
|
+
retryAfter?: number;
|
|
249
|
+
cause?: unknown;
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/** The request asked a model to do something it cannot — audio to Claude, tools
|
|
253
|
+
* to a text-only model, web search where unsupported, etc. Raised before any
|
|
254
|
+
* network call by `validateRequest`. */
|
|
255
|
+
declare class CapabilityError extends OdlaAIError {
|
|
256
|
+
constructor(message: string);
|
|
257
|
+
}
|
|
258
|
+
/** The request exceeded the model's context window. */
|
|
259
|
+
declare class ContextWindowError extends OdlaAIError {
|
|
260
|
+
constructor(message: string, opts?: {
|
|
261
|
+
providerStatus?: number;
|
|
262
|
+
cause?: unknown;
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
/** The request was malformed / rejected as invalid by the provider. */
|
|
266
|
+
declare class InvalidRequestError extends OdlaAIError {
|
|
267
|
+
constructor(message: string, opts?: {
|
|
268
|
+
providerStatus?: number;
|
|
269
|
+
cause?: unknown;
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/** Any other upstream provider failure (5xx, transport, unexpected shape). */
|
|
273
|
+
declare class ProviderError extends OdlaAIError {
|
|
274
|
+
constructor(message: string, opts?: {
|
|
275
|
+
providerStatus?: number;
|
|
276
|
+
cause?: unknown;
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
declare function isTextBlock(b: OracleContentBlock): b is TextBlock;
|
|
280
|
+
declare function isImageBlock(b: OracleContentBlock): b is ImageBlock;
|
|
281
|
+
declare function isAudioBlock(b: OracleContentBlock): b is AudioBlock;
|
|
282
|
+
declare function isDocumentBlock(b: OracleContentBlock): b is DocumentBlock;
|
|
283
|
+
declare function isToolUseBlock(b: OracleContentBlock): b is ToolUseBlock;
|
|
284
|
+
declare function isToolResultBlock(b: OracleContentBlock): b is ToolResultBlock;
|
|
285
|
+
declare function isThinkingBlock(b: OracleContentBlock): b is ThinkingBlock;
|
|
286
|
+
/** Normalize a message's `content` (string shorthand or block array) to blocks. */
|
|
287
|
+
declare function blocksOf(content: string | OracleContentBlock[]): OracleContentBlock[];
|
|
288
|
+
/** Concatenate the text of every TextBlock. Image/audio/tool/thinking ignored. */
|
|
289
|
+
declare function extractText(content: OracleContentBlock[]): string;
|
|
290
|
+
/** Collect every tool_use block from response or message content. */
|
|
291
|
+
declare function extractToolUses(content: OracleContentBlock[]): ToolUseBlock[];
|
|
292
|
+
|
|
293
|
+
/** The kind of model — chat/multimodal is the v1 focus; the others are modeled
|
|
294
|
+
* so embeddings, transcription, TTS, and image generation slot in later. */
|
|
295
|
+
type ModelKind = "chat" | "embed" | "transcribe" | "tts" | "image";
|
|
296
|
+
interface Capabilities {
|
|
297
|
+
kind: ModelKind;
|
|
298
|
+
/** Accepts text input. */
|
|
299
|
+
textIn: boolean;
|
|
300
|
+
/** Accepts image input (ImageBlock). */
|
|
301
|
+
imageIn: boolean;
|
|
302
|
+
/** Accepts audio input (AudioBlock). */
|
|
303
|
+
audioIn: boolean;
|
|
304
|
+
/** Accepts document/PDF input (DocumentBlock). */
|
|
305
|
+
documentIn: boolean;
|
|
306
|
+
/** Supports tool / function calling. */
|
|
307
|
+
toolUse: boolean;
|
|
308
|
+
/** Supports a native reasoning/thinking mode. */
|
|
309
|
+
thinking: boolean;
|
|
310
|
+
/** Supports an effort/reasoning-depth knob. */
|
|
311
|
+
effort: boolean;
|
|
312
|
+
/** Supports streaming responses. */
|
|
313
|
+
streaming: boolean;
|
|
314
|
+
/** Supports constrained JSON / structured output. */
|
|
315
|
+
structuredOutput: boolean;
|
|
316
|
+
/** Supports a provider server-side web-search tool. */
|
|
317
|
+
webSearch: boolean;
|
|
318
|
+
}
|
|
319
|
+
/** A catalog entry: a canonical model id mapped to a provider, that provider's
|
|
320
|
+
* native model id, and what the model can do. */
|
|
321
|
+
interface ModelSpec {
|
|
322
|
+
/** Canonical id used across odla-ai (e.g. "claude-opus-4-8", "gpt-5"). */
|
|
323
|
+
id: string;
|
|
324
|
+
provider: ProviderId;
|
|
325
|
+
/** The id passed to the provider SDK. Often equal to `id`. */
|
|
326
|
+
nativeId: string;
|
|
327
|
+
capabilities: Capabilities;
|
|
328
|
+
contextWindow?: number;
|
|
329
|
+
maxOutput?: number;
|
|
330
|
+
}
|
|
331
|
+
/** Sensible chat/multimodal defaults; per-model tables override what differs. */
|
|
332
|
+
declare function chatCapabilities(overrides?: Partial<Capabilities>): Capabilities;
|
|
333
|
+
/**
|
|
334
|
+
* Validate a request against a model's capabilities. Throws CapabilityError on
|
|
335
|
+
* the first violation. Runs before any provider call — the single choke point
|
|
336
|
+
* that turns "audio to Claude" from an opaque upstream 400 into a clear error.
|
|
337
|
+
*/
|
|
338
|
+
declare function validateRequest(spec: ModelSpec, req: OracleRequest): void;
|
|
339
|
+
|
|
340
|
+
declare const ANTHROPIC_MODELS: ModelSpec[];
|
|
341
|
+
|
|
342
|
+
declare const OPENAI_MODELS: ModelSpec[];
|
|
343
|
+
|
|
344
|
+
declare const GOOGLE_MODELS: ModelSpec[];
|
|
345
|
+
|
|
346
|
+
/** Canonical id → spec. */
|
|
347
|
+
type Catalog = Record<string, ModelSpec>;
|
|
348
|
+
/** The built-in catalog across Anthropic, OpenAI, and Google. */
|
|
349
|
+
declare const DEFAULT_CATALOG: Catalog;
|
|
350
|
+
/** Merge extra specs over a base catalog (later entries win by id). */
|
|
351
|
+
declare function buildCatalog(base: Catalog, extra?: ModelSpec[]): Catalog;
|
|
352
|
+
/** Look up a model, throwing a ConfigError (with the known ids) if unknown. */
|
|
353
|
+
declare function resolveModel(catalog: Catalog, id: string): ModelSpec;
|
|
354
|
+
/** List every provider the catalog can route to. */
|
|
355
|
+
declare function providersInCatalog(catalog: Catalog): ProviderId[];
|
|
356
|
+
|
|
357
|
+
interface Provider {
|
|
358
|
+
readonly id: ProviderId;
|
|
359
|
+
/** One assistant turn. Server-side tools (e.g. web search) are resolved
|
|
360
|
+
* internally; the returned response is final for this turn (its stopReason is
|
|
361
|
+
* never "pause_turn"). Client-side tool calls return with stopReason
|
|
362
|
+
* "tool_use" for the agent loop to handle. */
|
|
363
|
+
create(spec: ModelSpec, req: OracleRequest): Promise<OracleResponse>;
|
|
364
|
+
/** The same turn as an async stream of normalized OracleEvents. */
|
|
365
|
+
stream(spec: ModelSpec, req: OracleRequest): AsyncIterable<OracleEvent>;
|
|
366
|
+
}
|
|
367
|
+
/** Constructs a provider adapter bound to a resolved API key. */
|
|
368
|
+
type ProviderFactory = (apiKey: string) => Provider;
|
|
369
|
+
|
|
370
|
+
/** Static per-provider keys. */
|
|
371
|
+
type KeyMap = Partial<Record<ProviderId, string>>;
|
|
372
|
+
/** Dynamic key lookup — return undefined to signal "no key for this provider". */
|
|
373
|
+
type KeyResolver = (provider: ProviderId) => string | undefined | Promise<string | undefined>;
|
|
374
|
+
interface KeyOptions {
|
|
375
|
+
keys?: KeyMap;
|
|
376
|
+
/** Consulted first; falls back to `keys` when it returns undefined. */
|
|
377
|
+
resolveKey?: KeyResolver;
|
|
378
|
+
}
|
|
379
|
+
/** Best-effort key-shape check (used by smoke/diagnostics, never for gating —
|
|
380
|
+
* formats drift). */
|
|
381
|
+
declare function looksLikeKey(provider: ProviderId, key: string): boolean;
|
|
382
|
+
/** Redact anything that looks like a provider secret from a string (logs/errors). */
|
|
383
|
+
declare function redact(text: string): string;
|
|
384
|
+
|
|
385
|
+
interface InitOptions {
|
|
386
|
+
/** Static per-provider API keys (BYO). */
|
|
387
|
+
keys?: KeyMap;
|
|
388
|
+
/** Dynamic per-provider key lookup (multi-tenant / per-call). Consulted first. */
|
|
389
|
+
resolveKey?: KeyResolver;
|
|
390
|
+
/** Model used when a call omits `model`. */
|
|
391
|
+
defaultModel?: string;
|
|
392
|
+
/** Override / extend the built-in model catalog. */
|
|
393
|
+
catalog?: Catalog;
|
|
394
|
+
/** Inject provider adapters directly (tests, custom transports). When present
|
|
395
|
+
* for a provider, it is used verbatim and no key is required. */
|
|
396
|
+
providers?: Partial<Record<ProviderId, Provider>>;
|
|
397
|
+
}
|
|
398
|
+
/** Any turn's input — a canonical request with `model` optional (defaultModel fills). */
|
|
399
|
+
type ChatInput = Omit<OracleRequest, "model"> & {
|
|
400
|
+
model?: string;
|
|
401
|
+
};
|
|
402
|
+
interface ExtractTool {
|
|
403
|
+
name: string;
|
|
404
|
+
description?: string;
|
|
405
|
+
/** JSON Schema for the forced tool's arguments. */
|
|
406
|
+
parameters: Record<string, unknown>;
|
|
407
|
+
}
|
|
408
|
+
/** A forced structured extraction: schema in, validated object out. */
|
|
409
|
+
interface ExtractCall {
|
|
410
|
+
model?: string;
|
|
411
|
+
system?: string | TextBlock[];
|
|
412
|
+
user: string | OracleContentBlock[];
|
|
413
|
+
tool: ExtractTool;
|
|
414
|
+
maxTokens?: number;
|
|
415
|
+
}
|
|
416
|
+
/** A web-search-enabled call: the model searches and returns prose. */
|
|
417
|
+
interface SearchCall {
|
|
418
|
+
model?: string;
|
|
419
|
+
system?: string | TextBlock[];
|
|
420
|
+
user: string | OracleContentBlock[];
|
|
421
|
+
maxTokens?: number;
|
|
422
|
+
}
|
|
423
|
+
interface Ai {
|
|
424
|
+
/** The active model catalog. */
|
|
425
|
+
readonly catalog: Catalog;
|
|
426
|
+
/** One assistant turn (non-streaming). */
|
|
427
|
+
chat(input: ChatInput): Promise<OracleResponse>;
|
|
428
|
+
/** One assistant turn as a stream of normalized OracleEvents. */
|
|
429
|
+
stream(input: ChatInput): AsyncIterable<OracleEvent>;
|
|
430
|
+
/** Forced single-tool extraction → validated object. */
|
|
431
|
+
extract<T = unknown>(c: ExtractCall): Promise<{
|
|
432
|
+
value: T;
|
|
433
|
+
usage: OracleUsage;
|
|
434
|
+
}>;
|
|
435
|
+
/** Web-search-grounded prose answer. */
|
|
436
|
+
search(c: SearchCall): Promise<{
|
|
437
|
+
text: string;
|
|
438
|
+
usage: OracleUsage;
|
|
439
|
+
}>;
|
|
440
|
+
}
|
|
441
|
+
/** The minimal inference surface the agent loop and eval harness depend on. */
|
|
442
|
+
type Inference = Pick<Ai, "chat" | "stream" | "catalog">;
|
|
443
|
+
declare function init(opts?: InitOptions): Ai;
|
|
444
|
+
|
|
445
|
+
/** Generate the `llms.txt` context document for a given model catalog. */
|
|
446
|
+
declare function generateLlmsTxt(catalog?: Catalog): string;
|
|
447
|
+
|
|
448
|
+
declare function getProvider(id: ProviderId, apiKey: string): Promise<Provider>;
|
|
449
|
+
/** Test seam: register a provider instance directly (used to inject mocks). */
|
|
450
|
+
declare function registerProvider(id: ProviderId, apiKey: string, provider: Provider): void;
|
|
451
|
+
/** Test seam: clear the adapter cache. */
|
|
452
|
+
declare function clearProviderCache(): void;
|
|
453
|
+
|
|
454
|
+
/** Map any provider error to an OdlaAIError, returning it (does not throw).
|
|
455
|
+
* Re-returns an OdlaAIError unchanged (already normalized). */
|
|
456
|
+
declare function normalizeError(err: unknown, provider: ProviderId): OdlaAIError;
|
|
457
|
+
|
|
458
|
+
type TaintLabel = "web_untrusted" | "operator_pasted_untrusted" | "llm_inherited" | `tool_untrusted:${string}`;
|
|
459
|
+
type TaintSet = Set<TaintLabel>;
|
|
460
|
+
declare function taint(...labels: TaintLabel[]): TaintSet;
|
|
461
|
+
/** Raised when a tool's taint allowlist doesn't cover the conversation's taint. */
|
|
462
|
+
declare class TaintError extends OdlaAIError {
|
|
463
|
+
constructor(message: string);
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Throw unless every label currently on the conversation is in the sink's
|
|
467
|
+
* allowlist. `llm_inherited` is intentionally excludable: a tool that lists it as
|
|
468
|
+
* *not* accepted is one where model-derived instructions must never reach the
|
|
469
|
+
* sink (the classic injected-instruction propagation case).
|
|
470
|
+
*/
|
|
471
|
+
declare function assertSinkAcceptsTaint(sink: string, allowed: TaintLabel[], actual: TaintSet): void;
|
|
472
|
+
|
|
473
|
+
/** What a tool returns after running. */
|
|
474
|
+
interface ToolOutput {
|
|
475
|
+
content: string | OracleContentBlock[];
|
|
476
|
+
isError?: boolean;
|
|
477
|
+
}
|
|
478
|
+
/** Context handed to a tool handler when it runs. */
|
|
479
|
+
interface ToolContext {
|
|
480
|
+
/** The taint currently on the conversation feeding this call. */
|
|
481
|
+
taint: TaintSet;
|
|
482
|
+
/** Optional cancellation signal, threaded from the run. */
|
|
483
|
+
signal?: AbortSignal;
|
|
484
|
+
}
|
|
485
|
+
type ToolHandler = (input: Record<string, unknown>, ctx: ToolContext) => Promise<ToolOutput> | ToolOutput;
|
|
486
|
+
interface ToolDef {
|
|
487
|
+
name: string;
|
|
488
|
+
description: string;
|
|
489
|
+
/** JSON Schema for the tool arguments. */
|
|
490
|
+
inputSchema: Record<string, unknown>;
|
|
491
|
+
/** Local executor. Omit for provider server tools resolved inside the adapter. */
|
|
492
|
+
handler?: ToolHandler;
|
|
493
|
+
/** Taint labels this tool's output introduces into the conversation. */
|
|
494
|
+
outputTaint?: TaintLabel[];
|
|
495
|
+
/** If set, the tool only runs when the conversation taint ⊆ this allowlist. */
|
|
496
|
+
acceptsTaint?: TaintLabel[];
|
|
497
|
+
}
|
|
498
|
+
/** Project a ToolDef to the wire-level OracleTool the model sees. */
|
|
499
|
+
declare function toOracleTool(t: ToolDef): OracleTool;
|
|
500
|
+
|
|
501
|
+
interface Skill {
|
|
502
|
+
/** Skill name — used as the heading for its instructions in the system prompt. */
|
|
503
|
+
name: string;
|
|
504
|
+
/** Guidance appended to the persona's system prompt (when/how to use the tools). */
|
|
505
|
+
instructions?: string;
|
|
506
|
+
/** The tools this skill contributes to the agent. */
|
|
507
|
+
tools: ToolDef[];
|
|
508
|
+
}
|
|
509
|
+
interface ComposedPersona {
|
|
510
|
+
system: string | undefined;
|
|
511
|
+
tools: ToolDef[];
|
|
512
|
+
}
|
|
513
|
+
/** Merge a persona's own tools/system with its attached skills: skill tools are
|
|
514
|
+
* appended to the tool list, and each skill's instructions become a titled
|
|
515
|
+
* section of the system prompt. Order is preserved (persona first, then skills). */
|
|
516
|
+
declare function composeSkills(system: string | undefined, tools: ToolDef[] | undefined, skills: Skill[] | undefined): ComposedPersona;
|
|
517
|
+
|
|
518
|
+
interface MemoryScope {
|
|
519
|
+
/** Messages to prepend before this run's input. */
|
|
520
|
+
load(): Promise<OracleMessage[]> | OracleMessage[];
|
|
521
|
+
/** Persist the messages produced during this run (excludes what load() returned). */
|
|
522
|
+
append(messages: OracleMessage[]): Promise<void> | void;
|
|
523
|
+
}
|
|
524
|
+
/** A simple process-lifetime memory scope. */
|
|
525
|
+
declare class InMemoryScope implements MemoryScope {
|
|
526
|
+
private messages;
|
|
527
|
+
load(): OracleMessage[];
|
|
528
|
+
append(messages: OracleMessage[]): void;
|
|
529
|
+
clear(): void;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
interface Persona {
|
|
533
|
+
/** Human-readable role name (e.g. "researcher", "triager"). */
|
|
534
|
+
name: string;
|
|
535
|
+
/** Canonical model id the persona runs on. */
|
|
536
|
+
model: string;
|
|
537
|
+
/** System prompt defining the persona's behavior. */
|
|
538
|
+
system?: string;
|
|
539
|
+
/** Tools the persona may call. Handlers run locally; handler-less tools are
|
|
540
|
+
* provider server tools. */
|
|
541
|
+
tools?: ToolDef[];
|
|
542
|
+
/** Skills to attach — each contributes tools + instructions to the persona. */
|
|
543
|
+
skills?: Skill[];
|
|
544
|
+
/** Enable the provider's web-search server tool for this persona. */
|
|
545
|
+
webSearch?: boolean;
|
|
546
|
+
/** Max model turns before the loop stops (default 8). */
|
|
547
|
+
maxSteps?: number;
|
|
548
|
+
/** Reasoning depth (applied only where the model supports it). */
|
|
549
|
+
effort?: Effort;
|
|
550
|
+
/** Reasoning mode (applied only where the model supports it). */
|
|
551
|
+
thinking?: ThinkingMode;
|
|
552
|
+
temperature?: number;
|
|
553
|
+
/** Max output tokens per model turn (default 4096). */
|
|
554
|
+
maxTokens?: number;
|
|
555
|
+
/** Persistent memory scope loaded before, and appended after, each run. */
|
|
556
|
+
memory?: MemoryScope;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/** One resolved tool call within a run. */
|
|
560
|
+
interface ToolCallRecord {
|
|
561
|
+
toolUse: ToolUseBlock;
|
|
562
|
+
output: ToolOutput;
|
|
563
|
+
}
|
|
564
|
+
interface AgentRunInput {
|
|
565
|
+
/** A single user turn (convenience). */
|
|
566
|
+
input?: string | OracleContentBlock[];
|
|
567
|
+
/** Or an explicit list of messages (takes precedence when both are given). */
|
|
568
|
+
messages?: OracleMessage[];
|
|
569
|
+
signal?: AbortSignal;
|
|
570
|
+
}
|
|
571
|
+
type StoppedReason = "end_turn" | "max_steps" | "refusal";
|
|
572
|
+
interface AgentRun {
|
|
573
|
+
/** Concatenated text of the final assistant turn. */
|
|
574
|
+
finalText: string;
|
|
575
|
+
/** The last assistant response. */
|
|
576
|
+
response: OracleResponse;
|
|
577
|
+
/** The full conversation (loaded memory + input + assistant/tool turns). */
|
|
578
|
+
messages: OracleMessage[];
|
|
579
|
+
/** Accumulated usage across every model turn. */
|
|
580
|
+
usage: OracleUsage;
|
|
581
|
+
/** Number of model turns taken. */
|
|
582
|
+
steps: number;
|
|
583
|
+
/** Every tool call executed, in order. */
|
|
584
|
+
toolCalls: ToolCallRecord[];
|
|
585
|
+
stoppedReason: StoppedReason;
|
|
586
|
+
}
|
|
587
|
+
declare function runAgent(inference: Inference, persona: Persona, input: AgentRunInput): Promise<AgentRun>;
|
|
588
|
+
|
|
589
|
+
/** One evaluation case — an input plus whatever the grader needs to judge it. */
|
|
590
|
+
interface EvalCase {
|
|
591
|
+
name?: string;
|
|
592
|
+
/** A user turn (string / blocks) or an explicit conversation (message array). */
|
|
593
|
+
input: string | OracleContentBlock[] | OracleMessage[];
|
|
594
|
+
/** Grader-specific expectation (exact string, JSON subset, rubric text, …). */
|
|
595
|
+
expected?: unknown;
|
|
596
|
+
meta?: Record<string, unknown>;
|
|
597
|
+
}
|
|
598
|
+
interface GradeContext {
|
|
599
|
+
case: EvalCase;
|
|
600
|
+
/** The system-under-test's final text output. */
|
|
601
|
+
output: string;
|
|
602
|
+
/** The final model response. */
|
|
603
|
+
response: OracleResponse;
|
|
604
|
+
}
|
|
605
|
+
interface GradeResult {
|
|
606
|
+
pass: boolean;
|
|
607
|
+
/** 0..1 when a grader scores rather than passes/fails. */
|
|
608
|
+
score?: number;
|
|
609
|
+
reason?: string;
|
|
610
|
+
}
|
|
611
|
+
type Grader = (ctx: GradeContext) => Promise<GradeResult> | GradeResult;
|
|
612
|
+
|
|
613
|
+
interface EvalResult {
|
|
614
|
+
case: EvalCase;
|
|
615
|
+
output: string;
|
|
616
|
+
grade: GradeResult;
|
|
617
|
+
response: OracleResponse;
|
|
618
|
+
usage: OracleUsage;
|
|
619
|
+
}
|
|
620
|
+
interface EvalReport {
|
|
621
|
+
total: number;
|
|
622
|
+
passed: number;
|
|
623
|
+
failed: number;
|
|
624
|
+
passRate: number;
|
|
625
|
+
results: EvalResult[];
|
|
626
|
+
usage: OracleUsage;
|
|
627
|
+
}
|
|
628
|
+
interface EvaluateOptions {
|
|
629
|
+
inference: Inference;
|
|
630
|
+
cases: EvalCase[];
|
|
631
|
+
grader: Grader;
|
|
632
|
+
/** Run each case through this persona (agent loop). Mutually exclusive with model. */
|
|
633
|
+
persona?: Persona;
|
|
634
|
+
/** Or run each case as a single chat with this model + system. */
|
|
635
|
+
model?: string;
|
|
636
|
+
system?: string;
|
|
637
|
+
maxTokens?: number;
|
|
638
|
+
/** Max cases run concurrently (default 5). */
|
|
639
|
+
concurrency?: number;
|
|
640
|
+
}
|
|
641
|
+
declare function evaluate(opts: EvaluateOptions): Promise<EvalReport>;
|
|
642
|
+
|
|
643
|
+
/** Pass when trimmed output equals `case.expected` (stringified). */
|
|
644
|
+
declare function exactMatch(): Grader;
|
|
645
|
+
/** Pass when output contains `case.expected` (case-insensitive by default). */
|
|
646
|
+
declare function includes(opts?: {
|
|
647
|
+
caseInsensitive?: boolean;
|
|
648
|
+
}): Grader;
|
|
649
|
+
/** Pass when output parses as JSON and contains every key/value in
|
|
650
|
+
* `case.expected` (a recursive subset match). */
|
|
651
|
+
declare function structuredMatch(): Grader;
|
|
652
|
+
/** Grade open-ended output with a judge model. `case.expected` is the rubric.
|
|
653
|
+
* The judge is asked to return a strict JSON verdict which is tolerantly parsed. */
|
|
654
|
+
declare function llmJudge(opts: {
|
|
655
|
+
inference: Inference;
|
|
656
|
+
model: string;
|
|
657
|
+
extraGuidance?: string;
|
|
658
|
+
}): Grader;
|
|
659
|
+
|
|
660
|
+
/** Entity namespaces odla-ai owns in odla-db (all non-`$`, so no platform clash). */
|
|
661
|
+
declare const NS: {
|
|
662
|
+
readonly conversation: "agent_conversation";
|
|
663
|
+
readonly message: "agent_message";
|
|
664
|
+
readonly run: "agent_run";
|
|
665
|
+
};
|
|
666
|
+
/** Serialized odla-db schema (POST to `/app/:id/schema` as `{ schema: AGENT_SCHEMA }`). */
|
|
667
|
+
declare const AGENT_SCHEMA: {
|
|
668
|
+
readonly entities: {
|
|
669
|
+
readonly agent_conversation: {
|
|
670
|
+
readonly attrs: {
|
|
671
|
+
readonly key: {
|
|
672
|
+
readonly type: "string";
|
|
673
|
+
readonly unique: true;
|
|
674
|
+
readonly indexed: true;
|
|
675
|
+
readonly optional: false;
|
|
676
|
+
};
|
|
677
|
+
readonly sessionId: {
|
|
678
|
+
readonly type: "string";
|
|
679
|
+
readonly unique: false;
|
|
680
|
+
readonly indexed: true;
|
|
681
|
+
readonly optional: false;
|
|
682
|
+
};
|
|
683
|
+
readonly title: {
|
|
684
|
+
readonly type: "string";
|
|
685
|
+
readonly unique: false;
|
|
686
|
+
readonly indexed: false;
|
|
687
|
+
readonly optional: true;
|
|
688
|
+
};
|
|
689
|
+
readonly createdAt: {
|
|
690
|
+
readonly type: "date";
|
|
691
|
+
readonly unique: false;
|
|
692
|
+
readonly indexed: true;
|
|
693
|
+
readonly optional: false;
|
|
694
|
+
};
|
|
695
|
+
readonly updatedAt: {
|
|
696
|
+
readonly type: "date";
|
|
697
|
+
readonly unique: false;
|
|
698
|
+
readonly indexed: true;
|
|
699
|
+
readonly optional: false;
|
|
700
|
+
};
|
|
701
|
+
};
|
|
702
|
+
};
|
|
703
|
+
readonly agent_message: {
|
|
704
|
+
readonly attrs: {
|
|
705
|
+
readonly key: {
|
|
706
|
+
readonly type: "string";
|
|
707
|
+
readonly unique: true;
|
|
708
|
+
readonly indexed: true;
|
|
709
|
+
readonly optional: false;
|
|
710
|
+
};
|
|
711
|
+
readonly sessionId: {
|
|
712
|
+
readonly type: "string";
|
|
713
|
+
readonly unique: false;
|
|
714
|
+
readonly indexed: true;
|
|
715
|
+
readonly optional: false;
|
|
716
|
+
};
|
|
717
|
+
readonly seq: {
|
|
718
|
+
readonly type: "number";
|
|
719
|
+
readonly unique: false;
|
|
720
|
+
readonly indexed: true;
|
|
721
|
+
readonly optional: false;
|
|
722
|
+
};
|
|
723
|
+
readonly role: {
|
|
724
|
+
readonly type: "string";
|
|
725
|
+
readonly unique: false;
|
|
726
|
+
readonly indexed: false;
|
|
727
|
+
readonly optional: false;
|
|
728
|
+
};
|
|
729
|
+
readonly content: {
|
|
730
|
+
readonly type: "string";
|
|
731
|
+
readonly unique: false;
|
|
732
|
+
readonly indexed: false;
|
|
733
|
+
readonly optional: false;
|
|
734
|
+
};
|
|
735
|
+
readonly createdAt: {
|
|
736
|
+
readonly type: "date";
|
|
737
|
+
readonly unique: false;
|
|
738
|
+
readonly indexed: true;
|
|
739
|
+
readonly optional: false;
|
|
740
|
+
};
|
|
741
|
+
};
|
|
742
|
+
};
|
|
743
|
+
readonly agent_run: {
|
|
744
|
+
readonly attrs: {
|
|
745
|
+
readonly key: {
|
|
746
|
+
readonly type: "string";
|
|
747
|
+
readonly unique: true;
|
|
748
|
+
readonly indexed: true;
|
|
749
|
+
readonly optional: false;
|
|
750
|
+
};
|
|
751
|
+
readonly sessionId: {
|
|
752
|
+
readonly type: "string";
|
|
753
|
+
readonly unique: false;
|
|
754
|
+
readonly indexed: true;
|
|
755
|
+
readonly optional: false;
|
|
756
|
+
};
|
|
757
|
+
readonly persona: {
|
|
758
|
+
readonly type: "string";
|
|
759
|
+
readonly unique: false;
|
|
760
|
+
readonly indexed: false;
|
|
761
|
+
readonly optional: true;
|
|
762
|
+
};
|
|
763
|
+
readonly status: {
|
|
764
|
+
readonly type: "string";
|
|
765
|
+
readonly unique: false;
|
|
766
|
+
readonly indexed: true;
|
|
767
|
+
readonly optional: false;
|
|
768
|
+
};
|
|
769
|
+
readonly steps: {
|
|
770
|
+
readonly type: "number";
|
|
771
|
+
readonly unique: false;
|
|
772
|
+
readonly indexed: false;
|
|
773
|
+
readonly optional: false;
|
|
774
|
+
};
|
|
775
|
+
readonly inputTokens: {
|
|
776
|
+
readonly type: "number";
|
|
777
|
+
readonly unique: false;
|
|
778
|
+
readonly indexed: false;
|
|
779
|
+
readonly optional: false;
|
|
780
|
+
};
|
|
781
|
+
readonly outputTokens: {
|
|
782
|
+
readonly type: "number";
|
|
783
|
+
readonly unique: false;
|
|
784
|
+
readonly indexed: false;
|
|
785
|
+
readonly optional: false;
|
|
786
|
+
};
|
|
787
|
+
readonly finalText: {
|
|
788
|
+
readonly type: "string";
|
|
789
|
+
readonly unique: false;
|
|
790
|
+
readonly indexed: false;
|
|
791
|
+
readonly optional: true;
|
|
792
|
+
};
|
|
793
|
+
readonly trace: {
|
|
794
|
+
readonly type: "json";
|
|
795
|
+
readonly unique: false;
|
|
796
|
+
readonly indexed: false;
|
|
797
|
+
readonly optional: false;
|
|
798
|
+
};
|
|
799
|
+
readonly createdAt: {
|
|
800
|
+
readonly type: "date";
|
|
801
|
+
readonly unique: false;
|
|
802
|
+
readonly indexed: true;
|
|
803
|
+
readonly optional: false;
|
|
804
|
+
};
|
|
805
|
+
};
|
|
806
|
+
};
|
|
807
|
+
};
|
|
808
|
+
readonly links: {};
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
type OdlaScalar = string | number | boolean | null;
|
|
812
|
+
interface OdlaLookup {
|
|
813
|
+
ns: string;
|
|
814
|
+
attr: string;
|
|
815
|
+
value: OdlaScalar;
|
|
816
|
+
}
|
|
817
|
+
/** Entity reference: a raw id, or a natural-key `Lookup` for idempotent upsert. */
|
|
818
|
+
type OdlaEntityRef = string | OdlaLookup;
|
|
819
|
+
/** The odla-db transaction op union (subset we emit). */
|
|
820
|
+
type OdlaOp = {
|
|
821
|
+
t: "update";
|
|
822
|
+
ns: string;
|
|
823
|
+
id: OdlaEntityRef;
|
|
824
|
+
attrs: Record<string, unknown>;
|
|
825
|
+
} | {
|
|
826
|
+
t: "merge";
|
|
827
|
+
ns: string;
|
|
828
|
+
id: OdlaEntityRef;
|
|
829
|
+
attrs: Record<string, unknown>;
|
|
830
|
+
} | {
|
|
831
|
+
t: "delete";
|
|
832
|
+
ns: string;
|
|
833
|
+
id: OdlaEntityRef;
|
|
834
|
+
} | {
|
|
835
|
+
t: "link";
|
|
836
|
+
ns: string;
|
|
837
|
+
id: OdlaEntityRef;
|
|
838
|
+
label: string;
|
|
839
|
+
target: OdlaEntityRef;
|
|
840
|
+
} | {
|
|
841
|
+
t: "unlink";
|
|
842
|
+
ns: string;
|
|
843
|
+
id: OdlaEntityRef;
|
|
844
|
+
label: string;
|
|
845
|
+
target: OdlaEntityRef;
|
|
846
|
+
};
|
|
847
|
+
/** An InstaQL-style query object, e.g. `{ ns: { $: { where, order, limit } } }`. */
|
|
848
|
+
type OdlaQuery = Record<string, unknown>;
|
|
849
|
+
/** The subset of the odla-db Admin client odla-ai uses. */
|
|
850
|
+
interface OdlaDbClient {
|
|
851
|
+
/** Apply ops atomically; a stable `mutationId` gives exactly-once replay. */
|
|
852
|
+
transact(ops: OdlaOp[], opts?: {
|
|
853
|
+
mutationId?: string;
|
|
854
|
+
}): Promise<number>;
|
|
855
|
+
/** Run an InstaQL query; returns namespace → rows. */
|
|
856
|
+
query(query: OdlaQuery): Promise<Record<string, Record<string, unknown>[]>>;
|
|
857
|
+
/** Read one of this app's secrets by name (app-key credential; read-only). */
|
|
858
|
+
secrets: {
|
|
859
|
+
get(name: string): Promise<string>;
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
interface OdlaDbMemoryOptions {
|
|
864
|
+
db: OdlaDbClient;
|
|
865
|
+
/** Groups a conversation's turns; stable across runs to accumulate history. */
|
|
866
|
+
sessionId: string;
|
|
867
|
+
/** Optional human-readable title stored on the conversation node. */
|
|
868
|
+
title?: string;
|
|
869
|
+
/** Override entity namespaces (default NS.message / NS.conversation). */
|
|
870
|
+
namespaces?: {
|
|
871
|
+
message?: string;
|
|
872
|
+
conversation?: string;
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
declare class OdlaDbMemory implements MemoryScope {
|
|
876
|
+
private readonly db;
|
|
877
|
+
private readonly sessionId;
|
|
878
|
+
private readonly title;
|
|
879
|
+
private readonly msgNs;
|
|
880
|
+
private readonly convNs;
|
|
881
|
+
private loadedCount;
|
|
882
|
+
constructor(opts: OdlaDbMemoryOptions);
|
|
883
|
+
load(): Promise<OracleMessage[]>;
|
|
884
|
+
append(messages: OracleMessage[]): Promise<void>;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
interface PersistRunOptions {
|
|
888
|
+
db: OdlaDbClient;
|
|
889
|
+
/** Groups runs (typically the same session as the memory scope). */
|
|
890
|
+
sessionId: string;
|
|
891
|
+
personaName?: string;
|
|
892
|
+
/** Stable id for exactly-once persistence; defaults to `${sessionId}:${now}`. */
|
|
893
|
+
runId?: string;
|
|
894
|
+
namespace?: string;
|
|
895
|
+
}
|
|
896
|
+
/** Write a run trace; returns the record key. */
|
|
897
|
+
declare function persistRun(run: AgentRun, opts: PersistRunOptions): Promise<string>;
|
|
898
|
+
interface QueryRunsOptions {
|
|
899
|
+
db: OdlaDbClient;
|
|
900
|
+
sessionId: string;
|
|
901
|
+
limit?: number;
|
|
902
|
+
namespace?: string;
|
|
903
|
+
}
|
|
904
|
+
/** Read persisted runs for a session, newest first. */
|
|
905
|
+
declare function queryRuns(opts: QueryRunsOptions): Promise<Record<string, unknown>[]>;
|
|
906
|
+
|
|
907
|
+
/** Default secret name per provider. */
|
|
908
|
+
declare const DEFAULT_SECRET_NAMES: Record<ProviderId, string>;
|
|
909
|
+
interface OdlaDbKeyResolverOptions {
|
|
910
|
+
/** Map a provider to its secret name (default `<provider>_api_key`). Use this
|
|
911
|
+
* to scope per-end-user keys, e.g. `(p) => \`${p}_api_key__${userSub}\``. */
|
|
912
|
+
secretName?: (provider: ProviderId) => string;
|
|
913
|
+
/** Cache resolved keys in memory (default true). */
|
|
914
|
+
cache?: boolean;
|
|
915
|
+
}
|
|
916
|
+
/** Build a KeyResolver that reads provider keys from odla-db secrets. A missing
|
|
917
|
+
* secret resolves to `undefined` (→ that provider is simply unavailable, and
|
|
918
|
+
* odla-ai throws its own ConfigError) rather than surfacing odla-db's 404. */
|
|
919
|
+
declare function odlaDbKeyResolver(db: OdlaDbClient, opts?: OdlaDbKeyResolverOptions): KeyResolver;
|
|
920
|
+
|
|
921
|
+
type FetchLike = typeof fetch;
|
|
922
|
+
interface ProvisionContext {
|
|
923
|
+
/** The odla-db worker URL — always human-supplied, never hardcoded. */
|
|
924
|
+
endpoint: string;
|
|
925
|
+
/** Operator `ADMIN_SECRET` or an `odla_dev_...` developer token (owns the app). */
|
|
926
|
+
token: string;
|
|
927
|
+
fetch?: FetchLike;
|
|
928
|
+
}
|
|
929
|
+
/** Create an app (owned by the token's developer). Returns its id. */
|
|
930
|
+
declare function createApp(ctx: ProvisionContext, opts?: {
|
|
931
|
+
appId?: string;
|
|
932
|
+
name?: string;
|
|
933
|
+
}): Promise<string>;
|
|
934
|
+
/** Mint a per-app `odla_sk_...` key (shown once). */
|
|
935
|
+
declare function mintAppKey(ctx: ProvisionContext, appId: string): Promise<string>;
|
|
936
|
+
/** Push odla-ai's agent memory/run schema (authenticated with the app key). */
|
|
937
|
+
declare function pushAgentSchema(ctx: {
|
|
938
|
+
endpoint: string;
|
|
939
|
+
fetch?: FetchLike;
|
|
940
|
+
}, appId: string, appKey: string): Promise<void>;
|
|
941
|
+
/** Store a named secret (operator/dev token). Value must be a non-`$` string. */
|
|
942
|
+
declare function putSecret(ctx: ProvisionContext, appId: string, name: string, value: string): Promise<void>;
|
|
943
|
+
interface ProvisionAgentAppOptions extends ProvisionContext {
|
|
944
|
+
appId?: string;
|
|
945
|
+
appName?: string;
|
|
946
|
+
/** Provider keys to store as odla-db secrets (read later via odlaDbKeyResolver). */
|
|
947
|
+
providerKeys?: Partial<Record<ProviderId, string>>;
|
|
948
|
+
/** Map a provider to its secret name (default `<provider>_api_key`). */
|
|
949
|
+
secretName?: (provider: ProviderId) => string;
|
|
950
|
+
/** Push the agent schema (default true). */
|
|
951
|
+
pushSchema?: boolean;
|
|
952
|
+
}
|
|
953
|
+
interface ProvisionedApp {
|
|
954
|
+
appId: string;
|
|
955
|
+
/** The minted `odla_sk_...` app key — pass as `adminToken` to `@odla-ai/db`'s init. */
|
|
956
|
+
appKey: string;
|
|
957
|
+
}
|
|
958
|
+
/** One call to stand up an agent app: create → mint key → push schema → store
|
|
959
|
+
* provider keys as secrets. Returns the appId + app key for the runtime client. */
|
|
960
|
+
declare function provisionAgentApp(opts: ProvisionAgentAppOptions): Promise<ProvisionedApp>;
|
|
961
|
+
|
|
962
|
+
interface EntityCrudSkillOptions {
|
|
963
|
+
/** The injected odla-db client (from @odla-ai/db's init). */
|
|
964
|
+
db: OdlaDbClient;
|
|
965
|
+
/** Entity namespace, e.g. "todos". */
|
|
966
|
+
entity: string;
|
|
967
|
+
/** JSON-Schema `properties` for the create/update fields (e.g. { text: { type: "string" }, done: { type: "boolean" } }). */
|
|
968
|
+
fields: Record<string, unknown>;
|
|
969
|
+
/** Field names required to create (default: none). */
|
|
970
|
+
required?: string[];
|
|
971
|
+
/** Skill name (default `${entity} management`). */
|
|
972
|
+
name?: string;
|
|
973
|
+
/** Extra instructions appended to the generated guidance. */
|
|
974
|
+
instructions?: string;
|
|
975
|
+
/** Singular noun for tool names (default: `entity` with a trailing "s" stripped). */
|
|
976
|
+
singular?: string;
|
|
977
|
+
/** Plural noun for the list tool (default: `entity`). */
|
|
978
|
+
plural?: string;
|
|
979
|
+
/** Input field carrying the entity id in update/delete (default "id"). */
|
|
980
|
+
idField?: string;
|
|
981
|
+
/** Generate a new id on create (default crypto.randomUUID). */
|
|
982
|
+
genId?: () => string;
|
|
983
|
+
/** Attr stamped with Date.now() on create; pass false to disable (default "createdAt"). */
|
|
984
|
+
stampCreatedAt?: string | false;
|
|
985
|
+
/** Default ordering for the list tool (default { createdAt: "asc" }). */
|
|
986
|
+
order?: Record<string, "asc" | "desc">;
|
|
987
|
+
}
|
|
988
|
+
/** Build a CRUD Skill for one odla-db entity. */
|
|
989
|
+
declare function entityCrudSkill(opts: EntityCrudSkillOptions): Skill;
|
|
990
|
+
|
|
991
|
+
export { AGENT_SCHEMA, ANTHROPIC_MODELS, type AgentRun, type AgentRunInput, type Ai, type AudioBlock, type AudioMediaType, type AudioSource, AuthError, type Capabilities, CapabilityError, type Catalog, type ChatInput, type ComposedPersona, ConfigError, type ContentBlockDelta, type ContentBlockDeltaEvent, type ContentBlockStartEvent, type ContentBlockStopEvent, ContextWindowError, DEFAULT_CATALOG, DEFAULT_SECRET_NAMES, type DocumentBlock, type DocumentSource, type Effort, type EntityCrudSkillOptions, type EvalCase, type EvalReport, type EvalResult, type EvaluateOptions, type ExtractCall, type ExtractTool, GOOGLE_MODELS, type GradeContext, type GradeResult, type Grader, type ImageBlock, type ImageMediaType, type ImageSource, InMemoryScope, type Inference, type InitOptions, InvalidRequestError, type KeyMap, type KeyOptions, type KeyResolver, type MemoryScope, type MessageDeltaEvent, type MessageStartEvent, type MessageStopEvent, type ModelKind, type ModelSpec, NS, OPENAI_MODELS, OdlaAIError, type OdlaDbClient, type OdlaDbKeyResolverOptions, OdlaDbMemory, type OdlaDbMemoryOptions, type OdlaEntityRef, type OdlaLookup, type OdlaOp, type OdlaQuery, type OdlaScalar, type OracleContentBlock, type OracleErrorEvent, type OracleErrorShape, type OracleErrorType, type OracleEvent, type OracleMessage, type OracleRequest, type OracleResponse, type OracleRole, type OracleStopReason, type OracleTool, type OracleUsage, type PersistRunOptions, type Persona, type Provider, ProviderError, type ProviderFactory, type ProviderId, type ProvisionAgentAppOptions, type ProvisionContext, type ProvisionedApp, type QueryRunsOptions, RateLimitError, type ResponseFormat, type SearchCall, type Skill, type StoppedReason, TaintError, type TaintLabel, type TaintSet, type TextBlock, type ThinkingBlock, type ThinkingMode, type ToolCallRecord, type ToolChoice, type ToolContext, type ToolDef, type ToolHandler, type ToolOutput, type ToolResultBlock, type ToolUseBlock, addUsage, assertSinkAcceptsTaint, blocksOf, buildCatalog, chatCapabilities, clearProviderCache, composeSkills, createApp, emptyUsage, entityCrudSkill, evaluate, exactMatch, extractText, extractToolUses, generateLlmsTxt, getProvider, includes, init, isAudioBlock, isDocumentBlock, isImageBlock, isTextBlock, isThinkingBlock, isToolResultBlock, isToolUseBlock, llmJudge, looksLikeKey, mintAppKey, normalizeError, odlaDbKeyResolver, persistRun, providersInCatalog, provisionAgentApp, pushAgentSchema, putSecret, queryRuns, redact, registerProvider, resolveModel, runAgent, structuredMatch, taint, toOracleTool, validateRequest };
|