@lunora/agent 0.0.0 → 1.0.0-alpha.1
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/LICENSE.md +105 -0
- package/README.md +48 -43
- package/dist/channels.d.mts +54 -0
- package/dist/channels.d.ts +54 -0
- package/dist/channels.mjs +181 -0
- package/dist/component.d.mts +101 -0
- package/dist/component.d.ts +101 -0
- package/dist/component.mjs +407 -0
- package/dist/inbound.d.mts +29 -0
- package/dist/inbound.d.ts +29 -0
- package/dist/inbound.mjs +32 -0
- package/dist/index.d.mts +740 -0
- package/dist/index.d.ts +740 -0
- package/dist/index.mjs +18 -0
- package/dist/naming.d.mts +17 -0
- package/dist/naming.d.ts +17 -0
- package/dist/naming.mjs +8 -0
- package/dist/packem_shared/AGENT_MODULE-Dnt_-AAT.mjs +24 -0
- package/dist/packem_shared/VoiceSessionDO-DLoXsHGF.mjs +297 -0
- package/dist/packem_shared/adaptMcpResult-wtNMvLoP.mjs +65 -0
- package/dist/packem_shared/agentAsTool-Dt8NlU6k.mjs +94 -0
- package/dist/packem_shared/base64-BVwtgRJV.mjs +18 -0
- package/dist/packem_shared/braintrustTelemetry-wuGDErob.mjs +47 -0
- package/dist/packem_shared/buildModelMessages-BWFigaoo.mjs +69 -0
- package/dist/packem_shared/codeTool-CjgJOC9t.mjs +122 -0
- package/dist/packem_shared/collectAgenticMemoryTools-QrzpV-WX.mjs +97 -0
- package/dist/packem_shared/combineTelemetry-DCyaaWAI.mjs +43 -0
- package/dist/packem_shared/common-DAeFCot5.mjs +61 -0
- package/dist/packem_shared/compileAgentWorkflow-BxJjHgtD.mjs +55 -0
- package/dist/packem_shared/consoleTelemetry-z2MiP1jt.mjs +93 -0
- package/dist/packem_shared/createAgentContext-4xJGXNR4.mjs +50 -0
- package/dist/packem_shared/createAgentGenerate-BQv9YJ01.mjs +192 -0
- package/dist/packem_shared/createDispatchRunner-DSbp_dph-ZHTtxy3f.mjs +69 -0
- package/dist/packem_shared/defineAgent-D6maSbVc.mjs +148 -0
- package/dist/packem_shared/defineSkill-Ctf_S-rz.mjs +22 -0
- package/dist/packem_shared/functionTool-D6lCa2jB.mjs +20 -0
- package/dist/packem_shared/graph-component-aoUwO-f0.mjs +216 -0
- package/dist/packem_shared/memory-D4FPcBsX.mjs +12 -0
- package/dist/packem_shared/normalizeEntityName-CyEEWFkR.mjs +3 -0
- package/dist/packem_shared/runAgentLoop-Dhg4ZNvw.mjs +493 -0
- package/dist/packem_shared/runVoiceTurn-LnqLvCRR.mjs +211 -0
- package/dist/packem_shared/sandboxComponent-DR3pTwBL.mjs +194 -0
- package/dist/packem_shared/sentryTelemetry-CgqFJyLO.mjs +36 -0
- package/dist/packem_shared/types.d-BWG0uUtX.d.mts +1015 -0
- package/dist/packem_shared/types.d-BWG0uUtX.d.ts +1015 -0
- package/dist/sandbox.d.mts +185 -0
- package/dist/sandbox.d.ts +185 -0
- package/dist/sandbox.mjs +109 -0
- package/dist/telemetry/index.d.mts +150 -0
- package/dist/telemetry/index.d.ts +150 -0
- package/dist/telemetry/index.mjs +4 -0
- package/package.json +88 -7
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
import { initLunora } from '@lunora/server';
|
|
3
|
+
import { v } from '@lunora/values';
|
|
4
|
+
import { t as toBase64 } from './base64-BVwtgRJV.mjs';
|
|
5
|
+
|
|
6
|
+
const { internalAction } = initLunora.dataModel().create();
|
|
7
|
+
const sandboxScrapeDocument = () => globalThis.document?.documentElement?.outerHTML ?? "";
|
|
8
|
+
const MAX_FS_BYTES = 1e6;
|
|
9
|
+
const MAX_LS_PAGES = 20;
|
|
10
|
+
const fsEncoder = new TextEncoder();
|
|
11
|
+
const runBrowserOp = async (browser, request) => {
|
|
12
|
+
const url = request.url ?? "";
|
|
13
|
+
switch (request.op) {
|
|
14
|
+
case "content": {
|
|
15
|
+
return browser.content(url);
|
|
16
|
+
}
|
|
17
|
+
case "pdf": {
|
|
18
|
+
return { data: toBase64(await browser.pdf(url)), encoding: "base64", mediaType: "application/pdf" };
|
|
19
|
+
}
|
|
20
|
+
case "scrape": {
|
|
21
|
+
return browser.scrape(url, sandboxScrapeDocument);
|
|
22
|
+
}
|
|
23
|
+
case "screenshot": {
|
|
24
|
+
const bytes = await browser.screenshot(url, {
|
|
25
|
+
...request.fullPage === void 0 ? {} : { fullPage: request.fullPage },
|
|
26
|
+
...request.type === void 0 ? {} : { type: request.type }
|
|
27
|
+
});
|
|
28
|
+
return { data: toBase64(bytes), encoding: "base64", mediaType: request.type === "jpeg" ? "image/jpeg" : "image/png" };
|
|
29
|
+
}
|
|
30
|
+
default: {
|
|
31
|
+
throw new LunoraError("INTERNAL", `@lunora/agent: sandbox browser op "${request.op}" is not supported`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const runContainerOp = async (accessor, request) => {
|
|
36
|
+
const handle = accessor.any();
|
|
37
|
+
if (request.op === "exec") {
|
|
38
|
+
const response = await handle.fetch("/exec", {
|
|
39
|
+
body: JSON.stringify({ args: request.args ?? [], command: request.command ?? "" }),
|
|
40
|
+
headers: { "content-type": "application/json" },
|
|
41
|
+
method: "POST"
|
|
42
|
+
});
|
|
43
|
+
return response.text();
|
|
44
|
+
}
|
|
45
|
+
if (request.op === "fetch") {
|
|
46
|
+
const response = await handle.fetch(request.path ?? "/", {
|
|
47
|
+
...request.body === void 0 ? {} : { body: request.body },
|
|
48
|
+
method: request.method ?? "GET"
|
|
49
|
+
});
|
|
50
|
+
return response.text();
|
|
51
|
+
}
|
|
52
|
+
throw new LunoraError("INTERNAL", `@lunora/agent: sandbox container op "${request.op}" is not supported`);
|
|
53
|
+
};
|
|
54
|
+
const trimSlashes = (value) => {
|
|
55
|
+
let start = 0;
|
|
56
|
+
let end = value.length;
|
|
57
|
+
while (start < end && value[start] === "/") {
|
|
58
|
+
start += 1;
|
|
59
|
+
}
|
|
60
|
+
while (end > start && value[end - 1] === "/") {
|
|
61
|
+
end -= 1;
|
|
62
|
+
}
|
|
63
|
+
return value.slice(start, end);
|
|
64
|
+
};
|
|
65
|
+
const resolveFsKey = (root, path) => {
|
|
66
|
+
const base = trimSlashes(root);
|
|
67
|
+
const segments = [];
|
|
68
|
+
for (const segment of path.split("/")) {
|
|
69
|
+
if (segment === "" || segment === ".") {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (segment === "..") {
|
|
73
|
+
if (segments.length === 0) {
|
|
74
|
+
throw new LunoraError("BAD_REQUEST", "@lunora/agent: fs path escapes the sandbox root");
|
|
75
|
+
}
|
|
76
|
+
segments.pop();
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
segments.push(segment);
|
|
80
|
+
}
|
|
81
|
+
const relative = segments.join("/");
|
|
82
|
+
return base && relative ? `${base}/${relative}` : base || relative;
|
|
83
|
+
};
|
|
84
|
+
const listFsEntries = async (bucket, key, base) => {
|
|
85
|
+
const prefix = key.length > 0 ? `${key}/` : "";
|
|
86
|
+
const strip = base.length > 0 ? base.length + 1 : 0;
|
|
87
|
+
const entries = [];
|
|
88
|
+
let cursor;
|
|
89
|
+
for (let page = 0; page < MAX_LS_PAGES; page += 1) {
|
|
90
|
+
const result = await bucket.list({ prefix, ...cursor === void 0 ? {} : { cursor } });
|
|
91
|
+
for (const object of result.objects) {
|
|
92
|
+
entries.push(object.key.slice(strip));
|
|
93
|
+
}
|
|
94
|
+
if (!result.truncated || result.cursor === void 0) {
|
|
95
|
+
return { entries, truncated: false };
|
|
96
|
+
}
|
|
97
|
+
cursor = result.cursor;
|
|
98
|
+
}
|
|
99
|
+
return { entries, truncated: true };
|
|
100
|
+
};
|
|
101
|
+
const runFsOp = async (bucket, root, request) => {
|
|
102
|
+
const base = trimSlashes(root);
|
|
103
|
+
const key = resolveFsKey(root, request.path ?? "");
|
|
104
|
+
switch (request.op) {
|
|
105
|
+
case "ls": {
|
|
106
|
+
const { entries, truncated } = await listFsEntries(bucket, key, base);
|
|
107
|
+
return truncated ? { entries, truncated: true } : { entries };
|
|
108
|
+
}
|
|
109
|
+
case "read": {
|
|
110
|
+
const head = await bucket.head(key);
|
|
111
|
+
if (head && head.size > MAX_FS_BYTES) {
|
|
112
|
+
throw new LunoraError(
|
|
113
|
+
"BAD_REQUEST",
|
|
114
|
+
`@lunora/agent: fs read: "${request.path ?? ""}" is ${String(head.size)} bytes (max ${String(MAX_FS_BYTES)})`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
const object = await bucket.get(key);
|
|
118
|
+
if (!object) {
|
|
119
|
+
throw new LunoraError("NOT_FOUND", `@lunora/agent: fs read: no file at "${request.path ?? ""}"`);
|
|
120
|
+
}
|
|
121
|
+
return object.text();
|
|
122
|
+
}
|
|
123
|
+
case "rm": {
|
|
124
|
+
await bucket.delete(key);
|
|
125
|
+
return { path: request.path ?? "", removed: true };
|
|
126
|
+
}
|
|
127
|
+
case "stat": {
|
|
128
|
+
const head = await bucket.head(key);
|
|
129
|
+
return head ? { exists: true, size: head.size } : { exists: false };
|
|
130
|
+
}
|
|
131
|
+
case "write": {
|
|
132
|
+
const content = request.content ?? "";
|
|
133
|
+
const bytes = fsEncoder.encode(content).length;
|
|
134
|
+
if (bytes > MAX_FS_BYTES) {
|
|
135
|
+
throw new LunoraError("BAD_REQUEST", `@lunora/agent: fs write: ${String(bytes)} bytes exceeds the max (${String(MAX_FS_BYTES)})`);
|
|
136
|
+
}
|
|
137
|
+
await bucket.put(key, content);
|
|
138
|
+
return { bytes, path: request.path ?? "", wrote: true };
|
|
139
|
+
}
|
|
140
|
+
default: {
|
|
141
|
+
throw new LunoraError("INTERNAL", `@lunora/agent: sandbox fs op "${request.op}" is not supported`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const sandboxComponent = () => {
|
|
146
|
+
const invoke = internalAction.input({
|
|
147
|
+
args: v.optional(v.array(v.string())),
|
|
148
|
+
body: v.optional(v.string()),
|
|
149
|
+
bucket: v.optional(v.string()),
|
|
150
|
+
command: v.optional(v.string()),
|
|
151
|
+
content: v.optional(v.string()),
|
|
152
|
+
fullPage: v.optional(v.boolean()),
|
|
153
|
+
kind: v.union(v.literal("browser"), v.literal("container"), v.literal("fs")),
|
|
154
|
+
method: v.optional(v.string()),
|
|
155
|
+
name: v.optional(v.string()),
|
|
156
|
+
op: v.string(),
|
|
157
|
+
path: v.optional(v.string()),
|
|
158
|
+
root: v.optional(v.string()),
|
|
159
|
+
selector: v.optional(v.string()),
|
|
160
|
+
type: v.optional(v.string()),
|
|
161
|
+
url: v.optional(v.string())
|
|
162
|
+
}).action(async ({ args, ctx: context }) => {
|
|
163
|
+
const surface = context;
|
|
164
|
+
const request = args;
|
|
165
|
+
if (request.kind === "browser") {
|
|
166
|
+
if (!surface.browser) {
|
|
167
|
+
throw new LunoraError("INTERNAL", "@lunora/agent: sandbox browser op needs `ctx.browser` — install @lunora/browser and run codegen");
|
|
168
|
+
}
|
|
169
|
+
return runBrowserOp(surface.browser, request);
|
|
170
|
+
}
|
|
171
|
+
if (request.kind === "fs") {
|
|
172
|
+
const bucket = surface.env?.[request.bucket ?? ""];
|
|
173
|
+
if (!bucket || typeof bucket.get !== "function") {
|
|
174
|
+
throw new LunoraError(
|
|
175
|
+
"INTERNAL",
|
|
176
|
+
`@lunora/agent: sandbox fs op found no R2 bucket "${request.bucket ?? ""}" on env — declare the r2_bucket binding in wrangler.jsonc and run codegen`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
return runFsOp(bucket, request.root ?? "", request);
|
|
180
|
+
}
|
|
181
|
+
const name = request.name ?? "";
|
|
182
|
+
const accessor = surface.containers?.[name];
|
|
183
|
+
if (!accessor) {
|
|
184
|
+
throw new LunoraError(
|
|
185
|
+
"INTERNAL",
|
|
186
|
+
`@lunora/agent: sandbox container op found no ctx.containers["${name}"] — declare the container in lunora/containers.ts and run codegen`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
return runContainerOp(accessor, request);
|
|
190
|
+
});
|
|
191
|
+
return { invoke };
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export { resolveFsKey, runFsOp, sandboxComponent };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { r as readField, t as toolInputOf } from './common-DAeFCot5.mjs';
|
|
2
|
+
|
|
3
|
+
const stringOr = (value, fallback) => typeof value === "string" && value.length > 0 ? value : fallback;
|
|
4
|
+
const sentryTelemetry = (options) => {
|
|
5
|
+
const { functionId, recordInputs = false, Sentry: sentry } = options;
|
|
6
|
+
return {
|
|
7
|
+
executeLanguageModelCall: (options_) => {
|
|
8
|
+
const attributes = {
|
|
9
|
+
"gen_ai.operation.name": stringOr(functionId, "language_model_call"),
|
|
10
|
+
"gen_ai.request.model": readField(options_, "modelId"),
|
|
11
|
+
"gen_ai.system": readField(options_, "provider")
|
|
12
|
+
};
|
|
13
|
+
if (recordInputs) {
|
|
14
|
+
attributes["gen_ai.prompt"] = readField(options_, "messages");
|
|
15
|
+
}
|
|
16
|
+
return sentry.startSpan({ attributes, name: stringOr(functionId, "language_model_call"), op: "gen_ai.generate" }, () => options_.execute());
|
|
17
|
+
},
|
|
18
|
+
executeTool: (options_) => {
|
|
19
|
+
const toolName = readField(readField(options_, "toolCall"), "toolName");
|
|
20
|
+
const attributes = {
|
|
21
|
+
"gen_ai.operation.name": "execute_tool",
|
|
22
|
+
"gen_ai.tool.call.id": readField(options_, "toolCallId"),
|
|
23
|
+
"gen_ai.tool.name": toolName
|
|
24
|
+
};
|
|
25
|
+
if (recordInputs) {
|
|
26
|
+
attributes["gen_ai.tool.input"] = toolInputOf(options_);
|
|
27
|
+
}
|
|
28
|
+
return sentry.startSpan({ attributes, name: `execute_tool ${stringOr(toolName, "tool")}`, op: "gen_ai.execute_tool" }, () => options_.execute());
|
|
29
|
+
},
|
|
30
|
+
onError: (error) => {
|
|
31
|
+
sentry.captureException(error);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export { sentryTelemetry };
|