@vibe-lark/larkpal 0.1.22 → 0.1.24
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/main.mjs +88 -12
- package/package.json +1 -1
package/dist/main.mjs
CHANGED
|
@@ -435,7 +435,10 @@ var CCStreamParser = class extends EventEmitter {
|
|
|
435
435
|
this.handleResult(msg);
|
|
436
436
|
break;
|
|
437
437
|
case "system":
|
|
438
|
-
log$28.info("收到 system 消息", {
|
|
438
|
+
log$28.info("收到 system 消息", {
|
|
439
|
+
subtype: msg.subtype,
|
|
440
|
+
detail: JSON.stringify(msg).slice(0, 500)
|
|
441
|
+
});
|
|
439
442
|
this.emit("system", msg);
|
|
440
443
|
break;
|
|
441
444
|
default:
|
|
@@ -957,10 +960,15 @@ var SessionProcessManager = class {
|
|
|
957
960
|
*/
|
|
958
961
|
async executePrompt(config, callbacks) {
|
|
959
962
|
const { sessionId } = config;
|
|
963
|
+
const t0 = Date.now();
|
|
960
964
|
const prevLock = this.sessionLocks.get(sessionId);
|
|
961
965
|
if (prevLock) {
|
|
962
966
|
log$25.info("等待上一条消息处理完成", { sessionId });
|
|
963
967
|
await prevLock;
|
|
968
|
+
log$25.info("[perf] 串行锁等待完成", {
|
|
969
|
+
sessionId,
|
|
970
|
+
waitMs: Date.now() - t0
|
|
971
|
+
});
|
|
964
972
|
}
|
|
965
973
|
const completionPromise = this.createMessageCompletionPromise(sessionId);
|
|
966
974
|
this.sessionLocks.set(sessionId, completionPromise);
|
|
@@ -970,11 +978,16 @@ var SessionProcessManager = class {
|
|
|
970
978
|
log$25.info("向常驻进程发送消息", {
|
|
971
979
|
sessionId,
|
|
972
980
|
promptLength: config.prompt.length,
|
|
973
|
-
pid: existing.childProcess.pid
|
|
981
|
+
pid: existing.childProcess.pid,
|
|
982
|
+
prepareMs: Date.now() - t0
|
|
974
983
|
});
|
|
975
984
|
this.sendMessage(sessionId, config.prompt);
|
|
976
985
|
this.resetIdleTimer(sessionId);
|
|
977
986
|
await completionPromise;
|
|
987
|
+
log$25.info("[perf] executePrompt 完成(热进程)", {
|
|
988
|
+
sessionId,
|
|
989
|
+
totalMs: Date.now() - t0
|
|
990
|
+
});
|
|
978
991
|
return;
|
|
979
992
|
}
|
|
980
993
|
if (existing && (existing.status === "stopped" || existing.status === "crashed")) {
|
|
@@ -990,8 +1003,17 @@ var SessionProcessManager = class {
|
|
|
990
1003
|
await this.stopProcess(sessionId);
|
|
991
1004
|
this.sessionLocks.set(sessionId, completionPromise);
|
|
992
1005
|
}
|
|
1006
|
+
const tStart = Date.now();
|
|
993
1007
|
await this.startPersistentProcess(config);
|
|
1008
|
+
log$25.info("[perf] 冷启动进程完成", {
|
|
1009
|
+
sessionId,
|
|
1010
|
+
coldStartMs: Date.now() - tStart
|
|
1011
|
+
});
|
|
994
1012
|
await completionPromise;
|
|
1013
|
+
log$25.info("[perf] executePrompt 完成(冷启动)", {
|
|
1014
|
+
sessionId,
|
|
1015
|
+
totalMs: Date.now() - t0
|
|
1016
|
+
});
|
|
995
1017
|
}
|
|
996
1018
|
/**
|
|
997
1019
|
* 启动常驻 CC 进程
|
|
@@ -1207,10 +1229,31 @@ var SessionProcessManager = class {
|
|
|
1207
1229
|
*/
|
|
1208
1230
|
bindParserToCallbackProxy(parser, sessionId) {
|
|
1209
1231
|
const getCallbacks = () => this.activeCallbacks.get(sessionId);
|
|
1232
|
+
let firstTokenLogged = false;
|
|
1233
|
+
let messageSentAt = Date.now();
|
|
1234
|
+
const proc = this.processes.get(sessionId);
|
|
1235
|
+
if (proc) proc._resetPerfTimer = () => {
|
|
1236
|
+
firstTokenLogged = false;
|
|
1237
|
+
messageSentAt = Date.now();
|
|
1238
|
+
};
|
|
1210
1239
|
parser.on("textDelta", (text) => {
|
|
1240
|
+
if (!firstTokenLogged) {
|
|
1241
|
+
firstTokenLogged = true;
|
|
1242
|
+
log$25.info("[perf] 首 token (text)", {
|
|
1243
|
+
sessionId,
|
|
1244
|
+
ttftMs: Date.now() - messageSentAt
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1211
1247
|
getCallbacks()?.onTextDelta?.(text);
|
|
1212
1248
|
});
|
|
1213
1249
|
parser.on("thinkingDelta", (text) => {
|
|
1250
|
+
if (!firstTokenLogged) {
|
|
1251
|
+
firstTokenLogged = true;
|
|
1252
|
+
log$25.info("[perf] 首 token (thinking)", {
|
|
1253
|
+
sessionId,
|
|
1254
|
+
ttftMs: Date.now() - messageSentAt
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1214
1257
|
getCallbacks()?.onThinkingDelta?.(text);
|
|
1215
1258
|
});
|
|
1216
1259
|
parser.on("toolUseStart", (toolName, toolInput) => {
|
|
@@ -1223,9 +1266,18 @@ var SessionProcessManager = class {
|
|
|
1223
1266
|
getCallbacks()?.onToolProgress?.(toolName, elapsedSeconds);
|
|
1224
1267
|
});
|
|
1225
1268
|
parser.on("turnEnd", (stopReason) => {
|
|
1269
|
+
log$25.info("[perf] turnEnd", {
|
|
1270
|
+
sessionId,
|
|
1271
|
+
stopReason,
|
|
1272
|
+
sinceMessageMs: Date.now() - messageSentAt
|
|
1273
|
+
});
|
|
1226
1274
|
getCallbacks()?.onTurnEnd?.(stopReason);
|
|
1227
1275
|
});
|
|
1228
1276
|
parser.on("result", (result) => {
|
|
1277
|
+
log$25.info("[perf] result 事件", {
|
|
1278
|
+
sessionId,
|
|
1279
|
+
sinceMessageMs: Date.now() - messageSentAt
|
|
1280
|
+
});
|
|
1229
1281
|
getCallbacks()?.onResult?.(result);
|
|
1230
1282
|
this.resolveMessageCompletion(sessionId);
|
|
1231
1283
|
});
|
|
@@ -1249,6 +1301,7 @@ var SessionProcessManager = class {
|
|
|
1249
1301
|
log$25.error("无法发送消息:进程不存在或 stdin 不可用", { sessionId });
|
|
1250
1302
|
return;
|
|
1251
1303
|
}
|
|
1304
|
+
proc._resetPerfTimer?.();
|
|
1252
1305
|
const userMessageId = v4();
|
|
1253
1306
|
this.lastUserMessageIds.set(sessionId, userMessageId);
|
|
1254
1307
|
const payload = JSON.stringify({
|
|
@@ -4565,6 +4618,7 @@ function sortTraceValue(value) {
|
|
|
4565
4618
|
//#endregion
|
|
4566
4619
|
//#region src/card/cc-stream-bridge.ts
|
|
4567
4620
|
const log$18 = larkLogger("card/cc-stream-bridge");
|
|
4621
|
+
const CC_INTERNAL_PLACEHOLDER = "No response requested.";
|
|
4568
4622
|
/**
|
|
4569
4623
|
* CCStreamBridge — 将 CC 流事件桥接到 StreamingCardController
|
|
4570
4624
|
*
|
|
@@ -4683,6 +4737,15 @@ var CCStreamBridge = class {
|
|
|
4683
4737
|
accumulatedThinkingTextLen: this.accumulatedThinkingText.length
|
|
4684
4738
|
});
|
|
4685
4739
|
if (this.options.autoCompleteOnTurnEnd && stopReason === "end_turn") {
|
|
4740
|
+
const trimmedText = this.accumulatedText.trim();
|
|
4741
|
+
if (trimmedText === CC_INTERNAL_PLACEHOLDER || trimmedText === "") {
|
|
4742
|
+
log$18.info("检测到 CC 内部占位消息,静默丢弃", {
|
|
4743
|
+
text: trimmedText.slice(0, 50),
|
|
4744
|
+
sessionKey: this.options.sessionKey
|
|
4745
|
+
});
|
|
4746
|
+
this.controller.abortCard();
|
|
4747
|
+
return;
|
|
4748
|
+
}
|
|
4686
4749
|
this.controller.markFullyComplete();
|
|
4687
4750
|
this.controller.onIdle();
|
|
4688
4751
|
}
|
|
@@ -8711,7 +8774,8 @@ async function dispatchToCC(params) {
|
|
|
8711
8774
|
const isGroup = chatType === "group";
|
|
8712
8775
|
const replyInThread = !!threadId;
|
|
8713
8776
|
const replyToMessageId = threadId ? void 0 : ctx.messageId;
|
|
8714
|
-
|
|
8777
|
+
let textPrompt = formatForCC(ctx, isGroup);
|
|
8778
|
+
if (isGroup) textPrompt = `[直接@你的消息,请正常回复] ${textPrompt}`;
|
|
8715
8779
|
const imageResources = ctx.resources.filter((r) => r.type === "image");
|
|
8716
8780
|
let prompt = textPrompt;
|
|
8717
8781
|
if (imageResources.length > 0) {
|
|
@@ -8957,6 +9021,9 @@ async function dispatchToCC(params) {
|
|
|
8957
9021
|
chatId,
|
|
8958
9022
|
replyToMessageId: cardDeps.replyToMessageId
|
|
8959
9023
|
});
|
|
9024
|
+
cardController.ensureCardCreated().catch((err) => {
|
|
9025
|
+
log$11.warn("提前创建卡片失败(streaming 回调会重试)", { error: String(err) });
|
|
9026
|
+
});
|
|
8960
9027
|
const bridge = new CCStreamBridge(cardController, {
|
|
8961
9028
|
autoCompleteOnTurnEnd: true,
|
|
8962
9029
|
sessionKey: route.sessionId
|
|
@@ -9083,7 +9150,8 @@ async function dispatchTeammateEval(params) {
|
|
|
9083
9150
|
const teammateSessionKey = `teammate_${route.sessionId}`;
|
|
9084
9151
|
startToolUseTraceRun(teammateSessionKey);
|
|
9085
9152
|
const NO_REPLY_TOKEN = SILENT_REPLY_TOKEN;
|
|
9086
|
-
const
|
|
9153
|
+
const CC_INTERNAL_PLACEHOLDER = "No response requested.";
|
|
9154
|
+
const PREFIX_LEN = 22;
|
|
9087
9155
|
/** 缓冲的 thinking 内容 */
|
|
9088
9156
|
let thinkingBuffer = "";
|
|
9089
9157
|
/** text 前缀缓冲(用于判断是否为 NO_REPLY) */
|
|
@@ -9156,15 +9224,22 @@ async function dispatchTeammateEval(params) {
|
|
|
9156
9224
|
}
|
|
9157
9225
|
textPrefixBuffer += text;
|
|
9158
9226
|
if (textPrefixBuffer.length >= PREFIX_LEN) {
|
|
9159
|
-
|
|
9227
|
+
const trimmed = textPrefixBuffer.trim();
|
|
9228
|
+
if (trimmed === NO_REPLY_TOKEN || trimmed === CC_INTERNAL_PLACEHOLDER) {
|
|
9160
9229
|
silenced = true;
|
|
9161
|
-
log$11.info("teammate 前缀检测:
|
|
9230
|
+
log$11.info("teammate 前缀检测: 静默", {
|
|
9231
|
+
chatId,
|
|
9232
|
+
trimmed: trimmed.slice(0, 30)
|
|
9233
|
+
});
|
|
9162
9234
|
return;
|
|
9163
9235
|
}
|
|
9164
9236
|
confirmReply();
|
|
9165
9237
|
return;
|
|
9166
9238
|
}
|
|
9167
|
-
|
|
9239
|
+
const currentTrimmed = textPrefixBuffer.trim();
|
|
9240
|
+
const couldBeNoReply = NO_REPLY_TOKEN.startsWith(currentTrimmed);
|
|
9241
|
+
const couldBePlaceholder = CC_INTERNAL_PLACEHOLDER.startsWith(currentTrimmed);
|
|
9242
|
+
if (!couldBeNoReply && !couldBePlaceholder) confirmReply();
|
|
9168
9243
|
};
|
|
9169
9244
|
try {
|
|
9170
9245
|
await new Promise((resolve) => {
|
|
@@ -9211,11 +9286,11 @@ async function dispatchTeammateEval(params) {
|
|
|
9211
9286
|
}
|
|
9212
9287
|
if (!confirmed && !silenced) {
|
|
9213
9288
|
const trimmed = textPrefixBuffer.trim();
|
|
9214
|
-
if (trimmed === NO_REPLY_TOKEN || trimmed === "") {
|
|
9289
|
+
if (trimmed === NO_REPLY_TOKEN || trimmed === CC_INTERNAL_PLACEHOLDER || trimmed === "") {
|
|
9215
9290
|
silenced = true;
|
|
9216
|
-
log$11.info("teammate turnEnd 最终判断:
|
|
9291
|
+
log$11.info("teammate turnEnd 最终判断: 静默", {
|
|
9217
9292
|
chatId,
|
|
9218
|
-
trimmed
|
|
9293
|
+
trimmed: trimmed.slice(0, 30)
|
|
9219
9294
|
});
|
|
9220
9295
|
} else {
|
|
9221
9296
|
confirmReply();
|
|
@@ -11926,9 +12001,10 @@ var TeammateBuffer = class {
|
|
|
11926
12001
|
*/
|
|
11927
12002
|
buildEvalPrompt(messages) {
|
|
11928
12003
|
const header = [
|
|
11929
|
-
"[
|
|
11930
|
-
"
|
|
12004
|
+
"[旁听评估任务] 以下是群聊中最近的对话,你作为团队成员正在旁听。",
|
|
12005
|
+
"请判断是否需要主动参与讨论。如果不需要,只输出 NO_REPLY。",
|
|
11931
12006
|
"如果需要参与,直接输出你的回复内容。",
|
|
12007
|
+
"注意:这是一次旁听评估,仅在本次评估中适用 NO_REPLY 规则。后续如果用户直接 @你 则必须正常回复。",
|
|
11932
12008
|
"",
|
|
11933
12009
|
"---"
|
|
11934
12010
|
].join("\n");
|