Merge dded462469 into da71eaebd2
This commit is contained in:
commit
e2f0a82202
@ -73,6 +73,7 @@ Status: stable.
|
|||||||
- **BREAKING:** Gateway auth mode "none" is removed; gateway now requires token/password (Tailscale Serve identity still allowed).
|
- **BREAKING:** Gateway auth mode "none" is removed; gateway now requires token/password (Tailscale Serve identity still allowed).
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
- TUI: emit final assistant event when reply tags hide stream. (#4495) Thanks @ukeate.
|
||||||
- Telegram: use undici fetch for per-account proxy dispatcher. (#4456) Thanks @spiceoogway.
|
- Telegram: use undici fetch for per-account proxy dispatcher. (#4456) Thanks @spiceoogway.
|
||||||
- Telegram: fix HTML nesting for overlapping styles and links. (#4578) Thanks @ThanhNguyxn.
|
- Telegram: fix HTML nesting for overlapping styles and links. (#4578) Thanks @ThanhNguyxn.
|
||||||
- Telegram: avoid silent empty replies by tracking normalization skips before fallback. (#3796)
|
- Telegram: avoid silent empty replies by tracking normalization skips before fallback. (#3796)
|
||||||
|
|||||||
@ -176,6 +176,30 @@ export function handleMessageEnd(
|
|||||||
});
|
});
|
||||||
|
|
||||||
const text = ctx.stripBlockTags(rawText, { thinking: false, final: false });
|
const text = ctx.stripBlockTags(rawText, { thinking: false, final: false });
|
||||||
|
const { text: cleanedText, mediaUrls } = parseReplyDirectives(text);
|
||||||
|
const { text: previousCleanedText } = parseReplyDirectives(ctx.state.lastStreamedAssistant ?? "");
|
||||||
|
if (cleanedText && cleanedText !== previousCleanedText) {
|
||||||
|
const deltaText = cleanedText.startsWith(previousCleanedText)
|
||||||
|
? cleanedText.slice(previousCleanedText.length)
|
||||||
|
: cleanedText;
|
||||||
|
emitAgentEvent({
|
||||||
|
runId: ctx.params.runId,
|
||||||
|
stream: "assistant",
|
||||||
|
data: {
|
||||||
|
text: cleanedText,
|
||||||
|
delta: deltaText,
|
||||||
|
mediaUrls: mediaUrls?.length ? mediaUrls : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
void ctx.params.onAgentEvent?.({
|
||||||
|
stream: "assistant",
|
||||||
|
data: {
|
||||||
|
text: cleanedText,
|
||||||
|
delta: deltaText,
|
||||||
|
mediaUrls: mediaUrls?.length ? mediaUrls : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
const rawThinking =
|
const rawThinking =
|
||||||
ctx.state.includeReasoning || ctx.state.streamReasoning
|
ctx.state.includeReasoning || ctx.state.streamReasoning
|
||||||
? extractAssistantThinking(assistantMessage) || extractThinkingFromTaggedText(rawText)
|
? extractAssistantThinking(assistantMessage) || extractThinkingFromTaggedText(rawText)
|
||||||
|
|||||||
@ -221,6 +221,50 @@ describe("subscribeEmbeddedPiSession", () => {
|
|||||||
expect(payloads[0]?.text).toBe("MEDIA:");
|
expect(payloads[0]?.text).toBe("MEDIA:");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("emits agent events on message_end when reply tags hide final text", () => {
|
||||||
|
let handler: ((evt: unknown) => void) | undefined;
|
||||||
|
const session: StubSession = {
|
||||||
|
subscribe: (fn) => {
|
||||||
|
handler = fn;
|
||||||
|
return () => {};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const onAgentEvent = vi.fn();
|
||||||
|
|
||||||
|
subscribeEmbeddedPiSession({
|
||||||
|
session: session as unknown as Parameters<typeof subscribeEmbeddedPiSession>[0]["session"],
|
||||||
|
runId: "run",
|
||||||
|
onAgentEvent,
|
||||||
|
});
|
||||||
|
|
||||||
|
handler?.({ type: "message_start", message: { role: "assistant" } });
|
||||||
|
handler?.({
|
||||||
|
type: "message_update",
|
||||||
|
message: { role: "assistant" },
|
||||||
|
assistantMessageEvent: { type: "text_delta", delta: "[[reply_to: 123" },
|
||||||
|
});
|
||||||
|
handler?.({
|
||||||
|
type: "message_update",
|
||||||
|
message: { role: "assistant" },
|
||||||
|
assistantMessageEvent: { type: "text_delta", delta: "]] Hello" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const assistantMessage = {
|
||||||
|
role: "assistant",
|
||||||
|
content: [{ type: "text", text: "[[reply_to: 123]] Hello" }],
|
||||||
|
} as AssistantMessage;
|
||||||
|
handler?.({ type: "message_end", message: assistantMessage });
|
||||||
|
|
||||||
|
const payloads = onAgentEvent.mock.calls
|
||||||
|
.map((call) => call[0]?.data as Record<string, unknown> | undefined)
|
||||||
|
.filter((value): value is Record<string, unknown> => Boolean(value));
|
||||||
|
expect(payloads.length).toBeGreaterThan(0);
|
||||||
|
const last = payloads[payloads.length - 1];
|
||||||
|
expect(last?.text).toBe("Hello");
|
||||||
|
expect(last?.delta).toBe("Hello");
|
||||||
|
});
|
||||||
|
|
||||||
it("emits agent events when media arrives without text", () => {
|
it("emits agent events when media arrives without text", () => {
|
||||||
let handler: ((evt: unknown) => void) | undefined;
|
let handler: ((evt: unknown) => void) | undefined;
|
||||||
const session: StubSession = {
|
const session: StubSession = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user