@bastani/atomic 0.9.3-alpha.1 → 0.9.3-alpha.2

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 (172) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/builtin/cursor/CHANGELOG.md +15 -0
  3. package/dist/builtin/cursor/README.md +2 -1
  4. package/dist/builtin/cursor/package.json +2 -2
  5. package/dist/builtin/cursor/src/cursor-models-raw.json +2 -9
  6. package/dist/builtin/cursor/src/model-mapper.ts +14 -3
  7. package/dist/builtin/cursor/src/proto/protobuf-codec-base64.ts +22 -0
  8. package/dist/builtin/cursor/src/proto/protobuf-codec-request.ts +53 -13
  9. package/dist/builtin/cursor/src/proto/protobuf-codec-wire.ts +24 -7
  10. package/dist/builtin/cursor/src/proto/protobuf-codec.ts +3 -2
  11. package/dist/builtin/cursor/src/stream.ts +5 -11
  12. package/dist/builtin/cursor/src/transport-types.ts +3 -0
  13. package/dist/builtin/cursor/src/transport.ts +1 -0
  14. package/dist/builtin/intercom/package.json +1 -1
  15. package/dist/builtin/mcp/package.json +1 -1
  16. package/dist/builtin/subagents/CHANGELOG.md +9 -0
  17. package/dist/builtin/subagents/package.json +1 -1
  18. package/dist/builtin/subagents/src/extension/fanout-child.ts +1 -0
  19. package/dist/builtin/subagents/src/extension/index.ts +6 -3
  20. package/dist/builtin/subagents/src/extension/schemas.ts +0 -5
  21. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +1 -4
  22. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +15 -1
  23. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +35 -1
  24. package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +4 -2
  25. package/dist/builtin/subagents/src/shared/types-async.ts +1 -0
  26. package/dist/builtin/subagents/src/slash/prompt-template-bridge.ts +27 -5
  27. package/dist/builtin/subagents/src/tui/render-layout.ts +27 -4
  28. package/dist/builtin/subagents/src/tui/render-result-animation.ts +22 -31
  29. package/dist/builtin/subagents/src/tui/render-result-compact.ts +6 -6
  30. package/dist/builtin/subagents/src/tui/render-result.ts +20 -19
  31. package/dist/builtin/subagents/src/tui/render-status-progress.ts +3 -3
  32. package/dist/builtin/subagents/src/tui/render-widget.ts +46 -7
  33. package/dist/builtin/subagents/src/tui/render.ts +2 -2
  34. package/dist/builtin/web-access/package.json +1 -1
  35. package/dist/builtin/workflows/CHANGELOG.md +43 -0
  36. package/dist/builtin/workflows/README.md +1 -1
  37. package/dist/builtin/workflows/package.json +1 -1
  38. package/dist/builtin/workflows/src/authoring.d.ts +1 -1
  39. package/dist/builtin/workflows/src/durable/backend.ts +343 -0
  40. package/dist/builtin/workflows/src/durable/child-primitive.ts +79 -0
  41. package/dist/builtin/workflows/src/durable/dbos-backend.ts +421 -0
  42. package/dist/builtin/workflows/src/durable/dbos-envelope.ts +171 -0
  43. package/dist/builtin/workflows/src/durable/factory.ts +96 -0
  44. package/dist/builtin/workflows/src/durable/file-backend.ts +433 -0
  45. package/dist/builtin/workflows/src/durable/index.ts +73 -0
  46. package/dist/builtin/workflows/src/durable/resume-catalog.ts +217 -0
  47. package/dist/builtin/workflows/src/durable/resume-runtime.ts +299 -0
  48. package/dist/builtin/workflows/src/durable/scoped-backend.ts +171 -0
  49. package/dist/builtin/workflows/src/durable/stage-primitive.ts +284 -0
  50. package/dist/builtin/workflows/src/durable/tool-primitive.ts +180 -0
  51. package/dist/builtin/workflows/src/durable/types.ts +168 -0
  52. package/dist/builtin/workflows/src/durable/ui-primitive.ts +96 -0
  53. package/dist/builtin/workflows/src/engine/options.ts +3 -0
  54. package/dist/builtin/workflows/src/engine/primitives/parallel.ts +2 -2
  55. package/dist/builtin/workflows/src/engine/primitives/task.ts +4 -4
  56. package/dist/builtin/workflows/src/engine/primitives/ui.ts +22 -8
  57. package/dist/builtin/workflows/src/engine/primitives/workflow.ts +8 -0
  58. package/dist/builtin/workflows/src/engine/run-durable-finalize.ts +69 -0
  59. package/dist/builtin/workflows/src/engine/run-durable-stage-session.ts +31 -0
  60. package/dist/builtin/workflows/src/engine/run.ts +148 -6
  61. package/dist/builtin/workflows/src/engine/runtime.ts +8 -2
  62. package/dist/builtin/workflows/src/extension/extension-factory.ts +6 -12
  63. package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +5 -1
  64. package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +3 -0
  65. package/dist/builtin/workflows/src/extension/runtime.ts +48 -9
  66. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +143 -4
  67. package/dist/builtin/workflows/src/runs/background/quit.ts +61 -0
  68. package/dist/builtin/workflows/src/runs/background/status.ts +1 -0
  69. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +5 -5
  70. package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +74 -33
  71. package/dist/builtin/workflows/src/runs/foreground/executor-stage-context.ts +20 -1
  72. package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +8 -7
  73. package/dist/builtin/workflows/src/runs/foreground/executor-stage-replay.ts +1 -0
  74. package/dist/builtin/workflows/src/runs/foreground/executor-stage-types.ts +1 -1
  75. package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +19 -2
  76. package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +4 -0
  77. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +10 -10
  78. package/dist/builtin/workflows/src/runs/foreground/stage-runner-options.ts +5 -1
  79. package/dist/builtin/workflows/src/runs/foreground/stage-runner-send-user-message.ts +25 -0
  80. package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +3 -0
  81. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +16 -0
  82. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +20 -0
  83. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +23 -1
  84. package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +30 -1
  85. package/dist/builtin/workflows/src/shared/store-public-types.ts +6 -2
  86. package/dist/builtin/workflows/src/shared/store-run-methods.ts +12 -6
  87. package/dist/builtin/workflows/src/shared/types.ts +55 -0
  88. package/dist/builtin/workflows/src/tui/graph-view-constants.ts +1 -1
  89. package/dist/builtin/workflows/src/tui/graph-view-graph-render.ts +41 -0
  90. package/dist/builtin/workflows/src/tui/graph-view-input.ts +82 -24
  91. package/dist/builtin/workflows/src/tui/graph-view-render.ts +7 -0
  92. package/dist/builtin/workflows/src/tui/graph-view-state.ts +22 -2
  93. package/dist/builtin/workflows/src/tui/graph-view-types.ts +4 -5
  94. package/dist/builtin/workflows/src/tui/overlay-adapter.ts +9 -11
  95. package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +9 -3
  96. package/dist/builtin/workflows/src/tui/stage-chat-view-input.ts +11 -2
  97. package/dist/builtin/workflows/src/tui/stage-chat-view-live-events.ts +35 -0
  98. package/dist/builtin/workflows/src/tui/stage-chat-view-state.ts +51 -17
  99. package/dist/builtin/workflows/src/tui/stage-chat-view-status.ts +36 -0
  100. package/dist/builtin/workflows/src/tui/stage-chat-view-types.ts +5 -1
  101. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +3 -1
  102. package/dist/builtin/workflows/src/tui/status-list.ts +14 -2
  103. package/dist/builtin/workflows/src/tui/widget.ts +23 -8
  104. package/dist/builtin/workflows/src/tui/workflow-attach-pane-types.ts +5 -4
  105. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +8 -8
  106. package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +151 -0
  107. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  108. package/dist/core/extensions/loader-virtual-modules.js +47 -30
  109. package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
  110. package/dist/core/messages.d.ts +1 -0
  111. package/dist/core/messages.d.ts.map +1 -1
  112. package/dist/core/messages.js +46 -1
  113. package/dist/core/messages.js.map +1 -1
  114. package/dist/core/sdk.d.ts.map +1 -1
  115. package/dist/core/sdk.js +12 -0
  116. package/dist/core/sdk.js.map +1 -1
  117. package/dist/core/session-manager-core.d.ts +15 -7
  118. package/dist/core/session-manager-core.d.ts.map +1 -1
  119. package/dist/core/session-manager-core.js +20 -9
  120. package/dist/core/session-manager-core.js.map +1 -1
  121. package/dist/core/session-manager-entries.d.ts +2 -2
  122. package/dist/core/session-manager-entries.d.ts.map +1 -1
  123. package/dist/core/session-manager-entries.js +9 -3
  124. package/dist/core/session-manager-entries.js.map +1 -1
  125. package/dist/core/session-manager-history.d.ts.map +1 -1
  126. package/dist/core/session-manager-history.js +2 -1
  127. package/dist/core/session-manager-history.js.map +1 -1
  128. package/dist/core/session-manager-list.d.ts +3 -3
  129. package/dist/core/session-manager-list.d.ts.map +1 -1
  130. package/dist/core/session-manager-list.js +27 -8
  131. package/dist/core/session-manager-list.js.map +1 -1
  132. package/dist/core/session-manager-storage.d.ts +3 -1
  133. package/dist/core/session-manager-storage.d.ts.map +1 -1
  134. package/dist/core/session-manager-storage.js +55 -12
  135. package/dist/core/session-manager-storage.js.map +1 -1
  136. package/dist/core/session-manager-tool-dependencies.d.ts +10 -0
  137. package/dist/core/session-manager-tool-dependencies.d.ts.map +1 -0
  138. package/dist/core/session-manager-tool-dependencies.js +133 -0
  139. package/dist/core/session-manager-tool-dependencies.js.map +1 -0
  140. package/dist/core/session-manager-types.d.ts +22 -0
  141. package/dist/core/session-manager-types.d.ts.map +1 -1
  142. package/dist/core/session-manager-types.js.map +1 -1
  143. package/dist/core/session-manager.d.ts +2 -2
  144. package/dist/core/session-manager.d.ts.map +1 -1
  145. package/dist/core/session-manager.js +1 -1
  146. package/dist/core/session-manager.js.map +1 -1
  147. package/dist/modes/interactive/components/chat-session-host-runtime.d.ts +1 -0
  148. package/dist/modes/interactive/components/chat-session-host-runtime.d.ts.map +1 -1
  149. package/dist/modes/interactive/components/chat-session-host-runtime.js +12 -0
  150. package/dist/modes/interactive/components/chat-session-host-runtime.js.map +1 -1
  151. package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.d.ts +4 -0
  152. package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.d.ts.map +1 -0
  153. package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.js +131 -0
  154. package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.js.map +1 -0
  155. package/dist/modes/interactive/components/chat-session-host.d.ts +2 -0
  156. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  157. package/dist/modes/interactive/components/chat-session-host.js +7 -1
  158. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  159. package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -1
  160. package/dist/modes/interactive/components/chat-transcript.js +15 -4
  161. package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
  162. package/dist/modes/interactive/components/tool-execution.d.ts +3 -0
  163. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  164. package/dist/modes/interactive/components/tool-execution.js +26 -0
  165. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  166. package/docs/compaction.md +2 -0
  167. package/docs/models.md +1 -1
  168. package/docs/providers.md +2 -1
  169. package/docs/session-format.md +6 -0
  170. package/docs/sessions.md +6 -0
  171. package/docs/workflows.md +105 -3
  172. package/package.json +4 -3
