@lunora/agent 0.0.0 → 1.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/LICENSE.md +105 -0
  2. package/README.md +48 -43
  3. package/dist/channels.d.mts +54 -0
  4. package/dist/channels.d.ts +54 -0
  5. package/dist/channels.mjs +181 -0
  6. package/dist/component.d.mts +101 -0
  7. package/dist/component.d.ts +101 -0
  8. package/dist/component.mjs +407 -0
  9. package/dist/inbound.d.mts +29 -0
  10. package/dist/inbound.d.ts +29 -0
  11. package/dist/inbound.mjs +32 -0
  12. package/dist/index.d.mts +740 -0
  13. package/dist/index.d.ts +740 -0
  14. package/dist/index.mjs +18 -0
  15. package/dist/naming.d.mts +17 -0
  16. package/dist/naming.d.ts +17 -0
  17. package/dist/naming.mjs +8 -0
  18. package/dist/packem_shared/AGENT_MODULE-Dnt_-AAT.mjs +24 -0
  19. package/dist/packem_shared/VoiceSessionDO-DLoXsHGF.mjs +297 -0
  20. package/dist/packem_shared/adaptMcpResult-wtNMvLoP.mjs +65 -0
  21. package/dist/packem_shared/agentAsTool-Dt8NlU6k.mjs +94 -0
  22. package/dist/packem_shared/base64-BVwtgRJV.mjs +18 -0
  23. package/dist/packem_shared/braintrustTelemetry-wuGDErob.mjs +47 -0
  24. package/dist/packem_shared/buildModelMessages-BWFigaoo.mjs +69 -0
  25. package/dist/packem_shared/codeTool-CjgJOC9t.mjs +122 -0
  26. package/dist/packem_shared/collectAgenticMemoryTools-QrzpV-WX.mjs +97 -0
  27. package/dist/packem_shared/combineTelemetry-DCyaaWAI.mjs +43 -0
  28. package/dist/packem_shared/common-DAeFCot5.mjs +61 -0
  29. package/dist/packem_shared/compileAgentWorkflow-BxJjHgtD.mjs +55 -0
  30. package/dist/packem_shared/consoleTelemetry-z2MiP1jt.mjs +93 -0
  31. package/dist/packem_shared/createAgentContext-4xJGXNR4.mjs +50 -0
  32. package/dist/packem_shared/createAgentGenerate-BQv9YJ01.mjs +192 -0
  33. package/dist/packem_shared/createDispatchRunner-DSbp_dph-ZHTtxy3f.mjs +69 -0
  34. package/dist/packem_shared/defineAgent-D6maSbVc.mjs +148 -0
  35. package/dist/packem_shared/defineSkill-Ctf_S-rz.mjs +22 -0
  36. package/dist/packem_shared/functionTool-D6lCa2jB.mjs +20 -0
  37. package/dist/packem_shared/graph-component-aoUwO-f0.mjs +216 -0
  38. package/dist/packem_shared/memory-D4FPcBsX.mjs +12 -0
  39. package/dist/packem_shared/normalizeEntityName-CyEEWFkR.mjs +3 -0
  40. package/dist/packem_shared/runAgentLoop-Dhg4ZNvw.mjs +493 -0
  41. package/dist/packem_shared/runVoiceTurn-LnqLvCRR.mjs +211 -0
  42. package/dist/packem_shared/sandboxComponent-DR3pTwBL.mjs +194 -0
  43. package/dist/packem_shared/sentryTelemetry-CgqFJyLO.mjs +36 -0
  44. package/dist/packem_shared/types.d-BWG0uUtX.d.mts +1015 -0
  45. package/dist/packem_shared/types.d-BWG0uUtX.d.ts +1015 -0
  46. package/dist/sandbox.d.mts +185 -0
  47. package/dist/sandbox.d.ts +185 -0
  48. package/dist/sandbox.mjs +109 -0
  49. package/dist/telemetry/index.d.mts +150 -0
  50. package/dist/telemetry/index.d.ts +150 -0
  51. package/dist/telemetry/index.mjs +4 -0
  52. package/package.json +88 -7
