@superblocksteam/vite-plugin-file-sync 2.0.162 → 2.0.163-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (420) hide show
  1. package/dist/ai-service/agent/middleware.d.ts.map +1 -1
  2. package/dist/ai-service/agent/middleware.js +18 -7
  3. package/dist/ai-service/agent/middleware.js.map +1 -1
  4. package/dist/ai-service/agent/prompts/build-base-system-prompt.d.ts.map +1 -1
  5. package/dist/ai-service/agent/prompts/build-base-system-prompt.js +43 -29
  6. package/dist/ai-service/agent/prompts/build-base-system-prompt.js.map +1 -1
  7. package/dist/ai-service/agent/prompts/build-security-scan-prompt.d.ts.map +1 -1
  8. package/dist/ai-service/agent/prompts/build-security-scan-prompt.js +25 -0
  9. package/dist/ai-service/agent/prompts/build-security-scan-prompt.js.map +1 -1
  10. package/dist/ai-service/agent/subagents/coding/run-coding-subagent.d.ts.map +1 -1
  11. package/dist/ai-service/agent/subagents/coding/run-coding-subagent.js +15 -0
  12. package/dist/ai-service/agent/subagents/coding/run-coding-subagent.js.map +1 -1
  13. package/dist/ai-service/agent/tools/apis/test-api.d.ts.map +1 -1
  14. package/dist/ai-service/agent/tools/apis/test-api.js +4 -2
  15. package/dist/ai-service/agent/tools/apis/test-api.js.map +1 -1
  16. package/dist/ai-service/agent/tools/app-environment/switch-selected-environment.d.ts +18 -0
  17. package/dist/ai-service/agent/tools/app-environment/switch-selected-environment.d.ts.map +1 -0
  18. package/dist/ai-service/agent/tools/app-environment/switch-selected-environment.js +61 -0
  19. package/dist/ai-service/agent/tools/app-environment/switch-selected-environment.js.map +1 -0
  20. package/dist/ai-service/agent/tools/build-capture-screenshot.js +1 -1
  21. package/dist/ai-service/agent/tools/build-install-packages.d.ts.map +1 -1
  22. package/dist/ai-service/agent/tools/build-install-packages.js +21 -8
  23. package/dist/ai-service/agent/tools/build-install-packages.js.map +1 -1
  24. package/dist/ai-service/agent/tools/build-read-file.d.ts +87 -1
  25. package/dist/ai-service/agent/tools/build-read-file.d.ts.map +1 -1
  26. package/dist/ai-service/agent/tools/build-read-file.js +453 -82
  27. package/dist/ai-service/agent/tools/build-read-file.js.map +1 -1
  28. package/dist/ai-service/agent/tools/build-write-file.d.ts +1 -0
  29. package/dist/ai-service/agent/tools/build-write-file.d.ts.map +1 -1
  30. package/dist/ai-service/agent/tools/build-write-file.js +18 -2
  31. package/dist/ai-service/agent/tools/build-write-file.js.map +1 -1
  32. package/dist/ai-service/agent/tools/debug-cache.d.ts +11 -0
  33. package/dist/ai-service/agent/tools/debug-cache.d.ts.map +1 -1
  34. package/dist/ai-service/agent/tools/debug-cache.js +62 -14
  35. package/dist/ai-service/agent/tools/debug-cache.js.map +1 -1
  36. package/dist/ai-service/agent/tools/index.d.ts +2 -1
  37. package/dist/ai-service/agent/tools/index.d.ts.map +1 -1
  38. package/dist/ai-service/agent/tools/index.js +2 -1
  39. package/dist/ai-service/agent/tools/index.js.map +1 -1
  40. package/dist/ai-service/agent/tools/integrations/metadata.d.ts +1 -0
  41. package/dist/ai-service/agent/tools/integrations/metadata.d.ts.map +1 -1
  42. package/dist/ai-service/agent/tools/integrations/metadata.js +7 -2
  43. package/dist/ai-service/agent/tools/integrations/metadata.js.map +1 -1
  44. package/dist/ai-service/agent/tools/read-file-metrics.d.ts +30 -0
  45. package/dist/ai-service/agent/tools/read-file-metrics.d.ts.map +1 -0
  46. package/dist/ai-service/agent/tools/read-file-metrics.js +158 -0
  47. package/dist/ai-service/agent/tools/read-file-metrics.js.map +1 -0
  48. package/dist/ai-service/agent/tools/subagent-isolation.d.ts +27 -0
  49. package/dist/ai-service/agent/tools/subagent-isolation.d.ts.map +1 -0
  50. package/dist/ai-service/agent/tools/subagent-isolation.js +57 -0
  51. package/dist/ai-service/agent/tools/subagent-isolation.js.map +1 -0
  52. package/dist/ai-service/agent/tools.d.ts +4 -1
  53. package/dist/ai-service/agent/tools.d.ts.map +1 -1
  54. package/dist/ai-service/agent/tools.js +51 -5
  55. package/dist/ai-service/agent/tools.js.map +1 -1
  56. package/dist/ai-service/agent/tools2/tools/download-attachments.d.ts.map +1 -1
  57. package/dist/ai-service/agent/tools2/tools/download-attachments.js +1 -0
  58. package/dist/ai-service/agent/tools2/tools/download-attachments.js.map +1 -1
  59. package/dist/ai-service/agent/tools2/tools/start-test-run.d.ts.map +1 -1
  60. package/dist/ai-service/agent/tools2/tools/start-test-run.js +14 -0
  61. package/dist/ai-service/agent/tools2/tools/start-test-run.js.map +1 -1
  62. package/dist/ai-service/agent/utils.d.ts.map +1 -1
  63. package/dist/ai-service/agent/utils.js +2 -2
  64. package/dist/ai-service/agent/utils.js.map +1 -1
  65. package/dist/ai-service/app-interface/filesystem/draft-manager.d.ts +2 -1
  66. package/dist/ai-service/app-interface/filesystem/draft-manager.d.ts.map +1 -1
  67. package/dist/ai-service/app-interface/filesystem/draft-manager.js +3 -0
  68. package/dist/ai-service/app-interface/filesystem/draft-manager.js.map +1 -1
  69. package/dist/ai-service/app-interface/filesystem/handlers/skill-handler.d.ts +2 -1
  70. package/dist/ai-service/app-interface/filesystem/handlers/skill-handler.d.ts.map +1 -1
  71. package/dist/ai-service/app-interface/filesystem/handlers/skill-handler.js +13 -11
  72. package/dist/ai-service/app-interface/filesystem/handlers/skill-handler.js.map +1 -1
  73. package/dist/ai-service/app-interface/filesystem/virtual-file-system.d.ts.map +1 -1
  74. package/dist/ai-service/app-interface/filesystem/virtual-file-system.js +1 -1
  75. package/dist/ai-service/app-interface/filesystem/virtual-file-system.js.map +1 -1
  76. package/dist/ai-service/app-interface/shell.d.ts +18 -9
  77. package/dist/ai-service/app-interface/shell.d.ts.map +1 -1
  78. package/dist/ai-service/app-interface/shell.js +92 -112
  79. package/dist/ai-service/app-interface/shell.js.map +1 -1
  80. package/dist/ai-service/app-interface/typecheck-output-parser.d.ts +9 -0
  81. package/dist/ai-service/app-interface/typecheck-output-parser.d.ts.map +1 -0
  82. package/dist/ai-service/app-interface/typecheck-output-parser.js +21 -0
  83. package/dist/ai-service/app-interface/typecheck-output-parser.js.map +1 -0
  84. package/dist/ai-service/app-interface/vulnerability-gate.d.ts +5 -0
  85. package/dist/ai-service/app-interface/vulnerability-gate.d.ts.map +1 -1
  86. package/dist/ai-service/app-interface/vulnerability-gate.js +9 -2
  87. package/dist/ai-service/app-interface/vulnerability-gate.js.map +1 -1
  88. package/dist/ai-service/app-layout.d.ts +13 -0
  89. package/dist/ai-service/app-layout.d.ts.map +1 -0
  90. package/dist/ai-service/app-layout.js +25 -0
  91. package/dist/ai-service/app-layout.js.map +1 -0
  92. package/dist/ai-service/app-skills/manager.d.ts +2 -0
  93. package/dist/ai-service/app-skills/manager.d.ts.map +1 -1
  94. package/dist/ai-service/app-skills/manager.js +13 -6
  95. package/dist/ai-service/app-skills/manager.js.map +1 -1
  96. package/dist/ai-service/attachment-label-metrics.d.ts +5 -0
  97. package/dist/ai-service/attachment-label-metrics.d.ts.map +1 -0
  98. package/dist/ai-service/attachment-label-metrics.js +26 -0
  99. package/dist/ai-service/attachment-label-metrics.js.map +1 -0
  100. package/dist/ai-service/attachment-upload.d.ts.map +1 -1
  101. package/dist/ai-service/attachment-upload.js +6 -1
  102. package/dist/ai-service/attachment-upload.js.map +1 -1
  103. package/dist/ai-service/attachments/validate-prompt-attachments.d.ts +7 -0
  104. package/dist/ai-service/attachments/validate-prompt-attachments.d.ts.map +1 -0
  105. package/dist/ai-service/attachments/validate-prompt-attachments.js +96 -0
  106. package/dist/ai-service/attachments/validate-prompt-attachments.js.map +1 -0
  107. package/dist/ai-service/chat/chat-push-metrics.d.ts +17 -0
  108. package/dist/ai-service/chat/chat-push-metrics.d.ts.map +1 -1
  109. package/dist/ai-service/chat/chat-push-metrics.js +45 -0
  110. package/dist/ai-service/chat/chat-push-metrics.js.map +1 -1
  111. package/dist/ai-service/chat/chat-session-store.d.ts +51 -0
  112. package/dist/ai-service/chat/chat-session-store.d.ts.map +1 -1
  113. package/dist/ai-service/chat/chat-session-store.js +181 -4
  114. package/dist/ai-service/chat/chat-session-store.js.map +1 -1
  115. package/dist/ai-service/features.d.ts +32 -0
  116. package/dist/ai-service/features.d.ts.map +1 -1
  117. package/dist/ai-service/features.js +32 -0
  118. package/dist/ai-service/features.js.map +1 -1
  119. package/dist/ai-service/helper-system-ai-attributes.d.ts +1 -1
  120. package/dist/ai-service/helper-system-ai-attributes.d.ts.map +1 -1
  121. package/dist/ai-service/helper-system-ai-attributes.js.map +1 -1
  122. package/dist/ai-service/index.d.ts +19 -4
  123. package/dist/ai-service/index.d.ts.map +1 -1
  124. package/dist/ai-service/index.js +176 -23
  125. package/dist/ai-service/index.js.map +1 -1
  126. package/dist/ai-service/llm/client.d.ts +9 -0
  127. package/dist/ai-service/llm/client.d.ts.map +1 -1
  128. package/dist/ai-service/llm/client.js +13 -43
  129. package/dist/ai-service/llm/client.js.map +1 -1
  130. package/dist/ai-service/llm/context-v2/adapter.d.ts +2 -0
  131. package/dist/ai-service/llm/context-v2/adapter.d.ts.map +1 -1
  132. package/dist/ai-service/llm/context-v2/adapter.js +6 -0
  133. package/dist/ai-service/llm/context-v2/adapter.js.map +1 -1
  134. package/dist/ai-service/llm/context-v2/compaction/server-side.d.ts +8 -0
  135. package/dist/ai-service/llm/context-v2/compaction/server-side.d.ts.map +1 -1
  136. package/dist/ai-service/llm/context-v2/compaction/server-side.js +8 -0
  137. package/dist/ai-service/llm/context-v2/compaction/server-side.js.map +1 -1
  138. package/dist/ai-service/llm/context-v2/context-component-partition.d.ts +24 -0
  139. package/dist/ai-service/llm/context-v2/context-component-partition.d.ts.map +1 -0
  140. package/dist/ai-service/llm/context-v2/context-component-partition.js +222 -0
  141. package/dist/ai-service/llm/context-v2/context-component-partition.js.map +1 -0
  142. package/dist/ai-service/llm/context-v2/context-metrics.d.ts +9 -0
  143. package/dist/ai-service/llm/context-v2/context-metrics.d.ts.map +1 -1
  144. package/dist/ai-service/llm/context-v2/context-metrics.js +40 -2
  145. package/dist/ai-service/llm/context-v2/context-metrics.js.map +1 -1
  146. package/dist/ai-service/llm/context-v2/context.d.ts +116 -4
  147. package/dist/ai-service/llm/context-v2/context.d.ts.map +1 -1
  148. package/dist/ai-service/llm/context-v2/context.js +276 -64
  149. package/dist/ai-service/llm/context-v2/context.js.map +1 -1
  150. package/dist/ai-service/llm/context-v2/conversation-context.d.ts +18 -0
  151. package/dist/ai-service/llm/context-v2/conversation-context.d.ts.map +1 -1
  152. package/dist/ai-service/llm/context-v2/file-read-ledger.d.ts +218 -0
  153. package/dist/ai-service/llm/context-v2/file-read-ledger.d.ts.map +1 -0
  154. package/dist/ai-service/llm/context-v2/file-read-ledger.js +275 -0
  155. package/dist/ai-service/llm/context-v2/file-read-ledger.js.map +1 -0
  156. package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.d.ts.map +1 -1
  157. package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.js +5 -2
  158. package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.js.map +1 -1
  159. package/dist/ai-service/llm/context-v2/token-tracker.d.ts +2 -0
  160. package/dist/ai-service/llm/context-v2/token-tracker.d.ts.map +1 -1
  161. package/dist/ai-service/llm/context-v2/token-tracker.js +4 -0
  162. package/dist/ai-service/llm/context-v2/token-tracker.js.map +1 -1
  163. package/dist/ai-service/llm/context-v2/tool-schema-tokens.d.ts +22 -0
  164. package/dist/ai-service/llm/context-v2/tool-schema-tokens.d.ts.map +1 -0
  165. package/dist/ai-service/llm/context-v2/tool-schema-tokens.js +36 -0
  166. package/dist/ai-service/llm/context-v2/tool-schema-tokens.js.map +1 -0
  167. package/dist/ai-service/llm/context-v2/types.d.ts +8 -0
  168. package/dist/ai-service/llm/context-v2/types.d.ts.map +1 -1
  169. package/dist/ai-service/llm/context-v2/types.js +48 -0
  170. package/dist/ai-service/llm/context-v2/types.js.map +1 -1
  171. package/dist/ai-service/llm/error.d.ts +2 -0
  172. package/dist/ai-service/llm/error.d.ts.map +1 -1
  173. package/dist/ai-service/llm/error.js +1 -0
  174. package/dist/ai-service/llm/error.js.map +1 -1
  175. package/dist/ai-service/llm/retry-exhaustion-reason.d.ts +2 -0
  176. package/dist/ai-service/llm/retry-exhaustion-reason.d.ts.map +1 -0
  177. package/dist/ai-service/llm/retry-exhaustion-reason.js +2 -0
  178. package/dist/ai-service/llm/retry-exhaustion-reason.js.map +1 -0
  179. package/dist/ai-service/llm/stream/errors.d.ts +6 -7
  180. package/dist/ai-service/llm/stream/errors.d.ts.map +1 -1
  181. package/dist/ai-service/llm/stream/errors.js +7 -1
  182. package/dist/ai-service/llm/stream/errors.js.map +1 -1
  183. package/dist/ai-service/llm/stream/event-bus.d.ts +9 -1
  184. package/dist/ai-service/llm/stream/event-bus.d.ts.map +1 -1
  185. package/dist/ai-service/llm/stream/event-bus.js.map +1 -1
  186. package/dist/ai-service/llm/stream/idle-monitor.d.ts.map +1 -1
  187. package/dist/ai-service/llm/stream/idle-monitor.js.map +1 -1
  188. package/dist/ai-service/llm/stream/observers/context.d.ts.map +1 -1
  189. package/dist/ai-service/llm/stream/observers/context.js +13 -0
  190. package/dist/ai-service/llm/stream/observers/context.js.map +1 -1
  191. package/dist/ai-service/llm/stream/observers/llmobs.d.ts +14 -1
  192. package/dist/ai-service/llm/stream/observers/llmobs.d.ts.map +1 -1
  193. package/dist/ai-service/llm/stream/observers/llmobs.js +91 -7
  194. package/dist/ai-service/llm/stream/observers/llmobs.js.map +1 -1
  195. package/dist/ai-service/llm/stream/observers/logging.d.ts +3 -1
  196. package/dist/ai-service/llm/stream/observers/logging.d.ts.map +1 -1
  197. package/dist/ai-service/llm/stream/observers/logging.js +73 -52
  198. package/dist/ai-service/llm/stream/observers/logging.js.map +1 -1
  199. package/dist/ai-service/llm/stream/observers/retry-notification.d.ts.map +1 -1
  200. package/dist/ai-service/llm/stream/observers/retry-notification.js +16 -9
  201. package/dist/ai-service/llm/stream/observers/retry-notification.js.map +1 -1
  202. package/dist/ai-service/llm/stream/orchestrator.d.ts +5 -1
  203. package/dist/ai-service/llm/stream/orchestrator.d.ts.map +1 -1
  204. package/dist/ai-service/llm/stream/orchestrator.js +103 -12
  205. package/dist/ai-service/llm/stream/orchestrator.js.map +1 -1
  206. package/dist/ai-service/llm/stream/retry-engine.d.ts +3 -1
  207. package/dist/ai-service/llm/stream/retry-engine.d.ts.map +1 -1
  208. package/dist/ai-service/llm/stream/retry-engine.js +9 -0
  209. package/dist/ai-service/llm/stream/retry-engine.js.map +1 -1
  210. package/dist/ai-service/llm/stream/session.d.ts +8 -1
  211. package/dist/ai-service/llm/stream/session.d.ts.map +1 -1
  212. package/dist/ai-service/llm/stream/session.js +19 -0
  213. package/dist/ai-service/llm/stream/session.js.map +1 -1
  214. package/dist/ai-service/llm/stream/types.d.ts +13 -0
  215. package/dist/ai-service/llm/stream/types.d.ts.map +1 -1
  216. package/dist/ai-service/llm/stream/wait-state-tracker.d.ts +5 -14
  217. package/dist/ai-service/llm/stream/wait-state-tracker.d.ts.map +1 -1
  218. package/dist/ai-service/llm/stream/wait-state-tracker.js +25 -0
  219. package/dist/ai-service/llm/stream/wait-state-tracker.js.map +1 -1
  220. package/dist/ai-service/mcp/embedded-playwright-mcp-server.js +8 -8
  221. package/dist/ai-service/mcp/embedded-playwright-mcp-server.js.map +1 -1
  222. package/dist/ai-service/policy-gate-remediation-usage.d.ts +2 -0
  223. package/dist/ai-service/policy-gate-remediation-usage.d.ts.map +1 -0
  224. package/dist/ai-service/policy-gate-remediation-usage.js +56 -0
  225. package/dist/ai-service/policy-gate-remediation-usage.js.map +1 -0
  226. package/dist/ai-service/prompts/summarize-destructive-migration.d.ts +12 -0
  227. package/dist/ai-service/prompts/summarize-destructive-migration.d.ts.map +1 -0
  228. package/dist/ai-service/prompts/summarize-destructive-migration.js +37 -0
  229. package/dist/ai-service/prompts/summarize-destructive-migration.js.map +1 -0
  230. package/dist/ai-service/recording/storage/session-recording-storage.js +2 -2
  231. package/dist/ai-service/recording/storage/session-recording-storage.js.map +1 -1
  232. package/dist/ai-service/security/secret-scanner-service.d.ts.map +1 -1
  233. package/dist/ai-service/security/secret-scanner-service.js +88 -23
  234. package/dist/ai-service/security/secret-scanner-service.js.map +1 -1
  235. package/dist/ai-service/skills/index.d.ts +0 -7
  236. package/dist/ai-service/skills/index.d.ts.map +1 -1
  237. package/dist/ai-service/skills/index.js +0 -9
  238. package/dist/ai-service/skills/index.js.map +1 -1
  239. package/dist/ai-service/skills/system/_registry.generated.d.ts.map +1 -1
  240. package/dist/ai-service/skills/system/_registry.generated.js +4 -0
  241. package/dist/ai-service/skills/system/_registry.generated.js.map +1 -1
  242. package/dist/ai-service/skills/system/resolve.d.ts +2 -0
  243. package/dist/ai-service/skills/system/resolve.d.ts.map +1 -0
  244. package/dist/ai-service/skills/system/resolve.js +32 -0
  245. package/dist/ai-service/skills/system/resolve.js.map +1 -0
  246. package/dist/ai-service/skills/system/superblocks-frontend/_variants/api-imports-legacy.generated.d.ts +2 -0
  247. package/dist/ai-service/skills/system/superblocks-frontend/_variants/api-imports-legacy.generated.d.ts.map +1 -0
  248. package/dist/ai-service/skills/system/superblocks-frontend/_variants/api-imports-legacy.generated.js +9 -0
  249. package/dist/ai-service/skills/system/superblocks-frontend/_variants/api-imports-legacy.generated.js.map +1 -0
  250. package/dist/ai-service/skills/system/superblocks-frontend/_variants/api-imports-sdk.generated.d.ts +2 -0
  251. package/dist/ai-service/skills/system/superblocks-frontend/_variants/api-imports-sdk.generated.d.ts.map +1 -0
  252. package/dist/ai-service/skills/system/superblocks-frontend/_variants/api-imports-sdk.generated.js +11 -0
  253. package/dist/ai-service/skills/system/superblocks-frontend/_variants/api-imports-sdk.generated.js.map +1 -0
  254. package/dist/ai-service/skills/system/superblocks-frontend/skill.generated.d.ts +1 -1
  255. package/dist/ai-service/skills/system/superblocks-frontend/skill.generated.d.ts.map +1 -1
  256. package/dist/ai-service/skills/system/superblocks-frontend/skill.generated.js +16 -24
  257. package/dist/ai-service/skills/system/superblocks-frontend/skill.generated.js.map +1 -1
  258. package/dist/ai-service/skills/system/third-party-migration/skill.generated.d.ts +1 -1
  259. package/dist/ai-service/skills/system/third-party-migration/skill.generated.d.ts.map +1 -1
  260. package/dist/ai-service/skills/system/third-party-migration/skill.generated.js +1 -1
  261. package/dist/ai-service/state-machine/clark-fsm.d.ts +11 -0
  262. package/dist/ai-service/state-machine/clark-fsm.d.ts.map +1 -1
  263. package/dist/ai-service/state-machine/clark-fsm.js +7 -1
  264. package/dist/ai-service/state-machine/clark-fsm.js.map +1 -1
  265. package/dist/ai-service/state-machine/handlers/agent-planning.d.ts.map +1 -1
  266. package/dist/ai-service/state-machine/handlers/agent-planning.js +21 -0
  267. package/dist/ai-service/state-machine/handlers/agent-planning.js.map +1 -1
  268. package/dist/ai-service/state-machine/handlers/llm-generating.d.ts.map +1 -1
  269. package/dist/ai-service/state-machine/handlers/llm-generating.js +32 -9
  270. package/dist/ai-service/state-machine/handlers/llm-generating.js.map +1 -1
  271. package/dist/ai-service/state-machine/handlers/runtime-reviewing.d.ts.map +1 -1
  272. package/dist/ai-service/state-machine/handlers/runtime-reviewing.js +21 -2
  273. package/dist/ai-service/state-machine/handlers/runtime-reviewing.js.map +1 -1
  274. package/dist/ai-service/state-machine/helpers/stable-peer.d.ts +11 -2
  275. package/dist/ai-service/state-machine/helpers/stable-peer.d.ts.map +1 -1
  276. package/dist/ai-service/state-machine/helpers/stable-peer.js +105 -18
  277. package/dist/ai-service/state-machine/helpers/stable-peer.js.map +1 -1
  278. package/dist/ai-service/state-machine/mocks.d.ts +3 -1
  279. package/dist/ai-service/state-machine/mocks.d.ts.map +1 -1
  280. package/dist/ai-service/state-machine/mocks.js +52 -13
  281. package/dist/ai-service/state-machine/mocks.js.map +1 -1
  282. package/dist/ai-service/tasks/peer-push.d.ts +3 -0
  283. package/dist/ai-service/tasks/peer-push.d.ts.map +1 -1
  284. package/dist/ai-service/tasks/peer-push.js +33 -0
  285. package/dist/ai-service/tasks/peer-push.js.map +1 -1
  286. package/dist/ai-service/util/call-peer.d.ts +2 -0
  287. package/dist/ai-service/util/call-peer.d.ts.map +1 -1
  288. package/dist/ai-service/util/call-peer.js +17 -4
  289. package/dist/ai-service/util/call-peer.js.map +1 -1
  290. package/dist/ai-service/util/line-ranges.d.ts +21 -0
  291. package/dist/ai-service/util/line-ranges.d.ts.map +1 -0
  292. package/dist/ai-service/util/line-ranges.js +36 -0
  293. package/dist/ai-service/util/line-ranges.js.map +1 -0
  294. package/dist/ai-service/util/peer-liveness.d.ts +1 -0
  295. package/dist/ai-service/util/peer-liveness.d.ts.map +1 -1
  296. package/dist/ai-service/util/peer-liveness.js +2 -0
  297. package/dist/ai-service/util/peer-liveness.js.map +1 -1
  298. package/dist/dev-server-ws-smoke-client.d.ts.map +1 -1
  299. package/dist/dev-server-ws-smoke-client.js +7 -0
  300. package/dist/dev-server-ws-smoke-client.js.map +1 -1
  301. package/dist/draft-interface.d.ts +8 -0
  302. package/dist/draft-interface.d.ts.map +1 -1
  303. package/dist/early-error-relay.d.ts +2 -0
  304. package/dist/early-error-relay.d.ts.map +1 -1
  305. package/dist/early-error-relay.js +7 -3
  306. package/dist/early-error-relay.js.map +1 -1
  307. package/dist/file-sync-vite-plugin.d.ts.map +1 -1
  308. package/dist/file-sync-vite-plugin.js +43 -15
  309. package/dist/file-sync-vite-plugin.js.map +1 -1
  310. package/dist/file-system-helpers.d.ts +2 -2
  311. package/dist/file-system-helpers.d.ts.map +1 -1
  312. package/dist/file-system-helpers.js +3 -3
  313. package/dist/file-system-helpers.js.map +1 -1
  314. package/dist/git-service/errors.d.ts +9 -0
  315. package/dist/git-service/errors.d.ts.map +1 -1
  316. package/dist/git-service/errors.js +15 -0
  317. package/dist/git-service/errors.js.map +1 -1
  318. package/dist/git-service/index.d.ts +2 -2
  319. package/dist/git-service/index.d.ts.map +1 -1
  320. package/dist/git-service/index.js +2 -2
  321. package/dist/git-service/index.js.map +1 -1
  322. package/dist/index.d.ts +1 -0
  323. package/dist/index.d.ts.map +1 -1
  324. package/dist/index.js +1 -0
  325. package/dist/index.js.map +1 -1
  326. package/dist/lock-service/activity-tracker.d.ts +5 -0
  327. package/dist/lock-service/activity-tracker.d.ts.map +1 -1
  328. package/dist/lock-service/activity-tracker.js +10 -0
  329. package/dist/lock-service/activity-tracker.js.map +1 -1
  330. package/dist/lock-service/index.d.ts +69 -4
  331. package/dist/lock-service/index.d.ts.map +1 -1
  332. package/dist/lock-service/index.js +139 -29
  333. package/dist/lock-service/index.js.map +1 -1
  334. package/dist/migration-templates/app-fullstack/client/components/ui/accordion.tsx +9 -65
  335. package/dist/migration-templates/app-fullstack/client/components/ui/area-chart.tsx +36 -156
  336. package/dist/migration-templates/app-fullstack/client/components/ui/aspect-ratio.tsx +1 -5
  337. package/dist/migration-templates/app-fullstack/client/components/ui/avatar.tsx +4 -18
  338. package/dist/migration-templates/app-fullstack/client/components/ui/badge.tsx +6 -29
  339. package/dist/migration-templates/app-fullstack/client/components/ui/bar-chart.tsx +41 -167
  340. package/dist/migration-templates/app-fullstack/client/components/ui/breadcrumb.tsx +1 -4
  341. package/dist/migration-templates/app-fullstack/client/components/ui/button.tsx +5 -64
  342. package/dist/migration-templates/app-fullstack/client/components/ui/calendar.tsx +6 -42
  343. package/dist/migration-templates/app-fullstack/client/components/ui/card.tsx +1 -4
  344. package/dist/migration-templates/app-fullstack/client/components/ui/checkbox.tsx +4 -29
  345. package/dist/migration-templates/app-fullstack/client/components/ui/date-range-picker.tsx +13 -154
  346. package/dist/migration-templates/app-fullstack/client/components/ui/dialog.tsx +7 -34
  347. package/dist/migration-templates/app-fullstack/client/components/ui/file-dropzone.tsx +12 -95
  348. package/dist/migration-templates/app-fullstack/client/components/ui/file-input.tsx +12 -73
  349. package/dist/migration-templates/app-fullstack/client/components/ui/hover-card.tsx +10 -66
  350. package/dist/migration-templates/app-fullstack/client/components/ui/icon.tsx +3 -16
  351. package/dist/migration-templates/app-fullstack/client/components/ui/image.tsx +4 -16
  352. package/dist/migration-templates/app-fullstack/client/components/ui/input.tsx +18 -159
  353. package/dist/migration-templates/app-fullstack/client/components/ui/label.tsx +1 -4
  354. package/dist/migration-templates/app-fullstack/client/components/ui/line-chart.tsx +32 -148
  355. package/dist/migration-templates/app-fullstack/client/components/ui/link.tsx +4 -24
  356. package/dist/migration-templates/app-fullstack/client/components/ui/navigation-menu.tsx +3 -24
  357. package/dist/migration-templates/app-fullstack/client/components/ui/pagination.tsx +4 -24
  358. package/dist/migration-templates/app-fullstack/client/components/ui/pie-chart.tsx +28 -142
  359. package/dist/migration-templates/app-fullstack/client/components/ui/popover.tsx +9 -61
  360. package/dist/migration-templates/app-fullstack/client/components/ui/progress.tsx +2 -11
  361. package/dist/migration-templates/app-fullstack/client/components/ui/radar-chart.tsx +37 -171
  362. package/dist/migration-templates/app-fullstack/client/components/ui/radial-chart.tsx +50 -202
  363. package/dist/migration-templates/app-fullstack/client/components/ui/select.tsx +5 -35
  364. package/dist/migration-templates/app-fullstack/client/components/ui/separator.tsx +1 -8
  365. package/dist/migration-templates/app-fullstack/client/components/ui/sheet.tsx +7 -40
  366. package/dist/migration-templates/app-fullstack/client/components/ui/sidebar.tsx +3 -35
  367. package/dist/migration-templates/app-fullstack/client/components/ui/slider.tsx +11 -95
  368. package/dist/migration-templates/app-fullstack/client/components/ui/switch.tsx +5 -32
  369. package/dist/migration-templates/app-fullstack/client/components/ui/textarea.tsx +13 -90
  370. package/dist/migration-templates/app-fullstack/client/components/ui/toggle-group.tsx +11 -75
  371. package/dist/migration-templates/app-fullstack/client/components/ui/toggle.tsx +8 -70
  372. package/dist/migration-templates/app-fullstack/client/components/ui/tooltip.tsx +9 -62
  373. package/dist/parsing/imports.d.ts +22 -0
  374. package/dist/parsing/imports.d.ts.map +1 -1
  375. package/dist/parsing/imports.js +71 -0
  376. package/dist/parsing/imports.js.map +1 -1
  377. package/dist/reconnect-guard-plugin.d.ts +53 -0
  378. package/dist/reconnect-guard-plugin.d.ts.map +1 -0
  379. package/dist/reconnect-guard-plugin.js +203 -0
  380. package/dist/reconnect-guard-plugin.js.map +1 -0
  381. package/dist/resolver.d.ts +2 -1
  382. package/dist/resolver.d.ts.map +1 -1
  383. package/dist/resolver.js +4 -6
  384. package/dist/resolver.js.map +1 -1
  385. package/dist/router-parser-metrics.d.ts +2 -1
  386. package/dist/router-parser-metrics.d.ts.map +1 -1
  387. package/dist/router-parser-metrics.js.map +1 -1
  388. package/dist/router-parser.d.ts +10 -1
  389. package/dist/router-parser.d.ts.map +1 -1
  390. package/dist/router-parser.js +306 -69
  391. package/dist/router-parser.js.map +1 -1
  392. package/dist/scan-scope-merge-metrics.d.ts +2 -0
  393. package/dist/scan-scope-merge-metrics.d.ts.map +1 -0
  394. package/dist/scan-scope-merge-metrics.js +18 -0
  395. package/dist/scan-scope-merge-metrics.js.map +1 -0
  396. package/dist/scan-scope-merge.d.ts +2 -2
  397. package/dist/scan-scope-merge.d.ts.map +1 -1
  398. package/dist/scan-scope-merge.js +64 -14
  399. package/dist/scan-scope-merge.js.map +1 -1
  400. package/dist/server-rpc/index.d.ts.map +1 -1
  401. package/dist/server-rpc/index.js +12 -2
  402. package/dist/server-rpc/index.js.map +1 -1
  403. package/dist/socket-manager.d.ts +1 -1
  404. package/dist/socket-manager.d.ts.map +1 -1
  405. package/dist/socket-manager.js +276 -15
  406. package/dist/socket-manager.js.map +1 -1
  407. package/dist/sync-service/download.js +2 -2
  408. package/dist/sync-service/download.js.map +1 -1
  409. package/dist/sync-service/index.d.ts +95 -22
  410. package/dist/sync-service/index.d.ts.map +1 -1
  411. package/dist/sync-service/index.js +402 -56
  412. package/dist/sync-service/index.js.map +1 -1
  413. package/dist/sync-service/page-reference-guard.d.ts +17 -0
  414. package/dist/sync-service/page-reference-guard.d.ts.map +1 -0
  415. package/dist/sync-service/page-reference-guard.js +170 -0
  416. package/dist/sync-service/page-reference-guard.js.map +1 -0
  417. package/dist/util.d.ts.map +1 -1
  418. package/dist/util.js +16 -2
  419. package/dist/util.js.map +1 -1
  420. package/package.json +15 -14
