@axiom-lattice/gateway 2.1.53 → 2.1.55

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.
Files changed (42) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/CHANGELOG.md +19 -0
  3. package/dist/index.js +1043 -526
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +977 -449
  6. package/dist/index.mjs.map +1 -1
  7. package/jest.config.js +5 -0
  8. package/package.json +6 -5
  9. package/src/__tests__/__mocks__/e2b.ts +1 -0
  10. package/src/__tests__/channel-installations.test.ts +199 -0
  11. package/src/__tests__/sandbox-provider-registration.test.ts +74 -0
  12. package/src/__tests__/workspace.test.ts +119 -8
  13. package/src/channels/__tests__/routes.test.ts +71 -0
  14. package/src/channels/lark/README.md +187 -0
  15. package/src/channels/lark/__tests__/aggregator.test.ts +23 -0
  16. package/src/channels/lark/__tests__/controller.test.ts +270 -0
  17. package/src/channels/lark/__tests__/mapping-service.test.ts +118 -0
  18. package/src/channels/lark/__tests__/parser.test.ts +72 -0
  19. package/src/channels/lark/__tests__/sender.test.ts +37 -0
  20. package/src/channels/lark/__tests__/verification.test.ts +157 -0
  21. package/src/channels/lark/aggregator.ts +16 -0
  22. package/src/channels/lark/config.ts +44 -0
  23. package/src/channels/lark/controller.ts +189 -0
  24. package/src/channels/lark/mapping-service.ts +138 -0
  25. package/src/channels/lark/parser.ts +68 -0
  26. package/src/channels/lark/routes.ts +121 -0
  27. package/src/channels/lark/runner.ts +37 -0
  28. package/src/channels/lark/sender.ts +58 -0
  29. package/src/channels/lark/types.ts +33 -0
  30. package/src/channels/lark/verification.ts +67 -0
  31. package/src/channels/routes.ts +25 -0
  32. package/src/controllers/channel-installations.ts +354 -0
  33. package/src/controllers/sandbox.ts +30 -80
  34. package/src/controllers/skills.ts +71 -321
  35. package/src/controllers/threads.ts +8 -6
  36. package/src/controllers/workspace.ts +64 -179
  37. package/src/index.ts +28 -5
  38. package/src/routes/channel-installations.ts +33 -0
  39. package/src/routes/index.ts +6 -0
  40. package/src/schemas/index.ts +2 -2
  41. package/src/services/sandbox_service.ts +21 -21
  42. package/src/services/skill_service.ts +97 -0
@@ -1,4 +1,3 @@
1
- import { Readable } from "stream";
2
1
  import { FastifyInstance } from "fastify";
3
2
  import { sandboxService } from "../services/sandbox_service";
4
3
  import { getSandBoxManager } from "@axiom-lattice/core";