@@ -0,0 +1,10 @@
1
+ import type { ContextDeletionFilters, SessionEntry } from "./session-manager-types.ts";
2
+ /**
3
+ * Reconcile persisted context-compaction filters in place so replay never
4
+ * retains only one side of a tool-call/tool-result pair. Callers should pass a
5
+ * fresh, unshared filter set; this mutates and returns that same object. The
6
+ * fixpoint normally converges in one or two passes, while the bounded pass
7
+ * count is only a non-termination backstop for malformed historical sessions.
8
+ */
9
+ export declare function reconcilePersistedToolDependencyFilters(path: SessionEntry[], filters: ContextDeletionFilters): ContextDeletionFilters;
10
+ //# sourceMappingURL=session-manager-tool-dependencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager-tool-dependencies.d.ts","sourceRoot":"","sources":["../../src/core/session-manager-tool-dependencies.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,YAAY,EAAuB,MAAM,4BAA4B,CAAC;AAiG5G;;;;;;GAMG;AACH,wBAAgB,uCAAuC,CACtD,IAAI,EAAE,YAAY,EAAE,EACpB,OAAO,EAAE,sBAAsB,GAC7B,sBAAsB,CA0CxB","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport { contentArrayHasAssistantThinkingBlock } from \"./thinking-blocks.ts\";\nimport type { ContextDeletionFilters, SessionEntry, SessionMessageEntry } from \"./session-manager-types.ts\";\n\ninterface ToolCallReference {\n\tentry: SessionMessageEntry;\n\tblockIndex: number;\n\thasThinkingContent: boolean;\n}\n\ninterface ToolResultReference {\n\tentry: SessionMessageEntry;\n}\n\nfunction getMessageContent(message: AgentMessage): readonly unknown[] | undefined {\n\treturn \"content\" in message && Array.isArray(message.content) ? message.content : undefined;\n}\n\nfunction getToolCallContentBlockId(block: unknown): string | undefined {\n\tif (!block || typeof block !== \"object\") return undefined;\n\tconst candidate = block as { type?: unknown; id?: unknown };\n\treturn candidate.type === \"toolCall\" && typeof candidate.id === \"string\" ? candidate.id : undefined;\n}\n\nfunction getToolResultCallId(message: AgentMessage): string | undefined {\n\tif (message.role !== \"toolResult\") return undefined;\n\tconst toolCallId = (message as { toolCallId?: unknown }).toolCallId;\n\treturn typeof toolCallId === \"string\" ? toolCallId : undefined;\n}\n\nfunction collectToolReferences(path: SessionEntry[]): {\n\tcallsById: Map<string, ToolCallReference[]>;\n\tresultsByCallId: Map<string, ToolResultReference[]>;\n} {\n\tconst callsById = new Map<string, ToolCallReference[]>();\n\tconst resultsByCallId = new Map<string, ToolResultReference[]>();\n\tfor (const entry of path) {\n\t\tif (entry.type !== \"message\") continue;\n\t\tif (entry.message.role === \"assistant\") {\n\t\t\tconst content = getMessageContent(entry.message);\n\t\t\tif (!content) continue;\n\t\t\tconst hasThinkingContent = contentArrayHasAssistantThinkingBlock(entry.message.content);\n\t\t\tfor (const [blockIndex, block] of content.entries()) {\n\t\t\t\tconst callId = getToolCallContentBlockId(block);\n\t\t\t\tif (!callId) continue;\n\t\t\t\tconst refs = callsById.get(callId) ?? [];\n\t\t\t\trefs.push({ entry, blockIndex, hasThinkingContent });\n\t\t\t\tcallsById.set(callId, refs);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tconst resultCallId = getToolResultCallId(entry.message);\n\t\tif (!resultCallId) continue;\n\t\tconst refs = resultsByCallId.get(resultCallId) ?? [];\n\t\trefs.push({ entry });\n\t\tresultsByCallId.set(resultCallId, refs);\n\t}\n\treturn { callsById, resultsByCallId };\n}\n\nfunction isMessageEntryEffectivelyDeleted(entry: SessionMessageEntry, filters: ContextDeletionFilters): boolean {\n\tif (filters.deletedEntryIds.has(entry.id)) return true;\n\tconst deletedBlocks = filters.deletedContentBlocks.get(entry.id);\n\tif (!deletedBlocks || deletedBlocks.size === 0) return false;\n\tconst content = getMessageContent(entry.message);\n\treturn content !== undefined && content.length > 0 && content.every((_block, index) => deletedBlocks.has(index));\n}\n\nfunction isToolCallDeleted(ref: ToolCallReference, filters: ContextDeletionFilters): boolean {\n\tif (isMessageEntryEffectivelyDeleted(ref.entry, filters)) return true;\n\treturn filters.deletedContentBlocks.get(ref.entry.id)?.has(ref.blockIndex) === true;\n}\n\nfunction isToolResultDeleted(ref: ToolResultReference, filters: ContextDeletionFilters): boolean {\n\treturn isMessageEntryEffectivelyDeleted(ref.entry, filters);\n}\n\nfunction addEntryDeletion(filters: ContextDeletionFilters, entryId: string): boolean {\n\tif (filters.deletedEntryIds.has(entryId)) return false;\n\tfilters.deletedEntryIds.add(entryId);\n\tfilters.deletedContentBlocks.delete(entryId);\n\treturn true;\n}\n\nfunction addToolCallDeletion(filters: ContextDeletionFilters, ref: ToolCallReference): boolean {\n\tif (filters.deletedEntryIds.has(ref.entry.id)) return false;\n\tconst deletedBlocks = filters.deletedContentBlocks.get(ref.entry.id) ?? new Set<number>();\n\tif (deletedBlocks.has(ref.blockIndex)) return false;\n\tdeletedBlocks.add(ref.blockIndex);\n\tfilters.deletedContentBlocks.set(ref.entry.id, deletedBlocks);\n\treturn true;\n}\n\nfunction restoreResultEntry(filters: ContextDeletionFilters, entryId: string): boolean {\n\tconst hadEntryDeletion = filters.deletedEntryIds.delete(entryId);\n\tconst hadBlockDeletion = filters.deletedContentBlocks.delete(entryId);\n\treturn hadEntryDeletion || hadBlockDeletion;\n}\n\n/**\n * Reconcile persisted context-compaction filters in place so replay never\n * retains only one side of a tool-call/tool-result pair. Callers should pass a\n * fresh, unshared filter set; this mutates and returns that same object. The\n * fixpoint normally converges in one or two passes, while the bounded pass\n * count is only a non-termination backstop for malformed historical sessions.\n */\nexport function reconcilePersistedToolDependencyFilters(\n\tpath: SessionEntry[],\n\tfilters: ContextDeletionFilters,\n): ContextDeletionFilters {\n\tconst { callsById, resultsByCallId } = collectToolReferences(path);\n\tif (callsById.size === 0 || resultsByCallId.size === 0) return filters;\n\n\tlet changed = true;\n\tlet remainingPasses = Math.max(1, path.length * 2);\n\twhile (changed && remainingPasses > 0) {\n\t\tchanged = false;\n\t\tremainingPasses -= 1;\n\n\t\tfor (const [callId, callRefs] of callsById) {\n\t\t\tconst resultRefs = resultsByCallId.get(callId) ?? [];\n\t\t\tif (resultRefs.length === 0) continue;\n\t\t\tconst callDeleted = callRefs.every((ref) => isToolCallDeleted(ref, filters));\n\t\t\tif (callDeleted) {\n\t\t\t\tfor (const resultRef of resultRefs) {\n\t\t\t\t\tif (!isToolResultDeleted(resultRef, filters)) {\n\t\t\t\t\t\tchanged = addEntryDeletion(filters, resultRef.entry.id) || changed;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const resultRef of resultRefs) {\n\t\t\t\tif (!isToolResultDeleted(resultRef, filters)) continue;\n\t\t\t\tconst retainedThinkingCall = callRefs.some(\n\t\t\t\t\t(ref) => ref.hasThinkingContent && !isToolCallDeleted(ref, filters),\n\t\t\t\t);\n\t\t\t\tif (retainedThinkingCall) {\n\t\t\t\t\tchanged = restoreResultEntry(filters, resultRef.entry.id) || changed;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tfor (const callRef of callRefs) {\n\t\t\t\t\tif (!isToolCallDeleted(callRef, filters)) {\n\t\t\t\t\t\tchanged = addToolCallDeletion(filters, callRef) || changed;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn filters;\n}\n"]}
@@ -0,0 +1,133 @@
1
+ import { contentArrayHasAssistantThinkingBlock } from "./thinking-blocks.js";
2
+ function getMessageContent(message) {
3
+ return "content" in message && Array.isArray(message.content) ? message.content : undefined;
4
+ }
5
+ function getToolCallContentBlockId(block) {
6
+ if (!block || typeof block !== "object")
7
+ return undefined;
8
+ const candidate = block;
9
+ return candidate.type === "toolCall" && typeof candidate.id === "string" ? candidate.id : undefined;
10
+ }
11
+ function getToolResultCallId(message) {
12
+ if (message.role !== "toolResult")
13
+ return undefined;
14
+ const toolCallId = message.toolCallId;
15
+ return typeof toolCallId === "string" ? toolCallId : undefined;
16
+ }
17
+ function collectToolReferences(path) {
18
+ const callsById = new Map();
19
+ const resultsByCallId = new Map();
20
+ for (const entry of path) {
21
+ if (entry.type !== "message")
22
+ continue;
23
+ if (entry.message.role === "assistant") {
24
+ const content = getMessageContent(entry.message);
25
+ if (!content)
26
+ continue;
27
+ const hasThinkingContent = contentArrayHasAssistantThinkingBlock(entry.message.content);
28
+ for (const [blockIndex, block] of content.entries()) {
29
+ const callId = getToolCallContentBlockId(block);
30
+ if (!callId)
31
+ continue;
32
+ const refs = callsById.get(callId) ?? [];
33
+ refs.push({ entry, blockIndex, hasThinkingContent });
34
+ callsById.set(callId, refs);
35
+ }
36
+ continue;
37
+ }
38
+ const resultCallId = getToolResultCallId(entry.message);
39
+ if (!resultCallId)
40
+ continue;
41
+ const refs = resultsByCallId.get(resultCallId) ?? [];
42
+ refs.push({ entry });
43
+ resultsByCallId.set(resultCallId, refs);
44
+ }
45
+ return { callsById, resultsByCallId };
46
+ }
47
+ function isMessageEntryEffectivelyDeleted(entry, filters) {
48
+ if (filters.deletedEntryIds.has(entry.id))
49
+ return true;
50
+ const deletedBlocks = filters.deletedContentBlocks.get(entry.id);
51
+ if (!deletedBlocks || deletedBlocks.size === 0)
52
+ return false;
53
+ const content = getMessageContent(entry.message);
54
+ return content !== undefined && content.length > 0 && content.every((_block, index) => deletedBlocks.has(index));
55
+ }
56
+ function isToolCallDeleted(ref, filters) {
57
+ if (isMessageEntryEffectivelyDeleted(ref.entry, filters))
58
+ return true;
59
+ return filters.deletedContentBlocks.get(ref.entry.id)?.has(ref.blockIndex) === true;
60
+ }
61
+ function isToolResultDeleted(ref, filters) {
62
+ return isMessageEntryEffectivelyDeleted(ref.entry, filters);
63
+ }
64
+ function addEntryDeletion(filters, entryId) {
65
+ if (filters.deletedEntryIds.has(entryId))
66
+ return false;
67
+ filters.deletedEntryIds.add(entryId);
68
+ filters.deletedContentBlocks.delete(entryId);
69
+ return true;
70
+ }
71
+ function addToolCallDeletion(filters, ref) {
72
+ if (filters.deletedEntryIds.has(ref.entry.id))
73
+ return false;
74
+ const deletedBlocks = filters.deletedContentBlocks.get(ref.entry.id) ?? new Set();
75
+ if (deletedBlocks.has(ref.blockIndex))
76
+ return false;
77
+ deletedBlocks.add(ref.blockIndex);
78
+ filters.deletedContentBlocks.set(ref.entry.id, deletedBlocks);
79
+ return true;
80
+ }
81
+ function restoreResultEntry(filters, entryId) {
82
+ const hadEntryDeletion = filters.deletedEntryIds.delete(entryId);
83
+ const hadBlockDeletion = filters.deletedContentBlocks.delete(entryId);
84
+ return hadEntryDeletion || hadBlockDeletion;
85
+ }
86
+ /**
87
+ * Reconcile persisted context-compaction filters in place so replay never
88
+ * retains only one side of a tool-call/tool-result pair. Callers should pass a
89
+ * fresh, unshared filter set; this mutates and returns that same object. The
90
+ * fixpoint normally converges in one or two passes, while the bounded pass
91
+ * count is only a non-termination backstop for malformed historical sessions.
92
+ */
93
+ export function reconcilePersistedToolDependencyFilters(path, filters) {
94
+ const { callsById, resultsByCallId } = collectToolReferences(path);
95
+ if (callsById.size === 0 || resultsByCallId.size === 0)
96
+ return filters;
97
+ let changed = true;
98
+ let remainingPasses = Math.max(1, path.length * 2);
99
+ while (changed && remainingPasses > 0) {
100
+ changed = false;
101
+ remainingPasses -= 1;
102
+ for (const [callId, callRefs] of callsById) {
103
+ const resultRefs = resultsByCallId.get(callId) ?? [];
104
+ if (resultRefs.length === 0)
105
+ continue;
106
+ const callDeleted = callRefs.every((ref) => isToolCallDeleted(ref, filters));
107
+ if (callDeleted) {
108
+ for (const resultRef of resultRefs) {
109
+ if (!isToolResultDeleted(resultRef, filters)) {
110
+ changed = addEntryDeletion(filters, resultRef.entry.id) || changed;
111
+ }
112
+ }
113
+ continue;
114
+ }
115
+ for (const resultRef of resultRefs) {
116
+ if (!isToolResultDeleted(resultRef, filters))
117
+ continue;
118
+ const retainedThinkingCall = callRefs.some((ref) => ref.hasThinkingContent && !isToolCallDeleted(ref, filters));
119
+ if (retainedThinkingCall) {
120
+ changed = restoreResultEntry(filters, resultRef.entry.id) || changed;
121
+ continue;
122
+ }
123
+ for (const callRef of callRefs) {
124
+ if (!isToolCallDeleted(callRef, filters)) {
125
+ changed = addToolCallDeletion(filters, callRef) || changed;
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+ return filters;
132
+ }
133
+ //# sourceMappingURL=session-manager-tool-dependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager-tool-dependencies.js","sourceRoot":"","sources":["../../src/core/session-manager-tool-dependencies.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qCAAqC,EAAE,MAAM,sBAAsB,CAAC;AAa7E,SAAS,iBAAiB,CAAC,OAAqB;IAC/C,OAAO,SAAS,IAAI,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7F,CAAC;AAED,SAAS,yBAAyB,CAAC,KAAc;IAChD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC1D,MAAM,SAAS,GAAG,KAAyC,CAAC;IAC5D,OAAO,SAAS,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,SAAS,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACrG,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAqB;IACjD,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,SAAS,CAAC;IACpD,MAAM,UAAU,GAAI,OAAoC,CAAC,UAAU,CAAC;IACpE,OAAO,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;AAChE,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAoB;IAIlD,MAAM,SAAS,GAAG,IAAI,GAAG,EAA+B,CAAC;IACzD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAiC,CAAC;IACjE,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QAC1B,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;YAAE,SAAS;QACvC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACjD,IAAI,CAAC,OAAO;gBAAE,SAAS;YACvB,MAAM,kBAAkB,GAAG,qCAAqC,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACxF,KAAK,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;gBACrD,MAAM,MAAM,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;gBAChD,IAAI,CAAC,MAAM;oBAAE,SAAS;gBACtB,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;gBACzC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBACrD,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC7B,CAAC;YACD,SAAS;QACV,CAAC;QACD,MAAM,YAAY,GAAG,mBAAmB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,YAAY;YAAE,SAAS;QAC5B,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QACrD,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACrB,eAAe,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;AACvC,CAAC;AAED,SAAS,gCAAgC,CAAC,KAA0B,EAAE,OAA+B;IACpG,IAAI,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,MAAM,aAAa,GAAG,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7D,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjD,OAAO,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AAClH,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAsB,EAAE,OAA+B;IACjF,IAAI,gCAAgC,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACtE,OAAO,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;AACrF,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAwB,EAAE,OAA+B;IACrF,OAAO,gCAAgC,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,gBAAgB,CAAC,OAA+B,EAAE,OAAe;IACzE,IAAI,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACvD,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,mBAAmB,CAAC,OAA+B,EAAE,GAAsB;IACnF,IAAI,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5D,MAAM,aAAa,GAAG,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;IAC1F,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,KAAK,CAAC;IACpD,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAClC,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IAC9D,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,kBAAkB,CAAC,OAA+B,EAAE,OAAe;IAC3E,MAAM,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjE,MAAM,gBAAgB,GAAG,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACtE,OAAO,gBAAgB,IAAI,gBAAgB,CAAC;AAC7C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uCAAuC,CACtD,IAAoB,EACpB,OAA+B;IAE/B,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACnE,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,IAAI,eAAe,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IAEvE,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,IAAI,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnD,OAAO,OAAO,IAAI,eAAe,GAAG,CAAC,EAAE,CAAC;QACvC,OAAO,GAAG,KAAK,CAAC;QAChB,eAAe,IAAI,CAAC,CAAC;QAErB,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,SAAS,EAAE,CAAC;YAC5C,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACrD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACtC,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;YAC7E,IAAI,WAAW,EAAE,CAAC;gBACjB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;oBACpC,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;wBAC9C,OAAO,GAAG,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC;oBACpE,CAAC;gBACF,CAAC;gBACD,SAAS;YACV,CAAC;YAED,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;gBACpC,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC;oBAAE,SAAS;gBACvD,MAAM,oBAAoB,GAAG,QAAQ,CAAC,IAAI,CACzC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,kBAAkB,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,CACnE,CAAC;gBACF,IAAI,oBAAoB,EAAE,CAAC;oBAC1B,OAAO,GAAG,kBAAkB,CAAC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC;oBACrE,SAAS;gBACV,CAAC;gBACD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAChC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;wBAC1C,OAAO,GAAG,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,OAAO,CAAC;oBAC5D,CAAC;gBACF,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,OAAO,CAAC;AAChB,CAAC","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport { contentArrayHasAssistantThinkingBlock } from \"./thinking-blocks.ts\";\nimport type { ContextDeletionFilters, SessionEntry, SessionMessageEntry } from \"./session-manager-types.ts\";\n\ninterface ToolCallReference {\n\tentry: SessionMessageEntry;\n\tblockIndex: number;\n\thasThinkingContent: boolean;\n}\n\ninterface ToolResultReference {\n\tentry: SessionMessageEntry;\n}\n\nfunction getMessageContent(message: AgentMessage): readonly unknown[] | undefined {\n\treturn \"content\" in message && Array.isArray(message.content) ? message.content : undefined;\n}\n\nfunction getToolCallContentBlockId(block: unknown): string | undefined {\n\tif (!block || typeof block !== \"object\") return undefined;\n\tconst candidate = block as { type?: unknown; id?: unknown };\n\treturn candidate.type === \"toolCall\" && typeof candidate.id === \"string\" ? candidate.id : undefined;\n}\n\nfunction getToolResultCallId(message: AgentMessage): string | undefined {\n\tif (message.role !== \"toolResult\") return undefined;\n\tconst toolCallId = (message as { toolCallId?: unknown }).toolCallId;\n\treturn typeof toolCallId === \"string\" ? toolCallId : undefined;\n}\n\nfunction collectToolReferences(path: SessionEntry[]): {\n\tcallsById: Map<string, ToolCallReference[]>;\n\tresultsByCallId: Map<string, ToolResultReference[]>;\n} {\n\tconst callsById = new Map<string, ToolCallReference[]>();\n\tconst resultsByCallId = new Map<string, ToolResultReference[]>();\n\tfor (const entry of path) {\n\t\tif (entry.type !== \"message\") continue;\n\t\tif (entry.message.role === \"assistant\") {\n\t\t\tconst content = getMessageContent(entry.message);\n\t\t\tif (!content) continue;\n\t\t\tconst hasThinkingContent = contentArrayHasAssistantThinkingBlock(entry.message.content);\n\t\t\tfor (const [blockIndex, block] of content.entries()) {\n\t\t\t\tconst callId = getToolCallContentBlockId(block);\n\t\t\t\tif (!callId) continue;\n\t\t\t\tconst refs = callsById.get(callId) ?? [];\n\t\t\t\trefs.push({ entry, blockIndex, hasThinkingContent });\n\t\t\t\tcallsById.set(callId, refs);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tconst resultCallId = getToolResultCallId(entry.message);\n\t\tif (!resultCallId) continue;\n\t\tconst refs = resultsByCallId.get(resultCallId) ?? [];\n\t\trefs.push({ entry });\n\t\tresultsByCallId.set(resultCallId, refs);\n\t}\n\treturn { callsById, resultsByCallId };\n}\n\nfunction isMessageEntryEffectivelyDeleted(entry: SessionMessageEntry, filters: ContextDeletionFilters): boolean {\n\tif (filters.deletedEntryIds.has(entry.id)) return true;\n\tconst deletedBlocks = filters.deletedContentBlocks.get(entry.id);\n\tif (!deletedBlocks || deletedBlocks.size === 0) return false;\n\tconst content = getMessageContent(entry.message);\n\treturn content !== undefined && content.length > 0 && content.every((_block, index) => deletedBlocks.has(index));\n}\n\nfunction isToolCallDeleted(ref: ToolCallReference, filters: ContextDeletionFilters): boolean {\n\tif (isMessageEntryEffectivelyDeleted(ref.entry, filters)) return true;\n\treturn filters.deletedContentBlocks.get(ref.entry.id)?.has(ref.blockIndex) === true;\n}\n\nfunction isToolResultDeleted(ref: ToolResultReference, filters: ContextDeletionFilters): boolean {\n\treturn isMessageEntryEffectivelyDeleted(ref.entry, filters);\n}\n\nfunction addEntryDeletion(filters: ContextDeletionFilters, entryId: string): boolean {\n\tif (filters.deletedEntryIds.has(entryId)) return false;\n\tfilters.deletedEntryIds.add(entryId);\n\tfilters.deletedContentBlocks.delete(entryId);\n\treturn true;\n}\n\nfunction addToolCallDeletion(filters: ContextDeletionFilters, ref: ToolCallReference): boolean {\n\tif (filters.deletedEntryIds.has(ref.entry.id)) return false;\n\tconst deletedBlocks = filters.deletedContentBlocks.get(ref.entry.id) ?? new Set<number>();\n\tif (deletedBlocks.has(ref.blockIndex)) return false;\n\tdeletedBlocks.add(ref.blockIndex);\n\tfilters.deletedContentBlocks.set(ref.entry.id, deletedBlocks);\n\treturn true;\n}\n\nfunction restoreResultEntry(filters: ContextDeletionFilters, entryId: string): boolean {\n\tconst hadEntryDeletion = filters.deletedEntryIds.delete(entryId);\n\tconst hadBlockDeletion = filters.deletedContentBlocks.delete(entryId);\n\treturn hadEntryDeletion || hadBlockDeletion;\n}\n\n/**\n * Reconcile persisted context-compaction filters in place so replay never\n * retains only one side of a tool-call/tool-result pair. Callers should pass a\n * fresh, unshared filter set; this mutates and returns that same object. The\n * fixpoint normally converges in one or two passes, while the bounded pass\n * count is only a non-termination backstop for malformed historical sessions.\n */\nexport function reconcilePersistedToolDependencyFilters(\n\tpath: SessionEntry[],\n\tfilters: ContextDeletionFilters,\n): ContextDeletionFilters {\n\tconst { callsById, resultsByCallId } = collectToolReferences(path);\n\tif (callsById.size === 0 || resultsByCallId.size === 0) return filters;\n\n\tlet changed = true;\n\tlet remainingPasses = Math.max(1, path.length * 2);\n\twhile (changed && remainingPasses > 0) {\n\t\tchanged = false;\n\t\tremainingPasses -= 1;\n\n\t\tfor (const [callId, callRefs] of callsById) {\n\t\t\tconst resultRefs = resultsByCallId.get(callId) ?? [];\n\t\t\tif (resultRefs.length === 0) continue;\n\t\t\tconst callDeleted = callRefs.every((ref) => isToolCallDeleted(ref, filters));\n\t\t\tif (callDeleted) {\n\t\t\t\tfor (const resultRef of resultRefs) {\n\t\t\t\t\tif (!isToolResultDeleted(resultRef, filters)) {\n\t\t\t\t\t\tchanged = addEntryDeletion(filters, resultRef.entry.id) || changed;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const resultRef of resultRefs) {\n\t\t\t\tif (!isToolResultDeleted(resultRef, filters)) continue;\n\t\t\t\tconst retainedThinkingCall = callRefs.some(\n\t\t\t\t\t(ref) => ref.hasThinkingContent && !isToolCallDeleted(ref, filters),\n\t\t\t\t);\n\t\t\t\tif (retainedThinkingCall) {\n\t\t\t\t\tchanged = restoreResultEntry(filters, resultRef.entry.id) || changed;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tfor (const callRef of callRefs) {\n\t\t\t\t\tif (!isToolCallDeleted(callRef, filters)) {\n\t\t\t\t\t\tchanged = addToolCallDeletion(filters, callRef) || changed;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn filters;\n}\n"]}
@@ -2,6 +2,16 @@ import type { AgentMessage } from "@earendil-works/pi-agent-core";
2
2
  import type { ImageContent, TextContent } from "@earendil-works/pi-ai";
3
3
  import type { SessionManager } from "./session-manager-core.ts";
4
4
  export declare const CURRENT_SESSION_VERSION = 3;
5
+ /**
6
+ * Workflow linkage persisted on internal (workflow-created) session headers.
7
+ * Used to exclude workflow stage sessions from the standard `/resume` history
8
+ * while keeping them resumable through the workflow-specific resume path.
9
+ */
10
+ export interface SessionWorkflowMetadata {
11
+ runId: string;
12
+ stageId: string;
13
+ stageName: string;
14
+ }
5
15
  export interface SessionHeader {
6
16
  type: "session";
7
17
  version?: number;
@@ -9,10 +19,18 @@ export interface SessionHeader {
9
19
  timestamp: string;
10
20
  cwd: string;
11
21
  parentSession?: string;
22
+ /** Marks sessions created by automated machinery (e.g. workflow stages) so they can be excluded from standard resume history. */
23
+ internal?: boolean;
24
+ /** When internal, links the session to its owning workflow run/stage. */
25
+ workflow?: SessionWorkflowMetadata;
12
26
  }
13
27
  export interface NewSessionOptions {
14
28
  id?: string;
15
29
  parentSession?: string;
30
+ /** Mark the new session as internal (e.g. a workflow stage session). */
31
+ internal?: boolean;
32
+ /** Workflow run/stage linkage for internal workflow sessions. */
33
+ workflow?: SessionWorkflowMetadata;
16
34
  }
17
35
  export interface SessionEntryBase {
18
36
  type: string;
@@ -157,6 +175,10 @@ export interface SessionInfo {
157
175
  name?: string;
158
176
  /** Path to the parent session (if this session was forked). */
159
177
  parentSessionPath?: string;
178
+ /** True when this session was created by automated machinery (e.g. a workflow stage). */
179
+ internal?: boolean;
180
+ /** Workflow run/stage linkage when the session is an internal workflow session. */
181
+ workflow?: SessionWorkflowMetadata;
160
182
  created: Date;
161
183
  modified: Date;
162
184
  messageCount: number;
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager-types.d.ts","sourceRoot":"","sources":["../../src/core/session-manager-types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport type { SessionManager } from \"./session-manager-core.ts\";\n\nexport const CURRENT_SESSION_VERSION = 3;\n\nexport interface SessionHeader {\n\ttype: \"session\";\n\tversion?: number; // v1 sessions don't have this\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tparentSession?: string;\n}\n\nexport interface NewSessionOptions {\n\tid?: string;\n\tparentSession?: string;\n}\n\nexport interface SessionEntryBase {\n\ttype: string;\n\tid: string;\n\tparentId: string | null;\n\ttimestamp: string;\n}\n\nexport interface SessionMessageEntry extends SessionEntryBase {\n\ttype: \"message\";\n\tmessage: AgentMessage;\n}\n\nexport interface ThinkingLevelChangeEntry extends SessionEntryBase {\n\ttype: \"thinking_level_change\";\n\tthinkingLevel: string;\n}\n\nexport interface ContextWindowChangeEntry extends SessionEntryBase {\n\ttype: \"context_window_change\";\n\tcontextWindow: number;\n}\n\nexport interface ModelChangeEntry extends SessionEntryBase {\n\ttype: \"model_change\";\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface CompactionEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"compaction\";\n\tsummary: string;\n\tfirstKeptEntryId: string;\n\ttokensBefore: number;\n\t/** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */\n\tdetails?: T;\n\t/** True if generated by an extension, undefined/false if pi-generated (backward compatible) */\n\tfromHook?: boolean;\n}\n\nexport type ContextDeletionTarget =\n\t| { kind: \"entry\"; entryId: string }\n\t| { kind: \"content_block\"; entryId: string; blockIndex: number };\n\nexport interface ContextCompactionStats {\n\tobjectsBefore: number;\n\tobjectsAfter: number;\n\tobjectsDeleted: number;\n\ttokensBefore: number;\n\ttokensAfter: number;\n\tpercentReduction: number;\n}\n\nexport interface ContextCompactionEntry extends SessionEntryBase {\n\ttype: \"context_compaction\";\n\tpromptVersion: 1;\n\tdeletedTargets: ContextDeletionTarget[];\n\tprotectedEntryIds: string[];\n\tstats: ContextCompactionStats;\n\tbackupPath?: string;\n}\n\nexport interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"branch_summary\";\n\tfromId: string;\n\tsummary: string;\n\t/** Extension-specific data (not sent to LLM) */\n\tdetails?: T;\n\t/** True if generated by an extension, false if pi-generated */\n\tfromHook?: boolean;\n}\n\n/**\n * Custom entry for extensions to store extension-specific data in the session.\n * Use customType to identify your extension's entries.\n *\n * Purpose: Persist extension state across session reloads. On reload, extensions can\n * scan entries for their customType and reconstruct internal state.\n *\n * Does NOT participate in LLM context (ignored by buildSessionContext).\n * For injecting content into context, see CustomMessageEntry.\n */\nexport interface CustomEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom\";\n\tcustomType: string;\n\tdata?: T;\n}\n\n/** Label entry for user-defined bookmarks/markers on entries. */\nexport interface LabelEntry extends SessionEntryBase {\n\ttype: \"label\";\n\ttargetId: string;\n\tlabel: string | undefined;\n}\n\n/** Session metadata entry (e.g., user-defined display name). */\nexport interface SessionInfoEntry extends SessionEntryBase {\n\ttype: \"session_info\";\n\tname?: string;\n}\n\n/**\n * Custom message entry for extensions to inject messages into LLM context.\n * Use customType to identify your extension's entries.\n *\n * Unlike CustomEntry, this usually participates in LLM context.\n * The content is converted to a user message in buildSessionContext() unless\n * excludeFromContext is true. Use details for extension-specific metadata (not sent to LLM).\n *\n * display controls TUI rendering:\n * - false: hidden entirely\n * - true: rendered with distinct styling (different from user messages)\n */\nexport interface CustomMessageEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom_message\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdetails?: T;\n\tdisplay: boolean;\n\texcludeFromContext?: boolean;\n}\n\n/** Session entry - has id/parentId for tree structure (returned by \"read\" methods in SessionManager) */\nexport type SessionEntry =\n\t| SessionMessageEntry\n\t| ThinkingLevelChangeEntry\n\t| ContextWindowChangeEntry\n\t| ModelChangeEntry\n\t| CompactionEntry\n\t| ContextCompactionEntry\n\t| BranchSummaryEntry\n\t| CustomEntry\n\t| CustomMessageEntry\n\t| LabelEntry\n\t| SessionInfoEntry;\n\n/** Raw file entry (includes header) */\nexport type FileEntry = SessionHeader | SessionEntry;\n\n/** Tree node for getTree() - defensive copy of session structure */\nexport interface SessionTreeNode {\n\tentry: SessionEntry;\n\tchildren: SessionTreeNode[];\n\t/** Resolved label for this entry, if any */\n\tlabel?: string;\n\t/** Timestamp of the latest label change for this entry, if any */\n\tlabelTimestamp?: string;\n}\n\nexport interface SessionContext {\n\tmessages: AgentMessage[];\n\tthinkingLevel: string;\n\tcontextWindow: number | undefined;\n\tmodel: { provider: string; modelId: string } | null;\n}\n\nexport interface SessionInfo {\n\tpath: string;\n\tid: string;\n\t/** Working directory where the session was started. Empty string for old sessions. */\n\tcwd: string;\n\t/** User-defined display name from session_info entries. */\n\tname?: string;\n\t/** Path to the parent session (if this session was forked). */\n\tparentSessionPath?: string;\n\tcreated: Date;\n\tmodified: Date;\n\tmessageCount: number;\n\tfirstMessage: string;\n\tallMessagesText: string;\n}\n\nexport interface ContextDeletionFilters {\n\tdeletedEntryIds: Set<string>;\n\tdeletedContentBlocks: Map<string, Set<number>>;\n}\n\nexport type SessionListProgress = (loaded: number, total: number) => void;\n\nexport type ReadonlySessionManager = Pick<\n\tSessionManager,\n\t| \"getCwd\"\n\t| \"getSessionDir\"\n\t| \"usesDefaultSessionDir\"\n\t| \"getSessionId\"\n\t| \"getSessionFile\"\n\t| \"getLeafId\"\n\t| \"getLeafEntry\"\n\t| \"getEntry\"\n\t| \"getLabel\"\n\t| \"getBranch\"\n\t| \"getHeader\"\n\t| \"getEntries\"\n\t| \"getTree\"\n\t| \"getSessionName\"\n>;\n"]}
1
+ {"version":3,"file":"session-manager-types.d.ts","sourceRoot":"","sources":["../../src/core/session-manager-types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport type { SessionManager } from \"./session-manager-core.ts\";\n\nexport const CURRENT_SESSION_VERSION = 3;\n\n/**\n * Workflow linkage persisted on internal (workflow-created) session headers.\n * Used to exclude workflow stage sessions from the standard `/resume` history\n * while keeping them resumable through the workflow-specific resume path.\n */\nexport interface SessionWorkflowMetadata {\n\trunId: string;\n\tstageId: string;\n\tstageName: string;\n}\n\nexport interface SessionHeader {\n\ttype: \"session\";\n\tversion?: number; // v1 sessions don't have this\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tparentSession?: string;\n\t/** Marks sessions created by automated machinery (e.g. workflow stages) so they can be excluded from standard resume history. */\n\tinternal?: boolean;\n\t/** When internal, links the session to its owning workflow run/stage. */\n\tworkflow?: SessionWorkflowMetadata;\n}\n\nexport interface NewSessionOptions {\n\tid?: string;\n\tparentSession?: string;\n\t/** Mark the new session as internal (e.g. a workflow stage session). */\n\tinternal?: boolean;\n\t/** Workflow run/stage linkage for internal workflow sessions. */\n\tworkflow?: SessionWorkflowMetadata;\n}\n\nexport interface SessionEntryBase {\n\ttype: string;\n\tid: string;\n\tparentId: string | null;\n\ttimestamp: string;\n}\n\nexport interface SessionMessageEntry extends SessionEntryBase {\n\ttype: \"message\";\n\tmessage: AgentMessage;\n}\n\nexport interface ThinkingLevelChangeEntry extends SessionEntryBase {\n\ttype: \"thinking_level_change\";\n\tthinkingLevel: string;\n}\n\nexport interface ContextWindowChangeEntry extends SessionEntryBase {\n\ttype: \"context_window_change\";\n\tcontextWindow: number;\n}\n\nexport interface ModelChangeEntry extends SessionEntryBase {\n\ttype: \"model_change\";\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface CompactionEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"compaction\";\n\tsummary: string;\n\tfirstKeptEntryId: string;\n\ttokensBefore: number;\n\t/** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */\n\tdetails?: T;\n\t/** True if generated by an extension, undefined/false if pi-generated (backward compatible) */\n\tfromHook?: boolean;\n}\n\nexport type ContextDeletionTarget =\n\t| { kind: \"entry\"; entryId: string }\n\t| { kind: \"content_block\"; entryId: string; blockIndex: number };\n\nexport interface ContextCompactionStats {\n\tobjectsBefore: number;\n\tobjectsAfter: number;\n\tobjectsDeleted: number;\n\ttokensBefore: number;\n\ttokensAfter: number;\n\tpercentReduction: number;\n}\n\nexport interface ContextCompactionEntry extends SessionEntryBase {\n\ttype: \"context_compaction\";\n\tpromptVersion: 1;\n\tdeletedTargets: ContextDeletionTarget[];\n\tprotectedEntryIds: string[];\n\tstats: ContextCompactionStats;\n\tbackupPath?: string;\n}\n\nexport interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"branch_summary\";\n\tfromId: string;\n\tsummary: string;\n\t/** Extension-specific data (not sent to LLM) */\n\tdetails?: T;\n\t/** True if generated by an extension, false if pi-generated */\n\tfromHook?: boolean;\n}\n\n/**\n * Custom entry for extensions to store extension-specific data in the session.\n * Use customType to identify your extension's entries.\n *\n * Purpose: Persist extension state across session reloads. On reload, extensions can\n * scan entries for their customType and reconstruct internal state.\n *\n * Does NOT participate in LLM context (ignored by buildSessionContext).\n * For injecting content into context, see CustomMessageEntry.\n */\nexport interface CustomEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom\";\n\tcustomType: string;\n\tdata?: T;\n}\n\n/** Label entry for user-defined bookmarks/markers on entries. */\nexport interface LabelEntry extends SessionEntryBase {\n\ttype: \"label\";\n\ttargetId: string;\n\tlabel: string | undefined;\n}\n\n/** Session metadata entry (e.g., user-defined display name). */\nexport interface SessionInfoEntry extends SessionEntryBase {\n\ttype: \"session_info\";\n\tname?: string;\n}\n\n/**\n * Custom message entry for extensions to inject messages into LLM context.\n * Use customType to identify your extension's entries.\n *\n * Unlike CustomEntry, this usually participates in LLM context.\n * The content is converted to a user message in buildSessionContext() unless\n * excludeFromContext is true. Use details for extension-specific metadata (not sent to LLM).\n *\n * display controls TUI rendering:\n * - false: hidden entirely\n * - true: rendered with distinct styling (different from user messages)\n */\nexport interface CustomMessageEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom_message\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdetails?: T;\n\tdisplay: boolean;\n\texcludeFromContext?: boolean;\n}\n\n/** Session entry - has id/parentId for tree structure (returned by \"read\" methods in SessionManager) */\nexport type SessionEntry =\n\t| SessionMessageEntry\n\t| ThinkingLevelChangeEntry\n\t| ContextWindowChangeEntry\n\t| ModelChangeEntry\n\t| CompactionEntry\n\t| ContextCompactionEntry\n\t| BranchSummaryEntry\n\t| CustomEntry\n\t| CustomMessageEntry\n\t| LabelEntry\n\t| SessionInfoEntry;\n\n/** Raw file entry (includes header) */\nexport type FileEntry = SessionHeader | SessionEntry;\n\n/** Tree node for getTree() - defensive copy of session structure */\nexport interface SessionTreeNode {\n\tentry: SessionEntry;\n\tchildren: SessionTreeNode[];\n\t/** Resolved label for this entry, if any */\n\tlabel?: string;\n\t/** Timestamp of the latest label change for this entry, if any */\n\tlabelTimestamp?: string;\n}\n\nexport interface SessionContext {\n\tmessages: AgentMessage[];\n\tthinkingLevel: string;\n\tcontextWindow: number | undefined;\n\tmodel: { provider: string; modelId: string } | null;\n}\n\nexport interface SessionInfo {\n\tpath: string;\n\tid: string;\n\t/** Working directory where the session was started. Empty string for old sessions. */\n\tcwd: string;\n\t/** User-defined display name from session_info entries. */\n\tname?: string;\n\t/** Path to the parent session (if this session was forked). */\n\tparentSessionPath?: string;\n\t/** True when this session was created by automated machinery (e.g. a workflow stage). */\n\tinternal?: boolean;\n\t/** Workflow run/stage linkage when the session is an internal workflow session. */\n\tworkflow?: SessionWorkflowMetadata;\n\tcreated: Date;\n\tmodified: Date;\n\tmessageCount: number;\n\tfirstMessage: string;\n\tallMessagesText: string;\n}\n\nexport interface ContextDeletionFilters {\n\tdeletedEntryIds: Set<string>;\n\tdeletedContentBlocks: Map<string, Set<number>>;\n}\n\nexport type SessionListProgress = (loaded: number, total: number) => void;\n\nexport type ReadonlySessionManager = Pick<\n\tSessionManager,\n\t| \"getCwd\"\n\t| \"getSessionDir\"\n\t| \"usesDefaultSessionDir\"\n\t| \"getSessionId\"\n\t| \"getSessionFile\"\n\t| \"getLeafId\"\n\t| \"getLeafEntry\"\n\t| \"getEntry\"\n\t| \"getLabel\"\n\t| \"getBranch\"\n\t| \"getHeader\"\n\t| \"getEntries\"\n\t| \"getTree\"\n\t| \"getSessionName\"\n>;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager-types.js","sourceRoot":"","sources":["../../src/core/session-manager-types.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport type { SessionManager } from \"./session-manager-core.ts\";\n\nexport const CURRENT_SESSION_VERSION = 3;\n\nexport interface SessionHeader {\n\ttype: \"session\";\n\tversion?: number; // v1 sessions don't have this\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tparentSession?: string;\n}\n\nexport interface NewSessionOptions {\n\tid?: string;\n\tparentSession?: string;\n}\n\nexport interface SessionEntryBase {\n\ttype: string;\n\tid: string;\n\tparentId: string | null;\n\ttimestamp: string;\n}\n\nexport interface SessionMessageEntry extends SessionEntryBase {\n\ttype: \"message\";\n\tmessage: AgentMessage;\n}\n\nexport interface ThinkingLevelChangeEntry extends SessionEntryBase {\n\ttype: \"thinking_level_change\";\n\tthinkingLevel: string;\n}\n\nexport interface ContextWindowChangeEntry extends SessionEntryBase {\n\ttype: \"context_window_change\";\n\tcontextWindow: number;\n}\n\nexport interface ModelChangeEntry extends SessionEntryBase {\n\ttype: \"model_change\";\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface CompactionEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"compaction\";\n\tsummary: string;\n\tfirstKeptEntryId: string;\n\ttokensBefore: number;\n\t/** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */\n\tdetails?: T;\n\t/** True if generated by an extension, undefined/false if pi-generated (backward compatible) */\n\tfromHook?: boolean;\n}\n\nexport type ContextDeletionTarget =\n\t| { kind: \"entry\"; entryId: string }\n\t| { kind: \"content_block\"; entryId: string; blockIndex: number };\n\nexport interface ContextCompactionStats {\n\tobjectsBefore: number;\n\tobjectsAfter: number;\n\tobjectsDeleted: number;\n\ttokensBefore: number;\n\ttokensAfter: number;\n\tpercentReduction: number;\n}\n\nexport interface ContextCompactionEntry extends SessionEntryBase {\n\ttype: \"context_compaction\";\n\tpromptVersion: 1;\n\tdeletedTargets: ContextDeletionTarget[];\n\tprotectedEntryIds: string[];\n\tstats: ContextCompactionStats;\n\tbackupPath?: string;\n}\n\nexport interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"branch_summary\";\n\tfromId: string;\n\tsummary: string;\n\t/** Extension-specific data (not sent to LLM) */\n\tdetails?: T;\n\t/** True if generated by an extension, false if pi-generated */\n\tfromHook?: boolean;\n}\n\n/**\n * Custom entry for extensions to store extension-specific data in the session.\n * Use customType to identify your extension's entries.\n *\n * Purpose: Persist extension state across session reloads. On reload, extensions can\n * scan entries for their customType and reconstruct internal state.\n *\n * Does NOT participate in LLM context (ignored by buildSessionContext).\n * For injecting content into context, see CustomMessageEntry.\n */\nexport interface CustomEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom\";\n\tcustomType: string;\n\tdata?: T;\n}\n\n/** Label entry for user-defined bookmarks/markers on entries. */\nexport interface LabelEntry extends SessionEntryBase {\n\ttype: \"label\";\n\ttargetId: string;\n\tlabel: string | undefined;\n}\n\n/** Session metadata entry (e.g., user-defined display name). */\nexport interface SessionInfoEntry extends SessionEntryBase {\n\ttype: \"session_info\";\n\tname?: string;\n}\n\n/**\n * Custom message entry for extensions to inject messages into LLM context.\n * Use customType to identify your extension's entries.\n *\n * Unlike CustomEntry, this usually participates in LLM context.\n * The content is converted to a user message in buildSessionContext() unless\n * excludeFromContext is true. Use details for extension-specific metadata (not sent to LLM).\n *\n * display controls TUI rendering:\n * - false: hidden entirely\n * - true: rendered with distinct styling (different from user messages)\n */\nexport interface CustomMessageEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom_message\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdetails?: T;\n\tdisplay: boolean;\n\texcludeFromContext?: boolean;\n}\n\n/** Session entry - has id/parentId for tree structure (returned by \"read\" methods in SessionManager) */\nexport type SessionEntry =\n\t| SessionMessageEntry\n\t| ThinkingLevelChangeEntry\n\t| ContextWindowChangeEntry\n\t| ModelChangeEntry\n\t| CompactionEntry\n\t| ContextCompactionEntry\n\t| BranchSummaryEntry\n\t| CustomEntry\n\t| CustomMessageEntry\n\t| LabelEntry\n\t| SessionInfoEntry;\n\n/** Raw file entry (includes header) */\nexport type FileEntry = SessionHeader | SessionEntry;\n\n/** Tree node for getTree() - defensive copy of session structure */\nexport interface SessionTreeNode {\n\tentry: SessionEntry;\n\tchildren: SessionTreeNode[];\n\t/** Resolved label for this entry, if any */\n\tlabel?: string;\n\t/** Timestamp of the latest label change for this entry, if any */\n\tlabelTimestamp?: string;\n}\n\nexport interface SessionContext {\n\tmessages: AgentMessage[];\n\tthinkingLevel: string;\n\tcontextWindow: number | undefined;\n\tmodel: { provider: string; modelId: string } | null;\n}\n\nexport interface SessionInfo {\n\tpath: string;\n\tid: string;\n\t/** Working directory where the session was started. Empty string for old sessions. */\n\tcwd: string;\n\t/** User-defined display name from session_info entries. */\n\tname?: string;\n\t/** Path to the parent session (if this session was forked). */\n\tparentSessionPath?: string;\n\tcreated: Date;\n\tmodified: Date;\n\tmessageCount: number;\n\tfirstMessage: string;\n\tallMessagesText: string;\n}\n\nexport interface ContextDeletionFilters {\n\tdeletedEntryIds: Set<string>;\n\tdeletedContentBlocks: Map<string, Set<number>>;\n}\n\nexport type SessionListProgress = (loaded: number, total: number) => void;\n\nexport type ReadonlySessionManager = Pick<\n\tSessionManager,\n\t| \"getCwd\"\n\t| \"getSessionDir\"\n\t| \"usesDefaultSessionDir\"\n\t| \"getSessionId\"\n\t| \"getSessionFile\"\n\t| \"getLeafId\"\n\t| \"getLeafEntry\"\n\t| \"getEntry\"\n\t| \"getLabel\"\n\t| \"getBranch\"\n\t| \"getHeader\"\n\t| \"getEntries\"\n\t| \"getTree\"\n\t| \"getSessionName\"\n>;\n"]}
1
+ {"version":3,"file":"session-manager-types.js","sourceRoot":"","sources":["../../src/core/session-manager-types.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport type { SessionManager } from \"./session-manager-core.ts\";\n\nexport const CURRENT_SESSION_VERSION = 3;\n\n/**\n * Workflow linkage persisted on internal (workflow-created) session headers.\n * Used to exclude workflow stage sessions from the standard `/resume` history\n * while keeping them resumable through the workflow-specific resume path.\n */\nexport interface SessionWorkflowMetadata {\n\trunId: string;\n\tstageId: string;\n\tstageName: string;\n}\n\nexport interface SessionHeader {\n\ttype: \"session\";\n\tversion?: number; // v1 sessions don't have this\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tparentSession?: string;\n\t/** Marks sessions created by automated machinery (e.g. workflow stages) so they can be excluded from standard resume history. */\n\tinternal?: boolean;\n\t/** When internal, links the session to its owning workflow run/stage. */\n\tworkflow?: SessionWorkflowMetadata;\n}\n\nexport interface NewSessionOptions {\n\tid?: string;\n\tparentSession?: string;\n\t/** Mark the new session as internal (e.g. a workflow stage session). */\n\tinternal?: boolean;\n\t/** Workflow run/stage linkage for internal workflow sessions. */\n\tworkflow?: SessionWorkflowMetadata;\n}\n\nexport interface SessionEntryBase {\n\ttype: string;\n\tid: string;\n\tparentId: string | null;\n\ttimestamp: string;\n}\n\nexport interface SessionMessageEntry extends SessionEntryBase {\n\ttype: \"message\";\n\tmessage: AgentMessage;\n}\n\nexport interface ThinkingLevelChangeEntry extends SessionEntryBase {\n\ttype: \"thinking_level_change\";\n\tthinkingLevel: string;\n}\n\nexport interface ContextWindowChangeEntry extends SessionEntryBase {\n\ttype: \"context_window_change\";\n\tcontextWindow: number;\n}\n\nexport interface ModelChangeEntry extends SessionEntryBase {\n\ttype: \"model_change\";\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface CompactionEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"compaction\";\n\tsummary: string;\n\tfirstKeptEntryId: string;\n\ttokensBefore: number;\n\t/** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */\n\tdetails?: T;\n\t/** True if generated by an extension, undefined/false if pi-generated (backward compatible) */\n\tfromHook?: boolean;\n}\n\nexport type ContextDeletionTarget =\n\t| { kind: \"entry\"; entryId: string }\n\t| { kind: \"content_block\"; entryId: string; blockIndex: number };\n\nexport interface ContextCompactionStats {\n\tobjectsBefore: number;\n\tobjectsAfter: number;\n\tobjectsDeleted: number;\n\ttokensBefore: number;\n\ttokensAfter: number;\n\tpercentReduction: number;\n}\n\nexport interface ContextCompactionEntry extends SessionEntryBase {\n\ttype: \"context_compaction\";\n\tpromptVersion: 1;\n\tdeletedTargets: ContextDeletionTarget[];\n\tprotectedEntryIds: string[];\n\tstats: ContextCompactionStats;\n\tbackupPath?: string;\n}\n\nexport interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"branch_summary\";\n\tfromId: string;\n\tsummary: string;\n\t/** Extension-specific data (not sent to LLM) */\n\tdetails?: T;\n\t/** True if generated by an extension, false if pi-generated */\n\tfromHook?: boolean;\n}\n\n/**\n * Custom entry for extensions to store extension-specific data in the session.\n * Use customType to identify your extension's entries.\n *\n * Purpose: Persist extension state across session reloads. On reload, extensions can\n * scan entries for their customType and reconstruct internal state.\n *\n * Does NOT participate in LLM context (ignored by buildSessionContext).\n * For injecting content into context, see CustomMessageEntry.\n */\nexport interface CustomEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom\";\n\tcustomType: string;\n\tdata?: T;\n}\n\n/** Label entry for user-defined bookmarks/markers on entries. */\nexport interface LabelEntry extends SessionEntryBase {\n\ttype: \"label\";\n\ttargetId: string;\n\tlabel: string | undefined;\n}\n\n/** Session metadata entry (e.g., user-defined display name). */\nexport interface SessionInfoEntry extends SessionEntryBase {\n\ttype: \"session_info\";\n\tname?: string;\n}\n\n/**\n * Custom message entry for extensions to inject messages into LLM context.\n * Use customType to identify your extension's entries.\n *\n * Unlike CustomEntry, this usually participates in LLM context.\n * The content is converted to a user message in buildSessionContext() unless\n * excludeFromContext is true. Use details for extension-specific metadata (not sent to LLM).\n *\n * display controls TUI rendering:\n * - false: hidden entirely\n * - true: rendered with distinct styling (different from user messages)\n */\nexport interface CustomMessageEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom_message\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdetails?: T;\n\tdisplay: boolean;\n\texcludeFromContext?: boolean;\n}\n\n/** Session entry - has id/parentId for tree structure (returned by \"read\" methods in SessionManager) */\nexport type SessionEntry =\n\t| SessionMessageEntry\n\t| ThinkingLevelChangeEntry\n\t| ContextWindowChangeEntry\n\t| ModelChangeEntry\n\t| CompactionEntry\n\t| ContextCompactionEntry\n\t| BranchSummaryEntry\n\t| CustomEntry\n\t| CustomMessageEntry\n\t| LabelEntry\n\t| SessionInfoEntry;\n\n/** Raw file entry (includes header) */\nexport type FileEntry = SessionHeader | SessionEntry;\n\n/** Tree node for getTree() - defensive copy of session structure */\nexport interface SessionTreeNode {\n\tentry: SessionEntry;\n\tchildren: SessionTreeNode[];\n\t/** Resolved label for this entry, if any */\n\tlabel?: string;\n\t/** Timestamp of the latest label change for this entry, if any */\n\tlabelTimestamp?: string;\n}\n\nexport interface SessionContext {\n\tmessages: AgentMessage[];\n\tthinkingLevel: string;\n\tcontextWindow: number | undefined;\n\tmodel: { provider: string; modelId: string } | null;\n}\n\nexport interface SessionInfo {\n\tpath: string;\n\tid: string;\n\t/** Working directory where the session was started. Empty string for old sessions. */\n\tcwd: string;\n\t/** User-defined display name from session_info entries. */\n\tname?: string;\n\t/** Path to the parent session (if this session was forked). */\n\tparentSessionPath?: string;\n\t/** True when this session was created by automated machinery (e.g. a workflow stage). */\n\tinternal?: boolean;\n\t/** Workflow run/stage linkage when the session is an internal workflow session. */\n\tworkflow?: SessionWorkflowMetadata;\n\tcreated: Date;\n\tmodified: Date;\n\tmessageCount: number;\n\tfirstMessage: string;\n\tallMessagesText: string;\n}\n\nexport interface ContextDeletionFilters {\n\tdeletedEntryIds: Set<string>;\n\tdeletedContentBlocks: Map<string, Set<number>>;\n}\n\nexport type SessionListProgress = (loaded: number, total: number) => void;\n\nexport type ReadonlySessionManager = Pick<\n\tSessionManager,\n\t| \"getCwd\"\n\t| \"getSessionDir\"\n\t| \"usesDefaultSessionDir\"\n\t| \"getSessionId\"\n\t| \"getSessionFile\"\n\t| \"getLeafId\"\n\t| \"getLeafEntry\"\n\t| \"getEntry\"\n\t| \"getLabel\"\n\t| \"getBranch\"\n\t| \"getHeader\"\n\t| \"getEntries\"\n\t| \"getTree\"\n\t| \"getSessionName\"\n>;\n"]}
@@ -2,8 +2,8 @@ export { SessionManager } from "./session-manager-core.ts";
2
2
  export { buildContextDeletionFilteredPath, buildContextDeletionFilters, buildEffectiveContextDeletionFilters, buildSessionContext, getLatestCompactionBoundaryEntry, } from "./session-manager-history.ts";
3
3
  export { migrateSessionEntries, parseSessionEntries } from "./session-manager-migrations.ts";
4
4
  export { getDefaultSessionDir } from "./session-manager-paths.ts";
5
- export { findMostRecentSession, loadEntriesFromFile } from "./session-manager-storage.ts";
5
+ export { findMostRecentSession, isInternalHeader, loadEntriesFromFile } from "./session-manager-storage.ts";
6
6
  export { assertValidSessionId } from "./session-manager-validation.ts";
7
7
  export { CURRENT_SESSION_VERSION } from "./session-manager-types.ts";
8
- export type { BranchSummaryEntry, CompactionEntry, ContextCompactionEntry, ContextCompactionStats, ContextDeletionFilters, ContextDeletionTarget, ContextWindowChangeEntry, CustomEntry, CustomMessageEntry, FileEntry, LabelEntry, ModelChangeEntry, NewSessionOptions, ReadonlySessionManager, SessionContext, SessionEntry, SessionEntryBase, SessionHeader, SessionInfo, SessionInfoEntry, SessionListProgress, SessionMessageEntry, SessionTreeNode, ThinkingLevelChangeEntry, } from "./session-manager-types.ts";
8
+ export type { BranchSummaryEntry, CompactionEntry, ContextCompactionEntry, ContextCompactionStats, ContextDeletionFilters, ContextDeletionTarget, ContextWindowChangeEntry, CustomEntry, CustomMessageEntry, FileEntry, LabelEntry, ModelChangeEntry, NewSessionOptions, ReadonlySessionManager, SessionContext, SessionEntry, SessionEntryBase, SessionHeader, SessionInfo, SessionInfoEntry, SessionListProgress, SessionMessageEntry, SessionTreeNode, SessionWorkflowMetadata, ThinkingLevelChangeEntry, } from "./session-manager-types.ts";
9
9
  //# sourceMappingURL=session-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EACN,gCAAgC,EAChC,2BAA2B,EAC3B,oCAAoC,EACpC,mBAAmB,EACnB,gCAAgC,GAChC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,YAAY,EACX,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,wBAAwB,GACxB,MAAM,4BAA4B,CAAC","sourcesContent":["export { SessionManager } from \"./session-manager-core.ts\";\nexport {\n\tbuildContextDeletionFilteredPath,\n\tbuildContextDeletionFilters,\n\tbuildEffectiveContextDeletionFilters,\n\tbuildSessionContext,\n\tgetLatestCompactionBoundaryEntry,\n} from \"./session-manager-history.ts\";\nexport { migrateSessionEntries, parseSessionEntries } from \"./session-manager-migrations.ts\";\nexport { getDefaultSessionDir } from \"./session-manager-paths.ts\";\nexport { findMostRecentSession, loadEntriesFromFile } from \"./session-manager-storage.ts\";\nexport { assertValidSessionId } from \"./session-manager-validation.ts\";\nexport { CURRENT_SESSION_VERSION } from \"./session-manager-types.ts\";\nexport type {\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tContextCompactionEntry,\n\tContextCompactionStats,\n\tContextDeletionFilters,\n\tContextDeletionTarget,\n\tContextWindowChangeEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tFileEntry,\n\tLabelEntry,\n\tModelChangeEntry,\n\tNewSessionOptions,\n\tReadonlySessionManager,\n\tSessionContext,\n\tSessionEntry,\n\tSessionEntryBase,\n\tSessionHeader,\n\tSessionInfo,\n\tSessionInfoEntry,\n\tSessionListProgress,\n\tSessionMessageEntry,\n\tSessionTreeNode,\n\tThinkingLevelChangeEntry,\n} from \"./session-manager-types.ts\";\n"]}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EACN,gCAAgC,EAChC,2BAA2B,EAC3B,oCAAoC,EACpC,mBAAmB,EACnB,gCAAgC,GAChC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC5G,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,YAAY,EACX,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,uBAAuB,EACvB,wBAAwB,GACxB,MAAM,4BAA4B,CAAC","sourcesContent":["export { SessionManager } from \"./session-manager-core.ts\";\nexport {\n\tbuildContextDeletionFilteredPath,\n\tbuildContextDeletionFilters,\n\tbuildEffectiveContextDeletionFilters,\n\tbuildSessionContext,\n\tgetLatestCompactionBoundaryEntry,\n} from \"./session-manager-history.ts\";\nexport { migrateSessionEntries, parseSessionEntries } from \"./session-manager-migrations.ts\";\nexport { getDefaultSessionDir } from \"./session-manager-paths.ts\";\nexport { findMostRecentSession, isInternalHeader, loadEntriesFromFile } from \"./session-manager-storage.ts\";\nexport { assertValidSessionId } from \"./session-manager-validation.ts\";\nexport { CURRENT_SESSION_VERSION } from \"./session-manager-types.ts\";\nexport type {\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tContextCompactionEntry,\n\tContextCompactionStats,\n\tContextDeletionFilters,\n\tContextDeletionTarget,\n\tContextWindowChangeEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tFileEntry,\n\tLabelEntry,\n\tModelChangeEntry,\n\tNewSessionOptions,\n\tReadonlySessionManager,\n\tSessionContext,\n\tSessionEntry,\n\tSessionEntryBase,\n\tSessionHeader,\n\tSessionInfo,\n\tSessionInfoEntry,\n\tSessionListProgress,\n\tSessionMessageEntry,\n\tSessionTreeNode,\n\tSessionWorkflowMetadata,\n\tThinkingLevelChangeEntry,\n} from \"./session-manager-types.ts\";\n"]}
@@ -2,7 +2,7 @@ export { SessionManager } from "./session-manager-core.js";
2
2
  export { buildContextDeletionFilteredPath, buildContextDeletionFilters, buildEffectiveContextDeletionFilters, buildSessionContext, getLatestCompactionBoundaryEntry, } from "./session-manager-history.js";
3
3
  export { migrateSessionEntries, parseSessionEntries } from "./session-manager-migrations.js";
4
4
  export { getDefaultSessionDir } from "./session-manager-paths.js";
5
- export { findMostRecentSession, loadEntriesFromFile } from "./session-manager-storage.js";
5
+ export { findMostRecentSession, isInternalHeader, loadEntriesFromFile } from "./session-manager-storage.js";
6
6
  export { assertValidSessionId } from "./session-manager-validation.js";
7
7
  export { CURRENT_SESSION_VERSION } from "./session-manager-types.js";
8
8
  //# sourceMappingURL=session-manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EACN,gCAAgC,EAChC,2BAA2B,EAC3B,oCAAoC,EACpC,mBAAmB,EACnB,gCAAgC,GAChC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC","sourcesContent":["export { SessionManager } from \"./session-manager-core.ts\";\nexport {\n\tbuildContextDeletionFilteredPath,\n\tbuildContextDeletionFilters,\n\tbuildEffectiveContextDeletionFilters,\n\tbuildSessionContext,\n\tgetLatestCompactionBoundaryEntry,\n} from \"./session-manager-history.ts\";\nexport { migrateSessionEntries, parseSessionEntries } from \"./session-manager-migrations.ts\";\nexport { getDefaultSessionDir } from \"./session-manager-paths.ts\";\nexport { findMostRecentSession, loadEntriesFromFile } from \"./session-manager-storage.ts\";\nexport { assertValidSessionId } from \"./session-manager-validation.ts\";\nexport { CURRENT_SESSION_VERSION } from \"./session-manager-types.ts\";\nexport type {\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tContextCompactionEntry,\n\tContextCompactionStats,\n\tContextDeletionFilters,\n\tContextDeletionTarget,\n\tContextWindowChangeEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tFileEntry,\n\tLabelEntry,\n\tModelChangeEntry,\n\tNewSessionOptions,\n\tReadonlySessionManager,\n\tSessionContext,\n\tSessionEntry,\n\tSessionEntryBase,\n\tSessionHeader,\n\tSessionInfo,\n\tSessionInfoEntry,\n\tSessionListProgress,\n\tSessionMessageEntry,\n\tSessionTreeNode,\n\tThinkingLevelChangeEntry,\n} from \"./session-manager-types.ts\";\n"]}
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EACN,gCAAgC,EAChC,2BAA2B,EAC3B,oCAAoC,EACpC,mBAAmB,EACnB,gCAAgC,GAChC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC5G,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC","sourcesContent":["export { SessionManager } from \"./session-manager-core.ts\";\nexport {\n\tbuildContextDeletionFilteredPath,\n\tbuildContextDeletionFilters,\n\tbuildEffectiveContextDeletionFilters,\n\tbuildSessionContext,\n\tgetLatestCompactionBoundaryEntry,\n} from \"./session-manager-history.ts\";\nexport { migrateSessionEntries, parseSessionEntries } from \"./session-manager-migrations.ts\";\nexport { getDefaultSessionDir } from \"./session-manager-paths.ts\";\nexport { findMostRecentSession, isInternalHeader, loadEntriesFromFile } from \"./session-manager-storage.ts\";\nexport { assertValidSessionId } from \"./session-manager-validation.ts\";\nexport { CURRENT_SESSION_VERSION } from \"./session-manager-types.ts\";\nexport type {\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tContextCompactionEntry,\n\tContextCompactionStats,\n\tContextDeletionFilters,\n\tContextDeletionTarget,\n\tContextWindowChangeEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tFileEntry,\n\tLabelEntry,\n\tModelChangeEntry,\n\tNewSessionOptions,\n\tReadonlySessionManager,\n\tSessionContext,\n\tSessionEntry,\n\tSessionEntryBase,\n\tSessionHeader,\n\tSessionInfo,\n\tSessionInfoEntry,\n\tSessionListProgress,\n\tSessionMessageEntry,\n\tSessionTreeNode,\n\tSessionWorkflowMetadata,\n\tThinkingLevelChangeEntry,\n} from \"./session-manager-types.ts\";\n"]}
@@ -5,6 +5,7 @@ export declare function isChatSessionBashRunning<TExtraEntry extends ChatTranscr
5
5
  export declare function incrementOptimisticUserSignature<TExtraEntry extends ChatTranscriptEntryLike>(state: ChatSessionHostState<TExtraEntry>, signature: string): void;
6
6
  export declare function decrementOptimisticUserSignature<TExtraEntry extends ChatTranscriptEntryLike>(state: ChatSessionHostState<TExtraEntry>, signature: string): void;
7
7
  export declare function syncChatSessionAnimationTick<TExtraEntry extends ChatTranscriptEntryLike>(state: ChatSessionHostState<TExtraEntry>): void;
8
+ export declare function clearChatSessionBusyForTerminalWorkflowStage<TExtraEntry extends ChatTranscriptEntryLike>(state: ChatSessionHostState<TExtraEntry>): void;
8
9
  export declare function disposeChatSession<TExtraEntry extends ChatTranscriptEntryLike>(state: ChatSessionHostState<TExtraEntry>): void;
9
10
  export declare function notifyChatSessionWarning<TExtraEntry extends ChatTranscriptEntryLike>(state: ChatSessionHostState<TExtraEntry>, message: string): void;
10
11
  export declare function notifyChatSessionStatus<TExtraEntry extends ChatTranscriptEntryLike>(state: ChatSessionHostState<TExtraEntry>, message: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host-runtime.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAMzE,wBAAgB,sBAAsB,CAAC,WAAW,SAAS,uBAAuB,EAChF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,OAAO,CAET;AAED,wBAAgB,wBAAwB,CAAC,WAAW,SAAS,uBAAuB,EAClF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,OAAO,CAET;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,SAAS,EAAE,MAAM,GAChB,IAAI,CAKN;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,SAAS,EAAE,MAAM,GAChB,IAAI,CAIN;AAED,wBAAgB,4BAA4B,CAC1C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,IAAI,CAehD;AAED,wBAAgB,kBAAkB,CAAC,WAAW,SAAS,uBAAuB,EAC5E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,IAAI,CAUN;AAED,wBAAgB,wBAAwB,CAAC,WAAW,SAAS,uBAAuB,EAClF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,MAAM,GACd,IAAI,CAIN;AAED,wBAAgB,uBAAuB,CAAC,WAAW,SAAS,uBAAuB,EACjF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,MAAM,GACd,IAAI,CAIN;AAED,wBAAgB,0BAA0B,CACxC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAC/C,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAuBlC;AAED,wBAAgB,qBAAqB,CAAC,WAAW,SAAS,uBAAuB,EAC/E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,OAAO,GACf,IAAI,CAIN","sourcesContent":["import type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport type { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport {\n ANIMATION_FRAME_MS,\n STREAMING_RENDER_THROTTLE_MS,\n} from \"./chat-session-host-utils.ts\";\n\nexport function isChatSessionStreaming<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): boolean {\n return state.sdkBusy || state.isStreamingOverride?.() === true;\n}\n\nexport function isChatSessionBashRunning<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): boolean {\n return state.localBashRunning || state.isBashRunningOverride?.() === true;\n}\n\nexport function incrementOptimisticUserSignature<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n signature: string,\n): void {\n state.optimisticUserSignatureCounts.set(\n signature,\n (state.optimisticUserSignatureCounts.get(signature) ?? 0) + 1,\n );\n}\n\nexport function decrementOptimisticUserSignature<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n signature: string,\n): void {\n const count = state.optimisticUserSignatureCounts.get(signature) ?? 0;\n if (count <= 1) state.optimisticUserSignatureCounts.delete(signature);\n else state.optimisticUserSignatureCounts.set(signature, count - 1);\n}\n\nexport function syncChatSessionAnimationTick<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n const shouldAnimate =\n isChatSessionStreaming(state) ||\n (state.sdkBusy && state.liveChat.pendingToolIds().length > 0);\n if (shouldAnimate && !state.animationTimer) {\n state.animationTimer = setInterval(() => {\n state.requestRender?.();\n }, ANIMATION_FRAME_MS);\n state.animationTimer.unref?.();\n return;\n }\n if (!shouldAnimate && state.animationTimer) {\n clearInterval(state.animationTimer);\n state.animationTimer = undefined;\n }\n}\n\nexport function disposeChatSession<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): void {\n if (state.animationTimer) {\n clearInterval(state.animationTimer);\n state.animationTimer = undefined;\n }\n if (state.renderThrottleTimer) {\n clearTimeout(state.renderThrottleTimer);\n state.renderThrottleTimer = undefined;\n }\n state.editor = undefined;\n}\n\nexport function notifyChatSessionWarning<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n message: string,\n): void {\n state.statusMessage = message;\n state.showWarning?.(message);\n state.requestRender?.();\n}\n\nexport function notifyChatSessionStatus<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n message: string,\n): void {\n state.statusMessage = message;\n state.showStatus?.(message);\n state.requestRender?.();\n}\n\nexport function requiredChatSessionCommand<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n name: \"prompt\" | \"steer\" | \"followUp\" | \"resume\",\n): (text?: string) => Promise<void> {\n switch (name) {\n case \"prompt\":\n return async (text) => {\n if (!state.commands.prompt) throw new Error(\"no prompt command configured for this chat session\");\n await state.commands.prompt(text ?? \"\");\n };\n case \"steer\":\n return async (text) => {\n if (!state.commands.steer) throw new Error(\"no steer command configured for this chat session\");\n await state.commands.steer(text ?? \"\");\n };\n case \"followUp\":\n return async (text) => {\n if (!state.commands.followUp) throw new Error(\"no followUp command configured for this chat session\");\n await state.commands.followUp(text ?? \"\");\n };\n case \"resume\":\n return async (text) => {\n if (!state.commands.resume) throw new Error(\"no resume command configured for this chat session\");\n await state.commands.resume(text);\n };\n }\n}\n\nexport function afterChatSessionEvent<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n changed: boolean,\n): void {\n syncChatSessionAnimationTick(state);\n if (!changed) return;\n requestChatSessionEventRender(state);\n}\n\nfunction requestChatSessionEventRender<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n if (!isChatSessionStreaming(state)) {\n state.requestRender?.();\n return;\n }\n if (state.renderThrottleTimer) return;\n state.renderThrottleTimer = setTimeout(() => {\n state.renderThrottleTimer = undefined;\n state.requestRender?.();\n }, STREAMING_RENDER_THROTTLE_MS);\n state.renderThrottleTimer.unref?.();\n}\n"]}
1
+ {"version":3,"file":"chat-session-host-runtime.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAOzE,wBAAgB,sBAAsB,CAAC,WAAW,SAAS,uBAAuB,EAChF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,OAAO,CAET;AAED,wBAAgB,wBAAwB,CAAC,WAAW,SAAS,uBAAuB,EAClF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,OAAO,CAET;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,SAAS,EAAE,MAAM,GAChB,IAAI,CAKN;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,SAAS,EAAE,MAAM,GAChB,IAAI,CAIN;AAED,wBAAgB,4BAA4B,CAC1C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,IAAI,CAehD;AAED,wBAAgB,4CAA4C,CAC1D,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,IAAI,CAShD;AAED,wBAAgB,kBAAkB,CAAC,WAAW,SAAS,uBAAuB,EAC5E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,IAAI,CAWN;AAED,wBAAgB,wBAAwB,CAAC,WAAW,SAAS,uBAAuB,EAClF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,MAAM,GACd,IAAI,CAIN;AAED,wBAAgB,uBAAuB,CAAC,WAAW,SAAS,uBAAuB,EACjF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,MAAM,GACd,IAAI,CAIN;AAED,wBAAgB,0BAA0B,CACxC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAC/C,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAuBlC;AAED,wBAAgB,qBAAqB,CAAC,WAAW,SAAS,uBAAuB,EAC/E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,OAAO,GACf,IAAI,CAIN","sourcesContent":["import type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport type { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport { finalizeTerminalWorkflowToolEntries } from \"./chat-session-host-terminal-cleanup.ts\";\nimport {\n ANIMATION_FRAME_MS,\n STREAMING_RENDER_THROTTLE_MS,\n} from \"./chat-session-host-utils.ts\";\n\nexport function isChatSessionStreaming<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): boolean {\n return state.sdkBusy || state.isStreamingOverride?.() === true;\n}\n\nexport function isChatSessionBashRunning<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): boolean {\n return state.localBashRunning || state.isBashRunningOverride?.() === true;\n}\n\nexport function incrementOptimisticUserSignature<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n signature: string,\n): void {\n state.optimisticUserSignatureCounts.set(\n signature,\n (state.optimisticUserSignatureCounts.get(signature) ?? 0) + 1,\n );\n}\n\nexport function decrementOptimisticUserSignature<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n signature: string,\n): void {\n const count = state.optimisticUserSignatureCounts.get(signature) ?? 0;\n if (count <= 1) state.optimisticUserSignatureCounts.delete(signature);\n else state.optimisticUserSignatureCounts.set(signature, count - 1);\n}\n\nexport function syncChatSessionAnimationTick<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n const shouldAnimate =\n isChatSessionStreaming(state) ||\n (state.sdkBusy && state.liveChat.pendingToolIds().length > 0);\n if (shouldAnimate && !state.animationTimer) {\n state.animationTimer = setInterval(() => {\n state.requestRender?.();\n }, ANIMATION_FRAME_MS);\n state.animationTimer.unref?.();\n return;\n }\n if (!shouldAnimate && state.animationTimer) {\n clearInterval(state.animationTimer);\n state.animationTimer = undefined;\n }\n}\n\nexport function clearChatSessionBusyForTerminalWorkflowStage<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n state.sdkBusy = false;\n state.workingMessage = undefined;\n if (finalizeTerminalWorkflowToolEntries(state.transcript)) {\n state.transcriptComponent.invalidate();\n }\n state.liveChat.clearPendingTools();\n state.statusMessage = \"\";\n syncChatSessionAnimationTick(state);\n}\n\nexport function disposeChatSession<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): void {\n if (state.animationTimer) {\n clearInterval(state.animationTimer);\n state.animationTimer = undefined;\n }\n if (state.renderThrottleTimer) {\n clearTimeout(state.renderThrottleTimer);\n state.renderThrottleTimer = undefined;\n }\n state.transcriptComponent.invalidate();\n state.editor = undefined;\n}\n\nexport function notifyChatSessionWarning<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n message: string,\n): void {\n state.statusMessage = message;\n state.showWarning?.(message);\n state.requestRender?.();\n}\n\nexport function notifyChatSessionStatus<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n message: string,\n): void {\n state.statusMessage = message;\n state.showStatus?.(message);\n state.requestRender?.();\n}\n\nexport function requiredChatSessionCommand<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n name: \"prompt\" | \"steer\" | \"followUp\" | \"resume\",\n): (text?: string) => Promise<void> {\n switch (name) {\n case \"prompt\":\n return async (text) => {\n if (!state.commands.prompt) throw new Error(\"no prompt command configured for this chat session\");\n await state.commands.prompt(text ?? \"\");\n };\n case \"steer\":\n return async (text) => {\n if (!state.commands.steer) throw new Error(\"no steer command configured for this chat session\");\n await state.commands.steer(text ?? \"\");\n };\n case \"followUp\":\n return async (text) => {\n if (!state.commands.followUp) throw new Error(\"no followUp command configured for this chat session\");\n await state.commands.followUp(text ?? \"\");\n };\n case \"resume\":\n return async (text) => {\n if (!state.commands.resume) throw new Error(\"no resume command configured for this chat session\");\n await state.commands.resume(text);\n };\n }\n}\n\nexport function afterChatSessionEvent<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n changed: boolean,\n): void {\n syncChatSessionAnimationTick(state);\n if (!changed) return;\n requestChatSessionEventRender(state);\n}\n\nfunction requestChatSessionEventRender<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n if (!isChatSessionStreaming(state)) {\n state.requestRender?.();\n return;\n }\n if (state.renderThrottleTimer) return;\n state.renderThrottleTimer = setTimeout(() => {\n state.renderThrottleTimer = undefined;\n state.requestRender?.();\n }, STREAMING_RENDER_THROTTLE_MS);\n state.renderThrottleTimer.unref?.();\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { finalizeTerminalWorkflowToolEntries } from "./chat-session-host-terminal-cleanup.js";
1
2
  import { ANIMATION_FRAME_MS, STREAMING_RENDER_THROTTLE_MS, } from "./chat-session-host-utils.js";
2
3
  export function isChatSessionStreaming(state) {
3
4
  return state.sdkBusy || state.isStreamingOverride?.() === true;
@@ -30,6 +31,16 @@ export function syncChatSessionAnimationTick(state) {
30
31
  state.animationTimer = undefined;
31
32
  }
32
33
  }
34
+ export function clearChatSessionBusyForTerminalWorkflowStage(state) {
35
+ state.sdkBusy = false;
36
+ state.workingMessage = undefined;
37
+ if (finalizeTerminalWorkflowToolEntries(state.transcript)) {
38
+ state.transcriptComponent.invalidate();
39
+ }
40
+ state.liveChat.clearPendingTools();
41
+ state.statusMessage = "";
42
+ syncChatSessionAnimationTick(state);
43
+ }
33
44
  export function disposeChatSession(state) {
34
45
  if (state.animationTimer) {
35
46
  clearInterval(state.animationTimer);
@@ -39,6 +50,7 @@ export function disposeChatSession(state) {
39
50
  clearTimeout(state.renderThrottleTimer);
40
51
  state.renderThrottleTimer = undefined;
41
52
  }
53
+ state.transcriptComponent.invalidate();
42
54
  state.editor = undefined;
43
55
  }
44
56
  export function notifyChatSessionWarning(state, message) {
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host-runtime.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-runtime.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,8BAA8B,CAAC;AAEtC,MAAM,UAAU,sBAAsB,CACpC,KAAwC;IAExC,OAAO,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,mBAAmB,EAAE,EAAE,KAAK,IAAI,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,KAAwC;IAExC,OAAO,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,qBAAqB,EAAE,EAAE,KAAK,IAAI,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,gCAAgC,CAG9C,KAAwC,EACxC,SAAiB;IAEjB,KAAK,CAAC,6BAA6B,CAAC,GAAG,CACrC,SAAS,EACT,CAAC,KAAK,CAAC,6BAA6B,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAC9D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gCAAgC,CAG9C,KAAwC,EACxC,SAAiB;IAEjB,MAAM,KAAK,GAAG,KAAK,CAAC,6BAA6B,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACtE,IAAI,KAAK,IAAI,CAAC;QAAE,KAAK,CAAC,6BAA6B,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;;QACjE,KAAK,CAAC,6BAA6B,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,4BAA4B,CAE1C,KAAwC;IACxC,MAAM,aAAa,GACjB,sBAAsB,CAAC,KAAK,CAAC;QAC7B,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAChE,IAAI,aAAa,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QAC3C,KAAK,CAAC,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE;YACtC,KAAK,CAAC,aAAa,EAAE,EAAE,CAAC;QAC1B,CAAC,EAAE,kBAAkB,CAAC,CAAC;QACvB,KAAK,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC;QAC/B,OAAO;IACT,CAAC;IACD,IAAI,CAAC,aAAa,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;QAC3C,aAAa,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACpC,KAAK,CAAC,cAAc,GAAG,SAAS,CAAC;IACnC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,KAAwC;IAExC,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;QACzB,aAAa,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACpC,KAAK,CAAC,cAAc,GAAG,SAAS,CAAC;IACnC,CAAC;IACD,IAAI,KAAK,CAAC,mBAAmB,EAAE,CAAC;QAC9B,YAAY,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACxC,KAAK,CAAC,mBAAmB,GAAG,SAAS,CAAC;IACxC,CAAC;IACD,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,KAAwC,EACxC,OAAe;IAEf,KAAK,CAAC,aAAa,GAAG,OAAO,CAAC;IAC9B,KAAK,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,CAAC;IAC7B,KAAK,CAAC,aAAa,EAAE,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,KAAwC,EACxC,OAAe;IAEf,KAAK,CAAC,aAAa,GAAG,OAAO,CAAC;IAC9B,KAAK,CAAC,UAAU,EAAE,CAAC,OAAO,CAAC,CAAC;IAC5B,KAAK,CAAC,aAAa,EAAE,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,0BAA0B,CAGxC,KAAwC,EACxC,IAAgD;IAEhD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,KAAK,EAAE,IAAI,EAAE,EAAE;gBACpB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;gBAClG,MAAM,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YAC1C,CAAC,CAAC;QACJ,KAAK,OAAO;YACV,OAAO,KAAK,EAAE,IAAI,EAAE,EAAE;gBACpB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK;oBAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;gBAChG,MAAM,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YACzC,CAAC,CAAC;QACJ,KAAK,UAAU;YACb,OAAO,KAAK,EAAE,IAAI,EAAE,EAAE;gBACpB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ;oBAAE,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;gBACtG,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YAC5C,CAAC,CAAC;QACJ,KAAK,QAAQ;YACX,OAAO,KAAK,EAAE,IAAI,EAAE,EAAE;gBACpB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;gBAClG,MAAM,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACpC,CAAC,CAAC;IACN,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,KAAwC,EACxC,OAAgB;IAEhB,4BAA4B,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,6BAA6B,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,6BAA6B,CAEpC,KAAwC;IACxC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;QACnC,KAAK,CAAC,aAAa,EAAE,EAAE,CAAC;QACxB,OAAO;IACT,CAAC;IACD,IAAI,KAAK,CAAC,mBAAmB;QAAE,OAAO;IACtC,KAAK,CAAC,mBAAmB,GAAG,UAAU,CAAC,GAAG,EAAE;QAC1C,KAAK,CAAC,mBAAmB,GAAG,SAAS,CAAC;QACtC,KAAK,CAAC,aAAa,EAAE,EAAE,CAAC;IAC1B,CAAC,EAAE,4BAA4B,CAAC,CAAC;IACjC,KAAK,CAAC,mBAAmB,CAAC,KAAK,EAAE,EAAE,CAAC;AACtC,CAAC","sourcesContent":["import type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport type { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport {\n ANIMATION_FRAME_MS,\n STREAMING_RENDER_THROTTLE_MS,\n} from \"./chat-session-host-utils.ts\";\n\nexport function isChatSessionStreaming<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): boolean {\n return state.sdkBusy || state.isStreamingOverride?.() === true;\n}\n\nexport function isChatSessionBashRunning<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): boolean {\n return state.localBashRunning || state.isBashRunningOverride?.() === true;\n}\n\nexport function incrementOptimisticUserSignature<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n signature: string,\n): void {\n state.optimisticUserSignatureCounts.set(\n signature,\n (state.optimisticUserSignatureCounts.get(signature) ?? 0) + 1,\n );\n}\n\nexport function decrementOptimisticUserSignature<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n signature: string,\n): void {\n const count = state.optimisticUserSignatureCounts.get(signature) ?? 0;\n if (count <= 1) state.optimisticUserSignatureCounts.delete(signature);\n else state.optimisticUserSignatureCounts.set(signature, count - 1);\n}\n\nexport function syncChatSessionAnimationTick<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n const shouldAnimate =\n isChatSessionStreaming(state) ||\n (state.sdkBusy && state.liveChat.pendingToolIds().length > 0);\n if (shouldAnimate && !state.animationTimer) {\n state.animationTimer = setInterval(() => {\n state.requestRender?.();\n }, ANIMATION_FRAME_MS);\n state.animationTimer.unref?.();\n return;\n }\n if (!shouldAnimate && state.animationTimer) {\n clearInterval(state.animationTimer);\n state.animationTimer = undefined;\n }\n}\n\nexport function disposeChatSession<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): void {\n if (state.animationTimer) {\n clearInterval(state.animationTimer);\n state.animationTimer = undefined;\n }\n if (state.renderThrottleTimer) {\n clearTimeout(state.renderThrottleTimer);\n state.renderThrottleTimer = undefined;\n }\n state.editor = undefined;\n}\n\nexport function notifyChatSessionWarning<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n message: string,\n): void {\n state.statusMessage = message;\n state.showWarning?.(message);\n state.requestRender?.();\n}\n\nexport function notifyChatSessionStatus<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n message: string,\n): void {\n state.statusMessage = message;\n state.showStatus?.(message);\n state.requestRender?.();\n}\n\nexport function requiredChatSessionCommand<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n name: \"prompt\" | \"steer\" | \"followUp\" | \"resume\",\n): (text?: string) => Promise<void> {\n switch (name) {\n case \"prompt\":\n return async (text) => {\n if (!state.commands.prompt) throw new Error(\"no prompt command configured for this chat session\");\n await state.commands.prompt(text ?? \"\");\n };\n case \"steer\":\n return async (text) => {\n if (!state.commands.steer) throw new Error(\"no steer command configured for this chat session\");\n await state.commands.steer(text ?? \"\");\n };\n case \"followUp\":\n return async (text) => {\n if (!state.commands.followUp) throw new Error(\"no followUp command configured for this chat session\");\n await state.commands.followUp(text ?? \"\");\n };\n case \"resume\":\n return async (text) => {\n if (!state.commands.resume) throw new Error(\"no resume command configured for this chat session\");\n await state.commands.resume(text);\n };\n }\n}\n\nexport function afterChatSessionEvent<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n changed: boolean,\n): void {\n syncChatSessionAnimationTick(state);\n if (!changed) return;\n requestChatSessionEventRender(state);\n}\n\nfunction requestChatSessionEventRender<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n if (!isChatSessionStreaming(state)) {\n state.requestRender?.();\n return;\n }\n if (state.renderThrottleTimer) return;\n state.renderThrottleTimer = setTimeout(() => {\n state.renderThrottleTimer = undefined;\n state.requestRender?.();\n }, STREAMING_RENDER_THROTTLE_MS);\n state.renderThrottleTimer.unref?.();\n}\n"]}
1
+ {"version":3,"file":"chat-session-host-runtime.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport type { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport { finalizeTerminalWorkflowToolEntries } from \"./chat-session-host-terminal-cleanup.ts\";\nimport {\n ANIMATION_FRAME_MS,\n STREAMING_RENDER_THROTTLE_MS,\n} from \"./chat-session-host-utils.ts\";\n\nexport function isChatSessionStreaming<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): boolean {\n return state.sdkBusy || state.isStreamingOverride?.() === true;\n}\n\nexport function isChatSessionBashRunning<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): boolean {\n return state.localBashRunning || state.isBashRunningOverride?.() === true;\n}\n\nexport function incrementOptimisticUserSignature<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n signature: string,\n): void {\n state.optimisticUserSignatureCounts.set(\n signature,\n (state.optimisticUserSignatureCounts.get(signature) ?? 0) + 1,\n );\n}\n\nexport function decrementOptimisticUserSignature<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n signature: string,\n): void {\n const count = state.optimisticUserSignatureCounts.get(signature) ?? 0;\n if (count <= 1) state.optimisticUserSignatureCounts.delete(signature);\n else state.optimisticUserSignatureCounts.set(signature, count - 1);\n}\n\nexport function syncChatSessionAnimationTick<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n const shouldAnimate =\n isChatSessionStreaming(state) ||\n (state.sdkBusy && state.liveChat.pendingToolIds().length > 0);\n if (shouldAnimate && !state.animationTimer) {\n state.animationTimer = setInterval(() => {\n state.requestRender?.();\n }, ANIMATION_FRAME_MS);\n state.animationTimer.unref?.();\n return;\n }\n if (!shouldAnimate && state.animationTimer) {\n clearInterval(state.animationTimer);\n state.animationTimer = undefined;\n }\n}\n\nexport function clearChatSessionBusyForTerminalWorkflowStage<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n state.sdkBusy = false;\n state.workingMessage = undefined;\n if (finalizeTerminalWorkflowToolEntries(state.transcript)) {\n state.transcriptComponent.invalidate();\n }\n state.liveChat.clearPendingTools();\n state.statusMessage = \"\";\n syncChatSessionAnimationTick(state);\n}\n\nexport function disposeChatSession<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): void {\n if (state.animationTimer) {\n clearInterval(state.animationTimer);\n state.animationTimer = undefined;\n }\n if (state.renderThrottleTimer) {\n clearTimeout(state.renderThrottleTimer);\n state.renderThrottleTimer = undefined;\n }\n state.transcriptComponent.invalidate();\n state.editor = undefined;\n}\n\nexport function notifyChatSessionWarning<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n message: string,\n): void {\n state.statusMessage = message;\n state.showWarning?.(message);\n state.requestRender?.();\n}\n\nexport function notifyChatSessionStatus<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n message: string,\n): void {\n state.statusMessage = message;\n state.showStatus?.(message);\n state.requestRender?.();\n}\n\nexport function requiredChatSessionCommand<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n name: \"prompt\" | \"steer\" | \"followUp\" | \"resume\",\n): (text?: string) => Promise<void> {\n switch (name) {\n case \"prompt\":\n return async (text) => {\n if (!state.commands.prompt) throw new Error(\"no prompt command configured for this chat session\");\n await state.commands.prompt(text ?? \"\");\n };\n case \"steer\":\n return async (text) => {\n if (!state.commands.steer) throw new Error(\"no steer command configured for this chat session\");\n await state.commands.steer(text ?? \"\");\n };\n case \"followUp\":\n return async (text) => {\n if (!state.commands.followUp) throw new Error(\"no followUp command configured for this chat session\");\n await state.commands.followUp(text ?? \"\");\n };\n case \"resume\":\n return async (text) => {\n if (!state.commands.resume) throw new Error(\"no resume command configured for this chat session\");\n await state.commands.resume(text);\n };\n }\n}\n\nexport function afterChatSessionEvent<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n changed: boolean,\n): void {\n syncChatSessionAnimationTick(state);\n if (!changed) return;\n requestChatSessionEventRender(state);\n}\n\nfunction requestChatSessionEventRender<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n if (!isChatSessionStreaming(state)) {\n state.requestRender?.();\n return;\n }\n if (state.renderThrottleTimer) return;\n state.renderThrottleTimer = setTimeout(() => {\n state.renderThrottleTimer = undefined;\n state.requestRender?.();\n }, STREAMING_RENDER_THROTTLE_MS);\n state.renderThrottleTimer.unref?.();\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { ChatSessionHostEntry } from "./chat-session-host-types.ts";
2
+ import type { ChatTranscriptEntryLike } from "./chat-transcript.ts";
3
+ export declare function finalizeTerminalWorkflowToolEntries<TExtraEntry extends ChatTranscriptEntryLike>(entries: ChatSessionHostEntry<TExtraEntry>[]): boolean;
4
+ //# sourceMappingURL=chat-session-host-terminal-cleanup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-session-host-terminal-cleanup.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-terminal-cleanup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAMpE,wBAAgB,mCAAmC,CACjD,WAAW,SAAS,uBAAuB,EAC3C,OAAO,EAAE,oBAAoB,CAAC,WAAW,CAAC,EAAE,GAAG,OAAO,CAYvD","sourcesContent":["import type { ChatSessionHostEntry } from \"./chat-session-host-types.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\n\ntype ToolEntry = Extract<ChatSessionHostEntry<ChatTranscriptEntryLike>, { kind: \"tool\" }>;\ntype ToolResult = NonNullable<ToolEntry[\"result\"]>;\ntype ObjectRecord = Record<string, unknown>;\n\nexport function finalizeTerminalWorkflowToolEntries<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(entries: ChatSessionHostEntry<TExtraEntry>[]): boolean {\n let changed = false;\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n if (!isToolEntry(entry)) continue;\n const finalized = finalizeToolEntry(entry);\n if (finalized !== entry) {\n entries[i] = finalized as ChatSessionHostEntry<TExtraEntry>;\n changed = true;\n }\n }\n return changed;\n}\n\nfunction finalizeToolEntry(entry: ToolEntry): ToolEntry {\n const result = entry.result ? finalizeToolResult(entry.result) : undefined;\n const resultChanged = result !== entry.result;\n if (entry.isPartial === false && !resultChanged) return entry;\n return {\n ...entry,\n ...(result ? { result } : {}),\n isPartial: false,\n };\n}\n\nfunction finalizeToolResult(result: ToolResult): ToolResult {\n const details = finalizeDetails(result.details);\n if (details === result.details) return result;\n return { ...result, details };\n}\n\nfunction finalizeDetails(details: unknown): unknown {\n if (!isRecord(details)) return details;\n let changed = false;\n const next: ObjectRecord = { ...details };\n const progress = finalizeProgressArray(next.progress);\n if (progress !== next.progress) {\n next.progress = progress;\n changed = true;\n }\n if (Array.isArray(next.results)) {\n const results = next.results.map((item) => finalizeResultEntry(item));\n if (results.some((item, index) => item !== (next.results as unknown[])[index])) {\n next.results = results;\n changed = true;\n }\n }\n const workflowGraph = finalizeWorkflowGraph(next.workflowGraph);\n if (workflowGraph !== next.workflowGraph) {\n next.workflowGraph = workflowGraph;\n changed = true;\n }\n return changed ? next : details;\n}\n\nfunction finalizeResultEntry(entry: unknown): unknown {\n if (!isRecord(entry)) return entry;\n const progress = finalizeProgress(entry.progress);\n if (progress === entry.progress) return entry;\n return { ...entry, progress };\n}\n\nfunction finalizeProgressArray(progress: unknown): unknown {\n if (!Array.isArray(progress)) return progress;\n let changed = false;\n const next = progress.map((entry) => {\n const finalized = finalizeProgress(entry);\n if (finalized !== entry) changed = true;\n return finalized;\n });\n return changed ? next : progress;\n}\n\nfunction finalizeProgress(progress: unknown): unknown {\n if (!isRecord(progress) || progress.status !== \"running\") return progress;\n return {\n ...progress,\n status: \"detached\",\n activityState: undefined,\n currentTool: undefined,\n currentToolArgs: undefined,\n currentToolStartedAt: undefined,\n };\n}\n\nfunction finalizeWorkflowGraph(graph: unknown): unknown {\n if (!isRecord(graph)) return graph;\n const nodes = finalizeWorkflowGraphNodes(graph.nodes);\n const shouldClearCurrent = graph.currentNodeId !== undefined;\n if (nodes === graph.nodes && !shouldClearCurrent) return graph;\n return { ...graph, nodes, currentNodeId: undefined };\n}\n\nfunction finalizeWorkflowGraphNodes(nodes: unknown): unknown {\n if (!Array.isArray(nodes)) return nodes;\n let changed = false;\n const next = nodes.map((node) => {\n const finalized = finalizeWorkflowGraphNode(node);\n if (finalized !== node) changed = true;\n return finalized;\n });\n return changed ? next : nodes;\n}\n\nfunction finalizeWorkflowGraphNode(node: unknown): unknown {\n if (!isRecord(node)) return node;\n let changed = false;\n const next: ObjectRecord = { ...node };\n if (next.status === \"running\") {\n next.status = \"detached\";\n changed = true;\n }\n const children = finalizeWorkflowGraphNodes(next.children);\n if (children !== next.children) {\n next.children = children;\n changed = true;\n }\n return changed ? next : node;\n}\n\nfunction isToolEntry(entry: ChatSessionHostEntry<ChatTranscriptEntryLike>): entry is ToolEntry {\n return entry.role === \"tool\" && \"kind\" in entry && entry.kind === \"tool\";\n}\n\nfunction isRecord(value: unknown): value is ObjectRecord {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n"]}