@lunora/agent 1.0.0-alpha.7 → 1.0.0-alpha.71

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 (84) hide show
  1. package/dist/channels.d.mts +2 -2
  2. package/dist/channels.d.ts +2 -2
  3. package/dist/channels.mjs +1 -181
  4. package/dist/component.d.mts +2 -0
  5. package/dist/component.d.ts +2 -0
  6. package/dist/component.mjs +2 -418
  7. package/dist/inbound.d.mts +1 -1
  8. package/dist/inbound.d.ts +1 -1
  9. package/dist/inbound.mjs +1 -32
  10. package/dist/index.d.mts +38 -8
  11. package/dist/index.d.ts +38 -8
  12. package/dist/index.mjs +1 -18
  13. package/dist/naming.mjs +1 -8
  14. package/dist/packem_shared/AGENT_MODULE-M4D1EejI.mjs +1 -0
  15. package/dist/packem_shared/VoiceSessionDO-Dxj0V8Ej.mjs +1 -0
  16. package/dist/packem_shared/adaptMcpResult-CVlq-_TO.mjs +2 -0
  17. package/dist/packem_shared/agentAsTool-DrFnh9UQ.mjs +1 -0
  18. package/dist/packem_shared/base64-5eyBfWO3.mjs +1 -0
  19. package/dist/packem_shared/braintrustTelemetry-CoYK-pq7.mjs +1 -0
  20. package/dist/packem_shared/branch-marker-boZ00zmk.mjs +1 -0
  21. package/dist/packem_shared/buildModelMessages-Y4tGo1T9.mjs +5 -0
  22. package/dist/packem_shared/codeTool-qdwj8j8S.mjs +1 -0
  23. package/dist/packem_shared/collectAgenticMemoryTools-BeMWT2qt.mjs +1 -0
  24. package/dist/packem_shared/combineTelemetry-DgE9W9G8.mjs +1 -0
  25. package/dist/packem_shared/common-CJSjtsfv.mjs +1 -0
  26. package/dist/packem_shared/compileAgentWorkflow-GDJ_HWln.mjs +1 -0
  27. package/dist/packem_shared/component-shared-IZozysYq.mjs +1 -0
  28. package/dist/packem_shared/consoleTelemetry-BZY3Y-Ly.mjs +1 -0
  29. package/dist/packem_shared/createAgentContext-iS35-Xrs.mjs +1 -0
  30. package/dist/packem_shared/createAgentGenerate-9bZ2YhpN.mjs +3 -0
  31. package/dist/packem_shared/createDispatchRunner-pLyQ70FK-2_j6ocGT.mjs +1 -0
  32. package/dist/packem_shared/defineAgent-CZdh7y3W.mjs +3 -0
  33. package/dist/packem_shared/defineSkill-DGGvDWNq.mjs +1 -0
  34. package/dist/packem_shared/functionTool-D3CP4f8-.mjs +1 -0
  35. package/dist/packem_shared/memory-JI0lUu84.mjs +1 -0
  36. package/dist/packem_shared/normalizeEntityName-Ce0X6Afj.mjs +2 -0
  37. package/dist/packem_shared/otlpTelemetry-CoyeTO8S.mjs +1 -0
  38. package/dist/packem_shared/runAgentLoop-KUUoFT3r.mjs +3 -0
  39. package/dist/packem_shared/runVoiceTurn-CRPeNXsS.mjs +1 -0
  40. package/dist/packem_shared/sandboxComponent-BtOkUYpY.mjs +5 -0
  41. package/dist/packem_shared/sentryTelemetry-CPqEbFPA.mjs +1 -0
  42. package/dist/packem_shared/{types.d-boAM2Yi1.d.mts → types.d-eCuvcLzf.d.mts} +211 -21
  43. package/dist/packem_shared/{types.d-boAM2Yi1.d.ts → types.d-eCuvcLzf.d.ts} +211 -21
  44. package/dist/packem_shared/voice-turn-DbVR0H6T.mjs +1 -0
  45. package/dist/reply.d.mts +40 -0
  46. package/dist/reply.d.ts +40 -0
  47. package/dist/reply.mjs +1 -0
  48. package/dist/sandbox.d.mts +14 -13
  49. package/dist/sandbox.d.ts +14 -13
  50. package/dist/sandbox.mjs +1 -113
  51. package/dist/skill-markdown.d.mts +36 -0
  52. package/dist/skill-markdown.d.ts +36 -0
  53. package/dist/skill-markdown.mjs +1 -0
  54. package/dist/telemetry/index.d.mts +72 -9
  55. package/dist/telemetry/index.d.ts +72 -9
  56. package/dist/telemetry/index.mjs +1 -5
  57. package/package.json +18 -9
  58. package/dist/packem_shared/AGENT_MODULE-Dnt_-AAT.mjs +0 -24
  59. package/dist/packem_shared/VoiceSessionDO-DLoXsHGF.mjs +0 -297
  60. package/dist/packem_shared/adaptMcpResult-wtNMvLoP.mjs +0 -65
  61. package/dist/packem_shared/agentAsTool-CUHlWsmt.mjs +0 -98
  62. package/dist/packem_shared/base64-BVwtgRJV.mjs +0 -18
  63. package/dist/packem_shared/braintrustTelemetry-wuGDErob.mjs +0 -47
  64. package/dist/packem_shared/buildModelMessages-BWFigaoo.mjs +0 -69
  65. package/dist/packem_shared/codeTool-CjgJOC9t.mjs +0 -122
  66. package/dist/packem_shared/collectAgenticMemoryTools-QrzpV-WX.mjs +0 -97
  67. package/dist/packem_shared/combineTelemetry-DCyaaWAI.mjs +0 -43
  68. package/dist/packem_shared/common-DAeFCot5.mjs +0 -61
  69. package/dist/packem_shared/compileAgentWorkflow-DX90058f.mjs +0 -55
  70. package/dist/packem_shared/consoleTelemetry-z2MiP1jt.mjs +0 -93
  71. package/dist/packem_shared/createAgentContext-4xJGXNR4.mjs +0 -50
  72. package/dist/packem_shared/createAgentGenerate-BQv9YJ01.mjs +0 -192
  73. package/dist/packem_shared/createDispatchRunner-DSbp_dph-ZHTtxy3f.mjs +0 -69
  74. package/dist/packem_shared/defineAgent-DAwAZC9P.mjs +0 -148
  75. package/dist/packem_shared/defineSkill-Ctf_S-rz.mjs +0 -22
  76. package/dist/packem_shared/functionTool-D6lCa2jB.mjs +0 -20
  77. package/dist/packem_shared/graph-component-Bbaxxymp.mjs +0 -217
  78. package/dist/packem_shared/memory-D4FPcBsX.mjs +0 -12
  79. package/dist/packem_shared/normalizeEntityName-BouctxLC.mjs +0 -3
  80. package/dist/packem_shared/otlpTelemetry-DL6iZ9e2.mjs +0 -164
  81. package/dist/packem_shared/runAgentLoop-B3Q2o-Uz.mjs +0 -493
  82. package/dist/packem_shared/runVoiceTurn-LnqLvCRR.mjs +0 -211
  83. package/dist/packem_shared/sandboxComponent-DR3pTwBL.mjs +0 -194
  84. package/dist/packem_shared/sentryTelemetry-CgqFJyLO.mjs +0 -36
