@axiom-lattice/gateway 2.1.89 → 2.1.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -6409,8 +6409,183 @@ function registerChannelBindingRoutes(app2) {
6409
6409
  app2.delete("/api/channel-bindings/:id", deleteBinding);
6410
6410
  }
6411
6411
 
6412
+ // src/routes/a2a-bridge.ts
6413
+ import { v4 as v42 } from "uuid";
6414
+ var log = {
6415
+ info(msg, ctx) {
6416
+ console.log(JSON.stringify({ level: "info", msg, ...ctx }));
6417
+ },
6418
+ warn(msg, ctx) {
6419
+ console.warn(JSON.stringify({ level: "warn", msg, ...ctx }));
6420
+ },
6421
+ error(msg, ctx) {
6422
+ console.error(JSON.stringify({ level: "error", msg, ...ctx }));
6423
+ }
6424
+ };
6425
+ var connections = /* @__PURE__ */ new Map();
6426
+ var pending = /* @__PURE__ */ new Map();
6427
+ function getAgentIdFromPath(path3) {
6428
+ const match = path3.match(/^\/api\/a2a\/bridge\/proxy\/([^/]+)/);
6429
+ return match ? match[1] : null;
6430
+ }
6431
+ function handleBridgeConnection(socket, _request) {
6432
+ let agentId = null;
6433
+ log.info("Bridge WebSocket connected");
6434
+ socket.on("message", (raw) => {
6435
+ let msg;
6436
+ try {
6437
+ msg = JSON.parse(raw.toString());
6438
+ } catch {
6439
+ log.warn("Bridge invalid message");
6440
+ return;
6441
+ }
6442
+ switch (msg.type) {
6443
+ case "agent:register": {
6444
+ agentId = msg.agentId;
6445
+ if (!agentId) {
6446
+ socket.send(JSON.stringify({ type: "error", message: "agentId required" }));
6447
+ socket.close();
6448
+ return;
6449
+ }
6450
+ connections.set(agentId, {
6451
+ ws: socket,
6452
+ agentId,
6453
+ agentCard: msg.agentCard ?? {},
6454
+ connectedAt: Date.now()
6455
+ });
6456
+ log.info("Agent registered via bridge", { agentId });
6457
+ socket.send(JSON.stringify({ type: "agent:registered", agentId }));
6458
+ break;
6459
+ }
6460
+ case "http:response": {
6461
+ const requestId = msg.requestId;
6462
+ const p = pending.get(requestId);
6463
+ if (p) {
6464
+ clearTimeout(p.timer);
6465
+ pending.delete(requestId);
6466
+ p.resolve({
6467
+ status: msg.status ?? 200,
6468
+ headers: msg.headers ?? {},
6469
+ body: msg.body ?? ""
6470
+ });
6471
+ }
6472
+ break;
6473
+ }
6474
+ case "http:error": {
6475
+ const requestId = msg.requestId;
6476
+ const p = pending.get(requestId);
6477
+ if (p) {
6478
+ clearTimeout(p.timer);
6479
+ pending.delete(requestId);
6480
+ p.reject(new Error(msg.message ?? "Agent error"));
6481
+ }
6482
+ break;
6483
+ }
6484
+ }
6485
+ });
6486
+ socket.on("close", () => {
6487
+ if (agentId) {
6488
+ connections.delete(agentId);
6489
+ log.info("Bridge WebSocket disconnected", { agentId });
6490
+ for (const [reqId, p] of pending) {
6491
+ if (p.agentId === agentId) {
6492
+ clearTimeout(p.timer);
6493
+ p.reject(new Error("Agent disconnected"));
6494
+ pending.delete(reqId);
6495
+ }
6496
+ }
6497
+ }
6498
+ });
6499
+ socket.on("error", (err) => {
6500
+ log.error("Bridge WebSocket error", { agentId, error: err.message });
6501
+ });
6502
+ }
6503
+ async function handleBridgeProxy(request, reply) {
6504
+ const agentId = getAgentIdFromPath(request.url);
6505
+ if (!agentId) {
6506
+ reply.status(400).send({ error: "Agent ID not found in path" });
6507
+ return;
6508
+ }
6509
+ const conn = connections.get(agentId);
6510
+ if (!conn) {
6511
+ reply.status(503).send({
6512
+ error: "Agent not connected",
6513
+ message: `Agent "${agentId}" is not connected via WebSocket bridge`
6514
+ });
6515
+ return;
6516
+ }
6517
+ const requestId = v42();
6518
+ const subPath = request.url.replace(`/api/a2a/bridge/proxy/${agentId}`, "") || "/";
6519
+ let body;
6520
+ if (request.method === "POST" || request.method === "PUT") {
6521
+ body = typeof request.body === "string" ? request.body : JSON.stringify(request.body ?? {});
6522
+ }
6523
+ const bridgeRequest = {
6524
+ type: "http:request",
6525
+ requestId,
6526
+ method: request.method,
6527
+ path: subPath,
6528
+ headers: {
6529
+ "content-type": request.headers["content-type"] ?? "application/json",
6530
+ "accept": request.headers["accept"] ?? "*/*"
6531
+ },
6532
+ body: body ?? ""
6533
+ };
6534
+ const timeout = 3e5;
6535
+ try {
6536
+ const response = await new Promise((resolve, reject) => {
6537
+ const timer = setTimeout(() => {
6538
+ pending.delete(requestId);
6539
+ reject(new Error(`Bridge request timeout after ${timeout}ms`));
6540
+ }, timeout);
6541
+ pending.set(requestId, { resolve, reject, timer, agentId });
6542
+ try {
6543
+ if (conn.ws.readyState !== conn.ws.OPEN) {
6544
+ pending.delete(requestId);
6545
+ reject(new Error("WebSocket not open"));
6546
+ return;
6547
+ }
6548
+ conn.ws.send(JSON.stringify(bridgeRequest));
6549
+ } catch (err) {
6550
+ clearTimeout(timer);
6551
+ pending.delete(requestId);
6552
+ reject(err);
6553
+ }
6554
+ });
6555
+ for (const [key, value] of Object.entries(response.headers)) {
6556
+ if (!["content-length", "transfer-encoding", "connection"].includes(key.toLowerCase())) {
6557
+ reply.header(key, value);
6558
+ }
6559
+ }
6560
+ reply.status(response.status);
6561
+ try {
6562
+ const parsed = JSON.parse(response.body);
6563
+ reply.send(parsed);
6564
+ } catch {
6565
+ reply.send(response.body);
6566
+ }
6567
+ } catch (err) {
6568
+ log.error("Bridge proxy error", { agentId, error: err.message });
6569
+ reply.status(502).send({
6570
+ error: "Bridge proxy error",
6571
+ message: err.message
6572
+ });
6573
+ }
6574
+ }
6575
+ function registerA2ABridgeRoutes(app2) {
6576
+ app2.get("/api/a2a/bridge", { websocket: true }, (socket, req) => {
6577
+ handleBridgeConnection(socket, req);
6578
+ });
6579
+ app2.route({
6580
+ method: ["GET", "POST", "PUT", "DELETE", "PATCH"],
6581
+ url: "/api/a2a/bridge/proxy/*",
6582
+ handler: handleBridgeProxy
6583
+ });
6584
+ }
6585
+
6412
6586
  // src/routes/index.ts
