@lunora/agent 1.0.0-alpha.51 → 1.0.0-alpha.53

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 (36) hide show
  1. package/dist/channels.d.mts +2 -2
  2. package/dist/channels.d.ts +2 -2
  3. package/dist/component.d.mts +1 -0
  4. package/dist/component.d.ts +1 -0
  5. package/dist/component.mjs +2 -2
  6. package/dist/inbound.d.mts +1 -1
  7. package/dist/inbound.d.ts +1 -1
  8. package/dist/index.d.mts +2 -2
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.mjs +1 -1
  11. package/dist/packem_shared/AGENT_MODULE-gxKUkiCE.mjs +1 -0
  12. package/dist/packem_shared/{VoiceSessionDO-DNXzVGVf.mjs → VoiceSessionDO-CaFP3qTm.mjs} +1 -1
  13. package/dist/packem_shared/{agentAsTool-gH17BQ8M.mjs → agentAsTool-Cusr5NF2.mjs} +1 -1
  14. package/dist/packem_shared/{collectAgenticMemoryTools-DBcP8dUa.mjs → collectAgenticMemoryTools-cvrzaCqe.mjs} +1 -1
  15. package/dist/packem_shared/{compileAgentWorkflow-BW627hb5.mjs → compileAgentWorkflow-eUaTgBIK.mjs} +1 -1
  16. package/dist/packem_shared/{createAgentContext-D1cXHQO2.mjs → createAgentContext-JdRtKKoL.mjs} +1 -1
  17. package/dist/packem_shared/createDispatchRunner-BBuuGx3w-CLhnUgka.mjs +1 -0
  18. package/dist/packem_shared/{defineAgent-D0VIzlhu.mjs → defineAgent-DbRupRpO.mjs} +1 -1
  19. package/dist/packem_shared/{functionTool-CWHhkYqd.mjs → functionTool-DzlLvIPL.mjs} +1 -1
  20. package/dist/packem_shared/runAgentLoop-D1-SHp-g.mjs +3 -0
  21. package/dist/packem_shared/{runVoiceTurn-DhN9Asnn.mjs → runVoiceTurn-D-UHVqRs.mjs} +1 -1
  22. package/dist/packem_shared/{types.d-PMYeuDE7.d.mts → types.d-CeO8cn_u.d.mts} +117 -2
  23. package/dist/packem_shared/{types.d-PMYeuDE7.d.ts → types.d-CeO8cn_u.d.ts} +117 -2
  24. package/dist/packem_shared/{voice-turn-DzRKyf-x.mjs → voice-turn-CoAemsop.mjs} +1 -1
  25. package/dist/reply.d.mts +40 -0
  26. package/dist/reply.d.ts +40 -0
  27. package/dist/reply.mjs +1 -0
  28. package/dist/sandbox.d.mts +1 -1
  29. package/dist/sandbox.d.ts +1 -1
  30. package/dist/sandbox.mjs +1 -1
  31. package/dist/skill-markdown.d.mts +1 -1
  32. package/dist/skill-markdown.d.ts +1 -1
  33. package/package.json +11 -7
  34. package/dist/packem_shared/AGENT_MODULE-BXx-tSCe.mjs +0 -1
  35. package/dist/packem_shared/createDispatchRunner-EYOnoElU-CpVpdTXn.mjs +0 -1
  36. package/dist/packem_shared/runAgentLoop-nuk5NsAn.mjs +0 -3
@@ -1,5 +1,5 @@
1
- import { A as AgentDefinition } from "./packem_shared/types.d-PMYeuDE7.mjs";
2
- export type { I as InboundChannelEvent } from "./packem_shared/types.d-PMYeuDE7.mjs";
1
+ import { A as AgentDefinition } from "./packem_shared/types.d-CeO8cn_u.mjs";
2
+ export type { I as InboundChannelEvent } from "./packem_shared/types.d-CeO8cn_u.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-PMYeuDE7.js";
2
- export type { I as InboundChannelEvent } from "./packem_shared/types.d-PMYeuDE7.js";
1
+ import { A as AgentDefinition } from "./packem_shared/types.d-CeO8cn_u.js";
2
+ export type { I as InboundChannelEvent } from "./packem_shared/types.d-CeO8cn_u.js";
3
3
  import '@lunora/mail/inbound';
4
4
  import 'ai';