@@ -1,418 +1,2 @@
1
- import { LunoraError } from '@lunora/errors';
2
- import { defineTable, initLunora, defineSchemaExtension } from '@lunora/server';
3
- import { v } from '@lunora/values';
4
- import { a as asInternal, A as AGENT_EXTENSION_KEY, g as graphTables, d as definedColumns, b as graphComponent } from './packem_shared/graph-component-Bbaxxymp.mjs';
5
- export { n as normalizeEntityName } from './packem_shared/graph-component-Bbaxxymp.mjs';
6
- export { sandboxComponent } from './packem_shared/sandboxComponent-DR3pTwBL.mjs';
7
-
8
- const EPISODES_TABLE = "agent_episodes";
9
- const DEFAULT_EPISODE_RECALL = 5;
10
- const MAX_EPISODE_RECALL = 20;
11
- const MAX_EPISODE_SUMMARY_CHARS = 500;
12
- const MAX_EPISODE_RETENTION = 200;
13
- const WHITESPACE_RUN = /\s+/gu;
14
- const clampRecall = (value) => {
15
- if (value === void 0 || !Number.isFinite(value)) {
16
- return DEFAULT_EPISODE_RECALL;
17
- }
18
- return Math.min(MAX_EPISODE_RECALL, Math.max(1, Math.trunc(value)));
19
- };
20
- const episodeTables = {
21
- /**
22
- * One episode per completed run — a short natural-language summary of the
23
- * exchange, time-ordered for recency recall. `messageKey` (the extract
24
- * step's instance-scoped key) is the idempotency key so a workflow replay
25
- * never double-records the same run.
26
- */
27
- episodes: defineTable({
28
- createdAt: v.number(),
29
- messageKey: v.string(),
30
- owner: v.string(),
31
- /** A one/two-sentence summary of the run, injected as a memory-log line. */
32
- summary: v.string(),
33
- /** The thread the episode came from (provenance; not used for recall scope). */
34
- threadKey: v.optional(v.string())
35
- }).index("byOwnerCreatedAt", ["owner", "createdAt"]).index("byOwnerMessageKey", ["owner", "messageKey"], { unique: true }).public()
36
- };
37
- const { mutation: mutation$1, query: query$1 } = initLunora.dataModel().create();
38
- const episodicComponent = () => {
39
- const agentEpisodeUpsert = mutation$1.input({
40
- createdAt: v.optional(v.number()),
41
- messageKey: v.string(),
42
- owner: v.string(),
43
- summary: v.string(),
44
- threadKey: v.optional(v.string())
45
- }).mutation(async ({ args, ctx: context }) => {
46
- const summary = args.summary.replaceAll(WHITESPACE_RUN, " ").trim().slice(0, MAX_EPISODE_SUMMARY_CHARS);
47
- if (summary.length === 0) {
48
- return { recorded: false };
49
- }
50
- const existing = await context.db.query(EPISODES_TABLE).withIndex("byOwnerMessageKey", (q) => q.eq("owner", args.owner).eq("messageKey", args.messageKey)).first();
51
- if (existing) {
52
- return { recorded: false };
53
- }
54
- await context.db.insert(EPISODES_TABLE, {
55
- createdAt: args.createdAt ?? Date.now(),
56
- messageKey: args.messageKey,
57
- owner: args.owner,
58
- summary,
59
- ...args.threadKey === void 0 ? {} : { threadKey: args.threadKey }
60
- });
61
- const overflow = await context.db.query(EPISODES_TABLE).withIndex("byOwnerCreatedAt", (q) => q.eq("owner", args.owner)).order("asc").take(MAX_EPISODE_RETENTION + 1);
62
- for (const stale of overflow.slice(0, Math.max(0, overflow.length - MAX_EPISODE_RETENTION))) {
63
- await context.db.delete(stale["_id"]);
64
- }
65
- return { recorded: true };
66
- });
67
- const agentEpisodeRecall = query$1.input({
68
- limit: v.optional(v.number()),
69
- owner: v.string()
70
- }).query(async ({ args, ctx: context }) => {
71
- const recent = await context.db.query(EPISODES_TABLE).withIndex("byOwnerCreatedAt", (q) => q.eq("owner", args.owner)).order("desc").take(clampRecall(args.limit));
72
- if (recent.length === 0) {
73
- return { context: "" };
74
- }
75
- return {
76
- context: recent.toReversed().map((row) => `- ${row["summary"]}`).join("\n")
77
- };
78
- });
79
- return {
80
- agentEpisodeRecall: asInternal(agentEpisodeRecall),
81
- agentEpisodeUpsert: asInternal(agentEpisodeUpsert)
82
- };
83
- };
84
-
85
- const THREADS_BARE_TABLE = "threads";
86
- const MESSAGES_BARE_TABLE = "messages";
87
- const THREADS_TABLE = `${AGENT_EXTENSION_KEY}_${THREADS_BARE_TABLE}`;
88
- const MESSAGES_TABLE = `${AGENT_EXTENSION_KEY}_${MESSAGES_BARE_TABLE}`;
89
- const agentExtension = defineSchemaExtension(AGENT_EXTENSION_KEY, {
90
- tables: {
91
- [MESSAGES_BARE_TABLE]: defineTable({
92
- content: v.string(),
93
- createdAt: v.number(),
94
- messageKey: v.string(),
95
- role: v.union(v.literal("user"), v.literal("assistant"), v.literal("tool"), v.literal("system")),
96
- seq: v.number(),
97
- /**
98
- * Human-in-the-loop approval marker: `"awaiting_approval"` on the
99
- * placeholder written while a run pauses on a gated tool, then
100
- * `"approved"`/`"rejected"` on the tool result once resolved. Optional
101
- * so ordinary messages (and pre-existing rows) are unaffected.
102
- */
103
- status: v.optional(v.union(v.literal("awaiting_approval"), v.literal("approved"), v.literal("rejected"))),
104
- stepName: v.optional(v.string()),
105
- threadKey: v.string(),
106
- toolCallId: v.optional(v.string()),
107
- toolCalls: v.optional(v.array(v.object({ id: v.string(), input: v.any(), name: v.string() }))),
108
- toolName: v.optional(v.string())
109
- }).index("byThread", ["threadKey", "seq"]).index("byMessageKey", ["threadKey", "messageKey"], { unique: true }).public(),
110
- [THREADS_BARE_TABLE]: defineTable({
111
- agent: v.string(),
112
- createdAt: v.number(),
113
- error: v.optional(v.string()),
114
- /**
115
- * The workflow instance id of the run that currently owns this
116
- * thread. The concurrency guard compares it to a starting run's own
117
- * instance id — a match is a replay (allow), a mismatch while
118
- * `status === "running"` is a genuine second run (apply
119
- * `onConcurrentRun`). Also the target for `cancel`/`replace`. Optional
120
- * so pre-existing threads (written before this column) are unaffected.
121
- */
122
- instanceId: v.optional(v.string()),
123
- key: v.string(),
124
- // Next message seq — incremented on every append (see above).
125
- messageCount: v.number(),
126
- /**
127
- * Verified identity of the thread owner (pass `ctx.auth.userId`
128
- * when starting a run). When set, the public queries only answer
129
- * for a caller with that identity; when absent the thread is
130
- * readable by anyone who knows its key (single-tenant/anonymous
131
- * apps). First writer wins — a later run may not change it.
132
- */
133
- owner: v.optional(v.string()),
134
- /**
135
- * The thread's synced agent state — a JSON object written by the
136
- * internal `agentSetState` mutation (absolute REPLACE) and read by the
137
- * public `agentState` query (`ctx.getState` / `useAgentState`). Seeded
138
- * from `defineAgent({ initialState })` on thread creation. Optional so
139
- * agent-free apps and pre-existing threads (written before this column)
140
- * are unaffected.
141
- */
142
- state: v.optional(v.any()),
143
- status: v.union(v.literal("idle"), v.literal("running"), v.literal("error"), v.literal("cancelled"), v.literal("awaiting_input")),
144
- title: v.optional(v.string()),
145
- updatedAt: v.number(),
146
- /**
147
- * Cumulative token usage for the latest run on this thread, patched
148
- * at run end. Optional so agent-free apps and pre-existing threads
149
- * (written before this column existed) are unaffected.
150
- */
151
- usage: v.optional(v.object({ inputTokens: v.optional(v.number()), outputTokens: v.optional(v.number()), totalTokens: v.optional(v.number()) }))
152
- }).index("byKey", ["key"], { unique: true }).index("byAgent", ["agent"]).index("byInstance", ["instanceId"]).public(),
153
- // The owner-scoped graph-memory tables (`agent_entities`/`agent_edges`)
154
- // live in graph-component.ts alongside the functions that read/write
155
- // them; spread in here so the app still merges one `agentExtension`.
156
- ...graphTables,
157
- // The owner-scoped episodic-memory table (`agent_episodes`) lives in
158
- // episodic-component.ts alongside its functions; spread in here too.
159
- ...episodeTables
160
- }
161
- });
162
- const { mutation, query } = initLunora.dataModel().create();
163
- const agentComponent = () => {
164
- const agentEnsureThread = mutation.input({
165
- agent: v.string(),
166
- // Seed the thread's synced state — set on the INSERT branch only
167
- // (first writer wins, like owner/title), so a replay never re-seeds.
168
- initialState: v.optional(v.any()),
169
- instanceId: v.optional(v.string()),
170
- key: v.string(),
171
- onConcurrentRun: v.optional(v.union(v.literal("reject"), v.literal("queue"), v.literal("replace"))),
172
- owner: v.optional(v.string()),
173
- title: v.optional(v.string())
174
- }).mutation(async ({ args, ctx: context }) => {
175
- const now = Date.now();
176
- const existing = await context.db.query(THREADS_TABLE).withIndex("byKey", (q) => q.eq("key", args.key)).first();
177
- if (existing) {
178
- if (existing["owner"] !== args.owner && args.owner !== void 0) {
179
- throw new Error(`@lunora/agent: thread "${args.key}" belongs to another owner`);
180
- }
181
- const priorInstanceId = existing["instanceId"];
182
- const isConcurrentRun = (existing["status"] === "running" || existing["status"] === "awaiting_input") && priorInstanceId !== void 0 && (args.instanceId === void 0 || args.instanceId !== priorInstanceId);
183
- if (isConcurrentRun) {
184
- const policy = args.onConcurrentRun ?? "reject";
185
- if (policy !== "replace") {
186
- throw new LunoraError(
187
- "CONFLICT",
188
- `@lunora/agent: thread "${args.key}" already has a run in flight (instance "${priorInstanceId}") — onConcurrentRun="${policy}"`
189
- );
190
- }
191
- await context.db.patch(existing["_id"], {
192
- error: void 0,
193
- status: "running",
194
- updatedAt: now,
195
- ...args.instanceId === void 0 ? {} : { instanceId: args.instanceId }
196
- });
197
- return { created: false, priorInstanceId, replaced: true };
198
- }
199
- await context.db.patch(existing["_id"], {
200
- error: void 0,
201
- status: "running",
202
- updatedAt: now,
203
- ...args.instanceId === void 0 ? {} : { instanceId: args.instanceId }
204
- });
205
- return { created: false };
206
- }
207
- await context.db.insert(THREADS_TABLE, {
208
- agent: args.agent,
209
- createdAt: now,
210
- key: args.key,
211
- messageCount: 0,
212
- status: "running",
213
- updatedAt: now,
214
- ...definedColumns({ instanceId: args.instanceId, owner: args.owner, state: args.initialState, title: args.title })
215
- });
216
- return { created: true };
217
- });
218
- const agentAppendMessage = mutation.input({
219
- content: v.string(),
220
- messageKey: v.string(),
221
- role: v.union(v.literal("user"), v.literal("assistant"), v.literal("tool"), v.literal("system")),
222
- status: v.optional(v.union(v.literal("awaiting_approval"), v.literal("approved"), v.literal("rejected"))),
223
- stepName: v.optional(v.string()),
224
- threadKey: v.string(),
225
- toolCallId: v.optional(v.string()),
226
- toolCalls: v.optional(v.array(v.object({ id: v.string(), input: v.any(), name: v.string() }))),
227
- toolName: v.optional(v.string())
228
- }).mutation(async ({ args, ctx: context }) => {
229
- const existing = await context.db.query(MESSAGES_TABLE).withIndex("byMessageKey", (q) => q.eq("threadKey", args.threadKey).eq("messageKey", args.messageKey)).first();
230
- if (existing) {
231
- return { seq: existing["seq"] };
232
- }
233
- const thread = await context.db.query(THREADS_TABLE).withIndex("byKey", (q) => q.eq("key", args.threadKey)).first();
234
- if (!thread) {
235
- throw new Error(`@lunora/agent: cannot append to unknown thread "${args.threadKey}" — run agentEnsureThread first`);
236
- }
237
- const seq = thread["messageCount"];
238
- const now = Date.now();
239
- await context.db.insert(MESSAGES_TABLE, {
240
- content: args.content,
241
- createdAt: now,
242
- messageKey: args.messageKey,
243
- role: args.role,
244
- seq,
245
- threadKey: args.threadKey,
246
- ...args.status === void 0 ? {} : { status: args.status },
247
- ...args.stepName === void 0 ? {} : { stepName: args.stepName },
248
- ...args.toolCallId === void 0 ? {} : { toolCallId: args.toolCallId },
249
- ...args.toolCalls === void 0 ? {} : { toolCalls: args.toolCalls },
250
- ...args.toolName === void 0 ? {} : { toolName: args.toolName }
251
- });
252
- await context.db.patch(thread["_id"], { messageCount: seq + 1, updatedAt: now });
253
- return { seq };
254
- });
255
- const agentPatchThread = mutation.input({
256
- error: v.optional(v.string()),
257
- // Target by thread key (the loop) OR by workflow instance id (cancel,
258
- // which only knows the instance it terminated). Exactly one is set.
259
- instanceId: v.optional(v.string()),
260
- key: v.optional(v.string()),
261
- status: v.optional(v.union(v.literal("idle"), v.literal("running"), v.literal("error"), v.literal("cancelled"), v.literal("awaiting_input"))),
262
- title: v.optional(v.string()),
263
- usage: v.optional(v.object({ inputTokens: v.optional(v.number()), outputTokens: v.optional(v.number()), totalTokens: v.optional(v.number()) }))
264
- }).mutation(async ({ args, ctx: context }) => {
265
- const { instanceId, key } = args;
266
- let thread;
267
- if (key !== void 0) {
268
- thread = await context.db.query(THREADS_TABLE).withIndex("byKey", (q) => q.eq("key", key)).first();
269
- } else if (instanceId !== void 0) {
270
- thread = await context.db.query(THREADS_TABLE).withIndex("byInstance", (q) => q.eq("instanceId", instanceId)).first();
271
- }
272
- if (!thread) {
273
- return;
274
- }
275
- await context.db.patch(thread["_id"], {
276
- updatedAt: Date.now(),
277
- ...args.error === void 0 ? {} : { error: args.error },
278
- ...args.status === void 0 ? {} : { status: args.status },
279
- ...args.title === void 0 ? {} : { title: args.title },
280
- // The loop patches a per-run cumulative total; setting it (rather
281
- // than adding) keeps the write idempotent under workflow replay.
282
- ...args.usage === void 0 ? {} : { usage: args.usage }
283
- });
284
- });
285
- const agentSetState = mutation.input({
286
- key: v.string(),
287
- state: v.any()
288
- }).mutation(async ({ args, ctx: context }) => {
289
- const thread = await context.db.query(THREADS_TABLE).withIndex("byKey", (q) => q.eq("key", args.key)).first();
290
- if (!thread) {
291
- return;
292
- }
293
- await context.db.patch(thread["_id"], { state: args.state, updatedAt: Date.now() });
294
- });
295
- const readableThread = (thread, auth) => {
296
- if (!thread) {
297
- return void 0;
298
- }
299
- const { owner } = thread;
300
- if (owner !== void 0 && owner !== (auth.userId ?? void 0)) {
301
- return void 0;
302
- }
303
- return thread;
304
- };
305
- const agentThread = query.input({ key: v.string() }).query(async ({ args, ctx: context }) => {
306
- const thread = await context.db.query(THREADS_TABLE).withIndex("byKey", (q) => q.eq("key", args.key)).first();
307
- return readableThread(thread, context.auth);
308
- });
309
- const agentState = query.input({ key: v.string() }).query(async ({ args, ctx: context }) => {
310
- const thread = await context.db.query(THREADS_TABLE).withIndex("byKey", (q) => q.eq("key", args.key)).first();
311
- return readableThread(thread, context.auth)?.["state"];
312
- });
313
- const agentMessages = query.input({ key: v.string(), limit: v.optional(v.number()) }).query(async ({ args, ctx: context }) => {
314
- const thread = await context.db.query(THREADS_TABLE).withIndex("byKey", (q) => q.eq("key", args.key)).first();
315
- if (readableThread(thread, context.auth) === void 0) {
316
- return [];
317
- }
318
- if (args.limit !== void 0) {
319
- const tail = await context.db.query(MESSAGES_TABLE).withIndex("byThread", (q) => q.eq("threadKey", args.key)).order("desc").take(args.limit);
320
- return tail.toReversed();
321
- }
322
- return context.db.query(MESSAGES_TABLE).withIndex("byThread", (q) => q.eq("threadKey", args.key)).collect();
323
- });
324
- const agentResolveApproval = mutation.input({
325
- decision: v.union(v.literal("approve"), v.literal("reject")),
326
- instanceId: v.string(),
327
- note: v.optional(v.string()),
328
- threadKey: v.string(),
329
- toolCallId: v.string()
330
- }).mutation(async ({ args, ctx: context }) => {
331
- const thread = await context.db.query(THREADS_TABLE).withIndex("byKey", (q) => q.eq("key", args.threadKey)).first();
332
- const readable = readableThread(thread, context.auth);
333
- if (readable === void 0) {
334
- throw new LunoraError("FORBIDDEN", `@lunora/agent: not allowed to resolve approvals on thread "${args.threadKey}"`);
335
- }
336
- if (readable["instanceId"] !== args.instanceId) {
337
- throw new LunoraError("FORBIDDEN", `@lunora/agent: instance "${args.instanceId}" does not own thread "${args.threadKey}"`);
338
- }
339
- const agentName = readable["agent"];
340
- const { agents } = context;
341
- const handle = agents?.[agentName];
342
- if (typeof handle?.sendEvent !== "function") {
343
- throw new LunoraError(
344
- "INTERNAL",
345
- `@lunora/agent: no ctx.agents["${agentName}"] producer to resolve the approval — run codegen/dev so the agent binding is wired`
346
- );
347
- }
348
- await handle.sendEvent(args.instanceId, {
349
- payload: { decision: args.decision, toolCallId: args.toolCallId, ...args.note === void 0 ? {} : { note: args.note } },
350
- // Scoped per tool call — see the doc comment above.
351
- type: `agent-approval:${args.toolCallId}`
352
- });
353
- return { resolved: true };
354
- });
355
- const agentRun = mutation.input({
356
- agent: v.string(),
357
- input: v.string(),
358
- threadKey: v.string(),
359
- title: v.optional(v.string())
360
- }).mutation(async ({ args, ctx: context }) => {
361
- const { agents } = context;
362
- const handle = agents?.[args.agent];
363
- if (typeof handle?.run !== "function") {
364
- throw new LunoraError(
365
- "INTERNAL",
366
- `@lunora/agent: no ctx.agents["${args.agent}"] producer to start a run — run codegen/dev so the agent binding is wired, and check the agent name`
367
- );
368
- }
369
- if (handle.publicRun !== true) {
370
- throw new LunoraError(
371
- "FORBIDDEN",
372
- `@lunora/agent: agent "${args.agent}" is not enabled for public runs — set defineAgent({ publicRun: true }) to allow an external client (e.g. the @lunora/mcp server) to start it`
373
- );
374
- }
375
- const owner = context.auth.userId ?? void 0;
376
- const inflight = await context.db.query(THREADS_TABLE).withIndex("byKey", (q) => q.eq("key", args.threadKey)).first();
377
- if (inflight) {
378
- const status = inflight["status"];
379
- const inflightInstanceId = inflight["instanceId"];
380
- const inflightOwner = inflight["owner"];
381
- if ((status === "running" || status === "awaiting_input") && inflightInstanceId !== void 0 && (inflightOwner === void 0 || inflightOwner === owner)) {
382
- return { id: inflightInstanceId, threadKey: args.threadKey };
383
- }
384
- if (inflightOwner !== owner && owner !== void 0) {
385
- throw new LunoraError("FORBIDDEN", `@lunora/agent: thread "${args.threadKey}" belongs to another owner`);
386
- }
387
- }
388
- const { id } = await handle.run({
389
- input: args.input,
390
- threadKey: args.threadKey,
391
- ...owner === void 0 ? {} : { owner },
392
- ...args.title === void 0 ? {} : { title: args.title }
393
- });
394
- return { id, threadKey: args.threadKey };
395
- });
396
- const graph = graphComponent();
397
- const episodic = episodicComponent();
398
- return {
399
- extension: agentExtension,
400
- functions: {
401
- agentAppendMessage: asInternal(agentAppendMessage),
402
- agentEnsureThread: asInternal(agentEnsureThread),
403
- agentEpisodeRecall: episodic.agentEpisodeRecall,
404
- agentEpisodeUpsert: episodic.agentEpisodeUpsert,
405
- agentGraphTraverse: graph.agentGraphTraverse,
406
- agentGraphUpsert: graph.agentGraphUpsert,
407
- agentMessages,
408
- agentPatchThread: asInternal(agentPatchThread),
409
- agentResolveApproval,
410
- agentRun,
411
- agentSetState: asInternal(agentSetState),
412
- agentState,
413
- agentThread
414
- }
415
- };
416
- };
417
-
418
- export { agentComponent, agentExtension };
1
+ import{LunoraError as g}from"@lunora/errors";import{defineTable as v,initLunora as D,defineSchemaExtension as j}from"@lunora/server";import{v as e}from"@lunora/values";import{a as f,A as k,c as P,d as F}from"./packem_shared/component-shared-IZozysYq.mjs";import{graphTables as G,graphComponent as H}from"./packem_shared/normalizeEntityName-Ce0X6Afj.mjs";import{normalizeEntityName as pe}from"./packem_shared/normalizeEntityName-Ce0X6Afj.mjs";import{sandboxComponent as we}from"./packem_shared/sandboxComponent-BtOkUYpY.mjs";const A="agent_episodes",X=5,Q=20,Y=500,x=200,z=/\s+/gu,V=u=>u===void 0||!Number.isFinite(u)?X:Math.min(Q,Math.max(1,Math.trunc(u))),W={episodes:v({createdAt:e.number(),messageKey:e.string(),owner:e.string(),summary:e.string(),threadKey:e.optional(e.string())}).index("byOwnerCreatedAt",["owner","createdAt"]).index("byOwnerMessageKey",["owner","messageKey"],{unique:!0}).public()},{mutation:J,query:Z}=D.dataModel().create(),ee=()=>{const u=J.input({createdAt:e.optional(e.number()),messageKey:e.string(),owner:e.string(),summary:e.string(),threadKey:e.optional(e.string())}).mutation(async({args:s,ctx:y})=>{const w=s.summary.replaceAll(z," ").trim().slice(0,Y);if(w.length===0)return{recorded:!1};if(await y.db.query(A).withIndex("byOwnerMessageKey",h=>h.eq("owner",s.owner).eq("messageKey",s.messageKey)).first())return{recorded:!1};await y.db.insert(A,{createdAt:s.createdAt??Date.now(),messageKey:s.messageKey,owner:s.owner,summary:w,...s.threadKey===void 0?{}:{threadKey:s.threadKey}});const m=await y.db.query(A).withIndex("byOwnerCreatedAt",h=>h.eq("owner",s.owner)).order("asc").take(x+1);for(const h of m.slice(0,Math.max(0,m.length-x)))await y.db.delete(h._id);return{recorded:!0}}),o=Z.input({limit:e.optional(e.number()),owner:e.string()}).query(async({args:s,ctx:y})=>{const w=await y.db.query(A).withIndex("byOwnerCreatedAt",I=>I.eq("owner",s.owner)).order("desc").take(V(s.limit));return w.length===0?{context:""}:{context:w.toReversed().map(I=>`- ${I.summary}`).join(`
2
+ `)}});return{agentEpisodeRecall:f(o),agentEpisodeUpsert:f(u)}},S="threads",$="messages",M="run_queue",p=`${k}_${S}`,K=`${k}_${$}`,E=`${k}_${M}`,N=5,te=780*60*1e3,ne=j(k,{tables:{[$]:v({content:e.string(),createdAt:e.number(),messageKey:e.string(),role:e.union(e.literal("user"),e.literal("assistant"),e.literal("tool"),e.literal("system")),seq:e.number(),status:e.optional(e.union(e.literal("awaiting_approval"),e.literal("approved"),e.literal("rejected"))),stepName:e.optional(e.string()),threadKey:e.string(),toolCallId:e.optional(e.string()),toolCalls:e.optional(e.array(e.object({id:e.string(),input:e.any(),name:e.string()}))),toolName:e.optional(e.string())}).index("byThread",["threadKey","seq"]).index("byMessageKey",["threadKey","messageKey"],{unique:!0}).public(),[S]:v({agent:e.string(),createdAt:e.number(),error:e.optional(e.string()),instanceId:e.optional(e.string()),key:e.string(),messageCount:e.number(),owner:e.optional(e.string()),state:e.optional(e.any()),status:e.union(e.literal("idle"),e.literal("running"),e.literal("error"),e.literal("cancelled"),e.literal("awaiting_input")),title:e.optional(e.string()),updatedAt:e.number(),usage:e.optional(e.object({inputTokens:e.optional(e.number()),outputTokens:e.optional(e.number()),totalTokens:e.optional(e.number())}))}).index("byKey",["key"],{unique:!0}).index("byAgent",["agent"]).index("byInstance",["instanceId"]).public(),[M]:v({agent:e.string(),enqueuedAt:e.number(),instanceId:e.string(),position:e.number(),threadKey:e.string()}).index("byThread",["threadKey","position"]).index("byThreadInstance",["threadKey","instanceId"],{unique:!0}).public(),...G,...W}}),{mutation:b,query:T}=D.dataModel().create(),ie=async(u,o,s)=>{if(o.instanceId===void 0)throw new g("CONFLICT",`@lunora/agent: thread "${o.key}" already has a run in flight (instance "${o.priorInstanceId}") — cannot queue a dispatch with no instance id`);const{instanceId:y}=o,w=await u.query(E).withIndex("byThreadInstance",h=>h.eq("threadKey",o.key).eq("instanceId",y)).first();if(w)return{outcome:"queued",position:w.position};const I=await u.query(E).withIndex("byThread",h=>h.eq("threadKey",o.key)).collect();if(I.length>=N)throw new g("CONFLICT",`@lunora/agent: thread "${o.key}" run queue is full (depth ${String(N)}) — rejecting instance "${y}"`);const m=(I.at(-1)?.position??-1)+1;return await u.insert(E,{agent:o.agent,enqueuedAt:s,instanceId:y,position:m,threadKey:o.key}),{outcome:"queued",position:m}},ae=async(u,o,s)=>{if(o.policy==="queue")return ie(u,{agent:o.agent,instanceId:o.instanceId,key:o.key,priorInstanceId:o.priorInstanceId},s);if(o.policy!=="replace")throw new g("CONFLICT",`@lunora/agent: thread "${o.key}" already has a run in flight (instance "${o.priorInstanceId}") — onConcurrentRun="${o.policy}"`);return await u.patch(o.existingId,{error:void 0,status:"running",updatedAt:s,...o.instanceId===void 0?{}:{instanceId:o.instanceId}}),{outcome:"replaced",priorInstanceId:o.priorInstanceId}},le=()=>{const u=b.input({agent:e.string(),initialState:e.optional(e.any()),instanceId:e.optional(e.string()),key:e.string(),onConcurrentRun:e.optional(e.union(e.literal("reject"),e.literal("queue"),e.literal("replace"))),owner:e.optional(e.string()),title:e.optional(e.string())}).mutation(async({args:t,ctx:n})=>{const a=Date.now(),i=await n.db.query(p).withIndex("byKey",r=>r.eq("key",t.key)).first();if(i){if(i.owner!==t.owner&&t.owner!==void 0)throw new Error(`@lunora/agent: thread "${t.key}" belongs to another owner`);const r=i.instanceId,d=typeof i.updatedAt=="number"?i.updatedAt:0,c=i.status==="awaiting_input"?P:te;return!(a-d>c)&&(i.status==="running"||i.status==="awaiting_input")&&r!==void 0&&(t.instanceId===void 0||t.instanceId!==r)?ae(n.db,{agent:t.agent,existingId:i._id,instanceId:t.instanceId,key:t.key,policy:t.onConcurrentRun??"reject",priorInstanceId:r},a):(await n.db.patch(i._id,{error:void 0,status:"running",updatedAt:a,...t.instanceId===void 0?{}:{instanceId:t.instanceId}}),{outcome:"continued"})}return await n.db.insert(p,{agent:t.agent,createdAt:a,key:t.key,messageCount:0,status:"running",updatedAt:a,...F({instanceId:t.instanceId,owner:t.owner,state:t.initialState,title:t.title})}),{outcome:"created"}}),o=b.input({content:e.string(),messageKey:e.string(),role:e.union(e.literal("user"),e.literal("assistant"),e.literal("tool"),e.literal("system")),status:e.optional(e.union(e.literal("awaiting_approval"),e.literal("approved"),e.literal("rejected"))),stepName:e.optional(e.string()),threadKey:e.string(),toolCallId:e.optional(e.string()),toolCalls:e.optional(e.array(e.object({id:e.string(),input:e.any(),name:e.string()}))),toolName:e.optional(e.string())}).mutation(async({args:t,ctx:n})=>{const a=await n.db.query(K).withIndex("byMessageKey",c=>c.eq("threadKey",t.threadKey).eq("messageKey",t.messageKey)).first();if(a)return{seq:a.seq};const i=await n.db.query(p).withIndex("byKey",c=>c.eq("key",t.threadKey)).first();if(!i)throw new Error(`@lunora/agent: cannot append to unknown thread "${t.threadKey}" — run agentEnsureThread first`);const r=i.messageCount,d=Date.now();return await n.db.insert(K,{content:t.content,createdAt:d,messageKey:t.messageKey,role:t.role,seq:r,threadKey:t.threadKey,...t.status===void 0?{}:{status:t.status},...t.stepName===void 0?{}:{stepName:t.stepName},...t.toolCallId===void 0?{}:{toolCallId:t.toolCallId},...t.toolCalls===void 0?{}:{toolCalls:t.toolCalls},...t.toolName===void 0?{}:{toolName:t.toolName}}),await n.db.patch(i._id,{messageCount:r+1,updatedAt:d}),{seq:r}}),s=b.input({messageKey:e.string(),threadKey:e.string()}).mutation(async({args:t,ctx:n})=>{const a=await n.db.query(K).withIndex("byMessageKey",i=>i.eq("threadKey",t.threadKey).eq("messageKey",t.messageKey)).first();a&&await n.db.delete(a._id)}),y=b.input({error:e.optional(e.string()),instanceId:e.optional(e.string()),key:e.optional(e.string()),status:e.optional(e.union(e.literal("idle"),e.literal("running"),e.literal("error"),e.literal("cancelled"),e.literal("awaiting_input"))),title:e.optional(e.string()),usage:e.optional(e.object({inputTokens:e.optional(e.number()),outputTokens:e.optional(e.number()),totalTokens:e.optional(e.number())}))}).mutation(async({args:t,ctx:n})=>{const{instanceId:a,key:i}=t;let r;i!==void 0?r=await n.db.query(p).withIndex("byKey",d=>d.eq("key",i)).first():a!==void 0&&(r=await n.db.query(p).withIndex("byInstance",d=>d.eq("instanceId",a)).first()),r&&await n.db.patch(r._id,{updatedAt:Date.now(),...t.error===void 0?{}:{error:t.error},...t.status===void 0?{}:{status:t.status},...t.title===void 0?{}:{title:t.title},...t.usage===void 0?{}:{usage:t.usage}})}),w=b.input({error:e.optional(e.string()),instanceId:e.string(),key:e.string(),status:e.union(e.literal("idle"),e.literal("error"),e.literal("cancelled")),usage:e.optional(e.object({inputTokens:e.optional(e.number()),outputTokens:e.optional(e.number()),totalTokens:e.optional(e.number())}))}).mutation(async({args:t,ctx:n})=>{const a=Date.now(),i=await n.db.query(p).withIndex("byKey",l=>l.eq("key",t.key)).first();if(i?.instanceId!==t.instanceId){const l=await n.db.query(E).withIndex("byThreadInstance",q=>q.eq("threadKey",t.key).eq("instanceId",t.instanceId)).first();return l&&await n.db.delete(l._id),{}}const d=(await n.db.query(E).withIndex("byThread",l=>l.eq("threadKey",t.key)).collect())[0];if(!d)return await n.db.patch(i._id,{status:t.status,updatedAt:a,...t.error===void 0?{}:{error:t.error},...t.usage===void 0?{}:{usage:t.usage}}),{};const c=d.instanceId;return await n.db.delete(d._id),await n.db.patch(i._id,{instanceId:c,status:"running",updatedAt:a,...t.error===void 0?{}:{error:t.error},...t.usage===void 0?{}:{usage:t.usage}}),{dequeued:c}}),I=b.input({key:e.string(),state:e.any()}).mutation(async({args:t,ctx:n})=>{const a=await n.db.query(p).withIndex("byKey",i=>i.eq("key",t.key)).first();a&&await n.db.patch(a._id,{state:t.state,updatedAt:Date.now()})}),m=(t,n)=>{if(!t)return;const{owner:a}=t;if(!(a!==void 0&&a!==(n.userId??void 0)))return t},h=T.input({key:e.string()}).query(async({args:t,ctx:n})=>{const a=await n.db.query(p).withIndex("byKey",i=>i.eq("key",t.key)).first();return m(a,n.auth)}),O=T.input({key:e.string()}).query(async({args:t,ctx:n})=>{const a=await n.db.query(p).withIndex("byKey",i=>i.eq("key",t.key)).first();return m(a,n.auth)?.state}),L=T.input({key:e.string(),limit:e.optional(e.number())}).query(async({args:t,ctx:n})=>{const a=await n.db.query(p).withIndex("byKey",i=>i.eq("key",t.key)).first();return m(a,n.auth)===void 0?[]:t.limit!==void 0?(await n.db.query(K).withIndex("byThread",r=>r.eq("threadKey",t.key)).order("desc").take(t.limit)).toReversed():n.db.query(K).withIndex("byThread",i=>i.eq("threadKey",t.key)).collect()}),U=b.input({decision:e.union(e.literal("approve"),e.literal("reject")),instanceId:e.string(),note:e.optional(e.string()),threadKey:e.string(),toolCallId:e.string()}).mutation(async({args:t,ctx:n})=>{const a=await n.db.query(p).withIndex("byKey",l=>l.eq("key",t.threadKey)).first(),i=m(a,n.auth);if(i===void 0)throw new g("FORBIDDEN",`@lunora/agent: not allowed to resolve approvals on thread "${t.threadKey}"`);if(i.instanceId!==t.instanceId)throw new g("FORBIDDEN",`@lunora/agent: instance "${t.instanceId}" does not own thread "${t.threadKey}"`);const r=i.agent,{agents:d}=n,c=d?.[r];if(typeof c?.sendEvent!="function")throw new g("INTERNAL",`@lunora/agent: no ctx.agents["${r}"] producer to resolve the approval — run codegen/dev so the agent binding is wired`);return await c.sendEvent(t.instanceId,{payload:{decision:t.decision,toolCallId:t.toolCallId,...t.note===void 0?{}:{note:t.note}},type:`agent-approval:${t.toolCallId}`}),{resolved:!0}}),B=b.input({agent:e.string(),input:e.string(),threadKey:e.string(),title:e.optional(e.string())}).mutation(async({args:t,ctx:n})=>{const{agents:a}=n,i=a?.[t.agent];if(typeof i?.run!="function")throw new g("INTERNAL",`@lunora/agent: no ctx.agents["${t.agent}"] producer to start a run — run codegen/dev so the agent binding is wired, and check the agent name`);if(i.publicRun!==!0)throw new g("FORBIDDEN",`@lunora/agent: agent "${t.agent}" is not enabled for public runs — set defineAgent({ publicRun: true }) to allow an external client (e.g. the @lunora/mcp server) to start it`);const r=n.auth.userId??void 0,d=await n.db.query(p).withIndex("byKey",l=>l.eq("key",t.threadKey)).first();if(d){const l=d.status,q=d.instanceId,_=d.owner;if((l==="running"||l==="awaiting_input")&&q!==void 0&&(_===void 0||_===r))return{id:q,threadKey:t.threadKey};if(_!==r&&r!==void 0)throw new g("FORBIDDEN",`@lunora/agent: thread "${t.threadKey}" belongs to another owner`)}const{id:c}=await i.run({input:t.input,threadKey:t.threadKey,...r===void 0?{}:{owner:r},...t.title===void 0?{}:{title:t.title}});return{id:c,threadKey:t.threadKey}}),C=H(),R=ee();return{extension:ne,functions:{agentAppendMessage:f(o),agentCompleteRun:f(w),agentEnsureThread:f(u),agentEpisodeRecall:R.agentEpisodeRecall,agentEpisodeUpsert:R.agentEpisodeUpsert,agentGraphTraverse:C.agentGraphTraverse,agentGraphUpsert:C.agentGraphUpsert,agentMessages:L,agentDeleteMessage:f(s),agentPatchThread:f(y),agentResolveApproval:U,agentRun:B,agentSetState:f(I),agentState:O,agentThread:h}}};export{le as agentComponent,ne as agentExtension,pe as normalizeEntityName,we as sandboxComponent};
@@ -1,4 +1,4 @@
1
- import { A as AgentDefinition } from "./packem_shared/types.d-boAM2Yi1.mjs";
1
+ import { A as AgentDefinition } from "./packem_shared/types.d-eCuvcLzf.mjs";
2
2
  import '@lunora/mail/inbound';
