larkway 0.3.22 → 0.3.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/README.md +1 -1
- package/README.zh.md +1 -1
- package/dist/cli/index.js +23 -9
- package/dist/main.js +322 -174
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
You @ the bot in a Feishu thread. It runs on your machine — reading your real codebase, executing commands, opening MRs — and posts the result back. You define what the agent knows and what it can do. Larkway just carries the messages.
|
|
10
10
|
|
|
11
|
-
**Current release: v0.3.
|
|
11
|
+
**Current release: v0.3.24**
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
package/README.zh.md
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -111185,6 +111185,7 @@ var init_channelCardClient = __esm({
|
|
|
111185
111185
|
// src/lark/channelCardKitClient.ts
|
|
111186
111186
|
import { createHash } from "node:crypto";
|
|
111187
111187
|
function isRetryable2(err2) {
|
|
111188
|
+
if (err2 instanceof CardKitReplyConversionError) return true;
|
|
111188
111189
|
if (!(err2 instanceof Error)) return false;
|
|
111189
111190
|
const msg = err2.message.toLowerCase();
|
|
111190
111191
|
if (msg.includes("200810")) return true;
|
|
@@ -111227,10 +111228,21 @@ async function withCardKitRetry(label, fn, opts) {
|
|
|
111227
111228
|
}
|
|
111228
111229
|
throw lastErr;
|
|
111229
111230
|
}
|
|
111230
|
-
var ChannelCardKitClient;
|
|
111231
|
+
var CardKitReplyConversionError, ChannelCardKitClient;
|
|
111231
111232
|
var init_channelCardKitClient = __esm({
|
|
111232
111233
|
"src/lark/channelCardKitClient.ts"() {
|
|
111233
111234
|
"use strict";
|
|
111235
|
+
CardKitReplyConversionError = class extends Error {
|
|
111236
|
+
messageId;
|
|
111237
|
+
constructor(messageId, cause) {
|
|
111238
|
+
super(
|
|
111239
|
+
`[channel.cardkit] card.idConvert returned no card_id (messageId=${messageId})`
|
|
111240
|
+
);
|
|
111241
|
+
this.name = "CardKitReplyConversionError";
|
|
111242
|
+
this.messageId = messageId;
|
|
111243
|
+
this.cause = cause;
|
|
111244
|
+
}
|
|
111245
|
+
};
|
|
111234
111246
|
ChannelCardKitClient = class {
|
|
111235
111247
|
resolveChannel;
|
|
111236
111248
|
cardThreads;
|
|
@@ -111283,17 +111295,19 @@ var init_channelCardKitClient = __esm({
|
|
|
111283
111295
|
}
|
|
111284
111296
|
const converted = await withCardKitRetry(
|
|
111285
111297
|
"idConvert",
|
|
111286
|
-
() =>
|
|
111287
|
-
|
|
111288
|
-
|
|
111298
|
+
async () => {
|
|
111299
|
+
const converted2 = await this.channel().rawClient.cardkit.v1.card.idConvert({
|
|
111300
|
+
data: { message_id: messageId }
|
|
111301
|
+
});
|
|
111302
|
+
if (!converted2.data?.card_id) {
|
|
111303
|
+
throw new CardKitReplyConversionError(messageId);
|
|
111304
|
+
}
|
|
111305
|
+
return converted2;
|
|
111306
|
+
},
|
|
111289
111307
|
{ maxAttempts: this.maxAttempts, baseDelayMs: this.baseDelayMs }
|
|
111290
111308
|
);
|
|
111291
111309
|
const cardId = converted.data?.card_id;
|
|
111292
|
-
if (!cardId)
|
|
111293
|
-
throw new Error(
|
|
111294
|
-
`[channel.cardkit] card.idConvert returned no card_id (messageId=${messageId})`
|
|
111295
|
-
);
|
|
111296
|
-
}
|
|
111310
|
+
if (!cardId) throw new CardKitReplyConversionError(messageId);
|
|
111297
111311
|
this.cardThreads.set(messageId, opts.threadId ?? replyToMessageId);
|
|
111298
111312
|
return { cardId, messageId };
|
|
111299
111313
|
}
|
package/dist/main.js
CHANGED
|
@@ -115422,7 +115422,22 @@ var ChannelCardClient = class {
|
|
|
115422
115422
|
|
|
115423
115423
|
// src/lark/channelCardKitClient.ts
|
|
115424
115424
|
import { createHash } from "node:crypto";
|
|
115425
|
+
var CardKitReplyConversionError = class extends Error {
|
|
115426
|
+
messageId;
|
|
115427
|
+
constructor(messageId, cause) {
|
|
115428
|
+
super(
|
|
115429
|
+
`[channel.cardkit] card.idConvert returned no card_id (messageId=${messageId})`
|
|
115430
|
+
);
|
|
115431
|
+
this.name = "CardKitReplyConversionError";
|
|
115432
|
+
this.messageId = messageId;
|
|
115433
|
+
this.cause = cause;
|
|
115434
|
+
}
|
|
115435
|
+
};
|
|
115436
|
+
function cardKitReplyConversionMessageId(err) {
|
|
115437
|
+
return err instanceof CardKitReplyConversionError ? err.messageId : void 0;
|
|
115438
|
+
}
|
|
115425
115439
|
function isRetryable2(err) {
|
|
115440
|
+
if (err instanceof CardKitReplyConversionError) return true;
|
|
115426
115441
|
if (!(err instanceof Error)) return false;
|
|
115427
115442
|
const msg = err.message.toLowerCase();
|
|
115428
115443
|
if (msg.includes("200810")) return true;
|
|
@@ -115520,17 +115535,19 @@ var ChannelCardKitClient = class {
|
|
|
115520
115535
|
}
|
|
115521
115536
|
const converted = await withCardKitRetry(
|
|
115522
115537
|
"idConvert",
|
|
115523
|
-
() =>
|
|
115524
|
-
|
|
115525
|
-
|
|
115538
|
+
async () => {
|
|
115539
|
+
const converted2 = await this.channel().rawClient.cardkit.v1.card.idConvert({
|
|
115540
|
+
data: { message_id: messageId }
|
|
115541
|
+
});
|
|
115542
|
+
if (!converted2.data?.card_id) {
|
|
115543
|
+
throw new CardKitReplyConversionError(messageId);
|
|
115544
|
+
}
|
|
115545
|
+
return converted2;
|
|
115546
|
+
},
|
|
115526
115547
|
{ maxAttempts: this.maxAttempts, baseDelayMs: this.baseDelayMs }
|
|
115527
115548
|
);
|
|
115528
115549
|
const cardId = converted.data?.card_id;
|
|
115529
|
-
if (!cardId)
|
|
115530
|
-
throw new Error(
|
|
115531
|
-
`[channel.cardkit] card.idConvert returned no card_id (messageId=${messageId})`
|
|
115532
|
-
);
|
|
115533
|
-
}
|
|
115550
|
+
if (!cardId) throw new CardKitReplyConversionError(messageId);
|
|
115534
115551
|
this.cardThreads.set(messageId, opts.threadId ?? replyToMessageId);
|
|
115535
115552
|
return { cardId, messageId };
|
|
115536
115553
|
}
|
|
@@ -116732,20 +116749,6 @@ var ChannelClient = class {
|
|
|
116732
116749
|
};
|
|
116733
116750
|
|
|
116734
116751
|
// src/lark/card.ts
|
|
116735
|
-
function summarizeInput(input) {
|
|
116736
|
-
if (input === null || input === void 0) return "";
|
|
116737
|
-
let s;
|
|
116738
|
-
if (typeof input === "string") {
|
|
116739
|
-
s = input;
|
|
116740
|
-
} else if (typeof input === "object") {
|
|
116741
|
-
const obj = input;
|
|
116742
|
-
const snippet2 = obj["command"] ?? obj["path"] ?? obj["file_path"] ?? obj["description"] ?? null;
|
|
116743
|
-
s = snippet2 != null ? String(snippet2) : JSON.stringify(input);
|
|
116744
|
-
} else {
|
|
116745
|
-
s = String(input);
|
|
116746
|
-
}
|
|
116747
|
-
return s.length > 60 ? s.slice(0, 57) + "\u2026" : s;
|
|
116748
|
-
}
|
|
116749
116752
|
var MAX_CARD_ELEMENTS = 50;
|
|
116750
116753
|
var CHOICE_MARKERS = ["A", "B", "C", "D", "E"];
|
|
116751
116754
|
function choiceMarker(i) {
|
|
@@ -116896,7 +116899,7 @@ ${recent.join("\n")}` : recent.join("\n");
|
|
|
116896
116899
|
} else if (opts.status === "thinking") {
|
|
116897
116900
|
pushElement(elements, {
|
|
116898
116901
|
tag: "markdown",
|
|
116899
|
-
content: "\
|
|
116902
|
+
content: "\u52AA\u529B\u56DE\u7B54\u4E2D..."
|
|
116900
116903
|
});
|
|
116901
116904
|
}
|
|
116902
116905
|
if (opts.status === "failure" && opts.failureReason) {
|
|
@@ -116923,7 +116926,7 @@ ${recent.join("\n")}` : recent.join("\n");
|
|
|
116923
116926
|
pushElement(elements, buildChoiceRow(opts.choices));
|
|
116924
116927
|
}
|
|
116925
116928
|
const headerColor = opts.status === "thinking" || opts.status === "streaming" ? "blue" : opts.status === "success" ? "green" : "red";
|
|
116926
|
-
const statusText = opts.status === "thinking" ? "\
|
|
116929
|
+
const statusText = opts.status === "thinking" ? "\u5904\u7406\u4E2D" : opts.status === "streaming" ? "\u56DE\u7B54\u4E2D" : opts.status === "success" ? "\u2705 \u5B8C\u6210" : "\u274C \u51FA\u9519\u4E86";
|
|
116927
116930
|
const headerTitle = opts.titleOverride ?? statusText;
|
|
116928
116931
|
const card = {
|
|
116929
116932
|
schema: "2.0",
|
|
@@ -116948,7 +116951,6 @@ var CardHandleImpl = class {
|
|
|
116948
116951
|
showToolSummary;
|
|
116949
116952
|
state = {
|
|
116950
116953
|
textBuffer: "",
|
|
116951
|
-
currentRawMsgId: null,
|
|
116952
116954
|
toolStatusLines: [],
|
|
116953
116955
|
lastPatchAt: 0,
|
|
116954
116956
|
pendingPatch: null
|
|
@@ -116960,7 +116962,7 @@ var CardHandleImpl = class {
|
|
|
116960
116962
|
* before its own PATCH so the finalize is guaranteed to land LAST. Tracking
|
|
116961
116963
|
* only "the latest" is insufficient: an older retry can still be in flight
|
|
116962
116964
|
* after a newer live patch overwrote the pointer, then land after finalize and
|
|
116963
|
-
* flip the Feishu card back to
|
|
116965
|
+
* flip the Feishu card back to the in-progress render.
|
|
116964
116966
|
*/
|
|
116965
116967
|
livePatchesInFlight = /* @__PURE__ */ new Set();
|
|
116966
116968
|
constructor(opts) {
|
|
@@ -116972,8 +116974,9 @@ var CardHandleImpl = class {
|
|
|
116972
116974
|
// ── Public: handle ────────────────────────────────────────────────────────
|
|
116973
116975
|
handle(event) {
|
|
116974
116976
|
if (this.finalized) return;
|
|
116975
|
-
this.accumulate(event)
|
|
116976
|
-
|
|
116977
|
+
if (this.accumulate(event)) {
|
|
116978
|
+
this.scheduleThrottledPatch();
|
|
116979
|
+
}
|
|
116977
116980
|
}
|
|
116978
116981
|
// ── Public: finalize ─────────────────────────────────────────────────────
|
|
116979
116982
|
async finalize(opts) {
|
|
@@ -117014,37 +117017,14 @@ var CardHandleImpl = class {
|
|
|
117014
117017
|
}
|
|
117015
117018
|
// ── Private: accumulate ───────────────────────────────────────────────────
|
|
117016
117019
|
accumulate(event) {
|
|
117017
|
-
if (event.type === "
|
|
117018
|
-
|
|
117019
|
-
|
|
117020
|
-
|
|
117021
|
-
|
|
117022
|
-
|
|
117023
|
-
this.state.currentRawMsgId = rawMsgId;
|
|
117024
|
-
this.state.textBuffer += event.text;
|
|
117025
|
-
} else {
|
|
117026
|
-
if (this.state.currentRawMsgId === null) {
|
|
117027
|
-
this.state.currentRawMsgId = rawMsgId;
|
|
117028
|
-
}
|
|
117029
|
-
const prevTurnEnd = this.findPrevTurnEnd();
|
|
117030
|
-
this.state.textBuffer = this.state.textBuffer.slice(0, prevTurnEnd) + event.text;
|
|
117031
|
-
}
|
|
117032
|
-
} else if (event.type === "tool_use" && this.showToolSummary) {
|
|
117033
|
-
const summary = summarizeInput(event.toolInput);
|
|
117034
|
-
const line = summary ? `\u{1F527} ${event.toolName} ${summary}` : `\u{1F527} ${event.toolName}`;
|
|
117035
|
-
this.state.toolStatusLines.push(line);
|
|
117020
|
+
if (event.type === "answer_delta") {
|
|
117021
|
+
this.state.textBuffer += event.text;
|
|
117022
|
+
return true;
|
|
117023
|
+
} else if (event.type === "answer_snapshot") {
|
|
117024
|
+
this.state.textBuffer = event.text;
|
|
117025
|
+
return true;
|
|
117036
117026
|
}
|
|
117037
|
-
|
|
117038
|
-
/**
|
|
117039
|
-
* Returns the character offset in textBuffer where the CURRENT turn's text
|
|
117040
|
-
* starts. If there is only one turn, returns 0.
|
|
117041
|
-
*/
|
|
117042
|
-
findPrevTurnEnd() {
|
|
117043
|
-
if (!this.state.textBuffer) return 0;
|
|
117044
|
-
const sep = "\n\n";
|
|
117045
|
-
const lastSep = this.state.textBuffer.lastIndexOf(sep);
|
|
117046
|
-
if (lastSep === -1) return 0;
|
|
117047
|
-
return lastSep + sep.length;
|
|
117027
|
+
return false;
|
|
117048
117028
|
}
|
|
117049
117029
|
// ── Private: throttle ────────────────────────────────────────────────────
|
|
117050
117030
|
scheduleThrottledPatch() {
|
|
@@ -117117,14 +117097,6 @@ var CardHandleImpl = class {
|
|
|
117117
117097
|
await this.livePatchWithRetry(cardJsonStr);
|
|
117118
117098
|
}
|
|
117119
117099
|
};
|
|
117120
|
-
function extractRawMessageId(raw) {
|
|
117121
|
-
if (typeof raw !== "object" || raw === null) return null;
|
|
117122
|
-
const rec = raw;
|
|
117123
|
-
const msg = rec["message"];
|
|
117124
|
-
if (typeof msg !== "object" || msg === null) return null;
|
|
117125
|
-
const id = msg["id"];
|
|
117126
|
-
return typeof id === "string" ? id : null;
|
|
117127
|
-
}
|
|
117128
117100
|
async function createCardWithRetry(outbound, replyToMessageId, cardJson, opts, maxAttempts = 3) {
|
|
117129
117101
|
let lastErr;
|
|
117130
117102
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
@@ -117672,6 +117644,108 @@ function deriveTriggerFacts(parsed, isNewThread, larkCliProfile) {
|
|
|
117672
117644
|
};
|
|
117673
117645
|
}
|
|
117674
117646
|
|
|
117647
|
+
// src/agent/answerChannel.ts
|
|
117648
|
+
var ANSWER_BEGIN_MARKER = "LARKWAY_ANSWER_BEGIN";
|
|
117649
|
+
var ANSWER_END_MARKER = "LARKWAY_ANSWER_END";
|
|
117650
|
+
var STREAM_HOLD_CHARS = ANSWER_END_MARKER.length + 2;
|
|
117651
|
+
function stripLeadingNewline(text) {
|
|
117652
|
+
return text.replace(/^\r?\n/, "");
|
|
117653
|
+
}
|
|
117654
|
+
function stripTrailingNewline(text) {
|
|
117655
|
+
return text.replace(/\r?\n$/, "");
|
|
117656
|
+
}
|
|
117657
|
+
function markerLineIndex(text, marker) {
|
|
117658
|
+
const re = new RegExp(`(^|\\r?\\n)${marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(\\r?\\n|$)`);
|
|
117659
|
+
const match = re.exec(text);
|
|
117660
|
+
if (!match || match.index == null) return null;
|
|
117661
|
+
const lineStart = match.index + (match[1]?.length ?? 0);
|
|
117662
|
+
const lineEnd = lineStart + marker.length;
|
|
117663
|
+
const after = lineEnd + (match[2]?.length ?? 0);
|
|
117664
|
+
return { start: lineStart, end: after };
|
|
117665
|
+
}
|
|
117666
|
+
function hasUsefulText(text) {
|
|
117667
|
+
return text.length > 0;
|
|
117668
|
+
}
|
|
117669
|
+
function splitAnswerChannelText(text, raw) {
|
|
117670
|
+
const begin = markerLineIndex(text, ANSWER_BEGIN_MARKER);
|
|
117671
|
+
if (!begin) return [{ type: "internal_text", text, raw }];
|
|
117672
|
+
const before = stripTrailingNewline(text.slice(0, begin.start));
|
|
117673
|
+
const afterBegin = text.slice(begin.end);
|
|
117674
|
+
const end = markerLineIndex(afterBegin, ANSWER_END_MARKER);
|
|
117675
|
+
const answer = stripLeadingNewline(end ? afterBegin.slice(0, end.start) : afterBegin);
|
|
117676
|
+
const trailing = end ? stripLeadingNewline(afterBegin.slice(end.end)) : "";
|
|
117677
|
+
const events = [];
|
|
117678
|
+
if (before.trim()) events.push({ type: "internal_text", text: before, raw });
|
|
117679
|
+
events.push({ type: "answer_snapshot", text: stripTrailingNewline(answer), raw });
|
|
117680
|
+
if (trailing.trim()) events.push({ type: "internal_text", text: trailing, raw });
|
|
117681
|
+
return events;
|
|
117682
|
+
}
|
|
117683
|
+
var AnswerChannelExtractor = class {
|
|
117684
|
+
mode = "waiting";
|
|
117685
|
+
buffer = "";
|
|
117686
|
+
visibleText = "";
|
|
117687
|
+
ingestDelta(text, raw) {
|
|
117688
|
+
if (!text || this.mode === "closed") return [];
|
|
117689
|
+
this.buffer += text;
|
|
117690
|
+
return this.drain(raw);
|
|
117691
|
+
}
|
|
117692
|
+
ingestSnapshot(text, raw) {
|
|
117693
|
+
const events = splitAnswerChannelText(text, raw);
|
|
117694
|
+
const out = [];
|
|
117695
|
+
for (const event of events) {
|
|
117696
|
+
if (event.type !== "answer_snapshot") {
|
|
117697
|
+
out.push(event);
|
|
117698
|
+
continue;
|
|
117699
|
+
}
|
|
117700
|
+
if (event.text === this.visibleText) continue;
|
|
117701
|
+
this.visibleText = event.text;
|
|
117702
|
+
out.push(event);
|
|
117703
|
+
if (text.includes(ANSWER_END_MARKER)) this.mode = "closed";
|
|
117704
|
+
}
|
|
117705
|
+
return out;
|
|
117706
|
+
}
|
|
117707
|
+
drain(raw) {
|
|
117708
|
+
const events = [];
|
|
117709
|
+
if (this.mode === "waiting") {
|
|
117710
|
+
const begin = markerLineIndex(this.buffer, ANSWER_BEGIN_MARKER);
|
|
117711
|
+
if (!begin) {
|
|
117712
|
+
this.trimWaitingBuffer();
|
|
117713
|
+
return events;
|
|
117714
|
+
}
|
|
117715
|
+
const before = stripTrailingNewline(this.buffer.slice(0, begin.start));
|
|
117716
|
+
if (before.trim()) events.push({ type: "internal_text", text: before, raw });
|
|
117717
|
+
this.buffer = this.buffer.slice(begin.end);
|
|
117718
|
+
this.mode = "answer";
|
|
117719
|
+
}
|
|
117720
|
+
if (this.mode !== "answer") return events;
|
|
117721
|
+
const end = markerLineIndex(this.buffer, ANSWER_END_MARKER);
|
|
117722
|
+
if (end) {
|
|
117723
|
+
const answerTail = stripTrailingNewline(this.buffer.slice(0, end.start));
|
|
117724
|
+
if (hasUsefulText(answerTail)) events.push(this.answerDelta(answerTail, raw));
|
|
117725
|
+
const trailing = stripLeadingNewline(this.buffer.slice(end.end));
|
|
117726
|
+
if (trailing.trim()) events.push({ type: "internal_text", text: trailing, raw });
|
|
117727
|
+
this.buffer = "";
|
|
117728
|
+
this.mode = "closed";
|
|
117729
|
+
return events;
|
|
117730
|
+
}
|
|
117731
|
+
if (this.buffer.length <= STREAM_HOLD_CHARS) return events;
|
|
117732
|
+
const emitText = this.buffer.slice(0, this.buffer.length - STREAM_HOLD_CHARS);
|
|
117733
|
+
this.buffer = this.buffer.slice(this.buffer.length - STREAM_HOLD_CHARS);
|
|
117734
|
+
if (hasUsefulText(emitText)) events.push(this.answerDelta(emitText, raw));
|
|
117735
|
+
return events;
|
|
117736
|
+
}
|
|
117737
|
+
answerDelta(text, raw) {
|
|
117738
|
+
this.visibleText += text;
|
|
117739
|
+
return { type: "answer_delta", text, raw };
|
|
117740
|
+
}
|
|
117741
|
+
trimWaitingBuffer() {
|
|
117742
|
+
const max = ANSWER_BEGIN_MARKER.length + 2;
|
|
117743
|
+
if (this.buffer.length > max) {
|
|
117744
|
+
this.buffer = this.buffer.slice(this.buffer.length - max);
|
|
117745
|
+
}
|
|
117746
|
+
}
|
|
117747
|
+
};
|
|
117748
|
+
|
|
117675
117749
|
// src/claude/prompt.ts
|
|
117676
117750
|
var MEMORY_CATEGORY_FILE_NAMES = [
|
|
117677
117751
|
"preferences.md",
|
|
@@ -117698,19 +117772,23 @@ function renderStateContract(stateFilePath) {
|
|
|
117698
117772
|
return [
|
|
117699
117773
|
"<state-contract>",
|
|
117700
117774
|
"\u4F60\u548C\u8FD0\u8425\u4E4B\u95F4\u7684\u754C\u9762\u662F\u98DE\u4E66\u8BDD\u9898\u91CC\u7684 response surface,\u8FD9\u662F\u4E00\u4E2A thin-channel \u5916\u58F3:",
|
|
117701
|
-
"- \u9ED8\u8BA4\u4E3B\u56DE\u590D\u9762\u662F
|
|
117702
|
-
"- \
|
|
117703
|
-
"- bridge \u8D1F\u8D23\u521B\u5EFA/\u7F16\u8F91 post\u3001\u5FC5\u8981\u65F6\u521B\u5EFA/\u66F4\u65B0\u98DE\u4E66\u5361\u7247\u3001\u8282\u6D41\u3001\u6E32\u67D3\u6B63\u6587\u3001\u628A choices \u8F6C\u6210\u6309\u94AE\u5E76\u628A\u70B9\u51FB\u503C\u56DE\u4F20\u7ED9\u4F60\u3002",
|
|
117775
|
+
"- \u9ED8\u8BA4\u4E3B\u56DE\u590D\u9762\u662F\u4E00\u5F20 CardKit \u6D41\u5F0F\u5361\u7247:bridge \u8D77\u624B\u53EA\u663E\u793A\u4E00\u884C\u201C\u52AA\u529B\u56DE\u7B54\u4E2D...\u201D,\u7B54\u6848\u901A\u9053\u4E00\u4EA7\u51FA\u5C31\u9010 token \u6D41\u5165\u540C\u4E00\u5F20\u5361,\u5B8C\u6210\u540E\u6536\u655B\u6210\u5E72\u51C0\u603B\u7ED3\u5361\u3002",
|
|
117776
|
+
"- \u8FD0\u884C\u4E2D\u7EDD\u4E0D\u5C55\u793A\u601D\u8003\u3001\u5DE5\u5177\u8BE6\u60C5\u3001\u8FDB\u5EA6 list\u3001\u672C\u5730\u8DEF\u5F84\u6216\u539F\u59CB runner text_delta;\u8FD9\u4E9B\u90FD\u5C5E\u4E8E\u5185\u90E8\u901A\u9053\u3002",
|
|
117704
117777
|
"- \u4F60\u8D1F\u8D23\u628A\u6700\u7EC8\u7ED9\u8FD0\u8425\u770B\u7684\u6B63\u6587\u3001\u72B6\u6001\u3001\u4E0B\u4E00\u6B65\u95EE\u9898\u3001\u662F\u5426\u9700\u8981 choices/\u7ED3\u6784\u5316\u5361\u7247\u5199\u8FDB state.json\u3002",
|
|
117705
117778
|
`\u4F60\u4E0D\u76F4\u63A5\u53D1/\u7F16\u8F91 bridge \u7BA1\u7406\u7684 post \u6216\u5361\u7247;\u4F60\u53EA\u5199 ${stateTarget},bridge \u8BFB\u5B83\u6765\u505A\u5B89\u5168\u6E32\u67D3\u3002`,
|
|
117779
|
+
"",
|
|
117780
|
+
"\u7B54\u6848\u6D41\u901A\u9053:",
|
|
117781
|
+
`- \u53EA\u6709\u771F\u6B63\u8981\u7ED9\u7528\u6237\u770B\u7684\u7B54\u6848\u6B63\u6587,\u624D\u5305\u5728\u72EC\u7ACB\u884C marker \u4E4B\u95F4\u8F93\u51FA\u5230 stdout: \`${ANSWER_BEGIN_MARKER}\` \u5230 \`${ANSWER_END_MARKER}\`\u3002`,
|
|
117782
|
+
"- marker \u5916\u7684\u53D9\u8FF0\u3001\u8BA1\u5212\u3001\u5DE5\u5177\u8BF4\u660E\u3001\u5185\u90E8\u5206\u6790\u90FD\u4F1A\u88AB bridge \u5F53\u4F5C internal_text,\u4E0D\u4F1A\u8FDB\u5165\u5361\u7247\u3002",
|
|
117783
|
+
"- \u5F53\u6700\u7EC8\u7B54\u6848\u8FD8\u6CA1\u51C6\u5907\u597D\u65F6\u53EF\u4EE5\u4E0D\u8F93\u51FA\u7B54\u6848 marker;\u5361\u7247\u53EA\u4FDD\u6301\u201C\u52AA\u529B\u56DE\u7B54\u4E2D...\u201D\u3002\u4E00\u65E6\u5F00\u59CB\u8F93\u51FA\u7B54\u6848 marker \u5185\u6B63\u6587,bridge \u4F1A\u7ACB\u5373\u6D41\u5F0F\u5C55\u793A\u3002",
|
|
117784
|
+
"- \u6BCF\u8F6E\u7ED3\u675F\u524D\u4ECD\u5FC5\u987B\u5199 state.json;\u6700\u7EC8\u6570\u636E\u4EE5 state.json \u7684 last_message/content_blocks/choices \u7B49\u4E3A\u51C6,\u7B54\u6848\u6D41\u53EA\u662F\u8FD0\u884C\u4E2D\u53EF\u89C1\u7684\u4F4E\u5EF6\u8FDF\u6B63\u6587\u901A\u9053\u3002",
|
|
117706
117785
|
"**\u5B8C\u6210\u672C\u6B21\u54CD\u5E94\u524D\u5FC5\u987B**\u6839\u636E\u5F53\u524D\u5B9E\u9645\u72B6\u6001\u66F4\u65B0\u8FD9\u4E2A\u6587\u4EF6(\u539F\u5B50\u5199:\u5199 .tmp \u518D mv)\u3002",
|
|
117707
117786
|
"",
|
|
117708
117787
|
"\u4F60\u80FD\u5199\u7684\u5B57\u6BB5:",
|
|
117709
117788
|
"- status: in_progress / ready / failed(bridge \u552F\u4E00\u5F3A\u4F9D\u8D56\u7684\u5B57\u6BB5)",
|
|
117710
117789
|
"- last_message: \u7ED9\u8FD0\u8425\u770B\u7684\u5361\u7247\u6B63\u6587\u3002\u4F60\u81EA\u884C\u7EC4\u7EC7\u5C55\u793A\u5185\u5BB9,\u4F8B\u5982\u8FDB\u5EA6\u3001\u7ED3\u8BBA\u3001\u8BC1\u636E\u3001MR \u94FE\u63A5\u3001dev \u9884\u89C8\u3001\u9700\u8981\u7528\u6237\u8865\u5145\u7684\u4FE1\u606F",
|
|
117711
117790
|
"- error: \u5931\u8D25\u539F\u56E0(\u642D\u914D status=failed)",
|
|
117712
|
-
"- card_title: \
|
|
117713
|
-
"- card_color: \u5361\u7247\u914D\u8272(\u53EF\u9009,success/failure/neutral,\u4E5F\u53EF\u76F4\u63A5\u5199 green/red/grey)",
|
|
117791
|
+
"- card_title/card_color: \u517C\u5BB9\u5B57\u6BB5; \u9ED8\u8BA4 CardKit \u4E0D\u6E32\u67D3\u9876\u90E8\u6807\u9898\u8272\u6761,legacy/fallback \u5361\u7247\u8DEF\u5F84\u53EF\u80FD\u4F7F\u7528",
|
|
117714
117792
|
"- image_blocks: \u53EF\u9009\u56FE\u7247\u9884\u89C8\u5757\u6570\u7EC4,\u6700\u591A 4 \u4E2A\u3002\u6BCF\u9879 `{img_key, alt?, title?, mode?, preview?}`; `img_key` \u5FC5\u987B\u662F\u5DF2\u4E0A\u4F20/\u53EF\u7528\u4E8E\u5361\u7247\u7684 Feishu \u56FE\u7247 key,`alt` \u7701\u7565\u65F6 bridge \u9ED8\u8BA4\u201C\u56FE\u7247\u9884\u89C8\u201D,`mode` \u53EA\u5141\u8BB8 `crop_center`/`fit_horizontal` \u5E76\u6620\u5C04\u5230 Card JSON 2.0 `scale_type`,`preview` \u9ED8\u8BA4 true\u3002bridge \u4E0D\u8D1F\u8D23\u4E0B\u8F7D/\u4E0A\u4F20/\u9009\u62E9\u56FE\u7247;\u8FD9\u4E9B\u7531\u4F60\u7528 lark-cli \u7B49\u5DE5\u5177\u5148\u5B8C\u6210\u3002",
|
|
117715
117793
|
'- content_blocks: \u53EF\u9009\u6709\u5E8F\u6B63\u6587\u5757\u6570\u7EC4,\u6700\u591A 12 \u4E2A block\u3001\u6700\u591A 4 \u4E2A image block\u3002\u53EA\u652F\u6301\u7A84 union:`{type:"markdown", content}` \u548C `{type:"image", img_key, alt?, title?, mode?, preview?}`;\u4E0D\u652F\u6301 raw card JSON\u3002\u7528\u4E8E\u6B63\u6587\u4E0E\u56FE\u7247\u4EA4\u9519\u6392\u7248,\u4F8B\u5982 markdown -> image -> markdown -> image\u3002\u82E5 `content_blocks` \u975E\u7A7A,bridge \u4EE5\u5B83\u4F5C\u4E3A\u4E3B\u6B63\u6587\u5E76\u5FFD\u7565 `last_message` + `image_blocks` \u7684\u6B63\u6587\u6E32\u67D3,\u907F\u514D\u91CD\u590D;\u82E5\u7701\u7565\u5219\u4FDD\u6301\u65E7 `last_message` + `image_blocks` \u884C\u4E3A\u3002',
|
|
117716
117794
|
'- response_surface: \u53EF\u9009\u8986\u76D6\u5B57\u6BB5,\u5F62\u5982 `{mode:"card"|"post"|"hybrid", primary?:"card"|"post", post?:{mentions:[{user_id,label?}]}, card?:{compact?:boolean, capabilities?:[...]}}`\u3002\u9ED8\u8BA4\u53EF\u4E0D\u5199;\u65E0\u663E\u5F0F card \u610F\u56FE\u65F6 bridge \u6309 CardKit \u6D41\u5F0F\u5361\u7247\u5904\u7406,\u6700\u7EC8\u6536\u6210\u5E72\u51C0\u603B\u7ED3\u5361\u3002\u9700\u8981\u771F\u5B9E @ \u65F6\u628A\u76EE\u6807\u5199\u5165 `post.mentions`;\u4E0D\u8981\u5199 raw Feishu post/card JSON\u3002',
|
|
@@ -117724,8 +117802,8 @@ function renderStateContract(stateFilePath) {
|
|
|
117724
117802
|
"\u6302\u7740\u4E0D\u9000\u51FA = \u8BDD\u9898\u6C38\u8FDC\u5361\u5728\u300C\u6B63\u5728\u5904\u7406\u2026\u300D)\u3002",
|
|
117725
117803
|
"",
|
|
117726
117804
|
"\u5361\u7247\u5C55\u793A\u539F\u5219:",
|
|
117727
|
-
"- \u8FD0\u884C\u4E2D\u4E3B\u9762\u662F
|
|
117728
|
-
"- \u6700\u7EC8
|
|
117805
|
+
"- \u8FD0\u884C\u4E2D\u4E3B\u9762\u662F CardKit \u771F\u6D41\u5F0F\u5361\u7247;\u4E0D\u8981\u4F9D\u8D56\u5DE5\u5177\u6D41/\u65E5\u5FD7\u8868\u8FBE\u4E1A\u52A1\u9636\u6BB5,\u5B83\u4EEC\u4E0D\u4F1A\u663E\u793A\u3002",
|
|
117806
|
+
"- \u6700\u7EC8\u5361\u7247\u4EE5\u4F60\u7684 `last_message` \u4E3A\u4E3B;\u82E5\u5199\u4E86 `choices`\u3001`content_blocks` \u6216 `image_blocks`,bridge \u4F1A\u5728\u540C\u4E00\u5F20\u6700\u7EC8\u5361\u7247\u627F\u8F7D\u8FD9\u4E9B\u80FD\u529B\u3002",
|
|
117729
117807
|
"- \u4E0D\u8981\u4F9D\u8D56 bridge \u4ECE\u8F93\u51FA\u91CC\u89E3\u6790\u4E1A\u52A1\u9636\u6BB5\u3001MR\u3001\u9884\u89C8\u5730\u5740\u6216\u4E0B\u4E00\u6B65\u52A8\u4F5C;\u9700\u8981\u5C55\u793A\u7684\u5185\u5BB9\u4F60\u81EA\u5DF1\u5199\u8FDB last_message\u3002",
|
|
117730
117808
|
"- \u4E0D\u8981\u6C42\u56FA\u5B9A\u683C\u5F0F\u3002\u6839\u636E\u4EFB\u52A1\u9009\u62E9\u6700\u6E05\u695A\u7684\u8868\u8FBE:\u77ED\u7ED3\u8BBA\u3001\u5206\u70B9\u3001\u8868\u683C\u3001\u94FE\u63A5\u3001\u4E0B\u4E00\u6B65\u95EE\u9898\u90FD\u53EF\u4EE5\u3002",
|
|
117731
117809
|
"- \u5982\u679C\u672C\u8F6E\u6D89\u53CA repo / \u4EE3\u7801 / \u6587\u6863\u4FEE\u6539,last_message \u5E94\u5305\u542B\u8DB3\u591F\u8BA9\u8FD0\u8425\u9A8C\u6536\u7684\u8BC1\u636E,\u4F8B\u5982\u4F60\u5B9E\u9645\u4F7F\u7528\u7684 workspace/repo\u3001\u5173\u952E diff \u6216\u94FE\u63A5\u3001\u8FD0\u884C\u8FC7\u7684\u6D4B\u8BD5/\u68C0\u67E5\u547D\u4EE4\u548C\u7ED3\u679C\u3002\u5177\u4F53\u8BC1\u636E\u7531\u4EFB\u52A1\u51B3\u5B9A;dogfood E2E \u7684\u4E25\u683C\u6E05\u5355\u53EA\u5728 dogfood guide \u4E2D\u8981\u6C42\u3002",
|
|
@@ -119047,8 +119125,9 @@ var CardKitFileSchema = external_exports.object({
|
|
|
119047
119125
|
idempotencyKey: external_exports.string().min(1),
|
|
119048
119126
|
sequence: external_exports.number().int().nonnegative().default(0),
|
|
119049
119127
|
elements: external_exports.object({
|
|
119050
|
-
status: external_exports.object({ elementId: external_exports.string().min(1) }),
|
|
119051
|
-
thinking: external_exports.object({ elementId: external_exports.string().min(1) }),
|
|
119128
|
+
status: external_exports.object({ elementId: external_exports.string().min(1) }).optional(),
|
|
119129
|
+
thinking: external_exports.object({ elementId: external_exports.string().min(1) }).optional(),
|
|
119130
|
+
footer: external_exports.object({ elementId: external_exports.string().min(1) }).optional(),
|
|
119052
119131
|
final: external_exports.object({ elementId: external_exports.string().min(1) })
|
|
119053
119132
|
}).optional(),
|
|
119054
119133
|
lastVisibleFallbackMessageId: external_exports.string().min(1).nullable().default(null),
|
|
@@ -119111,13 +119190,11 @@ async function deleteCardKitFile(worktreePath) {
|
|
|
119111
119190
|
}
|
|
119112
119191
|
|
|
119113
119192
|
// src/lark/cardkitSurface.ts
|
|
119114
|
-
var CARDKIT_STATUS_ELEMENT_ID = "status_md";
|
|
119115
|
-
var CARDKIT_THINKING_ELEMENT_ID = "thinking_md";
|
|
119116
119193
|
var CARDKIT_FINAL_ELEMENT_ID = "final_md";
|
|
119194
|
+
var CARDKIT_FOOTER_ELEMENT_ID = "footer_md";
|
|
119117
119195
|
var CARDKIT_CHOICES_ELEMENT_ID = "choices_slot";
|
|
119118
119196
|
var MAX_CARD_BYTES = 30 * 1024;
|
|
119119
119197
|
var FINAL_BUDGET_CHARS = 22e3;
|
|
119120
|
-
var THINKING_BUDGET_CHARS = 6e3;
|
|
119121
119198
|
var CHOICE_MARKERS2 = ["A", "B", "C", "D", "E"];
|
|
119122
119199
|
function plainText2(content) {
|
|
119123
119200
|
return { tag: "plain_text", content };
|
|
@@ -119127,6 +119204,9 @@ function markdown(content, elementId) {
|
|
|
119127
119204
|
if (elementId) element["element_id"] = elementId;
|
|
119128
119205
|
return element;
|
|
119129
119206
|
}
|
|
119207
|
+
function buildCardKitAnswerElement(content = "") {
|
|
119208
|
+
return markdown(content, CARDKIT_FINAL_ELEMENT_ID);
|
|
119209
|
+
}
|
|
119130
119210
|
function safeAtMention(target) {
|
|
119131
119211
|
const id = target.user_id.trim();
|
|
119132
119212
|
if (!/^[A-Za-z0-9_:-]+$/.test(id)) return "";
|
|
@@ -119164,8 +119244,7 @@ function truncateCardToBudget(card) {
|
|
|
119164
119244
|
return cloned;
|
|
119165
119245
|
}
|
|
119166
119246
|
function buildCardKitInitialCard(opts = {}) {
|
|
119167
|
-
const
|
|
119168
|
-
const thinkingText = opts.thinkingText ?? "\u51C6\u5907\u542F\u52A8\u672C\u5730 agent\u3002";
|
|
119247
|
+
const footerText = opts.footerText ?? opts.statusText ?? "\u52AA\u529B\u56DE\u7B54\u4E2D...";
|
|
119169
119248
|
return {
|
|
119170
119249
|
schema: "2.0",
|
|
119171
119250
|
config: {
|
|
@@ -119178,45 +119257,11 @@ function buildCardKitInitialCard(opts = {}) {
|
|
|
119178
119257
|
print_strategy: "fast"
|
|
119179
119258
|
}
|
|
119180
119259
|
},
|
|
119181
|
-
header: {
|
|
119182
|
-
title: plainText2(opts.title ?? "\u5904\u7406\u4E2D"),
|
|
119183
|
-
template: "blue"
|
|
119184
|
-
},
|
|
119185
119260
|
body: {
|
|
119186
|
-
elements: [
|
|
119187
|
-
markdown(statusText, CARDKIT_STATUS_ELEMENT_ID),
|
|
119188
|
-
markdown(thinkingText, CARDKIT_THINKING_ELEMENT_ID),
|
|
119189
|
-
{ tag: "hr" },
|
|
119190
|
-
markdown(" ", CARDKIT_FINAL_ELEMENT_ID)
|
|
119191
|
-
]
|
|
119261
|
+
elements: [markdown(footerText, CARDKIT_FOOTER_ELEMENT_ID)]
|
|
119192
119262
|
}
|
|
119193
119263
|
};
|
|
119194
119264
|
}
|
|
119195
|
-
function summarizeCardKitToolInput(input) {
|
|
119196
|
-
if (input === null || input === void 0) return "";
|
|
119197
|
-
let raw;
|
|
119198
|
-
if (typeof input === "string") {
|
|
119199
|
-
raw = input;
|
|
119200
|
-
} else if (typeof input === "object") {
|
|
119201
|
-
const obj = input;
|
|
119202
|
-
const snippet2 = obj["command"] ?? obj["path"] ?? obj["file_path"] ?? obj["description"] ?? obj["cmd"] ?? null;
|
|
119203
|
-
raw = snippet2 != null ? String(snippet2) : JSON.stringify(input);
|
|
119204
|
-
} else {
|
|
119205
|
-
raw = String(input);
|
|
119206
|
-
}
|
|
119207
|
-
return raw.length > 80 ? `${raw.slice(0, 77)}...` : raw;
|
|
119208
|
-
}
|
|
119209
|
-
function buildCardKitProgressMarkdown(snapshot) {
|
|
119210
|
-
const status = snapshot.statusLines.slice(-3).map((line) => `- ${line.trim()}`);
|
|
119211
|
-
const tools = snapshot.toolLines.slice(-5).map((line) => `- ${line.trim()}`);
|
|
119212
|
-
const sections = [];
|
|
119213
|
-
if (status.length) sections.push(`**\u8FDB\u5EA6**
|
|
119214
|
-
${status.join("\n")}`);
|
|
119215
|
-
if (tools.length) sections.push(`**\u5DE5\u5177\u8C03\u7528**
|
|
119216
|
-
${tools.join("\n")}`);
|
|
119217
|
-
const body = sections.join("\n\n") || "\u6B63\u5728\u5904\u7406\u2026";
|
|
119218
|
-
return truncateChars(body, THINKING_BUDGET_CHARS, "\n\n_\u8FDB\u5EA6\u8F83\u957F,\u5DF2\u622A\u65AD\u3002_");
|
|
119219
|
-
}
|
|
119220
119265
|
function choiceMarker2(index) {
|
|
119221
119266
|
return CHOICE_MARKERS2[index] ?? String(index + 1);
|
|
119222
119267
|
}
|
|
@@ -119260,7 +119305,7 @@ function finalMarkdown(opts) {
|
|
|
119260
119305
|
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_");
|
|
119261
119306
|
}
|
|
119262
119307
|
function buildCardKitFinalCard(opts) {
|
|
119263
|
-
const elements = [
|
|
119308
|
+
const elements = [buildCardKitAnswerElement(finalMarkdown(opts))];
|
|
119264
119309
|
const images = [];
|
|
119265
119310
|
if (opts.contentBlocks?.length) {
|
|
119266
119311
|
for (const block of opts.contentBlocks) {
|
|
@@ -119286,10 +119331,6 @@ function buildCardKitFinalCard(opts) {
|
|
|
119286
119331
|
streaming_mode: false,
|
|
119287
119332
|
summary: { content: truncateChars(opts.finalText.replace(/\s+/g, " ").trim(), 50, "...") }
|
|
119288
119333
|
},
|
|
119289
|
-
header: {
|
|
119290
|
-
title: plainText2(opts.title ?? "\u5B8C\u6210"),
|
|
119291
|
-
template: "green"
|
|
119292
|
-
},
|
|
119293
119334
|
body: { elements }
|
|
119294
119335
|
});
|
|
119295
119336
|
}
|
|
@@ -119298,8 +119339,8 @@ function buildCardKitFinalMarkdown(opts) {
|
|
|
119298
119339
|
}
|
|
119299
119340
|
|
|
119300
119341
|
// src/bridge/cardkitProgress.ts
|
|
119301
|
-
var DEFAULT_PATCH_INTERVAL_MS =
|
|
119302
|
-
var DEFAULT_MAX_PROGRESS_UPDATES =
|
|
119342
|
+
var DEFAULT_PATCH_INTERVAL_MS = 250;
|
|
119343
|
+
var DEFAULT_MAX_PROGRESS_UPDATES = 240;
|
|
119303
119344
|
function idempotencyKey(facts) {
|
|
119304
119345
|
return deriveCardKitUuid(
|
|
119305
119346
|
["reply", facts.botId, facts.threadId, facts.triggerMessageId].join("\0")
|
|
@@ -119308,6 +119349,11 @@ function idempotencyKey(facts) {
|
|
|
119308
119349
|
function sequenceUuid(cardId, role, sequence) {
|
|
119309
119350
|
return deriveCardKitUuid([cardId, role, String(sequence)].join("\0"));
|
|
119310
119351
|
}
|
|
119352
|
+
function isMissingCardKitElementError(err) {
|
|
119353
|
+
if (!(err instanceof Error)) return false;
|
|
119354
|
+
const message = err.message.toLowerCase();
|
|
119355
|
+
return message.includes("element") && (message.includes("not found") || message.includes("not exist") || message.includes("\u4E0D\u5B58\u5728"));
|
|
119356
|
+
}
|
|
119311
119357
|
var LiveCardKitProgressHandle = class {
|
|
119312
119358
|
cardId;
|
|
119313
119359
|
messageId;
|
|
@@ -119316,12 +119362,12 @@ var LiveCardKitProgressHandle = class {
|
|
|
119316
119362
|
patchIntervalMs;
|
|
119317
119363
|
maxProgressUpdates;
|
|
119318
119364
|
onSequenceCommitted;
|
|
119319
|
-
|
|
119320
|
-
toolLines = [];
|
|
119365
|
+
answerBuffer = "";
|
|
119321
119366
|
pendingPatch = null;
|
|
119322
119367
|
inFlight = Promise.resolve();
|
|
119323
119368
|
closed = false;
|
|
119324
119369
|
progressUpdates = 0;
|
|
119370
|
+
answerElementCreated = false;
|
|
119325
119371
|
sequence = 0;
|
|
119326
119372
|
constructor(opts) {
|
|
119327
119373
|
this.cardKitClient = opts.cardKitClient;
|
|
@@ -119331,18 +119377,19 @@ var LiveCardKitProgressHandle = class {
|
|
|
119331
119377
|
this.patchIntervalMs = opts.patchIntervalMs;
|
|
119332
119378
|
this.maxProgressUpdates = opts.maxProgressUpdates;
|
|
119333
119379
|
this.onSequenceCommitted = opts.onSequenceCommitted;
|
|
119334
|
-
|
|
119380
|
+
}
|
|
119381
|
+
get answerText() {
|
|
119382
|
+
return this.answerBuffer;
|
|
119335
119383
|
}
|
|
119336
119384
|
handle(event) {
|
|
119337
119385
|
if (this.closed) return;
|
|
119338
|
-
if (event.type === "
|
|
119339
|
-
this.
|
|
119386
|
+
if (event.type === "answer_delta") {
|
|
119387
|
+
this.answerBuffer += event.text;
|
|
119340
119388
|
this.schedulePatch();
|
|
119341
119389
|
return;
|
|
119342
119390
|
}
|
|
119343
|
-
if (event.type === "
|
|
119344
|
-
|
|
119345
|
-
this.toolLines.push(`\u{1F527} ${event.toolName}${summary ? ` ${summary}` : ""}`);
|
|
119391
|
+
if (event.type === "answer_snapshot") {
|
|
119392
|
+
this.answerBuffer = event.text;
|
|
119346
119393
|
this.schedulePatch();
|
|
119347
119394
|
}
|
|
119348
119395
|
}
|
|
@@ -119358,17 +119405,21 @@ var LiveCardKitProgressHandle = class {
|
|
|
119358
119405
|
await this.drain();
|
|
119359
119406
|
this.closed = true;
|
|
119360
119407
|
const finalMarkdown2 = buildCardKitFinalMarkdown(opts);
|
|
119361
|
-
|
|
119362
|
-
|
|
119363
|
-
|
|
119364
|
-
|
|
119365
|
-
|
|
119366
|
-
|
|
119367
|
-
|
|
119368
|
-
|
|
119369
|
-
|
|
119370
|
-
|
|
119371
|
-
|
|
119408
|
+
if (finalMarkdown2 !== this.answerBuffer) {
|
|
119409
|
+
await this.withAnswerElement(finalMarkdown2);
|
|
119410
|
+
await this.next(
|
|
119411
|
+
(sequence) => this.cardKitClient.streamElementContent(
|
|
119412
|
+
this.cardId,
|
|
119413
|
+
CARDKIT_FINAL_ELEMENT_ID,
|
|
119414
|
+
finalMarkdown2,
|
|
119415
|
+
{
|
|
119416
|
+
sequence,
|
|
119417
|
+
uuid: sequenceUuid(this.cardId, "final-content", sequence)
|
|
119418
|
+
}
|
|
119419
|
+
)
|
|
119420
|
+
);
|
|
119421
|
+
this.answerBuffer = finalMarkdown2;
|
|
119422
|
+
}
|
|
119372
119423
|
await this.next(
|
|
119373
119424
|
(sequence) => this.cardKitClient.updateCardEntity(this.cardId, buildCardKitFinalCard(opts), {
|
|
119374
119425
|
sequence,
|
|
@@ -119408,23 +119459,38 @@ var LiveCardKitProgressHandle = class {
|
|
|
119408
119459
|
}
|
|
119409
119460
|
async patchProgress() {
|
|
119410
119461
|
if (this.closed || this.progressUpdates >= this.maxProgressUpdates) return;
|
|
119411
|
-
|
|
119412
|
-
statusLines: this.statusLines,
|
|
119413
|
-
toolLines: this.toolLines
|
|
119414
|
-
});
|
|
119462
|
+
if (!this.answerBuffer) return;
|
|
119415
119463
|
this.progressUpdates += 1;
|
|
119416
119464
|
this.inFlight = this.inFlight.then(
|
|
119417
|
-
() => this.
|
|
119418
|
-
(
|
|
119419
|
-
sequence,
|
|
119420
|
-
|
|
119421
|
-
|
|
119465
|
+
() => this.withAnswerElement(this.answerBuffer).then(
|
|
119466
|
+
() => this.next(
|
|
119467
|
+
(sequence) => this.cardKitClient.streamElementContent(this.cardId, CARDKIT_FINAL_ELEMENT_ID, this.answerBuffer, {
|
|
119468
|
+
sequence,
|
|
119469
|
+
uuid: sequenceUuid(this.cardId, "answer", sequence)
|
|
119470
|
+
})
|
|
119471
|
+
)
|
|
119422
119472
|
)
|
|
119423
119473
|
).catch((err) => {
|
|
119424
119474
|
console.warn("[cardkit_progress] progress update failed (continuing):", err);
|
|
119425
119475
|
});
|
|
119426
119476
|
await this.inFlight;
|
|
119427
119477
|
}
|
|
119478
|
+
async withAnswerElement(initialContent) {
|
|
119479
|
+
if (this.answerElementCreated) return;
|
|
119480
|
+
await this.next(
|
|
119481
|
+
(sequence) => this.cardKitClient.createElements(
|
|
119482
|
+
this.cardId,
|
|
119483
|
+
[buildCardKitAnswerElement(initialContent)],
|
|
119484
|
+
{
|
|
119485
|
+
sequence,
|
|
119486
|
+
uuid: sequenceUuid(this.cardId, "answer-element", sequence),
|
|
119487
|
+
type: "insert_before",
|
|
119488
|
+
targetElementId: CARDKIT_FOOTER_ELEMENT_ID
|
|
119489
|
+
}
|
|
119490
|
+
)
|
|
119491
|
+
);
|
|
119492
|
+
this.answerElementCreated = true;
|
|
119493
|
+
}
|
|
119428
119494
|
async next(fn) {
|
|
119429
119495
|
this.sequence += 1;
|
|
119430
119496
|
await fn(this.sequence);
|
|
@@ -119433,8 +119499,8 @@ var LiveCardKitProgressHandle = class {
|
|
|
119433
119499
|
};
|
|
119434
119500
|
async function createCardKitProgressHandle(opts) {
|
|
119435
119501
|
const key = idempotencyKey(opts.facts);
|
|
119436
|
-
const initialStatusText = opts.initialStatusText ?? "\
|
|
119437
|
-
const initialCard = buildCardKitInitialCard({
|
|
119502
|
+
const initialStatusText = opts.initialStatusText ?? "\u52AA\u529B\u56DE\u7B54\u4E2D...";
|
|
119503
|
+
const initialCard = buildCardKitInitialCard({ footerText: initialStatusText });
|
|
119438
119504
|
const created = opts.cardKitClient.createCardReply ? await opts.cardKitClient.createCardReply(
|
|
119439
119505
|
opts.replyToMessageId,
|
|
119440
119506
|
initialCard,
|
|
@@ -119463,7 +119529,6 @@ async function createCardKitProgressHandle(opts) {
|
|
|
119463
119529
|
idempotencyKey: key,
|
|
119464
119530
|
patchIntervalMs: opts.patchIntervalMs ?? DEFAULT_PATCH_INTERVAL_MS,
|
|
119465
119531
|
maxProgressUpdates: opts.maxProgressUpdates ?? DEFAULT_MAX_PROGRESS_UPDATES,
|
|
119466
|
-
initialStatusText,
|
|
119467
119532
|
onSequenceCommitted: opts.onSequenceCommitted
|
|
119468
119533
|
});
|
|
119469
119534
|
}
|
|
@@ -119475,7 +119540,7 @@ async function finalizeExistingCardKitCard(opts) {
|
|
|
119475
119540
|
await opts.onSequenceCommitted?.(sequence);
|
|
119476
119541
|
};
|
|
119477
119542
|
const finalMarkdown2 = buildCardKitFinalMarkdown(opts.final);
|
|
119478
|
-
|
|
119543
|
+
const streamFinalContent = () => next(
|
|
119479
119544
|
"reconcile-final-content",
|
|
119480
119545
|
(seq2, uuid) => opts.cardKitClient.streamElementContent(
|
|
119481
119546
|
opts.cardId,
|
|
@@ -119484,6 +119549,25 @@ async function finalizeExistingCardKitCard(opts) {
|
|
|
119484
119549
|
{ sequence: seq2, uuid }
|
|
119485
119550
|
)
|
|
119486
119551
|
);
|
|
119552
|
+
try {
|
|
119553
|
+
await streamFinalContent();
|
|
119554
|
+
} catch (err) {
|
|
119555
|
+
if (!isMissingCardKitElementError(err)) throw err;
|
|
119556
|
+
await next(
|
|
119557
|
+
"reconcile-final-element",
|
|
119558
|
+
(seq2, uuid) => opts.cardKitClient.createElements(
|
|
119559
|
+
opts.cardId,
|
|
119560
|
+
[buildCardKitAnswerElement(finalMarkdown2)],
|
|
119561
|
+
{
|
|
119562
|
+
sequence: seq2,
|
|
119563
|
+
uuid,
|
|
119564
|
+
type: "insert_before",
|
|
119565
|
+
targetElementId: CARDKIT_FOOTER_ELEMENT_ID
|
|
119566
|
+
}
|
|
119567
|
+
)
|
|
119568
|
+
);
|
|
119569
|
+
await streamFinalContent();
|
|
119570
|
+
}
|
|
119487
119571
|
await next(
|
|
119488
119572
|
"reconcile-final-card",
|
|
119489
119573
|
(seq2, uuid) => opts.cardKitClient.updateCardEntity(
|
|
@@ -120363,7 +120447,7 @@ async function dispatchResponseSurface(input) {
|
|
|
120363
120447
|
}
|
|
120364
120448
|
|
|
120365
120449
|
// src/bridge/postProgress.ts
|
|
120366
|
-
var DEFAULT_PLACEHOLDER_TEXT = "\
|
|
120450
|
+
var DEFAULT_PLACEHOLDER_TEXT = "\u52AA\u529B\u56DE\u7B54\u4E2D...";
|
|
120367
120451
|
var DEFAULT_PATCH_INTERVAL_MS2 = 1500;
|
|
120368
120452
|
var DEFAULT_MAX_PROGRESS_EDITS = 16;
|
|
120369
120453
|
function normalizeText2(text) {
|
|
@@ -120401,8 +120485,13 @@ var LivePostProgressHandle = class {
|
|
|
120401
120485
|
}
|
|
120402
120486
|
handle(event) {
|
|
120403
120487
|
if (this.closed) return;
|
|
120404
|
-
if (event.type
|
|
120405
|
-
|
|
120488
|
+
if (event.type === "answer_delta") {
|
|
120489
|
+
this.textBuffer += event.text;
|
|
120490
|
+
} else if (event.type === "answer_snapshot") {
|
|
120491
|
+
this.textBuffer = event.text;
|
|
120492
|
+
} else {
|
|
120493
|
+
return;
|
|
120494
|
+
}
|
|
120406
120495
|
this.schedulePatch();
|
|
120407
120496
|
}
|
|
120408
120497
|
async finalize(opts) {
|
|
@@ -121088,7 +121177,7 @@ var BridgeHandler = class {
|
|
|
121088
121177
|
threadId,
|
|
121089
121178
|
triggerMessageId: messageId
|
|
121090
121179
|
},
|
|
121091
|
-
initialStatusText: "\
|
|
121180
|
+
initialStatusText: "\u52AA\u529B\u56DE\u7B54\u4E2D...",
|
|
121092
121181
|
onSequenceCommitted: async (sequence) => {
|
|
121093
121182
|
await updateCardKitRecord({ status: "streaming", sequence });
|
|
121094
121183
|
}
|
|
@@ -121107,8 +121196,7 @@ var BridgeHandler = class {
|
|
|
121107
121196
|
idempotencyKey: cardKitProgress.idempotencyKey,
|
|
121108
121197
|
sequence: cardKitProgress.sequence,
|
|
121109
121198
|
elements: {
|
|
121110
|
-
|
|
121111
|
-
thinking: { elementId: "thinking_md" },
|
|
121199
|
+
footer: { elementId: "footer_md" },
|
|
121112
121200
|
final: { elementId: "final_md" }
|
|
121113
121201
|
},
|
|
121114
121202
|
lastVisibleFallbackMessageId: null,
|
|
@@ -121125,8 +121213,20 @@ var BridgeHandler = class {
|
|
|
121125
121213
|
reason: "response surface \u4F7F\u7528 CardKit \u4F5C\u4E3A\u672C\u8F6E\u4E3B\u56DE\u590D\u9762\u3002"
|
|
121126
121214
|
});
|
|
121127
121215
|
} catch (err) {
|
|
121128
|
-
|
|
121129
|
-
|
|
121216
|
+
const existingMessageId = cardKitReplyConversionMessageId(err);
|
|
121217
|
+
if (existingMessageId) {
|
|
121218
|
+
card = this.deps.cardRenderer.handleFor(existingMessageId);
|
|
121219
|
+
await this.deps.client.removeProcessingReaction?.(messageId);
|
|
121220
|
+
await recordEvent({
|
|
121221
|
+
status: "running",
|
|
121222
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
121223
|
+
appendPath: "\u5DF2\u6536\u7F16 CardKit \u5360\u4F4D\u5361",
|
|
121224
|
+
reason: "CardKit idConvert \u5931\u8D25\u4F46\u5360\u4F4D\u5361\u5DF2\u53D1\u51FA\uFF0Cbridge \u590D\u7528\u540C\u4E00\u5F20\u5361\u505A\u53EF\u89C1\u515C\u5E95\u3002"
|
|
121225
|
+
});
|
|
121226
|
+
} else {
|
|
121227
|
+
cardKitStartFailed = true;
|
|
121228
|
+
console.warn("[bridge.handler] create CardKit progress surface failed; using card fallback:", err);
|
|
121229
|
+
}
|
|
121130
121230
|
}
|
|
121131
121231
|
}
|
|
121132
121232
|
if (!card && !cardKitAvailable && postOutboundAvailable && this.deps.postClient) {
|
|
@@ -121153,7 +121253,7 @@ var BridgeHandler = class {
|
|
|
121153
121253
|
threadId,
|
|
121154
121254
|
triggerMessageId: messageId
|
|
121155
121255
|
},
|
|
121156
|
-
initialText: "\
|
|
121256
|
+
initialText: "\u52AA\u529B\u56DE\u7B54\u4E2D..."
|
|
121157
121257
|
});
|
|
121158
121258
|
await this.deps.client.removeProcessingReaction?.(messageId);
|
|
121159
121259
|
await recordEvent({
|
|
@@ -121274,7 +121374,7 @@ var BridgeHandler = class {
|
|
|
121274
121374
|
gitlabToken: this.deps.gitlabToken
|
|
121275
121375
|
});
|
|
121276
121376
|
let sessionId;
|
|
121277
|
-
let
|
|
121377
|
+
let trustedAnswerText = "";
|
|
121278
121378
|
try {
|
|
121279
121379
|
for await (const ev of handle.events) {
|
|
121280
121380
|
if (cardKitProgress) cardKitProgress.handle(ev);
|
|
@@ -121283,8 +121383,10 @@ var BridgeHandler = class {
|
|
|
121283
121383
|
if (ev.type === "system_init") {
|
|
121284
121384
|
sessionId = ev.sessionId;
|
|
121285
121385
|
}
|
|
121286
|
-
if (ev.type === "
|
|
121287
|
-
|
|
121386
|
+
if (ev.type === "answer_delta") {
|
|
121387
|
+
trustedAnswerText += ev.text;
|
|
121388
|
+
} else if (ev.type === "answer_snapshot") {
|
|
121389
|
+
trustedAnswerText = ev.text;
|
|
121288
121390
|
}
|
|
121289
121391
|
}
|
|
121290
121392
|
const result = await handle.done;
|
|
@@ -121330,7 +121432,8 @@ var BridgeHandler = class {
|
|
|
121330
121432
|
success = false;
|
|
121331
121433
|
failureReason = `claude exited ${result.exitCode} \u4E14 bot \u672A\u66F4\u65B0 state.json status \u2014 \u53EF\u80FD\u5D29\u6E83`;
|
|
121332
121434
|
}
|
|
121333
|
-
const
|
|
121435
|
+
const fallbackAnswer = trustedAnswerText.trim() || cardKitProgress?.answerText.trim() || "";
|
|
121436
|
+
const cardBody = reportedState?.last_message ?? (fallbackAnswer ? fallbackAnswer : "\u26A0\uFE0F \u672C\u8F6E\u6CA1\u6709\u62FF\u5230 agent \u7684\u65B0\u56DE\u590D(\u53EF\u80FD\u88AB\u4E2D\u65AD\u6216\u672A\u66F4\u65B0\u72B6\u6001),\u518D @ \u6211\u4E00\u6B21\u91CD\u8BD5\u3002");
|
|
121334
121437
|
const noReportThisTurn = reportedState === null;
|
|
121335
121438
|
const neutralTitle = noReportThisTurn && success && !failureReason ? "\u{1F4AC} \u5DF2\u56DE\u590D" : void 0;
|
|
121336
121439
|
const baseCardPayload = {
|
|
@@ -121546,12 +121649,32 @@ var BridgeHandler = class {
|
|
|
121546
121649
|
reason: String(err)
|
|
121547
121650
|
});
|
|
121548
121651
|
settle(false);
|
|
121652
|
+
const wtPath = this.deps.conventions.runtime === "agent_workspace" && this.deps.conventions.workspaceSessionsDir ? path10.join(this.deps.conventions.workspaceSessionsDir, threadId) : path10.join(this.deps.conventions.worktreesDir, threadId);
|
|
121653
|
+
const hardFailureText = `\u6267\u884C\u5931\u8D25: ${String(err)}`;
|
|
121654
|
+
const createHardFailurePostFallback = async (failureReason) => {
|
|
121655
|
+
const fallback = await createOnlyPostFallback({
|
|
121656
|
+
postClient: this.deps.postClient,
|
|
121657
|
+
replyToMessageId: messageId,
|
|
121658
|
+
replyInThread,
|
|
121659
|
+
botId: this.deps.botConfig?.id ?? "v1-default",
|
|
121660
|
+
threadId,
|
|
121661
|
+
triggerMessageId: messageId,
|
|
121662
|
+
finalText: hardFailureText,
|
|
121663
|
+
failureReason,
|
|
121664
|
+
title: "Larkway failure fallback",
|
|
121665
|
+
logPrefix: "[bridge.handler]"
|
|
121666
|
+
});
|
|
121667
|
+
if (fallback) {
|
|
121668
|
+
await deleteCardFile(wtPath);
|
|
121669
|
+
await deleteCardKitFile(wtPath);
|
|
121670
|
+
}
|
|
121671
|
+
return fallback;
|
|
121672
|
+
};
|
|
121549
121673
|
if (!card && cardKitProgress) {
|
|
121550
121674
|
try {
|
|
121551
121675
|
await cardKitProgress.finalize({
|
|
121552
|
-
finalText:
|
|
121676
|
+
finalText: hardFailureText
|
|
121553
121677
|
});
|
|
121554
|
-
const wtPath = this.deps.conventions.runtime === "agent_workspace" && this.deps.conventions.workspaceSessionsDir ? path10.join(this.deps.conventions.workspaceSessionsDir, threadId) : path10.join(this.deps.conventions.worktreesDir, threadId);
|
|
121555
121678
|
await deleteCardKitFile(wtPath);
|
|
121556
121679
|
} catch (cardKitFinalizeErr) {
|
|
121557
121680
|
console.error(
|
|
@@ -121562,6 +121685,9 @@ var BridgeHandler = class {
|
|
|
121562
121685
|
card = await this.deps.cardRenderer.start(messageId, { replyInThread, threadId });
|
|
121563
121686
|
} catch (cardStartErr) {
|
|
121564
121687
|
console.error("[bridge.handler] failure card start also failed:", cardStartErr);
|
|
121688
|
+
await createHardFailurePostFallback(
|
|
121689
|
+
`CardKit failure finalize failed: ${String(cardKitFinalizeErr)}; legacy visible card fallback also failed: ${String(cardStartErr)}`
|
|
121690
|
+
);
|
|
121565
121691
|
}
|
|
121566
121692
|
}
|
|
121567
121693
|
}
|
|
@@ -121579,6 +121705,9 @@ var BridgeHandler = class {
|
|
|
121579
121705
|
card = await this.deps.cardRenderer.start(messageId, { replyInThread, threadId });
|
|
121580
121706
|
} catch (cardStartErr) {
|
|
121581
121707
|
console.error("[bridge.handler] failure card start also failed:", cardStartErr);
|
|
121708
|
+
await createHardFailurePostFallback(
|
|
121709
|
+
`progress post failure update failed: ${String(postFinalizeErr)}; legacy visible card fallback also failed: ${String(cardStartErr)}`
|
|
121710
|
+
);
|
|
121582
121711
|
}
|
|
121583
121712
|
}
|
|
121584
121713
|
}
|
|
@@ -121592,8 +121721,10 @@ var BridgeHandler = class {
|
|
|
121592
121721
|
});
|
|
121593
121722
|
} catch (finalizeErr) {
|
|
121594
121723
|
console.error("[bridge.handler] finalize(failure) also failed:", finalizeErr);
|
|
121724
|
+
await createHardFailurePostFallback(
|
|
121725
|
+
`legacy visible failure card finalize failed: ${String(finalizeErr)}`
|
|
121726
|
+
);
|
|
121595
121727
|
}
|
|
121596
|
-
const wtPath = this.deps.conventions.runtime === "agent_workspace" && this.deps.conventions.workspaceSessionsDir ? path10.join(this.deps.conventions.workspaceSessionsDir, threadId) : path10.join(this.deps.conventions.worktreesDir, threadId);
|
|
121597
121728
|
await deleteCardFile(wtPath);
|
|
121598
121729
|
}
|
|
121599
121730
|
}
|
|
@@ -125416,7 +125547,7 @@ function buildCommand(opts) {
|
|
|
125416
125547
|
args.push("-p", opts.prompt);
|
|
125417
125548
|
return [bin, args];
|
|
125418
125549
|
}
|
|
125419
|
-
function* parseLinesMulti(line) {
|
|
125550
|
+
function* parseLinesMulti(line, answerExtractor = new AnswerChannelExtractor()) {
|
|
125420
125551
|
const trimmed = line.trim();
|
|
125421
125552
|
if (trimmed === "") return;
|
|
125422
125553
|
let obj;
|
|
@@ -125450,7 +125581,7 @@ function* parseLinesMulti(line) {
|
|
|
125450
125581
|
if (typeof item !== "object" || item === null) continue;
|
|
125451
125582
|
const block = item;
|
|
125452
125583
|
if (block["type"] === "text" && typeof block["text"] === "string") {
|
|
125453
|
-
yield
|
|
125584
|
+
yield* answerExtractor.ingestSnapshot(block["text"], obj);
|
|
125454
125585
|
emitted = true;
|
|
125455
125586
|
} else if (block["type"] === "tool_use") {
|
|
125456
125587
|
yield {
|
|
@@ -125468,6 +125599,22 @@ function* parseLinesMulti(line) {
|
|
|
125468
125599
|
yield { type: "raw", raw: obj };
|
|
125469
125600
|
return;
|
|
125470
125601
|
}
|
|
125602
|
+
if (eventType === "stream_event") {
|
|
125603
|
+
const event = record["event"];
|
|
125604
|
+
if (typeof event === "object" && event !== null) {
|
|
125605
|
+
const streamEvent = event;
|
|
125606
|
+
const delta = streamEvent["delta"];
|
|
125607
|
+
if (typeof delta === "object" && delta !== null) {
|
|
125608
|
+
const deltaRecord = delta;
|
|
125609
|
+
if (streamEvent["type"] === "content_block_delta" && deltaRecord["type"] === "text_delta" && typeof deltaRecord["text"] === "string") {
|
|
125610
|
+
yield* answerExtractor.ingestDelta(deltaRecord["text"], obj);
|
|
125611
|
+
return;
|
|
125612
|
+
}
|
|
125613
|
+
}
|
|
125614
|
+
}
|
|
125615
|
+
yield { type: "raw", raw: obj };
|
|
125616
|
+
return;
|
|
125617
|
+
}
|
|
125471
125618
|
if (eventType === "user") {
|
|
125472
125619
|
const message = record["message"];
|
|
125473
125620
|
if (typeof message === "object" && message !== null && Array.isArray(message["content"])) {
|
|
@@ -125641,9 +125788,10 @@ stderr: ${stderr}` : "")
|
|
|
125641
125788
|
// unblock the events loop so handler.ts can reach card.finalize().
|
|
125642
125789
|
signal: rlAbortController.signal
|
|
125643
125790
|
});
|
|
125791
|
+
const answerExtractor = new AnswerChannelExtractor();
|
|
125644
125792
|
try {
|
|
125645
125793
|
for await (const line of rl) {
|
|
125646
|
-
for (const event of parseLinesMulti(line)) {
|
|
125794
|
+
for (const event of parseLinesMulti(line, answerExtractor)) {
|
|
125647
125795
|
if (event.type === "system_init") {
|
|
125648
125796
|
discoveredSessionId = event.sessionId;
|
|
125649
125797
|
}
|
|
@@ -125795,7 +125943,7 @@ function* parseCodexLine(line) {
|
|
|
125795
125943
|
return;
|
|
125796
125944
|
}
|
|
125797
125945
|
if (itemRecord["type"] === "agent_message" && typeof itemRecord["text"] === "string") {
|
|
125798
|
-
yield
|
|
125946
|
+
yield* splitAnswerChannelText(itemRecord["text"], obj);
|
|
125799
125947
|
return;
|
|
125800
125948
|
}
|
|
125801
125949
|
}
|