@axiom-lattice/gateway 2.1.75 → 2.1.76

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.js CHANGED
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,6 +30,44 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
33
+ // src/channels/lark/sender.ts
34
+ var sender_exports = {};
35
+ __export(sender_exports, {
36
+ createLarkSender: () => createLarkSender
37
+ });
38
+ async function createLarkSender(config, client) {
39
+ const resolved = client ?? await createDefaultLarkClient(config);
40
+ return {
41
+ async sendTextReply(input) {
42
+ const response = await resolved.im.v1.message.create({
43
+ params: {
44
+ receive_id_type: "chat_id"
45
+ },
46
+ data: {
47
+ receive_id: input.chatId,
48
+ msg_type: "text",
49
+ content: JSON.stringify({ text: input.text })
50
+ }
51
+ });
52
+ if (response.code && response.code !== 0) {
53
+ throw new Error("Failed to send Lark reply");
54
+ }
55
+ }
56
+ };
57
+ }
58
+ async function createDefaultLarkClient(config) {
59
+ const Lark = await import("@larksuiteoapi/node-sdk");
60
+ return new Lark.Client({
61
+ appId: config.appId,
62
+ appSecret: config.appSecret
63
+ });
64
+ }
65
+ var init_sender = __esm({
66
+ "src/channels/lark/sender.ts"() {
67
+ "use strict";
68
+ }
69
+ });
70
+
30
71
  // src/index.ts
31
72
  var index_exports = {};
