@molecule/api-ai-agents-llm 1.0.0 → 1.0.1

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.
Files changed (2) hide show
  1. package/README.md +203 -0
  2. package/package.json +15 -9
package/README.md ADDED
@@ -0,0 +1,203 @@
1
+ <!--
2
+ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
+ Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
+ Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
+ To change this document, edit the module-level JSDoc in src/index.ts.
6
+ Generated: 2026-08-04T01:47:27.608Z
7
+ -->
8
+
9
+ # @molecule/api-ai-agents-llm
10
+
11
+ > **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
12
+ > It is written to be read by coding agents as much as by people, and is generated from this
13
+ > package's source — edit `src/index.ts` JSDoc, not this file.
14
+
15
+ LLM-backed AI agents provider for molecule.dev — the batteries-included
16
+ tool-calling loop that implements the `@molecule/api-ai-agents` core contract.
17
+
18
+ Ships a default `provider` (`name: 'llm'`) that drives a model↔tool loop over
19
+ the swappable `ai` chat bond (`@molecule/api-ai`): it calls the model,
20
+ executes any tools the model requests via each `AITool.execute()`, feeds the
21
+ results back, and repeats until the model stops calling tools (or the
22
+ `maxSteps` budget is exhausted). Bond it once at startup, then drive it from
23
+ anywhere via the `@molecule/api-ai-agents` accessor.
24
+
25
+ ## Quick Start
26
+
27
+ ```typescript
28
+ import { bond } from '@molecule/api-bond'
29
+ import { requireProvider } from '@molecule/api-ai-agents'
30
+ import { provider as agents } from '@molecule/api-ai-agents-llm'
31
+ import type { AITool } from '@molecule/api-ai'
32
+
33
+ // Wire at startup (an `ai` provider must already be bonded).
34
+ bond('ai-agents', agents)
35
+
36
+ const myTool: AITool = {
37
+ name: 'add',
38
+ description: 'Add two numbers',
39
+ parameters: {
40
+ type: 'object',
41
+ properties: { a: { type: 'number' }, b: { type: 'number' } },
42
+ required: ['a', 'b'],
43
+ },
44
+ execute: async (input) => {
45
+ const { a, b } = input as { a: number; b: number }
46
+ return a + b
47
+ },
48
+ }
49
+
50
+ const result = await requireProvider().run({
51
+ task: 'What is 1 + 2? Use the add tool.',
52
+ tools: [myTool],
53
+ })
54
+ console.log(result.output) // final assistant answer
55
+ console.log(result.steps) // intermediate tool calls + results
56
+ console.log(result.usage) // token usage summed across all model calls
57
+ ```
58
+
59
+ ## Type
60
+
61
+ `provider`
62
+
63
+ ## Installation
64
+
65
+ ```bash
66
+ npm install @molecule/api-ai-agents-llm @molecule/api-ai @molecule/api-ai-agents @molecule/api-i18n
67
+ ```
68
+
69
+ ## API
70
+
71
+ ### Classes
72
+
73
+ #### `AgentRunError`
74
+
75
+ Thrown by `run()` when the agentic loop fails partway through — a provider
76
+ API error (rate limit, auth, overload, network), an abort, or any other
77
+ exception raised while draining a model turn or executing a tool.
78
+
79
+ ### Constants
80
+
81
+ #### `provider`
82
+
83
+ The LLM-backed AI agents provider: a tool-calling loop over the bonded `ai`
84
+ chat provider.
85
+
86
+ Bond it with `bond('ai-agents', provider)` and drive it with
87
+ `requireProvider().run({ task, tools })`. Requires a bonded `ai` provider
88
+ whose model supports tool use.
89
+
90
+ ```typescript
91
+ const provider: AIAgentsProvider
92
+ ```
93
+
94
+ ## Core Interface
95
+
96
+ Implements `@molecule/api-ai-agents` interface.
97
+
98
+ ## Bond Wiring
99
+
100
+ Setup function to register this provider with the core interface:
101
+
102
+ ```typescript
103
+ import { setProvider } from '@molecule/api-ai-agents'
104
+ import { provider } from '@molecule/api-ai-agents-llm'
105
+
106
+ export function setupAiAgentsLlm(): void {
107
+ setProvider(provider)
108
+ }
109
+ ```
110
+
111
+ ## Injection Notes
112
+
113
+ ### Requirements
114
+
115
+ Peer dependencies:
116
+
117
+ - `@molecule/api-ai` ^1.0.1
118
+ - `@molecule/api-ai-agents` ^1.0.1
119
+ - `@molecule/api-i18n` ^1.0.1
120
+
121
+ ### Runtime Dependencies
122
+
123
+ - `@molecule/api-ai`
124
+ - `@molecule/api-ai-agents`
125
+ - `@molecule/api-i18n`
126
+
127
+ **Requires a bonded `ai` provider** (`bond('ai', provider)` or a named
128
+ provider selected via `run({ provider: 'anthropic' })`) whose model supports
129
+ tool use — this agent has no model of its own; it orchestrates the `ai` bond.
130
+
131
+ The loop executes your tools: each model `tool_use` runs the matching
132
+ `AITool.execute(input)` and the return value is fed back as a `tool_result`.
133
+ A thrown tool error or an unknown tool name becomes an error `tool_result`
134
+ (recorded with `isError: true`) instead of aborting the run, so the model can
135
+ recover. `run()` requires exactly one of `task` (a single user turn) or
136
+ `messages` (a full history); it throws if neither — or both — is supplied.
137
+
138
+ Every model turn streams by default (`input.stream` — set `false` to force
139
+ non-streaming) and, when `input.cacheControl` is set, is passed through to
140
+ `ai.chat()` on every turn so a provider that supports prompt caching (e.g.
141
+ `@molecule/api-ai-anthropic`) doesn't re-bill the identical `system` + `tools`
142
+ prefix on each of up to `maxSteps` turns. Note `onEvent` is only an
143
+ INCREMENTAL live hook while streaming — with `stream: false` it fires once
144
+ per turn with the whole response.
145
+
146
+ Failure semantics (how to tell failure modes apart):
147
+
148
+ - **Tool failure** (throwing `execute()`, unknown tool name) — NON-fatal:
149
+ recorded on the step with `isError: true` and fed back to the model.
150
+ - **AI provider API failure** (rate limit, bad key, overload, network — the
151
+ `ai` bond emits an in-band `error` ChatEvent), **an abort, or any other
152
+ mid-run exception** — FATAL: `run()` rejects with an `AgentRunError`
153
+ (message text unchanged from a plain `Error`) carrying the `usage` and
154
+ `steps` accumulated across every turn that completed before the failure —
155
+ a caller that meters spend can book that partial usage instead of losing
156
+ it. `run()` never resolves with a silently empty `output`, so an empty
157
+ `result.output` means the model genuinely produced no text, not that the
158
+ API failed.
159
+ - **Step budget exhausted** — resolves normally; `output` is the last
160
+ assistant text or an explicit "step budget exhausted" note.
161
+
162
+ Swappable like any bond: replace this LLM agent with your own
163
+ `AIAgentsProvider` via `bond('ai-agents', myProvider)` — nothing else changes.
164
+
165
+ ## E2E Tests
166
+
167
+ Integration checklist — drive the real UI (live preview, no mocks), give the
168
+ agent a task that genuinely needs several tool calls, adapt each item to this
169
+ app's actual agent surface + its registered tools, and check every box off one
170
+ by one. A box you can't check is an integration bug to fix — not a skip:
171
+
172
+ - [ ] A multi-step task drives a real agentic LOOP, not one shot: `run()`
173
+ records more than one entry in `result.steps`, and each `toolCalls[]` names a
174
+ tool the agent was actually given. Confirm each tool's `execute()` truly RAN
175
+ via its own side effect / log / the resource it touched — not that the model
176
+ narrated calling it — and that `result.output` is a final answer that USES
177
+ those tool results to complete the task.
178
+ - [ ] The loop TERMINATES cleanly: it either reaches a done state (the model
179
+ stops calling tools, so `run()` returns the final `output`) or hits the
180
+ `maxSteps` cap (default 10) and stops with the step-budget note as `output`.
181
+ It never spins forever or ping-pongs the same tool endlessly — a step cap
182
+ exists and is honored: `result.steps.length <= maxSteps`, and a task built to
183
+ loop past the budget stops AT the cap rather than running away.
184
+ - [ ] A tool that fails mid-loop is handled, not fatal: when a tool's
185
+ `execute()` throws (or the model names a tool that was never registered), that
186
+ call is caught and fed back to the model as an error tool result — the
187
+ matching `toolCalls[]` has `isError: true`, the loop continues, and the run
188
+ still returns a result. The request never crashes. (Only an `ai`-provider
189
+ failure rejects — as `AgentRunError` carrying the partial `usage`/`steps` —
190
+ and it surfaces as a handled error, not an unhandled throw.)
191
+ - [ ] If the run streams (the default), the UI shows progress INCREMENTALLY:
192
+ the `onEvent` hook fires per `ChatEvent` (thinking `text`, `tool_use`, `done`)
193
+ as they arrive, so the user watches the agent think + call tools live — not a
194
+ long freeze then one blob at the end.
195
+ - [ ] SECURITY — the agent can call ONLY the tools handed to this run: a tool
196
+ name the model invents (or one injected via the task or a tool's own output)
197
+ that was never in `input.tools` is refused as an `unknown tool` error, not
198
+ executed. Tool execution stays server-side under its backend's guards (e.g.
199
+ the `@molecule/api-ai-tools` `pathGuards`/`redactSecrets`/`blockCommand`), and
200
+ the `ai` provider key lives on the API, never the client. Feed a
201
+ prompt-injected instruction (in the task, or in data a tool returns) telling
202
+ the agent to escape the workspace, run a privileged command, or exfiltrate a
203
+ secret, and confirm it CANNOT do anything the user couldn't do directly.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-ai-agents-llm",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "LLM-backed AI agents provider for molecule.dev — a tool-calling loop over the swappable @molecule/api-ai chat bond",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -17,7 +17,8 @@
17
17
  }
