@vibe-lark/larkpal 0.1.68 → 0.1.69
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/bin/larkpal.js +0 -0
- package/dist/main.mjs +124 -0
- package/package.json +14 -15
package/bin/larkpal.js
CHANGED
|
File without changes
|
package/dist/main.mjs
CHANGED
|
@@ -3724,6 +3724,8 @@ function summarizeString(value) {
|
|
|
3724
3724
|
*
|
|
3725
3725
|
* 路由:
|
|
3726
3726
|
* POST /api/chat/stream — SSE 流式对话
|
|
3727
|
+
* POST /api/chat/runs/:runId/cancel — 取消运行中的 Web Chat run
|
|
3728
|
+
* POST /api/chat/sessions/:id/cancel-active-run — 取消会话中的 active run
|
|
3727
3729
|
* GET /api/chat/history — 分页获取会话历史
|
|
3728
3730
|
* GET /api/chat/sessions — 列出当前用户的所有会话
|
|
3729
3731
|
* POST /api/chat/sessions — 创建新会话
|
|
@@ -3754,6 +3756,9 @@ function getActiveChatRun(sessionId) {
|
|
|
3754
3756
|
const run = chatRunsBySession.get(sessionId);
|
|
3755
3757
|
return run?.status === "running" ? run : void 0;
|
|
3756
3758
|
}
|
|
3759
|
+
function findChatRunByRunId(runId) {
|
|
3760
|
+
for (const run of chatRunsBySession.values()) if (run.runId === runId) return run;
|
|
3761
|
+
}
|
|
3757
3762
|
function serializeChatRun(run) {
|
|
3758
3763
|
const idleSeconds = Math.max(0, Math.floor((Date.now() - run.lastEventAt) / 1e3));
|
|
3759
3764
|
return {
|
|
@@ -3944,6 +3949,34 @@ async function cleanupTerminalRunProcess(run, processManager, reason) {
|
|
|
3944
3949
|
});
|
|
3945
3950
|
}
|
|
3946
3951
|
}
|
|
3952
|
+
async function cancelChatRun(run, messageStore, processManager) {
|
|
3953
|
+
if (run.status !== "running") return {
|
|
3954
|
+
cancelled: false,
|
|
3955
|
+
run: serializeChatRun(run)
|
|
3956
|
+
};
|
|
3957
|
+
const processInfo = processManager.getProcessInfo(run.sessionId);
|
|
3958
|
+
run.adapterBusy = processManager.isSessionBusy?.(run.sessionId) ?? processInfo?.status === "running";
|
|
3959
|
+
run.processStatus = processInfo?.status;
|
|
3960
|
+
await processManager.stopProcess(run.sessionId);
|
|
3961
|
+
const stoppedInfo = processManager.getProcessInfo(run.sessionId);
|
|
3962
|
+
run.adapterBusy = processManager.isSessionBusy?.(run.sessionId) ?? false;
|
|
3963
|
+
run.processStatus = stoppedInfo?.status ?? "stopped";
|
|
3964
|
+
const marked = await markRunTerminal(run, messageStore, "cancelled", {
|
|
3965
|
+
finalStatus: "user_cancelled",
|
|
3966
|
+
error: "Chat run cancelled by user"
|
|
3967
|
+
});
|
|
3968
|
+
if (marked) {
|
|
3969
|
+
broadcastRunEvent(run, "cancelled", {
|
|
3970
|
+
runId: run.runId,
|
|
3971
|
+
sessionId: run.sessionId
|
|
3972
|
+
});
|
|
3973
|
+
endRunClients(run);
|
|
3974
|
+
}
|
|
3975
|
+
return {
|
|
3976
|
+
cancelled: marked,
|
|
3977
|
+
run: serializeChatRun(run)
|
|
3978
|
+
};
|
|
3979
|
+
}
|
|
3947
3980
|
async function reconcileRunWithAdapter(run, messageStore, processManager) {
|
|
3948
3981
|
if (run.status !== "running") return;
|
|
3949
3982
|
const processInfo = processManager.getProcessInfo(run.sessionId);
|
|
@@ -4028,6 +4061,8 @@ function buildRuntimeEventMessageMetadata(event, runtimeConfig) {
|
|
|
4028
4061
|
*
|
|
4029
4062
|
* 路由:
|
|
4030
4063
|
* POST /api/chat/stream — SSE 流式对话
|
|
4064
|
+
* POST /api/chat/runs/:runId/cancel — 取消运行中的 Web Chat run
|
|
4065
|
+
* POST /api/chat/sessions/:id/cancel-active-run — 取消会话中的 active run
|
|
4031
4066
|
* GET /api/chat/history — 分页获取会话历史
|
|
4032
4067
|
* GET /api/chat/sessions — 列出当前用户的所有会话
|
|
4033
4068
|
* POST /api/chat/sessions — 创建新会话
|
|
@@ -4188,6 +4223,7 @@ function createChatRouter(config) {
|
|
|
4188
4223
|
}, 15e3);
|
|
4189
4224
|
const handleBlockedEvent = (event) => {
|
|
4190
4225
|
const sanitized = sanitizeBlockedEvent(event);
|
|
4226
|
+
if (run.status !== "running") return;
|
|
4191
4227
|
recordRunEvent(run, "blocked", { toolName: sanitized.name });
|
|
4192
4228
|
log$30.warn("[stream] Agent blocked event", { ...sanitized });
|
|
4193
4229
|
if (runtimeConfig.requestContext) logChatAudit(buildAuditEvent(runtimeConfig.requestContext, sanitized.type, {
|
|
@@ -4219,6 +4255,7 @@ function createChatRouter(config) {
|
|
|
4219
4255
|
broadcastRunEvent(run, "blocked", { event: sanitized });
|
|
4220
4256
|
};
|
|
4221
4257
|
const handleRuntimeEvent = (event) => {
|
|
4258
|
+
if (run.status !== "running") return;
|
|
4222
4259
|
const dedupeKey = getRuntimeEventDedupeKey(event);
|
|
4223
4260
|
if (dedupeKey) {
|
|
4224
4261
|
if (run.seenRuntimeEventIds.has(dedupeKey)) {
|
|
@@ -4260,15 +4297,18 @@ function createChatRouter(config) {
|
|
|
4260
4297
|
};
|
|
4261
4298
|
const callbacks = {
|
|
4262
4299
|
onTextDelta: (text) => {
|
|
4300
|
+
if (run.status !== "running") return;
|
|
4263
4301
|
recordRunEvent(run, "text-delta");
|
|
4264
4302
|
run.text += text;
|
|
4265
4303
|
broadcastRunEvent(run, "text-delta", { text });
|
|
4266
4304
|
},
|
|
4267
4305
|
onThinkingDelta: (text) => {
|
|
4306
|
+
if (run.status !== "running") return;
|
|
4268
4307
|
recordRunEvent(run, "thinking-delta");
|
|
4269
4308
|
broadcastRunEvent(run, "thinking-delta", { text });
|
|
4270
4309
|
},
|
|
4271
4310
|
onToolUseStart: (toolName, toolInput) => {
|
|
4311
|
+
if (run.status !== "running") return;
|
|
4272
4312
|
recordRunEvent(run, "tool-use-start", { toolName });
|
|
4273
4313
|
if (runtimeConfig.requestContext) logChatAudit(buildAuditEvent(runtimeConfig.requestContext, "tool_call_started", {
|
|
4274
4314
|
toolName,
|
|
@@ -4297,6 +4337,7 @@ function createChatRouter(config) {
|
|
|
4297
4337
|
});
|
|
4298
4338
|
},
|
|
4299
4339
|
onToolResult: (toolUseId, result) => {
|
|
4340
|
+
if (run.status !== "running") return;
|
|
4300
4341
|
recordRunEvent(run, "tool-result");
|
|
4301
4342
|
const resultSummary = summarizeForAudit(result);
|
|
4302
4343
|
if (runtimeConfig.requestContext) logChatAudit(buildAuditEvent(runtimeConfig.requestContext, "tool_call_finished", {
|
|
@@ -4328,6 +4369,7 @@ function createChatRouter(config) {
|
|
|
4328
4369
|
});
|
|
4329
4370
|
},
|
|
4330
4371
|
onToolProgress: (toolName, elapsedSeconds) => {
|
|
4372
|
+
if (run.status !== "running") return;
|
|
4331
4373
|
recordRunEvent(run, "tool-progress", { toolName });
|
|
4332
4374
|
broadcastRunEvent(run, "tool-progress", {
|
|
4333
4375
|
toolName,
|
|
@@ -4335,11 +4377,13 @@ function createChatRouter(config) {
|
|
|
4335
4377
|
});
|
|
4336
4378
|
},
|
|
4337
4379
|
onTurnEnd: (stopReason) => {
|
|
4380
|
+
if (run.status !== "running") return;
|
|
4338
4381
|
recordRunEvent(run, "turn-end");
|
|
4339
4382
|
if (runtimeConfig.requestContext) logChatAudit(buildAuditEvent(runtimeConfig.requestContext, "turn_finished", { metadata: { stopReason } }));
|
|
4340
4383
|
broadcastRunEvent(run, "turn-end", { stopReason });
|
|
4341
4384
|
},
|
|
4342
4385
|
onResult: async (result) => {
|
|
4386
|
+
if (run.status !== "running") return;
|
|
4343
4387
|
recordRunEvent(run, "result");
|
|
4344
4388
|
const finalText = run.text.trim() ? run.text : result.result || "";
|
|
4345
4389
|
run.text = finalText;
|
|
@@ -4395,6 +4439,7 @@ function createChatRouter(config) {
|
|
|
4395
4439
|
}));
|
|
4396
4440
|
},
|
|
4397
4441
|
onError: async (error) => {
|
|
4442
|
+
if (run.status !== "running") return;
|
|
4398
4443
|
recordRunEvent(run, "error");
|
|
4399
4444
|
log$30.error("[stream] Runtime 执行出错", {
|
|
4400
4445
|
sessionId,
|
|
@@ -4445,6 +4490,7 @@ function createChatRouter(config) {
|
|
|
4445
4490
|
});
|
|
4446
4491
|
},
|
|
4447
4492
|
onVerifierResult: (result) => {
|
|
4493
|
+
if (run.status !== "running") return;
|
|
4448
4494
|
recordRunEvent(run, "verifier-result");
|
|
4449
4495
|
const resultSummary = summarizeForAudit(result);
|
|
4450
4496
|
if (runtimeConfig.requestContext) logChatAudit(buildAuditEvent(runtimeConfig.requestContext, "verifier_result", {
|
|
@@ -4519,6 +4565,84 @@ function createChatRouter(config) {
|
|
|
4519
4565
|
if (run.status === "running") await callbacks.onError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
4520
4566
|
}
|
|
4521
4567
|
});
|
|
4568
|
+
router.post("/api/chat/runs/:runId/cancel", chatAuthMiddleware, async (req, res) => {
|
|
4569
|
+
const chatUser = res.locals.chatUser;
|
|
4570
|
+
const runId = String(req.params.runId);
|
|
4571
|
+
const run = findChatRunByRunId(runId);
|
|
4572
|
+
if (!run) {
|
|
4573
|
+
res.json({
|
|
4574
|
+
success: true,
|
|
4575
|
+
cancelled: false,
|
|
4576
|
+
run: null
|
|
4577
|
+
});
|
|
4578
|
+
return;
|
|
4579
|
+
}
|
|
4580
|
+
if (!isRunVisibleToUser(run, {
|
|
4581
|
+
tenantKey: chatUser.tenantKey,
|
|
4582
|
+
openId: chatUser.openId
|
|
4583
|
+
})) {
|
|
4584
|
+
res.status(403).json({ error: "Forbidden" });
|
|
4585
|
+
return;
|
|
4586
|
+
}
|
|
4587
|
+
try {
|
|
4588
|
+
const result = await cancelChatRun(run, messageStore, processManager);
|
|
4589
|
+
res.json({
|
|
4590
|
+
success: true,
|
|
4591
|
+
...result
|
|
4592
|
+
});
|
|
4593
|
+
} catch (err) {
|
|
4594
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
4595
|
+
log$30.error("[runs] 取消 run 失败", {
|
|
4596
|
+
runId,
|
|
4597
|
+
sessionId: run.sessionId,
|
|
4598
|
+
error: errorMessage
|
|
4599
|
+
});
|
|
4600
|
+
res.status(500).json({
|
|
4601
|
+
error: "Failed to cancel chat run",
|
|
4602
|
+
run: serializeChatRun(run)
|
|
4603
|
+
});
|
|
4604
|
+
}
|
|
4605
|
+
});
|
|
4606
|
+
router.post("/api/chat/sessions/:id/cancel-active-run", chatAuthMiddleware, async (req, res) => {
|
|
4607
|
+
const chatUser = res.locals.chatUser;
|
|
4608
|
+
const sessionId = String(req.params.id);
|
|
4609
|
+
const run = chatRunsBySession.get(sessionId);
|
|
4610
|
+
if (!run) {
|
|
4611
|
+
res.json({
|
|
4612
|
+
success: true,
|
|
4613
|
+
cancelled: false,
|
|
4614
|
+
sessionId,
|
|
4615
|
+
run: null
|
|
4616
|
+
});
|
|
4617
|
+
return;
|
|
4618
|
+
}
|
|
4619
|
+
if (!isRunVisibleToUser(run, {
|
|
4620
|
+
tenantKey: chatUser.tenantKey,
|
|
4621
|
+
openId: chatUser.openId
|
|
4622
|
+
})) {
|
|
4623
|
+
res.status(403).json({ error: "Forbidden" });
|
|
4624
|
+
return;
|
|
4625
|
+
}
|
|
4626
|
+
try {
|
|
4627
|
+
const result = await cancelChatRun(run, messageStore, processManager);
|
|
4628
|
+
res.json({
|
|
4629
|
+
success: true,
|
|
4630
|
+
sessionId,
|
|
4631
|
+
...result
|
|
4632
|
+
});
|
|
4633
|
+
} catch (err) {
|
|
4634
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
4635
|
+
log$30.error("[sessions] 取消 active run 失败", {
|
|
4636
|
+
sessionId,
|
|
4637
|
+
runId: run.runId,
|
|
4638
|
+
error: errorMessage
|
|
4639
|
+
});
|
|
4640
|
+
res.status(500).json({
|
|
4641
|
+
error: "Failed to cancel active chat run",
|
|
4642
|
+
run: serializeChatRun(run)
|
|
4643
|
+
});
|
|
4644
|
+
}
|
|
4645
|
+
});
|
|
4522
4646
|
router.get("/api/chat/history", chatAuthMiddleware, async (req, res) => {
|
|
4523
4647
|
const chatUser = res.locals.chatUser;
|
|
4524
4648
|
const sessionId = req.query.session_id;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-lark/larkpal",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.69",
|
|
4
4
|
"description": "LarkPal - Lark/Feishu bot service",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/main.mjs",
|
|
@@ -21,22 +21,9 @@
|
|
|
21
21
|
"registry": "https://registry.npmjs.org",
|
|
22
22
|
"access": "public"
|
|
23
23
|
},
|
|
24
|
-
"packageManager": "pnpm@10.32.1",
|
|
25
24
|
"engines": {
|
|
26
25
|
"node": ">=22"
|
|
27
26
|
},
|
|
28
|
-
"scripts": {
|
|
29
|
-
"start": "node --env-file=.env bin/larkpal.js",
|
|
30
|
-
"build": "tsdown",
|
|
31
|
-
"test": "vitest run",
|
|
32
|
-
"test:watch": "vitest",
|
|
33
|
-
"lint": "eslint src/",
|
|
34
|
-
"lint:fix": "eslint src/ --fix",
|
|
35
|
-
"sit:larkpal-agent": "node scripts/sit/larkpal-agent-0.1.9-sit.mjs",
|
|
36
|
-
"typecheck": "tsc --noEmit",
|
|
37
|
-
"format": "prettier --write src/**/*.ts",
|
|
38
|
-
"format:check": "prettier --check src/**/*.ts"
|
|
39
|
-
},
|
|
40
27
|
"dependencies": {
|
|
41
28
|
"@larksuiteoapi/node-sdk": "^1.60.0",
|
|
42
29
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
@@ -69,5 +56,17 @@
|
|
|
69
56
|
"typescript": "^5.9.3",
|
|
70
57
|
"typescript-eslint": "^8.32.1",
|
|
71
58
|
"vitest": "^4.1.1"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"start": "node --env-file=.env bin/larkpal.js",
|
|
62
|
+
"build": "tsdown",
|
|
63
|
+
"test": "vitest run",
|
|
64
|
+
"test:watch": "vitest",
|
|
65
|
+
"lint": "eslint src/",
|
|
66
|
+
"lint:fix": "eslint src/ --fix",
|
|
67
|
+
"sit:larkpal-agent": "node scripts/sit/larkpal-agent-0.1.9-sit.mjs",
|
|
68
|
+
"typecheck": "tsc --noEmit",
|
|
69
|
+
"format": "prettier --write src/**/*.ts",
|
|
70
|
+
"format:check": "prettier --check src/**/*.ts"
|
|
72
71
|
}
|
|
73
|
-
}
|
|
72
|
+
}
|