@@ -55,15 +54,15 @@ export function registerSandboxProxyRoutes(app: FastifyInstance): void {
55
54
  const { assistantId, threadId } = request.params;
56
55
  const tenantId = (request.headers["x-tenant-id"] as string) || "default";
57
56
 
58
- const isolatedLevel = sandboxService.getFilesystemIsolatedLevel(tenantId, assistantId);
59
- if (!isolatedLevel) {
57
+ const vmIsolation = sandboxService.getFilesystemVmIsolation(tenantId, assistantId);
58
+ if (!vmIsolation) {
60
59
  return reply.status(500).send({ error: "Assistant sandbox config not found" });
61
60
  }
62
61
 
63
62
  const sandboxName = sandboxService.computeSandboxName(
64
63
  assistantId,
65
64
  threadId,
66
- isolatedLevel
65
+ vmIsolation
67
66
  );
68
67
 
69
68
  const sandboxManager = getSandBoxManager()
@@ -84,20 +83,15 @@ export function registerSandboxProxyRoutes(app: FastifyInstance): void {
84
83
  ? pathEntry
85
84
  : undefined;
86
85
 
87
- const formData = new FormData();
88
- formData.append("file", new Blob([buffer]), data.filename ?? "file");
89
-
90
- const path = `/home/gem/uploads/${pathValue ? pathValue : ""}${data.filename}`;
91
- const uploadResult = await sandbox.file.uploadFile({
92
- file: buffer,
93
- path: path,
94
- })
95
-
96
- if (!uploadResult.ok) {
97
- return reply.status(502).send({ error: `Upload error: ${uploadResult.error}` });
86
+ const filePath = `~/uploads/${pathValue ? pathValue : ""}${data.filename}`;
87
+ try {
88
+ await sandbox.file.uploadFile({ file: filePath, data: buffer });
89
+ } catch (err) {
90
+ reply.status(500).send({ error: String(err) });
91
+ return;
98
92
  }
99
93
 
100
- const relativePath = uploadResult.body?.data?.file_path.replace(`/home/gem`, "");
94
+ const relativePath = filePath.replace(`~/`, "");
101
95
  const result = { id: relativePath, name: data.filename, size: buffer.length };
102
96
 
103
97
  return reply.status(200).send({ message: "File uploaded successfully", ...result });
@@ -123,79 +117,35 @@ export function registerSandboxProxyRoutes(app: FastifyInstance): void {
123
117
  return reply.status(400).send({ error: "Query parameter 'path' is required" });
124
118
  }
125
119
 
126
- const isolatedLevel = sandboxService.getFilesystemIsolatedLevel(tenantId, assistantId);
127
- if (!isolatedLevel) {
128
- return reply.status(500).send({ error: "Assistant filesystem isolated level not found" });
120
+ const vmIsolation = sandboxService.getFilesystemVmIsolation(tenantId, assistantId);
121
+ if (!vmIsolation) {
122
+ return reply.status(500).send({ error: "Assistant filesystem vmIsolation not found" });
129
123
  }
130
124
 
131
125
  const sandboxName = sandboxService.computeSandboxName(
132
126
  assistantId,
133
127
  threadId,
134
- isolatedLevel
128
+ vmIsolation
135
129
  );
136
130
 
137
131
  const sandboxManager = getSandBoxManager();
138
132
  const sandbox = await sandboxManager.createSandbox(sandboxName);
139
133
 
140
134
  try {
141
- // Resolve path: if relative (no leading /), prefix with /home/gem
142
- const resolvedPath = filePath.startsWith("/home/gem") ? filePath : `/home/gem/${filePath.replace(/^\//, "")}`;
135
+ // Resolve path: convert ~/ prefix or relative path to sandbox path
136
+ const resolvedPath = filePath.startsWith("~/") ? filePath : `~/${filePath.replace(/^\//, "")}`;
143
137
  const filename = getFilenameFromPath(resolvedPath);
144
138
  const inferredContentType = getContentTypeFromFilename(filename);
145
139
 
146
- const downloadResult = await sandbox.file.downloadFile({
147
- path: resolvedPath,
148
- });
149
-
150
- if (!downloadResult.ok) {
151
- return reply.status(502).send({
152
- error: `Download error: ${JSON.stringify(downloadResult.error)}`,
153
- });
154
- }
155
-
156
- // Use body.stream() to get ReadableStream and pipe directly (no buffering)
157
- const body = downloadResult.body as unknown as {
158
- stream?: () => ReadableStream<Uint8Array>;
159
- contentType?: string;
160
- contentDisposition?: string;
161
- };
162
- if (typeof body?.stream === "function") {
163
- const webStream = body.stream();
164
- const nodeStream = Readable.fromWeb(webStream);
165
- const contentType = body.contentType ?? inferredContentType;
166
- const contentDisposition =
167
- body.contentDisposition ?? `inline; filename="${filename.replace(/"/g, '\\"')}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
168
- reply = reply.status(200).type(contentType).header("Content-Disposition", contentDisposition).send(nodeStream);
140
+ try {
141
+ const buf = await sandbox.file.downloadFile({ file: resolvedPath });
142
+ const contentDisposition = `inline; filename="${filename.replace(/"/g, '\\"')}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
143
+ reply = reply.status(200).type(inferredContentType).header("Content-Disposition", contentDisposition).send(buf);
169
144
  return reply;
145
+ } catch (err) {
146
+ reply.status(500).send({ error: String(err) });
147
+ return;
170
148
  }
171
-
172
- // Fallback: buffer body when stream is not available
173
- const bodyUnknown = downloadResult.body as unknown;
174
- let buf: Buffer;
175
- let contentType = inferredContentType;
176
- let contentDisposition = `inline; filename="${filename.replace(/"/g, '\\"')}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
177
-
178
- if (bodyUnknown instanceof ArrayBuffer) {
179
- buf = Buffer.from(bodyUnknown);
180
- } else if (bodyUnknown instanceof Buffer) {
181
- buf = bodyUnknown;
182
- } else if (
183
- bodyUnknown &&
184
- typeof (bodyUnknown as { arrayBuffer?: () => Promise<ArrayBuffer> }).arrayBuffer === "function"
185
- ) {
186
- const res = bodyUnknown as { arrayBuffer: () => Promise<ArrayBuffer>; headers?: Headers };
187
- buf = Buffer.from(await res.arrayBuffer());
188
- if (res.headers?.get("content-type")) contentType = res.headers.get("content-type")!;
189
- if (res.headers?.get("content-disposition")) contentDisposition = res.headers.get("content-disposition")!;
190
- } else if (bodyUnknown && typeof (bodyUnknown as { blob?: () => Promise<Blob> }).blob === "function") {
191
- const blob = await (bodyUnknown as { blob: () => Promise<Blob> }).blob();
192
- buf = Buffer.from(await blob.arrayBuffer());
193
- } else {
194
- return reply.status(502).send({ error: "Unexpected download response format" });
195
- }
196
-
197
- reply = reply.status(200).type(contentType).header("Content-Disposition", contentDisposition).send(buf);
198
- return reply;
199
149
  } catch (error: unknown) {
200
150
  const message = error instanceof Error ? error.message : String(error);
201
151
  return reply.status(502).send({ error: `Download proxy error: ${message}` });
@@ -219,11 +169,11 @@ export function registerSandboxProxyRoutes(app: FastifyInstance): void {
219
169
  // return reply.status(404).type("text/html").send(errorHtml);
220
170
  // }
221
171
 
222
- // const { isolatedLevel } = sandboxConfig;
172
+ // const { vmIsolation } = sandboxConfig;
223
173
  // const sandboxName = sandboxService.computeSandboxName(
224
174
  // assistantId,
225
175
  // threadId,
226
- // isolatedLevel
176
+ // vmIsolation
227
177
  // );
228
178
 
229
179
  // try {
@@ -234,7 +184,7 @@ export function registerSandboxProxyRoutes(app: FastifyInstance): void {
234
184
  // const errorHtml = sandboxService.generateErrorHtml(
235
185
  // assistantId,
236
186
  // threadId,
237
- // isolatedLevel,
187
+ // vmIsolation,
238
188
  // error.message || "Failed to connect to sandbox"
239
189
  // );
240
190
  // return reply.status(502).type("text/html").send(errorHtml);
@@ -270,11 +220,11 @@ export function registerSandboxProxyRoutes(app: FastifyInstance): void {
270
220
  // return;
271
221
  // }
272
222
 
273
- // const { isolatedLevel } = sandboxConfig;
223
+ // const { vmIsolation } = sandboxConfig;
274
224
  // const sandboxName = sandboxService.computeSandboxName(
275
225
  // assistantId,
276
226
  // threadId,
277
- // isolatedLevel
227
+ // vmIsolation
278
228
  // );
279
229
 
280
230
  // const targetUrl = sandboxService.getTargetUrl(sandboxName);
@@ -308,11 +258,11 @@ export function registerSandboxProxyRoutes(app: FastifyInstance): void {
308
258
  // return reply.status(404).send("Assistant not found");
309
259
  // }
310
260
 
311
- // const { isolatedLevel } = sandboxConfig;
261
+ // const { vmIsolation } = sandboxConfig;
312
262
  // const sandboxName = sandboxService.computeSandboxName(
313
263
  // assistantId,
314
264
  // threadId,
315
- // isolatedLevel
265
+ // vmIsolation
316
266
  // );
317
267
 
318
268
  // const targetPath = restPath ? `/vnc/${restPath}` : "/vnc/";