TUI/Gateway: fix pi streaming + tool routing + model display + msg updating (#8432)

* TUI/Gateway: fix pi streaming + tool routing

* Tests: clarify verbose tool output expectation

* fix: avoid seq gaps for targeted tool events (#8432) (thanks @gumadeiras)
This commit is contained in:
Gustavo Madeira Santana
2026-02-04 17:12:16 -05:00
committed by GitHub
parent a42e3cb78a
commit 38e6da1fe0
32 changed files with 1227 additions and 208 deletions

View File

@@ -1,4 +1,6 @@
import type { Component, TUI } from "@mariozechner/pi-tui";
import { randomUUID } from "node:crypto";
import type { SessionsPatchResult } from "../gateway/protocol/index.js";
import type { ChatLog } from "./components/chat-log.js";
import type { GatewayChatClient } from "./gateway-chat.js";
import type {
@@ -38,6 +40,9 @@ type CommandHandlerContext = {
abortActive: () => Promise<void>;
setActivityStatus: (text: string) => void;
formatSessionKey: (key: string) => string;
applySessionInfoFromPatch: (result: SessionsPatchResult) => void;
noteLocalRunId: (runId: string) => void;
forgetLocalRunId?: (runId: string) => void;
};
export function createCommandHandlers(context: CommandHandlerContext) {
@@ -57,6 +62,9 @@ export function createCommandHandlers(context: CommandHandlerContext) {
abortActive,
setActivityStatus,
formatSessionKey,
applySessionInfoFromPatch,
noteLocalRunId,
forgetLocalRunId,
} = context;
const setAgent = async (id: string) => {
@@ -81,11 +89,12 @@ export function createCommandHandlers(context: CommandHandlerContext) {
selector.onSelect = (item) => {
void (async () => {
try {
await client.patchSession({
const result = await client.patchSession({
key: state.currentSessionKey,
model: item.value,
});
chatLog.addSystem(`model set to ${item.value}`);
applySessionInfoFromPatch(result);
await refreshSessionInfo();
} catch (err) {
chatLog.addSystem(`model set failed: ${String(err)}`);
@@ -284,11 +293,12 @@ export function createCommandHandlers(context: CommandHandlerContext) {
await openModelSelector();
} else {
try {
await client.patchSession({
const result = await client.patchSession({
key: state.currentSessionKey,
model: args,
});
chatLog.addSystem(`model set to ${args}`);
applySessionInfoFromPatch(result);
await refreshSessionInfo();
} catch (err) {
chatLog.addSystem(`model set failed: ${String(err)}`);
@@ -309,11 +319,12 @@ export function createCommandHandlers(context: CommandHandlerContext) {
break;
}
try {
await client.patchSession({
const result = await client.patchSession({
key: state.currentSessionKey,
thinkingLevel: args,
});
chatLog.addSystem(`thinking set to ${args}`);
applySessionInfoFromPatch(result);
await refreshSessionInfo();
} catch (err) {
chatLog.addSystem(`think failed: ${String(err)}`);
@@ -325,12 +336,13 @@ export function createCommandHandlers(context: CommandHandlerContext) {
break;
}
try {
await client.patchSession({
const result = await client.patchSession({
key: state.currentSessionKey,
verboseLevel: args,
});
chatLog.addSystem(`verbose set to ${args}`);
await refreshSessionInfo();
applySessionInfoFromPatch(result);
await loadHistory();
} catch (err) {
chatLog.addSystem(`verbose failed: ${String(err)}`);
}
@@ -341,11 +353,12 @@ export function createCommandHandlers(context: CommandHandlerContext) {
break;
}
try {
await client.patchSession({
const result = await client.patchSession({
key: state.currentSessionKey,
reasoningLevel: args,
});
chatLog.addSystem(`reasoning set to ${args}`);
applySessionInfoFromPatch(result);
await refreshSessionInfo();
} catch (err) {
chatLog.addSystem(`reasoning failed: ${String(err)}`);
@@ -362,11 +375,12 @@ export function createCommandHandlers(context: CommandHandlerContext) {
const next =
normalized ?? (current === "off" ? "tokens" : current === "tokens" ? "full" : "off");
try {
await client.patchSession({
const result = await client.patchSession({
key: state.currentSessionKey,
responseUsage: next === "off" ? null : next,
});
chatLog.addSystem(`usage footer: ${next}`);
applySessionInfoFromPatch(result);
await refreshSessionInfo();
} catch (err) {
chatLog.addSystem(`usage failed: ${String(err)}`);
@@ -383,11 +397,12 @@ export function createCommandHandlers(context: CommandHandlerContext) {
break;
}
try {
await client.patchSession({
const result = await client.patchSession({
key: state.currentSessionKey,
elevatedLevel: args,
});
chatLog.addSystem(`elevated set to ${args}`);
applySessionInfoFromPatch(result);
await refreshSessionInfo();
} catch (err) {
chatLog.addSystem(`elevated failed: ${String(err)}`);
@@ -399,11 +414,12 @@ export function createCommandHandlers(context: CommandHandlerContext) {
break;
}
try {
await client.patchSession({
const result = await client.patchSession({
key: state.currentSessionKey,
groupActivation: args === "always" ? "always" : "mention",
});
chatLog.addSystem(`activation set to ${args}`);
applySessionInfoFromPatch(result);
await refreshSessionInfo();
} catch (err) {
chatLog.addSystem(`activation failed: ${String(err)}`);
@@ -448,17 +464,24 @@ export function createCommandHandlers(context: CommandHandlerContext) {
try {
chatLog.addUser(text);
tui.requestRender();
const runId = randomUUID();
noteLocalRunId(runId);
state.activeChatRunId = runId;
setActivityStatus("sending");
const { runId } = await client.sendChat({
await client.sendChat({
sessionKey: state.currentSessionKey,
message: text,
thinking: opts.thinking,
deliver: deliverDefault,
timeoutMs: opts.timeoutMs,
runId,
});
state.activeChatRunId = runId;
setActivityStatus("waiting");
} catch (err) {
if (state.activeChatRunId) {
forgetLocalRunId?.(state.activeChatRunId);
}
state.activeChatRunId = null;
chatLog.addSystem(`send failed: ${String(err)}`);
setActivityStatus("error");
}