@absolutejs/ai 0.0.10 → 0.0.12

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.
@@ -0,0 +1,115 @@
1
+ /**
2
+ * `codeModeTool` — Code Mode for AI agents.
3
+ *
4
+ * Instead of exposing N tools to the model and having it call them one
5
+ * at a time (N round-trips per turn, N tool-call tokens, the model has
6
+ * to track intermediate state in context), Code Mode exposes ONE tool:
7
+ * `run_code`. The model sees the typed TypeScript signatures of all
8
+ * underlying tools and emits a single function that chains them.
9
+ *
10
+ * Pattern was popularized by Cloudflare's Dynamic Workers (April 2026
11
+ * blog post: "100× faster than containers"). Anthropic's programmatic
12
+ * tool calling is the same idea — execution pauses on a sub-tool call,
13
+ * the API yields a tool_use, you return a result, execution resumes.
14
+ * Both vendors report ~80% token reduction on multi-tool turns.
15
+ *
16
+ * ```ts
17
+ * import { codeModeTool } from '@absolutejs/ai/tools';
18
+ *
19
+ * const tools = {
20
+ * run_code: codeModeTool({
21
+ * timeout: 5000,
22
+ * tools: {
23
+ * search_products: {
24
+ * description: 'Full-text search the product catalogue.',
25
+ * tsSignature: '(query: string) => Promise<Product[]>',
26
+ * handler: async (q) => db.products.search(q as string),
27
+ * },
28
+ * get_product: {
29
+ * description: 'Fetch one product by id.',
30
+ * tsSignature: '(id: string) => Promise<Product | null>',
31
+ * handler: async (id) => db.products.findById(id as string),
32
+ * },
33
+ * },
34
+ * types: `
35
+ * type Product = { id: string; name: string; price: number };
36
+ * `,
37
+ * }),
38
+ * };
39
+ * ```
40
+ *
41
+ * The model emits a single function:
42
+ *
43
+ * ```js
44
+ * const items = await search_products('hat');
45
+ * const cheapest = items.sort((a, b) => a.price - b.price)[0];
46
+ * const detail = await get_product(cheapest.id);
47
+ * return { name: detail.name, price: detail.price };
48
+ * ```
49
+ *
50
+ * One sandbox eval. Two host-fn calls. One returned value. The model's
51
+ * context only ever sees the final return — intermediate tool results
52
+ * don't enter the conversation window, so multi-step workflows are
53
+ * dramatically cheaper.
54
+ *
55
+ * Each underlying tool's `handler` runs on the HOST side (not in the
56
+ * sandbox). Async host fns work on both FFI (via the 0.4 pump) and
57
+ * Worker backends since isolated-jsc 0.4+. Errors thrown by host
58
+ * handlers propagate into the sandbox as JS Errors the model can
59
+ * catch and recover from.
60
+ */
61
+ import type { AIToolDefinition } from "../../../types/ai";
62
+ /**
63
+ * One callable surfaced to the sandbox. The `tsSignature` shows up in
64
+ * the model-visible description; `handler` runs on the host when the
65
+ * sandbox calls it.
66
+ */
67
+ export type CodeModeHostTool = {
68
+ /** One-line human description of what this tool does. */
69
+ description: string;
70
+ /** TypeScript signature shown to the model. Example:
71
+ * `'(query: string, options?: { limit?: number }) => Promise<Item[]>'`.
72
+ * The model writes JS against this signature; we don't enforce it at
73
+ * runtime — type-check is the model's responsibility. */
74
+ tsSignature: string;
75
+ /** Host implementation. Receives positional args as the model passed
76
+ * them. Return value is structure-cloned back into the sandbox. */
77
+ handler: (...args: unknown[]) => unknown;
78
+ };
79
+ /** Options for {@link codeModeTool}. */
80
+ export type CodeModeToolOptions = {
81
+ /** Map of host-tool name → {@link CodeModeHostTool}. */
82
+ tools: Record<string, CodeModeHostTool>;
83
+ /**
84
+ * Optional shared TypeScript declarations stitched into the prompt
85
+ * (type aliases, interfaces, etc.) so signatures can reference them.
86
+ * Use raw TS source; no parsing happens host-side.
87
+ */
88
+ types?: string;
89
+ /**
90
+ * Per-isolate heap memory cap (MB). Default 64. As with the regular
91
+ * code-execution tool, FFI's cold heap is much smaller than Worker's,
92
+ * but per-call retention scales similarly.
93
+ */
94
+ memoryLimit?: number;
95
+ /** Wall-clock timeout per `run_code` call (ms). Default 5000. */
96
+ timeout?: number;
97
+ /**
98
+ * isolated-jsc backend. Defaults to `'auto'`. Since isolated-jsc 0.4
99
+ * both backends support async host fns, so the choice is purely
100
+ * about cold spawn (FFI wins ~6×) vs Web APIs availability (Worker
101
+ * has `URL` / `TextEncoder` / `WebSocket`; FFI does not).
102
+ */
103
+ backend?: "auto" | "ffi" | "worker";
104
+ /**
105
+ * Override the auto-generated description. By default we emit the
106
+ * model-facing prompt: a short instruction header + the host fn
107
+ * signatures + any shared `types`.
108
+ */
109
+ description?: string;
110
+ /** Pool size cap. Default 8. */
111
+ poolSize?: number;
112
+ /** Recycle the isolate after N successful runs. Default 50. */
113
+ recycleAfter?: number;
114
+ };
115
+ export declare const codeModeTool: (options: CodeModeToolOptions) => AIToolDefinition;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `@absolutejs/ai/tools` — first-party `AIToolDefinition`s ready to drop
3
+ * into the `tools: {...}` map you hand to `streamAI` / `generateAI`.
4
+ *
5
+ * - {@link codeExecutionTool} — execute model-generated JavaScript in a
6
+ * sandboxed `@absolutejs/isolated-jsc` isolate. Optional peer; install
7
+ * `@absolutejs/isolated-jsc` to use it.
8
+ * - {@link codeModeTool} — "Code Mode" wrapper for N host tools: model
9
+ * sees typed TS signatures, emits one function chaining several
10
+ * tool calls, ~80% token reduction vs N separate tool calls.
11
+ */
12
+ export { codeExecutionTool, type CodeExecutionToolOptions, } from "./codeExecution";
13
+ export { type CodeModeHostTool, codeModeTool, type CodeModeToolOptions, } from "./codeMode";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/ai",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "AI runtime, providers, streaming, and framework adapters extracted from AbsoluteJS",
5
5
  "license": "BSL-1.1",
