@oh-my-pi/pi-coding-agent 16.0.10 → 16.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/cli.js +3344 -3371
  3. package/dist/types/advisor/index.d.ts +1 -0
  4. package/dist/types/advisor/transcript-recorder.d.ts +52 -0
  5. package/dist/types/commit/agentic/agent.d.ts +1 -1
  6. package/dist/types/config/settings-schema.d.ts +14 -8
  7. package/dist/types/edit/file-snapshot-store.d.ts +1 -1
  8. package/dist/types/extensibility/extensions/types.d.ts +7 -0
  9. package/dist/types/modes/components/__tests__/skill-message.test.d.ts +1 -0
  10. package/dist/types/modes/components/agent-hub.d.ts +6 -1
  11. package/dist/types/modes/components/agent-transcript-viewer.d.ts +39 -0
  12. package/dist/types/modes/components/assistant-message.d.ts +8 -0
  13. package/dist/types/modes/components/cache-invalidation-marker.d.ts +34 -0
  14. package/dist/types/modes/components/chat-transcript-builder.d.ts +42 -0
  15. package/dist/types/modes/components/compaction-summary-message.d.ts +14 -1
  16. package/dist/types/modes/components/index.d.ts +0 -1
  17. package/dist/types/modes/components/message-frame.d.ts +6 -4
  18. package/dist/types/modes/controllers/command-controller.d.ts +3 -2
  19. package/dist/types/modes/interactive-mode.d.ts +4 -2
  20. package/dist/types/modes/theme/theme.d.ts +7 -1
  21. package/dist/types/modes/types.d.ts +9 -2
  22. package/dist/types/registry/agent-registry.d.ts +10 -3
  23. package/dist/types/sdk.d.ts +1 -1
  24. package/dist/types/session/agent-session.d.ts +20 -1
  25. package/dist/types/session/compact-modes.d.ts +60 -0
  26. package/dist/types/session/session-context.d.ts +7 -0
  27. package/dist/types/session/session-dump-format.d.ts +1 -0
  28. package/dist/types/session/streaming-output.d.ts +0 -2
  29. package/dist/types/session/tool-choice-queue.d.ts +14 -0
  30. package/dist/types/system-prompt.d.ts +3 -3
  31. package/dist/types/tools/__tests__/json-tree.test.d.ts +1 -0
  32. package/dist/types/tools/index.d.ts +4 -0
  33. package/dist/types/tools/resolve.d.ts +15 -5
  34. package/package.json +12 -12
  35. package/src/advisor/index.ts +1 -0
  36. package/src/advisor/transcript-recorder.ts +136 -0
  37. package/src/cli/stats-cli.ts +2 -11
  38. package/src/collab/host.ts +25 -13
  39. package/src/commit/agentic/agent.ts +2 -1
  40. package/src/commit/agentic/tools/git-file-diff.ts +2 -2
  41. package/src/commit/changelog/index.ts +1 -1
  42. package/src/commit/map-reduce/map-phase.ts +1 -1
  43. package/src/commit/map-reduce/utils.ts +1 -1
  44. package/src/config/settings-schema.ts +16 -9
  45. package/src/config/settings.ts +0 -6
  46. package/src/debug/log-viewer.ts +4 -4
  47. package/src/debug/raw-sse.ts +4 -4
  48. package/src/edit/file-snapshot-store.ts +1 -1
  49. package/src/edit/renderer.ts +9 -9
  50. package/src/eval/js/tool-bridge.ts +3 -2
  51. package/src/eval/py/prelude.py +3 -2
  52. package/src/export/html/tool-views.generated.js +28 -28
  53. package/src/extensibility/extensions/types.ts +7 -0
  54. package/src/hindsight/mental-models.ts +1 -1
  55. package/src/internal-urls/docs-index.generated.txt +1 -1
  56. package/src/internal-urls/history-protocol.ts +8 -3
  57. package/src/irc/bus.ts +8 -0
  58. package/src/lsp/index.ts +2 -2
  59. package/src/lsp/render.ts +7 -7
  60. package/src/main.ts +4 -1
  61. package/src/modes/acp/acp-agent.ts +63 -0
  62. package/src/modes/components/__tests__/skill-message.test.ts +92 -0
  63. package/src/modes/components/agent-dashboard.ts +1 -1
  64. package/src/modes/components/agent-hub.ts +97 -920
  65. package/src/modes/components/agent-transcript-viewer.ts +461 -0
  66. package/src/modes/components/assistant-message.ts +21 -0
  67. package/src/modes/components/cache-invalidation-marker.ts +84 -0
  68. package/src/modes/components/chat-transcript-builder.ts +476 -0
  69. package/src/modes/components/compaction-summary-message.ts +29 -1
  70. package/src/modes/components/custom-message.ts +4 -1
  71. package/src/modes/components/diff.ts +12 -35
  72. package/src/modes/components/dynamic-border.ts +1 -1
  73. package/src/modes/components/extensions/extension-dashboard.ts +1 -1
  74. package/src/modes/components/extensions/inspector-panel.ts +5 -5
  75. package/src/modes/components/hook-selector.ts +2 -2
  76. package/src/modes/components/index.ts +0 -1
  77. package/src/modes/components/message-frame.ts +10 -6
  78. package/src/modes/components/model-selector.ts +2 -2
  79. package/src/modes/components/overlay-box.ts +10 -9
  80. package/src/modes/components/skill-message.ts +39 -19
  81. package/src/modes/components/tiny-title-download-progress.ts +1 -1
  82. package/src/modes/components/welcome.ts +1 -1
  83. package/src/modes/controllers/command-controller.ts +12 -2
  84. package/src/modes/controllers/event-controller.ts +15 -1
  85. package/src/modes/controllers/input-controller.ts +8 -1
  86. package/src/modes/controllers/selector-controller.ts +11 -1
  87. package/src/modes/interactive-mode.ts +13 -3
  88. package/src/modes/theme/theme.ts +14 -0
  89. package/src/modes/types.ts +9 -2
  90. package/src/modes/utils/ui-helpers.ts +20 -2
  91. package/src/prompts/steering/user-interjection.md +3 -4
  92. package/src/prompts/tools/read.md +1 -1
  93. package/src/registry/agent-registry.ts +13 -4
  94. package/src/sdk.ts +9 -7
  95. package/src/session/agent-session.ts +182 -16
  96. package/src/session/compact-modes.ts +105 -0
  97. package/src/session/messages.ts +7 -9
  98. package/src/session/session-context.ts +54 -7
  99. package/src/session/session-dump-format.ts +4 -2
  100. package/src/session/session-history-format.ts +1 -1
  101. package/src/session/snapcompact-inline.ts +2 -2
  102. package/src/session/streaming-output.ts +5 -5
  103. package/src/session/tool-choice-queue.ts +59 -0
  104. package/src/slash-commands/builtin-registry.ts +16 -4
  105. package/src/system-prompt.ts +10 -9
  106. package/src/task/executor.ts +1 -1
  107. package/src/task/output-manager.ts +5 -0
  108. package/src/tools/__tests__/json-tree.test.ts +35 -0
  109. package/src/tools/approval.ts +1 -1
  110. package/src/tools/bash-interactive.ts +4 -4
  111. package/src/tools/bash.ts +0 -1
  112. package/src/tools/browser.ts +0 -1
  113. package/src/tools/eval.ts +1 -1
  114. package/src/tools/gh.ts +1 -1
  115. package/src/tools/index.ts +4 -0
  116. package/src/tools/irc.ts +1 -1
  117. package/src/tools/json-tree.ts +22 -5
  118. package/src/tools/read.ts +5 -6
  119. package/src/tools/resolve.ts +66 -41
  120. package/src/tui/output-block.ts +9 -9
  121. package/src/web/scrapers/firefox-addons.ts +1 -1
  122. package/src/web/scrapers/github.ts +1 -1
  123. package/src/web/scrapers/go-pkg.ts +2 -2
  124. package/src/web/scrapers/metacpan.ts +2 -2
  125. package/src/web/scrapers/nvd.ts +2 -2
  126. package/src/web/scrapers/ollama.ts +1 -1
  127. package/src/web/scrapers/opencorporates.ts +1 -1
  128. package/src/web/scrapers/pub-dev.ts +1 -1
  129. package/src/web/scrapers/repology.ts +1 -1
  130. package/src/web/scrapers/sourcegraph.ts +1 -1
  131. package/src/web/scrapers/terraform.ts +6 -6
  132. package/src/web/scrapers/wikidata.ts +2 -2
  133. package/src/workspace-tree.ts +1 -1
  134. package/dist/types/modes/components/branch-summary-message.d.ts +0 -13
  135. package/src/modes/components/branch-summary-message.ts +0 -46