3
3
  import 'ai';
4
4
  /**
package/dist/inbound.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AgentDefinition } from "./packem_shared/types.d-boAM2Yi1.js";
1
+ import { A as AgentDefinition } from "./packem_shared/types.d-eCuvcLzf.js";
2
2
  import '@lunora/mail/inbound';
3
3
  import 'ai';
4
4
  /**
package/dist/inbound.mjs CHANGED
@@ -1,32 +1 @@
1
- import { LunoraError } from '@lunora/errors';
2
- import { createInboundEmailHandler, parseInboundEmail } from '@lunora/mail/inbound';
3
-
4
- const dispatchAgentEmail = (targets) => {
5
- const handler = createInboundEmailHandler({
6
- dispatch: async (email, context) => {
7
- for (const target of targets) {
8
- const mapper = target.agent.onEmail;
9
- if (!mapper) {
10
- continue;
11
- }
12
- const run = await mapper(email);
13
- if (run === null || run === void 0) {
14
- continue;
15
- }
16
- const binding = context.env[target.binding];
17
- if (!binding || typeof binding.create !== "function") {
18
- throw new LunoraError(
19
- "INTERNAL",
20
- `@lunora/agent: no Workflow binding "${target.binding}" on env for an inbound agent — run codegen/dev so wrangler.jsonc declares it`
21
- );
22
- }
23
- await binding.create({ params: run });
24
- return;
25
- }
26
- },
27
- parse: parseInboundEmail
28
- });
29
- return async (message, env, context) => handler(message, env, context);
30
- };
31
-
32
- export { dispatchAgentEmail };
1
+ import{LunoraError as i}from"@lunora/errors";import{createInboundEmailHandler as d,parseInboundEmail as u}from"@lunora/mail/inbound";import{h as f,B as l}from"./packem_shared/branch-marker-boZ00zmk.mjs";const E=c=>{const s=d({dispatch:async(a,o)=>{for(const n of c){const t=n.agent.onEmail;if(!t)continue;const r=await t(a);if(r==null)continue;const e=o.env[n.binding];if(!e||typeof e.create!="function")throw new i("INTERNAL",`@lunora/agent: no Workflow binding "${n.binding}" on env for an inbound agent — run codegen/dev so wrangler.jsonc declares it`);if(f(r))throw new i("BAD_REQUEST",`@lunora/agent: inbound run params ${l}`);await e.create({params:r});return}},parse:u});return async(a,o,n)=>s(a,o,n)};export{E as dispatchAgentEmail};
package/dist/index.d.mts 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-boAM2Yi1.mjs";
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.mjs";
1
+ import { A as AgentDefinition, e as AgentCompact, f as AgentEpisodeExtract, g as AgentGraphExtract, h as AgentGenerate, i as AgentTokenSink, j as AgentRunInput, k as AgentFunctionPaths, l as AgentRunFunction, m as AgentStepLike, n as AgentStreamGenerate, o as AgentRunResult, p as AgentMessageRow, q as AgentConfig, d as SkillDefinition, r as AnyAgentTool, s as AgentAsToolOptions, t as AgentSubToolInput, c as AgentToolDefinition, u as AgentBindingSpec, v as AgentHandle, w as AgentToolConfig, x as AgentFunctionReference, y as AgentModelInput, z as SkillConfig } from "./packem_shared/types.d-eCuvcLzf.mjs";
2
+ export type { B as AgentApprovalContext, C as AgentEmailMapper, D as AgentEmailRun, E as AgentGenerateOptions, F as AgentGenerateResult, G as AgentInstructionsContext, H as AgentLiveEvent, J as AgentMemoryOptions, K as AgentMemorySource, L as AgentMessageStatus, M as AgentOnReply, N as AgentOnStepFinish, O as AgentPrepareStep, P as AgentPrepareStepInput, Q as AgentPrepareStepResult, R as AgentProgressEvent, T as AgentReplyInfo, a as AgentReplyRef, U as AgentRunHandle, V as AgentStepFinishInfo, W as AgentStepInfo, X as AgentThreadStatus, Y as AgentTokenDelta, Z as AgentToolCall, b as AgentToolContext, _ as AgentUsage, $ as AgentVoiceConfig, a0 as AgentWorkflowBindingLike, a1 as AgentWorkflowInstanceLike, a2 as EnsureThreadOutcome } from "./packem_shared/types.d-eCuvcLzf.mjs";
3
3
  export { type AgentComponent, agentComponent, agentExtension } from "./component.mjs";
4
4
  import { FlexibleSchema, LanguageModel, ModelMessage } from 'ai';
5
5
  export { agentBindingName, agentClassName, agentDefaultName, voiceBindingName, voiceClassName } from "./naming.mjs";
@@ -183,7 +183,7 @@ declare const agentAsTool: (options: AgentAsToolOptions) => AgentToolDefinition<
183
183
  interface ToolScriptStep {
184
184
  /** A stable name later steps reference the output by. */