5
5
  /**
@@ -72,6 +72,7 @@ interface AgentComponent {
72
72
  extension: SchemaExtension;
73
73
  functions: {
74
74
  agentAppendMessage: AgentRegisteredFunction;
75
+ agentCompleteRun: AgentRegisteredFunction;
75
76
  agentEnsureThread: AgentRegisteredFunction;
76
77
  agentEpisodeRecall: AgentRegisteredFunction;
77
78
  agentEpisodeUpsert: AgentRegisteredFunction;
@@ -72,6 +72,7 @@ interface AgentComponent {
72
72
  extension: SchemaExtension;
73
73
  functions: {
74
74
  agentAppendMessage: AgentRegisteredFunction;
75
+ agentCompleteRun: AgentRegisteredFunction;
75
76
  agentEnsureThread: AgentRegisteredFunction;
76
77
  agentEpisodeRecall: AgentRegisteredFunction;
77
78
  agentEpisodeUpsert: AgentRegisteredFunction;
@@ -1,2 +1,2 @@
1
- import{LunoraError as w}from"@lunora/errors";import{defineTable as x,initLunora as $,defineSchemaExtension as j}from"@lunora/server";import{v as e}from"@lunora/values";import{i as b,o as k,s as O}from"./packem_shared/component-shared-BVjAbtUu.mjs";import{graphTables as S,graphComponent as F}from"./packem_shared/normalizeEntityName-DrEDaSSz.mjs";import{normalizeEntityName as re}from"./packem_shared/normalizeEntityName-DrEDaSSz.mjs";import{sandboxComponent as oe}from"./packem_shared/sandboxComponent-CKDGyK4Y.mjs";const I="agent_episodes",L=5,U=20,B=500,N=200,G=/\s+/gu,z=c=>c===void 0||!Number.isFinite(c)?L:Math.min(U,Math.max(1,Math.trunc(c))),P={episodes:x({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:H,query:J}=$.dataModel().create(),Q=()=>{const c=H.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:u})=>{const l=s.summary.replaceAll(G," ").trim().slice(0,B);if(l.length===0)return{recorded:!1};if(await u.db.query(I).withIndex("byOwnerMessageKey",p=>p.eq("owner",s.owner).eq("messageKey",s.messageKey)).first())return{recorded:!1};await u.db.insert(I,{createdAt:s.createdAt??Date.now(),messageKey:s.messageKey,owner:s.owner,summary:l,...s.threadKey===void 0?{}:{threadKey:s.threadKey}});const g=await u.db.query(I).withIndex("byOwnerCreatedAt",p=>p.eq("owner",s.owner)).order("asc").take(N+1);for(const p of g.slice(0,Math.max(0,g.length-N)))await u.db.delete(p._id);return{recorded:!0}}),f=J.input({limit:e.optional(e.number()),owner:e.string()}).query(async({args:s,ctx:u})=>{const l=await u.db.query(I).withIndex("byOwnerCreatedAt",g=>g.eq("owner",s.owner)).order("desc").take(z(s.limit));return l.length===0?{context:""}:{context:l.toReversed().map(g=>`- ${g.summary}`).join(`
2
- `)}});return{agentEpisodeRecall:b(f),agentEpisodeUpsert:b(c)}},T="threads",R="messages",d=`${k}_${T}`,K=`${k}_${R}`,V=j(k,{tables:{[R]:x({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(),[T]:x({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(),...S,...P}}),{mutation:m,query:q}=$.dataModel().create(),te=()=>{const c=m.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:a})=>{const r=Date.now(),n=await a.db.query(d).withIndex("byKey",i=>i.eq("key",t.key)).first();if(n){if(n.owner!==t.owner&&t.owner!==void 0)throw new Error(`@lunora/agent: thread "${t.key}" belongs to another owner`);const i=n.instanceId;if((n.status==="running"||n.status==="awaiting_input")&&i!==void 0&&(t.instanceId===void 0||t.instanceId!==i)){const o=t.onConcurrentRun??"reject";if(o!=="replace")throw new w("CONFLICT",`@lunora/agent: thread "${t.key}" already has a run in flight (instance "${i}") — onConcurrentRun="${o}"`);return await a.db.patch(n._id,{error:void 0,status:"running",updatedAt:r,...t.instanceId===void 0?{}:{instanceId:t.instanceId}}),{created:!1,priorInstanceId:i,replaced:!0}}return await a.db.patch(n._id,{error:void 0,status:"running",updatedAt:r,...t.instanceId===void 0?{}:{instanceId:t.instanceId}}),{created:!1}}return await a.db.insert(d,{agent:t.agent,createdAt:r,key:t.key,messageCount:0,status:"running",updatedAt:r,...O({instanceId:t.instanceId,owner:t.owner,state:t.initialState,title:t.title})}),{created:!0}}),f=m.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:a})=>{const r=await a.db.query(K).withIndex("byMessageKey",y=>y.eq("threadKey",t.threadKey).eq("messageKey",t.messageKey)).first();if(r)return{seq:r.seq};const n=await a.db.query(d).withIndex("byKey",y=>y.eq("key",t.threadKey)).first();if(!n)throw new Error(`@lunora/agent: cannot append to unknown thread "${t.threadKey}" — run agentEnsureThread first`);const i=n.messageCount,o=Date.now();return await a.db.insert(K,{content:t.content,createdAt:o,messageKey:t.messageKey,role:t.role,seq:i,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 a.db.patch(n._id,{messageCount:i+1,updatedAt:o}),{seq:i}}),s=m.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:a})=>{const{instanceId:r,key:n}=t;let i;n!==void 0?i=await a.db.query(d).withIndex("byKey",o=>o.eq("key",n)).first():r!==void 0&&(i=await a.db.query(d).withIndex("byInstance",o=>o.eq("instanceId",r)).first()),i&&await a.db.patch(i._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}})}),u=m.input({key:e.string(),state:e.any()}).mutation(async({args:t,ctx:a})=>{const r=await a.db.query(d).withIndex("byKey",n=>n.eq("key",t.key)).first();r&&await a.db.patch(r._id,{state:t.state,updatedAt:Date.now()})}),l=(t,a)=>{if(!t)return;const{owner:r}=t;if(!(r!==void 0&&r!==(a.userId??void 0)))return t},g=q.input({key:e.string()}).query(async({args:t,ctx:a})=>{const r=await a.db.query(d).withIndex("byKey",n=>n.eq("key",t.key)).first();return l(r,a.auth)}),p=q.input({key:e.string()}).query(async({args:t,ctx:a})=>{const r=await a.db.query(d).withIndex("byKey",n=>n.eq("key",t.key)).first();return l(r,a.auth)?.state}),_=q.input({key:e.string(),limit:e.optional(e.number())}).query(async({args:t,ctx:a})=>{const r=await a.db.query(d).withIndex("byKey",n=>n.eq("key",t.key)).first();return l(r,a.auth)===void 0?[]:t.limit!==void 0?(await a.db.query(K).withIndex("byThread",n=>n.eq("threadKey",t.key)).order("desc").take(t.limit)).toReversed():a.db.query(K).withIndex("byThread",n=>n.eq("threadKey",t.key)).collect()}),D=m.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:a})=>{const r=await a.db.query(d).withIndex("byKey",h=>h.eq("key",t.threadKey)).first(),n=l(r,a.auth);if(n===void 0)throw new w("FORBIDDEN",`@lunora/agent: not allowed to resolve approvals on thread "${t.threadKey}"`);if(n.instanceId!==t.instanceId)throw new w("FORBIDDEN",`@lunora/agent: instance "${t.instanceId}" does not own thread "${t.threadKey}"`);const i=n.agent,{agents:o}=a,y=o?.[i];if(typeof y?.sendEvent!="function")throw new w("INTERNAL",`@lunora/agent: no ctx.agents["${i}"] producer to resolve the approval — run codegen/dev so the agent binding is wired`);return await y.sendEvent(t.instanceId,{payload:{decision:t.decision,toolCallId:t.toolCallId,...t.note===void 0?{}:{note:t.note}},type:`agent-approval:${t.toolCallId}`}),{resolved:!0}}),M=m.input({agent:e.string(),input:e.string(),threadKey:e.string(),title:e.optional(e.string())}).mutation(async({args:t,ctx:a})=>{const{agents:r}=a,n=r?.[t.agent];if(typeof n?.run!="function")throw new w("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(n.publicRun!==!0)throw new w("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 i=a.auth.userId??void 0,o=await a.db.query(d).withIndex("byKey",h=>h.eq("key",t.threadKey)).first();if(o){const h=o.status,E=o.instanceId,v=o.owner;if((h==="running"||h==="awaiting_input")&&E!==void 0&&(v===void 0||v===i))return{id:E,threadKey:t.threadKey};if(v!==i&&i!==void 0)throw new w("FORBIDDEN",`@lunora/agent: thread "${t.threadKey}" belongs to another owner`)}const{id:y}=await n.run({input:t.input,threadKey:t.threadKey,...i===void 0?{}:{owner:i},...t.title===void 0?{}:{title:t.title}});return{id:y,threadKey:t.threadKey}}),C=F(),A=Q();return{extension:V,functions:{agentAppendMessage:b(f),agentEnsureThread:b(c),agentEpisodeRecall:A.agentEpisodeRecall,agentEpisodeUpsert:A.agentEpisodeUpsert,agentGraphTraverse:C.agentGraphTraverse,agentGraphUpsert:C.agentGraphUpsert,agentMessages:_,agentPatchThread:b(s),agentResolveApproval:D,agentRun:M,agentSetState:b(u),agentState:p,agentThread:g}}};export{te as agentComponent,V as agentExtension,re as normalizeEntityName,oe as sandboxComponent};
1
+ import{LunoraError as w}from"@lunora/errors";import{defineTable as x,initLunora as R,defineSchemaExtension as L}from"@lunora/server";import{v as e}from"@lunora/values";import{i as I,o as k,s as U}from"./packem_shared/component-shared-BVjAbtUu.mjs";import{graphTables as B,graphComponent as G}from"./packem_shared/normalizeEntityName-DrEDaSSz.mjs";import{normalizeEntityName as ce}from"./packem_shared/normalizeEntityName-DrEDaSSz.mjs";import{sandboxComponent as ge}from"./packem_shared/sandboxComponent-CKDGyK4Y.mjs";const f="agent_episodes",P=5,z=20,H=500,E=200,Q=/\s+/gu,W=l=>l===void 0||!Number.isFinite(l)?P:Math.min(z,Math.max(1,Math.trunc(l))),J={episodes:x({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:V,query:X}=R.dataModel().create(),Y=()=>{const l=V.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 p=s.summary.replaceAll(Q," ").trim().slice(0,H);if(p.length===0)return{recorded:!1};if(await y.db.query(f).withIndex("byOwnerMessageKey",h=>h.eq("owner",s.owner).eq("messageKey",s.messageKey)).first())return{recorded:!1};await y.db.insert(f,{createdAt:s.createdAt??Date.now(),messageKey:s.messageKey,owner:s.owner,summary:p,...s.threadKey===void 0?{}:{threadKey:s.threadKey}});const c=await y.db.query(f).withIndex("byOwnerCreatedAt",h=>h.eq("owner",s.owner)).order("asc").take(E+1);for(const h of c.slice(0,Math.max(0,c.length-E)))await y.db.delete(h._id);return{recorded:!0}}),i=X.input({limit:e.optional(e.number()),owner:e.string()}).query(async({args:s,ctx:y})=>{const p=await y.db.query(f).withIndex("byOwnerCreatedAt",c=>c.eq("owner",s.owner)).order("desc").take(W(s.limit));return p.length===0?{context:""}:{context:p.toReversed().map(c=>`- ${c.summary}`).join(`
2
+ `)}});return{agentEpisodeRecall:I(i),agentEpisodeUpsert:I(l)}},D="threads",j="messages",M="run_queue",g=`${k}_${D}`,v=`${k}_${j}`,K=`${k}_${M}`,_=5,Z=780*60*1e3,ee=L(k,{tables:{[j]:x({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(),[D]:x({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]:x({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(),...B,...J}}),{mutation:b,query:A}=R.dataModel().create(),te=async(l,i,s)=>{if(i.instanceId===void 0)throw new w("CONFLICT",`@lunora/agent: thread "${i.key}" already has a run in flight (instance "${i.priorInstanceId}") — cannot queue a dispatch with no instance id`);const{instanceId:y}=i,p=await l.query(K).withIndex("byThreadInstance",q=>q.eq("threadKey",i.key).eq("instanceId",y)).first();if(p)return{outcome:"queued",position:p.position};const c=await l.query(K).withIndex("byThread",q=>q.eq("threadKey",i.key)).collect();if(c.length>=_)throw new w("CONFLICT",`@lunora/agent: thread "${i.key}" run queue is full (depth ${String(_)}) — rejecting instance "${y}"`);const h=(c.at(-1)?.position??-1)+1;return await l.insert(K,{agent:i.agent,enqueuedAt:s,instanceId:y,position:h,threadKey:i.key}),{outcome:"queued",position:h}},ae=async(l,i,s)=>{if(i.policy==="queue")return te(l,{agent:i.agent,instanceId:i.instanceId,key:i.key,priorInstanceId:i.priorInstanceId},s);if(i.policy!=="replace")throw new w("CONFLICT",`@lunora/agent: thread "${i.key}" already has a run in flight (instance "${i.priorInstanceId}") — onConcurrentRun="${i.policy}"`);return await l.patch(i.existingId,{error:void 0,status:"running",updatedAt:s,...i.instanceId===void 0?{}:{instanceId:i.instanceId}}),{outcome:"replaced",priorInstanceId:i.priorInstanceId}},de=()=>{const l=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:a})=>{const r=Date.now(),n=await a.db.query(g).withIndex("byKey",o=>o.eq("key",t.key)).first();if(n){if(n.owner!==t.owner&&t.owner!==void 0)throw new Error(`@lunora/agent: thread "${t.key}" belongs to another owner`);const o=n.instanceId,d=typeof n.updatedAt=="number"?n.updatedAt:0;return!(r-d>Z)&&(n.status==="running"||n.status==="awaiting_input")&&o!==void 0&&(t.instanceId===void 0||t.instanceId!==o)?ae(a.db,{agent:t.agent,existingId:n._id,instanceId:t.instanceId,key:t.key,policy:t.onConcurrentRun??"reject",priorInstanceId:o},r):(await a.db.patch(n._id,{error:void 0,status:"running",updatedAt:r,...t.instanceId===void 0?{}:{instanceId:t.instanceId}}),{outcome:"continued"})}return await a.db.insert(g,{agent:t.agent,createdAt:r,key:t.key,messageCount:0,status:"running",updatedAt:r,...U({instanceId:t.instanceId,owner:t.owner,state:t.initialState,title:t.title})}),{outcome:"created"}}),i=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:a})=>{const r=await a.db.query(v).withIndex("byMessageKey",u=>u.eq("threadKey",t.threadKey).eq("messageKey",t.messageKey)).first();if(r)return{seq:r.seq};const n=await a.db.query(g).withIndex("byKey",u=>u.eq("key",t.threadKey)).first();if(!n)throw new Error(`@lunora/agent: cannot append to unknown thread "${t.threadKey}" — run agentEnsureThread first`);const o=n.messageCount,d=Date.now();return await a.db.insert(v,{content:t.content,createdAt:d,messageKey:t.messageKey,role:t.role,seq:o,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 a.db.patch(n._id,{messageCount:o+1,updatedAt:d}),{seq:o}}),s=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:a})=>{const{instanceId:r,key:n}=t;let o;n!==void 0?o=await a.db.query(g).withIndex("byKey",d=>d.eq("key",n)).first():r!==void 0&&(o=await a.db.query(g).withIndex("byInstance",d=>d.eq("instanceId",r)).first()),o&&await a.db.patch(o._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}})}),y=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:a})=>{const r=Date.now(),n=await a.db.query(g).withIndex("byKey",u=>u.eq("key",t.key)).first();if(n?.instanceId!==t.instanceId){const u=await a.db.query(K).withIndex("byThreadInstance",m=>m.eq("threadKey",t.key).eq("instanceId",t.instanceId)).first();return u&&await a.db.delete(u._id),{}}const o=(await a.db.query(K).withIndex("byThread",u=>u.eq("threadKey",t.key)).collect())[0];if(!o)return await a.db.patch(n._id,{status:t.status,updatedAt:r,...t.error===void 0?{}:{error:t.error},...t.usage===void 0?{}:{usage:t.usage}}),{};const d=o.instanceId;return await a.db.delete(o._id),await a.db.patch(n._id,{instanceId:d,status:"running",updatedAt:r,...t.error===void 0?{}:{error:t.error},...t.usage===void 0?{}:{usage:t.usage}}),{dequeued:d}}),p=b.input({key:e.string(),state:e.any()}).mutation(async({args:t,ctx:a})=>{const r=await a.db.query(g).withIndex("byKey",n=>n.eq("key",t.key)).first();r&&await a.db.patch(r._id,{state:t.state,updatedAt:Date.now()})}),c=(t,a)=>{if(!t)return;const{owner:r}=t;if(!(r!==void 0&&r!==(a.userId??void 0)))return t},h=A.input({key:e.string()}).query(async({args:t,ctx:a})=>{const r=await a.db.query(g).withIndex("byKey",n=>n.eq("key",t.key)).first();return c(r,a.auth)}),q=A.input({key:e.string()}).query(async({args:t,ctx:a})=>{const r=await a.db.query(g).withIndex("byKey",n=>n.eq("key",t.key)).first();return c(r,a.auth)?.state}),O=A.input({key:e.string(),limit:e.optional(e.number())}).query(async({args:t,ctx:a})=>{const r=await a.db.query(g).withIndex("byKey",n=>n.eq("key",t.key)).first();return c(r,a.auth)===void 0?[]:t.limit!==void 0?(await a.db.query(v).withIndex("byThread",n=>n.eq("threadKey",t.key)).order("desc").take(t.limit)).toReversed():a.db.query(v).withIndex("byThread",n=>n.eq("threadKey",t.key)).collect()}),F=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:a})=>{const r=await a.db.query(g).withIndex("byKey",m=>m.eq("key",t.threadKey)).first(),n=c(r,a.auth);if(n===void 0)throw new w("FORBIDDEN",`@lunora/agent: not allowed to resolve approvals on thread "${t.threadKey}"`);if(n.instanceId!==t.instanceId)throw new w("FORBIDDEN",`@lunora/agent: instance "${t.instanceId}" does not own thread "${t.threadKey}"`);const o=n.agent,{agents:d}=a,u=d?.[o];if(typeof u?.sendEvent!="function")throw new w("INTERNAL",`@lunora/agent: no ctx.agents["${o}"] producer to resolve the approval — run codegen/dev so the agent binding is wired`);return await u.sendEvent(t.instanceId,{payload:{decision:t.decision,toolCallId:t.toolCallId,...t.note===void 0?{}:{note:t.note}},type:`agent-approval:${t.toolCallId}`}),{resolved:!0}}),S=b.input({agent:e.string(),input:e.string(),threadKey:e.string(),title:e.optional(e.string())}).mutation(async({args:t,ctx:a})=>{const{agents:r}=a,n=r?.[t.agent];if(typeof n?.run!="function")throw new w("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(n.publicRun!==!0)throw new w("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 o=a.auth.userId??void 0,d=await a.db.query(g).withIndex("byKey",m=>m.eq("key",t.threadKey)).first();if(d){const m=d.status,N=d.instanceId,C=d.owner;if((m==="running"||m==="awaiting_input")&&N!==void 0&&(C===void 0||C===o))return{id:N,threadKey:t.threadKey};if(C!==o&&o!==void 0)throw new w("FORBIDDEN",`@lunora/agent: thread "${t.threadKey}" belongs to another owner`)}const{id:u}=await n.run({input:t.input,threadKey:t.threadKey,...o===void 0?{}:{owner:o},...t.title===void 0?{}:{title:t.title}});return{id:u,threadKey:t.threadKey}}),T=G(),$=Y();return{extension:ee,functions:{agentAppendMessage:I(i),agentCompleteRun:I(y),agentEnsureThread:I(l),agentEpisodeRecall:$.agentEpisodeRecall,agentEpisodeUpsert:$.agentEpisodeUpsert,agentGraphTraverse:T.agentGraphTraverse,agentGraphUpsert:T.agentGraphUpsert,agentMessages:O,agentPatchThread:I(s),agentResolveApproval:F,agentRun:S,agentSetState:I(p),agentState:q,agentThread:h}}};export{de as agentComponent,ee as agentExtension,ce as normalizeEntityName,ge as sandboxComponent};
@@ -1,4 +1,4 @@
1
- import { A as AgentDefinition } from "./packem_shared/types.d-PMYeuDE7.mjs";
1
+ import { A as AgentDefinition } from "./packem_shared/types.d-CeO8cn_u.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-PMYeuDE7.js";
1
+ import { A as AgentDefinition } from "./packem_shared/types.d-CeO8cn_u.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, d as AgentCompact, e as AgentEpisodeExtract, f as AgentGraphExtract, g as AgentGenerate, h as AgentTokenSink, i as AgentRunInput, j as AgentFunctionPaths, k as AgentRunFunction, l as AgentStepLike, m as AgentStreamGenerate, n as AgentRunResult, o as AgentMessageRow, p as AgentConfig, c as SkillDefinition, q as AnyAgentTool, r as AgentAsToolOptions, s as AgentSubToolInput, b as AgentToolDefinition, t as AgentBindingSpec, u as AgentHandle, v as AgentToolConfig, w as AgentFunctionReference, x as AgentModelInput, y as SkillConfig } from "./packem_shared/types.d-PMYeuDE7.mjs";
2
- export type { z as AgentApprovalContext, B as AgentEmailMapper, C as AgentEmailRun, D as AgentGenerateOptions, E as AgentGenerateResult, F as AgentInstructionsContext, G as AgentLiveEvent, H as AgentMemoryOptions, J as AgentMemorySource, K as AgentMessageStatus, L as AgentOnStepFinish, M as AgentPrepareStep, N as AgentPrepareStepInput, O as AgentPrepareStepResult, P as AgentProgressEvent, Q as AgentRunHandle, R as AgentStepFinishInfo, T as AgentStepInfo, U as AgentThreadStatus, V as AgentTokenDelta, W as AgentToolCall, a as AgentToolContext, X as AgentUsage, Y as AgentVoiceConfig, Z as AgentWorkflowBindingLike, _ as AgentWorkflowInstanceLike } from "./packem_shared/types.d-PMYeuDE7.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-CeO8cn_u.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-CeO8cn_u.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";
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AgentDefinition, d as AgentCompact, e as AgentEpisodeExtract, f as AgentGraphExtract, g as AgentGenerate, h as AgentTokenSink, i as AgentRunInput, j as AgentFunctionPaths, k as AgentRunFunction, l as AgentStepLike, m as AgentStreamGenerate, n as AgentRunResult, o as AgentMessageRow, p as AgentConfig, c as SkillDefinition, q as AnyAgentTool, r as AgentAsToolOptions, s as AgentSubToolInput, b as AgentToolDefinition, t as AgentBindingSpec, u as AgentHandle, v as AgentToolConfig, w as AgentFunctionReference, x as AgentModelInput, y as SkillConfig } from "./packem_shared/types.d-PMYeuDE7.js";
2
- export type { z as AgentApprovalContext, B as AgentEmailMapper, C as AgentEmailRun, D as AgentGenerateOptions, E as AgentGenerateResult, F as AgentInstructionsContext, G as AgentLiveEvent, H as AgentMemoryOptions, J as AgentMemorySource, K as AgentMessageStatus, L as AgentOnStepFinish, M as AgentPrepareStep, N as AgentPrepareStepInput, O as AgentPrepareStepResult, P as AgentProgressEvent, Q as AgentRunHandle, R as AgentStepFinishInfo, T as AgentStepInfo, U as AgentThreadStatus, V as AgentTokenDelta, W as AgentToolCall, a as AgentToolContext, X as AgentUsage, Y as AgentVoiceConfig, Z as AgentWorkflowBindingLike, _ as AgentWorkflowInstanceLike } from "./packem_shared/types.d-PMYeuDE7.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-CeO8cn_u.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-CeO8cn_u.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";
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{runAgentLoop as t,splitForCompaction as r}from"./packem_shared/runAgentLoop-nuk5NsAn.mjs";import{collectAgenticMemoryTools as a,toSearchResults as i}from"./packem_shared/collectAgenticMemoryTools-DBcP8dUa.mjs";import{agentAsTool as l}from"./packem_shared/agentAsTool-gH17BQ8M.mjs";import{codeTool as p}from"./packem_shared/codeTool-DYJVy-bH.mjs";import{agentComponent as c,agentExtension as x}from"./component.mjs";import{default as A}from"./packem_shared/createAgentContext-D1cXHQO2.mjs";import{defineAgent as d,defineAgentTool as u,isAgentDefinition as N}from"./packem_shared/defineAgent-D0VIzlhu.mjs";import{functionTool as D}from"./packem_shared/functionTool-CWHhkYqd.mjs";import{createAgentGenerate as M,createEpisodeExtract as O,createGraphExtract as _,createStreamGenerate as C,resolveAgentModel as G}from"./packem_shared/createAgentGenerate-BS1vasdV.mjs";import{adaptMcpResult as F,mcpTools as L}from"./packem_shared/adaptMcpResult-18G7zpFo.mjs";import{buildModelMessages as k}from"./packem_shared/buildModelMessages-Dm2wVNQy.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-BXx-tSCe.mjs";import{browserTool as W,containerTool as j,fsTool as q}from"./sandbox.mjs";import{defineSkill as J,isSkillDefinition as Y}from"./packem_shared/defineSkill-DfJxCwfZ.mjs";import{default as $}from"./packem_shared/VoiceSessionDO-DNXzVGVf.mjs";import{Q as oe}from"./packem_shared/voice-turn-DzRKyf-x.mjs";import{default as re}from"./packem_shared/compileAgentWorkflow-BW627hb5.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,W as browserTool,k as buildModelMessages,p as codeTool,a as collectAgenticMemoryTools,re as compileAgentWorkflow,j as containerTool,A as createAgentContext,M as createAgentGenerate,O as createEpisodeExtract,_ as createGraphExtract,C as createStreamGenerate,d as defineAgent,u as defineAgentTool,J as defineSkill,q 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-D1-SHp-g.mjs";import{collectAgenticMemoryTools as a,toSearchResults as i}from"./packem_shared/collectAgenticMemoryTools-cvrzaCqe.mjs";import{agentAsTool as l}from"./packem_shared/agentAsTool-Cusr5NF2.mjs";import{codeTool as p}from"./packem_shared/codeTool-DYJVy-bH.mjs";import{agentComponent as c,agentExtension as x}from"./component.mjs";import{default as A}from"./packem_shared/createAgentContext-JdRtKKoL.mjs";import{defineAgent as d,defineAgentTool as u,isAgentDefinition as N}from"./packem_shared/defineAgent-DbRupRpO.mjs";import{functionTool as D}from"./packem_shared/functionTool-DzlLvIPL.mjs";import{createAgentGenerate as M,createEpisodeExtract as O,createGraphExtract as _,createStreamGenerate as C,resolveAgentModel as G}from"./packem_shared/createAgentGenerate-BS1vasdV.mjs";import{adaptMcpResult as F,mcpTools as L}from"./packem_shared/adaptMcpResult-18G7zpFo.mjs";import{buildModelMessages as k}from"./packem_shared/buildModelMessages-Dm2wVNQy.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-gxKUkiCE.mjs";import{browserTool as W,containerTool as j,fsTool as q}from"./sandbox.mjs";import{defineSkill as J,isSkillDefinition as Y}from"./packem_shared/defineSkill-DfJxCwfZ.mjs";import{default as $}from"./packem_shared/VoiceSessionDO-CaFP3qTm.mjs";import{Q as oe}from"./packem_shared/voice-turn-CoAemsop.mjs";import{default as re}from"./packem_shared/compileAgentWorkflow-eUaTgBIK.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,W as browserTool,k as buildModelMessages,p as codeTool,a as collectAgenticMemoryTools,re as compileAgentWorkflow,j as containerTool,A as createAgentContext,M as createAgentGenerate,O as createEpisodeExtract,_ as createGraphExtract,C as createStreamGenerate,d as defineAgent,u as defineAgentTool,J as defineSkill,q 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
+ const e="agents",t="sandbox",n=`${t}:invoke`,s={appendMessage:`${e}:agentAppendMessage`,completeRun:`${e}:agentCompleteRun`,ensureThread:`${e}:agentEnsureThread`,episodeRecall:`${e}:agentEpisodeRecall`,episodeUpsert:`${e}:agentEpisodeUpsert`,graphTraverse:`${e}:agentGraphTraverse`,graphUpsert:`${e}:agentGraphUpsert`,listMessages:`${e}:agentMessages`,patchThread:`${e}:agentPatchThread`,run:`${e}:agentRun`,setState:`${e}:agentSetState`,state:`${e}:agentState`},r=a=>typeof a=="string"?{__lunoraRef:a}:a;export{e as AGENT_MODULE,s as DEFAULT_AGENT_FUNCTION_PATHS,n as SANDBOX_INVOKE_PATH,t as SANDBOX_MODULE,r as toFunctionReference};
@@ -1 +1 @@
1
- import{createAi as g}from"@lunora/ai";import{A as y}from"./createDispatchRunner-EYOnoElU-CpVpdTXn.mjs";import{a as m}from"./base64-B_qZ_Tyh.mjs";import{X as w,l as b,g as v,p as u,E as l,Y as A,Z as S,e as x,Q as I,P as k}from"./voice-turn-DzRKyf-x.mjs";import{createStreamGenerate as M}from"./createAgentGenerate-BS1vasdV.mjs";import{DEFAULT_AGENT_FUNCTION_PATHS as B,toFunctionReference as f}from"./AGENT_MODULE-BXx-tSCe.mjs";const U="@cf/openai/whisper-large-v3-turbo",z="@cf/deepgram/aura-1",F=8*1024*1024,N=256*1024,p=15,T=5e3;class L{agent;ai;env;exportName;paths;streamGenerate;sttModel;ttsModel;audioBuffers=new Map;bufferedBytes=new Map;controllers=new Map;state;constructor(t,e,s,n){this.state=t,this.env=e,this.agent=s,this.exportName=n,this.paths=B,this.ai=g({binding:e.AI,env:e}),this.streamGenerate=M(s,e),this.sttModel=s.voice?.stt??U,this.ttsModel=s.voice?.tts??z}fetch(t){if(t.headers.get("Upgrade")!=="websocket")return new Response("Expected a WebSocket upgrade",{status:426});const e=new URL(t.url).searchParams.get("threadKey");if(!e)return new Response("Missing threadKey",{status:400});const s=globalThis.WebSocketPair,n=new s,i=n[0],r=n[1];this.state.acceptWebSocket(r);const c=crypto.randomUUID(),o=w(t.headers.get("x-lunora-identity")),d=b(t.headers.get("x-lunora-userid")),a=v(t.headers.get("x-lunora-identity-exp"));if(u(a))return l(r),new Response(null,{status:101,webSocket:i});r.serializeAttachment?.({connectionId:c,threadKey:e,turn:0,...a===void 0?{}:{expiresAt:a},...o===void 0?{}:{identity:o},...d===void 0?{}:{userId:d}}),this.send(r,{audioFormat:this.agent.voice?.audioFormat??"mp3",type:"ready"});const h=this.agent.voice?.greeting;return h&&h.length>0&&this.state.waitUntil?.(this.speakGreeting(r,c,e,d,o,h)),new Response(null,{status:101,webSocket:i})}async webSocketMessage(t,e){const s=t.deserializeAttachment?.();if(s){if(u(s.expiresAt)){l(t);return}try{if(typeof e=="string"){await this.handleControl(t,s,e);return}this.bufferAudio(s.connectionId,new Uint8Array(e),t)}catch(n){this.send(t,{message:n instanceof Error?n.message:String(n),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 y({env:this.env,label:"@lunora/agent voice",...s===void 0?{}:{identity:s}})}async transcribe(t){const e=A(t);return S(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 n;try{n=JSON.parse(s)}catch{return}if(n.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(n.type==="commit"){const i=this.drainAudio(e.connectionId);await this.runTurn(t,e,{pcm:i});return}await this.runTurn(t,e,{text:n.text})}bufferAudio(t,e,s){const n=(this.bufferedBytes.get(t)??0)+e.byteLength;if(n>F){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,n)}drainAudio(t){const e=this.audioBuffers.get(t)??[];this.audioBuffers.delete(t),this.bufferedBytes.delete(t);const s=e.reduce((r,c)=>r+c.byteLength,0),n=new Uint8Array(s);let i=0;for(const r of e)n.set(r,i),i+=r.byteLength;return n}async runTurn(t,e,s){const n=new AbortController;this.controllers.set(e.connectionId,n);try{await I({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:n.signal,streamGenerate:this.streamGenerate,synthesize:async(i,r)=>this.synthesizeWithSignal(i,r),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)===n&&this.controllers.delete(e.connectionId),t.serializeAttachment?.({...e,turn:e.turn+1})}}async speakGreeting(t,e,s,n,i,r){const c=this.resolveRun(n,i),o=new AbortController,d=()=>o.signal.aborted;this.controllers.set(e,o);try{await c(f(this.paths.ensureThread),{agent:this.exportName,key:s,...this.agent.initialState===void 0?{}:{initialState:this.agent.initialState},...n===void 0?{}:{owner:n}});for await(const a of k(await this.synthesizeWithSignal(r,o.signal))){if(d()||(await this.waitForSocketDrain(t),d()))break;this.sendAudio(t,a)}d()||(await c(f(this.paths.appendMessage),{content:r,messageKey:"voice:greeting:assistant",role:"assistant",threadKey:s}),this.send(t,{text:r,type:"assistant_done"}))}catch(a){this.send(t,{message:a instanceof Error?a.message:String(a),type:"error"})}finally{this.controllers.get(e)===o&&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>N&&s<T;)await new Promise(n=>{setTimeout(n,p)}),s+=p}}export{L as default};
1
+ import{createAi as g}from"@lunora/ai";import{K as y}from"./createDispatchRunner-BBuuGx3w-CLhnUgka.mjs";import{a as m}from"./base64-B_qZ_Tyh.mjs";import{X as w,l as b,g as v,p as u,E as l,Y as A,Z as S,e as x,Q as I,P as k}from"./voice-turn-CoAemsop.mjs";import{createStreamGenerate as M}from"./createAgentGenerate-BS1vasdV.mjs";import{DEFAULT_AGENT_FUNCTION_PATHS as B,toFunctionReference as f}from"./AGENT_MODULE-gxKUkiCE.mjs";const U="@cf/openai/whisper-large-v3-turbo",z="@cf/deepgram/aura-1",F=8*1024*1024,N=256*1024,p=15,T=5e3;class L{agent;ai;env;exportName;paths;streamGenerate;sttModel;ttsModel;audioBuffers=new Map;bufferedBytes=new Map;controllers=new Map;state;constructor(t,e,s,n){this.state=t,this.env=e,this.agent=s,this.exportName=n,this.paths=B,this.ai=g({binding:e.AI,env:e}),this.streamGenerate=M(s,e),this.sttModel=s.voice?.stt??U,this.ttsModel=s.voice?.tts??z}fetch(t){if(t.headers.get("Upgrade")!=="websocket")return new Response("Expected a WebSocket upgrade",{status:426});const e=new URL(t.url).searchParams.get("threadKey");if(!e)return new Response("Missing threadKey",{status:400});const s=globalThis.WebSocketPair,n=new s,i=n[0],r=n[1];this.state.acceptWebSocket(r);const c=crypto.randomUUID(),o=w(t.headers.get("x-lunora-identity")),d=b(t.headers.get("x-lunora-userid")),a=v(t.headers.get("x-lunora-identity-exp"));if(u(a))return l(r),new Response(null,{status:101,webSocket:i});r.serializeAttachment?.({connectionId:c,threadKey:e,turn:0,...a===void 0?{}:{expiresAt:a},...o===void 0?{}:{identity:o},...d===void 0?{}:{userId:d}}),this.send(r,{audioFormat:this.agent.voice?.audioFormat??"mp3",type:"ready"});const h=this.agent.voice?.greeting;return h&&h.length>0&&this.state.waitUntil?.(this.speakGreeting(r,c,e,d,o,h)),new Response(null,{status:101,webSocket:i})}async webSocketMessage(t,e){const s=t.deserializeAttachment?.();if(s){if(u(s.expiresAt)){l(t);return}try{if(typeof e=="string"){await this.handleControl(t,s,e);return}this.bufferAudio(s.connectionId,new Uint8Array(e),t)}catch(n){this.send(t,{message:n instanceof Error?n.message:String(n),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 y({env:this.env,label:"@lunora/agent voice",...s===void 0?{}:{identity:s}})}async transcribe(t){const e=A(t);return S(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 n;try{n=JSON.parse(s)}catch{return}if(n.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(n.type==="commit"){const i=this.drainAudio(e.connectionId);await this.runTurn(t,e,{pcm:i});return}await this.runTurn(t,e,{text:n.text})}bufferAudio(t,e,s){const n=(this.bufferedBytes.get(t)??0)+e.byteLength;if(n>F){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,n)}drainAudio(t){const e=this.audioBuffers.get(t)??[];this.audioBuffers.delete(t),this.bufferedBytes.delete(t);const s=e.reduce((r,c)=>r+c.byteLength,0),n=new Uint8Array(s);let i=0;for(const r of e)n.set(r,i),i+=r.byteLength;return n}async runTurn(t,e,s){const n=new AbortController;this.controllers.set(e.connectionId,n);try{await I({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:n.signal,streamGenerate:this.streamGenerate,synthesize:async(i,r)=>this.synthesizeWithSignal(i,r),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)===n&&this.controllers.delete(e.connectionId),t.serializeAttachment?.({...e,turn:e.turn+1})}}async speakGreeting(t,e,s,n,i,r){const c=this.resolveRun(n,i),o=new AbortController,d=()=>o.signal.aborted;this.controllers.set(e,o);try{await c(f(this.paths.ensureThread),{agent:this.exportName,key:s,...this.agent.initialState===void 0?{}:{initialState:this.agent.initialState},...n===void 0?{}:{owner:n}});for await(const a of k(await this.synthesizeWithSignal(r,o.signal))){if(d()||(await this.waitForSocketDrain(t),d()))break;this.sendAudio(t,a)}d()||(await c(f(this.paths.appendMessage),{content:r,messageKey:"voice:greeting:assistant",role:"assistant",threadKey:s}),this.send(t,{text:r,type:"assistant_done"}))}catch(a){this.send(t,{message:a instanceof Error?a.message:String(a),type:"error"})}finally{this.controllers.get(e)===o&&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>N&&s<T;)await new Promise(n=>{setTimeout(n,p)}),s+=p}}export{L as default};
@@ -1 +1 @@
1
- import{LunoraError as p}from"@lunora/errors";import{jsonSchema as T}from"ai";import{isDuplicateInstanceError as $}from"../channels.mjs";import{agentBindingName as N}from"../naming.mjs";import{toFunctionReference as b,DEFAULT_AGENT_FUNCTION_PATHS as E}from"./AGENT_MODULE-BXx-tSCe.mjs";const A=new Set(["complete","errored","terminated"]),I=120,S=500,L=e=>e!==null&&typeof e=="object"&&typeof e.status=="string"?e.status:"unknown",k=async e=>{await new Promise(t=>{setTimeout(t,e)})},C=async(e,t,n,u)=>{for(let a=0;a<t;a+=1){const i=L(await e.status());if(A.has(i))return i;await u(n)}return"timeout"},R=e=>{for(let t=e.length-1;t>=0;t-=1){const n=e[t];if(n?.role==="assistant"&&(n.toolCalls===void 0||n.toolCalls.length===0))return n.content}return""},j=e=>{if(typeof e.name!="string"||e.name.length===0)throw new p("INTERNAL","@lunora/agent: agent.asTool requires a `name` (the child agent's export name, selecting its AGENT_* binding)");if(typeof e.description!="string"||e.description.length===0)throw new p("INTERNAL","@lunora/agent: agent.asTool requires a non-empty `description` (the parent model decides from it)");const{name:t}=e,n=N(t),u=e.maxPolls??I,a=e.pollIntervalMs??S,i=e.wait??k,m=b(E.listMessages),f=async(w,r)=>{const o=r.env[n];if(!o||typeof o.create!="function"||typeof o.get!="function")throw new p("INTERNAL",`@lunora/agent: agent.asTool("${t}") found no Workflow binding "${n}" on env — declare the "${t}" agent so codegen wires its binding`);const d=`${r.threadKey}::sub::${t}::${r.toolCallId}`,g=`sub-${t}-${r.toolCallId}`,h={input:w.prompt,threadKey:d};let c;try{const l=await o.create({id:g,params:h});c=await o.get(l.id)}catch(l){if(!$(l))throw l;c=await o.get(g)}const s=await C(c,u,a,i);if(s==="errored"||s==="terminated")return`Sub-agent "${t}" ${s} before producing an answer.`;if(s==="timeout")return`Sub-agent "${t}" did not finish within the allotted time.`;const y=await r.run(m,{key:d});return R(y)};return{description:e.description,execute:f,inputSchema:T({properties:{prompt:{description:"The task or question to delegate to the sub-agent.",type:"string"}},required:["prompt"],type:"object"}),isLunoraAgentTool:!0}};export{j as agentAsTool};
1
+ import{LunoraError as p}from"@lunora/errors";import{jsonSchema as T}from"ai";import{isDuplicateInstanceError as $}from"../channels.mjs";import{agentBindingName as N}from"../naming.mjs";import{toFunctionReference as b,DEFAULT_AGENT_FUNCTION_PATHS as E}from"./AGENT_MODULE-gxKUkiCE.mjs";const A=new Set(["complete","errored","terminated"]),I=120,S=500,L=e=>e!==null&&typeof e=="object"&&typeof e.status=="string"?e.status:"unknown",k=async e=>{await new Promise(t=>{setTimeout(t,e)})},C=async(e,t,n,u)=>{for(let a=0;a<t;a+=1){const i=L(await e.status());if(A.has(i))return i;await u(n)}return"timeout"},R=e=>{for(let t=e.length-1;t>=0;t-=1){const n=e[t];if(n?.role==="assistant"&&(n.toolCalls===void 0||n.toolCalls.length===0))return n.content}return""},j=e=>{if(typeof e.name!="string"||e.name.length===0)throw new p("INTERNAL","@lunora/agent: agent.asTool requires a `name` (the child agent's export name, selecting its AGENT_* binding)");if(typeof e.description!="string"||e.description.length===0)throw new p("INTERNAL","@lunora/agent: agent.asTool requires a non-empty `description` (the parent model decides from it)");const{name:t}=e,n=N(t),u=e.maxPolls??I,a=e.pollIntervalMs??S,i=e.wait??k,m=b(E.listMessages),f=async(w,r)=>{const o=r.env[n];if(!o||typeof o.create!="function"||typeof o.get!="function")throw new p("INTERNAL",`@lunora/agent: agent.asTool("${t}") found no Workflow binding "${n}" on env — declare the "${t}" agent so codegen wires its binding`);const d=`${r.threadKey}::sub::${t}::${r.toolCallId}`,g=`sub-${t}-${r.toolCallId}`,h={input:w.prompt,threadKey:d};let c;try{const l=await o.create({id:g,params:h});c=await o.get(l.id)}catch(l){if(!$(l))throw l;c=await o.get(g)}const s=await C(c,u,a,i);if(s==="errored"||s==="terminated")return`Sub-agent "${t}" ${s} before producing an answer.`;if(s==="timeout")return`Sub-agent "${t}" did not finish within the allotted time.`;const y=await r.run(m,{key:d});return R(y)};return{description:e.description,execute:f,inputSchema:T({properties:{prompt:{description:"The task or question to delegate to the sub-agent.",type:"string"}},required:["prompt"],type:"object"}),isLunoraAgentTool:!0}};export{j as agentAsTool};
@@ -1 +1 @@
1
- import{jsonSchema as u}from"ai";import{toFunctionReference as d}from"./AGENT_MODULE-BXx-tSCe.mjs";const y=240,h=50,m=(t,i)=>t.length<=i?t:`${t.slice(0,i)}…`,l=t=>{if(!(t===void 0||!Number.isFinite(t)))return Math.min(h,Math.max(1,Math.trunc(t)))},f=(t,i)=>{const r=t??{},s=Array.isArray(r.chunks)?r.chunks:[],e=Array.isArray(r.sources)?r.sources:[];return{results:s.map(o=>({id:typeof o.id=="string"?o.id:"",score:typeof o.score=="number"?o.score:0,snippet:m(typeof o.text=="string"?o.text:"",i),sourceId:typeof o.sourceId=="string"?o.sourceId:""})),sources:e}},g=u({additionalProperties:!1,properties:{query:{description:"Natural-language search query.",type:"string"},topK:{description:"Maximum number of hits to return.",type:"number"}},required:["query"],type:"object"}),k=u({additionalProperties:!1,properties:{id:{description:"The `id` of a hit returned by the search tool.",type:"string"}},required:["id"],type:"object"}),x=(t,i,r)=>{const s=d(i),e=Math.max(1,t.snippetChars??y),o=t.topK;return{description:`Search long-term memory for passages relevant to a query. Returns ranked { id, sourceId, score, snippet } hits — call again with a refined query to dig deeper.${r===void 0?"":` Use \`${r}\` with a hit's \`id\` to fetch its full text.`}`,execute:async(n,a)=>{const c=l(n.topK)??o,p=await a.run(s,{query:n.query,...c===void 0?{}:{topK:c}});return f(p,e)},inputSchema:g,isLunoraAgentTool:!0}},q=t=>{const i=d(t);return{description:"Fetch the full text of a memory document by the `id` from a search hit.",execute:(r,s)=>s.run(i,{id:r.id}),inputSchema:k,isLunoraAgentTool:!0}},A=(t,i)=>{const r=[];t.memory&&r.push({key:"default",...t.memory});for(const e of i)e.knowledge&&r.push({key:e.name,...e.knowledge});const s={};for(const e of r){if(e.kind==="graph"||e.kind==="episodic"||e.mode!=="agentic"||e.source===void 0)continue;const o=e.key==="default"?"searchMemory":`search_${e.key}`,n=e.key==="default"?"readMemory":`read_${e.key}`,a=e.read!==void 0;s[o]=x(e,e.source,a?n:void 0),a&&(s[n]=q(e.read))}return s};export{A as collectAgenticMemoryTools,f as toSearchResults};
1
+ import{jsonSchema as u}from"ai";import{toFunctionReference as d}from"./AGENT_MODULE-gxKUkiCE.mjs";const y=240,h=50,m=(t,i)=>t.length<=i?t:`${t.slice(0,i)}…`,l=t=>{if(!(t===void 0||!Number.isFinite(t)))return Math.min(h,Math.max(1,Math.trunc(t)))},f=(t,i)=>{const r=t??{},s=Array.isArray(r.chunks)?r.chunks:[],e=Array.isArray(r.sources)?r.sources:[];return{results:s.map(o=>({id:typeof o.id=="string"?o.id:"",score:typeof o.score=="number"?o.score:0,snippet:m(typeof o.text=="string"?o.text:"",i),sourceId:typeof o.sourceId=="string"?o.sourceId:""})),sources:e}},g=u({additionalProperties:!1,properties:{query:{description:"Natural-language search query.",type:"string"},topK:{description:"Maximum number of hits to return.",type:"number"}},required:["query"],type:"object"}),k=u({additionalProperties:!1,properties:{id:{description:"The `id` of a hit returned by the search tool.",type:"string"}},required:["id"],type:"object"}),x=(t,i,r)=>{const s=d(i),e=Math.max(1,t.snippetChars??y),o=t.topK;return{description:`Search long-term memory for passages relevant to a query. Returns ranked { id, sourceId, score, snippet } hits — call again with a refined query to dig deeper.${r===void 0?"":` Use \`${r}\` with a hit's \`id\` to fetch its full text.`}`,execute:async(n,a)=>{const c=l(n.topK)??o,p=await a.run(s,{query:n.query,...c===void 0?{}:{topK:c}});return f(p,e)},inputSchema:g,isLunoraAgentTool:!0}},q=t=>{const i=d(t);return{description:"Fetch the full text of a memory document by the `id` from a search hit.",execute:(r,s)=>s.run(i,{id:r.id}),inputSchema:k,isLunoraAgentTool:!0}},A=(t,i)=>{const r=[];t.memory&&r.push({key:"default",...t.memory});for(const e of i)e.knowledge&&r.push({key:e.name,...e.knowledge});const s={};for(const e of r){if(e.kind==="graph"||e.kind==="episodic"||e.mode!=="agentic"||e.source===void 0)continue;const o=e.key==="default"?"searchMemory":`search_${e.key}`,n=e.key==="default"?"readMemory":`read_${e.key}`,a=e.read!==void 0;s[o]=x(e,e.source,a?n:void 0),a&&(s[n]=q(e.read))}return s};export{A as collectAgenticMemoryTools,f as toSearchResults};
@@ -1 +1 @@
1
- import{defineWorkflow as m}from"@lunora/workflow";import{runAgentLoop as i}from"./runAgentLoop-nuk5NsAn.mjs";import{createStreamGenerate as p,createAgentGenerate as c,createEpisodeExtract as l,createGraphExtract as d,createCompact as f}from"./createAgentGenerate-BS1vasdV.mjs";import{agentDefaultName as u}from"../naming.mjs";import{DEFAULT_AGENT_FUNCTION_PATHS as v}from"./AGENT_MODULE-BXx-tSCe.mjs";import{A as E}from"./createDispatchRunner-EYOnoElU-CpVpdTXn.mjs";import{otlpTelemetry as N}from"./otlpTelemetry-DcW9mOLV.mjs";const T=(t,r,a)=>r===void 0?t:E({env:a,identity:{userId:r},label:"@lunora/agent"}),y=(t,r,a)=>{const e=r.LUNORA_OTLP_ENDPOINT;if(typeof e!="string"||e===""||t.telemetry?.isEnabled===!1)return t;const n=typeof r.LUNORA_OTLP_TOKEN=="string"?r.LUNORA_OTLP_TOKEN:void 0,o=[t.telemetry?.integrations].flat().filter(s=>s!==void 0);return{...t,telemetry:{...t.telemetry,integrations:[...o,N({conversationId:a,endpoint:e,token:n})],isEnabled:!0}}},G=(t,r,a)=>m({handler:async e=>{const n=y(t,e.env,e.params.threadKey);return i({agent:n,compact:f(),env:e.env,exportName:r,extractGraph:d(),extractEpisode:l(),generate:c(n,e.env),instanceId:e.event.instanceId,params:e.params,paths:a?.paths??v,run:T(e.run,e.params.owner,e.env),step:e.step,streamGenerate:p(n,e.env)})},name:t.name??u(r)});export{G as default};
1
+ import{defineWorkflow as m}from"@lunora/workflow";import{runAgentLoop as i}from"./runAgentLoop-D1-SHp-g.mjs";import{createStreamGenerate as p,createAgentGenerate as c,createEpisodeExtract as l,createGraphExtract as d,createCompact as f}from"./createAgentGenerate-BS1vasdV.mjs";import{agentDefaultName as u}from"../naming.mjs";import{DEFAULT_AGENT_FUNCTION_PATHS as v}from"./AGENT_MODULE-gxKUkiCE.mjs";import{K as E}from"./createDispatchRunner-BBuuGx3w-CLhnUgka.mjs";import{otlpTelemetry as N}from"./otlpTelemetry-DcW9mOLV.mjs";const T=(t,r,a)=>r===void 0?t:E({env:a,identity:{userId:r},label:"@lunora/agent"}),y=(t,r,a)=>{const e=r.LUNORA_OTLP_ENDPOINT;if(typeof e!="string"||e===""||t.telemetry?.isEnabled===!1)return t;const n=typeof r.LUNORA_OTLP_TOKEN=="string"?r.LUNORA_OTLP_TOKEN:void 0,o=[t.telemetry?.integrations].flat().filter(s=>s!==void 0);return{...t,telemetry:{...t.telemetry,integrations:[...o,N({conversationId:a,endpoint:e,token:n})],isEnabled:!0}}},G=(t,r,a)=>m({handler:async e=>{const n=y(t,e.env,e.params.threadKey);return i({agent:n,compact:f(),env:e.env,exportName:r,extractGraph:d(),extractEpisode:l(),generate:c(n,e.env),instanceId:e.event.instanceId,params:e.params,paths:a?.paths??v,run:T(e.run,e.params.owner,e.env),step:e.step,streamGenerate:p(n,e.env)})},name:t.name??u(r)});export{G as default};
@@ -1 +1 @@
1
- import{A as f}from"./createDispatchRunner-EYOnoElU-CpVpdTXn.mjs";import{LunoraError as i}from"@lunora/errors";import{h as g,B as l}from"./branch-marker-DELZqEOQ.mjs";import{toFunctionReference as p,DEFAULT_AGENT_FUNCTION_PATHS as w}from"./AGENT_MODULE-BXx-tSCe.mjs";const h=(r,c,s)=>{const o={},u=p(w.patchThread),d=()=>s??f({env:r,label:"@lunora/agent"});for(const t of c){const a=()=>{const n=r[t.binding];if(!n||typeof n.create!="function"||typeof n.get!="function")throw new i("INTERNAL",`@lunora/agent: no Workflow binding "${t.binding}" on env for agent "${t.exportName}" — run codegen/dev so wrangler.jsonc declares it`);return n};o[t.exportName]={cancel:async n=>{await(await a().get(n)).terminate();try{await d()(u,{instanceId:n,status:"cancelled"})}catch{}},publicRun:t.publicRun===!0,run:async(n,e)=>{if(g(n))throw new i("BAD_REQUEST",`@lunora/agent: run input ${l}`);return{id:(await a().create({...e?.id===void 0?{}:{id:e.id},params:n})).id}},sendEvent:async(n,e)=>{await(await a().get(n)).sendEvent(e)},status:async n=>(await a().get(n)).status()}}return o};export{h as default};
1
+ import{K as f}from"./createDispatchRunner-BBuuGx3w-CLhnUgka.mjs";import{LunoraError as i}from"@lunora/errors";import{h as g,B as l}from"./branch-marker-DELZqEOQ.mjs";import{toFunctionReference as p,DEFAULT_AGENT_FUNCTION_PATHS as w}from"./AGENT_MODULE-gxKUkiCE.mjs";const h=(r,c,s)=>{const o={},u=p(w.patchThread),d=()=>s??f({env:r,label:"@lunora/agent"});for(const t of c){const a=()=>{const n=r[t.binding];if(!n||typeof n.create!="function"||typeof n.get!="function")throw new i("INTERNAL",`@lunora/agent: no Workflow binding "${t.binding}" on env for agent "${t.exportName}" — run codegen/dev so wrangler.jsonc declares it`);return n};o[t.exportName]={cancel:async n=>{await(await a().get(n)).terminate();try{await d()(u,{instanceId:n,status:"cancelled"})}catch{}},publicRun:t.publicRun===!0,run:async(n,e)=>{if(g(n))throw new i("BAD_REQUEST",`@lunora/agent: run input ${l}`);return{id:(await a().create({...e?.id===void 0?{}:{id:e.id},params:n})).id}},sendEvent:async(n,e)=>{await(await a().get(n)).sendEvent(e)},status:async n=>(await a().get(n)).status()}}return o};export{h as default};
@@ -0,0 +1 @@
1
+ import{LunoraError as i}from"@lunora/errors";const O=t=>{let e="";for(let r=0;r<t.length;r+=32768)e+=String.fromCharCode(...t.subarray(r,r+32768));return btoa(e)},m=t=>O(t).replaceAll("+","-").replaceAll("/","_").replace(/=+$/,"");new TextDecoder;const w=new TextEncoder,N="=",R=t=>{for(let e=0;e<t.length;e+=1)if(t.charCodeAt(e)>255)return!1;return!0},I=t=>m(w.encode(JSON.stringify(t))),T=t=>!t.startsWith(N)&&R(t)?t:`${N}${m(w.encode(t))}`,_="/_lunora/scheduler/dispatch",L=3e4,E=t=>{let e=t.length;for(;e>0&&t[e-1]==="/";)e-=1;return t.slice(0,e)},S=Symbol("lunoraDispatchFailure"),g=t=>(Object.defineProperty(t,S,{value:!0}),t),v=(t,e,r)=>{try{const o=JSON.parse(r)?.error;if(typeof o=="object"&&o!==null&&typeof o.code=="string"){const{code:c,data:u,message:s}=o;return g(new i(c,typeof s=="string"?s:void 0,{data:u,status:e}))}}catch{}return g(new i("INTERNAL",`${t}: function dispatch failed (${String(e)}): ${r}`,{status:e}))},x=(t,e,r)=>new i("INTERNAL",`${t}: function dispatch to "${e}" timed out after ${String(r)}ms`,{status:503}),U=t=>{const{label:e}=t,r=globalThis.fetch,o=t.fetchImpl??(typeof r=="function"?r.bind(globalThis):void 0);return async(c,u,s={})=>{if(typeof o!="function")throw new TypeError(`${e}: no fetch implementation available — pass fetchImpl or run on a platform with global fetch`);const h=t.env.LUNORA_ORIGIN_URL;if(typeof h!="string"||h.length===0)throw new i("INTERNAL",`${e}: \`LUNORA_ORIGIN_URL\` must be set on the Worker env so a handler can call back into Lunora functions`);const f=t.env.LUNORA_ADMIN_TOKEN;if(typeof f!="string"||f.length===0)throw new i("INTERNAL",`${e}: \`LUNORA_ADMIN_TOKEN\` must be set on the Worker env to authenticate function dispatch`);const $=`${E(h)}${_}`,d={authorization:`Bearer ${f}`,"content-type":"application/json"};t.identity?.userId!==void 0&&(d["x-lunora-userid"]=T(t.identity.userId)),t.identity?.claims!==void 0&&(d["x-lunora-identity"]=I(t.identity.claims));const y=s.timeoutMs??L,b=AbortSignal.timeout(y),p=n=>{throw n instanceof Error&&n.name==="TimeoutError"?x(e,c.__lunoraRef,y):n};let a;try{a=await o($,{body:JSON.stringify({args:u??{},functionPath:c.__lunoraRef,shardKey:s.shardKey}),headers:d,method:"POST",signal:b})}catch(n){return p(n)}if(!a.ok){let n;try{n=await a.text()}catch(A){return p(A)}throw v(e,a.status,n)}let l;try{l=await a.text()}catch(n){return p(n)}if(l.length!==0)try{return JSON.parse(l)}catch{throw new i("INTERNAL",`${e}: function dispatch returned a non-JSON body (${String(a.status)}): ${l}`,{status:a.status})}}};export{U as K};
@@ -1,3 +1,3 @@
1
- import{LunoraError as s}from"@lunora/errors";import{collectAgenticMemoryTools as f}from"./collectAgenticMemoryTools-DBcP8dUa.mjs";import{agentAsTool as d}from"./agentAsTool-gH17BQ8M.mjs";import{r as m}from"./memory-DNRyyp1b.mjs";import{SKILL_NAME_PATTERN as h,RESERVED_SKILL_NAME as c}from"./defineSkill-DfJxCwfZ.mjs";const w=/^[a-zA-Z][\w-]*$/u,p=(e,r)=>{const o={...e.tools};for(const n of r)for(const[t,a]of Object.entries(n.tools??{})){if(Object.hasOwn(o,t))throw new s("INTERNAL",`@lunora/agent: skill "${n.name}" tool "${t}" collides with an existing tool — rename one (the agent's tool namespace is flat)`);o[t]=a}return o},y=(e,r)=>{const o=[];for(const n of[e.instructions,...r.map(t=>t.instructions)])n&&o.push(n);return o.length<=1?o[0]:n=>o.map(t=>typeof t=="function"?t(n):t).filter(t=>t.length>0).join(`
1
+ import{LunoraError as s}from"@lunora/errors";import{collectAgenticMemoryTools as f}from"./collectAgenticMemoryTools-cvrzaCqe.mjs";import{agentAsTool as d}from"./agentAsTool-Cusr5NF2.mjs";import{r as m}from"./memory-DNRyyp1b.mjs";import{SKILL_NAME_PATTERN as h,RESERVED_SKILL_NAME as c}from"./defineSkill-DfJxCwfZ.mjs";const w=/^[a-zA-Z][\w-]*$/u,p=(e,r)=>{const o={...e.tools};for(const n of r)for(const[t,a]of Object.entries(n.tools??{})){if(Object.hasOwn(o,t))throw new s("INTERNAL",`@lunora/agent: skill "${n.name}" tool "${t}" collides with an existing tool — rename one (the agent's tool namespace is flat)`);o[t]=a}return o},y=(e,r)=>{const o=[];for(const n of[e.instructions,...r.map(t=>t.instructions)])n&&o.push(n);return o.length<=1?o[0]:n=>o.map(t=>typeof t=="function"?t(n):t).filter(t=>t.length>0).join(`
2
2
 
3
3
  `)},N=(e,r)=>{const o=[];e.memory&&m(e.memory)&&o.push({key:"default",...e.memory});for(const n of r)n.knowledge&&m(n.knowledge)&&o.push({key:n.name,...n.knowledge});return o},T=e=>{const r=new Set;for(const o of e){if(typeof o.name!="string"||!h.test(o.name))throw new s("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 s("INTERNAL",`@lunora/agent: skill name "${c}" is reserved (it keys the agent's own \`memory\` source / the \`memory:retrieve\` step) — choose another name`);if(r.has(o.name))throw new s("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)`);r.add(o.name)}},A=(e,r)=>{if(e===void 0)return;const o=Object.keys(r).filter(n=>!e.includes(n));if(o.length>0)throw new s("INTERNAL",`@lunora/agent: \`activeTools\` omits the agentic-memory tool(s) ${o.map(n=>`"${n}"`).join(", ")} — the model could never call them; add them to \`activeTools\` (or drop \`activeTools\` to expose every tool)`)},k=(e,r)=>{const o=(n,t)=>{if(n&&n.kind!=="graph"&&n.kind!=="episodic"&&n.source===void 0)throw new s("INTERNAL",`@lunora/agent: ${t} requires a \`source\` action unless \`kind: "graph"\` or \`kind: "episodic"\``)};o(e.memory,"`memory`");for(const n of r)o(n.knowledge,`skill "${n.name}" \`knowledge\``)},$=e=>{const r=e.model;if(r==null||typeof r=="string"&&r.length===0)throw new s("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 s("INTERNAL","@lunora/agent: `maxTurns` must be a positive integer");const o=e.skills??[];T(o),k(e,o);const n=p(e,o),t=f(e,o);for(const[i,g]of Object.entries(t)){if(Object.hasOwn(n,i))throw new s("INTERNAL",`@lunora/agent: agentic-memory tool "${i}" collides with an existing tool — rename one (the agent's tool namespace is flat)`);n[i]=g}const a=Object.keys(t).length>0;A(e.activeTools,t);for(const i of Object.keys(n))if(!w.test(i))throw new s("INTERNAL",`@lunora/agent: tool name "${i}" is not a valid identifier (letters, digits, _ or -, starting with a letter)`);const l=N(e,o),u=y(e,o);return{...e,asTool:d,isLunoraAgent:!0,...o.some(i=>!!i.instructions)?{instructions:u}:{},...l.length>0?{memorySources:l}:{},...o.length>0||a?{tools:n}:{}}},b=e=>typeof e=="object"&&e!==null&&e.isLunoraAgent===!0,j=e=>{if(typeof e.execute!="function")throw new s("INTERNAL","@lunora/agent: defineAgentTool requires an `execute` function");if(typeof e.description!="string"||e.description.length===0)throw new s("INTERNAL","@lunora/agent: defineAgentTool requires a non-empty `description` (the model decides from it)");return{...e,isLunoraAgentTool:!0}};export{$ as defineAgent,j as defineAgentTool,b as isAgentDefinition};
@@ -1 +1 @@
1
- import{LunoraError as e}from"@lunora/errors";import{toFunctionReference as c}from"./AGENT_MODULE-BXx-tSCe.mjs";const s=(n,o)=>{if(typeof o.description!="string"||o.description.length===0)throw new e("INTERNAL","@lunora/agent: functionTool requires a non-empty `description` (the model decides from it)");if(o.inputSchema===void 0)throw new e("INTERNAL","@lunora/agent: functionTool requires an `inputSchema` (a zod schema or `jsonSchema(...)`)");const t=c(n);return{description:o.description,execute:(r,i)=>i.run(t,r),inputSchema:o.inputSchema,isLunoraAgentTool:!0}};export{s as functionTool};
1
+ import{LunoraError as e}from"@lunora/errors";import{toFunctionReference as c}from"./AGENT_MODULE-gxKUkiCE.mjs";const s=(n,o)=>{if(typeof o.description!="string"||o.description.length===0)throw new e("INTERNAL","@lunora/agent: functionTool requires a non-empty `description` (the model decides from it)");if(o.inputSchema===void 0)throw new e("INTERNAL","@lunora/agent: functionTool requires an `inputSchema` (a zod schema or `jsonSchema(...)`)");const t=c(n);return{description:o.description,execute:(r,i)=>i.run(t,r),inputSchema:o.inputSchema,isLunoraAgentTool:!0}};export{s as functionTool};
@@ -0,0 +1,3 @@
1
+ import{s as J}from"./component-shared-BVjAbtUu.mjs";import{resolveAgentModel as L}from"./createAgentGenerate-BS1vasdV.mjs";import{i as Y,c as K,t as Z,n as z}from"./memory-DNRyyp1b.mjs";import{buildModelMessages as F}from"./buildModelMessages-Dm2wVNQy.mjs";import{agentBindingName as G}from"../naming.mjs";import{toFunctionReference as v}from"./AGENT_MODULE-gxKUkiCE.mjs";const Q=8,P=e=>e===void 0?"null":JSON.stringify(e),V=e=>e===void 0?[]:[e].flat(),X=async(e,t)=>(await Promise.all(e.map(async o=>o({steps:t})))).some(Boolean),tt=(e,t)=>{if(t===void 0)return e;if(e===void 0)return{...t};const o={};for(const a of["inputTokens","outputTokens","totalTokens"])(e[a]!==void 0||t[a]!==void 0)&&(o[a]=(e[a]??0)+(t[a]??0));return o},et=async(e,t,o,a,s)=>{const{needsApproval:r}=e;return r===void 0||r===!1?!1:r===!0?!0:o.do(a,async()=>r(t,s))},at=async(e,t)=>{const{instanceId:o,patchThread:a,persist:s,step:r}=e;await s({content:`Awaiting approval to run tool "${t.name}".`,messageKey:`${o}:approval:${t.id}`,role:"tool",status:"awaiting_approval",toolCallId:t.id,toolName:t.name}),await a({status:"awaiting_input"});const i=await r.waitForEvent(`approval:${t.id}`,{type:`agent-approval:${t.id}`});return await a({status:"running"}),{decision:i.payload.decision,...i.payload.note===void 0?{}:{note:i.payload.note}}},ot=async(e,t)=>{const{env:o,getState:a,instanceId:s,onTokenDelta:r,persist:i,run:l,setState:d,step:p,threadKey:n,tools:u}=e,c=`tool:${t.name}:${t.id}`,m=u[t.name],h=`${s}:tool:${t.id}`;if(!m){await i({content:`Error: unknown tool "${t.name}"`,messageKey:h,role:"tool",stepName:c,toolCallId:t.id,toolName:t.name});return}const w=T=>{r?.({data:T,kind:"progress",threadKey:n,toolCallId:t.id})},C={env:o,getState:a,idempotencyKey:c,reportProgress:w,run:l,setState:d,threadKey:n,toolCallId:t.id},g={env:o,getState:a,idempotencyKey:c,reportProgress:w,run:l,threadKey:n,toolCallId:t.id},$=`tool:approval-gate:${t.id}`;let f;if(await et(m,t.input,p,$,g)){const{decision:T,note:I}=await at(e,t);if(T==="reject"){const M=I===void 0?"":` Reason: ${I}`;await i({content:`Tool "${t.name}" was rejected by the user and not run.${M}`,messageKey:h,role:"tool",status:"rejected",stepName:c,toolCallId:t.id,toolName:t.name});return}f="approved"}const k=await p.do(c,()=>Promise.resolve(m.execute(t.input,C)));await i({content:typeof k=="string"?k:P(k),messageKey:h,role:"tool",stepName:c,...f===void 0?{}:{status:f},toolCallId:t.id,toolName:t.name})},st=(e,t,o)=>{if(!t)return e;let{messages:a}=e;return t.messages!==void 0&&(a=t.messages),t.system!==void 0&&(a=[{content:t.system,role:"system"},...a]),{activeTools:t.activeTools??e.activeTools,messages:a,model:t.model===void 0?e.model:L(t.model,o),toolChoice:t.toolChoice??e.toolChoice}},nt=(e,t)=>{if(t===void 0||e.length<=t.maxMessages)return;const o=Math.max(1,t.keepRecent??Math.ceil(t.maxMessages/2));if(e.length<=o)return;let a=e.length-o;for(;a>0&&e[a]?.role==="tool";)a-=1;if(!(a<=0))return{older:e.slice(0,a),recent:e.slice(a)}},rt=async(e,t)=>{const{agent:o,compact:a,env:s}=e,r=nt(t,o.compaction);if(r===void 0||a===void 0)return{history:t,summary:void 0};try{const i=await a({env:s,messages:F({history:r.older}),model:o.compaction?.model??o.model});return i.length>0?{history:r.recent,summary:i}:{history:t,summary:void 0}}catch{return{history:t,summary:void 0}}},it=async(e,t,o)=>{const{agent:a,env:s,generate:r,instructions:i,listMessages:l,memoryContext:d,onTokenDelta:p,run:n,step:u,streamGenerate:c,threadKey:m}=e;return u.do(`llm:turn:${String(t)}`,async()=>{const h=await n(l,{key:m}),{history:w,summary:C}=await rt(e,h);let g={activeTools:a.activeTools,messages:F({history:w,instructions:i,memoryContext:d,summary:C}),model:void 0,toolChoice:a.toolChoice};a.prepareStep&&(g=st(g,await a.prepareStep({messages:g.messages,stepNumber:t,steps:o}),s));const $={messages:g.messages,...g.activeTools===void 0?{}:{activeTools:g.activeTools},...g.model===void 0?{}:{model:g.model},...g.toolChoice===void 0?{}:{toolChoice:g.toolChoice}};return c&&p?c($,f=>{p({text:f,threadKey:m,turn:t})}):r($)})},b=async(e,t)=>{const{agent:o,step:a}=e;o.onStepFinish&&await a.do(`agent:step-finish:${String(t.turn)}`,async()=>(await o.onStepFinish?.(t),!0))},dt=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},ct=e=>J({depth:e?.depth,fanOut:e?.fanOut,maxNodes:e?.maxNodes,maxSeeds:e?.maxSeeds}),lt=async(e,t,o,a)=>{if(e.source===void 0)return;const s=v(e.source),{topK:r}=e,i=K("memory:retrieve",e.key),l=await o.do(i,async()=>a(s,{query:t,...r===void 0?{}:{topK:r}}));return A(l)},ut=async(e,t,o,a,s,r)=>{if(o===void 0)return;const i=K("memory:traverse",e.key),l=await s.do(i,async()=>r(a,{owner:o,query:t,...ct(e.graph)}));return A(l)},pt=async(e,t,o,a,s)=>{if(t===void 0)return;const r=K("memory:recall",e.key),i={owner:t,...e.episodic?.recall===void 0?{}:{limit:e.episodic.recall}},l=await a.do(r,async()=>s(o,i));return A(l)},mt=async(e,t)=>e.kind==="episodic"?pt(e,t.owner,t.episodeRecall,t.step,t.run):e.kind==="graph"?ut(e,t.input,t.owner,t.graphTraverse,t.step,t.run):lt(e,t.input,t.step,t.run),yt=e=>{const t=e.findIndex(o=>o.kind==="episodic");return e.filter((o,a)=>o.kind!=="episodic"||a===t)},gt=async(e,t,o,a,s,r)=>{const i=yt(z(e));if(i.length===0)return;const l=v(a.graphTraverse),d=v(a.episodeRecall),p=[];for(const n of i){const u=await mt(n,{episodeRecall:d,graphTraverse:l,input:t,owner:o,run:r,step:s});u!==void 0&&p.push(u)}return p.length>0?p.join(`
2
+
3
+ `):void 0},vt=async e=>{const{agent:t,env:o,extractGraph:a,finalText:s,input:r,instanceId:i,owner:l,paths:d,run:p,step:n}=e;if(a===void 0||l===void 0||s===void 0||s.length===0)return;const u=Y(t);if(u!==void 0)try{const c={assistantText:s,env:o,model:u.graph?.extractionModel??t.model,userInput:r},m=await n.do(K("memory:extract",u.key),async()=>a(c));await p(v(d.graphUpsert),{...m,messageKey:`${i}:${K("extract",u.key)}`,owner:l})}catch{}},ht=async e=>{const{agent:t,env:o,extractEpisode:a,finalText:s,input:r,instanceId:i,owner:l,paths:d,run:p,step:n,threadKey:u}=e;if(a===void 0||l===void 0||s===void 0||s.length===0)return;const c=Z(t);if(c!==void 0)try{const m={assistantText:s,env:o,model:c.episodic?.extractionModel??t.model,userInput:r},{summary:h}=await n.do(K("memory:episode",c.key),async()=>a(m));await p(v(d.episodeUpsert),{messageKey:`${i}:${K("episode",c.key)}`,owner:l,summary:h,threadKey:u})}catch{}},wt=async(e,t,o)=>{const a=e[G(t)];if(!(!a||typeof a.get!="function"))try{await(await a.get(o)).terminate()}catch{}},ft="12 hours",xt=async(e,t,o)=>{await e.waitForEvent(`dequeue:${o}`,{timeout:ft,type:`agent-dequeue:${t}:${o}`})},Kt=async(e,t,o)=>{const a=e.env[G(e.exportName)];if(!a||typeof a.get!="function")return;const s=a.get.bind(a);try{await e.step.do(`dequeue-wake:${o}`,async()=>(await(await s(o)).sendEvent({payload:{threadKey:t},type:`agent-dequeue:${t}:${o}`}),o))}catch{}},$t=async(e,t,o)=>{const{onReply:a}=e,{replyRef:s}=t.params;if(!(a===void 0||s===void 0))try{await t.step.do("agent:reply",async()=>(await a({env:t.env,replyRef:s,result:o,threadKey:t.params.threadKey}),s.channel))}catch{}},Ct=async(e,t,o,a,s)=>{const{instanceId:r,persist:i}=e,l=o.usage===void 0?{}:{usage:o.usage};if(o.toolCalls.length===0){const d=o.output!==void 0&&o.text.length===0?P(o.output):o.text;return await i({content:d,messageKey:`${r}:assistant:${String(t)}`,role:"assistant"}),await b(e,{text:o.text,toolCalls:[],turn:t,...l}),{final:{stopped:"final",text:o.text,turns:t+1,...o.output===void 0?{}:{output:o.output}}}}await i({content:o.text,messageKey:`${r}:assistant:${String(t)}`,role:"assistant",toolCalls:o.toolCalls});for(const d of o.toolCalls)await ot(e,d);if(await b(e,{text:o.text,toolCalls:o.toolCalls,turn:t,...l}),a.push(dt(o)),s.length>0&&await X(s,a))return"stopCondition"},kt=async(e,t,o,a)=>{const s=[];let r,i=!1,l=0;for(let d=0;d<t;d+=1){const p=await it(e,d,s);a.value=tt(a.value,p.usage),l=d+1;const n=await Ct(e,d,p,s,o);if(n==="stopCondition"){i=!0;break}if(n!==void 0){r=n.final;break}}return{final:r,stoppedByCondition:i,turnsRun:l}},qt=async e=>{const{agent:t,compact:o,env:a,exportName:s,extractEpisode:r,extractGraph:i,generate:l,instanceId:d,onTokenDelta:p,params:n,paths:u,run:c,step:m,streamGenerate:h}=e,w=t.maxTurns??Q,C=V(t.stopWhen),g=v(u.appendMessage),$=v(u.completeRun),f=v(u.ensureThread),k=v(u.listMessages),T=v(u.patchThread),I=v(u.setState),M=v(u.state),E=async y=>{await c(g,{threadKey:n.threadKey,...y})},j=async y=>{await c(T,{key:n.threadKey,...y})},B=async()=>{await E({content:n.input,messageKey:`${d}:user`,role:"user"})},R=async y=>{const N=await c($,{instanceId:d,key:n.threadKey,...y});N?.dequeued!==void 0&&await Kt({env:a,exportName:s,step:m},n.threadKey,N.dequeued)},D=async()=>await c(M,{key:n.threadKey}),O=async y=>{await c(I,{key:n.threadKey,state:y})},q=await c(f,{agent:s,instanceId:d,key:n.threadKey,...t.initialState===void 0?{}:{initialState:t.initialState},...t.onConcurrentRun===void 0?{}:{onConcurrentRun:t.onConcurrentRun},...n.owner===void 0?{}:{owner:n.owner},...n.title===void 0?{}:{title:n.title}});q?.outcome==="replaced"&&await wt(a,s,q.priorInstanceId);const U=await gt(t,n.input,n.owner,u,m,c),_=typeof t.instructions=="function"?t.instructions({env:a,input:n.input,threadKey:n.threadKey}):t.instructions,W={agent:t,compact:o,env:a,generate:l,getState:D,instanceId:d,instructions:_,listMessages:k,memoryContext:U,onTokenDelta:p,patchThread:j,persist:E,run:c,setState:O,step:m,streamGenerate:h,threadKey:n.threadKey,tools:t.tools??{}},S={value:void 0};try{q?.outcome==="queued"&&await xt(m,n.threadKey,d),await B();const{final:y,stoppedByCondition:N,turnsRun:H}=await kt(W,w,C,S),x=S.value===void 0?{}:{usage:S.value};return await vt({agent:t,env:a,extractGraph:i,finalText:y?.text,input:n.input,instanceId:d,owner:n.owner,paths:u,run:c,step:m}),await ht({agent:t,env:a,extractEpisode:r,finalText:y?.text,input:n.input,instanceId:d,owner:n.owner,paths:u,run:c,step:m,threadKey:n.threadKey}),y?(await $t(t,{env:a,params:n,step:m},{...y,...x}),await R({status:"idle",...x}),{...y,...x}):N?(await R({status:"idle",...x}),{stopped:"stopCondition",turns:H,...x}):(await R({error:`agent stopped: maxTurns (${String(w)}) reached`,status:"error",...x}),{stopped:"maxTurns",turns:w,...x})}catch(y){throw await R({error:y instanceof Error?y.message:String(y),status:"error",...S.value===void 0?{}:{usage:S.value}}),y}};export{qt as runAgentLoop,nt as splitForCompaction};
@@ -1 +1 @@
1
- import"./base64-B_qZ_Tyh.mjs";import{X as s,Y as i,e as p,Z as n,Q as m,P as d}from"./voice-turn-DzRKyf-x.mjs";import"./buildModelMessages-Dm2wVNQy.mjs";import"./AGENT_MODULE-BXx-tSCe.mjs";export{s as parseIdentity,i as pcmToWav,p as readSynthesisAudio,n as readTranscriptionText,m as runVoiceTurn,d as toByteIterable};
1
+ import"./base64-B_qZ_Tyh.mjs";import{X as s,Y as i,e as p,Z as n,Q as m,P as d}from"./voice-turn-CoAemsop.mjs";import"./buildModelMessages-Dm2wVNQy.mjs";import"./AGENT_MODULE-gxKUkiCE.mjs";export{s as parseIdentity,i as pcmToWav,p as readSynthesisAudio,n as readTranscriptionText,m as runVoiceTurn,d as toByteIterable};
@@ -386,6 +386,38 @@ interface AgentStepFinishInfo {
386
386
  * @experimental
387
387
  */
