fix: restore model activity reasoning stream

This commit is contained in:
User
2026-07-14 15:03:07 +02:00
parent 1b1554b353
commit c7474f3852
11 changed files with 490 additions and 14 deletions
+3
View File
@@ -3,6 +3,7 @@ import type { RpcClient } from "../rpc/rpc-client.js";
export type ClientEvent =
| { type: "ui_request"; ui_request: any }
| { type: "text_delta"; text: string }
| { type: "activity_delta"; text: string }
| { type: "info"; [k: string]: any }
| { type: "system_event"; [k: string]: any };
@@ -27,6 +28,8 @@ export class SessionBridge {
this.fan({ type: "info", level: m.notifyType ?? "info", text: m.message ?? "" });
} else if (m.type === "message_update" && m.assistantMessageEvent?.type === "text_delta") {
this.fan({ type: "text_delta", text: m.assistantMessageEvent.delta ?? "" });
} else if (m.type === "message_update" && m.assistantMessageEvent?.type === "thinking_delta") {
this.fan({ type: "activity_delta", text: m.assistantMessageEvent.delta ?? "" });
} else if (m.type === "text_delta") {
this.fan({ type: "text_delta", text: m.text ?? "" });
// tool_execution_* events are intentionally NOT forwarded: they clutter
+2 -5
View File
@@ -69,8 +69,7 @@ export function sessionRoutes(
const options = {
provider: s.provider,
model: s.model,
// Keep the saved preference in the manifest; F1 starts tool-first.
thinking: "off",
thinking: s.thinking,
author: getUser(req).id,
question: b.question,
};
@@ -117,9 +116,7 @@ export function sessionRoutes(
const options = {
provider: saved?.provider,
model: saved?.model,
// Phase 1 must reach a widget instead of exposing a long reasoning trace.
// The session keeps its saved preference for later turns.
thinking: "off",
thinking: saved?.thinking ?? settings.thinking,
author: getUser(req).id,
mode: "resume" as const,
};
+59
View File
@@ -47,6 +47,65 @@ test("POST /sessions usa i settings (workspace/provider/model/thinking) e crea+a
unlinkSync(modelKey);
});
test("POST /sessions configura Pi con il thinking globale selezionato", async () => {
let configured: any;
const bridge = { onClientEvent: () => {}, emitClientEvent: () => {} };
const runtime = { bridge } as any;
const mgr = {
createFor: () => runtime,
configure: async (_rt: any, options: any) => { configured = options; },
start: () => {},
teardown: () => {},
} as any;
const app = buildApp(loadConfig({ THT_HARNESS_DIR: "../harness" }), {
mgr,
thtRunner: {
ollamaEnsure: async () => ({ ok: true }),
searchPack: async () => {},
sessionNew: async () => ({ id: "s-thinking" }),
} as any,
getSettings: () => ({ workspace: "psd", provider: "zai", model: "glm-5.2", thinking: "high" }) as any,
});
await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
await new Promise((resolve) => setImmediate(resolve));
expect(configured.thinking).toBe("high");
});
test("POST /sessions/:id/resume configura Pi con il thinking persistito", async () => {
let configured: any;
const bridge = { onClientEvent: () => {}, emitClientEvent: () => {} };
const runtime = { bridge } as any;
const mgr = {
get: () => undefined,
createFor: () => runtime,
configure: async (_rt: any, options: any) => { configured = options; },
start: () => {},
teardown: () => {},
} as any;
const app = buildApp(loadConfig({ THT_HARNESS_DIR: "../harness" }), {
mgr,
thtRunner: {
ollamaEnsure: async () => ({ ok: true }),
sessionShow: async () => ({
status: "open",
archived: false,
provider: "zai",
model: "glm-5.2",
thinking: "medium",
}),
reopenSession: async () => {},
} as any,
getSettings: () => ({ workspace: "psd", thinking: "low" }) as any,
});
await app.inject({ method: "POST", url: "/sessions/s-thinking/resume" });
await new Promise((resolve) => setImmediate(resolve));
expect(configured.thinking).toBe("medium");
});
test("POST /sessions/:id/response inoltra al bridge (no error)", async () => {
const app = buildApp(loadConfig({ THT_HARNESS_DIR: "../harness" }), {
thtRunner: {
+14
View File
@@ -28,6 +28,20 @@ test("real Pi message_update (assistantMessageEvent text_delta) becomes a text_d
expect(seen).toHaveLength(1);
});
test("real Pi thinking_delta becomes a dedicated activity_delta to the FE", () => {
const { rpc, fire } = fakeRpc();
const b = new SessionBridge(rpc);
const seen: any[] = [];
b.onClientEvent((e) => seen.push(e));
fire({
type: "message_update",
assistantMessageEvent: { type: "thinking_delta", contentIndex: 0, delta: "Valuto le ambiguità" },
});
expect(seen).toEqual([{ type: "activity_delta", text: "Valuto le ambiguità" }]);
});
test("extension_ui_request nativo (method:input, title=json) diventa ui_request col descriptor ed è il pendente", () => {
const { rpc, fire } = fakeRpc();
const b = new SessionBridge(rpc);