forked from bai/curriculum-project-hub
fix: ack Feishu card actions before interrupt work
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
import type { FeishuRuntime } from "../client.js";
|
||||
import { sendCard, patchCard } from "../client.js";
|
||||
import { sendCard, patchCard, sendText } from "../client.js";
|
||||
import { DEFAULT_MAX_MESSAGE_LENGTH, splitAtBoundary } from "../textStream.js";
|
||||
import {
|
||||
startToolUseTraceRun,
|
||||
@@ -106,26 +106,34 @@ export class StreamingAgentCard {
|
||||
async finish(fallbackText: string, options: { readonly interrupted?: boolean } = {}): Promise<void> {
|
||||
await this.flushChain;
|
||||
this.interrupted = options.interrupted === true;
|
||||
if (this.text.length > 0) {
|
||||
await this.flushCard("complete", this.text);
|
||||
return;
|
||||
try {
|
||||
let updated = true;
|
||||
if (this.text.length > 0) {
|
||||
updated = await this.flushCard("complete", this.text);
|
||||
} else if (this.currentMessageId === null && fallbackText.length > 0) {
|
||||
// No streaming text was sent. If we never created a card, send one now.
|
||||
this.text = fallbackText;
|
||||
updated = await this.flushCard("complete", this.text);
|
||||
} else if (this.currentMessageId !== null) {
|
||||
// Patch the existing card with the final text.
|
||||
updated = await this.flushCard("complete", fallbackText);
|
||||
}
|
||||
if (!updated && this.interrupted) {
|
||||
await sendText(this.rt, this.chatId, "\u5DF2\u4E2D\u65AD\u5F53\u524D\u8FD0\u884C\u3002");
|
||||
}
|
||||
} finally {
|
||||
clearToolUseTraceRun(this.runId);
|
||||
}
|
||||
// No streaming text was sent. If we never created a card, send one now.
|
||||
if (this.currentMessageId === null && fallbackText.length > 0) {
|
||||
this.text = fallbackText;
|
||||
await this.flushCard("complete", this.text);
|
||||
} else if (this.currentMessageId !== null) {
|
||||
// Patch the existing card with the final text
|
||||
await this.flushCard("complete", fallbackText);
|
||||
}
|
||||
clearToolUseTraceRun(this.runId);
|
||||
}
|
||||
|
||||
async fail(errorText: string): Promise<void> {
|
||||
await this.flushChain;
|
||||
this.text = errorText;
|
||||
await this.flushCard("complete", errorText, true);
|
||||
clearToolUseTraceRun(this.runId);
|
||||
try {
|
||||
this.text = errorText;
|
||||
await this.flushCard("complete", errorText, true);
|
||||
} finally {
|
||||
clearToolUseTraceRun(this.runId);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Internal flush logic ---
|
||||
@@ -139,23 +147,23 @@ export class StreamingAgentCard {
|
||||
});
|
||||
}
|
||||
|
||||
private async flush(): Promise<void> {
|
||||
private async flush(): Promise<boolean> {
|
||||
if (this.currentMessageId === null) {
|
||||
await this.flushCard(this.currentPhase(), this.text);
|
||||
const updated = await this.flushCard(this.currentPhase(), this.text);
|
||||
this.lastPatchAt = Date.now();
|
||||
return;
|
||||
return updated;
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
if (now - this.lastPatchAt < this.patchIntervalMs) return;
|
||||
if (now - this.lastPatchAt < this.patchIntervalMs) return true;
|
||||
this.lastPatchAt = now;
|
||||
await this.flushCard(this.currentPhase(), this.text);
|
||||
return this.flushCard(this.currentPhase(), this.text);
|
||||
}
|
||||
|
||||
private async flushCard(phase: CardPhase, text: string, isError = false): Promise<void> {
|
||||
private async flushCard(phase: CardPhase, text: string, isError = false): Promise<boolean> {
|
||||
const chunks = splitAtBoundary(text, this.maxMessageLength);
|
||||
const firstChunk = chunks[0];
|
||||
if (firstChunk === undefined) return;
|
||||
if (firstChunk === undefined) return true;
|
||||
|
||||
const toolUseSteps = getToolUseTraceSteps(this.runId);
|
||||
const card = buildAgentCard({
|
||||
@@ -171,6 +179,7 @@ export class StreamingAgentCard {
|
||||
|
||||
if (this.currentMessageId === null) {
|
||||
this.currentMessageId = await sendCard(this.rt, this.chatId, card);
|
||||
let updated = this.currentMessageId !== null;
|
||||
// Send overflow chunks as new messages (rare for agent output)
|
||||
for (const chunk of chunks.slice(1)) {
|
||||
const overflowCard = buildAgentCard({
|
||||
@@ -183,10 +192,13 @@ export class StreamingAgentCard {
|
||||
interrupted: this.interrupted,
|
||||
runId: undefined,
|
||||
});
|
||||
this.currentMessageId = await sendCard(this.rt, this.chatId, overflowCard);
|
||||
const overflowMessageId = await sendCard(this.rt, this.chatId, overflowCard);
|
||||
updated = updated && overflowMessageId !== null;
|
||||
this.currentMessageId = overflowMessageId;
|
||||
}
|
||||
return updated;
|
||||
} else {
|
||||
await patchCard(this.rt, this.currentMessageId, card);
|
||||
let updated = await patchCard(this.rt, this.currentMessageId, card);
|
||||
// For overflow, create new messages
|
||||
for (const chunk of chunks.slice(1)) {
|
||||
const overflowCard = buildAgentCard({
|
||||
@@ -199,8 +211,11 @@ export class StreamingAgentCard {
|
||||
interrupted: this.interrupted,
|
||||
runId: undefined,
|
||||
});
|
||||
this.currentMessageId = await sendCard(this.rt, this.chatId, overflowCard);
|
||||
const overflowMessageId = await sendCard(this.rt, this.chatId, overflowCard);
|
||||
updated = updated && overflowMessageId !== null;
|
||||
this.currentMessageId = overflowMessageId;
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user