@lunora/agent 1.0.0-alpha.4 → 1.0.0-alpha.6

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/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AgentDefinition, c as AgentCompact, d as AgentEpisodeExtract, e as AgentGraphExtract, f as AgentGenerate, g as AgentTokenSink, h as AgentRunInput, i as AgentFunctionPaths, j as AgentRunFunction, k as AgentStepLike, l as AgentStreamGenerate, m as AgentRunResult, n as AgentMessageRow, o as AgentConfig, S as SkillDefinition, p as AnyAgentTool, q as AgentAsToolOptions, r as AgentSubToolInput, b as AgentToolDefinition, s as AgentBindingSpec, t as AgentHandle, u as AgentToolConfig, v as AgentFunctionReference, w as AgentModelInput, x as SkillConfig } from "./packem_shared/types.d-BhJFTvz_.js";
2
- export type { y as AgentEmailMapper, z as AgentEmailRun, B as AgentGenerateOptions, C as AgentGenerateResult, D as AgentInstructionsContext, E as AgentLiveEvent, F as AgentMemoryOptions, G as AgentMemorySource, H as AgentMessageStatus, J as AgentOnStepFinish, K as AgentPrepareStep, L as AgentPrepareStepInput, M as AgentPrepareStepResult, N as AgentProgressEvent, O as AgentRunHandle, P as AgentStepFinishInfo, Q as AgentStepInfo, R as AgentThreadStatus, T as AgentTokenDelta, U as AgentToolCall, a as AgentToolContext, V as AgentUsage, W as AgentVoiceConfig, X as AgentWorkflowBindingLike, Y as AgentWorkflowInstanceLike } from "./packem_shared/types.d-BhJFTvz_.js";
1
+ import { A as AgentDefinition, c as AgentCompact, d as AgentEpisodeExtract, e as AgentGraphExtract, f as AgentGenerate, g as AgentTokenSink, h as AgentRunInput, i as AgentFunctionPaths, j as AgentRunFunction, k as AgentStepLike, l as AgentStreamGenerate, m as AgentRunResult, n as AgentMessageRow, o as AgentConfig, S as SkillDefinition, p as AnyAgentTool, q as AgentAsToolOptions, r as AgentSubToolInput, b as AgentToolDefinition, s as AgentBindingSpec, t as AgentHandle, u as AgentToolConfig, v as AgentFunctionReference, w as AgentModelInput, x as SkillConfig } from "./packem_shared/types.d-boAM2Yi1.js";
2
+ export type { y as AgentEmailMapper, z as AgentEmailRun, B as AgentGenerateOptions, C as AgentGenerateResult, D as AgentInstructionsContext, E as AgentLiveEvent, F as AgentMemoryOptions, G as AgentMemorySource, H as AgentMessageStatus, J as AgentOnStepFinish, K as AgentPrepareStep, L as AgentPrepareStepInput, M as AgentPrepareStepResult, N as AgentProgressEvent, O as AgentRunHandle, P as AgentStepFinishInfo, Q as AgentStepInfo, R as AgentThreadStatus, T as AgentTokenDelta, U as AgentToolCall, a as AgentToolContext, V as AgentUsage, W as AgentVoiceConfig, X as AgentWorkflowBindingLike, Y as AgentWorkflowInstanceLike } from "./packem_shared/types.d-boAM2Yi1.js";
3
3
  export { type AgentComponent, agentComponent, agentExtension } from "./component.js";
4
4
  import { FlexibleSchema, LanguageModel, ModelMessage } from 'ai';
5
5
  export { agentBindingName, agentClassName, agentDefaultName, voiceBindingName, voiceClassName } from "./naming.js";
@@ -9,95 +9,95 @@ import { WorkflowDefinition } from '@lunora/workflow';
9
9
  import '@lunora/mail/inbound';
10
10
  import '@lunora/server';
11
11
  /**
12
- * `AgentLoopOptions` is part of the experimental `@lunora/agent` API and may change without a major version bump.
13
- * @experimental
14
- */
12
+ * `AgentLoopOptions` is part of the experimental `@lunora/agent` API and may change without a major version bump.
13
+ * @experimental
14
+ */
15
15
  interface AgentLoopOptions {
16
16
  agent: AgentDefinition;
17
17
  /**
18
- * The history-compaction seam — production wires AI SDK `generateText`.
19
- * Absent (the default) disables compaction, so an agent with no `compaction`
20
- * config, and every unit test that doesn't opt in, is byte-identical.
21
- */
18
+ * The history-compaction seam — production wires AI SDK `generateText`.
19
+ * Absent (the default) disables compaction, so an agent with no `compaction`
20
+ * config, and every unit test that doesn't opt in, is byte-identical.
21
+ */
22
22
  compact?: AgentCompact;
23
23
  env: Record<string, unknown>;
24
24
  /** The agent's `lunora/agents.ts` export name (thread attribution). */
25
25
  exportName: string;
26
26
  /**
27
- * The run-end episode-summary seam — production wires AI SDK `generateText`.
28
- * Absent (the default) disables episode recording, so an agent with no
29
- * episodic memory, and every unit test that doesn't opt in, is byte-identical.
30
- */
27
+ * The run-end episode-summary seam — production wires AI SDK `generateText`.
28
+ * Absent (the default) disables episode recording, so an agent with no
29
+ * episodic memory, and every unit test that doesn't opt in, is byte-identical.
30
+ */
31
31
  extractEpisode?: AgentEpisodeExtract;
32
32
  /**
33
- * The run-end graph-extraction seam — production wires AI SDK `generateText`
34
- * with a structured `Output.object`. Absent (the default) disables
35
- * extraction, so an agent with no graph memory, and every unit test that
36
- * doesn't opt in, is byte-identical.
37
- */
33
+ * The run-end graph-extraction seam — production wires AI SDK `generateText`
34
+ * with a structured `Output.object`. Absent (the default) disables
35
+ * extraction, so an agent with no graph memory, and every unit test that
36
+ * doesn't opt in, is byte-identical.
37
+ */
38
38
  extractGraph?: AgentGraphExtract;
39
39
  /** The LLM-turn seam — production wires AI SDK `generateText`. */
40
40
  generate: AgentGenerate;
41
41
  /** The workflow instance id — the deterministic per-run message-key prefix. */
42
42
  instanceId: string;
43
43
  /**
44
- * Live-only sink for streamed token deltas. Supplied by the runtime (tees to
45
- * the existing stream transport); when present together with
46
- * {@link AgentLoopOptions.streamGenerate} each turn streams its deltas here
47
- * instead of a single non-streaming `generate` call. Absent (the default)
48
- * keeps the byte-identical non-streaming path. Never fired on a replay — the
49
- * memoized turn skips the step body that would emit deltas.
50
- */
44
+ * Live-only sink for streamed token deltas. Supplied by the runtime (tees to
45
+ * the existing stream transport); when present together with
46
+ * {@link AgentLoopOptions.streamGenerate} each turn streams its deltas here
47
+ * instead of a single non-streaming `generate` call. Absent (the default)
48
+ * keeps the byte-identical non-streaming path. Never fired on a replay — the
49
+ * memoized turn skips the step body that would emit deltas.
50
+ */
51
51
  onTokenDelta?: AgentTokenSink;
52
52
  params: AgentRunInput;
53
53
  paths: AgentFunctionPaths;
54
54
  run: AgentRunFunction;
55
55
  step: AgentStepLike;
56
56
  /**
57
- * The streaming LLM-turn seam — production wires AI SDK `streamText`. Used
58
- * only when {@link AgentLoopOptions.onTokenDelta} is also present; otherwise
59
- * the loop falls back to {@link AgentLoopOptions.generate} unchanged.
60
- */
57
+ * The streaming LLM-turn seam — production wires AI SDK `streamText`. Used
58
+ * only when {@link AgentLoopOptions.onTokenDelta} is also present; otherwise
59
+ * the loop falls back to {@link AgentLoopOptions.generate} unchanged.
60
+ */
61
61
  streamGenerate?: AgentStreamGenerate;
62
62
  }