@@ -0,0 +1,3 @@
1
+ import '@lunora/server';
2
+ import '@lunora/values';
3
+ export { b as graphComponent, g as graphTables, n as normalizeEntityName } from './graph-component-aoUwO-f0.mjs';
@@ -0,0 +1,493 @@
1
+ import { resolveAgentModel } from './createAgentGenerate-BQv9YJ01.mjs';
2
+ import { f as firstGraphSource, m as memoryStepName, a as firstEpisodicSource, r as resolveInjectedSources } from './memory-D4FPcBsX.mjs';
3
+ import { buildModelMessages } from './buildModelMessages-BWFigaoo.mjs';
4
+ import { agentBindingName } from '../naming.mjs';
5
+ import { toFunctionReference } from './AGENT_MODULE-Dnt_-AAT.mjs';
6
+
7
+ const DEFAULT_MAX_TURNS = 8;
8
+ const stringifyOutput = (output) => output === void 0 ? "null" : JSON.stringify(output);
9
+ const normalizeStopWhen = (stopWhen) => {
10
+ if (stopWhen === void 0) {
11
+ return [];
12
+ }
13
+ if (Array.isArray(stopWhen)) {
14
+ return stopWhen;
15
+ }
16
+ return [stopWhen];
17
+ };
18
+ const isStopConditionMet = async (conditions, steps) => {
19
+ const results = await Promise.all(conditions.map(async (condition) => condition({ steps })));
20
+ return results.some(Boolean);
21
+ };
22
+ const sumTokens = (a, b) => a === void 0 && b === void 0 ? void 0 : (a ?? 0) + (b ?? 0);
23
+ const addUsage = (base, next) => {
24
+ if (next === void 0) {
25
+ return base;
26
+ }
27
+ if (base === void 0) {
28
+ return { ...next };
29
+ }
30
+ const result = {};
31
+ const inputTokens = sumTokens(base.inputTokens, next.inputTokens);
32
+ const outputTokens = sumTokens(base.outputTokens, next.outputTokens);
33
+ const totalTokens = sumTokens(base.totalTokens, next.totalTokens);
34
+ if (inputTokens !== void 0) {
35
+ result.inputTokens = inputTokens;
36
+ }
37
+ if (outputTokens !== void 0) {
38
+ result.outputTokens = outputTokens;
39
+ }
40
+ if (totalTokens !== void 0) {
41
+ result.totalTokens = totalTokens;
42
+ }
43
+ return result;
44
+ };
45
+ const resolveNeedsApproval = async (tool, input, context) => {
46
+ const { needsApproval } = tool;
47
+ if (needsApproval === void 0 || needsApproval === false) {
48
+ return false;
49
+ }
50
+ if (needsApproval === true) {
51
+ return true;
52
+ }
53
+ return needsApproval(input, context);
54
+ };
55
+ const awaitApproval = async (turnContext, call) => {
56
+ const { instanceId, patchThread, persist, step } = turnContext;
57
+ await persist({
58
+ content: `Awaiting approval to run tool "${call.name}".`,
59
+ messageKey: `${instanceId}:approval:${call.id}`,
60
+ role: "tool",
61
+ status: "awaiting_approval",
62
+ toolCallId: call.id,
63
+ toolName: call.name
64
+ });
65
+ await patchThread({ status: "awaiting_input" });
66
+ const event = await step.waitForEvent(`approval:${call.id}`, { type: "agent-approval" });
67
+ await patchThread({ status: "running" });
68
+ return { decision: event.payload.decision, ...event.payload.note === void 0 ? {} : { note: event.payload.note } };
69
+ };
70
+ const runToolCall = async (turnContext, call) => {
71
+ const { env, getState, instanceId, onTokenDelta, persist, run, setState, step, threadKey, tools } = turnContext;
72
+ const stepName = `tool:${call.name}:${call.id}`;
73
+ const tool = tools[call.name];
74
+ const messageKey = `${instanceId}:tool:${call.id}`;
75
+ if (!tool) {
76
+ await persist({ content: `Error: unknown tool "${call.name}"`, messageKey, role: "tool", stepName, toolCallId: call.id, toolName: call.name });
77
+ return;
78
+ }
79
+ const reportProgress = (data) => {
80
+ onTokenDelta?.({ data, kind: "progress", threadKey, toolCallId: call.id });
81
+ };
82
+ const toolContext = { env, getState, idempotencyKey: stepName, reportProgress, run, setState, threadKey, toolCallId: call.id };
83
+ let status;
84
+ if (await resolveNeedsApproval(tool, call.input, toolContext)) {
85
+ const { decision, note } = await awaitApproval(turnContext, call);
86
+ if (decision === "reject") {
87
+ const reason = note === void 0 ? "" : ` Reason: ${note}`;
88
+ await persist({
89
+ content: `Tool "${call.name}" was rejected by the user and not run.${reason}`,
90
+ messageKey,
91
+ role: "tool",
92
+ status: "rejected",
93
+ stepName,
94
+ toolCallId: call.id,
95
+ toolName: call.name
96
+ });
97
+ return;
98
+ }
99
+ status = "approved";
100
+ }
101
+ const output = await step.do(stepName, () => Promise.resolve(tool.execute(call.input, toolContext)));
102
+ await persist({
103
+ content: typeof output === "string" ? output : stringifyOutput(output),
104
+ messageKey,
105
+ role: "tool",
106
+ stepName,
107
+ ...status === void 0 ? {} : { status },
108
+ toolCallId: call.id,
109
+ toolName: call.name
110
+ });
111
+ };
112
+ const applyPrepareStepResult = (base, overrides, env) => {
113
+ if (!overrides) {
114
+ return base;
115
+ }
116
+ let { messages } = base;
117
+ if (overrides.messages !== void 0) {
118
+ messages = overrides.messages;
119
+ }
120
+ if (overrides.system !== void 0) {
121
+ messages = [{ content: overrides.system, role: "system" }, ...messages];
122
+ }
123
+ return {
124
+ activeTools: overrides.activeTools ?? base.activeTools,
125
+ messages,
126
+ model: overrides.model === void 0 ? base.model : resolveAgentModel(overrides.model, env),
127
+ toolChoice: overrides.toolChoice ?? base.toolChoice
128
+ };
129
+ };
130
+ const splitForCompaction = (history, compaction) => {
131
+ if (compaction === void 0 || history.length <= compaction.maxMessages) {
132
+ return void 0;
133
+ }
134
+ const keepRecent = Math.max(1, compaction.keepRecent ?? Math.ceil(compaction.maxMessages / 2));
135
+ if (history.length <= keepRecent) {
136
+ return void 0;
137
+ }
138
+ let cut = history.length - keepRecent;
139
+ while (cut > 0 && history[cut]?.role === "tool") {
140
+ cut -= 1;
141
+ }
142
+ if (cut <= 0) {
143
+ return void 0;
144
+ }
145
+ return { older: history.slice(0, cut), recent: history.slice(cut) };
146
+ };
147
+ const compactHistory = async (turnContext, history) => {
148
+ const { agent, compact, env } = turnContext;
149
+ const split = splitForCompaction(history, agent.compaction);
150
+ if (split === void 0 || compact === void 0) {
151
+ return { history, summary: void 0 };
152
+ }
153
+ try {
154
+ const summary = await compact({ env, messages: buildModelMessages({ history: split.older }), model: agent.compaction?.model ?? agent.model });
155
+ return summary.length > 0 ? { history: split.recent, summary } : { history, summary: void 0 };
156
+ } catch {
157
+ return { history, summary: void 0 };
158
+ }
159
+ };
160
+ const generateTurn = async (turnContext, turn, steps) => {
161
+ const { agent, env, generate, instructions, listMessages, memoryContext, onTokenDelta, run, step, streamGenerate, threadKey } = turnContext;
162
+ return step.do(`llm:turn:${String(turn)}`, async () => {
163
+ const rawHistory = await run(listMessages, { key: threadKey });
164
+ const { history, summary } = await compactHistory(turnContext, rawHistory);
165
+ let prepared = {
166
+ activeTools: agent.activeTools,
167
+ messages: buildModelMessages({ history, instructions, memoryContext, summary }),
168
+ model: void 0,
169
+ toolChoice: agent.toolChoice
170
+ };
171
+ if (agent.prepareStep) {
172
+ prepared = applyPrepareStepResult(prepared, await agent.prepareStep({ messages: prepared.messages, stepNumber: turn, steps }), env);
173
+ }
174
+ const request = {
175
+ messages: prepared.messages,
176
+ ...prepared.activeTools === void 0 ? {} : { activeTools: prepared.activeTools },
177
+ ...prepared.model === void 0 ? {} : { model: prepared.model },
178
+ ...prepared.toolChoice === void 0 ? {} : { toolChoice: prepared.toolChoice }
179
+ };
180
+ if (streamGenerate && onTokenDelta) {
181
+ return streamGenerate(request, (text) => {
182
+ onTokenDelta({ text, threadKey, turn });
183
+ });
184
+ }
185
+ return generate(request);
186
+ });
187
+ };
188
+ const notifyStepFinish = async (turnContext, info) => {
189
+ const { agent, step } = turnContext;
190
+ if (!agent.onStepFinish) {
191
+ return;
192
+ }
193
+ await step.do(`agent:step-finish:${String(info.turn)}`, async () => {
194
+ await agent.onStepFinish?.(info);
195
+ return true;
196
+ });
197
+ };
198
+ const toStepInfo = (decision) => {
199
+ return {
200
+ text: decision.text,
201
+ toolCalls: decision.toolCalls.map((call) => {
202
+ return { input: call.input, toolCallId: call.id, toolName: call.name };
203
+ }),
204
+ ...decision.usage === void 0 ? {} : { usage: decision.usage }
205
+ };
206
+ };
207
+ const readRetrievedContext = (retrieved) => {
208
+ const context = retrieved?.context;
209
+ return typeof context === "string" && context.length > 0 ? context : void 0;
210
+ };
211
+ const graphTraverseBounds = (graph) => {
212
+ const bounds = {};
213
+ if (graph?.depth !== void 0) {
214
+ bounds.depth = graph.depth;
215
+ }
216
+ if (graph?.fanOut !== void 0) {
217
+ bounds.fanOut = graph.fanOut;
218
+ }
219
+ if (graph?.maxNodes !== void 0) {
220
+ bounds.maxNodes = graph.maxNodes;
221
+ }
222
+ if (graph?.maxSeeds !== void 0) {
223
+ bounds.maxSeeds = graph.maxSeeds;
224
+ }
225
+ return bounds;
226
+ };
227
+ const dispatchSemanticMemory = async (source, input, step, run) => {
228
+ if (source.source === void 0) {
229
+ return void 0;
230
+ }
231
+ const memorySource = toFunctionReference(source.source);
232
+ const { topK } = source;
233
+ const stepName = memoryStepName("memory:retrieve", source.key);
234
+ const retrieved = await step.do(stepName, async () => run(memorySource, { query: input, ...topK === void 0 ? {} : { topK } }));
235
+ return readRetrievedContext(retrieved);
236
+ };
237
+ const dispatchGraphMemory = async (source, input, owner, graphTraverse, step, run) => {
238
+ if (owner === void 0) {
239
+ return void 0;
240
+ }
241
+ const stepName = memoryStepName("memory:traverse", source.key);
242
+ const retrieved = await step.do(stepName, async () => run(graphTraverse, { owner, query: input, ...graphTraverseBounds(source.graph) }));
243
+ return readRetrievedContext(retrieved);
244
+ };
245
+ const dispatchEpisodicMemory = async (source, owner, episodeRecall, step, run) => {
246
+ if (owner === void 0) {
247
+ return void 0;
248
+ }
249
+ const stepName = memoryStepName("memory:recall", source.key);
250
+ const recallArgs = { owner, ...source.episodic?.recall === void 0 ? {} : { limit: source.episodic.recall } };
251
+ const retrieved = await step.do(stepName, async () => run(episodeRecall, recallArgs));
252
+ return readRetrievedContext(retrieved);
253
+ };
254
+ const dispatchInjectedSource = async (source, deps) => {
255
+ if (source.kind === "episodic") {
256
+ return dispatchEpisodicMemory(source, deps.owner, deps.episodeRecall, deps.step, deps.run);
257
+ }
258
+ if (source.kind === "graph") {
259
+ return dispatchGraphMemory(source, deps.input, deps.owner, deps.graphTraverse, deps.step, deps.run);
260
+ }
261
+ return dispatchSemanticMemory(source, deps.input, deps.step, deps.run);
262
+ };
263
+ const dedupeEpisodicSources = (sources) => {
264
+ let seenEpisodic = false;
265
+ return sources.filter((source) => {
266
+ if (source.kind !== "episodic") {
267
+ return true;
268
+ }
269
+ if (seenEpisodic) {
270
+ return false;
271
+ }
272
+ seenEpisodic = true;
273
+ return true;
274
+ });
275
+ };
276
+ const retrieveMemoryContext = async (agent, input, owner, paths, step, run) => {
277
+ const sources = dedupeEpisodicSources(resolveInjectedSources(agent));
278
+ if (sources.length === 0) {
279
+ return void 0;
280
+ }
281
+ const graphTraverse = toFunctionReference(paths.graphTraverse);
282
+ const episodeRecall = toFunctionReference(paths.episodeRecall);
283
+ const contexts = [];
284
+ for (const source of sources) {
285
+ const context = await dispatchInjectedSource(source, { episodeRecall, graphTraverse, input, owner, run, step });
286
+ if (context !== void 0) {
287
+ contexts.push(context);
288
+ }
289
+ }
290
+ return contexts.length > 0 ? contexts.join("\n\n") : void 0;
291
+ };
292
+ const extractGraphMemoryAtRunEnd = async (options) => {
293
+ const { agent, env, extractGraph, finalText, input, instanceId, owner, paths, run, step } = options;
294
+ if (extractGraph === void 0 || owner === void 0 || finalText === void 0 || finalText.length === 0) {
295
+ return;
296
+ }
297
+ const source = firstGraphSource(agent);
298
+ if (source === void 0) {
299
+ return;
300
+ }
301
+ try {
302
+ const graphInput = { assistantText: finalText, env, model: source.graph?.extractionModel ?? agent.model, userInput: input };
303
+ const extracted = await step.do(memoryStepName("memory:extract", source.key), async () => extractGraph(graphInput));
304
+ await run(toFunctionReference(paths.graphUpsert), { ...extracted, messageKey: `${instanceId}:${memoryStepName("extract", source.key)}`, owner });
305
+ } catch {
306
+ }
307
+ };
308
+ const extractEpisodeAtRunEnd = async (options) => {
309
+ const { agent, env, extractEpisode, finalText, input, instanceId, owner, paths, run, step, threadKey } = options;
310
+ if (extractEpisode === void 0 || owner === void 0 || finalText === void 0 || finalText.length === 0) {
311
+ return;
312
+ }
313
+ const source = firstEpisodicSource(agent);
314
+ if (source === void 0) {
315
+ return;
316
+ }
317
+ try {
318
+ const episodeInput = { assistantText: finalText, env, model: source.episodic?.extractionModel ?? agent.model, userInput: input };
319
+ const { summary } = await step.do(memoryStepName("memory:episode", source.key), async () => extractEpisode(episodeInput));
320
+ await run(toFunctionReference(paths.episodeUpsert), {
321
+ messageKey: `${instanceId}:${memoryStepName("episode", source.key)}`,
322
+ owner,
323
+ summary,
324
+ threadKey
325
+ });
326
+ } catch {
327
+ }
328
+ };
329
+ const terminatePriorInstance = async (env, exportName, priorInstanceId) => {
330
+ const binding = env[agentBindingName(exportName)];
331
+ if (!binding || typeof binding.get !== "function") {
332
+ return;
333
+ }
334
+ try {
335
+ const instance = await binding.get(priorInstanceId);
336
+ await instance.terminate();
337
+ } catch {
338
+ }
339
+ };
340
+ const handleTurn = async (turnContext, turn, decision, steps, stopConditions) => {
341
+ const { instanceId, persist } = turnContext;
342
+ const stepUsage = decision.usage === void 0 ? {} : { usage: decision.usage };
343
+ if (decision.toolCalls.length === 0) {
344
+ const content = decision.output !== void 0 && decision.text.length === 0 ? stringifyOutput(decision.output) : decision.text;
345
+ await persist({ content, messageKey: `${instanceId}:assistant:${String(turn)}`, role: "assistant" });
346
+ await notifyStepFinish(turnContext, { text: decision.text, toolCalls: [], turn, ...stepUsage });
347
+ return {
348
+ final: {
349
+ stopped: "final",
350
+ text: decision.text,
351
+ turns: turn + 1,
352
+ ...decision.output === void 0 ? {} : { output: decision.output }
353
+ }
354
+ };
355
+ }
356
+ await persist({ content: decision.text, messageKey: `${instanceId}:assistant:${String(turn)}`, role: "assistant", toolCalls: decision.toolCalls });
357
+ for (const call of decision.toolCalls) {
358
+ await runToolCall(turnContext, call);
359
+ }
360
+ await notifyStepFinish(turnContext, { text: decision.text, toolCalls: decision.toolCalls, turn, ...stepUsage });
361
+ steps.push(toStepInfo(decision));
362
+ if (stopConditions.length > 0 && await isStopConditionMet(stopConditions, steps)) {
363
+ return "stopCondition";
364
+ }
365
+ return void 0;
366
+ };
367
+ const runTurns = async (turnContext, maxTurns, stopConditions, usageBox) => {
368
+ const steps = [];
369
+ let final;
370
+ let stoppedByCondition = false;
371
+ let turnsRun = 0;
372
+ for (let turn = 0; turn < maxTurns; turn += 1) {
373
+ const decision = await generateTurn(turnContext, turn, steps);
374
+ usageBox.value = addUsage(usageBox.value, decision.usage);
375
+ turnsRun = turn + 1;
376
+ const outcome = await handleTurn(turnContext, turn, decision, steps, stopConditions);
377
+ if (outcome === "stopCondition") {
378
+ stoppedByCondition = true;
379
+ break;
380
+ }
381
+ if (outcome !== void 0) {
382
+ final = outcome.final;
383
+ break;
384
+ }
385
+ }
386
+ return { final, stoppedByCondition, turnsRun };
387
+ };
388
+ const runAgentLoop = async (options) => {
389
+ const { agent, compact, env, exportName, extractEpisode, extractGraph, generate, instanceId, onTokenDelta, params, paths, run, step, streamGenerate } = options;
390
+ const maxTurns = agent.maxTurns ?? DEFAULT_MAX_TURNS;
391
+ const stopConditions = normalizeStopWhen(agent.stopWhen);
392
+ const appendMessage = toFunctionReference(paths.appendMessage);
393
+ const ensureThread = toFunctionReference(paths.ensureThread);
394
+ const listMessages = toFunctionReference(paths.listMessages);
395
+ const patchThread = toFunctionReference(paths.patchThread);
396
+ const setStateRef = toFunctionReference(paths.setState);
397
+ const stateRef = toFunctionReference(paths.state);
398
+ const persist = async (message) => {
399
+ await run(appendMessage, { threadKey: params.threadKey, ...message });
400
+ };
401
+ const patchThreadByKey = async (patch) => {
402
+ await run(patchThread, { key: params.threadKey, ...patch });
403
+ };
404
+ const getState = async () => await run(stateRef, { key: params.threadKey });
405
+ const setState = async (state) => {
406
+ await run(setStateRef, { key: params.threadKey, state });
407
+ };
408
+ const bootstrap = await run(ensureThread, {
409
+ agent: exportName,
410
+ instanceId,
411
+ key: params.threadKey,
412
+ ...agent.initialState === void 0 ? {} : { initialState: agent.initialState },
413
+ ...agent.onConcurrentRun === void 0 ? {} : { onConcurrentRun: agent.onConcurrentRun },
414
+ ...params.owner === void 0 ? {} : { owner: params.owner },
415
+ ...params.title === void 0 ? {} : { title: params.title }
416
+ });
417
+ if (bootstrap?.replaced && bootstrap.priorInstanceId !== void 0) {
418
+ await terminatePriorInstance(env, exportName, bootstrap.priorInstanceId);
419
+ }
420
+ await persist({ content: params.input, messageKey: `${instanceId}:user`, role: "user" });
421
+ const memoryContext = await retrieveMemoryContext(agent, params.input, params.owner, paths, step, run);
422
+ const instructions = typeof agent.instructions === "function" ? agent.instructions({ env, input: params.input, threadKey: params.threadKey }) : agent.instructions;
423
+ const turnContext = {
424
+ agent,
425
+ compact,
426
+ env,
427
+ generate,
428
+ getState,
429
+ instanceId,
430
+ instructions,
431
+ listMessages,
432
+ memoryContext,
433
+ onTokenDelta,
434
+ patchThread: patchThreadByKey,
435
+ persist,
436
+ run,
437
+ setState,
438
+ step,
439
+ streamGenerate,
440
+ threadKey: params.threadKey,
441
+ tools: agent.tools ?? {}
442
+ };
443
+ const usageBox = { value: void 0 };
444
+ try {
445
+ const { final, stoppedByCondition, turnsRun } = await runTurns(turnContext, maxTurns, stopConditions, usageBox);
446
+ const usagePatch = usageBox.value === void 0 ? {} : { usage: usageBox.value };
447
+ await extractGraphMemoryAtRunEnd({
448
+ agent,
449
+ env,
450
+ extractGraph,
451
+ finalText: final?.text,
452
+ input: params.input,
453
+ instanceId,
454
+ owner: params.owner,
455
+ paths,
456
+ run,
457
+ step
458
+ });
459
+ await extractEpisodeAtRunEnd({
460
+ agent,
461
+ env,
462
+ extractEpisode,
463
+ finalText: final?.text,
464
+ input: params.input,
465
+ instanceId,
466
+ owner: params.owner,
467
+ paths,
468
+ run,
469
+ step,
470
+ threadKey: params.threadKey
471
+ });
472
+ if (final) {
473
+ await run(patchThread, { key: params.threadKey, status: "idle", ...usagePatch });
474
+ return { ...final, ...usagePatch };
475
+ }
476
+ if (stoppedByCondition) {
477
+ await run(patchThread, { key: params.threadKey, status: "idle", ...usagePatch });
478
+ return { stopped: "stopCondition", turns: turnsRun, ...usagePatch };
479
+ }
480
+ await run(patchThread, { error: `agent stopped: maxTurns (${String(maxTurns)}) reached`, key: params.threadKey, status: "error", ...usagePatch });
481
+ return { stopped: "maxTurns", turns: maxTurns, ...usagePatch };
482
+ } catch (error) {
483
+ await run(patchThread, {
484
+ error: error instanceof Error ? error.message : String(error),
485
+ key: params.threadKey,
486
+ status: "error",
487
+ ...usageBox.value === void 0 ? {} : { usage: usageBox.value }
488
+ });
489
+ throw error;
490
+ }
491
+ };
492
+
493
+ export { runAgentLoop, splitForCompaction };
@@ -0,0 +1,211 @@
1
+ import { f as fromBase64 } from './base64-BVwtgRJV.mjs';
2
+ import { buildModelMessages } from './buildModelMessages-BWFigaoo.mjs';
3
+ import { toFunctionReference } from './AGENT_MODULE-Dnt_-AAT.mjs';
4
+
5
+ const PCM_SAMPLE_RATE = 16e3;
6
+ const PCM_CHANNELS = 1;
7
+ const PCM_BITS_PER_SAMPLE = 16;
8
+ const SENTENCE_BOUNDARY = /[^.!?]*[.!?]+\s+/u;
9
+ const toByteIterable = async function* (source) {
10
+ if (source instanceof Uint8Array) {
11
+ yield source;
12
+ return;
13
+ }
14
+ if (source instanceof ReadableStream) {
15
+ const reader = source.getReader();
16
+ try {
17
+ for (; ; ) {
18
+ const { done, value } = await reader.read();
19
+ if (done) {
20
+ break;
21
+ }
22
+ yield value;
23
+ }
24
+ } finally {
25
+ reader.releaseLock();
26
+ }
27
+ return;
28
+ }
29
+ yield* source;
30
+ };
31
+ const pcmToWav = (pcm, sampleRate = PCM_SAMPLE_RATE, channels = PCM_CHANNELS, bitsPerSample = PCM_BITS_PER_SAMPLE) => {
32
+ const blockAlign = channels * bitsPerSample / 8;
33
+ const byteRate = sampleRate * blockAlign;
34
+ const buffer = new ArrayBuffer(44 + pcm.byteLength);
35
+ const view = new DataView(buffer);
36
+ const writeAscii = (offset, text) => {
37
+ for (let index = 0; index < text.length; index += 1) {
38
+ view.setUint8(offset + index, text.codePointAt(index) ?? 0);
39
+ }
40
+ };
41
+ writeAscii(0, "RIFF");
42
+ view.setUint32(4, 36 + pcm.byteLength, true);
43
+ writeAscii(8, "WAVE");
44
+ writeAscii(12, "fmt ");
45
+ view.setUint32(16, 16, true);
46
+ view.setUint16(20, 1, true);
47
+ view.setUint16(22, channels, true);
48
+ view.setUint32(24, sampleRate, true);
49
+ view.setUint32(28, byteRate, true);
50
+ view.setUint16(32, blockAlign, true);
51
+ view.setUint16(34, bitsPerSample, true);
52
+ writeAscii(36, "data");
53
+ view.setUint32(40, pcm.byteLength, true);
54
+ const out = new Uint8Array(buffer);
55
+ out.set(pcm, 44);
56
+ return out;
57
+ };
58
+ const takeSentences = (buffer) => {
59
+ const sentences = [];
60
+ let rest = buffer;
61
+ let match = SENTENCE_BOUNDARY.exec(rest);
62
+ while (match && match[0].length > 0) {
63
+ const consumed = match[0];
64
+ const sentence = consumed.trim();
65
+ if (sentence.length > 0) {
66
+ sentences.push(sentence);
67
+ }
68
+ rest = rest.slice(consumed.length);
69
+ match = SENTENCE_BOUNDARY.exec(rest);
70
+ }
71
+ return { rest, sentences };
72
+ };
73
+ const runVoiceTurn = async (options) => {
74
+ const {
75
+ agent,
76
+ connectionId,
77
+ env,
78
+ exportName,
79
+ owner,
80
+ paths,
81
+ pcm,
82
+ run,
83
+ send,
84
+ sendAudio,
85
+ signal,
86
+ streamGenerate,
87
+ synthesize,
88
+ text,
89
+ threadKey,
90
+ transcribe,
91
+ turn,
92
+ waitForDrain
93
+ } = options;
94
+ const isAborted = () => signal.aborted;
95
+ const appendMessage = toFunctionReference(paths.appendMessage);
96
+ const ensureThread = toFunctionReference(paths.ensureThread);
97
+ const listMessages = toFunctionReference(paths.listMessages);
98
+ const patchThread = toFunctionReference(paths.patchThread);
99
+ const userText = (text ?? (pcm ? await transcribe(pcm) : "")).trim();
100
+ if (userText.length === 0) {
101
+ return { assistantText: "", interrupted: false, userText: "" };
102
+ }
103
+ send({ text: userText, type: "user_transcript" });
104
+ await run(ensureThread, {
105
+ agent: exportName,
106
+ key: threadKey,
107
+ ...agent.initialState === void 0 ? {} : { initialState: agent.initialState },
108
+ ...owner === void 0 ? {} : { owner }
109
+ });
110
+ await run(appendMessage, { content: userText, messageKey: `voice:${connectionId}:${String(turn)}:user`, role: "user", threadKey });
111
+ await run(patchThread, { key: threadKey, status: "running" });
112
+ const instructions = typeof agent.instructions === "function" ? agent.instructions({ env, input: userText, threadKey }) : agent.instructions;
113
+ const history = await run(listMessages, { key: threadKey });
114
+ const messages = buildModelMessages({ history, ...instructions === void 0 ? {} : { instructions } });
115
+ let pending = "";
116
+ let spoken = "";
117
+ let ttsChain = Promise.resolve();
118
+ const speak = async (sentence) => {
119
+ if (isAborted() || sentence.length === 0) {
120
+ return;
121
+ }
122
+ let flushed = false;
123
+ try {
124
+ for await (const chunk of toByteIterable(await synthesize(sentence, signal))) {
125
+ if (isAborted()) {
126
+ break;
127
+ }
128
+ await waitForDrain?.();
129
+ if (isAborted()) {
130
+ break;
131
+ }
132
+ sendAudio(chunk);
133
+ flushed = true;
134
+ }
135
+ } catch (error) {
136
+ send({ message: error instanceof Error ? error.message : String(error), type: "error" });
137
+ }
138
+ if (flushed) {
139
+ spoken = spoken.length > 0 ? `${spoken} ${sentence}` : sentence;
140
+ }
141
+ };
142
+ const enqueueSpeak = (sentence) => {
143
+ ttsChain = ttsChain.then(async () => speak(sentence));
144
+ };
145
+ try {
146
+ const result = await streamGenerate({ messages, signal }, (delta) => {
147
+ if (isAborted()) {
148
+ return;
149
+ }
150
+ send({ text: delta, type: "assistant_delta" });
151
+ pending += delta;
152
+ const { rest, sentences } = takeSentences(pending);
153
+ pending = rest;
154
+ for (const sentence of sentences) {
155
+ enqueueSpeak(sentence);
156
+ }
157
+ });
158
+ if (!isAborted() && pending.trim().length > 0) {
159
+ enqueueSpeak(pending.trim());
160
+ }
161
+ pending = "";
162
+ await ttsChain;
163
+ const interrupted = isAborted();
164
+ const assistantText = interrupted ? spoken : result.text;
165
+ await run(appendMessage, { content: assistantText, messageKey: `voice:${connectionId}:${String(turn)}:assistant`, role: "assistant", threadKey });
166
+ await run(patchThread, { key: threadKey, status: "idle" });
167
+ send(interrupted ? { type: "interrupted" } : { text: assistantText, type: "assistant_done" });
168
+ return { assistantText, interrupted, userText };
169
+ } catch (error) {
170
+ await run(patchThread, { key: threadKey, status: "idle" });
171
+ throw error;
172
+ }
173
+ };
174
+ const parseIdentity = (raw) => {
175
+ if (!raw) {
176
+ return void 0;
177
+ }
178
+ try {
179
+ const parsed = JSON.parse(raw);
180
+ return typeof parsed === "object" && parsed !== null ? parsed : void 0;
181
+ } catch {
182
+ return void 0;
183
+ }
184
+ };
185
+ const readTranscriptionText = (result) => {
186
+ if (typeof result === "object" && result !== null && "text" in result) {
187
+ const { text } = result;
188
+ return typeof text === "string" ? text : "";
189
+ }
190
+ return "";
191
+ };
192
+ const readSynthesisAudio = (result) => {
193
+ if (result instanceof Uint8Array || result instanceof ReadableStream) {
194
+ return result;
195
+ }
196
+ if (result instanceof Response && result.body) {
197
+ return result.body;
198
+ }
199
+ if (typeof result === "object" && result !== null && "audio" in result) {
200
+ const { audio } = result;
201
+ if (typeof audio === "string") {
202
+ return fromBase64(audio);
203
+ }
204
+ if (audio instanceof ReadableStream || audio instanceof Uint8Array) {
205
+ return audio;
206
+ }
207
+ }
208
+ return new Uint8Array(0);
209
+ };
210
+
211
+ export { parseIdentity, pcmToWav, readSynthesisAudio, readTranscriptionText, runVoiceTurn, toByteIterable };