@lunora/agent 1.0.0-alpha.9 → 1.0.0-alpha.91
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 +3 -11
- package/dist/channels.d.ts +3 -11
- package/dist/channels.mjs +1 -181
- package/dist/component.d.mts +2 -0
- package/dist/component.d.ts +2 -0
- package/dist/component.mjs +2 -418
- package/dist/inbound.d.mts +7 -5
- package/dist/inbound.d.ts +7 -5
- package/dist/inbound.mjs +1 -32
- package/dist/index.d.mts +49 -8
- package/dist/index.d.ts +49 -8
- package/dist/index.mjs +1 -18
- package/dist/naming.mjs +1 -8
- package/dist/packem_shared/AGENT_MODULE-M4D1EejI.mjs +1 -0
- package/dist/packem_shared/VoiceSessionDO-BdvnaLoO.mjs +1 -0
- package/dist/packem_shared/adaptMcpResult-CVlq-_TO.mjs +2 -0
- package/dist/packem_shared/agent-loop-B3KTMfqm.mjs +3 -0
- package/dist/packem_shared/agentAsTool-CgZb6ycK.mjs +1 -0
- package/dist/packem_shared/base64-5eyBfWO3.mjs +1 -0
- package/dist/packem_shared/braintrustTelemetry-Byne8uPK.mjs +1 -0
- package/dist/packem_shared/branch-marker-boZ00zmk.mjs +1 -0
- package/dist/packem_shared/buildModelMessages-Y4tGo1T9.mjs +5 -0
- package/dist/packem_shared/codeTool-BQb-K3my.mjs +1 -0
- package/dist/packem_shared/collectAgenticMemoryTools-BeMWT2qt.mjs +1 -0
- package/dist/packem_shared/combineTelemetry-DgE9W9G8.mjs +1 -0
- package/dist/packem_shared/common-CJSjtsfv.mjs +1 -0
- package/dist/packem_shared/compileAgentWorkflow-DRkaF9sV.mjs +1 -0
- package/dist/packem_shared/component-shared-G8ngerkU.mjs +1 -0
- package/dist/packem_shared/consoleTelemetry-BZY3Y-Ly.mjs +1 -0
- package/dist/packem_shared/createAgentContext-DPFZ88dr.mjs +1 -0
- package/dist/packem_shared/createAgentGenerate-BOILDUZj.mjs +3 -0
- package/dist/packem_shared/createDispatchRunner-BMgSkFiH-DjUQx8vg.mjs +1 -0
- package/dist/packem_shared/defineAgent-Q3MlQjYs.mjs +3 -0
- package/dist/packem_shared/defineSkill-DGGvDWNq.mjs +1 -0
- package/dist/packem_shared/fnv1a-BNN96GYb.mjs +1 -0
- package/dist/packem_shared/functionTool-D3CP4f8-.mjs +1 -0
- package/dist/packem_shared/in-flight-calls-GH1A_1P3.mjs +1 -0
- package/dist/packem_shared/normalizeEntityName-k3fjicAG.mjs +2 -0
- package/dist/packem_shared/otlpTelemetry-ByqrB-72.mjs +1 -0
- package/dist/packem_shared/positive-integer-ztHqqpBk.mjs +1 -0
- package/dist/packem_shared/runAgentLoop-DJvzWDgh.mjs +1 -0
- package/dist/packem_shared/runVoiceTurn-D1WCjVPw.mjs +1 -0
- package/dist/packem_shared/sandboxComponent-BtOkUYpY.mjs +5 -0
- package/dist/packem_shared/sentryTelemetry-BHeydiAB.mjs +1 -0
- package/dist/packem_shared/tool-output-Cmk3JWMG.mjs +1 -0
- package/dist/packem_shared/{types.d-boAM2Yi1.d.mts → types.d-B8WZl1rU.d.mts} +255 -22
- package/dist/packem_shared/{types.d-boAM2Yi1.d.ts → types.d-B8WZl1rU.d.ts} +255 -22
- package/dist/packem_shared/voice-turn-D1ZzTzcE.mjs +1 -0
- package/dist/reply.d.mts +40 -0
- package/dist/reply.d.ts +40 -0
- package/dist/reply.mjs +1 -0
- package/dist/sandbox.d.mts +14 -13
- package/dist/sandbox.d.ts +14 -13
- package/dist/sandbox.mjs +1 -113
- package/dist/skill-markdown.d.mts +36 -0
- package/dist/skill-markdown.d.ts +36 -0
- package/dist/skill-markdown.mjs +1 -0
- package/dist/telemetry/index.d.mts +152 -33
- package/dist/telemetry/index.d.ts +152 -33
- package/dist/telemetry/index.mjs +1 -5
- package/package.json +18 -9
- package/dist/packem_shared/AGENT_MODULE-Dnt_-AAT.mjs +0 -24
- package/dist/packem_shared/VoiceSessionDO-BdwlLaXC.mjs +0 -297
- package/dist/packem_shared/adaptMcpResult-wtNMvLoP.mjs +0 -65
- package/dist/packem_shared/agentAsTool-CUHlWsmt.mjs +0 -98
- package/dist/packem_shared/base64-BVwtgRJV.mjs +0 -18
- package/dist/packem_shared/braintrustTelemetry-TP7Kwuuj.mjs +0 -47
- package/dist/packem_shared/buildModelMessages-BWFigaoo.mjs +0 -69
- package/dist/packem_shared/codeTool-CjgJOC9t.mjs +0 -122
- package/dist/packem_shared/collectAgenticMemoryTools-QrzpV-WX.mjs +0 -97
- package/dist/packem_shared/combineTelemetry-DCyaaWAI.mjs +0 -43
- package/dist/packem_shared/common-DQXayow6.mjs +0 -89
- package/dist/packem_shared/compileAgentWorkflow-DAfyUuI5.mjs +0 -78
- package/dist/packem_shared/consoleTelemetry--3sWfu1R.mjs +0 -93
- package/dist/packem_shared/createAgentContext-4xJGXNR4.mjs +0 -50
- package/dist/packem_shared/createAgentGenerate-DO7Z96zX.mjs +0 -192
- package/dist/packem_shared/createDispatchRunner-DSbp_dph-ZHTtxy3f.mjs +0 -69
- package/dist/packem_shared/defineAgent-DAwAZC9P.mjs +0 -148
- package/dist/packem_shared/defineSkill-Ctf_S-rz.mjs +0 -22
- package/dist/packem_shared/functionTool-D6lCa2jB.mjs +0 -20
- package/dist/packem_shared/graph-component-Bbaxxymp.mjs +0 -217
- package/dist/packem_shared/memory-D4FPcBsX.mjs +0 -12
- package/dist/packem_shared/normalizeEntityName-BouctxLC.mjs +0 -3
- package/dist/packem_shared/otlpTelemetry-CKgmWVLg.mjs +0 -170
- package/dist/packem_shared/runAgentLoop-M8PKbtWT.mjs +0 -493
- package/dist/packem_shared/runVoiceTurn-LnqLvCRR.mjs +0 -211
- package/dist/packem_shared/sandboxComponent-DR3pTwBL.mjs +0 -194
- package/dist/packem_shared/sentryTelemetry-A4F5ndh9.mjs +0 -36
|
@@ -0,0 +1,5 @@
|
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as n,t as _,s as y,c as I}from"./common-CJSjtsfv.mjs";import{c as x}from"./in-flight-calls-GH1A_1P3.mjs";const g=(c,i)=>typeof c=="string"&&c.length>0?c:i,k=c=>{const{functionId:i,recordInputs:d=!1,recordOutputs:p=!1,Sentry:u}=c,s=x((e,o,a,r)=>{const t={},l=y(n(r,"usage")??n(e.result,"usage"));if(l&&(t["gen_ai.usage.input_tokens"]=l.inputTokens,t["gen_ai.usage.output_tokens"]=l.outputTokens,t["gen_ai.usage.total_tokens"]=l.totalTokens),p){const m=I(n(r,"content")??n(e.result,"content"));m!==void 0&&(t["gen_ai.completion"]=m)}Object.keys(t).length>0&&e.span.setAttributes?.(t),e.span.setStatus?.(o?{code:1}:{code:2,message:a??""}),e.span.end()},e=>{e.span.end()}),f=(e,o,a)=>{const r=n(e,"callId");if(typeof r!="string")return;let t=a;o instanceof Error?t=o.message:typeof o=="string"&&o.length>0&&(t=o),s.close(r,!1,t,void 0)};return{executeLanguageModelCall:e=>{const{callId:o}=e,a={"gen_ai.operation.name":g(i,"language_model_call"),"gen_ai.request.model":n(e,"modelId"),"gen_ai.system":n(e,"provider")};return d&&(a["gen_ai.prompt"]=n(e,"messages")),u.startSpanManual({attributes:a,name:g(i,"language_model_call"),op:"gen_ai.generate"},async r=>{s.open(o,()=>({result:void 0,span:r}));try{const t=await e.execute(),l=s.get(o);return l!==void 0&&(l.result=t),t}catch(t){throw s.close(o,!1,t instanceof Error?t.message:String(t),void 0),t}})},executeTool:e=>{const o=n(n(e,"toolCall"),"toolName"),a={"gen_ai.operation.name":"execute_tool","gen_ai.tool.call.id":n(e,"toolCallId"),"gen_ai.tool.name":o};return d&&(a["gen_ai.tool.input"]=_(e)),u.startSpan({attributes:a,name:`execute_tool ${g(o,"tool")}`,op:"gen_ai.execute_tool"},()=>e.execute())},onAbort:e=>{f(e,n(e,"reason"),"aborted")},onEnd:e=>{s.fromLifecycle(e)},onError:e=>{u.captureException(n(e,"error")??e),f(e,n(e,"error"),"the model call failed")},onLanguageModelCallEnd:e=>{const o=n(e,"callId");typeof o=="string"&&s.close(o,!0,void 0,e)},onStepEnd:e=>{s.fromLifecycle(e)}}};export{k as sentryTelemetry};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const _=4e3,O="… [truncated]",t=T=>T.length<=4e3?T:`${T.slice(0,4e3-O.length)}${O}`;export{_ as M,t as c};
|
|
@@ -23,7 +23,7 @@ interface AgentStepLike {
|
|
|
23
23
|
/**
|
|
24
24
|
* Durably hibernate until an external event of `type` arrives, then return
|
|
25
25
|
* its payload. Used for human-in-the-loop approvals: a run pauses on
|
|
26
|
-
* `approval
|
|
26
|
+
* `approval:<toolCallId>` until a client resolves it. Like `do`, a resolved
|
|
27
27
|
* wait is memoized — a replay returns the recorded decision without pausing
|
|
28
28
|
* again. Signature mirrors `@lunora/workflow`'s `WorkflowStepLike`.
|
|
29
29
|
*/
|
|
@@ -42,13 +42,26 @@ interface AgentStepLike {
|
|
|
42
42
|
* `idempotencyKey`.
|
|
43
43
|
*
|
|
44
44
|
* The `idempotencyKey` is the deterministic durable-step name
|
|
45
|
-
* (`tool
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
45
|
+
* (`tool:<name>:<toolCallId>`, further suffixed per script step for a
|
|
46
|
+
* `codeTool`). A COMPLETED tool step is never re-run on a workflow replay
|
|
47
|
+
* (native step memoization) — but a step that FAILS mid-body is retried
|
|
48
|
+
* at-least-once, so a side-effecting tool (charge a card, send a mail) must
|
|
49
|
+
* dedupe on this key itself. `functionTool` forwards it to the dispatched
|
|
50
|
+
* function as `args.idempotencyKey` (pinned after the model input, so it
|
|
51
|
+
* can't be overridden) — a function that wants to dedupe declares
|
|
52
|
+
* `idempotencyKey: v.optional(v.string())` in its own args and checks it; a
|
|
53
|
+
* function that ignores it is unaffected (an undeclared arg field is dropped,
|
|
54
|
+
* not rejected).
|
|
49
55
|
* @experimental
|
|
50
56
|
*/
|
|
51
57
|
interface AgentToolContext {
|
|
58
|
+
/**
|
|
59
|
+
* How many sub-agent delegations deep this run already is — 0 for a run a
|
|
60
|
+
* user started, one more per `agent.asTool` hop. The loop copies it off
|
|
61
|
+
* {@link AgentRunInput.depth}; `agent.asTool` reads it to refuse spawning a
|
|
62
|
+
* child past the delegation-depth bound (see `as-tool.ts`). Absent is 0.
|
|
63
|
+
*/
|
|
64
|
+
depth?: number;
|
|
52
65
|
/** The Worker environment bindings. */
|
|
53
66
|
env: Record<string, unknown>;
|
|
54
67
|
/**
|
|
@@ -67,6 +80,14 @@ interface AgentToolContext {
|
|
|
67
80
|
getState: () => Promise<Record<string, unknown> | undefined>;
|
|
68
81
|
/** Deterministic idempotency key — the tool's durable-step name. */
|
|
69
82
|
idempotencyKey: string;
|
|
83
|
+
/**
|
|
84
|
+
* Verified owner of the thread this run belongs to (the loop copies it off
|
|
85
|
+
* {@link AgentRunInput.owner}); `undefined` on an anonymous/single-tenant
|
|
86
|
+
* thread. `agent.asTool` forwards it to the CHILD run, so a sub-agent thread
|
|
87
|
+
* under an owned parent inherits the same RLS scope instead of being created
|
|
88
|
+
* ownerless — which left it readable by anyone who knew its key.
|
|
89
|
+
*/
|
|
90
|
+
owner?: string;
|
|
70
91
|
/**
|
|
71
92
|
* Emit an EPHEMERAL progress event for this tool call on the agent's live
|
|
72
93
|
* channel — the same live-only sink the streamed token deltas ride. NOT
|
|
@@ -102,11 +123,45 @@ interface AgentToolContext {
|
|
|
102
123
|
* skip the write when it is already present.
|
|
103
124
|
*/
|
|
104
125
|
setState: (state: Record<string, unknown>) => Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* The durable-step handle (`step.do`/`waitForEvent`). ALWAYS present:
|
|
128
|
+
* `agent-loop.ts` threads it into every tool's context unconditionally, and
|
|
129
|
+
* it is required rather than optional so a missing handle is a compile
|
|
130
|
+
* error instead of a silent durability downgrade. `codeTool` uses it to give
|
|
131
|
+
* each script step its OWN nested durable boundary — see `code-tool.ts` — so
|
|
132
|
+
* a failure at script step 3 retries only step 3, not steps 1–2's
|
|
133
|
+
* already-committed side effects. Cloudflare Workflows supports a `step.do`
|
|
134
|
+
* nested inside another `step.do`'s callback (the codeTool call's own
|
|
135
|
+
* enclosing step). Most tools never touch this directly; a test driving
|
|
136
|
+
* `execute`/`runToolScript` by hand passes a pass-through double.
|
|
137
|
+
*/
|
|
138
|
+
step: AgentStepLike;
|
|
105
139
|
/** The thread this tool call belongs to. */
|
|
106
140
|
threadKey: string;
|
|
107
141
|
/** The provider-issued tool-call id. */
|
|
108
142
|
toolCallId: string;
|
|
109
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* The view of {@link AgentToolContext} handed to a `needsApproval` gate
|
|
146
|
+
* function — every field except `setState`, `step`, and `reportProgress`.
|
|
147
|
+
*
|
|
148
|
+
* `setState` is dropped because a gate that mutates thread state is a side
|
|
149
|
+
* effect inside a decision predicate, and `reportProgress` because emitting a
|
|
150
|
+
* live event is the same thing in observable form — the decision is what the
|
|
151
|
+
* loop reports, not the deciding. `step` goes because the loop already runs the
|
|
152
|
+
* gate inside a durable step of its own, so a gate has no business opening
|
|
153
|
+
* another.
|
|
154
|
+
*
|
|
155
|
+
* `getState` and `run` stay: reads are legitimate gate inputs (gate on the
|
|
156
|
+
* caller's plan tier, on a spend total), and the gate resolves inside its own
|
|
157
|
+
* durable step, so they are replay-safe there. Note this makes the type a
|
|
158
|
+
* NARROWING, not a proof of purity — `run` takes any
|
|
159
|
+
* {@link AgentFunctionReference}, so a gate can still dispatch a mutation
|
|
160
|
+
* before approval. Nothing in the type system distinguishes a query reference
|
|
161
|
+
* from a mutation one; keeping the gate side-effect-free is the author's.
|
|
162
|
+
* @experimental
|
|
163
|
+
*/
|
|
164
|
+
type AgentApprovalContext = Omit<AgentToolContext, "reportProgress" | "setState" | "step">;
|
|
110
165
|
/**
|
|
111
166
|
* An agent tool. Unlike a raw AI SDK tool, `execute` is NOT handed to the
|
|
112
167
|
* model call — the loop runs it itself inside a named durable step so a
|
|
@@ -127,17 +182,25 @@ interface AgentToolDefinition<Input = unknown, Output = unknown> {
|
|
|
127
182
|
* Gate the tool behind a human approval (mirrors the AI SDK's
|
|
128
183
|
* `needsApproval`). When it resolves truthy the durable run PAUSES — the
|
|
129
184
|
* thread moves to `"awaiting_input"` and the workflow hibernates on
|
|
130
|
-
* `approval
|
|
185
|
+
* `approval:<toolCallId>` — until a client calls `agents:agentResolveApproval`.
|
|
131
186
|
* On approve the tool runs exactly as normal; on reject it is skipped and a
|
|
132
187
|
* tool result explaining the rejection is persisted so the next turn recovers.
|
|
133
188
|
* A boolean gates statically; a function gates per input. Default: `false`
|
|
134
|
-
* (unchanged behavior).
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
189
|
+
* (unchanged behavior).
|
|
190
|
+
*
|
|
191
|
+
* The boolean/`undefined` forms are compile-time constants re-derived
|
|
192
|
+
* identically on every replay — no durable step. The FUNCTION form runs
|
|
193
|
+
* inside its OWN durable step (`tool:approval-gate:<toolCallId>`, distinct
|
|
194
|
+
* from the tool's own step), so it now runs exactly once per call, not once
|
|
195
|
+
* per replay. It must still be otherwise pure: deterministic given its
|
|
196
|
+
* inputs (no `Date.now()`/`Math.random()`) and free of side effects — the
|
|
197
|
+
* context it receives is {@link AgentApprovalContext}, which has neither
|
|
198
|
+
* `setState` nor `reportProgress`; state writes and progress events belong
|
|
199
|
+
* only in `execute`, inside the tool's own memoized step. It still holds
|
|
200
|
+
* `run`, which the type cannot narrow to reads — see
|
|
201
|
+
* {@link AgentApprovalContext}.
|
|
139
202
|
*/
|
|
140
|
-
needsApproval?: ((input: Input, context:
|
|
203
|
+
needsApproval?: ((input: Input, context: AgentApprovalContext) => boolean | Promise<boolean>) | boolean;
|
|
141
204
|
}
|
|
142
205
|
/**
|
|
143
206
|
* Author-supplied tool config (see {@link AgentToolDefinition}).
|
|
@@ -252,7 +315,7 @@ interface AgentMemoryOptions {
|
|
|
252
315
|
* (`key: "default"`) from {@link AgentConfig.memory}, then one per skill that
|
|
253
316
|
* carries `knowledge` (keyed by the skill's name). The key names the durable
|
|
254
317
|
* step — the default source keeps the historic `"memory:retrieve"`, a skill
|
|
255
|
-
* source uses `"memory:retrieve
|
|
318
|
+
* source uses `"memory:retrieve:<key>"` — so replay stays deterministic.
|
|
256
319
|
* @experimental
|
|
257
320
|
*/
|
|
258
321
|
interface AgentMemorySource extends AgentMemoryOptions {
|
|
@@ -308,7 +371,7 @@ interface SkillConfig {
|
|
|
308
371
|
knowledge?: AgentMemoryOptions;
|
|
309
372
|
/**
|
|
310
373
|
* The skill's identifier — namespaces this skill's `knowledge` memory source
|
|
311
|
-
* (the durable step `memory:retrieve
|
|
374
|
+
* (the durable step `memory:retrieve:<name>`). Must be identifier-shaped.
|
|
312
375
|
*/
|
|
313
376
|
name: string;
|
|
314
377
|
/**
|
|
@@ -318,6 +381,12 @@ interface SkillConfig {
|
|
|
318
381
|
*/
|
|
319
382
|
tools?: Record<string, AnyAgentTool>;
|
|
320
383
|
}
|
|
384
|
+
/**
|
|
385
|
+
* The code-side parts of a markdown-authored skill — everything `SKILL.md`
|
|
386
|
+
* cannot carry. `name` and `instructions` come from the file itself.
|
|
387
|
+
* @experimental
|
|
388
|
+
*/
|
|
389
|
+
type SkillMarkdownExtras = Omit<SkillConfig, "instructions" | "name">;
|
|
321
390
|
/**
|
|
322
391
|
* A `defineSkill` result — config plus the brand the agent merge checks.
|
|
323
392
|
* @experimental
|
|
@@ -358,11 +427,43 @@ interface AgentStepFinishInfo {
|
|
|
358
427
|
}
|
|
359
428
|
/**
|
|
360
429
|
* Called after each LLM turn with that turn's text, tool calls, and usage. Runs
|
|
361
|
-
* inside a named durable step (`agent:step-finish
|
|
430
|
+
* inside a named durable step (`agent:step-finish:<turn>`) so it fires exactly
|
|
362
431
|
* once per turn even across a workflow replay.
|
|
363
432
|
* @experimental
|
|
364
433
|
*/
|
|
365
434
|
type AgentOnStepFinish = (info: AgentStepFinishInfo) => Promise<void> | void;
|
|
435
|
+
/**
|
|
436
|
+
* What {@link AgentConfig.onReply} is called with when a triggered run reaches
|
|
437
|
+
* its final answer.
|
|
438
|
+
* @experimental
|
|
439
|
+
*/
|
|
440
|
+
interface AgentReplyInfo {
|
|
441
|
+
/** The worker `env` — where an outbound credential (a bot token, a mailer binding) lives. */
|
|
442
|
+
env: Record<string, unknown>;
|
|
443
|
+
/** Where to reply, captured by the mapper that started this run. */
|
|
444
|
+
replyRef: AgentReplyRef;
|
|
445
|
+
/** The run's final answer. */
|
|
446
|
+
result: AgentRunResult;
|
|
447
|
+
/** The thread this run belongs to. */
|
|
448
|
+
threadKey: string;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Send a triggered run's answer back where it came from — the outbound half of
|
|
452
|
+
* an `onEmail` / `onInbound` trigger.
|
|
453
|
+
*
|
|
454
|
+
* Called once, automatically, when a run started with a `replyRef` produces a
|
|
455
|
+
* final answer; a run without one (an ordinary in-app `ctx.agents.<name>.run`)
|
|
456
|
+
* never calls it. It runs inside a named durable step, so a transient failure
|
|
457
|
+
* is retried and a workflow replay does not send the answer twice.
|
|
458
|
+
*
|
|
459
|
+
* Delivery is the app's call, because only the app has the credential: email
|
|
460
|
+
* has a home already (`replyToEmail(mailer, ref, body)` from
|
|
461
|
+
* `@lunora/agent/reply`), while Slack/GitHub/Discord bot tokens have no
|
|
462
|
+
* framework-owned store yet — read them from `info.env` and make the provider
|
|
463
|
+
* call.
|
|
464
|
+
* @experimental
|
|
465
|
+
*/
|
|
466
|
+
type AgentOnReply = (info: AgentReplyInfo) => Promise<void> | void;
|
|
366
467
|
/**
|
|
367
468
|
* The input {@link AgentConfig.prepareStep} sees before a turn runs.
|
|
368
469
|
* @experimental
|
|
@@ -404,6 +505,39 @@ type AgentPrepareStep = (input: AgentPrepareStepInput) => AgentPrepareStepResult
|
|
|
404
505
|
* start a run from an inbound email.
|
|
405
506
|
* @experimental
|
|
406
507
|
*/
|
|
508
|
+
/**
|
|
509
|
+
* Where a triggered run should send its answer back to — captured by the
|
|
510
|
+
* mapper, from fields the verified inbound payload already carries, and carried
|
|
511
|
+
* through the run so {@link AgentConfig.onReply} can answer in the same place
|
|
512
|
+
* the question was asked.
|
|
513
|
+
*
|
|
514
|
+
* A discriminated union rather than an opaque blob because each channel threads
|
|
515
|
+
* differently: email by RFC 5322 `In-Reply-To`/`References`, Slack by
|
|
516
|
+
* `thread_ts`, GitHub by issue number, Discord by channel (plus the triggering
|
|
517
|
+
* message for a true reply).
|
|
518
|
+
* @experimental
|
|
519
|
+
*/
|
|
520
|
+
type AgentReplyRef = {
|
|
521
|
+
channel: "discord";
|
|
522
|
+
channelId: string;
|
|
523
|
+
messageId?: string;
|
|
524
|
+
} | {
|
|
525
|
+
channel: "email";
|
|
526
|
+
from: string;
|
|
527
|
+
messageId: string;
|
|
528
|
+
references?: string;
|
|
529
|
+
to: string[];
|
|
530
|
+
} | {
|
|
531
|
+
channel: "github";
|
|
532
|
+
commentId?: number;
|
|
533
|
+
issueNumber: number;
|
|
534
|
+
owner: string;
|
|
535
|
+
repo: string;
|
|
536
|
+
} | {
|
|
537
|
+
channel: "slack";
|
|
538
|
+
channelId: string;
|
|
539
|
+
threadTs: string;
|
|
540
|
+
};
|
|
407
541
|
interface AgentEmailRun {
|
|
408
542
|
/** The user message that starts (or continues) the thread — the model's prompt. */
|
|
409
543
|
input: string;
|
|
@@ -414,6 +548,13 @@ interface AgentEmailRun {
|
|
|
414
548
|
* `email.from`.
|
|
415
549
|
*/
|
|
416
550
|
owner?: string;
|
|
551
|
+
/**
|
|
552
|
+
* Where to send the answer — see {@link AgentReplyRef}. Populate it from the
|
|
553
|
+
* event the mapper already has (`captureEmailReplyRef(email)` does it for
|
|
554
|
+
* email) and the run calls {@link AgentConfig.onReply} with it once the
|
|
555
|
+
* final answer is ready. Omit it and the run simply never replies.
|
|
556
|
+
*/
|
|
557
|
+
replyRef?: AgentReplyRef;
|
|
417
558
|
/** The thread key — reuse to continue a conversation (e.g. a ticket id parsed from the subject). */
|
|
418
559
|
threadKey: string;
|
|
419
560
|
/** Optional thread title, set on first creation. */
|
|
@@ -484,6 +625,22 @@ interface AgentInboundChannel {
|
|
|
484
625
|
interface AgentConfig {
|
|
485
626
|
/** Restrict the tools the model may call, by name. Default: all tools. */
|
|
486
627
|
activeTools?: ReadonlyArray<string>;
|
|
628
|
+
/**
|
|
629
|
+
* How long a human-in-the-loop tool approval may stay pending before the
|
|
630
|
+
* run stops waiting — a Cloudflare Workflows duration: milliseconds, or a
|
|
631
|
+
* `"<n> <unit>"` string like `"3 days"` (the unit set is the host's, so a
|
|
632
|
+
* typo is a compile error). Default `"3 days"`.
|
|
633
|
+
*
|
|
634
|
+
* On timeout the call is treated as REJECTED (the run records why and
|
|
635
|
+
* continues down the normal rejection path), so a run whose approver never
|
|
636
|
+
* answers ends instead of hibernating forever.
|
|
637
|
+
*
|
|
638
|
+
* CLAMPED to one week. A longer wait would outlive the thread's
|
|
639
|
+
* abandoned-run horizon, letting a new run reclaim the thread while the
|
|
640
|
+
* approval is still pending — which is the exact failure this timeout
|
|
641
|
+
* exists to prevent, so it cannot be configured back into existence.
|
|
642
|
+
*/
|
|
643
|
+
approvalTimeout?: `${number} ${"day" | "hour" | "minute" | "month" | "second" | "week" | "year"}${"s" | ""}` | number;
|
|
487
644
|
/**
|
|
488
645
|
* Automatic thread-history compaction. When the persisted history exceeds
|
|
489
646
|
* `maxMessages`, the loop summarizes the older messages (all but the most
|
|
@@ -530,7 +687,7 @@ interface AgentConfig {
|
|
|
530
687
|
model: AgentModelInput;
|
|
531
688
|
/**
|
|
532
689
|
* Optional override for the deployed workflow name (`wrangler.jsonc`
|
|
533
|
-
* `workflows[].name`). Defaults to `agent
|
|
690
|
+
* `workflows[].name`). Defaults to `agent-<kebab-cased export name>`. Does
|
|
534
691
|
* NOT change the binding name, which is always derived from the export
|
|
535
692
|
* name (`support` → `AGENT_SUPPORT`).
|
|
536
693
|
*/
|
|
@@ -543,7 +700,16 @@ interface AgentConfig {
|
|
|
543
700
|
*
|
|
544
701
|
* - `"reject"` (default) — fail the new run fast with a `CONFLICT` error.
|
|
545
702
|
* - `"replace"` — terminate the in-flight instance and take the thread over.
|
|
546
|
-
* - `"queue"` —
|
|
703
|
+
* - `"queue"` — park the new run behind the one in flight (FIFO, up to five deep) and hibernate it until the thread is handed over.
|
|
704
|
+
*
|
|
705
|
+
* Each parked run is a live workflow instance waiting on an event, so the
|
|
706
|
+
* queue's depth cap is a real resource bound: past it, a start is rejected
|
|
707
|
+
* exactly as `"reject"` would. A `"replace"` arriving later supersedes the
|
|
708
|
+
* run in FLIGHT, not the queue — parked runs still take their turn after it.
|
|
709
|
+
*
|
|
710
|
+
* A dispatch with no instance id (the inbound-email / inbound-channel
|
|
711
|
+
* paths) cannot be parked, because nothing later can tell it apart from
|
|
712
|
+
* another such dispatch to wake it; `"queue"` rejects those.
|
|
547
713
|
*
|
|
548
714
|
* A workflow REPLAY re-enters the bootstrap under the SAME instance id and
|
|
549
715
|
* is never a concurrent run (the guard compares the stored instance id).
|
|
@@ -563,6 +729,12 @@ interface AgentConfig {
|
|
|
563
729
|
* signature over the raw body before calling `map`.
|
|
564
730
|
*/
|
|
565
731
|
onInbound?: AgentInboundChannel;
|
|
732
|
+
/**
|
|
733
|
+
* Called with the final answer when the run was triggered from a channel
|
|
734
|
+
* that gave it a `replyRef` — see {@link AgentOnReply}. This is how an
|
|
735
|
+
* inbound-triggered agent answers where it was asked.
|
|
736
|
+
*/
|
|
737
|
+
onReply?: AgentOnReply;
|
|
566
738
|
/** Called after each LLM turn — see {@link AgentOnStepFinish}. */
|
|
567
739
|
onStepFinish?: AgentOnStepFinish;
|
|
568
740
|
/**
|
|
@@ -577,7 +749,7 @@ interface AgentConfig {
|
|
|
577
749
|
* Opt this agent into being STARTED over the public RPC boundary — i.e. via
|
|
578
750
|
* the auto-registered `agents:agentRun` mutation an HTTP-only client (e.g.
|
|
579
751
|
* the `@lunora/mcp` server) calls. Default `false`: an agent is startable
|
|
580
|
-
* only from server-side app code (`ctx.agents
|
|
752
|
+
* only from server-side app code (`ctx.agents.<name>.run(...)`), so declaring
|
|
581
753
|
* an agent does NOT expose it to arbitrary RPC callers. Fail-closed — the run
|
|
582
754
|
* mutation refuses an agent that has not opted in, regardless of any MCP-side
|
|
583
755
|
* `allowAgents` configuration. A started thread is still owner-scoped to
|
|
@@ -649,8 +821,20 @@ interface AgentVoiceConfig {
|
|
|
649
821
|
/**
|
|
650
822
|
* Spoken on connect before the first user turn — a fixed greeting synthesized
|
|
651
823
|
* through the TTS model. Omit for a silent-until-spoken-to session.
|
|
824
|
+
*
|
|
825
|
+
* Synthesized once per THREAD, not once per socket: the greeting's persisted
|
|
826
|
+
* row is keyed per thread, and a reconnect onto a thread that already exists
|
|
827
|
+
* gets the `ready` frame without paying for the same line again.
|
|
652
828
|
*/
|
|
653
829
|
greeting?: string;
|
|
830
|
+
/**
|
|
831
|
+
* Cap on how many turns one voice socket may run before it is closed with
|
|
832
|
+
* code `4002`. Every turn is a full LLM generation plus sentence-by-sentence
|
|
833
|
+
* TTS — billed and persisted — on a hibernatable socket that can live for
|
|
834
|
+
* days, and the one-turn-in-flight guard throttles nothing. Defaults to 100;
|
|
835
|
+
* a client that hits the cap reconnects for a fresh budget.
|
|
836
|
+
*/
|
|
837
|
+
maxTurns?: number;
|
|
654
838
|
/**
|
|
655
839
|
* TTS voice/speaker id forwarded to the TTS model (e.g. a Deepgram Aura voice
|
|
656
840
|
* like `"aura-asteria-en"`). Model-specific; omitted when unset so the model
|
|
@@ -685,10 +869,10 @@ interface AgentSubToolInput {
|
|
|
685
869
|
interface AgentAsToolOptions {
|
|
686
870
|
/** What the sub-agent does — shown to the parent's model (it decides from it). */
|
|
687
871
|
description: string;
|
|
688
|
-
/** Cap on child-run status polls before giving up. Default
|
|
872
|
+
/** Cap on child-run status polls before giving up — a positive integer. Default 600 (with the 500 ms default interval, a five-minute budget). */
|
|
689
873
|
maxPolls?: number;
|
|
690
874
|
/**
|
|
691
|
-
* The child agent's export name — selects its `AGENT_
|
|
875
|
+
* The child agent's export name — selects its `AGENT_<NAME>` Workflow
|
|
692
876
|
* binding (e.g. `"researcher"` → `AGENT_RESEARCHER`). The model-facing tool
|
|
693
877
|
* name is the KEY assigned in the parent's `tools` map, not this.
|
|
694
878
|
*/
|
|
@@ -725,11 +909,39 @@ interface AgentDefinition extends AgentConfig {
|
|
|
725
909
|
*/
|
|
726
910
|
memorySources?: ReadonlyArray<AgentMemorySource>;
|
|
727
911
|
}
|
|
912
|
+
/**
|
|
913
|
+
* What `agentEnsureThread` reports back to the loop.
|
|
914
|
+
*
|
|
915
|
+
* A discriminated union rather than a bag of optional booleans: the four
|
|
916
|
+
* outcomes are mutually exclusive, and the data each carries only exists for its
|
|
917
|
+
* own case. `queued` has a position, `replaced` has the instance it took the
|
|
918
|
+
* thread from, and the other two have nothing — encoding that as five
|
|
919
|
+
* independent optional fields made every reader re-derive which combination was
|
|
920
|
+
* legal.
|
|
921
|
+
* @experimental
|
|
922
|
+
*/
|
|
923
|
+
type EnsureThreadOutcome = {
|
|
924
|
+
outcome: "continued" | "created";
|
|
925
|
+
} | {
|
|
926
|
+
outcome: "queued";
|
|
927
|
+
position: number;
|
|
928
|
+
} | {
|
|
929
|
+
outcome: "replaced";
|
|
930
|
+
priorInstanceId: string;
|
|
931
|
+
};
|
|
728
932
|
/**
|
|
729
933
|
* Params of one agent run (the compiled workflow's payload).
|
|
730
934
|
* @experimental
|
|
731
935
|
*/
|
|
732
936
|
interface AgentRunInput {
|
|
937
|
+
/**
|
|
938
|
+
* Sub-agent delegation depth. A run a user starts omits it (0); each
|
|
939
|
+
* `agent.asTool` hop stamps its child one deeper, and the tool refuses to
|
|
940
|
+
* delegate past the bound — `maxTurns` bounds one level's turns, this bounds
|
|
941
|
+
* the TREE (every hop mints a distinct child `threadKey`, so the per-thread
|
|
942
|
+
* run-queue cap never applies across them).
|
|
943
|
+
*/
|
|
944
|
+
depth?: number;
|
|
733
945
|
/** The user message that starts (or continues) the thread. */
|
|
734
946
|
input: string;
|
|
735
947
|
/**
|
|
@@ -741,6 +953,8 @@ interface AgentRunInput {
|
|
|
741
953
|
* the first run.
|
|
742
954
|
*/
|
|
743
955
|
owner?: string;
|
|
956
|
+
/** Where a triggered run sends its answer — see {@link AgentReplyRef}. */
|
|
957
|
+
replyRef?: AgentReplyRef;
|
|
744
958
|
/** The thread key — reuse to continue a conversation. */
|
|
745
959
|
threadKey: string;
|
|
746
960
|
/** Optional thread title, set on first creation. */
|
|
@@ -773,6 +987,17 @@ interface AgentRunResult {
|
|
|
773
987
|
*/
|
|
774
988
|
interface AgentFunctionPaths {
|
|
775
989
|
appendMessage: string;
|
|
990
|
+
/**
|
|
991
|
+
* The internal `agents:agentCompleteRun` mutation the loop dispatches at the
|
|
992
|
+
* end of a run: it writes the terminal status AND hands the thread to the
|
|
993
|
+
* next queued run in the same mutation.
|
|
994
|
+
*/
|
|
995
|
+
completeRun: string;
|
|
996
|
+
/**
|
|
997
|
+
* The internal `agents:agentDeleteMessage` mutation the loop dispatches to
|
|
998
|
+
* retire the HITL approval marker once the decision has landed.
|
|
999
|
+
*/
|
|
1000
|
+
deleteMessage: string;
|
|
776
1001
|
ensureThread: string;
|
|
777
1002
|
/** The internal `agents:agentEpisodeRecall` query the loop dispatches for an episodic-kind read. */
|
|
778
1003
|
episodeRecall: string;
|
|
@@ -824,6 +1049,14 @@ interface AgentMessageRow {
|
|
|
824
1049
|
interface AgentToolCall {
|
|
825
1050
|
id: string;
|
|
826
1051
|
input: unknown;
|
|
1052
|
+
/**
|
|
1053
|
+
* Why this call was REJECTED before it could run: the model's arguments
|
|
1054
|
+
* failed the tool's input schema, or did not parse as JSON. Present only on
|
|
1055
|
+
* a rejected call — the loop records it as a recoverable tool result and
|
|
1056
|
+
* never executes the tool, because the `input` above is the raw value the
|
|
1057
|
+
* provider sent, not a validated one.
|
|
1058
|
+
*/
|
|
1059
|
+
invalid?: string;
|
|
827
1060
|
name: string;
|
|
828
1061
|
}
|
|
829
1062
|
/**
|
|
@@ -1078,7 +1311,7 @@ interface AgentRunHandle {
|
|
|
1078
1311
|
id: string;
|
|
1079
1312
|
}
|
|
1080
1313
|
/**
|
|
1081
|
-
* The `ctx.agents
|
|
1314
|
+
* The `ctx.agents.<name>` producer handle.
|
|
1082
1315
|
* @experimental
|
|
1083
1316
|
*/
|
|
1084
1317
|
interface AgentHandle {
|
|
@@ -1111,4 +1344,4 @@ interface AgentHandle {
|
|
|
1111
1344
|
/** Read a run's workflow status by instance id. */
|
|
1112
1345
|
status: (id: string) => Promise<unknown>;
|
|
1113
1346
|
}
|
|
1114
|
-
export { AgentDefinition as A,
|
|
1347
|
+
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 };
|