@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/llms.txt
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# @odla-ai/ai — LLM context
|
|
2
|
+
|
|
3
|
+
One general-purpose interface for AI inference across Anthropic (Claude), OpenAI
|
|
4
|
+
(GPT), and Google (Gemini) — text, image, and audio — plus a tool-use agent
|
|
5
|
+
engine and an eval harness. Library-only: import in-process, bring your own keys.
|
|
6
|
+
Isomorphic (Node 20+, Cloudflare Workers, browser). Provider SDKs are lazy-loaded.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
npm i @odla-ai/ai
|
|
11
|
+
# provider SDKs are peer-lazy-loaded; install those you use:
|
|
12
|
+
# @anthropic-ai/sdk openai @google/genai
|
|
13
|
+
# optional, for odla-db-backed storage + secrets:
|
|
14
|
+
# @odla-ai/db
|
|
15
|
+
|
|
16
|
+
## Core call
|
|
17
|
+
|
|
18
|
+
import { init } from "@odla-ai/ai";
|
|
19
|
+
const ai = init({ keys: { anthropic: KEY, openai: KEY, google: KEY }, defaultModel: "claude-opus-4-8" });
|
|
20
|
+
const res = await ai.chat({ model: "gpt-5", messages: [{ role: "user", content: "hi" }], maxTokens: 256 });
|
|
21
|
+
// res.content: OracleContentBlock[] (text/tool_use/thinking)
|
|
22
|
+
|
|
23
|
+
- `ai.stream(input)` → async iterable of normalized events: message_start →
|
|
24
|
+
content_block_start → content_block_delta {text_delta|thinking_delta|input_json_delta}
|
|
25
|
+
→ content_block_stop → message_delta → message_stop (plus `error`).
|
|
26
|
+
- `ai.extract<T>({ model, user, tool })` → forced tool call; returns a parsed object.
|
|
27
|
+
- `ai.search({ model, user })` → web-search-grounded prose.
|
|
28
|
+
|
|
29
|
+
## Content blocks (multimodal)
|
|
30
|
+
|
|
31
|
+
text; image { source: base64|url }; audio { source: base64|url }; document (PDF);
|
|
32
|
+
tool_use { id, name, input }; tool_result { toolUseId, content }; thinking.
|
|
33
|
+
Audio input is accepted by OpenAI (`gpt-audio`) and Google, NOT by Claude — an
|
|
34
|
+
audio block to a Claude model throws CapabilityError before any network call.
|
|
35
|
+
|
|
36
|
+
## Agents
|
|
37
|
+
|
|
38
|
+
import { runAgent, type Persona, type ToolDef } from "@odla-ai/ai";
|
|
39
|
+
const add: ToolDef = { name: "add", description: "add", inputSchema: {...}, handler: (i) => ({ content: String(i.a + i.b) }) };
|
|
40
|
+
const persona: Persona = { name: "calc", model: "claude-opus-4-8", system: "...", tools: [add], maxSteps: 4 };
|
|
41
|
+
const run = await runAgent(ai, persona, { input: "what is 21+21?" });
|
|
42
|
+
// run.finalText, run.toolCalls, run.usage, run.steps, run.stoppedReason
|
|
43
|
+
|
|
44
|
+
Tools may carry taint labels (outputTaint / acceptsTaint) for a CaMeL-style
|
|
45
|
+
prompt-injection gate. Personas may carry a MemoryScope.
|
|
46
|
+
|
|
47
|
+
## Skills
|
|
48
|
+
|
|
49
|
+
A Skill = { name, instructions?, tools: ToolDef[] } is a bundle you attach to a
|
|
50
|
+
persona (persona.skills); its tools merge into the model's tool list and its
|
|
51
|
+
instructions into the system prompt. Turn an odla-db entity into CRUD tools:
|
|
52
|
+
|
|
53
|
+
import { entityCrudSkill } from "@odla-ai/ai";
|
|
54
|
+
const todos = entityCrudSkill({ db, entity: "todos", fields: { text: { type: "string" }, done: { type: "boolean" } }, required: ["text"] });
|
|
55
|
+
// → tools: list_todos, create_todo, update_todo (partial), delete_todo — handlers write to odla-db
|
|
56
|
+
const run = await runAgent(ai, { name: "todo-bot", model: "gpt-5", skills: [todos] }, { input: "add buy milk" });
|
|
57
|
+
|
|
58
|
+
## Evals
|
|
59
|
+
|
|
60
|
+
import { evaluate, exactMatch, llmJudge } from "@odla-ai/ai";
|
|
61
|
+
const report = await evaluate({ inference: ai, model: "claude-opus-4-8", grader: exactMatch(), cases: [{ input, expected }] });
|
|
62
|
+
// graders: exactMatch, includes, structuredMatch, llmJudge; pass a persona to eval an agent.
|
|
63
|
+
|
|
64
|
+
## Storage + BYO keys via odla-db (@odla-ai/db) — the handshake
|
|
65
|
+
|
|
66
|
+
Follows odla-db's model. An agent never takes a platform secret; it does a
|
|
67
|
+
device-authorization handshake for a scoped, revocable token, then provisions.
|
|
68
|
+
|
|
69
|
+
import { requestToken, init as odlaInit } from "@odla-ai/db";
|
|
70
|
+
import { provisionAgentApp, odlaDbKeyResolver, OdlaDbMemory, persistRun, init } from "@odla-ai/ai";
|
|
71
|
+
|
|
72
|
+
// 1. Handshake: the human supplies the endpoint and approves a short code in odla-db Studio.
|
|
73
|
+
const { token } = await requestToken({ endpoint: ODLA_URL, onCode: ({ userCode }) => show(userCode) });
|
|
74
|
+
|
|
75
|
+
// 2. Provision: create app, mint app key, push agent schema, store BYO provider keys as secrets.
|
|
76
|
+
const { appId, appKey } = await provisionAgentApp({ endpoint: ODLA_URL, token, providerKeys: { openai: OPENAI_KEY } });
|
|
77
|
+
|
|
78
|
+
// 3. Runtime: read keys from odla-db secrets; persist memory + run traces.
|
|
79
|
+
const db = odlaInit({ appId, adminToken: appKey, endpoint: ODLA_URL });
|
|
80
|
+
const ai = init({ resolveKey: odlaDbKeyResolver(db) });
|
|
81
|
+
const persona = { name: "assistant", model: "gpt-5", memory: new OdlaDbMemory({ db, sessionId: "user-42" }) };
|
|
82
|
+
const run = await runAgent(ai, persona, { input: "hello" });
|
|
83
|
+
await persistRun(run, { db, sessionId: "user-42" });
|
|
84
|
+
|
|
85
|
+
Secrets are read-only from the app key (odlaDbKeyResolver → db.secrets.get); they
|
|
86
|
+
are WRITTEN only with the operator/dev token via provisionAgentApp/putSecret. Keys
|
|
87
|
+
are AES-GCM-encrypted at rest in odla-db and never returned to browser clients.
|
|
88
|
+
|
|
89
|
+
## Errors
|
|
90
|
+
|
|
91
|
+
Every error is an OdlaAIError subclass with a stable `code` — branch on err.code:
|
|
92
|
+
config, auth, rate_limit, capability_unsupported, context_window, invalid_request,
|
|
93
|
+
tool_input_invalid, provider_error.
|
|
94
|
+
|
|
95
|
+
## Models
|
|
96
|
+
|
|
97
|
+
- `claude-opus-4-8` (anthropic) — text, image, tools, thinking, effort, web-search, structured
|
|
98
|
+
- `claude-sonnet-5` (anthropic) — text, image, tools, thinking, effort, web-search, structured
|
|
99
|
+
- `claude-fable-5` (anthropic) — text, image, tools, thinking, effort, web-search, structured
|
|
100
|
+
- `claude-haiku-4-5` (anthropic) — text, image, tools, structured
|
|
101
|
+
- `gpt-5.5` (openai) — text, image, tools, effort, structured
|
|
102
|
+
- `gpt-5` (openai) — text, image, tools, effort, structured
|
|
103
|
+
- `gpt-5-mini` (openai) — text, image, tools, effort, structured
|
|
104
|
+
- `gpt-4o` (openai) — text, image, tools, structured
|
|
105
|
+
- `gpt-audio` (openai) — text, audio, tools, structured
|
|
106
|
+
- `gemini-2.5-pro` (google) — text, image, audio, tools, thinking, effort, web-search, structured
|
|
107
|
+
- `gemini-2.5-flash` (google) — text, image, audio, tools, thinking, effort, web-search, structured
|
|
108
|
+
- `gemini-2.0-flash` (google) — text, image, audio, tools, web-search, structured
|
|
109
|
+
|
|
110
|
+
Model ids live in a data catalog and drift — verify against provider docs; extend
|
|
111
|
+
via buildCatalog / init({ catalog }).
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@odla-ai/ai",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "One general-purpose interface for AI inference across Anthropic (Claude), OpenAI, and Google (Gemini) — text, image, and audio — plus a tool-use agent engine and eval harness. The place every odla app reaches for when it needs AI. Isomorphic: Node 20+, Cloudflare Workers, the browser.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"llms.txt"
|
|
21
|
+
],
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=20"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"odla",
|
|
31
|
+
"odla-ai",
|
|
32
|
+
"ai",
|
|
33
|
+
"llm",
|
|
34
|
+
"claude",
|
|
35
|
+
"anthropic",
|
|
36
|
+
"openai",
|
|
37
|
+
"gpt",
|
|
38
|
+
"google",
|
|
39
|
+
"gemini",
|
|
40
|
+
"agent",
|
|
41
|
+
"inference",
|
|
42
|
+
"multimodal",
|
|
43
|
+
"tool-use"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsup",
|
|
47
|
+
"clean": "rm -rf dist",
|
|
48
|
+
"typecheck": "tsc --noEmit",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"smoke": "tsx scripts/smoke.ts",
|
|
51
|
+
"gen:llms": "tsx -e \"import('./src/index.ts').then(m => process.stdout.write(m.generateLlmsTxt()))\" > llms.txt",
|
|
52
|
+
"check:publish": "tsx scripts/check-publish-safety.ts",
|
|
53
|
+
"prepublishOnly": "npm run build && npm run check:publish"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@anthropic-ai/sdk": "^0.70.0",
|
|
57
|
+
"@google/genai": "^1.0.0",
|
|
58
|
+
"openai": "^6.0.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@odla-ai/db": "^0.2.0"
|
|
62
|
+
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"@odla-ai/db": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@odla-ai/db": "^0.2.1",
|
|
70
|
+
"@types/node": "^22.10.0",
|
|
71
|
+
"tsup": "^8.3.0",
|
|
72
|
+
"tsx": "^4.19.0",
|
|
73
|
+
"typescript": "^5.7.2",
|
|
74
|
+
"vitest": "^3.0.0"
|
|
75
|
+
}
|
|
76
|
+
}
|