@ashx-j/lunr 0.2.18 → 0.2.20
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/CHANGELOG.md +31 -1
- package/README.md +2 -2
- package/dist/builtin-extensions/ashxj-tui.d.ts +2 -2
- package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.js +11 -8
- package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
- package/dist/builtin-extensions/index.d.ts.map +1 -1
- package/dist/builtin-extensions/index.js +0 -2
- package/dist/builtin-extensions/index.js.map +1 -1
- package/dist/builtin-extensions/pi-intercom/broker/spawn.d.ts +6 -4
- package/dist/builtin-extensions/pi-intercom/broker/spawn.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-intercom/broker/spawn.js +93 -49
- package/dist/builtin-extensions/pi-intercom/broker/spawn.js.map +1 -1
- package/dist/builtin-extensions/pi-intercom/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-intercom/index.js +351 -351
- package/dist/builtin-extensions/pi-intercom/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +2 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +80 -43
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts +18 -8
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +36 -11
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +4 -3
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +21 -12
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts +7 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js +225 -15
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.d.ts +29 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js +179 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts +89 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js +541 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts +9 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +34 -9
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js +1 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts +2 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +35 -8
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js +3 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js +54 -38
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts +3 -6
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js +64 -5
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +21 -8
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +62 -16
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts +2 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js +75 -18
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts +13 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +67 -11
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js +5 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js +13 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts +3 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +68 -11
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts +12 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js +21 -2
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +16 -4
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +2 -0
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +24 -6
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +44 -4
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +227 -133
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.d.ts +2 -13
- package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.js +5 -91
- package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.js.map +1 -1
- package/dist/core/permissions.d.ts +1 -0
- package/dist/core/permissions.d.ts.map +1 -1
- package/dist/core/permissions.js +8 -4
- package/dist/core/permissions.js.map +1 -1
- package/dist/core/plan-mode.d.ts.map +1 -1
- package/dist/core/plan-mode.js +0 -5
- package/dist/core/plan-mode.js.map +1 -1
- package/dist/core/runtime-bridges.d.ts.map +1 -1
- package/dist/core/runtime-bridges.js +0 -2
- package/dist/core/runtime-bridges.js.map +1 -1
- package/dist/core/subagent-cancellation.d.ts +21 -0
- package/dist/core/subagent-cancellation.d.ts.map +1 -0
- package/dist/core/subagent-cancellation.js +53 -0
- package/dist/core/subagent-cancellation.js.map +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +12 -18
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +12 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +29 -22
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/node-runtime/{agent-session-services-35WNVGMR.js → agent-session-services-75JKASCW.js} +3 -3
- package/dist/node-runtime/{builtin-extensions-QATGXENO.js → builtin-extensions-X4JMM4ZS.js} +3 -3
- package/dist/node-runtime/{chunk-XATUM2HK.js → chunk-25I2BHAA.js} +1 -1
- package/dist/node-runtime/{chunk-MCUNIRD5.js → chunk-46ECNOLF.js} +477 -246
- package/dist/node-runtime/{chunk-J26TSGDL.js → chunk-6N22HULO.js} +8 -5
- package/dist/node-runtime/{chunk-NI6OTSBH.js → chunk-AL2FMKKM.js} +7 -7
- package/dist/node-runtime/chunk-AOFXZQKA.js +24 -0
- package/dist/node-runtime/chunk-BBUVIEZB.js +51 -0
- package/dist/node-runtime/{chunk-EBF6COVM.js → chunk-ELWEXVO5.js} +7 -7
- package/dist/node-runtime/{chunk-R5EDISSV.js → chunk-JHYKXIMM.js} +5 -2
- package/dist/node-runtime/{chunk-ATGA2WLC.js → chunk-JYNNB7DU.js} +397 -34
- package/dist/node-runtime/{chunk-ZBV7FAHG.js → chunk-K3646JTM.js} +17 -118
- package/dist/node-runtime/{chunk-PNJSG3IZ.js → chunk-LTYWTR3V.js} +1 -369
- package/dist/node-runtime/{chunk-G4P75AIS.js → chunk-QKFMBRAL.js} +47 -54
- package/dist/node-runtime/cli-runtime.js +1 -1
- package/dist/node-runtime/{command-AAV3YRR5.js → command-RBTRL55A.js} +1 -1
- package/dist/node-runtime/{gateway-OAC4OBBL.js → gateway-L4ANRTVE.js} +2 -2
- package/dist/node-runtime/index.js +10 -9
- package/dist/node-runtime/{interactive-mode-2SZUO53H.js → interactive-mode-HPUNH7SV.js} +5 -4
- package/dist/node-runtime/{interactive-view-S6J3QHEF.js → interactive-view-ILS6TAN5.js} +1 -1
- package/dist/node-runtime/{lunr-cron-AUUYP4N4.js → lunr-cron-NNYTWTGF.js} +2 -2
- package/dist/node-runtime/main.js +8 -8
- package/dist/node-runtime/{pi-intercom-EEMBGQID.js → pi-intercom-DDQMRNPJ.js} +96 -76
- package/dist/node-runtime/{pi-subagents-7YJ3I4VE.js → pi-subagents-T5WMMLBB.js} +1040 -318
- package/dist/node-runtime/rpc-entry.js +8 -8
- package/dist/node-runtime/{runtime-bridges-3RKBDLNA.js → runtime-bridges-NJQERQ72.js} +2 -4
- package/dist/node-runtime/{subagent-executor-5Q5A4HJ2.js → subagent-executor-SRFC26SJ.js} +168 -249
- package/docs/features.md +17 -3
- package/docs/keybindings.md +3 -1
- package/docs/settings.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
- package/dist/builtin-extensions/lunr-settings-tools.d.ts +0 -4
- package/dist/builtin-extensions/lunr-settings-tools.d.ts.map +0 -1
- package/dist/builtin-extensions/lunr-settings-tools.js +0 -120
- package/dist/builtin-extensions/lunr-settings-tools.js.map +0 -1
- package/dist/core/settings-tools-bridge.d.ts +0 -35
- package/dist/core/settings-tools-bridge.d.ts.map +0 -1
- package/dist/core/settings-tools-bridge.js +0 -56
- package/dist/core/settings-tools-bridge.js.map +0 -1
- package/dist/modes/interactive/injected-context.d.ts +0 -2
- package/dist/modes/interactive/injected-context.d.ts.map +0 -1
- package/dist/modes/interactive/injected-context.js +0 -7
- package/dist/modes/interactive/injected-context.js.map +0 -1
- package/dist/node-runtime/chunk-3NMWLTPV.js +0 -64
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-bridges.d.ts","sourceRoot":"","sources":["../../src/core/runtime-bridges.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-bridges.d.ts","sourceRoot":"","sources":["../../src/core/runtime-bridges.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,4BAA4B,CAAC;AAMlF,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,EAClC,OAAO,EACP,QAAQ,EACR,EAAE,IAAI,CAAC,+BAA+B,EAAE,SAAS,GAAG,UAAU,CAAC,GAAG,IAAI,CAOtE","sourcesContent":["import type { CreateAgentSessionRuntimeResult } from \"./agent-session-runtime.ts\";\nimport { registerCustomizeBridge } from \"./customize.ts\";\nimport { registerMemoryCapBridge } from \"./memory-cap.ts\";\nimport { getModelTiersBridge, registerModelTierBridge } from \"./model-tiers.ts\";\nimport { registerUsageServiceBridge } from \"./usage-service.ts\";\n\n/** Re-point every settings-backed process-global bridge at the applied runtime. */\nexport function bindRuntimeBridges({\n\tsession,\n\tservices,\n}: Pick<CreateAgentSessionRuntimeResult, \"session\" | \"services\">): void {\n\tconst { settingsManager, modelRuntime } = services;\n\tregisterModelTierBridge(settingsManager);\n\tgetModelTiersBridge()?.setParentThinkingProvider(() => session.thinkingLevel);\n\tregisterMemoryCapBridge(settingsManager);\n\tregisterCustomizeBridge(settingsManager);\n\tregisterUsageServiceBridge(modelRuntime, settingsManager);\n}\n"]}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { registerCustomizeBridge } from "./customize.js";
|
|
2
2
|
import { registerMemoryCapBridge } from "./memory-cap.js";
|
|
3
3
|
import { getModelTiersBridge, registerModelTierBridge } from "./model-tiers.js";
|
|
4
|
-
import { registerSettingsToolsBridge } from "./settings-tools-bridge.js";
|
|
5
4
|
import { registerUsageServiceBridge } from "./usage-service.js";
|
|
6
5
|
/** Re-point every settings-backed process-global bridge at the applied runtime. */
|
|
7
6
|
export function bindRuntimeBridges({ session, services, }) {
|
|
@@ -11,6 +10,5 @@ export function bindRuntimeBridges({ session, services, }) {
|
|
|
11
10
|
registerMemoryCapBridge(settingsManager);
|
|
12
11
|
registerCustomizeBridge(settingsManager);
|
|
13
12
|
registerUsageServiceBridge(modelRuntime, settingsManager);
|
|
14
|
-
registerSettingsToolsBridge(settingsManager, () => session.sessionId);
|
|
15
13
|
}
|
|
16
14
|
//# sourceMappingURL=runtime-bridges.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-bridges.js","sourceRoot":"","sources":["../../src/core/runtime-bridges.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"runtime-bridges.js","sourceRoot":"","sources":["../../src/core/runtime-bridges.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAEhE,mFAAmF;AACnF,MAAM,UAAU,kBAAkB,CAAC,EAClC,OAAO,EACP,QAAQ,GACuD,EAAQ;IACvE,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,QAAQ,CAAC;IACnD,uBAAuB,CAAC,eAAe,CAAC,CAAC;IACzC,mBAAmB,EAAE,EAAE,yBAAyB,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC9E,uBAAuB,CAAC,eAAe,CAAC,CAAC;IACzC,uBAAuB,CAAC,eAAe,CAAC,CAAC;IACzC,0BAA0B,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;AAAA,CAC1D","sourcesContent":["import type { CreateAgentSessionRuntimeResult } from \"./agent-session-runtime.ts\";\nimport { registerCustomizeBridge } from \"./customize.ts\";\nimport { registerMemoryCapBridge } from \"./memory-cap.ts\";\nimport { getModelTiersBridge, registerModelTierBridge } from \"./model-tiers.ts\";\nimport { registerUsageServiceBridge } from \"./usage-service.ts\";\n\n/** Re-point every settings-backed process-global bridge at the applied runtime. */\nexport function bindRuntimeBridges({\n\tsession,\n\tservices,\n}: Pick<CreateAgentSessionRuntimeResult, \"session\" | \"services\">): void {\n\tconst { settingsManager, modelRuntime } = services;\n\tregisterModelTierBridge(settingsManager);\n\tgetModelTiersBridge()?.setParentThinkingProvider(() => session.thinkingLevel);\n\tregisterMemoryCapBridge(settingsManager);\n\tregisterCustomizeBridge(settingsManager);\n\tregisterUsageServiceBridge(modelRuntime, settingsManager);\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface SubagentCancellation {
|
|
2
|
+
hasActiveRuns(): boolean;
|
|
3
|
+
stop(): Promise<{
|
|
4
|
+
requested: number;
|
|
5
|
+
failed: number;
|
|
6
|
+
}>;
|
|
7
|
+
}
|
|
8
|
+
export declare function registerSubagentCancellation(sessionId: string, handler: SubagentCancellation): () => void;
|
|
9
|
+
export declare function getSubagentCancellation(sessionId: string): SubagentCancellation | undefined;
|
|
10
|
+
export declare function createSubagentCancellation(options: {
|
|
11
|
+
pendingLaunches: ReadonlySet<Promise<void>>;
|
|
12
|
+
getActiveRunIds(): string[];
|
|
13
|
+
isCurrent(): boolean;
|
|
14
|
+
stopRun(id: string): Promise<boolean>;
|
|
15
|
+
}): SubagentCancellation;
|
|
16
|
+
export declare class SubagentEscapeSequence {
|
|
17
|
+
private sessionId;
|
|
18
|
+
private firstPress;
|
|
19
|
+
press(sessionId: string, active: boolean, now?: number): "parent" | "children" | undefined;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=subagent-cancellation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-cancellation.d.ts","sourceRoot":"","sources":["../../src/core/subagent-cancellation.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACpC,aAAa,IAAI,OAAO,CAAC;IACzB,IAAI,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvD;AAOD,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,MAAM,IAAI,CAKzG;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAE3F;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE;IACnD,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,eAAe,IAAI,MAAM,EAAE,CAAC;IAC5B,SAAS,IAAI,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtC,GAAG,oBAAoB,CAqBvB;AAED,qBAAa,sBAAsB;IAClC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,UAAU,CAAqB;IAEvC,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,SAAa,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAU7F;CACD","sourcesContent":["export interface SubagentCancellation {\n\thasActiveRuns(): boolean;\n\tstop(): Promise<{ requested: number; failed: number }>;\n}\n\nconst key = Symbol.for(\"@lunr/subagent-cancellation\");\nconst store = globalThis as typeof globalThis & { [key]?: Map<string, SubagentCancellation> };\nconst handlers = store[key] ?? new Map<string, SubagentCancellation>();\nstore[key] = handlers;\n\nexport function registerSubagentCancellation(sessionId: string, handler: SubagentCancellation): () => void {\n\thandlers.set(sessionId, handler);\n\treturn () => {\n\t\tif (handlers.get(sessionId) === handler) handlers.delete(sessionId);\n\t};\n}\n\nexport function getSubagentCancellation(sessionId: string): SubagentCancellation | undefined {\n\treturn handlers.get(sessionId);\n}\n\nexport function createSubagentCancellation(options: {\n\tpendingLaunches: ReadonlySet<Promise<void>>;\n\tgetActiveRunIds(): string[];\n\tisCurrent(): boolean;\n\tstopRun(id: string): Promise<boolean>;\n}): SubagentCancellation {\n\tlet stopping: Promise<{ requested: number; failed: number }> | undefined;\n\treturn {\n\t\thasActiveRuns: () =>\n\t\t\toptions.isCurrent() && (options.pendingLaunches.size > 0 || options.getActiveRunIds().length > 0),\n\t\tstop() {\n\t\t\tif (stopping) return stopping;\n\t\t\tstopping = (async () => {\n\t\t\t\tawait Promise.allSettled([...options.pendingLaunches]);\n\t\t\t\tif (!options.isCurrent()) return { requested: 0, failed: 0 };\n\t\t\t\tconst results = await Promise.allSettled(options.getActiveRunIds().map((id) => options.stopRun(id)));\n\t\t\t\treturn {\n\t\t\t\t\trequested: results.filter((result) => result.status === \"fulfilled\" && result.value).length,\n\t\t\t\t\tfailed: results.filter((result) => result.status === \"rejected\" || !result.value).length,\n\t\t\t\t};\n\t\t\t})().finally(() => {\n\t\t\t\tstopping = undefined;\n\t\t\t});\n\t\t\treturn stopping;\n\t\t},\n\t};\n}\n\nexport class SubagentEscapeSequence {\n\tprivate sessionId: string | undefined;\n\tprivate firstPress: number | undefined;\n\n\tpress(sessionId: string, active: boolean, now = Date.now()): \"parent\" | \"children\" | undefined {\n\t\tif (!active) {\n\t\t\tthis.firstPress = undefined;\n\t\t\tthis.sessionId = undefined;\n\t\t\treturn undefined;\n\t\t}\n\t\tconst second = this.sessionId === sessionId && this.firstPress !== undefined && now - this.firstPress < 500;\n\t\tthis.sessionId = sessionId;\n\t\tthis.firstPress = second ? undefined : now;\n\t\treturn second ? \"children\" : \"parent\";\n\t}\n}\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const key = Symbol.for("@lunr/subagent-cancellation");
|
|
2
|
+
const store = globalThis;
|
|
3
|
+
const handlers = store[key] ?? new Map();
|
|
4
|
+
store[key] = handlers;
|
|
5
|
+
export function registerSubagentCancellation(sessionId, handler) {
|
|
6
|
+
handlers.set(sessionId, handler);
|
|
7
|
+
return () => {
|
|
8
|
+
if (handlers.get(sessionId) === handler)
|
|
9
|
+
handlers.delete(sessionId);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function getSubagentCancellation(sessionId) {
|
|
13
|
+
return handlers.get(sessionId);
|
|
14
|
+
}
|
|
15
|
+
export function createSubagentCancellation(options) {
|
|
16
|
+
let stopping;
|
|
17
|
+
return {
|
|
18
|
+
hasActiveRuns: () => options.isCurrent() && (options.pendingLaunches.size > 0 || options.getActiveRunIds().length > 0),
|
|
19
|
+
stop() {
|
|
20
|
+
if (stopping)
|
|
21
|
+
return stopping;
|
|
22
|
+
stopping = (async () => {
|
|
23
|
+
await Promise.allSettled([...options.pendingLaunches]);
|
|
24
|
+
if (!options.isCurrent())
|
|
25
|
+
return { requested: 0, failed: 0 };
|
|
26
|
+
const results = await Promise.allSettled(options.getActiveRunIds().map((id) => options.stopRun(id)));
|
|
27
|
+
return {
|
|
28
|
+
requested: results.filter((result) => result.status === "fulfilled" && result.value).length,
|
|
29
|
+
failed: results.filter((result) => result.status === "rejected" || !result.value).length,
|
|
30
|
+
};
|
|
31
|
+
})().finally(() => {
|
|
32
|
+
stopping = undefined;
|
|
33
|
+
});
|
|
34
|
+
return stopping;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export class SubagentEscapeSequence {
|
|
39
|
+
sessionId;
|
|
40
|
+
firstPress;
|
|
41
|
+
press(sessionId, active, now = Date.now()) {
|
|
42
|
+
if (!active) {
|
|
43
|
+
this.firstPress = undefined;
|
|
44
|
+
this.sessionId = undefined;
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const second = this.sessionId === sessionId && this.firstPress !== undefined && now - this.firstPress < 500;
|
|
48
|
+
this.sessionId = sessionId;
|
|
49
|
+
this.firstPress = second ? undefined : now;
|
|
50
|
+
return second ? "children" : "parent";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=subagent-cancellation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-cancellation.js","sourceRoot":"","sources":["../../src/core/subagent-cancellation.ts"],"names":[],"mappings":"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","sourcesContent":["export interface SubagentCancellation {\n\thasActiveRuns(): boolean;\n\tstop(): Promise<{ requested: number; failed: number }>;\n}\n\nconst key = Symbol.for(\"@lunr/subagent-cancellation\");\nconst store = globalThis as typeof globalThis & { [key]?: Map<string, SubagentCancellation> };\nconst handlers = store[key] ?? new Map<string, SubagentCancellation>();\nstore[key] = handlers;\n\nexport function registerSubagentCancellation(sessionId: string, handler: SubagentCancellation): () => void {\n\thandlers.set(sessionId, handler);\n\treturn () => {\n\t\tif (handlers.get(sessionId) === handler) handlers.delete(sessionId);\n\t};\n}\n\nexport function getSubagentCancellation(sessionId: string): SubagentCancellation | undefined {\n\treturn handlers.get(sessionId);\n}\n\nexport function createSubagentCancellation(options: {\n\tpendingLaunches: ReadonlySet<Promise<void>>;\n\tgetActiveRunIds(): string[];\n\tisCurrent(): boolean;\n\tstopRun(id: string): Promise<boolean>;\n}): SubagentCancellation {\n\tlet stopping: Promise<{ requested: number; failed: number }> | undefined;\n\treturn {\n\t\thasActiveRuns: () =>\n\t\t\toptions.isCurrent() && (options.pendingLaunches.size > 0 || options.getActiveRunIds().length > 0),\n\t\tstop() {\n\t\t\tif (stopping) return stopping;\n\t\t\tstopping = (async () => {\n\t\t\t\tawait Promise.allSettled([...options.pendingLaunches]);\n\t\t\t\tif (!options.isCurrent()) return { requested: 0, failed: 0 };\n\t\t\t\tconst results = await Promise.allSettled(options.getActiveRunIds().map((id) => options.stopRun(id)));\n\t\t\t\treturn {\n\t\t\t\t\trequested: results.filter((result) => result.status === \"fulfilled\" && result.value).length,\n\t\t\t\t\tfailed: results.filter((result) => result.status === \"rejected\" || !result.value).length,\n\t\t\t\t};\n\t\t\t})().finally(() => {\n\t\t\t\tstopping = undefined;\n\t\t\t});\n\t\t\treturn stopping;\n\t\t},\n\t};\n}\n\nexport class SubagentEscapeSequence {\n\tprivate sessionId: string | undefined;\n\tprivate firstPress: number | undefined;\n\n\tpress(sessionId: string, active: boolean, now = Date.now()): \"parent\" | \"children\" | undefined {\n\t\tif (!active) {\n\t\t\tthis.firstPress = undefined;\n\t\t\tthis.sessionId = undefined;\n\t\t\treturn undefined;\n\t\t}\n\t\tconst second = this.sessionId === sessionId && this.firstPress !== undefined && now - this.firstPress < 500;\n\t\tthis.sessionId = sessionId;\n\t\tthis.firstPress = second ? undefined : now;\n\t\treturn second ? \"children\" : \"parent\";\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAkB,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AAE/G,OAAO,EAGN,KAAK,iBAAiB,EAEtB,MAAM,uBAAuB,CAAC;AAO/B;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,UAAU,UAAQ;IAClB,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IAGnC,OAAO,CAAC,gBAAgB,CAAU;IAElC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAAqB;IAGzC,OAAO,CAAC,eAAe,CAAC,CAAsB;IAC9C,OAAO,CAAC,aAAa,CAAgB;IAGrC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,cAAc,CAAC,CAAmB;IAC1C,OAAO,CAAC,YAAY,CAAS;IAE7B,YACC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,mBAAmB,SAAgB,EACnC,SAAS,SAAI,EACb,gBAAgB,UAAQ,EAiBxB;IAEQ,UAAU,IAAI,IAAI,CAK1B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAKxC;IAGD,mBAAmB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAK3C;IAGD,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAMnC;IAED,OAAO,CAAC,aAAa;IAIrB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAgBxC;IAED,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAclD;IAED,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,SAAS,GAAG,IAAI,CAEjE;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAK1C;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKlC;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQvC;IAED,OAAO,CAAC,qBAAqB;IAI7B,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,gBAAgB,CAAA;KAAE,GAAG,IAAI,CAwG9F;IAED,OAAO,CAAC,iBAAiB;CA6DzB","sourcesContent":["import type { AssistantMessage } from \"@ashx-j/lunr-ai\";\nimport { type Component, Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@ashx-j/lunr-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport {\n\tformatThoughtDuration,\n\tisThinkingRunComplete,\n\ttype ThinkingRunTiming,\n\tthinkingSnippet,\n} from \"./thinking-summary.ts\";\nimport { ThinkingTailComponent } from \"./thinking-tail.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tselectable = true;\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\t// lunr: collapsible reasoning — when true, a completed thinking run renders as\n\t// \"✻ Thought for Xs\" + its first sentence instead of the full block.\n\tprivate thinkingCollapse: boolean;\n\t// lunr: per-run expand. `expanded` still means \"all runs\" for setExpanded().\n\tprivate expanded = false;\n\tprivate expandedRuns = new Set<number>();\n\t// lunr: live per-run timings from interactive-mode; undefined = history message\n\t// (always treated as final, rendered without durations).\n\tprivate thinkingTimings?: ThinkingRunTiming[];\n\tprivate markdownTheme: MarkdownTheme;\n\t// lunr: kept for the deferred alternative hidden-thinking indicator (Phase 8 removed the label render).\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: retained for future use\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate thinkingSource?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tthinkingCollapse = false,\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.thinkingCollapse = thinkingCollapse;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\t// lunr: collapsible reasoning toggles (live; re-render like setHideThinkingBlock).\n\tsetThinkingCollapse(collapse: boolean): void {\n\t\tthis.thinkingCollapse = collapse;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\t// lunr: Expandable hook; true expands every thinking run, false collapses all.\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tif (!expanded) this.expandedRuns.clear();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tprivate isRunExpanded(runIndex: number): boolean {\n\t\treturn this.expanded || this.expandedRuns.has(runIndex);\n\t}\n\n\ttoggleThinkingRun(runIndex: number): void {\n\t\tif (this.expanded) {\n\t\t\tthis.expanded = false;\n\t\t\tthis.expandedRuns.clear();\n\t\t\tconst count = this.lastMessage ? collectThinkingRuns(this.lastMessage.content).length : 0;\n\t\t\tfor (let i = 0; i < count; i++) {\n\t\t\t\tif (i !== runIndex) this.expandedRuns.add(i);\n\t\t\t}\n\t\t} else if (this.expandedRuns.has(runIndex)) {\n\t\t\tthis.expandedRuns.delete(runIndex);\n\t\t} else {\n\t\t\tthis.expandedRuns.add(runIndex);\n\t\t}\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\thandleClick(localY: number, width: number): boolean {\n\t\tconst contentWidth = width;\n\t\tlet y = 0;\n\t\tfor (const child of this.contentContainer.children) {\n\t\t\tconst h = child.render(contentWidth).length;\n\t\t\tif (localY >= y && localY < y + h) {\n\t\t\t\tif (typeof child.handleClick === \"function\") {\n\t\t\t\t\treturn child.handleClick(localY - y, contentWidth);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\ty += h;\n\t\t}\n\t\treturn false;\n\t}\n\n\tsetThinkingTimings(timings: ThinkingRunTiming[] | undefined): void {\n\t\tthis.thinkingTimings = timings;\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) return lines;\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\n\t\treturn lines;\n\t}\n\n\tprivate thinkingSourceOptions(): { thinkingSource?: AssistantMessage } | undefined {\n\t\treturn this.thinkingSource ? { thinkingSource: this.thinkingSource } : undefined;\n\t}\n\n\tupdateContent(message: AssistantMessage, options?: { thinkingSource?: AssistantMessage }): void {\n\t\tthis.lastMessage = message;\n\t\tthis.thinkingSource = options?.thinkingSource;\n\n\t\t// Clear content container\n\t\tthis.contentContainer.clear();\n\n\t\tconst sourceMessage = this.thinkingSource ?? message;\n\t\tconst sourceThinkingRuns = collectThinkingRuns(sourceMessage.content);\n\t\tconst hasVisibleContent =\n\t\t\tmessage.content.some(\n\t\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t\t) ||\n\t\t\t(!this.hideThinkingBlock && sourceThinkingRuns.some((run) => run.length > 0));\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tlet isFirstTextBlock = true;\n\t\tlet thinkingRunIndex = -1;\n\t\tlet renderedThinking = false;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\t// lunr: leading ● marks the first text block (never thinking blocks). It rides\n\t\t\t\t// the defaultTextStyle below, so it renders bright white like the body.\n\t\t\t\tconst trimmed = content.text.trim();\n\t\t\t\tconst text = isFirstTextBlock ? `● ${trimmed}` : trimmed;\n\t\t\t\tisFirstTextBlock = false;\n\t\t\t\t// lunr: theme-polish — assistant message body renders bright white via the\n\t\t\t\t// shared userMessageText token (same knob as user messages).\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(text, this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (body: string) => theme.fg(\"userMessageText\", body),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tthinkingRunIndex++;\n\t\t\t\tconst displayBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tdisplayBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tconst thinkingBlocks = sourceThinkingRuns[thinkingRunIndex] ?? displayBlocks;\n\t\t\t\tif (thinkingBlocks.length === 0 || this.hideThinkingBlock) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\trenderedThinking = true;\n\t\t\t\tthis.renderThinkingRun(thinkingRunIndex, thinkingBlocks, message, i);\n\t\t\t}\n\t\t}\n\n\t\tif (!this.hideThinkingBlock && !renderedThinking && sourceThinkingRuns.length > 0) {\n\t\t\tthinkingRunIndex = 0;\n\t\t\tconst thinkingBlocks = sourceThinkingRuns[0] ?? [];\n\t\t\tif (thinkingBlocks.length > 0) {\n\t\t\t\tthis.renderThinkingRun(thinkingRunIndex, thinkingBlocks, message, -1);\n\t\t\t}\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t\tif (message.stopReason === \"length\") {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\"Error: Model stopped because it reached the maximum output token limit. The response may be incomplete.\",\n\t\t\t\t\t),\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), this.outputPad, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), this.outputPad, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate renderThinkingRun(\n\t\tthinkingRunIndex: number,\n\t\tthinkingBlocks: string[],\n\t\tdisplayMessage: AssistantMessage,\n\t\tdisplayIndex: number,\n\t): void {\n\t\tconst hasVisibleContentAfter =\n\t\t\tdisplayIndex >= 0\n\t\t\t\t? displayMessage.content\n\t\t\t\t\t\t.slice(displayIndex + 1)\n\t\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()))\n\t\t\t\t: displayMessage.content.some((c) => c.type === \"text\" && c.text.trim());\n\n\t\tconst runComplete = isThinkingRunComplete(\n\t\t\tfalse,\n\t\t\tthis.thinkingTimings?.[thinkingRunIndex],\n\t\t\tthis.thinkingTimings !== undefined,\n\t\t);\n\t\tconst wrap = (inner: Component): void => {\n\t\t\tthis.contentContainer.addChild(new ThinkingRunBlock(this, thinkingRunIndex, inner));\n\t\t};\n\t\tif (this.thinkingCollapse && !this.isRunExpanded(thinkingRunIndex) && runComplete) {\n\t\t\tconst timing = this.thinkingTimings?.[thinkingRunIndex];\n\t\t\tconst label =\n\t\t\t\ttiming?.end !== undefined\n\t\t\t\t\t? `✻ Thought for ${formatThoughtDuration(timing.end - timing.start)}`\n\t\t\t\t\t: \"✻ Thought\";\n\t\t\tconst block = new Container();\n\t\t\tblock.addChild(new Text(theme.fg(\"thinkingText\", theme.italic(label)), this.outputPad, 0));\n\t\t\tconst snippet = thinkingSnippet(thinkingBlocks.join(\"\\n\\n\"));\n\t\t\tif (snippet) {\n\t\t\t\tblock.addChild(new Text(theme.fg(\"thinkingText\", theme.italic(snippet)), this.outputPad + 2, 0));\n\t\t\t}\n\t\t\twrap(block);\n\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!runComplete && !this.isRunExpanded(thinkingRunIndex)) {\n\t\t\twrap(\n\t\t\t\tnew ThinkingTailComponent(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\titalic: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\twrap(\n\t\t\tnew Markdown(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\titalic: true,\n\t\t\t}),\n\t\t);\n\t\tif (hasVisibleContentAfter) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\t}\n}\n\nclass ThinkingRunBlock extends Container {\n\tprivate readonly owner: AssistantMessageComponent;\n\tprivate readonly runIndex: number;\n\n\tconstructor(owner: AssistantMessageComponent, runIndex: number, inner: Component) {\n\t\tsuper();\n\t\tthis.owner = owner;\n\t\tthis.runIndex = runIndex;\n\t\tthis.addChild(inner);\n\t}\n\n\thandleClick(_localY: number, _width: number): boolean {\n\t\tthis.owner.toggleThinkingRun(this.runIndex);\n\t\treturn true;\n\t}\n}\n\nfunction collectThinkingRuns(content: AssistantMessage[\"content\"]): string[][] {\n\tconst runs: string[][] = [];\n\tfor (let i = 0; i < content.length; i++) {\n\t\tconst block = content[i];\n\t\tif (block.type !== \"thinking\") continue;\n\t\tconst blocks: string[] = [];\n\t\tfor (; i < content.length; i++) {\n\t\t\tconst thinkingContent = content[i];\n\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\ti--;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\tif (thinking) blocks.push(thinking);\n\t\t}\n\t\tif (blocks.length > 0) runs.push(blocks);\n\t}\n\treturn runs;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAkB,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AAE/G,OAAO,EAGN,KAAK,iBAAiB,EAEtB,MAAM,uBAAuB,CAAC;AAO/B;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,UAAU,UAAQ;IAClB,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IAGnC,OAAO,CAAC,gBAAgB,CAAU;IAElC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAAqB;IAGzC,OAAO,CAAC,eAAe,CAAC,CAAsB;IAC9C,OAAO,CAAC,aAAa,CAAgB;IAGrC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,cAAc,CAAC,CAAmB;IAC1C,OAAO,CAAC,YAAY,CAAS;IAE7B,YACC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,mBAAmB,SAAgB,EACnC,SAAS,SAAI,EACb,gBAAgB,UAAQ,EAiBxB;IAEQ,UAAU,IAAI,IAAI,CAK1B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAKxC;IAGD,mBAAmB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAK3C;IAGD,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAMnC;IAED,OAAO,CAAC,aAAa;IAIrB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAgBxC;IAED,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAclD;IAED,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,SAAS,GAAG,IAAI,CAEjE;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAK1C;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKlC;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQvC;IAED,OAAO,CAAC,qBAAqB;IAI7B,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,gBAAgB,CAAA;KAAE,GAAG,IAAI,CAiG9F;IAED,OAAO,CAAC,iBAAiB;CA6DzB","sourcesContent":["import type { AssistantMessage } from \"@ashx-j/lunr-ai\";\nimport { type Component, Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@ashx-j/lunr-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport {\n\tformatThoughtDuration,\n\tisThinkingRunComplete,\n\ttype ThinkingRunTiming,\n\tthinkingSnippet,\n} from \"./thinking-summary.ts\";\nimport { ThinkingTailComponent } from \"./thinking-tail.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tselectable = true;\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\t// lunr: collapsible reasoning — when true, a completed thinking run renders as\n\t// \"✻ Thought for Xs\" + its first sentence instead of the full block.\n\tprivate thinkingCollapse: boolean;\n\t// lunr: per-run expand. `expanded` still means \"all runs\" for setExpanded().\n\tprivate expanded = false;\n\tprivate expandedRuns = new Set<number>();\n\t// lunr: live per-run timings from interactive-mode; undefined = history message\n\t// (always treated as final, rendered without durations).\n\tprivate thinkingTimings?: ThinkingRunTiming[];\n\tprivate markdownTheme: MarkdownTheme;\n\t// lunr: kept for the deferred alternative hidden-thinking indicator (Phase 8 removed the label render).\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: retained for future use\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate thinkingSource?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tthinkingCollapse = false,\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.thinkingCollapse = thinkingCollapse;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\t// lunr: collapsible reasoning toggles (live; re-render like setHideThinkingBlock).\n\tsetThinkingCollapse(collapse: boolean): void {\n\t\tthis.thinkingCollapse = collapse;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\t// lunr: Expandable hook; true expands every thinking run, false collapses all.\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tif (!expanded) this.expandedRuns.clear();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tprivate isRunExpanded(runIndex: number): boolean {\n\t\treturn this.expanded || this.expandedRuns.has(runIndex);\n\t}\n\n\ttoggleThinkingRun(runIndex: number): void {\n\t\tif (this.expanded) {\n\t\t\tthis.expanded = false;\n\t\t\tthis.expandedRuns.clear();\n\t\t\tconst count = this.lastMessage ? collectThinkingRuns(this.lastMessage.content).length : 0;\n\t\t\tfor (let i = 0; i < count; i++) {\n\t\t\t\tif (i !== runIndex) this.expandedRuns.add(i);\n\t\t\t}\n\t\t} else if (this.expandedRuns.has(runIndex)) {\n\t\t\tthis.expandedRuns.delete(runIndex);\n\t\t} else {\n\t\t\tthis.expandedRuns.add(runIndex);\n\t\t}\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\thandleClick(localY: number, width: number): boolean {\n\t\tconst contentWidth = width;\n\t\tlet y = 0;\n\t\tfor (const child of this.contentContainer.children) {\n\t\t\tconst h = child.render(contentWidth).length;\n\t\t\tif (localY >= y && localY < y + h) {\n\t\t\t\tif (typeof child.handleClick === \"function\") {\n\t\t\t\t\treturn child.handleClick(localY - y, contentWidth);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\ty += h;\n\t\t}\n\t\treturn false;\n\t}\n\n\tsetThinkingTimings(timings: ThinkingRunTiming[] | undefined): void {\n\t\tthis.thinkingTimings = timings;\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) return lines;\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\n\t\treturn lines;\n\t}\n\n\tprivate thinkingSourceOptions(): { thinkingSource?: AssistantMessage } | undefined {\n\t\treturn this.thinkingSource ? { thinkingSource: this.thinkingSource } : undefined;\n\t}\n\n\tupdateContent(message: AssistantMessage, options?: { thinkingSource?: AssistantMessage }): void {\n\t\tthis.lastMessage = message;\n\t\tthis.thinkingSource = options?.thinkingSource;\n\n\t\t// Clear content container\n\t\tthis.contentContainer.clear();\n\n\t\tconst sourceMessage = this.thinkingSource ?? message;\n\t\tconst sourceThinkingRuns = collectThinkingRuns(sourceMessage.content);\n\t\tconst hasVisibleContent = message.content.some(\n\t\t\t(c) =>\n\t\t\t\t(c.type === \"text\" && c.text.trim()) ||\n\t\t\t\t(!this.hideThinkingBlock && c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tlet isFirstTextBlock = true;\n\t\tlet thinkingRunIndex = -1;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\t// lunr: leading ● marks the first text block (never thinking blocks). It rides\n\t\t\t\t// the defaultTextStyle below, so it renders bright white like the body.\n\t\t\t\tconst trimmed = content.text.trim();\n\t\t\t\tconst text = isFirstTextBlock ? `● ${trimmed}` : trimmed;\n\t\t\t\tisFirstTextBlock = false;\n\t\t\t\t// lunr: theme-polish — assistant message body renders bright white via the\n\t\t\t\t// shared userMessageText token (same knob as user messages).\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(text, this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (body: string) => theme.fg(\"userMessageText\", body),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tthinkingRunIndex++;\n\t\t\t\tconst displayBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tdisplayBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (displayBlocks.length === 0 || this.hideThinkingBlock) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst sourceBlocks = sourceThinkingRuns[thinkingRunIndex] ?? [];\n\t\t\t\tconst fullyRevealed =\n\t\t\t\t\tdisplayBlocks.length === sourceBlocks.length &&\n\t\t\t\t\tdisplayBlocks.every((block, index) => block === sourceBlocks[index]);\n\t\t\t\tthis.renderThinkingRun(thinkingRunIndex, displayBlocks, message, i, fullyRevealed);\n\t\t\t}\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t\tif (message.stopReason === \"length\") {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\"Error: Model stopped because it reached the maximum output token limit. The response may be incomplete.\",\n\t\t\t\t\t),\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), this.outputPad, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), this.outputPad, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate renderThinkingRun(\n\t\tthinkingRunIndex: number,\n\t\tthinkingBlocks: string[],\n\t\tdisplayMessage: AssistantMessage,\n\t\tdisplayIndex: number,\n\t\tfullyRevealed: boolean,\n\t): void {\n\t\tconst hasVisibleContentAfter =\n\t\t\tdisplayIndex >= 0\n\t\t\t\t? displayMessage.content\n\t\t\t\t\t\t.slice(displayIndex + 1)\n\t\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()))\n\t\t\t\t: displayMessage.content.some((c) => c.type === \"text\" && c.text.trim());\n\n\t\t// Provider completion can precede the reveal cursor; keep animating until it catches up.\n\t\tconst runComplete =\n\t\t\tfullyRevealed &&\n\t\t\tisThinkingRunComplete(false, this.thinkingTimings?.[thinkingRunIndex], this.thinkingTimings !== undefined);\n\t\tconst wrap = (inner: Component): void => {\n\t\t\tthis.contentContainer.addChild(new ThinkingRunBlock(this, thinkingRunIndex, inner));\n\t\t};\n\t\tif (this.thinkingCollapse && !this.isRunExpanded(thinkingRunIndex) && runComplete) {\n\t\t\tconst timing = this.thinkingTimings?.[thinkingRunIndex];\n\t\t\tconst label =\n\t\t\t\ttiming?.end !== undefined\n\t\t\t\t\t? `✻ Thought for ${formatThoughtDuration(timing.end - timing.start)}`\n\t\t\t\t\t: \"✻ Thought\";\n\t\t\tconst block = new Container();\n\t\t\tblock.addChild(new Text(theme.fg(\"thinkingText\", theme.italic(label)), this.outputPad, 0));\n\t\t\tconst snippet = thinkingSnippet(thinkingBlocks.join(\"\\n\\n\"));\n\t\t\tif (snippet) {\n\t\t\t\tblock.addChild(new Text(theme.fg(\"thinkingText\", theme.italic(snippet)), this.outputPad + 2, 0));\n\t\t\t}\n\t\t\twrap(block);\n\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!runComplete && !this.isRunExpanded(thinkingRunIndex)) {\n\t\t\twrap(\n\t\t\t\tnew ThinkingTailComponent(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\titalic: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\twrap(\n\t\t\tnew Markdown(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\titalic: true,\n\t\t\t}),\n\t\t);\n\t\tif (hasVisibleContentAfter) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\t}\n}\n\nclass ThinkingRunBlock extends Container {\n\tprivate readonly owner: AssistantMessageComponent;\n\tprivate readonly runIndex: number;\n\n\tconstructor(owner: AssistantMessageComponent, runIndex: number, inner: Component) {\n\t\tsuper();\n\t\tthis.owner = owner;\n\t\tthis.runIndex = runIndex;\n\t\tthis.addChild(inner);\n\t}\n\n\thandleClick(_localY: number, _width: number): boolean {\n\t\tthis.owner.toggleThinkingRun(this.runIndex);\n\t\treturn true;\n\t}\n}\n\nfunction collectThinkingRuns(content: AssistantMessage[\"content\"]): string[][] {\n\tconst runs: string[][] = [];\n\tfor (let i = 0; i < content.length; i++) {\n\t\tconst block = content[i];\n\t\tif (block.type !== \"thinking\") continue;\n\t\tconst blocks: string[] = [];\n\t\tfor (; i < content.length; i++) {\n\t\t\tconst thinkingContent = content[i];\n\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\ti--;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\tif (thinking) blocks.push(thinking);\n\t\t}\n\t\truns.push(blocks);\n\t}\n\treturn runs;\n}\n"]}
|
|
@@ -142,15 +142,14 @@ export class AssistantMessageComponent extends Container {
|
|
|
142
142
|
this.contentContainer.clear();
|
|
143
143
|
const sourceMessage = this.thinkingSource ?? message;
|
|
144
144
|
const sourceThinkingRuns = collectThinkingRuns(sourceMessage.content);
|
|
145
|
-
const hasVisibleContent = message.content.some((c) => (c.type === "text" && c.text.trim()) ||
|
|
146
|
-
(!this.hideThinkingBlock &&
|
|
145
|
+
const hasVisibleContent = message.content.some((c) => (c.type === "text" && c.text.trim()) ||
|
|
146
|
+
(!this.hideThinkingBlock && c.type === "thinking" && c.thinking.trim()));
|
|
147
147
|
if (hasVisibleContent) {
|
|
148
148
|
this.contentContainer.addChild(new Spacer(1));
|
|
149
149
|
}
|
|
150
150
|
// Render content in order
|
|
151
151
|
let isFirstTextBlock = true;
|
|
152
152
|
let thinkingRunIndex = -1;
|
|
153
|
-
let renderedThinking = false;
|
|
154
153
|
for (let i = 0; i < message.content.length; i++) {
|
|
155
154
|
const content = message.content[i];
|
|
156
155
|
if (content.type === "text" && content.text.trim()) {
|
|
@@ -181,19 +180,13 @@ export class AssistantMessageComponent extends Container {
|
|
|
181
180
|
}
|
|
182
181
|
}
|
|
183
182
|
i--;
|
|
184
|
-
|
|
185
|
-
if (thinkingBlocks.length === 0 || this.hideThinkingBlock) {
|
|
183
|
+
if (displayBlocks.length === 0 || this.hideThinkingBlock) {
|
|
186
184
|
continue;
|
|
187
185
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (!this.hideThinkingBlock && !renderedThinking && sourceThinkingRuns.length > 0) {
|
|
193
|
-
thinkingRunIndex = 0;
|
|
194
|
-
const thinkingBlocks = sourceThinkingRuns[0] ?? [];
|
|
195
|
-
if (thinkingBlocks.length > 0) {
|
|
196
|
-
this.renderThinkingRun(thinkingRunIndex, thinkingBlocks, message, -1);
|
|
186
|
+
const sourceBlocks = sourceThinkingRuns[thinkingRunIndex] ?? [];
|
|
187
|
+
const fullyRevealed = displayBlocks.length === sourceBlocks.length &&
|
|
188
|
+
displayBlocks.every((block, index) => block === sourceBlocks[index]);
|
|
189
|
+
this.renderThinkingRun(thinkingRunIndex, displayBlocks, message, i, fullyRevealed);
|
|
197
190
|
}
|
|
198
191
|
}
|
|
199
192
|
// Check if incomplete/failed - show after partial content.
|
|
@@ -220,13 +213,15 @@ export class AssistantMessageComponent extends Container {
|
|
|
220
213
|
}
|
|
221
214
|
}
|
|
222
215
|
}
|
|
223
|
-
renderThinkingRun(thinkingRunIndex, thinkingBlocks, displayMessage, displayIndex) {
|
|
216
|
+
renderThinkingRun(thinkingRunIndex, thinkingBlocks, displayMessage, displayIndex, fullyRevealed) {
|
|
224
217
|
const hasVisibleContentAfter = displayIndex >= 0
|
|
225
218
|
? displayMessage.content
|
|
226
219
|
.slice(displayIndex + 1)
|
|
227
220
|
.some((c) => (c.type === "text" && c.text.trim()) || (c.type === "thinking" && c.thinking.trim()))
|
|
228
221
|
: displayMessage.content.some((c) => c.type === "text" && c.text.trim());
|
|
229
|
-
|
|
222
|
+
// Provider completion can precede the reveal cursor; keep animating until it catches up.
|
|
223
|
+
const runComplete = fullyRevealed &&
|
|
224
|
+
isThinkingRunComplete(false, this.thinkingTimings?.[thinkingRunIndex], this.thinkingTimings !== undefined);
|
|
230
225
|
const wrap = (inner) => {
|
|
231
226
|
this.contentContainer.addChild(new ThinkingRunBlock(this, thinkingRunIndex, inner));
|
|
232
227
|
};
|
|
@@ -297,8 +292,7 @@ function collectThinkingRuns(content) {
|
|
|
297
292
|
if (thinking)
|
|
298
293
|
blocks.push(thinking);
|
|
299
294
|
}
|
|
300
|
-
|
|
301
|
-
runs.push(blocks);
|
|
295
|
+
runs.push(blocks);
|
|
302
296
|
}
|
|
303
297
|
return runs;
|
|
304
298
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@ashx-j/lunr-ai\";\nimport { type Component, Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@ashx-j/lunr-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport {\n\tformatThoughtDuration,\n\tisThinkingRunComplete,\n\ttype ThinkingRunTiming,\n\tthinkingSnippet,\n} from \"./thinking-summary.ts\";\nimport { ThinkingTailComponent } from \"./thinking-tail.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tselectable = true;\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\t// lunr: collapsible reasoning — when true, a completed thinking run renders as\n\t// \"✻ Thought for Xs\" + its first sentence instead of the full block.\n\tprivate thinkingCollapse: boolean;\n\t// lunr: per-run expand. `expanded` still means \"all runs\" for setExpanded().\n\tprivate expanded = false;\n\tprivate expandedRuns = new Set<number>();\n\t// lunr: live per-run timings from interactive-mode; undefined = history message\n\t// (always treated as final, rendered without durations).\n\tprivate thinkingTimings?: ThinkingRunTiming[];\n\tprivate markdownTheme: MarkdownTheme;\n\t// lunr: kept for the deferred alternative hidden-thinking indicator (Phase 8 removed the label render).\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: retained for future use\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate thinkingSource?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tthinkingCollapse = false,\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.thinkingCollapse = thinkingCollapse;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\t// lunr: collapsible reasoning toggles (live; re-render like setHideThinkingBlock).\n\tsetThinkingCollapse(collapse: boolean): void {\n\t\tthis.thinkingCollapse = collapse;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\t// lunr: Expandable hook; true expands every thinking run, false collapses all.\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tif (!expanded) this.expandedRuns.clear();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tprivate isRunExpanded(runIndex: number): boolean {\n\t\treturn this.expanded || this.expandedRuns.has(runIndex);\n\t}\n\n\ttoggleThinkingRun(runIndex: number): void {\n\t\tif (this.expanded) {\n\t\t\tthis.expanded = false;\n\t\t\tthis.expandedRuns.clear();\n\t\t\tconst count = this.lastMessage ? collectThinkingRuns(this.lastMessage.content).length : 0;\n\t\t\tfor (let i = 0; i < count; i++) {\n\t\t\t\tif (i !== runIndex) this.expandedRuns.add(i);\n\t\t\t}\n\t\t} else if (this.expandedRuns.has(runIndex)) {\n\t\t\tthis.expandedRuns.delete(runIndex);\n\t\t} else {\n\t\t\tthis.expandedRuns.add(runIndex);\n\t\t}\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\thandleClick(localY: number, width: number): boolean {\n\t\tconst contentWidth = width;\n\t\tlet y = 0;\n\t\tfor (const child of this.contentContainer.children) {\n\t\t\tconst h = child.render(contentWidth).length;\n\t\t\tif (localY >= y && localY < y + h) {\n\t\t\t\tif (typeof child.handleClick === \"function\") {\n\t\t\t\t\treturn child.handleClick(localY - y, contentWidth);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\ty += h;\n\t\t}\n\t\treturn false;\n\t}\n\n\tsetThinkingTimings(timings: ThinkingRunTiming[] | undefined): void {\n\t\tthis.thinkingTimings = timings;\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) return lines;\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\n\t\treturn lines;\n\t}\n\n\tprivate thinkingSourceOptions(): { thinkingSource?: AssistantMessage } | undefined {\n\t\treturn this.thinkingSource ? { thinkingSource: this.thinkingSource } : undefined;\n\t}\n\n\tupdateContent(message: AssistantMessage, options?: { thinkingSource?: AssistantMessage }): void {\n\t\tthis.lastMessage = message;\n\t\tthis.thinkingSource = options?.thinkingSource;\n\n\t\t// Clear content container\n\t\tthis.contentContainer.clear();\n\n\t\tconst sourceMessage = this.thinkingSource ?? message;\n\t\tconst sourceThinkingRuns = collectThinkingRuns(sourceMessage.content);\n\t\tconst hasVisibleContent =\n\t\t\tmessage.content.some(\n\t\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t\t) ||\n\t\t\t(!this.hideThinkingBlock && sourceThinkingRuns.some((run) => run.length > 0));\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tlet isFirstTextBlock = true;\n\t\tlet thinkingRunIndex = -1;\n\t\tlet renderedThinking = false;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\t// lunr: leading ● marks the first text block (never thinking blocks). It rides\n\t\t\t\t// the defaultTextStyle below, so it renders bright white like the body.\n\t\t\t\tconst trimmed = content.text.trim();\n\t\t\t\tconst text = isFirstTextBlock ? `● ${trimmed}` : trimmed;\n\t\t\t\tisFirstTextBlock = false;\n\t\t\t\t// lunr: theme-polish — assistant message body renders bright white via the\n\t\t\t\t// shared userMessageText token (same knob as user messages).\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(text, this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (body: string) => theme.fg(\"userMessageText\", body),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tthinkingRunIndex++;\n\t\t\t\tconst displayBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tdisplayBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tconst thinkingBlocks = sourceThinkingRuns[thinkingRunIndex] ?? displayBlocks;\n\t\t\t\tif (thinkingBlocks.length === 0 || this.hideThinkingBlock) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\trenderedThinking = true;\n\t\t\t\tthis.renderThinkingRun(thinkingRunIndex, thinkingBlocks, message, i);\n\t\t\t}\n\t\t}\n\n\t\tif (!this.hideThinkingBlock && !renderedThinking && sourceThinkingRuns.length > 0) {\n\t\t\tthinkingRunIndex = 0;\n\t\t\tconst thinkingBlocks = sourceThinkingRuns[0] ?? [];\n\t\t\tif (thinkingBlocks.length > 0) {\n\t\t\t\tthis.renderThinkingRun(thinkingRunIndex, thinkingBlocks, message, -1);\n\t\t\t}\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t\tif (message.stopReason === \"length\") {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\"Error: Model stopped because it reached the maximum output token limit. The response may be incomplete.\",\n\t\t\t\t\t),\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), this.outputPad, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), this.outputPad, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate renderThinkingRun(\n\t\tthinkingRunIndex: number,\n\t\tthinkingBlocks: string[],\n\t\tdisplayMessage: AssistantMessage,\n\t\tdisplayIndex: number,\n\t): void {\n\t\tconst hasVisibleContentAfter =\n\t\t\tdisplayIndex >= 0\n\t\t\t\t? displayMessage.content\n\t\t\t\t\t\t.slice(displayIndex + 1)\n\t\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()))\n\t\t\t\t: displayMessage.content.some((c) => c.type === \"text\" && c.text.trim());\n\n\t\tconst runComplete = isThinkingRunComplete(\n\t\t\tfalse,\n\t\t\tthis.thinkingTimings?.[thinkingRunIndex],\n\t\t\tthis.thinkingTimings !== undefined,\n\t\t);\n\t\tconst wrap = (inner: Component): void => {\n\t\t\tthis.contentContainer.addChild(new ThinkingRunBlock(this, thinkingRunIndex, inner));\n\t\t};\n\t\tif (this.thinkingCollapse && !this.isRunExpanded(thinkingRunIndex) && runComplete) {\n\t\t\tconst timing = this.thinkingTimings?.[thinkingRunIndex];\n\t\t\tconst label =\n\t\t\t\ttiming?.end !== undefined\n\t\t\t\t\t? `✻ Thought for ${formatThoughtDuration(timing.end - timing.start)}`\n\t\t\t\t\t: \"✻ Thought\";\n\t\t\tconst block = new Container();\n\t\t\tblock.addChild(new Text(theme.fg(\"thinkingText\", theme.italic(label)), this.outputPad, 0));\n\t\t\tconst snippet = thinkingSnippet(thinkingBlocks.join(\"\\n\\n\"));\n\t\t\tif (snippet) {\n\t\t\t\tblock.addChild(new Text(theme.fg(\"thinkingText\", theme.italic(snippet)), this.outputPad + 2, 0));\n\t\t\t}\n\t\t\twrap(block);\n\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!runComplete && !this.isRunExpanded(thinkingRunIndex)) {\n\t\t\twrap(\n\t\t\t\tnew ThinkingTailComponent(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\titalic: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\twrap(\n\t\t\tnew Markdown(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\titalic: true,\n\t\t\t}),\n\t\t);\n\t\tif (hasVisibleContentAfter) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\t}\n}\n\nclass ThinkingRunBlock extends Container {\n\tprivate readonly owner: AssistantMessageComponent;\n\tprivate readonly runIndex: number;\n\n\tconstructor(owner: AssistantMessageComponent, runIndex: number, inner: Component) {\n\t\tsuper();\n\t\tthis.owner = owner;\n\t\tthis.runIndex = runIndex;\n\t\tthis.addChild(inner);\n\t}\n\n\thandleClick(_localY: number, _width: number): boolean {\n\t\tthis.owner.toggleThinkingRun(this.runIndex);\n\t\treturn true;\n\t}\n}\n\nfunction collectThinkingRuns(content: AssistantMessage[\"content\"]): string[][] {\n\tconst runs: string[][] = [];\n\tfor (let i = 0; i < content.length; i++) {\n\t\tconst block = content[i];\n\t\tif (block.type !== \"thinking\") continue;\n\t\tconst blocks: string[] = [];\n\t\tfor (; i < content.length; i++) {\n\t\t\tconst thinkingContent = content[i];\n\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\ti--;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\tif (thinking) blocks.push(thinking);\n\t\t}\n\t\tif (blocks.length > 0) runs.push(blocks);\n\t}\n\treturn runs;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"assistant-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@ashx-j/lunr-ai\";\nimport { type Component, Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@ashx-j/lunr-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport {\n\tformatThoughtDuration,\n\tisThinkingRunComplete,\n\ttype ThinkingRunTiming,\n\tthinkingSnippet,\n} from \"./thinking-summary.ts\";\nimport { ThinkingTailComponent } from \"./thinking-tail.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tselectable = true;\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\t// lunr: collapsible reasoning — when true, a completed thinking run renders as\n\t// \"✻ Thought for Xs\" + its first sentence instead of the full block.\n\tprivate thinkingCollapse: boolean;\n\t// lunr: per-run expand. `expanded` still means \"all runs\" for setExpanded().\n\tprivate expanded = false;\n\tprivate expandedRuns = new Set<number>();\n\t// lunr: live per-run timings from interactive-mode; undefined = history message\n\t// (always treated as final, rendered without durations).\n\tprivate thinkingTimings?: ThinkingRunTiming[];\n\tprivate markdownTheme: MarkdownTheme;\n\t// lunr: kept for the deferred alternative hidden-thinking indicator (Phase 8 removed the label render).\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: retained for future use\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate thinkingSource?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tthinkingCollapse = false,\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.thinkingCollapse = thinkingCollapse;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\t// lunr: collapsible reasoning toggles (live; re-render like setHideThinkingBlock).\n\tsetThinkingCollapse(collapse: boolean): void {\n\t\tthis.thinkingCollapse = collapse;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\t// lunr: Expandable hook; true expands every thinking run, false collapses all.\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tif (!expanded) this.expandedRuns.clear();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tprivate isRunExpanded(runIndex: number): boolean {\n\t\treturn this.expanded || this.expandedRuns.has(runIndex);\n\t}\n\n\ttoggleThinkingRun(runIndex: number): void {\n\t\tif (this.expanded) {\n\t\t\tthis.expanded = false;\n\t\t\tthis.expandedRuns.clear();\n\t\t\tconst count = this.lastMessage ? collectThinkingRuns(this.lastMessage.content).length : 0;\n\t\t\tfor (let i = 0; i < count; i++) {\n\t\t\t\tif (i !== runIndex) this.expandedRuns.add(i);\n\t\t\t}\n\t\t} else if (this.expandedRuns.has(runIndex)) {\n\t\t\tthis.expandedRuns.delete(runIndex);\n\t\t} else {\n\t\t\tthis.expandedRuns.add(runIndex);\n\t\t}\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\thandleClick(localY: number, width: number): boolean {\n\t\tconst contentWidth = width;\n\t\tlet y = 0;\n\t\tfor (const child of this.contentContainer.children) {\n\t\t\tconst h = child.render(contentWidth).length;\n\t\t\tif (localY >= y && localY < y + h) {\n\t\t\t\tif (typeof child.handleClick === \"function\") {\n\t\t\t\t\treturn child.handleClick(localY - y, contentWidth);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\ty += h;\n\t\t}\n\t\treturn false;\n\t}\n\n\tsetThinkingTimings(timings: ThinkingRunTiming[] | undefined): void {\n\t\tthis.thinkingTimings = timings;\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage, this.thinkingSourceOptions());\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) return lines;\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\n\t\treturn lines;\n\t}\n\n\tprivate thinkingSourceOptions(): { thinkingSource?: AssistantMessage } | undefined {\n\t\treturn this.thinkingSource ? { thinkingSource: this.thinkingSource } : undefined;\n\t}\n\n\tupdateContent(message: AssistantMessage, options?: { thinkingSource?: AssistantMessage }): void {\n\t\tthis.lastMessage = message;\n\t\tthis.thinkingSource = options?.thinkingSource;\n\n\t\t// Clear content container\n\t\tthis.contentContainer.clear();\n\n\t\tconst sourceMessage = this.thinkingSource ?? message;\n\t\tconst sourceThinkingRuns = collectThinkingRuns(sourceMessage.content);\n\t\tconst hasVisibleContent = message.content.some(\n\t\t\t(c) =>\n\t\t\t\t(c.type === \"text\" && c.text.trim()) ||\n\t\t\t\t(!this.hideThinkingBlock && c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tlet isFirstTextBlock = true;\n\t\tlet thinkingRunIndex = -1;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\t// lunr: leading ● marks the first text block (never thinking blocks). It rides\n\t\t\t\t// the defaultTextStyle below, so it renders bright white like the body.\n\t\t\t\tconst trimmed = content.text.trim();\n\t\t\t\tconst text = isFirstTextBlock ? `● ${trimmed}` : trimmed;\n\t\t\t\tisFirstTextBlock = false;\n\t\t\t\t// lunr: theme-polish — assistant message body renders bright white via the\n\t\t\t\t// shared userMessageText token (same knob as user messages).\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(text, this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (body: string) => theme.fg(\"userMessageText\", body),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tthinkingRunIndex++;\n\t\t\t\tconst displayBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tdisplayBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (displayBlocks.length === 0 || this.hideThinkingBlock) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst sourceBlocks = sourceThinkingRuns[thinkingRunIndex] ?? [];\n\t\t\t\tconst fullyRevealed =\n\t\t\t\t\tdisplayBlocks.length === sourceBlocks.length &&\n\t\t\t\t\tdisplayBlocks.every((block, index) => block === sourceBlocks[index]);\n\t\t\t\tthis.renderThinkingRun(thinkingRunIndex, displayBlocks, message, i, fullyRevealed);\n\t\t\t}\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t\tif (message.stopReason === \"length\") {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\"Error: Model stopped because it reached the maximum output token limit. The response may be incomplete.\",\n\t\t\t\t\t),\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), this.outputPad, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), this.outputPad, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate renderThinkingRun(\n\t\tthinkingRunIndex: number,\n\t\tthinkingBlocks: string[],\n\t\tdisplayMessage: AssistantMessage,\n\t\tdisplayIndex: number,\n\t\tfullyRevealed: boolean,\n\t): void {\n\t\tconst hasVisibleContentAfter =\n\t\t\tdisplayIndex >= 0\n\t\t\t\t? displayMessage.content\n\t\t\t\t\t\t.slice(displayIndex + 1)\n\t\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()))\n\t\t\t\t: displayMessage.content.some((c) => c.type === \"text\" && c.text.trim());\n\n\t\t// Provider completion can precede the reveal cursor; keep animating until it catches up.\n\t\tconst runComplete =\n\t\t\tfullyRevealed &&\n\t\t\tisThinkingRunComplete(false, this.thinkingTimings?.[thinkingRunIndex], this.thinkingTimings !== undefined);\n\t\tconst wrap = (inner: Component): void => {\n\t\t\tthis.contentContainer.addChild(new ThinkingRunBlock(this, thinkingRunIndex, inner));\n\t\t};\n\t\tif (this.thinkingCollapse && !this.isRunExpanded(thinkingRunIndex) && runComplete) {\n\t\t\tconst timing = this.thinkingTimings?.[thinkingRunIndex];\n\t\t\tconst label =\n\t\t\t\ttiming?.end !== undefined\n\t\t\t\t\t? `✻ Thought for ${formatThoughtDuration(timing.end - timing.start)}`\n\t\t\t\t\t: \"✻ Thought\";\n\t\t\tconst block = new Container();\n\t\t\tblock.addChild(new Text(theme.fg(\"thinkingText\", theme.italic(label)), this.outputPad, 0));\n\t\t\tconst snippet = thinkingSnippet(thinkingBlocks.join(\"\\n\\n\"));\n\t\t\tif (snippet) {\n\t\t\t\tblock.addChild(new Text(theme.fg(\"thinkingText\", theme.italic(snippet)), this.outputPad + 2, 0));\n\t\t\t}\n\t\t\twrap(block);\n\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!runComplete && !this.isRunExpanded(thinkingRunIndex)) {\n\t\t\twrap(\n\t\t\t\tnew ThinkingTailComponent(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\titalic: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\twrap(\n\t\t\tnew Markdown(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\titalic: true,\n\t\t\t}),\n\t\t);\n\t\tif (hasVisibleContentAfter) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\t}\n}\n\nclass ThinkingRunBlock extends Container {\n\tprivate readonly owner: AssistantMessageComponent;\n\tprivate readonly runIndex: number;\n\n\tconstructor(owner: AssistantMessageComponent, runIndex: number, inner: Component) {\n\t\tsuper();\n\t\tthis.owner = owner;\n\t\tthis.runIndex = runIndex;\n\t\tthis.addChild(inner);\n\t}\n\n\thandleClick(_localY: number, _width: number): boolean {\n\t\tthis.owner.toggleThinkingRun(this.runIndex);\n\t\treturn true;\n\t}\n}\n\nfunction collectThinkingRuns(content: AssistantMessage[\"content\"]): string[][] {\n\tconst runs: string[][] = [];\n\tfor (let i = 0; i < content.length; i++) {\n\t\tconst block = content[i];\n\t\tif (block.type !== \"thinking\") continue;\n\t\tconst blocks: string[] = [];\n\t\tfor (; i < content.length; i++) {\n\t\t\tconst thinkingContent = content[i];\n\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\ti--;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\tif (thinking) blocks.push(thinking);\n\t\t}\n\t\truns.push(blocks);\n\t}\n\treturn runs;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,SAAS,EAAwC,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AACxH,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,mCAAmC,CAAC;AAY3F,MAAM,WAAW,oBAAoB;IACpC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,WAAW,CAAO;IAC1B,OAAO,CAAC,mBAAmB,CAAY;IAGvC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,qBAAqB,CAAC,CAAY;IAC1C,OAAO,CAAC,uBAAuB,CAAC,CAAY;IAC5C,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,eAAe,CAAe;IACtC,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,cAAc,CAAC,CAA2B;IAClD,OAAO,CAAC,qBAAqB,CAAC,CAA2B;IACzD,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAC,CAIb;IACF,OAAO,CAAC,eAAe,CAA8D;IACrF,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,SAAS,CAAC,CAAyB;IAC3C,OAAO,CAAC,SAAS,CAAC,CAAyB;IAE3C,YACC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,GAAG,EACT,OAAO,kCAA2B,EAClC,cAAc,EAAE,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,SAAS,EACpD,EAAE,EAAE,GAAG,EACP,GAAG,EAAE,MAAM,EAgCX;IAED,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,gBAAgB;IAyBxB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,oBAAoB;IAQ5B,UAAU,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CAG1B;IAED,oBAAoB,IAAI,IAAI,CAI3B;IAED,eAAe,IAAI,IAAI,CAItB;IAED,YAAY,CACX,MAAM,EAAE;QACP,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAClF,OAAO,CAAC,EAAE,GAAG,CAAC;QACd,OAAO,EAAE,OAAO,CAAC;KACjB,EACD,SAAS,UAAQ,GACf,IAAI,CAMN;IAED,OAAO,CAAC,0BAA0B;IAuBlC,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAInC;IAED,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAMpD;IAID,WAAW,IAAI,MAAM,CAEpB;IAKD,oBAAoB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAKtC;IAID,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAIlC;IAID,aAAa,CAAC,IAAI,EAAE,sBAAsB,GAAG,IAAI,CAGhD;IAED,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,0BAA0B;IAYlC,OAAO,CAAC,uBAAuB;IAY/B,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,gBAAgB;IASxB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAGjC;IAED,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAGtC;IAEQ,UAAU,IAAI,IAAI,CAG1B;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAgCvC;IAED,OAAO,CAAC,aAAa;IA0HrB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,mBAAmB;CA0B3B;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,sBAAsB,GAAG,SAAS,EAC5C,IAAI,EAAE,sBAAsB,GAC1B,IAAI,CAMN","sourcesContent":["import { Box, type Component, Container, getCapabilities, Image, Spacer, Text, type TUI } from \"@ashx-j/lunr-tui\";\nimport type { ToolDefinition, ToolRenderContext } from \"../../../core/extensions/types.ts\";\nimport { createAllToolDefinitions, type ToolName } from \"../../../core/tools/index.ts\";\nimport {\n\tformatGroupedCall,\n\tgetTextOutput as getRenderedTextOutput,\n\ttoolGroupRole,\n\ttoolGroupTree,\n\ttoolStatusDot,\n} from \"../../../core/tools/render-utils.ts\";\nimport { convertToPng } from \"../../../utils/image-convert.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean;\n\timageWidthCells?: number;\n}\n\nexport class ToolExecutionComponent extends Container {\n\tprivate contentBox: Box;\n\tprivate contentText: Text;\n\tprivate selfRenderContainer: Container;\n\t// lunr: top spacer kept as a field so consecutive same-tool calls can be\n\t// grouped into one continuous background by zeroing it (setGroupContinuation).\n\tprivate topSpacer: Spacer;\n\tprivate callRendererComponent?: Component;\n\tprivate resultRendererComponent?: Component;\n\tprivate rendererState: any = {};\n\tprivate imageComponents: Image[] = [];\n\tprivate imageSpacers: Spacer[] = [];\n\tprivate toolName: string;\n\tprivate toolCallId: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate showImages: boolean;\n\tprivate imageWidthCells: number;\n\tprivate isPartial = true;\n\tprivate toolDefinition?: ToolDefinition<any, any>;\n\tprivate builtInToolDefinition?: ToolDefinition<any, any>;\n\tprivate ui: TUI;\n\tprivate cwd: string;\n\tprivate executionStarted = false;\n\tprivate argsComplete = false;\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\tprivate convertedImages: Map<number, { data: string; mimeType: string }> = new Map();\n\tprivate hideComponent = false;\n\tprivate groupContinuation = false;\n\tprivate groupFollowed = false;\n\tprivate groupPrev?: ToolExecutionComponent;\n\tprivate groupNext?: ToolExecutionComponent;\n\n\tconstructor(\n\t\ttoolName: string,\n\t\ttoolCallId: string,\n\t\targs: any,\n\t\toptions: ToolExecutionOptions = {},\n\t\ttoolDefinition: ToolDefinition<any, any> | undefined,\n\t\tui: TUI,\n\t\tcwd: string,\n\t) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.toolCallId = toolCallId;\n\t\tthis.args = args;\n\t\tthis.toolDefinition = toolDefinition;\n\t\tthis.builtInToolDefinition = createAllToolDefinitions(cwd)[toolName as ToolName];\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.imageWidthCells = options.imageWidthCells ?? 60;\n\t\tthis.ui = ui;\n\t\tthis.cwd = cwd;\n\n\t\tthis.topSpacer = new Spacer(1);\n\t\tthis.addChild(this.topSpacer);\n\n\t\t// Always create all shell variants. contentBox is used for default renderer-based composition.\n\t\t// selfRenderContainer is used when the tool renders its own framing.\n\t\t// contentText is reserved for generic fallback rendering when no tool definition exists.\n\t\t// lunr: default Box(1, 1). Same-name neighbors collapse facing pad only\n\t\t// (setGroupContinuation / setGroupFollowed); mixed and lone cards keep air.\n\t\tthis.contentBox = new Box(1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\t\tthis.contentText = new Text(\"\", 1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\t\tthis.selfRenderContainer = new Container();\n\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tthis.addChild(this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox);\n\t\t} else {\n\t\t\tthis.addChild(this.contentText);\n\t\t}\n\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate getCallRenderer(): ToolDefinition<any, any>[\"renderCall\"] | undefined {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderCall;\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderCall;\n\t\t}\n\t\treturn this.toolDefinition.renderCall ?? this.builtInToolDefinition.renderCall;\n\t}\n\n\tprivate getResultRenderer(): ToolDefinition<any, any>[\"renderResult\"] | undefined {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderResult;\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderResult;\n\t\t}\n\t\treturn this.toolDefinition.renderResult ?? this.builtInToolDefinition.renderResult;\n\t}\n\n\tprivate hasRendererDefinition(): boolean {\n\t\treturn this.builtInToolDefinition !== undefined || this.toolDefinition !== undefined;\n\t}\n\n\tprivate getRenderShell(): \"default\" | \"self\" {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderShell ?? \"default\";\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderShell ?? \"default\";\n\t\t}\n\t\treturn this.toolDefinition.renderShell ?? this.builtInToolDefinition.renderShell ?? \"default\";\n\t}\n\n\tprivate getRenderContext(lastComponent: Component | undefined): ToolRenderContext {\n\t\treturn {\n\t\t\targs: this.args,\n\t\t\ttoolCallId: this.toolCallId,\n\t\t\tinvalidate: () => {\n\t\t\t\tthis.invalidate();\n\t\t\t\tthis.ui.requestRender();\n\t\t\t},\n\t\t\trequestRender: () => {\n\t\t\t\tthis.ui.requestRender();\n\t\t\t},\n\t\t\tlastComponent,\n\t\t\tstate: this.rendererState,\n\t\t\tcwd: this.cwd,\n\t\t\texecutionStarted: this.executionStarted,\n\t\t\targsComplete: this.argsComplete,\n\t\t\tisPartial: this.isPartial,\n\t\t\texpanded: this.expanded,\n\t\t\tshowImages: this.showImages,\n\t\t\tisError: this.result?.isError ?? false,\n\t\t\tresult: this.result,\n\t\t\tgroupRole: toolGroupRole(this.groupContinuation, this.groupFollowed),\n\t\t};\n\t}\n\n\tprivate getStatusDot(): string {\n\t\tconst state = this.isPartial ? \"pending\" : this.result?.isError ? \"error\" : \"success\";\n\t\treturn toolStatusDot(state, theme);\n\t}\n\n\tprivate createCallFallback(): Component {\n\t\treturn new Text(\n\t\t\tformatGroupedCall({\n\t\t\t\trole: toolGroupRole(this.groupContinuation, this.groupFollowed),\n\t\t\t\tcompact: !this.isPartial && !this.expanded && !this.result?.isError,\n\t\t\t\ttree: toolGroupTree({ expanded: this.expanded, isError: this.result?.isError }),\n\t\t\t\tdot: this.getStatusDot(),\n\t\t\t\ttitle: theme.fg(\"toolTitle\", theme.bold(this.toolName)),\n\t\t\t}),\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\n\tprivate createResultFallback(): Component | undefined {\n\t\tconst output = this.getTextOutput();\n\t\tif (!output) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn new Text(theme.fg(\"toolOutput\", output), 0, 0);\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\tmarkExecutionStarted(): void {\n\t\tthis.executionStarted = true;\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tsetArgsComplete(): void {\n\t\tthis.argsComplete = true;\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tthis.updateDisplay();\n\t\tthis.refreshGroupTail();\n\t\tthis.maybeConvertImagesForKitty();\n\t}\n\n\tprivate maybeConvertImagesForKitty(): void {\n\t\tconst caps = getCapabilities();\n\t\tif (caps.images !== \"kitty\") return;\n\t\tif (!this.result) return;\n\n\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\tconst img = imageBlocks[i];\n\t\t\tif (!img.data || !img.mimeType) continue;\n\t\t\tif (img.mimeType === \"image/png\") continue;\n\t\t\tif (this.convertedImages.has(i)) continue;\n\n\t\t\tconst index = i;\n\t\t\tconvertToPng(img.data, img.mimeType).then((converted) => {\n\t\t\t\tif (converted) {\n\t\t\t\t\tthis.convertedImages.set(index, converted);\n\t\t\t\t\tthis.updateDisplay();\n\t\t\t\t\tthis.ui.requestRender();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t\tthis.refreshGroupTail();\n\t}\n\n\thandleClick(_localY: number, _width: number): boolean {\n\t\tif (this.isPartial) return false;\n\t\tif (this.toolName === \"subagent\" || this.toolName === \"subagent_wait\") return false;\n\t\tthis.setExpanded(!this.expanded);\n\t\tthis.ui.requestRender();\n\t\treturn true;\n\t}\n\n\t// lunr: consecutive same-tool grouping — exposes the tool name so the caller\n\t// can detect adjacency.\n\tgetToolName(): string {\n\t\treturn this.toolName;\n\t}\n\n\t// lunr: consecutive same-tool grouping — continuation calls hide the top\n\t// spacer and top box pad so adjacent same-bg boxes read as one continuous\n\t// background; the last card in a run keeps its bottom pad.\n\tsetGroupContinuation(on: boolean): void {\n\t\tthis.groupContinuation = on;\n\t\tthis.topSpacer.setLines(on ? 0 : 1);\n\t\tthis.applyGroupPadding();\n\t\tthis.invalidate();\n\t}\n\n\t// lunr: previous card in a same-name run drops its bottom pad so the next\n\t// header sits flush. Singletons and mixed neighbors keep paddingBottom = 1.\n\tsetGroupFollowed(on: boolean): void {\n\t\tthis.groupFollowed = on;\n\t\tthis.applyGroupPadding();\n\t\tthis.invalidate();\n\t}\n\n\t// lunr: same-name run link so a later card can hoist earlier error bodies\n\t// under the last leaf instead of splitting the tree.\n\tlinkGroupNext(next: ToolExecutionComponent): void {\n\t\tthis.groupNext = next;\n\t\tnext.groupPrev = this;\n\t}\n\n\tprivate applyGroupPadding(): void {\n\t\tconst top = this.groupContinuation ? 0 : 1;\n\t\tconst bottom = this.groupFollowed ? 0 : 1;\n\t\tthis.contentBox.setPaddingTop(top);\n\t\tthis.contentBox.setPaddingBottom(bottom);\n\t\tthis.contentText.setPaddingTop(top);\n\t\tthis.contentText.setPaddingBottom(bottom);\n\t\tif (this.getRenderShell() === \"self\" && this.callRendererComponent instanceof Box) {\n\t\t\tthis.callRendererComponent.setPaddingTop(top);\n\t\t\tthis.callRendererComponent.setPaddingBottom(bottom);\n\t\t}\n\t}\n\n\tprivate shouldHideGroupedErrorBody(): boolean {\n\t\treturn (\n\t\t\tBoolean(this.result?.isError) &&\n\t\t\tthis.groupFollowed &&\n\t\t\t!this.expanded &&\n\t\t\t!this.isPartial &&\n\t\t\tthis.getRenderShell() === \"default\" &&\n\t\t\tthis.toolName !== \"subagent\" &&\n\t\t\tthis.toolName !== \"subagent_wait\"\n\t\t);\n\t}\n\n\tprivate shouldSkipCompactResult(): boolean {\n\t\tif (this.result === undefined || this.isPartial || this.expanded) {\n\t\t\treturn false;\n\t\t}\n\t\t// lunr: collapsed mid-group errors stay header-only so the same-name\n\t\t// tree is not split; the last card hoists those bodies underneath.\n\t\tif (this.result.isError) {\n\t\t\treturn this.shouldHideGroupedErrorBody();\n\t\t}\n\t\treturn this.getRenderShell() === \"default\";\n\t}\n\n\tprivate formatHoistedGroupErrors(): string | undefined {\n\t\tif (this.groupFollowed || this.expanded) return undefined;\n\t\tconst texts: string[] = [];\n\t\tlet prev = this.groupPrev;\n\t\twhile (prev) {\n\t\t\tif (prev.shouldHideGroupedErrorBody()) {\n\t\t\t\tconst output = prev.getTextOutput().trim();\n\t\t\t\tif (output) texts.unshift(output);\n\t\t\t}\n\t\t\tprev = prev.groupPrev;\n\t\t}\n\t\treturn texts.length > 0 ? `\\n${texts.join(\"\\n\")}` : undefined;\n\t}\n\n\tprivate refreshGroupTail(): void {\n\t\tlet next = this.groupNext;\n\t\twhile (next) {\n\t\t\tconst card = next;\n\t\t\tnext = next.groupNext;\n\t\t\tif (!next) card.updateDisplay();\n\t\t}\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tthis.imageWidthCells = Math.max(1, Math.floor(width));\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.hideComponent) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (this.hasRendererDefinition() && this.getRenderShell() === \"self\") {\n\t\t\tconst contentLines = this.selfRenderContainer.render(width);\n\t\t\tif (contentLines.length === 0 && this.imageComponents.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst lines: string[] = [];\n\t\t\tif (contentLines.length > 0) {\n\t\t\t\tif (!this.groupContinuation) {\n\t\t\t\t\tlines.push(\"\");\n\t\t\t\t}\n\t\t\t\tlines.push(...contentLines);\n\t\t\t}\n\t\t\tfor (let i = 0; i < this.imageComponents.length; i++) {\n\t\t\t\tconst spacer = this.imageSpacers[i];\n\t\t\t\tif (spacer) {\n\t\t\t\t\tlines.push(...spacer.render(width));\n\t\t\t\t}\n\t\t\t\tconst imageComponent = this.imageComponents[i];\n\t\t\t\tif (imageComponent) {\n\t\t\t\t\tlines.push(...imageComponent.render(width));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\n\t\treturn super.render(width);\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tconst bgFn = this.isPartial\n\t\t\t? (text: string) => theme.bg(\"toolPendingBg\", text)\n\t\t\t: this.result?.isError\n\t\t\t\t? (text: string) => theme.bg(\"toolErrorBg\", text)\n\t\t\t\t: (text: string) => theme.bg(\"toolSuccessBg\", text);\n\n\t\tlet hasContent = false;\n\t\tthis.hideComponent = false;\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tconst renderContainer = this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox;\n\t\t\tif (renderContainer instanceof Box) {\n\t\t\t\trenderContainer.setBgFn(bgFn);\n\t\t\t}\n\t\t\trenderContainer.clear();\n\n\t\t\tconst callRenderer = this.getCallRenderer();\n\t\t\tif (!callRenderer) {\n\t\t\t\trenderContainer.addChild(this.createCallFallback());\n\t\t\t\thasContent = true;\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tconst component = callRenderer(this.args, theme, this.getRenderContext(this.callRendererComponent));\n\t\t\t\t\tthis.callRendererComponent = component;\n\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\thasContent = true;\n\t\t\t\t} catch {\n\t\t\t\t\tthis.callRendererComponent = undefined;\n\t\t\t\t\trenderContainer.addChild(this.createCallFallback());\n\t\t\t\t\thasContent = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst skipCompactBody = this.shouldSkipCompactResult();\n\t\t\t\tconst resultRenderer = this.getResultRenderer();\n\t\t\t\tif (!resultRenderer) {\n\t\t\t\t\tif (!skipCompactBody) {\n\t\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\t\tif (component) {\n\t\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst component = resultRenderer(\n\t\t\t\t\t\t\t{ content: this.result.content as any, details: this.result.details },\n\t\t\t\t\t\t\t{ expanded: this.expanded, isPartial: this.isPartial },\n\t\t\t\t\t\t\ttheme,\n\t\t\t\t\t\t\tthis.getRenderContext(this.resultRendererComponent),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis.resultRendererComponent = component;\n\t\t\t\t\t\tif (!skipCompactBody) {\n\t\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tthis.resultRendererComponent = undefined;\n\t\t\t\t\t\tif (!skipCompactBody) {\n\t\t\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\t\t\tif (component) {\n\t\t\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\t\t\thasContent = true;\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\t\t\t\tconst hoisted = this.formatHoistedGroupErrors();\n\t\t\t\tif (hoisted) {\n\t\t\t\t\trenderContainer.addChild(new Text(theme.fg(\"toolOutput\", hoisted), 0, 0));\n\t\t\t\t\thasContent = true;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.contentText.setCustomBgFn(bgFn);\n\t\t\tthis.contentText.setText(this.formatToolExecution());\n\t\t\thasContent = true;\n\t\t}\n\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\t\tfor (const spacer of this.imageSpacers) {\n\t\t\tthis.removeChild(spacer);\n\t\t}\n\t\tthis.imageSpacers = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\t\tconst caps = getCapabilities();\n\t\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\t\tconst img = imageBlocks[i];\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\tconst converted = this.convertedImages.get(i);\n\t\t\t\t\tconst imageData = converted?.data ?? img.data;\n\t\t\t\t\tconst imageMimeType = converted?.mimeType ?? img.mimeType;\n\t\t\t\t\tif (caps.images === \"kitty\" && imageMimeType !== \"image/png\") continue;\n\n\t\t\t\t\tconst spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(spacer);\n\t\t\t\t\tthis.imageSpacers.push(spacer);\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timageData,\n\t\t\t\t\t\timageMimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: this.imageWidthCells },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.hasRendererDefinition() && !hasContent && this.imageComponents.length === 0) {\n\t\t\tthis.hideComponent = true;\n\t\t}\n\n\t\tthis.applyGroupPadding();\n\t}\n\n\tprivate getTextOutput(): string {\n\t\treturn getRenderedTextOutput(this.result, this.showImages);\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tconst hideGroupedErrorBody = Boolean(this.result?.isError && this.groupFollowed && !this.expanded);\n\t\tconst compact = !this.isPartial && !this.expanded && (!this.result?.isError || hideGroupedErrorBody);\n\t\tlet text = formatGroupedCall({\n\t\t\trole: toolGroupRole(this.groupContinuation, this.groupFollowed),\n\t\t\tcompact,\n\t\t\ttree: toolGroupTree({ expanded: this.expanded, isError: this.result?.isError }),\n\t\t\tdot: this.getStatusDot(),\n\t\t\ttitle: theme.fg(\"toolTitle\", theme.bold(this.toolName)),\n\t\t});\n\t\tif (!compact) {\n\t\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\t\tif (content) {\n\t\t\t\ttext += `\\n\\n${content}`;\n\t\t\t}\n\t\t\tconst output = this.getTextOutput();\n\t\t\tif (output) {\n\t\t\t\ttext += `\\n${output}`;\n\t\t\t}\n\t\t}\n\t\tconst hoisted = this.formatHoistedGroupErrors();\n\t\tif (hoisted) {\n\t\t\ttext += hoisted;\n\t\t}\n\t\treturn text;\n\t}\n}\n\n/** Collapse facing pad when `next` is appended after a same-name tool card. */\nexport function applySameToolGrouping(\n\tprevious: ToolExecutionComponent | undefined,\n\tnext: ToolExecutionComponent,\n): void {\n\tif (previous && previous.getToolName() === next.getToolName()) {\n\t\tprevious.linkGroupNext(next);\n\t\tprevious.setGroupFollowed(true);\n\t\tnext.setGroupContinuation(true);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import { Box, type Component, Container, getCapabilities, Image, Spacer, Text, type TUI } from \"@ashx-j/lunr-tui\";\nimport type { ToolDefinition, ToolRenderContext } from \"../../../core/extensions/types.ts\";\nimport { createAllToolDefinitions, type ToolName } from \"../../../core/tools/index.ts\";\nimport {\n\tformatGroupedCall,\n\tgetTextOutput as getRenderedTextOutput,\n\ttoolGroupRole,\n\ttoolGroupTree,\n\ttoolStatusDot,\n} from \"../../../core/tools/render-utils.ts\";\nimport { convertToPng } from \"../../../utils/image-convert.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean;\n\timageWidthCells?: number;\n}\n\nexport class ToolExecutionComponent extends Container {\n\tprivate contentBox: Box;\n\tprivate contentText: Text;\n\tprivate selfRenderContainer: Container;\n\t// lunr: top spacer kept as a field so consecutive same-tool calls can be\n\t// grouped into one continuous background by zeroing it (setGroupContinuation).\n\tprivate topSpacer: Spacer;\n\tprivate callRendererComponent?: Component;\n\tprivate resultRendererComponent?: Component;\n\tprivate rendererState: any = {};\n\tprivate imageComponents: Image[] = [];\n\tprivate imageSpacers: Spacer[] = [];\n\tprivate toolName: string;\n\tprivate toolCallId: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate showImages: boolean;\n\tprivate imageWidthCells: number;\n\tprivate isPartial = true;\n\tprivate toolDefinition?: ToolDefinition<any, any>;\n\tprivate builtInToolDefinition?: ToolDefinition<any, any>;\n\tprivate ui: TUI;\n\tprivate cwd: string;\n\tprivate executionStarted = false;\n\tprivate argsComplete = false;\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\tprivate convertedImages: Map<number, { data: string; mimeType: string }> = new Map();\n\tprivate hideComponent = false;\n\tprivate groupContinuation = false;\n\tprivate groupFollowed = false;\n\tprivate groupPrev?: ToolExecutionComponent;\n\tprivate groupNext?: ToolExecutionComponent;\n\n\tconstructor(\n\t\ttoolName: string,\n\t\ttoolCallId: string,\n\t\targs: any,\n\t\toptions: ToolExecutionOptions = {},\n\t\ttoolDefinition: ToolDefinition<any, any> | undefined,\n\t\tui: TUI,\n\t\tcwd: string,\n\t) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.toolCallId = toolCallId;\n\t\tthis.args = args;\n\t\tthis.toolDefinition = toolDefinition;\n\t\tthis.builtInToolDefinition = createAllToolDefinitions(cwd)[toolName as ToolName];\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.imageWidthCells = options.imageWidthCells ?? 60;\n\t\tthis.ui = ui;\n\t\tthis.cwd = cwd;\n\n\t\tthis.topSpacer = new Spacer(1);\n\t\tthis.addChild(this.topSpacer);\n\n\t\t// Always create all shell variants. contentBox is used for default renderer-based composition.\n\t\t// selfRenderContainer is used when the tool renders its own framing.\n\t\t// contentText is reserved for generic fallback rendering when no tool definition exists.\n\t\t// lunr: default Box(1, 1). Same-name neighbors collapse facing pad only\n\t\t// (setGroupContinuation / setGroupFollowed); mixed and lone cards keep air.\n\t\tthis.contentBox = new Box(1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\t\tthis.contentText = new Text(\"\", 1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\t\tthis.selfRenderContainer = new Container();\n\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tthis.addChild(this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox);\n\t\t} else {\n\t\t\tthis.addChild(this.contentText);\n\t\t}\n\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate getCallRenderer(): ToolDefinition<any, any>[\"renderCall\"] | undefined {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderCall;\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderCall;\n\t\t}\n\t\treturn this.toolDefinition.renderCall ?? this.builtInToolDefinition.renderCall;\n\t}\n\n\tprivate getResultRenderer(): ToolDefinition<any, any>[\"renderResult\"] | undefined {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderResult;\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderResult;\n\t\t}\n\t\treturn this.toolDefinition.renderResult ?? this.builtInToolDefinition.renderResult;\n\t}\n\n\tprivate hasRendererDefinition(): boolean {\n\t\treturn this.builtInToolDefinition !== undefined || this.toolDefinition !== undefined;\n\t}\n\n\tprivate getRenderShell(): \"default\" | \"self\" {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderShell ?? \"default\";\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderShell ?? \"default\";\n\t\t}\n\t\treturn this.toolDefinition.renderShell ?? this.builtInToolDefinition.renderShell ?? \"default\";\n\t}\n\n\tprivate getRenderContext(lastComponent: Component | undefined): ToolRenderContext {\n\t\treturn {\n\t\t\targs: this.args,\n\t\t\ttoolCallId: this.toolCallId,\n\t\t\tinvalidate: () => {\n\t\t\t\tthis.invalidate();\n\t\t\t\tthis.ui.requestRender();\n\t\t\t},\n\t\t\trequestRender: () => {\n\t\t\t\tthis.ui.requestRender();\n\t\t\t},\n\t\t\tlastComponent,\n\t\t\tstate: this.rendererState,\n\t\t\tcwd: this.cwd,\n\t\t\texecutionStarted: this.executionStarted,\n\t\t\targsComplete: this.argsComplete,\n\t\t\tisPartial: this.isPartial,\n\t\t\texpanded: this.expanded,\n\t\t\tshowImages: this.showImages,\n\t\t\tisError: this.result?.isError ?? false,\n\t\t\tresult: this.result,\n\t\t\tgroupRole: toolGroupRole(this.groupContinuation, this.groupFollowed),\n\t\t};\n\t}\n\n\tprivate getStatusDot(): string {\n\t\tconst state = this.isPartial ? \"pending\" : this.result?.isError ? \"error\" : \"success\";\n\t\treturn toolStatusDot(state, theme);\n\t}\n\n\tprivate createCallFallback(): Component {\n\t\treturn new Text(\n\t\t\tformatGroupedCall({\n\t\t\t\trole: toolGroupRole(this.groupContinuation, this.groupFollowed),\n\t\t\t\tcompact: !this.isPartial && !this.expanded && !this.result?.isError,\n\t\t\t\ttree: toolGroupTree({ expanded: this.expanded, isError: this.result?.isError }),\n\t\t\t\tdot: this.getStatusDot(),\n\t\t\t\ttitle: theme.fg(\"toolTitle\", theme.bold(this.toolName)),\n\t\t\t}),\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\n\tprivate createResultFallback(): Component | undefined {\n\t\tconst output = this.getTextOutput();\n\t\tif (!output) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn new Text(theme.fg(\"toolOutput\", output), 0, 0);\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\tmarkExecutionStarted(): void {\n\t\tthis.executionStarted = true;\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tsetArgsComplete(): void {\n\t\tthis.argsComplete = true;\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tthis.updateDisplay();\n\t\tthis.refreshGroupTail();\n\t\tthis.maybeConvertImagesForKitty();\n\t}\n\n\tprivate maybeConvertImagesForKitty(): void {\n\t\tconst caps = getCapabilities();\n\t\tif (caps.images !== \"kitty\") return;\n\t\tif (!this.result) return;\n\n\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\tconst img = imageBlocks[i];\n\t\t\tif (!img.data || !img.mimeType) continue;\n\t\t\tif (img.mimeType === \"image/png\") continue;\n\t\t\tif (this.convertedImages.has(i)) continue;\n\n\t\t\tconst index = i;\n\t\t\tconvertToPng(img.data, img.mimeType).then((converted) => {\n\t\t\t\tif (converted) {\n\t\t\t\t\tthis.convertedImages.set(index, converted);\n\t\t\t\t\tthis.updateDisplay();\n\t\t\t\t\tthis.ui.requestRender();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t\tthis.refreshGroupTail();\n\t}\n\n\thandleClick(_localY: number, _width: number): boolean {\n\t\tif (this.isPartial) return false;\n\t\tif (this.toolName === \"subagent\" || this.toolName === \"subagent_wait\") return false;\n\t\tthis.setExpanded(!this.expanded);\n\t\tthis.ui.requestRender();\n\t\treturn true;\n\t}\n\n\t// lunr: consecutive same-tool grouping — exposes the tool name so the caller\n\t// can detect adjacency.\n\tgetToolName(): string {\n\t\treturn this.toolName;\n\t}\n\n\t// lunr: consecutive same-tool grouping — continuation calls hide the top\n\t// spacer and top box pad so adjacent same-bg boxes read as one continuous\n\t// background; the last card in a run keeps its bottom pad.\n\tsetGroupContinuation(on: boolean): void {\n\t\tthis.groupContinuation = on;\n\t\tthis.topSpacer.setLines(on ? 0 : 1);\n\t\tthis.applyGroupPadding();\n\t\tthis.invalidate();\n\t}\n\n\t// lunr: previous card in a same-name run drops its bottom pad so the next\n\t// header sits flush. Singletons and mixed neighbors keep paddingBottom = 1.\n\tsetGroupFollowed(on: boolean): void {\n\t\tthis.groupFollowed = on;\n\t\tthis.applyGroupPadding();\n\t\tthis.invalidate();\n\t}\n\n\t// lunr: same-name run link so a later card can hoist earlier error bodies\n\t// under the last leaf instead of splitting the tree.\n\tlinkGroupNext(next: ToolExecutionComponent): void {\n\t\tthis.groupNext = next;\n\t\tnext.groupPrev = this;\n\t}\n\n\tprivate applyGroupPadding(): void {\n\t\tconst top = this.groupContinuation ? 0 : 1;\n\t\tconst bottom = this.groupFollowed ? 0 : 1;\n\t\tthis.contentBox.setPaddingTop(top);\n\t\tthis.contentBox.setPaddingBottom(bottom);\n\t\tthis.contentText.setPaddingTop(top);\n\t\tthis.contentText.setPaddingBottom(bottom);\n\t\tif (this.getRenderShell() === \"self\" && this.callRendererComponent instanceof Box) {\n\t\t\tthis.callRendererComponent.setPaddingTop(top);\n\t\t\tthis.callRendererComponent.setPaddingBottom(bottom);\n\t\t}\n\t}\n\n\tprivate shouldHideGroupedErrorBody(): boolean {\n\t\treturn (\n\t\t\tBoolean(this.result?.isError) &&\n\t\t\tthis.groupFollowed &&\n\t\t\t!this.expanded &&\n\t\t\t!this.isPartial &&\n\t\t\tthis.getRenderShell() === \"default\" &&\n\t\t\tthis.toolName !== \"subagent\" &&\n\t\t\tthis.toolName !== \"subagent_wait\"\n\t\t);\n\t}\n\n\tprivate shouldSkipCompactResult(): boolean {\n\t\tif (this.result === undefined || this.isPartial || this.expanded) {\n\t\t\treturn false;\n\t\t}\n\t\t// lunr: collapsed finished subagent cards still show the compact row when a child\n\t\t// result exists. Async launch receipts (empty results) stay header-only.\n\t\tif (this.toolName === \"subagent\") {\n\t\t\tconst details = this.result.details as { mode?: string; results?: unknown[] } | undefined;\n\t\t\tif (this.result.isError) return false;\n\t\t\tif (Array.isArray(details?.results) && details.results.length > 0) return false;\n\t\t\tif (details?.mode === \"management\") return false;\n\t\t\treturn true;\n\t\t}\n\t\t// lunr: collapsed mid-group errors stay header-only so the same-name\n\t\t// tree is not split; the last card hoists those bodies underneath.\n\t\tif (this.result.isError) {\n\t\t\treturn this.shouldHideGroupedErrorBody();\n\t\t}\n\t\treturn this.getRenderShell() === \"default\";\n\t}\n\n\tprivate formatHoistedGroupErrors(): string | undefined {\n\t\tif (this.groupFollowed || this.expanded) return undefined;\n\t\tconst texts: string[] = [];\n\t\tlet prev = this.groupPrev;\n\t\twhile (prev) {\n\t\t\tif (prev.shouldHideGroupedErrorBody()) {\n\t\t\t\tconst output = prev.getTextOutput().trim();\n\t\t\t\tif (output) texts.unshift(output);\n\t\t\t}\n\t\t\tprev = prev.groupPrev;\n\t\t}\n\t\treturn texts.length > 0 ? `\\n${texts.join(\"\\n\")}` : undefined;\n\t}\n\n\tprivate refreshGroupTail(): void {\n\t\tlet next = this.groupNext;\n\t\twhile (next) {\n\t\t\tconst card = next;\n\t\t\tnext = next.groupNext;\n\t\t\tif (!next) card.updateDisplay();\n\t\t}\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tthis.imageWidthCells = Math.max(1, Math.floor(width));\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.hideComponent) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (this.hasRendererDefinition() && this.getRenderShell() === \"self\") {\n\t\t\tconst contentLines = this.selfRenderContainer.render(width);\n\t\t\tif (contentLines.length === 0 && this.imageComponents.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst lines: string[] = [];\n\t\t\tif (contentLines.length > 0) {\n\t\t\t\tif (!this.groupContinuation) {\n\t\t\t\t\tlines.push(\"\");\n\t\t\t\t}\n\t\t\t\tlines.push(...contentLines);\n\t\t\t}\n\t\t\tfor (let i = 0; i < this.imageComponents.length; i++) {\n\t\t\t\tconst spacer = this.imageSpacers[i];\n\t\t\t\tif (spacer) {\n\t\t\t\t\tlines.push(...spacer.render(width));\n\t\t\t\t}\n\t\t\t\tconst imageComponent = this.imageComponents[i];\n\t\t\t\tif (imageComponent) {\n\t\t\t\t\tlines.push(...imageComponent.render(width));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\n\t\treturn super.render(width);\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tconst bgFn = this.isPartial\n\t\t\t? (text: string) => theme.bg(\"toolPendingBg\", text)\n\t\t\t: this.result?.isError\n\t\t\t\t? (text: string) => theme.bg(\"toolErrorBg\", text)\n\t\t\t\t: (text: string) => theme.bg(\"toolSuccessBg\", text);\n\n\t\tlet hasContent = false;\n\t\tthis.hideComponent = false;\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tconst renderContainer = this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox;\n\t\t\tif (renderContainer instanceof Box) {\n\t\t\t\trenderContainer.setBgFn(bgFn);\n\t\t\t}\n\t\t\trenderContainer.clear();\n\n\t\t\tconst callRenderer = this.getCallRenderer();\n\t\t\tif (!callRenderer) {\n\t\t\t\trenderContainer.addChild(this.createCallFallback());\n\t\t\t\thasContent = true;\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tconst component = callRenderer(this.args, theme, this.getRenderContext(this.callRendererComponent));\n\t\t\t\t\tthis.callRendererComponent = component;\n\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\thasContent = true;\n\t\t\t\t} catch {\n\t\t\t\t\tthis.callRendererComponent = undefined;\n\t\t\t\t\trenderContainer.addChild(this.createCallFallback());\n\t\t\t\t\thasContent = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst skipCompactBody = this.shouldSkipCompactResult();\n\t\t\t\tconst resultRenderer = this.getResultRenderer();\n\t\t\t\tif (!resultRenderer) {\n\t\t\t\t\tif (!skipCompactBody) {\n\t\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\t\tif (component) {\n\t\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst component = resultRenderer(\n\t\t\t\t\t\t\t{ content: this.result.content as any, details: this.result.details },\n\t\t\t\t\t\t\t{ expanded: this.expanded, isPartial: this.isPartial },\n\t\t\t\t\t\t\ttheme,\n\t\t\t\t\t\t\tthis.getRenderContext(this.resultRendererComponent),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis.resultRendererComponent = component;\n\t\t\t\t\t\tif (!skipCompactBody) {\n\t\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tthis.resultRendererComponent = undefined;\n\t\t\t\t\t\tif (!skipCompactBody) {\n\t\t\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\t\t\tif (component) {\n\t\t\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\t\t\thasContent = true;\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\t\t\t\tconst hoisted = this.formatHoistedGroupErrors();\n\t\t\t\tif (hoisted) {\n\t\t\t\t\trenderContainer.addChild(new Text(theme.fg(\"toolOutput\", hoisted), 0, 0));\n\t\t\t\t\thasContent = true;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.contentText.setCustomBgFn(bgFn);\n\t\t\tthis.contentText.setText(this.formatToolExecution());\n\t\t\thasContent = true;\n\t\t}\n\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\t\tfor (const spacer of this.imageSpacers) {\n\t\t\tthis.removeChild(spacer);\n\t\t}\n\t\tthis.imageSpacers = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\t\tconst caps = getCapabilities();\n\t\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\t\tconst img = imageBlocks[i];\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\tconst converted = this.convertedImages.get(i);\n\t\t\t\t\tconst imageData = converted?.data ?? img.data;\n\t\t\t\t\tconst imageMimeType = converted?.mimeType ?? img.mimeType;\n\t\t\t\t\tif (caps.images === \"kitty\" && imageMimeType !== \"image/png\") continue;\n\n\t\t\t\t\tconst spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(spacer);\n\t\t\t\t\tthis.imageSpacers.push(spacer);\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timageData,\n\t\t\t\t\t\timageMimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: this.imageWidthCells },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.hasRendererDefinition() && !hasContent && this.imageComponents.length === 0) {\n\t\t\tthis.hideComponent = true;\n\t\t}\n\n\t\tthis.applyGroupPadding();\n\t}\n\n\tprivate getTextOutput(): string {\n\t\treturn getRenderedTextOutput(this.result, this.showImages);\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tconst hideGroupedErrorBody = Boolean(this.result?.isError && this.groupFollowed && !this.expanded);\n\t\tconst compact = !this.isPartial && !this.expanded && (!this.result?.isError || hideGroupedErrorBody);\n\t\tlet text = formatGroupedCall({\n\t\t\trole: toolGroupRole(this.groupContinuation, this.groupFollowed),\n\t\t\tcompact,\n\t\t\ttree: toolGroupTree({ expanded: this.expanded, isError: this.result?.isError }),\n\t\t\tdot: this.getStatusDot(),\n\t\t\ttitle: theme.fg(\"toolTitle\", theme.bold(this.toolName)),\n\t\t});\n\t\tif (!compact) {\n\t\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\t\tif (content) {\n\t\t\t\ttext += `\\n\\n${content}`;\n\t\t\t}\n\t\t\tconst output = this.getTextOutput();\n\t\t\tif (output) {\n\t\t\t\ttext += `\\n${output}`;\n\t\t\t}\n\t\t}\n\t\tconst hoisted = this.formatHoistedGroupErrors();\n\t\tif (hoisted) {\n\t\t\ttext += hoisted;\n\t\t}\n\t\treturn text;\n\t}\n}\n\n/** Collapse facing pad when `next` is appended after a same-name tool card. */\nexport function applySameToolGrouping(\n\tprevious: ToolExecutionComponent | undefined,\n\tnext: ToolExecutionComponent,\n): void {\n\tif (previous && previous.getToolName() === next.getToolName()) {\n\t\tprevious.linkGroupNext(next);\n\t\tprevious.setGroupFollowed(true);\n\t\tnext.setGroupContinuation(true);\n\t}\n}\n"]}
|
|
@@ -250,6 +250,18 @@ export class ToolExecutionComponent extends Container {
|
|
|
250
250
|
if (this.result === undefined || this.isPartial || this.expanded) {
|
|
251
251
|
return false;
|
|
252
252
|
}
|
|
253
|
+
// lunr: collapsed finished subagent cards still show the compact row when a child
|
|
254
|
+
// result exists. Async launch receipts (empty results) stay header-only.
|
|
255
|
+
if (this.toolName === "subagent") {
|
|
256
|
+
const details = this.result.details;
|
|
257
|
+
if (this.result.isError)
|
|
258
|
+
return false;
|
|
259
|
+
if (Array.isArray(details?.results) && details.results.length > 0)
|
|
260
|
+
return false;
|
|
261
|
+
if (details?.mode === "management")
|
|
262
|
+
return false;
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
253
265
|
// lunr: collapsed mid-group errors stay header-only so the same-name
|
|
254
266
|
// tree is not split; the last card hoists those bodies underneath.
|
|
255
267
|
if (this.result.isError) {
|