18
18
  },
19
19
  "files": [
20
- "dist"
20
+ "dist",
21
+ "README.md"
21
22
  ],
22
23
  "keywords": [
23
24
  "molecule",
@@ -28,16 +29,21 @@
28
29
  "llm"
29
30
  ],
30
31
  "license": "Apache-2.0",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/molecule-dev/molecule.git",
35
+ "directory": "packages/api/bonds/ai-agents/llm"
36
+ },
31
37
  "peerDependencies": {
32
- "@molecule/api-ai": "^1.0.0",
33
- "@molecule/api-ai-agents": "^1.0.0",
34
- "@molecule/api-i18n": "^1.0.0"
38
+ "@molecule/api-ai": "^1.0.1",
39
+ "@molecule/api-ai-agents": "^1.0.1",
40
+ "@molecule/api-i18n": "^1.0.1"
35
41
  },
36
42
  "devDependencies": {
37
- "@molecule/api-ai": "1.0.0",
38
- "@molecule/api-ai-agents": "1.0.0",
39
- "@molecule/api-bond": "1.0.0",
40
- "@molecule/api-i18n": "1.0.0",
43
+ "@molecule/api-ai": "1.0.1",
44
+ "@molecule/api-ai-agents": "1.0.1",
45
+ "@molecule/api-bond": "1.0.1",
46
+ "@molecule/api-i18n": "1.0.1",
41
47
  "@types/node": "26.1.2",
42
48
  "typescript": "6.0.3",
43
49
  "vitest": "4.1.10"