@lunora/agent 1.0.0-alpha.80 → 1.0.0-alpha.81

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 (30) hide show
  1. package/dist/channels.d.mts +2 -2
  2. package/dist/channels.d.ts +2 -2
  3. package/dist/component.mjs +1 -1
  4. package/dist/inbound.d.mts +1 -1
  5. package/dist/inbound.d.ts +1 -1
  6. package/dist/index.d.mts +13 -2
  7. package/dist/index.d.ts +13 -2
  8. package/dist/index.mjs +1 -1
  9. package/dist/packem_shared/VoiceSessionDO-DHtOAsd9.mjs +1 -0
  10. package/dist/packem_shared/agentAsTool-Xg7YCl5P.mjs +1 -0
  11. package/dist/packem_shared/{codeTool-qdwj8j8S.mjs → codeTool-DC62JfaY.mjs} +1 -1
  12. package/dist/packem_shared/{compileAgentWorkflow-rVUKXIXq.mjs → compileAgentWorkflow-D4q6vB3j.mjs} +1 -1
  13. package/dist/packem_shared/{defineAgent-CZdh7y3W.mjs → defineAgent-YTqqBCP3.mjs} +1 -1
  14. package/dist/packem_shared/runAgentLoop-oAmn3OyN.mjs +3 -0
  15. package/dist/packem_shared/runVoiceTurn-B9EXi1BC.mjs +1 -0
  16. package/dist/packem_shared/{types.d-eCuvcLzf.d.mts → types.d-DTKxPuh_.d.mts} +28 -1
  17. package/dist/packem_shared/{types.d-eCuvcLzf.d.ts → types.d-DTKxPuh_.d.ts} +28 -1
  18. package/dist/packem_shared/voice-turn-DhxJgQW1.mjs +1 -0
  19. package/dist/reply.d.mts +1 -1
  20. package/dist/reply.d.ts +1 -1
  21. package/dist/sandbox.d.mts +1 -1
  22. package/dist/sandbox.d.ts +1 -1
  23. package/dist/skill-markdown.d.mts +1 -1
  24. package/dist/skill-markdown.d.ts +1 -1
  25. package/package.json +7 -7
  26. package/dist/packem_shared/VoiceSessionDO-Dxj0V8Ej.mjs +0 -1
  27. package/dist/packem_shared/agentAsTool-DrFnh9UQ.mjs +0 -1
  28. package/dist/packem_shared/runAgentLoop-KUUoFT3r.mjs +0 -3
  29. package/dist/packem_shared/runVoiceTurn-CRPeNXsS.mjs +0 -1
  30. package/dist/packem_shared/voice-turn-DbVR0H6T.mjs +0 -1
@@ -1,5 +1,5 @@
1
- import { A as AgentDefinition } from "./packem_shared/types.d-eCuvcLzf.mjs";
2
- export type { I as InboundChannelEvent } from "./packem_shared/types.d-eCuvcLzf.mjs";
1
+ import { A as AgentDefinition } from "./packem_shared/types.d-DTKxPuh_.mjs";
2
+ export type { I as InboundChannelEvent } from "./packem_shared/types.d-DTKxPuh_.mjs";
3
3
  import '@lunora/mail/inbound';
4
4
  import 'ai';
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { A as AgentDefinition } from "./packem_shared/types.d-eCuvcLzf.js";
2
- export type { I as InboundChannelEvent } from "./packem_shared/types.d-eCuvcLzf.js";
1
+ import { A as AgentDefinition } from "./packem_shared/types.d-DTKxPuh_.js";
2
+ export type { I as InboundChannelEvent } from "./packem_shared/types.d-DTKxPuh_.js";
3
3
  import '@lunora/mail/inbound';
4
4
  import 'ai';
5
5
  /**
@@ -1,2 +1,2 @@
1
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};
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)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)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-eCuvcLzf.mjs";
1
+ import { A as AgentDefinition } from "./packem_shared/types.d-DTKxPuh_.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-eCuvcLzf.js";
1
+ import { A as AgentDefinition } from "./packem_shared/types.d-DTKxPuh_.js";
2
2
  import '@lunora/mail/inbound';
3
3
  import 'ai';
4
4
  /**
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
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";
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-DTKxPuh_.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-DTKxPuh_.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";
@@ -704,6 +704,13 @@ interface VoiceTurnResult {
704
704
  interface RunVoiceTurnOptions {
705
705
  /** The agent whose thread + models back this session. */
706
706
  agent: AgentDefinition;
707
+ /**
708
+ * History-compaction seam — the SAME one the durable loop uses. Voice and
709
+ * text turns share one thread, so an agent that declares `compaction` must
710
+ * get it here too; absent (or with no `compaction` config) the turn takes
711
+ * the byte-identical uncompacted path.
712
+ */
713
+ compact?: AgentCompact;
707
714
  /** Stable per-socket id — the message-key prefix that keeps persisted rows idempotent. */
708
715
  connectionId: string;
709
716
  /** The Worker env (resolves a dynamic `instructions` thunk). */
