gsd-pi 2.74.0-dev.14c45ac → 2.74.0-dev.20f79a8
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.
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -3
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +10 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +45 -4
- package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +144 -0
- package/dist/resources/extensions/gsd/ecosystem/loader.js +145 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/required-server-files.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
- package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +1 -9
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -9
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/models/capability-patches.d.ts +19 -0
- package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/capability-patches.js +36 -0
- package/packages/pi-ai/dist/models/capability-patches.js.map +1 -0
- package/packages/pi-ai/dist/{models.custom.d.ts → models/custom.d.ts} +1 -1
- package/packages/pi-ai/dist/models/custom.d.ts.map +1 -0
- package/packages/pi-ai/dist/{models.custom.js → models/custom.js} +4 -4
- package/packages/pi-ai/dist/models/custom.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts +1482 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.js +1484 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/anthropic.d.ts +377 -0
- package/packages/pi-ai/dist/models/generated/anthropic.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/anthropic.js +379 -0
- package/packages/pi-ai/dist/models/generated/anthropic.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts +700 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.js +702 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/cerebras.d.ts +71 -0
- package/packages/pi-ai/dist/models/generated/cerebras.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/cerebras.js +73 -0
- package/packages/pi-ai/dist/models/generated/cerebras.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.d.ts +590 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.js +444 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts +156 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.js +158 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts +105 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.js +107 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.d.ts +207 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.js +209 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google.d.ts +462 -0
- package/packages/pi-ai/dist/models/generated/google.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google.js +464 -0
- package/packages/pi-ai/dist/models/generated/google.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/groq.d.ts +309 -0
- package/packages/pi-ai/dist/models/generated/groq.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/groq.js +311 -0
- package/packages/pi-ai/dist/models/generated/groq.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/huggingface.d.ts +383 -0
- package/packages/pi-ai/dist/models/generated/huggingface.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/huggingface.js +347 -0
- package/packages/pi-ai/dist/models/generated/huggingface.js.map +1 -0
- package/packages/pi-ai/dist/{models.generated.d.ts → models/generated/index.d.ts} +1 -1
- package/packages/pi-ai/dist/{models.generated.d.ts.map → models/generated/index.d.ts.map} +1 -1
- package/packages/pi-ai/dist/models/generated/index.js +51 -0
- package/packages/pi-ai/dist/models/generated/index.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts +37 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.js +39 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts +105 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.js +107 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax.d.ts +105 -0
- package/packages/pi-ai/dist/models/generated/minimax.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax.js +107 -0
- package/packages/pi-ai/dist/models/generated/minimax.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/mistral.d.ts +445 -0
- package/packages/pi-ai/dist/models/generated/mistral.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/mistral.js +447 -0
- package/packages/pi-ai/dist/models/generated/mistral.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +139 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js +141 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts +700 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai.js +702 -0
- package/packages/pi-ai/dist/models/generated/openai.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.d.ts +122 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.js +124 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode.d.ts +530 -0
- package/packages/pi-ai/dist/models/generated/opencode.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode.js +532 -0
- package/packages/pi-ai/dist/models/generated/opencode.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/openrouter.d.ts +4270 -0
- package/packages/pi-ai/dist/models/generated/openrouter.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/openrouter.js +4272 -0
- package/packages/pi-ai/dist/models/generated/openrouter.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts +2604 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js +2606 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/xai.d.ts +411 -0
- package/packages/pi-ai/dist/models/generated/xai.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/xai.js +413 -0
- package/packages/pi-ai/dist/models/generated/xai.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/zai.d.ts +276 -0
- package/packages/pi-ai/dist/models/generated/zai.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/zai.js +239 -0
- package/packages/pi-ai/dist/models/generated/zai.js.map +1 -0
- package/packages/pi-ai/dist/models/index.d.ts +27 -0
- package/packages/pi-ai/dist/models/index.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/index.js +80 -0
- package/packages/pi-ai/dist/models/index.js.map +1 -0
- package/packages/pi-ai/dist/models.d.ts +1 -36
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.js +1 -2
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
- package/packages/pi-ai/dist/models.js +3 -112
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +6 -5
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +74 -40
- package/packages/pi-ai/src/index.ts +1 -9
- package/packages/pi-ai/src/models/capability-patches.ts +40 -0
- package/packages/pi-ai/src/{models.custom.ts → models/custom.ts} +4 -4
- package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1486 -0
- package/packages/pi-ai/src/models/generated/anthropic.ts +381 -0
- package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
- package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
- package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
- package/packages/pi-ai/src/models/generated/google-antigravity.ts +160 -0
- package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
- package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
- package/packages/pi-ai/src/models/generated/google.ts +466 -0
- package/packages/pi-ai/src/models/generated/groq.ts +313 -0
- package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
- package/packages/pi-ai/src/models/generated/index.ts +52 -0
- package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
- package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
- package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
- package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
- package/packages/pi-ai/src/models/generated/openai-codex.ts +143 -0
- package/packages/pi-ai/src/models/generated/openai.ts +704 -0
- package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
- package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
- package/packages/pi-ai/src/models/generated/openrouter.ts +4274 -0
- package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
- package/packages/pi-ai/src/models/generated/xai.ts +415 -0
- package/packages/pi-ai/src/models/generated/zai.ts +241 -0
- package/packages/pi-ai/src/models/index.ts +106 -0
- package/packages/pi-ai/src/models.generated.test.ts +1 -2
- package/packages/pi-ai/src/models.test.ts +6 -5
- package/packages/pi-ai/src/models.ts +3 -153
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -2
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +284 -10
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +23 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +47 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +22 -22
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +171 -24
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +38 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +13 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +53 -6
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +12 -6
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +357 -10
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +25 -10
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +67 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +23 -26
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +232 -47
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +44 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +73 -6
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +7 -3
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +56 -3
- package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +228 -0
- package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
- package/src/resources/extensions/gsd/types.ts +13 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +2 -1
- package/packages/pi-ai/dist/models.custom.d.ts.map +0 -1
- package/packages/pi-ai/dist/models.custom.js.map +0 -1
- package/packages/pi-ai/dist/models.generated.js +0 -14343
- package/packages/pi-ai/dist/models.generated.js.map +0 -1
- package/packages/pi-ai/src/models.generated.ts +0 -14345
- /package/dist/web/standalone/.next/static/{ZMKM0OI0CrTgzKWbgfPOg → ZDXqgjuglsRoazETSKw1J}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{ZMKM0OI0CrTgzKWbgfPOg → ZDXqgjuglsRoazETSKw1J}/_ssgManifest.js +0 -0
|
@@ -16,7 +16,13 @@ let lastContentLength = 0;
|
|
|
16
16
|
|
|
17
17
|
// --- Segment walker state (per streaming assistant turn) ---
|
|
18
18
|
type RenderedSegment =
|
|
19
|
-
| {
|
|
19
|
+
| {
|
|
20
|
+
kind: "text-run";
|
|
21
|
+
startIndex: number;
|
|
22
|
+
endIndex: number;
|
|
23
|
+
contentType: "text" | "thinking";
|
|
24
|
+
component: AssistantMessageComponent;
|
|
25
|
+
}
|
|
20
26
|
| { kind: "tool"; contentIndex: number; component: ToolExecutionComponent };
|
|
21
27
|
|
|
22
28
|
let renderedSegments: RenderedSegment[] = [];
|
|
@@ -89,6 +95,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
89
95
|
}
|
|
90
96
|
|
|
91
97
|
host.footer.invalidate();
|
|
98
|
+
const timestampFormat = host.settingsManager.getTimestampFormat();
|
|
92
99
|
|
|
93
100
|
// Reset content index tracker and pinned state when a new assistant message starts
|
|
94
101
|
if (event.type === "message_start" && event.message.role === "assistant") {
|
|
@@ -232,7 +239,10 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
232
239
|
// content (#4144 regression). Prior sub-turn children stay in
|
|
233
240
|
// chatContainer as frozen history; new segments append after them.
|
|
234
241
|
if (contentBlocks.length < lastContentLength) {
|
|
235
|
-
|
|
242
|
+
// Accumulate across successive shrinks — overwriting would drop
|
|
243
|
+
// segments displaced by an earlier shrink, leaving them stranded
|
|
244
|
+
// in chatContainer once the prune pass finally runs.
|
|
245
|
+
orphanedSegments = [...orphanedSegments, ...renderedSegments];
|
|
236
246
|
renderedSegments = [];
|
|
237
247
|
lastPinnedText = "";
|
|
238
248
|
lastProcessedContentIndex = 0;
|
|
@@ -319,44 +329,81 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
319
329
|
}
|
|
320
330
|
return false;
|
|
321
331
|
});
|
|
322
|
-
const shouldDropPreToolText = isClaudeCodeProvider && hasMcpToolBlock;
|
|
323
332
|
const firstToolIdx = blocks.findIndex((b: any) => b.type === "toolCall" || b.type === "serverToolUse");
|
|
333
|
+
const hasPostToolText = firstToolIdx >= 0
|
|
334
|
+
&& blocks.some(
|
|
335
|
+
(b: any, idx: number) => (
|
|
336
|
+
idx > firstToolIdx
|
|
337
|
+
&& b?.type === "text"
|
|
338
|
+
&& typeof b?.text === "string"
|
|
339
|
+
&& b.text.trim().length > 0
|
|
340
|
+
),
|
|
341
|
+
);
|
|
342
|
+
// Only prune provisional pre-tool prose after post-tool prose exists,
|
|
343
|
+
// so MCP tool-only windows do not blank the assistant content.
|
|
344
|
+
const shouldDropPreToolProse = isClaudeCodeProvider && hasMcpToolBlock && hasPostToolText;
|
|
324
345
|
type DesiredSegment =
|
|
325
|
-
| { kind: "text-run"; startIndex: number; endIndex: number }
|
|
346
|
+
| { kind: "text-run"; startIndex: number; endIndex: number; contentType: "text" | "thinking" }
|
|
326
347
|
| { kind: "tool"; contentIndex: number; toolId: string };
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
348
|
+
const desired: DesiredSegment[] = [];
|
|
349
|
+
let runStart = -1;
|
|
350
|
+
let runEnd = -1;
|
|
351
|
+
let runType: "text" | "thinking" | undefined;
|
|
352
|
+
const closeRun = () => {
|
|
353
|
+
if (runStart !== -1 && runType) {
|
|
354
|
+
desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
|
|
355
|
+
runStart = -1;
|
|
356
|
+
runEnd = -1;
|
|
357
|
+
runType = undefined;
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
361
|
+
const b = blocks[i];
|
|
362
|
+
const blockType = b.type === "text" || b.type === "thinking" ? b.type : undefined;
|
|
363
|
+
const isTextLike = blockType === "text" || blockType === "thinking";
|
|
364
|
+
const isTool = b.type === "toolCall" || b.type === "serverToolUse";
|
|
365
|
+
// For Claude Code MCP turns, prune only pre-tool prose, never thinking.
|
|
366
|
+
const textValue = blockType === "text" && typeof b?.text === "string" ? b.text : "";
|
|
367
|
+
const isLikelyQuestion = blockType === "text" && typeof textValue === "string" && /\?\s*$/.test(textValue.trim());
|
|
368
|
+
const shouldSkipProse = shouldDropPreToolProse
|
|
369
|
+
&& firstToolIdx >= 0
|
|
370
|
+
&& i < firstToolIdx
|
|
371
|
+
&& blockType === "text"
|
|
372
|
+
&& !isLikelyQuestion;
|
|
373
|
+
if (shouldSkipProse) {
|
|
374
|
+
closeRun();
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
if (isTextLike) {
|
|
378
|
+
if (runStart === -1) {
|
|
379
|
+
runStart = i;
|
|
380
|
+
runEnd = i;
|
|
381
|
+
runType = blockType;
|
|
382
|
+
} else if (runType !== blockType) {
|
|
383
|
+
closeRun();
|
|
384
|
+
runStart = i;
|
|
385
|
+
runEnd = i;
|
|
386
|
+
runType = blockType;
|
|
387
|
+
} else {
|
|
388
|
+
runEnd = i;
|
|
336
389
|
}
|
|
337
|
-
if (runStart === -1) runStart = i;
|
|
338
390
|
} else {
|
|
339
|
-
|
|
340
|
-
desired.push({ kind: "text-run", startIndex: runStart, endIndex: i - 1 });
|
|
341
|
-
runStart = -1;
|
|
342
|
-
}
|
|
391
|
+
closeRun();
|
|
343
392
|
if (isTool) {
|
|
344
393
|
desired.push({ kind: "tool", contentIndex: i, toolId: b.id });
|
|
345
394
|
}
|
|
346
395
|
}
|
|
347
396
|
}
|
|
348
|
-
|
|
349
|
-
desired.push({ kind: "text-run", startIndex: runStart, endIndex: blocks.length - 1 });
|
|
350
|
-
}
|
|
397
|
+
closeRun();
|
|
351
398
|
|
|
352
399
|
// Claude Code MCP can emit provisional pre-tool prose that gets
|
|
353
400
|
// superseded by post-tool output. Prune stale text-run segments so
|
|
354
401
|
// the final assistant output remains below tool output.
|
|
355
|
-
if (
|
|
402
|
+
if (shouldDropPreToolProse && firstToolIdx >= 0) {
|
|
356
403
|
if (orphanedSegments.length > 0) {
|
|
357
404
|
const remainingOrphans: RenderedSegment[] = [];
|
|
358
405
|
for (const orphan of orphanedSegments) {
|
|
359
|
-
if (orphan.kind === "text-run") {
|
|
406
|
+
if (orphan.kind === "text-run" && orphan.contentType === "text") {
|
|
360
407
|
host.chatContainer.removeChild(orphan.component);
|
|
361
408
|
if (host.streamingComponent === orphan.component) {
|
|
362
409
|
host.streamingComponent = undefined;
|
|
@@ -367,10 +414,10 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
367
414
|
}
|
|
368
415
|
orphanedSegments = remainingOrphans;
|
|
369
416
|
}
|
|
370
|
-
const
|
|
417
|
+
const desiredTextKeys = new Set(
|
|
371
418
|
desired
|
|
372
419
|
.filter((seg): seg is Extract<DesiredSegment, { kind: "text-run" }> => seg.kind === "text-run")
|
|
373
|
-
.map((seg) => seg.startIndex),
|
|
420
|
+
.map((seg) => `${seg.contentType}:${seg.startIndex}`),
|
|
374
421
|
);
|
|
375
422
|
const desiredToolIndices = new Set(
|
|
376
423
|
desired
|
|
@@ -379,7 +426,11 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
379
426
|
);
|
|
380
427
|
const nextRendered: RenderedSegment[] = [];
|
|
381
428
|
for (const seg of renderedSegments) {
|
|
382
|
-
if (
|
|
429
|
+
if (
|
|
430
|
+
seg.kind === "text-run"
|
|
431
|
+
&& seg.contentType === "text"
|
|
432
|
+
&& !desiredTextKeys.has(`${seg.contentType}:${seg.startIndex}`)
|
|
433
|
+
) {
|
|
383
434
|
host.chatContainer.removeChild(seg.component);
|
|
384
435
|
if (host.streamingComponent === seg.component) {
|
|
385
436
|
host.streamingComponent = undefined;
|
|
@@ -411,18 +462,24 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
411
462
|
} else {
|
|
412
463
|
// text-run segment
|
|
413
464
|
const existing = renderedSegments.find(
|
|
414
|
-
(s) => s.kind === "text-run" && s.startIndex === seg.startIndex,
|
|
465
|
+
(s) => s.kind === "text-run" && s.startIndex === seg.startIndex && s.contentType === seg.contentType,
|
|
415
466
|
);
|
|
416
467
|
if (!existing) {
|
|
417
468
|
const comp = new AssistantMessageComponent(
|
|
418
469
|
undefined,
|
|
419
470
|
host.hideThinkingBlock,
|
|
420
471
|
host.getMarkdownThemeWithSettings(),
|
|
421
|
-
|
|
472
|
+
timestampFormat,
|
|
422
473
|
{ startIndex: seg.startIndex, endIndex: seg.endIndex },
|
|
423
474
|
);
|
|
424
475
|
host.chatContainer.addChild(comp);
|
|
425
|
-
renderedSegments.push({
|
|
476
|
+
renderedSegments.push({
|
|
477
|
+
kind: "text-run",
|
|
478
|
+
startIndex: seg.startIndex,
|
|
479
|
+
endIndex: seg.endIndex,
|
|
480
|
+
contentType: seg.contentType,
|
|
481
|
+
component: comp,
|
|
482
|
+
});
|
|
426
483
|
host.streamingComponent = comp;
|
|
427
484
|
}
|
|
428
485
|
}
|
|
@@ -433,7 +490,9 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
433
490
|
for (const seg of renderedSegments) {
|
|
434
491
|
if (seg.kind === "text-run") {
|
|
435
492
|
// Find corresponding desired segment to get current endIndex
|
|
436
|
-
const d = desired.find(
|
|
493
|
+
const d = desired.find(
|
|
494
|
+
(ds) => ds.kind === "text-run" && ds.startIndex === seg.startIndex && ds.contentType === seg.contentType,
|
|
495
|
+
);
|
|
437
496
|
if (d && d.kind === "text-run" && d.endIndex !== seg.endIndex) {
|
|
438
497
|
seg.endIndex = d.endIndex;
|
|
439
498
|
seg.component.setRange({ startIndex: seg.startIndex, endIndex: seg.endIndex });
|
|
@@ -504,11 +563,11 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
504
563
|
}
|
|
505
564
|
break;
|
|
506
565
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
566
|
+
case "message_end":
|
|
567
|
+
if (event.message.role === "user") break;
|
|
568
|
+
if (event.message.role === "assistant") {
|
|
569
|
+
host.streamingMessage = event.message;
|
|
570
|
+
let errorMessage: string | undefined;
|
|
512
571
|
if (host.streamingMessage.stopReason === "aborted") {
|
|
513
572
|
const retryAttempt = host.session.retryAttempt;
|
|
514
573
|
errorMessage = retryAttempt > 0
|
|
@@ -517,18 +576,144 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
517
576
|
host.streamingMessage.errorMessage = errorMessage;
|
|
518
577
|
}
|
|
519
578
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
579
|
+
const shouldRenderAssistant = hasVisibleAssistantContent(host.streamingMessage)
|
|
580
|
+
|| (
|
|
581
|
+
(host.streamingMessage.stopReason === "aborted" || host.streamingMessage.stopReason === "error")
|
|
582
|
+
&& !hasAssistantToolBlocks(host.streamingMessage)
|
|
583
|
+
);
|
|
584
|
+
|
|
585
|
+
// The final message_end payload can contain additional text/thinking
|
|
586
|
+
// blocks that never arrived via message_update (e.g. SDK result
|
|
587
|
+
// aggregation). Rebuild this in-flight turn from final content so
|
|
588
|
+
// ranges/components don't keep stale partial indices.
|
|
589
|
+
if (renderedSegments.length > 0) {
|
|
590
|
+
const finalBlocks = host.streamingMessage.content;
|
|
591
|
+
type DesiredSegment =
|
|
592
|
+
| { kind: "text-run"; startIndex: number; endIndex: number; contentType: "text" | "thinking" }
|
|
593
|
+
| { kind: "tool"; contentIndex: number; toolId: string };
|
|
594
|
+
const desired: DesiredSegment[] = [];
|
|
595
|
+
let runStart = -1;
|
|
596
|
+
let runEnd = -1;
|
|
597
|
+
let runType: "text" | "thinking" | undefined;
|
|
598
|
+
const closeRun = () => {
|
|
599
|
+
if (runStart !== -1 && runType) {
|
|
600
|
+
desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
|
|
601
|
+
runStart = -1;
|
|
602
|
+
runEnd = -1;
|
|
603
|
+
runType = undefined;
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
for (let i = 0; i < finalBlocks.length; i++) {
|
|
608
|
+
const block = finalBlocks[i] as any;
|
|
609
|
+
const blockType = block?.type === "text" || block?.type === "thinking" ? block.type : undefined;
|
|
610
|
+
const isTextLike = blockType === "text" || blockType === "thinking";
|
|
611
|
+
const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
|
|
612
|
+
|
|
613
|
+
if (isTextLike) {
|
|
614
|
+
if (runStart === -1) {
|
|
615
|
+
runStart = i;
|
|
616
|
+
runEnd = i;
|
|
617
|
+
runType = blockType;
|
|
618
|
+
} else if (runType !== blockType) {
|
|
619
|
+
closeRun();
|
|
620
|
+
runStart = i;
|
|
621
|
+
runEnd = i;
|
|
622
|
+
runType = blockType;
|
|
623
|
+
} else {
|
|
624
|
+
runEnd = i;
|
|
625
|
+
}
|
|
626
|
+
} else {
|
|
627
|
+
closeRun();
|
|
628
|
+
if (isTool) {
|
|
629
|
+
desired.push({ kind: "tool", contentIndex: i, toolId: block.id });
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
closeRun();
|
|
634
|
+
|
|
635
|
+
const toolComponentsById = new Map<string, ToolExecutionComponent>();
|
|
636
|
+
for (const [toolId, component] of host.pendingTools.entries()) {
|
|
637
|
+
toolComponentsById.set(toolId, component);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
for (const seg of renderedSegments) {
|
|
641
|
+
host.chatContainer.removeChild(seg.component);
|
|
642
|
+
if (seg.kind === "tool") {
|
|
643
|
+
const priorBlocks = host.streamingMessage.content;
|
|
644
|
+
const priorBlock = priorBlocks[seg.contentIndex] as any;
|
|
645
|
+
if (priorBlock?.id && !toolComponentsById.has(priorBlock.id)) {
|
|
646
|
+
toolComponentsById.set(priorBlock.id, seg.component);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
renderedSegments = [];
|
|
651
|
+
host.streamingComponent = undefined;
|
|
652
|
+
|
|
653
|
+
for (const seg of desired) {
|
|
654
|
+
if (seg.kind === "tool") {
|
|
655
|
+
const finalBlock = finalBlocks[seg.contentIndex] as any;
|
|
656
|
+
let component = toolComponentsById.get(seg.toolId);
|
|
657
|
+
if (!component && finalBlock?.id) {
|
|
658
|
+
component = host.pendingTools.get(finalBlock.id);
|
|
659
|
+
}
|
|
660
|
+
if (!component && finalBlock?.type === "toolCall") {
|
|
661
|
+
component = new ToolExecutionComponent(
|
|
662
|
+
finalBlock.name,
|
|
663
|
+
finalBlock.arguments,
|
|
664
|
+
{ showImages: host.settingsManager.getShowImages() },
|
|
665
|
+
host.getRegisteredToolDefinition(finalBlock.name),
|
|
666
|
+
host.ui,
|
|
667
|
+
);
|
|
668
|
+
component.setExpanded(host.toolOutputExpanded);
|
|
669
|
+
host.pendingTools.set(finalBlock.id, component);
|
|
670
|
+
toolComponentsById.set(finalBlock.id, component);
|
|
671
|
+
} else if (!component && finalBlock?.type === "serverToolUse") {
|
|
672
|
+
component = new ToolExecutionComponent(
|
|
673
|
+
finalBlock.name,
|
|
674
|
+
finalBlock.input ?? {},
|
|
675
|
+
{ showImages: host.settingsManager.getShowImages() },
|
|
676
|
+
undefined,
|
|
677
|
+
host.ui,
|
|
678
|
+
);
|
|
679
|
+
component.setExpanded(host.toolOutputExpanded);
|
|
680
|
+
host.pendingTools.set(finalBlock.id, component);
|
|
681
|
+
toolComponentsById.set(finalBlock.id, component);
|
|
682
|
+
}
|
|
683
|
+
if (component) {
|
|
684
|
+
host.chatContainer.addChild(component);
|
|
685
|
+
renderedSegments.push({ kind: "tool", contentIndex: seg.contentIndex, component });
|
|
686
|
+
}
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const comp = new AssistantMessageComponent(
|
|
691
|
+
undefined,
|
|
692
|
+
host.hideThinkingBlock,
|
|
693
|
+
host.getMarkdownThemeWithSettings(),
|
|
694
|
+
timestampFormat,
|
|
695
|
+
{ startIndex: seg.startIndex, endIndex: seg.endIndex },
|
|
696
|
+
);
|
|
697
|
+
comp.updateContent(host.streamingMessage);
|
|
698
|
+
host.chatContainer.addChild(comp);
|
|
699
|
+
renderedSegments.push({
|
|
700
|
+
kind: "text-run",
|
|
701
|
+
startIndex: seg.startIndex,
|
|
702
|
+
endIndex: seg.endIndex,
|
|
703
|
+
contentType: seg.contentType,
|
|
704
|
+
component: comp,
|
|
705
|
+
});
|
|
706
|
+
host.streamingComponent = comp;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
if (!host.streamingComponent && shouldRenderAssistant) {
|
|
711
|
+
host.streamingComponent = new AssistantMessageComponent(
|
|
712
|
+
undefined,
|
|
713
|
+
host.hideThinkingBlock,
|
|
714
|
+
host.getMarkdownThemeWithSettings(),
|
|
715
|
+
timestampFormat,
|
|
716
|
+
);
|
|
532
717
|
host.chatContainer.addChild(host.streamingComponent);
|
|
533
718
|
}
|
|
534
719
|
if (host.streamingComponent) {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
|
|
4
|
+
import { buildAssistantReplaySegments } from "./interactive-mode.js";
|
|
5
|
+
|
|
6
|
+
test("buildAssistantReplaySegments preserves tool-first ordering", () => {
|
|
7
|
+
const segments = buildAssistantReplaySegments([
|
|
8
|
+
{ type: "toolCall", id: "t1", name: "read", arguments: {} },
|
|
9
|
+
{ type: "text", text: "Done." },
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
assert.deepEqual(segments, [
|
|
13
|
+
{ kind: "tool", contentIndex: 0 },
|
|
14
|
+
{ kind: "assistant", startIndex: 1, endIndex: 1 },
|
|
15
|
+
]);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("buildAssistantReplaySegments preserves interleaved assistant-tool-assistant runs", () => {
|
|
19
|
+
const segments = buildAssistantReplaySegments([
|
|
20
|
+
{ type: "text", text: "Let me check." },
|
|
21
|
+
{ type: "serverToolUse", id: "s1", name: "mcp__fs__glob", input: {} },
|
|
22
|
+
{ type: "thinking", thinking: "Tool result looks good." },
|
|
23
|
+
{ type: "text", text: "Here is the answer." },
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
assert.deepEqual(segments, [
|
|
27
|
+
{ kind: "assistant", startIndex: 0, endIndex: 0 },
|
|
28
|
+
{ kind: "tool", contentIndex: 1 },
|
|
29
|
+
{ kind: "assistant", startIndex: 2, endIndex: 3 },
|
|
30
|
+
]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("buildAssistantReplaySegments ignores non-rendered non-tool blocks", () => {
|
|
34
|
+
const segments = buildAssistantReplaySegments([
|
|
35
|
+
{ type: "text", text: "before" },
|
|
36
|
+
{ type: "webSearchResult", toolUseId: "s1", content: {} },
|
|
37
|
+
{ type: "text", text: "after" },
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
assert.deepEqual(segments, [
|
|
41
|
+
{ kind: "assistant", startIndex: 0, endIndex: 0 },
|
|
42
|
+
{ kind: "assistant", startIndex: 2, endIndex: 2 },
|
|
43
|
+
]);
|
|
44
|
+
});
|
|
@@ -127,6 +127,45 @@ function isExpandable(obj: unknown): obj is Expandable {
|
|
|
127
127
|
return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
export type AssistantReplaySegment =
|
|
131
|
+
| { kind: "assistant"; startIndex: number; endIndex: number }
|
|
132
|
+
| { kind: "tool"; contentIndex: number };
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Build replay segments for historical assistant messages so rebuild paths
|
|
136
|
+
* preserve the original content[] ordering between assistant prose and tools.
|
|
137
|
+
*/
|
|
138
|
+
export function buildAssistantReplaySegments(contentBlocks: Array<any>): AssistantReplaySegment[] {
|
|
139
|
+
const segments: AssistantReplaySegment[] = [];
|
|
140
|
+
let runStart = -1;
|
|
141
|
+
|
|
142
|
+
for (let i = 0; i < contentBlocks.length; i++) {
|
|
143
|
+
const block = contentBlocks[i];
|
|
144
|
+
const isAssistantText = block?.type === "text" || block?.type === "thinking";
|
|
145
|
+
const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
|
|
146
|
+
|
|
147
|
+
if (isAssistantText) {
|
|
148
|
+
if (runStart === -1) runStart = i;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (runStart !== -1) {
|
|
153
|
+
segments.push({ kind: "assistant", startIndex: runStart, endIndex: i - 1 });
|
|
154
|
+
runStart = -1;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (isTool) {
|
|
158
|
+
segments.push({ kind: "tool", contentIndex: i });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (runStart !== -1) {
|
|
163
|
+
segments.push({ kind: "assistant", startIndex: runStart, endIndex: contentBlocks.length - 1 });
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return segments;
|
|
167
|
+
}
|
|
168
|
+
|
|
130
169
|
type CompactionQueuedMessage = {
|
|
131
170
|
text: string;
|
|
132
171
|
mode: "steer" | "followUp";
|
|
@@ -2078,6 +2117,7 @@ export class InteractiveMode {
|
|
|
2078
2117
|
}
|
|
2079
2118
|
|
|
2080
2119
|
private addMessageToChat(message: AgentMessage, options?: { populateHistory?: boolean }): void {
|
|
2120
|
+
const timestampFormat = this.settingsManager.getTimestampFormat();
|
|
2081
2121
|
switch (message.role) {
|
|
2082
2122
|
case "bashExecution": {
|
|
2083
2123
|
const component = new BashExecutionComponent(message.command, this.ui, message.excludeFromContext);
|
|
@@ -2135,12 +2175,12 @@ export class InteractiveMode {
|
|
|
2135
2175
|
skillBlock.userMessage,
|
|
2136
2176
|
this.getMarkdownThemeWithSettings(),
|
|
2137
2177
|
message.timestamp,
|
|
2138
|
-
|
|
2178
|
+
timestampFormat,
|
|
2139
2179
|
);
|
|
2140
2180
|
this.chatContainer.addChild(userComponent);
|
|
2141
2181
|
}
|
|
2142
2182
|
} else {
|
|
2143
|
-
const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), message.timestamp,
|
|
2183
|
+
const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), message.timestamp, timestampFormat);
|
|
2144
2184
|
this.chatContainer.addChild(userComponent);
|
|
2145
2185
|
}
|
|
2146
2186
|
if (options?.populateHistory) {
|
|
@@ -2154,7 +2194,7 @@ export class InteractiveMode {
|
|
|
2154
2194
|
message,
|
|
2155
2195
|
this.hideThinkingBlock,
|
|
2156
2196
|
this.getMarkdownThemeWithSettings(),
|
|
2157
|
-
|
|
2197
|
+
timestampFormat,
|
|
2158
2198
|
);
|
|
2159
2199
|
this.chatContainer.addChild(assistantComponent);
|
|
2160
2200
|
break;
|
|
@@ -2192,6 +2232,7 @@ export class InteractiveMode {
|
|
|
2192
2232
|
options: { updateFooter?: boolean; populateHistory?: boolean } = {},
|
|
2193
2233
|
): void {
|
|
2194
2234
|
this.pendingTools.clear();
|
|
2235
|
+
const timestampFormat = this.settingsManager.getTimestampFormat();
|
|
2195
2236
|
|
|
2196
2237
|
if (options.updateFooter) {
|
|
2197
2238
|
this.footer.invalidate();
|
|
@@ -2201,9 +2242,30 @@ export class InteractiveMode {
|
|
|
2201
2242
|
for (const message of sessionContext.messages) {
|
|
2202
2243
|
// Assistant messages need special handling for tool calls
|
|
2203
2244
|
if (message.role === "assistant") {
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2245
|
+
const hasToolBlocks = message.content.some((c) => c.type === "toolCall" || c.type === "serverToolUse");
|
|
2246
|
+
if (!hasToolBlocks) {
|
|
2247
|
+
this.addMessageToChat(message);
|
|
2248
|
+
continue;
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
const assistantSegments: AssistantMessageComponent[] = [];
|
|
2252
|
+
const replaySegments = buildAssistantReplaySegments(message.content);
|
|
2253
|
+
|
|
2254
|
+
for (const segment of replaySegments) {
|
|
2255
|
+
if (segment.kind === "assistant") {
|
|
2256
|
+
const assistantComponent = new AssistantMessageComponent(
|
|
2257
|
+
message,
|
|
2258
|
+
this.hideThinkingBlock,
|
|
2259
|
+
this.getMarkdownThemeWithSettings(),
|
|
2260
|
+
timestampFormat,
|
|
2261
|
+
{ startIndex: segment.startIndex, endIndex: segment.endIndex },
|
|
2262
|
+
);
|
|
2263
|
+
this.chatContainer.addChild(assistantComponent);
|
|
2264
|
+
assistantSegments.push(assistantComponent);
|
|
2265
|
+
continue;
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
const content = message.content[segment.contentIndex];
|
|
2207
2269
|
if (content.type === "toolCall") {
|
|
2208
2270
|
const component = new ToolExecutionComponent(
|
|
2209
2271
|
content.name,
|
|
@@ -2259,6 +2321,11 @@ export class InteractiveMode {
|
|
|
2259
2321
|
}
|
|
2260
2322
|
}
|
|
2261
2323
|
}
|
|
2324
|
+
|
|
2325
|
+
// Match streaming-mode behavior: show metadata once on the final
|
|
2326
|
+
// assistant prose segment for this message.
|
|
2327
|
+
const lastAssistantSegment = assistantSegments[assistantSegments.length - 1];
|
|
2328
|
+
lastAssistantSegment?.setShowMetadata(true);
|
|
2262
2329
|
} else if (message.role === "toolResult") {
|
|
2263
2330
|
// Match tool results to pending tool components
|
|
2264
2331
|
const component = this.pendingTools.get(message.toolCallId);
|