6
6
  "type": "module",
@@ -62,6 +62,10 @@
62
62
  "./providers": {
63
63
  "import": "./dist/ai/providers/openaiCompatible.js",
64
64
  "types": "./dist/src/ai/providers/openaiCompatible.d.ts"
65
+ },
66
+ "./tools": {
67
+ "import": "./dist/ai/tools/index.js",
68
+ "types": "./dist/src/ai/tools/index.d.ts"
65
69
  }
66
70
  },
67
71
  "dependencies": {
@@ -69,6 +73,7 @@
69
73
  "@absolutejs/sync": "0.7.0"
70
74
  },
71
75
  "peerDependencies": {
76
+ "@absolutejs/isolated-jsc": ">= 0.4.0",
72
77
  "@angular/core": "^21.0.0",
73
78
  "elysia": "^1.4.18",
74
79
  "react": "^19.2.0",
@@ -76,6 +81,9 @@
76
81
  "vue": "^3.5.27"
77
82
  },
78
83
  "peerDependenciesMeta": {
84
+ "@absolutejs/isolated-jsc": {
85
+ "optional": true
86
+ },
79
87
  "@angular/core": {
80
88
  "optional": true
81
89
  },
@@ -91,21 +99,22 @@
91
99
  },
92
100
  "devDependencies": {
93
101
  "@absolutejs/absolute": "^0.19.0-beta.1051",
102
+ "@absolutejs/isolated-jsc": "0.6.0",
94
103
  "@angular/core": "^21.0.0",
104
+ "@eslint/js": "^10.0.1",
95
105
  "@types/bun": "1.3.9",
96
106
  "@types/react": "19.2.0",
97
107
  "elysia": "1.4.18",
98
- "react": "19.2.1",
99
- "svelte": "5.55.0",
100
- "typescript": "^5.9.3",
101
- "vue": "3.5.27",
102
- "@eslint/js": "^10.0.1",
103
108
  "eslint": "^10.0.3",
109
+ "eslint-plugin-absolute": "^0.2.6",
110
+ "eslint-plugin-promise": "^7.2.1",
104
111
  "globals": "^17.4.0",
105
112
  "prettier": "^3.5.3",
113
+ "react": "19.2.1",
114
+ "svelte": "5.55.0",
115
+ "typescript": "^5.9.3",
106
116
  "typescript-eslint": "^8.56.1",
107
- "eslint-plugin-absolute": "^0.2.6",
108
- "eslint-plugin-promise": "^7.2.1"
117
+ "vue": "3.5.27"
109
118
  },
110
119
  "scripts": {
111
120
  "build": "bun run scripts/build.ts",