@axiom-lattice/gateway 2.1.116 → 3.0.0
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/.turbo/turbo-build.log +15 -15
- package/CHANGELOG.md +37 -0
- package/dist/{a2a-ERG5RMUW.mjs → a2a-QMHEH3ZT.mjs} +77 -29
- package/dist/a2a-QMHEH3ZT.mjs.map +1 -0
- package/dist/index.js +1144 -177
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1013 -92
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -5
- package/src/__tests__/a2a.test.ts +82 -0
- package/src/__tests__/workspace.test.ts +13 -3
- package/src/config/local-a2a-templates.ts +59 -0
- package/src/controllers/__tests__/assistant-local-a2a.test.ts +147 -0
- package/src/controllers/__tests__/local-a2a-templates.test.ts +112 -0
- package/src/controllers/assistant.ts +126 -4
- package/src/controllers/local-a2a-templates.ts +18 -0
- package/src/controllers/local-a2a.ts +149 -0
- package/src/controllers/tasks.ts +2 -3
- package/src/controllers/workspace.ts +144 -17
- package/src/index.ts +2 -10
- package/src/routes/__tests__/a2a-test-connection.test.ts +177 -0
- package/src/routes/a2a-test-connection.ts +126 -0
- package/src/routes/a2a.ts +100 -28
- package/src/routes/index.ts +27 -0
- package/src/routes/stt.ts +102 -0
- package/src/services/__tests__/local-a2a.test.ts +124 -0
- package/src/services/eval-runner.ts +6 -0
- package/src/services/local-a2a.ts +352 -0
- package/src/utils/__tests__/local-a2a-runtime.test.ts +77 -0
- package/src/utils/__tests__/path-containment.test.ts +35 -0
- package/src/utils/a2a-url.ts +20 -0
- package/src/utils/local-a2a-runtime.ts +107 -0
- package/src/utils/path-containment.ts +38 -0
- package/dist/a2a-ERG5RMUW.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -12,19 +12,386 @@ import {
|
|
|
12
12
|
} from "./chunk-LHQY46YB.mjs";
|
|
13
13
|
|
|
14
14
|
// src/index.ts
|
|
15
|
+
import "dotenv/config";
|
|
15
16
|
import fastify from "fastify";
|
|
16
17
|
import cors from "@fastify/cors";
|
|
17
18
|
import multipart from "@fastify/multipart";
|
|
18
19
|
import sensible from "@fastify/sensible";
|
|
19
20
|
import websocket from "@fastify/websocket";
|
|
20
21
|
import staticPlugin from "@fastify/static";
|
|
21
|
-
import
|
|
22
|
+
import path3 from "path";
|
|
22
23
|
import { fileURLToPath } from "url";
|
|
23
24
|
|
|
24
25
|
// src/controllers/assistant.ts
|
|
25
26
|
import { agentInstanceManager, getStoreLattice } from "@axiom-lattice/core";
|
|
27
|
+
import { AgentType } from "@axiom-lattice/protocols";
|
|
26
28
|
import { randomUUID } from "crypto";
|
|
27
29
|
import { agentLatticeManager, eventBus } from "@axiom-lattice/core";
|
|
30
|
+
|
|
31
|
+
// src/services/local-a2a.ts
|
|
32
|
+
import { spawn } from "child_process";
|
|
33
|
+
import { existsSync, statSync } from "fs";
|
|
34
|
+
import { dirname, join, parse, resolve } from "path";
|
|
35
|
+
import { setTimeout as delay } from "timers/promises";
|
|
36
|
+
var STDERR_TAIL_LIMIT = 4096;
|
|
37
|
+
function readBooleanEnv(name, defaultValue, env = process.env) {
|
|
38
|
+
const value = env[name];
|
|
39
|
+
if (value === void 0) return defaultValue;
|
|
40
|
+
return value === "1" || value.toLowerCase() === "true";
|
|
41
|
+
}
|
|
42
|
+
function findWorkspaceRoot(startDir) {
|
|
43
|
+
let current = resolve(startDir);
|
|
44
|
+
const { root } = parse(current);
|
|
45
|
+
while (current !== root) {
|
|
46
|
+
if (existsSync(join(current, "pnpm-workspace.yaml"))) {
|
|
47
|
+
return current;
|
|
48
|
+
}
|
|
49
|
+
const parent = dirname(current);
|
|
50
|
+
if (parent === current) return null;
|
|
51
|
+
current = parent;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function resolveLocalA2AWorkingDirectory(options) {
|
|
55
|
+
if (options.envWorkdir) return options.envWorkdir;
|
|
56
|
+
if (options.commandCwd) return options.commandCwd;
|
|
57
|
+
return findWorkspaceRoot(options.currentCwd) || options.currentCwd;
|
|
58
|
+
}
|
|
59
|
+
function validateWorkingDirectory(cwd) {
|
|
60
|
+
try {
|
|
61
|
+
const stat2 = statSync(cwd);
|
|
62
|
+
if (!stat2.isDirectory()) {
|
|
63
|
+
return `Working directory is not a directory: ${cwd}`;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
68
|
+
return `Working directory is not accessible: ${cwd} (${message})`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function appendStderrTail(current, chunk) {
|
|
72
|
+
const next = `${current}${chunk}`;
|
|
73
|
+
if (next.length <= STDERR_TAIL_LIMIT) return next;
|
|
74
|
+
return next.slice(-STDERR_TAIL_LIMIT);
|
|
75
|
+
}
|
|
76
|
+
function formatExitMessage(exitReason, stderrTail) {
|
|
77
|
+
const stderr = stderrTail.trim();
|
|
78
|
+
return stderr ? `Exited before becoming ready (${exitReason}): ${stderr}` : `Exited before becoming ready (${exitReason})`;
|
|
79
|
+
}
|
|
80
|
+
async function probeReady(agentCardUrl, healthUrl, timeoutMs) {
|
|
81
|
+
const controller = new AbortController();
|
|
82
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
83
|
+
try {
|
|
84
|
+
if (healthUrl) {
|
|
85
|
+
const resp = await fetch(healthUrl, { signal: controller.signal });
|
|
86
|
+
if (!resp.ok) return false;
|
|
87
|
+
}
|
|
88
|
+
const cardResp = await fetch(agentCardUrl, { signal: controller.signal });
|
|
89
|
+
return cardResp.ok;
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
} finally {
|
|
93
|
+
clearTimeout(timer);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
var _LocalA2AService = class _LocalA2AService {
|
|
97
|
+
constructor() {
|
|
98
|
+
this.states = /* @__PURE__ */ new Map();
|
|
99
|
+
this.autoStartEnabled = readBooleanEnv("LOCAL_A2A_AUTO_START", true);
|
|
100
|
+
}
|
|
101
|
+
static getInstance() {
|
|
102
|
+
if (!_LocalA2AService.instance) {
|
|
103
|
+
_LocalA2AService.instance = new _LocalA2AService();
|
|
104
|
+
}
|
|
105
|
+
return _LocalA2AService.instance;
|
|
106
|
+
}
|
|
107
|
+
getOrCreateState(runtimeId, localRuntime) {
|
|
108
|
+
let state = this.states.get(runtimeId);
|
|
109
|
+
if (!state) {
|
|
110
|
+
state = {
|
|
111
|
+
runtimeId,
|
|
112
|
+
label: localRuntime.label || runtimeId,
|
|
113
|
+
status: this.autoStartEnabled ? "stopped" : "disabled",
|
|
114
|
+
enabled: this.autoStartEnabled,
|
|
115
|
+
assistantId: runtimeId,
|
|
116
|
+
agentCardUrl: localRuntime.agentCardUrl,
|
|
117
|
+
healthUrl: localRuntime.healthUrl,
|
|
118
|
+
localRuntime
|
|
119
|
+
};
|
|
120
|
+
this.states.set(runtimeId, state);
|
|
121
|
+
} else {
|
|
122
|
+
state.localRuntime = localRuntime;
|
|
123
|
+
state.label = localRuntime.label || state.label;
|
|
124
|
+
state.agentCardUrl = localRuntime.agentCardUrl;
|
|
125
|
+
state.healthUrl = localRuntime.healthUrl;
|
|
126
|
+
}
|
|
127
|
+
return state;
|
|
128
|
+
}
|
|
129
|
+
async getRegisteredState(runtimeId, localRuntime) {
|
|
130
|
+
const state = this.getOrCreateState(runtimeId, localRuntime);
|
|
131
|
+
if (state.process && state.status === "running") {
|
|
132
|
+
const alive = await probeReady(
|
|
133
|
+
localRuntime.agentCardUrl,
|
|
134
|
+
localRuntime.healthUrl,
|
|
135
|
+
2e3
|
|
136
|
+
);
|
|
137
|
+
if (!alive) {
|
|
138
|
+
state.process = void 0;
|
|
139
|
+
state.pid = void 0;
|
|
140
|
+
state.status = "stopped";
|
|
141
|
+
state.message = "Process exited unexpectedly";
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return this.snapshotState(state);
|
|
145
|
+
}
|
|
146
|
+
async startProvider(runtimeId, localRuntime) {
|
|
147
|
+
const state = this.getOrCreateState(runtimeId, localRuntime);
|
|
148
|
+
if (!state.enabled) {
|
|
149
|
+
state.status = "disabled";
|
|
150
|
+
state.message = "Disabled by configuration";
|
|
151
|
+
return this.snapshotState(state);
|
|
152
|
+
}
|
|
153
|
+
if (state.process && state.status === "running") {
|
|
154
|
+
return this.snapshotState(state);
|
|
155
|
+
}
|
|
156
|
+
state.enabled = true;
|
|
157
|
+
const { executable, args, cwd, env: cmdEnv } = localRuntime.command;
|
|
158
|
+
const resolvedCwd = resolveLocalA2AWorkingDirectory({
|
|
159
|
+
envWorkdir: process.env.LOCAL_A2A_WORKDIR || void 0,
|
|
160
|
+
commandCwd: cwd,
|
|
161
|
+
currentCwd: process.cwd()
|
|
162
|
+
});
|
|
163
|
+
const cwdError = validateWorkingDirectory(resolvedCwd);
|
|
164
|
+
if (cwdError) {
|
|
165
|
+
state.process = void 0;
|
|
166
|
+
state.pid = void 0;
|
|
167
|
+
state.status = "failed";
|
|
168
|
+
state.message = cwdError;
|
|
169
|
+
return this.snapshotState(state);
|
|
170
|
+
}
|
|
171
|
+
state.status = "starting";
|
|
172
|
+
state.message = "Starting";
|
|
173
|
+
let stderrTail = "";
|
|
174
|
+
const childEnv = cmdEnv ? { ...process.env, ...cmdEnv } : process.env;
|
|
175
|
+
const child = spawn(executable, args, {
|
|
176
|
+
cwd: resolvedCwd,
|
|
177
|
+
env: childEnv,
|
|
178
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
179
|
+
shell: false
|
|
180
|
+
});
|
|
181
|
+
state.process = child;
|
|
182
|
+
state.pid = child.pid ?? void 0;
|
|
183
|
+
child.once("error", (error) => {
|
|
184
|
+
const current = this.states.get(runtimeId);
|
|
185
|
+
if (!current) return;
|
|
186
|
+
current.process = void 0;
|
|
187
|
+
current.pid = void 0;
|
|
188
|
+
current.status = "failed";
|
|
189
|
+
const stderr = stderrTail.trim();
|
|
190
|
+
current.message = stderr ? `Failed to start: ${error.message}: ${stderr}` : `Failed to start: ${error.message}`;
|
|
191
|
+
});
|
|
192
|
+
child.stdout.on("data", (chunk) => {
|
|
193
|
+
const text = chunk.toString("utf8").trim();
|
|
194
|
+
if (text) console.log(`[local-a2a:${runtimeId}] ${text}`);
|
|
195
|
+
});
|
|
196
|
+
child.stderr.on("data", (chunk) => {
|
|
197
|
+
const rawText = chunk.toString("utf8");
|
|
198
|
+
stderrTail = appendStderrTail(stderrTail, rawText);
|
|
199
|
+
const text = rawText.trim();
|
|
200
|
+
if (text) console.error(`[local-a2a:${runtimeId}] ${text}`);
|
|
201
|
+
});
|
|
202
|
+
child.on("close", (code, signal) => {
|
|
203
|
+
const current = this.states.get(runtimeId);
|
|
204
|
+
if (!current) return;
|
|
205
|
+
current.process = void 0;
|
|
206
|
+
current.pid = void 0;
|
|
207
|
+
const exitReason = signal ?? code ?? "unknown";
|
|
208
|
+
if (current.status === "running") {
|
|
209
|
+
current.status = "stopped";
|
|
210
|
+
current.message = `Stopped (${exitReason})`;
|
|
211
|
+
} else if (current.status === "starting") {
|
|
212
|
+
current.status = "failed";
|
|
213
|
+
current.message = formatExitMessage(exitReason, stderrTail);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
const ready = await this.waitUntilReady(localRuntime, state, 15e3);
|
|
217
|
+
if (!ready) {
|
|
218
|
+
if (state.process) {
|
|
219
|
+
state.process.kill("SIGTERM");
|
|
220
|
+
}
|
|
221
|
+
state.process = void 0;
|
|
222
|
+
state.pid = void 0;
|
|
223
|
+
if (state.status !== "failed") {
|
|
224
|
+
state.status = "failed";
|
|
225
|
+
state.message = "Server did not become ready";
|
|
226
|
+
}
|
|
227
|
+
return this.snapshotState(state);
|
|
228
|
+
}
|
|
229
|
+
state.status = "running";
|
|
230
|
+
state.message = "Running";
|
|
231
|
+
state.lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
232
|
+
return this.snapshotState(state);
|
|
233
|
+
}
|
|
234
|
+
async stopProvider(runtimeId) {
|
|
235
|
+
const state = this.states.get(runtimeId);
|
|
236
|
+
if (!state) {
|
|
237
|
+
return this.emptyState(runtimeId);
|
|
238
|
+
}
|
|
239
|
+
const child = state.process;
|
|
240
|
+
if (child) {
|
|
241
|
+
child.kill("SIGTERM");
|
|
242
|
+
await delay(750);
|
|
243
|
+
if (child.exitCode === null) {
|
|
244
|
+
child.kill("SIGKILL");
|
|
245
|
+
}
|
|
246
|
+
state.process = void 0;
|
|
247
|
+
}
|
|
248
|
+
state.pid = void 0;
|
|
249
|
+
state.status = "stopped";
|
|
250
|
+
state.message = "Stopped";
|
|
251
|
+
state.lastStoppedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
252
|
+
return this.snapshotState(state);
|
|
253
|
+
}
|
|
254
|
+
async restartProvider(runtimeId, localRuntime) {
|
|
255
|
+
await this.stopProvider(runtimeId);
|
|
256
|
+
return this.startProvider(runtimeId, localRuntime);
|
|
257
|
+
}
|
|
258
|
+
removeState(runtimeId) {
|
|
259
|
+
const state = this.states.get(runtimeId);
|
|
260
|
+
if (state?.process) {
|
|
261
|
+
state.process.kill("SIGTERM");
|
|
262
|
+
state.process = void 0;
|
|
263
|
+
}
|
|
264
|
+
this.states.delete(runtimeId);
|
|
265
|
+
}
|
|
266
|
+
async waitUntilReady(localRuntime, state, timeoutMs) {
|
|
267
|
+
const start2 = Date.now();
|
|
268
|
+
while (Date.now() - start2 < timeoutMs) {
|
|
269
|
+
if (state.status === "failed") return false;
|
|
270
|
+
if (await probeReady(localRuntime.agentCardUrl, localRuntime.healthUrl, 1500)) {
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
await delay(500);
|
|
274
|
+
}
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
emptyState(runtimeId) {
|
|
278
|
+
return {
|
|
279
|
+
runtimeId,
|
|
280
|
+
label: runtimeId,
|
|
281
|
+
status: "stopped",
|
|
282
|
+
enabled: false
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
snapshotState(state) {
|
|
286
|
+
return {
|
|
287
|
+
runtimeId: state.runtimeId,
|
|
288
|
+
label: state.label,
|
|
289
|
+
status: state.status,
|
|
290
|
+
enabled: state.enabled,
|
|
291
|
+
assistantId: state.assistantId,
|
|
292
|
+
agentCardUrl: state.agentCardUrl,
|
|
293
|
+
healthUrl: state.healthUrl,
|
|
294
|
+
pid: state.pid,
|
|
295
|
+
message: state.message,
|
|
296
|
+
lastStartedAt: state.lastStartedAt,
|
|
297
|
+
lastStoppedAt: state.lastStoppedAt
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
_LocalA2AService.instance = null;
|
|
302
|
+
var LocalA2AService = _LocalA2AService;
|
|
303
|
+
var localA2AService = LocalA2AService.getInstance();
|
|
304
|
+
|
|
305
|
+
// src/utils/a2a-url.ts
|
|
306
|
+
var AGENT_CARD_PATH = "/.well-known/agent-card.json";
|
|
307
|
+
function normalizeA2AAgentCardUrl(value, defaultProtocol = "https://") {
|
|
308
|
+
const raw = value?.trim() ?? "";
|
|
309
|
+
if (!raw) return "";
|
|
310
|
+
const withProtocol = /^https?:\/\//i.test(raw) ? raw : `${defaultProtocol}${raw.replace(/^\/+/, "")}`;
|
|
311
|
+
const trimmed = withProtocol.replace(/\/+$/, "");
|
|
312
|
+
if (trimmed.endsWith(AGENT_CARD_PATH)) {
|
|
313
|
+
return trimmed;
|
|
314
|
+
}
|
|
315
|
+
return `${trimmed}${AGENT_CARD_PATH}`;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// src/utils/local-a2a-runtime.ts
|
|
319
|
+
function validateLocalRuntimeCommand(localRuntime) {
|
|
320
|
+
const runtime = localRuntime;
|
|
321
|
+
const executable = runtime.command?.executable;
|
|
322
|
+
if (typeof executable !== "string" || executable.trim().length === 0) {
|
|
323
|
+
return {
|
|
324
|
+
ok: false,
|
|
325
|
+
error: "Local managed A2A command executable is required"
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
const args = runtime.command?.args;
|
|
329
|
+
if (!Array.isArray(args) || !args.every((arg) => typeof arg === "string")) {
|
|
330
|
+
return {
|
|
331
|
+
ok: false,
|
|
332
|
+
error: "Local managed A2A command args must be an array of strings"
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
return { ok: true };
|
|
336
|
+
}
|
|
337
|
+
function getAgentCardPort(agentCardUrl) {
|
|
338
|
+
let url;
|
|
339
|
+
try {
|
|
340
|
+
url = new URL(agentCardUrl);
|
|
341
|
+
} catch {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
if (url.port) {
|
|
345
|
+
const port = Number(url.port);
|
|
346
|
+
return Number.isInteger(port) ? port : null;
|
|
347
|
+
}
|
|
348
|
+
if (url.protocol === "http:") return 80;
|
|
349
|
+
if (url.protocol === "https:") return 443;
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
function parseCommandPort(args) {
|
|
353
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
354
|
+
const arg = args[index];
|
|
355
|
+
const match = /^(--port|-p)(?:[=\s]+(\d+))?$/.exec(arg);
|
|
356
|
+
if (!match) continue;
|
|
357
|
+
const inlinePort = match[2];
|
|
358
|
+
if (inlinePort) return Number(inlinePort);
|
|
359
|
+
const nextArg = args[index + 1];
|
|
360
|
+
if (nextArg && /^\d+$/.test(nextArg)) {
|
|
361
|
+
return Number(nextArg);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
function isLoopbackHost(hostname) {
|
|
367
|
+
const normalized = hostname.toLowerCase();
|
|
368
|
+
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1" || normalized === "[::1]";
|
|
369
|
+
}
|
|
370
|
+
function validateLocalRuntimePort(localRuntime, agentCardUrl) {
|
|
371
|
+
let url;
|
|
372
|
+
try {
|
|
373
|
+
url = new URL(agentCardUrl);
|
|
374
|
+
} catch {
|
|
375
|
+
return { ok: true };
|
|
376
|
+
}
|
|
377
|
+
if (!isLoopbackHost(url.hostname) || !url.port) {
|
|
378
|
+
return { ok: true };
|
|
379
|
+
}
|
|
380
|
+
const commandPort = parseCommandPort(localRuntime.command.args);
|
|
381
|
+
if (commandPort === null) {
|
|
382
|
+
return { ok: true };
|
|
383
|
+
}
|
|
384
|
+
const agentCardPort = Number(url.port);
|
|
385
|
+
if (commandPort === agentCardPort) {
|
|
386
|
+
return { ok: true };
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
ok: false,
|
|
390
|
+
error: `Local managed A2A command port (${commandPort}) does not match agentCardUrl port (${agentCardPort}). Update the command args or Agent Card URL so they use the same port.`
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// src/controllers/assistant.ts
|
|
28
395
|
function getTenantId(request) {
|
|
29
396
|
const userTenantId = request.user?.tenantId;
|
|
30
397
|
if (userTenantId) {
|
|
@@ -154,6 +521,79 @@ async function createAssistant(request, reply) {
|
|
|
154
521
|
});
|
|
155
522
|
}
|
|
156
523
|
const id = data.id ?? randomUUID();
|
|
524
|
+
if (data.graphDefinition && data.graphDefinition.type === AgentType.A2A_REMOTE) {
|
|
525
|
+
const a2aConfig = data.graphDefinition;
|
|
526
|
+
const warnings = [];
|
|
527
|
+
const isLocalManaged = !!a2aConfig.localRuntime;
|
|
528
|
+
a2aConfig.agentCardUrl = normalizeA2AAgentCardUrl(
|
|
529
|
+
a2aConfig.agentCardUrl,
|
|
530
|
+
isLocalManaged ? "http://" : "https://"
|
|
531
|
+
);
|
|
532
|
+
if (a2aConfig.localRuntime) {
|
|
533
|
+
const commandValidation = validateLocalRuntimeCommand(
|
|
534
|
+
a2aConfig.localRuntime
|
|
535
|
+
);
|
|
536
|
+
if (!commandValidation.ok) {
|
|
537
|
+
return reply.status(400).send({
|
|
538
|
+
success: false,
|
|
539
|
+
message: commandValidation.error
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
a2aConfig.localRuntime.command.executable = a2aConfig.localRuntime.command.executable.trim();
|
|
543
|
+
a2aConfig.localRuntime.agentCardUrl = normalizeA2AAgentCardUrl(
|
|
544
|
+
a2aConfig.localRuntime.agentCardUrl || a2aConfig.agentCardUrl,
|
|
545
|
+
"http://"
|
|
546
|
+
);
|
|
547
|
+
a2aConfig.agentCardUrl = a2aConfig.localRuntime.agentCardUrl;
|
|
548
|
+
const portValidation = validateLocalRuntimePort(
|
|
549
|
+
a2aConfig.localRuntime,
|
|
550
|
+
a2aConfig.agentCardUrl
|
|
551
|
+
);
|
|
552
|
+
if (!portValidation.ok) {
|
|
553
|
+
return reply.status(400).send({
|
|
554
|
+
success: false,
|
|
555
|
+
message: portValidation.error
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (a2aConfig.localRuntime) {
|
|
560
|
+
const existingAssistants = await getStoreLattice("default", "assistant").store.getAllAssistants(tenantId);
|
|
561
|
+
const targetPort = getAgentCardPort(a2aConfig.localRuntime.agentCardUrl);
|
|
562
|
+
const duplicate = existingAssistants.find((a) => {
|
|
563
|
+
if (a.id === id) return false;
|
|
564
|
+
const gd = a.graphDefinition && typeof a.graphDefinition === "object" ? a.graphDefinition : void 0;
|
|
565
|
+
if (!gd || gd.type !== AgentType.A2A_REMOTE) return false;
|
|
566
|
+
const lr = gd.localRuntime;
|
|
567
|
+
if (!lr) return false;
|
|
568
|
+
const existingAgentCardUrl = normalizeA2AAgentCardUrl(lr.agentCardUrl, "http://");
|
|
569
|
+
const existingPort = getAgentCardPort(existingAgentCardUrl);
|
|
570
|
+
if (targetPort !== null && existingPort !== null) {
|
|
571
|
+
return existingPort === targetPort;
|
|
572
|
+
}
|
|
573
|
+
return existingAgentCardUrl === a2aConfig.localRuntime.agentCardUrl;
|
|
574
|
+
});
|
|
575
|
+
if (duplicate) {
|
|
576
|
+
const conflictDetail = targetPort === null ? `agentCardUrl "${a2aConfig.localRuntime.agentCardUrl}"` : `port ${targetPort}`;
|
|
577
|
+
return reply.status(409).send({
|
|
578
|
+
success: false,
|
|
579
|
+
message: `A local managed A2A assistant using ${conflictDetail} already exists: "${duplicate.name}". Each local managed A2A assistant needs a unique port.`
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
try {
|
|
584
|
+
const resp = await fetch(a2aConfig.agentCardUrl, {
|
|
585
|
+
signal: AbortSignal.timeout(5e3)
|
|
586
|
+
});
|
|
587
|
+
if (!resp.ok) {
|
|
588
|
+
warnings.push(`agentCardUrl returned HTTP ${resp.status}`);
|
|
589
|
+
}
|
|
590
|
+
} catch {
|
|
591
|
+
warnings.push(`agentCardUrl is not reachable: ${a2aConfig.agentCardUrl}`);
|
|
592
|
+
}
|
|
593
|
+
if (warnings.length > 0) {
|
|
594
|
+
console.warn(`[createAssistant] A2A warnings for ${a2aConfig.agentCardUrl}:`, warnings);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
157
597
|
return upsertAssistant(tenantId, id, data, reply, true);
|
|
158
598
|
}
|
|
159
599
|
async function updateAssistant(request, reply) {
|
|
@@ -167,11 +607,28 @@ async function deleteAssistant(request, reply) {
|
|
|
167
607
|
const { id } = request.params;
|
|
168
608
|
const storeLattice = getStoreLattice("default", "assistant");
|
|
169
609
|
const assistantStore = storeLattice.store;
|
|
610
|
+
const storedAssistant = await assistantStore.getAssistantById(tenantId, id);
|
|
611
|
+
const graphDefinition = storedAssistant?.graphDefinition;
|
|
612
|
+
const hasLocalRuntime = graphDefinition && typeof graphDefinition === "object" ? !!graphDefinition.localRuntime : false;
|
|
613
|
+
if (storedAssistant && hasLocalRuntime) {
|
|
614
|
+
localA2AService.removeState(id);
|
|
615
|
+
const deleted2 = await assistantStore.deleteAssistant(tenantId, id);
|
|
616
|
+
if (!deleted2) {
|
|
617
|
+
return reply.status(500).send({
|
|
618
|
+
success: false,
|
|
619
|
+
message: "Failed to delete assistant"
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
eventBus.publish("assistant:deleted", { id, tenantId });
|
|
623
|
+
return {
|
|
624
|
+
success: true,
|
|
625
|
+
message: "Deleted local A2A assistant"
|
|
626
|
+
};
|
|
627
|
+
}
|
|
170
628
|
const agentConfig = await agentLatticeManager.getAgentConfigWithTenant(tenantId, id);
|
|
171
629
|
const isCodeConfigured = !!agentConfig;
|
|
172
630
|
if (isCodeConfigured) {
|
|
173
|
-
|
|
174
|
-
if (!exists2) {
|
|
631
|
+
if (!storedAssistant) {
|
|
175
632
|
return reply.status(404).send({
|
|
176
633
|
success: false,
|
|
177
634
|
message: "Assistant not found (code-configured assistants cannot be deleted from code, only from store)"
|
|
@@ -184,8 +641,7 @@ async function deleteAssistant(request, reply) {
|
|
|
184
641
|
message: "Deleted assistant from store (code-configured registration remains)"
|
|
185
642
|
};
|
|
186
643
|
}
|
|
187
|
-
|
|
188
|
-
if (!exists) {
|
|
644
|
+
if (!storedAssistant) {
|
|
189
645
|
return reply.status(404).send({
|
|
190
646
|
success: false,
|
|
191
647
|
message: "Assistant not found"
|
|
@@ -319,7 +775,7 @@ var createRun = async (request, reply) => {
|
|
|
319
775
|
|
|
320
776
|
`);
|
|
321
777
|
if (!success) {
|
|
322
|
-
await new Promise((
|
|
778
|
+
await new Promise((resolve3) => reply.raw.once("drain", resolve3));
|
|
323
779
|
}
|
|
324
780
|
}
|
|
325
781
|
} catch (error) {
|
|
@@ -2911,15 +3367,14 @@ function getStore() {
|
|
|
2911
3367
|
async function listTasks(request, reply) {
|
|
2912
3368
|
try {
|
|
2913
3369
|
const tenantId = getTenantId9(request);
|
|
2914
|
-
const userId = getUserId4(request);
|
|
2915
3370
|
const query = request.query;
|
|
2916
3371
|
const store = getStore();
|
|
2917
3372
|
const tasks = await store.list({
|
|
2918
3373
|
tenantId,
|
|
2919
|
-
ownerId: query.ownerId || userId,
|
|
2920
3374
|
status: query.status,
|
|
2921
3375
|
priority: query.priority,
|
|
2922
|
-
|
|
3376
|
+
...query.ownerId && { ownerId: query.ownerId },
|
|
3377
|
+
...query.ownerType && { ownerType: query.ownerType },
|
|
2923
3378
|
metadata: query.metadata ? JSON.parse(query.metadata) : void 0,
|
|
2924
3379
|
projectId: query.projectId,
|
|
2925
3380
|
limit: query.limit ? parseInt(query.limit) : void 0,
|
|
@@ -4054,12 +4509,41 @@ function registerSandboxProxyRoutes(app2) {
|
|
|
4054
4509
|
}
|
|
4055
4510
|
|
|
4056
4511
|
// src/controllers/workspace.ts
|
|
4057
|
-
import * as
|
|
4058
|
-
import * as
|
|
4512
|
+
import * as fs2 from "fs/promises";
|
|
4513
|
+
import * as path2 from "path";
|
|
4514
|
+
import * as os from "os";
|
|
4059
4515
|
import { getStoreLattice as getStoreLattice7 } from "@axiom-lattice/core";
|
|
4060
4516
|
import { SandboxFilesystem, FilesystemBackend } from "@axiom-lattice/core";
|
|
4061
4517
|
import { getSandBoxManager as getSandBoxManager3 } from "@axiom-lattice/core";
|
|
4062
4518
|
import { v4 as uuidv42 } from "uuid";
|
|
4519
|
+
|
|
4520
|
+
// src/utils/path-containment.ts
|
|
4521
|
+
import * as fs from "fs/promises";
|
|
4522
|
+
import * as path from "path";
|
|
4523
|
+
var PathOutsideRootError = class extends Error {
|
|
4524
|
+
constructor(rootPath, targetPath) {
|
|
4525
|
+
super(`Path is outside the allowed root: ${targetPath}`);
|
|
4526
|
+
this.rootPath = rootPath;
|
|
4527
|
+
this.targetPath = targetPath;
|
|
4528
|
+
this.name = "PathOutsideRootError";
|
|
4529
|
+
}
|
|
4530
|
+
};
|
|
4531
|
+
function isPathWithinRoot(rootPath, targetPath) {
|
|
4532
|
+
const relative2 = path.relative(rootPath, targetPath);
|
|
4533
|
+
return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${path.sep}`) && !path.isAbsolute(relative2);
|
|
4534
|
+
}
|
|
4535
|
+
async function resolvePathWithinRoot(rootPath, targetPath) {
|
|
4536
|
+
const [resolvedRoot, resolvedTarget] = await Promise.all([
|
|
4537
|
+
fs.realpath(rootPath),
|
|
4538
|
+
fs.realpath(targetPath)
|
|
4539
|
+
]);
|
|
4540
|
+
if (!isPathWithinRoot(resolvedRoot, resolvedTarget)) {
|
|
4541
|
+
throw new PathOutsideRootError(resolvedRoot, resolvedTarget);
|
|
4542
|
+
}
|
|
4543
|
+
return { rootPath: resolvedRoot, targetPath: resolvedTarget };
|
|
4544
|
+
}
|
|
4545
|
+
|
|
4546
|
+
// src/controllers/workspace.ts
|
|
4063
4547
|
var WorkspaceController = class {
|
|
4064
4548
|
constructor() {
|
|
4065
4549
|
this.workspaceStore = getStoreLattice7("default", "workspace").store;
|
|
@@ -4220,16 +4704,23 @@ var WorkspaceController = class {
|
|
|
4220
4704
|
}),
|
|
4221
4705
|
workspace
|
|
4222
4706
|
};
|
|
4223
|
-
} else {
|
|
4224
|
-
console.log(`[getBackend] using FilesystemBackend rootDir=/lattice_store/tenants/${tenantId}/workspaces/${workspaceId}/${projectId}`);
|
|
4225
|
-
return {
|
|
4226
|
-
backend: new FilesystemBackend({
|
|
4227
|
-
rootDir: `/lattice_store/tenants/${tenantId}/workspaces/${workspaceId}/${projectId}`,
|
|
4228
|
-
virtualMode: true
|
|
4229
|
-
}),
|
|
4230
|
-
workspace
|
|
4231
|
-
};
|
|
4232
4707
|
}
|
|
4708
|
+
const rootDir = await this.getFilesystemRootDirectory(
|
|
4709
|
+
tenantId,
|
|
4710
|
+
workspaceId,
|
|
4711
|
+
projectId
|
|
4712
|
+
);
|
|
4713
|
+
console.log(`[getBackend] using FilesystemBackend rootDir=${rootDir}`);
|
|
4714
|
+
return {
|
|
4715
|
+
backend: new FilesystemBackend({
|
|
4716
|
+
rootDir,
|
|
4717
|
+
virtualMode: true
|
|
4718
|
+
}),
|
|
4719
|
+
workspace
|
|
4720
|
+
};
|
|
4721
|
+
}
|
|
4722
|
+
async getFilesystemRootDirectory(tenantId, workspaceId, projectId) {
|
|
4723
|
+
return `/lattice_store/tenants/${tenantId}/workspaces/${workspaceId}/${projectId}`;
|
|
4233
4724
|
}
|
|
4234
4725
|
isBinaryContentType(filename) {
|
|
4235
4726
|
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
@@ -4418,21 +4909,21 @@ var WorkspaceController = class {
|
|
|
4418
4909
|
async listPath(request) {
|
|
4419
4910
|
const tenantId = this.getTenantId(request);
|
|
4420
4911
|
const { workspaceId, projectId } = request.params;
|
|
4421
|
-
const
|
|
4912
|
+
const path4 = request.query.path || "/";
|
|
4422
4913
|
const assistantId = request.query.assistantId;
|
|
4423
|
-
console.log(`[listPath] tenantId=${tenantId} workspaceId=${workspaceId} projectId=${projectId} path=${
|
|
4424
|
-
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId,
|
|
4425
|
-
console.log(`[listPath] backend type=${backend.constructor.name} calling lsInfo(${
|
|
4426
|
-
const files = await backend.lsInfo(
|
|
4914
|
+
console.log(`[listPath] tenantId=${tenantId} workspaceId=${workspaceId} projectId=${projectId} path=${path4} assistantId=${assistantId}`);
|
|
4915
|
+
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, path4);
|
|
4916
|
+
console.log(`[listPath] backend type=${backend.constructor.name} calling lsInfo(${path4})`);
|
|
4917
|
+
const files = await backend.lsInfo(path4);
|
|
4427
4918
|
console.log(`[listPath] result count=${files.length}`);
|
|
4428
4919
|
return { success: true, data: files };
|
|
4429
4920
|
}
|
|
4430
4921
|
async readFile(request) {
|
|
4431
4922
|
const tenantId = this.getTenantId(request);
|
|
4432
4923
|
const { workspaceId, projectId } = request.params;
|
|
4433
|
-
const { path:
|
|
4434
|
-
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId,
|
|
4435
|
-
const content = await backend.read(
|
|
4924
|
+
const { path: path4, offset = 0, limit = 1e3, assistantId } = request.query;
|
|
4925
|
+
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, path4);
|
|
4926
|
+
const content = await backend.read(path4, Number(offset), Number(limit));
|
|
4436
4927
|
return { success: true, data: { content, offset, limit } };
|
|
4437
4928
|
}
|
|
4438
4929
|
/**
|
|
@@ -4444,7 +4935,7 @@ var WorkspaceController = class {
|
|
|
4444
4935
|
* - `path`: optional directory path relative to project root (e.g., "docs", "src/utils")
|
|
4445
4936
|
* - `assistantId`: optional query parameter for sandbox identity matching
|
|
4446
4937
|
* For sandbox storage, delegates to the sandbox upload API.
|
|
4447
|
-
* For filesystem storage, writes
|
|
4938
|
+
* For filesystem storage, writes under the same project root used by the file backend.
|
|
4448
4939
|
*/
|
|
4449
4940
|
async uploadFile(request, reply) {
|
|
4450
4941
|
const tenantId = this.getTenantId(request);
|
|
@@ -4478,7 +4969,7 @@ var WorkspaceController = class {
|
|
|
4478
4969
|
workspaceId,
|
|
4479
4970
|
projectId
|
|
4480
4971
|
};
|
|
4481
|
-
const realPath = pathValue ?
|
|
4972
|
+
const realPath = pathValue ? path2.posix.join(pathValue, filename) : path2.posix.join("/project/uploads", filename);
|
|
4482
4973
|
const isBinary = this.isBinaryContentType(filename);
|
|
4483
4974
|
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, realPath);
|
|
4484
4975
|
if (volumeBackend && !isBinary) {
|
|
@@ -4489,7 +4980,7 @@ var WorkspaceController = class {
|
|
|
4489
4980
|
const sandbox = await sandboxManager.getSandboxFromConfig(volumeConfig);
|
|
4490
4981
|
await sandbox.file.uploadFile({ file: realPath, data: buffer });
|
|
4491
4982
|
}
|
|
4492
|
-
const relativePath = pathValue ?
|
|
4983
|
+
const relativePath = pathValue ? path2.posix.join(pathValue, filename) : path2.posix.join("/project/uploads", filename);
|
|
4493
4984
|
const result2 = {
|
|
4494
4985
|
path: relativePath,
|
|
4495
4986
|
name: filename,
|
|
@@ -4499,14 +4990,43 @@ var WorkspaceController = class {
|
|
|
4499
4990
|
};
|
|
4500
4991
|
return reply.status(200).send({ success: true, data: result2 });
|
|
4501
4992
|
}
|
|
4502
|
-
const rootDir =
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4993
|
+
const rootDir = await this.getFilesystemRootDirectory(
|
|
4994
|
+
tenantId,
|
|
4995
|
+
workspaceId,
|
|
4996
|
+
projectId
|
|
4997
|
+
);
|
|
4998
|
+
await fs2.mkdir(rootDir, { recursive: true });
|
|
4999
|
+
const relativeDirectory = pathValue?.replace(/^[/\\]+/, "") || ".";
|
|
5000
|
+
const targetDir = path2.resolve(rootDir, relativeDirectory);
|
|
5001
|
+
if (!isPathWithinRoot(path2.resolve(rootDir), targetDir)) {
|
|
5002
|
+
return reply.status(400).send({
|
|
5003
|
+
success: false,
|
|
5004
|
+
error: "Upload path must stay within the project directory"
|
|
5005
|
+
});
|
|
5006
|
+
}
|
|
5007
|
+
await fs2.mkdir(targetDir, { recursive: true });
|
|
5008
|
+
const [resolvedRoot, resolvedTargetDir] = await Promise.all([
|
|
5009
|
+
fs2.realpath(rootDir),
|
|
5010
|
+
fs2.realpath(targetDir)
|
|
5011
|
+
]);
|
|
5012
|
+
if (!isPathWithinRoot(resolvedRoot, resolvedTargetDir)) {
|
|
5013
|
+
return reply.status(400).send({
|
|
5014
|
+
success: false,
|
|
5015
|
+
error: "Upload path must stay within the project directory"
|
|
5016
|
+
});
|
|
5017
|
+
}
|
|
5018
|
+
const safeFilename = path2.basename(filename);
|
|
5019
|
+
if (safeFilename !== filename) {
|
|
5020
|
+
return reply.status(400).send({
|
|
5021
|
+
success: false,
|
|
5022
|
+
error: "Invalid filename"
|
|
5023
|
+
});
|
|
5024
|
+
}
|
|
5025
|
+
const targetPath = path2.join(resolvedTargetDir, safeFilename);
|
|
5026
|
+
await fs2.writeFile(targetPath, buffer);
|
|
5027
|
+
const stat2 = await fs2.stat(targetPath);
|
|
4508
5028
|
const result = {
|
|
4509
|
-
path:
|
|
5029
|
+
path: path2.posix.join("/", relativeDirectory, safeFilename),
|
|
4510
5030
|
name: filename,
|
|
4511
5031
|
is_dir: false,
|
|
4512
5032
|
size: stat2.size,
|
|
@@ -4514,9 +5034,63 @@ var WorkspaceController = class {
|
|
|
4514
5034
|
};
|
|
4515
5035
|
return reply.status(200).send({ success: true, data: result });
|
|
4516
5036
|
} catch (error) {
|
|
5037
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4517
5038
|
return reply.status(500).send({
|
|
4518
5039
|
success: false,
|
|
4519
|
-
error: `Upload handler error: ${
|
|
5040
|
+
error: `Upload handler error: ${message}`
|
|
5041
|
+
});
|
|
5042
|
+
}
|
|
5043
|
+
}
|
|
5044
|
+
/**
|
|
5045
|
+
* Browse local filesystem directories for the folder picker.
|
|
5046
|
+
*
|
|
5047
|
+
* Security constraints:
|
|
5048
|
+
* - Restricted to os.homedir()
|
|
5049
|
+
* - Blacklists system directories
|
|
5050
|
+
* - Returns only directory names, no file contents or hidden files
|
|
5051
|
+
*/
|
|
5052
|
+
async browseFilesystem(request, reply) {
|
|
5053
|
+
const homeDir = os.homedir();
|
|
5054
|
+
const requestedPath = request.query.path || homeDir;
|
|
5055
|
+
const SYSTEM_BLACKLIST = ["/etc", "/sys", "/proc", "/var", "/tmp", "/dev"];
|
|
5056
|
+
try {
|
|
5057
|
+
const resolved = await resolvePathWithinRoot(homeDir, requestedPath);
|
|
5058
|
+
const normalized = resolved.targetPath;
|
|
5059
|
+
for (const blacklisted of SYSTEM_BLACKLIST) {
|
|
5060
|
+
if (isPathWithinRoot(blacklisted, normalized)) {
|
|
5061
|
+
return reply.status(403).send({
|
|
5062
|
+
success: false,
|
|
5063
|
+
error: `Cannot browse system directory: ${blacklisted}`
|
|
5064
|
+
});
|
|
5065
|
+
}
|
|
5066
|
+
}
|
|
5067
|
+
const entries = await fs2.readdir(normalized, { withFileTypes: true });
|
|
5068
|
+
const dirEntries = entries.filter((entry) => !entry.name.startsWith(".") && entry.isDirectory()).map((entry) => ({
|
|
5069
|
+
name: entry.name,
|
|
5070
|
+
path: path2.join(normalized, entry.name),
|
|
5071
|
+
isDirectory: true
|
|
5072
|
+
}));
|
|
5073
|
+
const parentPath = path2.dirname(normalized);
|
|
5074
|
+
const hasParent = parentPath !== normalized && isPathWithinRoot(resolved.rootPath, parentPath);
|
|
5075
|
+
return {
|
|
5076
|
+
success: true,
|
|
5077
|
+
data: {
|
|
5078
|
+
path: normalized,
|
|
5079
|
+
parentPath: hasParent ? parentPath : void 0,
|
|
5080
|
+
entries: dirEntries
|
|
5081
|
+
}
|
|
5082
|
+
};
|
|
5083
|
+
} catch (error) {
|
|
5084
|
+
if (error instanceof PathOutsideRootError) {
|
|
5085
|
+
return reply.status(403).send({
|
|
5086
|
+
success: false,
|
|
5087
|
+
error: "Browse restricted to home directory"
|
|
5088
|
+
});
|
|
5089
|
+
}
|
|
5090
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5091
|
+
return reply.status(400).send({
|
|
5092
|
+
success: false,
|
|
5093
|
+
error: `Cannot read directory: ${message}`
|
|
4520
5094
|
});
|
|
4521
5095
|
}
|
|
4522
5096
|
}
|
|
@@ -4577,6 +5151,10 @@ function registerWorkspaceRoutes(app2) {
|
|
|
4577
5151
|
"/api/workspaces/:workspaceId/projects/:projectId/viewfile",
|
|
4578
5152
|
controller.viewFile.bind(controller)
|
|
4579
5153
|
);
|
|
5154
|
+
app2.get(
|
|
5155
|
+
"/api/filesystem/browse",
|
|
5156
|
+
controller.browseFilesystem.bind(controller)
|
|
5157
|
+
);
|
|
4580
5158
|
}
|
|
4581
5159
|
|
|
4582
5160
|
// src/controllers/database-configs.ts
|
|
@@ -4796,7 +5374,7 @@ async function testDatabaseConnection(request, reply) {
|
|
|
4796
5374
|
await db.connect();
|
|
4797
5375
|
await db.listTables();
|
|
4798
5376
|
const latency = Date.now() - startTime;
|
|
4799
|
-
await new Promise((
|
|
5377
|
+
await new Promise((resolve3) => setTimeout(resolve3, 100));
|
|
4800
5378
|
await db.disconnect();
|
|
4801
5379
|
await sqlDatabaseManager.removeDatabase(tenantId, testKey);
|
|
4802
5380
|
return {
|
|
@@ -5690,6 +6268,9 @@ var EvalRunner = class {
|
|
|
5690
6268
|
const runId = uuidv43();
|
|
5691
6269
|
const concurrency = Math.max(1, Math.floor(project.concurrency) || 3);
|
|
5692
6270
|
await store.createRun(tenantId, projectId, runId, { totalCases, concurrency });
|
|
6271
|
+
const tsc = project.targetServerConfig ?? {};
|
|
6272
|
+
const workspaceId = tsc.workspace_id || "";
|
|
6273
|
+
const projectIdFromConfig = tsc.project_id || "";
|
|
5693
6274
|
const projectConfig = {
|
|
5694
6275
|
projectName: project.name,
|
|
5695
6276
|
version: project.version,
|
|
@@ -5697,7 +6278,9 @@ var EvalRunner = class {
|
|
|
5697
6278
|
suites: evalSuites,
|
|
5698
6279
|
judge_agent_config: { modelKey: resolvedJudgeModelKey },
|
|
5699
6280
|
lattice_server_config: {
|
|
5700
|
-
tenant_id: tenantId
|
|
6281
|
+
tenant_id: tenantId,
|
|
6282
|
+
workspace_id: workspaceId,
|
|
6283
|
+
project_id: projectIdFromConfig
|
|
5701
6284
|
},
|
|
5702
6285
|
concurrency
|
|
5703
6286
|
};
|
|
@@ -7109,8 +7692,8 @@ function getTenantId14(request) {
|
|
|
7109
7692
|
return request.headers["x-tenant-id"] || "default";
|
|
7110
7693
|
}
|
|
7111
7694
|
async function getInstallationStore() {
|
|
7112
|
-
const { getStoreLattice:
|
|
7113
|
-
const store =
|
|
7695
|
+
const { getStoreLattice: getStoreLattice31 } = await import("@axiom-lattice/core");
|
|
7696
|
+
const store = getStoreLattice31("default", "channelInstallation").store;
|
|
7114
7697
|
if (store) return store;
|
|
7115
7698
|
const { PostgreSQLChannelInstallationStore } = await import("@axiom-lattice/pg-stores");
|
|
7116
7699
|
const databaseUrl = process.env.DATABASE_URL;
|
|
@@ -7591,8 +8174,8 @@ var log = {
|
|
|
7591
8174
|
};
|
|
7592
8175
|
var connections = /* @__PURE__ */ new Map();
|
|
7593
8176
|
var pending = /* @__PURE__ */ new Map();
|
|
7594
|
-
function getAgentIdFromPath(
|
|
7595
|
-
const match =
|
|
8177
|
+
function getAgentIdFromPath(path4) {
|
|
8178
|
+
const match = path4.match(/^\/api\/a2a\/bridge\/proxy\/([^/]+)/);
|
|
7596
8179
|
return match ? match[1] : null;
|
|
7597
8180
|
}
|
|
7598
8181
|
function handleBridgeConnection(socket, _request) {
|
|
@@ -7700,12 +8283,12 @@ async function handleBridgeProxy(request, reply) {
|
|
|
7700
8283
|
};
|
|
7701
8284
|
const timeout = 3e5;
|
|
7702
8285
|
try {
|
|
7703
|
-
const response = await new Promise((
|
|
8286
|
+
const response = await new Promise((resolve3, reject) => {
|
|
7704
8287
|
const timer = setTimeout(() => {
|
|
7705
8288
|
pending.delete(requestId);
|
|
7706
8289
|
reject(new Error(`Bridge request timeout after ${timeout}ms`));
|
|
7707
8290
|
}, timeout);
|
|
7708
|
-
pending.set(requestId, { resolve, reject, timer, agentId });
|
|
8291
|
+
pending.set(requestId, { resolve: resolve3, reject, timer, agentId });
|
|
7709
8292
|
try {
|
|
7710
8293
|
if (conn.ws.readyState !== conn.ws.OPEN) {
|
|
7711
8294
|
pending.delete(requestId);
|
|
@@ -7750,9 +8333,352 @@ function registerA2ABridgeRoutes(app2) {
|
|
|
7750
8333
|
});
|
|
7751
8334
|
}
|
|
7752
8335
|
|
|
8336
|
+
// src/routes/stt.ts
|
|
8337
|
+
import { getSTTClient, sttModelLatticeManager } from "@axiom-lattice/core";
|
|
8338
|
+
var ALLOWED_AUDIO_FORMATS = /* @__PURE__ */ new Set([
|
|
8339
|
+
"webm",
|
|
8340
|
+
"wav",
|
|
8341
|
+
"mp3",
|
|
8342
|
+
"m4a",
|
|
8343
|
+
"ogg",
|
|
8344
|
+
"flac",
|
|
8345
|
+
"aac"
|
|
8346
|
+
]);
|
|
8347
|
+
var MAX_AUDIO_FILE_SIZE = 25 * 1024 * 1024;
|
|
8348
|
+
var registerSTTRoutes = (app2) => {
|
|
8349
|
+
app2.get("/api/stt/models", async (_request, reply) => {
|
|
8350
|
+
const models = sttModelLatticeManager.getAllSTTModelInfo();
|
|
8351
|
+
return reply.send({ models });
|
|
8352
|
+
});
|
|
8353
|
+
app2.post(
|
|
8354
|
+
"/api/stt/transcribe",
|
|
8355
|
+
{
|
|
8356
|
+
schema: {
|
|
8357
|
+
querystring: {
|
|
8358
|
+
type: "object",
|
|
8359
|
+
properties: {
|
|
8360
|
+
model: { type: "string" }
|
|
8361
|
+
}
|
|
8362
|
+
},
|
|
8363
|
+
response: {
|
|
8364
|
+
200: {
|
|
8365
|
+
type: "object",
|
|
8366
|
+
properties: {
|
|
8367
|
+
text: { type: "string" },
|
|
8368
|
+
confidence: { type: "number" }
|
|
8369
|
+
}
|
|
8370
|
+
}
|
|
8371
|
+
}
|
|
8372
|
+
}
|
|
8373
|
+
},
|
|
8374
|
+
async (request, reply) => {
|
|
8375
|
+
const modelKey = request.query.model || "default";
|
|
8376
|
+
const data = await request.file({
|
|
8377
|
+
limits: { fileSize: MAX_AUDIO_FILE_SIZE }
|
|
8378
|
+
});
|
|
8379
|
+
if (!data) {
|
|
8380
|
+
return reply.status(400).send({ error: "No audio file provided" });
|
|
8381
|
+
}
|
|
8382
|
+
const buffer = await data.toBuffer();
|
|
8383
|
+
if (buffer.length === 0) {
|
|
8384
|
+
return reply.status(400).send({ error: "Empty audio file" });
|
|
8385
|
+
}
|
|
8386
|
+
const format = (data.filename.split(".").pop() || "webm").toLowerCase();
|
|
8387
|
+
if (!ALLOWED_AUDIO_FORMATS.has(format)) {
|
|
8388
|
+
return reply.status(400).send({ error: `Unsupported audio format: ${format}` });
|
|
8389
|
+
}
|
|
8390
|
+
try {
|
|
8391
|
+
let client;
|
|
8392
|
+
try {
|
|
8393
|
+
client = getSTTClient(modelKey);
|
|
8394
|
+
} catch {
|
|
8395
|
+
return reply.status(404).send({ error: `STT model "${modelKey}" not found` });
|
|
8396
|
+
}
|
|
8397
|
+
const result = await client.transcribe(buffer, format);
|
|
8398
|
+
return reply.send({
|
|
8399
|
+
text: result.text,
|
|
8400
|
+
confidence: result.confidence
|
|
8401
|
+
});
|
|
8402
|
+
} catch (error) {
|
|
8403
|
+
const sanitizedMessage = error instanceof Error ? error.message : "Transcription failed";
|
|
8404
|
+
request.log.error(
|
|
8405
|
+
{ error: sanitizedMessage },
|
|
8406
|
+
"STT transcription failed"
|
|
8407
|
+
);
|
|
8408
|
+
return reply.status(500).send({ error: "Transcription service error. Please try again." });
|
|
8409
|
+
}
|
|
8410
|
+
}
|
|
8411
|
+
);
|
|
8412
|
+
};
|
|
8413
|
+
|
|
8414
|
+
// src/controllers/local-a2a.ts
|
|
8415
|
+
import { getStoreLattice as getStoreLattice15 } from "@axiom-lattice/core";
|
|
8416
|
+
import {
|
|
8417
|
+
AgentType as AgentType2
|
|
8418
|
+
} from "@axiom-lattice/protocols";
|
|
8419
|
+
function getTenantId17(request) {
|
|
8420
|
+
const userTenantId = request.user?.tenantId;
|
|
8421
|
+
if (userTenantId) return userTenantId;
|
|
8422
|
+
return request.headers["x-tenant-id"] || "default";
|
|
8423
|
+
}
|
|
8424
|
+
function getLocalRuntime(assistant) {
|
|
8425
|
+
const graphDefinition = assistant.graphDefinition;
|
|
8426
|
+
if (!graphDefinition || typeof graphDefinition !== "object") return void 0;
|
|
8427
|
+
if (graphDefinition.type !== AgentType2.A2A_REMOTE) return void 0;
|
|
8428
|
+
return graphDefinition.localRuntime;
|
|
8429
|
+
}
|
|
8430
|
+
async function getLocalA2AAssistants(tenantId) {
|
|
8431
|
+
const storeLattice = getStoreLattice15("default", "assistant");
|
|
8432
|
+
const assistants = await storeLattice.store.getAllAssistants(tenantId);
|
|
8433
|
+
const results = [];
|
|
8434
|
+
for (const assistant of assistants) {
|
|
8435
|
+
const runtime = getLocalRuntime(assistant);
|
|
8436
|
+
if (runtime) {
|
|
8437
|
+
results.push({ assistant, localRuntime: runtime });
|
|
8438
|
+
}
|
|
8439
|
+
}
|
|
8440
|
+
return results;
|
|
8441
|
+
}
|
|
8442
|
+
async function getLocalA2AAssistant(tenantId, assistantId) {
|
|
8443
|
+
const storeLattice = getStoreLattice15("default", "assistant");
|
|
8444
|
+
const assistant = await storeLattice.store.getAssistantById(tenantId, assistantId);
|
|
8445
|
+
if (!assistant) return null;
|
|
8446
|
+
const runtime = getLocalRuntime(assistant);
|
|
8447
|
+
if (!runtime) return null;
|
|
8448
|
+
return { assistant, localRuntime: runtime };
|
|
8449
|
+
}
|
|
8450
|
+
async function requireManagedAssistant(request, reply) {
|
|
8451
|
+
const assistantId = request.params.assistantId;
|
|
8452
|
+
if (!assistantId) {
|
|
8453
|
+
reply.status(400).send({ success: false, error: "assistantId is required" });
|
|
8454
|
+
return null;
|
|
8455
|
+
}
|
|
8456
|
+
const registered = await getLocalA2AAssistant(getTenantId17(request), assistantId);
|
|
8457
|
+
if (!registered) {
|
|
8458
|
+
reply.status(404).send({
|
|
8459
|
+
success: false,
|
|
8460
|
+
error: `Assistant ${assistantId} is not a local managed A2A assistant`
|
|
8461
|
+
});
|
|
8462
|
+
return null;
|
|
8463
|
+
}
|
|
8464
|
+
return { assistantId, localRuntime: registered.localRuntime };
|
|
8465
|
+
}
|
|
8466
|
+
async function getLocalA2AStatus(request, reply) {
|
|
8467
|
+
const tenantId = getTenantId17(request);
|
|
8468
|
+
const managed = await getLocalA2AAssistants(tenantId);
|
|
8469
|
+
const states = await Promise.all(
|
|
8470
|
+
managed.map(
|
|
8471
|
+
({ assistant, localRuntime }) => localA2AService.getRegisteredState(assistant.id, localRuntime)
|
|
8472
|
+
)
|
|
8473
|
+
);
|
|
8474
|
+
reply.send({ success: true, data: { records: states, total: states.length } });
|
|
8475
|
+
}
|
|
8476
|
+
async function getLocalA2AProvider(request, reply) {
|
|
8477
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
8478
|
+
if (!registered) return;
|
|
8479
|
+
const state = await localA2AService.getRegisteredState(
|
|
8480
|
+
registered.assistantId,
|
|
8481
|
+
registered.localRuntime
|
|
8482
|
+
);
|
|
8483
|
+
reply.send({ success: true, data: state });
|
|
8484
|
+
}
|
|
8485
|
+
async function startLocalA2AProvider(request, reply) {
|
|
8486
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
8487
|
+
if (!registered) return;
|
|
8488
|
+
const state = await localA2AService.startProvider(
|
|
8489
|
+
registered.assistantId,
|
|
8490
|
+
registered.localRuntime
|
|
8491
|
+
);
|
|
8492
|
+
reply.send({ success: true, data: state });
|
|
8493
|
+
}
|
|
8494
|
+
async function stopLocalA2AProvider(request, reply) {
|
|
8495
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
8496
|
+
if (!registered) return;
|
|
8497
|
+
const state = await localA2AService.stopProvider(registered.assistantId);
|
|
8498
|
+
reply.send({ success: true, data: state });
|
|
8499
|
+
}
|
|
8500
|
+
async function restartLocalA2AProvider(request, reply) {
|
|
8501
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
8502
|
+
if (!registered) return;
|
|
8503
|
+
const state = await localA2AService.restartProvider(
|
|
8504
|
+
registered.assistantId,
|
|
8505
|
+
registered.localRuntime
|
|
8506
|
+
);
|
|
8507
|
+
reply.send({ success: true, data: state });
|
|
8508
|
+
}
|
|
8509
|
+
|
|
8510
|
+
// src/config/local-a2a-templates.ts
|
|
8511
|
+
import { cliA2AEntryPath } from "@axiom-lattice/cli-a2a/cli-path";
|
|
8512
|
+
function buildCliA2ACommand(provider, agentName, agentDescription) {
|
|
8513
|
+
return {
|
|
8514
|
+
executable: process.execPath,
|
|
8515
|
+
args: [
|
|
8516
|
+
cliA2AEntryPath,
|
|
8517
|
+
"--provider",
|
|
8518
|
+
provider,
|
|
8519
|
+
"--hostname",
|
|
8520
|
+
"localhost",
|
|
8521
|
+
"--advertise-host",
|
|
8522
|
+
"localhost",
|
|
8523
|
+
"--agent-name",
|
|
8524
|
+
agentName,
|
|
8525
|
+
"--agent-description",
|
|
8526
|
+
agentDescription,
|
|
8527
|
+
"--log-level",
|
|
8528
|
+
"info"
|
|
8529
|
+
]
|
|
8530
|
+
};
|
|
8531
|
+
}
|
|
8532
|
+
var LOCAL_A2A_TEMPLATES = [
|
|
8533
|
+
{
|
|
8534
|
+
key: "claude",
|
|
8535
|
+
name: "Claude Code",
|
|
8536
|
+
command: buildCliA2ACommand(
|
|
8537
|
+
"claude",
|
|
8538
|
+
"Claude Code",
|
|
8539
|
+
"Local Claude Code wrapper exposed through A2A."
|
|
8540
|
+
)
|
|
8541
|
+
},
|
|
8542
|
+
{
|
|
8543
|
+
key: "codex",
|
|
8544
|
+
name: "Codex",
|
|
8545
|
+
command: buildCliA2ACommand(
|
|
8546
|
+
"codex",
|
|
8547
|
+
"Codex",
|
|
8548
|
+
"Local Codex wrapper exposed through A2A."
|
|
8549
|
+
)
|
|
8550
|
+
},
|
|
8551
|
+
{
|
|
8552
|
+
key: "opencode",
|
|
8553
|
+
name: "OpenCode",
|
|
8554
|
+
command: buildCliA2ACommand(
|
|
8555
|
+
"opencode",
|
|
8556
|
+
"OpenCode",
|
|
8557
|
+
"Local OpenCode wrapper exposed through A2A."
|
|
8558
|
+
)
|
|
8559
|
+
}
|
|
8560
|
+
];
|
|
8561
|
+
|
|
8562
|
+
// src/controllers/local-a2a-templates.ts
|
|
8563
|
+
async function getLocalA2ATemplates(_request, reply) {
|
|
8564
|
+
reply.send({
|
|
8565
|
+
success: true,
|
|
8566
|
+
data: {
|
|
8567
|
+
records: LOCAL_A2A_TEMPLATES,
|
|
8568
|
+
total: LOCAL_A2A_TEMPLATES.length
|
|
8569
|
+
}
|
|
8570
|
+
});
|
|
8571
|
+
}
|
|
8572
|
+
|
|
8573
|
+
// src/routes/a2a-test-connection.ts
|
|
8574
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
8575
|
+
function describeTestConnectionError(error, agentCardUrl) {
|
|
8576
|
+
if (!(error instanceof Error)) {
|
|
8577
|
+
return `Failed to fetch agent card from ${agentCardUrl}: ${String(error)}`;
|
|
8578
|
+
}
|
|
8579
|
+
const cause = error.cause;
|
|
8580
|
+
const causeParts = [];
|
|
8581
|
+
if (cause instanceof Error) {
|
|
8582
|
+
causeParts.push(cause.message);
|
|
8583
|
+
const causeCode = cause.code;
|
|
8584
|
+
if (causeCode && !causeParts.some((part) => part.includes(causeCode))) {
|
|
8585
|
+
causeParts.push(causeCode);
|
|
8586
|
+
}
|
|
8587
|
+
} else if (typeof cause === "object" && cause !== null) {
|
|
8588
|
+
const code = "code" in cause ? String(cause.code) : "";
|
|
8589
|
+
const message = "message" in cause ? String(cause.message) : "";
|
|
8590
|
+
if (message) causeParts.push(message);
|
|
8591
|
+
if (code && !message.includes(code)) causeParts.push(code);
|
|
8592
|
+
}
|
|
8593
|
+
const detail = causeParts.length > 0 ? ` (${causeParts.join(", ")})` : "";
|
|
8594
|
+
return `Failed to fetch agent card from ${agentCardUrl}: ${error.message}${detail}`;
|
|
8595
|
+
}
|
|
8596
|
+
async function ensureLocalRuntimeForConnectionTest(localRuntime, agentCardUrl) {
|
|
8597
|
+
const commandValidation = validateLocalRuntimeCommand(localRuntime);
|
|
8598
|
+
if (!commandValidation.ok) {
|
|
8599
|
+
return { error: commandValidation.error };
|
|
8600
|
+
}
|
|
8601
|
+
const testRuntime = {
|
|
8602
|
+
...localRuntime,
|
|
8603
|
+
agentCardUrl,
|
|
8604
|
+
command: {
|
|
8605
|
+
...localRuntime.command,
|
|
8606
|
+
executable: localRuntime.command.executable.trim()
|
|
8607
|
+
}
|
|
8608
|
+
};
|
|
8609
|
+
const portValidation = validateLocalRuntimePort(testRuntime, agentCardUrl);
|
|
8610
|
+
if (!portValidation.ok) {
|
|
8611
|
+
return { error: portValidation.error };
|
|
8612
|
+
}
|
|
8613
|
+
const state = await localA2AService.startProvider(
|
|
8614
|
+
`test-${randomUUID8()}`,
|
|
8615
|
+
testRuntime
|
|
8616
|
+
);
|
|
8617
|
+
if (state.status === "running") return { runtimeId: state.runtimeId };
|
|
8618
|
+
const detail = state.message ? ` ${state.message}` : "";
|
|
8619
|
+
localA2AService.removeState(state.runtimeId);
|
|
8620
|
+
return { error: `Local managed A2A server could not start for connection test.${detail}` };
|
|
8621
|
+
}
|
|
8622
|
+
async function readShortResponseBody(resp) {
|
|
8623
|
+
const body = await resp.text().catch(() => "");
|
|
8624
|
+
return body.length > 500 ? `${body.slice(0, 500)}...` : body;
|
|
8625
|
+
}
|
|
8626
|
+
function registerA2ATestConnectionRoute(app2) {
|
|
8627
|
+
app2.post("/api/a2a/test-connection", async (request, reply) => {
|
|
8628
|
+
const { agentCardUrl, apiKey, localRuntime } = request.body ?? {};
|
|
8629
|
+
const normalizedAgentCardUrl = normalizeA2AAgentCardUrl(
|
|
8630
|
+
agentCardUrl,
|
|
8631
|
+
localRuntime ? "http://" : "https://"
|
|
8632
|
+
);
|
|
8633
|
+
if (!normalizedAgentCardUrl) {
|
|
8634
|
+
return reply.status(400).send({ success: false, error: "agentCardUrl is required" });
|
|
8635
|
+
}
|
|
8636
|
+
let testRuntimeId = null;
|
|
8637
|
+
try {
|
|
8638
|
+
const headers = {};
|
|
8639
|
+
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
|
|
8640
|
+
if (localRuntime) {
|
|
8641
|
+
const localStartResult = await ensureLocalRuntimeForConnectionTest(localRuntime, normalizedAgentCardUrl);
|
|
8642
|
+
if ("error" in localStartResult) {
|
|
8643
|
+
return reply.send({ success: true, data: { reachable: false, error: localStartResult.error } });
|
|
8644
|
+
}
|
|
8645
|
+
testRuntimeId = localStartResult.runtimeId;
|
|
8646
|
+
}
|
|
8647
|
+
const resp = await fetch(normalizedAgentCardUrl, { headers, signal: AbortSignal.timeout(8e3) });
|
|
8648
|
+
if (!resp.ok) {
|
|
8649
|
+
const body = await readShortResponseBody(resp);
|
|
8650
|
+
const suffix = body ? `: ${body}` : "";
|
|
8651
|
+
return reply.send({ success: true, data: { reachable: false, error: `HTTP ${resp.status} ${resp.statusText}${suffix}` } });
|
|
8652
|
+
}
|
|
8653
|
+
const card = await resp.json();
|
|
8654
|
+
return reply.send({ success: true, data: { reachable: true, agentName: card.name, agentCard: card } });
|
|
8655
|
+
} catch (error) {
|
|
8656
|
+
return reply.send({
|
|
8657
|
+
success: true,
|
|
8658
|
+
data: {
|
|
8659
|
+
reachable: false,
|
|
8660
|
+
error: describeTestConnectionError(error, normalizedAgentCardUrl)
|
|
8661
|
+
}
|
|
8662
|
+
});
|
|
8663
|
+
} finally {
|
|
8664
|
+
if (testRuntimeId) {
|
|
8665
|
+
localA2AService.removeState(testRuntimeId);
|
|
8666
|
+
}
|
|
8667
|
+
}
|
|
8668
|
+
});
|
|
8669
|
+
}
|
|
8670
|
+
|
|
7753
8671
|
// src/routes/index.ts
|
|
7754
8672
|
var registerLatticeRoutes = (app2, channelDeps) => {
|
|
7755
8673
|
registerA2ABridgeRoutes(app2);
|
|
8674
|
+
registerSTTRoutes(app2);
|
|
8675
|
+
app2.get("/api/local-a2a", getLocalA2AStatus);
|
|
8676
|
+
app2.get("/api/local-a2a/templates", getLocalA2ATemplates);
|
|
8677
|
+
app2.get("/api/local-a2a/:assistantId", getLocalA2AProvider);
|
|
8678
|
+
app2.post("/api/local-a2a/:assistantId/start", startLocalA2AProvider);
|
|
8679
|
+
app2.post("/api/local-a2a/:assistantId/stop", stopLocalA2AProvider);
|
|
8680
|
+
app2.post("/api/local-a2a/:assistantId/restart", restartLocalA2AProvider);
|
|
8681
|
+
registerA2ATestConnectionRoute(app2);
|
|
7756
8682
|
app2.post("/api/runs", createRun);
|
|
7757
8683
|
app2.post("/api/resume_stream", resumeStream);
|
|
7758
8684
|
app2.post("/api/assistants/:assistantId/threads/:threadId/abort", abortRun);
|
|
@@ -8047,9 +8973,9 @@ function registerResourceRoutes(app2, controller) {
|
|
|
8047
8973
|
import { ExportableEntityRegistry as ExportableEntityRegistry3 } from "@axiom-lattice/core";
|
|
8048
8974
|
|
|
8049
8975
|
// src/export_registrations/skill.registration.ts
|
|
8050
|
-
import { getStoreLattice as
|
|
8976
|
+
import { getStoreLattice as getStoreLattice16 } from "@axiom-lattice/core";
|
|
8051
8977
|
function getStore2() {
|
|
8052
|
-
return
|
|
8978
|
+
return getStoreLattice16("default", "skill").store;
|
|
8053
8979
|
}
|
|
8054
8980
|
var skillRegistration = {
|
|
8055
8981
|
entityType: "skill",
|
|
@@ -8124,9 +9050,9 @@ var skillRegistration = {
|
|
|
8124
9050
|
};
|
|
8125
9051
|
|
|
8126
9052
|
// src/export_registrations/agent.registration.ts
|
|
8127
|
-
import { getStoreLattice as
|
|
9053
|
+
import { getStoreLattice as getStoreLattice17 } from "@axiom-lattice/core";
|
|
8128
9054
|
function getStore3() {
|
|
8129
|
-
return
|
|
9055
|
+
return getStoreLattice17("default", "assistant").store;
|
|
8130
9056
|
}
|
|
8131
9057
|
var agentRegistration = {
|
|
8132
9058
|
entityType: "agent",
|
|
@@ -8193,9 +9119,9 @@ var agentRegistration = {
|
|
|
8193
9119
|
};
|
|
8194
9120
|
|
|
8195
9121
|
// src/export_registrations/binding.registration.ts
|
|
8196
|
-
import { getStoreLattice as
|
|
9122
|
+
import { getStoreLattice as getStoreLattice18 } from "@axiom-lattice/core";
|
|
8197
9123
|
function getStore4() {
|
|
8198
|
-
return
|
|
9124
|
+
return getStoreLattice18("default", "channelBinding").store;
|
|
8199
9125
|
}
|
|
8200
9126
|
var bindingRegistration = {
|
|
8201
9127
|
entityType: "binding",
|
|
@@ -8283,9 +9209,9 @@ var bindingRegistration = {
|
|
|
8283
9209
|
};
|
|
8284
9210
|
|
|
8285
9211
|
// src/export_registrations/database-config.registration.ts
|
|
8286
|
-
import { getStoreLattice as
|
|
9212
|
+
import { getStoreLattice as getStoreLattice19 } from "@axiom-lattice/core";
|
|
8287
9213
|
function getStore5() {
|
|
8288
|
-
return
|
|
9214
|
+
return getStoreLattice19("default", "database").store;
|
|
8289
9215
|
}
|
|
8290
9216
|
var databaseConfigRegistration = {
|
|
8291
9217
|
entityType: "database_config",
|
|
@@ -8365,9 +9291,9 @@ var databaseConfigRegistration = {
|
|
|
8365
9291
|
};
|
|
8366
9292
|
|
|
8367
9293
|
// src/export_registrations/metrics-config.registration.ts
|
|
8368
|
-
import { getStoreLattice as
|
|
9294
|
+
import { getStoreLattice as getStoreLattice20 } from "@axiom-lattice/core";
|
|
8369
9295
|
function getStore6() {
|
|
8370
|
-
return
|
|
9296
|
+
return getStoreLattice20("default", "metrics").store;
|
|
8371
9297
|
}
|
|
8372
9298
|
var metricsConfigRegistration = {
|
|
8373
9299
|
entityType: "metrics_config",
|
|
@@ -8447,9 +9373,9 @@ var metricsConfigRegistration = {
|
|
|
8447
9373
|
};
|
|
8448
9374
|
|
|
8449
9375
|
// src/export_registrations/mcp-config.registration.ts
|
|
8450
|
-
import { getStoreLattice as
|
|
9376
|
+
import { getStoreLattice as getStoreLattice21 } from "@axiom-lattice/core";
|
|
8451
9377
|
function getStore7() {
|
|
8452
|
-
return
|
|
9378
|
+
return getStoreLattice21("default", "mcp").store;
|
|
8453
9379
|
}
|
|
8454
9380
|
var mcpConfigRegistration = {
|
|
8455
9381
|
entityType: "mcp_config",
|
|
@@ -8532,9 +9458,9 @@ var mcpConfigRegistration = {
|
|
|
8532
9458
|
};
|
|
8533
9459
|
|
|
8534
9460
|
// src/export_registrations/connection.registration.ts
|
|
8535
|
-
import { getStoreLattice as
|
|
9461
|
+
import { getStoreLattice as getStoreLattice22 } from "@axiom-lattice/core";
|
|
8536
9462
|
function getStore8() {
|
|
8537
|
-
return
|
|
9463
|
+
return getStoreLattice22("default", "connection").store;
|
|
8538
9464
|
}
|
|
8539
9465
|
async function listAllConnections(tenantId) {
|
|
8540
9466
|
const store = getStore8();
|
|
@@ -8616,9 +9542,9 @@ var connectionRegistration = {
|
|
|
8616
9542
|
};
|
|
8617
9543
|
|
|
8618
9544
|
// src/export_registrations/collection.registration.ts
|
|
8619
|
-
import { getStoreLattice as
|
|
9545
|
+
import { getStoreLattice as getStoreLattice23 } from "@axiom-lattice/core";
|
|
8620
9546
|
function getStore9() {
|
|
8621
|
-
return
|
|
9547
|
+
return getStoreLattice23("default", "collection").store;
|
|
8622
9548
|
}
|
|
8623
9549
|
var collectionRegistration = {
|
|
8624
9550
|
entityType: "collection",
|
|
@@ -8689,9 +9615,9 @@ var collectionRegistration = {
|
|
|
8689
9615
|
};
|
|
8690
9616
|
|
|
8691
9617
|
// src/export_registrations/channel-installation.registration.ts
|
|
8692
|
-
import { getStoreLattice as
|
|
9618
|
+
import { getStoreLattice as getStoreLattice24 } from "@axiom-lattice/core";
|
|
8693
9619
|
function getStore10() {
|
|
8694
|
-
return
|
|
9620
|
+
return getStoreLattice24("default", "channelInstallation").store;
|
|
8695
9621
|
}
|
|
8696
9622
|
var channelInstallationRegistration = {
|
|
8697
9623
|
entityType: "channel_installation",
|
|
@@ -8766,9 +9692,9 @@ var channelInstallationRegistration = {
|
|
|
8766
9692
|
};
|
|
8767
9693
|
|
|
8768
9694
|
// src/export_registrations/menu.registration.ts
|
|
8769
|
-
import { getStoreLattice as
|
|
9695
|
+
import { getStoreLattice as getStoreLattice25 } from "@axiom-lattice/core";
|
|
8770
9696
|
function getStore11() {
|
|
8771
|
-
return
|
|
9697
|
+
return getStoreLattice25("default", "menu").store;
|
|
8772
9698
|
}
|
|
8773
9699
|
var menuRegistration = {
|
|
8774
9700
|
entityType: "menu",
|
|
@@ -8846,9 +9772,9 @@ var menuRegistration = {
|
|
|
8846
9772
|
};
|
|
8847
9773
|
|
|
8848
9774
|
// src/export_registrations/task.registration.ts
|
|
8849
|
-
import { getStoreLattice as
|
|
9775
|
+
import { getStoreLattice as getStoreLattice26 } from "@axiom-lattice/core";
|
|
8850
9776
|
function getStore12() {
|
|
8851
|
-
return
|
|
9777
|
+
return getStoreLattice26("default", "task").store;
|
|
8852
9778
|
}
|
|
8853
9779
|
var taskRegistration = {
|
|
8854
9780
|
entityType: "task",
|
|
@@ -8934,9 +9860,9 @@ var taskRegistration = {
|
|
|
8934
9860
|
};
|
|
8935
9861
|
|
|
8936
9862
|
// src/export_registrations/a2a-api-key.registration.ts
|
|
8937
|
-
import { getStoreLattice as
|
|
9863
|
+
import { getStoreLattice as getStoreLattice27 } from "@axiom-lattice/core";
|
|
8938
9864
|
function getStore13() {
|
|
8939
|
-
return
|
|
9865
|
+
return getStoreLattice27("default", "a2aApiKey").store;
|
|
8940
9866
|
}
|
|
8941
9867
|
var a2aApiKeyRegistration = {
|
|
8942
9868
|
entityType: "a2a_api_key",
|
|
@@ -9007,9 +9933,9 @@ var a2aApiKeyRegistration = {
|
|
|
9007
9933
|
};
|
|
9008
9934
|
|
|
9009
9935
|
// src/export_registrations/eval.registration.ts
|
|
9010
|
-
import { getStoreLattice as
|
|
9936
|
+
import { getStoreLattice as getStoreLattice28 } from "@axiom-lattice/core";
|
|
9011
9937
|
function getStore14() {
|
|
9012
|
-
return
|
|
9938
|
+
return getStoreLattice28("default", "eval").store;
|
|
9013
9939
|
}
|
|
9014
9940
|
var evalRegistration = {
|
|
9015
9941
|
entityType: "eval",
|
|
@@ -9353,10 +10279,10 @@ function registerAllBuiltinEntities() {
|
|
|
9353
10279
|
|
|
9354
10280
|
// src/router/MessageRouter.ts
|
|
9355
10281
|
import {
|
|
9356
|
-
getStoreLattice as
|
|
10282
|
+
getStoreLattice as getStoreLattice29,
|
|
9357
10283
|
agentInstanceManager as agentInstanceManager6
|
|
9358
10284
|
} from "@axiom-lattice/core";
|
|
9359
|
-
import { randomUUID as
|
|
10285
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
9360
10286
|
var BindingNotFoundError = class extends Error {
|
|
9361
10287
|
constructor(message) {
|
|
9362
10288
|
super(message);
|
|
@@ -9516,7 +10442,7 @@ var MessageRouter = class {
|
|
|
9516
10442
|
channel: message.channel,
|
|
9517
10443
|
adapterChannel: adapter.channel
|
|
9518
10444
|
}, "Thread resolved by adapter strategy");
|
|
9519
|
-
const threadStore =
|
|
10445
|
+
const threadStore = getStoreLattice29("default", "thread").store;
|
|
9520
10446
|
try {
|
|
9521
10447
|
await threadStore.createThread(
|
|
9522
10448
|
tenantId,
|
|
@@ -9553,8 +10479,8 @@ var MessageRouter = class {
|
|
|
9553
10479
|
}
|
|
9554
10480
|
}
|
|
9555
10481
|
if (!threadId) {
|
|
9556
|
-
const threadStore =
|
|
9557
|
-
const newThreadId =
|
|
10482
|
+
const threadStore = getStoreLattice29("default", "thread").store;
|
|
10483
|
+
const newThreadId = randomUUID9();
|
|
9558
10484
|
console.log({
|
|
9559
10485
|
event: "dispatch:thread:create",
|
|
9560
10486
|
agentId,
|
|
@@ -9979,7 +10905,7 @@ ${summary}`
|
|
|
9979
10905
|
console.log(
|
|
9980
10906
|
`\u5C06\u5728 ${delayMs}ms \u540E\u91CD\u8BD5\u4EFB\u52A1 (${nextRetryCount}/${maxRetries})`
|
|
9981
10907
|
);
|
|
9982
|
-
await new Promise((
|
|
10908
|
+
await new Promise((resolve3) => setTimeout(resolve3, delayMs));
|
|
9983
10909
|
return handleAgentTask(taskRequest, nextRetryCount);
|
|
9984
10910
|
}
|
|
9985
10911
|
if (callback_event) {
|
|
@@ -10159,7 +11085,7 @@ import {
|
|
|
10159
11085
|
getLoggerLattice,
|
|
10160
11086
|
loggerLatticeManager,
|
|
10161
11087
|
sandboxLatticeManager as sandboxLatticeManager2,
|
|
10162
|
-
getStoreLattice as
|
|
11088
|
+
getStoreLattice as getStoreLattice30,
|
|
10163
11089
|
agentInstanceManager as agentInstanceManager8,
|
|
10164
11090
|
createSandboxProvider,
|
|
10165
11091
|
TokenCache,
|
|
@@ -10209,7 +11135,7 @@ var getHeaderValue = (header) => {
|
|
|
10209
11135
|
}
|
|
10210
11136
|
return header;
|
|
10211
11137
|
};
|
|
10212
|
-
var PUBLIC_ROUTES = ["/api/auth/login", "/api/auth/register", "/health"];
|
|
11138
|
+
var PUBLIC_ROUTES = ["/api/auth/login", "/api/auth/register", "/health", "/api/stt/models"];
|
|
10213
11139
|
app.addHook("preHandler", async (request, reply) => {
|
|
10214
11140
|
const user = extractUserFromAuthHeader(request.headers.authorization);
|
|
10215
11141
|
if (user) {
|
|
@@ -10269,9 +11195,9 @@ app.register(multipart, {
|
|
|
10269
11195
|
});
|
|
10270
11196
|
app.register(websocket);
|
|
10271
11197
|
var __filename = fileURLToPath(import.meta.url);
|
|
10272
|
-
var __dirname =
|
|
11198
|
+
var __dirname = path3.dirname(__filename);
|
|
10273
11199
|
app.register(staticPlugin, {
|
|
10274
|
-
root:
|
|
11200
|
+
root: path3.join(__dirname, "../public"),
|
|
10275
11201
|
prefix: "/"
|
|
10276
11202
|
});
|
|
10277
11203
|
app.setErrorHandler((error, request, reply) => {
|
|
@@ -10312,7 +11238,7 @@ function getConfiguredSandboxProvider() {
|
|
|
10312
11238
|
}
|
|
10313
11239
|
async function restoreMcpConnections() {
|
|
10314
11240
|
try {
|
|
10315
|
-
const storeLattice =
|
|
11241
|
+
const storeLattice = getStoreLattice30("default", "mcp");
|
|
10316
11242
|
const store = storeLattice.store;
|
|
10317
11243
|
if (!store) {
|
|
10318
11244
|
logger4.info("MCP store not configured, skipping connection restoration");
|
|
@@ -10381,7 +11307,7 @@ var start = async (config) => {
|
|
|
10381
11307
|
channelDeps = { router, installationStore };
|
|
10382
11308
|
try {
|
|
10383
11309
|
const a2aKeyStore = getStore15("default", "a2aApiKey").store;
|
|
10384
|
-
const a2a = await import("./a2a-
|
|
11310
|
+
const a2a = await import("./a2a-QMHEH3ZT.mjs");
|
|
10385
11311
|
a2a.setA2AKeyStore(a2aKeyStore);
|
|
10386
11312
|
await a2a.refreshStoreKeyMap();
|
|
10387
11313
|
logger4.info("A2A key store initialized");
|
|
@@ -10394,7 +11320,7 @@ var start = async (config) => {
|
|
|
10394
11320
|
}
|
|
10395
11321
|
setEvalRunService(evalRunner);
|
|
10396
11322
|
try {
|
|
10397
|
-
const menuStore =
|
|
11323
|
+
const menuStore = getStoreLattice30("default", "menu").store;
|
|
10398
11324
|
setMenuRegistry(menuStore);
|
|
10399
11325
|
logger4.info("Menu registry initialized");
|
|
10400
11326
|
} catch {
|
|
@@ -10410,7 +11336,7 @@ var start = async (config) => {
|
|
|
10410
11336
|
}
|
|
10411
11337
|
try {
|
|
10412
11338
|
const { ResourceController } = await import("./resources-VA7LSDKN.mjs");
|
|
10413
|
-
const sharedResourceStore =
|
|
11339
|
+
const sharedResourceStore = getStoreLattice30("default", "sharedResource").store;
|
|
10414
11340
|
const cache = new TokenCache();
|
|
10415
11341
|
const resourceController = new ResourceController({
|
|
10416
11342
|
store: sharedResourceStore,
|
|
@@ -10441,11 +11367,6 @@ var start = async (config) => {
|
|
|
10441
11367
|
const target_port = config?.port || Number(process.env.PORT) || 4001;
|
|
10442
11368
|
await app.listen({ port: target_port, host: "0.0.0.0" });
|
|
10443
11369
|
logger4.info(`Lattice Gateway is running on port: ${target_port}`);
|
|
10444
|
-
try {
|
|
10445
|
-
logger4.info("AgentLifecycleManager initialized");
|
|
10446
|
-
} catch (error) {
|
|
10447
|
-
logger4.warn("Failed to initialize AgentLifecycleManager", { error });
|
|
10448
|
-
}
|
|
10449
11370
|
const queueServiceConfig = config?.queueServiceConfig;
|
|
10450
11371
|
if (queueServiceConfig) {
|
|
10451
11372
|
setQueueServiceType(queueServiceConfig.type);
|