fix: start typing on partial deltas
This commit is contained in:
@@ -145,6 +145,23 @@ describe("runReplyAgent typing (heartbeat)", () => {
|
|||||||
expect(typing.startTypingLoop).toHaveBeenCalled();
|
expect(typing.startTypingLoop).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("signals typing even without consumer partial handler", async () => {
|
||||||
|
runEmbeddedPiAgentMock.mockImplementationOnce(
|
||||||
|
async (params: EmbeddedPiAgentParams) => {
|
||||||
|
await params.onPartialReply?.({ text: "hi" });
|
||||||
|
return { payloads: [{ text: "final" }], meta: {} };
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const { run, typing } = createMinimalRun({
|
||||||
|
typingMode: "message",
|
||||||
|
});
|
||||||
|
await run();
|
||||||
|
|
||||||
|
expect(typing.startTypingOnText).toHaveBeenCalledWith("hi");
|
||||||
|
expect(typing.startTypingLoop).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it("never signals typing for heartbeat runs", async () => {
|
it("never signals typing for heartbeat runs", async () => {
|
||||||
const onPartialReply = vi.fn();
|
const onPartialReply = vi.fn();
|
||||||
runEmbeddedPiAgentMock.mockImplementationOnce(
|
runEmbeddedPiAgentMock.mockImplementationOnce(
|
||||||
|
|||||||
@@ -547,6 +547,28 @@ export async function runReplyAgent(params: {
|
|||||||
const allowPartialStream = !(
|
const allowPartialStream = !(
|
||||||
followupRun.run.reasoningLevel === "stream" && opts?.onReasoningStream
|
followupRun.run.reasoningLevel === "stream" && opts?.onReasoningStream
|
||||||
);
|
);
|
||||||
|
const handlePartialForTyping = async (
|
||||||
|
payload: ReplyPayload,
|
||||||
|
): Promise<string | undefined> => {
|
||||||
|
if (!allowPartialStream) return undefined;
|
||||||
|
let text = payload.text;
|
||||||
|
if (!isHeartbeat && text?.includes("HEARTBEAT_OK")) {
|
||||||
|
const stripped = stripHeartbeatToken(text, {
|
||||||
|
mode: "message",
|
||||||
|
});
|
||||||
|
if (stripped.didStrip && !didLogHeartbeatStrip) {
|
||||||
|
didLogHeartbeatStrip = true;
|
||||||
|
logVerbose("Stripped stray HEARTBEAT_OK token from reply");
|
||||||
|
}
|
||||||
|
if (stripped.shouldSkip && (payload.mediaUrls?.length ?? 0) === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
text = stripped.text;
|
||||||
|
}
|
||||||
|
if (isSilentReplyText(text, SILENT_REPLY_TOKEN)) return undefined;
|
||||||
|
await typingSignals.signalTextDelta(text);
|
||||||
|
return text;
|
||||||
|
};
|
||||||
const fallbackResult = await runWithModelFallback({
|
const fallbackResult = await runWithModelFallback({
|
||||||
cfg: followupRun.run.config,
|
cfg: followupRun.run.config,
|
||||||
provider: followupRun.run.provider,
|
provider: followupRun.run.provider,
|
||||||
@@ -641,31 +663,15 @@ export async function runReplyAgent(params: {
|
|||||||
blockReplyBreak: resolvedBlockStreamingBreak,
|
blockReplyBreak: resolvedBlockStreamingBreak,
|
||||||
blockReplyChunking,
|
blockReplyChunking,
|
||||||
onPartialReply:
|
onPartialReply:
|
||||||
opts?.onPartialReply && allowPartialStream
|
allowPartialStream
|
||||||
? async (payload) => {
|
? async (payload) => {
|
||||||
let text = payload.text;
|
const textForTyping = await handlePartialForTyping(
|
||||||
if (!isHeartbeat && text?.includes("HEARTBEAT_OK")) {
|
payload,
|
||||||
const stripped = stripHeartbeatToken(text, {
|
);
|
||||||
mode: "message",
|
if (!opts?.onPartialReply || textForTyping === undefined)
|
||||||
});
|
return;
|
||||||
if (stripped.didStrip && !didLogHeartbeatStrip) {
|
await opts.onPartialReply({
|
||||||
didLogHeartbeatStrip = true;
|
text: textForTyping,
|
||||||
logVerbose(
|
|
||||||
"Stripped stray HEARTBEAT_OK token from reply",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
stripped.shouldSkip &&
|
|
||||||
(payload.mediaUrls?.length ?? 0) === 0
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
text = stripped.text;
|
|
||||||
}
|
|
||||||
if (isSilentReplyText(text, SILENT_REPLY_TOKEN)) return;
|
|
||||||
await typingSignals.signalTextDelta(text);
|
|
||||||
await opts.onPartialReply?.({
|
|
||||||
text,
|
|
||||||
mediaUrls: payload.mediaUrls,
|
mediaUrls: payload.mediaUrls,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user