@@ -1,16 +1,18 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { performance } from "node:perf_hooks";
3
3
  import { setImmediate } from "node:timers/promises";
4
+ import { promptCostTokensFrom } from "@superblocksteam/library-shared/types";
4
5
  import { getErrorMeta, getPrefixedLogger } from "../../../util/logger.js";
5
6
  import { LLMObsTracer } from "../../llmobs/tracer.js";
6
7
  import { findBreakpoints } from "./caching.js";
7
8
  import { SERVER_COMPACTION_INTERRUPTED_SUMMARY, SERVER_COMPACTION_SUMMARY, ServerSideCompactionStrategy, } from "./compaction/server-side.js";
8
9
  import { compactionThresholdTokens, DEFAULT_CACHING, resolveContextOptionsV2, } from "./config.js";
9
- import { recordContextPersist, recordPreflightCompaction, recordServerCompaction, recordTurnsSinceLastCompaction, } from "./context-metrics.js";
10
+ import { recordContextPersist, recordPostCompactionRecompute, recordPreflightCompaction, recordRetainedScreenshots, recordServerCompaction, recordTurnsSinceLastCompaction, } from "./context-metrics.js";
11
+ import { FileReadLedger } from "./file-read-ledger.js";
10
12
  import { OperationQueue } from "./operation-queue.js";