6413
6587
  var registerLatticeRoutes = (app2, channelDeps) => {
6588
+ registerA2ABridgeRoutes(app2);
6414
6589
  app2.post("/api/runs", createRun);
6415
6590
  app2.post("/api/resume_stream", resumeStream);
6416
6591
  app2.post("/api/assistants/:assistantId/threads/:threadId/abort", abortRun);
@@ -7446,6 +7621,12 @@ app.addHook("preHandler", async (request, reply) => {
7446
7621
  error: "Unauthorized - Missing or invalid token"
7447
7622
  });
7448
7623
  });
7624
+ app.addHook("onRequest", (request, reply, done) => {
7625
+ if (!request.headers["x-project-id"]) {
7626
+ request.headers["x-project-id"] = "default";
7627
+ }
7628
+ done();
7629
+ });
7449
7630
  app.addHook("onRequest", (request, reply, done) => {
7450
7631
  const context = {
7451
7632
  "x-tenant-id": getHeaderValue(request.headers["x-tenant-id"]),
@@ -7553,6 +7734,14 @@ var start = async (config) => {
7553
7734
  installationStore
7554
7735
  });
7555
7736
  channelDeps = { router, installationStore };
7737
+ try {
7738
+ const a2aKeyStore = getStoreLattice16("default", "a2aApiKey").store;
7739
+ const a2a = await import("./a2a-ERG5RMUW.mjs");
7740
+ a2a.setA2AKeyStore(a2aKeyStore);
7741
+ await a2a.refreshStoreKeyMap();
7742
+ logger3.info("A2A key store initialized");
7743
+ } catch {
7744
+ }
7556
7745
  } catch {
7557
7746
  }
7558
7747
  registerLatticeRoutes(app, channelDeps);