32
73
  __export(index_exports, {
@@ -5714,9 +5755,8 @@ function registerAuthRoutes(app2, config) {
5714
5755
  );
5715
5756
  }
5716
5757
 
5717
- // src/channels/lark/routes.ts
5718
- var import_core29 = require("@axiom-lattice/core");
5719
- var import_pg_stores = require("@axiom-lattice/pg-stores");
5758
+ // src/channels/lark/LarkChannelAdapter.ts
5759
+ var import_zod = require("zod");
5720
5760
 
5721
5761
  // src/channels/lark/parser.ts
5722
5762
  function parseLarkMessageEvent(payload) {
@@ -5756,279 +5796,62 @@ function normalizeChatType(chatType) {
5756
5796
  return chatType === "p2p" ? "direct" : "group";
5757
5797
  }
5758
5798
 
5759
- // src/channels/lark/controller.ts
5760
- function createLarkEventHandler(dependencies) {
5761
- return async function handleLarkEvent2(request, reply) {
5762
- const installationId = request.params?.installationId;
5763
- if (!installationId) {
5764
- reply.status(400).send({ success: false, message: "Missing installationId" });
5765
- return;
5766
- }
5767
- const config = await dependencies.getInstallationConfig(installationId);
5768
- if (!config) {
5769
- reply.status(404).send({ success: false, message: "Lark installation not found" });
5770
- return;
5771
- }
5772
- const body = dependencies.parseRequestBody(
5773
- request.body,
5774
- config.encryptKey
5775
- );
5776
- if (!dependencies.verifyParsedBody(body, config)) {
5777
- reply.status(401).send({ success: false, message: "Invalid Lark request" });
5778
- return;
5779
- }
5780
- if (body.type === "url_verification" && body.challenge) {
5781
- reply.status(200).send({ challenge: body.challenge });
5782
- return;
5783
- }
5784
- const parsed = dependencies.parseEvent(request.body);
5785
- if (!parsed) {
5786
- reply.status(200).send({ success: true, ignored: true });
5787
- return;
5788
- }
5789
- const receipt = await dependencies.claimInboundReceipt({
5790
- channel: "lark",
5791
- channelAppId: config.appId,
5792
- externalMessageId: parsed.messageId,
5793
- tenantId: config.tenantId
5794
- });
5795
- if (!receipt.accepted) {
5796
- reply.status(200).send(
5797
- receipt.status === "processing" ? { success: true, processing: true } : { success: true, duplicate: true }
5798
- );
5799
- return;
5800
- }
5801
- try {
5802
- const { threadId } = await dependencies.resolveThread({
5803
- channel: "lark",
5804
- channelAppId: config.appId,
5805
- tenantId: config.tenantId,
5806
- assistantId: config.assistantId,
5807
- mappingMode: config.mappingMode,
5808
- openId: parsed.openId,
5809
- chatId: parsed.chatId,
5810
- chatType: parsed.chatType,
5811
- messageId: parsed.messageId,
5812
- workspaceId: config.workspaceId,
5813
- projectId: config.projectId
5814
- });
5815
- const text = await dependencies.runAgentAndCollectText({
5816
- tenantId: config.tenantId,
5817
- assistantId: config.assistantId,
5818
- threadId,
5819
- text: parsed.text,
5820
- workspaceId: config.workspaceId,
5821
- projectId: config.projectId
5822
- });
5823
- await dependencies.sendTextReply({
5824
- chatId: parsed.chatId,
5825
- text,
5826
- config
5827
- });
5828
- await dependencies.markInboundReceiptCompleted({
5829
- channel: "lark",
5830
- channelAppId: config.appId,
5831
- externalMessageId: parsed.messageId,
5832
- tenantId: config.tenantId,
5833
- threadId
5834
- });
5835
- reply.status(200).send({ success: true, threadId });
5836
- } catch (error) {
5837
- await dependencies.markInboundReceiptFailed({
5838
- channel: "lark",
5839
- channelAppId: config.appId,
5840
- externalMessageId: parsed.messageId,
5841
- tenantId: config.tenantId
5842
- });
5843
- throw error;
5844
- }
5845
- };
5846
- }
5847
- var handleLarkEvent = createLarkEventHandler({
5848
- getInstallationConfig: async () => null,
5849
- parseRequestBody: (body) => body || {},
5850
- verifyParsedBody: () => true,
5851
- parseEvent: parseLarkMessageEvent,
5852
- claimInboundReceipt: async () => ({ accepted: true, status: "processing" }),
5853
- markInboundReceiptCompleted: async () => void 0,
5854
- markInboundReceiptFailed: async () => void 0,
5855
- resolveThread: async () => ({ threadId: "" }),
5856
- runAgentAndCollectText: async () => "",
5857
- sendTextReply: async () => void 0
5799
+ // src/channels/lark/LarkChannelAdapter.ts
5800
+ var larkConfigSchema = import_zod.z.object({
5801
+ appId: import_zod.z.string(),
5802
+ appSecret: import_zod.z.string(),
5803
+ verificationToken: import_zod.z.string().optional(),
5804
+ encryptKey: import_zod.z.string().optional()
5858
5805
  });
5859
-
5860
- // src/channels/lark/config.ts
5861
- function loadLarkIngressConfig() {
5862
- return {
5863
- enabled: process.env.LARK_ENABLED !== "false",
5864
- appId: process.env.LARK_APP_ID || "",
5865
- appSecret: process.env.LARK_APP_SECRET || "",
5866
- verificationToken: process.env.LARK_VERIFICATION_TOKEN,
5867
- encryptKey: process.env.LARK_ENCRYPT_KEY,
5868
- tenantId: process.env.LARK_TENANT_ID || "default",
5869
- assistantId: process.env.LARK_ASSISTANT_ID || "default_agent",
5870
- workspaceId: process.env.LARK_WORKSPACE_ID,
5871
- projectId: process.env.LARK_PROJECT_ID,
5872
- mappingMode: process.env.LARK_MAPPING_MODE || "hybrid"
5873
- };
5874
- }
5875
- function isLarkIngressEnabled(config) {
5876
- return config.enabled;
5877
- }
5878
-
5879
- // src/channels/lark/mapping-service.ts
5880
- var import_crypto6 = require("crypto");
5881
- function createChannelThreadMappingService(deps) {
5882
- return {
5883
- async getOrCreateThread(input) {
5884
- const externalSubjectKey = buildExternalSubjectKey(input);
5885
- const existing = await deps.mappingStore.getMappingBySubject({
5886
- channel: input.channel,
5887
- channelAppId: input.channelAppId,
5888
- tenantId: input.tenantId,
5889
- assistantId: input.assistantId,
5890
- externalSubjectKey
5891
- });
5892
- if (existing) {
5893
- return { threadId: existing.threadId };
5894
- }
5895
- const threadId = (deps.uuid || import_crypto6.randomUUID)();
5896
- await deps.threadStore.createThread(input.tenantId, input.assistantId, threadId, {
5806
+ var larkChannelAdapter = {
5807
+ channel: "lark",
5808
+ configSchema: larkConfigSchema,
5809
+ async receive(rawPayload, installation) {
5810
+ const event = parseLarkMessageEvent(rawPayload);
5811
+ if (!event) return null;
5812
+ return {
5813
+ channel: "lark",
5814
+ channelInstallationId: installation.id,
5815
+ tenantId: installation.tenantId,
5816
+ sender: {
5817
+ id: event.openId,
5818
+ displayName: void 0
5819
+ },
5820
+ content: {
5821
+ text: event.text,
5897
5822
  metadata: {
5898
- tenantId: input.tenantId,
5899
- workspaceId: input.workspaceId,
5900
- projectId: input.projectId,
5901
- channel: input.channel,
5902
- larkChatId: input.chatId,
5903
- larkOpenId: input.openId
5904
- }
5905
- });
5906
- try {
5907
- await deps.mappingStore.createMapping({
5908
- channel: input.channel,
5909
- channelAppId: input.channelAppId,
5910
- tenantId: input.tenantId,
5911
- assistantId: input.assistantId,
5912
- mappingMode: input.mappingMode,
5913
- externalSubjectType: resolveSubjectType(input.mappingMode, input.chatType) === "user" ? "user" : "chat",
5914
- externalSubjectKey,
5915
- larkOpenId: input.openId,
5916
- larkChatId: input.chatId,
5917
- larkMessageId: input.messageId,
5918
- threadId
5919
- });
5920
- } catch (error) {
5921
- if (!isUniqueViolation(error)) {
5922
- throw error;
5823
+ chatId: event.chatId,
5824
+ chatType: event.chatType,
5825
+ messageId: event.messageId
5923
5826
  }
5924
- const canonical = await deps.mappingStore.getMappingBySubject({
5925
- channel: input.channel,
5926
- channelAppId: input.channelAppId,
5927
- tenantId: input.tenantId,
5928
- assistantId: input.assistantId,
5929
- externalSubjectKey
5930
- });
5931
- if (!canonical) {
5932
- throw error;
5827
+ },
5828
+ conversation: {
5829
+ id: event.chatId,
5830
+ type: event.chatType
5831
+ },
5832
+ replyTarget: {
5833
+ adapterChannel: "lark",
5834
+ channelInstallationId: installation.id,
5835
+ rawTarget: {
5836
+ chatId: event.chatId,
5837
+ messageId: event.messageId,
5838
+ chatType: event.chatType
5933
5839
  }
5934
- await deps.threadStore.deleteThread(input.tenantId, threadId);
5935
- return { threadId: canonical.threadId };
5936
5840
  }
5937
- return { threadId };
5938
- }
5939
- };
5940
- }
5941
- function isUniqueViolation(error) {
5942
- return typeof error === "object" && error !== null && "code" in error && error.code === "23505";
5943
- }
5944
- function buildExternalSubjectKey(input) {
5945
- const subjectType = resolveSubjectType(input.mappingMode, input.chatType);
5946
- const subjectValue = subjectType === "user" ? input.openId : input.chatId;
5947
- return [
5948
- input.channel,
5949
- input.channelAppId,
5950
- `tenant:${input.tenantId}`,
5951
- `assistant:${input.assistantId}`,
5952
- `${subjectType}:${subjectValue}`
5953
- ].join(":");
5954
- }
5955
- function resolveSubjectType(mappingMode, chatType) {
5956
- if (mappingMode === "user") {
5957
- return "user";
5958
- }
5959
- if (mappingMode === "group") {
5960
- return "chat";
5961
- }
5962
- return chatType === "direct" ? "user" : "chat";
5963
- }
5964
-
5965
- // src/channels/lark/runner.ts
5966
- var import_core28 = require("@axiom-lattice/core");
5967
- var import_protocols5 = require("@axiom-lattice/protocols");
5968
-
5969
- // src/channels/lark/aggregator.ts
5970
- var import_protocols4 = require("@axiom-lattice/protocols");
5971
- function aggregateLarkReply(messageId, chunks) {
5972
- return chunks.filter(
5973
- (chunk) => chunk.type === import_protocols4.MessageChunkTypes.AI && chunk.data.id === messageId
5974
- ).map((chunk) => chunk.data.content || "").join("").trim();
5975
- }
5976
-
5977
- // src/channels/lark/runner.ts
5978
- async function runAgentAndCollectLarkReply(input) {
5979
- const agent = import_core28.agentInstanceManager.getAgent({
5980
- tenant_id: input.tenantId,
5981
- assistant_id: input.assistantId,
5982
- thread_id: input.threadId,
5983
- workspace_id: input.workspaceId,
5984
- project_id: input.projectId
5985
- });
5986
- const result = await agent.addMessage({
5987
- input: {
5988
- message: input.text
5989
- }
5990
- });
5991
- const chunks = [];
5992
- const stream = agent.chunkStream(result.messageId, [
5993
- import_protocols5.MessageChunkTypes.MESSAGE_COMPLETED
5994
- ]);
5995
- for await (const chunk of stream) {
5996
- chunks.push(chunk);
5841
+ };
5842
+ },
5843
+ async sendReply(replyTarget, message, installation) {
5844
+ const { createLarkSender: createLarkSender2 } = await Promise.resolve().then(() => (init_sender(), sender_exports));
5845
+ const sender = createLarkSender2(installation.config);
5846
+ await sender.sendTextReply({
5847
+ chatId: replyTarget.rawTarget.chatId,
5848
+ text: message.text
5849
+ });
5997
5850
  }
5998
- return aggregateLarkReply(result.messageId, chunks);
5999
- }
6000
-
6001
- // src/channels/lark/sender.ts
6002
- async function createLarkSender(config, client) {
6003
- const resolved = client ?? await createDefaultLarkClient(config);
6004
- return {
6005
- async sendTextReply(input) {
6006
- const response = await resolved.im.v1.message.create({
6007
- params: {
6008
- receive_id_type: "chat_id"
6009
- },
6010
- data: {
6011
- receive_id: input.chatId,
6012
- msg_type: "text",
6013
- content: JSON.stringify({ text: input.text })
6014
- }
6015
- });
6016
- if (response.code && response.code !== 0) {
6017
- throw new Error("Failed to send Lark reply");
6018
- }
6019
- }
6020
- };
6021
- }
6022
- async function createDefaultLarkClient(config) {
6023
- const Lark = await import("@larksuiteoapi/node-sdk");
6024
- return new Lark.Client({
6025
- appId: config.appId,
6026
- appSecret: config.appSecret
6027
- });
6028
- }
5851
+ };
6029
5852
 
6030
5853
  // src/channels/lark/verification.ts
6031
- var import_crypto7 = __toESM(require("crypto"));
5854
+ var import_crypto6 = __toESM(require("crypto"));
6032
5855
  function parseLarkRequestBody(body, encryptKey) {
6033
5856
  const parsed = body || {};
6034
5857
  if (encryptKey && typeof parsed.encrypt === "string") {
@@ -6037,138 +5860,210 @@ function parseLarkRequestBody(body, encryptKey) {
6037
5860
  return parsed;
6038
5861
  }
6039
5862
  function decryptLarkPayload(encryptKey, encryptedPayload) {
6040
- const key = import_crypto7.default.createHash("sha256").update(encryptKey).digest();
5863
+ const key = import_crypto6.default.createHash("sha256").update(encryptKey).digest();
6041
5864
  const buffer = Buffer.from(encryptedPayload, "base64");
6042
5865
  const iv = buffer.subarray(0, 16);
6043
5866
  const ciphertext = buffer.subarray(16);
6044
- const decipher = import_crypto7.default.createDecipheriv("aes-256-cbc", key, iv);
5867
+ const decipher = import_crypto6.default.createDecipheriv("aes-256-cbc", key, iv);
6045
5868
  const plaintext = Buffer.concat([
6046
5869
  decipher.update(ciphertext),
6047
5870
  decipher.final()
6048
5871
  ]).toString("utf8");
6049
5872
  return JSON.parse(plaintext);
6050
5873
  }
6051
- function createLarkRequestVerifier(config) {
6052
- return function verifyRequest(request) {
6053
- const body = parseLarkRequestBody(request.body, config.encryptKey);
6054
- return verifyLarkParsedBody(body, config);
6055
- };
6056
- }
6057
- function verifyLarkParsedBody(body, config) {
6058
- if (!config.verificationToken) {
6059
- return true;
5874
+
5875
+ // src/logger/Logger.ts
5876
+ var import_pino = __toESM(require("pino"));
5877
+ var import_pino_pretty = require("pino-pretty");
5878
+ var import_pino_roll = require("pino-roll");
5879
+ var PinoLoggerFactory = class _PinoLoggerFactory {
5880
+ constructor() {
5881
+ const isProd = process.env.NODE_ENV === "production";
5882
+ const loggerConfig = {
5883
+ // 自定义时间戳格式
5884
+ timestamp: () => `,"@timestamp":"${(/* @__PURE__ */ new Date()).toISOString()}"`,
5885
+ // 关闭默认的时间戳键
5886
+ base: {
5887
+ "@version": "1",
5888
+ app_name: "lattice",
5889
+ service_name: "lattice/graph-server",
5890
+ thread_name: "main",
5891
+ logger_name: "lattice-graph-logger"
5892
+ },
5893
+ formatters: {
5894
+ level: (label, number) => {
5895
+ return {
5896
+ level: label.toUpperCase(),
5897
+ level_value: number * 1e3
5898
+ };
5899
+ }
5900
+ }
5901
+ };
5902
+ if (isProd) {
5903
+ try {
5904
+ this.pinoLogger = (0, import_pino.default)(
5905
+ loggerConfig,
5906
+ import_pino.default.transport({
5907
+ target: "pino-roll",
5908
+ options: {
5909
+ file: "./logs/fin_ai_graph_server",
5910
+ frequency: "daily",
5911
+ mkdir: true
5912
+ }
5913
+ })
5914
+ );
5915
+ } catch (error) {
5916
+ console.error(
5917
+ "\u65E0\u6CD5\u521D\u59CB\u5316 pino-roll \u65E5\u5FD7\u8BB0\u5F55\u5668\uFF0C\u56DE\u9000\u5230\u63A7\u5236\u53F0\u65E5\u5FD7",
5918
+ error
5919
+ );
5920
+ this.pinoLogger = (0, import_pino.default)({
5921
+ ...loggerConfig,
5922
+ transport: {
5923
+ target: "pino-pretty",
5924
+ options: {
5925
+ colorize: true
5926
+ }
5927
+ }
5928
+ });
5929
+ }
5930
+ } else {
5931
+ this.pinoLogger = (0, import_pino.default)({
5932
+ ...loggerConfig,
5933
+ transport: {
5934
+ target: "pino-pretty",
5935
+ options: {
5936
+ colorize: true
5937
+ }
5938
+ }
5939
+ });
5940
+ }
6060
5941
  }
6061
- return extractVerificationToken(body) === config.verificationToken;
6062
- }
6063
- function extractVerificationToken(body) {
6064
- if (typeof body.token === "string") {
6065
- return body.token;
5942
+ static getInstance() {
5943
+ if (!_PinoLoggerFactory.instance) {
5944
+ _PinoLoggerFactory.instance = new _PinoLoggerFactory();
5945
+ }
5946
+ return _PinoLoggerFactory.instance;
5947
+ }
5948
+ getPinoLogger() {
5949
+ return this.pinoLogger;
5950
+ }
5951
+ };
5952
+ var Logger = class _Logger {
5953
+ constructor(options) {
5954
+ this.context = options?.context || {};
5955
+ this.name = options?.name || "lattice-graph-logger";
5956
+ this.serviceName = options?.serviceName || "lattice/graph-server";
5957
+ }
5958
+ /**
5959
+ * 获取合并了上下文的日志对象
5960
+ * @param additionalContext 额外的上下文数据
5961
+ * @returns 带有上下文的pino日志对象
5962
+ */
5963
+ getContextualLogger(additionalContext) {
5964
+ const pinoLogger = PinoLoggerFactory.getInstance().getPinoLogger();
5965
+ const contextObj = {
5966
+ "x-user-id": this.context["x-user-id"] || "",
5967
+ "x-tenant-id": this.context["x-tenant-id"] || "",
5968
+ "x-request-id": this.context["x-request-id"] || "",
5969
+ "x-task-id": this.context["x-task-id"] || "",
5970
+ "x-thread-id": this.context["x-thread-id"] || "",
5971
+ service_name: this.serviceName,
5972
+ logger_name: this.name,
5973
+ ...additionalContext
5974
+ };
5975
+ return pinoLogger.child(contextObj);
5976
+ }
5977
+ info(msg, obj) {
5978
+ this.getContextualLogger(obj).info(msg);
6066
5979
  }
6067
- if (typeof body.header?.token === "string") {
6068
- return body.header.token;
5980
+ error(msg, obj) {
5981
+ this.getContextualLogger(obj).error(msg);
6069
5982
  }
6070
- return void 0;
5983
+ warn(msg, obj) {
5984
+ this.getContextualLogger(obj).warn(msg);
5985
+ }
5986
+ debug(msg, obj) {
5987
+ this.getContextualLogger(obj).debug(msg);
5988
+ }
5989
+ /**
5990
+ * 更新Logger实例的上下文
5991
+ */
5992
+ updateContext(context) {
5993
+ this.context = {
5994
+ ...this.context,
5995
+ ...context
5996
+ };
5997
+ }
5998
+ /**
5999
+ * 创建一个新的Logger实例,继承当前Logger的上下文
6000
+ */
6001
+ child(options) {
6002
+ return new _Logger({
6003
+ name: options.name || this.name,
6004
+ serviceName: options.serviceName || this.serviceName,
6005
+ context: {
6006
+ ...this.context,
6007
+ ...options.context
6008
+ }
6009
+ });
6010
+ }
6011
+ };
6012
+
6013
+ // src/channels/lark/controller.ts
6014
+ var logger = new Logger({ serviceName: "lattice/gateway/lark" });
6015
+ function createLarkEventHandler(deps) {
6016
+ return async function handleLarkEvent(request, reply) {
6017
+ const { installationId } = request.params;
6018
+ const installation = await deps.installationStore.getInstallationById(installationId);
6019
+ if (!installation || installation.channel !== "lark") {
6020
+ reply.status(404).send({ success: false, message: "Installation not found" });
6021
+ return;
6022
+ }
6023
+ const body = parseLarkRequestBody(request.body, installation.config.encryptKey);
6024
+ if (body.type === "url_verification" && body.challenge) {
6025
+ reply.status(200).send({ challenge: body.challenge });
6026
+ return;
6027
+ }
6028
+ const inboundMessage = await larkChannelAdapter.receive(request.body, installation);
6029
+ if (!inboundMessage) {
6030
+ reply.status(200).send();
6031
+ return;
6032
+ }
6033
+ deps.router.dispatch(inboundMessage).catch((error) => {
6034
+ logger.error("Lark message dispatch error", {
6035
+ error: error instanceof Error ? error.message : String(error)
6036
+ });
6037
+ });
6038
+ reply.status(200).send();
6039
+ };
6071
6040
  }
6072
6041
 
6073
6042
  // src/channels/lark/routes.ts
6074
- function registerLarkChannelRoutes(app2, dependencies) {
6075
- const config = loadLarkIngressConfig();
6076
- if (!dependencies && !isLarkIngressEnabled(config)) {
6077
- return;
6078
- }
6079
- const handlerDependencies = dependencies || createDefaultLarkDependencies();
6043
+ function registerLarkChannelRoutes(app2, deps) {
6044
+ const handler = createLarkEventHandler({
6045
+ installationStore: deps.installationStore,
6046
+ router: deps.router
6047
+ });
6080
6048
  app2.post(
6081
6049
  "/api/channels/lark/installations/:installationId/events",
6082
- createLarkEventHandler({
6083
- ...handlerDependencies
6084
- })
6050
+ handler
6085
6051
  );
6086
6052
  }
6087
- function createDefaultLarkDependencies() {
6088
- const installationStore = new import_pg_stores.PostgreSQLChannelInstallationStore({
6089
- poolConfig: getDatabaseUrl()
6090
- });
6091
- const threadStore = (0, import_core29.getStoreLattice)("default", "thread").store;
6092
- const mappingStore = new import_pg_stores.ChannelIdentityMappingStore({
6093
- poolConfig: getDatabaseUrl()
6094
- });
6095
- const mappingService = createChannelThreadMappingService({
6096
- mappingStore,
6097
- threadStore
6098
- });
6099
- return {
6100
- getInstallationConfig: async (installationId) => {
6101
- const installation = await installationStore.getInstallationById(
6102
- installationId
6103
- );
6104
- if (!installation || installation.channel !== "lark") {
6105
- return null;
6106
- }
6107
- return {
6108
- enabled: true,
6109
- installationId: installation.id,
6110
- tenantId: installation.tenantId,
6111
- assistantId: installation.config.assistantId,
6112
- appId: installation.config.appId,
6113
- appSecret: installation.config.appSecret,
6114
- verificationToken: installation.config.verificationToken,
6115
- encryptKey: installation.config.encryptKey,
6116
- workspaceId: installation.config.workspaceId,
6117
- projectId: installation.config.projectId,
6118
- mappingMode: installation.config.mappingMode
6119
- };
6120
- },
6121
- parseRequestBody: (body, encryptKey) => parseLarkRequestBody(body, encryptKey),
6122
- verifyParsedBody: (body, config) => {
6123
- if (!config.verificationToken) {
6124
- return true;
6125
- }
6126
- return createLarkRequestVerifier(config)({
6127
- body
6128
- });
6129
- },
6130
- parseEvent: parseLarkMessageEvent,
6131
- claimInboundReceipt: (input) => mappingStore.claimInboundReceipt(input),
6132
- markInboundReceiptCompleted: (input) => mappingStore.markInboundReceiptCompleted(input),
6133
- markInboundReceiptFailed: (input) => mappingStore.markInboundReceiptFailed(input),
6134
- resolveThread: (input) => mappingService.getOrCreateThread(input),
6135
- runAgentAndCollectText: ({ tenantId, assistantId, threadId, text, workspaceId, projectId }) => runAgentAndCollectLarkReply({
6136
- tenantId,
6137
- assistantId,
6138
- threadId,
6139
- text,
6140
- workspaceId,
6141
- projectId
6142
- }),
6143
- sendTextReply: async ({ chatId, text, config }) => {
6144
- const sender = await createLarkSender({
6145
- appId: config.appId,
6146
- appSecret: config.appSecret
6147
- });
6148
- await sender.sendTextReply({ chatId, text });
6149
- }
6150
- };
6151
- }
6152
- function getDatabaseUrl() {
6153
- const databaseUrl = process.env.DATABASE_URL;
6154
- if (!databaseUrl) {
6155
- throw new Error("DATABASE_URL is required for Lark channel ingress");
6156
- }
6157
- return databaseUrl;
6158
- }
6159
6053
 
6160
6054
  // src/channels/routes.ts
6161
6055
  var channelRouteRegistrars = [
6162
- (app2, dependencies) => registerLarkChannelRoutes(app2, dependencies.lark)
6056
+ (app2, deps) => registerLarkChannelRoutes(app2, deps)
6163
6057
  ];
6164
- function registerChannelRoutes(app2, dependencies = {}) {
6058
+ function registerChannelRoutes(app2, dependencies) {
6059
+ if (!dependencies) return;
6165
6060
  for (const registerRoutes of channelRouteRegistrars) {
6166
6061
  registerRoutes(app2, dependencies);
6167
6062
  }
6168
6063
  }
6169
6064
 
6170
6065
  // src/controllers/channel-installations.ts
6171
- var import_crypto8 = require("crypto");
6066
+ var import_crypto7 = require("crypto");
6172
6067
  function getTenantId11(request) {
6173
6068
  const userTenantId = request.user?.tenantId;
6174
6069
  if (userTenantId) {
@@ -6177,12 +6072,15 @@ function getTenantId11(request) {
6177
6072
  return request.headers["x-tenant-id"] || "default";
6178
6073
  }
6179
6074
  async function getInstallationStore() {
6180
- const { PostgreSQLChannelInstallationStore: PostgreSQLChannelInstallationStore2 } = await import("@axiom-lattice/pg-stores");
6075
+ const { getStoreLattice: getStoreLattice16 } = await import("@axiom-lattice/core");
6076
+ const store = getStoreLattice16("default", "channelInstallation").store;
6077
+ if (store) return store;
6078
+ const { PostgreSQLChannelInstallationStore } = await import("@axiom-lattice/pg-stores");
6181
6079
  const databaseUrl = process.env.DATABASE_URL;
6182
6080
  if (!databaseUrl) {
6183
6081
  throw new Error("DATABASE_URL is required for channel installation store");
6184
6082
  }
6185
- return new PostgreSQLChannelInstallationStore2({
6083
+ return new PostgreSQLChannelInstallationStore({
6186
6084
  poolConfig: databaseUrl
6187
6085
  });
6188
6086
  }
@@ -6281,7 +6179,7 @@ async function createChannelInstallation(request, reply) {
6281
6179
  }
6282
6180
  }
6283
6181
  const store = await getInstallationStore();
6284
- const installationId = body.id || (0, import_crypto8.randomUUID)();
6182
+ const installationId = body.id || (0, import_crypto7.randomUUID)();
6285
6183
  const installation = await store.createInstallation(
6286
6184
  tenantId,
6287
6185
  installationId,
@@ -6404,8 +6302,129 @@ function registerChannelInstallationRoutes(app2) {
6404
6302
  app2.delete("/api/channel-installations/:installationId", deleteChannelInstallation);
6405
6303
  }
6406
6304
 
6305
+ // src/bindings/index.ts
6306
+ var registryInstance = null;
6307
+ function setBindingRegistry(registry) {
6308
+ registryInstance = registry;
6309
+ }
6310
+ function getBindingRegistry() {
6311
+ if (!registryInstance) {
6312
+ throw new Error("BindingRegistry not initialized. Call setBindingRegistry() first.");
6313
+ }
6314
+ return registryInstance;
6315
+ }
6316
+
6317
+ // src/controllers/channel-bindings.ts
6318
+ function getTenantId12(request) {
6319
+ const userTenantId = request.user?.tenantId;
6320
+ if (userTenantId) return userTenantId;
6321
+ return request.headers["x-tenant-id"] || "default";
6322
+ }
6323
+ async function getBindingList(request, _reply) {
6324
+ const tenantId = getTenantId12(request);
6325
+ const { channel, agentId, channelInstallationId, limit, offset } = request.query;
6326
+ try {
6327
+ const registry = getBindingRegistry();
6328
+ const bindings = await registry.list({ channel, agentId, tenantId, channelInstallationId, limit, offset });
6329
+ return { success: true, message: "Bindings retrieved", data: { records: bindings, total: bindings.length } };
6330
+ } catch (error) {
6331
+ console.error("Failed to get bindings:", error);
6332
+ return { success: false, message: "Failed to retrieve bindings", data: { records: [], total: 0 } };
6333
+ }
6334
+ }
6335
+ async function getBinding(request, reply) {
6336
+ const tenantId = getTenantId12(request);
6337
+ try {
6338
+ const registry = getBindingRegistry();
6339
+ const bindings = await registry.list({ tenantId });
6340
+ const binding = bindings.find((b) => b.id === request.params.id);
6341
+ if (!binding || binding.tenantId !== tenantId) {
6342
+ reply.status(404);
6343
+ return { success: false, message: "Binding not found" };
6344
+ }
6345
+ return { success: true, message: "Binding retrieved", data: binding };
6346
+ } catch (error) {
6347
+ console.error("Failed to get binding:", error);
6348
+ return { success: false, message: "Failed to retrieve binding" };
6349
+ }
6350
+ }
6351
+ async function createBinding(request, reply) {
6352
+ const tenantId = getTenantId12(request);
6353
+ try {
6354
+ const registry = getBindingRegistry();
6355
+ const binding = await registry.create({ ...request.body, tenantId });
6356
+ reply.status(201);
6357
+ return { success: true, message: "Binding created", data: binding };
6358
+ } catch (error) {
6359
+ console.error("Failed to create binding:", error);
6360
+ reply.status(500);
6361
+ return { success: false, message: "Failed to create binding" };
6362
+ }
6363
+ }
6364
+ async function updateBinding(request, reply) {
6365
+ try {
6366
+ const tenantId = getTenantId12(request);
6367
+ const registry = getBindingRegistry();
6368
+ const bindings = await registry.list({ tenantId });
6369
+ const existing = bindings.find((b) => b.id === request.params.id);
6370
+ if (!existing || existing.tenantId !== tenantId) {
6371
+ reply.status(404);
6372
+ return { success: false, message: "Binding not found" };
6373
+ }
6374
+ const binding = await registry.update(request.params.id, request.body);
6375
+ return { success: true, message: "Binding updated", data: binding };
6376
+ } catch (error) {
6377
+ console.error("Failed to update binding:", error);
6378
+ reply.status(500);
6379
+ return { success: false, message: "Failed to update binding" };
6380
+ }
6381
+ }
6382
+ async function deleteBinding(request, reply) {
6383
+ try {
6384
+ const tenantId = getTenantId12(request);
6385
+ const registry = getBindingRegistry();
6386
+ const bindings = await registry.list({ tenantId });
6387
+ const existing = bindings.find((b) => b.id === request.params.id);
6388
+ if (!existing || existing.tenantId !== tenantId) {
6389
+ reply.status(404);
6390
+ return { success: false, message: "Binding not found" };
6391
+ }
6392
+ await registry.delete(request.params.id);
6393
+ return { success: true, message: "Binding deleted" };
6394
+ } catch (error) {
6395
+ console.error("Failed to delete binding:", error);
6396
+ reply.status(500);
6397
+ return { success: false, message: "Failed to delete binding" };
6398
+ }
6399
+ }
6400
+ async function resolveBinding(request, _reply) {
6401
+ const tenantId = getTenantId12(request);
6402
+ const { channel, senderId, channelInstallationId } = request.query;
6403
+ try {
6404
+ const registry = getBindingRegistry();
6405
+ const binding = await registry.resolve({ channel, senderId, channelInstallationId, tenantId });
6406
+ if (!binding) {
6407
+ return { success: false, message: "No binding found", data: null };
6408
+ }
6409
+ return { success: true, message: "Binding found", data: binding };
6410
+ } catch (error) {
6411
+ console.error("Failed to resolve binding:", error);
6412
+ return { success: false, message: "Failed to resolve binding", data: null };
6413
+ }
6414
+ }
6415
+
6416
+ // src/routes/channel-bindings.ts
6417
+ function registerChannelBindingRoutes(app2) {
6418
+ app2.get("/api/channel-bindings", getBindingList);
6419
+ app2.get("/api/channel-bindings/resolve", resolveBinding);
6420
+ app2.post("/api/channel-bindings", createBinding);
6421
+ app2.get("/api/channel-bindings/:id", getBinding);
6422
+ app2.put("/api/channel-bindings/:id", updateBinding);
6423
+ app2.delete("/api/channel-bindings/:id", deleteBinding);
6424
+ }
6425
+
6407
6426
  // src/routes/index.ts
6408
- var registerLatticeRoutes = (app2) => {
6427
+ var registerLatticeRoutes = (app2, channelDeps) => {
6409
6428
  app2.post("/api/runs", createRun);
6410
6429
  app2.post("/api/resume_stream", resumeStream);
6411
6430
  app2.post("/api/assistants/:assistantId/threads/:threadId/abort", abortRun);
@@ -6540,8 +6559,46 @@ var registerLatticeRoutes = (app2) => {
6540
6559
  autoApproveUsers: process.env.AUTO_APPROVE_USERS !== "false",
6541
6560
  allowTenantRegistration: process.env.ALLOW_TENANT_REGISTRATION !== "false"
6542
6561
  });
6543
- registerChannelRoutes(app2);
6562
+ registerChannelRoutes(app2, channelDeps);
6544
6563
  registerChannelInstallationRoutes(app2);
6564
+ if (channelDeps) {
6565
+ registerChannelBindingRoutes(app2);
6566
+ }
6567
+ if (channelDeps?.router) {
6568
+ app2.post("/api/channels/inbound", async (request, reply) => {
6569
+ try {
6570
+ const router = channelDeps.router;
6571
+ const msg = request.body;
6572
+ if (!msg.channel || !msg.sender || !msg.content) {
6573
+ reply.status(400).send({
6574
+ success: false,
6575
+ message: "Missing required fields: channel, sender, content"
6576
+ });
6577
+ return;
6578
+ }
6579
+ const inboundMessage = {
6580
+ channel: msg.channel,
6581
+ channelInstallationId: msg.channelInstallationId || "",
6582
+ tenantId: msg.tenantId || "default",
6583
+ sender: {
6584
+ id: msg.sender.id,
6585
+ displayName: msg.sender.displayName
6586
+ },
6587
+ content: {
6588
+ text: msg.content.text
6589
+ },
6590
+ replyTarget: msg.replyTarget
6591
+ };
6592
+ await router.dispatch(inboundMessage).catch((error) => {
6593
+ console.error("Inbound dispatch error:", error);
6594
+ });
6595
+ reply.status(200).send({ accepted: true });
6596
+ } catch (error) {
6597
+ console.error("Inbound route error:", error);
6598
+ reply.status(500).send({ success: false, message: "Internal error" });
6599
+ }
6600
+ });
6601
+ }
6545
6602
  app2.get(
6546
6603
  "/api/workflows/definitions",
6547
6604
  getAllWorkflowDefinitions
@@ -6572,6 +6629,267 @@ var registerLatticeRoutes = (app2) => {
6572
6629
  );
6573
6630
  };
6574
6631
 
6632
+ // src/router/MessageRouter.ts
6633
+ var import_core28 = require("@axiom-lattice/core");
6634
+ var import_crypto8 = require("crypto");
6635
+ var BindingNotFoundError = class extends Error {
6636
+ constructor(message) {
6637
+ super(message);
6638
+ this.name = "BindingNotFoundError";
6639
+ }
6640
+ };
6641
+ var MessageRouter = class {
6642
+ constructor(config) {
6643
+ this.middlewares = [...config.middlewares];
6644
+ this.bindingRegistry = config.bindingRegistry;
6645
+ this.adapterRegistry = config.adapterRegistry;
6646
+ this.installationStore = config.installationStore;
6647
+ }
6648
+ use(middleware) {
6649
+ this.middlewares.push(middleware);
6650
+ }
6651
+ async dispatch(message) {
6652
+ const ctx = {
6653
+ inboundMessage: message,
6654
+ metadata: {}
6655
+ };
6656
+ try {
6657
+ await this.runMiddlewares(ctx, async () => {
6658
+ let binding = await this.bindingRegistry.resolve({
6659
+ channel: message.channel,
6660
+ senderId: message.sender.id,
6661
+ channelInstallationId: message.channelInstallationId,
6662
+ tenantId: message.tenantId
6663
+ });
6664
+ if (!binding) {
6665
+ const installation = await this.installationStore.getInstallationById(
6666
+ message.channelInstallationId
6667
+ );
6668
+ if (installation?.rejectWhenNoBinding) {
6669
+ throw new BindingNotFoundError(
6670
+ `No binding for sender "${message.sender.id}" on channel "${message.channel}"`
6671
+ );
6672
+ }
6673
+ if (installation?.fallbackAgentId) {
6674
+ binding = {
6675
+ id: "fallback",
6676
+ channel: message.channel,
6677
+ channelInstallationId: message.channelInstallationId,
6678
+ tenantId: message.tenantId,
6679
+ senderId: message.sender.id,
6680
+ agentId: installation.fallbackAgentId,
6681
+ threadId: void 0,
6682
+ threadMode: "fixed",
6683
+ enabled: true,
6684
+ createdAt: /* @__PURE__ */ new Date(),
6685
+ updatedAt: /* @__PURE__ */ new Date()
6686
+ };
6687
+ } else {
6688
+ throw new BindingNotFoundError(
6689
+ `No binding for sender "${message.sender.id}" and no fallback configured`
6690
+ );
6691
+ }
6692
+ }
6693
+ ctx.binding = binding;
6694
+ if (!binding.enabled) {
6695
+ throw new BindingNotFoundError(
6696
+ `Binding for sender "${message.sender.id}" is disabled`
6697
+ );
6698
+ }
6699
+ let threadId = ctx.binding.threadId;
6700
+ if (!threadId) {
6701
+ const threadStore = (0, import_core28.getStoreLattice)("default", "thread").store;
6702
+ const newThreadId = (0, import_crypto8.randomUUID)();
6703
+ const newThread = await threadStore.createThread(
6704
+ message.tenantId,
6705
+ ctx.binding.agentId,
6706
+ newThreadId,
6707
+ {
6708
+ metadata: {
6709
+ channel: message.channel,
6710
+ channelInstallationId: message.channelInstallationId,
6711
+ senderId: message.sender.id,
6712
+ bindingId: ctx.binding.id
6713
+ }
6714
+ }
6715
+ );
6716
+ threadId = newThread.id;
6717
+ if (ctx.binding.id !== "fallback") {
6718
+ await this.bindingRegistry.update(ctx.binding.id, { threadId });
6719
+ ctx.binding.threadId = threadId;
6720
+ } else {
6721
+ ctx.binding.threadId = threadId;
6722
+ }
6723
+ }
6724
+ const agent = import_core28.agentInstanceManager.getAgent({
6725
+ tenant_id: message.tenantId,
6726
+ assistant_id: ctx.binding.agentId,
6727
+ thread_id: threadId,
6728
+ workspace_id: ctx.binding.workspaceId || "",
6729
+ project_id: ctx.binding.projectId || ""
6730
+ });
6731
+ const invokeResult = await agent.invoke({
6732
+ input: { message: message.content.text }
6733
+ });
6734
+ ctx.result = extractTextFromInvokeResult(invokeResult);
6735
+ if (message.replyTarget) {
6736
+ const adapter = this.adapterRegistry.get(message.replyTarget.adapterChannel);
6737
+ if (adapter) {
6738
+ const installation = await this.installationStore.getInstallationById(
6739
+ message.channelInstallationId
6740
+ );
6741
+ if (installation) {
6742
+ await adapter.sendReply(
6743
+ message.replyTarget,
6744
+ { text: ctx.result },
6745
+ installation
6746
+ );
6747
+ }
6748
+ }
6749
+ }
6750
+ });
6751
+ return {
6752
+ success: true,
6753
+ bindingId: ctx.binding?.id,
6754
+ threadId: ctx.binding?.threadId,
6755
+ result: ctx.result
6756
+ };
6757
+ } catch (error) {
6758
+ ctx.error = error instanceof Error ? error : new Error(String(error));
6759
+ return {
6760
+ success: false,
6761
+ bindingId: ctx.binding?.id,
6762
+ threadId: ctx.binding?.threadId,
6763
+ error: ctx.error
6764
+ };
6765
+ }
6766
+ }
6767
+ async runMiddlewares(ctx, finalHandler) {
6768
+ const dispatch = (index) => {
6769
+ if (index >= this.middlewares.length) {
6770
+ return finalHandler();
6771
+ }
6772
+ const middleware = this.middlewares[index];
6773
+ return middleware(ctx, () => dispatch(index + 1));
6774
+ };
6775
+ return dispatch(0);
6776
+ }
6777
+ };
6778
+ function extractTextFromInvokeResult(result) {
6779
+ if (result && typeof result === "object" && "messages" in result) {
6780
+ const messages = result.messages;
6781
+ if (Array.isArray(messages)) {
6782
+ const aiMessages = messages.filter((m) => m.role === "ai");
6783
+ if (aiMessages.length > 0) {
6784
+ return aiMessages.map((m) => m.content).join("\n");
6785
+ }
6786
+ }
6787
+ }
6788
+ return JSON.stringify(result);
6789
+ }
6790
+
6791
+ // src/channels/registry.ts
6792
+ var ChannelAdapterRegistry = class {
6793
+ constructor() {
6794
+ this.adapters = /* @__PURE__ */ new Map();
6795
+ }
6796
+ register(adapter) {
6797
+ if (this.adapters.has(adapter.channel)) {
6798
+ throw new Error(`Channel adapter "${adapter.channel}" already registered`);
6799
+ }
6800
+ this.adapters.set(adapter.channel, adapter);
6801
+ }
6802
+ get(channel) {
6803
+ return this.adapters.get(channel);
6804
+ }
6805
+ list() {
6806
+ return Array.from(this.adapters.keys());
6807
+ }
6808
+ };
6809
+
6810
+ // src/router/middlewares/deduplication.ts
6811
+ var processedMessages = /* @__PURE__ */ new Map();
6812
+ function createDeduplicationMiddleware(ttlMs = 5 * 60 * 1e3) {
6813
+ return async (ctx, next) => {
6814
+ const msg = ctx.inboundMessage;
6815
+ const msgId = msg.content.metadata?.messageId;
6816
+ const key = msgId ? `${msg.channel}:${msg.channelInstallationId}:${msgId}` : `${msg.channel}:${msg.channelInstallationId}:${msg.sender.id}`;
6817
+ const now = Date.now();
6818
+ const lastProcessed = processedMessages.get(key);
6819
+ if (lastProcessed && now - lastProcessed < ttlMs) return;
6820
+ processedMessages.set(key, now);
6821
+ if (processedMessages.size > 1e4) {
6822
+ const oldest = Array.from(processedMessages.entries()).sort((a, b) => a[1] - b[1])[0];
6823
+ if (oldest) processedMessages.delete(oldest[0]);
6824
+ }
6825
+ await next();
6826
+ };
6827
+ }
6828
+
6829
+ // src/router/middlewares/rateLimit.ts
6830
+ var RateLimitError = class extends Error {
6831
+ constructor(message) {
6832
+ super(message);
6833
+ this.name = "RateLimitError";
6834
+ }
6835
+ };
6836
+ var rateCounters = /* @__PURE__ */ new Map();
6837
+ function createRateLimitMiddleware(maxRequests = 10, windowMs = 60 * 1e3, maxEntries = 1e4) {
6838
+ return async (ctx, next) => {
6839
+ const senderKey = `${ctx.inboundMessage.channel}:${ctx.inboundMessage.sender.id}`;
6840
+ const now = Date.now();
6841
+ let counter = rateCounters.get(senderKey);
6842
+ if (!counter || now > counter.resetAt) {
6843
+ counter = { count: 0, resetAt: now + windowMs };
6844
+ }
6845
+ counter.count++;
6846
+ rateCounters.set(senderKey, counter);
6847
+ if (rateCounters.size > maxEntries) {
6848
+ const oldest = Array.from(rateCounters.entries()).sort((a, b) => a[1].resetAt - b[1].resetAt)[0];
6849
+ if (oldest) rateCounters.delete(oldest[0]);
6850
+ }
6851
+ if (counter.count > maxRequests) {
6852
+ throw new RateLimitError(`Rate limit exceeded`);
6853
+ }
6854
+ await next();
6855
+ };
6856
+ }
6857
+
6858
+ // src/router/middlewares/auditLogger.ts
6859
+ var logger2 = new Logger({ serviceName: "lattice/gateway/audit" });
6860
+ function createAuditLoggerMiddleware() {
6861
+ return async (ctx, next) => {
6862
+ const start2 = Date.now();
6863
+ try {
6864
+ await next();
6865
+ logger2.info("message routed", {
6866
+ event: "message:routed",
6867
+ channel: ctx.inboundMessage.channel,
6868
+ senderId: ctx.inboundMessage.sender.id,
6869
+ agentId: ctx.binding?.agentId,
6870
+ threadId: ctx.binding?.threadId,
6871
+ duration: Date.now() - start2,
6872
+ status: "success"
6873
+ });
6874
+ } catch (error) {
6875
+ logger2.error(
6876
+ error instanceof Error ? error.message : String(error),
6877
+ {
6878
+ event: "message:error",
6879
+ channel: ctx.inboundMessage.channel,
6880
+ senderId: ctx.inboundMessage.sender.id,
6881
+ duration: Date.now() - start2,
6882
+ status: "error"
6883
+ }
6884
+ );
6885
+ throw error;
6886
+ }
6887
+ };
6888
+ }
6889
+
6890
+ // src/index.ts
6891
+ var import_core30 = require("@axiom-lattice/core");
6892
+
6575
6893
  // src/swagger.ts
6576
6894
  var import_swagger = __toESM(require("@fastify/swagger"));
6577
6895
  var import_swagger_ui = __toESM(require("@fastify/swagger-ui"));
@@ -6635,7 +6953,7 @@ var configureSwagger = async (app2, customSwaggerConfig, customSwaggerUiConfig)
6635
6953
  };
6636
6954
 
6637
6955
  // src/services/agent_task_consumer.ts
6638
- var import_core30 = require("@axiom-lattice/core");
6956
+ var import_core29 = require("@axiom-lattice/core");
6639
6957
  var handleAgentTask = async (taskRequest, retryCount = 0) => {
6640
6958
  const {
6641
6959
  assistant_id,
@@ -6653,18 +6971,18 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
6653
6971
  console.log(
6654
6972
  `\u5F00\u59CB\u5904\u7406\u4EFB\u52A1 [assistant_id: ${assistant_id}, thread_id: ${thread_id}]`
6655
6973
  );
6656
- const agent = import_core30.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
6657
- await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core30.QueueMode.STEER);
6974
+ const agent = import_core29.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
6975
+ await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core29.QueueMode.STEER);
6658
6976
  if (callback_event) {
6659
6977
  agent.subscribeOnce("message:completed", (evt) => {
6660
- import_core30.eventBus.publish(callback_event, {
6978
+ import_core29.eventBus.publish(callback_event, {
6661
6979
  success: true,
6662
6980
  state: evt.state,
6663
6981
  config: { assistant_id, thread_id, tenant_id }
6664
6982
  });
6665
6983
  if (main_thread_id && main_tenant_id) {
6666
6984
  try {
6667
- const mainAgent = import_core30.agentInstanceManager.getAgent({
6985
+ const mainAgent = import_core29.agentInstanceManager.getAgent({
6668
6986
  assistant_id: main_assistant_id ?? assistant_id,
6669
6987
  thread_id: main_thread_id,
6670
6988
  tenant_id: main_tenant_id
@@ -6692,7 +7010,7 @@ ${summary}`
6692
7010
  }
6693
7011
  });
6694
7012
  agent.subscribeOnce("message:interrupted", (evt) => {
6695
- import_core30.eventBus.publish(callback_event, {
7013
+ import_core29.eventBus.publish(callback_event, {
6696
7014
  success: true,
6697
7015
  state: evt.state,
6698
7016
  config: { assistant_id, thread_id, tenant_id }
@@ -6716,7 +7034,7 @@ ${summary}`
6716
7034
  return handleAgentTask(taskRequest, nextRetryCount);
6717
7035
  }
6718
7036
  if (callback_event) {
6719
- import_core30.eventBus.publish(callback_event, {
7037
+ import_core29.eventBus.publish(callback_event, {
6720
7038
  success: false,
6721
7039
  error: error instanceof Error ? error.message : String(error),
6722
7040
  config: { assistant_id, thread_id, tenant_id }
@@ -6754,7 +7072,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
6754
7072
  * 初始化事件监听和队列轮询
6755
7073
  */
6756
7074
  initialize() {
6757
- import_core30.eventBus.subscribe(import_core30.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
7075
+ import_core29.eventBus.subscribe(import_core29.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
6758
7076
  this.startPollingQueue();
6759
7077
  console.log("Agent\u4EFB\u52A1\u6D88\u8D39\u8005\u5DF2\u542F\u52A8\u5E76\u76D1\u542C\u4EFB\u52A1\u4E8B\u4EF6\u548C\u961F\u5217");
6760
7078
  }
@@ -6873,7 +7191,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
6873
7191
  handleAgentTask(taskRequest).catch((error) => {
6874
7192
  console.error("\u5904\u7406Agent\u4EFB\u52A1\u65F6\u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:", error);
6875
7193
  if (taskRequest.callback_event) {
6876
- import_core30.eventBus.publish(taskRequest.callback_event, {
7194
+ import_core29.eventBus.publish(taskRequest.callback_event, {
6877
7195
  success: false,
6878
7196
  error: error instanceof Error ? error.message : String(error),
6879
7197
  config: {
@@ -6894,7 +7212,7 @@ var AgentTaskConsumer = _AgentTaskConsumer;
6894
7212
 
6895
7213
  // src/index.ts
6896
7214
  var import_core31 = require("@axiom-lattice/core");
6897
- var import_protocols6 = require("@axiom-lattice/protocols");
7215
+ var import_protocols4 = require("@axiom-lattice/protocols");
6898
7216
  var import_meta = {};
6899
7217
  process.on("unhandledRejection", (reason, promise) => {
6900
7218
  console.error("\u672A\u5904\u7406\u7684Promise\u62D2\u7EDD:", reason);
@@ -6902,12 +7220,12 @@ process.on("unhandledRejection", (reason, promise) => {
6902
7220
  var DEFAULT_LOGGER_CONFIG = {
6903
7221
  name: "default",
6904
7222
  description: "Default logger for lattice-gateway service",
6905
- type: import_protocols6.LoggerType.PINO,
7223
+ type: import_protocols4.LoggerType.PINO,
6906
7224
  serviceName: "lattice/gateway",
6907
7225
  loggerName: "lattice/gateway"
6908
7226
  };
6909
7227
  var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
6910
- var logger = loggerLattice.client;
7228
+ var logger3 = loggerLattice.client;
6911
7229
  function initializeLogger(config) {
6912
7230
  if (import_core31.loggerLatticeManager.hasLattice("default")) {
6913
7231
  import_core31.loggerLatticeManager.removeLattice("default");
@@ -7000,7 +7318,7 @@ app.setErrorHandler((error, request, reply) => {
7000
7318
  "x-request-id": getHeaderValue(request.headers["x-request-id"]),
7001
7319
  "x-user-id": getHeaderValue(request.headers["x-user-id"])
7002
7320
  };
7003
- logger.error(
7321
+ logger3.error(
7004
7322
  `\u8BF7\u6C42\u9519\u8BEF: ${request.method} ${request.url} error:${error.message}`,
7005
7323
  {
7006
7324
  ...context,
@@ -7040,29 +7358,51 @@ var start = async (config) => {
7040
7358
  file: config.loggerConfig.file || DEFAULT_LOGGER_CONFIG.file
7041
7359
  };
7042
7360
  loggerLattice = initializeLogger(loggerConfig);
7043
- logger = loggerLattice.client;
7361
+ logger3 = loggerLattice.client;
7044
7362
  }
7045
7363
  app.decorate("loggerLattice", loggerLattice);
7046
- registerLatticeRoutes(app);
7364
+ let channelDeps;
7365
+ try {
7366
+ const { getStoreLattice: getStoreLattice16 } = await import("@axiom-lattice/core");
7367
+ const bindingStore = getStoreLattice16("default", "channelBinding").store;
7368
+ const installationStore = getStoreLattice16("default", "channelInstallation").store;
7369
+ setBindingRegistry(bindingStore);
7370
+ (0, import_core30.setBindingRegistry)(bindingStore);
7371
+ const adapterRegistry = new ChannelAdapterRegistry();
7372
+ adapterRegistry.register(larkChannelAdapter);
7373
+ const router = new MessageRouter({
7374
+ middlewares: [
7375
+ createDeduplicationMiddleware(),
7376
+ createRateLimitMiddleware(),
7377
+ createAuditLoggerMiddleware()
7378
+ ],
7379
+ bindingRegistry: bindingStore,
7380
+ adapterRegistry,
7381
+ installationStore
7382
+ });
7383
+ channelDeps = { router, installationStore };
7384
+ } catch {
7385
+ }
7386
+ registerLatticeRoutes(app, channelDeps);
7047
7387
  try {
7048
7388
  const storeLattice = (0, import_core31.getStoreLattice)("default", "database");
7049
7389
  const store = storeLattice.store;
7050
7390
  import_core31.sqlDatabaseManager.setConfigStore(store);
7051
- logger.info("Database config store set for SqlDatabaseManager");
7391
+ logger3.info("Database config store set for SqlDatabaseManager");
7052
7392
  } catch (error) {
7053
- logger.warn("Failed to set database config store: " + (error instanceof Error ? error.message : String(error)));
7393
+ logger3.warn("Failed to set database config store: " + (error instanceof Error ? error.message : String(error)));
7054
7394
  }
7055
7395
  if (!import_core31.sandboxLatticeManager.hasLattice("default")) {
7056
7396
  import_core31.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
7057
- logger.info("Registered sandbox manager from env configuration");
7397
+ logger3.info("Registered sandbox manager from env configuration");
7058
7398
  }
7059
7399
  const target_port = config?.port || Number(process.env.PORT) || 4001;
7060
7400
  await app.listen({ port: target_port, host: "0.0.0.0" });
7061
- logger.info(`Lattice Gateway is running on port: ${target_port}`);
7401
+ logger3.info(`Lattice Gateway is running on port: ${target_port}`);
7062
7402
  try {
7063
- logger.info("AgentLifecycleManager initialized");
7403
+ logger3.info("AgentLifecycleManager initialized");
7064
7404
  } catch (error) {
7065
- logger.warn("Failed to initialize AgentLifecycleManager", { error });
7405
+ logger3.warn("Failed to initialize AgentLifecycleManager", { error });
7066
7406
  }
7067
7407
  const queueServiceConfig = config?.queueServiceConfig;
7068
7408
  if (queueServiceConfig) {
@@ -7073,14 +7413,14 @@ var start = async (config) => {
7073
7413
  }
7074
7414
  }
7075
7415
  try {
7076
- logger.info("Starting agent instance recovery...");
7416
+ logger3.info("Starting agent instance recovery...");
7077
7417
  const restoreStats = await import_core31.agentInstanceManager.restore();
7078
- logger.info(`Agent recovery complete: ${restoreStats.restored} threads restored, ${restoreStats.errors} errors`);
7418
+ logger3.info(`Agent recovery complete: ${restoreStats.restored} threads restored, ${restoreStats.errors} errors`);
7079
7419
  } catch (error) {
7080
- logger.error("Agent recovery failed", { error });
7420
+ logger3.error("Agent recovery failed", { error });
7081
7421
  }
7082
7422
  } catch (err) {
7083
- logger.error("Server start failed", { error: err });
7423
+ logger3.error("Server start failed", { error: err });
7084
7424
  process.exit(1);
7085
7425
  }
7086
7426
  };