forked from EduCraft/curriculum-project-hub
fix(hub): always send interrupt notice when card finalize fails
If StreamingAgentCard.finish cannot patch the live card, plain-text fallback can still succeed with partial answer text. Interrupt is terminal — always emit the explicit 已中断 notice when the card path failed so teachers see the abort. Harden the integration assertion with waitFor.
This commit is contained in:
@@ -173,17 +173,20 @@ export class StreamingAgentCard {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let updated = true;
|
let cardUpdated = true;
|
||||||
if (answerText.length > 0 || segments.length > 0) {
|
if (answerText.length > 0 || segments.length > 0) {
|
||||||
updated = await this.flushCard("complete", answerText, isError, segments);
|
cardUpdated = await this.flushCard("complete", answerText, isError, segments);
|
||||||
} else if (this.currentMessageId !== null) {
|
} else if (this.currentMessageId !== null) {
|
||||||
updated = await this.flushCard("complete", "", isError, []);
|
cardUpdated = await this.flushCard("complete", "", isError, []);
|
||||||
}
|
}
|
||||||
if (!updated) {
|
if (!cardUpdated) {
|
||||||
// Card path failed (e.g. residual content policy). Deliver text + standalone images.
|
// Card path failed (e.g. residual content policy). Deliver text + standalone images.
|
||||||
updated = await this.deliverPlainFallback(segments, answerText);
|
await this.deliverPlainFallback(segments, answerText);
|
||||||
}
|
}
|
||||||
if (!updated && this.interrupted) {
|
// Interrupt is terminal; if the live card could not be finalized, always
|
||||||
|
// send an explicit notice so the teacher sees the abort even when plain
|
||||||
|
// text partial delivery succeeded.
|
||||||
|
if (!cardUpdated && this.interrupted) {
|
||||||
await sendText(this.rt, this.chatId, "\u5DF2\u4E2D\u65AD\u5F53\u524D\u8FD0\u884C\u3002", this.sendOptions);
|
await sendText(this.rt, this.chatId, "\u5DF2\u4E2D\u65AD\u5F53\u524D\u8FD0\u884C\u3002", this.sendOptions);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -1611,7 +1611,9 @@ describe("trigger full lifecycle (integration)", () => {
|
|||||||
expect(runs[0]?.status).toBe("CANCELED");
|
expect(runs[0]?.status).toBe("CANCELED");
|
||||||
});
|
});
|
||||||
expect(patch).toHaveBeenCalled();
|
expect(patch).toHaveBeenCalled();
|
||||||
expect(rt.sentTexts).toContain("已中断当前运行。");
|
await vi.waitFor(() => {
|
||||||
|
expect(rt.sentTexts).toContain("已中断当前运行。");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("denies interrupt when the operator lacks agent.cancel permission", async () => {
|
it("denies interrupt when the operator lacks agent.cancel permission", async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user