11
13
  import { CLIENT_COMPACTION_MARKER } from "./storage/event-types.js";
12
14
  import { estimateMessagesTokens, getTotalInputTokens, } from "./token-tracker.js";
13
- import { toStoredMessage, toSdkMessages, CACHE_BREAKPOINT_PROVIDER_OPTIONS, normalizeToolMessage, stripUndefinedFromToolOutputs, repairBrokenToolCalls, repairOrphanedToolResults, enforceToolUsePairing, normalizeReasoningProviderOptions, stripUnsignedReasoning, stripTrailingAssistantPrefill, extractTokenUsage, } from "./types.js";
15
+ import { toStoredMessage, toSdkMessages, CACHE_BREAKPOINT_PROVIDER_OPTIONS, normalizeToolMessage, stripUndefinedFromToolOutputs, repairBrokenToolCalls, repairOrphanedToolResults, enforceToolUsePairing, normalizeReasoningProviderOptions, stripUnsignedReasoning, stripTrailingAssistantPrefill, extractTokenUsage, SUMMARIZED_TOOL_OUTPUT_PREFIX, } from "./types.js";
14
16
  import { uniquifyFilePartFilenames } from "./uniquify-filenames.js";
15
17
  import { makeJsonSafeValue } from "./well-formed-text.js";
