@code-yeongyu/senpi 2026.6.30 → 2026.7.3

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 (272) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/dist/core/agent-session.d.ts +6 -1
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +42 -25
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/auth-storage.d.ts.map +1 -1
  7. package/dist/core/auth-storage.js +13 -5
  8. package/dist/core/auth-storage.js.map +1 -1
  9. package/dist/core/compaction/compaction.d.ts.map +1 -1
  10. package/dist/core/compaction/compaction.js +5 -8
  11. package/dist/core/compaction/compaction.js.map +1 -1
  12. package/dist/core/dynamic-prompt/build.d.ts +13 -0
  13. package/dist/core/dynamic-prompt/build.d.ts.map +1 -1
  14. package/dist/core/dynamic-prompt/build.js +24 -21
  15. package/dist/core/dynamic-prompt/build.js.map +1 -1
  16. package/dist/core/dynamic-prompt/exploration.d.ts.map +1 -1
  17. package/dist/core/dynamic-prompt/exploration.js +1 -3
  18. package/dist/core/dynamic-prompt/exploration.js.map +1 -1
  19. package/dist/core/dynamic-prompt/index.d.ts +1 -1
  20. package/dist/core/dynamic-prompt/index.d.ts.map +1 -1
  21. package/dist/core/dynamic-prompt/index.js.map +1 -1
  22. package/dist/core/dynamic-prompt/intent-gate.d.ts.map +1 -1
  23. package/dist/core/dynamic-prompt/intent-gate.js +20 -35
  24. package/dist/core/dynamic-prompt/intent-gate.js.map +1 -1
  25. package/dist/core/dynamic-prompt/parallel-tools.d.ts.map +1 -1
  26. package/dist/core/dynamic-prompt/parallel-tools.js +2 -4
  27. package/dist/core/dynamic-prompt/parallel-tools.js.map +1 -1
  28. package/dist/core/dynamic-prompt/style.d.ts.map +1 -1
  29. package/dist/core/dynamic-prompt/style.js +7 -26
  30. package/dist/core/dynamic-prompt/style.js.map +1 -1
  31. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.d.ts +3 -0
  32. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.d.ts.map +1 -0
  33. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js +16 -0
  34. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js.map +1 -0
  35. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.d.ts.map +1 -1
  36. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.js +3 -1
  37. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.js.map +1 -1
  38. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.d.ts.map +1 -1
  39. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.js +3 -1
  40. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.js.map +1 -1
  41. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.d.ts.map +1 -1
  42. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.js +6 -2
  43. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.js.map +1 -1
  44. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.d.ts.map +1 -1
  45. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.js +5 -3
  46. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.js.map +1 -1
  47. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.d.ts.map +1 -1
  48. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js +68 -8
  49. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js.map +1 -1
  50. package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
  51. package/dist/core/extensions/builtin/prompt-preset/presets.js +9 -0
  52. package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
  53. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
  54. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
  55. package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
  56. package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
  57. package/dist/core/extensions/index.d.ts +1 -1
  58. package/dist/core/extensions/index.d.ts.map +1 -1
  59. package/dist/core/extensions/index.js.map +1 -1
  60. package/dist/core/extensions/loader.d.ts.map +1 -1
  61. package/dist/core/extensions/loader.js +6 -0
  62. package/dist/core/extensions/loader.js.map +1 -1
  63. package/dist/core/extensions/runner.d.ts +2 -1
  64. package/dist/core/extensions/runner.d.ts.map +1 -1
  65. package/dist/core/extensions/runner.js +33 -1
  66. package/dist/core/extensions/runner.js.map +1 -1
  67. package/dist/core/extensions/types.d.ts +16 -2
  68. package/dist/core/extensions/types.d.ts.map +1 -1
  69. package/dist/core/extensions/types.js.map +1 -1
  70. package/dist/core/http-dispatcher.d.ts.map +1 -1
  71. package/dist/core/http-dispatcher.js +28 -1
  72. package/dist/core/http-dispatcher.js.map +1 -1
  73. package/dist/core/model-resolver.d.ts +10 -0
  74. package/dist/core/model-resolver.d.ts.map +1 -1
  75. package/dist/core/model-resolver.js +21 -27
  76. package/dist/core/model-resolver.js.map +1 -1
  77. package/dist/core/session-manager.d.ts +20 -1
  78. package/dist/core/session-manager.d.ts.map +1 -1
  79. package/dist/core/session-manager.js +87 -68
  80. package/dist/core/session-manager.js.map +1 -1
  81. package/dist/core/settings-manager.d.ts +3 -0
  82. package/dist/core/settings-manager.d.ts.map +1 -1
  83. package/dist/core/settings-manager.js +8 -0
  84. package/dist/core/settings-manager.js.map +1 -1
  85. package/dist/core/tools/bash.d.ts.map +1 -1
  86. package/dist/core/tools/bash.js +20 -5
  87. package/dist/core/tools/bash.js.map +1 -1
  88. package/dist/extension-system-migration.d.ts +2 -0
  89. package/dist/extension-system-migration.d.ts.map +1 -0
  90. package/dist/extension-system-migration.js +51 -0
  91. package/dist/extension-system-migration.js.map +1 -0
  92. package/dist/index.d.ts +3 -2
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +2 -1
  95. package/dist/index.js.map +1 -1
  96. package/dist/legacy-senpi-dir-migration.d.ts +2 -0
  97. package/dist/legacy-senpi-dir-migration.d.ts.map +1 -0
  98. package/dist/legacy-senpi-dir-migration.js +76 -0
  99. package/dist/legacy-senpi-dir-migration.js.map +1 -0
  100. package/dist/migrations.d.ts.map +1 -1
  101. package/dist/migrations.js +3 -95
  102. package/dist/migrations.js.map +1 -1
  103. package/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  104. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  105. package/dist/modes/interactive/components/assistant-message.js +15 -7
  106. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  107. package/dist/modes/interactive/components/custom-entry.d.ts +19 -0
  108. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -0
  109. package/dist/modes/interactive/components/custom-entry.js +49 -0
  110. package/dist/modes/interactive/components/custom-entry.js.map +1 -0
  111. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  112. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  113. package/dist/modes/interactive/components/settings-selector.js +13 -1
  114. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  115. package/dist/modes/interactive/components/status-indicator.d.ts +27 -0
  116. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -0
  117. package/dist/modes/interactive/components/status-indicator.js +64 -0
  118. package/dist/modes/interactive/components/status-indicator.js.map +1 -0
  119. package/dist/modes/interactive/components/user-message.d.ts +6 -2
  120. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  121. package/dist/modes/interactive/components/user-message.js +15 -4
  122. package/dist/modes/interactive/components/user-message.js.map +1 -1
  123. package/dist/modes/interactive/interactive-mode.d.ts +14 -15
  124. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  125. package/dist/modes/interactive/interactive-mode.js +177 -137
  126. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  127. package/dist/modes/rpc/rpc-client.d.ts +15 -0
  128. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  129. package/dist/modes/rpc/rpc-client.js +14 -0
  130. package/dist/modes/rpc/rpc-client.js.map +1 -1
  131. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  132. package/dist/modes/rpc/rpc-mode.js +16 -0
  133. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  134. package/dist/modes/rpc/rpc-types.d.ts +26 -0
  135. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  136. package/dist/modes/rpc/rpc-types.js.map +1 -1
  137. package/docs/extensions.md +55 -8
  138. package/docs/rpc.md +58 -0
  139. package/docs/sdk.md +28 -0
  140. package/docs/session-format.md +18 -8
  141. package/docs/settings.md +2 -1
  142. package/examples/extensions/README.md +1 -0
  143. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  144. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  145. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  146. package/examples/extensions/entry-renderer.ts +41 -0
  147. package/examples/extensions/gondolin/package-lock.json +2 -2
  148. package/examples/extensions/gondolin/package.json +1 -1
  149. package/examples/extensions/question.ts +1 -0
  150. package/examples/extensions/sandbox/package-lock.json +2 -2
  151. package/examples/extensions/sandbox/package.json +1 -1
  152. package/examples/extensions/with-deps/package-lock.json +2 -2
  153. package/examples/extensions/with-deps/package.json +1 -1
  154. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts +3 -1
  155. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  156. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +9 -1
  157. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  158. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.d.ts.map +1 -1
  159. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +4 -6
  160. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js.map +1 -1
  161. package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  162. package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.js +20 -2
  163. package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  164. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  165. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  166. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +6 -0
  167. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  168. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.d.ts.map +1 -1
  169. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js +2 -14
  170. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js.map +1 -1
  171. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  172. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +16 -5
  173. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js.map +1 -1
  174. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.d.ts.map +1 -1
  175. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js +2 -1
  176. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js.map +1 -1
  177. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.d.ts.map +1 -1
  178. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js +2 -1
  179. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js.map +1 -1
  180. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts.map +1 -1
  181. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +56 -39
  182. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
  183. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  184. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +8 -3
  185. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  186. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
  187. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +2 -14
  188. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
  189. package/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.d.ts.map +1 -1
  190. package/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js +2 -1
  191. package/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js.map +1 -1
  192. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +15 -45
  193. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  194. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +15 -45
  195. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
  196. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +456 -37
  197. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  198. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.d.ts +123 -0
  199. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
  200. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js +124 -4
  201. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js.map +1 -1
  202. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.d.ts +20 -0
  203. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.d.ts.map +1 -1
  204. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.js +18 -0
  205. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.js.map +1 -1
  206. package/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.d.ts +21 -0
  207. package/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.d.ts.map +1 -1
  208. package/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.js +18 -0
  209. package/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.js.map +1 -1
  210. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.d.ts +21 -0
  211. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.d.ts.map +1 -1
  212. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.js +18 -0
  213. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
  214. package/node_modules/@earendil-works/pi-ai/dist/providers/fireworks.models.d.ts +10 -5
  215. package/node_modules/@earendil-works/pi-ai/dist/providers/fireworks.models.d.ts.map +1 -1
  216. package/node_modules/@earendil-works/pi-ai/dist/providers/fireworks.models.js +4 -3
  217. package/node_modules/@earendil-works/pi-ai/dist/providers/fireworks.models.js.map +1 -1
  218. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.d.ts +82 -0
  219. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.d.ts.map +1 -1
  220. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js +57 -0
  221. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js.map +1 -1
  222. package/node_modules/@earendil-works/pi-ai/dist/providers/nvidia.models.d.ts +0 -28
  223. package/node_modules/@earendil-works/pi-ai/dist/providers/nvidia.models.d.ts.map +1 -1
  224. package/node_modules/@earendil-works/pi-ai/dist/providers/nvidia.models.js +0 -19
  225. package/node_modules/@earendil-works/pi-ai/dist/providers/nvidia.models.js.map +1 -1
  226. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js +5 -5
  227. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js.map +1 -1
  228. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.d.ts +89 -0
  229. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.d.ts.map +1 -1
  230. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.js +75 -2
  231. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.js.map +1 -1
  232. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +46 -4
  233. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
  234. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +91 -55
  235. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
  236. package/node_modules/@earendil-works/pi-ai/dist/providers/together.models.js +2 -2
  237. package/node_modules/@earendil-works/pi-ai/dist/providers/together.models.js.map +1 -1
  238. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts +44 -0
  239. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
  240. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js +41 -4
  241. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  242. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts +25 -0
  243. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts.map +1 -0
  244. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js +109 -0
  245. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js.map +1 -0
  246. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts +1 -0
  247. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts.map +1 -1
  248. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +6 -0
  249. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js.map +1 -1
  250. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  251. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +1 -0
  252. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  253. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.d.ts +1 -0
  254. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.d.ts.map +1 -1
  255. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +3 -0
  256. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js.map +1 -1
  257. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  258. package/node_modules/@earendil-works/pi-tui/dist/mux.d.ts +4 -0
  259. package/node_modules/@earendil-works/pi-tui/dist/mux.d.ts.map +1 -0
  260. package/node_modules/@earendil-works/pi-tui/dist/mux.js +10 -0
  261. package/node_modules/@earendil-works/pi-tui/dist/mux.js.map +1 -0
  262. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts +42 -1
  263. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts.map +1 -1
  264. package/node_modules/@earendil-works/pi-tui/dist/tui.js +422 -101
  265. package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +1 -1
  266. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +10 -0
  267. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +1 -1
  268. package/node_modules/@earendil-works/pi-tui/dist/utils.js +53 -13
  269. package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
  270. package/node_modules/@earendil-works/pi-tui/package.json +2 -1
  271. package/npm-shrinkwrap.json +9 -9
  272. package/package.json +4 -4
