gsd-pi 2.70.1-dev.6504106 → 2.70.1-dev.7d1d9d3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/resources/extensions/gsd/custom-workflow-engine.js +16 -12
  2. package/dist/resources/extensions/gsd/file-lock.js +60 -0
  3. package/dist/resources/extensions/gsd/workflow-events.js +25 -13
  4. package/dist/web/standalone/.next/BUILD_ID +1 -1
  5. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  6. package/dist/web/standalone/.next/build-manifest.json +2 -2
  7. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  8. package/dist/web/standalone/.next/required-server-files.json +1 -1
  9. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  10. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  11. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  17. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  18. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  20. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/index.html +1 -1
  26. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  33. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  34. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  35. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  36. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  37. package/dist/web/standalone/server.js +1 -1
  38. package/package.json +1 -1
  39. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +78 -0
  40. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  41. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  42. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +13 -3
  43. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  44. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +98 -0
  45. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +12 -3
  46. package/src/resources/extensions/gsd/custom-workflow-engine.ts +19 -14
  47. package/src/resources/extensions/gsd/file-lock.ts +59 -0
  48. package/src/resources/extensions/gsd/tests/file-lock.test.ts +103 -0
  49. package/src/resources/extensions/gsd/workflow-events.ts +34 -25
  50. /package/dist/web/standalone/.next/static/{T3hWbQ-WQBDEIGoaOOfEo → 52NuiWbmUzXpzxaTEDopT}/_buildManifest.js +0 -0
  51. /package/dist/web/standalone/.next/static/{T3hWbQ-WQBDEIGoaOOfEo → 52NuiWbmUzXpzxaTEDopT}/_ssgManifest.js +0 -0
@@ -284,6 +284,84 @@ test("chat-controller clears pinned zone when a new assistant message starts", a
284
284
  await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) });
285
285
  assert.equal(host.pinnedMessageContainer.children.length, 0, "pinned zone should clear on new assistant message");
286
286
  });