@@ -1,3 +1,4 @@
1
1
  export * from "./advise-tool";
2
2
  export * from "./runtime";
3
+ export * from "./transcript-recorder";
3
4
  export * from "./watchdog";
@@ -0,0 +1,52 @@
1
+ import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
+ /**
3
+ * Reserved transcript stem for advisor session files. Chosen so it cannot
4
+ * collide with a task subagent's `<id>.jsonl` (task ids are reserved against
5
+ * this exact stem in {@link AgentOutputManager}).
6
+ */
7
+ export declare const ADVISOR_TRANSCRIPT_STEM = "__advisor";
8
+ export declare const ADVISOR_TRANSCRIPT_FILENAME = "__advisor.jsonl";
9
+ /**
10
+ * Append-only persister for an advisor agent's transcript.
11
+ *
12
+ * The advisor is a passive reviewer with its own model usage, so — like a task
13
+ * subagent — its turns are written to a JSONL inside the owning session's
14
+ * artifacts dir (`<session>/__advisor.jsonl`, `<session>/<SubId>/__advisor.jsonl`
15
+ * for subagent advisors). That single file gives the advisor model proper usage
16
+ * attribution in `omp stats` (the stats parser scans the session dir
17
+ * recursively) and a read-only transcript in the Agent Hub, without making the
18
+ * advisor a registered, messageable peer.
19
+ *
20
+ * The target is derived from the *session file* (`getSessionFile()`), never
21
+ * `getArtifactsDir()` — subagents adopt the parent's artifact manager, so the
22
+ * artifacts dir points at the parent root and every subagent advisor would
23
+ * collide. The file path is resolved synchronously when a message finalizes and
24
+ * captured for the queued write, so a `/new`, resume, or session switch in
25
+ * flight can never misattribute an old advisor turn into the new session's file.
26
+ * On such a switch the previous writer is closed and the new file opened on the
27
+ * next recorded turn. The recorder never truncates: the advisor's in-memory
28
+ * context resets/compacts independently, but every billed turn is appended here.
29
+ */
30
+ export declare class AdvisorTranscriptRecorder {
31
+ #private;
32
+ private readonly resolveSessionFile;
33
+ private readonly resolveCwd;
34
+ /**
35
+ * @param after Optional barrier the queue starts behind — used on the advisor
36
+ * on→off→on toggle so a fresh recorder's first `open` waits for the prior
37
+ * recorder's `close` and the two never hold the same `__advisor.jsonl` at once.
38
+ */
39
+ constructor(resolveSessionFile: () => string | undefined, resolveCwd: () => string, after?: Promise<unknown>);
40
+ /**
41
+ * Persist one finalized advisor message. Assistant turns carry the usage the
42
+ * stats parser reads; tool results round out the Hub transcript; user deltas
43
+ * (the advisor's "session update" prompts) are persisted but flagged
44
+ * `synthetic`/agent-attributed so they never inflate user-message metrics.
45
+ * Non-conversational message kinds are skipped.
46
+ */
47
+ record(message: AgentMessage): void;
48
+ /** Flush pending writes (best-effort). */
49
+ flush(): Promise<void>;
50
+ /** Flush and close the writer, releasing the session file. */
51
+ close(): Promise<void>;
52
+ }
@@ -1,4 +1,4 @@
1
- import { type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
1
+ import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
2
  import type { Api, Model } from "@oh-my-pi/pi-ai";
3
3
  import type { ModelRegistry } from "../../config/model-registry";
4
4
  import type { Settings } from "../../config/settings";
@@ -775,10 +775,6 @@ export declare const SETTINGS_SCHEMA: {
775
775
  readonly description: "Remove the 1-character horizontal padding from the left and right of the terminal output";
776
776
  };
777
777
  };
