@axiom-lattice/gateway 7.0.0 → 8.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/dist/{WechatChannelAdapter-7WHE5UGY.mjs → WechatChannelAdapter-QLPJJD6S.mjs} +55 -4
- package/dist/WechatChannelAdapter-QLPJJD6S.mjs.map +1 -0
- package/dist/{a2a-standard-DP53K7RC.mjs → a2a-standard-VL5I7B4W.mjs} +831 -59
- package/dist/a2a-standard-VL5I7B4W.mjs.map +1 -0
- package/dist/{chunk-FGSFOXIX.mjs → chunk-L6MBEEII.mjs} +2 -2
- package/dist/{chunk-J6B2VFJ7.mjs → chunk-W3YH4S6G.mjs} +2 -1
- package/dist/{chunk-MWWLJMYN.mjs → chunk-XUWD4VKY.mjs} +4 -2
- package/dist/chunk-XUWD4VKY.mjs.map +1 -0
- package/dist/embed/embed-page-AgentDetailSideApp-NK6VQBXS.js +1 -0
- package/dist/embed/embed-page-AgentGovernanceWorkbench-TKVV2GA6.js +1 -0
- package/dist/embed/embed-page-LangfuseDashboard-EYK2T2VK.js +1 -0
- package/dist/embed/embed-page-MessageGraph-P73B52OR.js +6 -0
- package/dist/embed/embed-page-ReactChart-LK6DUA4R.js +1 -0
- package/dist/embed/embed-page-SkillFlow-54RIT6M2.js +1 -0
- package/dist/embed/{embed-page-TasksSideApp-D7FFG2OC.js → embed-page-TasksSideApp-RK64OPAA.js} +1 -1
- package/dist/embed/embed-page-ThreadMaintenancePanel-PI3U76W3.js +1 -0
- package/dist/embed/{embed-page-TopologyRuntimeView-IS6HEO4F.js → embed-page-TopologyRuntimeView-X6QPRQE2.js} +1 -1
- package/dist/embed/{embed-page-WorkflowAutomationView-IDVSQTJB.js → embed-page-WorkflowAutomationView-3PE6YCRK.js} +1 -1
- package/dist/embed/{embed-page-chunk-NFMLKSPM.js → embed-page-chunk-3VNL5M2Q.js} +1 -1
- package/dist/embed/embed-page-chunk-767LVAGR.js +7 -0
- package/dist/embed/embed-page-chunk-A5GIM22E.js +117 -0
- package/dist/embed/{embed-page-chunk-SRMYHWL3.js → embed-page-chunk-AICFKU43.js} +1 -1
- package/dist/embed/{embed-page-chunk-XFV3N2LD.js → embed-page-chunk-BD7DUF2M.js} +1 -1
- package/dist/embed/embed-page-chunk-D7YTSCUO.js +1 -0
- package/dist/embed/{embed-page-chunk-N66H4DNH.js → embed-page-chunk-EB43T3BJ.js} +283 -194
- package/dist/embed/{embed-page-chunk-JFMBLJXY.js → embed-page-chunk-GYO2ELMI.js} +1 -1
- package/dist/embed/{embed-page-chunk-EYYKNTX7.js → embed-page-chunk-KF3HZ4TX.js} +1 -1
- package/dist/embed/embed-page-chunk-MEY3NEJZ.js +211 -0
- package/dist/embed/{embed-page-chunk-TVVAPR7I.js → embed-page-chunk-OIML5DX4.js} +1 -1
- package/dist/embed/{embed-page-chunk-FEMHLB6I.js → embed-page-chunk-OKZPPZMF.js} +1 -1
- package/dist/embed/embed-page-chunk-T2HKN7ZS.js +459 -0
- package/dist/embed/{embed-page-chunk-S2KVN3RB.js → embed-page-chunk-TSZQWEXD.js} +1 -1
- package/dist/embed/embed-page-chunk-US46Q3B7.js +15 -0
- package/dist/embed/{embed-page-chunk-BOEX26H7.js → embed-page-chunk-UV6IYDW5.js} +8 -8
- package/dist/embed/embed-page-chunk-WXMPVIXV.js +59 -0
- package/dist/embed/embed-page-chunk-YWJQVBZV.js +1 -0
- package/dist/embed/embed-page-code-highlighter-DD23LJY3.js +1 -0
- package/dist/embed/{embed-page-en-ETUCVCSC.js → embed-page-en-E35GE7TA.js} +1 -1
- package/dist/embed/embed-page-en-EKHHBS6L.js +1 -0
- package/dist/embed/embed-page-en-KAXIJJ4X.js +1 -0
- package/dist/embed/embed-page-en-OIICQSPX.js +3 -0
- package/dist/embed/embed-page-en-PQOH5CU4.js +1 -0
- package/dist/embed/embed-page-en-TMGUHZ6Y.js +1 -0
- package/dist/embed/embed-page-en-XJYWUJEL.js +1 -0
- package/dist/embed/{embed-page-en-2SWQHPAC.js → embed-page-en-ZCNNAMUD.js} +1 -1
- package/dist/embed/{embed-page-mermaid-KEBBKHQH.js → embed-page-mermaid-IN3A3YH2.js} +1 -1
- package/dist/embed/embed-page-zh-2UVQB4RP.js +3 -0
- package/dist/embed/embed-page-zh-6EBUEFKP.js +1 -0
- package/dist/embed/embed-page-zh-B3WBWQAV.js +1 -0
- package/dist/embed/embed-page-zh-KEMYJJLT.js +1 -0
- package/dist/embed/embed-page-zh-XO36BV2R.js +1 -0
- package/dist/embed/{embed-page-zh-PRMID3YQ.js → embed-page-zh-Z3URTIHW.js} +1 -1
- package/dist/embed/{embed-page-zh-D3IC6BGA.js → embed-page-zh-ZLK3GLM3.js} +1 -1
- package/dist/embed/embed-page.js +1 -1
- package/dist/index.d.mts +118 -3
- package/dist/index.d.ts +118 -3
- package/dist/index.js +3862 -1525
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2105 -598
- package/dist/index.mjs.map +1 -1
- package/dist/{open-NTH7AGD3.mjs → open-7ED27I5B.mjs} +3 -3
- package/dist/{open-exposure-AGNG4MC3.mjs → open-exposure-I3DN2X4E.mjs} +6 -4
- package/dist/{open-exposure-AGNG4MC3.mjs.map → open-exposure-I3DN2X4E.mjs.map} +1 -1
- package/package.json +13 -7
- package/dist/WechatChannelAdapter-7WHE5UGY.mjs.map +0 -1
- package/dist/a2a-standard-DP53K7RC.mjs.map +0 -1
- package/dist/chunk-MWWLJMYN.mjs.map +0 -1
- package/dist/embed/embed-page-AgentDetailSideApp-KNVDO3FZ.js +0 -1
- package/dist/embed/embed-page-AgentGovernanceWorkbench-QSKWVADP.js +0 -1
- package/dist/embed/embed-page-MessageGraph-VGXX4OWU.js +0 -6
- package/dist/embed/embed-page-ReactChart-PIISVBLU.js +0 -1
- package/dist/embed/embed-page-SkillFlow-JLI5MEZE.js +0 -1
- package/dist/embed/embed-page-ThreadMaintenancePanel-FSQVVIIG.js +0 -1
- package/dist/embed/embed-page-chunk-37LGEEJU.js +0 -21
- package/dist/embed/embed-page-chunk-436REIWY.js +0 -1
- package/dist/embed/embed-page-chunk-4W34QOXT.js +0 -517
- package/dist/embed/embed-page-chunk-BANVRQT7.js +0 -322
- package/dist/embed/embed-page-code-highlighter-66CSPTFK.js +0 -1
- package/dist/embed/embed-page-en-7IHJFS63.js +0 -1
- package/dist/embed/embed-page-en-7NF4GCC2.js +0 -1
- package/dist/embed/embed-page-en-FP6DWSG3.js +0 -1
- package/dist/embed/embed-page-en-GHTROC4H.js +0 -1
- package/dist/embed/embed-page-en-WUFULCUS.js +0 -1
- package/dist/embed/embed-page-en-XUMHP5CL.js +0 -1
- package/dist/embed/embed-page-zh-G75LDQU4.js +0 -1
- package/dist/embed/embed-page-zh-KJXKOUIY.js +0 -1
- package/dist/embed/embed-page-zh-RMSS6PXD.js +0 -1
- package/dist/embed/embed-page-zh-VH6J7XZO.js +0 -1
- package/dist/embed/embed-page-zh-Y5X5Y2DF.js +0 -1
- /package/dist/{chunk-FGSFOXIX.mjs.map → chunk-L6MBEEII.mjs.map} +0 -0
- /package/dist/{chunk-J6B2VFJ7.mjs.map → chunk-W3YH4S6G.mjs.map} +0 -0
- /package/dist/{open-NTH7AGD3.mjs.map → open-7ED27I5B.mjs.map} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
import {
|
|
31
31
|
PluginToolScopeError,
|
|
32
32
|
invokePluginTool
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-XUWD4VKY.mjs";
|
|
34
34
|
import {
|
|
35
35
|
buildPreviewTokenScript
|
|
36
36
|
} from "./chunk-7CG57LEF.mjs";
|
|
@@ -2794,7 +2794,38 @@ async function threadOwnedBy(tenantId, assistantId, threadId) {
|
|
|
2794
2794
|
try {
|
|
2795
2795
|
const ledger = getStoreLattice5("default", "agentRun").store;
|
|
2796
2796
|
const runs = await ledger.listRuns(tenantId, threadId, { limit: 1 });
|
|
2797
|
-
|
|
2797
|
+
if (runs.some((run2) => run2.assistantId === assistantId)) return true;
|
|
2798
|
+
} catch {
|
|
2799
|
+
}
|
|
2800
|
+
try {
|
|
2801
|
+
const tasks = getStoreLattice5("default", "task").store;
|
|
2802
|
+
const matches = await tasks.list({ tenantId, threadId, limit: 1 });
|
|
2803
|
+
return matches.some((task) => task.ownerType === "agent" && task.ownerId === assistantId);
|
|
2804
|
+
} catch {
|
|
2805
|
+
return false;
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
async function threadIsNewForTenant(tenantId, threadId) {
|
|
2809
|
+
try {
|
|
2810
|
+
const existing = await getStoreLattice5("default", "thread").store.getThreadById(
|
|
2811
|
+
tenantId,
|
|
2812
|
+
threadId
|
|
2813
|
+
);
|
|
2814
|
+
if (existing) return false;
|
|
2815
|
+
} catch {
|
|
2816
|
+
return false;
|
|
2817
|
+
}
|
|
2818
|
+
try {
|
|
2819
|
+
const ledger = getStoreLattice5("default", "agentRun").store;
|
|
2820
|
+
const runs = await ledger.listRuns(tenantId, threadId, { limit: 1 });
|
|
2821
|
+
if (runs.length > 0) return false;
|
|
2822
|
+
} catch {
|
|
2823
|
+
return false;
|
|
2824
|
+
}
|
|
2825
|
+
try {
|
|
2826
|
+
const tasks = getStoreLattice5("default", "task").store;
|
|
2827
|
+
const matches = await tasks.list({ tenantId, threadId, limit: 1 });
|
|
2828
|
+
return matches.length === 0;
|
|
2798
2829
|
} catch {
|
|
2799
2830
|
return false;
|
|
2800
2831
|
}
|
|
@@ -2987,6 +3018,12 @@ var RUN_CREATE_UNAVAILABLE2 = "RUN_CREATE_UNAVAILABLE";
|
|
|
2987
3018
|
var RUN_CREATE_LOCK_TIMEOUT = "RUN_CREATE_LOCK_TIMEOUT";
|
|
2988
3019
|
var DEFAULT_WAIT_TIMEOUT_MS = 3e4;
|
|
2989
3020
|
var DEFAULT_POLL_INTERVAL_MS = 200;
|
|
3021
|
+
function getUserId3(request) {
|
|
3022
|
+
const userId = request.user?.id;
|
|
3023
|
+
if (userId) return userId;
|
|
3024
|
+
const header2 = request.headers["x-user-id"];
|
|
3025
|
+
return typeof header2 === "string" && header2.length > 0 ? header2 : void 0;
|
|
3026
|
+
}
|
|
2990
3027
|
var RUN_CREATE_LEASE = {
|
|
2991
3028
|
ttlMs: 12e4,
|
|
2992
3029
|
acquireTimeoutMs: 3e4,
|
|
@@ -3161,6 +3198,7 @@ function createRunLifecycleHandlers(deps = {}) {
|
|
|
3161
3198
|
const resolveRouter = deps.getRunCancelRouter ?? getRunCancelRouter;
|
|
3162
3199
|
const resolveLeaseStore = deps.getCoordinationLeaseStore ?? getConfiguredCoordinationLeaseStore;
|
|
3163
3200
|
const ownsThread = deps.threadOwnedBy ?? threadOwnedBy;
|
|
3201
|
+
const isNewThread = deps.threadIsNew ?? threadIsNewForTenant;
|
|
3164
3202
|
const wake = deps.wakeRunTaskQueue ?? wakeRunTaskQueue;
|
|
3165
3203
|
const idFactory = deps.idFactory ?? (() => v42());
|
|
3166
3204
|
const waitTimeoutMs = deps.waitTimeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;
|
|
@@ -3243,7 +3281,9 @@ function createRunLifecycleHandlers(deps = {}) {
|
|
|
3243
3281
|
const tenantId = getTenantId4(request);
|
|
3244
3282
|
const { assistantId, threadId } = request.params;
|
|
3245
3283
|
if (!await ownsThread(tenantId, assistantId, threadId)) {
|
|
3246
|
-
|
|
3284
|
+
if (!await isNewThread(tenantId, threadId)) {
|
|
3285
|
+
return notFound2(reply, THREAD_NOT_FOUND2, "Thread not found");
|
|
3286
|
+
}
|
|
3247
3287
|
}
|
|
3248
3288
|
const body = isRecord(request.body) ? request.body : {};
|
|
3249
3289
|
const mode = body.mode;
|
|
@@ -3290,6 +3330,11 @@ function createRunLifecycleHandlers(deps = {}) {
|
|
|
3290
3330
|
if (body.metadata !== void 0 && !isRecord(body.metadata)) {
|
|
3291
3331
|
return invalidRequest(reply, "metadata must be an object");
|
|
3292
3332
|
}
|
|
3333
|
+
const userId = getUserId3(request);
|
|
3334
|
+
const runConfig = userId ? {
|
|
3335
|
+
...isRecord(body.config) ? body.config : {},
|
|
3336
|
+
user_id: userId
|
|
3337
|
+
} : isRecord(body.config) ? body.config : void 0;
|
|
3293
3338
|
const maxActiveRunsForTenant = resolveRunTaskMaxActivePerTenant();
|
|
3294
3339
|
const createPending = async () => {
|
|
3295
3340
|
let threadRuns;
|
|
@@ -3333,7 +3378,7 @@ function createRunLifecycleHandlers(deps = {}) {
|
|
|
3333
3378
|
projectId: resolveAgentScope(request).project_id,
|
|
3334
3379
|
input: input ?? null,
|
|
3335
3380
|
command: command ?? null,
|
|
3336
|
-
config:
|
|
3381
|
+
config: runConfig ?? null,
|
|
3337
3382
|
metadata: body.metadata ?? null,
|
|
3338
3383
|
inputMessageIds: input ? extractAgentRunInputMessageIds2(input) : [],
|
|
3339
3384
|
...inheritedRevision === null ? {} : { capabilityRuntimeRevision: inheritedRevision },
|
|
@@ -4378,7 +4423,7 @@ async function handleConnection(socket, request) {
|
|
|
4378
4423
|
socket.send(JSON.stringify(payload));
|
|
4379
4424
|
return true;
|
|
4380
4425
|
};
|
|
4381
|
-
const
|
|
4426
|
+
const sendError4 = (code, message, options = {}) => {
|
|
4382
4427
|
send({
|
|
4383
4428
|
type: "error",
|
|
4384
4429
|
...options.subscriptionId === void 0 ? {} : { subscription_id: options.subscriptionId },
|
|
@@ -4411,7 +4456,7 @@ async function handleConnection(socket, request) {
|
|
|
4411
4456
|
} catch (error) {
|
|
4412
4457
|
if (!subscription.closed && !closed) {
|
|
4413
4458
|
const frame = mapThreadEventError(error);
|
|
4414
|
-
|
|
4459
|
+
sendError4(frame.code, frame.message, { subscriptionId: subscription.subscriptionId });
|
|
4415
4460
|
}
|
|
4416
4461
|
} finally {
|
|
4417
4462
|
await removeSubscription(subscription);
|
|
@@ -4419,7 +4464,7 @@ async function handleConnection(socket, request) {
|
|
|
4419
4464
|
};
|
|
4420
4465
|
const subscribe = (requestId, params) => {
|
|
4421
4466
|
if (subscriptions.size >= MAX_SUBSCRIPTIONS) {
|
|
4422
|
-
|
|
4467
|
+
sendError4(
|
|
4423
4468
|
"SUBSCRIPTION_LIMIT",
|
|
4424
4469
|
`at most ${MAX_SUBSCRIPTIONS} subscriptions are allowed`,
|
|
4425
4470
|
{ requestId }
|
|
@@ -4428,12 +4473,12 @@ async function handleConnection(socket, request) {
|
|
|
4428
4473
|
}
|
|
4429
4474
|
const normalized = validateThreadEventFilters(params ?? {});
|
|
4430
4475
|
if (normalized.error || !normalized.filters) {
|
|
4431
|
-
|
|
4476
|
+
sendError4("INVALID_SUBSCRIPTION", normalized.error ?? "invalid subscription params", { requestId });
|
|
4432
4477
|
return;
|
|
4433
4478
|
}
|
|
4434
4479
|
const since = parseSinceCursor(isRecord4(params) ? params.since : void 0);
|
|
4435
4480
|
if (since.error) {
|
|
4436
|
-
|
|
4481
|
+
sendError4("INVALID_SUBSCRIPTION", since.error, { requestId });
|
|
4437
4482
|
return;
|
|
4438
4483
|
}
|
|
4439
4484
|
const subscriptionId = randomUUID5();
|
|
@@ -4464,16 +4509,16 @@ async function handleConnection(socket, request) {
|
|
|
4464
4509
|
try {
|
|
4465
4510
|
message = JSON.parse(String(raw));
|
|
4466
4511
|
} catch {
|
|
4467
|
-
|
|
4512
|
+
sendError4("INVALID_REQUEST", "message must be valid JSON");
|
|
4468
4513
|
return;
|
|
4469
4514
|
}
|
|
4470
4515
|
if (!isRecord4(message)) {
|
|
4471
|
-
|
|
4516
|
+
sendError4("INVALID_REQUEST", "message must be an object");
|
|
4472
4517
|
return;
|
|
4473
4518
|
}
|
|
4474
4519
|
if (message.type === "subscription.subscribe") {
|
|
4475
4520
|
if (typeof message.id !== "string" || message.id.length === 0) {
|
|
4476
|
-
|
|
4521
|
+
sendError4("INVALID_REQUEST", "subscription id is required");
|
|
4477
4522
|
return;
|
|
4478
4523
|
}
|
|
4479
4524
|
subscribe(message.id, message.params);
|
|
@@ -4481,13 +4526,13 @@ async function handleConnection(socket, request) {
|
|
|
4481
4526
|
}
|
|
4482
4527
|
if (message.type === "subscription.unsubscribe") {
|
|
4483
4528
|
if (typeof message.id !== "string" || message.id.length === 0) {
|
|
4484
|
-
|
|
4529
|
+
sendError4("INVALID_REQUEST", "subscription id is required");
|
|
4485
4530
|
return;
|
|
4486
4531
|
}
|
|
4487
4532
|
unsubscribe(message.id);
|
|
4488
4533
|
return;
|
|
4489
4534
|
}
|
|
4490
|
-
|
|
4535
|
+
sendError4("UNKNOWN_MESSAGE_TYPE", "unknown message type");
|
|
4491
4536
|
};
|
|
4492
4537
|
cleanup = () => {
|
|
4493
4538
|
if (closed) return;
|
|
@@ -4864,6 +4909,16 @@ function getTenantId7(request) {
|
|
|
4864
4909
|
const header2 = request.headers["x-tenant-id"];
|
|
4865
4910
|
return typeof header2 === "string" && header2.length > 0 ? header2 : "default";
|
|
4866
4911
|
}
|
|
4912
|
+
function getUserId4(request) {
|
|
4913
|
+
const userId = request.user?.id;
|
|
4914
|
+
if (userId) return userId;
|
|
4915
|
+
const header2 = request.headers["x-user-id"];
|
|
4916
|
+
return typeof header2 === "string" && header2.length > 0 ? header2 : void 0;
|
|
4917
|
+
}
|
|
4918
|
+
function withUserId(config, userId) {
|
|
4919
|
+
if (!userId) return config;
|
|
4920
|
+
return { ...config ?? {}, user_id: userId };
|
|
4921
|
+
}
|
|
4867
4922
|
function headerValue3(request, name) {
|
|
4868
4923
|
const value = request.headers[name];
|
|
4869
4924
|
return typeof value === "string" ? value : void 0;
|
|
@@ -4937,7 +4992,10 @@ async function executeThreadCommand(request, reply) {
|
|
|
4937
4992
|
}
|
|
4938
4993
|
const mode = parseMode(args.multitask_strategy);
|
|
4939
4994
|
if (!mode) return badRequest2(reply, "invalid multitask_strategy");
|
|
4940
|
-
const customRunConfig =
|
|
4995
|
+
const customRunConfig = withUserId(
|
|
4996
|
+
args.config === void 0 ? void 0 : args.config,
|
|
4997
|
+
getUserId4(request)
|
|
4998
|
+
);
|
|
4941
4999
|
const agent2 = agentInstanceManager6.getAgent({
|
|
4942
5000
|
assistant_id: thread.assistantId,
|
|
4943
5001
|
thread_id: threadId,
|
|
@@ -4992,6 +5050,10 @@ async function executeThreadCommand(request, reply) {
|
|
|
4992
5050
|
);
|
|
4993
5051
|
}
|
|
4994
5052
|
};
|
|
5053
|
+
const customRunConfig = withUserId(
|
|
5054
|
+
args.config === void 0 ? void 0 : args.config,
|
|
5055
|
+
getUserId4(request)
|
|
5056
|
+
);
|
|
4995
5057
|
try {
|
|
4996
5058
|
const agent2 = agentInstanceManager6.getAgent({
|
|
4997
5059
|
assistant_id: thread.assistantId,
|
|
@@ -4999,7 +5061,7 @@ async function executeThreadCommand(request, reply) {
|
|
|
4999
5061
|
tenant_id: tenantId,
|
|
5000
5062
|
workspace_id: workspaceId,
|
|
5001
5063
|
project_id: projectId,
|
|
5002
|
-
custom_run_config:
|
|
5064
|
+
custom_run_config: customRunConfig
|
|
5003
5065
|
});
|
|
5004
5066
|
let interrupt;
|
|
5005
5067
|
try {
|
|
@@ -5033,7 +5095,7 @@ async function executeThreadCommand(request, reply) {
|
|
|
5033
5095
|
input: { id: messageId, message: answerText },
|
|
5034
5096
|
command: resume.command,
|
|
5035
5097
|
expected_interrupt_id: interruptId,
|
|
5036
|
-
...
|
|
5098
|
+
...customRunConfig === void 0 ? {} : { custom_run_config: customRunConfig }
|
|
5037
5099
|
}, QueueMode2.FOLLOWUP);
|
|
5038
5100
|
} catch (error) {
|
|
5039
5101
|
await releaseReservation();
|
|
@@ -5511,7 +5573,12 @@ function readCronMetadata(metadata) {
|
|
|
5511
5573
|
const cron = isRecord7(metadata) && isRecord7(metadata.cron) ? metadata.cron : {};
|
|
5512
5574
|
const multitaskStrategy = cron.multitaskStrategy === "interrupt" ? "interrupt" : "enqueue";
|
|
5513
5575
|
const onRunCompleted = cron.onRunCompleted === "delete" ? "delete" : "keep";
|
|
5514
|
-
return {
|
|
5576
|
+
return {
|
|
5577
|
+
multitaskStrategy,
|
|
5578
|
+
onRunCompleted,
|
|
5579
|
+
...typeof cron.workspaceId === "string" && cron.workspaceId.length > 0 ? { workspaceId: cron.workspaceId } : {},
|
|
5580
|
+
...typeof cron.projectId === "string" && cron.projectId.length > 0 ? { projectId: cron.projectId } : {}
|
|
5581
|
+
};
|
|
5515
5582
|
}
|
|
5516
5583
|
function queueModeFor(strategy) {
|
|
5517
5584
|
return strategy === "interrupt" ? QueueMode3.STEER : QueueMode3.FOLLOWUP;
|
|
@@ -5597,6 +5664,10 @@ function createAgentCronHandler(deps) {
|
|
|
5597
5664
|
const parts = payloadParts(payload);
|
|
5598
5665
|
const cron = readCronMetadata(taskInfo.metadata);
|
|
5599
5666
|
const mode = queueModeFor(cron.multitaskStrategy);
|
|
5667
|
+
const scope = {
|
|
5668
|
+
...cron.workspaceId === void 0 ? {} : { workspace_id: cron.workspaceId },
|
|
5669
|
+
...cron.projectId === void 0 ? {} : { project_id: cron.projectId }
|
|
5670
|
+
};
|
|
5600
5671
|
let threadId = taskInfo.threadId;
|
|
5601
5672
|
let createdThreadId;
|
|
5602
5673
|
try {
|
|
@@ -5605,18 +5676,25 @@ function createAgentCronHandler(deps) {
|
|
|
5605
5676
|
agent = deps.getAgent({
|
|
5606
5677
|
tenant_id: taskInfo.tenantId,
|
|
5607
5678
|
assistant_id: assistantId,
|
|
5608
|
-
thread_id: threadId
|
|
5679
|
+
thread_id: threadId,
|
|
5680
|
+
...scope
|
|
5609
5681
|
});
|
|
5610
5682
|
} else {
|
|
5611
5683
|
createdThreadId = idFactory();
|
|
5612
5684
|
threadId = createdThreadId;
|
|
5613
5685
|
await deps.createThread(taskInfo.tenantId, assistantId, threadId, {
|
|
5614
|
-
metadata: {
|
|
5686
|
+
metadata: {
|
|
5687
|
+
tenantId: taskInfo.tenantId,
|
|
5688
|
+
cronId: taskInfo.taskId,
|
|
5689
|
+
...cron.workspaceId === void 0 ? {} : { workspaceId: cron.workspaceId },
|
|
5690
|
+
...cron.projectId === void 0 ? {} : { projectId: cron.projectId }
|
|
5691
|
+
}
|
|
5615
5692
|
});
|
|
5616
5693
|
agent = deps.getAgent({
|
|
5617
5694
|
tenant_id: taskInfo.tenantId,
|
|
5618
5695
|
assistant_id: assistantId,
|
|
5619
|
-
thread_id: threadId
|
|
5696
|
+
thread_id: threadId,
|
|
5697
|
+
...scope
|
|
5620
5698
|
});
|
|
5621
5699
|
if (cron.onRunCompleted === "delete") {
|
|
5622
5700
|
const cleanupThreadId = threadId;
|
|
@@ -5685,6 +5763,8 @@ function toDto(task) {
|
|
|
5685
5763
|
cron_id: task.taskId,
|
|
5686
5764
|
...task.threadId === void 0 ? {} : { thread_id: task.threadId },
|
|
5687
5765
|
assistant_id: task.assistantId ?? "",
|
|
5766
|
+
...cron.workspaceId === void 0 ? {} : { workspace_id: cron.workspaceId },
|
|
5767
|
+
...cron.projectId === void 0 ? {} : { project_id: cron.projectId },
|
|
5688
5768
|
schedule: task.cronExpression ?? "",
|
|
5689
5769
|
timezone: task.timezone ?? "UTC",
|
|
5690
5770
|
...task.expiresAt === void 0 ? {} : { end_time: new Date(task.expiresAt).toISOString() },
|
|
@@ -5712,6 +5792,70 @@ function failure2(request, reply, error) {
|
|
|
5712
5792
|
request.log.error({ err: error }, "agent cron operation failed");
|
|
5713
5793
|
return reply.status(500).send({ success: false, error: "Agent cron operation failed" });
|
|
5714
5794
|
}
|
|
5795
|
+
function parseScopeId(value) {
|
|
5796
|
+
if (value === void 0 || value === null) return void 0;
|
|
5797
|
+
if (typeof value !== "string") return null;
|
|
5798
|
+
const trimmed = value.trim();
|
|
5799
|
+
return trimmed.length === 0 ? void 0 : trimmed;
|
|
5800
|
+
}
|
|
5801
|
+
async function resolveCronScope(body, tenantId) {
|
|
5802
|
+
const projectId = parseScopeId(body.project_id);
|
|
5803
|
+
if (projectId === null) {
|
|
5804
|
+
return { ok: false, status: 400, error: "project_id must be a string" };
|
|
5805
|
+
}
|
|
5806
|
+
const workspaceId = parseScopeId(body.workspace_id);
|
|
5807
|
+
if (workspaceId === null) {
|
|
5808
|
+
return { ok: false, status: 400, error: "workspace_id must be a string" };
|
|
5809
|
+
}
|
|
5810
|
+
if (projectId !== void 0) {
|
|
5811
|
+
try {
|
|
5812
|
+
const projectStore = getStoreLattice10("default", "project").store;
|
|
5813
|
+
const project = await projectStore.getProjectById(tenantId, projectId);
|
|
5814
|
+
if (!project || project.tenantId !== tenantId) {
|
|
5815
|
+
return { ok: false, status: 404, error: "Project not found" };
|
|
5816
|
+
}
|
|
5817
|
+
if (workspaceId !== void 0 && workspaceId !== project.workspaceId) {
|
|
5818
|
+
return {
|
|
5819
|
+
ok: false,
|
|
5820
|
+
status: 400,
|
|
5821
|
+
error: "project_id does not belong to workspace_id"
|
|
5822
|
+
};
|
|
5823
|
+
}
|
|
5824
|
+
return {
|
|
5825
|
+
ok: true,
|
|
5826
|
+
scope: {
|
|
5827
|
+
projectId,
|
|
5828
|
+
...project.workspaceId ? { workspaceId: project.workspaceId } : workspaceId === void 0 ? {} : { workspaceId }
|
|
5829
|
+
}
|
|
5830
|
+
};
|
|
5831
|
+
} catch {
|
|
5832
|
+
return { ok: false, status: 404, error: "Project not found" };
|
|
5833
|
+
}
|
|
5834
|
+
}
|
|
5835
|
+
if (workspaceId !== void 0) {
|
|
5836
|
+
try {
|
|
5837
|
+
const workspaceStore = getStoreLattice10("default", "workspace").store;
|
|
5838
|
+
const workspace = await workspaceStore.getWorkspaceById(tenantId, workspaceId);
|
|
5839
|
+
if (!workspace || workspace.tenantId !== tenantId) {
|
|
5840
|
+
return { ok: false, status: 404, error: "Workspace not found" };
|
|
5841
|
+
}
|
|
5842
|
+
return { ok: true, scope: { workspaceId } };
|
|
5843
|
+
} catch {
|
|
5844
|
+
return { ok: false, status: 404, error: "Workspace not found" };
|
|
5845
|
+
}
|
|
5846
|
+
}
|
|
5847
|
+
return { ok: true, scope: {} };
|
|
5848
|
+
}
|
|
5849
|
+
function cronMetadata(strategy, scope, completion) {
|
|
5850
|
+
return {
|
|
5851
|
+
cron: {
|
|
5852
|
+
multitaskStrategy: strategy,
|
|
5853
|
+
...completion === void 0 ? {} : { onRunCompleted: completion },
|
|
5854
|
+
...scope.workspaceId === void 0 ? {} : { workspaceId: scope.workspaceId },
|
|
5855
|
+
...scope.projectId === void 0 ? {} : { projectId: scope.projectId }
|
|
5856
|
+
}
|
|
5857
|
+
};
|
|
5858
|
+
}
|
|
5715
5859
|
function validCron(value) {
|
|
5716
5860
|
if (typeof value !== "string" || value.trim() === "") return void 0;
|
|
5717
5861
|
try {
|
|
@@ -5780,6 +5924,13 @@ async function createThreadCron(request, reply) {
|
|
|
5780
5924
|
return badRequest4(reply, "enabled must be a boolean");
|
|
5781
5925
|
}
|
|
5782
5926
|
const tenantId = getTenantId10(request);
|
|
5927
|
+
const scopeResolution = await resolveCronScope(body, tenantId);
|
|
5928
|
+
if (!scopeResolution.ok) {
|
|
5929
|
+
return reply.status(scopeResolution.status).send({
|
|
5930
|
+
success: false,
|
|
5931
|
+
error: scopeResolution.error
|
|
5932
|
+
});
|
|
5933
|
+
}
|
|
5783
5934
|
let thread;
|
|
5784
5935
|
try {
|
|
5785
5936
|
thread = await getStoreLattice10("default", "thread").store.getThreadById(
|
|
@@ -5802,7 +5953,7 @@ async function createThreadCron(request, reply) {
|
|
|
5802
5953
|
tenantId,
|
|
5803
5954
|
assistantId: thread.assistantId,
|
|
5804
5955
|
threadId: thread.id,
|
|
5805
|
-
metadata:
|
|
5956
|
+
metadata: cronMetadata(strategy, scopeResolution.scope)
|
|
5806
5957
|
});
|
|
5807
5958
|
if (!scheduled) return failure2(request, reply, new Error("scheduleCron rejected the task"));
|
|
5808
5959
|
if (body.enabled === false) {
|
|
@@ -5857,6 +6008,13 @@ async function createStatelessCron(request, reply) {
|
|
|
5857
6008
|
} catch (error) {
|
|
5858
6009
|
return failure2(request, reply, error);
|
|
5859
6010
|
}
|
|
6011
|
+
const scopeResolution = await resolveCronScope(body, tenantId);
|
|
6012
|
+
if (!scopeResolution.ok) {
|
|
6013
|
+
return reply.status(scopeResolution.status).send({
|
|
6014
|
+
success: false,
|
|
6015
|
+
error: scopeResolution.error
|
|
6016
|
+
});
|
|
6017
|
+
}
|
|
5860
6018
|
const lattice = schedule();
|
|
5861
6019
|
if (!lattice || !storageOf(lattice)) return unavailable2(reply);
|
|
5862
6020
|
const cronId = randomUUID10();
|
|
@@ -5868,7 +6026,7 @@ async function createStatelessCron(request, reply) {
|
|
|
5868
6026
|
maxRetries: 2,
|
|
5869
6027
|
tenantId,
|
|
5870
6028
|
assistantId: body.assistant_id,
|
|
5871
|
-
metadata:
|
|
6029
|
+
metadata: cronMetadata(strategy, scopeResolution.scope, completion)
|
|
5872
6030
|
});
|
|
5873
6031
|
if (!scheduled) return failure2(request, reply, new Error("scheduleCron rejected the task"));
|
|
5874
6032
|
if (body.enabled === false) {
|
|
@@ -6376,9 +6534,10 @@ function isSharedStore(kind) {
|
|
|
6376
6534
|
}
|
|
6377
6535
|
function computeMultiReplicaReadiness() {
|
|
6378
6536
|
const multiReplicaDeclared = isMultiReplicaDeclared();
|
|
6537
|
+
const strict = process.env.AXIOM_READINESS_STRICT === "true";
|
|
6379
6538
|
const warnings = [];
|
|
6380
6539
|
if (!multiReplicaDeclared) {
|
|
6381
|
-
return { multiReplicaDeclared, ok: true, warnings };
|
|
6540
|
+
return { multiReplicaDeclared, ok: true, strict, blocking: false, warnings };
|
|
6382
6541
|
}
|
|
6383
6542
|
for (const kind of SHARED_STORE_KINDS) {
|
|
6384
6543
|
const name = storeClassName(kind);
|
|
@@ -6424,16 +6583,35 @@ function computeMultiReplicaReadiness() {
|
|
|
6424
6583
|
);
|
|
6425
6584
|
}
|
|
6426
6585
|
}
|
|
6427
|
-
|
|
6586
|
+
const ok = warnings.length === 0;
|
|
6587
|
+
return {
|
|
6588
|
+
multiReplicaDeclared,
|
|
6589
|
+
ok,
|
|
6590
|
+
strict,
|
|
6591
|
+
blocking: strict && multiReplicaDeclared && !ok,
|
|
6592
|
+
warnings
|
|
6593
|
+
};
|
|
6428
6594
|
}
|
|
6429
|
-
|
|
6595
|
+
var MultiReplicaReadinessError = class extends Error {
|
|
6596
|
+
constructor(warnings) {
|
|
6597
|
+
super(`Multi-replica readiness blocked startup: ${warnings.join(" | ")}`);
|
|
6598
|
+
this.warnings = warnings;
|
|
6599
|
+
this.code = "MULTI_REPLICA_READINESS_BLOCKED";
|
|
6600
|
+
this.name = "MultiReplicaReadinessError";
|
|
6601
|
+
}
|
|
6602
|
+
};
|
|
6603
|
+
function assertMultiReplicaReadiness() {
|
|
6604
|
+
const { blocking, warnings } = computeMultiReplicaReadiness();
|
|
6605
|
+
if (blocking) throw new MultiReplicaReadinessError(warnings);
|
|
6606
|
+
}
|
|
6607
|
+
function warnMultiReplicaReadiness(logger9) {
|
|
6430
6608
|
const { multiReplicaDeclared, warnings } = computeMultiReplicaReadiness();
|
|
6431
6609
|
if (!multiReplicaDeclared) return;
|
|
6432
6610
|
for (const message of warnings) {
|
|
6433
|
-
|
|
6611
|
+
logger9.warn(message, { phase: "multi_replica_readiness" });
|
|
6434
6612
|
}
|
|
6435
6613
|
if (process.env.CHUNK_SOURCE?.trim() !== "redis") {
|
|
6436
|
-
|
|
6614
|
+
logger9.warn(
|
|
6437
6615
|
"Multi-replica: CHUNK_SOURCE is not 'redis'; agent run SSE and resume_stream are process-local and require thread affinity/sticky routing (set CHUNK_SOURCE=redis with REDIS_URL to share streams)",
|
|
6438
6616
|
{ phase: "multi_replica_readiness", feature: "agent-run-sse" }
|
|
6439
6617
|
);
|
|
@@ -6527,6 +6705,159 @@ async function getInfo(request, reply) {
|
|
|
6527
6705
|
}
|
|
6528
6706
|
}
|
|
6529
6707
|
|
|
6708
|
+
// src/controllers/observability.ts
|
|
6709
|
+
import {
|
|
6710
|
+
ObservabilityDashboardUnavailableError,
|
|
6711
|
+
ObservabilityDashboardUnsupportedError,
|
|
6712
|
+
ObservabilityLatticeManager
|
|
6713
|
+
} from "@axiom-lattice/core";
|
|
6714
|
+
|
|
6715
|
+
// src/controllers/tenant-scope.ts
|
|
6716
|
+
var TenantScopeError = class extends Error {
|
|
6717
|
+
/** Creates a tenant scope error. */
|
|
6718
|
+
constructor(code, statusCode, message) {
|
|
6719
|
+
super(message);
|
|
6720
|
+
this.code = code;
|
|
6721
|
+
this.statusCode = statusCode;
|
|
6722
|
+
this.name = "TenantScopeError";
|
|
6723
|
+
}
|
|
6724
|
+
};
|
|
6725
|
+
function resolveTenantScope(request, authRequired2) {
|
|
6726
|
+
const authenticated = request.user?.tenantId;
|
|
6727
|
+
const header2 = request.headers["x-tenant-id"];
|
|
6728
|
+
const requested = Array.isArray(header2) ? header2[0] : header2;
|
|
6729
|
+
if (authenticated) {
|
|
6730
|
+
if (requested && requested !== authenticated) {
|
|
6731
|
+
throw new TenantScopeError(
|
|
6732
|
+
"TENANT_ACCESS_DENIED",
|
|
6733
|
+
403,
|
|
6734
|
+
"Tenant access denied"
|
|
6735
|
+
);
|
|
6736
|
+
}
|
|
6737
|
+
return { tenantId: authenticated, userId: request.user?.id };
|
|
6738
|
+
}
|
|
6739
|
+
if (authRequired2) {
|
|
6740
|
+
throw new TenantScopeError(
|
|
6741
|
+
"UNAUTHENTICATED",
|
|
6742
|
+
401,
|
|
6743
|
+
"Console session required"
|
|
6744
|
+
);
|
|
6745
|
+
}
|
|
6746
|
+
return { tenantId: requested || "default" };
|
|
6747
|
+
}
|
|
6748
|
+
|
|
6749
|
+
// src/controllers/observability.ts
|
|
6750
|
+
var logger = new Logger({ serviceName: "lattice/gateway/observability" });
|
|
6751
|
+
var DASHBOARD_RANGES = /* @__PURE__ */ new Set([
|
|
6752
|
+
"1h",
|
|
6753
|
+
"24h",
|
|
6754
|
+
"7d",
|
|
6755
|
+
"30d"
|
|
6756
|
+
]);
|
|
6757
|
+
function buildObservabilityInfo(manager = ObservabilityLatticeManager.getInstance()) {
|
|
6758
|
+
const provider = manager.getDefault();
|
|
6759
|
+
if (!provider) return { enabled: false, dashboard: false };
|
|
6760
|
+
const url = provider.getTraceListUrl?.();
|
|
6761
|
+
return {
|
|
6762
|
+
enabled: true,
|
|
6763
|
+
dashboard: typeof provider.getDashboard === "function",
|
|
6764
|
+
provider: provider.type,
|
|
6765
|
+
...url ? { url } : {}
|
|
6766
|
+
};
|
|
6767
|
+
}
|
|
6768
|
+
async function getObservability(_request, reply) {
|
|
6769
|
+
return reply.send({ success: true, data: buildObservabilityInfo() });
|
|
6770
|
+
}
|
|
6771
|
+
function sendError(reply, status, code, message) {
|
|
6772
|
+
return reply.status(status).send({
|
|
6773
|
+
success: false,
|
|
6774
|
+
error: { code, message, retryable: false }
|
|
6775
|
+
});
|
|
6776
|
+
}
|
|
6777
|
+
async function getObservabilityDashboard(request, reply) {
|
|
6778
|
+
const provider = ObservabilityLatticeManager.getInstance().getDefault();
|
|
6779
|
+
if (!provider) {
|
|
6780
|
+
return sendError(
|
|
6781
|
+
reply,
|
|
6782
|
+
404,
|
|
6783
|
+
"OBSERVABILITY_DISABLED",
|
|
6784
|
+
"Observability is not enabled"
|
|
6785
|
+
);
|
|
6786
|
+
}
|
|
6787
|
+
if (typeof provider.getDashboard !== "function") {
|
|
6788
|
+
return sendError(
|
|
6789
|
+
reply,
|
|
6790
|
+
501,
|
|
6791
|
+
"OBSERVABILITY_DASHBOARD_UNSUPPORTED",
|
|
6792
|
+
"Dashboard is not supported by this provider"
|
|
6793
|
+
);
|
|
6794
|
+
}
|
|
6795
|
+
const range = request.query.range ?? "24h";
|
|
6796
|
+
if (!DASHBOARD_RANGES.has(range)) {
|
|
6797
|
+
return sendError(reply, 400, "INVALID_RANGE", "Invalid dashboard range");
|
|
6798
|
+
}
|
|
6799
|
+
let tenantId;
|
|
6800
|
+
try {
|
|
6801
|
+
tenantId = resolveTenantScope(
|
|
6802
|
+
request,
|
|
6803
|
+
process.env.AUTH_REQUIRED === "true"
|
|
6804
|
+
).tenantId;
|
|
6805
|
+
} catch (error) {
|
|
6806
|
+
if (error instanceof TenantScopeError) {
|
|
6807
|
+
return sendError(reply, error.statusCode, error.code, error.message);
|
|
6808
|
+
}
|
|
6809
|
+
return sendError(
|
|
6810
|
+
reply,
|
|
6811
|
+
401,
|
|
6812
|
+
"UNAUTHENTICATED",
|
|
6813
|
+
"Console session required"
|
|
6814
|
+
);
|
|
6815
|
+
}
|
|
6816
|
+
try {
|
|
6817
|
+
const result = await provider.getDashboard({
|
|
6818
|
+
range,
|
|
6819
|
+
tenantId
|
|
6820
|
+
});
|
|
6821
|
+
return reply.send({
|
|
6822
|
+
success: true,
|
|
6823
|
+
data: {
|
|
6824
|
+
provider: provider.type,
|
|
6825
|
+
range,
|
|
6826
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6827
|
+
version: result.version,
|
|
6828
|
+
...result.warnings ? { warnings: result.warnings } : {},
|
|
6829
|
+
payload: result.payload
|
|
6830
|
+
}
|
|
6831
|
+
});
|
|
6832
|
+
} catch (error) {
|
|
6833
|
+
if (error instanceof ObservabilityDashboardUnsupportedError) {
|
|
6834
|
+
return sendError(
|
|
6835
|
+
reply,
|
|
6836
|
+
501,
|
|
6837
|
+
"OBSERVABILITY_DASHBOARD_UNSUPPORTED",
|
|
6838
|
+
error.message
|
|
6839
|
+
);
|
|
6840
|
+
}
|
|
6841
|
+
if (error instanceof ObservabilityDashboardUnavailableError) {
|
|
6842
|
+
return sendError(
|
|
6843
|
+
reply,
|
|
6844
|
+
502,
|
|
6845
|
+
"OBSERVABILITY_DASHBOARD_UNAVAILABLE",
|
|
6846
|
+
error.message
|
|
6847
|
+
);
|
|
6848
|
+
}
|
|
6849
|
+
logger.warn("observability dashboard failed", {
|
|
6850
|
+
error: error instanceof Error ? error.message : String(error)
|
|
6851
|
+
});
|
|
6852
|
+
return sendError(
|
|
6853
|
+
reply,
|
|
6854
|
+
502,
|
|
6855
|
+
"OBSERVABILITY_DASHBOARD_FAILED",
|
|
6856
|
+
"Failed to load dashboard"
|
|
6857
|
+
);
|
|
6858
|
+
}
|
|
6859
|
+
}
|
|
6860
|
+
|
|
6530
6861
|
// src/controllers/system-metrics.ts
|
|
6531
6862
|
import {
|
|
6532
6863
|
getReplicaId as getReplicaId4,
|
|
@@ -7874,8 +8205,92 @@ async function executeSqlQuery(client, body, reply) {
|
|
|
7874
8205
|
}
|
|
7875
8206
|
|
|
7876
8207
|
// src/controllers/workflow-tracking.ts
|
|
7877
|
-
import {
|
|
7878
|
-
|
|
8208
|
+
import {
|
|
8209
|
+
getStoreLattice as getStoreLattice14,
|
|
8210
|
+
agentInstanceManager as agentInstanceManager7,
|
|
8211
|
+
ThreadStatus as ThreadStatus2,
|
|
8212
|
+
abortWorkflowRun as signalAbort
|
|
8213
|
+
} from "@axiom-lattice/core";
|
|
8214
|
+
|
|
8215
|
+
// src/router/roomInterrupt.ts
|
|
8216
|
+
var CLARIFY_FENCE = /^```clarify\n([\s\S]*?)\n```$/;
|
|
8217
|
+
function readClarifyValue(value) {
|
|
8218
|
+
if (typeof value !== "string") return void 0;
|
|
8219
|
+
const match = CLARIFY_FENCE.exec(value.trim());
|
|
8220
|
+
if (!match) return void 0;
|
|
8221
|
+
try {
|
|
8222
|
+
const parsed = JSON.parse(match[1]);
|
|
8223
|
+
if (typeof parsed === "object" && parsed !== null && Array.isArray(parsed.questions)) {
|
|
8224
|
+
return parsed;
|
|
8225
|
+
}
|
|
8226
|
+
} catch {
|
|
8227
|
+
}
|
|
8228
|
+
return void 0;
|
|
8229
|
+
}
|
|
8230
|
+
function rawInterruptId(interrupt, taskId, taskIndex, index) {
|
|
8231
|
+
const record = typeof interrupt === "object" && interrupt !== null ? interrupt : void 0;
|
|
8232
|
+
const rawId = record?.id;
|
|
8233
|
+
if (typeof rawId === "string" || typeof rawId === "number") return String(rawId);
|
|
8234
|
+
return `${taskId ?? `task-${taskIndex}`}:${index}`;
|
|
8235
|
+
}
|
|
8236
|
+
function pendingInterrupts(state) {
|
|
8237
|
+
if (typeof state !== "object" || state === null) return [];
|
|
8238
|
+
const tasks = state.tasks;
|
|
8239
|
+
if (!Array.isArray(tasks)) return [];
|
|
8240
|
+
const result = [];
|
|
8241
|
+
tasks.forEach((task, taskIndex) => {
|
|
8242
|
+
const record = typeof task === "object" && task !== null ? task : void 0;
|
|
8243
|
+
const rawTaskId = record?.id;
|
|
8244
|
+
const taskId = typeof rawTaskId === "string" || typeof rawTaskId === "number" ? String(rawTaskId) : void 0;
|
|
8245
|
+
const interrupts = record?.interrupts;
|
|
8246
|
+
if (!Array.isArray(interrupts)) return;
|
|
8247
|
+
interrupts.forEach((interrupt, index) => {
|
|
8248
|
+
const value = typeof interrupt === "object" && interrupt !== null ? interrupt.value : void 0;
|
|
8249
|
+
const clarify = readClarifyValue(value);
|
|
8250
|
+
result.push({
|
|
8251
|
+
interruptId: rawInterruptId(interrupt, taskId, taskIndex, index),
|
|
8252
|
+
...clarify === void 0 ? {} : { clarify }
|
|
8253
|
+
});
|
|
8254
|
+
});
|
|
8255
|
+
});
|
|
8256
|
+
return result;
|
|
8257
|
+
}
|
|
8258
|
+
function readPendingInterruptTarget(state) {
|
|
8259
|
+
const interrupts = pendingInterrupts(state);
|
|
8260
|
+
if (interrupts.length === 0) return void 0;
|
|
8261
|
+
const ids = new Set(interrupts.map((interrupt) => interrupt.interruptId));
|
|
8262
|
+
if (ids.size !== interrupts.length) return { conflict: true };
|
|
8263
|
+
const clarify = interrupts.find((interrupt) => interrupt.clarify !== void 0);
|
|
8264
|
+
if (clarify !== void 0) {
|
|
8265
|
+
if (!isOfficialInterruptId(clarify.interruptId) && interrupts.length > 1) return { conflict: true };
|
|
8266
|
+
return { target: clarify };
|
|
8267
|
+
}
|
|
8268
|
+
return interrupts.length === 1 ? { target: interrupts[0] } : { conflict: true };
|
|
8269
|
+
}
|
|
8270
|
+
function readExplicitInterruptTarget(state, interruptId) {
|
|
8271
|
+
const interrupts = pendingInterrupts(state);
|
|
8272
|
+
const matches = interrupts.filter((interrupt) => interrupt.interruptId === interruptId);
|
|
8273
|
+
if (matches.length > 1) return { conflict: true };
|
|
8274
|
+
const target = matches[0];
|
|
8275
|
+
if (target === void 0) return void 0;
|
|
8276
|
+
if (!isOfficialInterruptId(interruptId) && interrupts.length > 1) return { conflict: true };
|
|
8277
|
+
return { target };
|
|
8278
|
+
}
|
|
8279
|
+
function readClarifyInterruptTarget(state) {
|
|
8280
|
+
const match = readPendingInterruptTarget(state);
|
|
8281
|
+
return match !== void 0 && !("conflict" in match) && match.target.clarify !== void 0 ? match.target : void 0;
|
|
8282
|
+
}
|
|
8283
|
+
function readClarifyInterrupt(state) {
|
|
8284
|
+
return pendingInterrupts(state).find((interrupt) => interrupt.clarify !== void 0)?.clarify;
|
|
8285
|
+
}
|
|
8286
|
+
function buildClarifyResumeCommand(text, interruptId) {
|
|
8287
|
+
return resumeMap(interruptId, { data: { answers: [{ questionIndex: 0, otherText: text }] } });
|
|
8288
|
+
}
|
|
8289
|
+
function buildClarifySkipCommand(interruptId) {
|
|
8290
|
+
return resumeMap(interruptId, { data: { answers: [] } });
|
|
8291
|
+
}
|
|
8292
|
+
|
|
8293
|
+
// src/controllers/workflow-tracking.ts
|
|
7879
8294
|
function getTenantId14(request) {
|
|
7880
8295
|
const userTenantId = request.user?.tenantId;
|
|
7881
8296
|
if (userTenantId) return userTenantId;
|
|
@@ -8202,19 +8617,19 @@ async function deleteWorkflowRun(request, reply) {
|
|
|
8202
8617
|
return reply.status(404).send({ success: false, message: "Workflow run not found" });
|
|
8203
8618
|
}
|
|
8204
8619
|
if (run2.status === "running") {
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
thread_id: run2.threadId,
|
|
8211
|
-
tenant_id: tenantId,
|
|
8212
|
-
workspace_id,
|
|
8213
|
-
project_id
|
|
8620
|
+
const result = await requestWorkflowCancel(request, tenantId, run2);
|
|
8621
|
+
if (result === "unavailable") {
|
|
8622
|
+
return reply.status(503).send({
|
|
8623
|
+
success: false,
|
|
8624
|
+
message: "Workflow cancellation is unavailable on this replica"
|
|
8214
8625
|
});
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8626
|
+
}
|
|
8627
|
+
if (result === "accepted" || result === "not_found") {
|
|
8628
|
+
await store2.updateWorkflowRun(runId, {
|
|
8629
|
+
status: "cancelled",
|
|
8630
|
+
errorMessage: "Deleted by user",
|
|
8631
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
8632
|
+
}).catch(() => void 0);
|
|
8218
8633
|
}
|
|
8219
8634
|
}
|
|
8220
8635
|
await store2.deleteWorkflowRun(runId);
|
|
@@ -8307,29 +8722,62 @@ async function replyInboxTask(request, reply) {
|
|
|
8307
8722
|
data: { runId: run2.id, assistantId: run2.assistantId, threadId: run2.threadId, status: runStatus }
|
|
8308
8723
|
});
|
|
8309
8724
|
}
|
|
8310
|
-
agent.
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8725
|
+
const currentState = await agent.getCurrentState();
|
|
8726
|
+
const interruptMatch = readPendingInterruptTarget(currentState);
|
|
8727
|
+
if (!interruptMatch || "conflict" in interruptMatch) {
|
|
8728
|
+
return reply.status(409).send({
|
|
8729
|
+
success: false,
|
|
8730
|
+
message: "Cannot resume: pending interrupt is missing or ambiguous",
|
|
8731
|
+
data: { runId: run2.id, assistantId: run2.assistantId, threadId: run2.threadId }
|
|
8732
|
+
});
|
|
8733
|
+
}
|
|
8734
|
+
const interruptTarget = interruptMatch.target;
|
|
8735
|
+
const resume = interruptTarget.clarify ? clarifyResume({ answers }, interruptTarget.interruptId) : {
|
|
8736
|
+
command: resumeMap(interruptTarget.interruptId, {
|
|
8737
|
+
action: "submit",
|
|
8738
|
+
data: { answers },
|
|
8739
|
+
message: "Clarification answers submitted"
|
|
8740
|
+
})
|
|
8741
|
+
};
|
|
8742
|
+
if (!resume.command) {
|
|
8743
|
+
return reply.status(400).send({
|
|
8744
|
+
success: false,
|
|
8745
|
+
message: "error" in resume ? resume.error ?? "Invalid resume answers" : "Invalid resume answers"
|
|
8746
|
+
});
|
|
8747
|
+
}
|
|
8748
|
+
let queuedStatus = 200;
|
|
8749
|
+
let runPayload;
|
|
8750
|
+
const syntheticReply = {
|
|
8751
|
+
status(code) {
|
|
8752
|
+
queuedStatus = code;
|
|
8753
|
+
return this;
|
|
8754
|
+
},
|
|
8755
|
+
send(payload) {
|
|
8756
|
+
runPayload = payload;
|
|
8757
|
+
return this;
|
|
8758
|
+
},
|
|
8759
|
+
header() {
|
|
8760
|
+
return this;
|
|
8318
8761
|
}
|
|
8319
|
-
}
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8762
|
+
};
|
|
8763
|
+
await createRun(
|
|
8764
|
+
{
|
|
8765
|
+
...request,
|
|
8766
|
+
body: {
|
|
8767
|
+
assistant_id: run2.assistantId,
|
|
8768
|
+
thread_id: run2.threadId,
|
|
8769
|
+
background: true,
|
|
8770
|
+
command: resume.command
|
|
8326
8771
|
}
|
|
8327
|
-
}
|
|
8328
|
-
|
|
8772
|
+
},
|
|
8773
|
+
syntheticReply
|
|
8774
|
+
);
|
|
8775
|
+
if (queuedStatus >= 400) {
|
|
8776
|
+
return reply.status(queuedStatus).send(runPayload ?? {
|
|
8777
|
+
success: false,
|
|
8778
|
+
message: "Failed to enqueue workflow resume"
|
|
8329
8779
|
});
|
|
8330
|
-
}
|
|
8331
|
-
request.log.error(error, "Background resume failed");
|
|
8332
|
-
});
|
|
8780
|
+
}
|
|
8333
8781
|
return reply.status(200).send({
|
|
8334
8782
|
success: true,
|
|
8335
8783
|
message: "Resume request submitted successfully",
|
|
@@ -8348,6 +8796,60 @@ async function replyInboxTask(request, reply) {
|
|
|
8348
8796
|
});
|
|
8349
8797
|
}
|
|
8350
8798
|
}
|
|
8799
|
+
async function requestWorkflowCancel(request, tenantId, run2) {
|
|
8800
|
+
let agentRun;
|
|
8801
|
+
try {
|
|
8802
|
+
const ledger = getStoreLattice14("default", "agentRun").store;
|
|
8803
|
+
agentRun = await ledger.findRunning(tenantId, run2.threadId);
|
|
8804
|
+
} catch {
|
|
8805
|
+
}
|
|
8806
|
+
if (agentRun) {
|
|
8807
|
+
const router = getRunCancelRouter();
|
|
8808
|
+
if (router) {
|
|
8809
|
+
try {
|
|
8810
|
+
const result = await router.requestCancelById({
|
|
8811
|
+
tenantId,
|
|
8812
|
+
assistantId: run2.assistantId,
|
|
8813
|
+
threadId: run2.threadId,
|
|
8814
|
+
runId: agentRun.runId,
|
|
8815
|
+
reason: "abort"
|
|
8816
|
+
});
|
|
8817
|
+
if (result === "not_found") return "not_found";
|
|
8818
|
+
if (result === "terminal") return "terminal";
|
|
8819
|
+
signalAbort(run2.id);
|
|
8820
|
+
return "accepted";
|
|
8821
|
+
} catch {
|
|
8822
|
+
return "unavailable";
|
|
8823
|
+
}
|
|
8824
|
+
}
|
|
8825
|
+
try {
|
|
8826
|
+
const ledger = getStoreLattice14("default", "agentRun").store;
|
|
8827
|
+
const result = await ledger.requestCancel(tenantId, agentRun.runId);
|
|
8828
|
+
if (result === "not_found") return "not_found";
|
|
8829
|
+
if (result === "terminal") return "terminal";
|
|
8830
|
+
signalAbort(run2.id);
|
|
8831
|
+
return "accepted";
|
|
8832
|
+
} catch {
|
|
8833
|
+
return "unavailable";
|
|
8834
|
+
}
|
|
8835
|
+
}
|
|
8836
|
+
try {
|
|
8837
|
+
const workspace_id = request.headers["x-workspace-id"];
|
|
8838
|
+
const project_id = request.headers["x-project-id"];
|
|
8839
|
+
const agent = agentInstanceManager7.getAgent({
|
|
8840
|
+
assistant_id: run2.assistantId,
|
|
8841
|
+
thread_id: run2.threadId,
|
|
8842
|
+
tenant_id: tenantId,
|
|
8843
|
+
workspace_id,
|
|
8844
|
+
project_id
|
|
8845
|
+
});
|
|
8846
|
+
await agent.abort();
|
|
8847
|
+
signalAbort(run2.id);
|
|
8848
|
+
return "accepted";
|
|
8849
|
+
} catch {
|
|
8850
|
+
return "unavailable";
|
|
8851
|
+
}
|
|
8852
|
+
}
|
|
8351
8853
|
async function abortWorkflowRun(request, reply) {
|
|
8352
8854
|
try {
|
|
8353
8855
|
const { runId } = request.params;
|
|
@@ -8366,23 +8868,24 @@ async function abortWorkflowRun(request, reply) {
|
|
|
8366
8868
|
message: "Workflow run not found"
|
|
8367
8869
|
});
|
|
8368
8870
|
}
|
|
8871
|
+
const result = await requestWorkflowCancel(request, tenantId, run2);
|
|
8872
|
+
if (result === "not_found" || result === "terminal") {
|
|
8873
|
+
return reply.status(409).send({
|
|
8874
|
+
success: false,
|
|
8875
|
+
message: result === "terminal" ? "Workflow run is already finished" : "Workflow run is not running"
|
|
8876
|
+
});
|
|
8877
|
+
}
|
|
8878
|
+
if (result === "unavailable") {
|
|
8879
|
+
return reply.status(503).send({
|
|
8880
|
+
success: false,
|
|
8881
|
+
message: "Workflow cancellation is unavailable on this replica"
|
|
8882
|
+
});
|
|
8883
|
+
}
|
|
8369
8884
|
await store2.updateWorkflowRun(runId, {
|
|
8370
8885
|
status: "cancelled",
|
|
8371
8886
|
errorMessage: "Aborted by user",
|
|
8372
8887
|
completedAt: /* @__PURE__ */ new Date()
|
|
8373
|
-
}).catch(() =>
|
|
8374
|
-
});
|
|
8375
|
-
const workspace_id = request.headers["x-workspace-id"];
|
|
8376
|
-
const project_id = request.headers["x-project-id"];
|
|
8377
|
-
const agent = agentInstanceManager7.getAgent({
|
|
8378
|
-
assistant_id: run2.assistantId,
|
|
8379
|
-
thread_id: run2.threadId,
|
|
8380
|
-
tenant_id: tenantId,
|
|
8381
|
-
workspace_id,
|
|
8382
|
-
project_id
|
|
8383
|
-
});
|
|
8384
|
-
await agent.abort();
|
|
8385
|
-
signalAbort(runId);
|
|
8888
|
+
}).catch(() => void 0);
|
|
8386
8889
|
return reply.status(200).send({
|
|
8387
8890
|
success: true,
|
|
8388
8891
|
message: "Workflow aborted",
|
|
@@ -8408,7 +8911,7 @@ function getTenantId15(request) {
|
|
|
8408
8911
|
if (userTenantId) return userTenantId;
|
|
8409
8912
|
return request.headers["x-tenant-id"] || "default";
|
|
8410
8913
|
}
|
|
8411
|
-
function
|
|
8914
|
+
function getUserId5(request) {
|
|
8412
8915
|
const userId = request.user?.id || request.headers["x-user-id"];
|
|
8413
8916
|
if (!userId) throw new Error("User ID is required");
|
|
8414
8917
|
return userId;
|
|
@@ -8431,7 +8934,7 @@ async function updateLinkMeta(userId, tenantId, meta) {
|
|
|
8431
8934
|
}
|
|
8432
8935
|
async function createPersonalAssistant(request, reply) {
|
|
8433
8936
|
const tenantId = getTenantId15(request);
|
|
8434
|
-
const userId =
|
|
8937
|
+
const userId = getUserId5(request);
|
|
8435
8938
|
const { name, personality } = request.body;
|
|
8436
8939
|
if (!name || !personality) {
|
|
8437
8940
|
return reply.status(400).send({ success: false, message: "name and personality are required" });
|
|
@@ -8468,7 +8971,7 @@ async function createPersonalAssistant(request, reply) {
|
|
|
8468
8971
|
}
|
|
8469
8972
|
async function getPersonalAssistant(request, reply) {
|
|
8470
8973
|
const tenantId = getTenantId15(request);
|
|
8471
|
-
const userId =
|
|
8974
|
+
const userId = getUserId5(request);
|
|
8472
8975
|
const store2 = getAssistantStore();
|
|
8473
8976
|
const assistant = await store2.getByOwner(tenantId, userId);
|
|
8474
8977
|
if (!assistant) {
|
|
@@ -8485,7 +8988,7 @@ async function getPersonalAssistant(request, reply) {
|
|
|
8485
8988
|
}
|
|
8486
8989
|
async function deletePersonalAssistant(request, reply) {
|
|
8487
8990
|
const tenantId = getTenantId15(request);
|
|
8488
|
-
const userId =
|
|
8991
|
+
const userId = getUserId5(request);
|
|
8489
8992
|
const store2 = getAssistantStore();
|
|
8490
8993
|
const assistant = await store2.getByOwner(tenantId, userId);
|
|
8491
8994
|
if (!assistant) {
|
|
@@ -9162,7 +9665,7 @@ var ExportImportService = class {
|
|
|
9162
9665
|
// src/controllers/export-import.ts
|
|
9163
9666
|
import { ExportableEntityRegistry as ExportableEntityRegistry2 } from "@axiom-lattice/core";
|
|
9164
9667
|
var service = new ExportImportService();
|
|
9165
|
-
var
|
|
9668
|
+
var TenantScopeError2 = class extends Error {
|
|
9166
9669
|
constructor() {
|
|
9167
9670
|
super(...arguments);
|
|
9168
9671
|
this.statusCode = 403;
|
|
@@ -9174,12 +9677,12 @@ function resolveTenantId(request, routeTenantId) {
|
|
|
9174
9677
|
const headerTenantId = Array.isArray(header2) ? header2[0] : header2;
|
|
9175
9678
|
if (authenticatedTenantId) {
|
|
9176
9679
|
if (headerTenantId && headerTenantId !== authenticatedTenantId) {
|
|
9177
|
-
throw new
|
|
9680
|
+
throw new TenantScopeError2(
|
|
9178
9681
|
`Tenant scope mismatch: header tenant "${headerTenantId}" does not match authenticated tenant "${authenticatedTenantId}"`
|
|
9179
9682
|
);
|
|
9180
9683
|
}
|
|
9181
9684
|
if (routeTenantId && routeTenantId !== authenticatedTenantId) {
|
|
9182
|
-
throw new
|
|
9685
|
+
throw new TenantScopeError2(
|
|
9183
9686
|
`Tenant scope mismatch: route tenant "${routeTenantId}" does not match authenticated tenant "${authenticatedTenantId}"`
|
|
9184
9687
|
);
|
|
9185
9688
|
}
|
|
@@ -13033,7 +13536,9 @@ import {
|
|
|
13033
13536
|
} from "@axiom-lattice/protocols";
|
|
13034
13537
|
import {
|
|
13035
13538
|
getSandboxPluginCatalog as getSandboxPluginCatalog2,
|
|
13036
|
-
mcpManager as mcpManager2
|
|
13539
|
+
mcpManager as mcpManager2,
|
|
13540
|
+
resolvePluginConnections,
|
|
13541
|
+
verifyMcpUiScope
|
|
13037
13542
|
} from "@axiom-lattice/core";
|
|
13038
13543
|
|
|
13039
13544
|
// src/services/mcp-ui/UiResourceResolver.ts
|
|
@@ -13303,6 +13808,22 @@ var PluginMethodNotSupportedError = class extends Error {
|
|
|
13303
13808
|
this.name = "PluginMethodNotSupportedError";
|
|
13304
13809
|
}
|
|
13305
13810
|
};
|
|
13811
|
+
var McpAppScopeError = class extends Error {
|
|
13812
|
+
/**
|
|
13813
|
+
* @param status - HTTP status to return.
|
|
13814
|
+
* @param code - Stable machine-readable denial code.
|
|
13815
|
+
*/
|
|
13816
|
+
constructor(status, code) {
|
|
13817
|
+
super(code);
|
|
13818
|
+
this.status = status;
|
|
13819
|
+
this.code = code;
|
|
13820
|
+
this.name = "McpAppScopeError";
|
|
13821
|
+
}
|
|
13822
|
+
};
|
|
13823
|
+
function denyScope(status, code, detail) {
|
|
13824
|
+
console.warn(JSON.stringify({ event: "mcp-apps:scope-denied", ...detail, code }));
|
|
13825
|
+
return new McpAppScopeError(status, code);
|
|
13826
|
+
}
|
|
13306
13827
|
var ALLOWED_METHODS = /* @__PURE__ */ new Set(["tools/call", "tools/list", "resources/read"]);
|
|
13307
13828
|
function asRecord(value) {
|
|
13308
13829
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
@@ -13369,6 +13890,9 @@ function makeMcpAppHandlers(deps) {
|
|
|
13369
13890
|
}
|
|
13370
13891
|
return { status: 200, body: { tools: await deps.listTools(tenantId, ref) } };
|
|
13371
13892
|
} catch (error) {
|
|
13893
|
+
if (error instanceof McpAppScopeError) {
|
|
13894
|
+
return { status: error.status, body: { error: error.code } };
|
|
13895
|
+
}
|
|
13372
13896
|
if (error instanceof PluginToolScopeError) {
|
|
13373
13897
|
return { status: 403, body: { error: "PLUGIN_TOOL_SCOPE" } };
|
|
13374
13898
|
}
|
|
@@ -13412,8 +13936,84 @@ async function fetchPluginUiResource(backend, tenantId, pluginType, resource) {
|
|
|
13412
13936
|
prefersBorder: tool.ui.prefersBorder
|
|
13413
13937
|
};
|
|
13414
13938
|
}
|
|
13415
|
-
async function callPluginTool(backend, tenantId, ref, name, args, context) {
|
|
13416
|
-
|
|
13939
|
+
async function callPluginTool(backend, tenantId, ref, name, args, context, deps) {
|
|
13940
|
+
const scope = ref.scope ? (deps?.verifyScope ?? verifyMcpUiScope)(ref.scope) : null;
|
|
13941
|
+
if (ref.scope && !scope) {
|
|
13942
|
+
throw denyScope(403, "SCOPE_INVALID", {
|
|
13943
|
+
tenantId,
|
|
13944
|
+
pluginType: ref.pluginType,
|
|
13945
|
+
tool: name
|
|
13946
|
+
});
|
|
13947
|
+
}
|
|
13948
|
+
if (scope) {
|
|
13949
|
+
const mismatched = scope.tid !== tenantId || scope.plugin !== ref.pluginType || scope.resource !== ref.resource;
|
|
13950
|
+
if (mismatched) {
|
|
13951
|
+
throw denyScope(403, "SCOPE_MISMATCH", {
|
|
13952
|
+
tenantId,
|
|
13953
|
+
pluginType: ref.pluginType,
|
|
13954
|
+
tool: name,
|
|
13955
|
+
jti: scope.jti,
|
|
13956
|
+
threadId: scope.thid
|
|
13957
|
+
});
|
|
13958
|
+
}
|
|
13959
|
+
}
|
|
13960
|
+
const manifest = await backend.catalog.getValidatedManifest(tenantId, ref.pluginType);
|
|
13961
|
+
const rawConnectionKey = args.connectionKey;
|
|
13962
|
+
const explicit = typeof rawConnectionKey === "string" ? rawConnectionKey : void 0;
|
|
13963
|
+
const scoped = scope?.ck;
|
|
13964
|
+
const connectionRelevant = Boolean(manifest?.connection) || scoped !== void 0;
|
|
13965
|
+
if (connectionRelevant && (explicit !== void 0 ? explicit !== scoped : rawConnectionKey !== void 0)) {
|
|
13966
|
+
throw denyScope(403, "CONNECTION_NOT_ALLOWED", {
|
|
13967
|
+
tenantId,
|
|
13968
|
+
pluginType: ref.pluginType,
|
|
13969
|
+
tool: name,
|
|
13970
|
+
jti: scope?.jti,
|
|
13971
|
+
threadId: scope?.thid
|
|
13972
|
+
});
|
|
13973
|
+
}
|
|
13974
|
+
let connection;
|
|
13975
|
+
let connectionKey;
|
|
13976
|
+
if (scoped !== void 0) {
|
|
13977
|
+
const resolveConnections = deps?.resolveConnections ?? resolvePluginConnections;
|
|
13978
|
+
const resolved = await resolveConnections(
|
|
13979
|
+
ref.pluginType,
|
|
13980
|
+
{ connections: [scoped] },
|
|
13981
|
+
{ tenantId }
|
|
13982
|
+
);
|
|
13983
|
+
if (resolved.length === 0) {
|
|
13984
|
+
throw denyScope(403, "CONNECTION_NOT_ALLOWED", {
|
|
13985
|
+
tenantId,
|
|
13986
|
+
pluginType: ref.pluginType,
|
|
13987
|
+
tool: name,
|
|
13988
|
+
jti: scope?.jti,
|
|
13989
|
+
threadId: scope?.thid
|
|
13990
|
+
});
|
|
13991
|
+
}
|
|
13992
|
+
connection = resolved[0].config;
|
|
13993
|
+
connectionKey = resolved[0].key;
|
|
13994
|
+
}
|
|
13995
|
+
if (manifest?.connection && !connectionKey) {
|
|
13996
|
+
throw denyScope(409, "CONNECTION_REQUIRED", {
|
|
13997
|
+
tenantId,
|
|
13998
|
+
pluginType: ref.pluginType,
|
|
13999
|
+
tool: name,
|
|
14000
|
+
jti: scope?.jti,
|
|
14001
|
+
threadId: scope?.thid
|
|
14002
|
+
});
|
|
14003
|
+
}
|
|
14004
|
+
const identity = scope ? {
|
|
14005
|
+
workspaceId: scope.wid,
|
|
14006
|
+
projectId: scope.pid,
|
|
14007
|
+
threadId: scope.thid,
|
|
14008
|
+
assistantId: scope.aid
|
|
14009
|
+
} : {
|
|
14010
|
+
workspaceId: context?.workspaceId,
|
|
14011
|
+
projectId: context?.projectId
|
|
14012
|
+
};
|
|
14013
|
+
return invokePluginTool(backend, tenantId, ref.pluginType, name, args, {
|
|
14014
|
+
...identity,
|
|
14015
|
+
...connection === void 0 ? {} : { connection }
|
|
14016
|
+
});
|
|
13417
14017
|
}
|
|
13418
14018
|
function createDefaultPluginBackend() {
|
|
13419
14019
|
return {
|
|
@@ -13461,8 +14061,8 @@ function runContextOf(request) {
|
|
|
13461
14061
|
projectId: firstHeader(request, "x-project-id")
|
|
13462
14062
|
};
|
|
13463
14063
|
}
|
|
13464
|
-
function registerMcpAppRoutes(fastify2) {
|
|
13465
|
-
const handlers = makeMcpAppHandlers(
|
|
14064
|
+
function registerMcpAppRoutes(fastify2, deps = resolveMcpAppDeps()) {
|
|
14065
|
+
const handlers = makeMcpAppHandlers(deps);
|
|
13466
14066
|
fastify2.get("/mcp-apps/sandbox.html", async (_request, reply) => {
|
|
13467
14067
|
return reply.header("content-type", SANDBOX_HTML_CONTENT_TYPE).header("x-content-type-options", "nosniff").header("cache-control", "no-store").send(SANDBOX_HTML);
|
|
13468
14068
|
});
|
|
@@ -13493,6 +14093,7 @@ import { v4 as uuidv43 } from "uuid";
|
|
|
13493
14093
|
// src/services/eval-runner.ts
|
|
13494
14094
|
import { EventEmitter } from "events";
|
|
13495
14095
|
import {
|
|
14096
|
+
getReplicaId as getReplicaId6,
|
|
13496
14097
|
getStoreLattice as getStoreLattice20,
|
|
13497
14098
|
hasModelLatticeForTenant,
|
|
13498
14099
|
listModelLatticesForTenant,
|
|
@@ -13500,6 +14101,8 @@ import {
|
|
|
13500
14101
|
} from "@axiom-lattice/core";
|
|
13501
14102
|
import { v4 as uuidv42 } from "uuid";
|
|
13502
14103
|
var TERMINAL_PERSIST_ATTEMPTS = 2;
|
|
14104
|
+
var EVAL_EXECUTION_LEASE = "eval:execution";
|
|
14105
|
+
var EVAL_LEASE_TTL_MS = 6e4;
|
|
13503
14106
|
function mapLogs(logs) {
|
|
13504
14107
|
return logs.map((l) => ({
|
|
13505
14108
|
timestamp: l.ts,
|
|
@@ -13534,14 +14137,48 @@ var EvalRunner = class {
|
|
|
13534
14137
|
}
|
|
13535
14138
|
const leaseToken = Symbol(leaseKey);
|
|
13536
14139
|
this.projectLeases.set(leaseKey, leaseToken);
|
|
14140
|
+
let executionLease;
|
|
13537
14141
|
try {
|
|
13538
|
-
|
|
14142
|
+
executionLease = await this.acquireExecutionLease();
|
|
14143
|
+
return await this.startLeasedRun(
|
|
14144
|
+
tenantId,
|
|
14145
|
+
projectId,
|
|
14146
|
+
suiteIds,
|
|
14147
|
+
caseIds,
|
|
14148
|
+
runConfig,
|
|
14149
|
+
taskId,
|
|
14150
|
+
leaseKey,
|
|
14151
|
+
leaseToken,
|
|
14152
|
+
executionLease.release
|
|
14153
|
+
);
|
|
13539
14154
|
} catch (error) {
|
|
13540
14155
|
this.releaseProjectLease(leaseKey, leaseToken);
|
|
14156
|
+
await executionLease?.release();
|
|
13541
14157
|
throw error;
|
|
13542
14158
|
}
|
|
13543
14159
|
}
|
|
13544
|
-
|
|
14160
|
+
/** One eval at a time across replicas; the executing worker holds this lease. */
|
|
14161
|
+
async acquireExecutionLease() {
|
|
14162
|
+
const store2 = this.getLeaseStore();
|
|
14163
|
+
const holder = `${getReplicaId6()}#${uuidv42()}`;
|
|
14164
|
+
if (!await store2.tryAcquire(EVAL_EXECUTION_LEASE, holder, EVAL_LEASE_TTL_MS)) {
|
|
14165
|
+
throw new Error("An evaluation run is already in progress");
|
|
14166
|
+
}
|
|
14167
|
+
const heartbeat = setInterval(() => {
|
|
14168
|
+
void store2.renew(EVAL_EXECUTION_LEASE, holder, EVAL_LEASE_TTL_MS).catch(() => void 0);
|
|
14169
|
+
}, Math.max(1e3, Math.floor(EVAL_LEASE_TTL_MS / 3)));
|
|
14170
|
+
heartbeat.unref?.();
|
|
14171
|
+
return {
|
|
14172
|
+
release: async () => {
|
|
14173
|
+
clearInterval(heartbeat);
|
|
14174
|
+
await store2.release(EVAL_EXECUTION_LEASE, holder).catch(() => void 0);
|
|
14175
|
+
}
|
|
14176
|
+
};
|
|
14177
|
+
}
|
|
14178
|
+
getLeaseStore() {
|
|
14179
|
+
return getStoreLattice20("default", "lease").store;
|
|
14180
|
+
}
|
|
14181
|
+
async startLeasedRun(tenantId, projectId, suiteIds, caseIds, runConfig, taskId, leaseKey, leaseToken, releaseExecutionLease) {
|
|
13545
14182
|
const store2 = this.getEvalStore();
|
|
13546
14183
|
const project = await store2.getProjectById(tenantId, projectId);
|
|
13547
14184
|
if (!project) throw new Error("Project not found");
|
|
@@ -13719,6 +14356,12 @@ var EvalRunner = class {
|
|
|
13719
14356
|
});
|
|
13720
14357
|
};
|
|
13721
14358
|
const runPromise = (async () => {
|
|
14359
|
+
const cancelPoll = setInterval(() => {
|
|
14360
|
+
void Promise.resolve(this.getEvalStore().getRunById(tenantId, runId)).then((latest) => {
|
|
14361
|
+
if (latest?.cancelRequested) abortController.abort();
|
|
14362
|
+
}).catch(() => void 0);
|
|
14363
|
+
}, 1e3);
|
|
14364
|
+
cancelPoll.unref?.();
|
|
13722
14365
|
try {
|
|
13723
14366
|
const evalProject = new LatticeEvalProject(projectConfig, onCaseComplete);
|
|
13724
14367
|
const calibration = await evalProject.calibrateJudge();
|
|
@@ -13744,10 +14387,11 @@ var EvalRunner = class {
|
|
|
13744
14387
|
});
|
|
13745
14388
|
return { report };
|
|
13746
14389
|
} catch (err) {
|
|
13747
|
-
const
|
|
14390
|
+
const latest = await Promise.resolve(this.getEvalStore().getRunById(tenantId, runId)).catch(() => null);
|
|
14391
|
+
const errorMsg = latest?.cancelRequested ? "Run aborted" : err.message;
|
|
13748
14392
|
try {
|
|
13749
14393
|
await persistTerminal({
|
|
13750
|
-
status: "failed",
|
|
14394
|
+
status: latest?.cancelRequested ? "aborted" : "failed",
|
|
13751
14395
|
error: errorMsg,
|
|
13752
14396
|
completedAt: /* @__PURE__ */ new Date()
|
|
13753
14397
|
}, {
|
|
@@ -13759,11 +14403,13 @@ var EvalRunner = class {
|
|
|
13759
14403
|
}
|
|
13760
14404
|
throw err;
|
|
13761
14405
|
} finally {
|
|
14406
|
+
clearInterval(cancelPoll);
|
|
13762
14407
|
terminal.workerSettled = true;
|
|
13763
14408
|
if (terminal.persisted) {
|
|
13764
14409
|
this.runs.delete(runId);
|
|
13765
14410
|
this.releaseProjectLease(leaseKey, leaseToken);
|
|
13766
14411
|
}
|
|
14412
|
+
await releaseExecutionLease();
|
|
13767
14413
|
}
|
|
13768
14414
|
})();
|
|
13769
14415
|
this.runs.set(runId, { runId, projectId, tenantId, abortController, promise: runPromise, terminal, leaseKey, leaseToken, taskId });
|
|
@@ -13773,10 +14419,16 @@ var EvalRunner = class {
|
|
|
13773
14419
|
}
|
|
13774
14420
|
async abortRun(runId, tenantId) {
|
|
13775
14421
|
const ctx = this.runs.get(runId);
|
|
13776
|
-
if (
|
|
14422
|
+
if (ctx && tenantId !== void 0 && ctx.tenantId !== tenantId) return false;
|
|
14423
|
+
if (!ctx) {
|
|
14424
|
+
if (!tenantId) return false;
|
|
14425
|
+
const store3 = this.getEvalStore();
|
|
14426
|
+
return store3.requestCancel ? await Promise.resolve(store3.requestCancel(tenantId, runId)).catch(() => false) === true : false;
|
|
14427
|
+
}
|
|
13777
14428
|
if (ctx.terminal.claiming || ctx.terminal.persisted) return false;
|
|
13778
|
-
ctx.abortController.abort();
|
|
13779
14429
|
const store2 = this.getEvalStore();
|
|
14430
|
+
void Promise.resolve(store2.requestCancel?.(ctx.tenantId, runId)).catch(() => false);
|
|
14431
|
+
ctx.abortController.abort();
|
|
13780
14432
|
ctx.terminal.claiming = true;
|
|
13781
14433
|
try {
|
|
13782
14434
|
let lastError;
|
|
@@ -14253,8 +14905,8 @@ function registerEvalRoutes(app2) {
|
|
|
14253
14905
|
const tenantId = getTenantId19(request);
|
|
14254
14906
|
const { rid } = request.params;
|
|
14255
14907
|
const store2 = getEvalStore();
|
|
14256
|
-
const
|
|
14257
|
-
if (!
|
|
14908
|
+
const initial = await store2.getRunById(tenantId, rid);
|
|
14909
|
+
if (!initial) return reply.status(404).send({ success: false, message: "Run not found" });
|
|
14258
14910
|
reply.hijack();
|
|
14259
14911
|
reply.raw.writeHead(200, {
|
|
14260
14912
|
"Content-Type": "text/event-stream",
|
|
@@ -14262,67 +14914,74 @@ function registerEvalRoutes(app2) {
|
|
|
14262
14914
|
Connection: "keep-alive",
|
|
14263
14915
|
"Access-Control-Allow-Origin": "*"
|
|
14264
14916
|
});
|
|
14265
|
-
|
|
14266
|
-
|
|
14267
|
-
|
|
14917
|
+
let closed = false;
|
|
14918
|
+
let finished = false;
|
|
14919
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14920
|
+
let timer;
|
|
14268
14921
|
const cleanup = () => {
|
|
14269
|
-
|
|
14270
|
-
|
|
14271
|
-
|
|
14272
|
-
|
|
14273
|
-
if (settled) return;
|
|
14274
|
-
settled = true;
|
|
14275
|
-
cleanup();
|
|
14922
|
+
if (closed) return;
|
|
14923
|
+
closed = true;
|
|
14924
|
+
if (timer) clearInterval(timer);
|
|
14925
|
+
request.raw.off("close", cleanup);
|
|
14276
14926
|
};
|
|
14277
|
-
const
|
|
14278
|
-
if (
|
|
14279
|
-
|
|
14280
|
-
cleanup();
|
|
14281
|
-
reply.raw.write(`event: ${type}
|
|
14927
|
+
const write = (event, data) => {
|
|
14928
|
+
if (closed) return;
|
|
14929
|
+
reply.raw.write(`event: ${event}
|
|
14282
14930
|
data: ${JSON.stringify(data)}
|
|
14283
14931
|
|
|
14284
14932
|
`);
|
|
14933
|
+
};
|
|
14934
|
+
const finish = (event, data) => {
|
|
14935
|
+
if (finished) return;
|
|
14936
|
+
finished = true;
|
|
14937
|
+
write(event, data);
|
|
14938
|
+
cleanup();
|
|
14285
14939
|
reply.raw.end();
|
|
14286
14940
|
};
|
|
14287
|
-
const
|
|
14288
|
-
if (
|
|
14289
|
-
|
|
14941
|
+
const poll = async () => {
|
|
14942
|
+
if (closed || finished) return;
|
|
14943
|
+
let run2;
|
|
14944
|
+
let results;
|
|
14945
|
+
try {
|
|
14946
|
+
run2 = await store2.getRunById(tenantId, rid);
|
|
14947
|
+
if (!run2) {
|
|
14948
|
+
finish("error", { message: "Run not found" });
|
|
14949
|
+
return;
|
|
14950
|
+
}
|
|
14951
|
+
results = await store2.getResultsByRun(tenantId, rid);
|
|
14952
|
+
} catch (error) {
|
|
14290
14953
|
return;
|
|
14291
14954
|
}
|
|
14292
|
-
|
|
14293
|
-
|
|
14294
|
-
|
|
14295
|
-
|
|
14955
|
+
for (const result of results) {
|
|
14956
|
+
if (seen.has(result.id)) continue;
|
|
14957
|
+
seen.add(result.id);
|
|
14958
|
+
write("progress", {
|
|
14959
|
+
suiteName: result.suiteName,
|
|
14960
|
+
caseId: result.caseId,
|
|
14961
|
+
pass: result.pass,
|
|
14962
|
+
score: result.score,
|
|
14963
|
+
interrupted: result.interrupted ?? false,
|
|
14964
|
+
completed: run2.passedCases + run2.failedCases,
|
|
14965
|
+
total: run2.totalCases
|
|
14966
|
+
});
|
|
14967
|
+
}
|
|
14968
|
+
if (run2.status === "completed") {
|
|
14969
|
+
finish("completed", {
|
|
14970
|
+
passed: run2.passedCases,
|
|
14971
|
+
failed: run2.failedCases,
|
|
14972
|
+
avgScore: run2.avgScore
|
|
14973
|
+
});
|
|
14974
|
+
} else if (run2.status === "failed") {
|
|
14975
|
+
finish("error", { message: run2.error ?? "Evaluation failed" });
|
|
14976
|
+
} else if (run2.status === "aborted") {
|
|
14977
|
+
finish("error", { message: "Run aborted" });
|
|
14978
|
+
}
|
|
14296
14979
|
};
|
|
14297
|
-
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
|
|
14301
|
-
|
|
14302
|
-
} catch (error) {
|
|
14303
|
-
finish("error", { message: error.message });
|
|
14304
|
-
return;
|
|
14305
|
-
}
|
|
14306
|
-
if (settled) return;
|
|
14307
|
-
if (!reconciledRun) {
|
|
14308
|
-
cleanup();
|
|
14309
|
-
reply.raw.end();
|
|
14310
|
-
return;
|
|
14311
|
-
}
|
|
14312
|
-
if (reconciledRun.status === "completed") {
|
|
14313
|
-
finish("completed", {
|
|
14314
|
-
passed: reconciledRun.passedCases,
|
|
14315
|
-
failed: reconciledRun.failedCases,
|
|
14316
|
-
avgScore: reconciledRun.avgScore
|
|
14317
|
-
});
|
|
14318
|
-
} else if (reconciledRun.status === "failed") {
|
|
14319
|
-
finish("error", { message: reconciledRun.error ?? "Evaluation failed" });
|
|
14320
|
-
} else if (reconciledRun.status === "aborted") {
|
|
14321
|
-
finish("error", { message: "Run aborted" });
|
|
14322
|
-
} else if (!evalRunner.isRunning(rid, tenantId)) {
|
|
14323
|
-
cleanup();
|
|
14324
|
-
reply.raw.end();
|
|
14325
|
-
}
|
|
14980
|
+
request.raw.on("close", cleanup);
|
|
14981
|
+
await poll();
|
|
14982
|
+
if (!closed && !finished) timer = setInterval(() => {
|
|
14983
|
+
void poll();
|
|
14984
|
+
}, 1e3);
|
|
14326
14985
|
});
|
|
14327
14986
|
app2.post("/api/eval/runs/:rid/abort", async (request, reply) => {
|
|
14328
14987
|
try {
|
|
@@ -14332,7 +14991,7 @@ data: ${JSON.stringify(event.data)}
|
|
|
14332
14991
|
if (!run2) return reply.status(404).send({ success: false, message: "Run not found" });
|
|
14333
14992
|
const aborted = await evalRunner.abortRun(rid, tenantId);
|
|
14334
14993
|
if (!aborted) return reply.status(404).send({ success: false, message: "Run not found or not running" });
|
|
14335
|
-
reply.send({ success: true, message: "
|
|
14994
|
+
reply.status(202).send({ success: true, message: "Abort requested", data: { runId: rid } });
|
|
14336
14995
|
} catch (err) {
|
|
14337
14996
|
reply.status(500).send({ success: false, message: err.message });
|
|
14338
14997
|
}
|
|
@@ -14945,10 +15604,10 @@ function bypassesConsoleAuth(request) {
|
|
|
14945
15604
|
const path5 = request.url.split("?")[0];
|
|
14946
15605
|
const method = request.method;
|
|
14947
15606
|
if (method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/bootstrap$/.test(path5) || (method === "GET" || method === "POST") && /^\/api\/web-apps\/[^/]+\/runtime\/threads$/.test(path5) || (method === "PATCH" || method === "DELETE") && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/messages$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/files\/(viewfile|downloadfile)$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/api\/assistants\/[^/]+\/threads\/[^/]+\/sandbox\/(viewfile|downloadfile)$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/(messages\/stream|abort|attachments)$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/interrupts\/[^/]+\/resume$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs\/[^/]+$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs\/[^/]+\/join$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs\/[^/]+\/cancel$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/chat$/.test(path5) || method === "GET" && /^\/embed\/[^/]+$/.test(path5) || method === "GET" && path5 === "/mcp-apps/sandbox.html" || (method === "POST" || method === "DELETE") && path5 === "/open/mcp" || (method === "POST" || method === "GET") && (path5 === "/mcp" || path5 === "/mcp/") || method === "POST" && path5 === "/open/session" || (method === "GET" || method === "POST") && path5.startsWith("/open/sandbox/files/")) return true;
|
|
14948
|
-
if (request.method === "GET" && (/^\/api\/a2a\/agents\/[^/]+\/\.well-known\/agent-card\.json$/.test(path5) || /^\/a2a\/[^/]+\/\.well-known\/agent-card\.json$/.test(path5))) {
|
|
15607
|
+
if (request.method === "GET" && (/^\/api\/a2a\/agents\/[^/]+\/\.well-known\/agent-card\.json$/.test(path5) || /^\/a2a\/(?:v1\/)?[^/]+\/\.well-known\/agent-card\.json$/.test(path5))) {
|
|
14949
15608
|
return true;
|
|
14950
15609
|
}
|
|
14951
|
-
return request.method === "POST" && /^\/api\/a2a\/agents\/[^/]+\/jsonrpc$/.test(path5) || request.method === "POST" && /^\/a2a\/[^/]+$/.test(path5);
|
|
15610
|
+
return request.method === "POST" && /^\/api\/a2a\/agents\/[^/]+\/jsonrpc$/.test(path5) || request.method === "POST" && /^\/a2a\/(?:v1\/)?[^/]+$/.test(path5);
|
|
14952
15611
|
}
|
|
14953
15612
|
function registerConsoleAuthHook(app2, options) {
|
|
14954
15613
|
app2.addHook("preHandler", async (request, reply) => {
|
|
@@ -15053,7 +15712,7 @@ function normalizeChatType(chatType) {
|
|
|
15053
15712
|
|
|
15054
15713
|
// src/channels/lark/LarkChannelAdapter.ts
|
|
15055
15714
|
import * as Lark from "@larksuiteoapi/node-sdk";
|
|
15056
|
-
var
|
|
15715
|
+
var logger2 = new Logger({ serviceName: "lattice/gateway/lark" });
|
|
15057
15716
|
var activeConnections = /* @__PURE__ */ new Map();
|
|
15058
15717
|
function parseTextContent(content) {
|
|
15059
15718
|
if (!content) return null;
|
|
@@ -15141,21 +15800,21 @@ var larkChannelAdapter = {
|
|
|
15141
15800
|
async connect(installation, deps) {
|
|
15142
15801
|
const { id: installationId, tenantId, config } = installation;
|
|
15143
15802
|
if (!config.appId || !config.appSecret) {
|
|
15144
|
-
|
|
15803
|
+
logger2.warn("Lark installation missing credentials, skipping", { installationId });
|
|
15145
15804
|
return;
|
|
15146
15805
|
}
|
|
15147
15806
|
if (activeConnections.has(installationId)) {
|
|
15148
|
-
|
|
15807
|
+
logger2.warn("Lark WS already connected for installation, skipping", { installationId });
|
|
15149
15808
|
return;
|
|
15150
15809
|
}
|
|
15151
|
-
|
|
15810
|
+
logger2.info("Lark WS client starting", { installationId, tenantId });
|
|
15152
15811
|
const router = deps?.router;
|
|
15153
15812
|
const eventDispatcher = new Lark.EventDispatcher({}).register({
|
|
15154
15813
|
"im.message.receive_v1": async (data) => {
|
|
15155
15814
|
try {
|
|
15156
15815
|
const inbound = wsEventToInbound(data, installationId, tenantId);
|
|
15157
15816
|
if (!inbound) return;
|
|
15158
|
-
|
|
15817
|
+
logger2.info("Lark WS message received", {
|
|
15159
15818
|
installationId,
|
|
15160
15819
|
senderId: inbound.sender.id,
|
|
15161
15820
|
chatId: data.message?.chat_id
|
|
@@ -15163,14 +15822,14 @@ var larkChannelAdapter = {
|
|
|
15163
15822
|
if (router) {
|
|
15164
15823
|
const result = await router.dispatch(inbound);
|
|
15165
15824
|
if (!result.success) {
|
|
15166
|
-
|
|
15825
|
+
logger2.warn("Lark WS dispatch failed", {
|
|
15167
15826
|
installationId,
|
|
15168
15827
|
error: result.error?.message
|
|
15169
15828
|
});
|
|
15170
15829
|
}
|
|
15171
15830
|
}
|
|
15172
15831
|
} catch (err) {
|
|
15173
|
-
|
|
15832
|
+
logger2.error("Lark WS event handler error", {
|
|
15174
15833
|
installationId,
|
|
15175
15834
|
error: err instanceof Error ? err.message : String(err)
|
|
15176
15835
|
});
|
|
@@ -15184,25 +15843,25 @@ var larkChannelAdapter = {
|
|
|
15184
15843
|
});
|
|
15185
15844
|
await client.start({ eventDispatcher });
|
|
15186
15845
|
activeConnections.set(installationId, client);
|
|
15187
|
-
|
|
15846
|
+
logger2.info("Lark WS client connected", { installationId });
|
|
15188
15847
|
},
|
|
15189
15848
|
async disconnect(installationId) {
|
|
15190
15849
|
const client = activeConnections.get(installationId);
|
|
15191
15850
|
if (!client) {
|
|
15192
|
-
|
|
15851
|
+
logger2.warn("Lark WS not connected, nothing to disconnect", { installationId });
|
|
15193
15852
|
return;
|
|
15194
15853
|
}
|
|
15195
|
-
|
|
15854
|
+
logger2.info("Lark WS client disconnecting", { installationId });
|
|
15196
15855
|
try {
|
|
15197
15856
|
client.close({ force: true });
|
|
15198
15857
|
} catch (err) {
|
|
15199
|
-
|
|
15858
|
+
logger2.error("Lark WS client stop error", {
|
|
15200
15859
|
installationId,
|
|
15201
15860
|
error: err instanceof Error ? err.message : String(err)
|
|
15202
15861
|
});
|
|
15203
15862
|
}
|
|
15204
15863
|
activeConnections.delete(installationId);
|
|
15205
|
-
|
|
15864
|
+
logger2.info("Lark WS client disconnected", { installationId });
|
|
15206
15865
|
}
|
|
15207
15866
|
};
|
|
15208
15867
|
|
|
@@ -15267,7 +15926,7 @@ function verifyLarkRequestSignature(request, config) {
|
|
|
15267
15926
|
}
|
|
15268
15927
|
|
|
15269
15928
|
// src/channels/lark/controller.ts
|
|
15270
|
-
var
|
|
15929
|
+
var logger3 = new Logger({ serviceName: "lattice/gateway/lark" });
|
|
15271
15930
|
function createLarkEventHandler(deps) {
|
|
15272
15931
|
return async function handleLarkEvent(request, reply) {
|
|
15273
15932
|
const { installationId } = request.params;
|
|
@@ -15298,7 +15957,7 @@ function createLarkEventHandler(deps) {
|
|
|
15298
15957
|
return;
|
|
15299
15958
|
}
|
|
15300
15959
|
deps.router.dispatch(inboundMessage).catch((error) => {
|
|
15301
|
-
|
|
15960
|
+
logger3.error("Lark message dispatch error", {
|
|
15302
15961
|
error: error instanceof Error ? error.message : String(error)
|
|
15303
15962
|
});
|
|
15304
15963
|
});
|
|
@@ -15319,21 +15978,9 @@ function registerLarkChannelRoutes(app2, deps) {
|
|
|
15319
15978
|
}
|
|
15320
15979
|
|
|
15321
15980
|
// src/channels/wechat/controller.ts
|
|
15322
|
-
var qrSessions = /* @__PURE__ */ new Map();
|
|
15323
|
-
var SESSION_TTL_MS = 5 * 60 * 1e3;
|
|
15324
|
-
function cleanupExpiredSessions() {
|
|
15325
|
-
const now = Date.now();
|
|
15326
|
-
for (const [key, session] of qrSessions) {
|
|
15327
|
-
if (now - session.createdAt > SESSION_TTL_MS) {
|
|
15328
|
-
qrSessions.delete(key);
|
|
15329
|
-
}
|
|
15330
|
-
}
|
|
15331
|
-
}
|
|
15332
15981
|
async function handleGetQrCode(_request, reply) {
|
|
15333
15982
|
try {
|
|
15334
|
-
cleanupExpiredSessions();
|
|
15335
15983
|
const { qrcode, qrcodeImgUrl } = await getQrCode();
|
|
15336
|
-
qrSessions.set(qrcode, { qrcode, createdAt: Date.now() });
|
|
15337
15984
|
reply.send({ success: true, data: { qrcode, qrcodeImgUrl } });
|
|
15338
15985
|
} catch (err) {
|
|
15339
15986
|
reply.status(500).send({
|
|
@@ -15348,11 +15995,6 @@ async function handleGetQrCodeStatus(request, reply) {
|
|
|
15348
15995
|
reply.status(400).send({ success: false, message: "qrcode is required" });
|
|
15349
15996
|
return;
|
|
15350
15997
|
}
|
|
15351
|
-
const session = qrSessions.get(qrcode);
|
|
15352
|
-
if (!session) {
|
|
15353
|
-
reply.status(404).send({ success: false, message: "Session not found or expired" });
|
|
15354
|
-
return;
|
|
15355
|
-
}
|
|
15356
15998
|
try {
|
|
15357
15999
|
const result = await getQrCodeStatus(qrcode);
|
|
15358
16000
|
reply.send({ success: true, data: result });
|
|
@@ -15390,9 +16032,19 @@ import {
|
|
|
15390
16032
|
import { getStoreLattice as getStoreLattice25 } from "@axiom-lattice/core";
|
|
15391
16033
|
var _adapterRegistry;
|
|
15392
16034
|
var _router;
|
|
16035
|
+
var _onInstallationChanged;
|
|
15393
16036
|
function setChannelControllerDeps(deps) {
|
|
15394
16037
|
_adapterRegistry = deps.adapterRegistry;
|
|
15395
16038
|
_router = deps.router;
|
|
16039
|
+
_onInstallationChanged = deps.onInstallationChanged;
|
|
16040
|
+
}
|
|
16041
|
+
async function notifyInstallationChanged(tenantId, installationId) {
|
|
16042
|
+
if (!_onInstallationChanged) return;
|
|
16043
|
+
try {
|
|
16044
|
+
await _onInstallationChanged({ tenantId, installationId });
|
|
16045
|
+
} catch (error) {
|
|
16046
|
+
console.error("Failed to notify channel installation change:", error);
|
|
16047
|
+
}
|
|
15396
16048
|
}
|
|
15397
16049
|
function getTenantId20(request) {
|
|
15398
16050
|
const userTenantId = request.user?.tenantId;
|
|
@@ -15608,7 +16260,9 @@ async function createChannelInstallation(request, reply) {
|
|
|
15608
16260
|
installationId,
|
|
15609
16261
|
createInput
|
|
15610
16262
|
);
|
|
15611
|
-
if (
|
|
16263
|
+
if (_onInstallationChanged) {
|
|
16264
|
+
await notifyInstallationChanged(tenantId, installationId);
|
|
16265
|
+
} else if (body.enabled !== false && _adapterRegistry) {
|
|
15612
16266
|
const adapter = _adapterRegistry.get(body.channel);
|
|
15613
16267
|
if (adapter?.connect) {
|
|
15614
16268
|
try {
|
|
@@ -15663,6 +16317,19 @@ async function updateChannelInstallation(request, reply) {
|
|
|
15663
16317
|
reply.code(400);
|
|
15664
16318
|
return { success: false, message: "Invalid request body" };
|
|
15665
16319
|
}
|
|
16320
|
+
if (_onInstallationChanged) {
|
|
16321
|
+
const installation2 = await store2.updateInstallation(tenantId, installationId, body);
|
|
16322
|
+
if (!installation2) {
|
|
16323
|
+
reply.code(404);
|
|
16324
|
+
return { success: false, message: "Channel installation not found" };
|
|
16325
|
+
}
|
|
16326
|
+
await notifyInstallationChanged(tenantId, installationId);
|
|
16327
|
+
return {
|
|
16328
|
+
success: true,
|
|
16329
|
+
message: "Channel installation updated successfully",
|
|
16330
|
+
data: installation2
|
|
16331
|
+
};
|
|
16332
|
+
}
|
|
15666
16333
|
const adapter = _adapterRegistry?.get(existing.channel);
|
|
15667
16334
|
const disconnect = adapter?.disconnect;
|
|
15668
16335
|
const connect = adapter?.connect;
|
|
@@ -15782,7 +16449,7 @@ async function deleteChannelInstallation(request, reply) {
|
|
|
15782
16449
|
message: "Access denied"
|
|
15783
16450
|
};
|
|
15784
16451
|
}
|
|
15785
|
-
if (_adapterRegistry) {
|
|
16452
|
+
if (!_onInstallationChanged && _adapterRegistry) {
|
|
15786
16453
|
const adapter = _adapterRegistry.get(existing.channel);
|
|
15787
16454
|
if (adapter?.disconnect) {
|
|
15788
16455
|
try {
|
|
@@ -15800,6 +16467,7 @@ async function deleteChannelInstallation(request, reply) {
|
|
|
15800
16467
|
message: "Channel installation not found"
|
|
15801
16468
|
};
|
|
15802
16469
|
}
|
|
16470
|
+
await notifyInstallationChanged(tenantId, installationId);
|
|
15803
16471
|
return {
|
|
15804
16472
|
success: true,
|
|
15805
16473
|
message: "Channel installation deleted successfully"
|
|
@@ -16318,42 +16986,6 @@ function registerA2ABridgeRoutes(app2) {
|
|
|
16318
16986
|
|
|
16319
16987
|
// src/routes/stt.ts
|
|
16320
16988
|
import { sttModelLatticeManager } from "@axiom-lattice/core";
|
|
16321
|
-
|
|
16322
|
-
// src/controllers/tenant-scope.ts
|
|
16323
|
-
var TenantScopeError2 = class extends Error {
|
|
16324
|
-
/** Creates a tenant scope error. */
|
|
16325
|
-
constructor(code, statusCode, message) {
|
|
16326
|
-
super(message);
|
|
16327
|
-
this.code = code;
|
|
16328
|
-
this.statusCode = statusCode;
|
|
16329
|
-
this.name = "TenantScopeError";
|
|
16330
|
-
}
|
|
16331
|
-
};
|
|
16332
|
-
function resolveTenantScope(request, authRequired2) {
|
|
16333
|
-
const authenticated = request.user?.tenantId;
|
|
16334
|
-
const header2 = request.headers["x-tenant-id"];
|
|
16335
|
-
const requested = Array.isArray(header2) ? header2[0] : header2;
|
|
16336
|
-
if (authenticated) {
|
|
16337
|
-
if (requested && requested !== authenticated) {
|
|
16338
|
-
throw new TenantScopeError2(
|
|
16339
|
-
"TENANT_ACCESS_DENIED",
|
|
16340
|
-
403,
|
|
16341
|
-
"Tenant access denied"
|
|
16342
|
-
);
|
|
16343
|
-
}
|
|
16344
|
-
return { tenantId: authenticated, userId: request.user?.id };
|
|
16345
|
-
}
|
|
16346
|
-
if (authRequired2) {
|
|
16347
|
-
throw new TenantScopeError2(
|
|
16348
|
-
"UNAUTHENTICATED",
|
|
16349
|
-
401,
|
|
16350
|
-
"Console session required"
|
|
16351
|
-
);
|
|
16352
|
-
}
|
|
16353
|
-
return { tenantId: requested || "default" };
|
|
16354
|
-
}
|
|
16355
|
-
|
|
16356
|
-
// src/routes/stt.ts
|
|
16357
16989
|
function tenantIdOf(request) {
|
|
16358
16990
|
try {
|
|
16359
16991
|
return resolveTenantScope(request, false).tenantId;
|
|
@@ -16719,7 +17351,7 @@ import {
|
|
|
16719
17351
|
createTaskLifecycleService,
|
|
16720
17352
|
createTrustedAgentMessageDispatcher,
|
|
16721
17353
|
executionAuthorityRegistry,
|
|
16722
|
-
getReplicaId as
|
|
17354
|
+
getReplicaId as getReplicaId10,
|
|
16723
17355
|
getStoreLattice as getStoreLattice28,
|
|
16724
17356
|
hasModelLatticeForTenant as hasModelLatticeForTenant3,
|
|
16725
17357
|
ManagedTaskStartError,
|
|
@@ -17393,6 +18025,8 @@ var ProjectTaskRunPlanner = class {
|
|
|
17393
18025
|
throw asPlanError(error);
|
|
17394
18026
|
}
|
|
17395
18027
|
const inputId = (this.deps.idFactory ?? randomUUID20)();
|
|
18028
|
+
const actor3 = input.actor ?? SYSTEM_ACTOR;
|
|
18029
|
+
const userId = actor3.startsWith("user:") && actor3.length > "user:".length ? actor3.slice("user:".length) : void 0;
|
|
17396
18030
|
const trustedContext = {
|
|
17397
18031
|
projectTask: buildTrustedTaskContext(task, thread, inputId, rosterExempt)
|
|
17398
18032
|
};
|
|
@@ -17404,12 +18038,16 @@ var ProjectTaskRunPlanner = class {
|
|
|
17404
18038
|
projectId: task.projectId,
|
|
17405
18039
|
assistantId: task.ownerId,
|
|
17406
18040
|
threadId: thread.id,
|
|
17407
|
-
config: {
|
|
18041
|
+
config: {
|
|
18042
|
+
taskId: task.id,
|
|
18043
|
+
execution: { taskId: task.id },
|
|
18044
|
+
...userId ? { user_id: userId } : {}
|
|
18045
|
+
},
|
|
17408
18046
|
metadata: {
|
|
17409
18047
|
taskId: task.id,
|
|
17410
18048
|
projectId: task.projectId,
|
|
17411
18049
|
workspaceId: task.workspaceId,
|
|
17412
|
-
actor:
|
|
18050
|
+
actor: actor3,
|
|
17413
18051
|
mode: input.mode
|
|
17414
18052
|
}
|
|
17415
18053
|
};
|
|
@@ -18375,7 +19013,7 @@ function getTenantId24(request) {
|
|
|
18375
19013
|
if (typeof value !== "string" || !value) throw new HttpTaskError(400, "INVALID_TASK_INPUT");
|
|
18376
19014
|
return value;
|
|
18377
19015
|
}
|
|
18378
|
-
function
|
|
19016
|
+
function getUserId6(request) {
|
|
18379
19017
|
const user = request.user;
|
|
18380
19018
|
const value = user?.id ?? request.headers["x-user-id"];
|
|
18381
19019
|
if (typeof value !== "string" || !value) throw new HttpTaskError(400, "INVALID_TASK_INPUT", "User ID is required");
|
|
@@ -18541,7 +19179,7 @@ function withErrors(handler) {
|
|
|
18541
19179
|
}
|
|
18542
19180
|
async function authorizeRead(request, task, authorize) {
|
|
18543
19181
|
if (!task.projectId || task.projectId === "default") {
|
|
18544
|
-
if (task.ownerType !== "user" || task.ownerId !==
|
|
19182
|
+
if (task.ownerType !== "user" || task.ownerId !== getUserId6(request)) throw notFound6();
|
|
18545
19183
|
return;
|
|
18546
19184
|
}
|
|
18547
19185
|
let project;
|
|
@@ -18555,7 +19193,7 @@ async function authorizeRead(request, task, authorize) {
|
|
|
18555
19193
|
}
|
|
18556
19194
|
async function authorizeCommand(request, task, authorize, capability2) {
|
|
18557
19195
|
if (!task.projectId || task.projectId === "default") {
|
|
18558
|
-
if (task.ownerType !== "user" || task.ownerId !==
|
|
19196
|
+
if (task.ownerType !== "user" || task.ownerId !== getUserId6(request)) throw notFound6();
|
|
18559
19197
|
return;
|
|
18560
19198
|
}
|
|
18561
19199
|
let project;
|
|
@@ -18568,7 +19206,7 @@ async function authorizeCommand(request, task, authorize, capability2) {
|
|
|
18568
19206
|
if (task.workspaceId !== project.workspaceId) throw new HttpTaskError(404, "TASK_NOT_FOUND");
|
|
18569
19207
|
}
|
|
18570
19208
|
async function authorizeMutation(request, task, authorize) {
|
|
18571
|
-
const capability2 = task.ownerType === "agent" || task.ownerId !==
|
|
19209
|
+
const capability2 = task.ownerType === "agent" || task.ownerId !== getUserId6(request) ? "manage" : "send";
|
|
18572
19210
|
return authorizeCommand(request, task, authorize, capability2);
|
|
18573
19211
|
}
|
|
18574
19212
|
async function preauthorizeExplicitProject(request, authorize) {
|
|
@@ -18612,7 +19250,7 @@ function createTaskController(deps) {
|
|
|
18612
19250
|
const mutationMutex = deps.projectMutationMutex ?? projectMutationMutex;
|
|
18613
19251
|
const authorize = async (request, projectId, capability2) => deps.access.requireProjectAccess({
|
|
18614
19252
|
tenantId: getTenantId24(request),
|
|
18615
|
-
userId:
|
|
19253
|
+
userId: getUserId6(request),
|
|
18616
19254
|
projectId,
|
|
18617
19255
|
capability: capability2
|
|
18618
19256
|
});
|
|
@@ -18630,7 +19268,7 @@ function createTaskController(deps) {
|
|
|
18630
19268
|
};
|
|
18631
19269
|
const list = withErrors(async (request) => {
|
|
18632
19270
|
const tenantId = getTenantId24(request);
|
|
18633
|
-
const userId =
|
|
19271
|
+
const userId = getUserId6(request);
|
|
18634
19272
|
const query = exactObject(request.query, ["projectId", "status", "priority", "limit", "offset", "ownerType", "ownerId", "parentId", "metadata"]);
|
|
18635
19273
|
const projectId = typeof query.projectId === "string" ? query.projectId : void 0;
|
|
18636
19274
|
const limit = integer(query.limit, 1);
|
|
@@ -18709,7 +19347,7 @@ function createTaskController(deps) {
|
|
|
18709
19347
|
const create = withErrors(async (request, reply) => {
|
|
18710
19348
|
const body = snapshotCreate(request.body);
|
|
18711
19349
|
const tenantId = getTenantId24(request);
|
|
18712
|
-
const userId =
|
|
19350
|
+
const userId = getUserId6(request);
|
|
18713
19351
|
const governed = governedCreate(body);
|
|
18714
19352
|
if (governed) return reply.code(409).send({ success: false, code: governed });
|
|
18715
19353
|
if (!body.projectId || body.projectId === "default") {
|
|
@@ -18785,7 +19423,7 @@ function createTaskController(deps) {
|
|
|
18785
19423
|
await authorizeMutation(request, current3, authorize);
|
|
18786
19424
|
return lockedTask(request, current3, async (locked) => {
|
|
18787
19425
|
if (deps.commands) {
|
|
18788
|
-
const actor3 = `user:${
|
|
19426
|
+
const actor3 = `user:${getUserId6(request)}`;
|
|
18789
19427
|
await deps.commands.run(locked, { type: "delete", actor: actor3 });
|
|
18790
19428
|
return { success: true, message: "Task deleted" };
|
|
18791
19429
|
}
|
|
@@ -18826,7 +19464,7 @@ function createTaskController(deps) {
|
|
|
18826
19464
|
if (body.expectedUpdatedAt && body.expectedUpdatedAt !== locked.updatedAt.toISOString()) {
|
|
18827
19465
|
throw new HttpTaskError(409, "TASK_STATUS_CONFLICT");
|
|
18828
19466
|
}
|
|
18829
|
-
const result = await deps.commands.run(locked, { ...body, actor: `user:${
|
|
19467
|
+
const result = await deps.commands.run(locked, { ...body, actor: `user:${getUserId6(request)}` });
|
|
18830
19468
|
return { success: true, data: result.task, warnings: result.warnings };
|
|
18831
19469
|
}, capability2);
|
|
18832
19470
|
});
|
|
@@ -19172,8 +19810,8 @@ import { z as z5, ZodError as ZodError2 } from "zod";
|
|
|
19172
19810
|
|
|
19173
19811
|
// src/services/agent-web-app/AgentWebAppRuntimeService.ts
|
|
19174
19812
|
import { createHash as createHash5, randomUUID as randomUUID22 } from "crypto";
|
|
19175
|
-
import { MessageChunkTypes as
|
|
19176
|
-
import { getReplicaId as
|
|
19813
|
+
import { MessageChunkTypes as MessageChunkTypes3, parseAgentWebAppGenUIBlock, buildAffinityMissChunk as buildAffinityMissChunk2 } from "@axiom-lattice/protocols";
|
|
19814
|
+
import { getReplicaId as getReplicaId7, getThreadRunOwner as getThreadRunOwner2, normalizeAgentInterrupts as normalizeAgentInterrupts2 } from "@axiom-lattice/core";
|
|
19177
19815
|
function isRecord9(value) {
|
|
19178
19816
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19179
19817
|
}
|
|
@@ -19353,7 +19991,7 @@ var AgentWebAppRuntimeService = class {
|
|
|
19353
19991
|
async enqueueMessage(webAppId, userId, threadId, content, selection) {
|
|
19354
19992
|
const runtime = await this.resolveOwnedRuntime(webAppId, userId, threadId, selection);
|
|
19355
19993
|
const agent = this.resolveAgent(runtime, threadId);
|
|
19356
|
-
const execution = await this.execute(agent, runtime, { input: { message: content } });
|
|
19994
|
+
const execution = await this.execute(agent, runtime, userId, { input: { message: content } });
|
|
19357
19995
|
return { messageId: execution.messageId };
|
|
19358
19996
|
}
|
|
19359
19997
|
async removePendingMessage(webAppId, userId, threadId, messageId, selection) {
|
|
@@ -19372,7 +20010,7 @@ var AgentWebAppRuntimeService = class {
|
|
|
19372
20010
|
assistantId: runtime.webApp.assistantId,
|
|
19373
20011
|
threadId
|
|
19374
20012
|
});
|
|
19375
|
-
if (owner && owner !==
|
|
20013
|
+
if (owner && owner !== getReplicaId7()) {
|
|
19376
20014
|
return {
|
|
19377
20015
|
stream: (async function* () {
|
|
19378
20016
|
yield buildAffinityMissChunk2(owner, threadId);
|
|
@@ -19400,7 +20038,7 @@ var AgentWebAppRuntimeService = class {
|
|
|
19400
20038
|
const content = refs.length ? `${input.content}
|
|
19401
20039
|
|
|
19402
20040
|
${formatFileRefsSection(refs)}` : input.content;
|
|
19403
|
-
const execution = await this.execute(agent, runtime, { input: { message: content } });
|
|
20041
|
+
const execution = await this.execute(agent, runtime, userId, { input: { message: content } });
|
|
19404
20042
|
return { ...execution, allowInterrupts: runtime.webApp.features.hitl, allowGenUI: runtime.webApp.features.genUI };
|
|
19405
20043
|
}
|
|
19406
20044
|
async abort(webAppId, userId, threadId, selection) {
|
|
@@ -19503,17 +20141,21 @@ ${formatFileRefsSection(refs)}` : input.content;
|
|
|
19503
20141
|
);
|
|
19504
20142
|
if (matched.conflict) this.fail("INVALID_REQUEST", 409, "Interrupt is ambiguous");
|
|
19505
20143
|
if (!matched.interrupt) this.fail("INVALID_REQUEST", 400, "Interrupt not found");
|
|
19506
|
-
const execution = await this.execute(agent, runtime, {
|
|
20144
|
+
const execution = await this.execute(agent, runtime, userId, {
|
|
19507
20145
|
input: { message: input.message },
|
|
19508
20146
|
command: resumeMap(interruptId, input.response)
|
|
19509
20147
|
});
|
|
19510
20148
|
return { ...execution, allowInterrupts: true, allowGenUI: runtime.webApp.features.genUI };
|
|
19511
20149
|
}
|
|
19512
|
-
execute(agent, runtime, request) {
|
|
20150
|
+
execute(agent, runtime, userId, request) {
|
|
20151
|
+
const customRunConfig = {
|
|
20152
|
+
...runtime.modelKey ? { modelConfig: { modelKey: runtime.modelKey } } : {},
|
|
20153
|
+
...userId ? { user_id: userId } : {}
|
|
20154
|
+
};
|
|
19513
20155
|
return executeScopedAgentMessage(agent, {
|
|
19514
20156
|
...request,
|
|
19515
|
-
...
|
|
19516
|
-
}, [
|
|
20157
|
+
...Object.keys(customRunConfig).length > 0 ? { custom_run_config: customRunConfig } : {}
|
|
20158
|
+
}, [MessageChunkTypes3.MESSAGE_COMPLETED, MessageChunkTypes3.INTERRUPT, MessageChunkTypes3.MESSAGE_FAILED]);
|
|
19517
20159
|
}
|
|
19518
20160
|
async resolveRuntime(webAppId, selection) {
|
|
19519
20161
|
const webApp = await this.deps.webAppStore.findById(webAppId);
|
|
@@ -19778,7 +20420,7 @@ async function verifyWebAppToken(token, issuer, options = {}) {
|
|
|
19778
20420
|
|
|
19779
20421
|
// src/routes/agent-web-app-runtime.ts
|
|
19780
20422
|
import { createAgentWebAppStreamProjectionContext, projectAgentWebAppChunk, AGENT_AFFINITY_HEADER as AGENT_AFFINITY_HEADER2, AFFINITY_ECHO_HEADER as AFFINITY_ECHO_HEADER2, affinityEchoHeaders as affinityEchoHeaders2, REPLICA_HEADER as REPLICA_HEADER2 } from "@axiom-lattice/protocols";
|
|
19781
|
-
import { getReplicaId as
|
|
20423
|
+
import { getReplicaId as getReplicaId8 } from "@axiom-lattice/core";
|
|
19782
20424
|
var idSchema = z5.string().min(1).max(128);
|
|
19783
20425
|
var paramsSchema = z5.object({ webAppId: idSchema }).strict();
|
|
19784
20426
|
var threadParamsSchema = z5.object({ webAppId: idSchema, threadId: idSchema }).strict();
|
|
@@ -19804,7 +20446,7 @@ var resumeBodySchema = z5.object({
|
|
|
19804
20446
|
z5.object({ approved: z5.boolean(), feedback: z5.string().max(4096).optional() }).strict()
|
|
19805
20447
|
])
|
|
19806
20448
|
}).strict();
|
|
19807
|
-
var MAX_ATTACHMENT_BYTES =
|
|
20449
|
+
var MAX_ATTACHMENT_BYTES = 500 * 1024 * 1024;
|
|
19808
20450
|
var stateQuerySchema = z5.object({
|
|
19809
20451
|
threadId: idSchema,
|
|
19810
20452
|
projectId: idSchema.optional(),
|
|
@@ -20355,7 +20997,7 @@ function registerAgentWebAppRuntimeRoutes(app2, deps) {
|
|
|
20355
20997
|
if (!threadId) throw new AgentWebAppRuntimeError("INVALID_REQUEST", 400, "thread_id is required");
|
|
20356
20998
|
const content = body.messages.map((message) => message.content).join("\n");
|
|
20357
20999
|
const { messageId } = await deps.service.enqueueMessage(webAppId, identity.userId, threadId, content, { projectId: body.projectId, modelKey: body.modelKey });
|
|
20358
|
-
reply.header(REPLICA_HEADER2,
|
|
21000
|
+
reply.header(REPLICA_HEADER2, getReplicaId8());
|
|
20359
21001
|
for (const [name, value] of Object.entries(affinityEchoHeaders2(request.headers[AGENT_AFFINITY_HEADER2]))) {
|
|
20360
21002
|
reply.header(name, value);
|
|
20361
21003
|
}
|
|
@@ -20441,7 +21083,7 @@ function beginSse(reply, request) {
|
|
|
20441
21083
|
"X-Accel-Buffering": "no",
|
|
20442
21084
|
"Access-Control-Allow-Origin": "*",
|
|
20443
21085
|
"Access-Control-Expose-Headers": `${REPLICA_HEADER2}, ${AFFINITY_ECHO_HEADER2}`,
|
|
20444
|
-
[REPLICA_HEADER2]:
|
|
21086
|
+
[REPLICA_HEADER2]: getReplicaId8(),
|
|
20445
21087
|
...affinityEchoHeaders2(request.headers[AGENT_AFFINITY_HEADER2])
|
|
20446
21088
|
});
|
|
20447
21089
|
}
|
|
@@ -20886,7 +21528,7 @@ var CapabilityBundleService = class {
|
|
|
20886
21528
|
};
|
|
20887
21529
|
|
|
20888
21530
|
// src/controllers/capability-bundles.ts
|
|
20889
|
-
var
|
|
21531
|
+
var logger4 = new Logger({ serviceName: "lattice/gateway/capability-bundles" });
|
|
20890
21532
|
var capability = z8.unknown();
|
|
20891
21533
|
var createSchema = z8.object({ name: z8.string(), description: z8.string().optional(), capabilities: z8.array(capability) }).strict();
|
|
20892
21534
|
var updateSchema = createSchema.partial().extend({ expectedUpdatedAt: z8.string().optional() });
|
|
@@ -20904,14 +21546,14 @@ function tenant(request, authRequired2) {
|
|
|
20904
21546
|
if (authRequired2) throw new CapabilityBundleServiceError("INVALID_INPUT", "Unauthorized", 401);
|
|
20905
21547
|
return requested || "default";
|
|
20906
21548
|
}
|
|
20907
|
-
function
|
|
21549
|
+
function sendError2(reply, error) {
|
|
20908
21550
|
if (error instanceof CapabilityBundleServiceError) return reply.status(error.statusCode).send({ success: false, code: error.code, message: error.message });
|
|
20909
21551
|
if (error instanceof Error && error.name === "CapabilityBundleValidationError") {
|
|
20910
21552
|
const validationError = error;
|
|
20911
21553
|
const code = validationError.code === "CAPABILITY_BUNDLE_INELIGIBLE_CAPABILITY" ? "BUNDLE_PLUGIN_NOT_ELIGIBLE" : validationError.code === "CAPABILITY_BUNDLE_CREDENTIALS_FORBIDDEN" || validationError.code === "CAPABILITY_BUNDLE_INVALID_CONFIG" ? "INVALID_BUNDLE_CONFIG" : validationError.code;
|
|
20912
21554
|
return reply.status(400).send({ success: false, code, message: error.message, capabilityType: validationError.capabilityType, fieldPath: validationError.fieldPath });
|
|
20913
21555
|
}
|
|
20914
|
-
|
|
21556
|
+
logger4.error("Capability bundle controller error", { error: error instanceof Error ? error : new Error(String(error)) });
|
|
20915
21557
|
return reply.status(500).send({ success: false, code: "INTERNAL_ERROR", message: "Internal server error" });
|
|
20916
21558
|
}
|
|
20917
21559
|
var CapabilityBundleController = class {
|
|
@@ -20924,7 +21566,7 @@ var CapabilityBundleController = class {
|
|
|
20924
21566
|
const result = await this.service.list(tenant(request, this.authRequired));
|
|
20925
21567
|
return reply.send({ success: true, data: result.bundles, errors: result.errors });
|
|
20926
21568
|
} catch (error) {
|
|
20927
|
-
return
|
|
21569
|
+
return sendError2(reply, error);
|
|
20928
21570
|
}
|
|
20929
21571
|
}
|
|
20930
21572
|
async getBundle(request, reply) {
|
|
@@ -20934,7 +21576,7 @@ var CapabilityBundleController = class {
|
|
|
20934
21576
|
if (!parsed.success) return reply.status(400).send({ success: false, code: "INVALID_INPUT", message: "Invalid capability bundle ID" });
|
|
20935
21577
|
return reply.send({ success: true, data: await this.service.get(tenantId, parsed.data.bundleId) });
|
|
20936
21578
|
} catch (error) {
|
|
20937
|
-
return
|
|
21579
|
+
return sendError2(reply, error);
|
|
20938
21580
|
}
|
|
20939
21581
|
}
|
|
20940
21582
|
async createBundle(request, reply) {
|
|
@@ -20944,7 +21586,7 @@ var CapabilityBundleController = class {
|
|
|
20944
21586
|
if (!parsed.success) return reply.status(400).send({ success: false, code: "INVALID_INPUT", message: "Invalid capability bundle body" });
|
|
20945
21587
|
return reply.status(201).send({ success: true, data: await this.service.create(tenantId, parsed.data) });
|
|
20946
21588
|
} catch (error) {
|
|
20947
|
-
return
|
|
21589
|
+
return sendError2(reply, error);
|
|
20948
21590
|
}
|
|
20949
21591
|
}
|
|
20950
21592
|
async updateBundle(request, reply) {
|
|
@@ -20955,7 +21597,7 @@ var CapabilityBundleController = class {
|
|
|
20955
21597
|
if (!params.success || !parsed.success) return reply.status(400).send({ success: false, code: "INVALID_INPUT", message: "Invalid capability bundle request" });
|
|
20956
21598
|
return reply.send({ success: true, data: await this.service.update(tenantId, params.data.bundleId, parsed.data) });
|
|
20957
21599
|
} catch (error) {
|
|
20958
|
-
return
|
|
21600
|
+
return sendError2(reply, error);
|
|
20959
21601
|
}
|
|
20960
21602
|
}
|
|
20961
21603
|
async deleteBundle(request, reply) {
|
|
@@ -20966,7 +21608,7 @@ var CapabilityBundleController = class {
|
|
|
20966
21608
|
await this.service.remove(tenantId, parsed.data.bundleId);
|
|
20967
21609
|
return reply.send({ success: true, data: null });
|
|
20968
21610
|
} catch (error) {
|
|
20969
|
-
return
|
|
21611
|
+
return sendError2(reply, error);
|
|
20970
21612
|
}
|
|
20971
21613
|
}
|
|
20972
21614
|
async updateProjectBundles(request, reply) {
|
|
@@ -20977,7 +21619,7 @@ var CapabilityBundleController = class {
|
|
|
20977
21619
|
const result = await this.service.project(tenantId, request.params.projectId, parsed.data.bundleIds, true, parsed.data.expectedRevisions);
|
|
20978
21620
|
return reply.send({ success: true, data: { project: result.project, persistedBundleIds: result.persistedBundleIds, bundles: result.bundles, preview: result.preview } });
|
|
20979
21621
|
} catch (error) {
|
|
20980
|
-
return
|
|
21622
|
+
return sendError2(reply, error);
|
|
20981
21623
|
}
|
|
20982
21624
|
}
|
|
20983
21625
|
async getProjectBundles(request, reply) {
|
|
@@ -20986,7 +21628,7 @@ var CapabilityBundleController = class {
|
|
|
20986
21628
|
if (result.preview.errors.some((issue2) => issue2.code === "CAPABILITY_BUNDLE_CREDENTIALS_FORBIDDEN")) return reply.status(400).send({ success: false, code: "INVALID_BUNDLE_CONFIG", message: "Capability bundle record is invalid" });
|
|
20987
21629
|
return reply.send({ success: true, data: { project: result.project, persistedBundleIds: result.persistedBundleIds, bundles: result.bundles, preview: result.preview } });
|
|
20988
21630
|
} catch (error) {
|
|
20989
|
-
return
|
|
21631
|
+
return sendError2(reply, error);
|
|
20990
21632
|
}
|
|
20991
21633
|
}
|
|
20992
21634
|
async getProjectPreview(request, reply) {
|
|
@@ -20994,7 +21636,7 @@ var CapabilityBundleController = class {
|
|
|
20994
21636
|
const preview = await this.service.previewProject(tenant(request, this.authRequired), request.params.projectId);
|
|
20995
21637
|
return reply.send({ success: true, data: preview });
|
|
20996
21638
|
} catch (error) {
|
|
20997
|
-
return
|
|
21639
|
+
return sendError2(reply, error);
|
|
20998
21640
|
}
|
|
20999
21641
|
}
|
|
21000
21642
|
async postProjectPreview(request, reply) {
|
|
@@ -21005,7 +21647,7 @@ var CapabilityBundleController = class {
|
|
|
21005
21647
|
const result = await this.service.project(tenantId, request.params.projectId, parsed.data.bundleIds, false);
|
|
21006
21648
|
return reply.send({ success: true, data: result.preview });
|
|
21007
21649
|
} catch (error) {
|
|
21008
|
-
return
|
|
21650
|
+
return sendError2(reply, error);
|
|
21009
21651
|
}
|
|
21010
21652
|
}
|
|
21011
21653
|
};
|
|
@@ -22151,8 +22793,8 @@ var probeProviderSchema = z9.object({
|
|
|
22151
22793
|
}).strict();
|
|
22152
22794
|
|
|
22153
22795
|
// src/controllers/model-providers.ts
|
|
22154
|
-
var
|
|
22155
|
-
function
|
|
22796
|
+
var logger5 = new Logger({ serviceName: "lattice/gateway/model-providers" });
|
|
22797
|
+
function sendError3(reply, error) {
|
|
22156
22798
|
if (error instanceof ModelProviderServiceError) {
|
|
22157
22799
|
return reply.status(error.statusCode).send({
|
|
22158
22800
|
success: false,
|
|
@@ -22163,7 +22805,7 @@ function sendError2(reply, error) {
|
|
|
22163
22805
|
}
|
|
22164
22806
|
});
|
|
22165
22807
|
}
|
|
22166
|
-
if (error instanceof
|
|
22808
|
+
if (error instanceof TenantScopeError) {
|
|
22167
22809
|
return reply.status(error.statusCode).send({
|
|
22168
22810
|
success: false,
|
|
22169
22811
|
error: {
|
|
@@ -22183,7 +22825,7 @@ function sendError2(reply, error) {
|
|
|
22183
22825
|
}
|
|
22184
22826
|
});
|
|
22185
22827
|
}
|
|
22186
|
-
|
|
22828
|
+
logger5.error("Model provider controller error", {
|
|
22187
22829
|
error: error instanceof Error ? error : new Error(String(error))
|
|
22188
22830
|
});
|
|
22189
22831
|
return reply.status(500).send({
|
|
@@ -22207,7 +22849,7 @@ var ModelProviderController = class {
|
|
|
22207
22849
|
const catalog = await this.service.catalog(scope.userId, scope.tenantId);
|
|
22208
22850
|
return reply.send({ success: true, data: catalog });
|
|
22209
22851
|
} catch (error) {
|
|
22210
|
-
return
|
|
22852
|
+
return sendError3(reply, error);
|
|
22211
22853
|
}
|
|
22212
22854
|
}
|
|
22213
22855
|
/** Hydrates the runtime model registry from persisted providers (startup). */
|
|
@@ -22228,7 +22870,7 @@ var ModelProviderController = class {
|
|
|
22228
22870
|
data: { records, total: records.length }
|
|
22229
22871
|
});
|
|
22230
22872
|
} catch (error) {
|
|
22231
|
-
return
|
|
22873
|
+
return sendError3(reply, error);
|
|
22232
22874
|
}
|
|
22233
22875
|
}
|
|
22234
22876
|
/** GET /api/model-providers/:providerId */
|
|
@@ -22241,7 +22883,7 @@ var ModelProviderController = class {
|
|
|
22241
22883
|
data: await this.service.get(scope.userId, scope.tenantId, providerId2)
|
|
22242
22884
|
});
|
|
22243
22885
|
} catch (error) {
|
|
22244
|
-
return
|
|
22886
|
+
return sendError3(reply, error);
|
|
22245
22887
|
}
|
|
22246
22888
|
}
|
|
22247
22889
|
/** POST /api/model-providers */
|
|
@@ -22254,7 +22896,7 @@ var ModelProviderController = class {
|
|
|
22254
22896
|
data: await this.service.create(scope.userId, scope.tenantId, input)
|
|
22255
22897
|
});
|
|
22256
22898
|
} catch (error) {
|
|
22257
|
-
return
|
|
22899
|
+
return sendError3(reply, error);
|
|
22258
22900
|
}
|
|
22259
22901
|
}
|
|
22260
22902
|
/** PUT /api/model-providers/:providerId */
|
|
@@ -22273,7 +22915,7 @@ var ModelProviderController = class {
|
|
|
22273
22915
|
)
|
|
22274
22916
|
});
|
|
22275
22917
|
} catch (error) {
|
|
22276
|
-
return
|
|
22918
|
+
return sendError3(reply, error);
|
|
22277
22919
|
}
|
|
22278
22920
|
}
|
|
22279
22921
|
/** DELETE /api/model-providers/:providerId */
|
|
@@ -22284,7 +22926,7 @@ var ModelProviderController = class {
|
|
|
22284
22926
|
await this.service.remove(scope.userId, scope.tenantId, providerId2);
|
|
22285
22927
|
return reply.send({ success: true, data: null });
|
|
22286
22928
|
} catch (error) {
|
|
22287
|
-
return
|
|
22929
|
+
return sendError3(reply, error);
|
|
22288
22930
|
}
|
|
22289
22931
|
}
|
|
22290
22932
|
/** POST /api/model-providers/probe */
|
|
@@ -22297,7 +22939,7 @@ var ModelProviderController = class {
|
|
|
22297
22939
|
data: await this.service.probe(scope.userId, scope.tenantId, input)
|
|
22298
22940
|
});
|
|
22299
22941
|
} catch (error) {
|
|
22300
|
-
return
|
|
22942
|
+
return sendError3(reply, error);
|
|
22301
22943
|
}
|
|
22302
22944
|
}
|
|
22303
22945
|
/** PUT /api/model-providers/:providerId/models */
|
|
@@ -22316,7 +22958,7 @@ var ModelProviderController = class {
|
|
|
22316
22958
|
)
|
|
22317
22959
|
});
|
|
22318
22960
|
} catch (error) {
|
|
22319
|
-
return
|
|
22961
|
+
return sendError3(reply, error);
|
|
22320
22962
|
}
|
|
22321
22963
|
}
|
|
22322
22964
|
/** POST /api/model-providers/:providerId/discover */
|
|
@@ -22334,7 +22976,7 @@ var ModelProviderController = class {
|
|
|
22334
22976
|
)
|
|
22335
22977
|
});
|
|
22336
22978
|
} catch (error) {
|
|
22337
|
-
return
|
|
22979
|
+
return sendError3(reply, error);
|
|
22338
22980
|
}
|
|
22339
22981
|
}
|
|
22340
22982
|
/** POST /api/model-providers/:providerId/models/enabled */
|
|
@@ -22354,7 +22996,7 @@ var ModelProviderController = class {
|
|
|
22354
22996
|
)
|
|
22355
22997
|
});
|
|
22356
22998
|
} catch (error) {
|
|
22357
|
-
return
|
|
22999
|
+
return sendError3(reply, error);
|
|
22358
23000
|
}
|
|
22359
23001
|
}
|
|
22360
23002
|
};
|
|
@@ -23472,86 +24114,6 @@ import { toProjectRoomPublicMessage } from "@axiom-lattice/protocols";
|
|
|
23472
24114
|
|
|
23473
24115
|
// src/services/collaboration/RoomInterruptService.ts
|
|
23474
24116
|
import { randomUUID as randomUUID28 } from "crypto";
|
|
23475
|
-
|
|
23476
|
-
// src/router/roomInterrupt.ts
|
|
23477
|
-
var CLARIFY_FENCE = /^```clarify\n([\s\S]*?)\n```$/;
|
|
23478
|
-
function readClarifyValue(value) {
|
|
23479
|
-
if (typeof value !== "string") return void 0;
|
|
23480
|
-
const match = CLARIFY_FENCE.exec(value.trim());
|
|
23481
|
-
if (!match) return void 0;
|
|
23482
|
-
try {
|
|
23483
|
-
const parsed = JSON.parse(match[1]);
|
|
23484
|
-
if (typeof parsed === "object" && parsed !== null && Array.isArray(parsed.questions)) {
|
|
23485
|
-
return parsed;
|
|
23486
|
-
}
|
|
23487
|
-
} catch {
|
|
23488
|
-
}
|
|
23489
|
-
return void 0;
|
|
23490
|
-
}
|
|
23491
|
-
function rawInterruptId(interrupt, taskId, taskIndex, index) {
|
|
23492
|
-
const record = typeof interrupt === "object" && interrupt !== null ? interrupt : void 0;
|
|
23493
|
-
const rawId = record?.id;
|
|
23494
|
-
if (typeof rawId === "string" || typeof rawId === "number") return String(rawId);
|
|
23495
|
-
return `${taskId ?? `task-${taskIndex}`}:${index}`;
|
|
23496
|
-
}
|
|
23497
|
-
function pendingInterrupts(state) {
|
|
23498
|
-
if (typeof state !== "object" || state === null) return [];
|
|
23499
|
-
const tasks = state.tasks;
|
|
23500
|
-
if (!Array.isArray(tasks)) return [];
|
|
23501
|
-
const result = [];
|
|
23502
|
-
tasks.forEach((task, taskIndex) => {
|
|
23503
|
-
const record = typeof task === "object" && task !== null ? task : void 0;
|
|
23504
|
-
const rawTaskId = record?.id;
|
|
23505
|
-
const taskId = typeof rawTaskId === "string" || typeof rawTaskId === "number" ? String(rawTaskId) : void 0;
|
|
23506
|
-
const interrupts = record?.interrupts;
|
|
23507
|
-
if (!Array.isArray(interrupts)) return;
|
|
23508
|
-
interrupts.forEach((interrupt, index) => {
|
|
23509
|
-
const value = typeof interrupt === "object" && interrupt !== null ? interrupt.value : void 0;
|
|
23510
|
-
const clarify = readClarifyValue(value);
|
|
23511
|
-
result.push({
|
|
23512
|
-
interruptId: rawInterruptId(interrupt, taskId, taskIndex, index),
|
|
23513
|
-
...clarify === void 0 ? {} : { clarify }
|
|
23514
|
-
});
|
|
23515
|
-
});
|
|
23516
|
-
});
|
|
23517
|
-
return result;
|
|
23518
|
-
}
|
|
23519
|
-
function readPendingInterruptTarget(state) {
|
|
23520
|
-
const interrupts = pendingInterrupts(state);
|
|
23521
|
-
if (interrupts.length === 0) return void 0;
|
|
23522
|
-
const ids = new Set(interrupts.map((interrupt) => interrupt.interruptId));
|
|
23523
|
-
if (ids.size !== interrupts.length) return { conflict: true };
|
|
23524
|
-
const clarify = interrupts.find((interrupt) => interrupt.clarify !== void 0);
|
|
23525
|
-
if (clarify !== void 0) {
|
|
23526
|
-
if (!isOfficialInterruptId(clarify.interruptId) && interrupts.length > 1) return { conflict: true };
|
|
23527
|
-
return { target: clarify };
|
|
23528
|
-
}
|
|
23529
|
-
return interrupts.length === 1 ? { target: interrupts[0] } : { conflict: true };
|
|
23530
|
-
}
|
|
23531
|
-
function readExplicitInterruptTarget(state, interruptId) {
|
|
23532
|
-
const interrupts = pendingInterrupts(state);
|
|
23533
|
-
const matches = interrupts.filter((interrupt) => interrupt.interruptId === interruptId);
|
|
23534
|
-
if (matches.length > 1) return { conflict: true };
|
|
23535
|
-
const target = matches[0];
|
|
23536
|
-
if (target === void 0) return void 0;
|
|
23537
|
-
if (!isOfficialInterruptId(interruptId) && interrupts.length > 1) return { conflict: true };
|
|
23538
|
-
return { target };
|
|
23539
|
-
}
|
|
23540
|
-
function readClarifyInterruptTarget(state) {
|
|
23541
|
-
const match = readPendingInterruptTarget(state);
|
|
23542
|
-
return match !== void 0 && !("conflict" in match) && match.target.clarify !== void 0 ? match.target : void 0;
|
|
23543
|
-
}
|
|
23544
|
-
function readClarifyInterrupt(state) {
|
|
23545
|
-
return pendingInterrupts(state).find((interrupt) => interrupt.clarify !== void 0)?.clarify;
|
|
23546
|
-
}
|
|
23547
|
-
function buildClarifyResumeCommand(text, interruptId) {
|
|
23548
|
-
return resumeMap(interruptId, { data: { answers: [{ questionIndex: 0, otherText: text }] } });
|
|
23549
|
-
}
|
|
23550
|
-
function buildClarifySkipCommand(interruptId) {
|
|
23551
|
-
return resumeMap(interruptId, { data: { answers: [] } });
|
|
23552
|
-
}
|
|
23553
|
-
|
|
23554
|
-
// src/services/collaboration/RoomInterruptService.ts
|
|
23555
24117
|
var RESUMABLE_TASK_INTERRUPT_CODES = /* @__PURE__ */ new Set([
|
|
23556
24118
|
"PROJECT_TASK_NOT_RESUMABLE",
|
|
23557
24119
|
"PROJECT_TASK_NOT_READY",
|
|
@@ -25247,7 +25809,7 @@ function createRoomMessageRetentionJob(input) {
|
|
|
25247
25809
|
|
|
25248
25810
|
// src/services/collaboration/ProjectTaskExecutionMutex.ts
|
|
25249
25811
|
import { snapshotExactRecord as snapshotExactRecord8 } from "@axiom-lattice/protocols";
|
|
25250
|
-
import { getCoordinationLeaseStore, getReplicaId as
|
|
25812
|
+
import { getCoordinationLeaseStore, getReplicaId as getReplicaId9, withLease as withLease2 } from "@axiom-lattice/core";
|
|
25251
25813
|
var MACHINE_LEASE_OPTIONS = { ttlMs: 6e4, acquireTimeoutMs: 9e4, retryDelayMs: 100 };
|
|
25252
25814
|
function machineKey(scope) {
|
|
25253
25815
|
const snapshot = snapshotExactRecord8(scope, ["tenantId", "assistantId", "projectId"]);
|
|
@@ -25277,7 +25839,7 @@ var ProjectTaskExecutionMutex = class {
|
|
|
25277
25839
|
try {
|
|
25278
25840
|
const store2 = getCoordinationLeaseStore();
|
|
25279
25841
|
if (!store2) return await operation();
|
|
25280
|
-
return await withLease2(store2, leaseKey,
|
|
25842
|
+
return await withLease2(store2, leaseKey, getReplicaId9(), operation, MACHINE_LEASE_OPTIONS);
|
|
25281
25843
|
} finally {
|
|
25282
25844
|
this.release(key);
|
|
25283
25845
|
}
|
|
@@ -28556,7 +29118,7 @@ function broadcastModelProviderChanged(tenantId, providerId2) {
|
|
|
28556
29118
|
if (!tenantId) return;
|
|
28557
29119
|
try {
|
|
28558
29120
|
const outbox = getStoreLattice28("default", "outbox").store;
|
|
28559
|
-
void publishModelProviderChanged(outbox,
|
|
29121
|
+
void publishModelProviderChanged(outbox, getReplicaId10(), tenantId, providerId2);
|
|
28560
29122
|
} catch {
|
|
28561
29123
|
}
|
|
28562
29124
|
}
|
|
@@ -29173,6 +29735,11 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
29173
29735
|
getHealth
|
|
29174
29736
|
);
|
|
29175
29737
|
app2.get("/info", getInfo);
|
|
29738
|
+
app2.get("/api/observability", getObservability);
|
|
29739
|
+
app2.get(
|
|
29740
|
+
"/api/observability/dashboard",
|
|
29741
|
+
getObservabilityDashboard
|
|
29742
|
+
);
|
|
29176
29743
|
app2.get("/metrics", getSystemMetrics);
|
|
29177
29744
|
app2.get(
|
|
29178
29745
|
"/api/assistants/:assistantId/threads/:threadId/schedules",
|
|
@@ -30872,6 +31439,50 @@ var ChannelAdapterRegistry = class {
|
|
|
30872
31439
|
}
|
|
30873
31440
|
};
|
|
30874
31441
|
|
|
31442
|
+
// src/router/middlewares/channelSharedState.ts
|
|
31443
|
+
import { createClient as createClient2 } from "redis";
|
|
31444
|
+
var clientPromise;
|
|
31445
|
+
async function redis() {
|
|
31446
|
+
const url = process.env.REDIS_URL?.trim();
|
|
31447
|
+
if (!url) return void 0;
|
|
31448
|
+
if (!clientPromise) {
|
|
31449
|
+
clientPromise = (async () => {
|
|
31450
|
+
const client = createClient2({ url });
|
|
31451
|
+
client.on("error", () => void 0);
|
|
31452
|
+
await client.connect();
|
|
31453
|
+
return client;
|
|
31454
|
+
})();
|
|
31455
|
+
}
|
|
31456
|
+
try {
|
|
31457
|
+
const client = await clientPromise;
|
|
31458
|
+
return client.isOpen ? client : void 0;
|
|
31459
|
+
} catch {
|
|
31460
|
+
clientPromise = void 0;
|
|
31461
|
+
return void 0;
|
|
31462
|
+
}
|
|
31463
|
+
}
|
|
31464
|
+
async function claimDedupKey(key, ttlMs) {
|
|
31465
|
+
try {
|
|
31466
|
+
const client = await redis();
|
|
31467
|
+
if (!client) return void 0;
|
|
31468
|
+
const result = await client.set(key, "1", { NX: true, PX: ttlMs });
|
|
31469
|
+
return result === "OK";
|
|
31470
|
+
} catch {
|
|
31471
|
+
return void 0;
|
|
31472
|
+
}
|
|
31473
|
+
}
|
|
31474
|
+
async function incrementRateCounter(key, windowMs) {
|
|
31475
|
+
try {
|
|
31476
|
+
const client = await redis();
|
|
31477
|
+
if (!client) return void 0;
|
|
31478
|
+
const count = await client.incr(key);
|
|
31479
|
+
if (count === 1) await client.pExpire(key, windowMs);
|
|
31480
|
+
return count;
|
|
31481
|
+
} catch {
|
|
31482
|
+
return void 0;
|
|
31483
|
+
}
|
|
31484
|
+
}
|
|
31485
|
+
|
|
30875
31486
|
// src/router/middlewares/deduplication.ts
|
|
30876
31487
|
var processedMessages = /* @__PURE__ */ new Map();
|
|
30877
31488
|
function createDeduplicationMiddleware(ttlMs = 5 * 60 * 1e3) {
|
|
@@ -30891,6 +31502,16 @@ function createDeduplicationMiddleware(ttlMs = 5 * 60 * 1e3) {
|
|
|
30891
31502
|
}, "Duplicate message blocked by deduplication");
|
|
30892
31503
|
return;
|
|
30893
31504
|
}
|
|
31505
|
+
const sharedClaim = await claimDedupKey(`axiom:channel:dedup:${key}`, ttlMs);
|
|
31506
|
+
if (sharedClaim === false) {
|
|
31507
|
+
console.warn({
|
|
31508
|
+
event: "dedup:blocked",
|
|
31509
|
+
channel: msg.channel,
|
|
31510
|
+
senderId: msg.sender.id,
|
|
31511
|
+
messageId: msgId
|
|
31512
|
+
}, "Duplicate message blocked by deduplication");
|
|
31513
|
+
return;
|
|
31514
|
+
}
|
|
30894
31515
|
processedMessages.set(key, now);
|
|
30895
31516
|
}
|
|
30896
31517
|
if (processedMessages.size > 1e4) {
|
|
@@ -30913,11 +31534,12 @@ function createRateLimitMiddleware(maxRequests = 10, windowMs = 60 * 1e3, maxEnt
|
|
|
30913
31534
|
return async (ctx, next) => {
|
|
30914
31535
|
const senderKey = `${ctx.inboundMessage.channel}:${ctx.inboundMessage.sender.id}`;
|
|
30915
31536
|
const now = Date.now();
|
|
31537
|
+
const sharedCount = await incrementRateCounter(`axiom:channel:rate:${senderKey}`, windowMs);
|
|
30916
31538
|
let counter = rateCounters.get(senderKey);
|
|
30917
31539
|
if (!counter || now > counter.resetAt) {
|
|
30918
31540
|
counter = { count: 0, resetAt: now + windowMs };
|
|
30919
31541
|
}
|
|
30920
|
-
counter.count
|
|
31542
|
+
counter.count = sharedCount ?? counter.count + 1;
|
|
30921
31543
|
rateCounters.set(senderKey, counter);
|
|
30922
31544
|
if (rateCounters.size > maxEntries) {
|
|
30923
31545
|
const oldest = Array.from(rateCounters.entries()).sort((a, b) => a[1].resetAt - b[1].resetAt)[0];
|
|
@@ -30938,13 +31560,13 @@ function createRateLimitMiddleware(maxRequests = 10, windowMs = 60 * 1e3, maxEnt
|
|
|
30938
31560
|
}
|
|
30939
31561
|
|
|
30940
31562
|
// src/router/middlewares/auditLogger.ts
|
|
30941
|
-
var
|
|
31563
|
+
var logger6 = new Logger({ serviceName: "lattice/gateway/audit" });
|
|
30942
31564
|
function createAuditLoggerMiddleware() {
|
|
30943
31565
|
return async (ctx, next) => {
|
|
30944
31566
|
const start2 = Date.now();
|
|
30945
31567
|
try {
|
|
30946
31568
|
await next();
|
|
30947
|
-
|
|
31569
|
+
logger6.info("message routed", {
|
|
30948
31570
|
event: "message:routed",
|
|
30949
31571
|
channel: ctx.inboundMessage.channel,
|
|
30950
31572
|
senderId: ctx.inboundMessage.sender.id,
|
|
@@ -30954,7 +31576,7 @@ function createAuditLoggerMiddleware() {
|
|
|
30954
31576
|
status: "success"
|
|
30955
31577
|
});
|
|
30956
31578
|
} catch (error) {
|
|
30957
|
-
|
|
31579
|
+
logger6.error(
|
|
30958
31580
|
error instanceof Error ? error.message : String(error),
|
|
30959
31581
|
{
|
|
30960
31582
|
event: "message:error",
|
|
@@ -31000,9 +31622,59 @@ function parseWecomTextFrame(frame) {
|
|
|
31000
31622
|
}
|
|
31001
31623
|
|
|
31002
31624
|
// src/channels/wecom/cardTool.ts
|
|
31003
|
-
import { getToolLattice, registerToolLattice } from "@axiom-lattice/core";
|
|
31625
|
+
import { getStoreLattice as getStoreLattice38, getToolLattice, registerToolLattice } from "@axiom-lattice/core";
|
|
31004
31626
|
import { z as z12 } from "zod";
|
|
31005
31627
|
var CARD_TTL_MS = 10 * 6e4;
|
|
31628
|
+
var SHARED_NAMESPACE = ["channel-runtime", "wecom-card"];
|
|
31629
|
+
var SHARED_TTL_MINUTES = 10;
|
|
31630
|
+
function sharedStore() {
|
|
31631
|
+
try {
|
|
31632
|
+
return getStoreLattice38("default", "store").store;
|
|
31633
|
+
} catch {
|
|
31634
|
+
return null;
|
|
31635
|
+
}
|
|
31636
|
+
}
|
|
31637
|
+
async function putWecomCardForTenant(tenantId, key, card) {
|
|
31638
|
+
const accepted = putWecomCard(key, card);
|
|
31639
|
+
if (!accepted) return false;
|
|
31640
|
+
const store2 = sharedStore();
|
|
31641
|
+
if (!store2) return true;
|
|
31642
|
+
try {
|
|
31643
|
+
await store2.put(tenantId, {
|
|
31644
|
+
namespace: SHARED_NAMESPACE,
|
|
31645
|
+
key,
|
|
31646
|
+
value: { card },
|
|
31647
|
+
ttlMinutes: SHARED_TTL_MINUTES
|
|
31648
|
+
});
|
|
31649
|
+
} catch {
|
|
31650
|
+
}
|
|
31651
|
+
return true;
|
|
31652
|
+
}
|
|
31653
|
+
async function takeWecomCardForTenant(tenantId, key) {
|
|
31654
|
+
const store2 = sharedStore();
|
|
31655
|
+
if (store2) {
|
|
31656
|
+
try {
|
|
31657
|
+
const item = await store2.get(tenantId, SHARED_NAMESPACE, key);
|
|
31658
|
+
const card = item?.value?.card;
|
|
31659
|
+
if (card) {
|
|
31660
|
+
await store2.delete(tenantId, SHARED_NAMESPACE, key);
|
|
31661
|
+
takeWecomCard(key);
|
|
31662
|
+
return card;
|
|
31663
|
+
}
|
|
31664
|
+
} catch {
|
|
31665
|
+
}
|
|
31666
|
+
}
|
|
31667
|
+
return takeWecomCard(key);
|
|
31668
|
+
}
|
|
31669
|
+
async function discardWecomCardForTenant(tenantId, key) {
|
|
31670
|
+
discardWecomCard(key);
|
|
31671
|
+
const store2 = sharedStore();
|
|
31672
|
+
if (!store2) return;
|
|
31673
|
+
try {
|
|
31674
|
+
await store2.delete(tenantId, SHARED_NAMESPACE, key);
|
|
31675
|
+
} catch {
|
|
31676
|
+
}
|
|
31677
|
+
}
|
|
31006
31678
|
var MAX_CARD_ENTRIES = 1e3;
|
|
31007
31679
|
var cardEntries = /* @__PURE__ */ new Map();
|
|
31008
31680
|
function pruneCards(now) {
|
|
@@ -31216,6 +31888,11 @@ function readReplyKey(exeConfig) {
|
|
|
31216
31888
|
const key = configurable?.runConfig?.wecomReplyKey;
|
|
31217
31889
|
return typeof key === "string" && key.length > 0 ? key : void 0;
|
|
31218
31890
|
}
|
|
31891
|
+
function readTenantId(exeConfig) {
|
|
31892
|
+
const configurable = exeConfig?.configurable;
|
|
31893
|
+
const tenantId = configurable?.runConfig?.tenantId;
|
|
31894
|
+
return typeof tenantId === "string" && tenantId.length > 0 ? tenantId : "default";
|
|
31895
|
+
}
|
|
31219
31896
|
function registerWecomCardTool() {
|
|
31220
31897
|
if (getToolLattice("wecom_card")) return;
|
|
31221
31898
|
registerToolLattice(
|
|
@@ -31232,7 +31909,7 @@ function registerWecomCardTool() {
|
|
|
31232
31909
|
}
|
|
31233
31910
|
try {
|
|
31234
31911
|
const card = buildTemplateCard(input);
|
|
31235
|
-
if (!
|
|
31912
|
+
if (!await putWecomCardForTenant(readTenantId(exeConfig), replyKey, card)) {
|
|
31236
31913
|
return "ERROR: \u672C\u6761\u56DE\u590D\u5DF2\u7ED3\u675F\uFF0C\u65E0\u6CD5\u518D\u9644\u5E26\u5361\u7247\u3002\u8BF7\u628A\u7ED3\u679C\u5199\u5165\u6B63\u6587\u3002";
|
|
31237
31914
|
}
|
|
31238
31915
|
const title = card.main_title?.title;
|
|
@@ -31246,7 +31923,7 @@ function registerWecomCardTool() {
|
|
|
31246
31923
|
}
|
|
31247
31924
|
|
|
31248
31925
|
// src/channels/wecom/WecomChannelAdapter.ts
|
|
31249
|
-
var
|
|
31926
|
+
var logger7 = new Logger({ serviceName: "lattice/gateway/wecom" });
|
|
31250
31927
|
var wecomConfigSchema = z13.object({
|
|
31251
31928
|
botId: z13.string(),
|
|
31252
31929
|
secret: z13.string()
|
|
@@ -31338,12 +32015,12 @@ async function sendStreamFrame(connection, replyTarget, input) {
|
|
|
31338
32015
|
}
|
|
31339
32016
|
const frame = replyTarget.rawTarget?.frame;
|
|
31340
32017
|
if (!frame) {
|
|
31341
|
-
|
|
32018
|
+
logger7.warn("WeCom reply target has no inbound frame, skipping", {
|
|
31342
32019
|
installationId: replyTarget.channelInstallationId
|
|
31343
32020
|
});
|
|
31344
32021
|
return;
|
|
31345
32022
|
}
|
|
31346
|
-
const report = (message, error) =>
|
|
32023
|
+
const report = (message, error) => logger7.warn(message, {
|
|
31347
32024
|
installationId: replyTarget.channelInstallationId,
|
|
31348
32025
|
error: error instanceof Error ? error.message : String(error)
|
|
31349
32026
|
});
|
|
@@ -31364,7 +32041,7 @@ async function sendStreamFrame(connection, replyTarget, input) {
|
|
|
31364
32041
|
template_card: input.card
|
|
31365
32042
|
}));
|
|
31366
32043
|
rememberSentCard(input.card);
|
|
31367
|
-
|
|
32044
|
+
logger7.info("WeCom card sent", {
|
|
31368
32045
|
installationId: replyTarget.channelInstallationId,
|
|
31369
32046
|
cardType: input.card.card_type
|
|
31370
32047
|
});
|
|
@@ -31377,19 +32054,19 @@ async function sendEventReply(connection, replyTarget, input) {
|
|
|
31377
32054
|
if (!input.done) return;
|
|
31378
32055
|
const chatId = eventChatId(replyTarget);
|
|
31379
32056
|
if (!chatId) {
|
|
31380
|
-
|
|
32057
|
+
logger7.warn("WeCom card event has no chat id, cannot reply", {
|
|
31381
32058
|
installationId: replyTarget.channelInstallationId
|
|
31382
32059
|
});
|
|
31383
32060
|
return;
|
|
31384
32061
|
}
|
|
31385
32062
|
const sendMessage = connection.client.sendMessage;
|
|
31386
32063
|
if (!sendMessage) {
|
|
31387
|
-
|
|
32064
|
+
logger7.warn("WeCom client does not support sendMessage, cannot reply to card event", {
|
|
31388
32065
|
installationId: replyTarget.channelInstallationId
|
|
31389
32066
|
});
|
|
31390
32067
|
return;
|
|
31391
32068
|
}
|
|
31392
|
-
const report = (message, error) =>
|
|
32069
|
+
const report = (message, error) => logger7.warn(message, {
|
|
31393
32070
|
installationId: replyTarget.channelInstallationId,
|
|
31394
32071
|
error: error instanceof Error ? error.message : String(error)
|
|
31395
32072
|
});
|
|
@@ -31400,7 +32077,7 @@ async function sendEventReply(connection, replyTarget, input) {
|
|
|
31400
32077
|
template_card: input.card
|
|
31401
32078
|
}));
|
|
31402
32079
|
rememberSentCard(input.card);
|
|
31403
|
-
|
|
32080
|
+
logger7.info("WeCom card sent", {
|
|
31404
32081
|
installationId: replyTarget.channelInstallationId,
|
|
31405
32082
|
cardType: input.card.card_type
|
|
31406
32083
|
});
|
|
@@ -31496,14 +32173,14 @@ function handleTemplateCardEvent(rawFrame, installation, client, router) {
|
|
|
31496
32173
|
const userId = body.from?.userid;
|
|
31497
32174
|
const chatId = typeof body.chatid === "string" && body.chatid ? body.chatid : userId;
|
|
31498
32175
|
if (!userId || !chatId) {
|
|
31499
|
-
|
|
32176
|
+
logger7.warn("WeCom card event missing user/chat id, skipping", {
|
|
31500
32177
|
installationId: installation.id
|
|
31501
32178
|
});
|
|
31502
32179
|
return;
|
|
31503
32180
|
}
|
|
31504
32181
|
const { taskId, eventKey } = cardEventFields(event);
|
|
31505
32182
|
if (!claimCardEvent(taskId, eventKey)) {
|
|
31506
|
-
|
|
32183
|
+
logger7.info("WeCom duplicate card event ignored", {
|
|
31507
32184
|
installationId: installation.id,
|
|
31508
32185
|
taskId,
|
|
31509
32186
|
eventKey
|
|
@@ -31515,24 +32192,24 @@ function handleTemplateCardEvent(rawFrame, installation, client, router) {
|
|
|
31515
32192
|
const updated = acknowledgedCard(taskId, eventKey);
|
|
31516
32193
|
try {
|
|
31517
32194
|
void Promise.resolve(updateTemplateCard.call(client, rawFrame, updated)).catch((error) => {
|
|
31518
|
-
|
|
32195
|
+
logger7.warn("WeCom template card update failed", {
|
|
31519
32196
|
installationId: installation.id,
|
|
31520
32197
|
error: describeError(error)
|
|
31521
32198
|
});
|
|
31522
32199
|
});
|
|
31523
32200
|
} catch (error) {
|
|
31524
|
-
|
|
32201
|
+
logger7.warn("WeCom template card update failed", {
|
|
31525
32202
|
installationId: installation.id,
|
|
31526
32203
|
error: describeError(error)
|
|
31527
32204
|
});
|
|
31528
32205
|
}
|
|
31529
32206
|
} else {
|
|
31530
|
-
|
|
32207
|
+
logger7.warn("WeCom client does not support updateTemplateCard", {
|
|
31531
32208
|
installationId: installation.id
|
|
31532
32209
|
});
|
|
31533
32210
|
}
|
|
31534
32211
|
if (!router) return;
|
|
31535
|
-
|
|
32212
|
+
logger7.info("WeCom card event dispatched", {
|
|
31536
32213
|
installationId: installation.id,
|
|
31537
32214
|
taskId,
|
|
31538
32215
|
eventKey,
|
|
@@ -31540,13 +32217,13 @@ function handleTemplateCardEvent(rawFrame, installation, client, router) {
|
|
|
31540
32217
|
});
|
|
31541
32218
|
try {
|
|
31542
32219
|
void router.dispatch(cardEventInbound(frame, installation, { chatId, userId })).catch((error) => {
|
|
31543
|
-
|
|
32220
|
+
logger7.error("WeCom card event dispatch error", {
|
|
31544
32221
|
installationId: installation.id,
|
|
31545
32222
|
error: describeError(error)
|
|
31546
32223
|
});
|
|
31547
32224
|
});
|
|
31548
32225
|
} catch (error) {
|
|
31549
|
-
|
|
32226
|
+
logger7.error("WeCom card event dispatch error", {
|
|
31550
32227
|
installationId: installation.id,
|
|
31551
32228
|
error: describeError(error)
|
|
31552
32229
|
});
|
|
@@ -31590,13 +32267,13 @@ var wecomChannelAdapter = {
|
|
|
31590
32267
|
async sendReply(replyTarget, message, installation) {
|
|
31591
32268
|
const connection = activeConnections2.get(installation.id);
|
|
31592
32269
|
if (!connection) {
|
|
31593
|
-
|
|
32270
|
+
logger7.warn("WeCom bot not connected, cannot reply", {
|
|
31594
32271
|
installationId: installation.id
|
|
31595
32272
|
});
|
|
31596
32273
|
return;
|
|
31597
32274
|
}
|
|
31598
32275
|
const key = replyKeyForTarget(replyTarget);
|
|
31599
|
-
const card =
|
|
32276
|
+
const card = await takeWecomCardForTenant(installation.tenantId, key);
|
|
31600
32277
|
await sendStreamFrame(connection, replyTarget, {
|
|
31601
32278
|
text: message.text,
|
|
31602
32279
|
done: true,
|
|
@@ -31614,7 +32291,7 @@ var wecomChannelAdapter = {
|
|
|
31614
32291
|
async sendStreamChunk(replyTarget, chunk, installation) {
|
|
31615
32292
|
const connection = activeConnections2.get(installation.id);
|
|
31616
32293
|
if (!connection) {
|
|
31617
|
-
|
|
32294
|
+
logger7.warn("WeCom bot not connected, cannot stream reply", {
|
|
31618
32295
|
installationId: installation.id
|
|
31619
32296
|
});
|
|
31620
32297
|
return;
|
|
@@ -31623,9 +32300,9 @@ var wecomChannelAdapter = {
|
|
|
31623
32300
|
let card;
|
|
31624
32301
|
if (chunk.done) {
|
|
31625
32302
|
if (chunk.reason !== void 0 && chunk.reason !== "completed") {
|
|
31626
|
-
|
|
32303
|
+
await discardWecomCardForTenant(installation.tenantId, key);
|
|
31627
32304
|
} else {
|
|
31628
|
-
card =
|
|
32305
|
+
card = await takeWecomCardForTenant(installation.tenantId, key);
|
|
31629
32306
|
}
|
|
31630
32307
|
}
|
|
31631
32308
|
await sendStreamFrame(connection, replyTarget, {
|
|
@@ -31646,11 +32323,11 @@ var wecomChannelAdapter = {
|
|
|
31646
32323
|
async connect(installation, deps) {
|
|
31647
32324
|
const { id: installationId, tenantId, config } = installation;
|
|
31648
32325
|
if (!config.botId || !config.secret) {
|
|
31649
|
-
|
|
32326
|
+
logger7.warn("WeCom installation missing botId/secret, skipping", { installationId });
|
|
31650
32327
|
return;
|
|
31651
32328
|
}
|
|
31652
32329
|
if (activeConnections2.has(installationId)) {
|
|
31653
|
-
|
|
32330
|
+
logger7.warn("WeCom long connection already running, skipping", { installationId });
|
|
31654
32331
|
return;
|
|
31655
32332
|
}
|
|
31656
32333
|
const { router, wsClientFactory } = deps ?? {};
|
|
@@ -31661,7 +32338,7 @@ var wecomChannelAdapter = {
|
|
|
31661
32338
|
if (!inbound || !router) return void 0;
|
|
31662
32339
|
return router.dispatch(inbound);
|
|
31663
32340
|
}).catch((error) => {
|
|
31664
|
-
|
|
32341
|
+
logger7.error("WeCom message dispatch error", {
|
|
31665
32342
|
installationId,
|
|
31666
32343
|
error: error instanceof Error ? error.message : String(error)
|
|
31667
32344
|
});
|
|
@@ -31674,19 +32351,19 @@ var wecomChannelAdapter = {
|
|
|
31674
32351
|
connection.attempts = 0;
|
|
31675
32352
|
});
|
|
31676
32353
|
client.on("event.disconnected_event", () => {
|
|
31677
|
-
|
|
32354
|
+
logger7.warn("WeCom connection kicked by a newer connection; will reconnect", {
|
|
31678
32355
|
installationId
|
|
31679
32356
|
});
|
|
31680
32357
|
scheduleReconnect(installationId, connection);
|
|
31681
32358
|
});
|
|
31682
32359
|
activeConnections2.set(installationId, connection);
|
|
31683
32360
|
client.connect();
|
|
31684
|
-
|
|
32361
|
+
logger7.info("WeCom long connection starting", { installationId, tenantId });
|
|
31685
32362
|
},
|
|
31686
32363
|
async disconnect(installationId) {
|
|
31687
32364
|
const connection = activeConnections2.get(installationId);
|
|
31688
32365
|
if (!connection) {
|
|
31689
|
-
|
|
32366
|
+
logger7.warn("WeCom long connection not running, nothing to disconnect", { installationId });
|
|
31690
32367
|
return;
|
|
31691
32368
|
}
|
|
31692
32369
|
connection.intentional = true;
|
|
@@ -31697,20 +32374,20 @@ var wecomChannelAdapter = {
|
|
|
31697
32374
|
try {
|
|
31698
32375
|
connection.client.disconnect();
|
|
31699
32376
|
} catch (error) {
|
|
31700
|
-
|
|
32377
|
+
logger7.error("WeCom long connection stop error", {
|
|
31701
32378
|
installationId,
|
|
31702
32379
|
error: error instanceof Error ? error.message : String(error)
|
|
31703
32380
|
});
|
|
31704
32381
|
}
|
|
31705
32382
|
activeConnections2.delete(installationId);
|
|
31706
|
-
|
|
32383
|
+
logger7.info("WeCom long connection disconnected", { installationId });
|
|
31707
32384
|
}
|
|
31708
32385
|
};
|
|
31709
32386
|
function scheduleReconnect(installationId, connection) {
|
|
31710
32387
|
if (connection.intentional || connection.timer) return;
|
|
31711
32388
|
const delay3 = Math.min(RECONNECT_BASE_MS * 2 ** connection.attempts, RECONNECT_MAX_MS);
|
|
31712
32389
|
connection.attempts += 1;
|
|
31713
|
-
|
|
32390
|
+
logger7.info("WeCom reconnect scheduled", {
|
|
31714
32391
|
installationId,
|
|
31715
32392
|
delayMs: delay3,
|
|
31716
32393
|
attempt: connection.attempts
|
|
@@ -31723,7 +32400,7 @@ function scheduleReconnect(installationId, connection) {
|
|
|
31723
32400
|
try {
|
|
31724
32401
|
connection.client.connect();
|
|
31725
32402
|
} catch (error) {
|
|
31726
|
-
|
|
32403
|
+
logger7.error("WeCom reconnect failed", {
|
|
31727
32404
|
installationId,
|
|
31728
32405
|
error: error instanceof Error ? error.message : String(error)
|
|
31729
32406
|
});
|
|
@@ -31870,19 +32547,17 @@ import {
|
|
|
31870
32547
|
getLoggerLattice,
|
|
31871
32548
|
loggerLatticeManager,
|
|
31872
32549
|
sandboxLatticeManager as sandboxLatticeManager2,
|
|
31873
|
-
getStoreLattice as
|
|
32550
|
+
getStoreLattice as getStoreLattice42,
|
|
31874
32551
|
agentInstanceManager as agentInstanceManager13,
|
|
31875
32552
|
createSandboxProvider,
|
|
31876
32553
|
TokenCache,
|
|
31877
32554
|
mcpManager as mcpManager3,
|
|
31878
32555
|
convertToConnection as convertToConnection2,
|
|
31879
32556
|
createTrustedAgentMessageDispatcher as createTrustedAgentMessageDispatcher2,
|
|
31880
|
-
connectAllChannels,
|
|
31881
|
-
disconnectAllChannels,
|
|
31882
32557
|
ChannelConnectionLeader,
|
|
31883
32558
|
runAsLeader,
|
|
31884
32559
|
configureCoordinationLeaseStore,
|
|
31885
|
-
getReplicaId as
|
|
32560
|
+
getReplicaId as getReplicaId12,
|
|
31886
32561
|
tryAcquireThreadRun as tryAcquireThreadRun5,
|
|
31887
32562
|
taskLifecycleNotifier as taskLifecycleNotifier3,
|
|
31888
32563
|
projectTaskAdmissionNotifier as projectTaskAdmissionNotifier2,
|
|
@@ -31895,6 +32570,7 @@ import {
|
|
|
31895
32570
|
configureCollectionSync,
|
|
31896
32571
|
COLLECTION_CHANGED_TOPIC,
|
|
31897
32572
|
vectorStoreLatticeManager as vectorStoreLatticeManager2,
|
|
32573
|
+
observabilityLatticeManager,
|
|
31898
32574
|
getSandboxPluginCatalog as getSandboxPluginCatalog3,
|
|
31899
32575
|
getSandBoxManager as getSandBoxManager4,
|
|
31900
32576
|
installPluginHost,
|
|
@@ -31906,7 +32582,7 @@ import {
|
|
|
31906
32582
|
} from "@axiom-lattice/core";
|
|
31907
32583
|
|
|
31908
32584
|
// src/services/chunk/redisAppendLog.ts
|
|
31909
|
-
import { createClient as
|
|
32585
|
+
import { createClient as createClient3 } from "redis";
|
|
31910
32586
|
var VALUE_FIELD = "v";
|
|
31911
32587
|
var START_ID = "0-0";
|
|
31912
32588
|
var ChunkLogCorruptionError = class extends Error {
|
|
@@ -31923,7 +32599,7 @@ var ChunkLogCorruptionError = class extends Error {
|
|
|
31923
32599
|
}
|
|
31924
32600
|
};
|
|
31925
32601
|
async function createRedisAppendLog(url, options = {}) {
|
|
31926
|
-
const client =
|
|
32602
|
+
const client = createClient3({
|
|
31927
32603
|
url,
|
|
31928
32604
|
disableOfflineQueue: true,
|
|
31929
32605
|
socket: {
|
|
@@ -32113,7 +32789,7 @@ function readField(fields, name) {
|
|
|
32113
32789
|
}
|
|
32114
32790
|
|
|
32115
32791
|
// src/services/run-cancel/RedisRunCancelNotifier.ts
|
|
32116
|
-
import { createClient as
|
|
32792
|
+
import { createClient as createClient4 } from "redis";
|
|
32117
32793
|
import {
|
|
32118
32794
|
runCancelSignalSchema as runCancelSignalSchema2
|
|
32119
32795
|
} from "@axiom-lattice/protocols";
|
|
@@ -32514,7 +33190,7 @@ function createRedisRunCancelNotifier(options) {
|
|
|
32514
33190
|
});
|
|
32515
33191
|
}
|
|
32516
33192
|
function createNodeRedisClient2(url) {
|
|
32517
|
-
const client =
|
|
33193
|
+
const client = createClient4({
|
|
32518
33194
|
url,
|
|
32519
33195
|
disableOfflineQueue: true,
|
|
32520
33196
|
socket: {
|
|
@@ -32570,13 +33246,13 @@ import { RoomAgentMessageService } from "@axiom-lattice/core";
|
|
|
32570
33246
|
|
|
32571
33247
|
// src/router/MessageRouter.ts
|
|
32572
33248
|
import {
|
|
32573
|
-
getStoreLattice as
|
|
33249
|
+
getStoreLattice as getStoreLattice39,
|
|
32574
33250
|
agentInstanceManager as agentInstanceManager10
|
|
32575
33251
|
} from "@axiom-lattice/core";
|
|
32576
33252
|
import {
|
|
32577
33253
|
snapshotExactArray as snapshotExactArray3,
|
|
32578
33254
|
snapshotExactRecord as snapshotExactRecord15,
|
|
32579
|
-
MessageChunkTypes as
|
|
33255
|
+
MessageChunkTypes as MessageChunkTypes4
|
|
32580
33256
|
} from "@axiom-lattice/protocols";
|
|
32581
33257
|
import { randomUUID as randomUUID35 } from "crypto";
|
|
32582
33258
|
|
|
@@ -32895,7 +33571,7 @@ var _MessageRouter = class _MessageRouter {
|
|
|
32895
33571
|
channel: message.channel,
|
|
32896
33572
|
adapterChannel: adapter.channel
|
|
32897
33573
|
}, "Thread resolved by adapter strategy");
|
|
32898
|
-
const threadStore =
|
|
33574
|
+
const threadStore = getStoreLattice39("default", "thread").store;
|
|
32899
33575
|
try {
|
|
32900
33576
|
await threadStore.createThread(
|
|
32901
33577
|
tenantId,
|
|
@@ -32932,7 +33608,7 @@ var _MessageRouter = class _MessageRouter {
|
|
|
32932
33608
|
}
|
|
32933
33609
|
}
|
|
32934
33610
|
if (!threadId) {
|
|
32935
|
-
const threadStore =
|
|
33611
|
+
const threadStore = getStoreLattice39("default", "thread").store;
|
|
32936
33612
|
const newThreadId = randomUUID35();
|
|
32937
33613
|
console.log({
|
|
32938
33614
|
event: "dispatch:thread:create",
|
|
@@ -33167,8 +33843,8 @@ var _MessageRouter = class _MessageRouter {
|
|
|
33167
33843
|
...metadata && typeof metadata === "object" && !Array.isArray(metadata) ? metadata : {},
|
|
33168
33844
|
channelRun: true
|
|
33169
33845
|
};
|
|
33170
|
-
const runLedger =
|
|
33171
|
-
const jobStore =
|
|
33846
|
+
const runLedger = getStoreLattice39("default", "agentRun").store;
|
|
33847
|
+
const jobStore = getStoreLattice39("default", "channelReplyJob").store;
|
|
33172
33848
|
const runId = randomUUID35();
|
|
33173
33849
|
await jobStore.create({
|
|
33174
33850
|
runId,
|
|
@@ -33266,13 +33942,13 @@ var _MessageRouter = class _MessageRouter {
|
|
|
33266
33942
|
for await (const chunk of stream) {
|
|
33267
33943
|
if (state.finished) break;
|
|
33268
33944
|
if (!started) {
|
|
33269
|
-
if (chunk?.type ===
|
|
33945
|
+
if (chunk?.type === MessageChunkTypes4.HUMAN && chunk?.data?.id === inputMessageId) {
|
|
33270
33946
|
started = true;
|
|
33271
33947
|
}
|
|
33272
33948
|
continue;
|
|
33273
33949
|
}
|
|
33274
|
-
if (chunk?.type ===
|
|
33275
|
-
if (chunk.type ===
|
|
33950
|
+
if (chunk?.type === MessageChunkTypes4.MESSAGE_COMPLETED || chunk?.type === MessageChunkTypes4.MESSAGE_FAILED || chunk?.type === MessageChunkTypes4.INTERRUPT) {
|
|
33951
|
+
if (chunk.type === MessageChunkTypes4.MESSAGE_COMPLETED) {
|
|
33276
33952
|
normalEnd = true;
|
|
33277
33953
|
const grace = setTimeout(
|
|
33278
33954
|
() => {
|
|
@@ -33281,14 +33957,14 @@ var _MessageRouter = class _MessageRouter {
|
|
|
33281
33957
|
_MessageRouter.COMPLETION_GRACE_MS
|
|
33282
33958
|
);
|
|
33283
33959
|
grace.unref?.();
|
|
33284
|
-
} else if (chunk.type ===
|
|
33960
|
+
} else if (chunk.type === MessageChunkTypes4.MESSAGE_FAILED) {
|
|
33285
33961
|
await closeWith("failed");
|
|
33286
33962
|
} else {
|
|
33287
33963
|
await closeWith("interrupted");
|
|
33288
33964
|
}
|
|
33289
33965
|
break;
|
|
33290
33966
|
}
|
|
33291
|
-
if (chunk?.type !==
|
|
33967
|
+
if (chunk?.type !== MessageChunkTypes4.AI) continue;
|
|
33292
33968
|
const text = typeof chunk.data?.content === "string" ? chunk.data.content : void 0;
|
|
33293
33969
|
if (!text) continue;
|
|
33294
33970
|
accumulated += text;
|
|
@@ -34589,11 +35265,11 @@ function readPluginDeploymentLimits(env = process.env) {
|
|
|
34589
35265
|
};
|
|
34590
35266
|
}
|
|
34591
35267
|
function startPluginDeploymentRuntime(options) {
|
|
34592
|
-
const { lease, holder, logger:
|
|
35268
|
+
const { lease, holder, logger: logger9 } = options;
|
|
34593
35269
|
const forcedOn = process.env[PLUGIN_DEPLOYMENT_RUNTIME_FLAG] === "true" || process.env[PLUGIN_DEPLOYMENT_RUNTIME_FLAG] === "1";
|
|
34594
35270
|
const effectiveServiceBaseUrl = options.wiring.serviceBaseUrl ?? process.env.MICROSANDBOX_SERVICE_BASE_URL;
|
|
34595
35271
|
if (forcedOn && !effectiveServiceBaseUrl) {
|
|
34596
|
-
|
|
35272
|
+
logger9.warn(
|
|
34597
35273
|
`${PLUGIN_DEPLOYMENT_RUNTIME_FLAG} is enabled but MICROSANDBOX_SERVICE_BASE_URL is empty; skipping plugin deployment runtime`,
|
|
34598
35274
|
{ holder }
|
|
34599
35275
|
);
|
|
@@ -34612,8 +35288,8 @@ function startPluginDeploymentRuntime(options) {
|
|
|
34612
35288
|
};
|
|
34613
35289
|
const service2 = createService(deps);
|
|
34614
35290
|
register(service2);
|
|
34615
|
-
|
|
34616
|
-
const reconcile = runStartupReconcile(service2, reconcileDeadlineMs,
|
|
35291
|
+
logger9.info("plugin deployment runtime started", { holder });
|
|
35292
|
+
const reconcile = runStartupReconcile(service2, reconcileDeadlineMs, logger9, holder);
|
|
34617
35293
|
let held = false;
|
|
34618
35294
|
let inFlight = false;
|
|
34619
35295
|
const tick = async () => {
|
|
@@ -34621,18 +35297,18 @@ function startPluginDeploymentRuntime(options) {
|
|
|
34621
35297
|
inFlight = true;
|
|
34622
35298
|
try {
|
|
34623
35299
|
if (held) {
|
|
34624
|
-
held = await renewLease(lease, holder,
|
|
35300
|
+
held = await renewLease(lease, holder, logger9);
|
|
34625
35301
|
if (!held) {
|
|
34626
|
-
|
|
35302
|
+
logger9.warn("plugin deployment lease lost; watchdog paused", { holder });
|
|
34627
35303
|
}
|
|
34628
35304
|
} else {
|
|
34629
|
-
held = await acquireLease(lease, holder,
|
|
35305
|
+
held = await acquireLease(lease, holder, logger9);
|
|
34630
35306
|
if (held) {
|
|
34631
|
-
|
|
35307
|
+
logger9.info("plugin deployment lease acquired", { holder });
|
|
34632
35308
|
}
|
|
34633
35309
|
}
|
|
34634
35310
|
if (!held) return;
|
|
34635
|
-
await runWatchdog(service2, holder,
|
|
35311
|
+
await runWatchdog(service2, holder, logger9);
|
|
34636
35312
|
} finally {
|
|
34637
35313
|
inFlight = false;
|
|
34638
35314
|
}
|
|
@@ -34648,7 +35324,7 @@ function startPluginDeploymentRuntime(options) {
|
|
|
34648
35324
|
try {
|
|
34649
35325
|
await lease.release(PLUGIN_DEPLOYMENT_LEASE_KEY, holder);
|
|
34650
35326
|
} catch (error) {
|
|
34651
|
-
|
|
35327
|
+
logger9.warn("plugin deployment lease release failed", {
|
|
34652
35328
|
holder,
|
|
34653
35329
|
error: errorMessage8(error)
|
|
34654
35330
|
});
|
|
@@ -34656,16 +35332,16 @@ function startPluginDeploymentRuntime(options) {
|
|
|
34656
35332
|
held = false;
|
|
34657
35333
|
}
|
|
34658
35334
|
register(void 0);
|
|
34659
|
-
|
|
35335
|
+
logger9.info("plugin deployment runtime stopped", { holder });
|
|
34660
35336
|
}
|
|
34661
35337
|
};
|
|
34662
35338
|
}
|
|
34663
|
-
async function runStartupReconcile(service2, deadlineMs,
|
|
35339
|
+
async function runStartupReconcile(service2, deadlineMs, logger9, holder) {
|
|
34664
35340
|
try {
|
|
34665
35341
|
await withDeadline(service2.startupReconcile(), deadlineMs);
|
|
34666
|
-
|
|
35342
|
+
logger9.info("plugin deployment startup reconcile complete", { holder });
|
|
34667
35343
|
} catch (error) {
|
|
34668
|
-
|
|
35344
|
+
logger9.warn("plugin deployment startup reconcile failed", {
|
|
34669
35345
|
holder,
|
|
34670
35346
|
error: errorMessage8(error)
|
|
34671
35347
|
});
|
|
@@ -34688,7 +35364,7 @@ async function withDeadline(work, deadlineMs) {
|
|
|
34688
35364
|
if (timer !== void 0) clearTimeout(timer);
|
|
34689
35365
|
}
|
|
34690
35366
|
}
|
|
34691
|
-
async function acquireLease(lease, holder,
|
|
35367
|
+
async function acquireLease(lease, holder, logger9) {
|
|
34692
35368
|
try {
|
|
34693
35369
|
return await lease.tryAcquire(
|
|
34694
35370
|
PLUGIN_DEPLOYMENT_LEASE_KEY,
|
|
@@ -34696,14 +35372,14 @@ async function acquireLease(lease, holder, logger8) {
|
|
|
34696
35372
|
PLUGIN_DEPLOYMENT_LEASE_TTL_MS
|
|
34697
35373
|
);
|
|
34698
35374
|
} catch (error) {
|
|
34699
|
-
|
|
35375
|
+
logger9.warn("plugin deployment lease acquire failed", {
|
|
34700
35376
|
holder,
|
|
34701
35377
|
error: errorMessage8(error)
|
|
34702
35378
|
});
|
|
34703
35379
|
return false;
|
|
34704
35380
|
}
|
|
34705
35381
|
}
|
|
34706
|
-
async function renewLease(lease, holder,
|
|
35382
|
+
async function renewLease(lease, holder, logger9) {
|
|
34707
35383
|
try {
|
|
34708
35384
|
return await lease.renew(
|
|
34709
35385
|
PLUGIN_DEPLOYMENT_LEASE_KEY,
|
|
@@ -34711,18 +35387,18 @@ async function renewLease(lease, holder, logger8) {
|
|
|
34711
35387
|
PLUGIN_DEPLOYMENT_LEASE_TTL_MS
|
|
34712
35388
|
);
|
|
34713
35389
|
} catch (error) {
|
|
34714
|
-
|
|
35390
|
+
logger9.warn("plugin deployment lease renew failed", {
|
|
34715
35391
|
holder,
|
|
34716
35392
|
error: errorMessage8(error)
|
|
34717
35393
|
});
|
|
34718
35394
|
return false;
|
|
34719
35395
|
}
|
|
34720
35396
|
}
|
|
34721
|
-
async function runWatchdog(service2, holder,
|
|
35397
|
+
async function runWatchdog(service2, holder, logger9) {
|
|
34722
35398
|
try {
|
|
34723
35399
|
await service2.healthWatchdog();
|
|
34724
35400
|
} catch (error) {
|
|
34725
|
-
|
|
35401
|
+
logger9.warn("plugin deployment health watchdog failed", {
|
|
34726
35402
|
holder,
|
|
34727
35403
|
error: errorMessage8(error)
|
|
34728
35404
|
});
|
|
@@ -34822,8 +35498,8 @@ function resolveRetentionMs(value) {
|
|
|
34822
35498
|
|
|
34823
35499
|
// src/services/execution/threadTtlSweeper.ts
|
|
34824
35500
|
import {
|
|
34825
|
-
getReplicaId as
|
|
34826
|
-
getStoreLattice as
|
|
35501
|
+
getReplicaId as getReplicaId11,
|
|
35502
|
+
getStoreLattice as getStoreLattice40,
|
|
34827
35503
|
tryAcquireThreadRun as tryAcquireThreadRun2
|
|
34828
35504
|
} from "@axiom-lattice/core";
|
|
34829
35505
|
function createThreadTtlSweeper(options) {
|
|
@@ -34841,7 +35517,7 @@ function createThreadTtlSweeper(options) {
|
|
|
34841
35517
|
const result = { scanned: 0, pruned: 0, skipped: 0, errors: 0 };
|
|
34842
35518
|
let expired;
|
|
34843
35519
|
try {
|
|
34844
|
-
expired = await
|
|
35520
|
+
expired = await getStoreLattice40("default", "thread").store.listExpiredThreads(now(), batchSize);
|
|
34845
35521
|
} catch (error) {
|
|
34846
35522
|
result.errors += 1;
|
|
34847
35523
|
log2.warn("Thread TTL sweep failed to list expired threads", {
|
|
@@ -34854,11 +35530,11 @@ function createThreadTtlSweeper(options) {
|
|
|
34854
35530
|
let lease;
|
|
34855
35531
|
try {
|
|
34856
35532
|
lease = await tryAcquireThreadRun2({
|
|
34857
|
-
store:
|
|
35533
|
+
store: getStoreLattice40("default", "lease").store,
|
|
34858
35534
|
tenantId: thread.tenantId,
|
|
34859
35535
|
assistantId: thread.assistantId,
|
|
34860
35536
|
threadId: thread.id,
|
|
34861
|
-
owner:
|
|
35537
|
+
owner: getReplicaId11(),
|
|
34862
35538
|
ttlMs: 6e4
|
|
34863
35539
|
});
|
|
34864
35540
|
} catch (error) {
|
|
@@ -34874,7 +35550,7 @@ function createThreadTtlSweeper(options) {
|
|
|
34874
35550
|
continue;
|
|
34875
35551
|
}
|
|
34876
35552
|
try {
|
|
34877
|
-
const queueStore =
|
|
35553
|
+
const queueStore = getStoreLattice40("default", "threadMessageQueue").store;
|
|
34878
35554
|
const pending2 = await queueStore.getPendingMessages(thread.id, queueScopeFromThread(thread));
|
|
34879
35555
|
if (pending2.length > 0) {
|
|
34880
35556
|
result.skipped += 1;
|
|
@@ -34951,7 +35627,7 @@ function createThreadTtlSweeper(options) {
|
|
|
34951
35627
|
}
|
|
34952
35628
|
|
|
34953
35629
|
// src/services/execution/storeTtlSweeper.ts
|
|
34954
|
-
import { getStoreLattice as
|
|
35630
|
+
import { getStoreLattice as getStoreLattice41 } from "@axiom-lattice/core";
|
|
34955
35631
|
function parsePositiveInteger(value, fallback) {
|
|
34956
35632
|
const parsed = Number(value);
|
|
34957
35633
|
return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : fallback;
|
|
@@ -34974,7 +35650,7 @@ function createStoreTtlSweeper(options) {
|
|
|
34974
35650
|
const performSweep = async () => {
|
|
34975
35651
|
let store2;
|
|
34976
35652
|
try {
|
|
34977
|
-
store2 =
|
|
35653
|
+
store2 = getStoreLattice41("default", "store").store;
|
|
34978
35654
|
} catch (error) {
|
|
34979
35655
|
if (!warnedMissingStore) {
|
|
34980
35656
|
warnedMissingStore = true;
|
|
@@ -36415,7 +37091,7 @@ function createAgentRunRetentionJob(input) {
|
|
|
36415
37091
|
}
|
|
36416
37092
|
|
|
36417
37093
|
// src/services/run-task/RedisRunTaskWake.ts
|
|
36418
|
-
import { createClient as
|
|
37094
|
+
import { createClient as createClient5 } from "redis";
|
|
36419
37095
|
var RUN_TASK_WAKE_CHANNEL = "run-task:wake";
|
|
36420
37096
|
var DEFAULT_OPERATION_TIMEOUT_MS = 2e3;
|
|
36421
37097
|
var DEFAULT_RETRY_DELAYS_MS = [500, 2e3, 5e3, 1e4];
|
|
@@ -36808,7 +37484,7 @@ function createConfiguredRedisRunTaskWake(options) {
|
|
|
36808
37484
|
return createRedisRunTaskWake({ ...options, url });
|
|
36809
37485
|
}
|
|
36810
37486
|
function createNodeRedisClient3(url) {
|
|
36811
|
-
const client =
|
|
37487
|
+
const client = createClient5({
|
|
36812
37488
|
url,
|
|
36813
37489
|
disableOfflineQueue: true,
|
|
36814
37490
|
socket: {
|
|
@@ -36916,6 +37592,19 @@ function ingestRoomEvent(payload, broker) {
|
|
|
36916
37592
|
return broker.ingestForeignEvent(serialized);
|
|
36917
37593
|
}
|
|
36918
37594
|
|
|
37595
|
+
// src/services/channelInstallationSync.ts
|
|
37596
|
+
var CHANNEL_INSTALLATION_CHANGED_TOPIC = "channel-installation-changed";
|
|
37597
|
+
async function publishChannelInstallationChanged(outbox, owner, payload) {
|
|
37598
|
+
try {
|
|
37599
|
+
await outbox.append({
|
|
37600
|
+
topic: CHANNEL_INSTALLATION_CHANGED_TOPIC,
|
|
37601
|
+
payload,
|
|
37602
|
+
originReplicaId: owner
|
|
37603
|
+
});
|
|
37604
|
+
} catch {
|
|
37605
|
+
}
|
|
37606
|
+
}
|
|
37607
|
+
|
|
36919
37608
|
// src/services/assistantRegistrySync.ts
|
|
36920
37609
|
var ASSISTANT_CHANGE_EVENTS = ["assistant:created", "assistant:updated", "assistant:deleted"];
|
|
36921
37610
|
var ASSISTANT_CHANGED_TOPIC = "assistant-changed";
|
|
@@ -37000,6 +37689,743 @@ import {
|
|
|
37000
37689
|
REPLICA_HEADER as REPLICA_HEADER3,
|
|
37001
37690
|
AFFINITY_ECHO_HEADER as AFFINITY_ECHO_HEADER3
|
|
37002
37691
|
} from "@axiom-lattice/protocols";
|
|
37692
|
+
|
|
37693
|
+
// src/services/observability/LangfuseObservabilityProvider.ts
|
|
37694
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
37695
|
+
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
37696
|
+
import { LangfuseSpanProcessor } from "@langfuse/otel";
|
|
37697
|
+
import { CallbackHandler } from "@langfuse/langchain";
|
|
37698
|
+
import {
|
|
37699
|
+
ObservabilityDashboardUnavailableError as ObservabilityDashboardUnavailableError2,
|
|
37700
|
+
ObservabilityDashboardUnsupportedError as ObservabilityDashboardUnsupportedError2
|
|
37701
|
+
} from "@axiom-lattice/core";
|
|
37702
|
+
import {
|
|
37703
|
+
LANGFUSE_OBSERVABILITY_DASHBOARD_VERSION
|
|
37704
|
+
} from "@axiom-lattice/protocols";
|
|
37705
|
+
|
|
37706
|
+
// src/services/observability/LangfuseDashboardQueries.ts
|
|
37707
|
+
var DASHBOARD_SECTIONS = [
|
|
37708
|
+
"traces",
|
|
37709
|
+
"agentTraces",
|
|
37710
|
+
"costTokens",
|
|
37711
|
+
"latency",
|
|
37712
|
+
"errors",
|
|
37713
|
+
"agents",
|
|
37714
|
+
"models",
|
|
37715
|
+
"tools",
|
|
37716
|
+
"toolCalls"
|
|
37717
|
+
];
|
|
37718
|
+
var V1_METRICS_SECTIONS = /* @__PURE__ */ new Set([
|
|
37719
|
+
"traces",
|
|
37720
|
+
"agentTraces"
|
|
37721
|
+
]);
|
|
37722
|
+
var RANGE_MS = {
|
|
37723
|
+
"1h": 60 * 60 * 1e3,
|
|
37724
|
+
"24h": 24 * 60 * 60 * 1e3,
|
|
37725
|
+
"7d": 7 * 24 * 60 * 60 * 1e3,
|
|
37726
|
+
"30d": 30 * 24 * 60 * 60 * 1e3
|
|
37727
|
+
};
|
|
37728
|
+
var GRANULARITY = {
|
|
37729
|
+
"1h": "minute",
|
|
37730
|
+
"24h": "hour",
|
|
37731
|
+
"7d": "hour",
|
|
37732
|
+
"30d": "day"
|
|
37733
|
+
};
|
|
37734
|
+
var ROOT_FILTER = {
|
|
37735
|
+
column: "isRootObservation",
|
|
37736
|
+
operator: "=",
|
|
37737
|
+
value: true,
|
|
37738
|
+
type: "boolean"
|
|
37739
|
+
};
|
|
37740
|
+
function typeFilter(value) {
|
|
37741
|
+
return {
|
|
37742
|
+
column: "type",
|
|
37743
|
+
operator: "any of",
|
|
37744
|
+
value: [value],
|
|
37745
|
+
type: "stringOptions"
|
|
37746
|
+
};
|
|
37747
|
+
}
|
|
37748
|
+
function buildDashboardQueries(input) {
|
|
37749
|
+
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
37750
|
+
const fromTimestamp = new Date(
|
|
37751
|
+
now.getTime() - RANGE_MS[input.range]
|
|
37752
|
+
).toISOString();
|
|
37753
|
+
const toTimestamp = now.toISOString();
|
|
37754
|
+
const filters = [
|
|
37755
|
+
{
|
|
37756
|
+
column: "metadata",
|
|
37757
|
+
operator: "=",
|
|
37758
|
+
value: input.tenantId,
|
|
37759
|
+
type: "stringObject",
|
|
37760
|
+
key: "x-tenant-id"
|
|
37761
|
+
}
|
|
37762
|
+
];
|
|
37763
|
+
if (input.environment) {
|
|
37764
|
+
filters.push({
|
|
37765
|
+
column: "environment",
|
|
37766
|
+
operator: "=",
|
|
37767
|
+
value: input.environment,
|
|
37768
|
+
type: "string"
|
|
37769
|
+
});
|
|
37770
|
+
}
|
|
37771
|
+
const timeDimension = { granularity: GRANULARITY[input.range] };
|
|
37772
|
+
const window = { fromTimestamp, toTimestamp };
|
|
37773
|
+
return {
|
|
37774
|
+
traces: {
|
|
37775
|
+
view: "traces",
|
|
37776
|
+
metrics: [{ measure: "count", aggregation: "count" }],
|
|
37777
|
+
filters,
|
|
37778
|
+
timeDimension,
|
|
37779
|
+
...window,
|
|
37780
|
+
config: { row_limit: 1e3 }
|
|
37781
|
+
},
|
|
37782
|
+
agentTraces: {
|
|
37783
|
+
view: "traces",
|
|
37784
|
+
metrics: [{ measure: "count", aggregation: "count" }],
|
|
37785
|
+
dimensions: [{ field: "tags" }, { field: "name" }],
|
|
37786
|
+
filters,
|
|
37787
|
+
orderBy: [{ field: "count_count", direction: "desc" }],
|
|
37788
|
+
...window,
|
|
37789
|
+
config: { row_limit: 1e3 }
|
|
37790
|
+
},
|
|
37791
|
+
costTokens: {
|
|
37792
|
+
view: "observations",
|
|
37793
|
+
metrics: [
|
|
37794
|
+
{ measure: "totalCost", aggregation: "sum" },
|
|
37795
|
+
{ measure: "inputTokens", aggregation: "sum" },
|
|
37796
|
+
{ measure: "outputTokens", aggregation: "sum" }
|
|
37797
|
+
],
|
|
37798
|
+
dimensions: [{ field: "providedModelName" }],
|
|
37799
|
+
filters: [...filters, typeFilter("GENERATION")],
|
|
37800
|
+
timeDimension,
|
|
37801
|
+
...window,
|
|
37802
|
+
config: { row_limit: 1e3 }
|
|
37803
|
+
},
|
|
37804
|
+
latency: {
|
|
37805
|
+
view: "observations",
|
|
37806
|
+
metrics: [
|
|
37807
|
+
{ measure: "latency", aggregation: "p50" },
|
|
37808
|
+
{ measure: "latency", aggregation: "p95" },
|
|
37809
|
+
{ measure: "latency", aggregation: "p99" }
|
|
37810
|
+
],
|
|
37811
|
+
filters: [...filters, ROOT_FILTER],
|
|
37812
|
+
timeDimension,
|
|
37813
|
+
...window,
|
|
37814
|
+
config: { row_limit: 1e3 }
|
|
37815
|
+
},
|
|
37816
|
+
errors: {
|
|
37817
|
+
view: "observations",
|
|
37818
|
+
metrics: [{ measure: "count", aggregation: "count" }],
|
|
37819
|
+
dimensions: [{ field: "level" }],
|
|
37820
|
+
filters,
|
|
37821
|
+
timeDimension,
|
|
37822
|
+
...window,
|
|
37823
|
+
config: { row_limit: 1e3 }
|
|
37824
|
+
},
|
|
37825
|
+
agents: {
|
|
37826
|
+
view: "observations",
|
|
37827
|
+
metrics: [
|
|
37828
|
+
{ measure: "count", aggregation: "count" },
|
|
37829
|
+
{ measure: "totalCost", aggregation: "sum" },
|
|
37830
|
+
{ measure: "inputTokens", aggregation: "sum" },
|
|
37831
|
+
{ measure: "outputTokens", aggregation: "sum" }
|
|
37832
|
+
],
|
|
37833
|
+
dimensions: [{ field: "tags" }, { field: "level" }],
|
|
37834
|
+
filters,
|
|
37835
|
+
orderBy: [{ field: "count_count", direction: "desc" }],
|
|
37836
|
+
...window,
|
|
37837
|
+
config: { row_limit: 1e3 }
|
|
37838
|
+
},
|
|
37839
|
+
models: {
|
|
37840
|
+
view: "observations",
|
|
37841
|
+
metrics: [
|
|
37842
|
+
{ measure: "count", aggregation: "count" },
|
|
37843
|
+
{ measure: "totalCost", aggregation: "sum" },
|
|
37844
|
+
{ measure: "inputTokens", aggregation: "sum" },
|
|
37845
|
+
{ measure: "outputTokens", aggregation: "sum" },
|
|
37846
|
+
{ measure: "latency", aggregation: "p95" }
|
|
37847
|
+
],
|
|
37848
|
+
dimensions: [{ field: "providedModelName" }],
|
|
37849
|
+
filters: [...filters, typeFilter("GENERATION")],
|
|
37850
|
+
orderBy: [{ field: "count_count", direction: "desc" }],
|
|
37851
|
+
...window,
|
|
37852
|
+
config: { row_limit: 20 }
|
|
37853
|
+
},
|
|
37854
|
+
tools: {
|
|
37855
|
+
view: "observations",
|
|
37856
|
+
metrics: [{ measure: "count", aggregation: "count" }],
|
|
37857
|
+
dimensions: [{ field: "name" }],
|
|
37858
|
+
filters: [...filters, typeFilter("TOOL")],
|
|
37859
|
+
orderBy: [{ field: "count_count", direction: "desc" }],
|
|
37860
|
+
...window,
|
|
37861
|
+
config: { row_limit: 20 }
|
|
37862
|
+
},
|
|
37863
|
+
toolCalls: {
|
|
37864
|
+
view: "observations",
|
|
37865
|
+
metrics: [{ measure: "count", aggregation: "count" }],
|
|
37866
|
+
filters: [...filters, typeFilter("TOOL")],
|
|
37867
|
+
timeDimension,
|
|
37868
|
+
...window,
|
|
37869
|
+
config: { row_limit: 1e3 }
|
|
37870
|
+
}
|
|
37871
|
+
};
|
|
37872
|
+
}
|
|
37873
|
+
function rowsOf(data) {
|
|
37874
|
+
if (!data || typeof data !== "object") return [];
|
|
37875
|
+
const rows = data.data;
|
|
37876
|
+
if (!Array.isArray(rows)) return [];
|
|
37877
|
+
return rows.filter(
|
|
37878
|
+
(row) => row !== null && typeof row === "object" && !Array.isArray(row)
|
|
37879
|
+
);
|
|
37880
|
+
}
|
|
37881
|
+
function numberOf(row, key) {
|
|
37882
|
+
const value = row[key];
|
|
37883
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
37884
|
+
}
|
|
37885
|
+
function nullableNumber(row, key) {
|
|
37886
|
+
const value = row[key];
|
|
37887
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
37888
|
+
}
|
|
37889
|
+
function isoBucket(row) {
|
|
37890
|
+
const raw = row.time_dimension ?? row.timestamp;
|
|
37891
|
+
if (typeof raw !== "string" || raw.length === 0) return null;
|
|
37892
|
+
const parsed = new Date(raw);
|
|
37893
|
+
return Number.isFinite(parsed.getTime()) ? parsed.toISOString() : null;
|
|
37894
|
+
}
|
|
37895
|
+
function toSeries(data, key) {
|
|
37896
|
+
const points = [];
|
|
37897
|
+
for (const row of rowsOf(data)) {
|
|
37898
|
+
const bucket = isoBucket(row);
|
|
37899
|
+
if (!bucket) continue;
|
|
37900
|
+
points.push({ bucket, value: nullableNumber(row, key) });
|
|
37901
|
+
}
|
|
37902
|
+
return points.sort((a, b) => a.bucket.localeCompare(b.bucket));
|
|
37903
|
+
}
|
|
37904
|
+
function sumSeries(points) {
|
|
37905
|
+
return points.reduce((total, point) => total + (point.value ?? 0), 0);
|
|
37906
|
+
}
|
|
37907
|
+
function toAggregatedSeries(data, key) {
|
|
37908
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
37909
|
+
for (const row of rowsOf(data)) {
|
|
37910
|
+
const bucket = isoBucket(row);
|
|
37911
|
+
if (!bucket) continue;
|
|
37912
|
+
buckets.set(bucket, (buckets.get(bucket) ?? 0) + (nullableNumber(row, key) ?? 0));
|
|
37913
|
+
}
|
|
37914
|
+
return [...buckets.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([bucket, value]) => ({ bucket, value }));
|
|
37915
|
+
}
|
|
37916
|
+
function parseCostByModel(data) {
|
|
37917
|
+
const byModel = /* @__PURE__ */ new Map();
|
|
37918
|
+
for (const row of rowsOf(data)) {
|
|
37919
|
+
const bucket = isoBucket(row);
|
|
37920
|
+
if (!bucket) continue;
|
|
37921
|
+
const model = typeof row.providedModelName === "string" && row.providedModelName ? row.providedModelName : "unknown";
|
|
37922
|
+
const points = byModel.get(model) ?? [];
|
|
37923
|
+
points.push({ bucket, value: nullableNumber(row, "sum_totalCost") });
|
|
37924
|
+
byModel.set(model, points);
|
|
37925
|
+
}
|
|
37926
|
+
return [...byModel.entries()].map(([model, points]) => ({
|
|
37927
|
+
model,
|
|
37928
|
+
points: points.sort((a, b) => a.bucket.localeCompare(b.bucket))
|
|
37929
|
+
})).filter((series) => sumSeries(series.points) !== 0).sort((a, b) => sumSeries(b.points) - sumSeries(a.points));
|
|
37930
|
+
}
|
|
37931
|
+
function parseLevelSeries(data) {
|
|
37932
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
37933
|
+
for (const row of rowsOf(data)) {
|
|
37934
|
+
const bucket = isoBucket(row);
|
|
37935
|
+
if (!bucket) continue;
|
|
37936
|
+
const current3 = buckets.get(bucket) ?? { total: 0, errors: 0 };
|
|
37937
|
+
const count = numberOf(row, "count_count");
|
|
37938
|
+
current3.total += count;
|
|
37939
|
+
if (row.level === "ERROR") current3.errors += count;
|
|
37940
|
+
buckets.set(bucket, current3);
|
|
37941
|
+
}
|
|
37942
|
+
return [...buckets.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([bucket, value]) => ({
|
|
37943
|
+
bucket,
|
|
37944
|
+
value: value.total > 0 ? value.errors / value.total : 0
|
|
37945
|
+
}));
|
|
37946
|
+
}
|
|
37947
|
+
function parseModels(data) {
|
|
37948
|
+
return rowsOf(data).map((row) => ({
|
|
37949
|
+
model: typeof row.providedModelName === "string" && row.providedModelName ? row.providedModelName : "unknown",
|
|
37950
|
+
count: numberOf(row, "count_count"),
|
|
37951
|
+
costUsd: numberOf(row, "sum_totalCost"),
|
|
37952
|
+
inputTokens: numberOf(row, "sum_inputTokens"),
|
|
37953
|
+
outputTokens: numberOf(row, "sum_outputTokens"),
|
|
37954
|
+
p95LatencyMs: nullableNumber(row, "p95_latency")
|
|
37955
|
+
})).filter((row) => row.count > 0).sort((a, b) => b.count - a.count);
|
|
37956
|
+
}
|
|
37957
|
+
function assistantIdFromTags(tags) {
|
|
37958
|
+
if (!Array.isArray(tags)) return "unattributed";
|
|
37959
|
+
const assistantTag = tags.find(
|
|
37960
|
+
(tag) => typeof tag === "string" && tag.startsWith("assistant:")
|
|
37961
|
+
);
|
|
37962
|
+
if (!assistantTag) return "unattributed";
|
|
37963
|
+
const assistantId = assistantTag.slice("assistant:".length);
|
|
37964
|
+
return assistantId.length > 0 ? assistantId : "unattributed";
|
|
37965
|
+
}
|
|
37966
|
+
function parseAgentTraces(data) {
|
|
37967
|
+
const byAgent = /* @__PURE__ */ new Map();
|
|
37968
|
+
for (const row of rowsOf(data)) {
|
|
37969
|
+
const assistantId = assistantIdFromTags(row.tags);
|
|
37970
|
+
const current3 = byAgent.get(assistantId) ?? {
|
|
37971
|
+
calls: 0,
|
|
37972
|
+
names: /* @__PURE__ */ new Map()
|
|
37973
|
+
};
|
|
37974
|
+
const count = numberOf(row, "count_count");
|
|
37975
|
+
current3.calls += count;
|
|
37976
|
+
const name = typeof row.name === "string" ? row.name.trim() : "";
|
|
37977
|
+
if (name) {
|
|
37978
|
+
current3.names.set(name, (current3.names.get(name) ?? 0) + count);
|
|
37979
|
+
}
|
|
37980
|
+
byAgent.set(assistantId, current3);
|
|
37981
|
+
}
|
|
37982
|
+
return byAgent;
|
|
37983
|
+
}
|
|
37984
|
+
function parseAgents(observationData, traceData) {
|
|
37985
|
+
const observations = /* @__PURE__ */ new Map();
|
|
37986
|
+
for (const row of rowsOf(observationData)) {
|
|
37987
|
+
const assistantId = assistantIdFromTags(row.tags);
|
|
37988
|
+
const current3 = observations.get(assistantId) ?? {
|
|
37989
|
+
observations: 0,
|
|
37990
|
+
costUsd: 0,
|
|
37991
|
+
inputTokens: 0,
|
|
37992
|
+
outputTokens: 0,
|
|
37993
|
+
errorCount: 0
|
|
37994
|
+
};
|
|
37995
|
+
const count = numberOf(row, "count_count");
|
|
37996
|
+
current3.observations += count;
|
|
37997
|
+
current3.costUsd += numberOf(row, "sum_totalCost");
|
|
37998
|
+
current3.inputTokens += numberOf(row, "sum_inputTokens");
|
|
37999
|
+
current3.outputTokens += numberOf(row, "sum_outputTokens");
|
|
38000
|
+
if (row.level === "ERROR") current3.errorCount += count;
|
|
38001
|
+
observations.set(assistantId, current3);
|
|
38002
|
+
}
|
|
38003
|
+
const traces = parseAgentTraces(traceData);
|
|
38004
|
+
const ids = /* @__PURE__ */ new Set([...observations.keys(), ...traces.keys()]);
|
|
38005
|
+
return [...ids].map((assistantId) => {
|
|
38006
|
+
const observation = observations.get(assistantId) ?? {
|
|
38007
|
+
observations: 0,
|
|
38008
|
+
costUsd: 0,
|
|
38009
|
+
inputTokens: 0,
|
|
38010
|
+
outputTokens: 0,
|
|
38011
|
+
errorCount: 0
|
|
38012
|
+
};
|
|
38013
|
+
const trace = traces.get(assistantId);
|
|
38014
|
+
const bestName = trace ? [...trace.names.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] : void 0;
|
|
38015
|
+
return {
|
|
38016
|
+
assistantId,
|
|
38017
|
+
...bestName ? { name: bestName } : {},
|
|
38018
|
+
calls: trace?.calls ?? 0,
|
|
38019
|
+
observations: observation.observations,
|
|
38020
|
+
costUsd: observation.costUsd,
|
|
38021
|
+
inputTokens: observation.inputTokens,
|
|
38022
|
+
outputTokens: observation.outputTokens,
|
|
38023
|
+
errorCount: observation.errorCount,
|
|
38024
|
+
errorRate: observation.observations > 0 ? observation.errorCount / observation.observations : 0
|
|
38025
|
+
};
|
|
38026
|
+
}).sort(
|
|
38027
|
+
(a, b) => b.calls - a.calls || b.observations - a.observations
|
|
38028
|
+
);
|
|
38029
|
+
}
|
|
38030
|
+
function parseTools(data) {
|
|
38031
|
+
return rowsOf(data).map((row) => ({
|
|
38032
|
+
tool: typeof row.name === "string" && row.name ? row.name : "unknown",
|
|
38033
|
+
count: numberOf(row, "count_count")
|
|
38034
|
+
})).filter((row) => row.count > 0);
|
|
38035
|
+
}
|
|
38036
|
+
function assembleLangfuseDashboard(input) {
|
|
38037
|
+
const warnings = DASHBOARD_SECTIONS.filter(
|
|
38038
|
+
(section) => input.responses[section] === void 0
|
|
38039
|
+
);
|
|
38040
|
+
const tracesSeries = toSeries(input.responses.traces, "count_count");
|
|
38041
|
+
const costSeries = toAggregatedSeries(
|
|
38042
|
+
input.responses.costTokens,
|
|
38043
|
+
"sum_totalCost"
|
|
38044
|
+
);
|
|
38045
|
+
const inputTokenSeries = toAggregatedSeries(
|
|
38046
|
+
input.responses.costTokens,
|
|
38047
|
+
"sum_inputTokens"
|
|
38048
|
+
);
|
|
38049
|
+
const outputTokenSeries = toAggregatedSeries(
|
|
38050
|
+
input.responses.costTokens,
|
|
38051
|
+
"sum_outputTokens"
|
|
38052
|
+
);
|
|
38053
|
+
const latencyP50 = toSeries(input.responses.latency, "p50_latency");
|
|
38054
|
+
const latencyP95 = toSeries(input.responses.latency, "p95_latency");
|
|
38055
|
+
const latencyP99 = toSeries(input.responses.latency, "p99_latency");
|
|
38056
|
+
const errorRateSeries = parseLevelSeries(input.responses.errors);
|
|
38057
|
+
const errorRows = rowsOf(input.responses.errors);
|
|
38058
|
+
const totalObservationCount = errorRows.reduce(
|
|
38059
|
+
(total, row) => total + numberOf(row, "count_count"),
|
|
38060
|
+
0
|
|
38061
|
+
);
|
|
38062
|
+
const totalErrors = errorRows.filter((row) => row.level === "ERROR").reduce((total, row) => total + numberOf(row, "count_count"), 0);
|
|
38063
|
+
const traces = sumSeries(tracesSeries);
|
|
38064
|
+
return {
|
|
38065
|
+
warnings,
|
|
38066
|
+
payload: {
|
|
38067
|
+
samplingRate: input.samplingRate,
|
|
38068
|
+
kpis: {
|
|
38069
|
+
traces,
|
|
38070
|
+
costUsd: sumSeries(costSeries),
|
|
38071
|
+
inputTokens: sumSeries(inputTokenSeries),
|
|
38072
|
+
outputTokens: sumSeries(outputTokenSeries),
|
|
38073
|
+
errorRate: totalObservationCount > 0 ? totalErrors / totalObservationCount : 0
|
|
38074
|
+
},
|
|
38075
|
+
series: {
|
|
38076
|
+
traces: tracesSeries,
|
|
38077
|
+
cost: costSeries,
|
|
38078
|
+
tokens: {
|
|
38079
|
+
input: inputTokenSeries,
|
|
38080
|
+
output: outputTokenSeries
|
|
38081
|
+
},
|
|
38082
|
+
latency: {
|
|
38083
|
+
p50: latencyP50,
|
|
38084
|
+
p95: latencyP95,
|
|
38085
|
+
p99: latencyP99
|
|
38086
|
+
},
|
|
38087
|
+
errorRate: errorRateSeries,
|
|
38088
|
+
toolCalls: toSeries(input.responses.toolCalls, "count_count"),
|
|
38089
|
+
costByModel: parseCostByModel(input.responses.costTokens)
|
|
38090
|
+
},
|
|
38091
|
+
agents: parseAgents(
|
|
38092
|
+
input.responses.agents,
|
|
38093
|
+
input.responses.agentTraces
|
|
38094
|
+
),
|
|
38095
|
+
models: parseModels(input.responses.models),
|
|
38096
|
+
tools: parseTools(input.responses.tools)
|
|
38097
|
+
}
|
|
38098
|
+
};
|
|
38099
|
+
}
|
|
38100
|
+
|
|
38101
|
+
// src/services/observability/LangfuseObservabilityProvider.ts
|
|
38102
|
+
function parseSampleRate(raw) {
|
|
38103
|
+
const trimmed = raw?.trim();
|
|
38104
|
+
if (!trimmed) return 1;
|
|
38105
|
+
const value = Number(trimmed);
|
|
38106
|
+
if (!Number.isFinite(value)) return 1;
|
|
38107
|
+
return Math.min(1, Math.max(0, value));
|
|
38108
|
+
}
|
|
38109
|
+
function readLangfuseConfig(env = process.env) {
|
|
38110
|
+
if (env.LANGFUSE_ENABLED?.trim() !== "true") return void 0;
|
|
38111
|
+
const publicKey = env.LANGFUSE_PUBLIC_KEY?.trim();
|
|
38112
|
+
const secretKey = env.LANGFUSE_SECRET_KEY?.trim();
|
|
38113
|
+
const baseUrl = env.LANGFUSE_BASE_URL?.trim();
|
|
38114
|
+
if (!publicKey || !secretKey || !baseUrl) return void 0;
|
|
38115
|
+
return {
|
|
38116
|
+
publicKey,
|
|
38117
|
+
secretKey,
|
|
38118
|
+
baseUrl,
|
|
38119
|
+
uiUrl: env.LANGFUSE_UI_URL?.trim() || baseUrl,
|
|
38120
|
+
...env.LANGFUSE_RELEASE?.trim() ? { release: env.LANGFUSE_RELEASE.trim() } : {},
|
|
38121
|
+
...env.LANGFUSE_TRACING_ENVIRONMENT?.trim() ? { environment: env.LANGFUSE_TRACING_ENVIRONMENT.trim() } : {},
|
|
38122
|
+
sampleRate: parseSampleRate(env.LANGFUSE_SAMPLE_RATE)
|
|
38123
|
+
};
|
|
38124
|
+
}
|
|
38125
|
+
var USAGE_KEYS = /* @__PURE__ */ new Set([
|
|
38126
|
+
"max_tokens",
|
|
38127
|
+
"input_tokens",
|
|
38128
|
+
"output_tokens",
|
|
38129
|
+
"token_usage"
|
|
38130
|
+
]);
|
|
38131
|
+
var STRONG_SECRET_SUBSTRINGS = [
|
|
38132
|
+
"apikey",
|
|
38133
|
+
"authorization",
|
|
38134
|
+
"secret",
|
|
38135
|
+
"password",
|
|
38136
|
+
"passwd",
|
|
38137
|
+
"privatekey",
|
|
38138
|
+
"credential",
|
|
38139
|
+
"clientkey"
|
|
38140
|
+
];
|
|
38141
|
+
var SECRET_SUBSTRINGS = [...STRONG_SECRET_SUBSTRINGS, "token"];
|
|
38142
|
+
function keyWords(key) {
|
|
38143
|
+
return key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").split(/[^A-Za-z0-9]+/).filter(Boolean).map((word) => word.toLowerCase());
|
|
38144
|
+
}
|
|
38145
|
+
function isSecretKey(key) {
|
|
38146
|
+
const words = keyWords(key);
|
|
38147
|
+
const snake = words.join("_");
|
|
38148
|
+
const compact2 = words.join("");
|
|
38149
|
+
const components = new Set(words);
|
|
38150
|
+
const strongSecret = STRONG_SECRET_SUBSTRINGS.some(
|
|
38151
|
+
(substring) => compact2.includes(substring)
|
|
38152
|
+
) || components.has("private") && components.has("key") || components.has("api") && components.has("key");
|
|
38153
|
+
if (strongSecret) return true;
|
|
38154
|
+
const tokenUsage = components.has("token") && (components.has("count") || components.has("usage") || components.has("details"));
|
|
38155
|
+
if (USAGE_KEYS.has(snake) || snake.endsWith("_tokens") || snake.endsWith("token_usage") || tokenUsage) {
|
|
38156
|
+
return false;
|
|
38157
|
+
}
|
|
38158
|
+
return SECRET_SUBSTRINGS.some((substring) => compact2.includes(substring));
|
|
38159
|
+
}
|
|
38160
|
+
function redactText(value) {
|
|
38161
|
+
return value.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [redacted]").replace(/sk-[A-Za-z0-9_-]{8,}/g, "[redacted]");
|
|
38162
|
+
}
|
|
38163
|
+
function redactString(value) {
|
|
38164
|
+
const first = value.trimStart()[0];
|
|
38165
|
+
if (first === "{" || first === "[" || first === '"') {
|
|
38166
|
+
try {
|
|
38167
|
+
const redacted = JSON.stringify(redactLangfuseValue(JSON.parse(value)));
|
|
38168
|
+
return redacted ?? "null";
|
|
38169
|
+
} catch {
|
|
38170
|
+
}
|
|
38171
|
+
}
|
|
38172
|
+
return redactText(value);
|
|
38173
|
+
}
|
|
38174
|
+
function redactLangfuseValue(value) {
|
|
38175
|
+
if (typeof value === "string") return redactString(value);
|
|
38176
|
+
if (Array.isArray(value)) return value.map(redactLangfuseValue);
|
|
38177
|
+
if (typeof value === "object" && value !== null) {
|
|
38178
|
+
return Object.fromEntries(
|
|
38179
|
+
Object.entries(value).map(([key, nested]) => [
|
|
38180
|
+
key,
|
|
38181
|
+
isSecretKey(key) ? "[redacted]" : redactLangfuseValue(nested)
|
|
38182
|
+
])
|
|
38183
|
+
);
|
|
38184
|
+
}
|
|
38185
|
+
return value;
|
|
38186
|
+
}
|
|
38187
|
+
function tagsFor(context) {
|
|
38188
|
+
return [
|
|
38189
|
+
`tenant:${context.tenantId}`,
|
|
38190
|
+
...context.projectId ? [`project:${context.projectId}`] : [],
|
|
38191
|
+
`assistant:${context.assistantId}`,
|
|
38192
|
+
...context.source ? [`source:${context.source}`] : []
|
|
38193
|
+
];
|
|
38194
|
+
}
|
|
38195
|
+
function traceMetadataFor(context) {
|
|
38196
|
+
return {
|
|
38197
|
+
tenant_id: context.tenantId,
|
|
38198
|
+
...context.projectId ? { project_id: context.projectId } : {},
|
|
38199
|
+
...context.workspaceId ? { workspace_id: context.workspaceId } : {},
|
|
38200
|
+
assistant_id: context.assistantId,
|
|
38201
|
+
thread_id: context.threadId,
|
|
38202
|
+
run_id: context.runId,
|
|
38203
|
+
...context.taskId ? { task_id: context.taskId } : {},
|
|
38204
|
+
...context.source ? { source: context.source } : {}
|
|
38205
|
+
};
|
|
38206
|
+
}
|
|
38207
|
+
function createLangfuseProviderFromEnv(env = process.env, logger9) {
|
|
38208
|
+
const config = readLangfuseConfig(env);
|
|
38209
|
+
return config ? new LangfuseObservabilityProvider(config, logger9) : void 0;
|
|
38210
|
+
}
|
|
38211
|
+
var LangfuseMetricsHttpError = class extends Error {
|
|
38212
|
+
/**
|
|
38213
|
+
* @param status - HTTP status returned by Langfuse.
|
|
38214
|
+
*/
|
|
38215
|
+
constructor(status) {
|
|
38216
|
+
super(`Langfuse metrics request failed with ${status}`);
|
|
38217
|
+
this.status = status;
|
|
38218
|
+
this.name = "LangfuseMetricsHttpError";
|
|
38219
|
+
}
|
|
38220
|
+
};
|
|
38221
|
+
var LangfuseObservabilityProvider = class {
|
|
38222
|
+
/**
|
|
38223
|
+
* @param config - Parsed Langfuse configuration.
|
|
38224
|
+
* @param logger - Optional best-effort lifecycle logger.
|
|
38225
|
+
*/
|
|
38226
|
+
constructor(config, logger9) {
|
|
38227
|
+
this.config = config;
|
|
38228
|
+
this.logger = logger9;
|
|
38229
|
+
this.type = "langfuse";
|
|
38230
|
+
this.capabilities = {
|
|
38231
|
+
autoCallbacks: true,
|
|
38232
|
+
customObservations: false,
|
|
38233
|
+
scores: false,
|
|
38234
|
+
sessions: true,
|
|
38235
|
+
promptManagement: false
|
|
38236
|
+
};
|
|
38237
|
+
}
|
|
38238
|
+
warn(message, error) {
|
|
38239
|
+
try {
|
|
38240
|
+
this.logger?.warn(message, error);
|
|
38241
|
+
} catch {
|
|
38242
|
+
}
|
|
38243
|
+
}
|
|
38244
|
+
/**
|
|
38245
|
+
* Start the OpenTelemetry tracer provider exporting to Langfuse.
|
|
38246
|
+
*
|
|
38247
|
+
* @remarks
|
|
38248
|
+
* Never throws. If construction or registration fails, the provider is
|
|
38249
|
+
* marked not started and any constructed tracer provider is shut down
|
|
38250
|
+
* best-effort.
|
|
38251
|
+
*/
|
|
38252
|
+
async start() {
|
|
38253
|
+
if (this.tracerProvider) return;
|
|
38254
|
+
let provider;
|
|
38255
|
+
let processor;
|
|
38256
|
+
try {
|
|
38257
|
+
processor = new LangfuseSpanProcessor({
|
|
38258
|
+
publicKey: this.config.publicKey,
|
|
38259
|
+
secretKey: this.config.secretKey,
|
|
38260
|
+
baseUrl: this.config.baseUrl,
|
|
38261
|
+
...this.config.release ? { release: this.config.release } : {},
|
|
38262
|
+
...this.config.environment ? { environment: this.config.environment } : {},
|
|
38263
|
+
mask: ({ data }) => redactLangfuseValue(data)
|
|
38264
|
+
});
|
|
38265
|
+
provider = new NodeTracerProvider({ spanProcessors: [processor] });
|
|
38266
|
+
provider.register();
|
|
38267
|
+
this.tracerProvider = provider;
|
|
38268
|
+
} catch (error) {
|
|
38269
|
+
if (provider) {
|
|
38270
|
+
try {
|
|
38271
|
+
await provider.shutdown();
|
|
38272
|
+
} catch (shutdownError) {
|
|
38273
|
+
this.warn(
|
|
38274
|
+
"langfuse observability start cleanup failed",
|
|
38275
|
+
shutdownError
|
|
38276
|
+
);
|
|
38277
|
+
}
|
|
38278
|
+
} else if (processor) {
|
|
38279
|
+
try {
|
|
38280
|
+
await processor.shutdown();
|
|
38281
|
+
} catch (shutdownError) {
|
|
38282
|
+
this.warn(
|
|
38283
|
+
"langfuse observability start cleanup failed",
|
|
38284
|
+
shutdownError
|
|
38285
|
+
);
|
|
38286
|
+
}
|
|
38287
|
+
}
|
|
38288
|
+
this.warn("langfuse observability start failed", error);
|
|
38289
|
+
}
|
|
38290
|
+
}
|
|
38291
|
+
/**
|
|
38292
|
+
* Flush pending spans and shut down the tracer provider.
|
|
38293
|
+
*
|
|
38294
|
+
* @remarks
|
|
38295
|
+
* Never throws and is idempotent. OpenTelemetry has no process-wide
|
|
38296
|
+
* unregister API, so the host must install exactly one provider instance per
|
|
38297
|
+
* process; stopping flushes spans but does not remove the global registration.
|
|
38298
|
+
*/
|
|
38299
|
+
async stop() {
|
|
38300
|
+
const provider = this.tracerProvider;
|
|
38301
|
+
this.tracerProvider = void 0;
|
|
38302
|
+
if (!provider) return;
|
|
38303
|
+
try {
|
|
38304
|
+
await provider.shutdown();
|
|
38305
|
+
} catch (error) {
|
|
38306
|
+
this.warn("langfuse observability stop failed", error);
|
|
38307
|
+
}
|
|
38308
|
+
}
|
|
38309
|
+
/**
|
|
38310
|
+
* Fetches the Langfuse metrics dashboard for one tenant.
|
|
38311
|
+
*
|
|
38312
|
+
* @param input - Time range and server-resolved tenant scope.
|
|
38313
|
+
* @returns The normalized Langfuse payload.
|
|
38314
|
+
* @throws ObservabilityDashboardUnsupportedError for Langfuse < v4.
|
|
38315
|
+
* @throws ObservabilityDashboardUnavailableError when every query fails.
|
|
38316
|
+
*/
|
|
38317
|
+
async getDashboard(input) {
|
|
38318
|
+
const queries = buildDashboardQueries({
|
|
38319
|
+
range: input.range,
|
|
38320
|
+
tenantId: input.tenantId,
|
|
38321
|
+
...this.config.environment ? { environment: this.config.environment } : {}
|
|
38322
|
+
});
|
|
38323
|
+
const settled = await Promise.all(
|
|
38324
|
+
DASHBOARD_SECTIONS.map(async (section) => {
|
|
38325
|
+
try {
|
|
38326
|
+
const data = await this.fetchMetrics(queries[section], section);
|
|
38327
|
+
return { section, data, ok: true };
|
|
38328
|
+
} catch (error) {
|
|
38329
|
+
return { section, error, ok: false };
|
|
38330
|
+
}
|
|
38331
|
+
})
|
|
38332
|
+
);
|
|
38333
|
+
const failures = settled.filter((item) => !item.ok);
|
|
38334
|
+
if (failures.length === settled.length) {
|
|
38335
|
+
if (failures.some(
|
|
38336
|
+
(item) => !item.ok && item.error instanceof LangfuseMetricsHttpError && item.error.status === 404
|
|
38337
|
+
)) {
|
|
38338
|
+
throw new ObservabilityDashboardUnsupportedError2(
|
|
38339
|
+
"Langfuse metrics dashboard requires Langfuse v4+"
|
|
38340
|
+
);
|
|
38341
|
+
}
|
|
38342
|
+
throw new ObservabilityDashboardUnavailableError2(
|
|
38343
|
+
"Langfuse metrics dashboard is unavailable"
|
|
38344
|
+
);
|
|
38345
|
+
}
|
|
38346
|
+
const responses = {};
|
|
38347
|
+
for (const item of settled) {
|
|
38348
|
+
if (item.ok) responses[item.section] = item.data;
|
|
38349
|
+
}
|
|
38350
|
+
const assembled = assembleLangfuseDashboard({
|
|
38351
|
+
responses,
|
|
38352
|
+
samplingRate: this.config.sampleRate
|
|
38353
|
+
});
|
|
38354
|
+
return {
|
|
38355
|
+
version: LANGFUSE_OBSERVABILITY_DASHBOARD_VERSION,
|
|
38356
|
+
...assembled.warnings.length > 0 ? { warnings: assembled.warnings } : {},
|
|
38357
|
+
payload: {
|
|
38358
|
+
...assembled.payload,
|
|
38359
|
+
...this.config.environment ? { environment: this.config.environment } : {}
|
|
38360
|
+
}
|
|
38361
|
+
};
|
|
38362
|
+
}
|
|
38363
|
+
async fetchMetrics(query, section) {
|
|
38364
|
+
const base = this.config.baseUrl.replace(/\/+$/, "");
|
|
38365
|
+
const path5 = V1_METRICS_SECTIONS.has(section) ? "/api/public/metrics" : "/api/public/v2/metrics";
|
|
38366
|
+
let url = new URL(`${base}${path5}`);
|
|
38367
|
+
url.searchParams.set("query", JSON.stringify(query));
|
|
38368
|
+
const auth = Buffer2.from(
|
|
38369
|
+
`${this.config.publicKey}:${this.config.secretKey}`
|
|
38370
|
+
).toString("base64");
|
|
38371
|
+
const headers = {
|
|
38372
|
+
Authorization: `Basic ${auth}`,
|
|
38373
|
+
Accept: "application/json"
|
|
38374
|
+
};
|
|
38375
|
+
const signal = AbortSignal.timeout(1e4);
|
|
38376
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
38377
|
+
const response = await fetch(url, {
|
|
38378
|
+
headers,
|
|
38379
|
+
redirect: "manual",
|
|
38380
|
+
signal
|
|
38381
|
+
});
|
|
38382
|
+
if (response.status >= 300 && response.status < 400) {
|
|
38383
|
+
const location = response.headers.get("location");
|
|
38384
|
+
if (!location) throw new LangfuseMetricsHttpError(response.status);
|
|
38385
|
+
const next = new URL(location, url);
|
|
38386
|
+
if (next.protocol !== "http:" && next.protocol !== "https:") {
|
|
38387
|
+
throw new LangfuseMetricsHttpError(response.status);
|
|
38388
|
+
}
|
|
38389
|
+
url = next;
|
|
38390
|
+
continue;
|
|
38391
|
+
}
|
|
38392
|
+
if (!response.ok) throw new LangfuseMetricsHttpError(response.status);
|
|
38393
|
+
return response.json();
|
|
38394
|
+
}
|
|
38395
|
+
throw new LangfuseMetricsHttpError(508);
|
|
38396
|
+
}
|
|
38397
|
+
/**
|
|
38398
|
+
* Create a Langfuse callback handler for one invocation.
|
|
38399
|
+
*
|
|
38400
|
+
* @param context - Correlation fields for the running Agent invocation.
|
|
38401
|
+
* @returns One callback handler, or an empty list before start or when
|
|
38402
|
+
* sampled out.
|
|
38403
|
+
*/
|
|
38404
|
+
createCallbacks(context) {
|
|
38405
|
+
if (!this.tracerProvider) return [];
|
|
38406
|
+
if (this.config.sampleRate <= 0) return [];
|
|
38407
|
+
if (this.config.sampleRate < 1 && Math.random() >= this.config.sampleRate) {
|
|
38408
|
+
return [];
|
|
38409
|
+
}
|
|
38410
|
+
return [
|
|
38411
|
+
new CallbackHandler({
|
|
38412
|
+
sessionId: context.threadId,
|
|
38413
|
+
userId: context.userId,
|
|
38414
|
+
tags: tagsFor(context),
|
|
38415
|
+
traceMetadata: traceMetadataFor(context),
|
|
38416
|
+
...this.config.release ? { version: this.config.release } : {}
|
|
38417
|
+
})
|
|
38418
|
+
];
|
|
38419
|
+
}
|
|
38420
|
+
/**
|
|
38421
|
+
* @returns The configured Langfuse UI trace-list URL.
|
|
38422
|
+
*/
|
|
38423
|
+
getTraceListUrl() {
|
|
38424
|
+
return this.config.uiUrl;
|
|
38425
|
+
}
|
|
38426
|
+
};
|
|
38427
|
+
|
|
38428
|
+
// src/index.ts
|
|
37003
38429
|
process.on("unhandledRejection", (reason, promise) => {
|
|
37004
38430
|
console.error("\u672A\u5904\u7406\u7684Promise\u62D2\u7EDD:", reason);
|
|
37005
38431
|
});
|
|
@@ -37011,7 +38437,7 @@ var DEFAULT_LOGGER_CONFIG = {
|
|
|
37011
38437
|
loggerName: "lattice/gateway"
|
|
37012
38438
|
};
|
|
37013
38439
|
var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
|
|
37014
|
-
var
|
|
38440
|
+
var logger8 = loggerLattice.client;
|
|
37015
38441
|
function initializeLogger(config) {
|
|
37016
38442
|
if (loggerLatticeManager.hasLattice("default")) {
|
|
37017
38443
|
loggerLatticeManager.removeLattice("default");
|
|
@@ -37021,7 +38447,7 @@ function initializeLogger(config) {
|
|
|
37021
38447
|
}
|
|
37022
38448
|
var app = fastify({
|
|
37023
38449
|
logger: false,
|
|
37024
|
-
bodyLimit: Number(process.env.BODY_LIMIT) ||
|
|
38450
|
+
bodyLimit: Number(process.env.BODY_LIMIT) || 500 * 1024 * 1024,
|
|
37025
38451
|
// Composite subagent thread IDs ({mainThread}____{assistant}-general-purpose_{toolCallId})
|
|
37026
38452
|
// can exceed the 100-char default, which makes the router 404 before any
|
|
37027
38453
|
// handler runs. Allow the longest IDs the conventions can produce.
|
|
@@ -37081,6 +38507,7 @@ app.register(cors, {
|
|
|
37081
38507
|
exposedHeaders: [
|
|
37082
38508
|
"Content-Type",
|
|
37083
38509
|
"Content-Disposition",
|
|
38510
|
+
"A2A-Version",
|
|
37084
38511
|
REPLICA_HEADER3,
|
|
37085
38512
|
AFFINITY_ECHO_HEADER3
|
|
37086
38513
|
],
|
|
@@ -37089,7 +38516,7 @@ app.register(cors, {
|
|
|
37089
38516
|
app.register(sensible);
|
|
37090
38517
|
app.register(multipart, {
|
|
37091
38518
|
limits: {
|
|
37092
|
-
fileSize: Number(process.env.BODY_LIMIT) ||
|
|
38519
|
+
fileSize: Number(process.env.BODY_LIMIT) || 500 * 1024 * 1024
|
|
37093
38520
|
}
|
|
37094
38521
|
});
|
|
37095
38522
|
app.register(staticPlugin, {
|
|
@@ -37102,7 +38529,7 @@ app.setErrorHandler((error, request, reply) => {
|
|
|
37102
38529
|
"x-request-id": getHeaderValue(request.headers["x-request-id"]),
|
|
37103
38530
|
"x-user-id": getHeaderValue(request.headers["x-user-id"])
|
|
37104
38531
|
};
|
|
37105
|
-
|
|
38532
|
+
logger8.error(
|
|
37106
38533
|
`\u8BF7\u6C42\u9519\u8BEF: ${request.method} ${request.url} error:${error.message}`,
|
|
37107
38534
|
{
|
|
37108
38535
|
...context,
|
|
@@ -37135,17 +38562,17 @@ function getConfiguredSandboxProvider() {
|
|
|
37135
38562
|
}
|
|
37136
38563
|
async function restoreMcpConnections() {
|
|
37137
38564
|
try {
|
|
37138
|
-
const storeLattice =
|
|
38565
|
+
const storeLattice = getStoreLattice42("default", "mcp");
|
|
37139
38566
|
const store2 = storeLattice.store;
|
|
37140
38567
|
if (!store2) {
|
|
37141
|
-
|
|
38568
|
+
logger8.info("MCP store not configured, skipping connection restoration");
|
|
37142
38569
|
return;
|
|
37143
38570
|
}
|
|
37144
38571
|
const configs = (await store2.getAllConfigsWithoutTenant()).filter(
|
|
37145
38572
|
(c2) => c2.status === "connected"
|
|
37146
38573
|
);
|
|
37147
38574
|
if (configs.length === 0) return;
|
|
37148
|
-
|
|
38575
|
+
logger8.info(`Restoring ${configs.length} MCP server connections...`);
|
|
37149
38576
|
const deps = {
|
|
37150
38577
|
store: store2,
|
|
37151
38578
|
manager: mcpManager3,
|
|
@@ -37162,15 +38589,15 @@ async function restoreMcpConnections() {
|
|
|
37162
38589
|
results.forEach((result, index) => {
|
|
37163
38590
|
if (result.status === "rejected") {
|
|
37164
38591
|
const config = configs[index];
|
|
37165
|
-
|
|
38592
|
+
logger8.warn(
|
|
37166
38593
|
`Failed to restore MCP server "${config.tenantId}/${config.key}"`,
|
|
37167
38594
|
{ error: result.reason }
|
|
37168
38595
|
);
|
|
37169
38596
|
}
|
|
37170
38597
|
});
|
|
37171
|
-
|
|
38598
|
+
logger8.info(`MCP connection restoration complete: ${configs.length} servers`);
|
|
37172
38599
|
} catch (err) {
|
|
37173
|
-
|
|
38600
|
+
logger8.error("MCP connection restoration failed", { error: err });
|
|
37174
38601
|
}
|
|
37175
38602
|
}
|
|
37176
38603
|
var start = async (config) => {
|
|
@@ -37183,16 +38610,37 @@ var start = async (config) => {
|
|
|
37183
38610
|
file: config.loggerConfig.file || DEFAULT_LOGGER_CONFIG.file
|
|
37184
38611
|
};
|
|
37185
38612
|
loggerLattice = initializeLogger(loggerConfig);
|
|
37186
|
-
|
|
38613
|
+
logger8 = loggerLattice.client;
|
|
37187
38614
|
}
|
|
37188
38615
|
app.decorate("loggerLattice", loggerLattice);
|
|
38616
|
+
const observabilityProvider = observabilityLatticeManager.getDefault();
|
|
38617
|
+
if (observabilityProvider) {
|
|
38618
|
+
try {
|
|
38619
|
+
await observabilityProvider.start?.();
|
|
38620
|
+
} catch (error) {
|
|
38621
|
+
logger8.warn("Observability provider failed to start", {
|
|
38622
|
+
error: error instanceof Error ? error.message : String(error)
|
|
38623
|
+
});
|
|
38624
|
+
}
|
|
38625
|
+
app.addHook("onClose", async () => {
|
|
38626
|
+
try {
|
|
38627
|
+
await observabilityProvider.stop?.();
|
|
38628
|
+
} catch (error) {
|
|
38629
|
+
logger8.warn("Observability provider failed to stop", {
|
|
38630
|
+
error: error instanceof Error ? error.message : String(error)
|
|
38631
|
+
});
|
|
38632
|
+
}
|
|
38633
|
+
});
|
|
38634
|
+
}
|
|
37189
38635
|
let executionSupervisor;
|
|
37190
38636
|
let runTaskRuntime;
|
|
37191
38637
|
let runTaskWake;
|
|
37192
38638
|
let agentRunRetentionJob;
|
|
38639
|
+
let scheduleReconcileTimer;
|
|
38640
|
+
const channelLeaders = [];
|
|
37193
38641
|
let runLedger;
|
|
37194
38642
|
try {
|
|
37195
|
-
runLedger =
|
|
38643
|
+
runLedger = getStoreLattice42("default", "agentRun").store;
|
|
37196
38644
|
} catch {
|
|
37197
38645
|
}
|
|
37198
38646
|
if (runLedger) agentInstanceManager13.setRunLedger(runLedger);
|
|
@@ -37220,7 +38668,7 @@ var start = async (config) => {
|
|
|
37220
38668
|
chunkSourceHandle = await createRedisAppendLog(redisUrl, {
|
|
37221
38669
|
keyPrefix: chunkKeyPrefix,
|
|
37222
38670
|
logger: {
|
|
37223
|
-
warn: (message, context) =>
|
|
38671
|
+
warn: (message, context) => logger8.warn(message, context)
|
|
37224
38672
|
}
|
|
37225
38673
|
});
|
|
37226
38674
|
const sharedBuffer = new SharedChunkBuffer2({
|
|
@@ -37234,7 +38682,7 @@ var start = async (config) => {
|
|
|
37234
38682
|
chunkBufferManager.remove("default");
|
|
37235
38683
|
}
|
|
37236
38684
|
registerChunkBuffer("default", sharedBuffer);
|
|
37237
|
-
|
|
38685
|
+
logger8.info("Shared Redis chunk source enabled", {
|
|
37238
38686
|
phase: "chunk_source",
|
|
37239
38687
|
ttlMs,
|
|
37240
38688
|
maxLen
|
|
@@ -37246,7 +38694,7 @@ var start = async (config) => {
|
|
|
37246
38694
|
if (runLedger) {
|
|
37247
38695
|
runCancelNotifier = createRedisRunCancelNotifier({
|
|
37248
38696
|
url: runCancelRedisUrl,
|
|
37249
|
-
owner:
|
|
38697
|
+
owner: getReplicaId12(),
|
|
37250
38698
|
ledger: runLedger,
|
|
37251
38699
|
resolveAgent: (params) => (
|
|
37252
38700
|
// Never use getAgent() here: creating an idle instance lets its
|
|
@@ -37254,14 +38702,14 @@ var start = async (config) => {
|
|
|
37254
38702
|
resolveManagedRunCancelAgent(agentInstanceManager13, params)
|
|
37255
38703
|
),
|
|
37256
38704
|
logger: {
|
|
37257
|
-
warn: (message, context) =>
|
|
37258
|
-
info: (message, context) =>
|
|
38705
|
+
warn: (message, context) => logger8.warn(message, context),
|
|
38706
|
+
info: (message, context) => logger8.info(message, context)
|
|
37259
38707
|
}
|
|
37260
38708
|
});
|
|
37261
38709
|
try {
|
|
37262
38710
|
await runCancelNotifier.start();
|
|
37263
38711
|
} catch (error) {
|
|
37264
|
-
|
|
38712
|
+
logger8.warn("Run cancel subscriber failed to start", {
|
|
37265
38713
|
error: error instanceof Error ? error.message : String(error)
|
|
37266
38714
|
});
|
|
37267
38715
|
}
|
|
@@ -37269,13 +38717,13 @@ var start = async (config) => {
|
|
|
37269
38717
|
ledger: runLedger,
|
|
37270
38718
|
notifier: runCancelNotifier,
|
|
37271
38719
|
logger: {
|
|
37272
|
-
warn: (message, context) =>
|
|
38720
|
+
warn: (message, context) => logger8.warn(message, context)
|
|
37273
38721
|
}
|
|
37274
38722
|
}));
|
|
37275
38723
|
} else {
|
|
37276
|
-
|
|
38724
|
+
logger8.warn(
|
|
37277
38725
|
"Run cancel subscription disabled: the agent run ledger is not configured",
|
|
37278
|
-
{ owner:
|
|
38726
|
+
{ owner: getReplicaId12() }
|
|
37279
38727
|
);
|
|
37280
38728
|
}
|
|
37281
38729
|
}
|
|
@@ -37287,7 +38735,7 @@ var start = async (config) => {
|
|
|
37287
38735
|
),
|
|
37288
38736
|
keyPrefix: chunkKeyPrefix,
|
|
37289
38737
|
logger: {
|
|
37290
|
-
warn: (message, context) =>
|
|
38738
|
+
warn: (message, context) => logger8.warn(message, context)
|
|
37291
38739
|
}
|
|
37292
38740
|
});
|
|
37293
38741
|
setInterruptAnswerRegistry(interruptAnswerRegistry);
|
|
@@ -37295,10 +38743,10 @@ var start = async (config) => {
|
|
|
37295
38743
|
let projectRoomRealtimeRuntime;
|
|
37296
38744
|
if (projectRoomRealtimeMode === "single-gateway") {
|
|
37297
38745
|
projectRoomRealtimeRuntime = createProjectRoomRealtimeRuntime({
|
|
37298
|
-
tasks:
|
|
37299
|
-
rooms:
|
|
37300
|
-
memberships:
|
|
37301
|
-
log: { warn: (message, context) =>
|
|
38746
|
+
tasks: getStoreLattice42("default", "task").store,
|
|
38747
|
+
rooms: getStoreLattice42("default", "projectRoom").store,
|
|
38748
|
+
memberships: getStoreLattice42("default", "projectBotMembership").store,
|
|
38749
|
+
log: { warn: (message, context) => logger8.warn(message, context) }
|
|
37302
38750
|
});
|
|
37303
38751
|
}
|
|
37304
38752
|
let channelDeps;
|
|
@@ -37306,14 +38754,14 @@ var start = async (config) => {
|
|
|
37306
38754
|
adapterRegistry.register(larkChannelAdapter);
|
|
37307
38755
|
adapterRegistry.register(wecomChannelAdapter);
|
|
37308
38756
|
registerWecomCardTool();
|
|
37309
|
-
const { wechatChannelAdapter } = await import("./WechatChannelAdapter-
|
|
38757
|
+
const { wechatChannelAdapter } = await import("./WechatChannelAdapter-QLPJJD6S.mjs");
|
|
37310
38758
|
adapterRegistry.register(wechatChannelAdapter);
|
|
37311
38759
|
const durableChannelRuns = process.env.CHANNEL_DURABLE_RUNS !== "false";
|
|
37312
38760
|
let channelReplyDispatcher;
|
|
37313
38761
|
try {
|
|
37314
38762
|
const infrastructure = createChannelInfrastructure({
|
|
37315
38763
|
adapterRegistry,
|
|
37316
|
-
getStore: ((kind) =>
|
|
38764
|
+
getStore: ((kind) => getStoreLattice42("default", kind).store),
|
|
37317
38765
|
trustedDispatcher: createTrustedAgentMessageDispatcher2((scope) => agentInstanceManager13.getAgent(scope)),
|
|
37318
38766
|
middlewares: [
|
|
37319
38767
|
createDeduplicationMiddleware(),
|
|
@@ -37321,7 +38769,7 @@ var start = async (config) => {
|
|
|
37321
38769
|
createAuditLoggerMiddleware()
|
|
37322
38770
|
],
|
|
37323
38771
|
durableChannelRuns,
|
|
37324
|
-
warn: (message, context) =>
|
|
38772
|
+
warn: (message, context) => logger8.warn(message, context),
|
|
37325
38773
|
realtime: projectRoomRealtimeRuntime?.publisher
|
|
37326
38774
|
});
|
|
37327
38775
|
const bindingStore = infrastructure.bindingRegistry;
|
|
@@ -37335,25 +38783,25 @@ var start = async (config) => {
|
|
|
37335
38783
|
installationStore,
|
|
37336
38784
|
bindingRegistry: bindingStore,
|
|
37337
38785
|
realtime: projectRoomRealtimeRuntime?.publisher,
|
|
37338
|
-
warn: (message, context) =>
|
|
38786
|
+
warn: (message, context) => logger8.warn(message, context)
|
|
37339
38787
|
};
|
|
37340
38788
|
} catch (err) {
|
|
37341
|
-
|
|
38789
|
+
logger8.warn("Channel infrastructure unavailable", {
|
|
37342
38790
|
error: err instanceof Error ? err.message : String(err)
|
|
37343
38791
|
});
|
|
37344
38792
|
}
|
|
37345
38793
|
if (channelDeps && durableChannelRuns) {
|
|
37346
38794
|
try {
|
|
37347
38795
|
channelReplyDispatcher = new ChannelReplyDispatcher({
|
|
37348
|
-
jobStore:
|
|
37349
|
-
runLedger:
|
|
38796
|
+
jobStore: getStoreLattice42("default", "channelReplyJob").store,
|
|
38797
|
+
runLedger: getStoreLattice42("default", "agentRun").store,
|
|
37350
38798
|
loadFinalReplyText: createCheckpointFinalReplyLoader(),
|
|
37351
38799
|
adapterRegistry: channelDeps.adapterRegistry,
|
|
37352
38800
|
installationStore: channelDeps.installationStore,
|
|
37353
|
-
owner:
|
|
38801
|
+
owner: getReplicaId12(),
|
|
37354
38802
|
logger: {
|
|
37355
|
-
info: (message, context) =>
|
|
37356
|
-
warn: (message, context) =>
|
|
38803
|
+
info: (message, context) => logger8.info(message, context),
|
|
38804
|
+
warn: (message, context) => logger8.warn(message, context)
|
|
37357
38805
|
}
|
|
37358
38806
|
});
|
|
37359
38807
|
const dispatcher = channelReplyDispatcher;
|
|
@@ -37363,38 +38811,54 @@ var start = async (config) => {
|
|
|
37363
38811
|
await dispatcher.stop();
|
|
37364
38812
|
});
|
|
37365
38813
|
dispatcher.start();
|
|
37366
|
-
|
|
38814
|
+
logger8.info("Durable channel replies enabled", { owner: getReplicaId12() });
|
|
37367
38815
|
} catch (err) {
|
|
37368
|
-
|
|
38816
|
+
logger8.warn("Durable channel replies unavailable", {
|
|
37369
38817
|
error: err instanceof Error ? err.message : String(err)
|
|
37370
38818
|
});
|
|
37371
38819
|
}
|
|
37372
38820
|
}
|
|
37373
38821
|
setEvalRunService(evalRunner);
|
|
37374
38822
|
try {
|
|
37375
|
-
const menuStore =
|
|
38823
|
+
const menuStore = getStoreLattice42("default", "menu").store;
|
|
37376
38824
|
setMenuRegistry(menuStore);
|
|
37377
|
-
|
|
38825
|
+
logger8.info("Menu registry initialized");
|
|
37378
38826
|
} catch {
|
|
37379
38827
|
}
|
|
37380
38828
|
registerAllBuiltinEntities();
|
|
37381
38829
|
if (channelDeps?.router) {
|
|
37382
|
-
setChannelControllerDeps({
|
|
38830
|
+
setChannelControllerDeps({
|
|
38831
|
+
adapterRegistry,
|
|
38832
|
+
router: channelDeps.router,
|
|
38833
|
+
onInstallationChanged: async ({ tenantId, installationId }) => {
|
|
38834
|
+
try {
|
|
38835
|
+
const outbox = getStoreLattice42("default", "outbox").store;
|
|
38836
|
+
await publishChannelInstallationChanged(outbox, getReplicaId12(), {
|
|
38837
|
+
tenantId,
|
|
38838
|
+
installationId
|
|
38839
|
+
});
|
|
38840
|
+
} catch (err) {
|
|
38841
|
+
logger8.warn("Channel installation change wake failed", {
|
|
38842
|
+
error: err instanceof Error ? err.message : String(err)
|
|
38843
|
+
});
|
|
38844
|
+
}
|
|
38845
|
+
}
|
|
38846
|
+
});
|
|
37383
38847
|
}
|
|
37384
38848
|
await app.register(websocket);
|
|
37385
38849
|
const routes = registerLatticeRoutes(app, channelDeps, {
|
|
37386
38850
|
projectTaskEnabled: process.env.AXIOM_PROJECT_TASK_EXECUTION_ENABLED !== "false",
|
|
37387
|
-
projectTaskLog: { warn: (message, context) =>
|
|
38851
|
+
projectTaskLog: { warn: (message, context) => logger8.warn(message, context) },
|
|
37388
38852
|
projectRoomRealtimeRuntime
|
|
37389
38853
|
});
|
|
37390
38854
|
try {
|
|
37391
38855
|
const { A2AAuthService: A2AAuthService2, parseEnvKeys: parseEnvKeys2 } = await import("./A2AAuthService-7UGQ7GMW.mjs");
|
|
37392
|
-
const { registerA2AStandardRoutes } = await import("./a2a-standard-
|
|
38856
|
+
const { registerA2AStandardRoutes } = await import("./a2a-standard-VL5I7B4W.mjs");
|
|
37393
38857
|
const a2a = await import("./a2a-BHBLACJV.mjs");
|
|
37394
|
-
const a2aKeyStore =
|
|
37395
|
-
const assistantStore =
|
|
37396
|
-
const projectStore =
|
|
37397
|
-
const taskStore =
|
|
38858
|
+
const a2aKeyStore = getStoreLattice42("default", "a2aApiKey").store;
|
|
38859
|
+
const assistantStore = getStoreLattice42("default", "assistant").store;
|
|
38860
|
+
const projectStore = getStoreLattice42("default", "project").store;
|
|
38861
|
+
const taskStore = getStoreLattice42("default", "task").store;
|
|
37398
38862
|
const authService = new A2AAuthService2({
|
|
37399
38863
|
keyStore: a2aKeyStore,
|
|
37400
38864
|
assistantStore,
|
|
@@ -37412,19 +38876,19 @@ var start = async (config) => {
|
|
|
37412
38876
|
getProjectStore: () => projectStore
|
|
37413
38877
|
});
|
|
37414
38878
|
a2a.registerA2ARoutes(app);
|
|
37415
|
-
|
|
38879
|
+
logger8.info("A2A standard routes registered");
|
|
37416
38880
|
} catch (err) {
|
|
37417
|
-
|
|
38881
|
+
logger8.warn("A2A standard routes unavailable", {
|
|
37418
38882
|
error: err instanceof Error ? err.message : String(err)
|
|
37419
38883
|
});
|
|
37420
38884
|
}
|
|
37421
38885
|
try {
|
|
37422
|
-
const { registerOpenRoutes } = await import("./open-
|
|
38886
|
+
const { registerOpenRoutes } = await import("./open-7ED27I5B.mjs");
|
|
37423
38887
|
const { registerOpenSessionRoutes } = await import("./open-session-2Y7XJJW2.mjs");
|
|
37424
38888
|
const { registerOpenCatalogRoutes } = await import("./open-catalog-SZQ435AY.mjs");
|
|
37425
38889
|
const { registerOpenFilesRoutes } = await import("./open-files-V3R2BFTV.mjs");
|
|
37426
38890
|
const { registerOpenAuditRoutes } = await import("./open-audit-UJ3NXCGW.mjs");
|
|
37427
|
-
const { registerOpenExposureRoutes } = await import("./open-exposure-
|
|
38891
|
+
const { registerOpenExposureRoutes } = await import("./open-exposure-I3DN2X4E.mjs");
|
|
37428
38892
|
const { openLattice } = await import("./openLattice-Q6M5S6CY.mjs");
|
|
37429
38893
|
const { OpenRateLimiter } = await import("./openRateLimiter-XEOL3A5G.mjs");
|
|
37430
38894
|
const { createKbProvider } = await import("./kbProvider-2D6DZ34N.mjs");
|
|
@@ -37434,8 +38898,8 @@ var start = async (config) => {
|
|
|
37434
38898
|
const { CollectionService: CollectionService2 } = await import("./collection_service-RTRJEQFL.mjs");
|
|
37435
38899
|
openLattice.register(createKbProvider(new CollectionService2()));
|
|
37436
38900
|
openLattice.register(createOpenSandboxProvider());
|
|
37437
|
-
const threadStore =
|
|
37438
|
-
const assistantStore =
|
|
38901
|
+
const threadStore = getStoreLattice42("default", "thread").store;
|
|
38902
|
+
const assistantStore = getStoreLattice42("default", "assistant").store;
|
|
37439
38903
|
openLattice.register(
|
|
37440
38904
|
createAgentProvider({
|
|
37441
38905
|
threadStore,
|
|
@@ -37463,32 +38927,32 @@ var start = async (config) => {
|
|
|
37463
38927
|
registerOpenFilesRoutes(app);
|
|
37464
38928
|
registerOpenAuditRoutes(app);
|
|
37465
38929
|
registerOpenExposureRoutes(app);
|
|
37466
|
-
|
|
38930
|
+
logger8.info("Open API routes registered (kb + sandbox providers, session exchange)");
|
|
37467
38931
|
} catch (err) {
|
|
37468
|
-
|
|
38932
|
+
logger8.warn("Open API routes unavailable", {
|
|
37469
38933
|
error: err instanceof Error ? err.message : String(err)
|
|
37470
38934
|
});
|
|
37471
38935
|
}
|
|
37472
38936
|
try {
|
|
37473
38937
|
const { registerGatewaySandboxOpenCredentialProvider } = await import("./sandboxOpenCredentialProvider-AT227D4N.mjs");
|
|
37474
38938
|
registerGatewaySandboxOpenCredentialProvider((error) => {
|
|
37475
|
-
|
|
38939
|
+
logger8.warn("sandbox open-credential provider failed", { error });
|
|
37476
38940
|
});
|
|
37477
|
-
|
|
38941
|
+
logger8.info("Sandbox open-credential provider registered");
|
|
37478
38942
|
} catch (err) {
|
|
37479
|
-
|
|
38943
|
+
logger8.warn("Sandbox open-credential provider unavailable", {
|
|
37480
38944
|
error: err instanceof Error ? err.message : String(err)
|
|
37481
38945
|
});
|
|
37482
38946
|
}
|
|
37483
38947
|
if (!sandboxLatticeManager2.hasLattice("default")) {
|
|
37484
38948
|
sandboxLatticeManager2.registerLattice("default", getConfiguredSandboxProvider());
|
|
37485
|
-
|
|
38949
|
+
logger8.info("Registered sandbox manager from env configuration");
|
|
37486
38950
|
}
|
|
37487
38951
|
if (isPluginDeploymentRuntimeEnabled()) {
|
|
37488
38952
|
try {
|
|
37489
|
-
const pluginDeploymentStore =
|
|
37490
|
-
const tenantStore =
|
|
37491
|
-
const leaseStore2 =
|
|
38953
|
+
const pluginDeploymentStore = getStoreLattice42("default", "pluginDeployment").store;
|
|
38954
|
+
const tenantStore = getStoreLattice42("default", "tenant").store;
|
|
38955
|
+
const leaseStore2 = getStoreLattice42("default", "lease").store;
|
|
37492
38956
|
const listAllDeployments = async () => {
|
|
37493
38957
|
const tenants = await tenantStore.getAllTenants();
|
|
37494
38958
|
const lists = await Promise.all(
|
|
@@ -37509,90 +38973,112 @@ var start = async (config) => {
|
|
|
37509
38973
|
listAllDeployments,
|
|
37510
38974
|
// The service logs fields-first; the gateway logger is message-first.
|
|
37511
38975
|
logger: {
|
|
37512
|
-
info: (fields, message) =>
|
|
37513
|
-
warn: (fields, message) =>
|
|
37514
|
-
error: (fields, message) =>
|
|
38976
|
+
info: (fields, message) => logger8.info(message ?? "plugin deployment", fields),
|
|
38977
|
+
warn: (fields, message) => logger8.warn(message ?? "plugin deployment", fields),
|
|
38978
|
+
error: (fields, message) => logger8.error(message ?? "plugin deployment", fields)
|
|
37515
38979
|
}
|
|
37516
38980
|
},
|
|
37517
38981
|
lease: leaseStore2,
|
|
37518
|
-
holder:
|
|
37519
|
-
logger:
|
|
38982
|
+
holder: getReplicaId12(),
|
|
38983
|
+
logger: logger8
|
|
37520
38984
|
});
|
|
37521
38985
|
app.addHook("onClose", async () => {
|
|
37522
38986
|
await pluginDeploymentRuntime.dispose();
|
|
37523
38987
|
});
|
|
37524
|
-
|
|
38988
|
+
logger8.info("Plugin deployment runtime started");
|
|
37525
38989
|
} catch (err) {
|
|
37526
|
-
|
|
38990
|
+
logger8.warn("Plugin deployment runtime unavailable", {
|
|
37527
38991
|
error: err instanceof Error ? err.message : String(err)
|
|
37528
38992
|
});
|
|
37529
38993
|
}
|
|
37530
38994
|
}
|
|
37531
38995
|
try {
|
|
37532
38996
|
const { ResourceController } = await import("./resources-DAU5ZIPB.mjs");
|
|
37533
|
-
const sharedResourceStore =
|
|
38997
|
+
const sharedResourceStore = getStoreLattice42("default", "sharedResource").store;
|
|
37534
38998
|
const cache = new TokenCache();
|
|
37535
38999
|
const resourceController = new ResourceController({
|
|
37536
39000
|
store: sharedResourceStore,
|
|
37537
39001
|
sandboxManager: sandboxLatticeManager2,
|
|
37538
39002
|
cache,
|
|
37539
|
-
logger:
|
|
39003
|
+
logger: logger8
|
|
37540
39004
|
});
|
|
37541
39005
|
registerResourceRoutes(app, resourceController);
|
|
37542
|
-
|
|
39006
|
+
logger8.info("Resource share routes registered");
|
|
37543
39007
|
} catch (err) {
|
|
37544
|
-
|
|
39008
|
+
logger8.warn("Resource share infrastructure unavailable", {
|
|
37545
39009
|
error: err instanceof Error ? err.message : String(err)
|
|
37546
39010
|
});
|
|
37547
39011
|
}
|
|
37548
39012
|
if (channelDeps && process.env.CHANNELS_ENABLED !== "false") {
|
|
37549
39013
|
try {
|
|
37550
|
-
const
|
|
37551
|
-
|
|
37552
|
-
|
|
37553
|
-
|
|
37554
|
-
|
|
37555
|
-
|
|
37556
|
-
|
|
37557
|
-
|
|
37558
|
-
|
|
39014
|
+
const shardCount = parsePositiveInteger2(process.env.CHANNEL_SHARDS, 1);
|
|
39015
|
+
const leaseStore2 = getStoreLattice42("default", "lease").store;
|
|
39016
|
+
const installationStore = getStoreLattice42("default", "channelInstallation").store;
|
|
39017
|
+
for (let shard = 0; shard < shardCount; shard += 1) {
|
|
39018
|
+
const leader = new ChannelConnectionLeader({
|
|
39019
|
+
leaseStore: leaseStore2,
|
|
39020
|
+
owner: getReplicaId12(),
|
|
39021
|
+
shard,
|
|
39022
|
+
shardCount,
|
|
39023
|
+
loadDesired: () => installationStore.getAllInstallations(),
|
|
39024
|
+
connectInstallation: async (installation) => {
|
|
39025
|
+
const adapter = adapterRegistry.get(installation.channel);
|
|
39026
|
+
await adapter?.connect?.(installation, { router: channelDeps.router });
|
|
39027
|
+
},
|
|
39028
|
+
disconnectInstallation: async (installation) => {
|
|
39029
|
+
const adapter = adapterRegistry.get(installation.channel);
|
|
39030
|
+
await adapter?.disconnect?.(installation.id);
|
|
39031
|
+
},
|
|
39032
|
+
fingerprint: (installation) => JSON.stringify({
|
|
39033
|
+
channel: installation.channel,
|
|
39034
|
+
config: installation.config,
|
|
39035
|
+
fallbackAgentId: installation.fallbackAgentId,
|
|
39036
|
+
rejectWhenNoBinding: installation.rejectWhenNoBinding
|
|
39037
|
+
}),
|
|
39038
|
+
log: { warn: (message, context) => logger8.warn(message, context) }
|
|
39039
|
+
});
|
|
39040
|
+
channelLeaders.push(leader);
|
|
39041
|
+
leader.start();
|
|
39042
|
+
}
|
|
37559
39043
|
app.addHook("onClose", async () => {
|
|
37560
|
-
await
|
|
39044
|
+
await Promise.all(channelLeaders.map((leader) => leader.stop()));
|
|
37561
39045
|
});
|
|
37562
|
-
channelLeader.start();
|
|
37563
39046
|
} catch (err) {
|
|
37564
|
-
|
|
39047
|
+
logger8.error("Failed to start channel connections", {
|
|
37565
39048
|
error: err instanceof Error ? err.message : String(err)
|
|
37566
39049
|
});
|
|
37567
39050
|
}
|
|
37568
39051
|
}
|
|
37569
39052
|
const target_port = config?.port || Number(process.env.PORT) || 4001;
|
|
37570
|
-
configureCoordinationLeaseStore(
|
|
37571
|
-
const outboxStore =
|
|
39053
|
+
configureCoordinationLeaseStore(getStoreLattice42("default", "lease").store);
|
|
39054
|
+
const outboxStore = getStoreLattice42("default", "outbox").store;
|
|
37572
39055
|
taskLifecycleNotifier3.setOutbox(outboxStore);
|
|
37573
39056
|
projectTaskAdmissionNotifier2.setOutbox(outboxStore);
|
|
37574
|
-
configurePluginCatalogSync({ outbox: outboxStore, owner:
|
|
37575
|
-
configureCollectionSync({ outbox: outboxStore, owner:
|
|
39057
|
+
configurePluginCatalogSync({ outbox: outboxStore, owner: getReplicaId12() });
|
|
39058
|
+
configureCollectionSync({ outbox: outboxStore, owner: getReplicaId12() });
|
|
37576
39059
|
bridgeAssistantEvents(
|
|
37577
39060
|
(event, cb) => eventBus3.subscribe(event, cb),
|
|
37578
39061
|
outboxStore,
|
|
37579
|
-
|
|
39062
|
+
getReplicaId12()
|
|
37580
39063
|
);
|
|
37581
|
-
installAgentLifecycleSync({ outbox: outboxStore, owner:
|
|
39064
|
+
installAgentLifecycleSync({ outbox: outboxStore, owner: getReplicaId12() });
|
|
37582
39065
|
if (projectRoomRealtimeRuntime) {
|
|
37583
39066
|
projectRoomRealtimeRuntime.broker.setBroadcastHook((scope, serialized, sourceKey) => {
|
|
37584
|
-
void publishRoomEvent(outboxStore,
|
|
39067
|
+
void publishRoomEvent(outboxStore, getReplicaId12(), scope, serialized, sourceKey);
|
|
37585
39068
|
});
|
|
37586
39069
|
}
|
|
37587
39070
|
const outboxPoller = new OutboxPoller({
|
|
37588
39071
|
store: outboxStore,
|
|
37589
|
-
owner:
|
|
39072
|
+
owner: getReplicaId12(),
|
|
37590
39073
|
handlers: {
|
|
37591
39074
|
"task-lifecycle": (payload) => taskLifecycleNotifier3.deliverFromOutbox(payload),
|
|
37592
39075
|
"project-task-admission": (payload) => projectTaskAdmissionNotifier2.deliverFromOutbox(payload),
|
|
37593
39076
|
[ROOM_EVENT_TOPIC]: async (payload) => {
|
|
37594
39077
|
if (projectRoomRealtimeRuntime) ingestRoomEvent(payload, projectRoomRealtimeRuntime.broker);
|
|
37595
39078
|
},
|
|
39079
|
+
[CHANNEL_INSTALLATION_CHANGED_TOPIC]: async () => {
|
|
39080
|
+
for (const leader of channelLeaders) leader.wake();
|
|
39081
|
+
},
|
|
37596
39082
|
"assistant-changed": (payload) => handleAssistantChanged(payload, async (tenantId) => {
|
|
37597
39083
|
await agentLatticeManager6.initializeStoredAssistantsForTenant(tenantId);
|
|
37598
39084
|
invalidateAgentReflectionCache(tenantId);
|
|
@@ -37603,7 +39089,7 @@ var start = async (config) => {
|
|
|
37603
39089
|
},
|
|
37604
39090
|
[A2A_KEY_CHANGED_TOPIC]: (payload) => handleA2AKeyChanged(payload, () => refreshStoreKeyMap()),
|
|
37605
39091
|
[MCP_CONFIG_CHANGED_TOPIC]: (payload) => reconcileMcpConfigChange(payload, {
|
|
37606
|
-
store:
|
|
39092
|
+
store: getStoreLattice42("default", "mcp").store,
|
|
37607
39093
|
manager: mcpManager3,
|
|
37608
39094
|
convertToConnection: convertToConnection2
|
|
37609
39095
|
}),
|
|
@@ -37628,31 +39114,32 @@ var start = async (config) => {
|
|
|
37628
39114
|
await handleModelProviderChanged(payload, (tenantId, providerId2) => controller.reconcileProvider(tenantId, providerId2));
|
|
37629
39115
|
}
|
|
37630
39116
|
},
|
|
37631
|
-
log:
|
|
39117
|
+
log: logger8
|
|
37632
39118
|
});
|
|
37633
39119
|
try {
|
|
37634
39120
|
await outboxPoller.start();
|
|
37635
39121
|
} catch (err) {
|
|
37636
|
-
|
|
39122
|
+
logger8.warn("Outbox poller failed to start", { error: err instanceof Error ? err.message : String(err) });
|
|
37637
39123
|
}
|
|
37638
|
-
const leaseStore =
|
|
39124
|
+
const leaseStore = getStoreLattice42("default", "lease").store;
|
|
37639
39125
|
if (leaseStore.constructor?.name === "InMemoryLeaseStore") {
|
|
37640
|
-
|
|
39126
|
+
logger8.warn(
|
|
37641
39127
|
"Startup recovery leader gate uses a non-distributed lease store (per-process only); configure a shared 'lease' store for multi-replica deployments",
|
|
37642
39128
|
{ phase: "startup_recovery" }
|
|
37643
39129
|
);
|
|
37644
39130
|
}
|
|
37645
|
-
warnMultiReplicaReadiness(
|
|
39131
|
+
warnMultiReplicaReadiness(logger8);
|
|
39132
|
+
assertMultiReplicaReadiness();
|
|
37646
39133
|
if (scheduleLatticeManager3.hasLattice("default")) {
|
|
37647
39134
|
registerAgentCronHandler(scheduleLatticeManager3.getScheduleLattice("default"), {
|
|
37648
39135
|
getAgent: (params) => agentInstanceManager13.getAgent(params),
|
|
37649
|
-
createThread: (tenantId, assistantId, threadId, data) =>
|
|
39136
|
+
createThread: (tenantId, assistantId, threadId, data) => getStoreLattice42("default", "thread").store.createThread(tenantId, assistantId, threadId, data),
|
|
37650
39137
|
acquireThreadRun: (tenantId, assistantId, threadId) => tryAcquireThreadRun5({
|
|
37651
|
-
store:
|
|
39138
|
+
store: getStoreLattice42("default", "lease").store,
|
|
37652
39139
|
tenantId,
|
|
37653
39140
|
assistantId,
|
|
37654
39141
|
threadId,
|
|
37655
|
-
owner:
|
|
39142
|
+
owner: getReplicaId12(),
|
|
37656
39143
|
ttlMs: 6e4
|
|
37657
39144
|
}),
|
|
37658
39145
|
getMaintenanceStore: getCheckpointMaintenanceStore,
|
|
@@ -37660,63 +39147,73 @@ var start = async (config) => {
|
|
|
37660
39147
|
removeAgent: (params) => {
|
|
37661
39148
|
agentInstanceManager13.removeAgent(params);
|
|
37662
39149
|
},
|
|
37663
|
-
log: { warn: (message, context) =>
|
|
39150
|
+
log: { warn: (message, context) => logger8.warn(message, context) }
|
|
37664
39151
|
});
|
|
37665
39152
|
}
|
|
37666
39153
|
const startup = await runAsLeader(leaseStore, "startup-recovery", async () => {
|
|
37667
39154
|
if (routes.projectTaskRuntime) {
|
|
37668
|
-
await prepareProjectTaskRuntime(routes.projectTaskRuntime,
|
|
39155
|
+
await prepareProjectTaskRuntime(routes.projectTaskRuntime, logger8);
|
|
37669
39156
|
}
|
|
37670
39157
|
if (process.env.AXIOM_TASK_ORPHAN_RECOVERY === "true") {
|
|
37671
39158
|
try {
|
|
37672
39159
|
const { createOrphanRecoveryRuntime: createOrphanRecoveryRuntime2 } = await import("./OrphanRecoveryRuntime-T4T5NOZU.mjs");
|
|
37673
39160
|
const { createRecoveryCallerDeps: createRecoveryCallerDeps2 } = await import("./RecoveryCallerDeps-6SJUYJ5S.mjs");
|
|
37674
39161
|
const runtime = createOrphanRecoveryRuntime2({
|
|
37675
|
-
taskStore:
|
|
37676
|
-
workItemStore:
|
|
37677
|
-
tenantStore:
|
|
39162
|
+
taskStore: getStoreLattice42("default", "task").store,
|
|
39163
|
+
workItemStore: getStoreLattice42("default", "taskWorkItem").store,
|
|
39164
|
+
tenantStore: getStoreLattice42("default", "tenant").store,
|
|
37678
39165
|
...createRecoveryCallerDeps2(),
|
|
37679
|
-
log:
|
|
39166
|
+
log: logger8
|
|
37680
39167
|
});
|
|
37681
39168
|
await runtime.recoverAll();
|
|
37682
39169
|
} catch (err) {
|
|
37683
|
-
|
|
37684
|
-
}
|
|
37685
|
-
}
|
|
37686
|
-
if (scheduleLatticeManager3.hasLattice("default")) {
|
|
37687
|
-
try {
|
|
37688
|
-
const restored = await scheduleLatticeManager3.getScheduleLattice("default").restore();
|
|
37689
|
-
logger7.info("Scheduled tasks restored", { phase: "startup_recovery", restored });
|
|
37690
|
-
} catch (err) {
|
|
37691
|
-
logger7.warn("Scheduled task restore failed", {
|
|
37692
|
-
phase: "startup_recovery",
|
|
37693
|
-
error: err instanceof Error ? err.message : String(err)
|
|
37694
|
-
});
|
|
39170
|
+
logger8.warn("Task orphan recovery failed", { error: err instanceof Error ? err.message : String(err) });
|
|
37695
39171
|
}
|
|
37696
39172
|
}
|
|
37697
39173
|
}, { hold: true, ttlMs: 5 * 6e4 });
|
|
37698
39174
|
if (!startup.ran) {
|
|
37699
|
-
|
|
39175
|
+
logger8.info("Startup recovery skipped (another replica leads)", { phase: "startup_recovery" });
|
|
39176
|
+
}
|
|
39177
|
+
if (scheduleLatticeManager3.hasLattice("default")) {
|
|
39178
|
+
const schedule2 = scheduleLatticeManager3.getScheduleLattice("default");
|
|
39179
|
+
try {
|
|
39180
|
+
const restored = await schedule2.restore();
|
|
39181
|
+
logger8.info("Scheduled tasks restored", { phase: "startup_recovery", restored });
|
|
39182
|
+
} catch (err) {
|
|
39183
|
+
logger8.warn("Scheduled task restore failed", {
|
|
39184
|
+
phase: "startup_recovery",
|
|
39185
|
+
error: err instanceof Error ? err.message : String(err)
|
|
39186
|
+
});
|
|
39187
|
+
}
|
|
39188
|
+
const intervalMs = parsePositiveInteger2(process.env.SCHEDULE_RECONCILE_MS, 3e4);
|
|
39189
|
+
scheduleReconcileTimer = setInterval(() => {
|
|
39190
|
+
void Promise.resolve(schedule2.reconcile?.()).catch((err) => {
|
|
39191
|
+
logger8.warn("Scheduled task reconcile failed", {
|
|
39192
|
+
error: err instanceof Error ? err.message : String(err)
|
|
39193
|
+
});
|
|
39194
|
+
});
|
|
39195
|
+
}, intervalMs);
|
|
39196
|
+
scheduleReconcileTimer.unref?.();
|
|
37700
39197
|
}
|
|
37701
39198
|
if (process.env.EXECUTION_WORKER_ENABLED === "true") {
|
|
37702
39199
|
try {
|
|
37703
|
-
const queueStore =
|
|
39200
|
+
const queueStore = getStoreLattice42("default", "threadMessageQueue").store;
|
|
37704
39201
|
executionSupervisor = new ThreadExecutionSupervisor({
|
|
37705
39202
|
queueStore,
|
|
37706
39203
|
runLedger,
|
|
37707
39204
|
scanIntervalMs: Number(process.env.EXECUTION_SCAN_MS ?? "1000"),
|
|
37708
39205
|
maxConcurrentThreads: Number(process.env.EXECUTION_MAX_THREADS ?? "20"),
|
|
37709
|
-
log: { warn: (message, context) =>
|
|
39206
|
+
log: { warn: (message, context) => logger8.warn(message, context) }
|
|
37710
39207
|
});
|
|
37711
39208
|
executionSupervisor.start();
|
|
37712
39209
|
setExecutionSupervisor(executionSupervisor);
|
|
37713
|
-
|
|
39210
|
+
logger8.info("Execution worker supervisor started", {
|
|
37714
39211
|
scanIntervalMs: process.env.EXECUTION_SCAN_MS ?? "1000",
|
|
37715
39212
|
maxConcurrentThreads: process.env.EXECUTION_MAX_THREADS ?? "20",
|
|
37716
39213
|
runLedger: runLedger ? "enabled" : "disabled"
|
|
37717
39214
|
});
|
|
37718
39215
|
} catch (err) {
|
|
37719
|
-
|
|
39216
|
+
logger8.warn("Execution worker supervisor unavailable", {
|
|
37720
39217
|
error: err instanceof Error ? err.message : String(err)
|
|
37721
39218
|
});
|
|
37722
39219
|
}
|
|
@@ -37730,23 +39227,23 @@ var start = async (config) => {
|
|
|
37730
39227
|
);
|
|
37731
39228
|
runTaskWake = createConfiguredRedisRunTaskWake({
|
|
37732
39229
|
url: process.env.REDIS_URL,
|
|
37733
|
-
owner:
|
|
39230
|
+
owner: getReplicaId12(),
|
|
37734
39231
|
wake: () => runTaskRuntime?.wake() ?? Promise.resolve(),
|
|
37735
39232
|
logger: {
|
|
37736
|
-
warn: (message, context) =>
|
|
37737
|
-
info: (message, context) =>
|
|
39233
|
+
warn: (message, context) => logger8.warn(message, context),
|
|
39234
|
+
info: (message, context) => logger8.info(message, context)
|
|
37738
39235
|
}
|
|
37739
39236
|
});
|
|
37740
39237
|
setRunTaskWakeStatsSource(runTaskWake);
|
|
37741
39238
|
if (runTaskWake) setRunTaskWakePublisher(runTaskWake);
|
|
37742
39239
|
try {
|
|
37743
39240
|
const projectTaskRunHooks = createProjectTaskRunHooks({
|
|
37744
|
-
tasks:
|
|
37745
|
-
workItems:
|
|
37746
|
-
projects:
|
|
37747
|
-
rooms:
|
|
37748
|
-
bots:
|
|
37749
|
-
threads:
|
|
39241
|
+
tasks: getStoreLattice42("default", "task").store,
|
|
39242
|
+
workItems: getStoreLattice42("default", "taskWorkItem").store,
|
|
39243
|
+
projects: getStoreLattice42("default", "project").store,
|
|
39244
|
+
rooms: getStoreLattice42("default", "projectRoom").store,
|
|
39245
|
+
bots: getStoreLattice42("default", "projectBotMembership").store,
|
|
39246
|
+
threads: getStoreLattice42("default", "thread").store,
|
|
37750
39247
|
getThreadState: async ({ task, thread }) => agentInstanceManager13.getAgent({
|
|
37751
39248
|
tenant_id: task.tenantId,
|
|
37752
39249
|
assistant_id: task.ownerId,
|
|
@@ -37755,15 +39252,17 @@ var start = async (config) => {
|
|
|
37755
39252
|
project_id: task.projectId
|
|
37756
39253
|
}).getCurrentState(),
|
|
37757
39254
|
onTaskInterrupted: (input) => projectTaskInterrupt(input),
|
|
37758
|
-
logger: { warn: (message, context) =>
|
|
39255
|
+
logger: { warn: (message, context) => logger8.warn(message, context) }
|
|
37759
39256
|
});
|
|
37760
39257
|
runTaskRuntime = new RunTaskRuntime({
|
|
37761
39258
|
ledger: runLedger,
|
|
37762
39259
|
leaseStore,
|
|
37763
|
-
|
|
39260
|
+
// The worker holds the thread-run lease, so it can make the run's
|
|
39261
|
+
// scope authoritative on the shared per-thread instance.
|
|
39262
|
+
getAgent: (params) => agentInstanceManager13.getAgentForExecution(params),
|
|
37764
39263
|
...projectTaskRunRuntimeOptions(projectTaskRunHooks),
|
|
37765
39264
|
resolveRollbackStore: getCheckpointRollbackStore,
|
|
37766
|
-
owner:
|
|
39265
|
+
owner: getReplicaId12(),
|
|
37767
39266
|
executeEnabled: runTaskWorkerEnabled,
|
|
37768
39267
|
maxConcurrentJobs: parsePositiveInteger2(process.env.N_JOBS_PER_WORKER, 10),
|
|
37769
39268
|
maxRunningPerTenant: resolveRunTaskMaxRunningPerTenant(process.env),
|
|
@@ -37779,30 +39278,30 @@ var start = async (config) => {
|
|
|
37779
39278
|
rollbackBackoffBaseMs: parsePositiveInteger2(process.env.RUN_TASK_ROLLBACK_BACKOFF_MS, 1e3),
|
|
37780
39279
|
shutdownTimeoutMs: runTaskShutdownTimeoutMs,
|
|
37781
39280
|
logger: {
|
|
37782
|
-
info: (message, context) =>
|
|
37783
|
-
warn: (message, context) =>
|
|
39281
|
+
info: (message, context) => logger8.info(message, context),
|
|
39282
|
+
warn: (message, context) => logger8.warn(message, context)
|
|
37784
39283
|
}
|
|
37785
39284
|
});
|
|
37786
39285
|
runTaskRuntime.start();
|
|
37787
39286
|
setRunTaskRuntime(runTaskRuntime);
|
|
37788
|
-
|
|
39287
|
+
logger8.info("Run task runtime started", {
|
|
37789
39288
|
executeEnabled: runTaskWorkerEnabled,
|
|
37790
39289
|
maxConcurrentJobs: parsePositiveInteger2(process.env.N_JOBS_PER_WORKER, 10),
|
|
37791
39290
|
worker: runTaskRuntime.worker ? "enabled" : "disabled",
|
|
37792
39291
|
recovery: "enabled"
|
|
37793
39292
|
});
|
|
37794
39293
|
} catch (err) {
|
|
37795
|
-
|
|
39294
|
+
logger8.warn("Run task runtime unavailable", {
|
|
37796
39295
|
error: err instanceof Error ? err.message : String(err)
|
|
37797
39296
|
});
|
|
37798
39297
|
}
|
|
37799
39298
|
if (runTaskWake && runTaskRuntime?.worker) {
|
|
37800
39299
|
void runTaskWake.start().catch((err) => {
|
|
37801
|
-
|
|
39300
|
+
logger8.warn("Run task wake subscriber failed to start", {
|
|
37802
39301
|
error: err instanceof Error ? err.message : String(err)
|
|
37803
39302
|
});
|
|
37804
39303
|
});
|
|
37805
|
-
|
|
39304
|
+
logger8.info("Run task Redis wake started in background", {
|
|
37806
39305
|
subscriber: "enabled"
|
|
37807
39306
|
});
|
|
37808
39307
|
}
|
|
@@ -37810,17 +39309,17 @@ var start = async (config) => {
|
|
|
37810
39309
|
ledger: runLedger,
|
|
37811
39310
|
days: process.env.AGENT_RUN_RETENTION_DAYS,
|
|
37812
39311
|
log: {
|
|
37813
|
-
info: (message, context) =>
|
|
37814
|
-
warn: (message, context) =>
|
|
39312
|
+
info: (message, context) => logger8.info(message, context),
|
|
39313
|
+
warn: (message, context) => logger8.warn(message, context)
|
|
37815
39314
|
}
|
|
37816
39315
|
});
|
|
37817
39316
|
if (agentRunRetentionJob) {
|
|
37818
39317
|
agentRunRetentionJob.start();
|
|
37819
|
-
|
|
39318
|
+
logger8.info("Agent run retention job started", {
|
|
37820
39319
|
days: parseAgentRunRetentionDays(process.env.AGENT_RUN_RETENTION_DAYS)
|
|
37821
39320
|
});
|
|
37822
39321
|
} else {
|
|
37823
|
-
|
|
39322
|
+
logger8.warn("Agent run retention disabled", {
|
|
37824
39323
|
env: "AGENT_RUN_RETENTION_DAYS"
|
|
37825
39324
|
});
|
|
37826
39325
|
}
|
|
@@ -37829,8 +39328,8 @@ var start = async (config) => {
|
|
|
37829
39328
|
intervalMs: parsePositiveInteger2(process.env.THREAD_TTL_SWEEP_MS, 6e4),
|
|
37830
39329
|
batchSize: parsePositiveInteger2(process.env.THREAD_TTL_SWEEP_BATCH, 100),
|
|
37831
39330
|
log: {
|
|
37832
|
-
info: (message, context) =>
|
|
37833
|
-
warn: (message, context) =>
|
|
39331
|
+
info: (message, context) => logger8.info(message, context),
|
|
39332
|
+
warn: (message, context) => logger8.warn(message, context)
|
|
37834
39333
|
}
|
|
37835
39334
|
});
|
|
37836
39335
|
if (threadTtlSweeper) {
|
|
@@ -37838,7 +39337,7 @@ var start = async (config) => {
|
|
|
37838
39337
|
await threadTtlSweeper.stop();
|
|
37839
39338
|
});
|
|
37840
39339
|
threadTtlSweeper.start();
|
|
37841
|
-
|
|
39340
|
+
logger8.info("Thread TTL sweeper started", {
|
|
37842
39341
|
intervalMs: parsePositiveInteger2(process.env.THREAD_TTL_SWEEP_MS, 6e4),
|
|
37843
39342
|
batchSize: parsePositiveInteger2(process.env.THREAD_TTL_SWEEP_BATCH, 100)
|
|
37844
39343
|
});
|
|
@@ -37848,8 +39347,8 @@ var start = async (config) => {
|
|
|
37848
39347
|
intervalMs: storeTtlConfig.intervalMs,
|
|
37849
39348
|
batchSize: storeTtlConfig.batchSize,
|
|
37850
39349
|
log: {
|
|
37851
|
-
info: (message, context) =>
|
|
37852
|
-
warn: (message, context) =>
|
|
39350
|
+
info: (message, context) => logger8.info(message, context),
|
|
39351
|
+
warn: (message, context) => logger8.warn(message, context)
|
|
37853
39352
|
}
|
|
37854
39353
|
}) : void 0;
|
|
37855
39354
|
if (storeTtlSweeper) {
|
|
@@ -37857,31 +39356,31 @@ var start = async (config) => {
|
|
|
37857
39356
|
await storeTtlSweeper.stop();
|
|
37858
39357
|
});
|
|
37859
39358
|
storeTtlSweeper.start();
|
|
37860
|
-
|
|
39359
|
+
logger8.info("Store TTL sweeper started", {
|
|
37861
39360
|
intervalMs: storeTtlConfig.intervalMs,
|
|
37862
39361
|
batchSize: storeTtlConfig.batchSize
|
|
37863
39362
|
});
|
|
37864
39363
|
}
|
|
37865
39364
|
installLifespanHooks(app, config?.lifespans, {
|
|
37866
|
-
warn: (message, context) =>
|
|
39365
|
+
warn: (message, context) => logger8.warn(message, context)
|
|
37867
39366
|
});
|
|
37868
39367
|
await app.listen({ port: target_port, host: "0.0.0.0" });
|
|
37869
|
-
|
|
39368
|
+
logger8.info(`Lattice Gateway is running on port: ${target_port}`);
|
|
37870
39369
|
const outboxRetention = createOutboxRetentionJob({
|
|
37871
39370
|
outbox: outboxStore,
|
|
37872
|
-
log:
|
|
39371
|
+
log: logger8
|
|
37873
39372
|
});
|
|
37874
39373
|
outboxRetention.start();
|
|
37875
39374
|
restoreMcpConnections().catch((error) => {
|
|
37876
|
-
|
|
39375
|
+
logger8.error("MCP connection restoration failed", { error });
|
|
37877
39376
|
});
|
|
37878
39377
|
if (config?.gracefulShutdown !== false && !shutdownHandlersInstalled) {
|
|
37879
39378
|
shutdownHandlersInstalled = true;
|
|
37880
39379
|
const gracefulShutdown = createGracefulShutdown({
|
|
37881
39380
|
timeoutMs: config?.gracefulShutdownTimeoutMs ?? 1e4,
|
|
37882
39381
|
log: {
|
|
37883
|
-
info: (message, context) =>
|
|
37884
|
-
warn: (message, context) =>
|
|
39382
|
+
info: (message, context) => logger8.info(message, context),
|
|
39383
|
+
warn: (message, context) => logger8.warn(message, context)
|
|
37885
39384
|
},
|
|
37886
39385
|
steps: [
|
|
37887
39386
|
async () => {
|
|
@@ -37908,6 +39407,10 @@ var start = async (config) => {
|
|
|
37908
39407
|
},
|
|
37909
39408
|
() => outboxPoller.stop(),
|
|
37910
39409
|
() => outboxRetention.stop(),
|
|
39410
|
+
() => {
|
|
39411
|
+
if (scheduleReconcileTimer) clearInterval(scheduleReconcileTimer);
|
|
39412
|
+
scheduleReconcileTimer = void 0;
|
|
39413
|
+
},
|
|
37911
39414
|
() => threadTtlSweeper?.stop(),
|
|
37912
39415
|
() => storeTtlSweeper?.stop(),
|
|
37913
39416
|
() => chunkSourceHandle?.close(),
|
|
@@ -37921,7 +39424,7 @@ var start = async (config) => {
|
|
|
37921
39424
|
process.once("SIGINT", () => void gracefulShutdown("SIGINT"));
|
|
37922
39425
|
}
|
|
37923
39426
|
} catch (err) {
|
|
37924
|
-
|
|
39427
|
+
logger8.error("Server start failed", { error: err });
|
|
37925
39428
|
process.exit(1);
|
|
37926
39429
|
}
|
|
37927
39430
|
};
|
|
@@ -37945,6 +39448,7 @@ export {
|
|
|
37945
39448
|
DEFAULT_RUN_TASK_MAX_ATTEMPTS,
|
|
37946
39449
|
DEFAULT_RUN_TASK_SCAN_MS,
|
|
37947
39450
|
DEFAULT_THREAD_RUN_LEASE_TTL_MS,
|
|
39451
|
+
LangfuseObservabilityProvider,
|
|
37948
39452
|
LatticeGateway,
|
|
37949
39453
|
MIRRORED_AGENT_EVENTS,
|
|
37950
39454
|
MODEL_PROVIDER_CHANGED_TOPIC,
|
|
@@ -37958,6 +39462,7 @@ export {
|
|
|
37958
39462
|
RunTaskRuntime,
|
|
37959
39463
|
RunTaskWorker,
|
|
37960
39464
|
createConfiguredRedisRunTaskWake,
|
|
39465
|
+
createLangfuseProviderFromEnv,
|
|
37961
39466
|
createOrphanRecoveryRuntime,
|
|
37962
39467
|
createRecoveryCallerDeps,
|
|
37963
39468
|
createRedisAppendLog,
|
|
@@ -37976,8 +39481,10 @@ export {
|
|
|
37976
39481
|
publishAgentLifecycle,
|
|
37977
39482
|
publishModelProviderChanged,
|
|
37978
39483
|
publishRoomEvent,
|
|
39484
|
+
readLangfuseConfig,
|
|
37979
39485
|
recoverTask,
|
|
37980
39486
|
recoverTopCaller,
|
|
39487
|
+
redactLangfuseValue,
|
|
37981
39488
|
resolveTopCaller,
|
|
37982
39489
|
runOrphanRecovery,
|
|
37983
39490
|
setRunTaskRuntime,
|