@lunora/agent 1.0.0-alpha.125 → 1.0.0-alpha.126
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/channels.d.mts +2 -2
- package/dist/channels.d.ts +2 -2
- package/dist/component.mjs +1 -1
- package/dist/inbound.d.mts +1 -1
- package/dist/inbound.d.ts +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/VoiceSessionDO-Z-TCvJx2.mjs +1 -0
- package/dist/packem_shared/runVoiceTurn-DeKnbtou.mjs +1 -0
- package/dist/packem_shared/sandbox-budgets-DDvj4Orr.mjs +1 -0
- package/dist/packem_shared/sandboxComponent-CKX-iNXC.mjs +7 -0
- package/dist/packem_shared/{types.d-DdUBBTKO.d.mts → types.d-B_VV-x4x.d.mts} +24 -2
- package/dist/packem_shared/{types.d-DdUBBTKO.d.ts → types.d-B_VV-x4x.d.ts} +24 -2
- package/dist/packem_shared/voice-turn-hyURXfXc.mjs +1 -0
- package/dist/reply.d.mts +1 -1
- package/dist/reply.d.ts +1 -1
- package/dist/sandbox.d.mts +49 -4
- package/dist/sandbox.d.ts +49 -4
- package/dist/sandbox.mjs +1 -1
- package/dist/skill-markdown.d.mts +1 -1
- package/dist/skill-markdown.d.ts +1 -1
- package/package.json +2 -2
- package/dist/packem_shared/VoiceSessionDO-Ci1gaR3m.mjs +0 -1
- package/dist/packem_shared/base64-5eyBfWO3.mjs +0 -1
- package/dist/packem_shared/runVoiceTurn-B9WgyNaq.mjs +0 -1
- package/dist/packem_shared/sandboxComponent-BtOkUYpY.mjs +0 -5
- package/dist/packem_shared/voice-turn-CYXdylKF.mjs +0 -1
package/dist/channels.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as AgentDefinition } from "./packem_shared/types.d-
|
|
2
|
-
export type { I as InboundChannelEvent } from "./packem_shared/types.d-
|
|
1
|
+
import { A as AgentDefinition } from "./packem_shared/types.d-B_VV-x4x.mjs";
|
|
2
|
+
export type { I as InboundChannelEvent } from "./packem_shared/types.d-B_VV-x4x.mjs";
|
|
3
3
|
import '@lunora/mail/inbound';
|
|
4
4
|
import 'ai';
|
|
5
5
|
/**
|
package/dist/channels.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as AgentDefinition } from "./packem_shared/types.d-
|
|
2
|
-
export type { I as InboundChannelEvent } from "./packem_shared/types.d-
|
|
1
|
+
import { A as AgentDefinition } from "./packem_shared/types.d-B_VV-x4x.js";
|
|
2
|
+
export type { I as InboundChannelEvent } from "./packem_shared/types.d-B_VV-x4x.js";
|
|
3
3
|
import '@lunora/mail/inbound';
|
|
4
4
|
import 'ai';
|
|
5
5
|
/**
|
package/dist/component.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{LunoraError as g}from"@lunora/errors";import{defineTable as k,initLunora as D,defineSchemaExtension as j}from"@lunora/server";import{v as e}from"@lunora/values";import{a as q,A as _,d as P,b as F}from"./packem_shared/component-shared-G8ngerkU.mjs";import{graphTables as G,graphComponent as H}from"./packem_shared/normalizeEntityName-k3fjicAG.mjs";import{normalizeEntityName as he}from"./packem_shared/normalizeEntityName-k3fjicAG.mjs";import{sandboxComponent as we}from"./packem_shared/sandboxComponent-
|
|
1
|
+
import{LunoraError as g}from"@lunora/errors";import{defineTable as k,initLunora as D,defineSchemaExtension as j}from"@lunora/server";import{v as e}from"@lunora/values";import{a as q,A as _,d as P,b as F}from"./packem_shared/component-shared-G8ngerkU.mjs";import{graphTables as G,graphComponent as H}from"./packem_shared/normalizeEntityName-k3fjicAG.mjs";import{normalizeEntityName as he}from"./packem_shared/normalizeEntityName-k3fjicAG.mjs";import{sandboxComponent as we}from"./packem_shared/sandboxComponent-CKX-iNXC.mjs";const v="agent_episodes",X=5,Q=20,W=500,N=200,Y=/\s+/gu,z=d=>d===void 0||!Number.isFinite(d)?X:Math.min(Q,Math.max(1,Math.trunc(d))),V={episodes:k({createdAt:e.number(),messageKey:e.string(),owner:e.string(),summary:e.string(),threadKey:e.optional(e.string())}).index("byOwnerCreatedAt",["owner","createdAt"]).index("byOwnerMessageKey",["owner","messageKey"],{unique:!0}).public()},{mutation:J,query:Z}=D.dataModel().create(),ee=()=>{const d=J.input({createdAt:e.optional(e.number()),messageKey:e.string(),owner:e.string(),summary:e.string(),threadKey:e.optional(e.string())}).mutation(async({args:s,ctx:u})=>{const c=s.summary.replaceAll(Y," ").trim().slice(0,W);if(c.length===0)return{recorded:!1};if(await u.db.query(v).withIndex("byOwnerMessageKey",I=>I.eq("owner",s.owner).eq("messageKey",s.messageKey)).first())return{recorded:!1};await u.db.insert(v,{createdAt:s.createdAt??Date.now(),messageKey:s.messageKey,owner:s.owner,summary:c,...s.threadKey===void 0?{}:{threadKey:s.threadKey}});const w=await u.db.query(v).withIndex("byOwnerCreatedAt",I=>I.eq("owner",s.owner)).order("asc").take(N+1);for(const I of w.slice(0,Math.max(0,w.length-N)))await u.db.delete(I._id);return{recorded:!0}}),o=Z.input({limit:e.optional(e.number()),owner:e.string()}).query(async({args:s,ctx:u})=>{const c=await u.db.query(v).withIndex("byOwnerCreatedAt",h=>h.eq("owner",s.owner)).order("desc").take(z(s.limit));return c.length===0?{context:""}:{context:c.toReversed().map(h=>`- ${h.summary}`).join(`
|
|
2
2
|
`)}});return{agentEpisodeRecall:q(o),agentEpisodeUpsert:q(d)}},S="threads",$="messages",M="run_queue",p=`${_}_${S}`,E=`${_}_${$}`,A=`${_}_${M}`,x=5,te=780*60*1e3,ne=j(_,{tables:{[$]:k({content:e.string(),createdAt:e.number(),messageKey:e.string(),role:e.union(e.literal("user"),e.literal("assistant"),e.literal("tool"),e.literal("system")),seq:e.number(),status:e.optional(e.union(e.literal("awaiting_approval"),e.literal("approved"),e.literal("rejected"))),stepName:e.optional(e.string()),threadKey:e.string(),toolCallId:e.optional(e.string()),toolCalls:e.optional(e.array(e.object({id:e.string(),input:e.any(),name:e.string()}))),toolName:e.optional(e.string())}).index("byThread",["threadKey","seq"]).index("byMessageKey",["threadKey","messageKey"],{unique:!0}).public(),[S]:k({agent:e.string(),createdAt:e.number(),error:e.optional(e.string().nullable()),completedInstanceId:e.optional(e.string().nullable()),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]:k({agent:e.string(),enqueuedAt:e.number(),instanceId:e.string(),position:e.number(),threadKey:e.string()}).index("byThread",["threadKey","position"]).index("byThreadInstance",["threadKey","instanceId"],{unique:!0}).public(),...G,...V}}),{mutation:f,query:T}=D.dataModel().create(),ie=async(d,o,s)=>{if(o.instanceId===void 0)throw new g("CONFLICT",`@lunora/agent: thread "${o.key}" already has a run in flight (instance "${o.priorInstanceId}") — cannot queue a dispatch with no instance id`);const{instanceId:u}=o,c=await d.query(A).withIndex("byThreadInstance",I=>I.eq("threadKey",o.key).eq("instanceId",u)).first();if(c)return{outcome:"queued",position:c.position};const h=await d.query(A).withIndex("byThread",I=>I.eq("threadKey",o.key)).collect();if(h.length>=x)throw new g("CONFLICT",`@lunora/agent: thread "${o.key}" run queue is full (depth ${String(x)}) — rejecting instance "${u}"`);const w=(h.at(-1)?.position??-1)+1;return await d.insert(A,{agent:o.agent,enqueuedAt:s,instanceId:u,position:w,threadKey:o.key}),{outcome:"queued",position:w}},ae=async(d,o,s)=>{if(o.policy==="queue")return ie(d,{agent:o.agent,instanceId:o.instanceId,key:o.key,priorInstanceId:o.priorInstanceId},s);if(o.policy!=="replace")throw new g("CONFLICT",`@lunora/agent: thread "${o.key}" already has a run in flight (instance "${o.priorInstanceId}") — onConcurrentRun="${o.policy}"`);return await d.patch(o.existingId,{error:null,status:"running",updatedAt:s,...o.instanceId===void 0?{}:{completedInstanceId:null,instanceId:o.instanceId}}),{outcome:"replaced",priorInstanceId:o.priorInstanceId}},oe=(d,o,s)=>{const u=d.instanceId;if(u===void 0||o===u||d.status!=="running"&&d.status!=="awaiting_input")return;const c=typeof d.updatedAt=="number"?d.updatedAt:0,h=d.status==="awaiting_input"?F:te;return s-c>h?void 0:u},ce=()=>{const d=f.input({agent:e.string(),initialState:e.optional(e.any()),instanceId:e.optional(e.string()),key:e.string(),onConcurrentRun:e.optional(e.union(e.literal("reject"),e.literal("queue"),e.literal("replace"))),owner:e.optional(e.string()),title:e.optional(e.string())}).mutation(async({args:t,ctx:n})=>{const a=Date.now(),i=await n.db.query(p).withIndex("byKey",r=>r.eq("key",t.key)).first();if(i){if(i.owner!==t.owner)throw new Error(`@lunora/agent: thread "${t.key}" belongs to another owner`);if(t.instanceId!==void 0&&i.completedInstanceId===t.instanceId)return{outcome:"completed"};const r=oe(i,t.instanceId,a);return r!==void 0?ae(n.db,{agent:t.agent,existingId:i._id,instanceId:t.instanceId,key:t.key,policy:t.onConcurrentRun??"reject",priorInstanceId:r},a):(await n.db.patch(i._id,{error:null,status:"running",updatedAt:a,...t.instanceId===void 0?{}:{completedInstanceId:null,instanceId:t.instanceId}}),{outcome:"continued"})}return await n.db.insert(p,{agent:t.agent,createdAt:a,key:t.key,messageCount:0,status:"running",updatedAt:a,...P({instanceId:t.instanceId,owner:t.owner,state:t.initialState,title:t.title})}),{outcome:"created"}}),o=f.input({content:e.string(),messageKey:e.string(),role:e.union(e.literal("user"),e.literal("assistant"),e.literal("tool"),e.literal("system")),status:e.optional(e.union(e.literal("awaiting_approval"),e.literal("approved"),e.literal("rejected"))),stepName:e.optional(e.string()),threadKey:e.string(),toolCallId:e.optional(e.string()),toolCalls:e.optional(e.array(e.object({id:e.string(),input:e.any(),name:e.string()}))),toolName:e.optional(e.string())}).mutation(async({args:t,ctx:n})=>{const a=await n.db.query(E).withIndex("byMessageKey",y=>y.eq("threadKey",t.threadKey).eq("messageKey",t.messageKey)).first();if(a)return{seq:a.seq};const i=await n.db.query(p).withIndex("byKey",y=>y.eq("key",t.threadKey)).first();if(!i)throw new Error(`@lunora/agent: cannot append to unknown thread "${t.threadKey}" — run agentEnsureThread first`);const r=i.messageCount,l=Date.now();return await n.db.insert(E,{content:t.content,createdAt:l,messageKey:t.messageKey,role:t.role,seq:r,threadKey:t.threadKey,...t.status===void 0?{}:{status:t.status},...t.stepName===void 0?{}:{stepName:t.stepName},...t.toolCallId===void 0?{}:{toolCallId:t.toolCallId},...t.toolCalls===void 0?{}:{toolCalls:t.toolCalls},...t.toolName===void 0?{}:{toolName:t.toolName}}),await n.db.patch(i._id,{messageCount:r+1,updatedAt:l}),{seq:r}}),s=f.input({messageKey:e.string(),threadKey:e.string()}).mutation(async({args:t,ctx:n})=>{const a=await n.db.query(E).withIndex("byMessageKey",i=>i.eq("threadKey",t.threadKey).eq("messageKey",t.messageKey)).first();a&&await n.db.delete(a._id)}),u=f.input({error:e.optional(e.string()),instanceId:e.optional(e.string()),key:e.optional(e.string()),status:e.optional(e.union(e.literal("idle"),e.literal("running"),e.literal("error"),e.literal("cancelled"),e.literal("awaiting_input"))),title:e.optional(e.string()),usage:e.optional(e.object({inputTokens:e.optional(e.number()),outputTokens:e.optional(e.number()),totalTokens:e.optional(e.number())}))}).mutation(async({args:t,ctx:n})=>{const{instanceId:a,key:i}=t;let r;i!==void 0?r=await n.db.query(p).withIndex("byKey",l=>l.eq("key",i)).first():a!==void 0&&(r=await n.db.query(p).withIndex("byInstance",l=>l.eq("instanceId",a)).first()),r&&await n.db.patch(r._id,{updatedAt:Date.now(),...t.error===void 0?{}:{error:t.error},...t.status===void 0?{}:{status:t.status},...t.title===void 0?{}:{title:t.title},...t.usage===void 0?{}:{usage:t.usage}})}),c=f.input({error:e.optional(e.string()),instanceId:e.string(),key:e.string(),status:e.union(e.literal("idle"),e.literal("error"),e.literal("cancelled")),usage:e.optional(e.object({inputTokens:e.optional(e.number()),outputTokens:e.optional(e.number()),totalTokens:e.optional(e.number())}))}).mutation(async({args:t,ctx:n})=>{const a=Date.now(),i=await n.db.query(p).withIndex("byKey",b=>b.eq("key",t.key)).first();if(i?.instanceId!==t.instanceId){if(i?.completedInstanceId===t.instanceId&&i.status==="running"&&typeof i.instanceId=="string")return{dequeued:i.instanceId};const b=await n.db.query(A).withIndex("byThreadInstance",K=>K.eq("threadKey",t.key).eq("instanceId",t.instanceId)).first();return b&&await n.db.delete(b._id),{}}const y=(i.completedInstanceId===t.instanceId?[]:await n.db.query(A).withIndex("byThread",b=>b.eq("threadKey",t.key)).collect())[0];if(!y)return await n.db.patch(i._id,{completedInstanceId:t.instanceId,status:t.status,updatedAt:a,...t.error===void 0?{}:{error:t.error},...t.usage===void 0?{}:{usage:t.usage}}),{};const m=y.instanceId;return await n.db.delete(y._id),await n.db.patch(i._id,{completedInstanceId:t.instanceId,instanceId:m,status:"running",updatedAt:a,...t.error===void 0?{}:{error:t.error},...t.usage===void 0?{}:{usage:t.usage}}),{dequeued:m}}),h=f.input({key:e.string(),state:e.any()}).mutation(async({args:t,ctx:n})=>{const a=await n.db.query(p).withIndex("byKey",i=>i.eq("key",t.key)).first();a&&await n.db.patch(a._id,{state:t.state,updatedAt:Date.now()})}),w=(t,n)=>{if(!t)return;const{owner:a}=t;if(!(a!==void 0&&a!==(n.userId??void 0)))return t},I=T.input({key:e.string()}).query(async({args:t,ctx:n})=>{const a=await n.db.query(p).withIndex("byKey",i=>i.eq("key",t.key)).first();return w(a,n.auth)}),O=T.input({key:e.string()}).query(async({args:t,ctx:n})=>{const a=await n.db.query(p).withIndex("byKey",i=>i.eq("key",t.key)).first();return w(a,n.auth)?.state}),L=T.input({key:e.string(),limit:e.optional(e.number())}).query(async({args:t,ctx:n})=>{const a=await n.db.query(p).withIndex("byKey",i=>i.eq("key",t.key)).first();return w(a,n.auth)===void 0?[]:t.limit!==void 0?(await n.db.query(E).withIndex("byThread",r=>r.eq("threadKey",t.key)).order("desc").take(t.limit)).toReversed():n.db.query(E).withIndex("byThread",i=>i.eq("threadKey",t.key)).collect()}),U=f.input({decision:e.union(e.literal("approve"),e.literal("reject")),instanceId:e.string(),note:e.optional(e.string()),threadKey:e.string(),toolCallId:e.string()}).mutation(async({args:t,ctx:n})=>{const a=await n.db.query(p).withIndex("byKey",m=>m.eq("key",t.threadKey)).first(),i=w(a,n.auth);if(i===void 0)throw new g("FORBIDDEN",`@lunora/agent: not allowed to resolve approvals on thread "${t.threadKey}"`);if(i.instanceId!==t.instanceId)throw new g("FORBIDDEN",`@lunora/agent: instance "${t.instanceId}" does not own thread "${t.threadKey}"`);const r=i.agent,{agents:l}=n,y=l?.[r];if(typeof y?.sendEvent!="function")throw new g("INTERNAL",`@lunora/agent: no ctx.agents["${r}"] producer to resolve the approval — run codegen/dev so the agent binding is wired`);return await 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}}),B=f.input({agent:e.string(),input:e.string(),threadKey:e.string(),title:e.optional(e.string())}).mutation(async({args:t,ctx:n})=>{const{agents:a}=n,i=a?.[t.agent];if(typeof i?.run!="function")throw new g("INTERNAL",`@lunora/agent: no ctx.agents["${t.agent}"] producer to start a run — run codegen/dev so the agent binding is wired, and check the agent name`);if(i.publicRun!==!0)throw new g("FORBIDDEN",`@lunora/agent: agent "${t.agent}" is not enabled for public runs — set defineAgent({ publicRun: true }) to allow an external client (e.g. the @lunora/mcp server) to start it`);const r=n.auth.userId??void 0,l=await n.db.query(p).withIndex("byKey",m=>m.eq("key",t.threadKey)).first();if(l){const m=l.status,b=l.instanceId,K=l.owner;if((m==="running"||m==="awaiting_input")&&b!==void 0&&(K===void 0||K===r))return{id:b,threadKey:t.threadKey};if(K!==r)throw new g("FORBIDDEN",`@lunora/agent: thread "${t.threadKey}" belongs to another owner`)}const{id:y}=await i.run({input:t.input,threadKey:t.threadKey,...r===void 0?{}:{owner:r},...t.title===void 0?{}:{title:t.title}});return{id:y,threadKey:t.threadKey}}),C=H(),R=ee();return{extension:ne,functions:{agentAppendMessage:q(o),agentCompleteRun:q(c),agentEnsureThread:q(d),agentEpisodeRecall:R.agentEpisodeRecall,agentEpisodeUpsert:R.agentEpisodeUpsert,agentGraphTraverse:C.agentGraphTraverse,agentGraphUpsert:C.agentGraphUpsert,agentMessages:L,agentDeleteMessage:q(s),agentPatchThread:q(u),agentResolveApproval:U,agentRun:B,agentSetState:q(h),agentState:O,agentThread:I}}};export{ce as agentComponent,ne as agentExtension,he as normalizeEntityName,we as sandboxComponent};
|
package/dist/inbound.d.mts
CHANGED
package/dist/inbound.d.ts
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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-
|
|
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
|
|
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-B_VV-x4x.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 AgentRunOptions, W as AgentStepFinishInfo, X as AgentStepInfo, Y as AgentThreadStatus, Z as AgentTokenDelta, _ as AgentToolCall, b as AgentToolContext, $ as AgentUsage, a0 as AgentVoiceConfig, a1 as AgentWorkflowBindingLike, a2 as AgentWorkflowInstanceLike, a3 as EnsureThreadOutcome } from "./packem_shared/types.d-B_VV-x4x.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";
|
|
6
|
-
export { type BrowserToolInput, type BrowserToolOptions, type ContainerToolInput, type ContainerToolOptions, type FsToolInput, type FsToolOptions, browserTool, containerTool, fsTool } from "./sandbox.mjs";
|
|
6
|
+
export { type BrowserRenderResult, type BrowserToolInput, type BrowserToolOptions, type ContainerToolInput, type ContainerToolOptions, type FsToolInput, type FsToolOptions, browserTool, containerTool, fsTool } from "./sandbox.mjs";
|
|
7
7
|
import { createAi } from '@lunora/ai';
|
|
8
8
|
import { WorkflowDefinition } from '@lunora/workflow';
|
|
9
9
|
import '@lunora/mail/inbound';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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-
|
|
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
|
|
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-B_VV-x4x.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 AgentRunOptions, W as AgentStepFinishInfo, X as AgentStepInfo, Y as AgentThreadStatus, Z as AgentTokenDelta, _ as AgentToolCall, b as AgentToolContext, $ as AgentUsage, a0 as AgentVoiceConfig, a1 as AgentWorkflowBindingLike, a2 as AgentWorkflowInstanceLike, a3 as EnsureThreadOutcome } from "./packem_shared/types.d-B_VV-x4x.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";
|
|
6
|
-
export { type BrowserToolInput, type BrowserToolOptions, type ContainerToolInput, type ContainerToolOptions, type FsToolInput, type FsToolOptions, browserTool, containerTool, fsTool } from "./sandbox.js";
|
|
6
|
+
export { type BrowserRenderResult, type BrowserToolInput, type BrowserToolOptions, type ContainerToolInput, type ContainerToolOptions, type FsToolInput, type FsToolOptions, browserTool, containerTool, fsTool } from "./sandbox.js";
|
|
7
7
|
import { createAi } from '@lunora/ai';
|
|
8
8
|
import { WorkflowDefinition } from '@lunora/workflow';
|
|
9
9
|
import '@lunora/mail/inbound';
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as t,s as r}from"./packem_shared/agent-loop-ByRhLA54.mjs";import{collectAgenticMemoryTools as a,toSearchResults as i}from"./packem_shared/collectAgenticMemoryTools-BeMWT2qt.mjs";import{agentAsTool as l}from"./packem_shared/agentAsTool-CgZb6ycK.mjs";import{codeTool as m}from"./packem_shared/codeTool-BQb-K3my.mjs";import{agentComponent as c,agentExtension as x}from"./component.mjs";import{default as A}from"./packem_shared/createAgentContext-BvU9LP43.mjs";import{defineAgent as d,defineAgentTool as u,isAgentDefinition as N}from"./packem_shared/defineAgent-C3FzOwlh.mjs";import{functionTool as D}from"./packem_shared/functionTool-D3CP4f8-.mjs";import{createAgentGenerate as M,createEpisodeExtract as O,createGraphExtract as _,createStreamGenerate as C,resolveAgentModel as G}from"./packem_shared/createAgentGenerate-BOILDUZj.mjs";import{adaptMcpResult as F,mcpTools as L}from"./packem_shared/adaptMcpResult-CVlq-_TO.mjs";import{buildModelMessages as k}from"./packem_shared/buildModelMessages-Y4tGo1T9.mjs";import{agentBindingName as R,agentClassName as V,agentDefaultName as b,voiceBindingName as h,voiceClassName as w}from"./naming.mjs";import{AGENT_MODULE as I,DEFAULT_AGENT_FUNCTION_PATHS as P,SANDBOX_INVOKE_PATH as X,SANDBOX_MODULE as y,toFunctionReference as K}from"./packem_shared/AGENT_MODULE-M4D1EejI.mjs";import{browserTool as j,containerTool as q,fsTool as z}from"./sandbox.mjs";import{defineSkill as Q,isSkillDefinition as Y}from"./packem_shared/defineSkill-DGGvDWNq.mjs";import{default as $}from"./packem_shared/VoiceSessionDO-
|
|
1
|
+
import{r as t,s as r}from"./packem_shared/agent-loop-ByRhLA54.mjs";import{collectAgenticMemoryTools as a,toSearchResults as i}from"./packem_shared/collectAgenticMemoryTools-BeMWT2qt.mjs";import{agentAsTool as l}from"./packem_shared/agentAsTool-CgZb6ycK.mjs";import{codeTool as m}from"./packem_shared/codeTool-BQb-K3my.mjs";import{agentComponent as c,agentExtension as x}from"./component.mjs";import{default as A}from"./packem_shared/createAgentContext-BvU9LP43.mjs";import{defineAgent as d,defineAgentTool as u,isAgentDefinition as N}from"./packem_shared/defineAgent-C3FzOwlh.mjs";import{functionTool as D}from"./packem_shared/functionTool-D3CP4f8-.mjs";import{createAgentGenerate as M,createEpisodeExtract as O,createGraphExtract as _,createStreamGenerate as C,resolveAgentModel as G}from"./packem_shared/createAgentGenerate-BOILDUZj.mjs";import{adaptMcpResult as F,mcpTools as L}from"./packem_shared/adaptMcpResult-CVlq-_TO.mjs";import{buildModelMessages as k}from"./packem_shared/buildModelMessages-Y4tGo1T9.mjs";import{agentBindingName as R,agentClassName as V,agentDefaultName as b,voiceBindingName as h,voiceClassName as w}from"./naming.mjs";import{AGENT_MODULE as I,DEFAULT_AGENT_FUNCTION_PATHS as P,SANDBOX_INVOKE_PATH as X,SANDBOX_MODULE as y,toFunctionReference as K}from"./packem_shared/AGENT_MODULE-M4D1EejI.mjs";import{browserTool as j,containerTool as q,fsTool as z}from"./sandbox.mjs";import{defineSkill as Q,isSkillDefinition as Y}from"./packem_shared/defineSkill-DGGvDWNq.mjs";import{default as $}from"./packem_shared/VoiceSessionDO-Z-TCvJx2.mjs";import{r as oe}from"./packem_shared/voice-turn-hyURXfXc.mjs";import{default as re}from"./packem_shared/compileAgentWorkflow-DGw7K1vH.mjs";export{I as AGENT_MODULE,P as DEFAULT_AGENT_FUNCTION_PATHS,X as SANDBOX_INVOKE_PATH,y as SANDBOX_MODULE,$ as VoiceSessionDO,F as adaptMcpResult,l as agentAsTool,R as agentBindingName,V as agentClassName,c as agentComponent,b as agentDefaultName,x as agentExtension,j as browserTool,k as buildModelMessages,m as codeTool,a as collectAgenticMemoryTools,re as compileAgentWorkflow,q as containerTool,A as createAgentContext,M as createAgentGenerate,O as createEpisodeExtract,_ as createGraphExtract,C as createStreamGenerate,d as defineAgent,u as defineAgentTool,Q as defineSkill,z as fsTool,D as functionTool,N as isAgentDefinition,Y as isSkillDefinition,L as mcpTools,G as resolveAgentModel,t as runAgentLoop,oe as runVoiceTurn,r as splitForCompaction,K as toFunctionReference,i as toSearchResults,h as voiceBindingName,w as voiceClassName};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createAi as A}from"@lunora/ai";import{t as b}from"./createDispatchRunner-BxtGxAQi-DXXP7SxZ.mjs";import{p as x,d as T,a as _,i as p,b as y,c as v,e as E,t as k,f as M,r as w,g as I}from"./voice-turn-hyURXfXc.mjs";import{createStreamGenerate as C,createCompact as R}from"./createAgentGenerate-BOILDUZj.mjs";import{DEFAULT_AGENT_FUNCTION_PATHS as L,toFunctionReference as m}from"./AGENT_MODULE-M4D1EejI.mjs";const N="@cf/openai/whisper-large-v3-turbo",O="@cf/deepgram/aura-1",U=8*1024*1024,B=100,f=4e3,g=f*4+1024,F=4002,D=4003,z=4004,W=256*1024,S=15,G=5e3,X=h=>{if(h===null||typeof h!="object")return!1;const{text:t,type:e}=h;return e==="commit"||e==="interrupt"||e==="text"&&typeof t=="string"};class J{agent;ai;env;exportName;paths;streamGenerate;sttModel;ttsModel;maxSessionTurns;audioBuffers=new Map;bufferedBytes=new Map;controllers=new Map;state;constructor(t,e,s,r){this.state=t,this.env=e,this.agent=s,this.exportName=r,this.paths=L,this.ai=A({binding:e.AI,env:e}),this.streamGenerate=C(s,e),this.sttModel=s.voice?.stt??N,this.ttsModel=s.voice?.tts??O,this.maxSessionTurns=s.voice?.maxTurns??B}fetch(t){if(t.headers.get("Upgrade")!=="websocket")return new Response("Expected a WebSocket upgrade",{status:426});const s=new URL(t.url).searchParams.get("threadKey");if(!s)return new Response("Missing threadKey",{status:400});const r=globalThis.WebSocketPair,i=new r,n=i[0],o=i[1];this.state.acceptWebSocket(o);const c=crypto.randomUUID(),d=x(t.headers.get("x-lunora-identity")),a=T(t.headers.get("x-lunora-userid")),u=_(t.headers.get("x-lunora-identity-exp"));if(p(u))return y(o),new Response(null,{status:101,webSocket:n});o.serializeAttachment?.({connectionId:c,threadKey:s,turn:0,...u===void 0?{}:{expiresAt:u},...d===void 0?{}:{identity:d},...a===void 0?{}:{userId:a}}),this.send(o,{audioFormat:this.agent.voice?.audioFormat??"mp3",type:"ready"});const l=this.agent.voice?.greeting;return l&&l.length>0&&this.state.waitUntil?.(this.speakGreeting(o,c,s,a,d,l)),new Response(null,{status:101,webSocket:n})}async webSocketMessage(t,e){const s=t.deserializeAttachment?.();if(s){if(p(s.expiresAt)){y(t);return}try{if(typeof e=="string"){await this.handleControl(t,s,e);return}this.bufferAudio(s.connectionId,new Uint8Array(e),t)}catch(r){this.send(t,{message:r instanceof Error?r.message:String(r),type:"error"})}}}webSocketClose(t){this.cleanupSocket(t)}webSocketError(t){this.cleanupSocket(t)}resolveRun(t,e){const s=t===void 0&&e===void 0?void 0:{...e===void 0?{}:{claims:e},...t===void 0?{}:{userId:t}};return b({env:this.env,label:"@lunora/agent voice",...s===void 0?{}:{identity:s}})}async transcribe(t){const e=v(t);return E(await this.ai.run(this.sttModel,{audio:k(e)}))}async synthesize(t,e){const s=this.agent.voice?.speaker;return M(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){if(s.length>g){this.send(t,{message:`control frame exceeds the maximum of ${String(g)} characters`,type:"error"}),this.closeSocket(t,z,"control_frame_limit");return}let r;try{r=JSON.parse(s)}catch{return}if(!X(r)){this.send(t,{message:'unsupported control frame — expected { type: "text", text }, { type: "commit" } or { type: "interrupt" }',type:"error"});return}const i=r;if(i.type==="interrupt"){this.controllers.get(e.connectionId)?.abort();return}if(i.type==="text"&&i.text.length>f){this.send(t,{message:`text frame exceeds the maximum of ${String(f)} characters`,type:"error"});return}if(e.turn>=this.maxSessionTurns){this.send(t,{message:`voice session reached its ${String(this.maxSessionTurns)}-turn limit — reconnect to continue`,type:"error"}),this.closeSocket(t,F,"turn_limit");return}if(this.controllers.has(e.connectionId)){i.type==="commit"&&this.drainAudio(e.connectionId),this.send(t,{message:"a turn is already in progress — send an interrupt before the next utterance",type:"error"});return}if(i.type==="commit"){const n=this.drainAudio(e.connectionId);await this.runTurn(t,e,{pcm:n});return}await this.runTurn(t,e,{text:i.text})}bufferAudio(t,e,s){const r=(this.bufferedBytes.get(t)??0)+e.byteLength;if(r>U){this.audioBuffers.delete(t),this.bufferedBytes.delete(t),this.send(s,{message:"utterance exceeded the maximum buffer — send a commit sooner",type:"error"}),this.closeSocket(s,D,"utterance_too_large");return}const i=this.audioBuffers.get(t)??[];i.push(e),this.audioBuffers.set(t,i),this.bufferedBytes.set(t,r)}drainAudio(t){const e=this.audioBuffers.get(t)??[];this.audioBuffers.delete(t),this.bufferedBytes.delete(t);const s=e.reduce((n,o)=>n+o.byteLength,0),r=new Uint8Array(s);let i=0;for(const n of e)r.set(n,i),i+=n.byteLength;return r}async runTurn(t,e,s){const r=new AbortController;this.controllers.set(e.connectionId,r);try{await w({agent:this.agent,compact:R(),connectionId:e.connectionId,env:this.env,exportName:this.exportName,paths:this.paths,run:this.resolveRun(e.userId,e.identity),send:i=>{this.send(t,i)},sendAudio:i=>{this.sendAudio(t,i)},signal:r.signal,streamGenerate:this.streamGenerate,synthesize:async(i,n)=>this.synthesizeWithSignal(i,n),threadKey:e.threadKey,transcribe:async i=>this.transcribe(i),turn:e.turn,waitForDrain:async()=>this.waitForSocketDrain(t),...e.userId===void 0?{}:{owner:e.userId},...s.pcm===void 0?{}:{pcm:s.pcm},...s.text===void 0?{}:{text:s.text}})}finally{this.controllers.get(e.connectionId)===r&&this.controllers.delete(e.connectionId),t.serializeAttachment?.({...e,turn:e.turn+1})}}async speakGreeting(t,e,s,r,i,n){const o=this.resolveRun(r,i),c=new AbortController,d=()=>c.signal.aborted;this.controllers.set(e,c);try{if((await o(m(this.paths.ensureThread),{agent:this.exportName,key:s,...this.agent.initialState===void 0?{}:{initialState:this.agent.initialState},...r===void 0?{}:{owner:r}}))?.outcome!=="created")return;for await(const u of I(await this.synthesizeWithSignal(n,c.signal))){if(d()||(await this.waitForSocketDrain(t),d()))break;this.sendAudio(t,u)}d()||(await o(m(this.paths.appendMessage),{content:n,messageKey:"voice:greeting:assistant",role:"assistant",threadKey:s}),this.send(t,{text:n,type:"assistant_done"}))}catch(a){this.send(t,{message:a instanceof Error?a.message:String(a),type:"error"})}finally{this.controllers.get(e)===c&&this.controllers.delete(e)}}async synthesizeWithSignal(t,e){return e.aborted?new Uint8Array(0):this.synthesize(t,e)}cleanupSocket(t){const e=t.deserializeAttachment?.();e&&(this.controllers.get(e.connectionId)?.abort(),this.controllers.delete(e.connectionId),this.audioBuffers.delete(e.connectionId),this.bufferedBytes.delete(e.connectionId))}closeSocket(t,e,s){try{t.close?.(e,s)}catch{}}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>W&&s<G;)await new Promise(r=>{setTimeout(r,S)}),s+=S}}export{J as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{p as s,c as i,f as p,e as n,r as m,g as c}from"./voice-turn-hyURXfXc.mjs";import"./agent-loop-ByRhLA54.mjs";import"./buildModelMessages-Y4tGo1T9.mjs";import"./AGENT_MODULE-M4D1EejI.mjs";export{s as parseIdentity,i as pcmToWav,p as readSynthesisAudio,n as readTranscriptionText,m as runVoiceTurn,c as toByteIterable};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const _=12e4,S=15e4,T=12e4,O=12e4,E=15e4;export{S,E as a,_ as b,T as c,O as d};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{LunoraError as i}from"@lunora/errors";import{initLunora as x}from"@lunora/server";import{v as a}from"@lunora/values";import{b as T,c as S,d as _}from"./sandbox-budgets-DDvj4Orr.mjs";const v=async(e,t,n)=>{if(e===null)return{overflowed:!1,text:""};const r=e.getReader(),o=new TextDecoder,s=()=>{r.cancel().catch(()=>{})};n?.addEventListener("abort",s);let c="",d=0,l=!1;try{for(;n?.aborted!==!0;){const{done:h,value:p}=await r.read();if(h)break;if(d+p.byteLength>t){l=!0,c+=o.decode(p.subarray(0,t-d),{stream:!0});break}d+=p.byteLength,c+=o.decode(p,{stream:!0})}c+=o.decode()}finally{n?.removeEventListener("abort",s),r.cancel().catch(()=>{})}if(n?.aborted===!0)throw n.reason;return{overflowed:l,text:c}},{internalAction:A}=x.dataModel().create(),N=()=>globalThis.document?.documentElement?.outerHTML??"",u=1e6,g=1e6,$=20,R=new TextEncoder,L=e=>{const t=[`exit code: ${String(e.code)}`];return e.stdout.length>0&&t.push(`stdout:
|
|
2
|
+
${e.stdout}`),e.stderr.length>0&&t.push(`stderr:
|
|
3
|
+
${e.stderr}`),t.join(`
|
|
4
|
+
|
|
5
|
+
`)},B=async(e,t)=>{const n=AbortSignal.timeout(_);try{const r=await e.fetch(t.path??"/",{...t.body===void 0?{}:{body:t.body},method:t.method??"GET",signal:n}),o=await v(r.body,g,n);return o.overflowed?`${o.text}
|
|
6
|
+
|
|
7
|
+
[truncated at ${String(g)} bytes]`:o.text}catch(r){return`fetch failed: ${r instanceof Error?r.message:String(r)}`}},O=async(e,t)=>{if(t.instance===void 0||t.instance.length===0)throw new i("BAD_REQUEST","@lunora/agent: sandbox container op arrived with no `instance` — the tool pins the thread's own container");const n=e.get(t.instance);if(t.op==="exec")try{return L(await n.exec(t.command??"",{args:t.args??[],timeoutMs:S}))}catch(r){return`exec failed: ${r instanceof Error?r.message:String(r)}`}if(t.op==="fetch")return await B(n,t);throw new i("INTERNAL",`@lunora/agent: sandbox container op "${t.op}" is not supported`)},m=(e,t)=>new i("INTERNAL",`@lunora/agent: sandbox ${e} op found no R2 bucket "${t}" on env — declare the r2_bucket binding in wrangler.jsonc and run codegen`),f=(e,t)=>{const n=e.env?.[t.bucket??""];return n&&typeof n.get=="function"?n:void 0},w=(e,t)=>{if(!e)throw m("browser",t.bucket??"");return e},E=e=>{let t=0,n=e.length;for(;t<n&&e[t]==="/";)t+=1;for(;n>t&&e[n-1]==="/";)n-=1;return e.slice(t,n)},y=(e,t)=>{const n=E(e),r=[];for(const s of t.split("/"))if(!(s===""||s===".")){if(s===".."){if(r.length===0)throw new i("BAD_REQUEST","@lunora/agent: fs path escapes the sandbox root");r.pop();continue}r.push(s)}const o=r.join("/");return n&&o?`${n}/${o}`:n||o},k=async(e,t,n)=>{const r=t.length>0?`${t}/`:"",o=n.length>0?n.length+1:0,s=[];let c;for(let d=0;d<$;d+=1){const l=await e.list({prefix:r,...c===void 0?{}:{cursor:c}});for(const h of l.objects)s.push(h.key.slice(o));if(!l.truncated||l.cursor===void 0)return{entries:s,truncated:!1};c=l.cursor}return{entries:s,truncated:!0}},b=async(e,t,n,r,o)=>{const s=y(t,n);return await e.put(s,r),{bytes:r.byteLength,key:s,mediaType:o}},M=async(e,t,n)=>{const r=t.url??"",o={timeoutMs:T};switch(t.op){case"content":return e.content(r,o);case"pdf":return b(w(n,t),t.root??"",t.path??"",await e.pdf(r,o),"application/pdf");case"scrape":return e.scrape(r,N,o);case"screenshot":{const s=w(n,t),c=await e.screenshot(r,{...o,...t.fullPage===void 0?{}:{fullPage:t.fullPage},...t.type===void 0?{}:{type:t.type}});return b(s,t.root??"",t.path??"",c,t.type==="jpeg"?"image/jpeg":"image/png")}default:throw new i("INTERNAL",`@lunora/agent: sandbox browser op "${t.op}" is not supported`)}},I=async(e,t,n)=>{const r=E(t),o=y(t,n.path??"");switch(n.op){case"ls":{const{entries:s,truncated:c}=await k(e,o,r);return c?{entries:s,truncated:!0}:{entries:s}}case"read":{const s=await e.head(o);if(s&&s.size>u)throw new i("BAD_REQUEST",`@lunora/agent: fs read: "${n.path??""}" is ${String(s.size)} bytes (max ${String(u)})`);const c=await e.get(o);if(!c)throw new i("NOT_FOUND",`@lunora/agent: fs read: no file at "${n.path??""}"`);return c.text()}case"rm":return await e.delete(o),{path:n.path??"",removed:!0};case"stat":{const s=await e.head(o);return s?{exists:!0,size:s.size}:{exists:!1}}case"write":{const s=n.content??"",c=R.encode(s).length;if(c>u)throw new i("BAD_REQUEST",`@lunora/agent: fs write: ${String(c)} bytes exceeds the max (${String(u)})`);return await e.put(o,s),{bytes:c,path:n.path??"",wrote:!0}}default:throw new i("INTERNAL",`@lunora/agent: sandbox fs op "${n.op}" is not supported`)}},U=()=>({invoke:A.input({args:a.optional(a.array(a.string())),body:a.optional(a.string()),bucket:a.optional(a.string()),command:a.optional(a.string()),content:a.optional(a.string()),fullPage:a.optional(a.boolean()),instance:a.optional(a.string()),kind:a.union(a.literal("browser"),a.literal("container"),a.literal("fs")),method:a.optional(a.string()),name:a.optional(a.string()),op:a.string(),path:a.optional(a.string()),root:a.optional(a.string()),selector:a.optional(a.string()),type:a.optional(a.string()),url:a.optional(a.string())}).action(async({args:t,ctx:n})=>{const r=n,o=t;if(o.kind==="browser"){if(!r.browser)throw new i("INTERNAL","@lunora/agent: sandbox browser op needs `ctx.browser` — install @lunora/browser and run codegen");return M(r.browser,o,f(r,o))}if(o.kind==="fs"){const d=f(r,o);if(!d)throw m("fs",o.bucket??"");return I(d,o.root??"",o)}const s=o.name??"",c=r.containers?.[s];if(!c)throw new i("INTERNAL",`@lunora/agent: sandbox container op found no ctx.containers["${s}"] — declare the container in lunora/containers.ts and run codegen`);return O(c,o)})});export{y as resolveFsKey,I as runFsOp,U as sandboxComponent};
|
|
@@ -9,11 +9,33 @@ import { FlexibleSchema, LanguageModel, ModelMessage, ToolSet, ToolChoice, ToolC
|
|
|
9
9
|
interface AgentFunctionReference {
|
|
10
10
|
__lunoraRef: string;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Per-call options an {@link AgentRunFunction} forwards to the dispatcher —
|
|
14
|
+
* a structural subset of `@lunora/dispatch`'s `RunFunctionOptions`, declared
|
|
15
|
+
* locally so this module stays free of that import.
|
|
16
|
+
* @experimental
|
|
17
|
+
*/
|
|
18
|
+
interface AgentRunOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Abort the dispatch after this many ms, overriding the runner's 30s
|
|
21
|
+
* default (`DEFAULT_DISPATCH_TIMEOUT_MS`).
|
|
22
|
+
*
|
|
23
|
+
* Load-bearing for any tool whose target legitimately runs longer than
|
|
24
|
+
* that. A dispatch timeout answers 503, which is NOT a deterministic
|
|
25
|
+
* dispatch failure, so the tool's `step.do` rethrows and the host retries
|
|
26
|
+
* the step — dispatching the same call again while the FIRST one is still
|
|
27
|
+
* running. For a side-effecting target (a container command, a billed page
|
|
28
|
+
* render) that is a second execution, not a second attempt. Set this at
|
|
29
|
+
* least as wide as the target's own budget, and give the target an inner
|
|
30
|
+
* deadline strictly under it so the target aborts itself first.
|
|
31
|
+
*/
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
}
|
|
12
34
|
/**
|
|
13
35
|
* `ctx.run`-shaped dispatcher the loop uses to call Lunora functions.
|
|
14
36
|
* @experimental
|
|
15
37
|
*/
|
|
16
|
-
type AgentRunFunction = (reference: AgentFunctionReference, args?: Record<string, unknown
|
|
38
|
+
type AgentRunFunction = (reference: AgentFunctionReference, args?: Record<string, unknown>, options?: AgentRunOptions) => Promise<unknown>;
|
|
17
39
|
/**
|
|
18
40
|
* Structural subset of the Cloudflare Workflows durable-step API the loop needs.
|
|
19
41
|
* @experimental
|
|
@@ -1348,4 +1370,4 @@ interface AgentHandle {
|
|
|
1348
1370
|
/** Read a run's workflow status by instance id. */
|
|
1349
1371
|
status: (id: string) => Promise<unknown>;
|
|
1350
1372
|
}
|
|
1351
|
-
export {
|
|
1373
|
+
export { AgentUsage 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, AgentRunOptions as V, AgentStepFinishInfo as W, AgentStepInfo as X, AgentThreadStatus as Y, AgentTokenDelta as Z, AgentToolCall as _, AgentReplyRef as a, AgentVoiceConfig as a0, AgentWorkflowBindingLike as a1, AgentWorkflowInstanceLike as a2, EnsureThreadOutcome as a3, 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 };
|
|
@@ -9,11 +9,33 @@ import { FlexibleSchema, LanguageModel, ModelMessage, ToolSet, ToolChoice, ToolC
|
|
|
9
9
|
interface AgentFunctionReference {
|
|
10
10
|
__lunoraRef: string;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Per-call options an {@link AgentRunFunction} forwards to the dispatcher —
|
|
14
|
+
* a structural subset of `@lunora/dispatch`'s `RunFunctionOptions`, declared
|
|
15
|
+
* locally so this module stays free of that import.
|
|
16
|
+
* @experimental
|
|
17
|
+
*/
|
|
18
|
+
interface AgentRunOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Abort the dispatch after this many ms, overriding the runner's 30s
|
|
21
|
+
* default (`DEFAULT_DISPATCH_TIMEOUT_MS`).
|
|
22
|
+
*
|
|
23
|
+
* Load-bearing for any tool whose target legitimately runs longer than
|
|
24
|
+
* that. A dispatch timeout answers 503, which is NOT a deterministic
|
|
25
|
+
* dispatch failure, so the tool's `step.do` rethrows and the host retries
|
|
26
|
+
* the step — dispatching the same call again while the FIRST one is still
|
|
27
|
+
* running. For a side-effecting target (a container command, a billed page
|
|
28
|
+
* render) that is a second execution, not a second attempt. Set this at
|
|
29
|
+
* least as wide as the target's own budget, and give the target an inner
|
|
30
|
+
* deadline strictly under it so the target aborts itself first.
|
|
31
|
+
*/
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
}
|
|
12
34
|
/**
|
|
13
35
|
* `ctx.run`-shaped dispatcher the loop uses to call Lunora functions.
|
|
14
36
|
* @experimental
|
|
15
37
|
*/
|
|
16
|
-
type AgentRunFunction = (reference: AgentFunctionReference, args?: Record<string, unknown
|
|
38
|
+
type AgentRunFunction = (reference: AgentFunctionReference, args?: Record<string, unknown>, options?: AgentRunOptions) => Promise<unknown>;
|
|
17
39
|
/**
|
|
18
40
|
* Structural subset of the Cloudflare Workflows durable-step API the loop needs.
|
|
19
41
|
* @experimental
|
|
@@ -1348,4 +1370,4 @@ interface AgentHandle {
|
|
|
1348
1370
|
/** Read a run's workflow status by instance id. */
|
|
1349
1371
|
status: (id: string) => Promise<unknown>;
|
|
1350
1372
|
}
|
|
1351
|
-
export {
|
|
1373
|
+
export { AgentUsage 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, AgentRunOptions as V, AgentStepFinishInfo as W, AgentStepInfo as X, AgentThreadStatus as Y, AgentTokenDelta as Z, AgentToolCall as _, AgentReplyRef as a, AgentVoiceConfig as a0, AgentWorkflowBindingLike as a1, AgentWorkflowInstanceLike as a2, EnsureThreadOutcome as a3, 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 };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as z}from"./agent-loop-ByRhLA54.mjs";import{buildModelMessages as G}from"./buildModelMessages-Y4tGo1T9.mjs";import{toFunctionReference as A}from"./AGENT_MODULE-M4D1EejI.mjs";const ot=t=>{let e="";for(let r=0;r<t.length;r+=32768)e+=String.fromCharCode(...t.subarray(r,r+32768));return btoa(e)},P=t=>{const e=atob(t),n=new Uint8Array(e.length);for(let r=0;r<e.length;r+=1)n[r]=e.codePointAt(r)??0;return n},C=t=>{const e=t.replaceAll("-","+").replaceAll("_","/"),n=e+"=".repeat((4-e.length%4)%4);return P(n)},D=new TextDecoder;new TextEncoder;const N="=",Q=t=>{if(t)try{const e=t[0]==="{"?t:D.decode(C(t)),n=JSON.parse(e);if(n&&typeof n=="object"&&!Array.isArray(n))return n}catch{}},ct=t=>{if(t){if(!t.startsWith(N))return t;try{return D.decode(C(t.slice(N.length)))}catch{return}}},dt=t=>{const e=Number(t);return Number.isFinite(e)&&e>0?e:void 0},ut=t=>typeof t=="number"&&Date.now()>=t,yt=t=>{try{t.send(JSON.stringify({code:"TOKEN_EXPIRED",error:{code:"TOKEN_EXPIRED",message:"authentication token expired"},message:"authentication token expired",type:"error"})),t.close?.(4001,"token_expired")}catch{}},Y=16e3,Z=1,tt=16,M=/[.!?]\s/u,et=/\s/u,nt=async function*(t){if(t instanceof Uint8Array){yield t;return}if(t instanceof ReadableStream){const e=t.getReader();try{for(;;){const{done:n,value:r}=await e.read();if(n)break;yield r}}finally{e.releaseLock()}return}yield*t},ft=(t,e=Y,n=Z,r=tt)=>{const i=n*r/8,l=e*i,m=new ArrayBuffer(44+t.byteLength),s=new DataView(m),u=(p,b)=>{for(let d=0;d<b.length;d+=1)s.setUint8(p+d,b.codePointAt(d)??0)};u(0,"RIFF"),s.setUint32(4,36+t.byteLength,!0),u(8,"WAVE"),u(12,"fmt "),s.setUint32(16,16,!0),s.setUint16(20,1,!0),s.setUint16(22,n,!0),s.setUint32(24,e,!0),s.setUint32(28,l,!0),s.setUint16(32,i,!0),s.setUint16(34,r,!0),u(36,"data"),s.setUint32(40,t.byteLength,!0);const a=new Uint8Array(m);return a.set(t,44),a},rt=t=>{const e=[];let n=t,r=M.exec(n);for(;r;){let i=r.index+1;for(;i<n.length&&et.test(n[i]??"");)i+=1;const l=n.slice(0,i).trim();l.length>0&&e.push(l),n=n.slice(i),r=M.exec(n)}return{rest:n,sentences:e}},lt=async t=>{const{agent:e,compact:n,connectionId:r,env:i,exportName:l,owner:m,paths:s,pcm:u,run:a,send:p,sendAudio:b,signal:d,streamGenerate:H,synthesize:L,text:B,threadKey:o,transcribe:F,turn:U,waitForDrain:O}=t,h=()=>d.aborted,v=A(s.appendMessage),$=A(s.ensureThread),K=A(s.listMessages),x=A(s.patchThread);await a($,{agent:l,key:o,...e.initialState===void 0?{}:{initialState:e.initialState},...m===void 0?{}:{owner:m}});try{const y=(B??(u?await F(u):"")).trim();if(y.length===0)return await a(x,{key:o,status:"idle"}),{assistantText:"",interrupted:!1,userText:""};p({text:y,type:"user_transcript"}),await a(v,{content:y,messageKey:`voice:${r}:${String(U)}:user`,role:"user",threadKey:o}),await a(x,{key:o,status:"running"});const _=typeof e.instructions=="function"?e.instructions({env:i,input:y,threadKey:o}):e.instructions,j=await a(K,{key:o}),{history:W,summary:I}=await z({agent:e,compact:n,env:i},j),V=G({history:W,..._===void 0?{}:{instructions:_},...I===void 0?{}:{summary:I}});let g="",E="",k=Promise.resolve();const X=async c=>{if(h()||c.length===0)return;let w=!1;try{for await(const f of nt(await L(c,d))){if(h()||(await O?.(),h()))break;b(f),w=!0}}catch(f){p({message:f instanceof Error?f.message:String(f),type:"error"})}w&&(E=E.length>0?`${E} ${c}`:c)},R=c=>{k=k.then(async()=>X(c))},J=await H({messages:V,signal:d},c=>{if(h())return;p({text:c,type:"assistant_delta"}),g+=c;const{rest:w,sentences:f}=rt(g);g=w;for(const q of f)R(q)});!h()&&g.trim().length>0&&R(g.trim()),g="",await k;const S=h(),T=S?E:J.text;return await a(v,{content:T,messageKey:`voice:${r}:${String(U)}:assistant`,role:"assistant",threadKey:o}),await a(x,{key:o,status:"idle"}),p(S?{type:"interrupted"}:{text:T,type:"assistant_done"}),{assistantText:T,interrupted:S,userText:y}}catch(y){throw await a(x,{key:o,status:"idle"}),y}},pt=t=>Q(t),ht=t=>{if(typeof t=="object"&&t!==null&&"text"in t){const{text:e}=t;return typeof e=="string"?e:""}return""},gt=t=>{if(t instanceof Uint8Array||t instanceof ReadableStream)return t;if(t instanceof Response&&t.body)return t.body;if(typeof t=="object"&&t!==null&&"audio"in t){const{audio:e}=t;if(typeof e=="string")return P(e);if(e instanceof ReadableStream||e instanceof Uint8Array)return e}return new Uint8Array(0)};export{dt as a,yt as b,ft as c,ct as d,ht as e,gt as f,nt as g,ut as i,pt as p,lt as r,ot as t};
|
package/dist/reply.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Mailer } from '@lunora/mail';
|
|
2
2
|
import { InboundEmail } from '@lunora/mail/inbound';
|
|
3
|
-
import { a as AgentReplyRef } from "./packem_shared/types.d-
|
|
3
|
+
import { a as AgentReplyRef } from "./packem_shared/types.d-B_VV-x4x.mjs";
|
|
4
4
|
import 'ai';
|
|
5
5
|
/** The email arm of {@link AgentReplyRef}, narrowed for the helpers below. */
|
|
6
6
|
type EmailReplyRef = Extract<AgentReplyRef, {
|
package/dist/reply.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Mailer } from '@lunora/mail';
|
|
2
2
|
import { InboundEmail } from '@lunora/mail/inbound';
|
|
3
|
-
import { a as AgentReplyRef } from "./packem_shared/types.d-
|
|
3
|
+
import { a as AgentReplyRef } from "./packem_shared/types.d-B_VV-x4x.js";
|
|
4
4
|
import 'ai';
|
|
5
5
|
/** The email arm of {@link AgentReplyRef}, narrowed for the helpers below. */
|
|
6
6
|
type EmailReplyRef = Extract<AgentReplyRef, {
|
package/dist/sandbox.d.mts
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
|
-
import { b as AgentToolContext, c as AgentToolDefinition } from "./packem_shared/types.d-
|
|
1
|
+
import { b as AgentToolContext, c as AgentToolDefinition } from "./packem_shared/types.d-B_VV-x4x.mjs";
|
|
2
2
|
import '@lunora/mail/inbound';
|
|
3
3
|
import 'ai';
|
|
4
|
+
/**
|
|
5
|
+
* What a byte-returning browser op resolves to. The render is written to R2 and
|
|
6
|
+
* its key comes back — never the bytes, which would be truncated to the model's
|
|
7
|
+
* output cap and billed for nothing.
|
|
8
|
+
* @experimental
|
|
9
|
+
*/
|
|
10
|
+
interface BrowserRenderResult {
|
|
11
|
+
/** Size of the stored object. */
|
|
12
|
+
bytes: number;
|
|
13
|
+
/** The absolute R2 key the render was written to. */
|
|
14
|
+
key: string;
|
|
15
|
+
/** The render's content type, e.g. `image/jpeg`. */
|
|
16
|
+
mediaType: string;
|
|
17
|
+
}
|
|
4
18
|
/**
|
|
5
19
|
* The model-provided input to a {@link browserTool} call — a discriminated
|
|
6
20
|
* union on `op` so one tool exposes every headless-browser capability.
|
|
@@ -44,6 +58,17 @@ type ContainerToolInput = {
|
|
|
44
58
|
* @experimental
|
|
45
59
|
*/
|
|
46
60
|
interface BrowserToolOptions {
|
|
61
|
+
/**
|
|
62
|
+
* R2 binding name the byte-returning ops (`screenshot`, `pdf`) write their
|
|
63
|
+
* render to. REQUIRED for those two: a render is billed, and a tool result
|
|
64
|
+
* is capped at `MAX_TOOL_OUTPUT_CHARS`, so base64 bytes inline would be
|
|
65
|
+
* truncated mid-string and unusable by the model — paid for and thrown
|
|
66
|
+
* away. With a bucket the op returns `{ bytes, key, mediaType }` and the
|
|
67
|
+
* app serves or post-processes the object by key. `content`/`scrape`
|
|
68
|
+
* return text and need no bucket; without one, a `screenshot`/`pdf` call is
|
|
69
|
+
* refused as a tool result (never dispatched) so nothing is billed.
|
|
70
|
+
*/
|
|
71
|
+
bucket?: string;
|
|
47
72
|
/** Override the model-facing description (what the tool does). */
|
|
48
73
|
description?: string;
|
|
49
74
|
/**
|
|
@@ -55,6 +80,14 @@ interface BrowserToolOptions {
|
|
|
55
80
|
* keep it deterministic).
|
|
56
81
|
*/
|
|
57
82
|
needsApproval?: ((input: BrowserToolInput) => boolean) | boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Key prefix inside {@link BrowserToolOptions.bucket} that renders are
|
|
85
|
+
* written under, isolating them from the rest of the bucket. Default: the
|
|
86
|
+
* bucket root. Each render lands at `<root>/<threadKey>/<toolCallId>.<ext>`
|
|
87
|
+
* — derived only from replay-stable identifiers, so a retried step
|
|
88
|
+
* overwrites its own object rather than accumulating one per attempt.
|
|
89
|
+
*/
|
|
90
|
+
root?: string;
|
|
58
91
|
}
|
|
59
92
|
/**
|
|
60
93
|
* The model-provided input to a {@link fsTool} call — a discriminated union on
|
|
@@ -133,6 +166,12 @@ interface ContainerToolOptions {
|
|
|
133
166
|
* `@cloudflare/playwright` `launch` peer) to `createShardDO()` — codegen never
|
|
134
167
|
* injects that peer, so the browser op throws a directed error until it is wired.
|
|
135
168
|
*
|
|
169
|
+
* `content`/`scrape` return text. `screenshot`/`pdf` write the render to
|
|
170
|
+
* `opts.bucket` and return `{ bytes, key, mediaType }` — never the bytes
|
|
171
|
+
* themselves, which a 4000-char tool-output cap would truncate into something
|
|
172
|
+
* unusable after paying for the render. Without a bucket those two ops are
|
|
173
|
+
* refused as a tool result and never dispatched.
|
|
174
|
+
*
|
|
136
175
|
* Security: the model chooses the `url` with no allowlist, so this is an SSRF
|
|
137
176
|
* surface — pass `opts.needsApproval` to gate calls a prompt-injected model
|
|
138
177
|
* could aim at internal/link-local endpoints.
|
|
@@ -142,12 +181,12 @@ interface ContainerToolOptions {
|
|
|
142
181
|
*
|
|
143
182
|
* export const researcher = defineAgent({
|
|
144
183
|
* model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
|
|
145
|
-
* tools: { browser: browserTool() },
|
|
184
|
+
* tools: { browser: browserTool({ bucket: "SANDBOX_BUCKET", root: "renders" }) },
|
|
146
185
|
* });
|
|
147
186
|
* ```
|
|
148
187
|
* @experimental
|
|
149
188
|
*/
|
|
150
|
-
declare const browserTool: (options?: BrowserToolOptions) => AgentToolDefinition<BrowserToolInput, string>;
|
|
189
|
+
declare const browserTool: (options?: BrowserToolOptions) => AgentToolDefinition<BrowserToolInput, BrowserRenderResult | string>;
|
|
151
190
|
/**
|
|
152
191
|
* A batteries-included agent tool that talks to a declared Cloudflare
|
|
153
192
|
* Container. `name` is the `ctx.containers.<name>` key (the `lunora/containers.ts`
|
|
@@ -155,6 +194,12 @@ declare const browserTool: (options?: BrowserToolOptions) => AgentToolDefinition
|
|
|
155
194
|
* the model picks via `op`. The call dispatches to the auto-registered
|
|
156
195
|
* `sandbox:invoke` action, which carries `ctx.containers`.
|
|
157
196
|
*
|
|
197
|
+
* Every call is addressed to ONE instance per thread (`ctx.containers.<name>
|
|
198
|
+
* .get(threadKey)`), not a random pool member, so a multi-step session shares a
|
|
199
|
+
* filesystem — size the container's `maxInstances` for the number of live
|
|
200
|
+
* threads. See `sandbox-budgets.ts` for the time budgets and the re-execution
|
|
201
|
+
* ceiling that remains.
|
|
202
|
+
*
|
|
158
203
|
* By default a read-only (GET/HEAD/OPTIONS, or method-omitted) `fetch` runs
|
|
159
204
|
* unattended while everything else is gated behind a human approval — an
|
|
160
205
|
* `exec`; a `fetch` whose path resolves to the privileged exec route (both
|
|
@@ -202,4 +247,4 @@ declare const containerTool: (name: string, options?: ContainerToolOptions) => A
|
|
|
202
247
|
* @experimental
|
|
203
248
|
*/
|
|
204
249
|
declare const fsTool: (bucket: string, options?: FsToolOptions) => AgentToolDefinition<FsToolInput>;
|
|
205
|
-
export { type BrowserToolInput, type BrowserToolOptions, type ContainerToolInput, type ContainerToolOptions, type FsToolInput, type FsToolOptions, browserTool, containerTool, fsTool };
|
|
250
|
+
export { type BrowserRenderResult, type BrowserToolInput, type BrowserToolOptions, type ContainerToolInput, type ContainerToolOptions, type FsToolInput, type FsToolOptions, browserTool, containerTool, fsTool };
|
package/dist/sandbox.d.ts
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
|
-
import { b as AgentToolContext, c as AgentToolDefinition } from "./packem_shared/types.d-
|
|
1
|
+
import { b as AgentToolContext, c as AgentToolDefinition } from "./packem_shared/types.d-B_VV-x4x.js";
|
|
2
2
|
import '@lunora/mail/inbound';
|
|
3
3
|
import 'ai';
|
|
4
|
+
/**
|
|
5
|
+
* What a byte-returning browser op resolves to. The render is written to R2 and
|
|
6
|
+
* its key comes back — never the bytes, which would be truncated to the model's
|
|
7
|
+
* output cap and billed for nothing.
|
|
8
|
+
* @experimental
|
|
9
|
+
*/
|
|
10
|
+
interface BrowserRenderResult {
|
|
11
|
+
/** Size of the stored object. */
|
|
12
|
+
bytes: number;
|
|
13
|
+
/** The absolute R2 key the render was written to. */
|
|
14
|
+
key: string;
|
|
15
|
+
/** The render's content type, e.g. `image/jpeg`. */
|
|
16
|
+
mediaType: string;
|
|
17
|
+
}
|
|
4
18
|
/**
|
|
5
19
|
* The model-provided input to a {@link browserTool} call — a discriminated
|
|
6
20
|
* union on `op` so one tool exposes every headless-browser capability.
|
|
@@ -44,6 +58,17 @@ type ContainerToolInput = {
|
|
|
44
58
|
* @experimental
|
|
45
59
|
*/
|
|
46
60
|
interface BrowserToolOptions {
|
|
61
|
+
/**
|
|
62
|
+
* R2 binding name the byte-returning ops (`screenshot`, `pdf`) write their
|
|
63
|
+
* render to. REQUIRED for those two: a render is billed, and a tool result
|
|
64
|
+
* is capped at `MAX_TOOL_OUTPUT_CHARS`, so base64 bytes inline would be
|
|
65
|
+
* truncated mid-string and unusable by the model — paid for and thrown
|
|
66
|
+
* away. With a bucket the op returns `{ bytes, key, mediaType }` and the
|
|
67
|
+
* app serves or post-processes the object by key. `content`/`scrape`
|
|
68
|
+
* return text and need no bucket; without one, a `screenshot`/`pdf` call is
|
|
69
|
+
* refused as a tool result (never dispatched) so nothing is billed.
|
|
70
|
+
*/
|
|
71
|
+
bucket?: string;
|
|
47
72
|
/** Override the model-facing description (what the tool does). */
|
|
48
73
|
description?: string;
|
|
49
74
|
/**
|
|
@@ -55,6 +80,14 @@ interface BrowserToolOptions {
|
|
|
55
80
|
* keep it deterministic).
|
|
56
81
|
*/
|
|
57
82
|
needsApproval?: ((input: BrowserToolInput) => boolean) | boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Key prefix inside {@link BrowserToolOptions.bucket} that renders are
|
|
85
|
+
* written under, isolating them from the rest of the bucket. Default: the
|
|
86
|
+
* bucket root. Each render lands at `<root>/<threadKey>/<toolCallId>.<ext>`
|
|
87
|
+
* — derived only from replay-stable identifiers, so a retried step
|
|
88
|
+
* overwrites its own object rather than accumulating one per attempt.
|
|
89
|
+
*/
|
|
90
|
+
root?: string;
|
|
58
91
|
}
|
|
59
92
|
/**
|
|
60
93
|
* The model-provided input to a {@link fsTool} call — a discriminated union on
|
|
@@ -133,6 +166,12 @@ interface ContainerToolOptions {
|
|
|
133
166
|
* `@cloudflare/playwright` `launch` peer) to `createShardDO()` — codegen never
|
|
134
167
|
* injects that peer, so the browser op throws a directed error until it is wired.
|
|
135
168
|
*
|
|
169
|
+
* `content`/`scrape` return text. `screenshot`/`pdf` write the render to
|
|
170
|
+
* `opts.bucket` and return `{ bytes, key, mediaType }` — never the bytes
|
|
171
|
+
* themselves, which a 4000-char tool-output cap would truncate into something
|
|
172
|
+
* unusable after paying for the render. Without a bucket those two ops are
|
|
173
|
+
* refused as a tool result and never dispatched.
|
|
174
|
+
*
|
|
136
175
|
* Security: the model chooses the `url` with no allowlist, so this is an SSRF
|
|
137
176
|
* surface — pass `opts.needsApproval` to gate calls a prompt-injected model
|
|
138
177
|
* could aim at internal/link-local endpoints.
|
|
@@ -142,12 +181,12 @@ interface ContainerToolOptions {
|
|
|
142
181
|
*
|
|
143
182
|
* export const researcher = defineAgent({
|
|
144
183
|
* model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
|
|
145
|
-
* tools: { browser: browserTool() },
|
|
184
|
+
* tools: { browser: browserTool({ bucket: "SANDBOX_BUCKET", root: "renders" }) },
|
|
146
185
|
* });
|
|
147
186
|
* ```
|
|
148
187
|
* @experimental
|
|
149
188
|
*/
|
|
150
|
-
declare const browserTool: (options?: BrowserToolOptions) => AgentToolDefinition<BrowserToolInput, string>;
|
|
189
|
+
declare const browserTool: (options?: BrowserToolOptions) => AgentToolDefinition<BrowserToolInput, BrowserRenderResult | string>;
|
|
151
190
|
/**
|
|
152
191
|
* A batteries-included agent tool that talks to a declared Cloudflare
|
|
153
192
|
* Container. `name` is the `ctx.containers.<name>` key (the `lunora/containers.ts`
|
|
@@ -155,6 +194,12 @@ declare const browserTool: (options?: BrowserToolOptions) => AgentToolDefinition
|
|
|
155
194
|
* the model picks via `op`. The call dispatches to the auto-registered
|
|
156
195
|
* `sandbox:invoke` action, which carries `ctx.containers`.
|
|
157
196
|
*
|
|
197
|
+
* Every call is addressed to ONE instance per thread (`ctx.containers.<name>
|
|
198
|
+
* .get(threadKey)`), not a random pool member, so a multi-step session shares a
|
|
199
|
+
* filesystem — size the container's `maxInstances` for the number of live
|
|
200
|
+
* threads. See `sandbox-budgets.ts` for the time budgets and the re-execution
|
|
201
|
+
* ceiling that remains.
|
|
202
|
+
*
|
|
158
203
|
* By default a read-only (GET/HEAD/OPTIONS, or method-omitted) `fetch` runs
|
|
159
204
|
* unattended while everything else is gated behind a human approval — an
|
|
160
205
|
* `exec`; a `fetch` whose path resolves to the privileged exec route (both
|
|
@@ -202,4 +247,4 @@ declare const containerTool: (name: string, options?: ContainerToolOptions) => A
|
|
|
202
247
|
* @experimental
|
|
203
248
|
*/
|
|
204
249
|
declare const fsTool: (bucket: string, options?: FsToolOptions) => AgentToolDefinition<FsToolInput>;
|
|
205
|
-
export { type BrowserToolInput, type BrowserToolOptions, type ContainerToolInput, type ContainerToolOptions, type FsToolInput, type FsToolOptions, browserTool, containerTool, fsTool };
|
|
250
|
+
export { type BrowserRenderResult, type BrowserToolInput, type BrowserToolOptions, type ContainerToolInput, type ContainerToolOptions, type FsToolInput, type FsToolOptions, browserTool, containerTool, fsTool };
|
package/dist/sandbox.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LunoraError as a}from"@lunora/errors";import{jsonSchema as
|
|
1
|
+
import{LunoraError as a}from"@lunora/errors";import{jsonSchema as s}from"ai";import{toFunctionReference as h,SANDBOX_INVOKE_PATH as u}from"./packem_shared/AGENT_MODULE-M4D1EejI.mjs";import{S as l,a as T}from"./packem_shared/sandbox-budgets-DDvj4Orr.mjs";const i=h(u),f=e=>{if(e.op==="pdf")return"pdf";if(e.op==="screenshot")return e.type==="jpeg"?"jpeg":"png"},g=new Set(["bucket","path","root"]),m='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`.',E='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`).',y='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`.',S=e=>e.op==="write"||e.op==="rm",A=s({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"}),O=s({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"}),_=new Set(["DELETE","PATCH","POST","PUT"]),b=e=>e.op==="exec"||_.has((e.method??"GET").toUpperCase()),w=s({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"}),v=(e={})=>{const t=e.bucket!==void 0&&e.bucket.length>0?e.bucket:void 0;return{description:e.description??m,execute:async(n,r)=>{const o=f(n);if(o!==void 0&&t===void 0)return`Cannot run a "${n.op}": this browser tool has no \`bucket\` configured, so the render has nowhere to go. Use "content" or "scrape" for page text, or ask the operator to pass \`browserTool({ bucket })\`.`;const c=o===void 0?{}:{bucket:t,path:`${r.threadKey}/${r.toolCallId}.${o}`,...e.root===void 0?{}:{root:e.root}},p=Object.fromEntries(Object.entries(n).filter(([d])=>!g.has(d)));return await r.run(i,{...p,...c,kind:"browser"},{timeoutMs:l})},inputSchema:O,isLunoraAgentTool:!0,...e.needsApproval===void 0?{}:{needsApproval:e.needsApproval}}},C=(e,t={})=>{if(typeof e!="string"||e.length===0)throw new a("INTERNAL","@lunora/agent: containerTool requires a container `name` (the ctx.containers.<name> key from lunora/containers.ts)");const n=t.needsApproval??b;return{description:t.description??E,execute:(r,o)=>o.run(i,{...r,instance:o.threadKey,kind:"container",name:e},{timeoutMs:T}),inputSchema:w,isLunoraAgentTool:!0,needsApproval:n}},L=(e,t={})=>{if(typeof e!="string"||e.length===0)throw new a("INTERNAL","@lunora/agent: fsTool requires an R2 `bucket` binding name (the r2_bucket declared in wrangler.jsonc)");return{description:t.description??y,execute:(n,r)=>{const o=typeof t.root=="function"?t.root(r):t.root??"";return r.run(i,{...n,bucket:e,kind:"fs",root:o})},inputSchema:A,isLunoraAgentTool:!0,needsApproval:t.needsApproval??S}};export{v as browserTool,C as containerTool,L as fsTool};
|
package/dist/skill-markdown.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/agent",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.126",
|
|
4
4
|
"description": "Durable AI agents for Lunora: defineAgent compiles a replay-safe tool-loop onto Cloudflare Workflows, with DO SQLite threads and live message subscriptions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"access": "public"
|
|
85
85
|
},
|
|
86
86
|
"dependencies": {
|
|
87
|
-
"@lunora/ai": "1.0.0-alpha.
|
|
87
|
+
"@lunora/ai": "1.0.0-alpha.94",
|
|
88
88
|
"@lunora/errors": "1.0.0-alpha.39",
|
|
89
89
|
"@lunora/mail": "1.0.0-alpha.84",
|
|
90
90
|
"@lunora/server": "1.0.0-alpha.134",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createAi as A}from"@lunora/ai";import{t as b}from"./createDispatchRunner-BxtGxAQi-DXXP7SxZ.mjs";import{t as x}from"./base64-5eyBfWO3.mjs";import{p as T,d as _,a as v,i as p,b as y,c as E,e as k,f as M,r as w,t as I}from"./voice-turn-CYXdylKF.mjs";import{createStreamGenerate as C,createCompact as R}from"./createAgentGenerate-BOILDUZj.mjs";import{DEFAULT_AGENT_FUNCTION_PATHS as L,toFunctionReference as m}from"./AGENT_MODULE-M4D1EejI.mjs";const N="@cf/openai/whisper-large-v3-turbo",O="@cf/deepgram/aura-1",U=8*1024*1024,B=100,f=4e3,g=f*4+1024,F=4002,D=4003,z=4004,W=256*1024,S=15,G=5e3,X=h=>{if(h===null||typeof h!="object")return!1;const{text:t,type:e}=h;return e==="commit"||e==="interrupt"||e==="text"&&typeof t=="string"};class Y{agent;ai;env;exportName;paths;streamGenerate;sttModel;ttsModel;maxSessionTurns;audioBuffers=new Map;bufferedBytes=new Map;controllers=new Map;state;constructor(t,e,r,s){this.state=t,this.env=e,this.agent=r,this.exportName=s,this.paths=L,this.ai=A({binding:e.AI,env:e}),this.streamGenerate=C(r,e),this.sttModel=r.voice?.stt??N,this.ttsModel=r.voice?.tts??O,this.maxSessionTurns=r.voice?.maxTurns??B}fetch(t){if(t.headers.get("Upgrade")!=="websocket")return new Response("Expected a WebSocket upgrade",{status:426});const r=new URL(t.url).searchParams.get("threadKey");if(!r)return new Response("Missing threadKey",{status:400});const s=globalThis.WebSocketPair,i=new s,n=i[0],o=i[1];this.state.acceptWebSocket(o);const c=crypto.randomUUID(),d=T(t.headers.get("x-lunora-identity")),a=_(t.headers.get("x-lunora-userid")),u=v(t.headers.get("x-lunora-identity-exp"));if(p(u))return y(o),new Response(null,{status:101,webSocket:n});o.serializeAttachment?.({connectionId:c,threadKey:r,turn:0,...u===void 0?{}:{expiresAt:u},...d===void 0?{}:{identity:d},...a===void 0?{}:{userId:a}}),this.send(o,{audioFormat:this.agent.voice?.audioFormat??"mp3",type:"ready"});const l=this.agent.voice?.greeting;return l&&l.length>0&&this.state.waitUntil?.(this.speakGreeting(o,c,r,a,d,l)),new Response(null,{status:101,webSocket:n})}async webSocketMessage(t,e){const r=t.deserializeAttachment?.();if(r){if(p(r.expiresAt)){y(t);return}try{if(typeof e=="string"){await this.handleControl(t,r,e);return}this.bufferAudio(r.connectionId,new Uint8Array(e),t)}catch(s){this.send(t,{message:s instanceof Error?s.message:String(s),type:"error"})}}}webSocketClose(t){this.cleanupSocket(t)}webSocketError(t){this.cleanupSocket(t)}resolveRun(t,e){const r=t===void 0&&e===void 0?void 0:{...e===void 0?{}:{claims:e},...t===void 0?{}:{userId:t}};return b({env:this.env,label:"@lunora/agent voice",...r===void 0?{}:{identity:r}})}async transcribe(t){const e=E(t);return k(await this.ai.run(this.sttModel,{audio:x(e)}))}async synthesize(t,e){const r=this.agent.voice?.speaker;return M(await this.ai.run(this.ttsModel,{text:t,...r===void 0?{}:{speaker:r}},e===void 0?void 0:{signal:e}))}async handleControl(t,e,r){if(r.length>g){this.send(t,{message:`control frame exceeds the maximum of ${String(g)} characters`,type:"error"}),this.closeSocket(t,z,"control_frame_limit");return}let s;try{s=JSON.parse(r)}catch{return}if(!X(s)){this.send(t,{message:'unsupported control frame — expected { type: "text", text }, { type: "commit" } or { type: "interrupt" }',type:"error"});return}const i=s;if(i.type==="interrupt"){this.controllers.get(e.connectionId)?.abort();return}if(i.type==="text"&&i.text.length>f){this.send(t,{message:`text frame exceeds the maximum of ${String(f)} characters`,type:"error"});return}if(e.turn>=this.maxSessionTurns){this.send(t,{message:`voice session reached its ${String(this.maxSessionTurns)}-turn limit — reconnect to continue`,type:"error"}),this.closeSocket(t,F,"turn_limit");return}if(this.controllers.has(e.connectionId)){i.type==="commit"&&this.drainAudio(e.connectionId),this.send(t,{message:"a turn is already in progress — send an interrupt before the next utterance",type:"error"});return}if(i.type==="commit"){const n=this.drainAudio(e.connectionId);await this.runTurn(t,e,{pcm:n});return}await this.runTurn(t,e,{text:i.text})}bufferAudio(t,e,r){const s=(this.bufferedBytes.get(t)??0)+e.byteLength;if(s>U){this.audioBuffers.delete(t),this.bufferedBytes.delete(t),this.send(r,{message:"utterance exceeded the maximum buffer — send a commit sooner",type:"error"}),this.closeSocket(r,D,"utterance_too_large");return}const i=this.audioBuffers.get(t)??[];i.push(e),this.audioBuffers.set(t,i),this.bufferedBytes.set(t,s)}drainAudio(t){const e=this.audioBuffers.get(t)??[];this.audioBuffers.delete(t),this.bufferedBytes.delete(t);const r=e.reduce((n,o)=>n+o.byteLength,0),s=new Uint8Array(r);let i=0;for(const n of e)s.set(n,i),i+=n.byteLength;return s}async runTurn(t,e,r){const s=new AbortController;this.controllers.set(e.connectionId,s);try{await w({agent:this.agent,compact:R(),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:s.signal,streamGenerate:this.streamGenerate,synthesize:async(i,n)=>this.synthesizeWithSignal(i,n),threadKey:e.threadKey,transcribe:async i=>this.transcribe(i),turn:e.turn,waitForDrain:async()=>this.waitForSocketDrain(t),...e.userId===void 0?{}:{owner:e.userId},...r.pcm===void 0?{}:{pcm:r.pcm},...r.text===void 0?{}:{text:r.text}})}finally{this.controllers.get(e.connectionId)===s&&this.controllers.delete(e.connectionId),t.serializeAttachment?.({...e,turn:e.turn+1})}}async speakGreeting(t,e,r,s,i,n){const o=this.resolveRun(s,i),c=new AbortController,d=()=>c.signal.aborted;this.controllers.set(e,c);try{if((await o(m(this.paths.ensureThread),{agent:this.exportName,key:r,...this.agent.initialState===void 0?{}:{initialState:this.agent.initialState},...s===void 0?{}:{owner:s}}))?.outcome!=="created")return;for await(const u of I(await this.synthesizeWithSignal(n,c.signal))){if(d()||(await this.waitForSocketDrain(t),d()))break;this.sendAudio(t,u)}d()||(await o(m(this.paths.appendMessage),{content:n,messageKey:"voice:greeting:assistant",role:"assistant",threadKey:r}),this.send(t,{text:n,type:"assistant_done"}))}catch(a){this.send(t,{message:a instanceof Error?a.message:String(a),type:"error"})}finally{this.controllers.get(e)===c&&this.controllers.delete(e)}}async synthesizeWithSignal(t,e){return e.aborted?new Uint8Array(0):this.synthesize(t,e)}cleanupSocket(t){const e=t.deserializeAttachment?.();e&&(this.controllers.get(e.connectionId)?.abort(),this.controllers.delete(e.connectionId),this.audioBuffers.delete(e.connectionId),this.bufferedBytes.delete(e.connectionId))}closeSocket(t,e,r){try{t.close?.(e,r)}catch{}}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 r=0;for(;typeof e.bufferedAmount=="number"&&e.bufferedAmount>W&&r<G;)await new Promise(s=>{setTimeout(s,S)}),r+=S}}export{Y as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const a=n=>{let t="";for(let e=0;e<n.length;e+=32768)t+=String.fromCharCode(...n.subarray(e,e+32768));return btoa(t)},o=n=>{const t=atob(n),r=new Uint8Array(t.length);for(let e=0;e<t.length;e+=1)r[e]=t.codePointAt(e)??0;return r},s=n=>{const t=n.replaceAll("-","+").replaceAll("_","/"),r=t+"=".repeat((4-t.length%4)%4);return o(r)};export{o as a,s as f,a as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./base64-5eyBfWO3.mjs";import{p as s,c as p,f as m,e as n,r as c,t as d}from"./voice-turn-CYXdylKF.mjs";import"./agent-loop-ByRhLA54.mjs";import"./buildModelMessages-Y4tGo1T9.mjs";import"./AGENT_MODULE-M4D1EejI.mjs";export{s as parseIdentity,p as pcmToWav,m as readSynthesisAudio,n as readTranscriptionText,c as runVoiceTurn,d as toByteIterable};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import{LunoraError as c}from"@lunora/errors";import{initLunora as h}from"@lunora/server";import{v as t}from"@lunora/values";import{t as g}from"./base64-5eyBfWO3.mjs";const{internalAction:w}=h.dataModel().create(),m=()=>globalThis.document?.documentElement?.outerHTML??"",l=1e6,b=20,x=new TextEncoder,y=async(e,n)=>{const o=n.url??"";switch(n.op){case"content":return e.content(o);case"pdf":return{data:g(await e.pdf(o)),encoding:"base64",mediaType:"application/pdf"};case"scrape":return e.scrape(o,m);case"screenshot":{const s=await e.screenshot(o,{...n.fullPage===void 0?{}:{fullPage:n.fullPage},...n.type===void 0?{}:{type:n.type}});return{data:g(s),encoding:"base64",mediaType:n.type==="jpeg"?"image/jpeg":"image/png"}}default:throw new c("INTERNAL",`@lunora/agent: sandbox browser op "${n.op}" is not supported`)}},E=e=>{const n=[`exit code: ${String(e.code)}`];return e.stdout.length>0&&n.push(`stdout:
|
|
2
|
-
${e.stdout}`),e.stderr.length>0&&n.push(`stderr:
|
|
3
|
-
${e.stderr}`),n.join(`
|
|
4
|
-
|
|
5
|
-
`)},$=async(e,n)=>{const o=e.any();if(n.op==="exec")try{return E(await o.exec(n.command??"",{args:n.args??[]}))}catch(s){return`exec failed: ${s instanceof Error?s.message:String(s)}`}if(n.op==="fetch")return(await o.fetch(n.path??"/",{...n.body===void 0?{}:{body:n.body},method:n.method??"GET"})).text();throw new c("INTERNAL",`@lunora/agent: sandbox container op "${n.op}" is not supported`)},u=e=>{let n=0,o=e.length;for(;n<o&&e[n]==="/";)n+=1;for(;o>n&&e[o-1]==="/";)o-=1;return e.slice(n,o)},T=(e,n)=>{const o=u(e),s=[];for(const r of n.split("/"))if(!(r===""||r===".")){if(r===".."){if(s.length===0)throw new c("BAD_REQUEST","@lunora/agent: fs path escapes the sandbox root");s.pop();continue}s.push(r)}const a=s.join("/");return o&&a?`${o}/${a}`:o||a},S=async(e,n,o)=>{const s=n.length>0?`${n}/`:"",a=o.length>0?o.length+1:0,r=[];let i;for(let d=0;d<b;d+=1){const p=await e.list({prefix:s,...i===void 0?{}:{cursor:i}});for(const f of p.objects)r.push(f.key.slice(a));if(!p.truncated||p.cursor===void 0)return{entries:r,truncated:!1};i=p.cursor}return{entries:r,truncated:!0}},N=async(e,n,o)=>{const s=u(n),a=T(n,o.path??"");switch(o.op){case"ls":{const{entries:r,truncated:i}=await S(e,a,s);return i?{entries:r,truncated:!0}:{entries:r}}case"read":{const r=await e.head(a);if(r&&r.size>l)throw new c("BAD_REQUEST",`@lunora/agent: fs read: "${o.path??""}" is ${String(r.size)} bytes (max ${String(l)})`);const i=await e.get(a);if(!i)throw new c("NOT_FOUND",`@lunora/agent: fs read: no file at "${o.path??""}"`);return i.text()}case"rm":return await e.delete(a),{path:o.path??"",removed:!0};case"stat":{const r=await e.head(a);return r?{exists:!0,size:r.size}:{exists:!1}}case"write":{const r=o.content??"",i=x.encode(r).length;if(i>l)throw new c("BAD_REQUEST",`@lunora/agent: fs write: ${String(i)} bytes exceeds the max (${String(l)})`);return await e.put(a,r),{bytes:i,path:o.path??"",wrote:!0}}default:throw new c("INTERNAL",`@lunora/agent: sandbox fs op "${o.op}" is not supported`)}},_=()=>({invoke:w.input({args:t.optional(t.array(t.string())),body:t.optional(t.string()),bucket:t.optional(t.string()),command:t.optional(t.string()),content:t.optional(t.string()),fullPage:t.optional(t.boolean()),kind:t.union(t.literal("browser"),t.literal("container"),t.literal("fs")),method:t.optional(t.string()),name:t.optional(t.string()),op:t.string(),path:t.optional(t.string()),root:t.optional(t.string()),selector:t.optional(t.string()),type:t.optional(t.string()),url:t.optional(t.string())}).action(async({args:n,ctx:o})=>{const s=o,a=n;if(a.kind==="browser"){if(!s.browser)throw new c("INTERNAL","@lunora/agent: sandbox browser op needs `ctx.browser` — install @lunora/browser and run codegen");return y(s.browser,a)}if(a.kind==="fs"){const d=s.env?.[a.bucket??""];if(!d||typeof d.get!="function")throw new c("INTERNAL",`@lunora/agent: sandbox fs op found no R2 bucket "${a.bucket??""}" on env — declare the r2_bucket binding in wrangler.jsonc and run codegen`);return N(d,a.root??"",a)}const r=a.name??"",i=s.containers?.[r];if(!i)throw new c("INTERNAL",`@lunora/agent: sandbox container op found no ctx.containers["${r}"] — declare the container in lunora/containers.ts and run codegen`);return $(i,a)})});export{T as resolveFsKey,N as runFsOp,_ as sandboxComponent};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{f as P,a as q}from"./base64-5eyBfWO3.mjs";import{c as z}from"./agent-loop-ByRhLA54.mjs";import{buildModelMessages as G}from"./buildModelMessages-Y4tGo1T9.mjs";import{toFunctionReference as T}from"./AGENT_MODULE-M4D1EejI.mjs";const D=new TextDecoder;new TextEncoder;const N="=",Q=t=>{if(t)try{const e=t[0]==="{"?t:D.decode(P(t)),n=JSON.parse(e);if(n&&typeof n=="object"&&!Array.isArray(n))return n}catch{}},ct=t=>{if(t){if(!t.startsWith(N))return t;try{return D.decode(P(t.slice(N.length)))}catch{return}}},dt=t=>{const e=Number(t);return Number.isFinite(e)&&e>0?e:void 0},ut=t=>typeof t=="number"&&Date.now()>=t,ft=t=>{try{t.send(JSON.stringify({code:"TOKEN_EXPIRED",error:{code:"TOKEN_EXPIRED",message:"authentication token expired"},message:"authentication token expired",type:"error"})),t.close?.(4001,"token_expired")}catch{}},Y=16e3,Z=1,tt=16,M=/[.!?]\s/u,et=/\s/u,nt=async function*(t){if(t instanceof Uint8Array){yield t;return}if(t instanceof ReadableStream){const e=t.getReader();try{for(;;){const{done:n,value:r}=await e.read();if(n)break;yield r}}finally{e.releaseLock()}return}yield*t},yt=(t,e=Y,n=Z,r=tt)=>{const i=n*r/8,p=e*i,m=new ArrayBuffer(44+t.byteLength),s=new DataView(m),u=(l,E)=>{for(let d=0;d<E.length;d+=1)s.setUint8(l+d,E.codePointAt(d)??0)};u(0,"RIFF"),s.setUint32(4,36+t.byteLength,!0),u(8,"WAVE"),u(12,"fmt "),s.setUint32(16,16,!0),s.setUint16(20,1,!0),s.setUint16(22,n,!0),s.setUint32(24,e,!0),s.setUint32(28,p,!0),s.setUint16(32,i,!0),s.setUint16(34,r,!0),u(36,"data"),s.setUint32(40,t.byteLength,!0);const a=new Uint8Array(m);return a.set(t,44),a},st=t=>{const e=[];let n=t,r=M.exec(n);for(;r;){let i=r.index+1;for(;i<n.length&&et.test(n[i]??"");)i+=1;const p=n.slice(0,i).trim();p.length>0&&e.push(p),n=n.slice(i),r=M.exec(n)}return{rest:n,sentences:e}},pt=async t=>{const{agent:e,compact:n,connectionId:r,env:i,exportName:p,owner:m,paths:s,pcm:u,run:a,send:l,sendAudio:E,signal:d,streamGenerate:C,synthesize:H,text:L,threadKey:o,transcribe:F,turn:U,waitForDrain:O}=t,h=()=>d.aborted,v=T(s.appendMessage),$=T(s.ensureThread),B=T(s.listMessages),b=T(s.patchThread);await a($,{agent:p,key:o,...e.initialState===void 0?{}:{initialState:e.initialState},...m===void 0?{}:{owner:m}});try{const f=(L??(u?await F(u):"")).trim();if(f.length===0)return await a(b,{key:o,status:"idle"}),{assistantText:"",interrupted:!1,userText:""};l({text:f,type:"user_transcript"}),await a(v,{content:f,messageKey:`voice:${r}:${String(U)}:user`,role:"user",threadKey:o}),await a(b,{key:o,status:"running"});const I=typeof e.instructions=="function"?e.instructions({env:i,input:f,threadKey:o}):e.instructions,K=await a(B,{key:o}),{history:j,summary:R}=await z({agent:e,compact:n,env:i},K),W=G({history:j,...I===void 0?{}:{instructions:I},...R===void 0?{}:{summary:R}});let g="",w="",S=Promise.resolve();const V=async c=>{if(h()||c.length===0)return;let x=!1;try{for await(const y of nt(await H(c,d))){if(h()||(await O?.(),h()))break;E(y),x=!0}}catch(y){l({message:y instanceof Error?y.message:String(y),type:"error"})}x&&(w=w.length>0?`${w} ${c}`:c)},_=c=>{S=S.then(async()=>V(c))},X=await C({messages:W,signal:d},c=>{if(h())return;l({text:c,type:"assistant_delta"}),g+=c;const{rest:x,sentences:y}=st(g);g=x;for(const J of y)_(J)});!h()&&g.trim().length>0&&_(g.trim()),g="",await S;const k=h(),A=k?w:X.text;return await a(v,{content:A,messageKey:`voice:${r}:${String(U)}:assistant`,role:"assistant",threadKey:o}),await a(b,{key:o,status:"idle"}),l(k?{type:"interrupted"}:{text:A,type:"assistant_done"}),{assistantText:A,interrupted:k,userText:f}}catch(f){throw await a(b,{key:o,status:"idle"}),f}},lt=t=>Q(t),ht=t=>{if(typeof t=="object"&&t!==null&&"text"in t){const{text:e}=t;return typeof e=="string"?e:""}return""},gt=t=>{if(t instanceof Uint8Array||t instanceof ReadableStream)return t;if(t instanceof Response&&t.body)return t.body;if(typeof t=="object"&&t!==null&&"audio"in t){const{audio:e}=t;if(typeof e=="string")return q(e);if(e instanceof ReadableStream||e instanceof Uint8Array)return e}return new Uint8Array(0)};export{dt as a,ft as b,yt as c,ct as d,ht as e,gt as f,ut as i,lt as p,pt as r,nt as t};
|