16
18
  const logger = getPrefixedLogger("[context-v2]");
@@ -186,6 +188,34 @@ function stripScreenshotMediaFromToolMessage(msg) {
186
188
  logger.info("Stripped screenshot media from tool message before storage");
187
189
  return { ...msg, content: strippedContent };
188
190
  }
191
+ /**
192
+ * Return `messages` with screenshot media kept only on the newest screenshot.
193
+ *
194
+ * Pure: messages that are not rewritten come back by reference, and when
195
+ * nothing needs stripping the original array is returned unchanged, so the
196
+ * common case allocates nothing.
197
+ */
198
+ function stripAllButLatestScreenshotMedia(messages) {
199
+ let latestKept = false;
200
+ let retained = 0;
201
+ let stripped = 0;
202
+ let next;
203
+ for (let i = messages.length - 1; i >= 0; i--) {
204
+ const msg = messages[i];
205
+ if (!msg || !hasScreenshotMedia(msg)) {
206
+ continue;
207
+ }
208
+ retained++;
209
+ if (!latestKept) {
210
+ latestKept = true;
211
+ continue;
212
+ }
213
+ next ??= [...messages];
214
+ next[i] = stripScreenshotMediaFromToolMessage(msg);
215
+ stripped++;
216
+ }
217
+ return { messages: next ?? messages, retained, stripped };
218
+ }
189
219
  export class ContextV2 {
190
220
  systemPrompt;
191
221
  messages = [];
@@ -198,6 +228,21 @@ export class ContextV2 {
198
228
  rootDir;
199
229
  skillsNeedReload = false;
200
230
  readSystemSkills = new Set();
231
+ /**
232
+ * Reads the model can still see, so `build_readFile` can stub a redundant
233
+ * re-read instead of re-appending the bytes.
234
+ *
235
+ * This lives here and must not be moved "up" to `AppShell` for convenience.
236
+ * `AppShell` is per-app/dev-server and shared across conversations, so a
237
+ * ledger there would answer "already in context" after a New Chat for a file
238
+ * the conversation has never seen. `ContextV2` owns `messages` privately, so
239
+ * it is the only layer that can answer whether a tool result is still
240
+ * visible.
241
+ */
242
+ fileReadLedger = new FileReadLedger({
243
+ isToolResultLive: (id) => this.isToolResultLive(id),
244
+ historyLength: () => this.messages.length,
245
+ });
201
246
  getModeState;
202
247
  /**
203
248
  * Real provider usage captured when `runCompactionIfNeeded` defers past an
@@ -226,6 +271,15 @@ export class ContextV2 {
226
271
  serverCompactionCompletedBeforeStart = false;
227
272
  completedTurnCount = 0;
228
273
  lastCompactionAtTurnIndex = 0;
274
+ /**
275
+ * Set when a compaction just committed, cleared by the next response that
276
+ * carries real usage. Lets {@link ingestResponse} attribute that response's
277
+ * input tokens to the compaction that rewrote the prefix it now has to
278
+ * recompute — the split between cached and fresh tokens is the actual cache
279
+ * cost of the compaction. A second compaction before any real usage arrives
280
+ * overwrites the pending path; only the latest is attributed.
281
+ */
282
+ pendingCompactionRecomputePath;
229
283
  // When disposed, this context may still be referenced by in-flight streams.
230
284
  // Keep it inert so stale generations cannot persist cleared history.
231
285
  isDisposed = false;
@@ -398,7 +452,7 @@ export class ContextV2 {
398
452
  }
399
453
  markSkillsNeedReload() {
400
454
  this.skillsNeedReload = true;
401
- this.readSystemSkills.clear();
455
+ this.clearContextDerivedReadState();
402
456
  }
403
457
  checkAndClearSkillsNeedReload() {
404
458
  if (this.skillsNeedReload) {
@@ -413,6 +467,108 @@ export class ContextV2 {
413
467
  markSystemSkillRead(path) {
414
468
  this.readSystemSkills.add(path);
415
469
  }
470
+ /**
471
+ * Drops per-conversation state derived from what the model can currently see.
472
+ * Called wherever history is compacted, truncated, or reloaded, so anything
473
+ * keyed on "the model already has this" is dropped in one place.
474
+ *
475
+ * {@link pendingCompactionRecomputePath} is not that kind of state: it is
476
+ * set *by* compaction so the next real-usage response can record the
477
+ * rewritten prefix's cache cost. Phase 2 always requests a skills reload,
478
+ * so clearing the latch here would drop the metric on the path it exists
479
+ * to measure. Truncate/reload pass
480
+ * `dropPendingCompactionRecompute` because they break the prefix
481
+ * assumption.
482
+ */
483
+ clearContextDerivedReadState(options = {}) {
484
+ this.readSystemSkills.clear();
485
+ this.fileReadLedger.clear();
486
+ if (options.dropPendingCompactionRecompute) {
487
+ this.pendingCompactionRecomputePath = undefined;
488
+ }
489
+ }
490
+ evaluateFileRead(input) {
491
+ return this.fileReadLedger.evaluate(input);
492
+ }
493
+ recordFileRead(input) {
494
+ this.fileReadLedger.recordServed(input);
495
+ }
496
+ recordFileReadStub(filePath, requested) {
497
+ this.fileReadLedger.recordStub(filePath, requested);
498
+ }
499
+ /** Ledger entry count, for the read-file metric. */
500
+ fileReadLedgerSize() {
501
+ return this.fileReadLedger.size();
502
+ }
503
+ /**
504
+ * Called by the stream observer when the provider reports `clear_tool_uses`.
505
+ *
506
+ * Provider-side clearing is reported in aggregate only - no call ids - so
507
+ * everything keyed on "the model already has this" is dropped rather than
508
+ * guessing which results died.
509
+ */
510
+ onServerToolUsesCleared() {
511
+ // Only the ledger. Clearing skill-read state here would change behavior at
512
+ // the `off` flag, and it is not needed: one system-skill read puts
513
+ // `build_readFile` in the provider's name-scoped `excludeTools`, so skill
514
+ // reads survive the clear that triggered this.
515
+ this.fileReadLedger.clear();
516
+ }
517
+ /**
518
+ * Called by the stream observer when a step's messages are thrown away
519
+ * instead of committed.
520
+ *
521
+ * The reads that step issued are still pending in the ledger, waiting for an
522
+ * append that is never coming. Left alone they would read as visible on the
523
+ * retry, and the retried request does not carry them.
524
+ */
525
+ onStepDiscarded() {
526
+ this.fileReadLedger.dropPendingContributions();
527
+ }
528
+ /**
529
+ * Whether the model can still see the output of a tool result.
530
+ *
531
+ * Both the `[summarized] ` output prefix and the `summarized` message flag
532
+ * are checked because phase 1 sets both and either could move. The
533
+ * input-side `[summarized: do not use this as tool input] ` prefix is a
534
+ * different marker on tool CALLS and deliberately does not count.
535
+ */
536
+ isToolResultLive(toolCallId) {
537
+ return this.findLiveToolResultPart(toolCallId) !== undefined;
538
+ }
539
+ /**
540
+ * The live tool-result output text for `toolCallId`, for diff-based
541
+ * re-injection when `build_readFile` finds a changed file. Undefined when
542
+ * the id has no live, text-typed tool-result part - the caller falls back
543
+ * to serving full content rather than diffing against nothing.
544
+ */
545
+ getLiveToolResultText(toolCallId) {
546
+ const part = this.findLiveToolResultPart(toolCallId);
547
+ return part === undefined ? undefined : extractToolResultText(part);
548
+ }
549
+ /** Shared traversal behind {@link isToolResultLive} and {@link getLiveToolResultText}. */
550
+ findLiveToolResultPart(toolCallId) {
551
+ for (let i = this.messages.length - 1; i >= 0; i--) {
552
+ const msg = this.messages[i];
553
+ if (msg?.role !== "tool" || !Array.isArray(msg.content)) {
554
+ continue;
555
+ }
556
+ const part = msg.content.find((candidate) => typeof candidate === "object" &&
557
+ candidate !== null &&
558
+ "type" in candidate &&
559
+ candidate.type === "tool-result" &&
560
+ "toolCallId" in candidate &&
561
+ candidate.toolCallId === toolCallId);
562
+ if (!part) {
563
+ continue;
564
+ }
565
+ if (msg._superblocks?.summarized === true) {
566
+ return undefined;
567
+ }
568
+ return isSummarizedToolOutput(part) ? undefined : part;
569
+ }
570
+ return undefined;
571
+ }
416
572
  setAttachments(attachments) {
417
573
  this.attachments = attachments;
418
574
  void this.persist("attachments");
@@ -422,12 +578,16 @@ export class ContextV2 {
422
578
  }
423
579
  truncateAfterTimestamp(timestamp) {
424
580
  this.invalidateMessageCache();
425
- this.readSystemSkills.clear();
581
+ this.clearContextDerivedReadState({
582
+ dropPendingCompactionRecompute: true,
583
+ });
426
584
  void this.queue.enqueue(async () => {
427
585
  const initialCount = this.messages.length;
428
586
  this.messages = this.messages.filter((msg) => !msg._superblocks?.timestamp ||
429
587
  msg._superblocks.timestamp <= timestamp);
430
- this.readSystemSkills.clear();
588
+ this.clearContextDerivedReadState({
589
+ dropPendingCompactionRecompute: true,
590
+ });
431
591
  this.invalidateMessageCache();
432
592
  const removed = initialCount - this.messages.length;
433
593
  logger.info(`Truncated context after timestamp ${timestamp}. Removed ${removed} messages, ${this.messages.length} remaining.`);
@@ -438,12 +598,21 @@ export class ContextV2 {
438
598
  const context = new ContextV2(options);
439
599
  context.messages = record.messages;
440
600
  context.attachments = record.attachments;
441
- // Live sessions keep media on only the newest screenshot, but event-log
442
- // entries are appended before that stripping happens, so a restored
443
- // record can resurrect every screenshot's media. Re-stripping here keeps
444
- // the restored request bytes identical to what the provider's prompt
445
- // cache saw before the restart (APPS-4751) — and avoids re-sending
446
- // megabytes of stale base64.
601
+ // A live session keeps media on EVERY screenshot until a compaction
602
+ // commit -- rewriting one the model has already been sent poisons the
603
+ // prompt-cache entry sitting on it (APPS-5709). Do not "restore symmetry"
604
+ // by putting this call back on `addResponses`; that is the bug.
605
+ //
606
+ // This still has to run. `toPersistedRecord` already strips `main.json`,
607
+ // so for a record restore it is a no-op, but the event log appends full
608
+ // media per message before any stripping, so a replay can resurrect every
609
+ // screenshot's bytes. Without this, restore re-sends megabytes of stale
610
+ // base64.
611
+ //
612
+ // The consequence is deliberate: a restored context holds one image where
613
+ // the live one held many, so its prefix differs and a mid-turn restart is
614
+ // a one-shot cache miss. That is the accepted trade -- restarts are rare,
615
+ // and the alternative was rewriting history on every capture.
447
616
  context.stripAllButLatestScreenshot();
448
617
  return context;
449
618
  }
@@ -454,6 +623,28 @@ export class ContextV2 {
454
623
  attachments: this.attachments,
455
624
  };
456
625
  }
626
+ /**
627
+ * The record written to disk: {@link toRecord} with screenshot media kept
628
+ * only on the newest screenshot.
629
+ *
630
+ * In-memory messages deliberately keep every image, because rewriting one
631
+ * the model has already been sent invalidates the prompt-cache entry sitting
632
+ * on it (APPS-5709). The stored record is under no such constraint -- it is
633
+ * only ever read back through `fromRecord` / `replayMessages`, both of which
634
+ * strip to the newest screenshot anyway -- so bounding it here keeps the
635
+ * snapshot small without touching the conversation. Without this, a long
636
+ * verification-heavy turn walks the record toward the >5MB warning in
637
+ * `LocalContextStorageV2`.
638
+ *
639
+ * The event log is intentionally left alone: it stores full media per
640
+ * message by design, and replay strips on the way back in.
641
+ */
642
+ toPersistedRecord() {
643
+ return {
644
+ ...this.toRecord(),
645
+ messages: stripAllButLatestScreenshotMedia(this.messages).messages,
646
+ };
647
+ }
457
648
  setSystemPrompt(prompt) {
458
649
  this.systemPrompt = toStoredMessage(prompt);
459
650
  this.invalidateMessageCache();
@@ -520,9 +711,7 @@ export class ContextV2 {
520
711
  await this.appendEvent("prompt_sent", storedMessage);
521
712
  continue;
522
713
  }
523
- const storedResponse = this.ingestResponse(message, ZERO_USAGE, {
524
- stripOlderScreenshots: false,
525
- });
714
+ const storedResponse = this.ingestResponse(message, ZERO_USAGE);
526
715
  const eventUsage = message.role === "assistant"
527
716
  ? extractTokenUsage(ZERO_USAGE)
528
717
  : undefined;
@@ -544,9 +733,7 @@ export class ContextV2 {
544
733
  async addResponse(response, usage) {
545
734
  this.invalidateMessageCache();
546
735
  await this.queue.enqueue(async () => {
547
- const storedResponse = this.ingestResponse(response, usage, {
548
- stripOlderScreenshots: true,
549
- });
736
+ const storedResponse = this.ingestResponse(response, usage);
550
737
  this.invalidateMessageCache();
551
738
  if (response.role === "assistant" || response.role === "tool") {
552
739
  const eventUsage = response.role === "assistant" ? extractTokenUsage(usage) : undefined;
@@ -574,9 +761,9 @@ export class ContextV2 {
574
761
  * message is appended to the event log (an O(1) append that carries
575
762
  * per-message durability), and the legacy full-record snapshot is deferred
576
763
  * to {@link endTurn} so the whole generation costs one rewrite instead of
577
- * one per message. Screenshot-media stripping is likewise deferred to a
578
- * single backward pass (mirroring {@link initializeWith}) instead of an
579
- * O(history) scan per message.
764
+ * one per message. Committing is append-only: nothing already sent to the
765
+ * model is rewritten here, so the prompt-cache entries sitting on those
766
+ * messages stay valid (APPS-5709).
580
767
  */
581
768
  async addResponses(responses, usage) {
582
769
  if (responses.length === 0) {
@@ -585,9 +772,7 @@ export class ContextV2 {
585
772
  this.invalidateMessageCache();
586
773
  await this.queue.enqueue(async () => {
587
774
  for (const response of responses) {
588
- const storedResponse = this.ingestResponse(response, usage, {
589
- stripOlderScreenshots: false,
590
- });
775
+ const storedResponse = this.ingestResponse(response, usage);
591
776
  if (response.role === "assistant" || response.role === "tool") {
592
777
  const eventUsage = response.role === "assistant"
593
778
  ? extractTokenUsage(usage)
@@ -595,7 +780,12 @@ export class ContextV2 {
595
780
  await this.appendEvent("response_received", storedResponse, eventUsage);
596
781
  }
597
782
  }
598
- this.stripAllButLatestScreenshot();
783
+ // Screenshot media is deliberately NOT stripped here. Every message the
784
+ // model has already been sent is a position the prompt cache may hold an
785
+ // entry on; rewriting one in place poisons that entry permanently, and
786
+ // screenshot tool results always terminate their step, so they always
787
+ // carry the trailing breakpoint. Stripping happens where the prefix is
788
+ // being rebuilt anyway -- compaction and replay (APPS-5709).
599
789
  this.invalidateMessageCache();
600
790
  });
601
791
  // Compaction runs once after the step is committed. It inspects the whole
@@ -630,15 +820,16 @@ export class ContextV2 {
630
820
  await this.persist("turn_end");
631
821
  });
632
822
  }
633
- recordInterCompactionTurnInterval() {
823
+ recordInterCompactionTurnInterval(path) {
634
824
  const turnsSince = this.completedTurnCount - this.lastCompactionAtTurnIndex;
635
825
  if (turnsSince > 0) {
636
826
  recordTurnsSinceLastCompaction(turnsSince);
637
827
  }
638
828
  this.lastCompactionAtTurnIndex = this.completedTurnCount;
829
+ this.pendingCompactionRecomputePath = path;
639
830
  }
640
831
  /** Store a single assistant/tool/other response message and return it. */
641
- ingestResponse(response, usage, options) {
832
+ ingestResponse(response, usage) {
642
833
  switch (response.role) {
643
834
  case "assistant": {
644
835
  // Total input tokens = non-cached + cached (prompt caching splits these)
@@ -648,6 +839,20 @@ export class ContextV2 {
648
839
  // Use the higher of reported tokens or last known to maintain monotonicity.
649
840
  const lastKnownTokens = this.getLastKnownInputTokens();
650
841
  const cumulativeInputTokens = Math.max(reportedInputTokens, lastKnownTokens);
842
+ // The first response with real usage after a compaction committed is
843
+ // the one that resent the (now rewritten) prefix, so its cache split
844
+ // is that compaction's actual cost. One-shot: cleared immediately so
845
+ // a later unrelated response never gets attributed to it.
846
+ if (this.pendingCompactionRecomputePath && reportedInputTokens > 0) {
847
+ const costTokens = promptCostTokensFrom(usage);
848
+ recordPostCompactionRecompute({
849
+ ...this.getMetricIdentity(),
850
+ cachedInputTokens: costTokens.cachedReadTokens,
851
+ newInputTokens: costTokens.inputTokens,
852
+ path: this.pendingCompactionRecomputePath,
853
+ });
854
+ this.pendingCompactionRecomputePath = undefined;
855
+ }
651
856
  normalizeReasoningProviderOptions(response);
652
857
  const extraMeta = this.compaction.collectAssistantMetadata(response) ?? {};
653
858
  const storedResponse = toStoredMessage(response, {
@@ -660,21 +865,6 @@ export class ContextV2 {
660
865
  }
661
866
  case "tool": {
662
867
  const normalized = normalizeToolMessage(stripUndefinedFromToolOutputs(response));
663
- // Strip media from older screenshots so at most one is kept in stored
664
- // messages. Bulk replay defers this to a single pass at the end.
665
- if (options.stripOlderScreenshots && hasScreenshotMedia(normalized)) {
666
- let strippedCount = 0;
667
- for (let i = 0; i < this.messages.length; i++) {
668
- const msg = this.messages[i];
669
- if (msg && hasScreenshotMedia(msg)) {
670
- this.messages[i] = stripScreenshotMediaFromToolMessage(msg);
671
- strippedCount++;
672
- }
673
- }
674
- if (strippedCount > 0) {
675
- logger.info(`Stripped media from ${strippedCount} older screenshot(s)`);
676
- }
677
- }
678
868
  const extraMeta = this.compaction.collectToolMetadata(normalized) ?? {};
679
869
  const storedResponse = toStoredMessage(normalized, extraMeta);
680
870
  this.messages.push(storedResponse);
@@ -687,24 +877,20 @@ export class ContextV2 {
687
877
  }
688
878
  }
689
879
  }
690
- /** Single backwards pass keeping media on only the newest screenshot. */
880
+ /**
881
+ * Single backwards pass keeping media on only the newest screenshot.
882
+ *
883
+ * Only safe to call where the cached prefix is already being discarded --
884
+ * compaction commits and replay. Calling it mid-turn rewrites messages the
885
+ * model has already been sent, which invalidates the cache entries sitting
886
+ * on them (APPS-5709).
887
+ */
691
888
  stripAllButLatestScreenshot() {
692
- let latestKept = false;
693
- let strippedCount = 0;
694
- for (let i = this.messages.length - 1; i >= 0; i--) {
695
- const msg = this.messages[i];
696
- if (!msg || !hasScreenshotMedia(msg)) {
697
- continue;
698
- }
699
- if (!latestKept) {
700
- latestKept = true;
701
- continue;
702
- }
703
- this.messages[i] = stripScreenshotMediaFromToolMessage(msg);
704
- strippedCount++;
705
- }
706
- if (strippedCount > 0) {
707
- logger.info(`Stripped media from ${strippedCount} older screenshot(s)`);
889
+ const { messages, retained, stripped } = stripAllButLatestScreenshotMedia(this.messages);
890
+ this.messages = messages;
891
+ recordRetainedScreenshots(retained);
892
+ if (stripped > 0) {
893
+ logger.info(`Stripped media from ${stripped} older screenshot(s)`);
708
894
  }
709
895
  }
710
896
  /**
@@ -761,16 +947,17 @@ export class ContextV2 {
761
947
  usage: effectiveUsage,
762
948
  });
763
949
  if (result.messages) {
764
- this.recordInterCompactionTurnInterval();
950
+ this.recordInterCompactionTurnInterval("client");
765
951
  // Retained assistant messages still carry pre-compaction
766
952
  // `cumulativeInputTokens`. Mark them so the post-compaction floor
767
953
  // resets (see `markPreCompactionBaselines` / `getLastKnownInputTokens`).
768
954
  this.messages = this.markPreCompactionBaselines(result.messages);
955
+ this.stripAllButLatestScreenshot();
769
956
  this.invalidateMessageCache();
770
957
  }
771
958
  if (result.skillsNeedReload) {
772
959
  this.skillsNeedReload = true;
773
- this.readSystemSkills.clear();
960
+ this.clearContextDerivedReadState();
774
961
  }
775
962
  if (result.eventLogAnchor && result.messages) {
776
963
  // Append the marked messages so the reset survives reload from the
@@ -1070,10 +1257,11 @@ export class ContextV2 {
1070
1257
  }
1071
1258
  this.messages = candidate;
1072
1259
  committed = true;
1260
+ this.stripAllButLatestScreenshot();
1073
1261
  this.invalidateMessageCache();
1074
1262
  if (result.skillsNeedReload) {
1075
1263
  this.skillsNeedReload = true;
1076
- this.readSystemSkills.clear();
1264
+ this.clearContextDerivedReadState();
1077
1265
  }
1078
1266
  if (result.eventLogAnchor) {
1079
1267
  await this.appendCompactionWindow(this.messages);
@@ -1254,11 +1442,12 @@ export class ContextV2 {
1254
1442
  : null;
1255
1443
  if (marked) {
1256
1444
  this.messages = marked;
1445
+ this.stripAllButLatestScreenshot();
1257
1446
  this.invalidateMessageCache();
1258
1447
  }
1259
1448
  if (result.skillsNeedReload) {
1260
1449
  this.skillsNeedReload = true;
1261
- this.readSystemSkills.clear();
1450
+ this.clearContextDerivedReadState();
1262
1451
  }
1263
1452
  const marker = result.messages?.[0];
1264
1453
  const summary = typeof marker?.content === "string"
@@ -1267,7 +1456,7 @@ export class ContextV2 {
1267
1456
  const durationMs = this.getActiveServerCompactionDurationMs();
1268
1457
  const didComplete = this.completeServerCompactionMessage(summary, detectedGeneration);
1269
1458
  if (didComplete) {
1270
- this.recordInterCompactionTurnInterval();
1459
+ this.recordInterCompactionTurnInterval("server");
1271
1460
  recordServerCompaction({
1272
1461
  ...this.getMetricIdentity(),
1273
1462
  durationMs,
@@ -1632,7 +1821,7 @@ export class ContextV2 {
1632
1821
  const eluStart = performance.eventLoopUtilization();
1633
1822
  let persistError;
1634
1823
  try {
1635
- await onPersist(this.toRecord());
1824
+ await onPersist(this.toPersistedRecord());
1636
1825
  }
1637
1826
  catch (err) {
1638
1827
  persistError = err;
@@ -1663,4 +1852,27 @@ export class ContextV2 {
1663
1852
  });
1664
1853
  }
1665
1854
  }
1855
+ /**
1856
+ * A tool-result part's output text, when it has one. Undefined for a
1857
+ * non-text output (or not a tool-result part at all) rather than an empty
1858
+ * string, so callers can tell "no text" from "empty text".
1859
+ */
1860
+ function extractToolResultText(part) {
1861
+ if (typeof part !== "object" || part === null || !("output" in part)) {
1862
+ return undefined;
1863
+ }
1864
+ const output = part.output;
1865
+ if (typeof output !== "object" || output === null || !("value" in output)) {
1866
+ return undefined;
1867
+ }
1868
+ const value = output.value;
1869
+ return typeof value === "string" ? value : undefined;
1870
+ }
1871
+ /**
1872
+ * True when a tool-result part's output carries the phase-1 summarized
1873
+ * prefix, meaning the model sees a summary instead of the real output.
1874
+ */
1875
+ function isSummarizedToolOutput(part) {
1876
+ return (extractToolResultText(part) ?? "").startsWith(SUMMARIZED_TOOL_OUTPUT_PREFIX);
1877
+ }
1666
1878
  //# sourceMappingURL=context.js.map