larkway 0.3.34 → 0.3.36
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/README.md +1 -1
- package/README.zh.md +1 -1
- package/dist/cli/index.js +280 -74
- package/dist/main.js +893 -31
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -24969,13 +24969,13 @@ var require_lib2 = __commonJS({
|
|
|
24969
24969
|
Domain[Domain["Lark"] = 1] = "Lark";
|
|
24970
24970
|
})(exports.Domain || (exports.Domain = {}));
|
|
24971
24971
|
exports.LoggerLevel = void 0;
|
|
24972
|
-
(function(
|
|
24973
|
-
|
|
24974
|
-
|
|
24975
|
-
|
|
24976
|
-
|
|
24977
|
-
|
|
24978
|
-
|
|
24972
|
+
(function(LoggerLevel2) {
|
|
24973
|
+
LoggerLevel2[LoggerLevel2["fatal"] = 0] = "fatal";
|
|
24974
|
+
LoggerLevel2[LoggerLevel2["error"] = 1] = "error";
|
|
24975
|
+
LoggerLevel2[LoggerLevel2["warn"] = 2] = "warn";
|
|
24976
|
+
LoggerLevel2[LoggerLevel2["info"] = 3] = "info";
|
|
24977
|
+
LoggerLevel2[LoggerLevel2["debug"] = 4] = "debug";
|
|
24978
|
+
LoggerLevel2[LoggerLevel2["trace"] = 5] = "trace";
|
|
24979
24979
|
})(exports.LoggerLevel || (exports.LoggerLevel = {}));
|
|
24980
24980
|
var CEventType = /* @__PURE__ */ Symbol("event-type");
|
|
24981
24981
|
var CTenantKey = /* @__PURE__ */ Symbol("tenant-key");
|
|
@@ -108498,7 +108498,7 @@ var require_lib2 = __commonJS({
|
|
|
108498
108498
|
return this.impl.run(producer);
|
|
108499
108499
|
}
|
|
108500
108500
|
};
|
|
108501
|
-
var
|
|
108501
|
+
var DEFAULT_THROTTLE_MS2 = 100;
|
|
108502
108502
|
var DEFAULT_THROTTLE_CHARS = 50;
|
|
108503
108503
|
var CardStreamControllerImpl = class {
|
|
108504
108504
|
constructor(sender, to, idType, opts, initial) {
|
|
@@ -108512,7 +108512,7 @@ var require_lib2 = __commonJS({
|
|
|
108512
108512
|
this._current = initial;
|
|
108513
108513
|
const cfg = sender.config;
|
|
108514
108514
|
this.throttle = new Throttle({
|
|
108515
|
-
ms: (_a = cfg.streamThrottleMs) !== null && _a !== void 0 ? _a :
|
|
108515
|
+
ms: (_a = cfg.streamThrottleMs) !== null && _a !== void 0 ? _a : DEFAULT_THROTTLE_MS2,
|
|
108516
108516
|
chars: (_b = cfg.streamThrottleChars) !== null && _b !== void 0 ? _b : DEFAULT_THROTTLE_CHARS
|
|
108517
108517
|
}, () => this.patch());
|
|
108518
108518
|
}
|
|
@@ -116537,6 +116537,119 @@ var ChannelPostClient = class {
|
|
|
116537
116537
|
}
|
|
116538
116538
|
};
|
|
116539
116539
|
|
|
116540
|
+
// src/lark/channelCotClient.ts
|
|
116541
|
+
var COT_REQUEST_TIMEOUT_MS = 8e3;
|
|
116542
|
+
async function withTimeout(p, ms, label) {
|
|
116543
|
+
let timer;
|
|
116544
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
116545
|
+
timer = setTimeout(
|
|
116546
|
+
() => reject(new Error(`[channel.cot] ${label} timed out after ${ms}ms`)),
|
|
116547
|
+
ms
|
|
116548
|
+
);
|
|
116549
|
+
timer.unref?.();
|
|
116550
|
+
});
|
|
116551
|
+
try {
|
|
116552
|
+
return await Promise.race([p, timeout]);
|
|
116553
|
+
} finally {
|
|
116554
|
+
if (timer) clearTimeout(timer);
|
|
116555
|
+
}
|
|
116556
|
+
}
|
|
116557
|
+
function assertOk(res, label) {
|
|
116558
|
+
if (res.code !== void 0 && res.code !== 0) {
|
|
116559
|
+
throw new Error(
|
|
116560
|
+
`[channel.cot] ${label} failed: code=${res.code} msg=${res.msg ?? "<no msg>"}`
|
|
116561
|
+
);
|
|
116562
|
+
}
|
|
116563
|
+
}
|
|
116564
|
+
var ChannelCotClient = class {
|
|
116565
|
+
resolveChannel;
|
|
116566
|
+
constructor(opts) {
|
|
116567
|
+
this.resolveChannel = opts.resolveChannel;
|
|
116568
|
+
}
|
|
116569
|
+
channel() {
|
|
116570
|
+
const ch = this.resolveChannel();
|
|
116571
|
+
if (!ch) {
|
|
116572
|
+
throw new Error("[channel.cot] outbound called before the Channel SDK connected");
|
|
116573
|
+
}
|
|
116574
|
+
return ch;
|
|
116575
|
+
}
|
|
116576
|
+
/** Every COT call goes through here, so all get the same hard timeout. */
|
|
116577
|
+
request(opts) {
|
|
116578
|
+
return withTimeout(
|
|
116579
|
+
this.channel().rawClient.request(opts),
|
|
116580
|
+
COT_REQUEST_TIMEOUT_MS,
|
|
116581
|
+
`${opts.method} ${opts.url}`
|
|
116582
|
+
);
|
|
116583
|
+
}
|
|
116584
|
+
async create(target) {
|
|
116585
|
+
const receiveIdType = target.threadId ? "thread_id" : "chat_id";
|
|
116586
|
+
const receiveId = target.threadId ?? target.chatId;
|
|
116587
|
+
const res = await this.request({
|
|
116588
|
+
url: "/open-apis/im/v1/message_cot",
|
|
116589
|
+
method: "POST",
|
|
116590
|
+
params: { receive_id_type: receiveIdType },
|
|
116591
|
+
data: {
|
|
116592
|
+
receive_id: receiveId,
|
|
116593
|
+
// origin_message_id only anchors non-thread bubbles; harmless if set,
|
|
116594
|
+
// but omitted for topic threads where the thread id already anchors.
|
|
116595
|
+
...!target.threadId && target.originMessageId ? { origin_message_id: target.originMessageId } : {}
|
|
116596
|
+
}
|
|
116597
|
+
});
|
|
116598
|
+
assertOk(res, "create");
|
|
116599
|
+
const cotId = stringField(res.data, "cot_id");
|
|
116600
|
+
const messageId = stringField(res.data, "message_id");
|
|
116601
|
+
if (!cotId || !messageId) {
|
|
116602
|
+
throw new Error(
|
|
116603
|
+
`[channel.cot] create returned no cot_id/message_id (${JSON.stringify(res.data ?? {}).slice(0, 200)})`
|
|
116604
|
+
);
|
|
116605
|
+
}
|
|
116606
|
+
return { cotId, messageId };
|
|
116607
|
+
}
|
|
116608
|
+
async update(ref, events) {
|
|
116609
|
+
if (events.length === 0) return;
|
|
116610
|
+
const res = await this.request({
|
|
116611
|
+
url: "/open-apis/im/v1/message_cot",
|
|
116612
|
+
method: "PUT",
|
|
116613
|
+
data: { cot_id: ref.cotId, message_id: ref.messageId, events: [...events] }
|
|
116614
|
+
});
|
|
116615
|
+
assertOk(res, "update");
|
|
116616
|
+
}
|
|
116617
|
+
async complete(ref, reason) {
|
|
116618
|
+
const res = await this.request({
|
|
116619
|
+
url: `/open-apis/im/v1/message_cot/complete/${encodeURIComponent(ref.cotId)}`,
|
|
116620
|
+
method: "POST",
|
|
116621
|
+
params: { message_id: ref.messageId, reason }
|
|
116622
|
+
});
|
|
116623
|
+
assertOk(res, "complete");
|
|
116624
|
+
}
|
|
116625
|
+
async resolveThreadId(messageId) {
|
|
116626
|
+
try {
|
|
116627
|
+
const res = await this.request({
|
|
116628
|
+
url: `/open-apis/im/v1/messages/${encodeURIComponent(messageId)}`,
|
|
116629
|
+
method: "GET"
|
|
116630
|
+
});
|
|
116631
|
+
if (res.code !== void 0 && res.code !== 0) return void 0;
|
|
116632
|
+
const items = res.data?.["items"];
|
|
116633
|
+
if (!Array.isArray(items)) return void 0;
|
|
116634
|
+
for (const item of items) {
|
|
116635
|
+
if (item && typeof item === "object") {
|
|
116636
|
+
const threadId = item["thread_id"];
|
|
116637
|
+
if (typeof threadId === "string" && threadId.startsWith("omt_")) {
|
|
116638
|
+
return threadId;
|
|
116639
|
+
}
|
|
116640
|
+
}
|
|
116641
|
+
}
|
|
116642
|
+
return void 0;
|
|
116643
|
+
} catch {
|
|
116644
|
+
return void 0;
|
|
116645
|
+
}
|
|
116646
|
+
}
|
|
116647
|
+
};
|
|
116648
|
+
function stringField(data, key) {
|
|
116649
|
+
const value = data?.[key];
|
|
116650
|
+
return typeof value === "string" ? value : void 0;
|
|
116651
|
+
}
|
|
116652
|
+
|
|
116540
116653
|
// src/lark/channelClient.ts
|
|
116541
116654
|
var execFile = promisify(execFileCallback);
|
|
116542
116655
|
var LEARNED_CHATS_LIMIT = 100;
|
|
@@ -116589,13 +116702,13 @@ function arrayField(obj, key) {
|
|
|
116589
116702
|
const value = obj[key];
|
|
116590
116703
|
return Array.isArray(value) ? value : null;
|
|
116591
116704
|
}
|
|
116592
|
-
function
|
|
116705
|
+
function stringField2(obj, key) {
|
|
116593
116706
|
if (!obj || typeof obj !== "object") return void 0;
|
|
116594
116707
|
const value = obj[key];
|
|
116595
116708
|
return typeof value === "string" ? value : void 0;
|
|
116596
116709
|
}
|
|
116597
116710
|
function nonEmptyStringField(obj, key) {
|
|
116598
|
-
const value =
|
|
116711
|
+
const value = stringField2(obj, key);
|
|
116599
116712
|
return value && value.length > 0 ? value : void 0;
|
|
116600
116713
|
}
|
|
116601
116714
|
function parseLarkCliMessages(stdout) {
|
|
@@ -116809,6 +116922,8 @@ var ChannelClient = class {
|
|
|
116809
116922
|
cardKitClient = null;
|
|
116810
116923
|
/** Lazily built and only requested by main.ts when post outbound gates are configured. */
|
|
116811
116924
|
postClient = null;
|
|
116925
|
+
/** Lazily built COT (思维链) client; only requested when a bot enables cot != off. */
|
|
116926
|
+
cotClient = null;
|
|
116812
116927
|
constructor(opts) {
|
|
116813
116928
|
if (!opts.appId || !opts.appSecret) {
|
|
116814
116929
|
throw new Error(
|
|
@@ -117074,6 +117189,22 @@ var ChannelClient = class {
|
|
|
117074
117189
|
}
|
|
117075
117190
|
return this.cardKitClient;
|
|
117076
117191
|
}
|
|
117192
|
+
/**
|
|
117193
|
+
* Return an OutboundCotClient bound to this client's channel handle.
|
|
117194
|
+
*
|
|
117195
|
+
* main.ts only calls this when the bot's `cot` config is not "off". The COT
|
|
117196
|
+
* bubble uses the SDK's generic rawClient.request() (tenant token auto-
|
|
117197
|
+
* injected via the same token manager as every other outbound call), so it
|
|
117198
|
+
* adds no auth surface. Resolves the live channel lazily at call time.
|
|
117199
|
+
*/
|
|
117200
|
+
outboundCotClient() {
|
|
117201
|
+
if (!this.cotClient) {
|
|
117202
|
+
this.cotClient = new ChannelCotClient({
|
|
117203
|
+
resolveChannel: () => this.channel
|
|
117204
|
+
});
|
|
117205
|
+
}
|
|
117206
|
+
return this.cotClient;
|
|
117207
|
+
}
|
|
117077
117208
|
/**
|
|
117078
117209
|
* Return an OutboundPostClient bound to this client's channel handle.
|
|
117079
117210
|
*
|
|
@@ -117377,7 +117508,7 @@ var ChannelClient = class {
|
|
|
117377
117508
|
const chats = parseLarkCliMessages(stdout) ?? [];
|
|
117378
117509
|
fetched += chats.length;
|
|
117379
117510
|
for (const raw of chats) {
|
|
117380
|
-
const chatId =
|
|
117511
|
+
const chatId = stringField2(raw, "chat_id");
|
|
117381
117512
|
if (!chatId?.startsWith("oc_")) continue;
|
|
117382
117513
|
discoveredChatIds.add(chatId);
|
|
117383
117514
|
const before = this.recentlySeenChatIds.size;
|
|
@@ -117391,7 +117522,7 @@ var ChannelClient = class {
|
|
|
117391
117522
|
const hasMore = Boolean(
|
|
117392
117523
|
(data && typeof data === "object" && data["has_more"]) ?? (parsed && typeof parsed === "object" && parsed["has_more"])
|
|
117393
117524
|
);
|
|
117394
|
-
pageToken =
|
|
117525
|
+
pageToken = stringField2(data, "page_token") ?? stringField2(parsed, "page_token") ?? "";
|
|
117395
117526
|
if (!hasMore || !pageToken) break;
|
|
117396
117527
|
}
|
|
117397
117528
|
if (newlyLearned > 0) {
|
|
@@ -118517,7 +118648,7 @@ function senderOpenIdOf(senderId) {
|
|
|
118517
118648
|
import fs from "node:fs/promises";
|
|
118518
118649
|
|
|
118519
118650
|
// src/agent/triggerFacts.ts
|
|
118520
|
-
function
|
|
118651
|
+
function stringField3(value) {
|
|
118521
118652
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
118522
118653
|
}
|
|
118523
118654
|
function mentionType(raw) {
|
|
@@ -118535,9 +118666,9 @@ function mentionType(raw) {
|
|
|
118535
118666
|
}
|
|
118536
118667
|
function deriveTriggerFacts(parsed, isNewThread, larkCliProfile) {
|
|
118537
118668
|
const raw = parsed.raw;
|
|
118538
|
-
const feishuRootId =
|
|
118539
|
-
const feishuThreadId =
|
|
118540
|
-
const chatType =
|
|
118669
|
+
const feishuRootId = stringField3(raw["root_id"]);
|
|
118670
|
+
const feishuThreadId = stringField3(raw["thread_id"]);
|
|
118671
|
+
const chatType = stringField3(raw["chat_type"]) ?? "unknown";
|
|
118541
118672
|
const triggerType = raw["larkway_trigger_type"] === "card_action" ? "card_action" : feishuRootId || !isNewThread ? "topic_continuation" : "top_level_mention";
|
|
118542
118673
|
const profileFlag = larkCliProfile ? ` --profile ${larkCliProfile}` : "";
|
|
118543
118674
|
return {
|
|
@@ -118546,7 +118677,7 @@ function deriveTriggerFacts(parsed, isNewThread, larkCliProfile) {
|
|
|
118546
118677
|
chatType,
|
|
118547
118678
|
feishuThreadId,
|
|
118548
118679
|
feishuRootId,
|
|
118549
|
-
createTime:
|
|
118680
|
+
createTime: stringField3(raw["create_time"]) ?? parsed.raw.create_time,
|
|
118550
118681
|
rawMessagePointer: `lark-cli api GET /open-apis/im/v1/messages/${parsed.messageId}${profileFlag} --as bot`
|
|
118551
118682
|
};
|
|
118552
118683
|
}
|
|
@@ -120458,6 +120589,8 @@ async function deleteCardKitFile(worktreePath) {
|
|
|
120458
120589
|
var CARDKIT_FINAL_ELEMENT_ID = "final_md";
|
|
120459
120590
|
var CARDKIT_FOOTER_ELEMENT_ID = "footer_md";
|
|
120460
120591
|
var CARDKIT_CHOICES_ELEMENT_ID = "choices_slot";
|
|
120592
|
+
var CARDKIT_COT_PANEL_ELEMENT_ID = "cot_panel";
|
|
120593
|
+
var CARDKIT_COT_INNER_ELEMENT_ID = "cot_inner_md";
|
|
120461
120594
|
var MAX_CARD_BYTES = 30 * 1024;
|
|
120462
120595
|
var FINAL_BUDGET_CHARS = 22e3;
|
|
120463
120596
|
var CHOICE_MARKERS2 = ["A", "B", "C", "D", "E"];
|
|
@@ -120472,6 +120605,15 @@ function markdown(content, elementId) {
|
|
|
120472
120605
|
function buildCardKitAnswerElement(content = "") {
|
|
120473
120606
|
return markdown(content, CARDKIT_FINAL_ELEMENT_ID);
|
|
120474
120607
|
}
|
|
120608
|
+
function buildCotPanelElement(opts) {
|
|
120609
|
+
return {
|
|
120610
|
+
tag: "collapsible_panel",
|
|
120611
|
+
element_id: CARDKIT_COT_PANEL_ELEMENT_ID,
|
|
120612
|
+
expanded: opts.expanded,
|
|
120613
|
+
header: { title: { tag: "markdown", content: opts.title } },
|
|
120614
|
+
elements: [markdown(opts.content || "\u2026", CARDKIT_COT_INNER_ELEMENT_ID)]
|
|
120615
|
+
};
|
|
120616
|
+
}
|
|
120475
120617
|
function safeAtMention(target) {
|
|
120476
120618
|
const id = target.user_id.trim();
|
|
120477
120619
|
if (!/^[A-Za-z0-9_:-]+$/.test(id)) return "";
|
|
@@ -120570,7 +120712,17 @@ function finalMarkdown(opts) {
|
|
|
120570
120712
|
return truncateChars([mentionLine, body].filter(Boolean).join("\n\n") || "\u5B8C\u6210\u3002", FINAL_BUDGET_CHARS, "\n\n_\u5185\u5BB9\u8FC7\u957F,\u5DF2\u622A\u65AD\u3002_");
|
|
120571
120713
|
}
|
|
120572
120714
|
function buildCardKitFinalCard(opts) {
|
|
120573
|
-
const elements = [
|
|
120715
|
+
const elements = [];
|
|
120716
|
+
if (opts.cotPanel) {
|
|
120717
|
+
elements.push(
|
|
120718
|
+
buildCotPanelElement({
|
|
120719
|
+
expanded: false,
|
|
120720
|
+
title: opts.cotPanel.title,
|
|
120721
|
+
content: opts.cotPanel.content
|
|
120722
|
+
})
|
|
120723
|
+
);
|
|
120724
|
+
}
|
|
120725
|
+
elements.push(buildCardKitAnswerElement(finalMarkdown(opts)));
|
|
120574
120726
|
const images = [];
|
|
120575
120727
|
if (opts.contentBlocks?.length) {
|
|
120576
120728
|
for (const block of opts.contentBlocks) {
|
|
@@ -120607,6 +120759,9 @@ function buildCardKitFinalMarkdown(opts) {
|
|
|
120607
120759
|
var DEFAULT_PATCH_INTERVAL_MS = 250;
|
|
120608
120760
|
var DEFAULT_MAX_PROGRESS_UPDATES = 240;
|
|
120609
120761
|
var BACKOFF_LADDER_MS = [250, 1e3, 2e3, 5e3];
|
|
120762
|
+
var COT_PANEL_BUDGET_CHARS = 4e3;
|
|
120763
|
+
var COT_TOOL_ARGS_MAX = 200;
|
|
120764
|
+
var COT_TOOL_RESULT_MAX = 1200;
|
|
120610
120765
|
function idempotencyKey(facts) {
|
|
120611
120766
|
return deriveCardKitUuid(
|
|
120612
120767
|
["reply", facts.botId, facts.threadId, facts.triggerMessageId].join("\0")
|
|
@@ -120643,6 +120798,37 @@ function summarizeError(err) {
|
|
|
120643
120798
|
function toolStatusText(toolUseCount) {
|
|
120644
120799
|
return toolUseCount > 0 ? `\u52AA\u529B\u56DE\u7B54\u4E2D... \xB7 \u5DF2\u7528 ${toolUseCount} \u4E2A\u5DE5\u5177` : "\u52AA\u529B\u56DE\u7B54\u4E2D...";
|
|
120645
120800
|
}
|
|
120801
|
+
function clip(value, max) {
|
|
120802
|
+
const text = String(value ?? "");
|
|
120803
|
+
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
120804
|
+
}
|
|
120805
|
+
function cotBriefToolTitle(name) {
|
|
120806
|
+
return String(name ?? "tool");
|
|
120807
|
+
}
|
|
120808
|
+
function cotExtractToolResultText(raw) {
|
|
120809
|
+
if (typeof raw !== "object" || raw === null) return "";
|
|
120810
|
+
const message = raw["message"];
|
|
120811
|
+
if (typeof message !== "object" || message === null) return "";
|
|
120812
|
+
const content = message["content"];
|
|
120813
|
+
if (!Array.isArray(content)) return "";
|
|
120814
|
+
const parts = [];
|
|
120815
|
+
for (const item of content) {
|
|
120816
|
+
if (typeof item !== "object" || item === null) continue;
|
|
120817
|
+
const block = item;
|
|
120818
|
+
if (block["type"] !== "tool_result") continue;
|
|
120819
|
+
const inner = block["content"];
|
|
120820
|
+
if (typeof inner === "string") parts.push(inner);
|
|
120821
|
+
else if (Array.isArray(inner)) {
|
|
120822
|
+
for (const piece of inner) {
|
|
120823
|
+
if (typeof piece === "object" && piece !== null) {
|
|
120824
|
+
const text = piece["text"];
|
|
120825
|
+
if (typeof text === "string") parts.push(text);
|
|
120826
|
+
}
|
|
120827
|
+
}
|
|
120828
|
+
}
|
|
120829
|
+
}
|
|
120830
|
+
return parts.join("\n").trim();
|
|
120831
|
+
}
|
|
120646
120832
|
var LiveCardKitProgressHandle = class {
|
|
120647
120833
|
cardId;
|
|
120648
120834
|
messageId;
|
|
@@ -120660,6 +120846,23 @@ var LiveCardKitProgressHandle = class {
|
|
|
120660
120846
|
immediatePatchStarted = false;
|
|
120661
120847
|
metrics = initialLiveMetrics();
|
|
120662
120848
|
sequence = 0;
|
|
120849
|
+
// COT-in-card (方案 B) state. All no-ops when cotDetail is undefined.
|
|
120850
|
+
cotDetail;
|
|
120851
|
+
onCotPanelCreated;
|
|
120852
|
+
cotBuffer = "";
|
|
120853
|
+
cotTruncated = false;
|
|
120854
|
+
cotPanelCreated = false;
|
|
120855
|
+
cotPendingPatch = null;
|
|
120856
|
+
cotSawThinkingDelta = false;
|
|
120857
|
+
cotToolIndex = 0;
|
|
120858
|
+
cotPendingTools = [];
|
|
120859
|
+
cotErrored = false;
|
|
120860
|
+
// Panel formatting state: keep a tool line and following reasoning on
|
|
120861
|
+
// separate lines, and collapse consecutive same-name tool calls into a count.
|
|
120862
|
+
cotAfterTool = false;
|
|
120863
|
+
cotLastToolName;
|
|
120864
|
+
cotLastToolCount = 0;
|
|
120865
|
+
cotLastToolLineStart = -1;
|
|
120663
120866
|
constructor(opts) {
|
|
120664
120867
|
this.cardKitClient = opts.cardKitClient;
|
|
120665
120868
|
this.cardId = opts.cardId;
|
|
@@ -120667,6 +120870,8 @@ var LiveCardKitProgressHandle = class {
|
|
|
120667
120870
|
this.idempotencyKey = opts.idempotencyKey;
|
|
120668
120871
|
this.patchIntervalMs = opts.patchIntervalMs;
|
|
120669
120872
|
this.maxProgressUpdates = opts.maxProgressUpdates;
|
|
120873
|
+
this.cotDetail = opts.cot?.detail;
|
|
120874
|
+
this.onCotPanelCreated = opts.onCotPanelCreated;
|
|
120670
120875
|
this.onSequenceCommitted = opts.onSequenceCommitted;
|
|
120671
120876
|
this.onLiveMetricsChanged = opts.onLiveMetricsChanged;
|
|
120672
120877
|
}
|
|
@@ -120678,6 +120883,7 @@ var LiveCardKitProgressHandle = class {
|
|
|
120678
120883
|
}
|
|
120679
120884
|
handle(event) {
|
|
120680
120885
|
if (this.closed) return;
|
|
120886
|
+
if (this.cotDetail) this.handleCot(event);
|
|
120681
120887
|
if (event.type === "tool_use") {
|
|
120682
120888
|
this.recordToolUse();
|
|
120683
120889
|
this.patchStatus(toolStatusText(this.metrics.toolUseCount));
|
|
@@ -120696,6 +120902,11 @@ var LiveCardKitProgressHandle = class {
|
|
|
120696
120902
|
}
|
|
120697
120903
|
}
|
|
120698
120904
|
async drain() {
|
|
120905
|
+
if (this.cotPendingPatch) {
|
|
120906
|
+
clearTimeout(this.cotPendingPatch);
|
|
120907
|
+
this.cotPendingPatch = null;
|
|
120908
|
+
await this.cotPatch();
|
|
120909
|
+
}
|
|
120699
120910
|
if (this.pendingPatch) {
|
|
120700
120911
|
clearTimeout(this.pendingPatch);
|
|
120701
120912
|
this.pendingPatch = null;
|
|
@@ -120706,6 +120917,7 @@ var LiveCardKitProgressHandle = class {
|
|
|
120706
120917
|
async finalize(opts) {
|
|
120707
120918
|
await this.drain();
|
|
120708
120919
|
this.closed = true;
|
|
120920
|
+
const finalOpts = { ...opts, cotPanel: this.cotPanelForFinalCard() };
|
|
120709
120921
|
const finalMarkdown2 = buildCardKitFinalMarkdown(opts);
|
|
120710
120922
|
if (finalMarkdown2 !== this.answerBuffer) {
|
|
120711
120923
|
await this.withAnswerElement(finalMarkdown2);
|
|
@@ -120723,7 +120935,7 @@ var LiveCardKitProgressHandle = class {
|
|
|
120723
120935
|
this.answerBuffer = finalMarkdown2;
|
|
120724
120936
|
}
|
|
120725
120937
|
await this.next(
|
|
120726
|
-
(sequence) => this.cardKitClient.updateCardEntity(this.cardId, buildCardKitFinalCard(
|
|
120938
|
+
(sequence) => this.cardKitClient.updateCardEntity(this.cardId, buildCardKitFinalCard(finalOpts), {
|
|
120727
120939
|
sequence,
|
|
120728
120940
|
uuid: sequenceUuid(this.cardId, "final-card", sequence)
|
|
120729
120941
|
})
|
|
@@ -120750,6 +120962,149 @@ var LiveCardKitProgressHandle = class {
|
|
|
120750
120962
|
clearTimeout(this.pendingPatch);
|
|
120751
120963
|
this.pendingPatch = null;
|
|
120752
120964
|
}
|
|
120965
|
+
if (this.cotPendingPatch) {
|
|
120966
|
+
clearTimeout(this.cotPendingPatch);
|
|
120967
|
+
this.cotPendingPatch = null;
|
|
120968
|
+
}
|
|
120969
|
+
}
|
|
120970
|
+
/** Mark the reasoning panel's turn as errored so its settled title reflects it. */
|
|
120971
|
+
markCotError() {
|
|
120972
|
+
this.cotErrored = true;
|
|
120973
|
+
}
|
|
120974
|
+
// ── COT-in-card (方案 B) ────────────────────────────────────────────────
|
|
120975
|
+
//
|
|
120976
|
+
// Reasoning + tool activity stream into a collapsible_panel that is created
|
|
120977
|
+
// LAZILY on the first such event (a thinking-free short turn shows no panel),
|
|
120978
|
+
// inserted above the answer, then collapsed + retitled inside the final card
|
|
120979
|
+
// (buildCardKitFinalCard, not a separate PATCH — the full-card rebuild would
|
|
120980
|
+
// clobber a PATCH). Every step is best-effort: a panel failure never touches
|
|
120981
|
+
// the answer stream.
|
|
120982
|
+
handleCot(event) {
|
|
120983
|
+
switch (event.type) {
|
|
120984
|
+
case "thinking_delta":
|
|
120985
|
+
this.cotSawThinkingDelta = true;
|
|
120986
|
+
this.cotAppendReasoning(event.text);
|
|
120987
|
+
break;
|
|
120988
|
+
case "thinking_snapshot":
|
|
120989
|
+
if (this.cotSawThinkingDelta) break;
|
|
120990
|
+
this.cotAppendReasoning(event.text);
|
|
120991
|
+
break;
|
|
120992
|
+
case "tool_use":
|
|
120993
|
+
this.cotAppendToolUse(event.toolName, event.toolInput);
|
|
120994
|
+
break;
|
|
120995
|
+
case "tool_result":
|
|
120996
|
+
this.cotAppendToolResult(event.raw);
|
|
120997
|
+
break;
|
|
120998
|
+
default:
|
|
120999
|
+
break;
|
|
121000
|
+
}
|
|
121001
|
+
}
|
|
121002
|
+
cotAppendReasoning(text) {
|
|
121003
|
+
if (this.cotAfterTool) {
|
|
121004
|
+
this.cotAppend("\n");
|
|
121005
|
+
this.cotAfterTool = false;
|
|
121006
|
+
}
|
|
121007
|
+
this.cotLastToolName = void 0;
|
|
121008
|
+
this.cotAppend(text);
|
|
121009
|
+
}
|
|
121010
|
+
cotAppendToolUse(toolName, toolInput) {
|
|
121011
|
+
this.cotPendingTools.push(`tool-${++this.cotToolIndex}`);
|
|
121012
|
+
const name = cotBriefToolTitle(toolName);
|
|
121013
|
+
if (this.cotDetail === "brief" && name === this.cotLastToolName && this.cotLastToolLineStart >= 0 && !this.cotTruncated) {
|
|
121014
|
+
this.cotLastToolCount += 1;
|
|
121015
|
+
this.cotBuffer = this.cotBuffer.slice(0, this.cotLastToolLineStart);
|
|
121016
|
+
this.cotAppend(`
|
|
121017
|
+
|
|
121018
|
+
\u{1F527} ${name} \xD7${this.cotLastToolCount}`);
|
|
121019
|
+
this.cotAfterTool = true;
|
|
121020
|
+
return;
|
|
121021
|
+
}
|
|
121022
|
+
this.cotLastToolLineStart = this.cotBuffer.length;
|
|
121023
|
+
this.cotLastToolName = name;
|
|
121024
|
+
this.cotLastToolCount = 1;
|
|
121025
|
+
let line = `
|
|
121026
|
+
|
|
121027
|
+
\u{1F527} ${name}`;
|
|
121028
|
+
if (this.cotDetail === "detailed" && toolInput !== void 0 && toolInput !== null) {
|
|
121029
|
+
line += `
|
|
121030
|
+
\`\`\`
|
|
121031
|
+
${clip(JSON.stringify(toolInput), COT_TOOL_ARGS_MAX)}
|
|
121032
|
+
\`\`\``;
|
|
121033
|
+
}
|
|
121034
|
+
this.cotAppend(line);
|
|
121035
|
+
this.cotAfterTool = true;
|
|
121036
|
+
}
|
|
121037
|
+
cotAppendToolResult(raw) {
|
|
121038
|
+
this.cotPendingTools.shift();
|
|
121039
|
+
if (this.cotDetail !== "detailed") return;
|
|
121040
|
+
const text = cotExtractToolResultText(raw);
|
|
121041
|
+
if (!text) return;
|
|
121042
|
+
this.cotAppend(`
|
|
121043
|
+
> ${clip(text, COT_TOOL_RESULT_MAX).replace(/\n/g, "\n> ")}`);
|
|
121044
|
+
this.cotAfterTool = true;
|
|
121045
|
+
this.cotLastToolName = void 0;
|
|
121046
|
+
}
|
|
121047
|
+
/** Append to the panel buffer under the hard char budget, then schedule a patch. */
|
|
121048
|
+
cotAppend(text) {
|
|
121049
|
+
if (this.closed || this.cotTruncated) return;
|
|
121050
|
+
const remaining = COT_PANEL_BUDGET_CHARS - this.cotBuffer.length;
|
|
121051
|
+
if (text.length >= remaining) {
|
|
121052
|
+
this.cotBuffer += text.slice(0, Math.max(0, remaining)) + "\n\n_\u2026\u601D\u8003\u5185\u5BB9\u8F83\u957F\uFF0C\u540E\u7EED\u7701\u7565_";
|
|
121053
|
+
this.cotTruncated = true;
|
|
121054
|
+
} else {
|
|
121055
|
+
this.cotBuffer += text;
|
|
121056
|
+
}
|
|
121057
|
+
this.cotSchedulePatch();
|
|
121058
|
+
}
|
|
121059
|
+
cotSchedulePatch() {
|
|
121060
|
+
if (this.cotPendingPatch || this.closed) return;
|
|
121061
|
+
this.cotPendingPatch = setTimeout(() => {
|
|
121062
|
+
this.cotPendingPatch = null;
|
|
121063
|
+
void this.cotPatch();
|
|
121064
|
+
}, this.patchIntervalMs);
|
|
121065
|
+
this.cotPendingPatch.unref?.();
|
|
121066
|
+
}
|
|
121067
|
+
async cotPatch() {
|
|
121068
|
+
if (this.closed || !this.cotBuffer) return;
|
|
121069
|
+
this.inFlight = this.inFlight.then(() => this.cotEnsurePanel()).then(
|
|
121070
|
+
() => this.next(
|
|
121071
|
+
(sequence) => this.cardKitClient.streamElementContent(
|
|
121072
|
+
this.cardId,
|
|
121073
|
+
CARDKIT_COT_INNER_ELEMENT_ID,
|
|
121074
|
+
this.cotBuffer,
|
|
121075
|
+
{ sequence, uuid: sequenceUuid(this.cardId, "cot-inner", sequence) }
|
|
121076
|
+
)
|
|
121077
|
+
)
|
|
121078
|
+
).catch((err) => {
|
|
121079
|
+
console.warn("[cardkit_progress] COT panel patch failed (continuing):", err);
|
|
121080
|
+
});
|
|
121081
|
+
await this.inFlight;
|
|
121082
|
+
}
|
|
121083
|
+
/** Lazily insert the expanded reasoning panel, once, above the answer/footer. */
|
|
121084
|
+
async cotEnsurePanel() {
|
|
121085
|
+
if (this.cotPanelCreated) return;
|
|
121086
|
+
this.cotPanelCreated = true;
|
|
121087
|
+
const target = this.answerElementCreated ? CARDKIT_FINAL_ELEMENT_ID : CARDKIT_FOOTER_ELEMENT_ID;
|
|
121088
|
+
await this.next(
|
|
121089
|
+
(sequence) => this.cardKitClient.createElements(
|
|
121090
|
+
this.cardId,
|
|
121091
|
+
[buildCotPanelElement({ expanded: true, title: "\u601D\u8003\u4E2D\u2026", content: this.cotBuffer || "\u2026" })],
|
|
121092
|
+
{
|
|
121093
|
+
sequence,
|
|
121094
|
+
uuid: sequenceUuid(this.cardId, "cot-panel", sequence),
|
|
121095
|
+
type: "insert_before",
|
|
121096
|
+
targetElementId: target
|
|
121097
|
+
}
|
|
121098
|
+
)
|
|
121099
|
+
);
|
|
121100
|
+
this.onCotPanelCreated?.(CARDKIT_COT_PANEL_ELEMENT_ID);
|
|
121101
|
+
}
|
|
121102
|
+
cotPanelForFinalCard() {
|
|
121103
|
+
if (!this.cotPanelCreated) return void 0;
|
|
121104
|
+
return {
|
|
121105
|
+
title: this.cotErrored ? "\u601D\u8003\u8FC7\u7A0B\uFF08\u672C\u8F6E\u51FA\u9519\uFF09" : "\u601D\u8003\u8FC7\u7A0B",
|
|
121106
|
+
content: this.cotBuffer
|
|
121107
|
+
};
|
|
120753
121108
|
}
|
|
120754
121109
|
recordAnswerEvent(type2) {
|
|
120755
121110
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -120922,6 +121277,8 @@ async function createCardKitProgressHandle(opts) {
|
|
|
120922
121277
|
idempotencyKey: key,
|
|
120923
121278
|
patchIntervalMs: opts.patchIntervalMs ?? DEFAULT_PATCH_INTERVAL_MS,
|
|
120924
121279
|
maxProgressUpdates: opts.maxProgressUpdates ?? DEFAULT_MAX_PROGRESS_UPDATES,
|
|
121280
|
+
cot: opts.cot,
|
|
121281
|
+
onCotPanelCreated: opts.onCotPanelCreated,
|
|
120925
121282
|
onSequenceCommitted: opts.onSequenceCommitted,
|
|
120926
121283
|
onLiveMetricsChanged: opts.onLiveMetricsChanged
|
|
120927
121284
|
});
|
|
@@ -120986,6 +121343,369 @@ async function finalizeExistingCardKitCard(opts) {
|
|
|
120986
121343
|
return sequence;
|
|
120987
121344
|
}
|
|
120988
121345
|
|
|
121346
|
+
// src/bridge/cotProgress.ts
|
|
121347
|
+
var DEFAULT_THROTTLE_MS = 600;
|
|
121348
|
+
var COT_TOOL_RESULT_MAX2 = 1200;
|
|
121349
|
+
var COT_TEXT_MAX = 1200;
|
|
121350
|
+
var COT_INPUT_PREVIEW_MAX = 200;
|
|
121351
|
+
async function resolveCotTargets(client, hint) {
|
|
121352
|
+
const chatFallback = {
|
|
121353
|
+
chatId: hint.chatId,
|
|
121354
|
+
threadId: void 0,
|
|
121355
|
+
originMessageId: hint.originMessageId
|
|
121356
|
+
};
|
|
121357
|
+
const threadAttempt = (threadId) => ({
|
|
121358
|
+
chatId: hint.chatId,
|
|
121359
|
+
threadId,
|
|
121360
|
+
// origin is omitted on the wire for the thread channel (see
|
|
121361
|
+
// ChannelCotClient.create), so keeping it here is harmless.
|
|
121362
|
+
originMessageId: hint.originMessageId
|
|
121363
|
+
});
|
|
121364
|
+
if (hint.threadId && hint.threadId.startsWith("omt_")) {
|
|
121365
|
+
return [threadAttempt(hint.threadId), chatFallback];
|
|
121366
|
+
}
|
|
121367
|
+
if (hint.threadId && hint.originMessageId) {
|
|
121368
|
+
const omt = await client.resolveThreadId(hint.originMessageId);
|
|
121369
|
+
if (omt && omt.startsWith("omt_")) {
|
|
121370
|
+
return [threadAttempt(omt), chatFallback];
|
|
121371
|
+
}
|
|
121372
|
+
}
|
|
121373
|
+
return [chatFallback];
|
|
121374
|
+
}
|
|
121375
|
+
function truncate(value, max) {
|
|
121376
|
+
const text = String(value ?? "");
|
|
121377
|
+
return text.length > max ? `${text.slice(0, max)}...` : text;
|
|
121378
|
+
}
|
|
121379
|
+
function summarizeError2(err) {
|
|
121380
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
121381
|
+
return message.replace(/\s+/g, " ").trim().slice(0, 240) || "unknown error";
|
|
121382
|
+
}
|
|
121383
|
+
function makeEvent(eventType, content) {
|
|
121384
|
+
return { event_type: eventType, content: JSON.stringify(content), timestamp: Date.now() };
|
|
121385
|
+
}
|
|
121386
|
+
function payloadSummary(events) {
|
|
121387
|
+
return `payload=[${events.map((e) => `${e.event_type}:${e.content.length}`).join(",")}]`;
|
|
121388
|
+
}
|
|
121389
|
+
function briefToolTitle(name, input) {
|
|
121390
|
+
if (input && typeof input === "object") {
|
|
121391
|
+
const record = input;
|
|
121392
|
+
const command = record["command"] ?? record["cmd"];
|
|
121393
|
+
if (typeof command === "string" && command.trim()) {
|
|
121394
|
+
return `${name}: ${truncate(command.trim(), 80)}`;
|
|
121395
|
+
}
|
|
121396
|
+
const filePath = record["file_path"] ?? record["path"] ?? record["notebook_path"];
|
|
121397
|
+
if (typeof filePath === "string" && filePath.trim()) {
|
|
121398
|
+
return `${name}: ${truncate(filePath.trim(), 80)}`;
|
|
121399
|
+
}
|
|
121400
|
+
}
|
|
121401
|
+
return name;
|
|
121402
|
+
}
|
|
121403
|
+
function extractToolResultText(raw) {
|
|
121404
|
+
if (typeof raw !== "object" || raw === null) return "";
|
|
121405
|
+
const message = raw["message"];
|
|
121406
|
+
if (typeof message !== "object" || message === null) return "";
|
|
121407
|
+
const content = message["content"];
|
|
121408
|
+
if (!Array.isArray(content)) return "";
|
|
121409
|
+
const parts = [];
|
|
121410
|
+
for (const item of content) {
|
|
121411
|
+
if (typeof item !== "object" || item === null) continue;
|
|
121412
|
+
const block = item;
|
|
121413
|
+
if (block["type"] !== "tool_result") continue;
|
|
121414
|
+
const inner = block["content"];
|
|
121415
|
+
if (typeof inner === "string") {
|
|
121416
|
+
parts.push(inner);
|
|
121417
|
+
} else if (Array.isArray(inner)) {
|
|
121418
|
+
for (const piece of inner) {
|
|
121419
|
+
if (typeof piece === "object" && piece !== null) {
|
|
121420
|
+
const text = piece["text"];
|
|
121421
|
+
if (typeof text === "string") parts.push(text);
|
|
121422
|
+
}
|
|
121423
|
+
}
|
|
121424
|
+
}
|
|
121425
|
+
}
|
|
121426
|
+
return parts.join("\n").trim();
|
|
121427
|
+
}
|
|
121428
|
+
var LiveCotProgressHandle = class {
|
|
121429
|
+
cotClient;
|
|
121430
|
+
detail;
|
|
121431
|
+
runId;
|
|
121432
|
+
scope;
|
|
121433
|
+
throttleMs;
|
|
121434
|
+
reasoningMessageId;
|
|
121435
|
+
ref;
|
|
121436
|
+
_disabled = false;
|
|
121437
|
+
closed = false;
|
|
121438
|
+
buffer = [];
|
|
121439
|
+
timer;
|
|
121440
|
+
flushing;
|
|
121441
|
+
reasoningOpen = false;
|
|
121442
|
+
sawThinkingDelta = false;
|
|
121443
|
+
toolIndex = 0;
|
|
121444
|
+
/** FIFO of tool_use awaiting a tool_result — larkway events carry no id. */
|
|
121445
|
+
pendingTools = [];
|
|
121446
|
+
constructor(opts) {
|
|
121447
|
+
this.cotClient = opts.cotClient;
|
|
121448
|
+
this.detail = opts.detail;
|
|
121449
|
+
this.runId = opts.runId;
|
|
121450
|
+
this.scope = opts.scope;
|
|
121451
|
+
this.throttleMs = opts.throttleMs;
|
|
121452
|
+
this.reasoningMessageId = `reasoning-${opts.runId}`;
|
|
121453
|
+
}
|
|
121454
|
+
get disabled() {
|
|
121455
|
+
return this._disabled;
|
|
121456
|
+
}
|
|
121457
|
+
async start(target, inputPreview) {
|
|
121458
|
+
try {
|
|
121459
|
+
const attempts = await resolveCotTargets(this.cotClient, target);
|
|
121460
|
+
this.ref = await this.createWithFallback(attempts);
|
|
121461
|
+
if (!this.ref) {
|
|
121462
|
+
this._disabled = true;
|
|
121463
|
+
return;
|
|
121464
|
+
}
|
|
121465
|
+
this.enqueue("RUN_STARTED", {
|
|
121466
|
+
threadId: this.scope,
|
|
121467
|
+
runId: this.runId,
|
|
121468
|
+
input: { query: truncate(inputPreview, COT_INPUT_PREVIEW_MAX) }
|
|
121469
|
+
});
|
|
121470
|
+
} catch (err) {
|
|
121471
|
+
this._disabled = true;
|
|
121472
|
+
console.warn("[cot_progress] create failed; COT disabled for this run:", summarizeError2(err));
|
|
121473
|
+
}
|
|
121474
|
+
}
|
|
121475
|
+
/**
|
|
121476
|
+
* Try each create target in order, returning the first that succeeds. A
|
|
121477
|
+
* failed attempt with a next one queued (i.e. the thread channel, which our
|
|
121478
|
+
* tenant currently rejects) logs an info line and degrades to the next
|
|
121479
|
+
* (chat-level) channel — NOT a disable. Only when the last attempt fails do
|
|
121480
|
+
* we give up (caller disables). Never throws.
|
|
121481
|
+
*/
|
|
121482
|
+
async createWithFallback(attempts) {
|
|
121483
|
+
for (let i = 0; i < attempts.length; i++) {
|
|
121484
|
+
const attempt = attempts[i];
|
|
121485
|
+
try {
|
|
121486
|
+
const ref = await this.cotClient.create(attempt);
|
|
121487
|
+
console.info(
|
|
121488
|
+
"[cot_progress] created",
|
|
121489
|
+
`cotId=${ref.cotId}`,
|
|
121490
|
+
`channel=${attempt.threadId ? "thread" : "chat_id"}`,
|
|
121491
|
+
`messageId=${ref.messageId}`,
|
|
121492
|
+
// origin decides in-topic vs group-top anchoring (see handler) — log it
|
|
121493
|
+
// so a future anchoring failure is diagnosable from the create line.
|
|
121494
|
+
`origin=${attempt.originMessageId ?? "none"}`
|
|
121495
|
+
);
|
|
121496
|
+
return ref;
|
|
121497
|
+
} catch (err) {
|
|
121498
|
+
if (i < attempts.length - 1) {
|
|
121499
|
+
console.info(
|
|
121500
|
+
"[cot_progress] thread channel rejected, falling back to chat-level bubble:",
|
|
121501
|
+
summarizeError2(err)
|
|
121502
|
+
);
|
|
121503
|
+
} else {
|
|
121504
|
+
console.warn(
|
|
121505
|
+
"[cot_progress] create failed on all channels; COT disabled for this run:",
|
|
121506
|
+
summarizeError2(err)
|
|
121507
|
+
);
|
|
121508
|
+
}
|
|
121509
|
+
}
|
|
121510
|
+
}
|
|
121511
|
+
return void 0;
|
|
121512
|
+
}
|
|
121513
|
+
handle(event) {
|
|
121514
|
+
if (this._disabled || this.closed || !this.ref) return;
|
|
121515
|
+
switch (event.type) {
|
|
121516
|
+
case "thinking_delta":
|
|
121517
|
+
this.sawThinkingDelta = true;
|
|
121518
|
+
this.openReasoning();
|
|
121519
|
+
this.enqueue("REASONING_MESSAGE_CONTENT", {
|
|
121520
|
+
messageId: this.reasoningMessageId,
|
|
121521
|
+
delta: truncate(event.text, COT_TEXT_MAX)
|
|
121522
|
+
});
|
|
121523
|
+
break;
|
|
121524
|
+
case "thinking_snapshot":
|
|
121525
|
+
if (this.sawThinkingDelta) break;
|
|
121526
|
+
this.openReasoning();
|
|
121527
|
+
this.enqueue("REASONING_MESSAGE_CONTENT", {
|
|
121528
|
+
messageId: this.reasoningMessageId,
|
|
121529
|
+
delta: truncate(event.text, COT_TEXT_MAX)
|
|
121530
|
+
});
|
|
121531
|
+
break;
|
|
121532
|
+
case "tool_use":
|
|
121533
|
+
this.onToolUse(event.toolName, event.toolInput);
|
|
121534
|
+
break;
|
|
121535
|
+
case "tool_result":
|
|
121536
|
+
this.onToolResult(event.raw);
|
|
121537
|
+
break;
|
|
121538
|
+
default:
|
|
121539
|
+
break;
|
|
121540
|
+
}
|
|
121541
|
+
}
|
|
121542
|
+
onToolUse(toolName, toolInput) {
|
|
121543
|
+
this.closeReasoning();
|
|
121544
|
+
const toolCallId = `tool-${this.runId}-${++this.toolIndex}`;
|
|
121545
|
+
this.pendingTools.push({ id: toolCallId, name: toolName, input: toolInput });
|
|
121546
|
+
this.enqueue("TOOL_CALL_START", {
|
|
121547
|
+
toolCallId,
|
|
121548
|
+
toolCallName: toolName,
|
|
121549
|
+
title: briefToolTitle(toolName, toolInput)
|
|
121550
|
+
});
|
|
121551
|
+
if (this.detail === "detailed" && toolInput !== void 0 && toolInput !== null) {
|
|
121552
|
+
this.enqueue("TOOL_CALL_ARGS", {
|
|
121553
|
+
toolCallId,
|
|
121554
|
+
delta: truncate(JSON.stringify(toolInput), COT_TEXT_MAX)
|
|
121555
|
+
});
|
|
121556
|
+
}
|
|
121557
|
+
this.enqueue("TOOL_CALL_END", { toolCallId });
|
|
121558
|
+
}
|
|
121559
|
+
onToolResult(raw) {
|
|
121560
|
+
const pending = this.pendingTools.shift();
|
|
121561
|
+
if (this.detail !== "detailed") return;
|
|
121562
|
+
const toolCallId = pending?.id ?? `tool-${this.runId}-${this.toolIndex}`;
|
|
121563
|
+
const text = extractToolResultText(raw);
|
|
121564
|
+
this.enqueue("TOOL_CALL_RESULT", {
|
|
121565
|
+
toolCallId,
|
|
121566
|
+
content: text ? truncate(text, COT_TOOL_RESULT_MAX2) : "\u5DE5\u5177\u8C03\u7528\u5DF2\u5B8C\u6210"
|
|
121567
|
+
});
|
|
121568
|
+
}
|
|
121569
|
+
openReasoning() {
|
|
121570
|
+
if (this.reasoningOpen) return;
|
|
121571
|
+
this.reasoningOpen = true;
|
|
121572
|
+
this.enqueue("REASONING_START", { messageId: this.reasoningMessageId });
|
|
121573
|
+
this.enqueue("REASONING_MESSAGE_START", {
|
|
121574
|
+
messageId: this.reasoningMessageId,
|
|
121575
|
+
role: "reasoning"
|
|
121576
|
+
});
|
|
121577
|
+
}
|
|
121578
|
+
closeReasoning() {
|
|
121579
|
+
if (!this.reasoningOpen) return;
|
|
121580
|
+
this.reasoningOpen = false;
|
|
121581
|
+
this.enqueue("REASONING_MESSAGE_END", { messageId: this.reasoningMessageId });
|
|
121582
|
+
this.enqueue("REASONING_END", { messageId: this.reasoningMessageId });
|
|
121583
|
+
}
|
|
121584
|
+
/**
|
|
121585
|
+
* Terminal-state invariant: once a bubble exists (ref set), finalize ALWAYS
|
|
121586
|
+
* best-effort tears it down — even if a mid-run PUT already disabled us. A
|
|
121587
|
+
* "half-way self-disable" must never equal "bubble orphaned forever in
|
|
121588
|
+
* 思考中" (the real-machine Round B bug: a mid-stream PUT 400 disabled the
|
|
121589
|
+
* handle, and the old `if (_disabled) return` guards then skipped BOTH
|
|
121590
|
+
* RUN_FINISHED and complete). We stop accepting new stream events, then drive
|
|
121591
|
+
* teardown directly, each step independently try/caught:
|
|
121592
|
+
* (1) flush the backlog — only while still healthy (a disabled handle
|
|
121593
|
+
* abandons the backlog and jumps straight to the terminal PUT);
|
|
121594
|
+
* (2) a MINIMAL, balanced terminal PUT (close any open reasoning block +
|
|
121595
|
+
* RUN_FINISHED/RUN_ERROR) sent DIRECTLY, bypassing the _disabled gate;
|
|
121596
|
+
* (3) complete.
|
|
121597
|
+
* Any step failing warns and continues — the bubble must leave 思考中.
|
|
121598
|
+
*/
|
|
121599
|
+
async finalize(reason, opts) {
|
|
121600
|
+
if (this.closed || !this.ref) {
|
|
121601
|
+
this.closed = true;
|
|
121602
|
+
return;
|
|
121603
|
+
}
|
|
121604
|
+
this.closed = true;
|
|
121605
|
+
if (this.timer) {
|
|
121606
|
+
clearTimeout(this.timer);
|
|
121607
|
+
this.timer = void 0;
|
|
121608
|
+
}
|
|
121609
|
+
const ref = this.ref;
|
|
121610
|
+
if (!this._disabled) {
|
|
121611
|
+
try {
|
|
121612
|
+
await this.flush();
|
|
121613
|
+
} catch {
|
|
121614
|
+
}
|
|
121615
|
+
}
|
|
121616
|
+
const terminal = this.buildTerminalEvents(reason, opts);
|
|
121617
|
+
try {
|
|
121618
|
+
await this.cotClient.update(ref, terminal);
|
|
121619
|
+
} catch (err) {
|
|
121620
|
+
console.warn(
|
|
121621
|
+
"[cot_progress] terminal update failed (continuing to complete):",
|
|
121622
|
+
summarizeError2(err),
|
|
121623
|
+
payloadSummary(terminal)
|
|
121624
|
+
);
|
|
121625
|
+
}
|
|
121626
|
+
try {
|
|
121627
|
+
await this.cotClient.complete(ref, reason);
|
|
121628
|
+
console.info("[cot_progress] completed", `cotId=${ref.cotId}`, `reason=${reason}`);
|
|
121629
|
+
} catch (err) {
|
|
121630
|
+
console.warn("[cot_progress] complete failed (continuing):", summarizeError2(err));
|
|
121631
|
+
}
|
|
121632
|
+
}
|
|
121633
|
+
/**
|
|
121634
|
+
* The minimal terminal event batch: close any still-open reasoning block so
|
|
121635
|
+
* REASONING_MESSAGE/REASONING START/END stay balanced, then the run's
|
|
121636
|
+
* terminal marker. Tool calls need no closing here — onToolUse always emits
|
|
121637
|
+
* TOOL_CALL_END synchronously alongside START. Built directly (not via the
|
|
121638
|
+
* _disabled-gated enqueue) so it survives a mid-run disable.
|
|
121639
|
+
*/
|
|
121640
|
+
buildTerminalEvents(reason, opts) {
|
|
121641
|
+
const events = [];
|
|
121642
|
+
if (this.reasoningOpen) {
|
|
121643
|
+
this.reasoningOpen = false;
|
|
121644
|
+
events.push(makeEvent("REASONING_MESSAGE_END", { messageId: this.reasoningMessageId }));
|
|
121645
|
+
events.push(makeEvent("REASONING_END", { messageId: this.reasoningMessageId }));
|
|
121646
|
+
}
|
|
121647
|
+
if (reason === "error") {
|
|
121648
|
+
events.push(makeEvent("RUN_ERROR", { message: truncate(opts?.message ?? "run failed", COT_TEXT_MAX) }));
|
|
121649
|
+
} else {
|
|
121650
|
+
events.push(makeEvent("RUN_FINISHED", { threadId: this.scope, runId: this.runId, status: "done" }));
|
|
121651
|
+
}
|
|
121652
|
+
return events;
|
|
121653
|
+
}
|
|
121654
|
+
close() {
|
|
121655
|
+
this.closed = true;
|
|
121656
|
+
if (this.timer) {
|
|
121657
|
+
clearTimeout(this.timer);
|
|
121658
|
+
this.timer = void 0;
|
|
121659
|
+
}
|
|
121660
|
+
}
|
|
121661
|
+
enqueue(eventType, content) {
|
|
121662
|
+
if (this._disabled || !this.ref) return;
|
|
121663
|
+
this.buffer.push(makeEvent(eventType, content));
|
|
121664
|
+
this.scheduleFlush();
|
|
121665
|
+
}
|
|
121666
|
+
scheduleFlush() {
|
|
121667
|
+
if (this.timer || this.flushing || this._disabled) return;
|
|
121668
|
+
this.timer = setTimeout(() => {
|
|
121669
|
+
this.timer = void 0;
|
|
121670
|
+
void this.flush();
|
|
121671
|
+
}, this.throttleMs);
|
|
121672
|
+
this.timer.unref?.();
|
|
121673
|
+
}
|
|
121674
|
+
async flush() {
|
|
121675
|
+
if (this._disabled || !this.ref) return;
|
|
121676
|
+
if (this.flushing) {
|
|
121677
|
+
await this.flushing;
|
|
121678
|
+
if (this.buffer.length > 0 && !this._disabled) await this.flush();
|
|
121679
|
+
return;
|
|
121680
|
+
}
|
|
121681
|
+
const events = this.buffer.splice(0);
|
|
121682
|
+
if (events.length === 0) return;
|
|
121683
|
+
this.flushing = this.cotClient.update(this.ref, events).catch((err) => {
|
|
121684
|
+
this._disabled = true;
|
|
121685
|
+
console.warn(
|
|
121686
|
+
"[cot_progress] update failed; COT disabled for this run:",
|
|
121687
|
+
summarizeError2(err),
|
|
121688
|
+
payloadSummary(events)
|
|
121689
|
+
);
|
|
121690
|
+
}).finally(() => {
|
|
121691
|
+
this.flushing = void 0;
|
|
121692
|
+
if (this.buffer.length > 0 && !this._disabled) this.scheduleFlush();
|
|
121693
|
+
});
|
|
121694
|
+
await this.flushing;
|
|
121695
|
+
}
|
|
121696
|
+
};
|
|
121697
|
+
async function createCotProgressHandle(opts) {
|
|
121698
|
+
const handle = new LiveCotProgressHandle({
|
|
121699
|
+
cotClient: opts.cotClient,
|
|
121700
|
+
detail: opts.detail,
|
|
121701
|
+
runId: opts.runId,
|
|
121702
|
+
scope: opts.scope,
|
|
121703
|
+
throttleMs: opts.throttleMs ?? DEFAULT_THROTTLE_MS
|
|
121704
|
+
});
|
|
121705
|
+
await handle.start(opts.target, opts.inputPreview);
|
|
121706
|
+
return handle;
|
|
121707
|
+
}
|
|
121708
|
+
|
|
120989
121709
|
// src/lark/postContent.ts
|
|
120990
121710
|
function assertSafeUserId(userId) {
|
|
120991
121711
|
if (!/^[A-Za-z0-9_:-]+$/.test(userId)) {
|
|
@@ -121065,6 +121785,7 @@ function derivePostIdempotencyKey(input) {
|
|
|
121065
121785
|
// src/bridge/handler.ts
|
|
121066
121786
|
var DEFAULT_CARDKIT_RESPONSE_SURFACE_TIMEOUT_MS = 20 * 60 * 1e3;
|
|
121067
121787
|
var DEFAULT_CARDKIT_IDLE_TIMEOUT_MS = 3 * 60 * 1e3;
|
|
121788
|
+
var COT_BUBBLE_CREATE_BUDGET_MS = 3e3;
|
|
121068
121789
|
function summarizeMentionPolicyRules(rules) {
|
|
121069
121790
|
const counts = /* @__PURE__ */ new Map();
|
|
121070
121791
|
for (const rule of rules) {
|
|
@@ -121474,6 +122195,9 @@ var BridgeHandler = class {
|
|
|
121474
122195
|
async handleOne(event) {
|
|
121475
122196
|
const settleMessageId = event.message_id;
|
|
121476
122197
|
let settled = false;
|
|
122198
|
+
let cotPublisher;
|
|
122199
|
+
let bubbleCreate;
|
|
122200
|
+
let cotTurnOutcome = "done";
|
|
121477
122201
|
const settle = (ok) => {
|
|
121478
122202
|
if (settled) return;
|
|
121479
122203
|
settled = true;
|
|
@@ -121604,6 +122328,43 @@ var BridgeHandler = class {
|
|
|
121604
122328
|
console.warn("[bridge.handler] write CardKit live metrics failed:", err);
|
|
121605
122329
|
});
|
|
121606
122330
|
};
|
|
122331
|
+
const cotDetail = this.deps.botConfig?.cot ?? "brief";
|
|
122332
|
+
const cotSurface = this.deps.botConfig?.cotSurface ?? "bubble";
|
|
122333
|
+
const cotCardOption = cotDetail !== "off" && cotSurface === "card" ? { detail: cotDetail } : void 0;
|
|
122334
|
+
const createCotBubble = async (originMessageId) => {
|
|
122335
|
+
if (!(this.deps.cotClient && cotDetail !== "off" && cotSurface === "bubble")) return;
|
|
122336
|
+
if (bubbleCreate) return;
|
|
122337
|
+
bubbleCreate = createCotProgressHandle({
|
|
122338
|
+
cotClient: this.deps.cotClient,
|
|
122339
|
+
detail: cotDetail,
|
|
122340
|
+
runId: messageId,
|
|
122341
|
+
scope: threadId,
|
|
122342
|
+
inputPreview: parsed.text,
|
|
122343
|
+
target: {
|
|
122344
|
+
chatId: parsed.chatId,
|
|
122345
|
+
threadId: typeof parsed.raw.thread_id === "string" && parsed.raw.thread_id ? parsed.raw.thread_id : void 0,
|
|
122346
|
+
originMessageId
|
|
122347
|
+
}
|
|
122348
|
+
});
|
|
122349
|
+
const raced = await Promise.race([
|
|
122350
|
+
bubbleCreate.then((handle) => ({ ready: true, handle })),
|
|
122351
|
+
new Promise((resolve2) => {
|
|
122352
|
+
const t = setTimeout(
|
|
122353
|
+
() => resolve2({ ready: false }),
|
|
122354
|
+
this.deps.cotBubbleCreateBudgetMs ?? COT_BUBBLE_CREATE_BUDGET_MS
|
|
122355
|
+
);
|
|
122356
|
+
t.unref?.();
|
|
122357
|
+
})
|
|
122358
|
+
]);
|
|
122359
|
+
if (raced.ready) {
|
|
122360
|
+
cotPublisher = raced.handle;
|
|
122361
|
+
} else {
|
|
122362
|
+
void bubbleCreate.then((handle) => {
|
|
122363
|
+
cotPublisher = handle;
|
|
122364
|
+
});
|
|
122365
|
+
}
|
|
122366
|
+
};
|
|
122367
|
+
if (!isNewThread) await createCotBubble(messageId);
|
|
121607
122368
|
const createCardKitPlaceholder = async () => {
|
|
121608
122369
|
if (!card && cardKitAvailable && this.deps.cardKitClient) {
|
|
121609
122370
|
try {
|
|
@@ -121617,6 +122378,19 @@ var BridgeHandler = class {
|
|
|
121617
122378
|
triggerMessageId: messageId
|
|
121618
122379
|
},
|
|
121619
122380
|
initialStatusText: "\u52AA\u529B\u56DE\u7B54\u4E2D...",
|
|
122381
|
+
cot: cotCardOption,
|
|
122382
|
+
onCotPanelCreated: (elementId) => {
|
|
122383
|
+
void updateCardKitRecord({
|
|
122384
|
+
elements: {
|
|
122385
|
+
...cardKitRecord?.elements ?? {
|
|
122386
|
+
footer: { elementId: "footer_md" },
|
|
122387
|
+
final: { elementId: "final_md" }
|
|
122388
|
+
},
|
|
122389
|
+
thinking: { elementId }
|
|
122390
|
+
}
|
|
122391
|
+
}).catch(() => {
|
|
122392
|
+
});
|
|
122393
|
+
},
|
|
121620
122394
|
onSequenceCommitted: async (sequence) => {
|
|
121621
122395
|
await updateCardKitRecord({ status: "streaming", sequence });
|
|
121622
122396
|
},
|
|
@@ -121887,6 +122661,10 @@ var BridgeHandler = class {
|
|
|
121887
122661
|
console.warn("[bridge.handler] mtime fact computation failed (continuing):", err);
|
|
121888
122662
|
}
|
|
121889
122663
|
}
|
|
122664
|
+
if (isNewThread) {
|
|
122665
|
+
const anchorMessageId = cardKitProgress?.messageId ?? card?.messageId ?? messageId;
|
|
122666
|
+
await createCotBubble(anchorMessageId);
|
|
122667
|
+
}
|
|
121890
122668
|
let currentExisting = existing;
|
|
121891
122669
|
let attempt = 0;
|
|
121892
122670
|
while (true) {
|
|
@@ -122021,6 +122799,7 @@ var BridgeHandler = class {
|
|
|
122021
122799
|
}
|
|
122022
122800
|
if (cardKitProgress) cardKitProgress.handle(ev);
|
|
122023
122801
|
else if (card) card.handle(ev);
|
|
122802
|
+
if (cotPublisher) cotPublisher.handle(ev);
|
|
122024
122803
|
if (ev.type === "system_init") {
|
|
122025
122804
|
sessionId = ev.sessionId;
|
|
122026
122805
|
}
|
|
@@ -122035,6 +122814,14 @@ var BridgeHandler = class {
|
|
|
122035
122814
|
clearInterval(idleWatchdog);
|
|
122036
122815
|
idleWatchdog = void 0;
|
|
122037
122816
|
}
|
|
122817
|
+
cotTurnOutcome = interruptedByIdle ? "error" : "done";
|
|
122818
|
+
if (cotPublisher) {
|
|
122819
|
+
void cotPublisher.finalize(
|
|
122820
|
+
interruptedByIdle ? "error" : "done",
|
|
122821
|
+
interruptedByIdle ? { message: "idle timeout" } : void 0
|
|
122822
|
+
).catch(() => {
|
|
122823
|
+
});
|
|
122824
|
+
}
|
|
122038
122825
|
if (isAgentWorkspace && result.pooled === true) {
|
|
122039
122826
|
const sessionPidFile = path10.join(worktreePath, ".larkway", "runner.pid");
|
|
122040
122827
|
await pidFileWriteSettled;
|
|
@@ -122193,6 +122980,7 @@ var BridgeHandler = class {
|
|
|
122193
122980
|
});
|
|
122194
122981
|
}
|
|
122195
122982
|
try {
|
|
122983
|
+
if (!success) cardKitProgress.markCotError();
|
|
122196
122984
|
await cardKitProgress.finalize({
|
|
122197
122985
|
title: baseCardPayload.titleOverride,
|
|
122198
122986
|
finalText: baseCardPayload.finalText,
|
|
@@ -122341,6 +123129,11 @@ var BridgeHandler = class {
|
|
|
122341
123129
|
}
|
|
122342
123130
|
} catch (err) {
|
|
122343
123131
|
console.error("[bridge.handler] handleOne failed for thread", threadId, err);
|
|
123132
|
+
cotTurnOutcome = "error";
|
|
123133
|
+
if (cotPublisher) {
|
|
123134
|
+
void cotPublisher.finalize("error", { message: String(err) }).catch(() => {
|
|
123135
|
+
});
|
|
123136
|
+
}
|
|
122344
123137
|
await this.deps.client.removeProcessingReaction?.(messageId);
|
|
122345
123138
|
await recordEvent({
|
|
122346
123139
|
status: "failed",
|
|
@@ -122374,6 +123167,7 @@ var BridgeHandler = class {
|
|
|
122374
123167
|
};
|
|
122375
123168
|
if (!card && cardKitProgress) {
|
|
122376
123169
|
try {
|
|
123170
|
+
cardKitProgress.markCotError();
|
|
122377
123171
|
await cardKitProgress.finalize({
|
|
122378
123172
|
finalText: hardFailureText
|
|
122379
123173
|
});
|
|
@@ -122416,6 +123210,11 @@ var BridgeHandler = class {
|
|
|
122416
123210
|
}
|
|
122417
123211
|
}
|
|
122418
123212
|
} finally {
|
|
123213
|
+
cotPublisher?.close();
|
|
123214
|
+
if (bubbleCreate) {
|
|
123215
|
+
void bubbleCreate.then((handle) => handle.finalize(cotTurnOutcome).catch(() => {
|
|
123216
|
+
}));
|
|
123217
|
+
}
|
|
122419
123218
|
settle(false);
|
|
122420
123219
|
}
|
|
122421
123220
|
}
|
|
@@ -125095,9 +125894,9 @@ function writeScalar(state, string, level, iskey, inblock) {
|
|
|
125095
125894
|
}
|
|
125096
125895
|
function blockHeader(string, indentPerLevel) {
|
|
125097
125896
|
var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : "";
|
|
125098
|
-
var
|
|
125099
|
-
var keep =
|
|
125100
|
-
var chomp = keep ? "+" :
|
|
125897
|
+
var clip2 = string[string.length - 1] === "\n";
|
|
125898
|
+
var keep = clip2 && (string[string.length - 2] === "\n" || string === "\n");
|
|
125899
|
+
var chomp = keep ? "+" : clip2 ? "" : "-";
|
|
125101
125900
|
return indentIndicator + chomp + "\n";
|
|
125102
125901
|
}
|
|
125103
125902
|
function dropEndingNewline(string) {
|
|
@@ -125742,6 +126541,31 @@ var BotConfigSchema = external_exports.object({
|
|
|
125742
126541
|
* @default "claude"
|
|
125743
126542
|
*/
|
|
125744
126543
|
backend: external_exports.string().min(1).default("claude"),
|
|
126544
|
+
/**
|
|
126545
|
+
* COT (思维链) 气泡:把 agent 的 thinking 思考过程 + 工具调用摘要实时推到飞书
|
|
126546
|
+
* 原生的可折叠思维链气泡(与最终答案卡片互不干扰,最终答案永远只走卡片)。
|
|
126547
|
+
*
|
|
126548
|
+
* - "off":完全不调用 message_cot API(零网络、零副作用)。
|
|
126549
|
+
* - "brief"(默认):思考过程 + 工具名摘要。
|
|
126550
|
+
* - "detailed":额外推工具入参(TOOL_CALL_ARGS)与截断后的工具结果。
|
|
126551
|
+
*
|
|
126552
|
+
* message_cot 是无公开文档的 API —— 任何一步失败都会在本次会话内自动降级、
|
|
126553
|
+
* 只记 warn,绝不影响卡片和最终答案(见 src/bridge/cotProgress.ts)。
|
|
126554
|
+
*/
|
|
126555
|
+
cot: external_exports.enum(["off", "brief", "detailed"]).default("brief"),
|
|
126556
|
+
/**
|
|
126557
|
+
* COT 展示形态。`cot` 管密度(off/brief/detailed),这个管落点:
|
|
126558
|
+
* - "bubble"(默认):走飞书原生 message_cot 思维链气泡(src/bridge/cotProgress.ts)——
|
|
126559
|
+
* 客户端原生渲染(工具图标列表 + 可折叠头),真机体验最好。已知限制:话题内
|
|
126560
|
+
* 锚定不可用(气泡落群顶层,本租户 thread 通道判死),收尾 bug 已在 main 修复。
|
|
126561
|
+
* - "card":思考过程内嵌进答案卡片里的 collapsible_panel(懒创建、答案上方)。
|
|
126562
|
+
* ⚠️ 实验选项 —— 2026-07-05 真机实测:飞书客户端**不渲染 collapsible_panel 的
|
|
126563
|
+
* 折叠交互**(API 全 code=0,但面板被拍平成普通文本、无折叠箭头、终态也不可折叠;
|
|
126564
|
+
* CardKit 无 GET 读回、只能真机人眼验)。故 card 形态目前仅作纯文本内嵌展示用,
|
|
126565
|
+
* 体验不如气泡,不建议作默认。见 memory feishu-message-cot-api。
|
|
126566
|
+
* cot="off" 时本字段无意义(两种形态都不产出)。
|
|
126567
|
+
*/
|
|
126568
|
+
cotSurface: external_exports.enum(["card", "bubble"]).default("bubble"),
|
|
125745
126569
|
/**
|
|
125746
126570
|
* 话题 ↔ 飞书任务句柄(docs/task-handle.md,v2)。省略此字段不代表关闭,但也
|
|
125747
126571
|
* 不会触发任何自动建清单——main.ts 在 startup 时只做只读解析(yaml 里的
|
|
@@ -126772,6 +127596,9 @@ function* parseLinesMulti(line, answerExtractor = new AnswerChannelExtractor())
|
|
|
126772
127596
|
if (block["type"] === "text" && typeof block["text"] === "string") {
|
|
126773
127597
|
yield* answerExtractor.ingestGrowingSnapshot(block["text"], obj);
|
|
126774
127598
|
emitted = true;
|
|
127599
|
+
} else if (block["type"] === "thinking" && typeof block["thinking"] === "string") {
|
|
127600
|
+
yield { type: "thinking_snapshot", text: block["thinking"], raw: obj };
|
|
127601
|
+
emitted = true;
|
|
126775
127602
|
} else if (block["type"] === "tool_use") {
|
|
126776
127603
|
yield {
|
|
126777
127604
|
type: "tool_use",
|
|
@@ -126799,6 +127626,10 @@ function* parseLinesMulti(line, answerExtractor = new AnswerChannelExtractor())
|
|
|
126799
127626
|
yield* answerExtractor.ingestDelta(deltaRecord["text"], obj);
|
|
126800
127627
|
return;
|
|
126801
127628
|
}
|
|
127629
|
+
if (streamEvent["type"] === "content_block_delta" && deltaRecord["type"] === "thinking_delta" && typeof deltaRecord["thinking"] === "string") {
|
|
127630
|
+
yield { type: "thinking_delta", text: deltaRecord["thinking"], raw: obj };
|
|
127631
|
+
return;
|
|
127632
|
+
}
|
|
126802
127633
|
}
|
|
126803
127634
|
}
|
|
126804
127635
|
yield { type: "raw", raw: obj };
|
|
@@ -127727,7 +128558,10 @@ function buildCodexEnv(botGitIdentity, gitlabToken) {
|
|
|
127727
128558
|
}
|
|
127728
128559
|
function buildCodexCommand(opts, codexBinPath = "codex") {
|
|
127729
128560
|
void opts;
|
|
127730
|
-
return [
|
|
128561
|
+
return [
|
|
128562
|
+
codexBinPath,
|
|
128563
|
+
["-c", "model_reasoning_summary=detailed", "app-server", "--stdio"]
|
|
128564
|
+
];
|
|
127731
128565
|
}
|
|
127732
128566
|
function codexThreadSandboxMode(mode) {
|
|
127733
128567
|
return mode === "ask" ? "read-only" : "danger-full-access";
|
|
@@ -127777,6 +128611,16 @@ var CodexAppServerLineParser = class {
|
|
|
127777
128611
|
yield* this.answerExtractor.ingestDelta(delta, obj);
|
|
127778
128612
|
return;
|
|
127779
128613
|
}
|
|
128614
|
+
if (method === "item/reasoning/summaryTextDelta") {
|
|
128615
|
+
const delta = typeof params?.["delta"] === "string" ? params["delta"] : "";
|
|
128616
|
+
if (delta) yield { type: "thinking_delta", text: delta, raw: obj };
|
|
128617
|
+
return;
|
|
128618
|
+
}
|
|
128619
|
+
if (method === "item/reasoning/summaryPartAdded") {
|
|
128620
|
+
const summaryIndex = typeof params?.["summaryIndex"] === "number" ? params["summaryIndex"] : 0;
|
|
128621
|
+
if (summaryIndex > 0) yield { type: "thinking_delta", text: "\n\n", raw: obj };
|
|
128622
|
+
return;
|
|
128623
|
+
}
|
|
127780
128624
|
if (method === "item/started") {
|
|
127781
128625
|
const item = asRecord(params?.["item"]);
|
|
127782
128626
|
if (item?.["type"] === "commandExecution" && typeof item["command"] === "string") {
|
|
@@ -127800,11 +128644,20 @@ var CodexAppServerLineParser = class {
|
|
|
127800
128644
|
yield* this.answerExtractor.ingestSnapshot(item["text"], obj);
|
|
127801
128645
|
return;
|
|
127802
128646
|
}
|
|
128647
|
+
if (item?.["type"] === "reasoning") {
|
|
128648
|
+
const summary = reasoningSummaryText(item["summary"]);
|
|
128649
|
+
if (summary) yield { type: "thinking_snapshot", text: summary, raw: obj };
|
|
128650
|
+
return;
|
|
128651
|
+
}
|
|
127803
128652
|
return;
|
|
127804
128653
|
}
|
|
127805
128654
|
yield { type: "raw", raw: obj };
|
|
127806
128655
|
}
|
|
127807
128656
|
};
|
|
128657
|
+
function reasoningSummaryText(summary) {
|
|
128658
|
+
if (!Array.isArray(summary)) return "";
|
|
128659
|
+
return summary.filter((s) => typeof s === "string" && s.length > 0).join("\n\n");
|
|
128660
|
+
}
|
|
127808
128661
|
function asRecord(value) {
|
|
127809
128662
|
return typeof value === "object" && value !== null ? value : void 0;
|
|
127810
128663
|
}
|
|
@@ -129186,7 +130039,7 @@ function isTaskRequestTimeoutError(err) {
|
|
|
129186
130039
|
if (err instanceof TaskApiError && err.cause instanceof TaskRequestTimeoutError) return true;
|
|
129187
130040
|
return false;
|
|
129188
130041
|
}
|
|
129189
|
-
function
|
|
130042
|
+
function withTimeout2(promise, ms, label) {
|
|
129190
130043
|
let timer;
|
|
129191
130044
|
const timeout = new Promise((_, reject) => {
|
|
129192
130045
|
timer = setTimeout(() => reject(new TaskRequestTimeoutError(`${label} timed out after ${ms}ms`)), ms);
|
|
@@ -129203,7 +130056,7 @@ var TaskListClient = class {
|
|
|
129203
130056
|
}
|
|
129204
130057
|
/** Single choke point for every outbound call — applies the timeout race uniformly. */
|
|
129205
130058
|
#request(config, label) {
|
|
129206
|
-
return
|
|
130059
|
+
return withTimeout2(this.#requester.request(config), this.#timeoutMs, label);
|
|
129207
130060
|
}
|
|
129208
130061
|
async getTask(taskGuid) {
|
|
129209
130062
|
let resp;
|
|
@@ -129521,13 +130374,13 @@ function mergeDescriptionSnapshot(original, input) {
|
|
|
129521
130374
|
return `${humanPart}${sep}${block}`;
|
|
129522
130375
|
}
|
|
129523
130376
|
var FAILURE_COMMENT_MAX_LEN = 500;
|
|
129524
|
-
function
|
|
130377
|
+
function truncate2(text, max) {
|
|
129525
130378
|
if (text.length <= max) return text;
|
|
129526
130379
|
return `${text.slice(0, max)}\u2026(\u622A\u65AD)`;
|
|
129527
130380
|
}
|
|
129528
130381
|
function renderFailureComment(failureReason) {
|
|
129529
130382
|
return `\u26A0\uFE0F \u672C\u8F6E\u6267\u884C\u5931\u8D25
|
|
129530
|
-
${
|
|
130383
|
+
${truncate2(failureReason ?? "\u672A\u77E5\u539F\u56E0", FAILURE_COMMENT_MAX_LEN)}`;
|
|
129531
130384
|
}
|
|
129532
130385
|
async function applyTaskHandleWriteback(patch, deps) {
|
|
129533
130386
|
try {
|
|
@@ -129782,7 +130635,8 @@ function renderCandidateUnboundAlertComment() {
|
|
|
129782
130635
|
return "\u26A0\uFE0F \u6B64\u4EFB\u52A1\u672A\u80FD\u81EA\u52A8\u5173\u8054\u5230\u4EFB\u4F55\u8BDD\u9898:\u8BF7\u68C0\u67E5\u4EFB\u52A1\u6807\u9898\u662F\u5426\u4E0E\u8BDD\u9898\u6839\u6D88\u606F\u4E00\u81F4,\u6216\u5728\u5BF9\u5E94\u8BDD\u9898\u91CC @ \u4E00\u6B21 agent \u8BA9\u5B83\u8BA4\u9886\u8FD9\u4E2A\u4EFB\u52A1\u3002";
|
|
129783
130636
|
}
|
|
129784
130637
|
function normalizeForExactMatch(text) {
|
|
129785
|
-
|
|
130638
|
+
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
130639
|
+
return collapsed.replace(/^(?:@\S+\s+)+/, "").trim();
|
|
129786
130640
|
}
|
|
129787
130641
|
function isBridgeTouched(description) {
|
|
129788
130642
|
return typeof description === "string" && description.includes(STATUS_SNAPSHOT_MARKER);
|
|
@@ -130804,6 +131658,7 @@ async function runV2Mode({
|
|
|
130804
131658
|
const cardKitClient = shouldProvideResponseSurfaceCardKitClient(
|
|
130805
131659
|
bot.response_surface_prototype
|
|
130806
131660
|
) ? client.outboundCardKitClient() : void 0;
|
|
131661
|
+
const cotClient = bot.cot !== "off" && bot.cotSurface === "bubble" ? client.outboundCotClient() : void 0;
|
|
130807
131662
|
let effectiveTaskHandleTasklistGuid;
|
|
130808
131663
|
let taskHandleLifecycle;
|
|
130809
131664
|
let taskHandleClaim;
|
|
@@ -130814,7 +131669,11 @@ async function runV2Mode({
|
|
|
130814
131669
|
{
|
|
130815
131670
|
const guid = bot.taskHandle?.tasklistGuid ?? await readTeamTasklistGuid(resolveTaskTeamRegistryPath());
|
|
130816
131671
|
if (guid) {
|
|
130817
|
-
const taskSdkClient = new import_node_sdk2.Client({
|
|
131672
|
+
const taskSdkClient = new import_node_sdk2.Client({
|
|
131673
|
+
appId: bot.app_id,
|
|
131674
|
+
appSecret,
|
|
131675
|
+
loggerLevel: import_node_sdk2.LoggerLevel.fatal
|
|
131676
|
+
});
|
|
130818
131677
|
const taskRequester = {
|
|
130819
131678
|
request: (config2) => taskSdkClient.request(config2)
|
|
130820
131679
|
};
|
|
@@ -131021,9 +131880,12 @@ async function runV2Mode({
|
|
|
131021
131880
|
response_surface_prototype: bot.response_surface_prototype,
|
|
131022
131881
|
taskHandle: effectiveTaskHandleTasklistGuid ? { tasklistGuid: effectiveTaskHandleTasklistGuid } : void 0,
|
|
131023
131882
|
model: bot.model,
|
|
131024
|
-
effort: bot.effort
|
|
131883
|
+
effort: bot.effort,
|
|
131884
|
+
cot: bot.cot,
|
|
131885
|
+
cotSurface: bot.cotSurface
|
|
131025
131886
|
},
|
|
131026
131887
|
cardKitClient,
|
|
131888
|
+
cotClient,
|
|
131027
131889
|
postClient,
|
|
131028
131890
|
gitlabToken: effectiveGitlabToken,
|
|
131029
131891
|
agentMemory: bot.agent_memory,
|