778
- readonly "display.tabWidth": {
779
- readonly type: "number";
780
- readonly default: 3;
781
- };
782
778
  readonly "display.shimmer": {
783
779
  readonly type: "enum";
784
780
  readonly values: readonly ["classic", "kitt", "disabled"];
@@ -823,6 +819,16 @@ export declare const SETTINGS_SCHEMA: {
823
819
  readonly description: "Show per-turn token usage on assistant messages";
824
820
  };
825
821
  };
822
+ readonly "display.cacheMissMarker": {
823
+ readonly type: "boolean";
824
+ readonly default: true;
825
+ readonly ui: {
826
+ readonly tab: "appearance";
827
+ readonly group: "Display";
828
+ readonly label: "Cache Miss Marker";
829
+ readonly description: "Show a divider above an assistant turn whose request lost (missed) the prompt cache";
830
+ };
831
+ };
826
832
  readonly showHardwareCursor: {
827
833
  readonly type: "boolean";
828
834
  readonly default: true;
@@ -875,14 +881,14 @@ export declare const SETTINGS_SCHEMA: {
875
881
  readonly description: "Apply loop guard to assistant prose messages in addition to thinking logs";
876
882
  };
877
883
  };
878
- readonly repeatToolDescriptions: {
884
+ readonly inlineToolDescriptors: {
879
885
  readonly type: "boolean";
880
- readonly default: false;
886
+ readonly default: true;
881
887
  readonly ui: {
882
888
  readonly tab: "model";
883
889
  readonly group: "Prompt";
884
- readonly label: "Repeat Tool Descriptions";
885
- readonly description: "Render full tool descriptions in the system prompt instead of a tool name list";
890
+ readonly label: "Inline Tool Descriptors";
891
+ readonly description: "Render full tool descriptors in the system prompt and strip top-level/nested descriptions from provider tool schemas so descriptor text is sent once";
886
892
  };
887
893
  };
888
894
  readonly includeModelInPrompt: {
@@ -48,7 +48,7 @@ export declare function recordFileSnapshot(session: FileSnapshotStoreOwner, abso
48
48
  /**
49
49
  * The 1-indexed file lines a hashline-formatted body actually displayed.
50
50
  * Single `NN:` rows contribute that line; a collapsed summary `NN-MM:` row
51
- * (a `{ .. }` brace pair) contributes only its boundary lines `NN` and `MM` —
51
+ * (a `{ }` brace pair) contributes only its boundary lines `NN` and `MM` —
52
52
  * the elided interior was never shown, so editing inside it must be rejected.
53
53
  */
54
54
  export declare function parseSeenLinesFromHashlineBody(body: string): number[];
@@ -25,6 +25,7 @@ import type * as PiCodingAgent from "../../index";
25
25
  import type { MemoryRuntimeContext } from "../../memory-backend";
26
26
  import type { CustomEditor } from "../../modes/components/custom-editor";
27
27
  import type { Theme } from "../../modes/theme/theme";
28
+ import type { CompactMode } from "../../session/compact-modes";
28
29
  import type { CustomMessage } from "../../session/messages";
29
30
  import type { ReadonlySessionManager, SessionManager } from "../../session/session-manager";
30
31
  import type { BashToolDetails, BashToolInput, FindToolDetails, FindToolInput, ReadToolDetails, ReadToolInput, SearchToolDetails, SearchToolInput, WriteToolInput } from "../../tools";
@@ -171,6 +172,12 @@ export interface ContextUsage {
171
172
  export interface CompactOptions {
172
173
  onComplete?: (result: CompactionResult) => void;
173
174
  onError?: (error: Error) => void;
175
+ /**
176
+ * Force a one-off compaction mode for this invocation, overriding the
177
+ * configured `compaction.strategy` / `remoteEnabled` (the `/compact`
178
+ * subcommands: `soft` | `remote` | `snapcompact`). Omitted = configured behavior.
179
+ */
180
+ mode?: CompactMode;
174
181
  }
175
182
  /**
176
183
  * Context passed to extension event handlers.
@@ -62,6 +62,11 @@ export declare class AgentHubOverlayComponent extends Container {
62
62
  dispose(): void;
63
63
  render(width: number): readonly string[];
64
64
  handleInput(keyData: string): void;
65
- /** Open the chat view for an agent id (public for table Enter and tests). */
65
+ /**
66
+ * Open the fullscreen transcript viewer for an agent id (public for table Enter
67
+ * and tests). Mounts {@link AgentTranscriptViewer} as a `fullscreen` overlay so it
68
+ * owns the alternate screen; the hub table stays mounted underneath and is
69
+ * restored when the viewer closes. No-op without a real TUI (render-only test stub).
70
+ */
66
71
  openChat(id: string): void;
67
72
  }
@@ -0,0 +1,39 @@
1
+ import type { AgentTool } from "@oh-my-pi/pi-agent-core";
2
+ import { type Component, type TUI } from "@oh-my-pi/pi-tui";
3
+ import type { KeyId } from "../../config/keybindings";
4
+ import type { MessageRenderer } from "../../extensibility/extensions/types";
5
+ import type { AgentLifecycleManager } from "../../registry/agent-lifecycle";
6
+ import type { AgentRegistry } from "../../registry/agent-registry";
7
+ import type { SessionObserverRegistry } from "../session-observer-registry";
8
+ import type { AgentHubRemote } from "./agent-hub";
9
+ export interface AgentTranscriptViewerDeps {
10
+ agentId: string;
11
+ registry: AgentRegistry;
12
+ /** Collab guest: read transcript from the host instead of a local file. */
13
+ remote?: AgentHubRemote;
14
+ /** Progress/cost snapshot source for the stats line. */
15
+ observers?: SessionObserverRegistry;
16
+ /** Revive+prompt path for messageable local agents. Lazy to avoid touching the global. */
17
+ lifecycle?: () => AgentLifecycleManager;
18
+ ui: TUI;
19
+ getTool?: (name: string) => AgentTool | undefined;
20
+ getMessageRenderer?: (customType: string) => MessageRenderer | undefined;
21
+ cwd: string;
22
+ hideThinkingBlock?: () => boolean;
23
+ expandKeys: KeyId[];
24
+ /** Keys that toggle the whole hub closed (app.agents.hub + app.session.observe). */
25
+ hubKeys: KeyId[];
26
+ requestRender: () => void;
27
+ /** Close just this viewer (Esc), returning to the hub table. */
28
+ onClose: () => void;
29
+ /** Close this viewer AND the hub (hub-toggle keys). */
30
+ onHubClose: () => void;
31
+ }
32
+ export declare class AgentTranscriptViewer implements Component {
33
+ #private;
34
+ private readonly deps;
35
+ constructor(deps: AgentTranscriptViewerDeps);
36
+ dispose(): void;
37
+ handleInput(data: string): void;
38
+ render(width: number): readonly string[];
39
+ }
@@ -1,6 +1,7 @@
1
1
  import type { AssistantMessage, ImageContent } from "@oh-my-pi/pi-ai";
2
2
  import { Container, type ImageBudget } from "@oh-my-pi/pi-tui";
3
3
  import type { AssistantThinkingRenderer } from "../../extensibility/extensions/types";
4
+ import { type CacheInvalidation } from "./cache-invalidation-marker";
4
5
  /**
5
6
  * Component that renders a complete assistant message
6
7
  */
@@ -11,6 +12,13 @@ export declare class AssistantMessageComponent extends Container {
11
12
  private readonly thinkingRenderers;
12
13
  private readonly imageBudget?;
13
14
  constructor(message?: AssistantMessage, hideThinkingBlock?: boolean, onImageUpdate?: (() => void) | undefined, thinkingRenderers?: readonly AssistantThinkingRenderer[], imageBudget?: ImageBudget | undefined);
15
+ /**
16
+ * Show or clear the slim cache-invalidation divider above this turn. Set at
17
+ * `message_end` (live) or during rebuild, once the turn's usage is known and
18
+ * compared against the previous turn's cache footprint. Bumps the transcript
19
+ * block version so the change repaints even after content finalized.
20
+ */
21
+ setCacheInvalidation(info: CacheInvalidation | undefined): void;
14
22
  invalidate(): void;
15
23
  setHideThinkingBlock(hide: boolean): void;
16
24
  dispose(): void;
@@ -0,0 +1,34 @@
1
+ import type { Usage } from "@oh-my-pi/pi-ai";
2
+ import type { Component } from "@oh-my-pi/pi-tui";
3
+ /** A prompt-cache invalidation detected from a turn's usage. */
4
+ export interface CacheInvalidation {
5
+ /** Prompt tokens the cold turn had to (re)process instead of reading from cache. */
6
+ reprocessedTokens: number;
7
+ }
8
+ /**
9
+ * Decide whether `current` turn lost the prompt cache that `prev` established.
10
+ *
11
+ * The provider reports a warm prefix as `cacheRead`; a model/thinking/tool/
12
+ * system-prompt change (or a history rewrite) breaks the prefix, so the next
13
+ * request reads nothing from cache and re-pays for the whole prompt. We detect
14
+ * that as: the previous turn cached a meaningful prefix, yet this turn's
15
+ * `cacheRead` collapsed to zero while it still reprocessed a non-trivial prompt.
16
+ * Returns `undefined` (no marker) for the first turn, tiny contexts, and turns
17
+ * that reused any cache.
18
+ */
19
+ export declare function detectCacheInvalidation(prev: Usage | undefined, current: Usage): CacheInvalidation | undefined;
20
+ /**
21
+ * Slim left-aligned divider rendered above an assistant turn whose request lost
22
+ * the prompt cache. Mirrors the compaction divider's banner styling but spans
23
+ * only a short rule plus label (not the full width) and carries no expandable
24
+ * detail:
25
+ *
26
+ * ────────── ⊘ cache miss · 50.9k tokens
27
+ */
28
+ export declare class CacheInvalidationMarkerComponent implements Component {
29
+ #private;
30
+ private readonly info;
31
+ constructor(info: CacheInvalidation);
32
+ invalidate(): void;
33
+ render(width: number): readonly string[];
34
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Builds transcript components from persisted session message entries — the
3
+ * file/remote-backed counterpart to {@link UiHelpers.addMessageToChat} (which is
4
+ * bound to the live InteractiveModeContext). Used by the fullscreen transcript
5
+ * viewer ({@link AgentTranscriptViewer}) to render a parked subagent / advisor /
6
+ * collab-guest transcript that has no live session.
7
+ *
8
+ * Unlike the old incremental hub sync, {@link ChatTranscriptBuilder.rebuild}
9
+ * always discards prior components and rebuilds the whole transcript from the
10
+ * supplied entries. Re-rendering a growing transcript is therefore O(n) in the
11
+ * entry count, but it cannot duplicate or misorder rows the way incremental
12
+ * component reuse could.
13
+ */
14
+ import type { AgentTool } from "@oh-my-pi/pi-agent-core";
15
+ import { type TUI } from "@oh-my-pi/pi-tui";
16
+ import type { MessageRenderer } from "../../extensibility/extensions/types";
17
+ import type { SessionMessageEntry } from "../../session/session-entries";
18
+ import { TranscriptContainer } from "./transcript-container";
19
+ export interface ChatTranscriptBuilderDeps {
20
+ ui: TUI;
21
+ getTool?: (name: string) => AgentTool | undefined;
22
+ getMessageRenderer?: (customType: string) => MessageRenderer | undefined;
23
+ cwd: string;
24
+ hideThinkingBlock?: () => boolean;
25
+ requestRender: () => void;
26
+ }
27
+ export declare class ChatTranscriptBuilder {
28
+ #private;
29
+ private readonly deps;
30
+ readonly container: TranscriptContainer;
31
+ constructor(deps: ChatTranscriptBuilderDeps);
32
+ /** Whether the transcript currently holds any rendered rows. */
33
+ get isEmpty(): boolean;
34
+ /** Discard all components and rebuild the whole transcript from `entries`. */
35
+ rebuild(entries: SessionMessageEntry[]): void;
36
+ /** Toggle tool-output expansion across every expandable component. */
37
+ setExpanded(expanded: boolean): void;
38
+ get expanded(): boolean;
39
+ /** Tear down components (sealing pending spinners) and clear build state. */
40
+ reset(): void;
41
+ dispose(): void;
42
+ }
@@ -1,5 +1,5 @@
1
1
  import { type Component } from "@oh-my-pi/pi-tui";
2
- import type { CompactionSummaryMessage, CustomMessage } from "../../session/messages";
2
+ import type { BranchSummaryMessage, CompactionSummaryMessage, CustomMessage } from "../../session/messages";
3
3
  /**
4
4
  * Compaction point in the transcript, rendered as a slim horizontal divider:
5
5
  *
@@ -31,3 +31,16 @@ export declare class HandoffSummaryMessageComponent implements Component {
31
31
  render(width: number): readonly string[];
32
32
  }
33
33
  export declare function createHandoffSummaryMessageComponent(message: CustomMessage<unknown>, expanded: boolean): HandoffSummaryMessageComponent | undefined;
34
+ /**
35
+ * A branch summary collapses a side branch back into the main line. Render it
36
+ * with the same slim divider as `/compact` and handoff rather than a `[branch]`
37
+ * box, so every history-collapse point reads as one consistent banner.
38
+ */
39
+ export declare class BranchSummaryMessageComponent implements Component {
40
+ #private;
41
+ private readonly message;
42
+ constructor(message: BranchSummaryMessage);
43
+ setExpanded(expanded: boolean): void;
44
+ invalidate(): void;
45
+ render(width: number): readonly string[];
46
+ }
@@ -1,7 +1,6 @@
1
1
  export * from "./assistant-message";
2
2
  export * from "./bash-execution";
3
3
  export * from "./bordered-loader";
4
- export * from "./branch-summary-message";
5
4
  export * from "./compaction-summary-message";
6
5
  export * from "./countdown-timer";
7
6
  export * from "./custom-editor";
@@ -29,14 +29,16 @@ export interface RebuildFrameOptions<M extends FramedMessage> {
29
29
  message: M;
30
30
  box: Box;
31
31
  expanded: boolean;
32
+ /** Icon glyph shown before the customType in the default header (e.g. a hook/extension icon). */
33
+ icon?: string;
32
34
  /** Collapse the markdown body to this many lines when `expanded` is false. Omit to never collapse. */
33
35
  collapseAfterLines?: number;
34
36
  customRenderer?: FramedRenderer<M>;
35
37
  }
36
38
  /**
37
- * Attempt the custom renderer; on failure or undefined return, populate
38
- * `box` with the default `[customType]` label + markdown body and return
39
- * undefined. When the custom renderer succeeds, return its Component so the
40
- * caller can mount it and skip the default box.
39
+ * Attempt the custom renderer; on failure or undefined return, populate `box`
40
+ * with the default outlined card — an `icon customType` header + markdown body
41
+ * and return undefined. When the custom renderer succeeds, return its Component
42
+ * so the caller can mount it and skip the default box.
41
43
  */
42
44
  export declare function renderFramedMessage<M extends FramedMessage>(opts: RebuildFrameOptions<M>): Component | undefined;
@@ -3,6 +3,7 @@ import { type ProviderDetails, type UsageReport } from "@oh-my-pi/pi-ai";
3
3
  import type { CompactOptions } from "../../extensibility/extensions/types";
4
4
  import { theme } from "../../modes/theme/theme";
5
5
  import type { InteractiveModeContext } from "../../modes/types";
6
+ import type { CompactMode } from "../../session/compact-modes";
6
7
  import { type ShakeMode } from "../../session/shake-types";
7
8
  export declare class CommandController {
8
9
  #private;
@@ -31,14 +32,14 @@ export declare class CommandController {
31
32
  handleRenameCommand(title: string): Promise<void>;
32
33
  handleBashCommand(command: string, excludeFromContext?: boolean): Promise<void>;
33
34
  handlePythonCommand(code: string, excludeFromContext?: boolean): Promise<void>;
34
- handleCompactCommand(customInstructions?: string, beforeFlush?: (outcome: CompactionOutcome) => void | Promise<void>): Promise<CompactionOutcome>;
35
+ handleCompactCommand(customInstructions?: string, mode?: CompactMode, beforeFlush?: (outcome: CompactionOutcome) => void | Promise<void>): Promise<CompactionOutcome>;
35
36
  /**
36
37
  * TUI handler for `/shake`. `elide` drops heavy structural content and
37
38
  * `images` strips image blocks. Rebuilds the chat and reports counts.
38
39
  */
39
40
  handleShakeCommand(mode: ShakeMode): Promise<void>;
40
41
  handleSkillCommand(skillPath: string, args: string): Promise<void>;
41
- executeCompaction(customInstructionsOrOptions?: string | CompactOptions, isAuto?: boolean, beforeFlush?: (outcome: CompactionOutcome) => void | Promise<void>): Promise<CompactionOutcome>;
42
+ executeCompaction(customInstructionsOrOptions?: string | CompactOptions, isAuto?: boolean, beforeFlush?: (outcome: CompactionOutcome) => void | Promise<void>, mode?: CompactMode): Promise<CompactionOutcome>;
42
43
  handleHandoffCommand(customInstructions?: string): Promise<void>;
43
44
  }
44
45
  export declare function renderProviderSection(details: ProviderDetails, uiTheme: Pick<typeof theme, "fg">): string;
@@ -1,6 +1,6 @@
1
1
  import { type Agent, type AgentMessage } from "@oh-my-pi/pi-agent-core";
2
2
  import type { CompactionOutcome } from "@oh-my-pi/pi-agent-core/compaction";
3
- import type { AssistantMessage, ImageContent, Message, UsageReport } from "@oh-my-pi/pi-ai";
3
+ import type { AssistantMessage, ImageContent, Message, Usage, UsageReport } from "@oh-my-pi/pi-ai";
4
4
  import type { Component, EditorTheme } from "@oh-my-pi/pi-tui";
5
5
  import { Container, Loader, Spacer, Text, TUI } from "@oh-my-pi/pi-tui";
6
6
  import type { CollabGuestLink } from "../collab/guest";
@@ -12,6 +12,7 @@ import type { CompactOptions } from "../extensibility/extensions/types";
12
12
  import type { MCPManager } from "../mcp";
13
13
  import { type PlanApprovalDetails } from "../plan-mode/approved-plan";
14
14
  import type { AgentSession } from "../session/agent-session";
15
+ import type { CompactMode } from "../session/compact-modes";
15
16
  import { HistoryStorage } from "../session/history-storage";
16
17
  import type { SessionContext } from "../session/session-context";
17
18
  import type { SessionManager } from "../session/session-manager";
@@ -118,6 +119,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
118
119
  isPythonMode: boolean;
119
120
  streamingComponent: AssistantMessageComponent | undefined;
120
121
  streamingMessage: AssistantMessage | undefined;
122
+ lastAssistantUsage: Usage | undefined;
121
123
  loadingAnimation: Loader | undefined;
122
124
  autoCompactionLoader: Loader | undefined;
123
125
  retryLoader: Loader | undefined;
@@ -298,7 +300,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
298
300
  handlePythonCommand(code: string, excludeFromContext?: boolean): Promise<void>;
299
301
  handleMCPCommand(text: string): Promise<void>;
300
302
  handleSSHCommand(text: string): Promise<void>;
301
- handleCompactCommand(customInstructions?: string, beforeFlush?: (outcome: CompactionOutcome) => void | Promise<void>): Promise<CompactionOutcome>;
303
+ handleCompactCommand(customInstructions?: string, mode?: CompactMode, beforeFlush?: (outcome: CompactionOutcome) => void | Promise<void>): Promise<CompactionOutcome>;
302
304
  handleHandoffCommand(customInstructions?: string): Promise<void>;
303
305
  handleShakeCommand(mode: ShakeMode): Promise<void>;
304
306
  executeCompaction(customInstructionsOrOptions?: string | CompactOptions, isAuto?: boolean): Promise<CompactionOutcome>;
@@ -6,7 +6,7 @@ export type SymbolPreset = "unicode" | "nerd" | "ascii";
6
6
  /**
7
7
  * All available symbol keys organized by category.
8
8
  */
9
- export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "status.done" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.search" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.time" | "icon.pi" | "icon.ghost" | "icon.agents" | "icon.job" | "icon.cache" | "icon.input" | "icon.output" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.mic" | "icon.camera" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "radio.selected" | "radio.unselected" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.files" | "tab.shell" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers" | "tool.write" | "tool.edit" | "tool.bash" | "tool.ssh" | "tool.lsp" | "tool.gh" | "tool.webSearch" | "tool.exa" | "tool.browser" | "tool.eval" | "tool.debug" | "tool.mcp" | "tool.job" | "tool.task" | "tool.todo" | "tool.memory" | "tool.ask" | "tool.resolve" | "tool.review" | "tool.inspectImage" | "tool.goal" | "tool.irc";
9
+ export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "status.done" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.search" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.time" | "icon.pi" | "icon.ghost" | "icon.agents" | "icon.job" | "icon.cache" | "icon.cacheMiss" | "icon.input" | "icon.output" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.mic" | "icon.camera" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "radio.selected" | "radio.unselected" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.files" | "tab.shell" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers" | "tool.write" | "tool.edit" | "tool.bash" | "tool.ssh" | "tool.lsp" | "tool.gh" | "tool.webSearch" | "tool.exa" | "tool.browser" | "tool.eval" | "tool.debug" | "tool.mcp" | "tool.job" | "tool.task" | "tool.todo" | "tool.memory" | "tool.ask" | "tool.resolve" | "tool.review" | "tool.inspectImage" | "tool.goal" | "tool.irc";
10
10
  export type SpinnerType = "status" | "activity";
11
11
  export type ThemeColor = "accent" | "border" | "borderAccent" | "borderMuted" | "success" | "error" | "warning" | "muted" | "dim" | "text" | "thinkingText" | "userMessageText" | "customMessageText" | "customMessageLabel" | "toolTitle" | "toolOutput" | "mdHeading" | "mdLink" | "mdLinkUrl" | "mdCode" | "mdCodeBlock" | "mdCodeBlockBorder" | "mdQuote" | "mdQuoteBorder" | "mdHr" | "mdListBullet" | "toolDiffAdded" | "toolDiffRemoved" | "toolDiffContext" | "syntaxComment" | "syntaxKeyword" | "syntaxFunction" | "syntaxVariable" | "syntaxString" | "syntaxNumber" | "syntaxType" | "syntaxOperator" | "syntaxPunctuation" | "thinkingOff" | "thinkingMinimal" | "thinkingLow" | "thinkingMedium" | "thinkingHigh" | "thinkingXhigh" | "bashMode" | "pythonMode" | "statusLineSep" | "statusLineModel" | "statusLinePath" | "statusLineGitClean" | "statusLineGitDirty" | "statusLineContext" | "statusLineSpend" | "statusLineStaged" | "statusLineDirty" | "statusLineUntracked" | "statusLineOutput" | "statusLineCost" | "statusLineSubagents";
12
12
  /** Check if a string is a valid ThemeColor value */
@@ -123,6 +123,11 @@ export declare class Theme {
123
123
  bottomRight: string;
124
124
  horizontal: string;
125
125
  vertical: string;
126
+ cross: string;
127
+ teeDown: string;
128
+ teeUp: string;
129
+ teeRight: string;
130
+ teeLeft: string;
126
131
  };
127
132
  get boxSharp(): {
128
133
  topLeft: string;
@@ -173,6 +178,7 @@ export declare class Theme {
173
178
  agents: string;
174
179
  job: string;
175
180
  cache: string;
181
+ cacheMiss: string;
176
182
  input: string;
177
183
  output: string;
178
184
  host: string;
@@ -1,6 +1,6 @@
1
1
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
2
  import type { CompactionOutcome } from "@oh-my-pi/pi-agent-core/compaction";
3
- import type { AssistantMessage, ImageContent, Message, UsageReport } from "@oh-my-pi/pi-ai";
3
+ import type { AssistantMessage, ImageContent, Message, Usage, UsageReport } from "@oh-my-pi/pi-ai";
4
4
  import type { Component, Container, EditorTheme, Loader, Spacer, Text, TUI } from "@oh-my-pi/pi-tui";
5
5
  import type { CollabGuestLink } from "../collab/guest";
6
6
  import type { CollabHost } from "../collab/host";
@@ -11,6 +11,7 @@ import type { CompactOptions } from "../extensibility/extensions/types";
11
11
  import type { MCPManager } from "../mcp";
12
12
  import type { PlanApprovalDetails } from "../plan-mode/approved-plan";
13
13
  import type { AgentSession } from "../session/agent-session";
14
+ import type { CompactMode } from "../session/compact-modes";
14
15
  import type { HistoryStorage } from "../session/history-storage";
15
16
  import type { SessionContext } from "../session/session-context";
16
17
  import type { SessionManager } from "../session/session-manager";
@@ -139,6 +140,12 @@ export interface InteractiveModeContext {
139
140
  isPythonMode: boolean;
140
141
  streamingComponent: AssistantMessageComponent | undefined;
141
142
  streamingMessage: AssistantMessage | undefined;
143
+ /**
144
+ * Usage of the most recently rendered assistant turn, used to detect a
145
+ * prompt-cache invalidation on the next turn (cache footprint collapse).
146
+ * Reseeded by `renderSessionContext` on every rebuild/session switch.
147
+ */
148
+ lastAssistantUsage: Usage | undefined;
142
149
  loadingAnimation: Loader | undefined;
143
150
  autoCompactionLoader: Loader | undefined;
144
151
  retryLoader: Loader | undefined;
@@ -273,7 +280,7 @@ export interface InteractiveModeContext {
273
280
  handlePythonCommand(code: string, excludeFromContext?: boolean): Promise<void>;
274
281
  handleMCPCommand(text: string): Promise<void>;
275
282
  handleSSHCommand(text: string): Promise<void>;
276
- handleCompactCommand(customInstructions?: string): Promise<CompactionOutcome>;
283
+ handleCompactCommand(customInstructions?: string, mode?: CompactMode): Promise<CompactionOutcome>;
277
284
  handleHandoffCommand(customInstructions?: string): Promise<void>;
278
285
  handleShakeCommand(mode: ShakeMode): Promise<void>;
279
286
  handleMoveCommand(targetPath: string): Promise<void>;
@@ -18,7 +18,13 @@ export declare const MAIN_AGENT_ID = "Main";
18
18
  * - `aborted`: hard-killed, terminal.
19
19
  */
20
20
  export type AgentStatus = "running" | "idle" | "parked" | "aborted";
21
- export type AgentKind = "main" | "sub";
21
+ /**
22
+ * - `main`/`sub`: the user-facing agent tree (driving agent + task subagents).
23
+ * - `advisor`: a passive review transcript persisted like a subagent for usage
24
+ * attribution and Agent Hub observability, but never a peer — hidden from
25
+ * agent-facing rosters (`irc`, `history://`) and not messageable/revivable.
26
+ */
27
+ export type AgentKind = "main" | "sub" | "advisor";
22
28
  export interface AgentRef {
23
29
  id: string;
24
30
  displayName: string;
@@ -81,8 +87,9 @@ export declare class AgentRegistry {
81
87
  get(id: string): AgentRef | undefined;
82
88
  list(): AgentRef[];
83
89
  /**
84
- * Returns every alive agent (running | idle) except the caller.
85
- * Flat namespace: every agent can see every other agent.
90
+ * Returns every alive agent (running | idle) except the caller. Advisor refs
91
+ * are observability-only transcripts, never peers, so they are excluded.
92
+ * Flat namespace: every other agent is visible.
86
93
  */
87
94
  listVisibleTo(id: string): AgentRef[];
88
95
  onChange(listener: RegistryListener): () => void;
@@ -288,7 +288,7 @@ export interface BuildSystemPromptOptions {
288
288
  }>;
289
289
  cwd?: string;
290
290
  appendPrompt?: string;
291
- repeatToolDescriptions?: boolean;
291
+ inlineToolDescriptors?: boolean;
292
292
  }
293
293
  /**
294
294
  * Build the default provider-facing system prompt blocks.
@@ -13,7 +13,7 @@
13
13
  * Modes use this class and add their own I/O layer on top.
14
14
  */
15
15
  import type { InMemorySnapshotStore } from "@oh-my-pi/hashline";
16
- import { Agent, type AgentEvent, type AgentMessage, type AgentState, type AgentTool, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
16
+ import { Agent, type AgentEvent, type AgentMessage, type AgentState, type AgentTool, ThinkingLevel, type ToolChoiceDirective } from "@oh-my-pi/pi-agent-core";
17
17
  import { type CompactionResult, type ShakeConfig } from "@oh-my-pi/pi-agent-core/compaction";
18
18
  import type { AssistantMessage, ImageContent, Message, MessageAttribution, Model, ProviderSessionState, ResetCreditAccountStatus, ResetCreditRedeemOutcome, ResetCreditTarget, ServiceTier, SimpleStreamOptions, TextContent, ToolChoice, UsageReport } from "@oh-my-pi/pi-ai";
19
19
  import { Effort } from "@oh-my-pi/pi-ai";
@@ -237,6 +237,12 @@ export interface AgentSessionConfig {
237
237
  advisorReadOnlyTools?: AgentTool[];
238
238
  /** Preloaded watchdog prompt content for the advisor. */
239
239
  advisorWatchdogPrompt?: string;
240
+ /**
241
+ * Strip tool descriptions from provider-bound tool specs on side requests
242
+ * (handoff). Must match the session-start value used to build the system
243
+ * prompt so inline descriptors are not also sent through provider schemas.
244
+ */
245
+ pruneToolDescriptions?: boolean;
240
246
  /**
241
247
  * Disconnect this session's OWNED MCP manager on dispose. Provided only when
242
248
  * the session created the manager (top-level sessions); subagents reuse a
@@ -380,6 +386,19 @@ export declare class AgentSession {
380
386
  getAgentId(): string | undefined;
381
387
  /** Advance the tool-choice queue and return the next directive for the upcoming LLM call. */
382
388
  nextToolChoice(): ToolChoice | undefined;
389
+ /**
390
+ * The per-turn tool-choice directive for the agent loop's `getToolChoice`. Priority:
391
+ * 1. a HARD forced choice from the queue (genuine forces: user-force, eager-todo, …) —
392
+ * consuming, unchanged from `nextToolChoice`;
393
+ * 2. else, when a non-forcing preview is pending, a {@link SoftToolRequirement} — a
394
+ * PEEK (advances/pops nothing), so the agent-loop injects the reminder once per head
395
+ * and escalates to a forced `resolve` only if the model declines. A compliant turn
396
+ * pays ZERO tool_choice change (no prompt-cache messages-cache invalidation);
397
+ * 3. else undefined.
398
+ */
399
+ nextToolChoiceDirective(): ToolChoiceDirective | undefined;
400
+ /** Peek the head non-forcing pending preview invoker, for the `resolve` tool's dispatch. */
401
+ peekPendingInvoker(): ((input: unknown) => Promise<unknown> | unknown) | undefined;
383
402
  /**
384
403
  * Force the next model call to target a specific active tool, then terminate
385
404
  * the agent loop. Pushes a two-step sequence [forced, "none"] so the model