@lunora/agent 1.0.0-alpha.6 → 1.0.0-alpha.61
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.d.mts +2 -0
- package/dist/component.d.ts +2 -0
- 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 +38 -8
- package/dist/index.d.ts +38 -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-DPDIzZSY.mjs +1 -0
- package/dist/packem_shared/adaptMcpResult-CVlq-_TO.mjs +2 -0
- package/dist/packem_shared/agentAsTool-DrFnh9UQ.mjs +1 -0
- package/dist/packem_shared/base64-5eyBfWO3.mjs +1 -0
- package/dist/packem_shared/braintrustTelemetry-CoYK-pq7.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-qdwj8j8S.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-DITp-XD6.mjs +1 -0
- package/dist/packem_shared/component-shared-IZozysYq.mjs +1 -0
- package/dist/packem_shared/consoleTelemetry-BZY3Y-Ly.mjs +1 -0
- package/dist/packem_shared/createAgentContext-VYm8bG12.mjs +1 -0
- package/dist/packem_shared/createAgentGenerate-9bZ2YhpN.mjs +3 -0
- package/dist/packem_shared/createDispatchRunner-CH4tZsza-CJeRsY7-.mjs +1 -0
- package/dist/packem_shared/defineAgent-CZdh7y3W.mjs +3 -0
- package/dist/packem_shared/defineSkill-DGGvDWNq.mjs +1 -0
- package/dist/packem_shared/functionTool-D3CP4f8-.mjs +1 -0
- package/dist/packem_shared/memory-JI0lUu84.mjs +1 -0
- package/dist/packem_shared/normalizeEntityName-Ce0X6Afj.mjs +2 -0
- package/dist/packem_shared/otlpTelemetry-yAjOjxn0.mjs +1 -0
- package/dist/packem_shared/runAgentLoop-KUUoFT3r.mjs +3 -0
- package/dist/packem_shared/runVoiceTurn-9zfLZi2_.mjs +1 -0
- package/dist/packem_shared/sandboxComponent-BtOkUYpY.mjs +5 -0
- package/dist/packem_shared/sentryTelemetry-CPqEbFPA.mjs +1 -0
- package/dist/packem_shared/{types.d-boAM2Yi1.d.mts → types.d-eCuvcLzf.d.mts} +211 -21
- package/dist/packem_shared/{types.d-boAM2Yi1.d.ts → types.d-eCuvcLzf.d.ts} +211 -21
- package/dist/packem_shared/voice-turn-CL9QCbEf.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 +136 -1
- package/dist/telemetry/index.d.ts +136 -1
- package/dist/telemetry/index.mjs +1 -4
- package/package.json +18 -9
- 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
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-eCuvcLzf.mjs";
|
|
2
|
+
export type { I as InboundChannelEvent } from "./packem_shared/types.d-eCuvcLzf.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-eCuvcLzf.js";
|
|
2
|
+
export type { I as InboundChannelEvent } from "./packem_shared/types.d-eCuvcLzf.js";
|
|
3
3
|
import '@lunora/mail/inbound';
|
|
4
4
|
import 'ai';
|
|
5
5
|
/**
|
package/dist/channels.mjs
CHANGED
|
@@ -1,181 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const DEFAULT_TIMESTAMP_TOLERANCE = 300;
|
|
4
|
-
const NON_HEX = /[^0-9a-f]/iu;
|
|
5
|
-
const encoder = new TextEncoder();
|
|
6
|
-
const utf8 = (value) => new Uint8Array(encoder.encode(value));
|
|
7
|
-
const hexToBytes = (hex) => {
|
|
8
|
-
if (hex.length % 2 !== 0 || NON_HEX.test(hex)) {
|
|
9
|
-
throw new LunoraError("BAD_REQUEST", "@lunora/agent: malformed hex signature");
|
|
10
|
-
}
|
|
11
|
-
const bytes = new Uint8Array(hex.length / 2);
|
|
12
|
-
for (let index = 0; index < bytes.length; index += 1) {
|
|
13
|
-
bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
|
|
14
|
-
}
|
|
15
|
-
return bytes;
|
|
16
|
-
};
|
|
17
|
-
const verifyHmacSha256 = async (secret, message, signatureHex) => {
|
|
18
|
-
try {
|
|
19
|
-
const key = await crypto.subtle.importKey("raw", utf8(secret), { hash: "SHA-256", name: "HMAC" }, false, ["verify"]);
|
|
20
|
-
return await crypto.subtle.verify("HMAC", key, hexToBytes(signatureHex), utf8(message));
|
|
21
|
-
} catch {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
const isFreshTimestamp = (timestampSeconds, nowSeconds, tolerance) => Number.isFinite(timestampSeconds) && Math.abs(nowSeconds - timestampSeconds) <= tolerance;
|
|
26
|
-
const verifySlack = async (options) => {
|
|
27
|
-
const { body, now = Date.now() / 1e3, signature, signingSecret, timestamp, tolerance = DEFAULT_TIMESTAMP_TOLERANCE } = options;
|
|
28
|
-
if (!signature || !timestamp || !signature.startsWith("v0=")) {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
if (!isFreshTimestamp(Number(timestamp), now, tolerance)) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
return verifyHmacSha256(signingSecret, `v0:${timestamp}:${body}`, signature.slice("v0=".length));
|
|
35
|
-
};
|
|
36
|
-
const verifyGithub = async (options) => {
|
|
37
|
-
const { body, secret, signature } = options;
|
|
38
|
-
if (!signature?.startsWith("sha256=")) {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
return verifyHmacSha256(secret, body, signature.slice("sha256=".length));
|
|
42
|
-
};
|
|
43
|
-
const verifyDiscord = async (options) => {
|
|
44
|
-
const { body, publicKey, signature, timestamp } = options;
|
|
45
|
-
if (!signature || !timestamp) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
try {
|
|
49
|
-
const key = await crypto.subtle.importKey("raw", hexToBytes(publicKey), { name: "Ed25519" }, false, ["verify"]);
|
|
50
|
-
return await crypto.subtle.verify({ name: "Ed25519" }, key, hexToBytes(signature), utf8(timestamp + body));
|
|
51
|
-
} catch {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
const detectChannel = (headers) => {
|
|
56
|
-
if (headers.has("x-slack-signature")) {
|
|
57
|
-
return "slack";
|
|
58
|
-
}
|
|
59
|
-
if (headers.has("x-hub-signature-256")) {
|
|
60
|
-
return "github";
|
|
61
|
-
}
|
|
62
|
-
if (headers.has("x-signature-ed25519")) {
|
|
63
|
-
return "discord";
|
|
64
|
-
}
|
|
65
|
-
return void 0;
|
|
66
|
-
};
|
|
67
|
-
const resolveSecret = (secret, env) => {
|
|
68
|
-
if (typeof secret === "function") {
|
|
69
|
-
return secret(env);
|
|
70
|
-
}
|
|
71
|
-
const value = env[secret];
|
|
72
|
-
return typeof value === "string" ? value : void 0;
|
|
73
|
-
};
|
|
74
|
-
const verifyChannel = async (channel, secret, headers, body) => {
|
|
75
|
-
switch (channel) {
|
|
76
|
-
case "discord": {
|
|
77
|
-
return verifyDiscord({
|
|
78
|
-
body,
|
|
79
|
-
publicKey: secret,
|
|
80
|
-
signature: headers.get("x-signature-ed25519") ?? void 0,
|
|
81
|
-
timestamp: headers.get("x-signature-timestamp") ?? void 0
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
case "github": {
|
|
85
|
-
return verifyGithub({ body, secret, signature: headers.get("x-hub-signature-256") ?? void 0 });
|
|
86
|
-
}
|
|
87
|
-
case "slack": {
|
|
88
|
-
return verifySlack({
|
|
89
|
-
body,
|
|
90
|
-
signature: headers.get("x-slack-signature") ?? void 0,
|
|
91
|
-
signingSecret: secret,
|
|
92
|
-
timestamp: headers.get("x-slack-request-timestamp") ?? void 0
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
default: {
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
const discordPongResponse = (channel, body) => {
|
|
101
|
-
if (channel !== "discord") {
|
|
102
|
-
return void 0;
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
if (JSON.parse(body).type === 1) {
|
|
106
|
-
return Response.json({ type: 1 });
|
|
107
|
-
}
|
|
108
|
-
} catch {
|
|
109
|
-
}
|
|
110
|
-
return void 0;
|
|
111
|
-
};
|
|
112
|
-
const UNSAFE_INSTANCE_ID = /[^\w-]/gu;
|
|
113
|
-
const DUPLICATE_INSTANCE = /already[\s-]?exists/iu;
|
|
114
|
-
const ack = () => new Response(void 0, { status: 200 });
|
|
115
|
-
const isDuplicateInstanceError = (error) => DUPLICATE_INSTANCE.test(error instanceof Error ? error.message : String(error));
|
|
116
|
-
const deliveryId = (channel, headers, body) => {
|
|
117
|
-
if (channel === "github") {
|
|
118
|
-
return headers.get("x-github-delivery") ?? void 0;
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
const parsed = JSON.parse(body);
|
|
122
|
-
const raw = channel === "slack" ? parsed.event_id : parsed.id;
|
|
123
|
-
return typeof raw === "string" ? raw : void 0;
|
|
124
|
-
} catch {
|
|
125
|
-
return void 0;
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
const startChannelRun = async (workflow, run, channel, id) => {
|
|
129
|
-
const sanitizedId = id === void 0 ? "" : id.replaceAll(UNSAFE_INSTANCE_ID, "");
|
|
130
|
-
if (sanitizedId === "") {
|
|
131
|
-
await workflow.create({ params: run });
|
|
132
|
-
return ack();
|
|
133
|
-
}
|
|
134
|
-
try {
|
|
135
|
-
await workflow.create({ id: `${channel}-${sanitizedId}`.slice(0, 60), params: run });
|
|
136
|
-
} catch (error) {
|
|
137
|
-
if (isDuplicateInstanceError(error)) {
|
|
138
|
-
return ack();
|
|
139
|
-
}
|
|
140
|
-
throw error;
|
|
141
|
-
}
|
|
142
|
-
return ack();
|
|
143
|
-
};
|
|
144
|
-
const dispatchAgentChannel = (targets) => async (request, env) => {
|
|
145
|
-
const body = await request.text();
|
|
146
|
-
const channel = detectChannel(request.headers);
|
|
147
|
-
if (channel === void 0) {
|
|
148
|
-
return new Response("Unrecognized webhook", { status: 400 });
|
|
149
|
-
}
|
|
150
|
-
const eligible = targets.map((target) => {
|
|
151
|
-
return { config: target.agent.onInbound, target };
|
|
152
|
-
}).filter((entry) => entry.config?.channel === channel);
|
|
153
|
-
const event = { channel, headers: request.headers, json: () => JSON.parse(body), rawBody: body };
|
|
154
|
-
let verifiedAny = false;
|
|
155
|
-
for (const { config, target } of eligible) {
|
|
156
|
-
const secret = resolveSecret(config.secret, env);
|
|
157
|
-
if (secret === void 0 || !await verifyChannel(channel, secret, request.headers, body)) {
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
verifiedAny = true;
|
|
161
|
-
const pong = discordPongResponse(channel, body);
|
|
162
|
-
if (pong) {
|
|
163
|
-
return pong;
|
|
164
|
-
}
|
|
165
|
-
const run = await config.map(event);
|
|
166
|
-
if (!run) {
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
const workflow = env[target.binding];
|
|
170
|
-
if (!workflow || typeof workflow.create !== "function") {
|
|
171
|
-
throw new LunoraError(
|
|
172
|
-
"INTERNAL",
|
|
173
|
-
`@lunora/agent: no Workflow binding "${target.binding}" on env for an inbound-channel agent — run codegen/dev so wrangler.jsonc declares it`
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
return await startChannelRun(workflow, run, channel, deliveryId(channel, request.headers, body));
|
|
177
|
-
}
|
|
178
|
-
return verifiedAny ? new Response(void 0, { status: 204 }) : new Response("Invalid signature", { status: 401 });
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
export { dispatchAgentChannel, isDuplicateInstanceError, verifyDiscord, verifyGithub, verifySlack };
|
|
1
|
+
import{LunoraError as w}from"@lunora/errors";import{h as b,B as E}from"./packem_shared/branch-marker-boZ00zmk.mjs";const A=300,x=/[^0-9a-f]/iu,N=new TextEncoder,p=t=>new Uint8Array(N.encode(t)),v=t=>{if(t.length%2!==0||x.test(t))throw new w("BAD_REQUEST","@lunora/agent: malformed hex signature");const e=new Uint8Array(t.length/2);for(let n=0;n<e.length;n+=1)e[n]=Number.parseInt(t.slice(n*2,n*2+2),16);return e},m=async(t,e,n)=>{try{const r=await crypto.subtle.importKey("raw",p(t),{hash:"SHA-256",name:"HMAC"},!1,["verify"]);return await crypto.subtle.verify("HMAC",r,v(n),p(e))}catch{return!1}},R=(t,e,n)=>Number.isFinite(t)&&Math.abs(e-t)<=n,S=async t=>{const{body:e,now:n=Date.now()/1e3,signature:r,signingSecret:s,timestamp:a,tolerance:o=A}=t;return!r||!a||!r.startsWith("v0=")||!R(Number(a),n,o)?!1:m(s,`v0:${a}:${e}`,r.slice(3))},k=async t=>{const{body:e,secret:n,signature:r}=t;return r?.startsWith("sha256=")?m(n,e,r.slice(7)):!1},T=async t=>{const{body:e,publicKey:n,signature:r,timestamp:s}=t;if(!r||!s)return!1;try{const a=await crypto.subtle.importKey("raw",v(n),{name:"Ed25519"},!1,["verify"]);return await crypto.subtle.verify({name:"Ed25519"},a,v(r),p(s+e))}catch{return!1}},C=t=>{if(t.has("x-slack-signature"))return"slack";if(t.has("x-hub-signature-256"))return"github";if(t.has("x-signature-ed25519"))return"discord"},I=(t,e)=>{if(typeof t=="function")return t(e);const n=e[t];return typeof n=="string"?n:void 0},_=async(t,e,n,r)=>{switch(t){case"discord":return T({body:r,publicKey:e,signature:n.get("x-signature-ed25519")??void 0,timestamp:n.get("x-signature-timestamp")??void 0});case"github":return k({body:r,secret:e,signature:n.get("x-hub-signature-256")??void 0});case"slack":return S({body:r,signature:n.get("x-slack-signature")??void 0,signingSecret:e,timestamp:n.get("x-slack-request-timestamp")??void 0});default:return!1}},B=(t,e)=>{if(t==="discord")try{if(JSON.parse(e).type===1)return Response.json({type:1})}catch{}},h=t=>t.toString(16).padStart(4,"0"),D=t=>{let e=8997,n=33826,r=40164,s=52210;for(let a=0;a<t.length;a+=1){const o=t.codePointAt(a)??0;e^=o&65535,n^=o>>>16&65535;const c=e*435,i=n*435,d=r*435+e*256,g=s*435+n*256,u=i+(c>>>16),l=d+(u>>>16),f=g+(l>>>16);e=c&65535,n=u&65535,r=l&65535,s=f&65535}return h(s)+h(r)+h(n)+h(e)},H=/already[\s-]?exists/iu,y=()=>new Response(void 0,{status:200}),M=t=>H.test(t instanceof Error?t.message:String(t)),U=(t,e,n)=>{if(t==="github")return e.get("x-github-delivery")??void 0;try{const r=JSON.parse(n),s=t==="slack"?r.event_id:r.id;return typeof s=="string"?s:void 0}catch{return}},O=async(t,e,n,r)=>{if(b(e))throw new w("BAD_REQUEST",`@lunora/agent: inbound channel run params ${E}`);if(r===void 0||r==="")return await t.create({params:e}),y();try{await t.create({id:`${n}-${D(r)}`,params:e})}catch(s){if(M(s))return y();throw s}return y()},L=t=>async(e,n)=>{const r=await e.text(),s=C(e.headers);if(s===void 0)return new Response("Unrecognized webhook",{status:400});const a=t.map(i=>({config:i.agent.onInbound,target:i})).filter(i=>i.config?.channel===s),o={channel:s,headers:e.headers,json:()=>JSON.parse(r),rawBody:r};let c=!1;for(const{config:i,target:d}of a){const g=I(i.secret,n);if(g===void 0||!await _(s,g,e.headers,r))continue;c=!0;const u=B(s,r);if(u)return u;const l=await i.map(o);if(!l)continue;const f=n[d.binding];if(!f||typeof f.create!="function")throw new w("INTERNAL",`@lunora/agent: no Workflow binding "${d.binding}" on env for an inbound-channel agent — run codegen/dev so wrangler.jsonc declares it`);return await O(f,l,s,U(s,e.headers,r))}return c?new Response(void 0,{status:204}):new Response("Invalid signature",{status:401})};export{L as dispatchAgentChannel,M as isDuplicateInstanceError,T as verifyDiscord,k as verifyGithub,S as verifySlack};
|
package/dist/component.d.mts
CHANGED
|
@@ -72,6 +72,8 @@ interface AgentComponent {
|
|
|
72
72
|
extension: SchemaExtension;
|
|
73
73
|
functions: {
|
|
74
74
|
agentAppendMessage: AgentRegisteredFunction;
|
|
75
|
+
agentCompleteRun: AgentRegisteredFunction;
|
|
76
|
+
agentDeleteMessage: AgentRegisteredFunction;
|
|
75
77
|
agentEnsureThread: AgentRegisteredFunction;
|
|
76
78
|
agentEpisodeRecall: AgentRegisteredFunction;
|
|
77
79
|
agentEpisodeUpsert: AgentRegisteredFunction;
|
package/dist/component.d.ts
CHANGED
|
@@ -72,6 +72,8 @@ interface AgentComponent {
|
|
|
72
72
|
extension: SchemaExtension;
|
|
73
73
|
functions: {
|
|
74
74
|
agentAppendMessage: AgentRegisteredFunction;
|
|
75
|
+
agentCompleteRun: AgentRegisteredFunction;
|
|
76
|
+
agentDeleteMessage: AgentRegisteredFunction;
|
|
75
77
|
agentEnsureThread: AgentRegisteredFunction;
|
|
76
78
|
agentEpisodeRecall: AgentRegisteredFunction;
|
|
77
79
|
agentEpisodeUpsert: AgentRegisteredFunction;
|