@@ -785,6 +792,8 @@ declare class VoiceSessionDO {
785
792
  protected readonly streamGenerate: AgentStreamGenerate;
786
793
  protected readonly sttModel: string;
787
794
  protected readonly ttsModel: string;
795
+ /** Turn budget for one socket — see {@link DEFAULT_MAX_SESSION_TURNS}. */
796
+ private readonly maxSessionTurns;
788
797
  private readonly audioBuffers;
789
798
  private readonly bufferedBytes;
790
799
  private readonly controllers;
@@ -823,6 +832,8 @@ declare class VoiceSessionDO {
823
832
  private synthesizeWithSignal;
824
833
  /** Abort an in-flight turn and free a socket's transient buffers. */
825
834
  private cleanupSocket;
835
+ /** Close a socket that broke a session bound, swallowing an already-closed error (never throw from a handler). */
836
+ private closeSocket;
826
837
  /** Send a JSON control frame, swallowing a closed-socket error (never throw from a handler). */
827
838
  private send;
828
839
  /** Send a binary audio frame, swallowing a closed-socket error. */
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
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.js";
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.js";
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-DTKxPuh_.js";
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-DTKxPuh_.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";
@@ -704,6 +704,13 @@ interface VoiceTurnResult {
704
704
  interface RunVoiceTurnOptions {
705
705
  /** The agent whose thread + models back this session. */
706
706
  agent: AgentDefinition;
707
+ /**
708
+ * History-compaction seam — the SAME one the durable loop uses. Voice and
709
+ * text turns share one thread, so an agent that declares `compaction` must
710
+ * get it here too; absent (or with no `compaction` config) the turn takes
711
+ * the byte-identical uncompacted path.
712
+ */
713
+ compact?: AgentCompact;
707
714
  /** Stable per-socket id — the message-key prefix that keeps persisted rows idempotent. */
708
715
  connectionId: string;
709
716
  /** The Worker env (resolves a dynamic `instructions` thunk). */
@@ -785,6 +792,8 @@ declare class VoiceSessionDO {
785
792
  protected readonly streamGenerate: AgentStreamGenerate;
786
793
  protected readonly sttModel: string;
787
794
  protected readonly ttsModel: string;
795
+ /** Turn budget for one socket — see {@link DEFAULT_MAX_SESSION_TURNS}. */
796
+ private readonly maxSessionTurns;
788
797
  private readonly audioBuffers;
789
798
  private readonly bufferedBytes;
790
799
  private readonly controllers;
@@ -823,6 +832,8 @@ declare class VoiceSessionDO {
823
832
  private synthesizeWithSignal;
824
833
  /** Abort an in-flight turn and free a socket's transient buffers. */
825
834
  private cleanupSocket;
835
+ /** Close a socket that broke a session bound, swallowing an already-closed error (never throw from a handler). */
836
+ private closeSocket;
826
837
  /** Send a JSON control frame, swallowing a closed-socket error (never throw from a handler). */
827
838
  private send;
828
839
  /** Send a binary audio frame, swallowing a closed-socket error. */
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{runAgentLoop as t,splitForCompaction as r}from"./packem_shared/runAgentLoop-KUUoFT3r.mjs";import{collectAgenticMemoryTools as a,toSearchResults as i}from"./packem_shared/collectAgenticMemoryTools-BeMWT2qt.mjs";import{agentAsTool as l}from"./packem_shared/agentAsTool-DrFnh9UQ.mjs";import{codeTool as p}from"./packem_shared/codeTool-qdwj8j8S.mjs";import{agentComponent as c,agentExtension as x}from"./component.mjs";import{default as A}from"./packem_shared/createAgentContext-iS35-Xrs.mjs";import{defineAgent as d,defineAgentTool as u,isAgentDefinition as N}from"./packem_shared/defineAgent-CZdh7y3W.mjs";import{functionTool as D}from"./packem_shared/functionTool-D3CP4f8-.mjs";import{createAgentGenerate as M,createEpisodeExtract as O,createGraphExtract as _,createStreamGenerate as C,resolveAgentModel as G}from"./packem_shared/createAgentGenerate-9bZ2YhpN.mjs";import{adaptMcpResult as F,mcpTools as L}from"./packem_shared/adaptMcpResult-CVlq-_TO.mjs";import{buildModelMessages as k}from"./packem_shared/buildModelMessages-Y4tGo1T9.mjs";import{agentBindingName as R,agentClassName as V,agentDefaultName as b,voiceBindingName as h,voiceClassName as w}from"./naming.mjs";import{AGENT_MODULE as I,DEFAULT_AGENT_FUNCTION_PATHS as P,SANDBOX_INVOKE_PATH as X,SANDBOX_MODULE as y,toFunctionReference as K}from"./packem_shared/AGENT_MODULE-M4D1EejI.mjs";import{browserTool as j,containerTool as q,fsTool as z}from"./sandbox.mjs";import{defineSkill as Q,isSkillDefinition as Y}from"./packem_shared/defineSkill-DGGvDWNq.mjs";import{default as $}from"./packem_shared/VoiceSessionDO-Dxj0V8Ej.mjs";import{r as oe}from"./packem_shared/voice-turn-DbVR0H6T.mjs";import{default as re}from"./packem_shared/compileAgentWorkflow-rVUKXIXq.mjs";export{I as AGENT_MODULE,P as DEFAULT_AGENT_FUNCTION_PATHS,X as SANDBOX_INVOKE_PATH,y as SANDBOX_MODULE,$ as VoiceSessionDO,F as adaptMcpResult,l as agentAsTool,R as agentBindingName,V as agentClassName,c as agentComponent,b as agentDefaultName,x as agentExtension,j as browserTool,k as buildModelMessages,p as codeTool,a as collectAgenticMemoryTools,re as compileAgentWorkflow,q as containerTool,A as createAgentContext,M as createAgentGenerate,O as createEpisodeExtract,_ as createGraphExtract,C as createStreamGenerate,d as defineAgent,u as defineAgentTool,Q as defineSkill,z as fsTool,D as functionTool,N as isAgentDefinition,Y as isSkillDefinition,L as mcpTools,G as resolveAgentModel,t as runAgentLoop,oe as runVoiceTurn,r as splitForCompaction,K as toFunctionReference,i as toSearchResults,h as voiceBindingName,w as voiceClassName};
1
+ import{runAgentLoop as t,splitForCompaction as r}from"./packem_shared/runAgentLoop-oAmn3OyN.mjs";import{collectAgenticMemoryTools as a,toSearchResults as i}from"./packem_shared/collectAgenticMemoryTools-BeMWT2qt.mjs";import{agentAsTool as l}from"./packem_shared/agentAsTool-Xg7YCl5P.mjs";import{codeTool as p}from"./packem_shared/codeTool-DC62JfaY.mjs";import{agentComponent as c,agentExtension as x}from"./component.mjs";import{default as A}from"./packem_shared/createAgentContext-iS35-Xrs.mjs";import{defineAgent as d,defineAgentTool as u,isAgentDefinition as N}from"./packem_shared/defineAgent-YTqqBCP3.mjs";import{functionTool as D}from"./packem_shared/functionTool-D3CP4f8-.mjs";import{createAgentGenerate as M,createEpisodeExtract as O,createGraphExtract as _,createStreamGenerate as C,resolveAgentModel as G}from"./packem_shared/createAgentGenerate-9bZ2YhpN.mjs";import{adaptMcpResult as F,mcpTools as L}from"./packem_shared/adaptMcpResult-CVlq-_TO.mjs";import{buildModelMessages as k}from"./packem_shared/buildModelMessages-Y4tGo1T9.mjs";import{agentBindingName as R,agentClassName as V,agentDefaultName as b,voiceBindingName as h,voiceClassName as w}from"./naming.mjs";import{AGENT_MODULE as I,DEFAULT_AGENT_FUNCTION_PATHS as P,SANDBOX_INVOKE_PATH as X,SANDBOX_MODULE as y,toFunctionReference as K}from"./packem_shared/AGENT_MODULE-M4D1EejI.mjs";import{browserTool as j,containerTool as q,fsTool as z}from"./sandbox.mjs";import{defineSkill as Q,isSkillDefinition as Y}from"./packem_shared/defineSkill-DGGvDWNq.mjs";import{default as $}from"./packem_shared/VoiceSessionDO-DHtOAsd9.mjs";import{r as oe}from"./packem_shared/voice-turn-DhxJgQW1.mjs";import{default as re}from"./packem_shared/compileAgentWorkflow-D4q6vB3j.mjs";export{I as AGENT_MODULE,P as DEFAULT_AGENT_FUNCTION_PATHS,X as SANDBOX_INVOKE_PATH,y as SANDBOX_MODULE,$ as VoiceSessionDO,F as adaptMcpResult,l as agentAsTool,R as agentBindingName,V as agentClassName,c as agentComponent,b as agentDefaultName,x as agentExtension,j as browserTool,k as buildModelMessages,p as codeTool,a as collectAgenticMemoryTools,re as compileAgentWorkflow,q as containerTool,A as createAgentContext,M as createAgentGenerate,O as createEpisodeExtract,_ as createGraphExtract,C as createStreamGenerate,d as defineAgent,u as defineAgentTool,Q as defineSkill,z as fsTool,D as functionTool,N as isAgentDefinition,Y as isSkillDefinition,L as mcpTools,G as resolveAgentModel,t as runAgentLoop,oe as runVoiceTurn,r as splitForCompaction,K as toFunctionReference,i as toSearchResults,h as voiceBindingName,w as voiceClassName};
@@ -0,0 +1 @@
1
+ import{createAi as S}from"@lunora/ai";import{F as A}from"./createDispatchRunner-pLyQ70FK-2_j6ocGT.mjs";import{t as b}from"./base64-5eyBfWO3.mjs";import{p as T,d as _,a as x,i as f,b as p,c as v,e as E,f as k,r as M,t as w}from"./voice-turn-DhxJgQW1.mjs";import{createStreamGenerate as I,createCompact as R}from"./createAgentGenerate-9bZ2YhpN.mjs";import{DEFAULT_AGENT_FUNCTION_PATHS as C,toFunctionReference as y}from"./AGENT_MODULE-M4D1EejI.mjs";const L="@cf/openai/whisper-large-v3-turbo",N="@cf/deepgram/aura-1",O=8*1024*1024,U=100,l=4e3,m=l*4+1024,B=4002,F=4003,D=4004,z=256*1024,g=15,W=5e3;class V{agent;ai;env;exportName;paths;streamGenerate;sttModel;ttsModel;maxSessionTurns;audioBuffers=new Map;bufferedBytes=new Map;controllers=new Map;state;constructor(e,t,s,r){this.state=e,this.env=t,this.agent=s,this.exportName=r,this.paths=C,this.ai=S({binding:t.AI,env:t}),this.streamGenerate=I(s,t),this.sttModel=s.voice?.stt??L,this.ttsModel=s.voice?.tts??N;const i=s.voice?.maxTurns;this.maxSessionTurns=Number.isInteger(i)&&i>0?i:U}fetch(e){if(e.headers.get("Upgrade")!=="websocket")return new Response("Expected a WebSocket upgrade",{status:426});const s=new URL(e.url).searchParams.get("threadKey");if(!s)return new Response("Missing threadKey",{status:400});const r=globalThis.WebSocketPair,i=new r,n=i[0],o=i[1];this.state.acceptWebSocket(o);const c=crypto.randomUUID(),d=T(e.headers.get("x-lunora-identity")),a=_(e.headers.get("x-lunora-userid")),h=x(e.headers.get("x-lunora-identity-exp"));if(f(h))return p(o),new Response(null,{status:101,webSocket:n});o.serializeAttachment?.({connectionId:c,threadKey:s,turn:0,...h===void 0?{}:{expiresAt:h},...d===void 0?{}:{identity:d},...a===void 0?{}:{userId:a}}),this.send(o,{audioFormat:this.agent.voice?.audioFormat??"mp3",type:"ready"});const u=this.agent.voice?.greeting;return u&&u.length>0&&this.state.waitUntil?.(this.speakGreeting(o,c,s,a,d,u)),new Response(null,{status:101,webSocket:n})}async webSocketMessage(e,t){const s=e.deserializeAttachment?.();if(s){if(f(s.expiresAt)){p(e);return}try{if(typeof t=="string"){await this.handleControl(e,s,t);return}this.bufferAudio(s.connectionId,new Uint8Array(t),e)}catch(r){this.send(e,{message:r instanceof Error?r.message:String(r),type:"error"})}}}webSocketClose(e){this.cleanupSocket(e)}webSocketError(e){this.cleanupSocket(e)}resolveRun(e,t){const s=e===void 0&&t===void 0?void 0:{...t===void 0?{}:{claims:t},...e===void 0?{}:{userId:e}};return A({env:this.env,label:"@lunora/agent voice",...s===void 0?{}:{identity:s}})}async transcribe(e){const t=v(e);return E(await this.ai.run(this.sttModel,{audio:b(t)}))}async synthesize(e,t){const s=this.agent.voice?.speaker;return k(await this.ai.run(this.ttsModel,{text:e,...s===void 0?{}:{speaker:s}},t===void 0?void 0:{signal:t}))}async handleControl(e,t,s){if(s.length>m){this.send(e,{message:`control frame exceeds the maximum of ${String(m)} characters`,type:"error"}),this.closeSocket(e,D,"control_frame_limit");return}let r;try{r=JSON.parse(s)}catch{return}if(r.type==="interrupt"){this.controllers.get(t.connectionId)?.abort();return}if(r.type==="text"&&r.text.length>l){this.send(e,{message:`text frame exceeds the maximum of ${String(l)} characters`,type:"error"});return}if(t.turn>=this.maxSessionTurns){this.send(e,{message:`voice session reached its ${String(this.maxSessionTurns)}-turn limit — reconnect to continue`,type:"error"}),this.closeSocket(e,B,"turn_limit");return}if(this.controllers.has(t.connectionId)){this.send(e,{message:"a turn is already in progress — send an interrupt before the next utterance",type:"error"});return}if(r.type==="commit"){const i=this.drainAudio(t.connectionId);await this.runTurn(e,t,{pcm:i});return}await this.runTurn(e,t,{text:r.text})}bufferAudio(e,t,s){const r=(this.bufferedBytes.get(e)??0)+t.byteLength;if(r>O){this.audioBuffers.delete(e),this.bufferedBytes.delete(e),this.send(s,{message:"utterance exceeded the maximum buffer — send a commit sooner",type:"error"}),this.closeSocket(s,F,"utterance_too_large");return}const i=this.audioBuffers.get(e)??[];i.push(t),this.audioBuffers.set(e,i),this.bufferedBytes.set(e,r)}drainAudio(e){const t=this.audioBuffers.get(e)??[];this.audioBuffers.delete(e),this.bufferedBytes.delete(e);const s=t.reduce((n,o)=>n+o.byteLength,0),r=new Uint8Array(s);let i=0;for(const n of t)r.set(n,i),i+=n.byteLength;return r}async runTurn(e,t,s){const r=new AbortController;this.controllers.set(t.connectionId,r);try{await M({agent:this.agent,compact:R(),connectionId:t.connectionId,env:this.env,exportName:this.exportName,paths:this.paths,run:this.resolveRun(t.userId,t.identity),send:i=>{this.send(e,i)},sendAudio:i=>{this.sendAudio(e,i)},signal:r.signal,streamGenerate:this.streamGenerate,synthesize:async(i,n)=>this.synthesizeWithSignal(i,n),threadKey:t.threadKey,transcribe:async i=>this.transcribe(i),turn:t.turn,waitForDrain:async()=>this.waitForSocketDrain(e),...t.userId===void 0?{}:{owner:t.userId},...s.pcm===void 0?{}:{pcm:s.pcm},...s.text===void 0?{}:{text:s.text}})}finally{this.controllers.get(t.connectionId)===r&&this.controllers.delete(t.connectionId),e.serializeAttachment?.({...t,turn:t.turn+1})}}async speakGreeting(e,t,s,r,i,n){const o=this.resolveRun(r,i),c=new AbortController,d=()=>c.signal.aborted;this.controllers.set(t,c);try{if((await o(y(this.paths.ensureThread),{agent:this.exportName,key:s,...this.agent.initialState===void 0?{}:{initialState:this.agent.initialState},...r===void 0?{}:{owner:r}}))?.outcome!=="created")return;for await(const h of w(await this.synthesizeWithSignal(n,c.signal))){if(d()||(await this.waitForSocketDrain(e),d()))break;this.sendAudio(e,h)}d()||(await o(y(this.paths.appendMessage),{content:n,messageKey:"voice:greeting:assistant",role:"assistant",threadKey:s}),this.send(e,{text:n,type:"assistant_done"}))}catch(a){this.send(e,{message:a instanceof Error?a.message:String(a),type:"error"})}finally{this.controllers.get(t)===c&&this.controllers.delete(t)}}async synthesizeWithSignal(e,t){return t.aborted?new Uint8Array(0):this.synthesize(e,t)}cleanupSocket(e){const t=e.deserializeAttachment?.();t&&(this.controllers.get(t.connectionId)?.abort(),this.controllers.delete(t.connectionId),this.audioBuffers.delete(t.connectionId),this.bufferedBytes.delete(t.connectionId))}closeSocket(e,t,s){try{e.close?.(t,s)}catch{}}send(e,t){try{e.send(JSON.stringify(t))}catch{}}sendAudio(e,t){try{e.send(t)}catch{}}async waitForSocketDrain(e){const t=e;let s=0;for(;typeof t.bufferedAmount=="number"&&t.bufferedAmount>z&&s<W;)await new Promise(r=>{setTimeout(r,g)}),s+=g}}export{V as default};
@@ -0,0 +1 @@
1
+ import{LunoraError as d}from"@lunora/errors";import{jsonSchema as N}from"ai";import{isDuplicateInstanceError as b}from"../channels.mjs";import{agentBindingName as E}from"../naming.mjs";import{toFunctionReference as I,DEFAULT_AGENT_FUNCTION_PATHS as L}from"./AGENT_MODULE-M4D1EejI.mjs";const S=new Set(["complete","errored","terminated"]),$=120,f=3,_=500,P=t=>t!==null&&typeof t=="object"&&typeof t.status=="string"?t.status:"unknown",v=async t=>{await new Promise(e=>{setTimeout(e,t)})},M=async(t,e,n,u)=>{for(let o=0;o<e;o+=1){const i=P(await t.status());if(S.has(i))return i;await u(n)}return"timeout"},R=t=>{for(let e=t.length-1;e>=0;e-=1){const n=t[e];if(n?.role==="assistant"&&(n.toolCalls===void 0||n.toolCalls.length===0))return n.content}return""},k=t=>{if(typeof t.name!="string"||t.name.length===0)throw new d("INTERNAL","@lunora/agent: agent.asTool requires a `name` (the child agent's export name, selecting its AGENT_* binding)");if(typeof t.description!="string"||t.description.length===0)throw new d("INTERNAL","@lunora/agent: agent.asTool requires a non-empty `description` (the parent model decides from it)");if(t.maxPolls!==void 0&&(!Number.isInteger(t.maxPolls)||t.maxPolls<1))throw new d("INTERNAL","@lunora/agent: agent.asTool `maxPolls` must be a positive integer");const{name:e}=t,n=E(e),u=t.maxPolls??$,o=t.pollIntervalMs??_,i=t.wait??v,p=I(L.listMessages),w=async(T,r)=>{const m=(Number.isInteger(r.depth)?r.depth:0)+1;if(m>f)return`Sub-agent "${e}" was not started: the maximum delegation depth of ${String(f)} is already reached. Answer with what you have instead of delegating further.`;const a=r.env[n];if(!a||typeof a.create!="function"||typeof a.get!="function")throw new d("INTERNAL",`@lunora/agent: agent.asTool("${e}") found no Workflow binding "${n}" on env — declare the "${e}" agent so codegen wires its binding`);const g=`${r.threadKey}::sub::${e}::${r.toolCallId}`,h=`sub-${e}-${r.toolCallId}`,y={depth:m,input:T.prompt,threadKey:g};let s;try{const c=await a.create({id:h,params:y});s=await a.get(c.id)}catch(c){if(!b(c))throw c;s=await a.get(h)}const l=await M(s,u,o,i);if(l==="errored"||l==="terminated")return`Sub-agent "${e}" ${l} before producing an answer.`;if(l==="timeout"){try{await s.terminate()}catch{}return`Sub-agent "${e}" did not finish within the allotted time.`}const A=await r.run(p,{key:g});return R(A)};return{description:t.description,execute:w,inputSchema:N({properties:{prompt:{description:"The task or question to delegate to the sub-agent.",type:"string"}},required:["prompt"],type:"object"}),isLunoraAgentTool:!0}};export{k as agentAsTool};
@@ -1 +1 @@
1
- import{LunoraError as a}from"@lunora/errors";import{jsonSchema as A}from"ai";const $=16,y=4e3,b=e=>{if(e===void 0)return e;const o=typeof e=="string"?e:JSON.stringify(e);return o.length<=y?e:`${o.slice(0,y)}… [truncated]`},T=(e,o)=>{let t=e;for(const s of o.split(".")){if(t===null||typeof t!="object"||!Object.hasOwn(t,s))return;t=t[s]}return t},c=(e,o)=>{if(Array.isArray(e))return e.map(r=>c(r,o));if(e===null||typeof e!="object")return e;const t=e;if(typeof t.$from=="string"){const r=t.$from;if(!(r in o))throw new a("BAD_REQUEST",`@lunora/agent: code step references unknown result "${r}" (define it in an earlier step)`);return typeof t.$path=="string"?T(o[r],t.$path):o[r]}const s={};for(const[r,i]of Object.entries(t))r!=="__proto__"&&(s[r]=c(i,o));return s},g=async(e,o,t,s)=>{const r=Array.isArray(e.steps)?e.steps.slice(0,s):[],i={},p=[],d=new Set;for(const n of r){if(d.has(n.id))throw new a("BAD_REQUEST",`@lunora/agent: duplicate code step id "${n.id}" — each step id must be unique (later steps reference an output by id via $from)`);d.add(n.id)}for(const n of r){const l=o[n.tool];if(!l)throw new a("BAD_REQUEST",`@lunora/agent: code step calls unknown tool "${n.tool}" (available: ${Object.keys(o).join(", ")})`);const m=c(n.input??{},i),f={...t,idempotencyKey:`${t.idempotencyKey}:${n.id}`,toolCallId:`${t.toolCallId}:${n.id}`},h=()=>Promise.resolve(l.execute(m,f)),u=await t.step.do(f.idempotencyKey,h);i[n.id]=u,p.push({id:n.id,output:b(u)})}return{final:p.at(-1)?.output,results:p}},v=e=>`Compose MULTIPLE tool calls in one turn as a script, instead of one call per turn. Provide \`steps\`: an ordered array of \`{ id, tool, input }\`. A later step's \`input\` may reference an earlier step's output with \`{ "$from": "<stepId>", "$path": "optional.dot.path" }\`. Available tools: ${Object.entries(e).map(([o,t])=>`"${o}" — ${t.description}`).join("; ")}.`,w=A({properties:{steps:{description:"Ordered tool calls; a later input may reference an earlier output via { $from, $path }.",items:{additionalProperties:!1,properties:{id:{description:"A name later steps reference this output by.",type:"string"},input:{additionalProperties:!0,description:"The tool input (may embed $from refs).",type:"object"},tool:{description:"The tool to call.",type:"string"}},required:["id","tool"],type:"object"},type:"array"}},required:["steps"],type:"object"}),S=(e,o={})=>{const t=e;if(!t||typeof t!="object"||Object.keys(t).length===0)throw new a("INTERNAL","@lunora/agent: codeTool requires a non-empty map of tools to compose");for(const[r,i]of Object.entries(t))if(i.needsApproval!==void 0&&i.needsApproval!==!1)throw new a("INTERNAL",`@lunora/agent: codeTool cannot compose "${r}" — it has a \`needsApproval\` gate a code-mode script can't pause for. Expose it as a normal top-level tool, or gate the whole script via codeTool's \`needsApproval\`.`);const s=o.maxSteps??$;return{description:o.description??v(e),execute:(r,i)=>g(r,e,i,s),inputSchema:w,isLunoraAgentTool:!0,...o.needsApproval===void 0?{}:{needsApproval:o.needsApproval}}};export{S as codeTool,c as resolveReferences,g as runToolScript};
1
+ import{LunoraError as a}from"@lunora/errors";import{jsonSchema as A}from"ai";const b=16,m=4e3,$=e=>{if(e===void 0)return e;const o=typeof e=="string"?e:JSON.stringify(e);return o.length<=m?e:`${o.slice(0,m)}… [truncated]`},T=(e,o)=>{let t=e;for(const s of o.split(".")){if(t===null||typeof t!="object"||!Object.hasOwn(t,s))return;t=t[s]}return t},c=(e,o)=>{if(Array.isArray(e))return e.map(r=>c(r,o));if(e===null||typeof e!="object")return e;const t=e;if(typeof t.$from=="string"){const r=t.$from;if(!(r in o))throw new a("BAD_REQUEST",`@lunora/agent: code step references unknown result "${r}" (define it in an earlier step)`);return typeof t.$path=="string"?T(o[r],t.$path):o[r]}const s={};for(const[r,i]of Object.entries(t))r!=="__proto__"&&(s[r]=c(i,o));return s},g=async(e,o,t,s)=>{const r=Array.isArray(e.steps)?e.steps.slice(0,s):[],i={},p=[],d=new Set;for(const n of r){if(d.has(n.id))throw new a("BAD_REQUEST",`@lunora/agent: duplicate code step id "${n.id}" — each step id must be unique (later steps reference an output by id via $from)`);d.add(n.id)}for(const n of r){const l=o[n.tool];if(!l)throw new a("BAD_REQUEST",`@lunora/agent: code step calls unknown tool "${n.tool}" (available: ${Object.keys(o).join(", ")})`);const y=c(n.input??{},i),f={...t,idempotencyKey:`${t.idempotencyKey}:${n.id}`,toolCallId:`${t.toolCallId}:${n.id}`},h=()=>Promise.resolve(l.execute(y,f)),u=await t.step.do(f.idempotencyKey,h);i[n.id]=u,p.push({id:n.id,output:$(u)})}return{final:p.at(-1)?.output,results:p}},S=e=>`Compose MULTIPLE tool calls in one turn as a script, instead of one call per turn. Provide \`steps\`: an ordered array of \`{ id, tool, input }\`. A later step's \`input\` may reference an earlier step's output with \`{ "$from": "<stepId>", "$path": "optional.dot.path" }\`. Available tools: ${Object.entries(e).map(([o,t])=>`"${o}" — ${t.description}`).join("; ")}.`,v=A({properties:{steps:{description:"Ordered tool calls; a later input may reference an earlier output via { $from, $path }.",items:{additionalProperties:!1,properties:{id:{description:"A name later steps reference this output by.",type:"string"},input:{additionalProperties:!0,description:"The tool input (may embed $from refs).",type:"object"},tool:{description:"The tool to call.",type:"string"}},required:["id","tool"],type:"object"},type:"array"}},required:["steps"],type:"object"}),j=(e,o={})=>{const t=e;if(!t||typeof t!="object"||Object.keys(t).length===0)throw new a("INTERNAL","@lunora/agent: codeTool requires a non-empty map of tools to compose");for(const[r,i]of Object.entries(t))if(i.needsApproval!==void 0&&i.needsApproval!==!1)throw new a("INTERNAL",`@lunora/agent: codeTool cannot compose "${r}" — it has a \`needsApproval\` gate a code-mode script can't pause for. Expose it as a normal top-level tool, or gate the whole script via codeTool's \`needsApproval\`.`);if(o.maxSteps!==void 0&&(!Number.isInteger(o.maxSteps)||o.maxSteps<1))throw new a("INTERNAL","@lunora/agent: codeTool `maxSteps` must be a positive integer");const s=o.maxSteps??b;return{description:o.description??S(e),execute:(r,i)=>g(r,e,i,s),inputSchema:v,isLunoraAgentTool:!0,...o.needsApproval===void 0?{}:{needsApproval:o.needsApproval}}};export{j as codeTool,c as resolveReferences,g as runToolScript};
@@ -1 +1 @@
1
- import{defineWorkflow as s}from"@lunora/workflow";import{runAgentLoop as m}from"./runAgentLoop-KUUoFT3r.mjs";import{createStreamGenerate as p,createAgentGenerate as l,createEpisodeExtract as f,createGraphExtract as d,createCompact as u}from"./createAgentGenerate-9bZ2YhpN.mjs";import{agentDefaultName as c}from"../naming.mjs";import{DEFAULT_AGENT_FUNCTION_PATHS as A}from"./AGENT_MODULE-M4D1EejI.mjs";import{F as T}from"./createDispatchRunner-pLyQ70FK-2_j6ocGT.mjs";import{otlpTelemetry as y}from"./otlpTelemetry-CywiFp-X.mjs";const E=(r,t,a)=>t===void 0?r:T({env:a,identity:{userId:t},label:"@lunora/agent"}),O=(r,t,a)=>{const e=t.LUNORA_OTLP_ENDPOINT;if(typeof e!="string"||e===""||r.telemetry?.isEnabled===!1)return r;const n=typeof t.LUNORA_OTLP_TOKEN=="string"?t.LUNORA_OTLP_TOKEN:void 0,i=[r.telemetry?.integrations].flat().filter(o=>o!==void 0);return{...r,telemetry:{...r.telemetry,integrations:[...i,y({conversationId:a,endpoint:e,token:n})],isEnabled:!0}}},I=(r,t,a)=>s({handler:async e=>{const n=O(r,e.env,e.params.threadKey);return m({agent:n,compact:u(),env:e.env,exportName:t,extractGraph:d(),extractEpisode:f(),generate:l(n,e.env),instanceId:e.event.instanceId,params:e.params,paths:a?.paths??A,run:E(e.run,e.params.owner,e.env),step:e.step,streamGenerate:p(n,e.env)})},name:r.name??c(t)});export{I as default};
1
+ import{defineWorkflow as s}from"@lunora/workflow";import{runAgentLoop as m}from"./runAgentLoop-oAmn3OyN.mjs";import{createStreamGenerate as p,createAgentGenerate as l,createEpisodeExtract as f,createGraphExtract as d,createCompact as u}from"./createAgentGenerate-9bZ2YhpN.mjs";import{agentDefaultName as c}from"../naming.mjs";import{DEFAULT_AGENT_FUNCTION_PATHS as A}from"./AGENT_MODULE-M4D1EejI.mjs";import{F as T}from"./createDispatchRunner-pLyQ70FK-2_j6ocGT.mjs";import{otlpTelemetry as y}from"./otlpTelemetry-CywiFp-X.mjs";const E=(r,t,a)=>t===void 0?r:T({env:a,identity:{userId:t},label:"@lunora/agent"}),O=(r,t,a)=>{const e=t.LUNORA_OTLP_ENDPOINT;if(typeof e!="string"||e===""||r.telemetry?.isEnabled===!1)return r;const n=typeof t.LUNORA_OTLP_TOKEN=="string"?t.LUNORA_OTLP_TOKEN:void 0,i=[r.telemetry?.integrations].flat().filter(o=>o!==void 0);return{...r,telemetry:{...r.telemetry,integrations:[...i,y({conversationId:a,endpoint:e,token:n})],isEnabled:!0}}},I=(r,t,a)=>s({handler:async e=>{const n=O(r,e.env,e.params.threadKey);return m({agent:n,compact:u(),env:e.env,exportName:t,extractGraph:d(),extractEpisode:f(),generate:l(n,e.env),instanceId:e.event.instanceId,params:e.params,paths:a?.paths??A,run:E(e.run,e.params.owner,e.env),step:e.step,streamGenerate:p(n,e.env)})},name:r.name??c(t)});export{I as default};
@@ -1,3 +1,3 @@
1
- import{LunoraError as r}from"@lunora/errors";import{collectAgenticMemoryTools as h}from"./collectAgenticMemoryTools-BeMWT2qt.mjs";import{agentAsTool as f}from"./agentAsTool-DrFnh9UQ.mjs";import{i as m}from"./memory-JI0lUu84.mjs";import{SKILL_NAME_PATTERN as g,RESERVED_SKILL_NAME as c}from"./defineSkill-DGGvDWNq.mjs";const w=/^[a-zA-Z][\w-]*$/u,p=(e,n)=>{const o={...e.tools};for(const t of n)for(const[s,l]of Object.entries(t.tools??{})){if(Object.hasOwn(o,s))throw new r("INTERNAL",`@lunora/agent: skill "${t.name}" tool "${s}" collides with an existing tool — rename one (the agent's tool namespace is flat)`);o[s]=l}return o},T=(e,n)=>{const o=[];for(const t of[e.instructions,...n.map(s=>s.instructions)])t&&o.push(t);return o.length<=1?o[0]:t=>o.map(s=>typeof s=="function"?s(t):s).filter(s=>s.length>0).join(`
1
+ import{LunoraError as r}from"@lunora/errors";import{collectAgenticMemoryTools as h}from"./collectAgenticMemoryTools-BeMWT2qt.mjs";import{agentAsTool as f}from"./agentAsTool-Xg7YCl5P.mjs";import{i as m}from"./memory-JI0lUu84.mjs";import{SKILL_NAME_PATTERN as g,RESERVED_SKILL_NAME as c}from"./defineSkill-DGGvDWNq.mjs";const w=/^[a-zA-Z][\w-]*$/u,p=(e,n)=>{const o={...e.tools};for(const t of n)for(const[s,l]of Object.entries(t.tools??{})){if(Object.hasOwn(o,s))throw new r("INTERNAL",`@lunora/agent: skill "${t.name}" tool "${s}" collides with an existing tool — rename one (the agent's tool namespace is flat)`);o[s]=l}return o},T=(e,n)=>{const o=[];for(const t of[e.instructions,...n.map(s=>s.instructions)])t&&o.push(t);return o.length<=1?o[0]:t=>o.map(s=>typeof s=="function"?s(t):s).filter(s=>s.length>0).join(`
2
2
 
3
3
  `)},k=(e,n)=>{const o=[];e.memory&&m(e.memory)&&o.push({key:"default",...e.memory});for(const t of n)t.knowledge&&m(t.knowledge)&&o.push({key:t.name,...t.knowledge});return o},N=e=>{const n=new Set;for(const o of e){if(typeof o.name!="string"||!g.test(o.name))throw new r("INTERNAL",`@lunora/agent: skill \`name\` must be a valid identifier (letters, digits, _ or -, starting with a letter), got ${JSON.stringify(o.name)}`);if(o.name===c)throw new r("INTERNAL",`@lunora/agent: skill name "${c}" is reserved (it keys the agent's own \`memory\` source / the \`memory:retrieve\` step) — choose another name`);if(n.has(o.name))throw new r("INTERNAL",`@lunora/agent: skill name "${o.name}" is used by more than one skill — rename one (a skill name keys its knowledge memory source, which must be unique)`);n.add(o.name)}},A=(e,n)=>{if(e===void 0)return;const o=Object.keys(n).filter(t=>!e.includes(t));if(o.length>0)throw new r("INTERNAL",`@lunora/agent: \`activeTools\` omits the agentic-memory tool(s) ${o.map(t=>`"${t}"`).join(", ")} — the model could never call them; add them to \`activeTools\` (or drop \`activeTools\` to expose every tool)`)},y=(e,n)=>{const o=(t,s)=>{if(t&&t.kind!=="graph"&&t.kind!=="episodic"&&t.source===void 0)throw new r("INTERNAL",`@lunora/agent: ${s} requires a \`source\` action unless \`kind: "graph"\` or \`kind: "episodic"\``)};o(e.memory,"`memory`");for(const t of n)o(t.knowledge,`skill "${t.name}" \`knowledge\``)},v=e=>{const n=e.model;if(n==null||typeof n=="string"&&n.length===0)throw new r("INTERNAL","@lunora/agent: defineAgent requires a `model` (a Workers AI id, an AI SDK LanguageModel, or an (env) => model thunk)");if(e.maxTurns!==void 0&&(!Number.isInteger(e.maxTurns)||e.maxTurns<1))throw new r("INTERNAL","@lunora/agent: `maxTurns` must be a positive integer");const o=e.skills??[];N(o),y(e,o);const t=p(e,o),s=h(e,o);for(const[i,d]of Object.entries(s)){if(Object.hasOwn(t,i))throw new r("INTERNAL",`@lunora/agent: agentic-memory tool "${i}" collides with an existing tool — rename one (the agent's tool namespace is flat)`);t[i]=d}const l=Object.keys(s).length>0;A(e.activeTools,s);for(const i of Object.keys(t))if(!w.test(i))throw new r("INTERNAL",`@lunora/agent: tool name "${i}" is not a valid identifier (letters, digits, _ or -, starting with a letter)`);const a=k(e,o),u=T(e,o);return{...e,asTool:f,isLunoraAgent:!0,...o.some(i=>!!i.instructions)?{instructions:u}:{},...a.length>0?{memorySources:a}:{},...o.length>0||l?{tools:t}:{}}},S=e=>typeof e=="object"&&e!==null&&e.isLunoraAgent===!0,O=e=>{if(typeof e.execute!="function")throw new r("INTERNAL","@lunora/agent: defineAgentTool requires an `execute` function");if(typeof e.description!="string"||e.description.length===0)throw new r("INTERNAL","@lunora/agent: defineAgentTool requires a non-empty `description` (the model decides from it)");return{...e,isLunoraAgentTool:!0}};export{v as defineAgent,O as defineAgentTool,S as isAgentDefinition};
@@ -0,0 +1,3 @@
1
+ import{d as J,b as O}from"./component-shared-IZozysYq.mjs";import{resolveAgentModel as Q}from"./createAgentGenerate-9bZ2YhpN.mjs";import{r as Y,f as Z,m as T,a as tt}from"./memory-JI0lUu84.mjs";import{buildModelMessages as F}from"./buildModelMessages-Y4tGo1T9.mjs";import{agentBindingName as q}from"../naming.mjs";import{toFunctionReference as g}from"./AGENT_MODULE-M4D1EejI.mjs";const et=8,ot=e=>Number.isInteger(e)&&e>0?e:0,j=e=>e===void 0?"null":JSON.stringify(e),nt=e=>e===void 0?[]:[e].flat(),at=async(e,t)=>(await Promise.all(e.map(async o=>o({steps:t})))).some(Boolean),st=(e,t)=>{if(t===void 0)return e;if(e===void 0)return{...t};const n={};for(const o of["inputTokens","outputTokens","totalTokens"])(e[o]!==void 0||t[o]!==void 0)&&(n[o]=(e[o]??0)+(t[o]??0));return n},rt=async(e,t,n,o,a)=>{const{needsApproval:r}=e;return r===void 0||r===!1?!1:r===!0?!0:n.do(o,async()=>r(t,a))},it="WorkflowTimeoutError",ct=e=>e instanceof Error&&e.name===it,P=4320*60*1e3,ut={day:864e5,hour:36e5,minute:6e4,month:30*864e5,second:1e3,week:7*864e5,year:365*864e5},dt=/^(\d+(?:\.\d+)?) (day|hour|minute|month|second|week|year)s?$/u,pt=e=>{if(e===void 0)return P;if(typeof e=="number")return Math.min(e,O);const t=dt.exec(e);return t===null?P:Math.min(Number(t[1])*ut[t[2]],O)},lt=async(e,t)=>{const{agent:n,deleteMessage:o,instanceId:a,patchThread:r,persist:c,step:u}=e;await c({content:`Awaiting approval to run tool "${t.name}".`,messageKey:`${a}:approval:${t.id}`,role:"tool",status:"awaiting_approval",toolCallId:t.id,toolName:t.name}),await r({status:"awaiting_input"});const i=await u.waitForEvent(`approval:${t.id}`,{timeout:pt(n.approvalTimeout),type:`agent-approval:${t.id}`}).then(p=>({decision:p.payload.decision,...p.payload.note===void 0?{}:{note:p.payload.note}})).catch(p=>{if(!ct(p))throw p;return{decision:"reject",note:"approval timed out"}});return await o(`${a}:approval:${t.id}`),await r({status:"running"}),i},mt=async(e,t)=>{const{depth:n,env:o,getState:a,instanceId:r,onTokenDelta:c,persist:u,run:i,setState:p,step:s,threadKey:d,tools:l}=e,m=`tool:${t.name}:${t.id}`,h=l[t.name],f=`${r}:tool:${t.id}`;if(!h){await u({content:`Error: unknown tool "${t.name}"`,messageKey:f,role:"tool",stepName:m,toolCallId:t.id,toolName:t.name});return}const v={depth:n,env:o,getState:a,idempotencyKey:m,reportProgress:R=>{c?.({data:R,kind:"progress",threadKey:d,toolCallId:t.id})},run:i,setState:p,step:s,threadKey:d,toolCallId:t.id},x={depth:n,env:o,getState:a,idempotencyKey:m,run:i,threadKey:d,toolCallId:t.id},S=`tool:approval-gate:${t.id}`;let C;if(await rt(h,t.input,s,S,x)){const{decision:R,note:K}=await lt(e,t);if(R==="reject"){const I=K===void 0?"":` Reason: ${K}`;await u({content:`Tool "${t.name}" was rejected by the user and not run.${I}`,messageKey:f,role:"tool",status:"rejected",stepName:m,toolCallId:t.id,toolName:t.name});return}C="approved"}const M=await s.do(m,()=>Promise.resolve(h.execute(t.input,v)));await u({content:typeof M=="string"?M:j(M),messageKey:f,role:"tool",stepName:m,...C===void 0?{}:{status:C},toolCallId:t.id,toolName:t.name})},yt=(e,t,n)=>{if(!t)return e;let{messages:o}=e;return t.messages!==void 0&&(o=t.messages),t.system!==void 0&&(o=[{content:t.system,role:"system"},...o]),{activeTools:t.activeTools??e.activeTools,messages:o,model:t.model===void 0?e.model:Q(t.model,n),toolChoice:t.toolChoice??e.toolChoice}},vt=(e,t)=>{if(t===void 0||e.length<=t.maxMessages)return;const n=Math.max(1,t.keepRecent??Math.ceil(t.maxMessages/2));if(e.length<=n)return;let o=e.length-n;for(;o>0&&e[o]?.role==="tool";)o-=1;if(!(o<=0))return{older:e.slice(0,o),recent:e.slice(o)}},gt=async(e,t)=>{const{agent:n,compact:o,env:a}=e,r=vt(t,n.compaction);if(r===void 0||o===void 0)return{history:t,summary:void 0};try{const c=await o({env:a,messages:F({history:r.older}),model:n.compaction?.model??n.model});return c.length>0?{history:r.recent,summary:c}:{history:t,summary:void 0}}catch{return{history:t,summary:void 0}}},ht=async(e,t,n)=>{const{agent:o,env:a,generate:r,instructions:c,listMessages:u,memoryContext:i,onTokenDelta:p,run:s,step:d,streamGenerate:l,threadKey:m}=e;return d.do(`llm:turn:${String(t)}`,async()=>{const h=await s(u,{key:m}),{history:f,summary:$}=await gt(e,h);let v={activeTools:o.activeTools,messages:F({history:f,instructions:c,memoryContext:i,summary:$}),model:void 0,toolChoice:o.toolChoice};o.prepareStep&&(v=yt(v,await o.prepareStep({messages:v.messages,stepNumber:t,steps:n}),a));const x={messages:v.messages,...v.activeTools===void 0?{}:{activeTools:v.activeTools},...v.model===void 0?{}:{model:v.model},...v.toolChoice===void 0?{}:{toolChoice:v.toolChoice}};return l&&p?l(x,S=>{p({text:S,threadKey:m,turn:t})}):r(x)})},D=async(e,t)=>{const{agent:n,step:o}=e;n.onStepFinish&&await o.do(`agent:step-finish:${String(t.turn)}`,async()=>(await n.onStepFinish?.(t),!0))},ft=e=>({text:e.text,toolCalls:e.toolCalls.map(t=>({input:t.input,toolCallId:t.id,toolName:t.name})),...e.usage===void 0?{}:{usage:e.usage}}),U=e=>{const t=e?.context;return typeof t=="string"&&t.length>0?t:void 0},wt=e=>J({depth:e?.depth,fanOut:e?.fanOut,maxNodes:e?.maxNodes,maxSeeds:e?.maxSeeds}),Tt=async(e,t,n,o)=>{if(e.source===void 0)return;const a=g(e.source),{topK:r}=e,c=T("memory:retrieve",e.key),u=await n.do(c,async()=>o(a,{query:t,...r===void 0?{}:{topK:r}}));return U(u)},xt=async(e,t,n,o,a,r)=>{if(n===void 0)return;const c=T("memory:traverse",e.key),u=await a.do(c,async()=>r(o,{owner:n,query:t,...wt(e.graph)}));return U(u)},St=async(e,t,n,o,a)=>{if(t===void 0)return;const r=T("memory:recall",e.key),c={owner:t,...e.episodic?.recall===void 0?{}:{limit:e.episodic.recall}},u=await o.do(r,async()=>a(n,c));return U(u)},Ct=async(e,t)=>e.kind==="episodic"?St(e,t.owner,t.episodeRecall,t.step,t.run):e.kind==="graph"?xt(e,t.input,t.owner,t.graphTraverse,t.step,t.run):Tt(e,t.input,t.step,t.run),Mt=e=>{const t=e.findIndex(n=>n.kind==="episodic");return e.filter((n,o)=>n.kind!=="episodic"||o===t)},Rt=async(e,t,n,o,a,r)=>{const c=Mt(Y(e));if(c.length===0)return;const u=g(o.graphTraverse),i=g(o.episodeRecall),p=[];for(const s of c){const d=await Ct(s,{episodeRecall:i,graphTraverse:u,input:t,owner:n,run:r,step:a});d!==void 0&&p.push(d)}return p.length>0?p.join(`
2
+
3
+ `):void 0},kt=async e=>{const{agent:t,env:n,extractGraph:o,finalText:a,input:r,instanceId:c,owner:u,paths:i,run:p,step:s}=e;if(o===void 0||u===void 0||a===void 0||a.length===0)return;const d=Z(t);if(d!==void 0)try{const l={assistantText:a,env:n,model:d.graph?.extractionModel??t.model,userInput:r},m=await s.do(T("memory:extract",d.key),async()=>o(l));await p(g(i.graphUpsert),{...m,messageKey:`${c}:${T("extract",d.key)}`,owner:u})}catch{}},$t=async e=>{const{agent:t,env:n,extractEpisode:o,finalText:a,input:r,instanceId:c,owner:u,paths:i,run:p,step:s,threadKey:d}=e;if(o===void 0||u===void 0||a===void 0||a.length===0)return;const l=tt(t);if(l!==void 0)try{const m={assistantText:a,env:n,model:l.episodic?.extractionModel??t.model,userInput:r},{summary:h}=await s.do(T("memory:episode",l.key),async()=>o(m));await p(g(i.episodeUpsert),{messageKey:`${c}:${T("episode",l.key)}`,owner:u,summary:h,threadKey:d})}catch{}},Kt=async(e,t,n)=>{const o=e[q(t)];if(!(!o||typeof o.get!="function"))try{await(await o.get(n)).terminate()}catch{}},Et="12 hours",Nt=async(e,t,n)=>{await e.waitForEvent(`dequeue:${n}`,{timeout:Et,type:`agent-dequeue:${t}:${n}`})},It=async(e,t,n)=>{const o=e.env[q(e.exportName)];if(!o||typeof o.get!="function")return;const a=o.get.bind(o);try{await e.step.do(`dequeue-wake:${n}`,async()=>(await(await a(n)).sendEvent({payload:{threadKey:t},type:`agent-dequeue:${t}:${n}`}),n))}catch{}},At=async(e,t,n)=>{const{onReply:o}=e,{replyRef:a}=t.params;if(!(o===void 0||a===void 0))try{await t.step.do("agent:reply",async()=>(await o({env:t.env,replyRef:a,result:n,threadKey:t.params.threadKey}),a.channel))}catch{}},Ut=async(e,t,n,o,a)=>{const{instanceId:r,persist:c}=e,u=n.usage===void 0?{}:{usage:n.usage};if(n.toolCalls.length===0){const i=n.output!==void 0&&n.text.length===0?j(n.output):n.text;return await c({content:i,messageKey:`${r}:assistant:${String(t)}`,role:"assistant"}),await D(e,{text:n.text,toolCalls:[],turn:t,...u}),{final:{stopped:"final",text:n.text,turns:t+1,...n.output===void 0?{}:{output:n.output}}}}await c({content:n.text,messageKey:`${r}:assistant:${String(t)}`,role:"assistant",toolCalls:n.toolCalls});for(const i of n.toolCalls)await mt(e,i);if(await D(e,{text:n.text,toolCalls:n.toolCalls,turn:t,...u}),o.push(ft(n)),a.length>0&&await at(a,o))return"stopCondition"},_t=async(e,t,n,o)=>{const a=[];let r,c=!1,u=0;for(let i=0;i<t;i+=1){const p=await ht(e,i,a);o.value=st(o.value,p.usage),u=i+1;const s=await Ut(e,i,p,a,n);if(s==="stopCondition"){c=!0;break}if(s!==void 0){r=s.final;break}}return{final:r,stoppedByCondition:c,turnsRun:u}},Bt=async e=>{const{agent:t,compact:n,env:o,exportName:a,extractEpisode:r,extractGraph:c,generate:u,instanceId:i,onTokenDelta:p,params:s,paths:d,run:l,step:m,streamGenerate:h}=e,f=t.maxTurns??et,$=nt(t.stopWhen),v=g(d.appendMessage),x=g(d.completeRun),S=g(d.ensureThread),C=g(d.listMessages),M=g(d.deleteMessage),R=g(d.patchThread),K=g(d.setState),I=g(d.state),_=async y=>{await l(v,{threadKey:s.threadKey,...y})},B=async y=>{await l(R,{key:s.threadKey,...y})},G=async y=>{await l(M,{messageKey:y,threadKey:s.threadKey})},b=async()=>{await _({content:s.input,messageKey:`${i}:user`,role:"user"})},E=async y=>{const N=await l(x,{instanceId:i,key:s.threadKey,...y});N?.dequeued!==void 0&&await It({env:o,exportName:a,step:m},s.threadKey,N.dequeued)},L=async()=>await l(I,{key:s.threadKey}),W=async y=>{await l(K,{key:s.threadKey,state:y})},A=await l(S,{agent:a,instanceId:i,key:s.threadKey,...t.initialState===void 0?{}:{initialState:t.initialState},...t.onConcurrentRun===void 0?{}:{onConcurrentRun:t.onConcurrentRun},...s.owner===void 0?{}:{owner:s.owner},...s.title===void 0?{}:{title:s.title}});A?.outcome==="replaced"&&await Kt(o,a,A.priorInstanceId);const z=await Rt(t,s.input,s.owner,d,m,l),H=typeof t.instructions=="function"?t.instructions({env:o,input:s.input,threadKey:s.threadKey}):t.instructions,V={agent:t,compact:n,depth:ot(s.depth),env:o,generate:u,getState:L,instanceId:i,instructions:H,listMessages:C,memoryContext:z,onTokenDelta:p,deleteMessage:G,patchThread:B,persist:_,run:l,setState:W,step:m,streamGenerate:h,threadKey:s.threadKey,tools:t.tools??{}},k={value:void 0};try{A?.outcome==="queued"&&await Nt(m,s.threadKey,i),await b();const{final:y,stoppedByCondition:N,turnsRun:X}=await _t(V,f,$,k),w=k.value===void 0?{}:{usage:k.value};return await kt({agent:t,env:o,extractGraph:c,finalText:y?.text,input:s.input,instanceId:i,owner:s.owner,paths:d,run:l,step:m}),await $t({agent:t,env:o,extractEpisode:r,finalText:y?.text,input:s.input,instanceId:i,owner:s.owner,paths:d,run:l,step:m,threadKey:s.threadKey}),y?(await At(t,{env:o,params:s,step:m},{...y,...w}),await E({status:"idle",...w}),{...y,...w}):N?(await E({status:"idle",...w}),{stopped:"stopCondition",turns:X,...w}):(await E({error:`agent stopped: maxTurns (${String(f)}) reached`,status:"error",...w}),{stopped:"maxTurns",turns:f,...w})}catch(y){throw await E({error:y instanceof Error?y.message:String(y),status:"error",...k.value===void 0?{}:{usage:k.value}}),y}};export{gt as compactHistory,Bt as runAgentLoop,vt as splitForCompaction};
@@ -0,0 +1 @@
1
+ import"./base64-5eyBfWO3.mjs";import{p as s,c as p,f as m,e as n,r as c,t as d}from"./voice-turn-DhxJgQW1.mjs";import"./runAgentLoop-oAmn3OyN.mjs";import"./buildModelMessages-Y4tGo1T9.mjs";import"./AGENT_MODULE-M4D1EejI.mjs";export{s as parseIdentity,p as pcmToWav,m as readSynthesisAudio,n as readTranscriptionText,c as runVoiceTurn,d as toByteIterable};
@@ -55,6 +55,13 @@ interface AgentStepLike {
55
55
  * @experimental
56
56
  */
57
57
  interface AgentToolContext {
58
+ /**
59
+ * How many sub-agent delegations deep this run already is — 0 for a run a
60
+ * user started, one more per `agent.asTool` hop. The loop copies it off
61
+ * {@link AgentRunInput.depth}; `agent.asTool` reads it to refuse spawning a
62
+ * child past the delegation-depth bound (see `as-tool.ts`). Absent is 0.
63
+ */
64
+ depth?: number;
58
65
  /** The Worker environment bindings. */
59
66
  env: Record<string, unknown>;
60
67
  /**
@@ -806,8 +813,20 @@ interface AgentVoiceConfig {
806
813
  /**
807
814
  * Spoken on connect before the first user turn — a fixed greeting synthesized
808
815
  * through the TTS model. Omit for a silent-until-spoken-to session.
816
+ *
817
+ * Synthesized once per THREAD, not once per socket: the greeting's persisted
818
+ * row is keyed per thread, and a reconnect onto a thread that already exists
819
+ * gets the `ready` frame without paying for the same line again.
809
820
  */
810
821
  greeting?: string;
822
+ /**
823
+ * Cap on how many turns one voice socket may run before it is closed with
824
+ * code `4002`. Every turn is a full LLM generation plus sentence-by-sentence
825
+ * TTS — billed and persisted — on a hibernatable socket that can live for
826
+ * days, and the one-turn-in-flight guard throttles nothing. Defaults to 100;
827
+ * a client that hits the cap reconnects for a fresh budget.
828
+ */
829
+ maxTurns?: number;
811
830
  /**
812
831
  * TTS voice/speaker id forwarded to the TTS model (e.g. a Deepgram Aura voice
813
832
  * like `"aura-asteria-en"`). Model-specific; omitted when unset so the model
@@ -842,7 +861,7 @@ interface AgentSubToolInput {
842
861
  interface AgentAsToolOptions {
843
862
  /** What the sub-agent does — shown to the parent's model (it decides from it). */
844
863
  description: string;
845
- /** Cap on child-run status polls before giving up. Default 120. */
864
+ /** Cap on child-run status polls before giving up — a positive integer. Default 120. */
846
865
  maxPolls?: number;
847
866
  /**
848
867
  * The child agent's export name — selects its `AGENT_<NAME>` Workflow
@@ -907,6 +926,14 @@ type EnsureThreadOutcome = {
907
926
  * @experimental
908
927
  */
909
928
  interface AgentRunInput {
929
+ /**
930
+ * Sub-agent delegation depth. A run a user starts omits it (0); each
931
+ * `agent.asTool` hop stamps its child one deeper, and the tool refuses to
932
+ * delegate past the bound — `maxTurns` bounds one level's turns, this bounds
933
+ * the TREE (every hop mints a distinct child `threadKey`, so the per-thread
934
+ * run-queue cap never applies across them).
935
+ */
936
+ depth?: number;
910
937
  /** The user message that starts (or continues) the thread. */
911
938
  input: string;
912
939
  /**
@@ -55,6 +55,13 @@ interface AgentStepLike {
55
55
  * @experimental
56
56
  */
57
57
  interface AgentToolContext {
58
+ /**
59
+ * How many sub-agent delegations deep this run already is — 0 for a run a
60
+ * user started, one more per `agent.asTool` hop. The loop copies it off
61
+ * {@link AgentRunInput.depth}; `agent.asTool` reads it to refuse spawning a
62
+ * child past the delegation-depth bound (see `as-tool.ts`). Absent is 0.
63
+ */
64
+ depth?: number;
58
65
  /** The Worker environment bindings. */
59
66
  env: Record<string, unknown>;
60
67
  /**
@@ -806,8 +813,20 @@ interface AgentVoiceConfig {
806
813
  /**
807
814
  * Spoken on connect before the first user turn — a fixed greeting synthesized
808
815
  * through the TTS model. Omit for a silent-until-spoken-to session.
816
+ *
817
+ * Synthesized once per THREAD, not once per socket: the greeting's persisted
818
+ * row is keyed per thread, and a reconnect onto a thread that already exists
819
+ * gets the `ready` frame without paying for the same line again.
809
820
  */
810
821
  greeting?: string;
822
+ /**
823
+ * Cap on how many turns one voice socket may run before it is closed with
824
+ * code `4002`. Every turn is a full LLM generation plus sentence-by-sentence
825
+ * TTS — billed and persisted — on a hibernatable socket that can live for
826
+ * days, and the one-turn-in-flight guard throttles nothing. Defaults to 100;
827
+ * a client that hits the cap reconnects for a fresh budget.
828
+ */
829
+ maxTurns?: number;
811
830
  /**
812
831
  * TTS voice/speaker id forwarded to the TTS model (e.g. a Deepgram Aura voice
813
832
  * like `"aura-asteria-en"`). Model-specific; omitted when unset so the model
@@ -842,7 +861,7 @@ interface AgentSubToolInput {
842
861
  interface AgentAsToolOptions {
843
862
  /** What the sub-agent does — shown to the parent's model (it decides from it). */
844
863
  description: string;
845
- /** Cap on child-run status polls before giving up. Default 120. */
864
+ /** Cap on child-run status polls before giving up — a positive integer. Default 120. */
846
865
  maxPolls?: number;
847
866
  /**
848
867
  * The child agent's export name — selects its `AGENT_<NAME>` Workflow
@@ -907,6 +926,14 @@ type EnsureThreadOutcome = {
907
926
  * @experimental
908
927
  */
909
928
  interface AgentRunInput {
929
+ /**
930
+ * Sub-agent delegation depth. A run a user starts omits it (0); each
931
+ * `agent.asTool` hop stamps its child one deeper, and the tool refuses to
932
+ * delegate past the bound — `maxTurns` bounds one level's turns, this bounds
933
+ * the TREE (every hop mints a distinct child `threadKey`, so the per-thread
934
+ * run-queue cap never applies across them).
935
+ */
936
+ depth?: number;
910
937
  /** The user message that starts (or continues) the thread. */
911
938
  input: string;
912
939
  /**
@@ -0,0 +1 @@
1
+ import{f as P,a as q}from"./base64-5eyBfWO3.mjs";import{compactHistory as z}from"./runAgentLoop-oAmn3OyN.mjs";import{buildModelMessages as G}from"./buildModelMessages-Y4tGo1T9.mjs";import{toFunctionReference as T}from"./AGENT_MODULE-M4D1EejI.mjs";const D=new TextDecoder;new TextEncoder;const N="=",Q=t=>{if(t)try{const e=t[0]==="{"?t:D.decode(P(t)),n=JSON.parse(e);if(n&&typeof n=="object"&&!Array.isArray(n))return n}catch{}},ct=t=>{if(t){if(!t.startsWith(N))return t;try{return D.decode(P(t.slice(N.length)))}catch{return}}},dt=t=>{const e=Number(t);return Number.isFinite(e)&&e>0?e:void 0},ut=t=>typeof t=="number"&&Date.now()>=t,ft=t=>{try{t.send(JSON.stringify({code:"TOKEN_EXPIRED",error:{code:"TOKEN_EXPIRED",message:"authentication token expired"},type:"error"})),t.close?.(4001,"token_expired")}catch{}},Y=16e3,Z=1,tt=16,M=/[.!?]\s/u,et=/\s/u,nt=async function*(t){if(t instanceof Uint8Array){yield t;return}if(t instanceof ReadableStream){const e=t.getReader();try{for(;;){const{done:n,value:r}=await e.read();if(n)break;yield r}}finally{e.releaseLock()}return}yield*t},yt=(t,e=Y,n=Z,r=tt)=>{const i=n*r/8,p=e*i,m=new ArrayBuffer(44+t.byteLength),s=new DataView(m),u=(l,E)=>{for(let d=0;d<E.length;d+=1)s.setUint8(l+d,E.codePointAt(d)??0)};u(0,"RIFF"),s.setUint32(4,36+t.byteLength,!0),u(8,"WAVE"),u(12,"fmt "),s.setUint32(16,16,!0),s.setUint16(20,1,!0),s.setUint16(22,n,!0),s.setUint32(24,e,!0),s.setUint32(28,p,!0),s.setUint16(32,i,!0),s.setUint16(34,r,!0),u(36,"data"),s.setUint32(40,t.byteLength,!0);const a=new Uint8Array(m);return a.set(t,44),a},st=t=>{const e=[];let n=t,r=M.exec(n);for(;r;){let i=r.index+1;for(;i<n.length&&et.test(n[i]??"");)i+=1;const p=n.slice(0,i).trim();p.length>0&&e.push(p),n=n.slice(i),r=M.exec(n)}return{rest:n,sentences:e}},pt=async t=>{const{agent:e,compact:n,connectionId:r,env:i,exportName:p,owner:m,paths:s,pcm:u,run:a,send:l,sendAudio:E,signal:d,streamGenerate:C,synthesize:H,text:L,threadKey:o,transcribe:F,turn:U,waitForDrain:O}=t,h=()=>d.aborted,v=T(s.appendMessage),$=T(s.ensureThread),B=T(s.listMessages),b=T(s.patchThread);await a($,{agent:p,key:o,...e.initialState===void 0?{}:{initialState:e.initialState},...m===void 0?{}:{owner:m}});try{const f=(L??(u?await F(u):"")).trim();if(f.length===0)return await a(b,{key:o,status:"idle"}),{assistantText:"",interrupted:!1,userText:""};l({text:f,type:"user_transcript"}),await a(v,{content:f,messageKey:`voice:${r}:${String(U)}:user`,role:"user",threadKey:o}),await a(b,{key:o,status:"running"});const I=typeof e.instructions=="function"?e.instructions({env:i,input:f,threadKey:o}):e.instructions,K=await a(B,{key:o}),{history:j,summary:R}=await z({agent:e,compact:n,env:i},K),W=G({history:j,...I===void 0?{}:{instructions:I},...R===void 0?{}:{summary:R}});let g="",w="",S=Promise.resolve();const V=async c=>{if(h()||c.length===0)return;let x=!1;try{for await(const y of nt(await H(c,d))){if(h()||(await O?.(),h()))break;E(y),x=!0}}catch(y){l({message:y instanceof Error?y.message:String(y),type:"error"})}x&&(w=w.length>0?`${w} ${c}`:c)},_=c=>{S=S.then(async()=>V(c))},X=await C({messages:W,signal:d},c=>{if(h())return;l({text:c,type:"assistant_delta"}),g+=c;const{rest:x,sentences:y}=st(g);g=x;for(const J of y)_(J)});!h()&&g.trim().length>0&&_(g.trim()),g="",await S;const A=h(),k=A?w:X.text;return await a(v,{content:k,messageKey:`voice:${r}:${String(U)}:assistant`,role:"assistant",threadKey:o}),await a(b,{key:o,status:"idle"}),l(A?{type:"interrupted"}:{text:k,type:"assistant_done"}),{assistantText:k,interrupted:A,userText:f}}catch(f){throw await a(b,{key:o,status:"idle"}),f}},lt=t=>Q(t),ht=t=>{if(typeof t=="object"&&t!==null&&"text"in t){const{text:e}=t;return typeof e=="string"?e:""}return""},gt=t=>{if(t instanceof Uint8Array||t instanceof ReadableStream)return t;if(t instanceof Response&&t.body)return t.body;if(typeof t=="object"&&t!==null&&"audio"in t){const{audio:e}=t;if(typeof e=="string")return q(e);if(e instanceof ReadableStream||e instanceof Uint8Array)return e}return new Uint8Array(0)};export{dt as a,ft as b,yt as c,ct as d,ht as e,gt as f,ut as i,lt as p,pt as r,nt as t};
package/dist/reply.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Mailer } from '@lunora/mail';
2
2
  import { InboundEmail } from '@lunora/mail/inbound';
3
- import { a as AgentReplyRef } from "./packem_shared/types.d-eCuvcLzf.mjs";
3
+ import { a as AgentReplyRef } from "./packem_shared/types.d-DTKxPuh_.mjs";
4
4
  import 'ai';
5
5
  /** The email arm of {@link AgentReplyRef}, narrowed for the helpers below. */
6
6
  type EmailReplyRef = Extract<AgentReplyRef, {
package/dist/reply.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Mailer } from '@lunora/mail';
2
2
  import { InboundEmail } from '@lunora/mail/inbound';
3
- import { a as AgentReplyRef } from "./packem_shared/types.d-eCuvcLzf.js";
3
+ import { a as AgentReplyRef } from "./packem_shared/types.d-DTKxPuh_.js";
4
4
  import 'ai';
5
5
  /** The email arm of {@link AgentReplyRef}, narrowed for the helpers below. */
6
6
  type EmailReplyRef = Extract<AgentReplyRef, {
@@ -1,4 +1,4 @@
1
- import { b as AgentToolContext, c as AgentToolDefinition } from "./packem_shared/types.d-eCuvcLzf.mjs";
1
+ import { b as AgentToolContext, c as AgentToolDefinition } from "./packem_shared/types.d-DTKxPuh_.mjs";
2
2
  import '@lunora/mail/inbound';
3
3
  import 'ai';
4
4
  /**
package/dist/sandbox.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { b as AgentToolContext, c as AgentToolDefinition } from "./packem_shared/types.d-eCuvcLzf.js";
1
+ import { b as AgentToolContext, c as AgentToolDefinition } from "./packem_shared/types.d-DTKxPuh_.js";
2
2
  import '@lunora/mail/inbound';
3
3
  import 'ai';
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as SkillMarkdownExtras, d as SkillDefinition } from "./packem_shared/types.d-eCuvcLzf.mjs";
1
+ import { S as SkillMarkdownExtras, d as SkillDefinition } from "./packem_shared/types.d-DTKxPuh_.mjs";
2
2
  import '@lunora/mail/inbound';
3
3
  import 'ai';
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as SkillMarkdownExtras, d as SkillDefinition } from "./packem_shared/types.d-eCuvcLzf.js";
1
+ import { S as SkillMarkdownExtras, d as SkillDefinition } from "./packem_shared/types.d-DTKxPuh_.js";
2
2
  import '@lunora/mail/inbound';
3
3
  import 'ai';
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/agent",
3
- "version": "1.0.0-alpha.80",
3
+ "version": "1.0.0-alpha.81",
4
4
  "description": "Durable AI agents for Lunora: defineAgent compiles a replay-safe tool-loop onto Cloudflare Workflows, with DO SQLite threads and live message subscriptions",
5
5
  "keywords": [
6
6
  "agent",
@@ -84,12 +84,12 @@
84
84
  "access": "public"
85
85
  },
86
86
  "dependencies": {
87
- "@lunora/ai": "1.0.0-alpha.68",
88
- "@lunora/errors": "1.0.0-alpha.28",
89
- "@lunora/mail": "1.0.0-alpha.58",
90
- "@lunora/server": "1.0.0-alpha.98",
91
- "@lunora/values": "1.0.0-alpha.36",
92
- "@lunora/workflow": "1.0.0-alpha.41",
87
+ "@lunora/ai": "1.0.0-alpha.69",
88
+ "@lunora/errors": "1.0.0-alpha.29",
89
+ "@lunora/mail": "1.0.0-alpha.59",
90
+ "@lunora/server": "1.0.0-alpha.99",
91
+ "@lunora/values": "1.0.0-alpha.37",
92
+ "@lunora/workflow": "1.0.0-alpha.42",
93
93
  "@modelcontextprotocol/sdk": "^1.30.0",
94
94
  "ai": "7.0.59",
95
95
  "yaml": "^2.9.0"
@@ -1 +0,0 @@
1
- import{createAi as g}from"@lunora/ai";import{F as b}from"./createDispatchRunner-pLyQ70FK-2_j6ocGT.mjs";import{t as m}from"./base64-5eyBfWO3.mjs";import{p as A,d as S,a as v,i as l,b as f,c as w,e as k,f as x,r as T,t as E}from"./voice-turn-DbVR0H6T.mjs";import{createStreamGenerate as M}from"./createAgentGenerate-9bZ2YhpN.mjs";import{DEFAULT_AGENT_FUNCTION_PATHS as B,toFunctionReference as p}from"./AGENT_MODULE-M4D1EejI.mjs";const _="@cf/openai/whisper-large-v3-turbo",I="@cf/deepgram/aura-1",U=8*1024*1024,F=256*1024,y=15,D=5e3;class O{agent;ai;env;exportName;paths;streamGenerate;sttModel;ttsModel;audioBuffers=new Map;bufferedBytes=new Map;controllers=new Map;state;constructor(t,e,s,r){this.state=t,this.env=e,this.agent=s,this.exportName=r,this.paths=B,this.ai=g({binding:e.AI,env:e}),this.streamGenerate=M(s,e),this.sttModel=s.voice?.stt??_,this.ttsModel=s.voice?.tts??I}fetch(t){if(t.headers.get("Upgrade")!=="websocket")return new Response("Expected a WebSocket upgrade",{status:426});const s=new URL(t.url).searchParams.get("threadKey");if(!s)return new Response("Missing threadKey",{status:400});const r=globalThis.WebSocketPair,i=new r,n=i[0],o=i[1];this.state.acceptWebSocket(o);const c=crypto.randomUUID(),d=A(t.headers.get("x-lunora-identity")),a=S(t.headers.get("x-lunora-userid")),h=v(t.headers.get("x-lunora-identity-exp"));if(l(h))return f(o),new Response(null,{status:101,webSocket:n});o.serializeAttachment?.({connectionId:c,threadKey:s,turn:0,...h===void 0?{}:{expiresAt:h},...d===void 0?{}:{identity:d},...a===void 0?{}:{userId:a}}),this.send(o,{audioFormat:this.agent.voice?.audioFormat??"mp3",type:"ready"});const u=this.agent.voice?.greeting;return u&&u.length>0&&this.state.waitUntil?.(this.speakGreeting(o,c,s,a,d,u)),new Response(null,{status:101,webSocket:n})}async webSocketMessage(t,e){const s=t.deserializeAttachment?.();if(s){if(l(s.expiresAt)){f(t);return}try{if(typeof e=="string"){await this.handleControl(t,s,e);return}this.bufferAudio(s.connectionId,new Uint8Array(e),t)}catch(r){this.send(t,{message:r instanceof Error?r.message:String(r),type:"error"})}}}webSocketClose(t){this.cleanupSocket(t)}webSocketError(t){this.cleanupSocket(t)}resolveRun(t,e){const s=t===void 0&&e===void 0?void 0:{...e===void 0?{}:{claims:e},...t===void 0?{}:{userId:t}};return b({env:this.env,label:"@lunora/agent voice",...s===void 0?{}:{identity:s}})}async transcribe(t){const e=w(t);return k(await this.ai.run(this.sttModel,{audio:m(e)}))}async synthesize(t,e){const s=this.agent.voice?.speaker;return x(await this.ai.run(this.ttsModel,{text:t,...s===void 0?{}:{speaker:s}},e===void 0?void 0:{signal:e}))}async handleControl(t,e,s){let r;try{r=JSON.parse(s)}catch{return}if(r.type==="interrupt"){this.controllers.get(e.connectionId)?.abort();return}if(this.controllers.has(e.connectionId)){this.send(t,{message:"a turn is already in progress — send an interrupt before the next utterance",type:"error"});return}if(r.type==="commit"){const i=this.drainAudio(e.connectionId);await this.runTurn(t,e,{pcm:i});return}await this.runTurn(t,e,{text:r.text})}bufferAudio(t,e,s){const r=(this.bufferedBytes.get(t)??0)+e.byteLength;if(r>U){this.audioBuffers.delete(t),this.bufferedBytes.delete(t),this.send(s,{message:"utterance exceeded the maximum buffer — send a commit sooner",type:"error"});return}const i=this.audioBuffers.get(t)??[];i.push(e),this.audioBuffers.set(t,i),this.bufferedBytes.set(t,r)}drainAudio(t){const e=this.audioBuffers.get(t)??[];this.audioBuffers.delete(t),this.bufferedBytes.delete(t);const s=e.reduce((n,o)=>n+o.byteLength,0),r=new Uint8Array(s);let i=0;for(const n of e)r.set(n,i),i+=n.byteLength;return r}async runTurn(t,e,s){const r=new AbortController;this.controllers.set(e.connectionId,r);try{await T({agent:this.agent,connectionId:e.connectionId,env:this.env,exportName:this.exportName,paths:this.paths,run:this.resolveRun(e.userId,e.identity),send:i=>{this.send(t,i)},sendAudio:i=>{this.sendAudio(t,i)},signal:r.signal,streamGenerate:this.streamGenerate,synthesize:async(i,n)=>this.synthesizeWithSignal(i,n),threadKey:e.threadKey,transcribe:async i=>this.transcribe(i),turn:e.turn,waitForDrain:async()=>this.waitForSocketDrain(t),...e.userId===void 0?{}:{owner:e.userId},...s.pcm===void 0?{}:{pcm:s.pcm},...s.text===void 0?{}:{text:s.text}})}finally{this.controllers.get(e.connectionId)===r&&this.controllers.delete(e.connectionId),t.serializeAttachment?.({...e,turn:e.turn+1})}}async speakGreeting(t,e,s,r,i,n){const o=this.resolveRun(r,i),c=new AbortController,d=()=>c.signal.aborted;this.controllers.set(e,c);try{await o(p(this.paths.ensureThread),{agent:this.exportName,key:s,...this.agent.initialState===void 0?{}:{initialState:this.agent.initialState},...r===void 0?{}:{owner:r}});for await(const a of E(await this.synthesizeWithSignal(n,c.signal))){if(d()||(await this.waitForSocketDrain(t),d()))break;this.sendAudio(t,a)}d()||(await o(p(this.paths.appendMessage),{content:n,messageKey:"voice:greeting:assistant",role:"assistant",threadKey:s}),this.send(t,{text:n,type:"assistant_done"}))}catch(a){this.send(t,{message:a instanceof Error?a.message:String(a),type:"error"})}finally{this.controllers.get(e)===c&&this.controllers.delete(e)}}async synthesizeWithSignal(t,e){return e.aborted?new Uint8Array(0):this.synthesize(t,e)}cleanupSocket(t){const e=t.deserializeAttachment?.();e&&(this.controllers.get(e.connectionId)?.abort(),this.controllers.delete(e.connectionId),this.audioBuffers.delete(e.connectionId),this.bufferedBytes.delete(e.connectionId))}send(t,e){try{t.send(JSON.stringify(e))}catch{}}sendAudio(t,e){try{t.send(e)}catch{}}async waitForSocketDrain(t){const e=t;let s=0;for(;typeof e.bufferedAmount=="number"&&e.bufferedAmount>F&&s<D;)await new Promise(r=>{setTimeout(r,y)}),s+=y}}export{O as default};
@@ -1 +0,0 @@
1
- import{LunoraError as d}from"@lunora/errors";import{jsonSchema as y}from"ai";import{isDuplicateInstanceError as A}from"../channels.mjs";import{agentBindingName as L}from"../naming.mjs";import{toFunctionReference as N,DEFAULT_AGENT_FUNCTION_PATHS as b}from"./AGENT_MODULE-M4D1EejI.mjs";const E=new Set(["complete","errored","terminated"]),I=120,S=500,$=t=>t!==null&&typeof t=="object"&&typeof t.status=="string"?t.status:"unknown",_=async t=>{await new Promise(e=>{setTimeout(e,t)})},M=async(t,e,n,c)=>{for(let a=0;a<e;a+=1){const i=$(await t.status());if(E.has(i))return i;await c(n)}return"timeout"},P=t=>{for(let e=t.length-1;e>=0;e-=1){const n=t[e];if(n?.role==="assistant"&&(n.toolCalls===void 0||n.toolCalls.length===0))return n.content}return""},k=t=>{if(typeof t.name!="string"||t.name.length===0)throw new d("INTERNAL","@lunora/agent: agent.asTool requires a `name` (the child agent's export name, selecting its AGENT_* binding)");if(typeof t.description!="string"||t.description.length===0)throw new d("INTERNAL","@lunora/agent: agent.asTool requires a non-empty `description` (the parent model decides from it)");const{name:e}=t,n=L(e),c=t.maxPolls??I,a=t.pollIntervalMs??S,i=t.wait??_,p=N(b.listMessages),f=async(h,r)=>{const o=r.env[n];if(!o||typeof o.create!="function"||typeof o.get!="function")throw new d("INTERNAL",`@lunora/agent: agent.asTool("${e}") found no Workflow binding "${n}" on env — declare the "${e}" agent so codegen wires its binding`);const m=`${r.threadKey}::sub::${e}::${r.toolCallId}`,g=`sub-${e}-${r.toolCallId}`,w={input:h.prompt,threadKey:m};let u;try{const l=await o.create({id:g,params:w});u=await o.get(l.id)}catch(l){if(!A(l))throw l;u=await o.get(g)}const s=await M(u,c,a,i);if(s==="errored"||s==="terminated")return`Sub-agent "${e}" ${s} before producing an answer.`;if(s==="timeout")return`Sub-agent "${e}" did not finish within the allotted time.`;const T=await r.run(p,{key:m});return P(T)};return{description:t.description,execute:f,inputSchema:y({properties:{prompt:{description:"The task or question to delegate to the sub-agent.",type:"string"}},required:["prompt"],type:"object"}),isLunoraAgentTool:!0}};export{k as agentAsTool};
@@ -1,3 +0,0 @@
1
- import{d as J,b as _}from"./component-shared-IZozysYq.mjs";import{resolveAgentModel as Q}from"./createAgentGenerate-9bZ2YhpN.mjs";import{r as Y,f as Z,m as T,a as tt}from"./memory-JI0lUu84.mjs";import{buildModelMessages as D}from"./buildModelMessages-Y4tGo1T9.mjs";import{agentBindingName as F}from"../naming.mjs";import{toFunctionReference as g}from"./AGENT_MODULE-M4D1EejI.mjs";const et=8,q=e=>e===void 0?"null":JSON.stringify(e),ot=e=>e===void 0?[]:[e].flat(),nt=async(e,t)=>(await Promise.all(e.map(async o=>o({steps:t})))).some(Boolean),at=(e,t)=>{if(t===void 0)return e;if(e===void 0)return{...t};const n={};for(const o of["inputTokens","outputTokens","totalTokens"])(e[o]!==void 0||t[o]!==void 0)&&(n[o]=(e[o]??0)+(t[o]??0));return n},st=async(e,t,n,o,a)=>{const{needsApproval:r}=e;return r===void 0||r===!1?!1:r===!0?!0:n.do(o,async()=>r(t,a))},rt="WorkflowTimeoutError",it=e=>e instanceof Error&&e.name===rt,O=4320*60*1e3,ct={day:864e5,hour:36e5,minute:6e4,month:30*864e5,second:1e3,week:7*864e5,year:365*864e5},ut=/^(\d+(?:\.\d+)?) (day|hour|minute|month|second|week|year)s?$/u,dt=e=>{if(e===void 0)return O;if(typeof e=="number")return Math.min(e,_);const t=ut.exec(e);return t===null?O:Math.min(Number(t[1])*ct[t[2]],_)},pt=async(e,t)=>{const{agent:n,deleteMessage:o,instanceId:a,patchThread:r,persist:i,step:u}=e;await i({content:`Awaiting approval to run tool "${t.name}".`,messageKey:`${a}:approval:${t.id}`,role:"tool",status:"awaiting_approval",toolCallId:t.id,toolName:t.name}),await r({status:"awaiting_input"});const c=await u.waitForEvent(`approval:${t.id}`,{timeout:dt(n.approvalTimeout),type:`agent-approval:${t.id}`}).then(p=>({decision:p.payload.decision,...p.payload.note===void 0?{}:{note:p.payload.note}})).catch(p=>{if(!it(p))throw p;return{decision:"reject",note:"approval timed out"}});return await o(`${a}:approval:${t.id}`),await r({status:"running"}),c},lt=async(e,t)=>{const{env:n,getState:o,instanceId:a,onTokenDelta:r,persist:i,run:u,setState:c,step:p,threadKey:s,tools:l}=e,d=`tool:${t.name}:${t.id}`,y=l[t.name],h=`${a}:tool:${t.id}`;if(!y){await i({content:`Error: unknown tool "${t.name}"`,messageKey:h,role:"tool",stepName:d,toolCallId:t.id,toolName:t.name});return}const C={env:n,getState:o,idempotencyKey:d,reportProgress:R=>{r?.({data:R,kind:"progress",threadKey:s,toolCallId:t.id})},run:u,setState:c,step:p,threadKey:s,toolCallId:t.id},v={env:n,getState:o,idempotencyKey:d,run:u,threadKey:s,toolCallId:t.id},S=`tool:approval-gate:${t.id}`;let f;if(await st(y,t.input,p,S,v)){const{decision:R,note:$}=await pt(e,t);if(R==="reject"){const N=$===void 0?"":` Reason: ${$}`;await i({content:`Tool "${t.name}" was rejected by the user and not run.${N}`,messageKey:h,role:"tool",status:"rejected",stepName:d,toolCallId:t.id,toolName:t.name});return}f="approved"}const M=await p.do(d,()=>Promise.resolve(y.execute(t.input,C)));await i({content:typeof M=="string"?M:q(M),messageKey:h,role:"tool",stepName:d,...f===void 0?{}:{status:f},toolCallId:t.id,toolName:t.name})},mt=(e,t,n)=>{if(!t)return e;let{messages:o}=e;return t.messages!==void 0&&(o=t.messages),t.system!==void 0&&(o=[{content:t.system,role:"system"},...o]),{activeTools:t.activeTools??e.activeTools,messages:o,model:t.model===void 0?e.model:Q(t.model,n),toolChoice:t.toolChoice??e.toolChoice}},yt=(e,t)=>{if(t===void 0||e.length<=t.maxMessages)return;const n=Math.max(1,t.keepRecent??Math.ceil(t.maxMessages/2));if(e.length<=n)return;let o=e.length-n;for(;o>0&&e[o]?.role==="tool";)o-=1;if(!(o<=0))return{older:e.slice(0,o),recent:e.slice(o)}},vt=async(e,t)=>{const{agent:n,compact:o,env:a}=e,r=yt(t,n.compaction);if(r===void 0||o===void 0)return{history:t,summary:void 0};try{const i=await o({env:a,messages:D({history:r.older}),model:n.compaction?.model??n.model});return i.length>0?{history:r.recent,summary:i}:{history:t,summary:void 0}}catch{return{history:t,summary:void 0}}},gt=async(e,t,n)=>{const{agent:o,env:a,generate:r,instructions:i,listMessages:u,memoryContext:c,onTokenDelta:p,run:s,step:l,streamGenerate:d,threadKey:y}=e;return l.do(`llm:turn:${String(t)}`,async()=>{const h=await s(u,{key:y}),{history:x,summary:C}=await vt(e,h);let v={activeTools:o.activeTools,messages:D({history:x,instructions:i,memoryContext:c,summary:C}),model:void 0,toolChoice:o.toolChoice};o.prepareStep&&(v=mt(v,await o.prepareStep({messages:v.messages,stepNumber:t,steps:n}),a));const S={messages:v.messages,...v.activeTools===void 0?{}:{activeTools:v.activeTools},...v.model===void 0?{}:{model:v.model},...v.toolChoice===void 0?{}:{toolChoice:v.toolChoice}};return d&&p?d(S,f=>{p({text:f,threadKey:y,turn:t})}):r(S)})},P=async(e,t)=>{const{agent:n,step:o}=e;n.onStepFinish&&await o.do(`agent:step-finish:${String(t.turn)}`,async()=>(await n.onStepFinish?.(t),!0))},ht=e=>({text:e.text,toolCalls:e.toolCalls.map(t=>({input:t.input,toolCallId:t.id,toolName:t.name})),...e.usage===void 0?{}:{usage:e.usage}}),A=e=>{const t=e?.context;return typeof t=="string"&&t.length>0?t:void 0},ft=e=>J({depth:e?.depth,fanOut:e?.fanOut,maxNodes:e?.maxNodes,maxSeeds:e?.maxSeeds}),wt=async(e,t,n,o)=>{if(e.source===void 0)return;const a=g(e.source),{topK:r}=e,i=T("memory:retrieve",e.key),u=await n.do(i,async()=>o(a,{query:t,...r===void 0?{}:{topK:r}}));return A(u)},Tt=async(e,t,n,o,a,r)=>{if(n===void 0)return;const i=T("memory:traverse",e.key),u=await a.do(i,async()=>r(o,{owner:n,query:t,...ft(e.graph)}));return A(u)},xt=async(e,t,n,o,a)=>{if(t===void 0)return;const r=T("memory:recall",e.key),i={owner:t,...e.episodic?.recall===void 0?{}:{limit:e.episodic.recall}},u=await o.do(r,async()=>a(n,i));return A(u)},St=async(e,t)=>e.kind==="episodic"?xt(e,t.owner,t.episodeRecall,t.step,t.run):e.kind==="graph"?Tt(e,t.input,t.owner,t.graphTraverse,t.step,t.run):wt(e,t.input,t.step,t.run),Ct=e=>{const t=e.findIndex(n=>n.kind==="episodic");return e.filter((n,o)=>n.kind!=="episodic"||o===t)},Mt=async(e,t,n,o,a,r)=>{const i=Ct(Y(e));if(i.length===0)return;const u=g(o.graphTraverse),c=g(o.episodeRecall),p=[];for(const s of i){const l=await St(s,{episodeRecall:c,graphTraverse:u,input:t,owner:n,run:r,step:a});l!==void 0&&p.push(l)}return p.length>0?p.join(`
2
-
3
- `):void 0},Rt=async e=>{const{agent:t,env:n,extractGraph:o,finalText:a,input:r,instanceId:i,owner:u,paths:c,run:p,step:s}=e;if(o===void 0||u===void 0||a===void 0||a.length===0)return;const l=Z(t);if(l!==void 0)try{const d={assistantText:a,env:n,model:l.graph?.extractionModel??t.model,userInput:r},y=await s.do(T("memory:extract",l.key),async()=>o(d));await p(g(c.graphUpsert),{...y,messageKey:`${i}:${T("extract",l.key)}`,owner:u})}catch{}},kt=async e=>{const{agent:t,env:n,extractEpisode:o,finalText:a,input:r,instanceId:i,owner:u,paths:c,run:p,step:s,threadKey:l}=e;if(o===void 0||u===void 0||a===void 0||a.length===0)return;const d=tt(t);if(d!==void 0)try{const y={assistantText:a,env:n,model:d.episodic?.extractionModel??t.model,userInput:r},{summary:h}=await s.do(T("memory:episode",d.key),async()=>o(y));await p(g(c.episodeUpsert),{messageKey:`${i}:${T("episode",d.key)}`,owner:u,summary:h,threadKey:l})}catch{}},$t=async(e,t,n)=>{const o=e[F(t)];if(!(!o||typeof o.get!="function"))try{await(await o.get(n)).terminate()}catch{}},Kt="12 hours",Et=async(e,t,n)=>{await e.waitForEvent(`dequeue:${n}`,{timeout:Kt,type:`agent-dequeue:${t}:${n}`})},Nt=async(e,t,n)=>{const o=e.env[F(e.exportName)];if(!o||typeof o.get!="function")return;const a=o.get.bind(o);try{await e.step.do(`dequeue-wake:${n}`,async()=>(await(await a(n)).sendEvent({payload:{threadKey:t},type:`agent-dequeue:${t}:${n}`}),n))}catch{}},It=async(e,t,n)=>{const{onReply:o}=e,{replyRef:a}=t.params;if(!(o===void 0||a===void 0))try{await t.step.do("agent:reply",async()=>(await o({env:t.env,replyRef:a,result:n,threadKey:t.params.threadKey}),a.channel))}catch{}},At=async(e,t,n,o,a)=>{const{instanceId:r,persist:i}=e,u=n.usage===void 0?{}:{usage:n.usage};if(n.toolCalls.length===0){const c=n.output!==void 0&&n.text.length===0?q(n.output):n.text;return await i({content:c,messageKey:`${r}:assistant:${String(t)}`,role:"assistant"}),await P(e,{text:n.text,toolCalls:[],turn:t,...u}),{final:{stopped:"final",text:n.text,turns:t+1,...n.output===void 0?{}:{output:n.output}}}}await i({content:n.text,messageKey:`${r}:assistant:${String(t)}`,role:"assistant",toolCalls:n.toolCalls});for(const c of n.toolCalls)await lt(e,c);if(await P(e,{text:n.text,toolCalls:n.toolCalls,turn:t,...u}),o.push(ht(n)),a.length>0&&await nt(a,o))return"stopCondition"},Ut=async(e,t,n,o)=>{const a=[];let r,i=!1,u=0;for(let c=0;c<t;c+=1){const p=await gt(e,c,a);o.value=at(o.value,p.usage),u=c+1;const s=await At(e,c,p,a,n);if(s==="stopCondition"){i=!0;break}if(s!==void 0){r=s.final;break}}return{final:r,stoppedByCondition:i,turnsRun:u}},jt=async e=>{const{agent:t,compact:n,env:o,exportName:a,extractEpisode:r,extractGraph:i,generate:u,instanceId:c,onTokenDelta:p,params:s,paths:l,run:d,step:y,streamGenerate:h}=e,x=t.maxTurns??et,C=ot(t.stopWhen),v=g(l.appendMessage),S=g(l.completeRun),f=g(l.ensureThread),M=g(l.listMessages),R=g(l.deleteMessage),$=g(l.patchThread),N=g(l.setState),j=g(l.state),U=async m=>{await d(v,{threadKey:s.threadKey,...m})},B=async m=>{await d($,{key:s.threadKey,...m})},G=async m=>{await d(R,{messageKey:m,threadKey:s.threadKey})},L=async()=>{await U({content:s.input,messageKey:`${c}:user`,role:"user"})},K=async m=>{const E=await d(S,{instanceId:c,key:s.threadKey,...m});E?.dequeued!==void 0&&await Nt({env:o,exportName:a,step:y},s.threadKey,E.dequeued)},b=async()=>await d(j,{key:s.threadKey}),W=async m=>{await d(N,{key:s.threadKey,state:m})},I=await d(f,{agent:a,instanceId:c,key:s.threadKey,...t.initialState===void 0?{}:{initialState:t.initialState},...t.onConcurrentRun===void 0?{}:{onConcurrentRun:t.onConcurrentRun},...s.owner===void 0?{}:{owner:s.owner},...s.title===void 0?{}:{title:s.title}});I?.outcome==="replaced"&&await $t(o,a,I.priorInstanceId);const H=await Mt(t,s.input,s.owner,l,y,d),V=typeof t.instructions=="function"?t.instructions({env:o,input:s.input,threadKey:s.threadKey}):t.instructions,X={agent:t,compact:n,env:o,generate:u,getState:b,instanceId:c,instructions:V,listMessages:M,memoryContext:H,onTokenDelta:p,deleteMessage:G,patchThread:B,persist:U,run:d,setState:W,step:y,streamGenerate:h,threadKey:s.threadKey,tools:t.tools??{}},k={value:void 0};try{I?.outcome==="queued"&&await Et(y,s.threadKey,c),await L();const{final:m,stoppedByCondition:E,turnsRun:z}=await Ut(X,x,C,k),w=k.value===void 0?{}:{usage:k.value};return await Rt({agent:t,env:o,extractGraph:i,finalText:m?.text,input:s.input,instanceId:c,owner:s.owner,paths:l,run:d,step:y}),await kt({agent:t,env:o,extractEpisode:r,finalText:m?.text,input:s.input,instanceId:c,owner:s.owner,paths:l,run:d,step:y,threadKey:s.threadKey}),m?(await It(t,{env:o,params:s,step:y},{...m,...w}),await K({status:"idle",...w}),{...m,...w}):E?(await K({status:"idle",...w}),{stopped:"stopCondition",turns:z,...w}):(await K({error:`agent stopped: maxTurns (${String(x)}) reached`,status:"error",...w}),{stopped:"maxTurns",turns:x,...w})}catch(m){throw await K({error:m instanceof Error?m.message:String(m),status:"error",...k.value===void 0?{}:{usage:k.value}}),m}};export{jt as runAgentLoop,yt as splitForCompaction};
@@ -1 +0,0 @@
1
- import"./base64-5eyBfWO3.mjs";import{p as s,c as i,f as p,e as n,r as m,t as c}from"./voice-turn-DbVR0H6T.mjs";import"./buildModelMessages-Y4tGo1T9.mjs";import"./AGENT_MODULE-M4D1EejI.mjs";export{s as parseIdentity,i as pcmToWav,p as readSynthesisAudio,n as readTranscriptionText,m as runVoiceTurn,c as toByteIterable};
@@ -1 +0,0 @@
1
- import{f as N,a as V}from"./base64-5eyBfWO3.mjs";import{buildModelMessages as X}from"./buildModelMessages-Y4tGo1T9.mjs";import{toFunctionReference as x}from"./AGENT_MODULE-M4D1EejI.mjs";const M=new TextDecoder;new TextEncoder;const R="=",J=t=>{if(t)try{const e=t[0]==="{"?t:M.decode(N(t)),n=JSON.parse(e);if(n&&typeof n=="object"&&!Array.isArray(n))return n}catch{}},st=t=>{if(t){if(!t.startsWith(R))return t;try{return M.decode(N(t.slice(R.length)))}catch{return}}},rt=t=>{const e=Number(t);return Number.isFinite(e)&&e>0?e:void 0},it=t=>typeof t=="number"&&Date.now()>=t,at=t=>{try{t.send(JSON.stringify({code:"TOKEN_EXPIRED",error:{code:"TOKEN_EXPIRED",message:"authentication token expired"},type:"error"})),t.close?.(4001,"token_expired")}catch{}},q=16e3,z=1,G=16,_=/[.!?]\s/u,Q=/\s/u,Y=async function*(t){if(t instanceof Uint8Array){yield t;return}if(t instanceof ReadableStream){const e=t.getReader();try{for(;;){const{done:n,value:i}=await e.read();if(n)break;yield i}}finally{e.releaseLock()}return}yield*t},ot=(t,e=q,n=z,i=G)=>{const a=n*i/8,u=e*a,f=new ArrayBuffer(44+t.byteLength),s=new DataView(f),r=(w,p)=>{for(let l=0;l<p.length;l+=1)s.setUint8(w+l,p.codePointAt(l)??0)};r(0,"RIFF"),s.setUint32(4,36+t.byteLength,!0),r(8,"WAVE"),r(12,"fmt "),s.setUint32(16,16,!0),s.setUint16(20,1,!0),s.setUint16(22,n,!0),s.setUint32(24,e,!0),s.setUint32(28,u,!0),s.setUint16(32,a,!0),s.setUint16(34,i,!0),r(36,"data"),s.setUint32(40,t.byteLength,!0);const y=new Uint8Array(f);return y.set(t,44),y},Z=t=>{const e=[];let n=t,i=_.exec(n);for(;i;){let a=i.index+1;for(;a<n.length&&Q.test(n[a]??"");)a+=1;const u=n.slice(0,a).trim();u.length>0&&e.push(u),n=n.slice(a),i=_.exec(n)}return{rest:n,sentences:e}},ct=async t=>{const{agent:e,connectionId:n,env:i,exportName:a,owner:u,paths:f,pcm:s,run:r,send:y,sendAudio:w,signal:p,streamGenerate:l,synthesize:P,text:D,threadKey:d,transcribe:C,turn:A,waitForDrain:L}=t,h=()=>p.aborted,k=x(f.appendMessage),F=x(f.ensureThread),O=x(f.listMessages),T=x(f.patchThread),m=(D??(s?await C(s):"")).trim();if(m.length===0)return{assistantText:"",interrupted:!1,userText:""};y({text:m,type:"user_transcript"}),await r(F,{agent:a,key:d,...e.initialState===void 0?{}:{initialState:e.initialState},...u===void 0?{}:{owner:u}}),await r(k,{content:m,messageKey:`voice:${n}:${String(A)}:user`,role:"user",threadKey:d}),await r(T,{key:d,status:"running"});const U=typeof e.instructions=="function"?e.instructions({env:i,input:m,threadKey:d}):e.instructions,$=await r(O,{key:d}),B=X({history:$,...U===void 0?{}:{instructions:U}});let g="",b="",S=Promise.resolve();const H=async o=>{if(h()||o.length===0)return;let E=!1;try{for await(const c of Y(await P(o,p))){if(h()||(await L?.(),h()))break;w(c),E=!0}}catch(c){y({message:c instanceof Error?c.message:String(c),type:"error"})}E&&(b=b.length>0?`${b} ${o}`:o)},v=o=>{S=S.then(async()=>H(o))};try{const o=await l({messages:B,signal:p},I=>{if(h())return;y({text:I,type:"assistant_delta"}),g+=I;const{rest:K,sentences:j}=Z(g);g=K;for(const W of j)v(W)});!h()&&g.trim().length>0&&v(g.trim()),g="",await S;const E=h(),c=E?b:o.text;return await r(k,{content:c,messageKey:`voice:${n}:${String(A)}:assistant`,role:"assistant",threadKey:d}),await r(T,{key:d,status:"idle"}),y(E?{type:"interrupted"}:{text:c,type:"assistant_done"}),{assistantText:c,interrupted:E,userText:m}}catch(o){throw await r(T,{key:d,status:"idle"}),o}},dt=t=>J(t),ut=t=>{if(typeof t=="object"&&t!==null&&"text"in t){const{text:e}=t;return typeof e=="string"?e:""}return""},ft=t=>{if(t instanceof Uint8Array||t instanceof ReadableStream)return t;if(t instanceof Response&&t.body)return t.body;if(typeof t=="object"&&t!==null&&"audio"in t){const{audio:e}=t;if(typeof e=="string")return V(e);if(e instanceof ReadableStream||e instanceof Uint8Array)return e}return new Uint8Array(0)};export{rt as a,at as b,ot as c,st as d,ut as e,ft as f,it as i,dt as p,ct as r,Y as t};