@lunora/agent 1.0.0-alpha.5 → 1.0.0-alpha.51
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/channels.mjs +1 -181
- package/dist/component.mjs +2 -418
- package/dist/inbound.d.mts +1 -1
- package/dist/inbound.d.ts +1 -1
- package/dist/inbound.mjs +1 -32
- package/dist/index.d.mts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.mjs +1 -18
- package/dist/naming.mjs +1 -8
- package/dist/packem_shared/AGENT_MODULE-BXx-tSCe.mjs +1 -0
- package/dist/packem_shared/VoiceSessionDO-DNXzVGVf.mjs +1 -0
- package/dist/packem_shared/adaptMcpResult-18G7zpFo.mjs +2 -0
- package/dist/packem_shared/agentAsTool-gH17BQ8M.mjs +1 -0
- package/dist/packem_shared/base64-B_qZ_Tyh.mjs +1 -0
- package/dist/packem_shared/braintrustTelemetry-CnOI5WAw.mjs +1 -0
- package/dist/packem_shared/branch-marker-DELZqEOQ.mjs +1 -0
- package/dist/packem_shared/buildModelMessages-Dm2wVNQy.mjs +5 -0
- package/dist/packem_shared/codeTool-DYJVy-bH.mjs +1 -0
- package/dist/packem_shared/collectAgenticMemoryTools-DBcP8dUa.mjs +1 -0
- package/dist/packem_shared/combineTelemetry-oLCV_EPV.mjs +1 -0
- package/dist/packem_shared/common-Dck97z3Y.mjs +1 -0
- package/dist/packem_shared/compileAgentWorkflow-BW627hb5.mjs +1 -0
- package/dist/packem_shared/component-shared-BVjAbtUu.mjs +1 -0
- package/dist/packem_shared/consoleTelemetry-C_85CaZ7.mjs +1 -0
- package/dist/packem_shared/createAgentContext-D1cXHQO2.mjs +1 -0
- package/dist/packem_shared/createAgentGenerate-BS1vasdV.mjs +3 -0
- package/dist/packem_shared/createDispatchRunner-EYOnoElU-CpVpdTXn.mjs +1 -0
- package/dist/packem_shared/defineAgent-D0VIzlhu.mjs +3 -0
- package/dist/packem_shared/defineSkill-DfJxCwfZ.mjs +1 -0
- package/dist/packem_shared/functionTool-CWHhkYqd.mjs +1 -0
- package/dist/packem_shared/memory-DNRyyp1b.mjs +1 -0
- package/dist/packem_shared/normalizeEntityName-DrEDaSSz.mjs +2 -0
- package/dist/packem_shared/otlpTelemetry-DcW9mOLV.mjs +1 -0
- package/dist/packem_shared/runAgentLoop-nuk5NsAn.mjs +3 -0
- package/dist/packem_shared/runVoiceTurn-DhN9Asnn.mjs +1 -0
- package/dist/packem_shared/sandboxComponent-CKDGyK4Y.mjs +1 -0
- package/dist/packem_shared/sentryTelemetry-Dr2aPuvl.mjs +1 -0
- package/dist/packem_shared/{types.d-boAM2Yi1.d.mts → types.d-PMYeuDE7.d.mts} +40 -17
- package/dist/packem_shared/{types.d-boAM2Yi1.d.ts → types.d-PMYeuDE7.d.ts} +40 -17
- package/dist/packem_shared/voice-turn-DzRKyf-x.mjs +1 -0
- package/dist/sandbox.d.mts +2 -2
- package/dist/sandbox.d.ts +2 -2
- 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 +82 -1
- package/dist/telemetry/index.d.ts +82 -1
- package/dist/telemetry/index.mjs +1 -4
- package/package.json +13 -8
- package/dist/packem_shared/AGENT_MODULE-Dnt_-AAT.mjs +0 -24
- package/dist/packem_shared/VoiceSessionDO-DLoXsHGF.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-wuGDErob.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-DAeFCot5.mjs +0 -61
- package/dist/packem_shared/compileAgentWorkflow-DX90058f.mjs +0 -55
- package/dist/packem_shared/consoleTelemetry-z2MiP1jt.mjs +0 -93
- package/dist/packem_shared/createAgentContext-4xJGXNR4.mjs +0 -50
- package/dist/packem_shared/createAgentGenerate-BQv9YJ01.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/runAgentLoop-B3Q2o-Uz.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-CgqFJyLO.mjs +0 -36
|
@@ -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,7 +42,7 @@ interface AgentStepLike {
|
|
|
42
42
|
* `idempotencyKey`.
|
|
43
43
|
*
|
|
44
44
|
* The `idempotencyKey` is the deterministic durable-step name
|
|
45
|
-
* (`tool
|
|
45
|
+
* (`tool:<name>:<toolCallId>`). A COMPLETED tool step is never re-run on a
|
|
46
46
|
* workflow replay (native step memoization) — but a step that FAILS mid-body
|
|
47
47
|
* is retried at-least-once, so a side-effecting tool (charge a card, send a
|
|
48
48
|
* mail) must dedupe on this key itself.
|
|
@@ -107,6 +107,17 @@ interface AgentToolContext {
|
|
|
107
107
|
/** The provider-issued tool-call id. */
|
|
108
108
|
toolCallId: string;
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* The READ-ONLY view of {@link AgentToolContext} handed to a `needsApproval`
|
|
112
|
+
* gate function — every field except `setState`. A gate that mutates thread
|
|
113
|
+
* state is a side effect inside a decision predicate, which this type makes a
|
|
114
|
+
* compile-time error rather than a documented-but-unenforced rule: `getState`
|
|
115
|
+
* and `run` stay available (reads are legitimate gate inputs, and the
|
|
116
|
+
* function form is resolved inside its own durable step, so they are
|
|
117
|
+
* replay-safe there too).
|
|
118
|
+
* @experimental
|
|
119
|
+
*/
|
|
120
|
+
type AgentApprovalContext = Omit<AgentToolContext, "setState">;
|
|
110
121
|
/**
|
|
111
122
|
* An agent tool. Unlike a raw AI SDK tool, `execute` is NOT handed to the
|
|
112
123
|
* model call — the loop runs it itself inside a named durable step so a
|
|
@@ -127,17 +138,23 @@ interface AgentToolDefinition<Input = unknown, Output = unknown> {
|
|
|
127
138
|
* Gate the tool behind a human approval (mirrors the AI SDK's
|
|
128
139
|
* `needsApproval`). When it resolves truthy the durable run PAUSES — the
|
|
129
140
|
* thread moves to `"awaiting_input"` and the workflow hibernates on
|
|
130
|
-
* `approval
|
|
141
|
+
* `approval:<toolCallId>` — until a client calls `agents:agentResolveApproval`.
|
|
131
142
|
* On approve the tool runs exactly as normal; on reject it is skipped and a
|
|
132
143
|
* tool result explaining the rejection is persisted so the next turn recovers.
|
|
133
144
|
* A boolean gates statically; a function gates per input. Default: `false`
|
|
134
|
-
* (unchanged behavior).
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
145
|
+
* (unchanged behavior).
|
|
146
|
+
*
|
|
147
|
+
* The boolean/`undefined` forms are compile-time constants re-derived
|
|
148
|
+
* identically on every replay — no durable step. The FUNCTION form runs
|
|
149
|
+
* inside its OWN durable step (`tool:approval-gate:<toolCallId>`, distinct
|
|
150
|
+
* from the tool's own step), so it now runs exactly once per call, not once
|
|
151
|
+
* per replay. It must still be otherwise pure: deterministic given its
|
|
152
|
+
* inputs (no `Date.now()`/`Math.random()`) and free of side effects — the
|
|
153
|
+
* context it receives is {@link AgentApprovalContext}, which has no
|
|
154
|
+
* `setState`; state writes belong only in `execute`, inside the tool's own
|
|
155
|
+
* memoized step.
|
|
139
156
|
*/
|
|
140
|
-
needsApproval?: ((input: Input, context:
|
|
157
|
+
needsApproval?: ((input: Input, context: AgentApprovalContext) => boolean | Promise<boolean>) | boolean;
|
|
141
158
|
}
|
|
142
159
|
/**
|
|
143
160
|
* Author-supplied tool config (see {@link AgentToolDefinition}).
|
|
@@ -252,7 +269,7 @@ interface AgentMemoryOptions {
|
|
|
252
269
|
* (`key: "default"`) from {@link AgentConfig.memory}, then one per skill that
|
|
253
270
|
* carries `knowledge` (keyed by the skill's name). The key names the durable
|
|
254
271
|
* step — the default source keeps the historic `"memory:retrieve"`, a skill
|
|
255
|
-
* source uses `"memory:retrieve
|
|
272
|
+
* source uses `"memory:retrieve:<key>"` — so replay stays deterministic.
|
|
256
273
|
* @experimental
|
|
257
274
|
*/
|
|
258
275
|
interface AgentMemorySource extends AgentMemoryOptions {
|
|
@@ -308,7 +325,7 @@ interface SkillConfig {
|
|
|
308
325
|
knowledge?: AgentMemoryOptions;
|
|
309
326
|
/**
|
|
310
327
|
* The skill's identifier — namespaces this skill's `knowledge` memory source
|
|
311
|
-
* (the durable step `memory:retrieve
|
|
328
|
+
* (the durable step `memory:retrieve:<name>`). Must be identifier-shaped.
|
|
312
329
|
*/
|
|
313
330
|
name: string;
|
|
314
331
|
/**
|
|
@@ -318,6 +335,12 @@ interface SkillConfig {
|
|
|
318
335
|
*/
|
|
319
336
|
tools?: Record<string, AnyAgentTool>;
|
|
320
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* The code-side parts of a markdown-authored skill — everything `SKILL.md`
|
|
340
|
+
* cannot carry. `name` and `instructions` come from the file itself.
|
|
341
|
+
* @experimental
|
|
342
|
+
*/
|
|
343
|
+
type SkillMarkdownExtras = Omit<SkillConfig, "instructions" | "name">;
|
|
321
344
|
/**
|
|
322
345
|
* A `defineSkill` result — config plus the brand the agent merge checks.
|
|
323
346
|
* @experimental
|
|
@@ -358,7 +381,7 @@ interface AgentStepFinishInfo {
|
|
|
358
381
|
}
|
|
359
382
|
/**
|
|
360
383
|
* Called after each LLM turn with that turn's text, tool calls, and usage. Runs
|
|
361
|
-
* inside a named durable step (`agent:step-finish
|
|
384
|
+
* inside a named durable step (`agent:step-finish:<turn>`) so it fires exactly
|
|
362
385
|
* once per turn even across a workflow replay.
|
|
363
386
|
* @experimental
|
|
364
387
|
*/
|
|
@@ -530,7 +553,7 @@ interface AgentConfig {
|
|
|
530
553
|
model: AgentModelInput;
|
|
531
554
|
/**
|
|
532
555
|
* Optional override for the deployed workflow name (`wrangler.jsonc`
|
|
533
|
-
* `workflows[].name`). Defaults to `agent
|
|
556
|
+
* `workflows[].name`). Defaults to `agent-<kebab-cased export name>`. Does
|
|
534
557
|
* NOT change the binding name, which is always derived from the export
|
|
535
558
|
* name (`support` → `AGENT_SUPPORT`).
|
|
536
559
|
*/
|
|
@@ -577,7 +600,7 @@ interface AgentConfig {
|
|
|
577
600
|
* Opt this agent into being STARTED over the public RPC boundary — i.e. via
|
|
578
601
|
* the auto-registered `agents:agentRun` mutation an HTTP-only client (e.g.
|
|
579
602
|
* the `@lunora/mcp` server) calls. Default `false`: an agent is startable
|
|
580
|
-
* only from server-side app code (`ctx.agents
|
|
603
|
+
* only from server-side app code (`ctx.agents.<name>.run(...)`), so declaring
|
|
581
604
|
* an agent does NOT expose it to arbitrary RPC callers. Fail-closed — the run
|
|
582
605
|
* mutation refuses an agent that has not opted in, regardless of any MCP-side
|
|
583
606
|
* `allowAgents` configuration. A started thread is still owner-scoped to
|
|
@@ -688,7 +711,7 @@ interface AgentAsToolOptions {
|
|
|
688
711
|
/** Cap on child-run status polls before giving up. Default 120. */
|
|
689
712
|
maxPolls?: number;
|
|
690
713
|
/**
|
|
691
|
-
* The child agent's export name — selects its `AGENT_
|
|
714
|
+
* The child agent's export name — selects its `AGENT_<NAME>` Workflow
|
|
692
715
|
* binding (e.g. `"researcher"` → `AGENT_RESEARCHER`). The model-facing tool
|
|
693
716
|
* name is the KEY assigned in the parent's `tools` map, not this.
|
|
694
717
|
*/
|
|
@@ -1078,7 +1101,7 @@ interface AgentRunHandle {
|
|
|
1078
1101
|
id: string;
|
|
1079
1102
|
}
|
|
1080
1103
|
/**
|
|
1081
|
-
* The `ctx.agents
|
|
1104
|
+
* The `ctx.agents.<name>` producer handle.
|
|
1082
1105
|
* @experimental
|
|
1083
1106
|
*/
|
|
1084
1107
|
interface AgentHandle {
|
|
@@ -1111,4 +1134,4 @@ interface AgentHandle {
|
|
|
1111
1134
|
/** Read a run's workflow status by instance id. */
|
|
1112
1135
|
status: (id: string) => Promise<unknown>;
|
|
1113
1136
|
}
|
|
1114
|
-
export { AgentDefinition as A,
|
|
1137
|
+
export { AgentDefinition as A, AgentEmailMapper as B, AgentEmailRun as C, AgentGenerateOptions as D, AgentGenerateResult as E, AgentInstructionsContext as F, AgentLiveEvent as G, AgentMemoryOptions as H, InboundChannelEvent as I, AgentMemorySource as J, AgentMessageStatus as K, AgentOnStepFinish as L, AgentPrepareStep as M, AgentPrepareStepInput as N, AgentPrepareStepResult as O, AgentProgressEvent as P, AgentRunHandle as Q, AgentStepFinishInfo as R, SkillMarkdownExtras as S, AgentStepInfo as T, AgentThreadStatus as U, AgentTokenDelta as V, AgentToolCall as W, AgentUsage as X, AgentVoiceConfig as Y, AgentWorkflowBindingLike as Z, AgentWorkflowInstanceLike as _, AgentToolContext as a, AgentToolDefinition as b, SkillDefinition as c, AgentCompact as d, AgentEpisodeExtract as e, AgentGraphExtract as f, AgentGenerate as g, AgentTokenSink as h, AgentRunInput as i, AgentFunctionPaths as j, AgentRunFunction as k, AgentStepLike as l, AgentStreamGenerate as m, AgentRunResult as n, AgentMessageRow as o, AgentConfig as p, AnyAgentTool as q, AgentAsToolOptions as r, AgentSubToolInput as s, AgentBindingSpec as t, AgentHandle as u, AgentToolConfig as v, AgentFunctionReference as w, AgentModelInput as x, SkillConfig as y, AgentApprovalContext as z };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{s as $,o as z}from"./base64-B_qZ_Tyh.mjs";import{buildModelMessages as B}from"./buildModelMessages-Dm2wVNQy.mjs";import{toFunctionReference as b}from"./AGENT_MODULE-BXx-tSCe.mjs";const D=new TextDecoder;new TextEncoder;const K="=",G=t=>{if(t)try{const e=t[0]==="{"?t:D.decode($(t)),n=JSON.parse(e);if(n&&typeof n=="object"&&!Array.isArray(n))return n}catch{}},nt=t=>{if(t){if(!t.startsWith(K))return t;try{return D.decode($(t.slice(K.length)))}catch{return}}},rt=t=>{const e=Number(t);return Number.isFinite(e)&&e>0?e:void 0},st=t=>typeof t=="number"&&Date.now()>=t,it=t=>{try{t.send(JSON.stringify({code:"TOKEN_EXPIRED",error:{code:"TOKEN_EXPIRED",message:"authentication token expired"},type:"error"})),t.close?.(4001,"token_expired")}catch{}},q=16e3,C=1,H=16,N=/[^.!?]*[.!?]+\s+/u,Q=async function*(t){if(t instanceof Uint8Array){yield t;return}if(t instanceof ReadableStream){const e=t.getReader();try{for(;;){const{done:n,value:i}=await e.read();if(n)break;yield i}}finally{e.releaseLock()}return}yield*t},at=(t,e=q,n=C,i=H)=>{const u=n*i/8,y=e*u,d=new ArrayBuffer(44+t.byteLength),r=new DataView(d),s=(U,l)=>{for(let g=0;g<l.length;g+=1)r.setUint8(U+g,l.codePointAt(g)??0)};s(0,"RIFF"),r.setUint32(4,36+t.byteLength,!0),s(8,"WAVE"),s(12,"fmt "),r.setUint32(16,16,!0),r.setUint16(20,1,!0),r.setUint16(22,n,!0),r.setUint32(24,e,!0),r.setUint32(28,y,!0),r.setUint16(32,u,!0),r.setUint16(34,i,!0),s(36,"data"),r.setUint32(40,t.byteLength,!0);const f=new Uint8Array(d);return f.set(t,44),f},Y=t=>{const e=[];let n=t,i=N.exec(n);for(;i&&i[0].length>0;){const u=i[0],y=u.trim();y.length>0&&e.push(y),n=n.slice(u.length),i=N.exec(n)}return{rest:n,sentences:e}},ot=async t=>{const{agent:e,connectionId:n,env:i,exportName:u,owner:y,paths:d,pcm:r,run:s,send:f,sendAudio:U,signal:l,streamGenerate:g,synthesize:_,text:F,threadKey:c,transcribe:I,turn:k,waitForDrain:L}=t,p=()=>l.aborted,E=b(d.appendMessage),M=b(d.ensureThread),P=b(d.listMessages),A=b(d.patchThread),w=(F??(r?await I(r):"")).trim();if(w.length===0)return{assistantText:"",interrupted:!1,userText:""};f({text:w,type:"user_transcript"}),await s(M,{agent:u,key:c,...e.initialState===void 0?{}:{initialState:e.initialState},...y===void 0?{}:{owner:y}}),await s(E,{content:w,messageKey:`voice:${n}:${String(k)}:user`,role:"user",threadKey:c}),await s(A,{key:c,status:"running"});const T=typeof e.instructions=="function"?e.instructions({env:i,input:w,threadKey:c}):e.instructions,O=await s(P,{key:c}),j=B({history:O,...T===void 0?{}:{instructions:T}});let h="",x="",S=Promise.resolve();const J=async a=>{if(p()||a.length===0)return;let m=!1;try{for await(const o of Q(await _(a,l))){if(p()||(await L?.(),p()))break;U(o),m=!0}}catch(o){f({message:o instanceof Error?o.message:String(o),type:"error"})}m&&(x=x.length>0?`${x} ${a}`:a)},R=a=>{S=S.then(async()=>J(a))};try{const a=await g({messages:j,signal:l},v=>{if(p())return;f({text:v,type:"assistant_delta"}),h+=v;const{rest:V,sentences:W}=Y(h);h=V;for(const X of W)R(X)});!p()&&h.trim().length>0&&R(h.trim()),h="",await S;const m=p(),o=m?x:a.text;return await s(E,{content:o,messageKey:`voice:${n}:${String(k)}:assistant`,role:"assistant",threadKey:c}),await s(A,{key:c,status:"idle"}),f(m?{type:"interrupted"}:{text:o,type:"assistant_done"}),{assistantText:o,interrupted:m,userText:w}}catch(a){throw await s(A,{key:c,status:"idle"}),a}},ct=t=>G(t),ut=t=>{if(typeof t=="object"&&t!==null&&"text"in t){const{text:e}=t;return typeof e=="string"?e:""}return""},yt=t=>{if(t instanceof Uint8Array||t instanceof ReadableStream)return t;if(t instanceof Response&&t.body)return t.body;if(typeof t=="object"&&t!==null&&"audio"in t){const{audio:e}=t;if(typeof e=="string")return z(e);if(e instanceof ReadableStream||e instanceof Uint8Array)return e}return new Uint8Array(0)};export{it as E,Q as P,ot as Q,ct as X,at as Y,ut as Z,yt as e,rt as g,nt as l,st as p};
|
package/dist/sandbox.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as AgentToolContext, b as AgentToolDefinition } from "./packem_shared/types.d-
|
|
1
|
+
import { a as AgentToolContext, b as AgentToolDefinition } from "./packem_shared/types.d-PMYeuDE7.mjs";
|
|
2
2
|
import '@lunora/mail/inbound';
|
|
3
3
|
import 'ai';
|
|
4
4
|
/**
|
|
@@ -149,7 +149,7 @@ interface ContainerToolOptions {
|
|
|
149
149
|
declare const browserTool: (options?: BrowserToolOptions) => AgentToolDefinition<BrowserToolInput, string>;
|
|
150
150
|
/**
|
|
151
151
|
* A batteries-included agent tool that talks to a declared Cloudflare
|
|
152
|
-
* Container. `name` is the `ctx.containers
|
|
152
|
+
* Container. `name` is the `ctx.containers.<name>` key (the `lunora/containers.ts`
|
|
153
153
|
* export). One tool exposes `fetch` (HTTP request) and `exec` (run a command);
|
|
154
154
|
* the model picks via `op`. The call dispatches to the auto-registered
|
|
155
155
|
* `sandbox:invoke` action, which carries `ctx.containers`.
|
package/dist/sandbox.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as AgentToolContext, b as AgentToolDefinition } from "./packem_shared/types.d-
|
|
1
|
+
import { a as AgentToolContext, b as AgentToolDefinition } from "./packem_shared/types.d-PMYeuDE7.js";
|
|
2
2
|
import '@lunora/mail/inbound';
|
|
3
3
|
import 'ai';
|
|
4
4
|
/**
|
|
@@ -149,7 +149,7 @@ interface ContainerToolOptions {
|
|
|
149
149
|
declare const browserTool: (options?: BrowserToolOptions) => AgentToolDefinition<BrowserToolInput, string>;
|
|
150
150
|
/**
|
|
151
151
|
* A batteries-included agent tool that talks to a declared Cloudflare
|
|
152
|
-
* Container. `name` is the `ctx.containers
|
|
152
|
+
* Container. `name` is the `ctx.containers.<name>` key (the `lunora/containers.ts`
|
|
153
153
|
* export). One tool exposes `fetch` (HTTP request) and `exec` (run a command);
|
|
154
154
|
* the model picks via `op`. The call dispatches to the auto-registered
|
|
155
155
|
* `sandbox:invoke` action, which carries `ctx.containers`.
|
package/dist/sandbox.mjs
CHANGED
|
@@ -1,113 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { jsonSchema } from 'ai';
|
|
3
|
-
import { toFunctionReference, SANDBOX_INVOKE_PATH } from './packem_shared/AGENT_MODULE-Dnt_-AAT.mjs';
|
|
4
|
-
|
|
5
|
-
const SANDBOX_REF = toFunctionReference(SANDBOX_INVOKE_PATH);
|
|
6
|
-
const DEFAULT_BROWSER_DESCRIPTION = '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`.';
|
|
7
|
-
const DEFAULT_CONTAINER_DESCRIPTION = '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`).';
|
|
8
|
-
const DEFAULT_FS_DESCRIPTION = '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`.';
|
|
9
|
-
const defaultFsGate = (input) => input.op === "write" || input.op === "rm";
|
|
10
|
-
const FS_TOOL_SCHEMA = jsonSchema({
|
|
11
|
-
properties: {
|
|
12
|
-
content: { description: "write: the file contents.", type: "string" },
|
|
13
|
-
op: { description: "The filesystem operation to run.", enum: ["ls", "read", "write", "rm", "stat"], type: "string" },
|
|
14
|
-
path: { description: "The file or directory path, relative to the sandbox root.", type: "string" }
|
|
15
|
-
},
|
|
16
|
-
required: ["op"],
|
|
17
|
-
type: "object"
|
|
18
|
-
});
|
|
19
|
-
const BROWSER_TOOL_SCHEMA = jsonSchema({
|
|
20
|
-
properties: {
|
|
21
|
-
fullPage: { description: "screenshot: capture the full scrollable page rather than just the viewport.", type: "boolean" },
|
|
22
|
-
op: { description: "The browser operation to run.", enum: ["screenshot", "scrape", "pdf", "content"], type: "string" },
|
|
23
|
-
selector: { description: "scrape: optional CSS selector hint to narrow the extraction.", type: "string" },
|
|
24
|
-
type: { description: "screenshot: image encoding (default png).", enum: ["png", "jpeg"], type: "string" },
|
|
25
|
-
url: { description: "The URL to operate on.", type: "string" }
|
|
26
|
-
},
|
|
27
|
-
required: ["op", "url"],
|
|
28
|
-
type: "object"
|
|
29
|
-
});
|
|
30
|
-
const CONTAINER_EXEC_ROUTE = "/exec";
|
|
31
|
-
const CONTAINER_PATH_QUERY_SPLIT = /[?#]/u;
|
|
32
|
-
const normalizeContainerPath = (path) => {
|
|
33
|
-
const [raw = ""] = (path ?? "").split(CONTAINER_PATH_QUERY_SPLIT);
|
|
34
|
-
const segments = [];
|
|
35
|
-
for (const segment of raw.split("/")) {
|
|
36
|
-
if (segment === "" || segment === ".") {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
if (segment === "..") {
|
|
40
|
-
segments.pop();
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
segments.push(segment);
|
|
44
|
-
}
|
|
45
|
-
return `/${segments.join("/")}`;
|
|
46
|
-
};
|
|
47
|
-
const NON_IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["DELETE", "PATCH", "POST", "PUT"]);
|
|
48
|
-
const defaultContainerGate = (input) => {
|
|
49
|
-
if (input.op === "exec") {
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
if (normalizeContainerPath(input.path) === CONTAINER_EXEC_ROUTE) {
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
return NON_IDEMPOTENT_METHODS.has((input.method ?? "GET").toUpperCase());
|
|
56
|
-
};
|
|
57
|
-
const CONTAINER_TOOL_SCHEMA = jsonSchema({
|
|
58
|
-
properties: {
|
|
59
|
-
args: { description: "exec: command arguments.", items: { type: "string" }, type: "array" },
|
|
60
|
-
body: { description: "fetch: request body.", type: "string" },
|
|
61
|
-
command: { description: "exec: the command to run.", type: "string" },
|
|
62
|
-
method: { description: "fetch: HTTP method (default GET).", type: "string" },
|
|
63
|
-
op: { description: "The container operation to run.", enum: ["fetch", "exec"], type: "string" },
|
|
64
|
-
path: { description: "fetch: request path on the container (e.g. /health).", type: "string" }
|
|
65
|
-
},
|
|
66
|
-
required: ["op"],
|
|
67
|
-
type: "object"
|
|
68
|
-
});
|
|
69
|
-
const browserTool = (options = {}) => {
|
|
70
|
-
return {
|
|
71
|
-
description: options.description ?? DEFAULT_BROWSER_DESCRIPTION,
|
|
72
|
-
// Pin `kind` LAST so out-of-schema model input can never override it.
|
|
73
|
-
execute: (input, context) => context.run(SANDBOX_REF, { ...input, kind: "browser" }),
|
|
74
|
-
inputSchema: BROWSER_TOOL_SCHEMA,
|
|
75
|
-
isLunoraAgentTool: true,
|
|
76
|
-
...options.needsApproval === void 0 ? {} : { needsApproval: options.needsApproval }
|
|
77
|
-
};
|
|
78
|
-
};
|
|
79
|
-
const containerTool = (name, options = {}) => {
|
|
80
|
-
if (typeof name !== "string" || name.length === 0) {
|
|
81
|
-
throw new LunoraError("INTERNAL", "@lunora/agent: containerTool requires a container `name` (the ctx.containers.<name> key from lunora/containers.ts)");
|
|
82
|
-
}
|
|
83
|
-
const needsApproval = options.needsApproval ?? defaultContainerGate;
|
|
84
|
-
return {
|
|
85
|
-
description: options.description ?? DEFAULT_CONTAINER_DESCRIPTION,
|
|
86
|
-
// Pin `kind`/`name` LAST so out-of-schema model input can never override
|
|
87
|
-
// the authoritative container the author pinned.
|
|
88
|
-
execute: (input, context) => context.run(SANDBOX_REF, { ...input, kind: "container", name }),
|
|
89
|
-
inputSchema: CONTAINER_TOOL_SCHEMA,
|
|
90
|
-
isLunoraAgentTool: true,
|
|
91
|
-
needsApproval
|
|
92
|
-
};
|
|
93
|
-
};
|
|
94
|
-
const fsTool = (bucket, options = {}) => {
|
|
95
|
-
if (typeof bucket !== "string" || bucket.length === 0) {
|
|
96
|
-
throw new LunoraError("INTERNAL", "@lunora/agent: fsTool requires an R2 `bucket` binding name (the r2_bucket declared in wrangler.jsonc)");
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
description: options.description ?? DEFAULT_FS_DESCRIPTION,
|
|
100
|
-
// Pin kind/bucket/root LAST so out-of-schema model input can never override
|
|
101
|
-
// the authoritative bucket + sandbox root the author pinned. `root` may be
|
|
102
|
-
// a function of the ctx (per-run/owner isolation), resolved here.
|
|
103
|
-
execute: (input, context) => {
|
|
104
|
-
const root = typeof options.root === "function" ? options.root(context) : options.root ?? "";
|
|
105
|
-
return context.run(SANDBOX_REF, { ...input, bucket, kind: "fs", root });
|
|
106
|
-
},
|
|
107
|
-
inputSchema: FS_TOOL_SCHEMA,
|
|
108
|
-
isLunoraAgentTool: true,
|
|
109
|
-
needsApproval: options.needsApproval ?? defaultFsGate
|
|
110
|
-
};
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
export { browserTool, containerTool, fsTool };
|
|
1
|
+
import{LunoraError as p}from"@lunora/errors";import{jsonSchema as i}from"ai";import{toFunctionReference as a,SANDBOX_INVOKE_PATH as c}from"./packem_shared/AGENT_MODULE-BXx-tSCe.mjs";const s=a(c),d='Drive a headless browser: screenshot a page, render it to PDF, read its HTML content, or scrape it. Set `op` to "screenshot" | "pdf" | "content" | "scrape" and pass the target `url`.',u='Talk to a sandboxed container: `fetch` an HTTP path on it, or `exec` a command inside it. Set `op` to "fetch" (with `path`) or "exec" (with `command`).',h='Read and write files in a persistent sandbox filesystem. Set `op` to "ls" (list a directory), "read", "write" (with `content`), "rm", or "stat", and pass `path`.',l=e=>e.op==="write"||e.op==="rm",m=i({properties:{content:{description:"write: the file contents.",type:"string"},op:{description:"The filesystem operation to run.",enum:["ls","read","write","rm","stat"],type:"string"},path:{description:"The file or directory path, relative to the sandbox root.",type:"string"}},required:["op"],type:"object"}),g=i({properties:{fullPage:{description:"screenshot: capture the full scrollable page rather than just the viewport.",type:"boolean"},op:{description:"The browser operation to run.",enum:["screenshot","scrape","pdf","content"],type:"string"},selector:{description:"scrape: optional CSS selector hint to narrow the extraction.",type:"string"},type:{description:"screenshot: image encoding (default png).",enum:["png","jpeg"],type:"string"},url:{description:"The URL to operate on.",type:"string"}},required:["op","url"],type:"object"}),f="/exec",y=/[?#]/u,T=e=>{const[t=""]=(e??"").split(y),o=[];for(const r of t.split("/"))if(!(r===""||r===".")){if(r===".."){o.pop();continue}o.push(r)}return`/${o.join("/")}`},w=new Set(["DELETE","PATCH","POST","PUT"]),b=e=>e.op==="exec"||T(e.path)===f?!0:w.has((e.method??"GET").toUpperCase()),x=i({properties:{args:{description:"exec: command arguments.",items:{type:"string"},type:"array"},body:{description:"fetch: request body.",type:"string"},command:{description:"exec: the command to run.",type:"string"},method:{description:"fetch: HTTP method (default GET).",type:"string"},op:{description:"The container operation to run.",enum:["fetch","exec"],type:"string"},path:{description:"fetch: request path on the container (e.g. /health).",type:"string"}},required:["op"],type:"object"}),E=(e={})=>({description:e.description??d,execute:(t,o)=>o.run(s,{...t,kind:"browser"}),inputSchema:g,isLunoraAgentTool:!0,...e.needsApproval===void 0?{}:{needsApproval:e.needsApproval}}),L=(e,t={})=>{if(typeof e!="string"||e.length===0)throw new p("INTERNAL","@lunora/agent: containerTool requires a container `name` (the ctx.containers.<name> key from lunora/containers.ts)");const o=t.needsApproval??b;return{description:t.description??u,execute:(r,n)=>n.run(s,{...r,kind:"container",name:e}),inputSchema:x,isLunoraAgentTool:!0,needsApproval:o}},j=(e,t={})=>{if(typeof e!="string"||e.length===0)throw new p("INTERNAL","@lunora/agent: fsTool requires an R2 `bucket` binding name (the r2_bucket declared in wrangler.jsonc)");return{description:t.description??h,execute:(o,r)=>{const n=typeof t.root=="function"?t.root(r):t.root??"";return r.run(s,{...o,bucket:e,kind:"fs",root:n})},inputSchema:m,isLunoraAgentTool:!0,needsApproval:t.needsApproval??l}};export{E as browserTool,L as containerTool,j as fsTool};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { S as SkillMarkdownExtras, c as SkillDefinition } from "./packem_shared/types.d-PMYeuDE7.mjs";
|
|
2
|
+
import '@lunora/mail/inbound';
|
|
3
|
+
import 'ai';
|
|
4
|
+
/**
|
|
5
|
+
* Declare a skill whose prose lives in a markdown file.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import triage from "./skills/triage/SKILL.md?raw";
|
|
9
|
+
* import { functionTool } from "@lunora/agent";
|
|
10
|
+
* import { skillFromMarkdown } from "@lunora/agent/skill-markdown";
|
|
11
|
+
*
|
|
12
|
+
* export const triageSkill = skillFromMarkdown(triage, {
|
|
13
|
+
* tools: { searchCode: functionTool(api.code.search, { ... }) },
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ```md
|
|
18
|
+
* ---
|
|
19
|
+
* name: triage
|
|
20
|
+
* ---
|
|
21
|
+
* Reproduce the report before proposing a cause. Cite the failing test.
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* The split is the point: the instructions are the part a non-author reads,
|
|
25
|
+
* reviews and copies between projects, so they belong in a file that is legible
|
|
26
|
+
* on its own — and the `name` travels WITH that file, so a skill can move
|
|
27
|
+
* without a matching TypeScript wrapper. Tools and `knowledge` stay in code,
|
|
28
|
+
* because they are code.
|
|
29
|
+
*
|
|
30
|
+
* Getting the markdown here is the caller's job (`?raw` under Vite, a build-time
|
|
31
|
+
* import elsewhere) — a Worker has no filesystem to read it from at runtime, so
|
|
32
|
+
* this takes the string rather than a path.
|
|
33
|
+
* @experimental
|
|
34
|
+
*/
|
|
35
|
+
declare const skillFromMarkdown: (markdown: string, extras?: SkillMarkdownExtras) => SkillDefinition;
|
|
36
|
+
export { type SkillMarkdownExtras, skillFromMarkdown };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { S as SkillMarkdownExtras, c as SkillDefinition } from "./packem_shared/types.d-PMYeuDE7.js";
|
|
2
|
+
import '@lunora/mail/inbound';
|
|
3
|
+
import 'ai';
|
|
4
|
+
/**
|
|
5
|
+
* Declare a skill whose prose lives in a markdown file.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import triage from "./skills/triage/SKILL.md?raw";
|
|
9
|
+
* import { functionTool } from "@lunora/agent";
|
|
10
|
+
* import { skillFromMarkdown } from "@lunora/agent/skill-markdown";
|
|
11
|
+
*
|
|
12
|
+
* export const triageSkill = skillFromMarkdown(triage, {
|
|
13
|
+
* tools: { searchCode: functionTool(api.code.search, { ... }) },
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ```md
|
|
18
|
+
* ---
|
|
19
|
+
* name: triage
|
|
20
|
+
* ---
|
|
21
|
+
* Reproduce the report before proposing a cause. Cite the failing test.
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* The split is the point: the instructions are the part a non-author reads,
|
|
25
|
+
* reviews and copies between projects, so they belong in a file that is legible
|
|
26
|
+
* on its own — and the `name` travels WITH that file, so a skill can move
|
|
27
|
+
* without a matching TypeScript wrapper. Tools and `knowledge` stay in code,
|
|
28
|
+
* because they are code.
|
|
29
|
+
*
|
|
30
|
+
* Getting the markdown here is the caller's job (`?raw` under Vite, a build-time
|
|
31
|
+
* import elsewhere) — a Worker has no filesystem to read it from at runtime, so
|
|
32
|
+
* this takes the string rather than a path.
|
|
33
|
+
* @experimental
|
|
34
|
+
*/
|
|
35
|
+
declare const skillFromMarkdown: (markdown: string, extras?: SkillMarkdownExtras) => SkillDefinition;
|
|
36
|
+
export { type SkillMarkdownExtras, skillFromMarkdown };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as o}from"@lunora/errors";import{parse as s}from"yaml";import{defineSkill as l}from"./packem_shared/defineSkill-DfJxCwfZ.mjs";const m=/^\uFEFF?[ \t]*---[ \t]*\r?\n/u,d=/^---[ \t]*$/mu,h=n=>{const r=m.exec(n);if(!r)return{body:n.trim(),data:{}};const t=n.slice(r[0].length),e=d.exec(t);if(!e)throw new o("INTERNAL","@lunora/agent: the skill markdown opens with `---` but never closes the frontmatter block. Add a closing `---` on its own line.");let a;try{a=s(t.slice(0,e.index))}catch(i){throw new o("INTERNAL",`@lunora/agent: the skill markdown has invalid YAML frontmatter — ${i instanceof Error?i.message:String(i)}`)}return{body:t.slice(e.index+e[0].length).trim(),data:typeof a=="object"&&a!==null?a:{}}},c=(n,r={})=>{if(typeof n!="string")throw new o("INTERNAL",`@lunora/agent: skillFromMarkdown expects the markdown SOURCE as a string, got ${typeof n}`);const{body:t,data:e}=h(n);if(e.name!==void 0&&typeof e.name!="string")throw new o("INTERNAL",`@lunora/agent: the skill markdown's \`name\` must be a string, got ${Array.isArray(e.name)?"array":typeof e.name}. Quote it if the value looks like a number or a boolean (\`name: "2fa"\`).`);if(typeof e.name!="string")throw new o("INTERNAL","@lunora/agent: skillFromMarkdown found no `name` in the markdown frontmatter. Open the file with a `---` line, put `name: <identifier>` on its own line, and close it with `---`. Other keys are parsed and ignored — only `name` is read here.");if(t==="")throw new o("INTERNAL",`@lunora/agent: the skill markdown for "${e.name}" has no body — the instructions below the closing \`---\` are what the skill contributes.`);return l({...r,instructions:t,name:e.name})};export{c as skillFromMarkdown};
|
|
@@ -122,6 +122,87 @@ interface ConsoleTelemetryOptions extends CommonOptions {
|
|
|
122
122
|
* @experimental
|
|
123
123
|
*/
|
|
124
124
|
declare const consoleTelemetry: (options?: ConsoleTelemetryOptions) => Telemetry;
|
|
125
|
+
/**
|
|
126
|
+
* Options for {@link otlpTelemetry}.
|
|
127
|
+
* @experimental
|
|
128
|
+
*/
|
|
129
|
+
interface OtlpTelemetryOptions extends CommonOptions {
|
|
130
|
+
/**
|
|
131
|
+
* Conversation / session id to tag each generation span with, emitted as the
|
|
132
|
+
* `gen_ai.conversation.id` semantic-convention attribute so a multi-turn
|
|
133
|
+
* conversation's model turns group in the trace store. On a deployed agent the
|
|
134
|
+
* platform wiring passes the run's `threadKey` here automatically (one thread =
|
|
135
|
+
* one conversation). Omitted → the attribute is absent (backward-compatible),
|
|
136
|
+
* and each turn's span is ungrouped.
|
|
137
|
+
*/
|
|
138
|
+
conversationId?: string;
|
|
139
|
+
/**
|
|
140
|
+
* The OTLP-over-HTTP collector base endpoint (e.g. the Lunora Cloud's `/v1`
|
|
141
|
+
* base). Spans are POSTed to `${endpoint}/v1/traces`; a trailing slash is
|
|
142
|
+
* tolerated. On the platform this is the injected `LUNORA_OTLP_ENDPOINT`.
|
|
143
|
+
*/
|
|
144
|
+
endpoint: string;
|
|
145
|
+
/**
|
|
146
|
+
* Extra headers merged onto every POST — typically the correlation headers
|
|
147
|
+
* the platform injects. `Content-Type: application/json` is set by default.
|
|
148
|
+
*/
|
|
149
|
+
headers?: Record<string, string>;
|
|
150
|
+
/** `service.name` resource attribute on every span. Defaults to `lunora`. */
|
|
151
|
+
serviceName?: string;
|
|
152
|
+
/**
|
|
153
|
+
* Bearer token added as `Authorization: Bearer` (wins over any authorization
|
|
154
|
+
* in `headers`) — the injected `LUNORA_OTLP_TOKEN`. Omit for an
|
|
155
|
+
* unauthenticated collector.
|
|
156
|
+
*/
|
|
157
|
+
token?: string;
|
|
158
|
+
/**
|
|
159
|
+
* Trace id (32-hex) to hang every span of this run under, so one agent run
|
|
160
|
+
* reads as one trace. Pass a stable id derived from the run (e.g. the
|
|
161
|
+
* workflow run id). Omitted → each span mints its own trace id (still valid,
|
|
162
|
+
* just ungrouped).
|
|
163
|
+
*/
|
|
164
|
+
traceId?: string;
|
|
165
|
+
/**
|
|
166
|
+
* The Worker request's `waitUntil`, so a fire-and-forget export survives
|
|
167
|
+
* isolate teardown after the turn returns. Omit and the send degrades to
|
|
168
|
+
* best-effort.
|
|
169
|
+
*/
|
|
170
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* An OTLP-over-HTTP telemetry integration for `@lunora/agent`.
|
|
174
|
+
*
|
|
175
|
+
* The OTLP counterpart to the `sentryTelemetry` / `braintrustTelemetry` bridges:
|
|
176
|
+
* it wraps each language-model call and tool execution in an OTLP **span**
|
|
177
|
+
* (`gen_ai.*` semantic-convention attributes — model, provider, token usage,
|
|
178
|
+
* tool name) and ships it to a collector, so agent generations land in the same
|
|
179
|
+
* trace store as the rest of an app's telemetry (the Lunora Cloud, or any OTel
|
|
180
|
+
* collector). Plug it into `defineAgent({ telemetry: { isEnabled: true,
|
|
181
|
+
* integrations: [otlpTelemetry({ endpoint, token })] } })`.
|
|
182
|
+
*
|
|
183
|
+
* Emitting inside the turn's execution wrapper means one span per **real** turn:
|
|
184
|
+
* the agent loop memoizes each `step.do('llm:turn:N')`, so a Workflow replay
|
|
185
|
+
* returns the cached result without re-invoking `execute`, and no duplicate span
|
|
186
|
+
* is emitted. Privacy-safe by default — `recordInputs`/`recordOutputs` both
|
|
187
|
+
* default `false`, so no prompt or generated text leaves the worker without an
|
|
188
|
+
* explicit opt-in; only structural metadata + token counts are recorded.
|
|
189
|
+
*
|
|
190
|
+
* Each export is fire-and-forget (registered with `waitUntil` when supplied);
|
|
191
|
+
* every rejection is swallowed so a flaky collector never surfaces to the run.
|
|
192
|
+
*
|
|
193
|
+
* Two deliberate differences from the SDK-backed bridges, which delegate to a
|
|
194
|
+
* host tracer. First, no `onError`: a failed call already emits a span with
|
|
195
|
+
* `status.code === 2`, so the failure is on the trace and there is no host client
|
|
196
|
+
* to also notify. Second, flat not nested: every span gets `traceId` (shared when
|
|
197
|
+
* `traceId` is set) but no `parentSpanId`, so model-call and tool spans are
|
|
198
|
+
* siblings under the run rather than a tree — OTLP has no ambient span context to
|
|
199
|
+
* parent to here.
|
|
200
|
+
* @param options `endpoint` (+ optional `token`/`headers`/`serviceName`),
|
|
201
|
+
* `traceId` to group a run's spans, `waitUntil`, and the `recordInputs`/
|
|
202
|
+
* `recordOutputs` privacy flags.
|
|
203
|
+
* @experimental
|
|
204
|
+
*/
|
|
205
|
+
declare const otlpTelemetry: (options: OtlpTelemetryOptions) => Telemetry;
|
|
125
206
|
/**
|
|
126
207
|
* The minimal, **structural** slice of `@sentry/cloudflare` (equivalently
|
|
127
208
|
* `@sentry/node`/`@sentry/browser`) this bridge needs. `@sentry/cloudflare` is
|
|
@@ -170,4 +251,4 @@ interface SentryTelemetryOptions extends CommonOptions {
|
|
|
170
251
|
* @experimental
|
|
171
252
|
*/
|
|
172
253
|
declare const sentryTelemetry: (options: SentryTelemetryOptions) => Telemetry;
|
|
173
|
-
export { type BraintrustLike, type BraintrustSpan, type BraintrustTelemetryOptions, type CommonOptions, type ConsoleLogLevel, type ConsoleLogger, type ConsoleTelemetryOptions, type SentryLike, type SentryTelemetryOptions, braintrustTelemetry, combineTelemetry, consoleTelemetry, sentryTelemetry };
|
|
254
|
+
export { type BraintrustLike, type BraintrustSpan, type BraintrustTelemetryOptions, type CommonOptions, type ConsoleLogLevel, type ConsoleLogger, type ConsoleTelemetryOptions, type OtlpTelemetryOptions, type SentryLike, type SentryTelemetryOptions, braintrustTelemetry, combineTelemetry, consoleTelemetry, otlpTelemetry, sentryTelemetry };
|
|
@@ -122,6 +122,87 @@ interface ConsoleTelemetryOptions extends CommonOptions {
|
|
|
122
122
|
* @experimental
|
|
123
123
|
*/
|
|
124
124
|
declare const consoleTelemetry: (options?: ConsoleTelemetryOptions) => Telemetry;
|
|
125
|
+
/**
|
|
126
|
+
* Options for {@link otlpTelemetry}.
|
|
127
|
+
* @experimental
|
|
128
|
+
*/
|
|
129
|
+
interface OtlpTelemetryOptions extends CommonOptions {
|
|
130
|
+
/**
|
|
131
|
+
* Conversation / session id to tag each generation span with, emitted as the
|
|
132
|
+
* `gen_ai.conversation.id` semantic-convention attribute so a multi-turn
|
|
133
|
+
* conversation's model turns group in the trace store. On a deployed agent the
|
|
134
|
+
* platform wiring passes the run's `threadKey` here automatically (one thread =
|
|
135
|
+
* one conversation). Omitted → the attribute is absent (backward-compatible),
|
|
136
|
+
* and each turn's span is ungrouped.
|
|
137
|
+
*/
|
|
138
|
+
conversationId?: string;
|
|
139
|
+
/**
|
|
140
|
+
* The OTLP-over-HTTP collector base endpoint (e.g. the Lunora Cloud's `/v1`
|
|
141
|
+
* base). Spans are POSTed to `${endpoint}/v1/traces`; a trailing slash is
|
|
142
|
+
* tolerated. On the platform this is the injected `LUNORA_OTLP_ENDPOINT`.
|
|
143
|
+
*/
|
|
144
|
+
endpoint: string;
|
|
145
|
+
/**
|
|
146
|
+
* Extra headers merged onto every POST — typically the correlation headers
|
|
147
|
+
* the platform injects. `Content-Type: application/json` is set by default.
|
|
148
|
+
*/
|
|
149
|
+
headers?: Record<string, string>;
|
|
150
|
+
/** `service.name` resource attribute on every span. Defaults to `lunora`. */
|
|
151
|
+
serviceName?: string;
|
|
152
|
+
/**
|
|
153
|
+
* Bearer token added as `Authorization: Bearer` (wins over any authorization
|
|
154
|
+
* in `headers`) — the injected `LUNORA_OTLP_TOKEN`. Omit for an
|
|
155
|
+
* unauthenticated collector.
|
|
156
|
+
*/
|
|
157
|
+
token?: string;
|
|
158
|
+
/**
|
|
159
|
+
* Trace id (32-hex) to hang every span of this run under, so one agent run
|
|
160
|
+
* reads as one trace. Pass a stable id derived from the run (e.g. the
|
|
161
|
+
* workflow run id). Omitted → each span mints its own trace id (still valid,
|
|
162
|
+
* just ungrouped).
|
|
163
|
+
*/
|
|
164
|
+
traceId?: string;
|
|
165
|
+
/**
|
|
166
|
+
* The Worker request's `waitUntil`, so a fire-and-forget export survives
|
|
167
|
+
* isolate teardown after the turn returns. Omit and the send degrades to
|
|
168
|
+
* best-effort.
|
|
169
|
+
*/
|
|
170
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* An OTLP-over-HTTP telemetry integration for `@lunora/agent`.
|
|
174
|
+
*
|
|
175
|
+
* The OTLP counterpart to the `sentryTelemetry` / `braintrustTelemetry` bridges:
|
|
176
|
+
* it wraps each language-model call and tool execution in an OTLP **span**
|
|
177
|
+
* (`gen_ai.*` semantic-convention attributes — model, provider, token usage,
|
|
178
|
+
* tool name) and ships it to a collector, so agent generations land in the same
|
|
179
|
+
* trace store as the rest of an app's telemetry (the Lunora Cloud, or any OTel
|
|
180
|
+
* collector). Plug it into `defineAgent({ telemetry: { isEnabled: true,
|
|
181
|
+
* integrations: [otlpTelemetry({ endpoint, token })] } })`.
|
|
182
|
+
*
|
|
183
|
+
* Emitting inside the turn's execution wrapper means one span per **real** turn:
|
|
184
|
+
* the agent loop memoizes each `step.do('llm:turn:N')`, so a Workflow replay
|
|
185
|
+
* returns the cached result without re-invoking `execute`, and no duplicate span
|
|
186
|
+
* is emitted. Privacy-safe by default — `recordInputs`/`recordOutputs` both
|
|
187
|
+
* default `false`, so no prompt or generated text leaves the worker without an
|
|
188
|
+
* explicit opt-in; only structural metadata + token counts are recorded.
|
|
189
|
+
*
|
|
190
|
+
* Each export is fire-and-forget (registered with `waitUntil` when supplied);
|
|
191
|
+
* every rejection is swallowed so a flaky collector never surfaces to the run.
|
|
192
|
+
*
|
|
193
|
+
* Two deliberate differences from the SDK-backed bridges, which delegate to a
|
|
194
|
+
* host tracer. First, no `onError`: a failed call already emits a span with
|
|
195
|
+
* `status.code === 2`, so the failure is on the trace and there is no host client
|
|
196
|
+
* to also notify. Second, flat not nested: every span gets `traceId` (shared when
|
|
197
|
+
* `traceId` is set) but no `parentSpanId`, so model-call and tool spans are
|
|
198
|
+
* siblings under the run rather than a tree — OTLP has no ambient span context to
|
|
199
|
+
* parent to here.
|
|
200
|
+
* @param options `endpoint` (+ optional `token`/`headers`/`serviceName`),
|
|
201
|
+
* `traceId` to group a run's spans, `waitUntil`, and the `recordInputs`/
|
|
202
|
+
* `recordOutputs` privacy flags.
|
|
203
|
+
* @experimental
|
|
204
|
+
*/
|
|
205
|
+
declare const otlpTelemetry: (options: OtlpTelemetryOptions) => Telemetry;
|
|
125
206
|
/**
|
|
126
207
|
* The minimal, **structural** slice of `@sentry/cloudflare` (equivalently
|
|
127
208
|
* `@sentry/node`/`@sentry/browser`) this bridge needs. `@sentry/cloudflare` is
|
|
@@ -170,4 +251,4 @@ interface SentryTelemetryOptions extends CommonOptions {
|
|
|
170
251
|
* @experimental
|
|
171
252
|
*/
|
|
172
253
|
declare const sentryTelemetry: (options: SentryTelemetryOptions) => Telemetry;
|
|
173
|
-
export { type BraintrustLike, type BraintrustSpan, type BraintrustTelemetryOptions, type CommonOptions, type ConsoleLogLevel, type ConsoleLogger, type ConsoleTelemetryOptions, type SentryLike, type SentryTelemetryOptions, braintrustTelemetry, combineTelemetry, consoleTelemetry, sentryTelemetry };
|
|
254
|
+
export { type BraintrustLike, type BraintrustSpan, type BraintrustTelemetryOptions, type CommonOptions, type ConsoleLogLevel, type ConsoleLogger, type ConsoleTelemetryOptions, type OtlpTelemetryOptions, type SentryLike, type SentryTelemetryOptions, braintrustTelemetry, combineTelemetry, consoleTelemetry, otlpTelemetry, sentryTelemetry };
|
package/dist/telemetry/index.mjs
CHANGED
|
@@ -1,4 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { combineTelemetry } from '../packem_shared/combineTelemetry-DCyaaWAI.mjs';
|
|
3
|
-
export { consoleTelemetry } from '../packem_shared/consoleTelemetry-z2MiP1jt.mjs';
|
|
4
|
-
export { sentryTelemetry } from '../packem_shared/sentryTelemetry-CgqFJyLO.mjs';
|
|
1
|
+
import{braintrustTelemetry as o}from"../packem_shared/braintrustTelemetry-CnOI5WAw.mjs";import{combineTelemetry as m}from"../packem_shared/combineTelemetry-oLCV_EPV.mjs";import{consoleTelemetry as p}from"../packem_shared/consoleTelemetry-C_85CaZ7.mjs";import{otlpTelemetry as f}from"../packem_shared/otlpTelemetry-DcW9mOLV.mjs";import{sentryTelemetry as T}from"../packem_shared/sentryTelemetry-Dr2aPuvl.mjs";export{o as braintrustTelemetry,m as combineTelemetry,p as consoleTelemetry,f as otlpTelemetry,T as sentryTelemetry};
|
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.51",
|
|
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",
|
|
@@ -62,6 +62,10 @@
|
|
|
62
62
|
"types": "./dist/naming.d.ts",
|
|
63
63
|
"import": "./dist/naming.mjs"
|
|
64
64
|
},
|
|
65
|
+
"./skill-markdown": {
|
|
66
|
+
"types": "./dist/skill-markdown.d.ts",
|
|
67
|
+
"import": "./dist/skill-markdown.mjs"
|
|
68
|
+
},
|
|
65
69
|
"./sandbox": {
|
|
66
70
|
"types": "./dist/sandbox.d.ts",
|
|
67
71
|
"import": "./dist/sandbox.mjs"
|
|
@@ -76,14 +80,15 @@
|
|
|
76
80
|
"access": "public"
|
|
77
81
|
},
|
|
78
82
|
"dependencies": {
|
|
79
|
-
"@lunora/ai": "1.0.0-alpha.
|
|
80
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
81
|
-
"@lunora/mail": "1.0.0-alpha.
|
|
82
|
-
"@lunora/server": "1.0.0-alpha.
|
|
83
|
-
"@lunora/values": "1.0.0-alpha.
|
|
84
|
-
"@lunora/workflow": "1.0.0-alpha.
|
|
83
|
+
"@lunora/ai": "1.0.0-alpha.56",
|
|
84
|
+
"@lunora/errors": "1.0.0-alpha.20",
|
|
85
|
+
"@lunora/mail": "1.0.0-alpha.47",
|
|
86
|
+
"@lunora/server": "1.0.0-alpha.70",
|
|
87
|
+
"@lunora/values": "1.0.0-alpha.25",
|
|
88
|
+
"@lunora/workflow": "1.0.0-alpha.26",
|
|
85
89
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
86
|
-
"ai": "7.0.
|
|
90
|
+
"ai": "7.0.37",
|
|
91
|
+
"yaml": "^2.9.0"
|
|
87
92
|
},
|
|
88
93
|
"engines": {
|
|
89
94
|
"node": "^22.15.0 || >=24.11.0"
|