185
185
  id: string;
186
- /** The tool's input; values may embed `{ "$from": "&lt;stepId>", "$path": "a.b" }` refs. */
186
+ /** The tool's input; values may embed `{ "$from": "<stepId>", "$path": "a.b" }` refs. */
187
187
  input?: Record<string, unknown>;
188
188
  /** The tool to call — one of the tools handed to {@link codeTool}. */
189
189
  tool: string;
@@ -239,6 +239,16 @@ interface CodeToolOptions {
239
239
  * keep approval-gated tools as normal top-level tools. Gate the whole script via
240
240
  * `opts.needsApproval` instead.
241
241
  *
242
+ * STEP-OUTPUT CONTRACT — **every step's output must be JSON-serializable.** Each
243
+ * step runs inside its own durable `step.do`, so the workflow host serializes
244
+ * the returned value before the next step (or the tool result) ever sees it. A
245
+ * `Date` comes back as an ISO string, a `Map`/`Set` as `{}`, `undefined` as
246
+ * `null` or a dropped key, and a `bigint` throws outright. That applies to the
247
+ * value a later step reads through `{ "$from": … }` just as much as to the
248
+ * returned `results` — the hand-off is durable state, not an in-memory one. A
249
+ * composed tool that wants to pass a rich value should return its JSON form
250
+ * (`date.toISOString()`, `[...map]`) and let the consuming step rebuild it.
251
+ *
242
252
  * ```ts
243
253
  * import { codeTool, defineAgent, functionTool } from "@lunora/agent";
244
254
  *
@@ -344,8 +354,14 @@ interface FunctionToolOptions<Input> {
344
354
  * ```
345
355
  *
346
356
  * 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.
357
+ * path. The model-provided input is passed as the function's args, so
358
+ * `inputSchema` should mirror the referenced function's argument validator
359
+ * PLUS the call's `idempotencyKey`, pinned onto the args after the model
360
+ * input (so out-of-schema model input can never override it). A function
361
+ * that wants to dedupe a side-effecting call across an at-least-once step
362
+ * retry declares `idempotencyKey: v.optional(v.string())` in its own args
363
+ * and checks it; a function that ignores it is unaffected — an args field
364
+ * the function's own validator doesn't declare is dropped, not rejected.
349
365
  * @experimental
350
366
  */
351
367
  declare const functionTool: <Input extends Record<string, unknown> = Record<string, unknown>, Output = unknown>(reference: AgentFunctionReference | string, options: FunctionToolOptions<Input>) => AgentToolDefinition<Input, Output>;
@@ -471,6 +487,17 @@ interface McpToolsOptions {
471
487
  command?: string;
472
488
  /** Identify this client to the server on connect. Default `"lunora-agent"`. */
473
489
  name?: string;
490
+ /**
491
+ * Gate an adapted tool's call behind a human approval. Defaults to
492
+ * **unattended** (no gate) — matching today's behavior. An MCP tool's
493
+ * result feeds back into the model's context (`adaptMcpResult`), so a
494
+ * hostile downstream server can pair indirect prompt injection with an
495
+ * unattended mutating tool call; pass a boolean to gate every adapted
496
+ * tool the same way, or a predicate `(toolName, input) => boolean` to
497
+ * gate per tool (evaluated from replay-stable input, so keep it
498
+ * deterministic).
499
+ */
500
+ needsApproval?: ((toolName: string, input: Record<string, unknown>) => boolean) | boolean;
474
501
  /** Only adapt these tool names (default: every tool the server lists). */
475
502
  only?: ReadonlyArray<string>;
476
503
  /** Prefix added to each adapted tool's key (disambiguate multiple servers). */
@@ -510,6 +537,9 @@ declare const adaptMcpResult: (result: McpCallResult) => unknown;
510
537
  * every call. In the Workers runtime only the HTTP/SSE transports run (stdio
511
538
  * does not) — pass `url`, or inject an already-connected `client` for a custom
512
539
  * transport (also the test seam).
540
+ *
541
+ * Every adapted tool runs UNATTENDED by default (no approval gate) — pass
542
+ * `opts.needsApproval` to change that; see {@link McpToolsOptions.needsApproval}.
513
543
  * @experimental
514
544
  */
515
545
  declare const mcpTools: (options: McpToolsOptions) => Promise<Record<string, AgentToolDefinition<Record<string, unknown>>>>;
@@ -808,15 +838,15 @@ declare class VoiceSessionDO {
808
838
  }
809
839
  /**
810
840
  * Compile a `defineAgent` definition into the workflow the generated
811
- * `&lt;Name>AgentWorkflow` entrypoint class runs. Codegen emits, per agent:
841
+ * `<Name>AgentWorkflow` entrypoint class runs. Codegen emits, per agent:
812
842
  *
813
843
  * ```ts
814
844
  * import LunoraWorkflow from "@lunora/workflow/do";
815
845
  * import { compileAgentWorkflow } from "@lunora/agent";
816
846
  * import { support } from "../agents.js";
817
847
  *
818
- * export class SupportAgentWorkflow extends LunoraWorkflow&lt;AgentRunInput, AgentRunResult> {
819
- * public constructor(ctx: ConstructorParameters&lt;typeof LunoraWorkflow>[0], env: Record&lt;string, unknown>) {
848
+ * export class SupportAgentWorkflow extends LunoraWorkflow<AgentRunInput, AgentRunResult> {
849
+ * public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
820
850
  * super(ctx, env, compileAgentWorkflow(support, "support"), "support");
821
851
  * }
822
852
  * }