287
+ test("chat-controller clears pinned zone when the agent turn ends", async () => {
288
+ globalThis[Symbol.for("@gsd/pi-coding-agent:theme")] = {
289
+ fg: (_key, text) => text,
290
+ bg: (_key, text) => text,
291
+ bold: (text) => text,
292
+ italic: (text) => text,
293
+ truncate: (text) => text,
294
+ };
295
+ const host = createHost();
296
+ const toolCall = {
297
+ type: "toolCall",
298
+ id: "tool-clear-on-end-1",
299
+ name: "exec_command",
300
+ arguments: { cmd: "echo hi" },
301
+ };
302
+ await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) });
303
+ host.getMarkdownThemeWithSettings = () => ({});
304
+ await handleAgentEvent(host, {
305
+ type: "message_update",
306
+ message: makeAssistant([{ type: "text", text: "Working on it." }, toolCall]),
307
+ assistantMessageEvent: {
308
+ type: "toolcall_end",
309
+ contentIndex: 1,
310
+ toolCall: {
311
+ ...toolCall,
312
+ externalResult: {
313
+ content: [{ type: "text", text: "ok" }],
314
+ details: {},
315
+ isError: false,
316
+ },
317
+ },
318
+ partial: makeAssistant([{ type: "text", text: "Working on it." }, toolCall]),
319
+ },
320
+ });
321
+ assert.ok(host.pinnedMessageContainer.children.length > 0, "pinned zone should be populated before agent_end");
322
+ await handleAgentEvent(host, { type: "agent_end" });
323
+ assert.equal(host.pinnedMessageContainer.children.length, 0, "pinned zone should clear on agent_end");
324
+ });
325
+ test("chat-controller clears pinned zone when assistant message ends", async () => {
326
+ globalThis[Symbol.for("@gsd/pi-coding-agent:theme")] = {
327
+ fg: (_key, text) => text,
328
+ bg: (_key, text) => text,
329
+ bold: (text) => text,
330
+ italic: (text) => text,
331
+ truncate: (text) => text,
332
+ };
333
+ const host = createHost();
334
+ const toolCall = {
335
+ type: "toolCall",
336
+ id: "tool-msg-end-1",
337
+ name: "exec_command",
338
+ arguments: { cmd: "echo hi" },
339
+ };
340
+ await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) });
341
+ host.getMarkdownThemeWithSettings = () => ({});
342
+ const msgContent = [{ type: "text", text: "Summary after tools." }, toolCall];
343
+ await handleAgentEvent(host, {
344
+ type: "message_update",
345
+ message: makeAssistant(msgContent),
346
+ assistantMessageEvent: {
347
+ type: "toolcall_end",
348
+ contentIndex: 1,
349
+ toolCall: {
350
+ ...toolCall,
351
+ externalResult: {
352
+ content: [{ type: "text", text: "ok" }],
353
+ details: {},
354
+ isError: false,
355
+ },
356
+ },
357
+ partial: makeAssistant(msgContent),
358
+ },
359
+ });
360
+ assert.ok(host.pinnedMessageContainer.children.length > 0, "pinned zone should be populated during streaming");
361
+ // End the assistant message (e.g. before form elicitation) — pinned zone should clear
362
+ await handleAgentEvent(host, { type: "message_end", message: makeAssistant(msgContent) });
363
+ assert.equal(host.pinnedMessageContainer.children.length, 0, "pinned zone should clear on message_end to prevent duplicate display");
364
+ });
287
365
  test("chat-controller does not pin when there are no tool calls", async () => {
288
366
  globalThis[Symbol.for("@gsd/pi-coding-agent:theme")] = {
289
367
  fg: (_key, text) => text,
@@ -1 +1 @@
1
- {"version":3,"file":"chat-controller-ordering.test.js","sourceRoot":"","sources":["../../src/core/chat-controller-ordering.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qDAAqD,CAAC;AAEvF,SAAS,SAAS;IACjB,OAAO;QACN,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,CAAC;QACT,SAAS,EAAE,CAAC;QACZ,UAAU,EAAE,CAAC;QACb,WAAW,EAAE,CAAC;QACd,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;KACpE,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,OAAc;IACpC,OAAO;QACN,IAAI,EAAE,WAAW;QACjB,OAAO;QACP,GAAG,EAAE,oBAAoB;QACzB,QAAQ,EAAE,aAAa;QACvB,KAAK,EAAE,iBAAiB;QACxB,KAAK,EAAE,SAAS,EAAE;QAClB,UAAU,EAAE,MAAM;QAClB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACrB,CAAC;AACH,CAAC;AAED,SAAS,UAAU;IAClB,MAAM,aAAa,GAAG;QACrB,QAAQ,EAAE,EAAW;QACrB,QAAQ,CAAC,SAAc;YACtB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/B,CAAC;QACD,WAAW,CAAC,SAAc;YACzB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC7C,IAAI,GAAG,KAAK,CAAC,CAAC;gBAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,KAAK;YACJ,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACpB,CAAC;KACD,CAAC;IAEF,MAAM,sBAAsB,GAAG;QAC9B,QAAQ,EAAE,EAAW;QACrB,QAAQ,CAAC,SAAc;YACtB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/B,CAAC;QACD,WAAW,CAAC,SAAc;YACzB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC7C,IAAI,GAAG,KAAK,CAAC,CAAC;gBAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,KAAK;YACJ,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACpB,CAAC;KACD,CAAC;IAEF,MAAM,IAAI,GAAQ;QACjB,aAAa,EAAE,IAAI;QACnB,IAAI,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;QACpB,aAAa,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE;QACtC,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE;QAC7E,EAAE,EAAE,EAAE,aAAa,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;QACvD,MAAM,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE;QAChC,WAAW,EAAE,EAAE;QACf,eAAe,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE;QACxD,aAAa;QACb,eAAe,EAAE,EAAE,kBAAkB,EAAE,GAAG,EAAE,CAAC,eAAe,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE;QAC1F,YAAY,EAAE,IAAI,GAAG,EAAE;QACvB,kBAAkB,EAAE,KAAK;QACzB,iBAAiB,EAAE,KAAK;QACxB,UAAU,EAAE,KAAK;QACjB,qBAAqB,EAAE,YAAY;QACnC,wBAAwB,EAAE,EAAE;QAC5B,eAAe,EAAE,EAAE;QACnB,wBAAwB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE;QAC7C,sBAAsB;QACtB,gBAAgB,EAAE,GAAG,EAAE,GAAE,CAAC;QAC1B,4BAA4B,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;QACxC,qBAAqB,EAAE,GAAG,EAAE,CAAC,EAAE;QAC/B,2BAA2B,EAAE,GAAG,EAAE,CAAC,SAAS;QAC5C,sBAAsB,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;QACtC,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;QACjC,oBAAoB,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;QACpC,UAAU,EAAE,GAAG,EAAE,GAAE,CAAC;QACpB,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;QACnB,4BAA4B,EAAE,GAAG,EAAE,GAAE,CAAC;QACtC,mBAAmB,EAAE,GAAG,EAAE,GAAE,CAAC;QAC7B,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;KACjC,CAAC;IAEF,OAAO,IAAI,CAAC;AACb,CAAC;AAED,IAAI,CAAC,6FAA6F,EAAE,KAAK,IAAI,EAAE;IAC9G,0DAA0D;IAC1D,mEAAmE;IAClE,UAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,GAAG;QAC/D,EAAE,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI;QACxC,EAAE,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI;QACxC,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;QAC5B,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;QAC9B,QAAQ,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;KAChC,CAAC;IAEF,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,YAAY,CAAC;IAC5B,MAAM,QAAQ,GAAG;QAChB,IAAI,EAAE,UAAU;QAChB,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,cAAc;QACpB,SAAS,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE;KAC7B,CAAC;IAEF,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,CAAC,EAAS,CAAC,CAAC;IAE3F,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,EAAE,SAAS,EAAE,yDAAyD,CAAC,CAAC;IAC5G,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,8CAA8C,CAAC,CAAC;IAEpG,MAAM,gBAAgB,CACrB,IAAI,EACJ;QACC,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC;QAClC,qBAAqB,EAAE;YACtB,IAAI,EAAE,cAAc;YACpB,YAAY,EAAE,CAAC;YACf,QAAQ,EAAE;gBACT,GAAG,QAAQ;gBACX,cAAc,EAAE;oBACf,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;oBAChD,OAAO,EAAE,EAAE;oBACX,OAAO,EAAE,KAAK;iBACd;aACD;YACD,OAAO,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC;SAClC;KACM,CACR,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,EAAE,SAAS,EAAE,uEAAuE,CAAC,CAAC;IAC1H,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,gDAAgD,CAAC,CAAC;IACtG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,wBAAwB,CAAC,CAAC;IAE1F,sEAAsE;IACtE,IAAI,CAAC,4BAA4B,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAE/C,MAAM,gBAAgB,CACrB,IAAI,EACJ;QACC,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,aAAa,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAClE,qBAAqB,EAAE;YACtB,IAAI,EAAE,YAAY;YAClB,YAAY,EAAE,CAAC;YACf,KAAK,EAAE,MAAM;YACb,OAAO,EAAE,aAAa,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;SAClE;KACM,CACR,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,4DAA4D,CAAC,CAAC;IAClH,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,wBAAwB,CAAC,CAAC;IAC1F,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,2BAA2B,CAAC,CAAC;AAC9F,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,iGAAiG,EAAE,KAAK,IAAI,EAAE;IACjH,UAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,GAAG;QAC/D,EAAE,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI;QACxC,EAAE,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI;QACxC,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;QAC5B,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;QAC9B,QAAQ,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;KAChC,CAAC;IAEF,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,cAAc,CAAC;IAC9B,MAAM,aAAa,GAAG;QACrB,IAAI,EAAE,eAAe;QACrB,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,uCAAuC;QAC7C,KAAK,EAAE,EAAE,UAAU,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,iBAAiB,EAAE,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE;KAChG,CAAC;IAEF,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,CAAC,EAAS,CAAC,CAAC;IAE3F,MAAM,gBAAgB,CACrB,IAAI,EACJ;QACC,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,aAAa,CAAC,CAAC,aAAa,CAAC,CAAC;QACvC,qBAAqB,EAAE;YACtB,IAAI,EAAE,iBAAiB;YACvB,YAAY,EAAE,CAAC;YACf,OAAO,EAAE,aAAa,CAAC,CAAC,aAAa,CAAC,CAAC;SACvC;KACM,CACR,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,EAAE,SAAS,EAAE,wEAAwE,CAAC,CAAC;IAC3H,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,6CAA6C,CAAC,CAAC;IACnG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,wBAAwB,CAAC,CAAC;IAE1F,IAAI,CAAC,4BAA4B,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/C,MAAM,aAAa,GAAG,aAAa,CAAC;QACnC;YACC,GAAG,aAAa;YAChB,cAAc,EAAE;gBACf,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,2CAA2C,EAAE,CAAC;gBAC9E,OAAO,EAAE,EAAE;gBACX,OAAO,EAAE,IAAI;aACb;SACD;QACD,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,+CAA+C,EAAE;KACvE,CAAC,CAAC;IAEH,MAAM,gBAAgB,CACrB,IAAI,EACJ;QACC,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,aAAa;QACtB,qBAAqB,EAAE;YACtB,IAAI,EAAE,iBAAiB;YACvB,YAAY,EAAE,CAAC;YACf,OAAO,EAAE,aAAa;SACtB;KACM,CACR,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,gEAAgE,CAAC,CAAC;IACtH,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,wBAAwB,CAAC,CAAC;IAC1F,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,2BAA2B,CAAC,CAAC;AAC9F,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qFAAqF,EAAE,KAAK,IAAI,EAAE;IACrG,UAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,GAAG;QAC/D,EAAE,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI;QACxC,EAAE,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI;QACxC,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;QAC5B,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;QAC9B,QAAQ,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;KAChC,CAAC;IAEF,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,YAAY,CAAC;IAC5B,MAAM,QAAQ,GAAG;QAChB,IAAI,EAAE,UAAU;QAChB,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,cAAc;QACpB,SAAS,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE;KAC7B,CAAC;IAEF,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,CAAC,EAAS,CAAC,CAAC;IAE3F,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,8CAA8C,CAAC,CAAC;IAE7G,mDAAmD;IACnD,IAAI,CAAC,4BAA4B,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/C,MAAM,gBAAgB,CACrB,IAAI,EACJ;QACC,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,aAAa,CAAC;YACtB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,EAAE;YACnD,QAAQ;SACR,CAAC;QACF,qBAAqB,EAAE;YACtB,IAAI,EAAE,cAAc;YACpB,YAAY,EAAE,CAAC;YACf,QAAQ,EAAE;gBACT,GAAG,QAAQ;gBACX,cAAc,EAAE;oBACf,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;oBAClD,OAAO,EAAE,EAAE;oBACX,OAAO,EAAE,KAAK;iBACd;aACD;YACD,OAAO,EAAE,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,EAAE,EAAE,QAAQ,CAAC,CAAC;SACvF;KACM,CACR,CAAC;IAEF,uEAAuE;IACvE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,2CAA2C,CAAC,CAAC;IAC1G,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC;IAC1F,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;AACtF,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;IACxF,UAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,GAAG;QAC/D,EAAE,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI;QACxC,EAAE,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI;QACxC,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;QAC5B,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;QAC9B,QAAQ,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;KAChC,CAAC;IAEF,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG;QAChB,IAAI,EAAE,UAAU;QAChB,EAAE,EAAE,cAAc;QAClB,IAAI,EAAE,cAAc;QACpB,SAAS,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE;KAC7B,CAAC;IAEF,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,CAAC,EAAS,CAAC,CAAC;IAE3F,2BAA2B;IAC3B,IAAI,CAAC,4BAA4B,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/C,MAAM,gBAAgB,CACrB,IAAI,EACJ;QACC,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC5E,qBAAqB,EAAE;YACtB,IAAI,EAAE,cAAc;YACpB,YAAY,EAAE,CAAC;YACf,QAAQ,EAAE;gBACT,GAAG,QAAQ;gBACX,cAAc,EAAE;oBACf,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;oBACvC,OAAO,EAAE,EAAE;oBACX,OAAO,EAAE,KAAK;iBACd;aACD;YACD,OAAO,EAAE,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,QAAQ,CAAC,CAAC;SAC5E;KACM,CACR,CAAC;IAEF,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,iCAAiC,CAAC,CAAC;IAE9F,2DAA2D;IAC3D,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,CAAC,EAAS,CAAC,CAAC;IAE3F,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,mDAAmD,CAAC,CAAC;AACnH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;IAC3E,UAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,GAAG;QAC/D,EAAE,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI;QACxC,EAAE,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI;QACxC,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;QAC5B,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;QAC9B,QAAQ,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI;KAChC,CAAC;IAEF,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAE1B,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,CAAC,EAAS,CAAC,CAAC;IAE3F,IAAI,CAAC,4BAA4B,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/C,MAAM,gBAAgB,CACrB,IAAI,EACJ;QACC,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,EAAE,CAAC,CAAC;QAC7E,qBAAqB,EAAE;YACtB,IAAI,EAAE,YAAY;YAClB,YAAY,EAAE,CAAC;YACf,KAAK,EAAE,2BAA2B;YAClC,OAAO,EAAE,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,EAAE,CAAC,CAAC;SAC7E;KACM,CACR,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,kDAAkD,CAAC,CAAC;AAClH,CAAC,CAAC,CAAC","sourcesContent":["import assert from \"node:assert/strict\";\nimport { test } from \"node:test\";\n\nimport { handleAgentEvent } from \"../modes/interactive/controllers/chat-controller.js\";\n\nfunction makeUsage() {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotalTokens: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\nfunction makeAssistant(content: any[]) {\n\treturn {\n\t\trole: \"assistant\",\n\t\tcontent,\n\t\tapi: \"anthropic-messages\",\n\t\tprovider: \"claude-code\",\n\t\tmodel: \"claude-sonnet-4\",\n\t\tusage: makeUsage(),\n\t\tstopReason: \"stop\",\n\t\ttimestamp: Date.now(),\n\t};\n}\n\nfunction createHost() {\n\tconst chatContainer = {\n\t\tchildren: [] as any[],\n\t\taddChild(component: any) {\n\t\t\tthis.children.push(component);\n\t\t},\n\t\tremoveChild(component: any) {\n\t\t\tconst idx = this.children.indexOf(component);\n\t\t\tif (idx !== -1) this.children.splice(idx, 1);\n\t\t},\n\t\tclear() {\n\t\t\tthis.children = [];\n\t\t},\n\t};\n\n\tconst pinnedMessageContainer = {\n\t\tchildren: [] as any[],\n\t\taddChild(component: any) {\n\t\t\tthis.children.push(component);\n\t\t},\n\t\tremoveChild(component: any) {\n\t\t\tconst idx = this.children.indexOf(component);\n\t\t\tif (idx !== -1) this.children.splice(idx, 1);\n\t\t},\n\t\tclear() {\n\t\t\tthis.children = [];\n\t\t},\n\t};\n\n\tconst host: any = {\n\t\tisInitialized: true,\n\t\tinit: async () => {},\n\t\tdefaultEditor: { onEscape: undefined },\n\t\teditor: {},\n\t\tsession: { retryAttempt: 0, abortCompaction: () => {}, abortRetry: () => {} },\n\t\tui: { requestRender: () => {}, terminal: { rows: 50 } },\n\t\tfooter: { invalidate: () => {} },\n\t\tkeybindings: {},\n\t\tstatusContainer: { clear: () => {}, addChild: () => {} },\n\t\tchatContainer,\n\t\tsettingsManager: { getTimestampFormat: () => \"date-time-iso\", getShowImages: () => false },\n\t\tpendingTools: new Map(),\n\t\ttoolOutputExpanded: false,\n\t\thideThinkingBlock: false,\n\t\tisBashMode: false,\n\t\tdefaultWorkingMessage: \"Working...\",\n\t\tcompactionQueuedMessages: [],\n\t\teditorContainer: {},\n\t\tpendingMessagesContainer: { clear: () => {} },\n\t\tpinnedMessageContainer,\n\t\taddMessageToChat: () => {},\n\t\tgetMarkdownThemeWithSettings: () => ({}),\n\t\tformatWebSearchResult: () => \"\",\n\t\tgetRegisteredToolDefinition: () => undefined,\n\t\tcheckShutdownRequested: async () => {},\n\t\trebuildChatFromMessages: () => {},\n\t\tflushCompactionQueue: async () => {},\n\t\tshowStatus: () => {},\n\t\tshowError: () => {},\n\t\tupdatePendingMessagesDisplay: () => {},\n\t\tupdateTerminalTitle: () => {},\n\t\tupdateEditorBorderColor: () => {},\n\t};\n\n\treturn host;\n}\n\ntest(\"chat-controller keeps tool output ahead of delayed assistant text for external tool streams\", async () => {\n\t// ToolExecutionComponent uses the global theme singleton.\n\t// Install a minimal no-op theme implementation for this unit test.\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\tconst toolId = \"mcp-tool-1\";\n\tconst toolCall = {\n\t\ttype: \"toolCall\",\n\t\tid: toolId,\n\t\tname: \"exec_command\",\n\t\targuments: { cmd: \"echo hi\" },\n\t};\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\tassert.equal(host.streamingComponent, undefined, \"assistant component should be deferred at message_start\");\n\tassert.equal(host.chatContainer.children.length, 0, \"nothing should render before content arrives\");\n\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([toolCall]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\tcontentIndex: 0,\n\t\t\t\ttoolCall: {\n\t\t\t\t\t...toolCall,\n\t\t\t\t\texternalResult: {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"tool output\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpartial: makeAssistant([toolCall]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.equal(host.streamingComponent, undefined, \"assistant text container should remain deferred for tool-only updates\");\n\tassert.equal(host.chatContainer.children.length, 1, \"tool execution block should render immediately\");\n\tassert.equal(host.chatContainer.children[0]?.constructor?.name, \"ToolExecutionComponent\");\n\n\t// Re-assert required host method before the text-bearing update path.\n\thost.getMarkdownThemeWithSettings = () => ({});\n\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([toolCall, { type: \"text\", text: \"done\" }]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"text_delta\",\n\t\t\t\tcontentIndex: 1,\n\t\t\t\tdelta: \"done\",\n\t\t\t\tpartial: makeAssistant([toolCall, { type: \"text\", text: \"done\" }]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.equal(host.chatContainer.children.length, 2, \"assistant content should render after existing tool output\");\n\tassert.equal(host.chatContainer.children[0]?.constructor?.name, \"ToolExecutionComponent\");\n\tassert.equal(host.chatContainer.children[1]?.constructor?.name, \"AssistantMessageComponent\");\n});\n\ntest(\"chat-controller keeps serverToolUse output ahead of assistant text when external results arrive\", async () => {\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\tconst toolId = \"mcp-secure-1\";\n\tconst serverToolUse = {\n\t\ttype: \"serverToolUse\",\n\t\tid: toolId,\n\t\tname: \"mcp__gsd-workflow__secure_env_collect\",\n\t\tinput: { projectDir: \"/tmp/project\", keys: [{ key: \"SECURE_PASSWORD\" }], destination: \"dotenv\" },\n\t};\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([serverToolUse]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"server_tool_use\",\n\t\t\t\tcontentIndex: 0,\n\t\t\t\tpartial: makeAssistant([serverToolUse]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.equal(host.streamingComponent, undefined, \"assistant content should stay deferred while only tool content streams\");\n\tassert.equal(host.chatContainer.children.length, 1, \"server tool block should render immediately\");\n\tassert.equal(host.chatContainer.children[0]?.constructor?.name, \"ToolExecutionComponent\");\n\n\thost.getMarkdownThemeWithSettings = () => ({});\n\tconst resultMessage = makeAssistant([\n\t\t{\n\t\t\t...serverToolUse,\n\t\t\texternalResult: {\n\t\t\t\tcontent: [{ type: \"text\", text: \"secure_env_collect was cancelled by user.\" }],\n\t\t\t\tdetails: {},\n\t\t\t\tisError: true,\n\t\t\t},\n\t\t},\n\t\t{ type: \"text\", text: \"The secure password collection was cancelled.\" },\n\t]);\n\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: resultMessage,\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"server_tool_use\",\n\t\t\t\tcontentIndex: 0,\n\t\t\t\tpartial: resultMessage,\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.equal(host.chatContainer.children.length, 2, \"assistant text should render after existing server tool output\");\n\tassert.equal(host.chatContainer.children[0]?.constructor?.name, \"ToolExecutionComponent\");\n\tassert.equal(host.chatContainer.children[1]?.constructor?.name, \"AssistantMessageComponent\");\n});\n\ntest(\"chat-controller pins latest assistant text above editor when tool calls are present\", async () => {\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\tconst toolId = \"tool-pin-1\";\n\tconst toolCall = {\n\t\ttype: \"toolCall\",\n\t\tid: toolId,\n\t\tname: \"exec_command\",\n\t\targuments: { cmd: \"echo hi\" },\n\t};\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\tassert.equal(host.pinnedMessageContainer.children.length, 0, \"pinned zone should be empty at message_start\");\n\n\t// Send a message with text followed by a tool call\n\thost.getMarkdownThemeWithSettings = () => ({});\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([\n\t\t\t\t{ type: \"text\", text: \"Looking at the files now.\" },\n\t\t\t\ttoolCall,\n\t\t\t]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\tcontentIndex: 1,\n\t\t\t\ttoolCall: {\n\t\t\t\t\t...toolCall,\n\t\t\t\t\texternalResult: {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"file contents\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpartial: makeAssistant([{ type: \"text\", text: \"Looking at the files now.\" }, toolCall]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\t// Pinned zone should now have a DynamicBorder and a Markdown component\n\tassert.equal(host.pinnedMessageContainer.children.length, 2, \"pinned zone should have border + markdown\");\n\tassert.equal(host.pinnedMessageContainer.children[0]?.constructor?.name, \"DynamicBorder\");\n\tassert.equal(host.pinnedMessageContainer.children[1]?.constructor?.name, \"Markdown\");\n});\n\ntest(\"chat-controller clears pinned zone when a new assistant message starts\", async () => {\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\tconst toolCall = {\n\t\ttype: \"toolCall\",\n\t\tid: \"tool-clear-1\",\n\t\tname: \"exec_command\",\n\t\targuments: { cmd: \"echo hi\" },\n\t};\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\t// Populate the pinned zone\n\thost.getMarkdownThemeWithSettings = () => ({});\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([{ type: \"text\", text: \"Working on it.\" }, toolCall]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\tcontentIndex: 1,\n\t\t\t\ttoolCall: {\n\t\t\t\t\t...toolCall,\n\t\t\t\t\texternalResult: {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"ok\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpartial: makeAssistant([{ type: \"text\", text: \"Working on it.\" }, toolCall]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.ok(host.pinnedMessageContainer.children.length > 0, \"pinned zone should be populated\");\n\n\t// Start a new assistant message — pinned zone should clear\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\tassert.equal(host.pinnedMessageContainer.children.length, 0, \"pinned zone should clear on new assistant message\");\n});\n\ntest(\"chat-controller does not pin when there are no tool calls\", async () => {\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\thost.getMarkdownThemeWithSettings = () => ({});\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([{ type: \"text\", text: \"Just some text, no tools.\" }]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"text_delta\",\n\t\t\t\tcontentIndex: 0,\n\t\t\t\tdelta: \"Just some text, no tools.\",\n\t\t\t\tpartial: makeAssistant([{ type: \"text\", text: \"Just some text, no tools.\" }]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.equal(host.pinnedMessageContainer.children.length, 0, \"pinned zone should stay empty without tool calls\");\n});\n"]}
1
+ {"version":3,"file":"chat-controller-ordering.test.js","sourceRoot":"","sources":["../../src/core/chat-controller-ordering.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport { test } from \"node:test\";\n\nimport { handleAgentEvent } from \"../modes/interactive/controllers/chat-controller.js\";\n\nfunction makeUsage() {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotalTokens: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\nfunction makeAssistant(content: any[]) {\n\treturn {\n\t\trole: \"assistant\",\n\t\tcontent,\n\t\tapi: \"anthropic-messages\",\n\t\tprovider: \"claude-code\",\n\t\tmodel: \"claude-sonnet-4\",\n\t\tusage: makeUsage(),\n\t\tstopReason: \"stop\",\n\t\ttimestamp: Date.now(),\n\t};\n}\n\nfunction createHost() {\n\tconst chatContainer = {\n\t\tchildren: [] as any[],\n\t\taddChild(component: any) {\n\t\t\tthis.children.push(component);\n\t\t},\n\t\tremoveChild(component: any) {\n\t\t\tconst idx = this.children.indexOf(component);\n\t\t\tif (idx !== -1) this.children.splice(idx, 1);\n\t\t},\n\t\tclear() {\n\t\t\tthis.children = [];\n\t\t},\n\t};\n\n\tconst pinnedMessageContainer = {\n\t\tchildren: [] as any[],\n\t\taddChild(component: any) {\n\t\t\tthis.children.push(component);\n\t\t},\n\t\tremoveChild(component: any) {\n\t\t\tconst idx = this.children.indexOf(component);\n\t\t\tif (idx !== -1) this.children.splice(idx, 1);\n\t\t},\n\t\tclear() {\n\t\t\tthis.children = [];\n\t\t},\n\t};\n\n\tconst host: any = {\n\t\tisInitialized: true,\n\t\tinit: async () => {},\n\t\tdefaultEditor: { onEscape: undefined },\n\t\teditor: {},\n\t\tsession: { retryAttempt: 0, abortCompaction: () => {}, abortRetry: () => {} },\n\t\tui: { requestRender: () => {}, terminal: { rows: 50 } },\n\t\tfooter: { invalidate: () => {} },\n\t\tkeybindings: {},\n\t\tstatusContainer: { clear: () => {}, addChild: () => {} },\n\t\tchatContainer,\n\t\tsettingsManager: { getTimestampFormat: () => \"date-time-iso\", getShowImages: () => false },\n\t\tpendingTools: new Map(),\n\t\ttoolOutputExpanded: false,\n\t\thideThinkingBlock: false,\n\t\tisBashMode: false,\n\t\tdefaultWorkingMessage: \"Working...\",\n\t\tcompactionQueuedMessages: [],\n\t\teditorContainer: {},\n\t\tpendingMessagesContainer: { clear: () => {} },\n\t\tpinnedMessageContainer,\n\t\taddMessageToChat: () => {},\n\t\tgetMarkdownThemeWithSettings: () => ({}),\n\t\tformatWebSearchResult: () => \"\",\n\t\tgetRegisteredToolDefinition: () => undefined,\n\t\tcheckShutdownRequested: async () => {},\n\t\trebuildChatFromMessages: () => {},\n\t\tflushCompactionQueue: async () => {},\n\t\tshowStatus: () => {},\n\t\tshowError: () => {},\n\t\tupdatePendingMessagesDisplay: () => {},\n\t\tupdateTerminalTitle: () => {},\n\t\tupdateEditorBorderColor: () => {},\n\t};\n\n\treturn host;\n}\n\ntest(\"chat-controller keeps tool output ahead of delayed assistant text for external tool streams\", async () => {\n\t// ToolExecutionComponent uses the global theme singleton.\n\t// Install a minimal no-op theme implementation for this unit test.\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\tconst toolId = \"mcp-tool-1\";\n\tconst toolCall = {\n\t\ttype: \"toolCall\",\n\t\tid: toolId,\n\t\tname: \"exec_command\",\n\t\targuments: { cmd: \"echo hi\" },\n\t};\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\tassert.equal(host.streamingComponent, undefined, \"assistant component should be deferred at message_start\");\n\tassert.equal(host.chatContainer.children.length, 0, \"nothing should render before content arrives\");\n\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([toolCall]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\tcontentIndex: 0,\n\t\t\t\ttoolCall: {\n\t\t\t\t\t...toolCall,\n\t\t\t\t\texternalResult: {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"tool output\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpartial: makeAssistant([toolCall]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.equal(host.streamingComponent, undefined, \"assistant text container should remain deferred for tool-only updates\");\n\tassert.equal(host.chatContainer.children.length, 1, \"tool execution block should render immediately\");\n\tassert.equal(host.chatContainer.children[0]?.constructor?.name, \"ToolExecutionComponent\");\n\n\t// Re-assert required host method before the text-bearing update path.\n\thost.getMarkdownThemeWithSettings = () => ({});\n\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([toolCall, { type: \"text\", text: \"done\" }]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"text_delta\",\n\t\t\t\tcontentIndex: 1,\n\t\t\t\tdelta: \"done\",\n\t\t\t\tpartial: makeAssistant([toolCall, { type: \"text\", text: \"done\" }]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.equal(host.chatContainer.children.length, 2, \"assistant content should render after existing tool output\");\n\tassert.equal(host.chatContainer.children[0]?.constructor?.name, \"ToolExecutionComponent\");\n\tassert.equal(host.chatContainer.children[1]?.constructor?.name, \"AssistantMessageComponent\");\n});\n\ntest(\"chat-controller keeps serverToolUse output ahead of assistant text when external results arrive\", async () => {\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\tconst toolId = \"mcp-secure-1\";\n\tconst serverToolUse = {\n\t\ttype: \"serverToolUse\",\n\t\tid: toolId,\n\t\tname: \"mcp__gsd-workflow__secure_env_collect\",\n\t\tinput: { projectDir: \"/tmp/project\", keys: [{ key: \"SECURE_PASSWORD\" }], destination: \"dotenv\" },\n\t};\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([serverToolUse]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"server_tool_use\",\n\t\t\t\tcontentIndex: 0,\n\t\t\t\tpartial: makeAssistant([serverToolUse]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.equal(host.streamingComponent, undefined, \"assistant content should stay deferred while only tool content streams\");\n\tassert.equal(host.chatContainer.children.length, 1, \"server tool block should render immediately\");\n\tassert.equal(host.chatContainer.children[0]?.constructor?.name, \"ToolExecutionComponent\");\n\n\thost.getMarkdownThemeWithSettings = () => ({});\n\tconst resultMessage = makeAssistant([\n\t\t{\n\t\t\t...serverToolUse,\n\t\t\texternalResult: {\n\t\t\t\tcontent: [{ type: \"text\", text: \"secure_env_collect was cancelled by user.\" }],\n\t\t\t\tdetails: {},\n\t\t\t\tisError: true,\n\t\t\t},\n\t\t},\n\t\t{ type: \"text\", text: \"The secure password collection was cancelled.\" },\n\t]);\n\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: resultMessage,\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"server_tool_use\",\n\t\t\t\tcontentIndex: 0,\n\t\t\t\tpartial: resultMessage,\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.equal(host.chatContainer.children.length, 2, \"assistant text should render after existing server tool output\");\n\tassert.equal(host.chatContainer.children[0]?.constructor?.name, \"ToolExecutionComponent\");\n\tassert.equal(host.chatContainer.children[1]?.constructor?.name, \"AssistantMessageComponent\");\n});\n\ntest(\"chat-controller pins latest assistant text above editor when tool calls are present\", async () => {\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\tconst toolId = \"tool-pin-1\";\n\tconst toolCall = {\n\t\ttype: \"toolCall\",\n\t\tid: toolId,\n\t\tname: \"exec_command\",\n\t\targuments: { cmd: \"echo hi\" },\n\t};\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\tassert.equal(host.pinnedMessageContainer.children.length, 0, \"pinned zone should be empty at message_start\");\n\n\t// Send a message with text followed by a tool call\n\thost.getMarkdownThemeWithSettings = () => ({});\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([\n\t\t\t\t{ type: \"text\", text: \"Looking at the files now.\" },\n\t\t\t\ttoolCall,\n\t\t\t]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\tcontentIndex: 1,\n\t\t\t\ttoolCall: {\n\t\t\t\t\t...toolCall,\n\t\t\t\t\texternalResult: {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"file contents\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpartial: makeAssistant([{ type: \"text\", text: \"Looking at the files now.\" }, toolCall]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\t// Pinned zone should now have a DynamicBorder and a Markdown component\n\tassert.equal(host.pinnedMessageContainer.children.length, 2, \"pinned zone should have border + markdown\");\n\tassert.equal(host.pinnedMessageContainer.children[0]?.constructor?.name, \"DynamicBorder\");\n\tassert.equal(host.pinnedMessageContainer.children[1]?.constructor?.name, \"Markdown\");\n});\n\ntest(\"chat-controller clears pinned zone when a new assistant message starts\", async () => {\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\tconst toolCall = {\n\t\ttype: \"toolCall\",\n\t\tid: \"tool-clear-1\",\n\t\tname: \"exec_command\",\n\t\targuments: { cmd: \"echo hi\" },\n\t};\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\t// Populate the pinned zone\n\thost.getMarkdownThemeWithSettings = () => ({});\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([{ type: \"text\", text: \"Working on it.\" }, toolCall]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\tcontentIndex: 1,\n\t\t\t\ttoolCall: {\n\t\t\t\t\t...toolCall,\n\t\t\t\t\texternalResult: {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"ok\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpartial: makeAssistant([{ type: \"text\", text: \"Working on it.\" }, toolCall]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.ok(host.pinnedMessageContainer.children.length > 0, \"pinned zone should be populated\");\n\n\t// Start a new assistant message — pinned zone should clear\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\tassert.equal(host.pinnedMessageContainer.children.length, 0, \"pinned zone should clear on new assistant message\");\n});\n\ntest(\"chat-controller clears pinned zone when the agent turn ends\", async () => {\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\tconst toolCall = {\n\t\ttype: \"toolCall\",\n\t\tid: \"tool-clear-on-end-1\",\n\t\tname: \"exec_command\",\n\t\targuments: { cmd: \"echo hi\" },\n\t};\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\thost.getMarkdownThemeWithSettings = () => ({});\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([{ type: \"text\", text: \"Working on it.\" }, toolCall]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\tcontentIndex: 1,\n\t\t\t\ttoolCall: {\n\t\t\t\t\t...toolCall,\n\t\t\t\t\texternalResult: {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"ok\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpartial: makeAssistant([{ type: \"text\", text: \"Working on it.\" }, toolCall]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.ok(host.pinnedMessageContainer.children.length > 0, \"pinned zone should be populated before agent_end\");\n\n\tawait handleAgentEvent(host, { type: \"agent_end\" } as any);\n\n\tassert.equal(host.pinnedMessageContainer.children.length, 0, \"pinned zone should clear on agent_end\");\n});\n\ntest(\"chat-controller clears pinned zone when assistant message ends\", async () => {\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\tconst toolCall = {\n\t\ttype: \"toolCall\",\n\t\tid: \"tool-msg-end-1\",\n\t\tname: \"exec_command\",\n\t\targuments: { cmd: \"echo hi\" },\n\t};\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\thost.getMarkdownThemeWithSettings = () => ({});\n\tconst msgContent = [{ type: \"text\", text: \"Summary after tools.\" }, toolCall];\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant(msgContent),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\tcontentIndex: 1,\n\t\t\t\ttoolCall: {\n\t\t\t\t\t...toolCall,\n\t\t\t\t\texternalResult: {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"ok\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpartial: makeAssistant(msgContent),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.ok(host.pinnedMessageContainer.children.length > 0, \"pinned zone should be populated during streaming\");\n\n\t// End the assistant message (e.g. before form elicitation) — pinned zone should clear\n\tawait handleAgentEvent(host, { type: \"message_end\", message: makeAssistant(msgContent) } as any);\n\n\tassert.equal(host.pinnedMessageContainer.children.length, 0, \"pinned zone should clear on message_end to prevent duplicate display\");\n});\n\ntest(\"chat-controller does not pin when there are no tool calls\", async () => {\n\t(globalThis as any)[Symbol.for(\"@gsd/pi-coding-agent:theme\")] = {\n\t\tfg: (_key: string, text: string) => text,\n\t\tbg: (_key: string, text: string) => text,\n\t\tbold: (text: string) => text,\n\t\titalic: (text: string) => text,\n\t\ttruncate: (text: string) => text,\n\t};\n\n\tconst host = createHost();\n\n\tawait handleAgentEvent(host, { type: \"message_start\", message: makeAssistant([]) } as any);\n\n\thost.getMarkdownThemeWithSettings = () => ({});\n\tawait handleAgentEvent(\n\t\thost,\n\t\t{\n\t\t\ttype: \"message_update\",\n\t\t\tmessage: makeAssistant([{ type: \"text\", text: \"Just some text, no tools.\" }]),\n\t\t\tassistantMessageEvent: {\n\t\t\t\ttype: \"text_delta\",\n\t\t\t\tcontentIndex: 0,\n\t\t\t\tdelta: \"Just some text, no tools.\",\n\t\t\t\tpartial: makeAssistant([{ type: \"text\", text: \"Just some text, no tools.\" }]),\n\t\t\t},\n\t\t} as any,\n\t);\n\n\tassert.equal(host.pinnedMessageContainer.children.length, 0, \"pinned zone should stay empty without tool calls\");\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-controller.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AA+BnG,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACvE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,4BAA4B,EAAE,MAAM,GAAG,CAAC;IACxC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACxD,qBAAqB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACpD,2BAA2B,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IACvD,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,wBAAwB,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CAChD,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgf7C"}
1
+ {"version":3,"file":"chat-controller.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AA+BnG,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACvE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,4BAA4B,EAAE,MAAM,GAAG,CAAC;IACxC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACxD,qBAAqB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACpD,2BAA2B,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IACvD,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,wBAAwB,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CAChD,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyf7C"}
@@ -314,6 +314,16 @@ export async function handleAgentEvent(host, event) {
314
314
  }
315
315
  host.streamingComponent = undefined;
316
316
  host.streamingMessage = undefined;
317
+ // Clear pinned output once the message is finalized in the chat
318
+ // container — prevents duplicate display when the agent continues
319
+ // (e.g. form elicitation) after the assistant message ends.
320
+ if (pinnedBorder)
321
+ pinnedBorder.stopSpinner();
322
+ host.pinnedMessageContainer.clear();
323
+ lastPinnedText = "";
324
+ hasToolsInTurn = false;
325
+ pinnedBorder = undefined;
326
+ pinnedTextComponent = undefined;
317
327
  host.footer.invalidate();
318
328
  }
319
329
  host.ui.requestRender();
@@ -356,12 +366,12 @@ export async function handleAgentEvent(host, event) {
356
366
  host.streamingMessage = undefined;
357
367
  }
358
368
  host.pendingTools.clear();
359
- // Stop spinner on pinned border and switch label from "Working · Latest Output" to "Latest Output"
369
+ // Pinned output is only useful while work is actively streaming.
370
+ // Keep chat history as the single source after completion.
360
371
  if (pinnedBorder) {
361
372
  pinnedBorder.stopSpinner();
362
- pinnedBorder.setLabel("Latest Output");
363
373
  }
364
- // Keep pinned message visible until the next assistant turn starts.
374
+ host.pinnedMessageContainer.clear();
365
375
  lastPinnedText = "";
366
376
  hasToolsInTurn = false;
367
377
  pinnedBorder = undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"chat-controller.js","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { Loader, Markdown, Spacer, Text } from \"@gsd/pi-tui\";\n\nimport type { InteractiveModeEvent, InteractiveModeStateHost } from \"../interactive-mode-state.js\";\nimport { theme } from \"../theme/theme.js\";\nimport { AssistantMessageComponent } from \"../components/assistant-message.js\";\nimport { ToolExecutionComponent } from \"../components/tool-execution.js\";\nimport { DynamicBorder } from \"../components/dynamic-border.js\";\nimport { appKey } from \"../components/keybinding-hints.js\";\n\n// Tracks the last processed content index to avoid re-scanning all blocks on every message_update\nlet lastProcessedContentIndex = 0;\n\nfunction hasVisibleAssistantContent(message: { content: Array<any> }): boolean {\n\treturn message.content.some(\n\t\t(c) =>\n\t\t\t(c.type === \"text\" && typeof c.text === \"string\" && c.text.trim().length > 0)\n\t\t\t|| (c.type === \"thinking\" && typeof c.thinking === \"string\" && c.thinking.trim().length > 0),\n\t);\n}\n\nfunction hasAssistantToolBlocks(message: { content: Array<any> }): boolean {\n\treturn message.content.some((c) => c.type === \"toolCall\" || c.type === \"serverToolUse\");\n}\n\n// Tracks the latest assistant text for the pinned message zone\nlet lastPinnedText = \"\";\n// Whether any tool execution has been added in this assistant turn (triggers pinned display)\nlet hasToolsInTurn = false;\n// Reference to the pinned border so we can toggle its label between working/idle\nlet pinnedBorder: DynamicBorder | undefined;\n// Reference to the pinned markdown component below the border\nlet pinnedTextComponent: Markdown | undefined;\n\nexport async function handleAgentEvent(host: InteractiveModeStateHost & {\n\tinit: () => Promise<void>;\n\tgetMarkdownThemeWithSettings: () => any;\n\taddMessageToChat: (message: any, options?: any) => void;\n\tformatWebSearchResult: (content: unknown) => string;\n\tgetRegisteredToolDefinition: (toolName: string) => any;\n\tcheckShutdownRequested: () => Promise<void>;\n\trebuildChatFromMessages: () => void;\n\tflushCompactionQueue: (options?: { willRetry?: boolean }) => Promise<void>;\n\tshowStatus: (message: string) => void;\n\tshowError: (message: string) => void;\n\tupdatePendingMessagesDisplay: () => void;\n\tupdateTerminalTitle: () => void;\n\tupdateEditorBorderColor: () => void;\n\tpendingMessagesContainer: { clear: () => void };\n}, event: InteractiveModeEvent): Promise<void> {\n\tif (!host.isInitialized) {\n\t\tawait host.init();\n\t}\n\n\thost.footer.invalidate();\n\n\t// Reset content index tracker and pinned state when a new assistant message starts\n\tif (event.type === \"message_start\" && event.message.role === \"assistant\") {\n\t\tlastProcessedContentIndex = 0;\n\t\tlastPinnedText = \"\";\n\t\thasToolsInTurn = false;\n\t\tif (pinnedBorder) pinnedBorder.stopSpinner();\n\t\tpinnedBorder = undefined;\n\t\tpinnedTextComponent = undefined;\n\t\thost.pinnedMessageContainer.clear();\n\t}\n\n\tswitch (event.type) {\n\t\tcase \"session_state_changed\":\n\t\t\tswitch (event.reason) {\n\t\t\t\tcase \"new_session\":\n\t\t\t\tcase \"switch_session\":\n\t\t\t\tcase \"fork\":\n\t\t\t\t\thost.streamingComponent = undefined;\n\t\t\t\t\thost.streamingMessage = undefined;\n\t\t\t\t\thost.pendingTools.clear();\n\t\t\t\t\thost.pendingMessagesContainer.clear();\n\t\t\t\t\thost.pinnedMessageContainer.clear();\n\t\t\t\t\tlastPinnedText = \"\";\n\t\t\t\t\thasToolsInTurn = false;\n\t\t\t\t\tif (pinnedBorder) pinnedBorder.stopSpinner();\n\t\t\t\t\tpinnedBorder = undefined;\n\t\t\t\t\tpinnedTextComponent = undefined;\n\t\t\t\t\thost.compactionQueuedMessages = [];\n\t\t\t\t\thost.rebuildChatFromMessages();\n\t\t\t\t\thost.updatePendingMessagesDisplay();\n\t\t\t\t\thost.updateTerminalTitle();\n\t\t\t\t\thost.updateEditorBorderColor();\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t\treturn;\n\t\t\t\tcase \"set_session_name\":\n\t\t\t\t\thost.updateTerminalTitle();\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t\treturn;\n\t\t\t\tcase \"set_model\":\n\t\t\t\tcase \"set_thinking_level\":\n\t\t\t\t\thost.updateEditorBorderColor();\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t\treturn;\n\t\t\t\tdefault:\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t\treturn;\n\t\t\t}\n\t\tcase \"agent_start\":\n\t\t\tif (host.retryEscapeHandler) {\n\t\t\t\thost.defaultEditor.onEscape = host.retryEscapeHandler;\n\t\t\t\thost.retryEscapeHandler = undefined;\n\t\t\t}\n\t\t\tif (host.retryLoader) {\n\t\t\t\thost.retryLoader.stop();\n\t\t\t\thost.retryLoader = undefined;\n\t\t\t}\n\t\t\tif (host.loadingAnimation) {\n\t\t\t\thost.loadingAnimation.stop();\n\t\t\t}\n\t\t\thost.statusContainer.clear();\n\t\t\thost.loadingAnimation = new Loader(\n\t\t\t\thost.ui,\n\t\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t\thost.defaultWorkingMessage,\n\t\t\t);\n\t\t\thost.statusContainer.addChild(host.loadingAnimation);\n\t\t\tif (host.pendingWorkingMessage !== undefined) {\n\t\t\t\tif (host.pendingWorkingMessage) {\n\t\t\t\t\thost.loadingAnimation.setMessage(host.pendingWorkingMessage);\n\t\t\t\t}\n\t\t\t\thost.pendingWorkingMessage = undefined;\n\t\t\t}\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"message_start\":\n\t\t\tif (event.message.role === \"custom\") {\n\t\t\t\thost.addMessageToChat(event.message);\n\t\t\t\thost.ui.requestRender();\n\t\t\t} else if (event.message.role === \"user\") {\n\t\t\t\thost.addMessageToChat(event.message);\n\t\t\t\thost.updatePendingMessagesDisplay();\n\t\t\t\thost.ui.requestRender();\n\t\t\t} else if (event.message.role === \"assistant\") {\n\t\t\t\thost.streamingMessage = event.message;\n\t\t\t\t// External-tool providers can stream multiple assistant turns through\n\t\t\t\t// one response. Delay component creation until visible assistant text\n\t\t\t\t// arrives so tool outputs keep chronological ordering.\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"message_update\":\n\t\t\tif (event.message.role === \"assistant\") {\n\t\t\t\thost.streamingMessage = event.message;\n\t\t\t\tconst innerEvent = event.assistantMessageEvent;\n\n\t\t\t\tlet externalToolResult:\n\t\t\t\t\t| { toolCallId: string; content: Array<{ type: string; text?: string; data?: string; mimeType?: string }>; details: Record<string, unknown>; isError: boolean }\n\t\t\t\t\t| undefined;\n\t\t\t\tif (innerEvent.type === \"toolcall_end\" && innerEvent.toolCall) {\n\t\t\t\t\tconst tc = innerEvent.toolCall as any;\n\t\t\t\t\tconst ext = tc.externalResult;\n\t\t\t\t\tif (ext) {\n\t\t\t\t\t\texternalToolResult = {\n\t\t\t\t\t\t\ttoolCallId: tc.id,\n\t\t\t\t\t\t\tcontent: ext.content ?? [{ type: \"text\", text: \"\" }],\n\t\t\t\t\t\t\tdetails: ext.details ?? {},\n\t\t\t\t\t\t\tisError: ext.isError ?? false,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t} else if (innerEvent.type === \"server_tool_use\") {\n\t\t\t\t\tconst idx = typeof innerEvent.contentIndex === \"number\" ? innerEvent.contentIndex : -1;\n\t\t\t\t\tconst block = idx >= 0 ? (host.streamingMessage.content[idx] as any) : undefined;\n\t\t\t\t\tconst ext = block?.externalResult;\n\t\t\t\t\tif (block?.id && ext) {\n\t\t\t\t\t\texternalToolResult = {\n\t\t\t\t\t\t\ttoolCallId: block.id,\n\t\t\t\t\t\t\tcontent: ext.content ?? [{ type: \"text\", text: \"\" }],\n\t\t\t\t\t\t\tdetails: ext.details ?? {},\n\t\t\t\t\t\t\tisError: ext.isError ?? false,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst contentBlocks = host.streamingMessage.content;\n\t\t\t\t// Some adapters reuse a single assistant lifecycle while internally\n\t\t\t\t// spanning multiple provider turns. When a new turn starts, content\n\t\t\t\t// length can shrink back to 0/1; reset scan index to avoid skipping.\n\t\t\t\tif (lastProcessedContentIndex >= contentBlocks.length) {\n\t\t\t\t\tlastProcessedContentIndex = 0;\n\t\t\t\t}\n\t\t\t\tfor (let i = lastProcessedContentIndex; i < contentBlocks.length; i++) {\n\t\t\t\t\tconst content = contentBlocks[i];\n\t\t\t\t\tif (content.type === \"toolCall\") {\n\t\t\t\t\t\tif (!host.pendingTools.has(content.id)) {\n\t\t\t\t\t\t\tconst component = new ToolExecutionComponent(\n\t\t\t\t\t\t\t\tcontent.name,\n\t\t\t\t\t\t\t\tcontent.arguments,\n\t\t\t\t\t\t\t\t{ showImages: host.settingsManager.getShowImages() },\n\t\t\t\t\t\t\t\thost.getRegisteredToolDefinition(content.name),\n\t\t\t\t\t\t\t\thost.ui,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tcomponent.setExpanded(host.toolOutputExpanded);\n\t\t\t\t\t\t\thost.chatContainer.addChild(component);\n\t\t\t\t\t\t\thost.pendingTools.set(content.id, component);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\thost.pendingTools.get(content.id)?.updateArgs(content.arguments);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (content.type === \"serverToolUse\") {\n\t\t\t\t\t\tif (!host.pendingTools.has(content.id)) {\n\t\t\t\t\t\t\tconst component = new ToolExecutionComponent(\n\t\t\t\t\t\t\t\tcontent.name,\n\t\t\t\t\t\t\t\tcontent.input ?? {},\n\t\t\t\t\t\t\t\t{ showImages: host.settingsManager.getShowImages() },\n\t\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\thost.ui,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tcomponent.setExpanded(host.toolOutputExpanded);\n\t\t\t\t\t\t\thost.chatContainer.addChild(component);\n\t\t\t\t\t\t\thost.pendingTools.set(content.id, component);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (content.type === \"webSearchResult\") {\n\t\t\t\t\t\tconst component = host.pendingTools.get(content.toolUseId);\n\t\t\t\t\t\tif (component) {\n\t\t\t\t\t\t\tif (process.env.PI_OFFLINE === \"1\") {\n\t\t\t\t\t\t\t\tcomponent.updateResult({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"Web search disabled (offline mode)\" }],\n\t\t\t\t\t\t\t\t\tisError: false,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconst searchContent = content.content;\n\t\t\t\t\t\t\t\tconst isError = searchContent && typeof searchContent === \"object\" && \"type\" in (searchContent as any) && (searchContent as any).type === \"web_search_tool_result_error\";\n\t\t\t\t\t\t\t\tcomponent.updateResult({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: host.formatWebSearchResult(searchContent) }],\n\t\t\t\t\t\t\t\t\tisError: !!isError,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// When the stream adapter signals a completed tool call with an\n\t\t\t\t// external result (from Claude Code SDK), update the pending\n\t\t\t\t// ToolExecutionComponent immediately so output is visible in\n\t\t\t\t// real-time instead of waiting for the session to end.\n\t\t\t\tif (externalToolResult) {\n\t\t\t\t\tconst component = host.pendingTools.get(externalToolResult.toolCallId);\n\t\t\t\t\tif (component) {\n\t\t\t\t\t\tcomponent.updateResult({\n\t\t\t\t\t\t\tcontent: externalToolResult.content,\n\t\t\t\t\t\t\tdetails: externalToolResult.details,\n\t\t\t\t\t\t\tisError: externalToolResult.isError,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Render assistant text/thinking after tool components so mixed\n\t\t\t\t// streams keep chronological ordering in the chat container.\n\t\t\t\tconst hasToolBlocks = hasAssistantToolBlocks(host.streamingMessage);\n\t\t\t\tif (!host.streamingComponent && hasVisibleAssistantContent(host.streamingMessage)) {\n\t\t\t\t\thost.streamingComponent = new AssistantMessageComponent(\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\thost.hideThinkingBlock,\n\t\t\t\t\t\thost.getMarkdownThemeWithSettings(),\n\t\t\t\t\t\thost.settingsManager.getTimestampFormat(),\n\t\t\t\t\t);\n\t\t\t\t\thost.chatContainer.addChild(host.streamingComponent);\n\t\t\t\t}\n\t\t\t\tif (host.streamingComponent) {\n\t\t\t\t\tif (hasToolBlocks) {\n\t\t\t\t\t\thost.chatContainer.removeChild(host.streamingComponent);\n\t\t\t\t\t\thost.chatContainer.addChild(host.streamingComponent);\n\t\t\t\t\t}\n\t\t\t\t\thost.streamingComponent.updateContent(host.streamingMessage);\n\t\t\t\t}\n\n\t\t\t\t// Update index: fully processed blocks won't need re-scanning.\n\t\t\t\t// Keep the last block's index (it may still be accumulating data),\n\t\t\t\t// so we re-check it next time but skip all earlier ones.\n\t\t\t\tif (contentBlocks.length > 0) {\n\t\t\t\t\tlastProcessedContentIndex = Math.max(0, contentBlocks.length - 1);\n\t\t\t\t}\n\n\t\t\t\t// Pinned message: mirror the latest assistant text above the editor\n\t\t\t\t// when tool executions push it out of the viewport.\n\t\t\t\tconst hasTools = contentBlocks.some(\n\t\t\t\t\t(c: any) => c.type === \"toolCall\" || c.type === \"serverToolUse\",\n\t\t\t\t);\n\t\t\t\tif (hasTools) hasToolsInTurn = true;\n\n\t\t\t\tif (hasToolsInTurn) {\n\t\t\t\t\t// Collect the latest text block(s) from the assistant message\n\t\t\t\t\tlet latestText = \"\";\n\t\t\t\t\tfor (let i = contentBlocks.length - 1; i >= 0; i--) {\n\t\t\t\t\t\tconst c = contentBlocks[i] as any;\n\t\t\t\t\t\tif (c.type === \"text\" && c.text?.trim()) {\n\t\t\t\t\t\t\tlatestText = c.text.trim();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (latestText && latestText !== lastPinnedText) {\n\t\t\t\t\t\tlastPinnedText = latestText;\n\n\t\t\t\t\t\tif (!pinnedBorder) {\n\t\t\t\t\t\t\t// First time: create border + text component\n\t\t\t\t\t\t\thost.pinnedMessageContainer.clear();\n\t\t\t\t\t\t\tpinnedBorder = new DynamicBorder(\n\t\t\t\t\t\t\t\t(str: string) => theme.fg(\"dim\", str),\n\t\t\t\t\t\t\t\t\"Working · Latest Output\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tpinnedBorder.startSpinner(host.ui, (str: string) => theme.fg(\"accent\", str));\n\t\t\t\t\t\t\thost.pinnedMessageContainer.addChild(pinnedBorder);\n\t\t\t\t\t\t\tpinnedTextComponent = new Markdown(latestText, 1, 0, host.getMarkdownThemeWithSettings());\n\t\t\t\t\t\t\t// Cap pinned content to ~40% of terminal height so tall output\n\t\t\t\t\t\t\t// doesn't exceed the viewport and cause render flashing.\n\t\t\t\t\t\t\tpinnedTextComponent.maxLines = Math.max(3, Math.floor(host.ui.terminal.rows * 0.4));\n\t\t\t\t\t\t\thost.pinnedMessageContainer.addChild(pinnedTextComponent);\n\t\t\t\t\t\t\t// Hide the separate status loader — the pinned zone replaces it\n\t\t\t\t\t\t\tif (host.loadingAnimation) {\n\t\t\t\t\t\t\t\thost.loadingAnimation.stop();\n\t\t\t\t\t\t\t\thost.loadingAnimation = undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\thost.statusContainer.clear();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Update existing markdown component in-place\n\t\t\t\t\t\t\tpinnedTextComponent?.setText(latestText);\n\t\t\t\t\t\t\t// Refresh maxLines in case terminal was resized\n\t\t\t\t\t\t\tif (pinnedTextComponent) {\n\t\t\t\t\t\t\t\tpinnedTextComponent.maxLines = Math.max(3, Math.floor(host.ui.terminal.rows * 0.4));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"message_end\":\n\t\t\tif (event.message.role === \"user\") break;\n\t\t\tif (event.message.role === \"assistant\") {\n\t\t\t\thost.streamingMessage = event.message;\n\t\t\t\tlet errorMessage: string | undefined;\n\t\t\t\tif (host.streamingMessage.stopReason === \"aborted\") {\n\t\t\t\t\tconst retryAttempt = host.session.retryAttempt;\n\t\t\t\t\terrorMessage = retryAttempt > 0\n\t\t\t\t\t\t? `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? \"s\" : \"\"}`\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\t\thost.streamingMessage.errorMessage = errorMessage;\n\t\t\t\t}\n\n\t\t\t\tconst shouldRenderAssistant = hasVisibleAssistantContent(host.streamingMessage)\n\t\t\t\t\t|| (\n\t\t\t\t\t\t(host.streamingMessage.stopReason === \"aborted\" || host.streamingMessage.stopReason === \"error\")\n\t\t\t\t\t\t&& !hasAssistantToolBlocks(host.streamingMessage)\n\t\t\t\t\t);\n\t\t\t\tif (!host.streamingComponent && shouldRenderAssistant) {\n\t\t\t\t\thost.streamingComponent = new AssistantMessageComponent(\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\thost.hideThinkingBlock,\n\t\t\t\t\t\thost.getMarkdownThemeWithSettings(),\n\t\t\t\t\t\thost.settingsManager.getTimestampFormat(),\n\t\t\t\t\t);\n\t\t\t\t\thost.chatContainer.addChild(host.streamingComponent);\n\t\t\t\t}\n\t\t\t\tif (host.streamingComponent) {\n\t\t\t\t\thost.streamingComponent.updateContent(host.streamingMessage);\n\t\t\t\t}\n\n\t\t\t\tif (host.streamingMessage.stopReason === \"aborted\" || host.streamingMessage.stopReason === \"error\") {\n\t\t\t\t\tif (!errorMessage) {\n\t\t\t\t\t\terrorMessage = host.streamingMessage.errorMessage || \"Error\";\n\t\t\t\t\t}\n\t\t\t\t\tfor (const [, component] of host.pendingTools.entries()) {\n\t\t\t\t\t\tcomponent.updateResult({ content: [{ type: \"text\", text: errorMessage }], isError: true });\n\t\t\t\t\t}\n\t\t\t\t\thost.pendingTools.clear();\n\t\t\t\t} else {\n\t\t\t\t\tfor (const [, component] of host.pendingTools.entries()) {\n\t\t\t\t\t\tcomponent.setArgsComplete();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\thost.streamingComponent = undefined;\n\t\t\t\thost.streamingMessage = undefined;\n\t\t\t\thost.footer.invalidate();\n\t\t\t}\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"tool_execution_start\":\n\t\t\tif (!host.pendingTools.has(event.toolCallId)) {\n\t\t\t\tconst component = new ToolExecutionComponent(\n\t\t\t\t\tevent.toolName,\n\t\t\t\t\tevent.args,\n\t\t\t\t\t{ showImages: host.settingsManager.getShowImages() },\n\t\t\t\t\thost.getRegisteredToolDefinition(event.toolName),\n\t\t\t\t\thost.ui,\n\t\t\t\t);\n\t\t\t\tcomponent.setExpanded(host.toolOutputExpanded);\n\t\t\t\thost.chatContainer.addChild(component);\n\t\t\t\thost.pendingTools.set(event.toolCallId, component);\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"tool_execution_update\": {\n\t\t\tconst component = host.pendingTools.get(event.toolCallId);\n\t\t\tif (component) {\n\t\t\t\tcomponent.updateResult({ ...event.partialResult, isError: false }, true);\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"tool_execution_end\": {\n\t\t\tconst component = host.pendingTools.get(event.toolCallId);\n\t\t\tif (component) {\n\t\t\t\tcomponent.updateResult({ ...event.result, isError: event.isError });\n\t\t\t\thost.pendingTools.delete(event.toolCallId);\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"agent_end\":\n\t\t\tif (host.loadingAnimation) {\n\t\t\t\thost.loadingAnimation.stop();\n\t\t\t\thost.loadingAnimation = undefined;\n\t\t\t\thost.statusContainer.clear();\n\t\t\t}\n\t\t\tif (host.streamingComponent) {\n\t\t\t\thost.chatContainer.removeChild(host.streamingComponent);\n\t\t\t\thost.streamingComponent = undefined;\n\t\t\t\thost.streamingMessage = undefined;\n\t\t\t}\n\t\t\thost.pendingTools.clear();\n\t\t\t// Stop spinner on pinned border and switch label from \"Working · Latest Output\" to \"Latest Output\"\n\t\t\tif (pinnedBorder) {\n\t\t\t\tpinnedBorder.stopSpinner();\n\t\t\t\tpinnedBorder.setLabel(\"Latest Output\");\n\t\t\t}\n\t\t\t// Keep pinned message visible until the next assistant turn starts.\n\t\t\tlastPinnedText = \"\";\n\t\t\thasToolsInTurn = false;\n\t\t\tpinnedBorder = undefined;\n\t\t\tpinnedTextComponent = undefined;\n\t\t\tawait host.checkShutdownRequested();\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"auto_compaction_start\":\n\t\t\thost.autoCompactionEscapeHandler = host.defaultEditor.onEscape;\n\t\t\thost.defaultEditor.onEscape = () => host.session.abortCompaction();\n\t\t\thost.statusContainer.clear();\n\t\t\thost.autoCompactionLoader = new Loader(\n\t\t\t\thost.ui,\n\t\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t\t`${event.reason === \"overflow\" ? \"Context overflow detected, \" : \"\"}Auto-compacting... (${appKey(host.keybindings, \"interrupt\")} to cancel)`,\n\t\t\t);\n\t\t\thost.statusContainer.addChild(host.autoCompactionLoader);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"auto_compaction_end\":\n\t\t\tif (host.autoCompactionEscapeHandler) {\n\t\t\t\thost.defaultEditor.onEscape = host.autoCompactionEscapeHandler;\n\t\t\t\thost.autoCompactionEscapeHandler = undefined;\n\t\t\t}\n\t\t\tif (host.autoCompactionLoader) {\n\t\t\t\thost.autoCompactionLoader.stop();\n\t\t\t\thost.autoCompactionLoader = undefined;\n\t\t\t\thost.statusContainer.clear();\n\t\t\t}\n\t\t\tif (event.aborted) {\n\t\t\t\thost.showStatus(\"Auto-compaction cancelled\");\n\t\t\t} else if (event.result) {\n\t\t\t\thost.chatContainer.clear();\n\t\t\t\thost.rebuildChatFromMessages();\n\t\t\t\thost.addMessageToChat({\n\t\t\t\t\trole: \"compactionSummary\",\n\t\t\t\t\ttokensBefore: event.result.tokensBefore,\n\t\t\t\t\tsummary: event.result.summary,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t});\n\t\t\t\thost.footer.invalidate();\n\t\t\t} else if (event.errorMessage) {\n\t\t\t\thost.chatContainer.addChild(new Spacer(1));\n\t\t\t\thost.chatContainer.addChild(new Text(theme.fg(\"error\", event.errorMessage), 1, 0));\n\t\t\t}\n\t\t\tvoid host.flushCompactionQueue({ willRetry: event.willRetry });\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"auto_retry_start\":\n\t\t\thost.retryEscapeHandler = host.defaultEditor.onEscape;\n\t\t\thost.defaultEditor.onEscape = () => host.session.abortRetry();\n\t\t\thost.statusContainer.clear();\n\t\t\thost.retryLoader = new Loader(\n\t\t\t\thost.ui,\n\t\t\t\t(spinner) => theme.fg(\"warning\", spinner),\n\t\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t\t`Retrying (${event.attempt}/${event.maxAttempts}) in ${Math.round(event.delayMs / 1000)}s... (${appKey(host.keybindings, \"interrupt\")} to cancel)`,\n\t\t\t);\n\t\t\thost.statusContainer.addChild(host.retryLoader);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"auto_retry_end\":\n\t\t\tif (host.retryEscapeHandler) {\n\t\t\t\thost.defaultEditor.onEscape = host.retryEscapeHandler;\n\t\t\t\thost.retryEscapeHandler = undefined;\n\t\t\t}\n\t\t\tif (host.retryLoader) {\n\t\t\t\thost.retryLoader.stop();\n\t\t\t\thost.retryLoader = undefined;\n\t\t\t\thost.statusContainer.clear();\n\t\t\t}\n\t\t\tif (!event.success) {\n\t\t\t\thost.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || \"Unknown error\"}`);\n\t\t\t}\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"fallback_provider_switch\":\n\t\t\thost.showStatus(`Switched from ${event.from} → ${event.to} (${event.reason})`);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"fallback_provider_restored\":\n\t\t\thost.showStatus(`Restored to ${event.provider}`);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"fallback_chain_exhausted\":\n\t\t\thost.showError(event.reason);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"image_overflow_recovery\":\n\t\t\thost.showStatus(\n\t\t\t\t`Removed ${event.strippedCount} older image(s) to comply with API limits. Retrying...`,\n\t\t\t);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\t}\n}\n"]}
1
+ {"version":3,"file":"chat-controller.js","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { Loader, Markdown, Spacer, Text } from \"@gsd/pi-tui\";\n\nimport type { InteractiveModeEvent, InteractiveModeStateHost } from \"../interactive-mode-state.js\";\nimport { theme } from \"../theme/theme.js\";\nimport { AssistantMessageComponent } from \"../components/assistant-message.js\";\nimport { ToolExecutionComponent } from \"../components/tool-execution.js\";\nimport { DynamicBorder } from \"../components/dynamic-border.js\";\nimport { appKey } from \"../components/keybinding-hints.js\";\n\n// Tracks the last processed content index to avoid re-scanning all blocks on every message_update\nlet lastProcessedContentIndex = 0;\n\nfunction hasVisibleAssistantContent(message: { content: Array<any> }): boolean {\n\treturn message.content.some(\n\t\t(c) =>\n\t\t\t(c.type === \"text\" && typeof c.text === \"string\" && c.text.trim().length > 0)\n\t\t\t|| (c.type === \"thinking\" && typeof c.thinking === \"string\" && c.thinking.trim().length > 0),\n\t);\n}\n\nfunction hasAssistantToolBlocks(message: { content: Array<any> }): boolean {\n\treturn message.content.some((c) => c.type === \"toolCall\" || c.type === \"serverToolUse\");\n}\n\n// Tracks the latest assistant text for the pinned message zone\nlet lastPinnedText = \"\";\n// Whether any tool execution has been added in this assistant turn (triggers pinned display)\nlet hasToolsInTurn = false;\n// Reference to the pinned border so we can toggle its label between working/idle\nlet pinnedBorder: DynamicBorder | undefined;\n// Reference to the pinned markdown component below the border\nlet pinnedTextComponent: Markdown | undefined;\n\nexport async function handleAgentEvent(host: InteractiveModeStateHost & {\n\tinit: () => Promise<void>;\n\tgetMarkdownThemeWithSettings: () => any;\n\taddMessageToChat: (message: any, options?: any) => void;\n\tformatWebSearchResult: (content: unknown) => string;\n\tgetRegisteredToolDefinition: (toolName: string) => any;\n\tcheckShutdownRequested: () => Promise<void>;\n\trebuildChatFromMessages: () => void;\n\tflushCompactionQueue: (options?: { willRetry?: boolean }) => Promise<void>;\n\tshowStatus: (message: string) => void;\n\tshowError: (message: string) => void;\n\tupdatePendingMessagesDisplay: () => void;\n\tupdateTerminalTitle: () => void;\n\tupdateEditorBorderColor: () => void;\n\tpendingMessagesContainer: { clear: () => void };\n}, event: InteractiveModeEvent): Promise<void> {\n\tif (!host.isInitialized) {\n\t\tawait host.init();\n\t}\n\n\thost.footer.invalidate();\n\n\t// Reset content index tracker and pinned state when a new assistant message starts\n\tif (event.type === \"message_start\" && event.message.role === \"assistant\") {\n\t\tlastProcessedContentIndex = 0;\n\t\tlastPinnedText = \"\";\n\t\thasToolsInTurn = false;\n\t\tif (pinnedBorder) pinnedBorder.stopSpinner();\n\t\tpinnedBorder = undefined;\n\t\tpinnedTextComponent = undefined;\n\t\thost.pinnedMessageContainer.clear();\n\t}\n\n\tswitch (event.type) {\n\t\tcase \"session_state_changed\":\n\t\t\tswitch (event.reason) {\n\t\t\t\tcase \"new_session\":\n\t\t\t\tcase \"switch_session\":\n\t\t\t\tcase \"fork\":\n\t\t\t\t\thost.streamingComponent = undefined;\n\t\t\t\t\thost.streamingMessage = undefined;\n\t\t\t\t\thost.pendingTools.clear();\n\t\t\t\t\thost.pendingMessagesContainer.clear();\n\t\t\t\t\thost.pinnedMessageContainer.clear();\n\t\t\t\t\tlastPinnedText = \"\";\n\t\t\t\t\thasToolsInTurn = false;\n\t\t\t\t\tif (pinnedBorder) pinnedBorder.stopSpinner();\n\t\t\t\t\tpinnedBorder = undefined;\n\t\t\t\t\tpinnedTextComponent = undefined;\n\t\t\t\t\thost.compactionQueuedMessages = [];\n\t\t\t\t\thost.rebuildChatFromMessages();\n\t\t\t\t\thost.updatePendingMessagesDisplay();\n\t\t\t\t\thost.updateTerminalTitle();\n\t\t\t\t\thost.updateEditorBorderColor();\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t\treturn;\n\t\t\t\tcase \"set_session_name\":\n\t\t\t\t\thost.updateTerminalTitle();\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t\treturn;\n\t\t\t\tcase \"set_model\":\n\t\t\t\tcase \"set_thinking_level\":\n\t\t\t\t\thost.updateEditorBorderColor();\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t\treturn;\n\t\t\t\tdefault:\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t\treturn;\n\t\t\t}\n\t\tcase \"agent_start\":\n\t\t\tif (host.retryEscapeHandler) {\n\t\t\t\thost.defaultEditor.onEscape = host.retryEscapeHandler;\n\t\t\t\thost.retryEscapeHandler = undefined;\n\t\t\t}\n\t\t\tif (host.retryLoader) {\n\t\t\t\thost.retryLoader.stop();\n\t\t\t\thost.retryLoader = undefined;\n\t\t\t}\n\t\t\tif (host.loadingAnimation) {\n\t\t\t\thost.loadingAnimation.stop();\n\t\t\t}\n\t\t\thost.statusContainer.clear();\n\t\t\thost.loadingAnimation = new Loader(\n\t\t\t\thost.ui,\n\t\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t\thost.defaultWorkingMessage,\n\t\t\t);\n\t\t\thost.statusContainer.addChild(host.loadingAnimation);\n\t\t\tif (host.pendingWorkingMessage !== undefined) {\n\t\t\t\tif (host.pendingWorkingMessage) {\n\t\t\t\t\thost.loadingAnimation.setMessage(host.pendingWorkingMessage);\n\t\t\t\t}\n\t\t\t\thost.pendingWorkingMessage = undefined;\n\t\t\t}\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"message_start\":\n\t\t\tif (event.message.role === \"custom\") {\n\t\t\t\thost.addMessageToChat(event.message);\n\t\t\t\thost.ui.requestRender();\n\t\t\t} else if (event.message.role === \"user\") {\n\t\t\t\thost.addMessageToChat(event.message);\n\t\t\t\thost.updatePendingMessagesDisplay();\n\t\t\t\thost.ui.requestRender();\n\t\t\t} else if (event.message.role === \"assistant\") {\n\t\t\t\thost.streamingMessage = event.message;\n\t\t\t\t// External-tool providers can stream multiple assistant turns through\n\t\t\t\t// one response. Delay component creation until visible assistant text\n\t\t\t\t// arrives so tool outputs keep chronological ordering.\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"message_update\":\n\t\t\tif (event.message.role === \"assistant\") {\n\t\t\t\thost.streamingMessage = event.message;\n\t\t\t\tconst innerEvent = event.assistantMessageEvent;\n\n\t\t\t\tlet externalToolResult:\n\t\t\t\t\t| { toolCallId: string; content: Array<{ type: string; text?: string; data?: string; mimeType?: string }>; details: Record<string, unknown>; isError: boolean }\n\t\t\t\t\t| undefined;\n\t\t\t\tif (innerEvent.type === \"toolcall_end\" && innerEvent.toolCall) {\n\t\t\t\t\tconst tc = innerEvent.toolCall as any;\n\t\t\t\t\tconst ext = tc.externalResult;\n\t\t\t\t\tif (ext) {\n\t\t\t\t\t\texternalToolResult = {\n\t\t\t\t\t\t\ttoolCallId: tc.id,\n\t\t\t\t\t\t\tcontent: ext.content ?? [{ type: \"text\", text: \"\" }],\n\t\t\t\t\t\t\tdetails: ext.details ?? {},\n\t\t\t\t\t\t\tisError: ext.isError ?? false,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t} else if (innerEvent.type === \"server_tool_use\") {\n\t\t\t\t\tconst idx = typeof innerEvent.contentIndex === \"number\" ? innerEvent.contentIndex : -1;\n\t\t\t\t\tconst block = idx >= 0 ? (host.streamingMessage.content[idx] as any) : undefined;\n\t\t\t\t\tconst ext = block?.externalResult;\n\t\t\t\t\tif (block?.id && ext) {\n\t\t\t\t\t\texternalToolResult = {\n\t\t\t\t\t\t\ttoolCallId: block.id,\n\t\t\t\t\t\t\tcontent: ext.content ?? [{ type: \"text\", text: \"\" }],\n\t\t\t\t\t\t\tdetails: ext.details ?? {},\n\t\t\t\t\t\t\tisError: ext.isError ?? false,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst contentBlocks = host.streamingMessage.content;\n\t\t\t\t// Some adapters reuse a single assistant lifecycle while internally\n\t\t\t\t// spanning multiple provider turns. When a new turn starts, content\n\t\t\t\t// length can shrink back to 0/1; reset scan index to avoid skipping.\n\t\t\t\tif (lastProcessedContentIndex >= contentBlocks.length) {\n\t\t\t\t\tlastProcessedContentIndex = 0;\n\t\t\t\t}\n\t\t\t\tfor (let i = lastProcessedContentIndex; i < contentBlocks.length; i++) {\n\t\t\t\t\tconst content = contentBlocks[i];\n\t\t\t\t\tif (content.type === \"toolCall\") {\n\t\t\t\t\t\tif (!host.pendingTools.has(content.id)) {\n\t\t\t\t\t\t\tconst component = new ToolExecutionComponent(\n\t\t\t\t\t\t\t\tcontent.name,\n\t\t\t\t\t\t\t\tcontent.arguments,\n\t\t\t\t\t\t\t\t{ showImages: host.settingsManager.getShowImages() },\n\t\t\t\t\t\t\t\thost.getRegisteredToolDefinition(content.name),\n\t\t\t\t\t\t\t\thost.ui,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tcomponent.setExpanded(host.toolOutputExpanded);\n\t\t\t\t\t\t\thost.chatContainer.addChild(component);\n\t\t\t\t\t\t\thost.pendingTools.set(content.id, component);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\thost.pendingTools.get(content.id)?.updateArgs(content.arguments);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (content.type === \"serverToolUse\") {\n\t\t\t\t\t\tif (!host.pendingTools.has(content.id)) {\n\t\t\t\t\t\t\tconst component = new ToolExecutionComponent(\n\t\t\t\t\t\t\t\tcontent.name,\n\t\t\t\t\t\t\t\tcontent.input ?? {},\n\t\t\t\t\t\t\t\t{ showImages: host.settingsManager.getShowImages() },\n\t\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\thost.ui,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tcomponent.setExpanded(host.toolOutputExpanded);\n\t\t\t\t\t\t\thost.chatContainer.addChild(component);\n\t\t\t\t\t\t\thost.pendingTools.set(content.id, component);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (content.type === \"webSearchResult\") {\n\t\t\t\t\t\tconst component = host.pendingTools.get(content.toolUseId);\n\t\t\t\t\t\tif (component) {\n\t\t\t\t\t\t\tif (process.env.PI_OFFLINE === \"1\") {\n\t\t\t\t\t\t\t\tcomponent.updateResult({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"Web search disabled (offline mode)\" }],\n\t\t\t\t\t\t\t\t\tisError: false,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconst searchContent = content.content;\n\t\t\t\t\t\t\t\tconst isError = searchContent && typeof searchContent === \"object\" && \"type\" in (searchContent as any) && (searchContent as any).type === \"web_search_tool_result_error\";\n\t\t\t\t\t\t\t\tcomponent.updateResult({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: host.formatWebSearchResult(searchContent) }],\n\t\t\t\t\t\t\t\t\tisError: !!isError,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// When the stream adapter signals a completed tool call with an\n\t\t\t\t// external result (from Claude Code SDK), update the pending\n\t\t\t\t// ToolExecutionComponent immediately so output is visible in\n\t\t\t\t// real-time instead of waiting for the session to end.\n\t\t\t\tif (externalToolResult) {\n\t\t\t\t\tconst component = host.pendingTools.get(externalToolResult.toolCallId);\n\t\t\t\t\tif (component) {\n\t\t\t\t\t\tcomponent.updateResult({\n\t\t\t\t\t\t\tcontent: externalToolResult.content,\n\t\t\t\t\t\t\tdetails: externalToolResult.details,\n\t\t\t\t\t\t\tisError: externalToolResult.isError,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Render assistant text/thinking after tool components so mixed\n\t\t\t\t// streams keep chronological ordering in the chat container.\n\t\t\t\tconst hasToolBlocks = hasAssistantToolBlocks(host.streamingMessage);\n\t\t\t\tif (!host.streamingComponent && hasVisibleAssistantContent(host.streamingMessage)) {\n\t\t\t\t\thost.streamingComponent = new AssistantMessageComponent(\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\thost.hideThinkingBlock,\n\t\t\t\t\t\thost.getMarkdownThemeWithSettings(),\n\t\t\t\t\t\thost.settingsManager.getTimestampFormat(),\n\t\t\t\t\t);\n\t\t\t\t\thost.chatContainer.addChild(host.streamingComponent);\n\t\t\t\t}\n\t\t\t\tif (host.streamingComponent) {\n\t\t\t\t\tif (hasToolBlocks) {\n\t\t\t\t\t\thost.chatContainer.removeChild(host.streamingComponent);\n\t\t\t\t\t\thost.chatContainer.addChild(host.streamingComponent);\n\t\t\t\t\t}\n\t\t\t\t\thost.streamingComponent.updateContent(host.streamingMessage);\n\t\t\t\t}\n\n\t\t\t\t// Update index: fully processed blocks won't need re-scanning.\n\t\t\t\t// Keep the last block's index (it may still be accumulating data),\n\t\t\t\t// so we re-check it next time but skip all earlier ones.\n\t\t\t\tif (contentBlocks.length > 0) {\n\t\t\t\t\tlastProcessedContentIndex = Math.max(0, contentBlocks.length - 1);\n\t\t\t\t}\n\n\t\t\t\t// Pinned message: mirror the latest assistant text above the editor\n\t\t\t\t// when tool executions push it out of the viewport.\n\t\t\t\tconst hasTools = contentBlocks.some(\n\t\t\t\t\t(c: any) => c.type === \"toolCall\" || c.type === \"serverToolUse\",\n\t\t\t\t);\n\t\t\t\tif (hasTools) hasToolsInTurn = true;\n\n\t\t\t\tif (hasToolsInTurn) {\n\t\t\t\t\t// Collect the latest text block(s) from the assistant message\n\t\t\t\t\tlet latestText = \"\";\n\t\t\t\t\tfor (let i = contentBlocks.length - 1; i >= 0; i--) {\n\t\t\t\t\t\tconst c = contentBlocks[i] as any;\n\t\t\t\t\t\tif (c.type === \"text\" && c.text?.trim()) {\n\t\t\t\t\t\t\tlatestText = c.text.trim();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (latestText && latestText !== lastPinnedText) {\n\t\t\t\t\t\tlastPinnedText = latestText;\n\n\t\t\t\t\t\tif (!pinnedBorder) {\n\t\t\t\t\t\t\t// First time: create border + text component\n\t\t\t\t\t\t\thost.pinnedMessageContainer.clear();\n\t\t\t\t\t\t\tpinnedBorder = new DynamicBorder(\n\t\t\t\t\t\t\t\t(str: string) => theme.fg(\"dim\", str),\n\t\t\t\t\t\t\t\t\"Working · Latest Output\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tpinnedBorder.startSpinner(host.ui, (str: string) => theme.fg(\"accent\", str));\n\t\t\t\t\t\t\thost.pinnedMessageContainer.addChild(pinnedBorder);\n\t\t\t\t\t\t\tpinnedTextComponent = new Markdown(latestText, 1, 0, host.getMarkdownThemeWithSettings());\n\t\t\t\t\t\t\t// Cap pinned content to ~40% of terminal height so tall output\n\t\t\t\t\t\t\t// doesn't exceed the viewport and cause render flashing.\n\t\t\t\t\t\t\tpinnedTextComponent.maxLines = Math.max(3, Math.floor(host.ui.terminal.rows * 0.4));\n\t\t\t\t\t\t\thost.pinnedMessageContainer.addChild(pinnedTextComponent);\n\t\t\t\t\t\t\t// Hide the separate status loader — the pinned zone replaces it\n\t\t\t\t\t\t\tif (host.loadingAnimation) {\n\t\t\t\t\t\t\t\thost.loadingAnimation.stop();\n\t\t\t\t\t\t\t\thost.loadingAnimation = undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\thost.statusContainer.clear();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Update existing markdown component in-place\n\t\t\t\t\t\t\tpinnedTextComponent?.setText(latestText);\n\t\t\t\t\t\t\t// Refresh maxLines in case terminal was resized\n\t\t\t\t\t\t\tif (pinnedTextComponent) {\n\t\t\t\t\t\t\t\tpinnedTextComponent.maxLines = Math.max(3, Math.floor(host.ui.terminal.rows * 0.4));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"message_end\":\n\t\t\tif (event.message.role === \"user\") break;\n\t\t\tif (event.message.role === \"assistant\") {\n\t\t\t\thost.streamingMessage = event.message;\n\t\t\t\tlet errorMessage: string | undefined;\n\t\t\t\tif (host.streamingMessage.stopReason === \"aborted\") {\n\t\t\t\t\tconst retryAttempt = host.session.retryAttempt;\n\t\t\t\t\terrorMessage = retryAttempt > 0\n\t\t\t\t\t\t? `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? \"s\" : \"\"}`\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\t\thost.streamingMessage.errorMessage = errorMessage;\n\t\t\t\t}\n\n\t\t\t\tconst shouldRenderAssistant = hasVisibleAssistantContent(host.streamingMessage)\n\t\t\t\t\t|| (\n\t\t\t\t\t\t(host.streamingMessage.stopReason === \"aborted\" || host.streamingMessage.stopReason === \"error\")\n\t\t\t\t\t\t&& !hasAssistantToolBlocks(host.streamingMessage)\n\t\t\t\t\t);\n\t\t\t\tif (!host.streamingComponent && shouldRenderAssistant) {\n\t\t\t\t\thost.streamingComponent = new AssistantMessageComponent(\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\thost.hideThinkingBlock,\n\t\t\t\t\t\thost.getMarkdownThemeWithSettings(),\n\t\t\t\t\t\thost.settingsManager.getTimestampFormat(),\n\t\t\t\t\t);\n\t\t\t\t\thost.chatContainer.addChild(host.streamingComponent);\n\t\t\t\t}\n\t\t\t\tif (host.streamingComponent) {\n\t\t\t\t\thost.streamingComponent.updateContent(host.streamingMessage);\n\t\t\t\t}\n\n\t\t\t\tif (host.streamingMessage.stopReason === \"aborted\" || host.streamingMessage.stopReason === \"error\") {\n\t\t\t\t\tif (!errorMessage) {\n\t\t\t\t\t\terrorMessage = host.streamingMessage.errorMessage || \"Error\";\n\t\t\t\t\t}\n\t\t\t\t\tfor (const [, component] of host.pendingTools.entries()) {\n\t\t\t\t\t\tcomponent.updateResult({ content: [{ type: \"text\", text: errorMessage }], isError: true });\n\t\t\t\t\t}\n\t\t\t\t\thost.pendingTools.clear();\n\t\t\t\t} else {\n\t\t\t\t\tfor (const [, component] of host.pendingTools.entries()) {\n\t\t\t\t\t\tcomponent.setArgsComplete();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\thost.streamingComponent = undefined;\n\t\t\t\thost.streamingMessage = undefined;\n\t\t\t\t// Clear pinned output once the message is finalized in the chat\n\t\t\t\t// container — prevents duplicate display when the agent continues\n\t\t\t\t// (e.g. form elicitation) after the assistant message ends.\n\t\t\t\tif (pinnedBorder) pinnedBorder.stopSpinner();\n\t\t\t\thost.pinnedMessageContainer.clear();\n\t\t\t\tlastPinnedText = \"\";\n\t\t\t\thasToolsInTurn = false;\n\t\t\t\tpinnedBorder = undefined;\n\t\t\t\tpinnedTextComponent = undefined;\n\t\t\t\thost.footer.invalidate();\n\t\t\t}\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"tool_execution_start\":\n\t\t\tif (!host.pendingTools.has(event.toolCallId)) {\n\t\t\t\tconst component = new ToolExecutionComponent(\n\t\t\t\t\tevent.toolName,\n\t\t\t\t\tevent.args,\n\t\t\t\t\t{ showImages: host.settingsManager.getShowImages() },\n\t\t\t\t\thost.getRegisteredToolDefinition(event.toolName),\n\t\t\t\t\thost.ui,\n\t\t\t\t);\n\t\t\t\tcomponent.setExpanded(host.toolOutputExpanded);\n\t\t\t\thost.chatContainer.addChild(component);\n\t\t\t\thost.pendingTools.set(event.toolCallId, component);\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"tool_execution_update\": {\n\t\t\tconst component = host.pendingTools.get(event.toolCallId);\n\t\t\tif (component) {\n\t\t\t\tcomponent.updateResult({ ...event.partialResult, isError: false }, true);\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"tool_execution_end\": {\n\t\t\tconst component = host.pendingTools.get(event.toolCallId);\n\t\t\tif (component) {\n\t\t\t\tcomponent.updateResult({ ...event.result, isError: event.isError });\n\t\t\t\thost.pendingTools.delete(event.toolCallId);\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"agent_end\":\n\t\t\tif (host.loadingAnimation) {\n\t\t\t\thost.loadingAnimation.stop();\n\t\t\t\thost.loadingAnimation = undefined;\n\t\t\t\thost.statusContainer.clear();\n\t\t\t}\n\t\t\tif (host.streamingComponent) {\n\t\t\t\thost.chatContainer.removeChild(host.streamingComponent);\n\t\t\t\thost.streamingComponent = undefined;\n\t\t\t\thost.streamingMessage = undefined;\n\t\t\t}\n\t\t\thost.pendingTools.clear();\n\t\t\t// Pinned output is only useful while work is actively streaming.\n\t\t\t// Keep chat history as the single source after completion.\n\t\t\tif (pinnedBorder) {\n\t\t\t\tpinnedBorder.stopSpinner();\n\t\t\t}\n\t\t\thost.pinnedMessageContainer.clear();\n\t\t\tlastPinnedText = \"\";\n\t\t\thasToolsInTurn = false;\n\t\t\tpinnedBorder = undefined;\n\t\t\tpinnedTextComponent = undefined;\n\t\t\tawait host.checkShutdownRequested();\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"auto_compaction_start\":\n\t\t\thost.autoCompactionEscapeHandler = host.defaultEditor.onEscape;\n\t\t\thost.defaultEditor.onEscape = () => host.session.abortCompaction();\n\t\t\thost.statusContainer.clear();\n\t\t\thost.autoCompactionLoader = new Loader(\n\t\t\t\thost.ui,\n\t\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t\t`${event.reason === \"overflow\" ? \"Context overflow detected, \" : \"\"}Auto-compacting... (${appKey(host.keybindings, \"interrupt\")} to cancel)`,\n\t\t\t);\n\t\t\thost.statusContainer.addChild(host.autoCompactionLoader);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"auto_compaction_end\":\n\t\t\tif (host.autoCompactionEscapeHandler) {\n\t\t\t\thost.defaultEditor.onEscape = host.autoCompactionEscapeHandler;\n\t\t\t\thost.autoCompactionEscapeHandler = undefined;\n\t\t\t}\n\t\t\tif (host.autoCompactionLoader) {\n\t\t\t\thost.autoCompactionLoader.stop();\n\t\t\t\thost.autoCompactionLoader = undefined;\n\t\t\t\thost.statusContainer.clear();\n\t\t\t}\n\t\t\tif (event.aborted) {\n\t\t\t\thost.showStatus(\"Auto-compaction cancelled\");\n\t\t\t} else if (event.result) {\n\t\t\t\thost.chatContainer.clear();\n\t\t\t\thost.rebuildChatFromMessages();\n\t\t\t\thost.addMessageToChat({\n\t\t\t\t\trole: \"compactionSummary\",\n\t\t\t\t\ttokensBefore: event.result.tokensBefore,\n\t\t\t\t\tsummary: event.result.summary,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t});\n\t\t\t\thost.footer.invalidate();\n\t\t\t} else if (event.errorMessage) {\n\t\t\t\thost.chatContainer.addChild(new Spacer(1));\n\t\t\t\thost.chatContainer.addChild(new Text(theme.fg(\"error\", event.errorMessage), 1, 0));\n\t\t\t}\n\t\t\tvoid host.flushCompactionQueue({ willRetry: event.willRetry });\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"auto_retry_start\":\n\t\t\thost.retryEscapeHandler = host.defaultEditor.onEscape;\n\t\t\thost.defaultEditor.onEscape = () => host.session.abortRetry();\n\t\t\thost.statusContainer.clear();\n\t\t\thost.retryLoader = new Loader(\n\t\t\t\thost.ui,\n\t\t\t\t(spinner) => theme.fg(\"warning\", spinner),\n\t\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t\t`Retrying (${event.attempt}/${event.maxAttempts}) in ${Math.round(event.delayMs / 1000)}s... (${appKey(host.keybindings, \"interrupt\")} to cancel)`,\n\t\t\t);\n\t\t\thost.statusContainer.addChild(host.retryLoader);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"auto_retry_end\":\n\t\t\tif (host.retryEscapeHandler) {\n\t\t\t\thost.defaultEditor.onEscape = host.retryEscapeHandler;\n\t\t\t\thost.retryEscapeHandler = undefined;\n\t\t\t}\n\t\t\tif (host.retryLoader) {\n\t\t\t\thost.retryLoader.stop();\n\t\t\t\thost.retryLoader = undefined;\n\t\t\t\thost.statusContainer.clear();\n\t\t\t}\n\t\t\tif (!event.success) {\n\t\t\t\thost.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || \"Unknown error\"}`);\n\t\t\t}\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"fallback_provider_switch\":\n\t\t\thost.showStatus(`Switched from ${event.from} → ${event.to} (${event.reason})`);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"fallback_provider_restored\":\n\t\t\thost.showStatus(`Restored to ${event.provider}`);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"fallback_chain_exhausted\":\n\t\t\thost.showError(event.reason);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"image_overflow_recovery\":\n\t\t\thost.showStatus(\n\t\t\t\t`Removed ${event.strippedCount} older image(s) to comply with API limits. Retrying...`,\n\t\t\t);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\t}\n}\n"]}
@@ -338,6 +338,104 @@ test("chat-controller clears pinned zone when a new assistant message starts", a
338
338
  assert.equal(host.pinnedMessageContainer.children.length, 0, "pinned zone should clear on new assistant message");
339
339
  });
340
340
 
341
+ test("chat-controller clears pinned zone when the agent turn ends", async () => {
342
+ (globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
343
+ fg: (_key: string, text: string) => text,
344
+ bg: (_key: string, text: string) => text,
345
+ bold: (text: string) => text,
346
+ italic: (text: string) => text,
347
+ truncate: (text: string) => text,
348
+ };
349
+
350
+ const host = createHost();
351
+ const toolCall = {
352
+ type: "toolCall",
353
+ id: "tool-clear-on-end-1",
354
+ name: "exec_command",
355
+ arguments: { cmd: "echo hi" },
356
+ };
357
+
358
+ await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) } as any);
359
+
360
+ host.getMarkdownThemeWithSettings = () => ({});
361
+ await handleAgentEvent(
362
+ host,
363
+ {
364
+ type: "message_update",
365
+ message: makeAssistant([{ type: "text", text: "Working on it." }, toolCall]),
366
+ assistantMessageEvent: {
367
+ type: "toolcall_end",
368
+ contentIndex: 1,
369
+ toolCall: {
370
+ ...toolCall,
371
+ externalResult: {
372
+ content: [{ type: "text", text: "ok" }],
373
+ details: {},
374
+ isError: false,
375
+ },
376
+ },
377
+ partial: makeAssistant([{ type: "text", text: "Working on it." }, toolCall]),
378
+ },
379
+ } as any,
380
+ );
381
+
382
+ assert.ok(host.pinnedMessageContainer.children.length > 0, "pinned zone should be populated before agent_end");
383
+
384
+ await handleAgentEvent(host, { type: "agent_end" } as any);
385
+
386
+ assert.equal(host.pinnedMessageContainer.children.length, 0, "pinned zone should clear on agent_end");
387
+ });
388
+
389
+ test("chat-controller clears pinned zone when assistant message ends", async () => {
390
+ (globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
391
+ fg: (_key: string, text: string) => text,
392
+ bg: (_key: string, text: string) => text,
393
+ bold: (text: string) => text,
394
+ italic: (text: string) => text,
395
+ truncate: (text: string) => text,
396
+ };
397
+
398
+ const host = createHost();
399
+ const toolCall = {
400
+ type: "toolCall",
401
+ id: "tool-msg-end-1",
402
+ name: "exec_command",
403
+ arguments: { cmd: "echo hi" },
404
+ };
405
+
406
+ await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) } as any);
407
+
408
+ host.getMarkdownThemeWithSettings = () => ({});
409
+ const msgContent = [{ type: "text", text: "Summary after tools." }, toolCall];
410
+ await handleAgentEvent(
411
+ host,
412
+ {
413
+ type: "message_update",
414
+ message: makeAssistant(msgContent),
415
+ assistantMessageEvent: {
416
+ type: "toolcall_end",
417
+ contentIndex: 1,
418
+ toolCall: {
419
+ ...toolCall,
420
+ externalResult: {
421
+ content: [{ type: "text", text: "ok" }],
422
+ details: {},
423
+ isError: false,
424
+ },
425
+ },
426
+ partial: makeAssistant(msgContent),
427
+ },
428
+ } as any,
429
+ );
430
+
431
+ assert.ok(host.pinnedMessageContainer.children.length > 0, "pinned zone should be populated during streaming");
432
+
433
+ // End the assistant message (e.g. before form elicitation) — pinned zone should clear
434
+ await handleAgentEvent(host, { type: "message_end", message: makeAssistant(msgContent) } as any);
435
+
436
+ assert.equal(host.pinnedMessageContainer.children.length, 0, "pinned zone should clear on message_end to prevent duplicate display");
437
+ });
438
+
341
439
  test("chat-controller does not pin when there are no tool calls", async () => {
342
440
  (globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
343
441
  fg: (_key: string, text: string) => text,
@@ -380,6 +380,15 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
380
380
  }
381
381
  host.streamingComponent = undefined;
382
382
  host.streamingMessage = undefined;
383
+ // Clear pinned output once the message is finalized in the chat
384
+ // container — prevents duplicate display when the agent continues
385
+ // (e.g. form elicitation) after the assistant message ends.
386
+ if (pinnedBorder) pinnedBorder.stopSpinner();
387
+ host.pinnedMessageContainer.clear();
388
+ lastPinnedText = "";
389
+ hasToolsInTurn = false;
390
+ pinnedBorder = undefined;
391
+ pinnedTextComponent = undefined;
383
392
  host.footer.invalidate();
384
393
  }
385
394
  host.ui.requestRender();
@@ -432,12 +441,12 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
432
441
  host.streamingMessage = undefined;
433
442
  }
434
443
  host.pendingTools.clear();
435
- // Stop spinner on pinned border and switch label from "Working · Latest Output" to "Latest Output"
444
+ // Pinned output is only useful while work is actively streaming.
445
+ // Keep chat history as the single source after completion.
436
446
  if (pinnedBorder) {
437
447
  pinnedBorder.stopSpinner();
438
- pinnedBorder.setLabel("Latest Output");
439
448
  }
440
- // Keep pinned message visible until the next assistant turn starts.
449
+ host.pinnedMessageContainer.clear();
441
450
  lastPinnedText = "";
442
451
  hasToolsInTurn = false;
443
452
  pinnedBorder = undefined;