63
63
  /**
64
- * Decide the compaction split for a turn: when `compaction` is configured and the
65
- * history exceeds `maxMessages`, return the `older` messages to summarize and the
66
- * `recent` tail to keep verbatim (the most recent `keepRecent`, default
67
- * `ceil(maxMessages / 2)`). Returns `undefined` when compaction is unset, the
68
- * history is short enough, or the tail would be the whole history — a PURE
69
- * decision (no I/O), unit-testable in isolation.
70
- * @experimental
71
- */
64
+ * Decide the compaction split for a turn: when `compaction` is configured and the
65
+ * history exceeds `maxMessages`, return the `older` messages to summarize and the
66
+ * `recent` tail to keep verbatim (the most recent `keepRecent`, default
67
+ * `ceil(maxMessages / 2)`). Returns `undefined` when compaction is unset, the
68
+ * history is short enough, or the tail would be the whole history — a PURE
69
+ * decision (no I/O), unit-testable in isolation.
70
+ * @experimental
71
+ */
72
72
  declare const splitForCompaction: (history: ReadonlyArray<AgentMessageRow>, compaction: AgentConfig["compaction"]) => {
73
73
  older: AgentMessageRow[];
74
74
  recent: AgentMessageRow[];
75
75
  } | undefined;
76
76
  /**
77
- * The durable tool-loop. Correctness rests on two invariants:
78
- *
79
- * 1. **Deterministic step names.** Each LLM turn is `llm:turn:N` (`N` = the
80
- * loop index, replay-stable) and each tool call is `tool:NAME:CALL_ID`
81
- * (`CALL_ID` = the provider's stable id, itself replayed from the memoized LLM
82
- * step). Native `step.do` memoization then guarantees a COMPLETED step is
83
- * never re-run on replay — a resumed run cannot double-charge a card. A step
84
- * that FAILS mid-body is retried at-least-once; the tool receives its step
85
- * name as `idempotencyKey` to dedupe on.
86
- *
87
- * 2. **Idempotent persistence.** Every message write is keyed
88
- * `INSTANCE:ROLE:POSITION` and the append mutation dedupes on it, so a
89
- * replayed persist is a no-op — the thread never duplicates.
90
- *
91
- * Loop control derives ONLY from persisted step outputs (never fresh
92
- * `Date.now()`/`Math.random()` at the top level), so replays walk the same
93
- * step-name sequence.
94
- * @experimental
95
- */
77
+ * The durable tool-loop. Correctness rests on two invariants:
78
+ *
79
+ * 1. **Deterministic step names.** Each LLM turn is `llm:turn:N` (`N` = the
80
+ * loop index, replay-stable) and each tool call is `tool:NAME:CALL_ID`
81
+ * (`CALL_ID` = the provider's stable id, itself replayed from the memoized LLM
82
+ * step). Native `step.do` memoization then guarantees a COMPLETED step is
83
+ * never re-run on replay — a resumed run cannot double-charge a card. A step
84
+ * that FAILS mid-body is retried at-least-once; the tool receives its step
85
+ * name as `idempotencyKey` to dedupe on.
86
+ *
87
+ * 2. **Idempotent persistence.** Every message write is keyed
88
+ * `INSTANCE:ROLE:POSITION` and the append mutation dedupes on it, so a
89
+ * replayed persist is a no-op — the thread never duplicates.
90
+ *
91
+ * Loop control derives ONLY from persisted step outputs (never fresh
92
+ * `Date.now()`/`Math.random()` at the top level), so replays walk the same
93
+ * step-name sequence.
94
+ * @experimental
95
+ */
96
96
  declare const runAgentLoop: (options: AgentLoopOptions) => Promise<AgentRunResult>;