388
388
  type AgentOnStepFinish = (info: AgentStepFinishInfo) => Promise<void> | void;
389
+ /**
390
+ * What {@link AgentConfig.onReply} is called with when a triggered run reaches
391
+ * its final answer.
392
+ * @experimental
393
+ */
394
+ interface AgentReplyInfo {
395
+ /** The worker `env` — where an outbound credential (a bot token, a mailer binding) lives. */
396
+ env: Record<string, unknown>;
397
+ /** Where to reply, captured by the mapper that started this run. */
398
+ replyRef: AgentReplyRef;
399
+ /** The run's final answer. */
400
+ result: AgentRunResult;
401
+ /** The thread this run belongs to. */
402
+ threadKey: string;
403
+ }
404
+ /**
405
+ * Send a triggered run's answer back where it came from — the outbound half of
406
+ * an `onEmail` / `onInbound` trigger.
407
+ *
408
+ * Called once, automatically, when a run started with a `replyRef` produces a
409
+ * final answer; a run without one (an ordinary in-app `ctx.agents.<name>.run`)
410
+ * never calls it. It runs inside a named durable step, so a transient failure
411
+ * is retried and a workflow replay does not send the answer twice.
412
+ *
413
+ * Delivery is the app's call, because only the app has the credential: email
414
+ * has a home already (`replyToEmail(mailer, ref, body)` from
415
+ * `@lunora/agent/reply`), while Slack/GitHub/Discord bot tokens have no
416
+ * framework-owned store yet — read them from `info.env` and make the provider
417
+ * call.
418
+ * @experimental
419
+ */
420
+ type AgentOnReply = (info: AgentReplyInfo) => Promise<void> | void;
389
421
  /**
390
422
  * The input {@link AgentConfig.prepareStep} sees before a turn runs.
391
423
  * @experimental
@@ -427,6 +459,39 @@ type AgentPrepareStep = (input: AgentPrepareStepInput) => AgentPrepareStepResult
427
459
  * start a run from an inbound email.
428
460
  * @experimental
429
461
  */
