fix(chat): stabilize web UI tool runs

This commit is contained in:
Peter Steinberger
2026-01-05 17:15:17 +00:00
parent 86c404c48b
commit b7e708c764
11 changed files with 176 additions and 45 deletions

View File

@@ -650,23 +650,10 @@ export function subscribeEmbeddedPiSession(params: {
if (evtType === "text_end" && blockReplyBreak === "text_end") {
if (blockChunking && blockBuffer.length > 0) {
drainBlockBuffer(true);
} else if (next && next !== lastBlockReplyText) {
lastBlockReplyText = next || undefined;
if (next) assistantTexts.push(next);
if (next && params.onBlockReply) {
const { text: cleanedText, mediaUrls } =
splitMediaFromOutput(next);
if (cleanedText || (mediaUrls && mediaUrls.length > 0)) {
void params.onBlockReply({
text: cleanedText,
mediaUrls: mediaUrls?.length ? mediaUrls : undefined,
});
}
}
} else if (blockBuffer.length > 0) {
emitBlockChunk(blockBuffer);
}
deltaBuffer = "";
blockBuffer = "";
lastStreamedAssistant = undefined;
}
}
}

View File

@@ -205,6 +205,7 @@ export async function handleCommands(params: {
resolvedVerboseLevel,
resolvedElevatedLevel,
resolveDefaultThinkingLevel,
provider,
model,
contextTokens,
isGroup,

View File

@@ -41,6 +41,7 @@ import {
type SessionEntry,
saveSessionStore,
} from "../config/sessions.js";
import { registerAgentRunContext } from "../infra/agent-events.js";
import {
loadVoiceWakeConfig,
setVoiceWakeTriggers,
@@ -844,12 +845,12 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
ctx.chatAbortControllers.delete(runId);
ctx.chatRunBuffers.delete(runId);
ctx.chatDeltaSentAt.delete(runId);
ctx.removeChatRun(active.sessionId, runId, sessionKey);
ctx.removeChatRun(runId, runId, sessionKey);
const payload = {
runId,
sessionKey,
seq: (ctx.agentRunSeq.get(active.sessionId) ?? 0) + 1,
seq: (ctx.agentRunSeq.get(runId) ?? 0) + 1,
state: "aborted" as const,
};
ctx.broadcast("chat", payload);
@@ -940,6 +941,7 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
lastTo: entry?.lastTo,
};
const clientRunId = p.idempotencyKey;
registerAgentRunContext(clientRunId, { sessionKey: p.sessionKey });
const cached = ctx.dedupe.get(`chat:${clientRunId}`);
if (cached) {
@@ -962,7 +964,7 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
sessionId,
sessionKey: p.sessionKey,
});
ctx.addChatRun(sessionId, {
ctx.addChatRun(clientRunId, {
sessionKey: p.sessionKey,
clientRunId,
});
@@ -978,6 +980,7 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
{
message: messageWithAttachments,
sessionId,
runId: clientRunId,
thinking: p.thinking,
deliver: p.deliver,
timeout: Math.ceil(timeoutMs / 1000).toString(),

View File

@@ -3,6 +3,7 @@ import { randomUUID } from "node:crypto";
import { resolveThinkingDefault } from "../../agents/model-selection.js";
import { agentCommand } from "../../commands/agent.js";
import { type SessionEntry, saveSessionStore } from "../../config/sessions.js";
import { registerAgentRunContext } from "../../infra/agent-events.js";
import { defaultRuntime } from "../../runtime.js";
import { resolveSendPolicy } from "../../sessions/send-policy.js";
import { buildMessageWithAttachments } from "../chat-attachments.js";
@@ -115,12 +116,12 @@ export const chatHandlers: GatewayRequestHandlers = {
context.chatAbortControllers.delete(runId);
context.chatRunBuffers.delete(runId);
context.chatDeltaSentAt.delete(runId);
context.removeChatRun(active.sessionId, runId, sessionKey);
context.removeChatRun(runId, runId, sessionKey);
const payload = {
runId,
sessionKey,
seq: (context.agentRunSeq.get(active.sessionId) ?? 0) + 1,
seq: (context.agentRunSeq.get(runId) ?? 0) + 1,
state: "aborted" as const,
};
context.broadcast("chat", payload);
@@ -201,6 +202,7 @@ export const chatHandlers: GatewayRequestHandlers = {
lastTo: entry?.lastTo,
};
const clientRunId = p.idempotencyKey;
registerAgentRunContext(clientRunId, { sessionKey: p.sessionKey });
const sendPolicy = resolveSendPolicy({
cfg,
@@ -236,7 +238,7 @@ export const chatHandlers: GatewayRequestHandlers = {
sessionId,
sessionKey: p.sessionKey,
});
context.addChatRun(sessionId, {
context.addChatRun(clientRunId, {
sessionKey: p.sessionKey,
clientRunId,
});
@@ -252,6 +254,7 @@ export const chatHandlers: GatewayRequestHandlers = {
{
message: messageWithAttachments,
sessionId,
runId: clientRunId,
thinking: p.thinking,
deliver: p.deliver,
timeout: Math.ceil(timeoutMs / 1000).toString(),

View File

@@ -830,7 +830,7 @@ describe("gateway server chat", () => {
);
emitAgentEvent({
runId: "sess-main",
runId: "idem-1",
stream: "lifecycle",
data: { phase: "end" },
});
@@ -852,7 +852,7 @@ describe("gateway server chat", () => {
);
emitAgentEvent({
runId: "sess-main",
runId: "idem-2",
stream: "lifecycle",
data: { phase: "end" },
});