97
97
  /**
98
- * Input the model provides to a minted `searchMemory` tool.
99
- * @experimental
100
- */
98
+ * Input the model provides to a minted `searchMemory` tool.
99
+ * @experimental
100
+ */
101
101
  interface AgentMemorySearchInput {
102
102
  /** The natural-language query. */
103
103
  query: string;
@@ -105,17 +105,17 @@ interface AgentMemorySearchInput {
105
105
  topK?: number;
106
106
  }
107
107
  /**
108
- * Input the model provides to a minted `readMemory` tool.
109
- * @experimental
110
- */
108
+ * Input the model provides to a minted `readMemory` tool.
109
+ * @experimental
110
+ */
111
111
  interface AgentMemoryReadInput {
112
112
  /** The chunk/document id from a `searchMemory` hit. */
113
113
  id: string;
114
114
  }
115
115
  /**
116
- * One ranked hit in a {@link AgentMemorySearchResult}.
117
- * @experimental
118
- */
116
+ * One ranked hit in a {@link AgentMemorySearchResult}.
117
+ * @experimental
118
+ */
119
119
  interface AgentMemorySearchHit {
120
120
  id: string;
121
121
  score: number;
@@ -124,62 +124,62 @@ interface AgentMemorySearchHit {
124
124
  sourceId: string;
125
125
  }
126
126
  /**
127
- * The compact shape a minted `searchMemory` tool returns to the model: ranked
128
- * hits plus deduped source refs, with the giant joined `.context` string
129
- * DROPPED — the model reads snippets and decides what (if anything) to pull with
130
- * `readMemory`, which is the whole point of agentic (vs inject) retrieval.
131
- * @experimental
132
- */
127
+ * The compact shape a minted `searchMemory` tool returns to the model: ranked
128
+ * hits plus deduped source refs, with the giant joined `.context` string
129
+ * DROPPED — the model reads snippets and decides what (if anything) to pull with
130
+ * `readMemory`, which is the whole point of agentic (vs inject) retrieval.
131
+ * @experimental
132
+ */
133
133
  interface AgentMemorySearchResult {
134
134
  results: AgentMemorySearchHit[];
135
135
  sources: ReadonlyArray<unknown>;
136
136
  }
137
137
  /**
138
- * Project a `@lunora/ai/rag` `RetrieveResult` into the compact
139
- * {@link AgentMemorySearchResult} a minted `searchMemory` tool returns. Defensive
140
- * against a source action that returns a differently-shaped value (the dispatch
141
- * boundary is untyped): a missing `chunks`/`sources` degrades to empty.
142
- * @experimental
143
- */
138
+ * Project a `@lunora/ai/rag` `RetrieveResult` into the compact
139
+ * {@link AgentMemorySearchResult} a minted `searchMemory` tool returns. Defensive
140
+ * against a source action that returns a differently-shaped value (the dispatch
141
+ * boundary is untyped): a missing `chunks`/`sources` degrades to empty.
142
+ * @experimental
143
+ */
144
144
  declare const toSearchResults: (retrieved: unknown, snippetChars: number) => AgentMemorySearchResult;
145
145
  /**
146
- * Mint the model-facing tools for every `mode: "agentic"` memory source — the
147
- * agent's own `memory` (keyed `"default"` → `searchMemory`/`readMemory`) and
148
- * each skill's `knowledge` (keyed by the skill name → `search_KEY`/`read_KEY`).
149
- * An `"inject"`-mode source contributes NO tool (it stays on the auto-injection
150
- * path). The returned map is folded into the agent's flat tool namespace by
151
- * `defineAgent`, where a collision with a real tool throws.
152
- *
153
- * Walks the same two source origins as `collectMemorySources` so the two stay in
154
- * lockstep; the split is deliberate — inject sources feed retrieval, agentic
155
- * sources feed tools, and no source is ever on both paths.
156
- * @experimental
157
- */
146
+ * Mint the model-facing tools for every `mode: "agentic"` memory source — the
147
+ * agent's own `memory` (keyed `"default"` → `searchMemory`/`readMemory`) and
148
+ * each skill's `knowledge` (keyed by the skill name → `search_KEY`/`read_KEY`).
149
+ * An `"inject"`-mode source contributes NO tool (it stays on the auto-injection
150
+ * path). The returned map is folded into the agent's flat tool namespace by
151
+ * `defineAgent`, where a collision with a real tool throws.
152
+ *
153
+ * Walks the same two source origins as `collectMemorySources` so the two stay in
154
+ * lockstep; the split is deliberate — inject sources feed retrieval, agentic
155
+ * sources feed tools, and no source is ever on both paths.
156
+ * @experimental
157
+ */
158
158
  declare const collectAgenticMemoryTools: (config: AgentConfig, skills: ReadonlyArray<SkillDefinition>) => Record<string, AnyAgentTool>;
159
159
  /**
160
- * Adapt a declared agent into a tool the parent's model can call: `execute`
161
- * starts a CHILD run on the child agent's Workflow binding, waits for it to
162
- * finish, and returns its final answer — so a supervisor agent can delegate to
163
- * specialists.
164
- *
165
- * Replay-safety: the whole `execute` runs inside the loop's `tool:NAME:CALL_ID`
166
- * durable step, so a completed sub-run is memoized and never re-run. The child
167
- * `threadKey` and Workflow instance id both DERIVE from the parent's
168
- * (replay-stable) `threadKey` + `toolCallId`, so a retried step reuses the same
169
- * child run rather than forking a new one (idempotent create-or-get). No
170
- * `Date.now()`/`Math.random()`.
171
- *
172
- * The child's completion is observed by POLLING `instance.status()` (Cloudflare
173
- * Workflows has no in-step await-instance primitive), and the answer is read
174
- * back from the child's persisted thread — the single source of truth — via the
175
- * shared `agents:agentMessages` runtime function.
176
- * @experimental
177
- */
160
+ * Adapt a declared agent into a tool the parent's model can call: `execute`
161
+ * starts a CHILD run on the child agent's Workflow binding, waits for it to
162
+ * finish, and returns its final answer — so a supervisor agent can delegate to
163
+ * specialists.
164
+ *
165
+ * Replay-safety: the whole `execute` runs inside the loop's `tool:NAME:CALL_ID`
166
+ * durable step, so a completed sub-run is memoized and never re-run. The child
167
+ * `threadKey` and Workflow instance id both DERIVE from the parent's
168
+ * (replay-stable) `threadKey` + `toolCallId`, so a retried step reuses the same
169
+ * child run rather than forking a new one (idempotent create-or-get). No
170
+ * `Date.now()`/`Math.random()`.
171
+ *
172
+ * The child's completion is observed by POLLING `instance.status()` (Cloudflare
173
+ * Workflows has no in-step await-instance primitive), and the answer is read
174
+ * back from the child's persisted thread — the single source of truth — via the
175
+ * shared `agents:agentMessages` runtime function.
176
+ * @experimental
177
+ */
178
178
  declare const agentAsTool: (options: AgentAsToolOptions) => AgentToolDefinition<AgentSubToolInput, string>;
179
179
  /**
180
- * One step of a tool-composition script — call `tool` with `input`, bind the result to `id`.
181
- * @experimental
182
- */
180
+ * One step of a tool-composition script — call `tool` with `input`, bind the result to `id`.
181
+ * @experimental
182
+ */
183
183
  interface ToolScriptStep {
184
184
  /** A stable name later steps reference the output by. */
185
185
  id: string;
@@ -189,16 +189,16 @@ interface ToolScriptStep {
189
189
  tool: string;
190
190
  }
191
191
  /**
192
- * The model-provided input to a {@link codeTool} call.
193
- * @experimental
194
- */
192
+ * The model-provided input to a {@link codeTool} call.
193
+ * @experimental
194
+ */
195
195
  interface ToolScript {
196
196
  steps: ToolScriptStep[];
197
197
  }
198
198
  /**
199
- * The result of running a {@link ToolScript}: each step's output plus the last one.
200
- * @experimental
201
- */
199
+ * The result of running a {@link ToolScript}: each step's output plus the last one.
200
+ * @experimental
201
+ */
202
202
  interface ToolScriptResult {
203
203
  final: unknown;
204
204
  results: ReadonlyArray<{
@@ -207,121 +207,114 @@ interface ToolScriptResult {
207
207
  }>;
208
208
  }
209
209
  /**
210
- * Author-supplied config for {@link codeTool}.
211
- * @experimental
212
- */
210
+ * Author-supplied config for {@link codeTool}.
211
+ * @experimental
212
+ */
213
213
  interface CodeToolOptions {
214
214
  /** Override the model-facing description (the default lists the available tools). */
215
215
  description?: string;
216
216
  /** Max steps per script (default 16). */
217
217
  maxSteps?: number;
218
218
  /**
219
- * Gate a whole script behind a human approval. Default: unattended. Note the
220
- * COMPOSED tools cannot carry their own approval gate — `codeTool` rejects any
221
- * tool with a `needsApproval`, because a code-mode script runs its steps in one
222
- * shot and can't pause mid-script to hibernate for HITL. Gate the whole script
223
- * here instead. Evaluated from replay-stable input, so keep it deterministic.
224
- */
219
+ * Gate a whole script behind a human approval. Default: unattended. Note the
220
+ * COMPOSED tools cannot carry their own approval gate — `codeTool` rejects any
221
+ * tool with a `needsApproval`, because a code-mode script runs its steps in one
222
+ * shot and can't pause mid-script to hibernate for HITL. Gate the whole script
223
+ * here instead. Evaluated from replay-stable input, so keep it deterministic.
224
+ */
225
225
  needsApproval?: ((input: ToolScript) => boolean) | boolean;
226
226
  }
227
227
  /**
228
- * Resolve `{ "$from": "&lt;stepId>", "$path"?: "a.b" }` references in a step's input
229
- * against earlier step results, recursing through nested objects and arrays. An
230
- * unknown `$from` throws a forward/typo reference is a hard error, not a silent
231
- * `undefined`. Pure and deterministic (no I/O), so it's unit-testable alone.
232
- */
233
-
234
- /**
235
- * A "code mode" tool: instead of the model calling one tool per turn, it writes a
236
- * SCRIPT that composes several of the tools you hand `codeTool` chaining a
237
- * later call's input to an earlier call's output and the whole thing runs in a
238
- * single turn. This is a SAFE interpreted data-flow between whitelisted tools
239
- * (no `eval`, no isolate), so it runs natively in workerd; arbitrary-code
240
- * execution (the Cloudflare Worker Loader path) is a separate future mode.
241
- *
242
- * Each composed tool dispatches through the same durable context a normal call
243
- * gets (inheriting RLS), with a per-step idempotency key. A code-mode script runs
244
- * its steps in one shot and CANNOT pause mid-script for a human approval, so
245
- * `codeTool` REJECTS at construction any tool carrying a `needsApproval` gate —
246
- * keep approval-gated tools as normal top-level tools. Gate the whole script via
247
- * `opts.needsApproval` instead.
248
- *
249
- * ```ts
250
- * import { codeTool, defineAgent, functionTool } from "@lunora/agent";
251
- *
252
- * export const analyst = defineAgent({
253
- * model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
254
- * tools: {
255
- * run: codeTool({
256
- * findUser: functionTool("users:byEmail", { description: "Look up a user by email.", inputSchema }),
257
- * recentOrders: functionTool("orders:recent", { description: "List a user's recent orders.", inputSchema }),
258
- * }),
259
- * },
260
- * });
261
- * // The model can now, in one turn, `findUser` then feed `{ "$from": "u", "$path": "id" }` into `recentOrders`.
262
- * ```
263
- * @experimental
264
- */
228
+ * A "code mode" tool: instead of the model calling one tool per turn, it writes a
229
+ * SCRIPT that composes several of the tools you hand `codeTool` — chaining a
230
+ * later call's input to an earlier call's output and the whole thing runs in a
231
+ * single turn. This is a SAFE interpreted data-flow between whitelisted tools
232
+ * (no `eval`, no isolate), so it runs natively in workerd; arbitrary-code
233
+ * execution (the Cloudflare Worker Loader path) is a separate future mode.
234
+ *
235
+ * Each composed tool dispatches through the same durable context a normal call
236
+ * gets (inheriting RLS), with a per-step idempotency key. A code-mode script runs
237
+ * its steps in one shot and CANNOT pause mid-script for a human approval, so
238
+ * `codeTool` REJECTS at construction any tool carrying a `needsApproval` gate
239
+ * keep approval-gated tools as normal top-level tools. Gate the whole script via
240
+ * `opts.needsApproval` instead.
241
+ *
242
+ * ```ts
243
+ * import { codeTool, defineAgent, functionTool } from "@lunora/agent";
244
+ *
245
+ * export const analyst = defineAgent({
246
+ * model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
247
+ * tools: {
248
+ * run: codeTool({
249
+ * findUser: functionTool("users:byEmail", { description: "Look up a user by email.", inputSchema }),
250
+ * recentOrders: functionTool("orders:recent", { description: "List a user's recent orders.", inputSchema }),
251
+ * }),
252
+ * },
253
+ * });
254
+ * // The model can now, in one turn, `findUser` then feed `{ "$from": "u", "$path": "id" }` into `recentOrders`.
255
+ * ```
256
+ * @experimental
257
+ */
265
258
  declare const codeTool: (tools: Record<string, AnyAgentTool>, options?: CodeToolOptions) => AgentToolDefinition<ToolScript, ToolScriptResult>;
266
259
  /**
267
- * Build the `ctx.agents` producer surface from the codegen-emitted spec list
268
- * (`LUNORA_AGENTS`), mirroring the `ctx.queues` property-access pattern: each
269
- * declared agent resolves its `AGENT_*` Workflow binding off `env` lazily, so
270
- * a missing binding only errors when that agent is actually started.
271
- *
272
- * `cancel` also needs to write the thread's status, so it dispatches the agent
273
- * runtime's `agentPatchThread` mutation. Production leaves `dispatch` undefined
274
- * and the env-backed `createDispatchRunner` (the same runner the workflow body
275
- * uses — it POSTs to `/_lunora/scheduler/dispatch`) is built on demand; tests
276
- * inject a `dispatch` double.
277
- * @experimental
278
- */
260
+ * Build the `ctx.agents` producer surface from the codegen-emitted spec list
261
+ * (`LUNORA_AGENTS`), mirroring the `ctx.queues` property-access pattern: each
262
+ * declared agent resolves its `AGENT_*` Workflow binding off `env` lazily, so
263
+ * a missing binding only errors when that agent is actually started.
264
+ *
265
+ * `cancel` also needs to write the thread's status, so it dispatches the agent
266
+ * runtime's `agentPatchThread` mutation. Production leaves `dispatch` undefined
267
+ * and the env-backed `createDispatchRunner` (the same runner the workflow body
268
+ * uses — it POSTs to `/_lunora/scheduler/dispatch`) is built on demand; tests
269
+ * inject a `dispatch` double.
270
+ * @experimental
271
+ */
279
272
  declare const createAgentContext: (env: Record<string, unknown>, specs: ReadonlyArray<AgentBindingSpec>, dispatch?: AgentRunFunction) => Record<string, AgentHandle>;
280
273
  /**
281
- * Declare a durable agent. The definition compiles onto a Cloudflare Workflow
282
- * (each LLM turn and each tool call a named durable step; thread messages
283
- * persisted idempotently in DO SQLite), invoked from mutations/actions via
284
- * `ctx.agents.NAME.run(...)` and observed live by subscribing to the
285
- * `agents:agentMessages` query.
286
- *
287
- * ```ts
288
- * // lunora/agents.ts
289
- * import { defineAgent, defineAgentTool } from "@lunora/agent";
290
- *
291
- * export const support = defineAgent({
292
- * instructions: "You are a helpful support agent.",
293
- * model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
294
- * tools: {
295
- * getWeather: defineAgentTool({
296
- * description: "Look up the current weather for a city.",
297
- * execute: async ({ city }, { run }) => run(api.weather.lookup, { city }),
298
- * inputSchema: jsonSchema({ properties: { city: { type: "string" } }, required: ["city"], type: "object" }),
299
- * }),
300
- * },
301
- * });
302
- * ```
303
- *
304
- * Declaring an agent is enough — codegen auto-registers the `agents:*` runtime
305
- * functions (from `agentComponent()`) and the `ctx.agents` producer surface.
306
- * @experimental
307
- */
274
+ * Declare a durable agent. The definition compiles onto a Cloudflare Workflow
275
+ * (each LLM turn and each tool call a named durable step; thread messages
276
+ * persisted idempotently in DO SQLite), invoked from mutations/actions via
277
+ * `ctx.agents.NAME.run(...)` and observed live by subscribing to the
278
+ * `agents:agentMessages` query.
279
+ *
280
+ * ```ts
281
+ * // lunora/agents.ts
282
+ * import { defineAgent, defineAgentTool } from "@lunora/agent";
283
+ *
284
+ * export const support = defineAgent({
285
+ * instructions: "You are a helpful support agent.",
286
+ * model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
287
+ * tools: {
288
+ * getWeather: defineAgentTool({
289
+ * description: "Look up the current weather for a city.",
290
+ * execute: async ({ city }, { run }) => run(api.weather.lookup, { city }),
291
+ * inputSchema: jsonSchema({ properties: { city: { type: "string" } }, required: ["city"], type: "object" }),
292
+ * }),
293
+ * },
294
+ * });
295
+ * ```
296
+ *
297
+ * Declaring an agent is enough — codegen auto-registers the `agents:*` runtime
298
+ * functions (from `agentComponent()`) and the `ctx.agents` producer surface.
299
+ * @experimental
300
+ */
308
301
  declare const defineAgent: (config: AgentConfig) => AgentDefinition;
309
302
  /**
310
- * Runtime brand check for a {@link AgentDefinition}.
311
- * @experimental
312
- */
303
+ * Runtime brand check for a {@link AgentDefinition}.
304
+ * @experimental
305
+ */
313
306
  declare const isAgentDefinition: (value: unknown) => value is AgentDefinition;
314
307
  /**
315
- * Declare an agent tool — see `AgentToolDefinition` for why `execute` runs in
316
- * the loop's durable step (with an `AgentToolContext`) rather than inside the
317
- * model call.
318
- * @experimental
319
- */
308
+ * Declare an agent tool — see `AgentToolDefinition` for why `execute` runs in
309
+ * the loop's durable step (with an `AgentToolContext`) rather than inside the
310
+ * model call.
311
+ * @experimental
312
+ */
320
313
  declare const defineAgentTool: <Input, Output>(config: AgentToolConfig<Input, Output>) => AgentToolDefinition<Input, Output>;
321
314
  /**
322
- * Author-supplied config for {@link functionTool}.
323
- * @experimental
324
- */
315
+ * Author-supplied config for {@link functionTool}.
316
+ * @experimental
317
+ */
325
318
  interface FunctionToolOptions<Input> {
326
319
  /** What the tool does — shown to the model (the model decides from it). */
327
320
  description: string;
@@ -329,106 +322,100 @@ interface FunctionToolOptions<Input> {
329
322
  inputSchema: FlexibleSchema<Input>;
330
323
  }
331
324
  /**
332
- * Expose any Lunora query/mutation/action as an agent tool. The returned
333
- * definition's `execute` dispatches the referenced function through the loop's
334
- * existing `run` seam (the workflow `ctx.run`) — so there is no bespoke wrapper
335
- * per tool, and the call runs inside the loop's named durable step exactly like
336
- * any other tool.
337
- *
338
- * ```ts
339
- * import { functionTool } from "@lunora/agent";
340
- * import { api } from "./_generated/api";
341
- *
342
- * export const support = defineAgent({
343
- * model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
344
- * tools: {
345
- * lookupOrder: functionTool(api.orders.byId, {
346
- * description: "Look up an order by its id.",
347
- * inputSchema: jsonSchema({ properties: { id: { type: "string" } }, required: ["id"], type: "object" }),
348
- * }),
349
- * },
350
- * });
351
- * ```
352
- *
353
- * The function reference may be a typed `api.*` reference or a `"module:name"`
354
- * path. The model-provided input is passed verbatim as the function's args, so
355
- * `inputSchema` should mirror the referenced function's argument validator.
356
- * @experimental
357
- */
325
+ * Expose any Lunora query/mutation/action as an agent tool. The returned
326
+ * definition's `execute` dispatches the referenced function through the loop's
327
+ * existing `run` seam (the workflow `ctx.run`) — so there is no bespoke wrapper
328
+ * per tool, and the call runs inside the loop's named durable step exactly like
329
+ * any other tool.
330
+ *
331
+ * ```ts
332
+ * import { functionTool } from "@lunora/agent";
333
+ * import { api } from "./_generated/api";
334
+ *
335
+ * export const support = defineAgent({
336
+ * model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
337
+ * tools: {
338
+ * lookupOrder: functionTool(api.orders.byId, {
339
+ * description: "Look up an order by its id.",
340
+ * inputSchema: jsonSchema({ properties: { id: { type: "string" } }, required: ["id"], type: "object" }),
341
+ * }),
342
+ * },
343
+ * });
344
+ * ```
345
+ *
346
+ * The function reference may be a typed `api.*` reference or a `"module:name"`
347
+ * path. The model-provided input is passed verbatim as the function's args, so
348
+ * `inputSchema` should mirror the referenced function's argument validator.
349
+ * @experimental
350
+ */
358
351
  declare const functionTool: <Input extends Record<string, unknown> = Record<string, unknown>, Output = unknown>(reference: AgentFunctionReference | string, options: FunctionToolOptions<Input>) => AgentToolDefinition<Input, Output>;
359
352
  /**
360
- * Resolve the configured model against the Worker env (see `AgentModelInput`).
361
- * @experimental
362
- */
353
+ * Resolve the configured model against the Worker env (see `AgentModelInput`).
354
+ * @experimental
355
+ */
363
356
  declare const resolveAgentModel: (model: AgentModelInput, env: Record<string, unknown>) => LanguageModel;
364
357
  /**
365
- * Build the production LLM-turn seam over AI SDK `generateText`. The agent's
366
- * tools are exposed to the model schema-only (NO `execute`) — the model can
367
- * decide to call them, but execution happens back in the loop as named
368
- * durable steps, never inside the model call.
369
- *
370
- * The static generation settings (`temperature`, `maxOutputTokens`,
371
- * `toolChoice`, `output`, `telemetry`) come off the agent config; the per-turn
372
- * `activeTools` / `toolChoice` / `model` overrides (from `prepareStep`) arrive
373
- * on each call. When `output` is set the model runs with `Output.object` and
374
- * the parsed answer is returned alongside the text.
375
- * @experimental
376
- */
358
+ * Build the production LLM-turn seam over AI SDK `generateText`. The agent's
359
+ * tools are exposed to the model schema-only (NO `execute`) — the model can
360
+ * decide to call them, but execution happens back in the loop as named
361
+ * durable steps, never inside the model call.
362
+ *
363
+ * The static generation settings (`temperature`, `maxOutputTokens`,
364
+ * `toolChoice`, `output`, `telemetry`) come off the agent config; the per-turn
365
+ * `activeTools` / `toolChoice` / `model` overrides (from `prepareStep`) arrive
366
+ * on each call. When `output` is set the model runs with `Output.object` and
367
+ * the parsed answer is returned alongside the text.
368
+ * @experimental
369
+ */
377
370
  declare const createAgentGenerate: (agent: AgentDefinition, env: Record<string, unknown>) => AgentGenerate;
378
371
  /**
379
- * The streaming counterpart of {@link createAgentGenerate} over AI SDK
380
- * `streamText`. It tees each text delta to `onDelta` as the model produces it,
381
- * then resolves the SAME {@link AgentGenerate} result the non-streaming seam
382
- * returns — identical `{ text, toolCalls, usage, output }` — so the value the
383
- * durable `llm:turn:N` step memoizes (and persists) is byte-for-byte unchanged
384
- * whether the turn streamed or not.
385
- *
386
- * Deltas are live-only: the seam runs inside the turn's durable step, so a
387
- * workflow replay serves the memoized final value without re-invoking it — no
388
- * delta is ever re-emitted. The persisted assistant message stays the single
389
- * source of truth.
390
- * @experimental
391
- */
372
+ * The streaming counterpart of {@link createAgentGenerate} over AI SDK
373
+ * `streamText`. It tees each text delta to `onDelta` as the model produces it,
374
+ * then resolves the SAME {@link AgentGenerate} result the non-streaming seam
375
+ * returns — identical `{ text, toolCalls, usage, output }` — so the value the
376
+ * durable `llm:turn:N` step memoizes (and persists) is byte-for-byte unchanged
377
+ * whether the turn streamed or not.
378
+ *
379
+ * Deltas are live-only: the seam runs inside the turn's durable step, so a
380
+ * workflow replay serves the memoized final value without re-invoking it — no
381
+ * delta is ever re-emitted. The persisted assistant message stays the single
382
+ * source of truth.
383
+ * @experimental
384
+ */
392
385
  declare const createStreamGenerate: (agent: AgentDefinition, env: Record<string, unknown>) => AgentStreamGenerate;
393
386
  /**
394
- * Build the production run-end graph-extraction seam over AI SDK `generateText`
395
- * with an `Output.object` setting (the non-deprecated replacement for
396
- * `generateObject`, and the same structured-output path the turn seams use). It
397
- * resolves the (optionally cheaper) extraction model against the env, runs the
398
- * model over {@link GRAPH_EXTRACTION_SCHEMA}, and returns the parsed
399
- * `{ entities, relations }`. Wired by `compileAgentWorkflow` and called inside
400
- * the loop's memoized `memory:extract` step.
401
- * @experimental
402
- */
387
+ * Build the production run-end graph-extraction seam over AI SDK `generateText`
388
+ * with an `Output.object` setting (the non-deprecated replacement for
389
+ * `generateObject`, and the same structured-output path the turn seams use). It
390
+ * resolves the (optionally cheaper) extraction model against the env, runs the
391
+ * model over {@link GRAPH_EXTRACTION_SCHEMA}, and returns the parsed
392
+ * `{ entities, relations }`. Wired by `compileAgentWorkflow` and called inside
393
+ * the loop's memoized `memory:extract` step.
394
+ * @experimental
395
+ */
403
396
  declare const createGraphExtract: () => AgentGraphExtract;
404
397
  /**
405
- * Build the production run-end episode-extraction seam over AI SDK `generateText`.
406
- * Unlike the graph extractor this needs no structured schema — an episode is a
407
- * single natural-language summary — so it returns the trimmed model text. Wired
408
- * by `compileAgentWorkflow` and called inside the loop's memoized
409
- * `memory:episode` step.
410
- * @experimental
411
- */
398
+ * Build the production run-end episode-extraction seam over AI SDK `generateText`.
399
+ * Unlike the graph extractor this needs no structured schema — an episode is a
400
+ * single natural-language summary — so it returns the trimmed model text. Wired
401
+ * by `compileAgentWorkflow` and called inside the loop's memoized
402
+ * `memory:episode` step.
403
+ * @experimental
404
+ */
412
405
  declare const createEpisodeExtract: () => AgentEpisodeExtract;
413
406
  /**
414
- * Build the production history-compaction seam over AI SDK `generateText`: it
415
- * summarizes the older conversation messages under {@link COMPACTION_SYSTEM} and
416
- * returns the brief. Wired by `compileAgentWorkflow` and called inside the loop's
417
- * memoized `llm:turn:N` step so the summarization is replay-safe.
418
- */
419
- /**
420
- * One text/image/… content part of an MCP `CallToolResult`.
421
- * @experimental
422
- */
407
+ * One text/image/… content part of an MCP `CallToolResult`.
408
+ * @experimental
409
+ */
423
410
  interface McpContentPart {
424
411
  [key: string]: unknown;
425
412
  text?: string;
426
413
  type: string;
427
414
  }
428
415
  /**
429
- * The result of an MCP `tools/call` — the structural subset the adapter reads.
430
- * @experimental
431
- */
416
+ * The result of an MCP `tools/call` — the structural subset the adapter reads.
417
+ * @experimental
418
+ */
432
419
  interface McpCallResult {
433
420
  [key: string]: unknown;
434
421
  content?: ReadonlyArray<McpContentPart>;
@@ -436,9 +423,9 @@ interface McpCallResult {
436
423
  structuredContent?: unknown;
437
424
  }
438
425
  /**
439
- * One entry of an MCP `tools/list` — the structural subset the adapter reads.
440
- * @experimental
441
- */
426
+ * One entry of an MCP `tools/list` — the structural subset the adapter reads.
427
+ * @experimental
428
+ */
442
429
  interface McpToolInfo {
443
430
  description?: string;
444
431
  inputSchema: {
@@ -450,11 +437,11 @@ interface McpToolInfo {
450
437
  name: string;
451
438
  }
452
439
  /**
453
- * Structural subset of `@modelcontextprotocol/sdk`'s `Client` the adapter uses.
454
- * Declaring it locally lets tests inject a mock without the real SDK (and its
455
- * transport) and keeps the heavy dependency behind a lazy dynamic import.
456
- * @experimental
457
- */
440
+ * Structural subset of `@modelcontextprotocol/sdk`'s `Client` the adapter uses.
441
+ * Declaring it locally lets tests inject a mock without the real SDK (and its
442
+ * transport) and keeps the heavy dependency behind a lazy dynamic import.
443
+ * @experimental
444
+ */
458
445
  interface McpClientLike {
459
446
  callTool: (params: {
460
447
  arguments?: Record<string, unknown>;
@@ -467,20 +454,20 @@ interface McpClientLike {
467
454
  }>;
468
455
  }
469
456
  /**
470
- * Options for {@link mcpTools}.
471
- * @experimental
472
- */
457
+ * Options for {@link mcpTools}.
458
+ * @experimental
459
+ */
473
460
  interface McpToolsOptions {
474
461
  /**
475
- * A pre-built (already-connected) MCP client. Takes precedence over `url` —
476
- * the seam tests inject, and the escape hatch for a custom transport.
477
- */
462
+ * A pre-built (already-connected) MCP client. Takes precedence over `url` —
463
+ * the seam tests inject, and the escape hatch for a custom transport.
464
+ */
478
465
  client?: McpClientLike;
479
466
  /**
480
- * A stdio command. NOT supported in the Workers runtime (stdio transports
481
- * cannot run in workerd) — passing it throws unless a `client` is injected.
482
- * Present so the intent is explicit rather than silently unsupported.
483
- */
467
+ * A stdio command. NOT supported in the Workers runtime (stdio transports
468
+ * cannot run in workerd) — passing it throws unless a `client` is injected.
469
+ * Present so the intent is explicit rather than silently unsupported.
470
+ */
484
471
  command?: string;
485
472
  /** Identify this client to the server on connect. Default `"lunora-agent"`. */
486
473
  name?: string;
@@ -496,43 +483,43 @@ interface McpToolsOptions {
496
483
  version?: string;
497
484
  }
498
485
  /**
499
- * Reduce an MCP tool result to the value persisted as the tool message. A
500
- * server's `structuredContent` is returned as-is; otherwise the text parts are
501
- * joined. An `isError` result is returned as an error STRING (not thrown) so
502
- * the next LLM turn can recover, consistent with the loop's unknown-tool path.
503
- * @experimental
504
- */
486
+ * Reduce an MCP tool result to the value persisted as the tool message. A
487
+ * server's `structuredContent` is returned as-is; otherwise the text parts are
488
+ * joined. An `isError` result is returned as an error STRING (not thrown) so
489
+ * the next LLM turn can recover, consistent with the loop's unknown-tool path.
490
+ * @experimental
491
+ */
505
492
  declare const adaptMcpResult: (result: McpCallResult) => unknown;
506
493
  /**
507
- * Connect to an external MCP server, list its tools, and adapt each into an
508
- * {@link AgentToolDefinition} — a record you spread into an agent's `tools`.
509
- * Each adapted tool's `execute` calls the MCP tool through the client, and runs
510
- * inside the loop's named durable step like any other tool (so a completed call
511
- * is never re-run on a workflow replay).
512
- *
513
- * ```ts
514
- * export const support = defineAgent({
515
- * model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
516
- * tools: {
517
- * ...(await mcpTools({ url: "https://mcp.example.com/mcp" })),
518
- * },
519
- * });
520
- * ```
521
- *
522
- * The connection is made at build time (listing tools needs it), then reused by
523
- * every call. In the Workers runtime only the HTTP/SSE transports run (stdio
524
- * does not) — pass `url`, or inject an already-connected `client` for a custom
525
- * transport (also the test seam).
526
- * @experimental
527
- */
494
+ * Connect to an external MCP server, list its tools, and adapt each into an
495
+ * {@link AgentToolDefinition} — a record you spread into an agent's `tools`.
496
+ * Each adapted tool's `execute` calls the MCP tool through the client, and runs
497
+ * inside the loop's named durable step like any other tool (so a completed call
498
+ * is never re-run on a workflow replay).
499
+ *
500
+ * ```ts
501
+ * export const support = defineAgent({
502
+ * model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
503
+ * tools: {
504
+ * ...(await mcpTools({ url: "https://mcp.example.com/mcp" })),
505
+ * },
506
+ * });
507
+ * ```
508
+ *
509
+ * The connection is made at build time (listing tools needs it), then reused by
510
+ * every call. In the Workers runtime only the HTTP/SSE transports run (stdio
511
+ * does not) — pass `url`, or inject an already-connected `client` for a custom
512
+ * transport (also the test seam).
513
+ * @experimental
514
+ */
528
515
  declare const mcpTools: (options: McpToolsOptions) => Promise<Record<string, AgentToolDefinition<Record<string, unknown>>>>;
529
516
  /**
530
- * Assemble the AI SDK conversation for one LLM turn: instructions, then the
531
- * retrieved memory context (when any), then the persisted thread history with
532
- * tool calls/results correlated the way providers expect (assistant tool-call
533
- * parts answered by tool-result parts sharing the `toolCallId`).
534
- * @experimental
535
- */
517
+ * Assemble the AI SDK conversation for one LLM turn: instructions, then the
518
+ * retrieved memory context (when any), then the persisted thread history with
519
+ * tool calls/results correlated the way providers expect (assistant tool-call
520
+ * parts answered by tool-result parts sharing the `toolCallId`).
521
+ * @experimental
522
+ */
536
523
  declare const buildModelMessages: (options: {
537
524
  history: ReadonlyArray<AgentMessageRow>;
538
525
  instructions?: string;
@@ -540,79 +527,79 @@ declare const buildModelMessages: (options: {
540
527
  summary?: string;
541
528
  }) => ModelMessage[];
542
529
  /**
543
- * The namespace the agent runtime functions register under. Codegen
544
- * auto-registers `agentComponent().functions` here whenever `lunora/agents.ts`
545
- * declares an agent, so the loop's dispatch paths below hold by construction.
546
- * @experimental
547
- */
530
+ * The namespace the agent runtime functions register under. Codegen
531
+ * auto-registers `agentComponent().functions` here whenever `lunora/agents.ts`
532
+ * declares an agent, so the loop's dispatch paths below hold by construction.
533
+ * @experimental
534
+ */
548
535
  declare const AGENT_MODULE = "agents";
549
536
  /**
550
- * The namespace + name the batteries-included sandbox dispatcher registers
551
- * under. Codegen auto-registers `sandboxComponent().invoke` here whenever
552
- * `lunora/` imports a sandbox tool (`browserTool`/`containerTool`), so the
553
- * tools' `execute` can dispatch to it through the loop's `run` seam.
554
- * @experimental
555
- */
537
+ * The namespace + name the batteries-included sandbox dispatcher registers
538
+ * under. Codegen auto-registers `sandboxComponent().invoke` here whenever
539
+ * `lunora/` imports a sandbox tool (`browserTool`/`containerTool`), so the
540
+ * tools' `execute` can dispatch to it through the loop's `run` seam.
541
+ * @experimental
542
+ */
556
543
  declare const SANDBOX_MODULE = "sandbox";
557
544
  /**
558
- * The dispatch path of the sandbox runtime action (an internal action).
559
- * @experimental
560
- */
545
+ * The dispatch path of the sandbox runtime action (an internal action).
546
+ * @experimental
547
+ */
561
548
  declare const SANDBOX_INVOKE_PATH: "sandbox:invoke";
562
549
  /**
563
- * Default dispatch paths of the agent runtime functions.
564
- * @experimental
565
- */
550
+ * Default dispatch paths of the agent runtime functions.
551
+ * @experimental
552
+ */
566
553
  declare const DEFAULT_AGENT_FUNCTION_PATHS: AgentFunctionPaths;
567
554
  /**
568
- * Mint a dispatchable function reference from a path (or pass one through).
569
- * @experimental
570
- */
555
+ * Mint a dispatchable function reference from a path (or pass one through).
556
+ * @experimental
557
+ */
571
558
  declare const toFunctionReference: (source: AgentFunctionReference | string) => AgentFunctionReference;
572
559
  /**
573
- * Declare a reusable skill: a bundle of expertise — an instruction fragment,
574
- * tools, and retrieval `knowledge` — an agent composes in via
575
- * `defineAgent({ skills: [...] })`. Reuse-first: a skill's `tools` carry the
576
- * SAME `AnyAgentTool` shape agents already use (`functionTool` / `mcpTools` /
577
- * `agentAsTool`), and `knowledge` reuses `memory`'s `AgentMemoryOptions`
578
- * retrieval verbatim.
579
- *
580
- * ```ts
581
- * import { defineSkill, functionTool } from "@lunora/agent";
582
- *
583
- * export const billing = defineSkill({
584
- * name: "billing",
585
- * instructions: "When asked about invoices, cite the invoice id.",
586
- * knowledge: { source: "rag:searchBillingDocs", topK: 4 },
587
- * tools: {
588
- * lookupInvoice: functionTool(api.billing.invoiceById, {
589
- * description: "Look up an invoice by id.",
590
- * inputSchema: jsonSchema({ properties: { id: { type: "string" } }, required: ["id"], type: "object" }),
591
- * }),
592
- * },
593
- * });
594
- * ```
595
- *
596
- * The merge into the agent's flat namespace (tool-name collisions, instruction
597
- * ordering, per-skill knowledge retrieval) happens in `defineAgent` — a skill
598
- * only validates its own `name`; tool-name validation is deferred to the merge,
599
- * which owns the flat model-facing namespace.
600
- * @experimental
601
- */
560
+ * Declare a reusable skill: a bundle of expertise — an instruction fragment,
561
+ * tools, and retrieval `knowledge` — an agent composes in via
562
+ * `defineAgent({ skills: [...] })`. Reuse-first: a skill's `tools` carry the
563
+ * SAME `AnyAgentTool` shape agents already use (`functionTool` / `mcpTools` /
564
+ * `agentAsTool`), and `knowledge` reuses `memory`'s `AgentMemoryOptions`
565
+ * retrieval verbatim.
566
+ *
567
+ * ```ts
568
+ * import { defineSkill, functionTool } from "@lunora/agent";
569
+ *
570
+ * export const billing = defineSkill({
571
+ * name: "billing",
572
+ * instructions: "When asked about invoices, cite the invoice id.",
573
+ * knowledge: { source: "rag:searchBillingDocs", topK: 4 },
574
+ * tools: {
575
+ * lookupInvoice: functionTool(api.billing.invoiceById, {
576
+ * description: "Look up an invoice by id.",
577
+ * inputSchema: jsonSchema({ properties: { id: { type: "string" } }, required: ["id"], type: "object" }),
578
+ * }),
579
+ * },
580
+ * });
581
+ * ```
582
+ *
583
+ * The merge into the agent's flat namespace (tool-name collisions, instruction
584
+ * ordering, per-skill knowledge retrieval) happens in `defineAgent` — a skill
585
+ * only validates its own `name`; tool-name validation is deferred to the merge,
586
+ * which owns the flat model-facing namespace.
587
+ * @experimental
588
+ */
602
589
  declare const defineSkill: (config: SkillConfig) => SkillDefinition;
603
590
  /**
604
- * Runtime brand check for a {@link SkillDefinition}.
605
- * @experimental
606
- */
591
+ * Runtime brand check for a {@link SkillDefinition}.
592
+ * @experimental
593
+ */
607
594
  declare const isSkillDefinition: (value: unknown) => value is SkillDefinition;
608
595
  /**
609
- * A control frame the server sends the client as a JSON text message (audio
610
- * rides separate binary frames). `ready` announces the negotiated codec on
611
- * connect; `user_transcript` carries the STT result; `assistant_delta` streams
612
- * the live LLM text; `assistant_done` is the final turn text; `interrupted`
613
- * acks a barge-in; `error` reports a non-fatal turn failure.
614
- * @experimental
615
- */
596
+ * A control frame the server sends the client as a JSON text message (audio
597
+ * rides separate binary frames). `ready` announces the negotiated codec on
598
+ * connect; `user_transcript` carries the STT result; `assistant_delta` streams
599
+ * the live LLM text; `assistant_done` is the final turn text; `interrupted`
600
+ * acks a barge-in; `error` reports a non-fatal turn failure.
601
+ * @experimental
602
+ */
616
603
  type VoiceServerFrame = {
617
604
  audioFormat: "mp3" | "wav";
618
605
  type: "ready";
@@ -632,9 +619,9 @@ type VoiceServerFrame = {
632
619
  type: "interrupted";
633
620
  };
634
621
  /**
635
- * A control frame the client sends the server (audio rides separate binary frames).
636
- * @experimental
637
- */
622
+ * A control frame the client sends the server (audio rides separate binary frames).
623
+ * @experimental
624
+ */
638
625
  type VoiceClientFrame = {
639
626
  text: string;
640
627
  type: "text";
@@ -644,34 +631,34 @@ type VoiceClientFrame = {
644
631
  type: "interrupt";
645
632
  };
646
633
  /**
647
- * A synthesized-audio source the TTS seam yields — normalized to bytes by {@link toByteIterable}.
648
- * @experimental
649
- */
634
+ * A synthesized-audio source the TTS seam yields — normalized to bytes by {@link toByteIterable}.
635
+ * @experimental
636
+ */
650
637
  type VoiceAudioSource = AsyncIterable<Uint8Array> | ReadableStream<Uint8Array> | Uint8Array;
651
638
  /**
652
- * Transcribe one buffered utterance (16kHz mono 16-bit PCM) to text.
653
- * @experimental
654
- */
639
+ * Transcribe one buffered utterance (16kHz mono 16-bit PCM) to text.
640
+ * @experimental
641
+ */
655
642
  type VoiceTranscribe = (pcm: Uint8Array) => Promise<string>;
656
643
  /**
657
- * Synthesize one sentence to an audio byte stream; honors `signal` for barge-in.
658
- * @experimental
659
- */
644
+ * Synthesize one sentence to an audio byte stream; honors `signal` for barge-in.
645
+ * @experimental
646
+ */
660
647
  type VoiceSynthesize = (text: string, signal: AbortSignal) => Promise<VoiceAudioSource>;
661
648
  /**
662
- * Send a JSON control frame to the client.
663
- * @experimental
664
- */
649
+ * Send a JSON control frame to the client.
650
+ * @experimental
651
+ */
665
652
  type VoiceSend = (frame: VoiceServerFrame) => void;
666
653
  /**
667
- * Send a binary audio frame to the client.
668
- * @experimental
669
- */
654
+ * Send a binary audio frame to the client.
655
+ * @experimental
656
+ */
670
657
  type VoiceSendAudio = (bytes: Uint8Array) => void;
671
658
  /**
672
- * The outcome of one voice turn.
673
- * @experimental
674
- */
659
+ * The outcome of one voice turn.
660
+ * @experimental
661
+ */
675
662
  interface VoiceTurnResult {
676
663
  /** The final assistant text (may be partial if `interrupted`). */
677
664
  assistantText: string;
@@ -681,9 +668,9 @@ interface VoiceTurnResult {
681
668
  userText: string;
682
669
  }
683
670
  /**
684
- * Options for one {@link runVoiceTurn}.
685
- * @experimental
686
- */
671
+ * Options for one {@link runVoiceTurn}.
672
+ * @experimental
673
+ */
687
674
  interface RunVoiceTurnOptions {
688
675
  /** The agent whose thread + models back this session. */
689
676
  agent: AgentDefinition;
@@ -722,24 +709,21 @@ interface RunVoiceTurnOptions {
722
709
  /** Optional outbound-audio backpressure: awaited before each audio frame so a slow client can't balloon DO memory. Never throws. */
723
710
  waitForDrain?: () => Promise<void>;
724
711
  }
725
- /** Normalize a {@link VoiceAudioSource} to an async iterable of byte chunks. */
726
-
727
- /**
728
- * Run one conversational voice turn IN-DO: transcribe the utterance (or take the
729
- * typed text), persist the user turn onto the SHARED agent thread, stream the
730
- * assistant reply, and synthesize it sentence-by-sentence back to the client —
731
- * TTS overlapping generation, both cancellable by a barge-in `signal`.
732
- *
733
- * This is NOT the replay-durable Workflow tool-loop: a voice turn is
734
- * conversational only (no tools in v1) and not replay-safe. Persistence stays
735
- * idempotent by `voice:{connectionId}:{turn}:{role}` message keys so a resent
736
- * frame never duplicates a row; the thread tables are the same ones the durable
737
- * agent loop and `useAgentChat` read, so a voice session and a text session on
738
- * the same `threadKey` share one history.
739
- * @experimental
740
- */
712
+ /**
713
+ * Run one conversational voice turn IN-DO: transcribe the utterance (or take the
714
+ * typed text), persist the user turn onto the SHARED agent thread, stream the
715
+ * assistant reply, and synthesize it sentence-by-sentence back to the client
716
+ * TTS overlapping generation, both cancellable by a barge-in `signal`.
717
+ *
718
+ * This is NOT the replay-durable Workflow tool-loop: a voice turn is
719
+ * conversational only (no tools in v1) and not replay-safe. Persistence stays
720
+ * idempotent by `voice:{connectionId}:{turn}:{role}` message keys so a resent
721
+ * frame never duplicates a row; the thread tables are the same ones the durable
722
+ * agent loop and `useAgentChat` read, so a voice session and a text session on
723
+ * the same `threadKey` share one history.
724
+ * @experimental
725
+ */
741
726
  declare const runVoiceTurn: (options: RunVoiceTurnOptions) => Promise<VoiceTurnResult>;
742
- /** Parse the JSON identity envelope forwarded on the `x-lunora-identity` upgrade header. */
743
727
  /** Structural subset of `DurableObjectState` the voice DO needs (typed locally for unit doubles). */
744
728
  interface VoiceSessionState {
745
729
  acceptWebSocket: (ws: WebSocket, tags?: string[]) => void;
@@ -747,21 +731,21 @@ interface VoiceSessionState {
747
731
  waitUntil?: (promise: Promise<unknown>) => void;
748
732
  }
749
733
  /**
750
- * A hibernatable-WebSocket Durable Object that runs an agent's real-time VOICE
751
- * session. One instance per `threadKey`: the client opens a WebSocket, streams
752
- * 16kHz mono PCM as binary frames, and marks utterance boundaries with a JSON
753
- * `{ type: "commit" }` control frame; the DO transcribes the utterance, streams
754
- * the agent's reply through the LLM, and synthesizes it back as MP3 binary
755
- * frames — all IN-DO. It SHARES the agent's `agent_threads`/`agent_messages`
756
- * tables through the same runtime dispatch seam the durable loop uses, so voice
757
- * and text turns interleave on one history.
758
- *
759
- * Codegen emits a thin subclass per voice-enabled agent (e.g.
760
- * `SupportVoiceDO extends VoiceSessionDO`, constructed with the agent
761
- * definition + its export name) bound under the agent's `VOICE_...` Durable
762
- * Object binding.
763
- * @experimental
764
- */
734
+ * A hibernatable-WebSocket Durable Object that runs an agent's real-time VOICE
735
+ * session. One instance per `threadKey`: the client opens a WebSocket, streams
736
+ * 16kHz mono PCM as binary frames, and marks utterance boundaries with a JSON
737
+ * `{ type: "commit" }` control frame; the DO transcribes the utterance, streams
738
+ * the agent's reply through the LLM, and synthesizes it back as MP3 binary
739
+ * frames — all IN-DO. It SHARES the agent's `agent_threads`/`agent_messages`
740
+ * tables through the same runtime dispatch seam the durable loop uses, so voice
741
+ * and text turns interleave on one history.
742
+ *
743
+ * Codegen emits a thin subclass per voice-enabled agent (e.g.
744
+ * `SupportVoiceDO extends VoiceSessionDO`, constructed with the agent
745
+ * definition + its export name) bound under the agent's `VOICE_...` Durable
746
+ * Object binding.
747
+ * @experimental
748
+ */
765
749
  declare class VoiceSessionDO {
766
750
  protected readonly agent: AgentDefinition;
767
751
  protected readonly ai: ReturnType<typeof createAi>;
@@ -785,11 +769,11 @@ declare class VoiceSessionDO {
785
769
  /** Abort any in-flight turn + free the socket's buffers on error. Never throws. */
786
770
  webSocketError(ws: WebSocket): void;
787
771
  /**
788
- * The runtime dispatch seam reaching the shared agent thread functions. When
789
- * the socket carries a verified identity it is forwarded so the `agents:*`
790
- * thread writes are attributed to the caller (RLS / row ownership) rather
791
- * than the anonymous system dispatch.
792
- */
772
+ * The runtime dispatch seam reaching the shared agent thread functions. When
773
+ * the socket carries a verified identity it is forwarded so the `agents:*`
774
+ * thread writes are attributed to the caller (RLS / row ownership) rather
775
+ * than the anonymous system dispatch.
776
+ */
793
777
  protected resolveRun(userId?: string, claims?: Record<string, unknown>): AgentRunFunction;
794
778
  /** Production STT seam: WAV-wrap the utterance and run the batch transcription model. */
795
779
  protected transcribe(pcm: Uint8Array): Promise<string>;
@@ -814,34 +798,34 @@ declare class VoiceSessionDO {
814
798
  /** Send a binary audio frame, swallowing a closed-socket error. */
815
799
  private sendAudio;
816
800
  /**
817
- * Outbound backpressure: if the socket exposes `bufferedAmount`, yield in
818
- * short polls until the send buffer drains below the cap so a slow client
819
- * can't balloon DO memory. Bounded by {@link MAX_DRAIN_WAIT_MS} so a stuck
820
- * socket never blocks a turn forever, and never throws (a socket without
821
- * `bufferedAmount` resolves immediately).
822
- */
801
+ * Outbound backpressure: if the socket exposes `bufferedAmount`, yield in
802
+ * short polls until the send buffer drains below the cap so a slow client
803
+ * can't balloon DO memory. Bounded by {@link MAX_DRAIN_WAIT_MS} so a stuck
804
+ * socket never blocks a turn forever, and never throws (a socket without
805
+ * `bufferedAmount` resolves immediately).
806
+ */
823
807
  private waitForSocketDrain;
824
808
  }
825
809
  /**
826
- * Compile a `defineAgent` definition into the workflow the generated
827
- * `&lt;Name>AgentWorkflow` entrypoint class runs. Codegen emits, per agent:
828
- *
829
- * ```ts
830
- * import LunoraWorkflow from "@lunora/workflow/do";
831
- * import { compileAgentWorkflow } from "@lunora/agent";
832
- * import { support } from "../agents.js";
833
- *
834
- * export class SupportAgentWorkflow extends LunoraWorkflow&lt;AgentRunInput, AgentRunResult> {
835
- * public constructor(ctx: ConstructorParameters&lt;typeof LunoraWorkflow>[0], env: Record&lt;string, unknown>) {
836
- * super(ctx, env, compileAgentWorkflow(support, "support"), "support");
837
- * }
838
- * }
839
- * ```
840
- *
841
- * The workflow ctx supplies durability (`step.do`) and the Lunora dispatcher
842
- * (`run`); the loop supplies determinism (step naming + idempotent persists).
843
- * @experimental
844
- */
810
+ * Compile a `defineAgent` definition into the workflow the generated
811
+ * `&lt;Name>AgentWorkflow` entrypoint class runs. Codegen emits, per agent:
812
+ *
813
+ * ```ts
814
+ * import LunoraWorkflow from "@lunora/workflow/do";
815
+ * import { compileAgentWorkflow } from "@lunora/agent";
816
+ * import { support } from "../agents.js";
817
+ *
818
+ * export class SupportAgentWorkflow extends LunoraWorkflow&lt;AgentRunInput, AgentRunResult> {
819
+ * public constructor(ctx: ConstructorParameters&lt;typeof LunoraWorkflow>[0], env: Record&lt;string, unknown>) {
820
+ * super(ctx, env, compileAgentWorkflow(support, "support"), "support");
821
+ * }
822
+ * }
823
+ * ```
824
+ *
825
+ * The workflow ctx supplies durability (`step.do`) and the Lunora dispatcher
826
+ * (`run`); the loop supplies determinism (step naming + idempotent persists).
827
+ * @experimental
828
+ */
845
829
  declare const compileAgentWorkflow: (agent: AgentDefinition, exportName: string, options?: {
846
830
  paths?: AgentFunctionPaths;
847
831
  }) => WorkflowDefinition<AgentRunInput, AgentRunResult>;