462
+ /**
463
+ * Where a triggered run should send its answer back to — captured by the
464
+ * mapper, from fields the verified inbound payload already carries, and carried
465
+ * through the run so {@link AgentConfig.onReply} can answer in the same place
466
+ * the question was asked.
467
+ *
468
+ * A discriminated union rather than an opaque blob because each channel threads
469
+ * differently: email by RFC 5322 `In-Reply-To`/`References`, Slack by
470
+ * `thread_ts`, GitHub by issue number, Discord by channel (plus the triggering
471
+ * message for a true reply).
472
+ * @experimental
473
+ */
474
+ type AgentReplyRef = {
475
+ channel: "discord";
476
+ channelId: string;
477
+ messageId?: string;
478
+ } | {
479
+ channel: "email";
480
+ from: string;
481
+ messageId: string;
482
+ references?: string;
483
+ to: string[];
484
+ } | {
485
+ channel: "github";
486
+ commentId?: number;
487
+ issueNumber: number;
488
+ owner: string;
489
+ repo: string;
490
+ } | {
491
+ channel: "slack";
492
+ channelId: string;
493
+ threadTs: string;
494
+ };
430
495
  interface AgentEmailRun {
431
496
  /** The user message that starts (or continues) the thread — the model's prompt. */
432
497
  input: string;
@@ -437,6 +502,13 @@ interface AgentEmailRun {
437
502
  * `email.from`.
438
503
  */
439
504
  owner?: string;
505
+ /**
506
+ * Where to send the answer — see {@link AgentReplyRef}. Populate it from the
507
+ * event the mapper already has (`captureEmailReplyRef(email)` does it for
508
+ * email) and the run calls {@link AgentConfig.onReply} with it once the
509
+ * final answer is ready. Omit it and the run simply never replies.
510
+ */
511
+ replyRef?: AgentReplyRef;
440
512
  /** The thread key — reuse to continue a conversation (e.g. a ticket id parsed from the subject). */
441
513
  threadKey: string;
442
514
  /** Optional thread title, set on first creation. */
@@ -566,7 +638,16 @@ interface AgentConfig {
566
638
  *
567
639
  * - `"reject"` (default) — fail the new run fast with a `CONFLICT` error.
568
640
  * - `"replace"` — terminate the in-flight instance and take the thread over.
569
- * - `"queue"` — reserved for a future durable queue; currently degrades to `"reject"` (no queue exists yet), tracked as a follow-up.
641
+ * - `"queue"` — park the new run behind the one in flight (FIFO, up to five deep) and hibernate it until the thread is handed over.
642
+ *
643
+ * Each parked run is a live workflow instance waiting on an event, so the
644
+ * queue's depth cap is a real resource bound: past it, a start is rejected
645
+ * exactly as `"reject"` would. A `"replace"` arriving later supersedes the
646
+ * run in FLIGHT, not the queue — parked runs still take their turn after it.
647
+ *
648
+ * A dispatch with no instance id (the inbound-email / inbound-channel
649
+ * paths) cannot be parked, because nothing later can tell it apart from
650
+ * another such dispatch to wake it; `"queue"` rejects those.
570
651
  *
571
652
  * A workflow REPLAY re-enters the bootstrap under the SAME instance id and
572
653
  * is never a concurrent run (the guard compares the stored instance id).
@@ -586,6 +667,12 @@ interface AgentConfig {
586
667
  * signature over the raw body before calling `map`.
587
668
  */
588
669
  onInbound?: AgentInboundChannel;
670
+ /**
671
+ * Called with the final answer when the run was triggered from a channel
672
+ * that gave it a `replyRef` — see {@link AgentOnReply}. This is how an
673
+ * inbound-triggered agent answers where it was asked.
674
+ */
675
+ onReply?: AgentOnReply;
589
676
  /** Called after each LLM turn — see {@link AgentOnStepFinish}. */
590
677
  onStepFinish?: AgentOnStepFinish;
591
678
  /**
@@ -748,6 +835,26 @@ interface AgentDefinition extends AgentConfig {
748
835
  */
749
836
  memorySources?: ReadonlyArray<AgentMemorySource>;
750
837
  }
838
+ /**
839
+ * What `agentEnsureThread` reports back to the loop.
840
+ *
841
+ * A discriminated union rather than a bag of optional booleans: the four
842
+ * outcomes are mutually exclusive, and the data each carries only exists for its
843
+ * own case. `queued` has a position, `replaced` has the instance it took the
844
+ * thread from, and the other two have nothing — encoding that as five
845
+ * independent optional fields made every reader re-derive which combination was
846
+ * legal.
847
+ * @experimental
848
+ */
849
+ type EnsureThreadOutcome = {
850
+ outcome: "continued" | "created";
851
+ } | {
852
+ outcome: "queued";
853
+ position: number;
854
+ } | {
855
+ outcome: "replaced";
856
+ priorInstanceId: string;
857
+ };
751
858
  /**
752
859
  * Params of one agent run (the compiled workflow's payload).
753
860
  * @experimental
@@ -764,6 +871,8 @@ interface AgentRunInput {
764
871
  * the first run.
765
872
  */
766
873
  owner?: string;
874
+ /** Where a triggered run sends its answer — see {@link AgentReplyRef}. */
875
+ replyRef?: AgentReplyRef;
767
876
  /** The thread key — reuse to continue a conversation. */
768
877
  threadKey: string;
769
878
  /** Optional thread title, set on first creation. */
@@ -796,6 +905,12 @@ interface AgentRunResult {
796
905
  */
797
906
  interface AgentFunctionPaths {
798
907
  appendMessage: string;
908
+ /**
909
+ * The internal `agents:agentCompleteRun` mutation the loop dispatches at the
910
+ * end of a run: it writes the terminal status AND hands the thread to the
911
+ * next queued run in the same mutation.
912
+ */
913
+ completeRun: string;
799
914
  ensureThread: string;
800
915
  /** The internal `agents:agentEpisodeRecall` query the loop dispatches for an episodic-kind read. */
801
916
  episodeRecall: string;
@@ -1134,4 +1249,4 @@ interface AgentHandle {
1134
1249
  /** Read a run's workflow status by instance id. */
1135
1250
  status: (id: string) => Promise<unknown>;
1136
1251
  }
1137
- export { AgentDefinition as A, AgentEmailMapper as B, AgentEmailRun as C, AgentGenerateOptions as D, AgentGenerateResult as E, AgentInstructionsContext as F, AgentLiveEvent as G, AgentMemoryOptions as H, InboundChannelEvent as I, AgentMemorySource as J, AgentMessageStatus as K, AgentOnStepFinish as L, AgentPrepareStep as M, AgentPrepareStepInput as N, AgentPrepareStepResult as O, AgentProgressEvent as P, AgentRunHandle as Q, AgentStepFinishInfo as R, SkillMarkdownExtras as S, AgentStepInfo as T, AgentThreadStatus as U, AgentTokenDelta as V, AgentToolCall as W, AgentUsage as X, AgentVoiceConfig as Y, AgentWorkflowBindingLike as Z, AgentWorkflowInstanceLike as _, AgentToolContext as a, AgentToolDefinition as b, SkillDefinition as c, AgentCompact as d, AgentEpisodeExtract as e, AgentGraphExtract as f, AgentGenerate as g, AgentTokenSink as h, AgentRunInput as i, AgentFunctionPaths as j, AgentRunFunction as k, AgentStepLike as l, AgentStreamGenerate as m, AgentRunResult as n, AgentMessageRow as o, AgentConfig as p, AnyAgentTool as q, AgentAsToolOptions as r, AgentSubToolInput as s, AgentBindingSpec as t, AgentHandle as u, AgentToolConfig as v, AgentFunctionReference as w, AgentModelInput as x, SkillConfig as y, AgentApprovalContext as z };
1252
+ export { AgentVoiceConfig as $, AgentDefinition as A, AgentApprovalContext as B, AgentEmailMapper as C, AgentEmailRun as D, AgentGenerateOptions as E, AgentGenerateResult as F, AgentInstructionsContext as G, AgentLiveEvent as H, InboundChannelEvent as I, AgentMemoryOptions as J, AgentMemorySource as K, AgentMessageStatus as L, AgentOnReply as M, AgentOnStepFinish as N, AgentPrepareStep as O, AgentPrepareStepInput as P, AgentPrepareStepResult as Q, AgentProgressEvent as R, SkillMarkdownExtras as S, AgentReplyInfo as T, AgentRunHandle as U, AgentStepFinishInfo as V, AgentStepInfo as W, AgentThreadStatus as X, AgentTokenDelta as Y, AgentToolCall as Z, AgentUsage as _, AgentReplyRef as a, AgentWorkflowBindingLike as a0, AgentWorkflowInstanceLike as a1, EnsureThreadOutcome as a2, AgentToolContext as b, AgentToolDefinition as c, SkillDefinition as d, AgentCompact as e, AgentEpisodeExtract as f, AgentGraphExtract as g, AgentGenerate as h, AgentTokenSink as i, AgentRunInput as j, AgentFunctionPaths as k, AgentRunFunction as l, AgentStepLike as m, AgentStreamGenerate as n, AgentRunResult as o, AgentMessageRow as p, AgentConfig as q, AnyAgentTool as r, AgentAsToolOptions as s, AgentSubToolInput as t, AgentBindingSpec as u, AgentHandle as v, AgentToolConfig as w, AgentFunctionReference as x, AgentModelInput as y, SkillConfig as z };
@@ -386,6 +386,38 @@ interface AgentStepFinishInfo {
386
386
  * @experimental
387
387
  */
388
388
  type AgentOnStepFinish = (info: AgentStepFinishInfo) => Promise<void> | void;
389
+ /**
390
+ * What {@link AgentConfig.onReply} is called with when a triggered run reaches
391
+ * its final answer.
392
+ * @experimental
393
+ */
394
+ interface AgentReplyInfo {
395
+ /** The worker `env` — where an outbound credential (a bot token, a mailer binding) lives. */
396
+ env: Record<string, unknown>;
397
+ /** Where to reply, captured by the mapper that started this run. */
398
+ replyRef: AgentReplyRef;
399
+ /** The run's final answer. */
400
+ result: AgentRunResult;
401
+ /** The thread this run belongs to. */
402
+ threadKey: string;
403
+ }
404
+ /**
405
+ * Send a triggered run's answer back where it came from — the outbound half of
406
+ * an `onEmail` / `onInbound` trigger.
407
+ *
408
+ * Called once, automatically, when a run started with a `replyRef` produces a
409
+ * final answer; a run without one (an ordinary in-app `ctx.agents.<name>.run`)
410
+ * never calls it. It runs inside a named durable step, so a transient failure
411
+ * is retried and a workflow replay does not send the answer twice.
412
+ *
413
+ * Delivery is the app's call, because only the app has the credential: email
414
+ * has a home already (`replyToEmail(mailer, ref, body)` from
415
+ * `@lunora/agent/reply`), while Slack/GitHub/Discord bot tokens have no
416
+ * framework-owned store yet — read them from `info.env` and make the provider
417
+ * call.
418
+ * @experimental
419
+ */
420
+ type AgentOnReply = (info: AgentReplyInfo) => Promise<void> | void;
389
421
  /**
390
422
  * The input {@link AgentConfig.prepareStep} sees before a turn runs.
391
423
  * @experimental
@@ -427,6 +459,39 @@ type AgentPrepareStep = (input: AgentPrepareStepInput) => AgentPrepareStepResult
427
459
  * start a run from an inbound email.
428
460
  * @experimental
429
461
  */
462
+ /**
463
+ * Where a triggered run should send its answer back to — captured by the
464
+ * mapper, from fields the verified inbound payload already carries, and carried
465
+ * through the run so {@link AgentConfig.onReply} can answer in the same place
466
+ * the question was asked.
467
+ *
468
+ * A discriminated union rather than an opaque blob because each channel threads
469
+ * differently: email by RFC 5322 `In-Reply-To`/`References`, Slack by
470
+ * `thread_ts`, GitHub by issue number, Discord by channel (plus the triggering
471
+ * message for a true reply).
472
+ * @experimental
473
+ */
474
+ type AgentReplyRef = {
475
+ channel: "discord";
476
+ channelId: string;
477
+ messageId?: string;
478
+ } | {
479
+ channel: "email";
480
+ from: string;
481
+ messageId: string;
482
+ references?: string;
483
+ to: string[];
484
+ } | {
485
+ channel: "github";
486
+ commentId?: number;
487
+ issueNumber: number;
488
+ owner: string;
489
+ repo: string;
490
+ } | {
491
+ channel: "slack";
492
+ channelId: string;
493
+ threadTs: string;
494
+ };
430
495
  interface AgentEmailRun {
431
496
  /** The user message that starts (or continues) the thread — the model's prompt. */
432
497
  input: string;
@@ -437,6 +502,13 @@ interface AgentEmailRun {
437
502
  * `email.from`.
438
503
  */
439
504
  owner?: string;
505
+ /**
506
+ * Where to send the answer — see {@link AgentReplyRef}. Populate it from the
507
+ * event the mapper already has (`captureEmailReplyRef(email)` does it for
508
+ * email) and the run calls {@link AgentConfig.onReply} with it once the
509
+ * final answer is ready. Omit it and the run simply never replies.
510
+ */
511
+ replyRef?: AgentReplyRef;
440
512
  /** The thread key — reuse to continue a conversation (e.g. a ticket id parsed from the subject). */
441
513
  threadKey: string;
442
514
  /** Optional thread title, set on first creation. */
@@ -566,7 +638,16 @@ interface AgentConfig {
566
638
  *
567
639
  * - `"reject"` (default) — fail the new run fast with a `CONFLICT` error.
568
640
  * - `"replace"` — terminate the in-flight instance and take the thread over.
569
- * - `"queue"` — reserved for a future durable queue; currently degrades to `"reject"` (no queue exists yet), tracked as a follow-up.
641
+ * - `"queue"` — park the new run behind the one in flight (FIFO, up to five deep) and hibernate it until the thread is handed over.
642
+ *
643
+ * Each parked run is a live workflow instance waiting on an event, so the
644
+ * queue's depth cap is a real resource bound: past it, a start is rejected
645
+ * exactly as `"reject"` would. A `"replace"` arriving later supersedes the
646
+ * run in FLIGHT, not the queue — parked runs still take their turn after it.
647
+ *
648
+ * A dispatch with no instance id (the inbound-email / inbound-channel
649
+ * paths) cannot be parked, because nothing later can tell it apart from
650
+ * another such dispatch to wake it; `"queue"` rejects those.
570
651
  *
571
652
  * A workflow REPLAY re-enters the bootstrap under the SAME instance id and
572
653
  * is never a concurrent run (the guard compares the stored instance id).
@@ -586,6 +667,12 @@ interface AgentConfig {
586
667
  * signature over the raw body before calling `map`.
587
668
  */
588
669
  onInbound?: AgentInboundChannel;
670
+ /**
671
+ * Called with the final answer when the run was triggered from a channel
672
+ * that gave it a `replyRef` — see {@link AgentOnReply}. This is how an
673
+ * inbound-triggered agent answers where it was asked.
674
+ */
675
+ onReply?: AgentOnReply;
589
676
  /** Called after each LLM turn — see {@link AgentOnStepFinish}. */
590
677
  onStepFinish?: AgentOnStepFinish;
591
678
  /**
@@ -748,6 +835,26 @@ interface AgentDefinition extends AgentConfig {
748
835
  */
749
836
  memorySources?: ReadonlyArray<AgentMemorySource>;
750
837
  }
838
+ /**
839
+ * What `agentEnsureThread` reports back to the loop.
840
+ *
841
+ * A discriminated union rather than a bag of optional booleans: the four
842
+ * outcomes are mutually exclusive, and the data each carries only exists for its
843
+ * own case. `queued` has a position, `replaced` has the instance it took the
844
+ * thread from, and the other two have nothing — encoding that as five
845
+ * independent optional fields made every reader re-derive which combination was
846
+ * legal.
847
+ * @experimental
848
+ */
849
+ type EnsureThreadOutcome = {
850
+ outcome: "continued" | "created";
851
+ } | {
852
+ outcome: "queued";
853
+ position: number;
854
+ } | {
855
+ outcome: "replaced";
856
+ priorInstanceId: string;
857
+ };
751
858
  /**
752
859
  * Params of one agent run (the compiled workflow's payload).
753
860
  * @experimental
@@ -764,6 +871,8 @@ interface AgentRunInput {
764
871
  * the first run.
765
872
  */
766
873
  owner?: string;
874
+ /** Where a triggered run sends its answer — see {@link AgentReplyRef}. */
875
+ replyRef?: AgentReplyRef;
767
876
  /** The thread key — reuse to continue a conversation. */
768
877
  threadKey: string;
769
878
  /** Optional thread title, set on first creation. */
@@ -796,6 +905,12 @@ interface AgentRunResult {
796
905
  */
797
906
  interface AgentFunctionPaths {
798
907
  appendMessage: string;
908
+ /**
909
+ * The internal `agents:agentCompleteRun` mutation the loop dispatches at the
910
+ * end of a run: it writes the terminal status AND hands the thread to the
911
+ * next queued run in the same mutation.
912
+ */
913
+ completeRun: string;
799
914
  ensureThread: string;
800
915
  /** The internal `agents:agentEpisodeRecall` query the loop dispatches for an episodic-kind read. */
801
916
  episodeRecall: string;
@@ -1134,4 +1249,4 @@ interface AgentHandle {
1134
1249
  /** Read a run's workflow status by instance id. */
1135
1250
  status: (id: string) => Promise<unknown>;
1136
1251
  }
1137
- export { AgentDefinition as A, AgentEmailMapper as B, AgentEmailRun as C, AgentGenerateOptions as D, AgentGenerateResult as E, AgentInstructionsContext as F, AgentLiveEvent as G, AgentMemoryOptions as H, InboundChannelEvent as I, AgentMemorySource as J, AgentMessageStatus as K, AgentOnStepFinish as L, AgentPrepareStep as M, AgentPrepareStepInput as N, AgentPrepareStepResult as O, AgentProgressEvent as P, AgentRunHandle as Q, AgentStepFinishInfo as R, SkillMarkdownExtras as S, AgentStepInfo as T, AgentThreadStatus as U, AgentTokenDelta as V, AgentToolCall as W, AgentUsage as X, AgentVoiceConfig as Y, AgentWorkflowBindingLike as Z, AgentWorkflowInstanceLike as _, AgentToolContext as a, AgentToolDefinition as b, SkillDefinition as c, AgentCompact as d, AgentEpisodeExtract as e, AgentGraphExtract as f, AgentGenerate as g, AgentTokenSink as h, AgentRunInput as i, AgentFunctionPaths as j, AgentRunFunction as k, AgentStepLike as l, AgentStreamGenerate as m, AgentRunResult as n, AgentMessageRow as o, AgentConfig as p, AnyAgentTool as q, AgentAsToolOptions as r, AgentSubToolInput as s, AgentBindingSpec as t, AgentHandle as u, AgentToolConfig as v, AgentFunctionReference as w, AgentModelInput as x, SkillConfig as y, AgentApprovalContext as z };
1252
+ export { AgentVoiceConfig as $, AgentDefinition as A, AgentApprovalContext as B, AgentEmailMapper as C, AgentEmailRun as D, AgentGenerateOptions as E, AgentGenerateResult as F, AgentInstructionsContext as G, AgentLiveEvent as H, InboundChannelEvent as I, AgentMemoryOptions as J, AgentMemorySource as K, AgentMessageStatus as L, AgentOnReply as M, AgentOnStepFinish as N, AgentPrepareStep as O, AgentPrepareStepInput as P, AgentPrepareStepResult as Q, AgentProgressEvent as R, SkillMarkdownExtras as S, AgentReplyInfo as T, AgentRunHandle as U, AgentStepFinishInfo as V, AgentStepInfo as W, AgentThreadStatus as X, AgentTokenDelta as Y, AgentToolCall as Z, AgentUsage as _, AgentReplyRef as a, AgentWorkflowBindingLike as a0, AgentWorkflowInstanceLike as a1, EnsureThreadOutcome as a2, AgentToolContext as b, AgentToolDefinition as c, SkillDefinition as d, AgentCompact as e, AgentEpisodeExtract as f, AgentGraphExtract as g, AgentGenerate as h, AgentTokenSink as i, AgentRunInput as j, AgentFunctionPaths as k, AgentRunFunction as l, AgentStepLike as m, AgentStreamGenerate as n, AgentRunResult as o, AgentMessageRow as p, AgentConfig as q, AnyAgentTool as r, AgentAsToolOptions as s, AgentSubToolInput as t, AgentBindingSpec as u, AgentHandle as v, AgentToolConfig as w, AgentFunctionReference as x, AgentModelInput as y, SkillConfig as z };
@@ -1 +1 @@
1
- import{s as $,o as z}from"./base64-B_qZ_Tyh.mjs";import{buildModelMessages as B}from"./buildModelMessages-Dm2wVNQy.mjs";import{toFunctionReference as b}from"./AGENT_MODULE-BXx-tSCe.mjs";const D=new TextDecoder;new TextEncoder;const K="=",G=t=>{if(t)try{const e=t[0]==="{"?t:D.decode($(t)),n=JSON.parse(e);if(n&&typeof n=="object"&&!Array.isArray(n))return n}catch{}},nt=t=>{if(t){if(!t.startsWith(K))return t;try{return D.decode($(t.slice(K.length)))}catch{return}}},rt=t=>{const e=Number(t);return Number.isFinite(e)&&e>0?e:void 0},st=t=>typeof t=="number"&&Date.now()>=t,it=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,C=1,H=16,N=/[^.!?]*[.!?]+\s+/u,Q=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},at=(t,e=q,n=C,i=H)=>{const u=n*i/8,y=e*u,d=new ArrayBuffer(44+t.byteLength),r=new DataView(d),s=(U,l)=>{for(let g=0;g<l.length;g+=1)r.setUint8(U+g,l.codePointAt(g)??0)};s(0,"RIFF"),r.setUint32(4,36+t.byteLength,!0),s(8,"WAVE"),s(12,"fmt "),r.setUint32(16,16,!0),r.setUint16(20,1,!0),r.setUint16(22,n,!0),r.setUint32(24,e,!0),r.setUint32(28,y,!0),r.setUint16(32,u,!0),r.setUint16(34,i,!0),s(36,"data"),r.setUint32(40,t.byteLength,!0);const f=new Uint8Array(d);return f.set(t,44),f},Y=t=>{const e=[];let n=t,i=N.exec(n);for(;i&&i[0].length>0;){const u=i[0],y=u.trim();y.length>0&&e.push(y),n=n.slice(u.length),i=N.exec(n)}return{rest:n,sentences:e}},ot=async t=>{const{agent:e,connectionId:n,env:i,exportName:u,owner:y,paths:d,pcm:r,run:s,send:f,sendAudio:U,signal:l,streamGenerate:g,synthesize:_,text:F,threadKey:c,transcribe:I,turn:k,waitForDrain:L}=t,p=()=>l.aborted,E=b(d.appendMessage),M=b(d.ensureThread),P=b(d.listMessages),A=b(d.patchThread),w=(F??(r?await I(r):"")).trim();if(w.length===0)return{assistantText:"",interrupted:!1,userText:""};f({text:w,type:"user_transcript"}),await s(M,{agent:u,key:c,...e.initialState===void 0?{}:{initialState:e.initialState},...y===void 0?{}:{owner:y}}),await s(E,{content:w,messageKey:`voice:${n}:${String(k)}:user`,role:"user",threadKey:c}),await s(A,{key:c,status:"running"});const T=typeof e.instructions=="function"?e.instructions({env:i,input:w,threadKey:c}):e.instructions,O=await s(P,{key:c}),j=B({history:O,...T===void 0?{}:{instructions:T}});let h="",x="",S=Promise.resolve();const J=async a=>{if(p()||a.length===0)return;let m=!1;try{for await(const o of Q(await _(a,l))){if(p()||(await L?.(),p()))break;U(o),m=!0}}catch(o){f({message:o instanceof Error?o.message:String(o),type:"error"})}m&&(x=x.length>0?`${x} ${a}`:a)},R=a=>{S=S.then(async()=>J(a))};try{const a=await g({messages:j,signal:l},v=>{if(p())return;f({text:v,type:"assistant_delta"}),h+=v;const{rest:V,sentences:W}=Y(h);h=V;for(const X of W)R(X)});!p()&&h.trim().length>0&&R(h.trim()),h="",await S;const m=p(),o=m?x:a.text;return await s(E,{content:o,messageKey:`voice:${n}:${String(k)}:assistant`,role:"assistant",threadKey:c}),await s(A,{key:c,status:"idle"}),f(m?{type:"interrupted"}:{text:o,type:"assistant_done"}),{assistantText:o,interrupted:m,userText:w}}catch(a){throw await s(A,{key:c,status:"idle"}),a}},ct=t=>G(t),ut=t=>{if(typeof t=="object"&&t!==null&&"text"in t){const{text:e}=t;return typeof e=="string"?e:""}return""},yt=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 z(e);if(e instanceof ReadableStream||e instanceof Uint8Array)return e}return new Uint8Array(0)};export{it as E,Q as P,ot as Q,ct as X,at as Y,ut as Z,yt as e,rt as g,nt as l,st as p};
1
+ import{s as $,o as z}from"./base64-B_qZ_Tyh.mjs";import{buildModelMessages as B}from"./buildModelMessages-Dm2wVNQy.mjs";import{toFunctionReference as b}from"./AGENT_MODULE-gxKUkiCE.mjs";const D=new TextDecoder;new TextEncoder;const K="=",G=t=>{if(t)try{const e=t[0]==="{"?t:D.decode($(t)),n=JSON.parse(e);if(n&&typeof n=="object"&&!Array.isArray(n))return n}catch{}},nt=t=>{if(t){if(!t.startsWith(K))return t;try{return D.decode($(t.slice(K.length)))}catch{return}}},rt=t=>{const e=Number(t);return Number.isFinite(e)&&e>0?e:void 0},st=t=>typeof t=="number"&&Date.now()>=t,it=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,C=1,H=16,N=/[^.!?]*[.!?]+\s+/u,Q=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},at=(t,e=q,n=C,i=H)=>{const u=n*i/8,y=e*u,d=new ArrayBuffer(44+t.byteLength),r=new DataView(d),s=(U,l)=>{for(let g=0;g<l.length;g+=1)r.setUint8(U+g,l.codePointAt(g)??0)};s(0,"RIFF"),r.setUint32(4,36+t.byteLength,!0),s(8,"WAVE"),s(12,"fmt "),r.setUint32(16,16,!0),r.setUint16(20,1,!0),r.setUint16(22,n,!0),r.setUint32(24,e,!0),r.setUint32(28,y,!0),r.setUint16(32,u,!0),r.setUint16(34,i,!0),s(36,"data"),r.setUint32(40,t.byteLength,!0);const f=new Uint8Array(d);return f.set(t,44),f},Y=t=>{const e=[];let n=t,i=N.exec(n);for(;i&&i[0].length>0;){const u=i[0],y=u.trim();y.length>0&&e.push(y),n=n.slice(u.length),i=N.exec(n)}return{rest:n,sentences:e}},ot=async t=>{const{agent:e,connectionId:n,env:i,exportName:u,owner:y,paths:d,pcm:r,run:s,send:f,sendAudio:U,signal:l,streamGenerate:g,synthesize:_,text:F,threadKey:c,transcribe:I,turn:k,waitForDrain:L}=t,p=()=>l.aborted,E=b(d.appendMessage),M=b(d.ensureThread),P=b(d.listMessages),A=b(d.patchThread),w=(F??(r?await I(r):"")).trim();if(w.length===0)return{assistantText:"",interrupted:!1,userText:""};f({text:w,type:"user_transcript"}),await s(M,{agent:u,key:c,...e.initialState===void 0?{}:{initialState:e.initialState},...y===void 0?{}:{owner:y}}),await s(E,{content:w,messageKey:`voice:${n}:${String(k)}:user`,role:"user",threadKey:c}),await s(A,{key:c,status:"running"});const T=typeof e.instructions=="function"?e.instructions({env:i,input:w,threadKey:c}):e.instructions,O=await s(P,{key:c}),j=B({history:O,...T===void 0?{}:{instructions:T}});let h="",x="",S=Promise.resolve();const J=async a=>{if(p()||a.length===0)return;let m=!1;try{for await(const o of Q(await _(a,l))){if(p()||(await L?.(),p()))break;U(o),m=!0}}catch(o){f({message:o instanceof Error?o.message:String(o),type:"error"})}m&&(x=x.length>0?`${x} ${a}`:a)},R=a=>{S=S.then(async()=>J(a))};try{const a=await g({messages:j,signal:l},v=>{if(p())return;f({text:v,type:"assistant_delta"}),h+=v;const{rest:V,sentences:W}=Y(h);h=V;for(const X of W)R(X)});!p()&&h.trim().length>0&&R(h.trim()),h="",await S;const m=p(),o=m?x:a.text;return await s(E,{content:o,messageKey:`voice:${n}:${String(k)}:assistant`,role:"assistant",threadKey:c}),await s(A,{key:c,status:"idle"}),f(m?{type:"interrupted"}:{text:o,type:"assistant_done"}),{assistantText:o,interrupted:m,userText:w}}catch(a){throw await s(A,{key:c,status:"idle"}),a}},ct=t=>G(t),ut=t=>{if(typeof t=="object"&&t!==null&&"text"in t){const{text:e}=t;return typeof e=="string"?e:""}return""},yt=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 z(e);if(e instanceof ReadableStream||e instanceof Uint8Array)return e}return new Uint8Array(0)};export{it as E,Q as P,ot as Q,ct as X,at as Y,ut as Z,yt as e,rt as g,nt as l,st as p};
@@ -0,0 +1,40 @@
1
+ import { Mailer } from '@lunora/mail';
2
+ import { InboundEmail } from '@lunora/mail/inbound';
3
+ import { a as AgentReplyRef } from "./packem_shared/types.d-CeO8cn_u.mjs";
4
+ import 'ai';
5
+ /** The email arm of {@link AgentReplyRef}, narrowed for the helpers below. */
6
+ type EmailReplyRef = Extract<AgentReplyRef, {
7
+ channel: "email";
8
+ }>;
9
+ /**
10
+ * Capture a reply reference from an already-parsed inbound email — call it in
11
+ * an `onEmail` mapper and put the result on the run's `replyRef`.
12
+ *
13
+ * Returns `undefined` when the message carries no `Message-ID`: there is
14
+ * nothing to thread a reply against, and an unthreaded reply lands as a new
15
+ * conversation in the recipient's client, which is worse than not replying.
16
+ */
17
+ declare const captureEmailReplyRef: (email: InboundEmail) => EmailReplyRef | undefined;
18
+ /** RFC 5322 threading: append the replied-to id to any existing `References` chain. */
19
+ declare const buildReferences: (replyRef: EmailReplyRef) => string;
20
+ /** Subject + body of a reply. */
21
+ interface ReplyBody {
22
+ subject: string;
23
+ text: string;
24
+ }
25
+ /**
26
+ * Send a threaded reply through the app's own `@lunora/mail` mailer.
27
+ *
28
+ * The mailer is a parameter rather than something this module constructs: the
29
+ * app already configures one (API key or `send_email` binding), and passing it
30
+ * in keeps this module free of any runtime dependency on `@lunora/mail`.
31
+ *
32
+ * The reply goes to the original sender, from the mailer's configured default.
33
+ * An app running several aliases that wants the reply to come from whichever
34
+ * mailbox received the message passes `from: replyRef.to[0]` itself — a
35
+ * decision only the app can make.
36
+ */
37
+ declare const replyToEmail: (mailer: Mailer, replyRef: EmailReplyRef, body: ReplyBody) => Promise<{
38
+ id: string;
39
+ }>;
40
+ export { type EmailReplyRef, ReplyBody, buildReferences, captureEmailReplyRef, replyToEmail };
@@ -0,0 +1,40 @@
1
+ import { Mailer } from '@lunora/mail';
2
+ import { InboundEmail } from '@lunora/mail/inbound';
3
+ import { a as AgentReplyRef } from "./packem_shared/types.d-CeO8cn_u.js";
4
+ import 'ai';
5
+ /** The email arm of {@link AgentReplyRef}, narrowed for the helpers below. */
6
+ type EmailReplyRef = Extract<AgentReplyRef, {
7
+ channel: "email";
8
+ }>;
9
+ /**
10
+ * Capture a reply reference from an already-parsed inbound email — call it in
11
+ * an `onEmail` mapper and put the result on the run's `replyRef`.
12
+ *
13
+ * Returns `undefined` when the message carries no `Message-ID`: there is
14
+ * nothing to thread a reply against, and an unthreaded reply lands as a new
15
+ * conversation in the recipient's client, which is worse than not replying.
16
+ */
17
+ declare const captureEmailReplyRef: (email: InboundEmail) => EmailReplyRef | undefined;
18
+ /** RFC 5322 threading: append the replied-to id to any existing `References` chain. */
19
+ declare const buildReferences: (replyRef: EmailReplyRef) => string;
20
+ /** Subject + body of a reply. */
21
+ interface ReplyBody {
22
+ subject: string;
23
+ text: string;
24
+ }
25
+ /**
26
+ * Send a threaded reply through the app's own `@lunora/mail` mailer.
27
+ *
28
+ * The mailer is a parameter rather than something this module constructs: the
29
+ * app already configures one (API key or `send_email` binding), and passing it
30
+ * in keeps this module free of any runtime dependency on `@lunora/mail`.
31
+ *
32
+ * The reply goes to the original sender, from the mailer's configured default.
33
+ * An app running several aliases that wants the reply to come from whichever
34
+ * mailbox received the message passes `from: replyRef.to[0]` itself — a
35
+ * decision only the app can make.
36
+ */
37
+ declare const replyToEmail: (mailer: Mailer, replyRef: EmailReplyRef, body: ReplyBody) => Promise<{
38
+ id: string;
39
+ }>;
40
+ export { type EmailReplyRef, ReplyBody, buildReferences, captureEmailReplyRef, replyToEmail };
package/dist/reply.mjs ADDED
@@ -0,0 +1 @@
1
+ const c=e=>{if(e.messageId!==void 0)return{channel:"email",from:e.from,messageId:e.messageId,to:e.to,...e.references===void 0?{}:{references:e.references}}},a=e=>e.references===void 0?e.messageId:`${e.references} ${e.messageId}`,o=async(e,s,r)=>e.send({headers:{"In-Reply-To":s.messageId,References:a(s)},subject:r.subject,text:r.text,to:s.from});export{a as buildReferences,c as captureEmailReplyRef,o as replyToEmail};
@@ -1,4 +1,4 @@
1
- import { a as AgentToolContext, b as AgentToolDefinition } from "./packem_shared/types.d-PMYeuDE7.mjs";
1
+ import { b as AgentToolContext, c as AgentToolDefinition } from "./packem_shared/types.d-CeO8cn_u.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 { a as AgentToolContext, b as AgentToolDefinition } from "./packem_shared/types.d-PMYeuDE7.js";
1
+ import { b as AgentToolContext, c as AgentToolDefinition } from "./packem_shared/types.d-CeO8cn_u.js";
2
2
  import '@lunora/mail/inbound';
3
3
  import 'ai';
4
4
  /**
package/dist/sandbox.mjs CHANGED
@@ -1 +1 @@
1
- import{LunoraError as p}from"@lunora/errors";import{jsonSchema as i}from"ai";import{toFunctionReference as a,SANDBOX_INVOKE_PATH as c}from"./packem_shared/AGENT_MODULE-BXx-tSCe.mjs";const s=a(c),d='Drive a headless browser: screenshot a page, render it to PDF, read its HTML content, or scrape it. Set `op` to "screenshot" | "pdf" | "content" | "scrape" and pass the target `url`.',u='Talk to a sandboxed container: `fetch` an HTTP path on it, or `exec` a command inside it. Set `op` to "fetch" (with `path`) or "exec" (with `command`).',h='Read and write files in a persistent sandbox filesystem. Set `op` to "ls" (list a directory), "read", "write" (with `content`), "rm", or "stat", and pass `path`.',l=e=>e.op==="write"||e.op==="rm",m=i({properties:{content:{description:"write: the file contents.",type:"string"},op:{description:"The filesystem operation to run.",enum:["ls","read","write","rm","stat"],type:"string"},path:{description:"The file or directory path, relative to the sandbox root.",type:"string"}},required:["op"],type:"object"}),g=i({properties:{fullPage:{description:"screenshot: capture the full scrollable page rather than just the viewport.",type:"boolean"},op:{description:"The browser operation to run.",enum:["screenshot","scrape","pdf","content"],type:"string"},selector:{description:"scrape: optional CSS selector hint to narrow the extraction.",type:"string"},type:{description:"screenshot: image encoding (default png).",enum:["png","jpeg"],type:"string"},url:{description:"The URL to operate on.",type:"string"}},required:["op","url"],type:"object"}),f="/exec",y=/[?#]/u,T=e=>{const[t=""]=(e??"").split(y),o=[];for(const r of t.split("/"))if(!(r===""||r===".")){if(r===".."){o.pop();continue}o.push(r)}return`/${o.join("/")}`},w=new Set(["DELETE","PATCH","POST","PUT"]),b=e=>e.op==="exec"||T(e.path)===f?!0:w.has((e.method??"GET").toUpperCase()),x=i({properties:{args:{description:"exec: command arguments.",items:{type:"string"},type:"array"},body:{description:"fetch: request body.",type:"string"},command:{description:"exec: the command to run.",type:"string"},method:{description:"fetch: HTTP method (default GET).",type:"string"},op:{description:"The container operation to run.",enum:["fetch","exec"],type:"string"},path:{description:"fetch: request path on the container (e.g. /health).",type:"string"}},required:["op"],type:"object"}),E=(e={})=>({description:e.description??d,execute:(t,o)=>o.run(s,{...t,kind:"browser"}),inputSchema:g,isLunoraAgentTool:!0,...e.needsApproval===void 0?{}:{needsApproval:e.needsApproval}}),L=(e,t={})=>{if(typeof e!="string"||e.length===0)throw new p("INTERNAL","@lunora/agent: containerTool requires a container `name` (the ctx.containers.<name> key from lunora/containers.ts)");const o=t.needsApproval??b;return{description:t.description??u,execute:(r,n)=>n.run(s,{...r,kind:"container",name:e}),inputSchema:x,isLunoraAgentTool:!0,needsApproval:o}},j=(e,t={})=>{if(typeof e!="string"||e.length===0)throw new p("INTERNAL","@lunora/agent: fsTool requires an R2 `bucket` binding name (the r2_bucket declared in wrangler.jsonc)");return{description:t.description??h,execute:(o,r)=>{const n=typeof t.root=="function"?t.root(r):t.root??"";return r.run(s,{...o,bucket:e,kind:"fs",root:n})},inputSchema:m,isLunoraAgentTool:!0,needsApproval:t.needsApproval??l}};export{E as browserTool,L as containerTool,j as fsTool};
1
+ import{LunoraError as p}from"@lunora/errors";import{jsonSchema as i}from"ai";import{toFunctionReference as a,SANDBOX_INVOKE_PATH as c}from"./packem_shared/AGENT_MODULE-gxKUkiCE.mjs";const s=a(c),d='Drive a headless browser: screenshot a page, render it to PDF, read its HTML content, or scrape it. Set `op` to "screenshot" | "pdf" | "content" | "scrape" and pass the target `url`.',u='Talk to a sandboxed container: `fetch` an HTTP path on it, or `exec` a command inside it. Set `op` to "fetch" (with `path`) or "exec" (with `command`).',h='Read and write files in a persistent sandbox filesystem. Set `op` to "ls" (list a directory), "read", "write" (with `content`), "rm", or "stat", and pass `path`.',l=e=>e.op==="write"||e.op==="rm",m=i({properties:{content:{description:"write: the file contents.",type:"string"},op:{description:"The filesystem operation to run.",enum:["ls","read","write","rm","stat"],type:"string"},path:{description:"The file or directory path, relative to the sandbox root.",type:"string"}},required:["op"],type:"object"}),g=i({properties:{fullPage:{description:"screenshot: capture the full scrollable page rather than just the viewport.",type:"boolean"},op:{description:"The browser operation to run.",enum:["screenshot","scrape","pdf","content"],type:"string"},selector:{description:"scrape: optional CSS selector hint to narrow the extraction.",type:"string"},type:{description:"screenshot: image encoding (default png).",enum:["png","jpeg"],type:"string"},url:{description:"The URL to operate on.",type:"string"}},required:["op","url"],type:"object"}),f="/exec",y=/[?#]/u,T=e=>{const[t=""]=(e??"").split(y),o=[];for(const r of t.split("/"))if(!(r===""||r===".")){if(r===".."){o.pop();continue}o.push(r)}return`/${o.join("/")}`},w=new Set(["DELETE","PATCH","POST","PUT"]),b=e=>e.op==="exec"||T(e.path)===f?!0:w.has((e.method??"GET").toUpperCase()),x=i({properties:{args:{description:"exec: command arguments.",items:{type:"string"},type:"array"},body:{description:"fetch: request body.",type:"string"},command:{description:"exec: the command to run.",type:"string"},method:{description:"fetch: HTTP method (default GET).",type:"string"},op:{description:"The container operation to run.",enum:["fetch","exec"],type:"string"},path:{description:"fetch: request path on the container (e.g. /health).",type:"string"}},required:["op"],type:"object"}),E=(e={})=>({description:e.description??d,execute:(t,o)=>o.run(s,{...t,kind:"browser"}),inputSchema:g,isLunoraAgentTool:!0,...e.needsApproval===void 0?{}:{needsApproval:e.needsApproval}}),L=(e,t={})=>{if(typeof e!="string"||e.length===0)throw new p("INTERNAL","@lunora/agent: containerTool requires a container `name` (the ctx.containers.<name> key from lunora/containers.ts)");const o=t.needsApproval??b;return{description:t.description??u,execute:(r,n)=>n.run(s,{...r,kind:"container",name:e}),inputSchema:x,isLunoraAgentTool:!0,needsApproval:o}},j=(e,t={})=>{if(typeof e!="string"||e.length===0)throw new p("INTERNAL","@lunora/agent: fsTool requires an R2 `bucket` binding name (the r2_bucket declared in wrangler.jsonc)");return{description:t.description??h,execute:(o,r)=>{const n=typeof t.root=="function"?t.root(r):t.root??"";return r.run(s,{...o,bucket:e,kind:"fs",root:n})},inputSchema:m,isLunoraAgentTool:!0,needsApproval:t.needsApproval??l}};export{E as browserTool,L as containerTool,j as fsTool};
@@ -1,4 +1,4 @@
1
- import { S as SkillMarkdownExtras, c as SkillDefinition } from "./packem_shared/types.d-PMYeuDE7.mjs";
1
+ import { S as SkillMarkdownExtras, d as SkillDefinition } from "./packem_shared/types.d-CeO8cn_u.mjs";
2
2
  import '@lunora/mail/inbound';
3
3
  import 'ai';
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as SkillMarkdownExtras, c as SkillDefinition } from "./packem_shared/types.d-PMYeuDE7.js";
1
+ import { S as SkillMarkdownExtras, d as SkillDefinition } from "./packem_shared/types.d-CeO8cn_u.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.51",
3
+ "version": "1.0.0-alpha.53",
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",
@@ -66,6 +66,10 @@
66
66
  "types": "./dist/skill-markdown.d.ts",
67
67
  "import": "./dist/skill-markdown.mjs"
68
68
  },
69
+ "./reply": {
70
+ "types": "./dist/reply.d.ts",
71
+ "import": "./dist/reply.mjs"
72
+ },
69
73
  "./sandbox": {
70
74
  "types": "./dist/sandbox.d.ts",
71
75
  "import": "./dist/sandbox.mjs"
@@ -80,12 +84,12 @@
80
84
  "access": "public"
81
85
  },
82
86
  "dependencies": {
83
- "@lunora/ai": "1.0.0-alpha.56",
84
- "@lunora/errors": "1.0.0-alpha.20",
85
- "@lunora/mail": "1.0.0-alpha.47",
86
- "@lunora/server": "1.0.0-alpha.70",
87
- "@lunora/values": "1.0.0-alpha.25",
88
- "@lunora/workflow": "1.0.0-alpha.26",
87
+ "@lunora/ai": "1.0.0-alpha.57",
88
+ "@lunora/errors": "1.0.0-alpha.21",
89
+ "@lunora/mail": "1.0.0-alpha.48",
90
+ "@lunora/server": "1.0.0-alpha.72",
91
+ "@lunora/values": "1.0.0-alpha.26",
92
+ "@lunora/workflow": "1.0.0-alpha.28",
89
93
  "@modelcontextprotocol/sdk": "^1.29.0",
90
94
  "ai": "7.0.37",
91
95
  "yaml": "^2.9.0"
@@ -1 +0,0 @@
1
- const e="agents",t="sandbox",s=`${t}:invoke`,n={appendMessage:`${e}:agentAppendMessage`,ensureThread:`${e}:agentEnsureThread`,episodeRecall:`${e}:agentEpisodeRecall`,episodeUpsert:`${e}:agentEpisodeUpsert`,graphTraverse:`${e}:agentGraphTraverse`,graphUpsert:`${e}:agentGraphUpsert`,listMessages:`${e}:agentMessages`,patchThread:`${e}:agentPatchThread`,run:`${e}:agentRun`,setState:`${e}:agentSetState`,state:`${e}:agentState`},r=a=>typeof a=="string"?{__lunoraRef:a}:a;export{e as AGENT_MODULE,n as DEFAULT_AGENT_FUNCTION_PATHS,s as SANDBOX_INVOKE_PATH,t as SANDBOX_MODULE,r as toFunctionReference};
@@ -1 +0,0 @@
1
- import{LunoraError as a}from"@lunora/errors";const g=t=>{let e="";for(let n=0;n<t.length;n+=32768)e+=String.fromCharCode(...t.subarray(n,n+32768));return btoa(e)},p=t=>g(t).replaceAll("+","-").replaceAll("/","_").replace(/=+$/,"");new TextDecoder;const y=new TextEncoder,f="=",w=t=>{for(let e=0;e<t.length;e+=1)if(t.charCodeAt(e)>255)return!1;return!0},$=t=>p(y.encode(JSON.stringify(t))),b=t=>!t.startsWith(f)&&w(t)?t:`${f}${p(y.encode(t))}`,m="/_lunora/scheduler/dispatch",I=t=>{let e=t.length;for(;e>0&&t[e-1]==="/";)e-=1;return t.slice(0,e)},A=(t,e,n)=>{try{const r=JSON.parse(n)?.error;if(typeof r=="object"&&r!==null&&typeof r.code=="string"){const{code:s,data:c,message:i}=r;return new a(s,typeof i=="string"?i:void 0,{data:c,status:e})}}catch{}return new a("INTERNAL",`${t}: function dispatch failed (${String(e)}): ${n}`,{status:e})},R=t=>{const{label:e}=t,n=globalThis.fetch,r=t.fetchImpl??(typeof n=="function"?n.bind(globalThis):void 0);return async(s,c,i={})=>{if(typeof r!="function")throw new TypeError(`${e}: no fetch implementation available — pass fetchImpl or run on a platform with global fetch`);const l=t.env.LUNORA_ORIGIN_URL;if(typeof l!="string"||l.length===0)throw new a("INTERNAL",`${e}: \`LUNORA_ORIGIN_URL\` must be set on the Worker env so a handler can call back into Lunora functions`);const u=t.env.LUNORA_ADMIN_TOKEN;if(typeof u!="string"||u.length===0)throw new a("INTERNAL",`${e}: \`LUNORA_ADMIN_TOKEN\` must be set on the Worker env to authenticate function dispatch`);const N=`${I(l)}${m}`,h={authorization:`Bearer ${u}`,"content-type":"application/json"};t.identity?.userId!==void 0&&(h["x-lunora-userid"]=b(t.identity.userId)),t.identity?.claims!==void 0&&(h["x-lunora-identity"]=$(t.identity.claims));const o=await r(N,{body:JSON.stringify({args:c??{},functionPath:s.__lunoraRef,shardKey:i.shardKey}),headers:h,method:"POST"});if(!o.ok)throw A(e,o.status,await o.text());const d=await o.text();if(d.length!==0)try{return JSON.parse(d)}catch{throw new a("INTERNAL",`${e}: function dispatch returned a non-JSON body (${String(o.status)}): ${d}`,{status:o.status})}}};export{R as A};
@@ -1,3 +0,0 @@
1
- import{s as q}from"./component-shared-BVjAbtUu.mjs";import{resolveAgentModel as L}from"./createAgentGenerate-BS1vasdV.mjs";import{i as _,c as C,t as J,n as Q}from"./memory-DNRyyp1b.mjs";import{buildModelMessages as E}from"./buildModelMessages-Dm2wVNQy.mjs";import{agentBindingName as V}from"../naming.mjs";import{toFunctionReference as v}from"./AGENT_MODULE-BXx-tSCe.mjs";const W=8,b=e=>e===void 0?"null":JSON.stringify(e),X=e=>e===void 0?[]:[e].flat(),Y=async(e,t)=>(await Promise.all(e.map(async o=>o({steps:t})))).some(Boolean),Z=(e,t)=>{if(t===void 0)return e;if(e===void 0)return{...t};const o={};for(const a of["inputTokens","outputTokens","totalTokens"])(e[a]!==void 0||t[a]!==void 0)&&(o[a]=(e[a]??0)+(t[a]??0));return o},z=async(e,t,o,a,r)=>{const{needsApproval:n}=e;return n===void 0||n===!1?!1:n===!0?!0:o.do(a,async()=>n(t,r))},H=async(e,t)=>{const{instanceId:o,patchThread:a,persist:r,step:n}=e;await r({content:`Awaiting approval to run tool "${t.name}".`,messageKey:`${o}:approval:${t.id}`,role:"tool",status:"awaiting_approval",toolCallId:t.id,toolName:t.name}),await a({status:"awaiting_input"});const i=await n.waitForEvent(`approval:${t.id}`,{type:`agent-approval:${t.id}`});return await a({status:"running"}),{decision:i.payload.decision,...i.payload.note===void 0?{}:{note:i.payload.note}}},tt=async(e,t)=>{const{env:o,getState:a,instanceId:r,onTokenDelta:n,persist:i,run:d,setState:c,step:p,threadKey:s,tools:u}=e,l=`tool:${t.name}:${t.id}`,m=u[t.name],h=`${r}:tool:${t.id}`;if(!m){await i({content:`Error: unknown tool "${t.name}"`,messageKey:h,role:"tool",stepName:l,toolCallId:t.id,toolName:t.name});return}const f=T=>{n?.({data:T,kind:"progress",threadKey:s,toolCallId:t.id})},$={env:o,getState:a,idempotencyKey:l,reportProgress:f,run:d,setState:c,threadKey:s,toolCallId:t.id},g={env:o,getState:a,idempotencyKey:l,reportProgress:f,run:d,threadKey:s,toolCallId:t.id},K=`tool:approval-gate:${t.id}`;let x;if(await z(m,t.input,p,K,g)){const{decision:T,note:S}=await H(e,t);if(T==="reject"){const M=S===void 0?"":` Reason: ${S}`;await i({content:`Tool "${t.name}" was rejected by the user and not run.${M}`,messageKey:h,role:"tool",status:"rejected",stepName:l,toolCallId:t.id,toolName:t.name});return}x="approved"}const w=await p.do(l,()=>Promise.resolve(m.execute(t.input,$)));await i({content:typeof w=="string"?w:b(w),messageKey:h,role:"tool",stepName:l,...x===void 0?{}:{status:x},toolCallId:t.id,toolName:t.name})},et=(e,t,o)=>{if(!t)return e;let{messages:a}=e;return t.messages!==void 0&&(a=t.messages),t.system!==void 0&&(a=[{content:t.system,role:"system"},...a]),{activeTools:t.activeTools??e.activeTools,messages:a,model:t.model===void 0?e.model:L(t.model,o),toolChoice:t.toolChoice??e.toolChoice}},at=(e,t)=>{if(t===void 0||e.length<=t.maxMessages)return;const o=Math.max(1,t.keepRecent??Math.ceil(t.maxMessages/2));if(e.length<=o)return;let a=e.length-o;for(;a>0&&e[a]?.role==="tool";)a-=1;if(!(a<=0))return{older:e.slice(0,a),recent:e.slice(a)}},ot=async(e,t)=>{const{agent:o,compact:a,env:r}=e,n=at(t,o.compaction);if(n===void 0||a===void 0)return{history:t,summary:void 0};try{const i=await a({env:r,messages:E({history:n.older}),model:o.compaction?.model??o.model});return i.length>0?{history:n.recent,summary:i}:{history:t,summary:void 0}}catch{return{history:t,summary:void 0}}},st=async(e,t,o)=>{const{agent:a,env:r,generate:n,instructions:i,listMessages:d,memoryContext:c,onTokenDelta:p,run:s,step:u,streamGenerate:l,threadKey:m}=e;return u.do(`llm:turn:${String(t)}`,async()=>{const h=await s(d,{key:m}),{history:f,summary:$}=await ot(e,h);let g={activeTools:a.activeTools,messages:E({history:f,instructions:i,memoryContext:c,summary:$}),model:void 0,toolChoice:a.toolChoice};a.prepareStep&&(g=et(g,await a.prepareStep({messages:g.messages,stepNumber:t,steps:o}),r));const K={messages:g.messages,...g.activeTools===void 0?{}:{activeTools:g.activeTools},...g.model===void 0?{}:{model:g.model},...g.toolChoice===void 0?{}:{toolChoice:g.toolChoice}};return l&&p?l(K,x=>{p({text:x,threadKey:m,turn:t})}):n(K)})},A=async(e,t)=>{const{agent:o,step:a}=e;o.onStepFinish&&await a.do(`agent:step-finish:${String(t.turn)}`,async()=>(await o.onStepFinish?.(t),!0))},nt=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}}),R=e=>{const t=e?.context;return typeof t=="string"&&t.length>0?t:void 0},rt=e=>q({depth:e?.depth,fanOut:e?.fanOut,maxNodes:e?.maxNodes,maxSeeds:e?.maxSeeds}),it=async(e,t,o,a)=>{if(e.source===void 0)return;const r=v(e.source),{topK:n}=e,i=C("memory:retrieve",e.key),d=await o.do(i,async()=>a(r,{query:t,...n===void 0?{}:{topK:n}}));return R(d)},lt=async(e,t,o,a,r,n)=>{if(o===void 0)return;const i=C("memory:traverse",e.key),d=await r.do(i,async()=>n(a,{owner:o,query:t,...rt(e.graph)}));return R(d)},dt=async(e,t,o,a,r)=>{if(t===void 0)return;const n=C("memory:recall",e.key),i={owner:t,...e.episodic?.recall===void 0?{}:{limit:e.episodic.recall}},d=await a.do(n,async()=>r(o,i));return R(d)},ct=async(e,t)=>e.kind==="episodic"?dt(e,t.owner,t.episodeRecall,t.step,t.run):e.kind==="graph"?lt(e,t.input,t.owner,t.graphTraverse,t.step,t.run):it(e,t.input,t.step,t.run),ut=e=>{const t=e.findIndex(o=>o.kind==="episodic");return e.filter((o,a)=>o.kind!=="episodic"||a===t)},pt=async(e,t,o,a,r,n)=>{const i=ut(Q(e));if(i.length===0)return;const d=v(a.graphTraverse),c=v(a.episodeRecall),p=[];for(const s of i){const u=await ct(s,{episodeRecall:c,graphTraverse:d,input:t,owner:o,run:n,step:r});u!==void 0&&p.push(u)}return p.length>0?p.join(`
2
-
3
- `):void 0},mt=async e=>{const{agent:t,env:o,extractGraph:a,finalText:r,input:n,instanceId:i,owner:d,paths:c,run:p,step:s}=e;if(a===void 0||d===void 0||r===void 0||r.length===0)return;const u=_(t);if(u!==void 0)try{const l={assistantText:r,env:o,model:u.graph?.extractionModel??t.model,userInput:n},m=await s.do(C("memory:extract",u.key),async()=>a(l));await p(v(c.graphUpsert),{...m,messageKey:`${i}:${C("extract",u.key)}`,owner:d})}catch{}},yt=async e=>{const{agent:t,env:o,extractEpisode:a,finalText:r,input:n,instanceId:i,owner:d,paths:c,run:p,step:s,threadKey:u}=e;if(a===void 0||d===void 0||r===void 0||r.length===0)return;const l=J(t);if(l!==void 0)try{const m={assistantText:r,env:o,model:l.episodic?.extractionModel??t.model,userInput:n},{summary:h}=await s.do(C("memory:episode",l.key),async()=>a(m));await p(v(c.episodeUpsert),{messageKey:`${i}:${C("episode",l.key)}`,owner:d,summary:h,threadKey:u})}catch{}},gt=async(e,t,o)=>{const a=e[V(t)];if(!(!a||typeof a.get!="function"))try{await(await a.get(o)).terminate()}catch{}},vt=async(e,t,o,a,r)=>{const{instanceId:n,persist:i}=e,d=o.usage===void 0?{}:{usage:o.usage};if(o.toolCalls.length===0){const c=o.output!==void 0&&o.text.length===0?b(o.output):o.text;return await i({content:c,messageKey:`${n}:assistant:${String(t)}`,role:"assistant"}),await A(e,{text:o.text,toolCalls:[],turn:t,...d}),{final:{stopped:"final",text:o.text,turns:t+1,...o.output===void 0?{}:{output:o.output}}}}await i({content:o.text,messageKey:`${n}:assistant:${String(t)}`,role:"assistant",toolCalls:o.toolCalls});for(const c of o.toolCalls)await tt(e,c);if(await A(e,{text:o.text,toolCalls:o.toolCalls,turn:t,...d}),a.push(nt(o)),r.length>0&&await Y(r,a))return"stopCondition"},ht=async(e,t,o,a)=>{const r=[];let n,i=!1,d=0;for(let c=0;c<t;c+=1){const p=await st(e,c,r);a.value=Z(a.value,p.usage),d=c+1;const s=await vt(e,c,p,r,o);if(s==="stopCondition"){i=!0;break}if(s!==void 0){n=s.final;break}}return{final:n,stoppedByCondition:i,turnsRun:d}},$t=async e=>{const{agent:t,compact:o,env:a,exportName:r,extractEpisode:n,extractGraph:i,generate:d,instanceId:c,onTokenDelta:p,params:s,paths:u,run:l,step:m,streamGenerate:h}=e,f=t.maxTurns??W,$=X(t.stopWhen),g=v(u.appendMessage),K=v(u.ensureThread),x=v(u.listMessages),w=v(u.patchThread),T=v(u.setState),S=v(u.state),M=async y=>{await l(g,{threadKey:s.threadKey,...y})},F=async y=>{await l(w,{key:s.threadKey,...y})},G=async()=>await l(S,{key:s.threadKey}),j=async y=>{await l(T,{key:s.threadKey,state:y})},N=await l(K,{agent:r,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}});N?.replaced&&N.priorInstanceId!==void 0&&await gt(a,r,N.priorInstanceId),await M({content:s.input,messageKey:`${c}:user`,role:"user"});const B=await pt(t,s.input,s.owner,u,m,l),D=typeof t.instructions=="function"?t.instructions({env:a,input:s.input,threadKey:s.threadKey}):t.instructions,P={agent:t,compact:o,env:a,generate:d,getState:G,instanceId:c,instructions:D,listMessages:x,memoryContext:B,onTokenDelta:p,patchThread:F,persist:M,run:l,setState:j,step:m,streamGenerate:h,threadKey:s.threadKey,tools:t.tools??{}},I={value:void 0};try{const{final:y,stoppedByCondition:O,turnsRun:U}=await ht(P,f,$,I),k=I.value===void 0?{}:{usage:I.value};return await mt({agent:t,env:a,extractGraph:i,finalText:y?.text,input:s.input,instanceId:c,owner:s.owner,paths:u,run:l,step:m}),await yt({agent:t,env:a,extractEpisode:n,finalText:y?.text,input:s.input,instanceId:c,owner:s.owner,paths:u,run:l,step:m,threadKey:s.threadKey}),y?(await l(w,{key:s.threadKey,status:"idle",...k}),{...y,...k}):O?(await l(w,{key:s.threadKey,status:"idle",...k}),{stopped:"stopCondition",turns:U,...k}):(await l(w,{error:`agent stopped: maxTurns (${String(f)}) reached`,key:s.threadKey,status:"error",...k}),{stopped:"maxTurns",turns:f,...k})}catch(y){throw await l(w,{error:y instanceof Error?y.message:String(y),key:s.threadKey,status:"error",...I.value===void 0?{}:{usage:I.value}}),y}};export{$t as runAgentLoop,at as splitForCompaction};