@@ -132,47 +132,40 @@ export function getLatestCompactionEntry(entries) {
132
132
  }
133
133
  return null;
134
134
  }
135
- /**
136
- * Build the session context from entries using tree traversal.
137
- * If leafId is provided, walks from that entry to root.
138
- * Handles compaction and branch summaries along the path.
139
- */
140
- export function buildSessionContext(entries, leafId, byId) {
141
- // Build uuid index if not available
142
- if (!byId) {
143
- byId = new Map();
144
- for (const entry of entries) {
145
- byId.set(entry.id, entry);
146
- }
135
+ function buildEntryIndex(entries, byId) {
136
+ if (byId)
137
+ return byId;
138
+ const index = new Map();
139
+ for (const entry of entries) {
140
+ index.set(entry.id, entry);
147
141
  }
148
- // Find leaf
142
+ return index;
143
+ }
144
+ function buildSessionPath(entries, leafId, byId) {
145
+ const index = buildEntryIndex(entries, byId);
149
146
  let leaf;
150
147
  if (leafId === null) {
151
- // Explicitly null - return no messages (navigated to before first entry)
152
- return { messages: [], thinkingLevel: "off", model: null };
148
+ return [];
153
149
  }
154
150
  if (leafId) {
155
- leaf = byId.get(leafId);
151
+ leaf = index.get(leafId);
156
152
  }
153
+ leaf ??= entries[entries.length - 1];
157
154
  if (!leaf) {
158
- // Fallback to last entry (when leafId is undefined)
159
- leaf = entries[entries.length - 1];
160
- }
161
- if (!leaf) {
162
- return { messages: [], thinkingLevel: "off", model: null };
155
+ return [];
163
156
  }
164
- // Walk from leaf to root, collecting path
165
157
  const path = [];
166
158
  let current = leaf;
167
159
  while (current) {
168
160
  path.push(current);
169
- current = current.parentId ? byId.get(current.parentId) : undefined;
161
+ current = current.parentId ? index.get(current.parentId) : undefined;
170
162
  }
171
163
  path.reverse();
172
- // Extract settings and find compaction
164
+ return path;
165
+ }
166
+ function getSessionContextSettings(path) {
173
167
  let thinkingLevel = "off";
174
168
  let model = null;
175
- let compaction = null;
176
169
  for (const entry of path) {
177
170
  if (entry.type === "thinking_level_change") {
178
171
  thinkingLevel = entry.thinkingLevel;
@@ -183,55 +176,74 @@ export function buildSessionContext(entries, leafId, byId) {
183
176
  else if (entry.type === "message" && entry.message.role === "assistant") {
184
177
  model = { provider: entry.message.provider, modelId: entry.message.model };
185
178
  }
186
- else if (entry.type === "compaction") {
179
+ }
180
+ return { thinkingLevel, model };
181
+ }
182
+ /**
183
+ * Project one selected session entry into LLM/runtime messages.
184
+ * Plain custom entries are display/state entries and do not participate in context.
185
+ */
186
+ export function sessionEntryToContextMessages(entry) {
187
+ if (entry.type === "message") {
188
+ return [entry.message];
189
+ }
190
+ if (entry.type === "custom_message") {
191
+ return [createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp)];
192
+ }
193
+ if (entry.type === "branch_summary" && entry.summary) {
194
+ return [createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp)];
195
+ }
196
+ if (entry.type === "compaction") {
197
+ return [createCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp, entry.details)];
198
+ }
199
+ return [];
200
+ }
201
+ /**
202
+ * Build the active, compaction-aware session entry list.
203
+ *
204
+ * This follows the current leaf path. If the path contains compaction entries,
205
+ * the latest compaction is represented by the compaction entry itself, followed
206
+ * by the kept entries starting at firstKeptEntryId and all entries after the
207
+ * compaction entry. Older summarized entries are omitted.
208
+ */
209
+ export function buildContextEntries(entries, leafId, byId) {
210
+ const path = buildSessionPath(entries, leafId, byId);
211
+ let compaction = null;
212
+ for (const entry of path) {
213
+ if (entry.type === "compaction") {
187
214
  compaction = entry;
188
215
  }
189
216
  }
190
- // Build messages and collect corresponding entries
191
- // When there's a compaction, we need to:
192
- // 1. Emit summary first (entry = compaction)
193
- // 2. Emit kept messages (from firstKeptEntryId up to compaction)
194
- // 3. Emit messages after compaction
195
- const messages = [];
196
- const appendMessage = (entry) => {
197
- if (entry.type === "message") {
198
- messages.push(entry.message);
199
- }
200
- else if (entry.type === "custom_message") {
201
- messages.push(createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp));
202
- }
203
- else if (entry.type === "branch_summary" && entry.summary) {
204
- messages.push(createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp));
205
- }
206
- };
207
- if (compaction) {
208
- // Emit summary first
209
- messages.push(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp, compaction.details));
210
- // Find compaction index in path
211
- const compactionIdx = path.findIndex((e) => e.type === "compaction" && e.id === compaction.id);
212
- // Emit kept messages (before compaction, starting from firstKeptEntryId)
213
- let foundFirstKept = false;
214
- for (let i = 0; i < compactionIdx; i++) {
215
- const entry = path[i];
216
- if (entry.id === compaction.firstKeptEntryId) {
217
- foundFirstKept = true;
218
- }
219
- if (foundFirstKept) {
220
- appendMessage(entry);
221
- }
222
- }
223
- // Emit messages after compaction
224
- for (let i = compactionIdx + 1; i < path.length; i++) {
225
- const entry = path[i];
226
- appendMessage(entry);
227
- }
217
+ if (!compaction) {
218
+ return path;
228
219
  }
229
- else {
230
- // No compaction - emit all messages, handle branch summaries and custom messages
231
- for (const entry of path) {
232
- appendMessage(entry);
220
+ const compactionIdx = path.findIndex((entry) => entry.id === compaction.id);
221
+ if (compactionIdx < 0) {
222
+ return path;
223
+ }
224
+ const contextEntries = [compaction];
225
+ let foundFirstKept = false;
226
+ for (let i = 0; i < compactionIdx; i++) {
227
+ const entry = path[i];
228
+ if (entry.id === compaction.firstKeptEntryId) {
229
+ foundFirstKept = true;
230
+ }
231
+ if (foundFirstKept) {
232
+ contextEntries.push(entry);
233
233
  }
234
234
  }
235
+ contextEntries.push(...path.slice(compactionIdx + 1));
236
+ return contextEntries;
237
+ }
238
+ /**
239
+ * Build the session context from entries using tree traversal.
240
+ * If leafId is provided, walks from that entry to root.
241
+ * Handles compaction and branch summaries along the path.
242
+ */
243
+ export function buildSessionContext(entries, leafId, byId) {
244
+ const path = buildSessionPath(entries, leafId, byId);
245
+ const { thinkingLevel, model } = getSessionContextSettings(path);
246
+ const messages = buildContextEntries(entries, leafId, byId).flatMap(sessionEntryToContextMessages);
235
247
  return { messages, thinkingLevel, model };
236
248
  }
237
249
  /**
@@ -926,6 +938,13 @@ export class SessionManager {
926
938
  }
927
939
  return path;
928
940
  }
941
+ /**
942
+ * Build the active, compaction-aware entry list for context/rendering.
943
+ * Uses tree traversal from current leaf.
944
+ */
945
+ buildContextEntries() {
946
+ return buildContextEntries(this.getEntries(), this.leafId);
947
+ }
929
948
  /**
930
949
  * Build the session context (what gets sent to the LLM).
931
950
  * Uses tree traversal from current leaf.