@namzu/sdk 39.0.0 → 41.0.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 (289) hide show
  1. package/CHANGELOG.md +328 -0
  2. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  3. package/dist/bridge/a2a/mapper.js +8 -0
  4. package/dist/bridge/a2a/mapper.js.map +1 -1
  5. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  6. package/dist/bridge/sse/mapper.js +11 -0
  7. package/dist/bridge/sse/mapper.js.map +1 -1
  8. package/dist/connector/index.d.ts +2 -2
  9. package/dist/connector/index.d.ts.map +1 -1
  10. package/dist/connector/index.js +1 -1
  11. package/dist/connector/index.js.map +1 -1
  12. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  13. package/dist/connector/mcp/adapter.js +112 -10
  14. package/dist/connector/mcp/adapter.js.map +1 -1
  15. package/dist/connector/mcp/audio-admission.d.ts +17 -0
  16. package/dist/connector/mcp/audio-admission.d.ts.map +1 -0
  17. package/dist/connector/mcp/audio-admission.js +171 -0
  18. package/dist/connector/mcp/audio-admission.js.map +1 -0
  19. package/dist/connector/mcp/client.d.ts +252 -1
  20. package/dist/connector/mcp/client.d.ts.map +1 -1
  21. package/dist/connector/mcp/client.js +611 -39
  22. package/dist/connector/mcp/client.js.map +1 -1
  23. package/dist/connector/mcp/envelope.d.ts +91 -0
  24. package/dist/connector/mcp/envelope.d.ts.map +1 -0
  25. package/dist/connector/mcp/envelope.js +173 -0
  26. package/dist/connector/mcp/envelope.js.map +1 -0
  27. package/dist/connector/mcp/era.d.ts +130 -0
  28. package/dist/connector/mcp/era.d.ts.map +1 -0
  29. package/dist/connector/mcp/era.js +304 -0
  30. package/dist/connector/mcp/era.js.map +1 -0
  31. package/dist/connector/mcp/errors.d.ts +106 -0
  32. package/dist/connector/mcp/errors.d.ts.map +1 -0
  33. package/dist/connector/mcp/errors.js +154 -0
  34. package/dist/connector/mcp/errors.js.map +1 -0
  35. package/dist/connector/mcp/http-sse.d.ts +11 -0
  36. package/dist/connector/mcp/http-sse.d.ts.map +1 -1
  37. package/dist/connector/mcp/http-sse.js +21 -6
  38. package/dist/connector/mcp/http-sse.js.map +1 -1
  39. package/dist/connector/mcp/index.d.ts +7 -0
  40. package/dist/connector/mcp/index.d.ts.map +1 -1
  41. package/dist/connector/mcp/index.js +10 -0
  42. package/dist/connector/mcp/index.js.map +1 -1
  43. package/dist/connector/mcp/streamable-http.d.ts +83 -0
  44. package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
  45. package/dist/connector/mcp/streamable-http.js +177 -11
  46. package/dist/connector/mcp/streamable-http.js.map +1 -1
  47. package/dist/connector/mcp/x-mcp-header.d.ts +56 -0
  48. package/dist/connector/mcp/x-mcp-header.d.ts.map +1 -0
  49. package/dist/connector/mcp/x-mcp-header.js +254 -0
  50. package/dist/connector/mcp/x-mcp-header.js.map +1 -0
  51. package/dist/constants/mcp/index.d.ts +123 -15
  52. package/dist/constants/mcp/index.d.ts.map +1 -1
  53. package/dist/constants/mcp/index.js +135 -16
  54. package/dist/constants/mcp/index.js.map +1 -1
  55. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  56. package/dist/manager/agent/lifecycle.js +23 -0
  57. package/dist/manager/agent/lifecycle.js.map +1 -1
  58. package/dist/manager/run/persistence.d.ts +8 -0
  59. package/dist/manager/run/persistence.d.ts.map +1 -1
  60. package/dist/manager/run/persistence.js +12 -0
  61. package/dist/manager/run/persistence.js.map +1 -1
  62. package/dist/prompt/coding-agent-doctrine.d.ts +20 -0
  63. package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
  64. package/dist/prompt/coding-agent-doctrine.js +19 -3
  65. package/dist/prompt/coding-agent-doctrine.js.map +1 -1
  66. package/dist/prompt/index.d.ts +1 -1
  67. package/dist/prompt/index.d.ts.map +1 -1
  68. package/dist/prompt/index.js +1 -1
  69. package/dist/prompt/index.js.map +1 -1
  70. package/dist/public-runtime.d.ts +6 -4
  71. package/dist/public-runtime.d.ts.map +1 -1
  72. package/dist/public-runtime.js +8 -4
  73. package/dist/public-runtime.js.map +1 -1
  74. package/dist/public-tools.d.ts +11 -0
  75. package/dist/public-tools.d.ts.map +1 -1
  76. package/dist/public-tools.js +14 -0
  77. package/dist/public-tools.js.map +1 -1
  78. package/dist/registry/tool/execute.d.ts.map +1 -1
  79. package/dist/registry/tool/execute.js +2 -3
  80. package/dist/registry/tool/execute.js.map +1 -1
  81. package/dist/registry/tool/portable.d.ts +65 -0
  82. package/dist/registry/tool/portable.d.ts.map +1 -0
  83. package/dist/registry/tool/portable.js +244 -0
  84. package/dist/registry/tool/portable.js.map +1 -0
  85. package/dist/registry/tool/schema.d.ts +32 -5
  86. package/dist/registry/tool/schema.d.ts.map +1 -1
  87. package/dist/registry/tool/schema.js +35 -9
  88. package/dist/registry/tool/schema.js.map +1 -1
  89. package/dist/registry/toolset/catalog.js +8 -8
  90. package/dist/registry/toolset/catalog.js.map +1 -1
  91. package/dist/runtime/jobs/awaited-jobs.d.ts +215 -0
  92. package/dist/runtime/jobs/awaited-jobs.d.ts.map +1 -0
  93. package/dist/runtime/jobs/awaited-jobs.js +259 -0
  94. package/dist/runtime/jobs/awaited-jobs.js.map +1 -0
  95. package/dist/runtime/jobs/registry.d.ts +33 -2
  96. package/dist/runtime/jobs/registry.d.ts.map +1 -1
  97. package/dist/runtime/jobs/registry.js +37 -0
  98. package/dist/runtime/jobs/registry.js.map +1 -1
  99. package/dist/runtime/query/executor.d.ts +28 -0
  100. package/dist/runtime/query/executor.d.ts.map +1 -1
  101. package/dist/runtime/query/executor.js +39 -1
  102. package/dist/runtime/query/executor.js.map +1 -1
  103. package/dist/runtime/query/file-evidence-context.d.ts.map +1 -1
  104. package/dist/runtime/query/file-evidence-context.js +159 -43
  105. package/dist/runtime/query/file-evidence-context.js.map +1 -1
  106. package/dist/runtime/query/file-evidence-replay.d.ts +260 -0
  107. package/dist/runtime/query/file-evidence-replay.d.ts.map +1 -0
  108. package/dist/runtime/query/file-evidence-replay.js +647 -0
  109. package/dist/runtime/query/file-evidence-replay.js.map +1 -0
  110. package/dist/runtime/query/file-evidence-seed.d.ts +50 -0
  111. package/dist/runtime/query/file-evidence-seed.d.ts.map +1 -0
  112. package/dist/runtime/query/file-evidence-seed.js +100 -0
  113. package/dist/runtime/query/file-evidence-seed.js.map +1 -0
  114. package/dist/runtime/query/index.d.ts.map +1 -1
  115. package/dist/runtime/query/index.js +94 -2
  116. package/dist/runtime/query/index.js.map +1 -1
  117. package/dist/runtime/query/iteration/index.d.ts +87 -9
  118. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  119. package/dist/runtime/query/iteration/index.js +193 -28
  120. package/dist/runtime/query/iteration/index.js.map +1 -1
  121. package/dist/runtime/query/iteration/phases/context.d.ts +10 -0
  122. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  123. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  124. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  125. package/dist/runtime/query/iteration/phases/tool-review.js +5 -1
  126. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  127. package/dist/runtime/query/plugin-hooks.d.ts +14 -0
  128. package/dist/runtime/query/plugin-hooks.d.ts.map +1 -1
  129. package/dist/runtime/query/plugin-hooks.js +18 -0
  130. package/dist/runtime/query/plugin-hooks.js.map +1 -1
  131. package/dist/runtime/query/repeat-call.d.ts +17 -4
  132. package/dist/runtime/query/repeat-call.d.ts.map +1 -1
  133. package/dist/runtime/query/repeat-call.js +26 -19
  134. package/dist/runtime/query/repeat-call.js.map +1 -1
  135. package/dist/runtime/query/steering.d.ts +11 -1
  136. package/dist/runtime/query/steering.d.ts.map +1 -1
  137. package/dist/runtime/query/steering.js +12 -1
  138. package/dist/runtime/query/steering.js.map +1 -1
  139. package/dist/runtime/query/tooling.d.ts +2 -0
  140. package/dist/runtime/query/tooling.d.ts.map +1 -1
  141. package/dist/runtime/query/tooling.js +1 -0
  142. package/dist/runtime/query/tooling.js.map +1 -1
  143. package/dist/sandbox/provider/local.d.ts.map +1 -1
  144. package/dist/sandbox/provider/local.js +46 -3
  145. package/dist/sandbox/provider/local.js.map +1 -1
  146. package/dist/scheduler/completion-inbox.d.ts +48 -2
  147. package/dist/scheduler/completion-inbox.d.ts.map +1 -1
  148. package/dist/scheduler/completion-inbox.js +102 -10
  149. package/dist/scheduler/completion-inbox.js.map +1 -1
  150. package/dist/scheduler/local.d.ts.map +1 -1
  151. package/dist/scheduler/local.js +8 -0
  152. package/dist/scheduler/local.js.map +1 -1
  153. package/dist/store/run/disk.d.ts +35 -1
  154. package/dist/store/run/disk.d.ts.map +1 -1
  155. package/dist/store/run/disk.js +100 -0
  156. package/dist/store/run/disk.js.map +1 -1
  157. package/dist/tools/builtins/bash.d.ts.map +1 -1
  158. package/dist/tools/builtins/bash.js +4 -10
  159. package/dist/tools/builtins/bash.js.map +1 -1
  160. package/dist/tools/builtins/edit-apply.d.ts +126 -0
  161. package/dist/tools/builtins/edit-apply.d.ts.map +1 -0
  162. package/dist/tools/builtins/edit-apply.js +360 -0
  163. package/dist/tools/builtins/edit-apply.js.map +1 -0
  164. package/dist/tools/builtins/edit.d.ts +143 -1
  165. package/dist/tools/builtins/edit.d.ts.map +1 -1
  166. package/dist/tools/builtins/edit.js +37 -219
  167. package/dist/tools/builtins/edit.js.map +1 -1
  168. package/dist/tools/builtins/index.d.ts +1 -0
  169. package/dist/tools/builtins/index.d.ts.map +1 -1
  170. package/dist/tools/builtins/index.js +9 -3
  171. package/dist/tools/builtins/index.js.map +1 -1
  172. package/dist/tools/builtins/job.js +1 -1
  173. package/dist/tools/builtins/job.js.map +1 -1
  174. package/dist/tools/builtins/read-file.d.ts +2 -2
  175. package/dist/tools/builtins/read-file.d.ts.map +1 -1
  176. package/dist/tools/builtins/read-file.js +50 -65
  177. package/dist/tools/builtins/read-file.js.map +1 -1
  178. package/dist/tools/builtins/read-render.d.ts +56 -0
  179. package/dist/tools/builtins/read-render.d.ts.map +1 -0
  180. package/dist/tools/builtins/read-render.js +73 -0
  181. package/dist/tools/builtins/read-render.js.map +1 -0
  182. package/dist/tools/builtins/wait-for-job-bounds.d.ts +67 -0
  183. package/dist/tools/builtins/wait-for-job-bounds.d.ts.map +1 -0
  184. package/dist/tools/builtins/wait-for-job-bounds.js +108 -0
  185. package/dist/tools/builtins/wait-for-job-bounds.js.map +1 -0
  186. package/dist/tools/builtins/wait-for-job.d.ts +6 -0
  187. package/dist/tools/builtins/wait-for-job.d.ts.map +1 -0
  188. package/dist/tools/builtins/wait-for-job.js +162 -0
  189. package/dist/tools/builtins/wait-for-job.js.map +1 -0
  190. package/dist/tools/builtins/write-file.js +5 -0
  191. package/dist/tools/builtins/write-file.js.map +1 -1
  192. package/dist/tools/coordinator/index.d.ts.map +1 -1
  193. package/dist/tools/coordinator/index.js +1 -7
  194. package/dist/tools/coordinator/index.js.map +1 -1
  195. package/dist/tools/file-read-tracker.d.ts.map +1 -1
  196. package/dist/tools/file-read-tracker.js +88 -10
  197. package/dist/tools/file-read-tracker.js.map +1 -1
  198. package/dist/types/agent/scheduler.d.ts +20 -0
  199. package/dist/types/agent/scheduler.d.ts.map +1 -1
  200. package/dist/types/agent/task.d.ts +20 -0
  201. package/dist/types/agent/task.d.ts.map +1 -1
  202. package/dist/types/connector/mcp.d.ts +205 -0
  203. package/dist/types/connector/mcp.d.ts.map +1 -1
  204. package/dist/types/message/index.d.ts +1 -1
  205. package/dist/types/message/index.d.ts.map +1 -1
  206. package/dist/types/message/index.js +2 -0
  207. package/dist/types/message/index.js.map +1 -1
  208. package/dist/types/run/entity.d.ts +13 -0
  209. package/dist/types/run/entity.d.ts.map +1 -1
  210. package/dist/types/run/events.d.ts +56 -0
  211. package/dist/types/run/events.d.ts.map +1 -1
  212. package/dist/types/run/events.js.map +1 -1
  213. package/dist/types/run/store.d.ts +41 -0
  214. package/dist/types/run/store.d.ts.map +1 -1
  215. package/dist/types/sandbox/index.d.ts +83 -15
  216. package/dist/types/sandbox/index.d.ts.map +1 -1
  217. package/dist/types/sandbox/index.js.map +1 -1
  218. package/dist/types/tool/index.d.ts +109 -0
  219. package/dist/types/tool/index.d.ts.map +1 -1
  220. package/dist/types/tool/index.js.map +1 -1
  221. package/dist/utils/env.d.ts +19 -0
  222. package/dist/utils/env.d.ts.map +1 -0
  223. package/dist/utils/env.js +25 -0
  224. package/dist/utils/env.js.map +1 -0
  225. package/package.json +1 -1
  226. package/src/bridge/a2a/mapper.ts +8 -0
  227. package/src/bridge/sse/mapper.ts +11 -0
  228. package/src/connector/index.ts +27 -0
  229. package/src/connector/mcp/adapter.ts +123 -10
  230. package/src/connector/mcp/audio-admission.ts +173 -0
  231. package/src/connector/mcp/client.ts +694 -45
  232. package/src/connector/mcp/envelope.ts +235 -0
  233. package/src/connector/mcp/era.ts +400 -0
  234. package/src/connector/mcp/errors.ts +171 -0
  235. package/src/connector/mcp/http-sse.ts +23 -6
  236. package/src/connector/mcp/index.ts +37 -0
  237. package/src/connector/mcp/streamable-http.ts +199 -11
  238. package/src/connector/mcp/x-mcp-header.ts +322 -0
  239. package/src/constants/mcp/index.ts +145 -16
  240. package/src/manager/agent/lifecycle.ts +29 -0
  241. package/src/manager/run/persistence.ts +12 -0
  242. package/src/prompt/coding-agent-doctrine.ts +31 -4
  243. package/src/prompt/index.ts +1 -0
  244. package/src/public-runtime.ts +37 -1
  245. package/src/public-tools.ts +18 -0
  246. package/src/registry/tool/execute.ts +2 -4
  247. package/src/registry/tool/portable.ts +264 -0
  248. package/src/registry/tool/schema.ts +38 -8
  249. package/src/registry/toolset/catalog.ts +8 -9
  250. package/src/runtime/jobs/awaited-jobs.ts +271 -0
  251. package/src/runtime/jobs/registry.ts +50 -0
  252. package/src/runtime/query/executor.ts +49 -1
  253. package/src/runtime/query/file-evidence-context.ts +190 -46
  254. package/src/runtime/query/file-evidence-replay.ts +776 -0
  255. package/src/runtime/query/file-evidence-seed.ts +126 -0
  256. package/src/runtime/query/index.ts +104 -2
  257. package/src/runtime/query/iteration/index.ts +202 -28
  258. package/src/runtime/query/iteration/phases/context.ts +10 -0
  259. package/src/runtime/query/iteration/phases/tool-review.ts +4 -0
  260. package/src/runtime/query/plugin-hooks.ts +20 -0
  261. package/src/runtime/query/repeat-call.ts +28 -18
  262. package/src/runtime/query/steering.ts +11 -0
  263. package/src/runtime/query/tooling.ts +3 -0
  264. package/src/sandbox/provider/local.ts +45 -2
  265. package/src/scheduler/completion-inbox.ts +105 -9
  266. package/src/scheduler/local.ts +8 -0
  267. package/src/store/run/disk.ts +108 -0
  268. package/src/tools/builtins/bash.ts +4 -10
  269. package/src/tools/builtins/edit-apply.ts +456 -0
  270. package/src/tools/builtins/edit.ts +39 -270
  271. package/src/tools/builtins/index.ts +9 -3
  272. package/src/tools/builtins/job.ts +1 -1
  273. package/src/tools/builtins/read-file.ts +56 -77
  274. package/src/tools/builtins/read-render.ts +104 -0
  275. package/src/tools/builtins/wait-for-job-bounds.ts +179 -0
  276. package/src/tools/builtins/wait-for-job.ts +184 -0
  277. package/src/tools/builtins/write-file.ts +5 -0
  278. package/src/tools/coordinator/index.ts +1 -7
  279. package/src/tools/file-read-tracker.ts +85 -7
  280. package/src/types/agent/scheduler.ts +21 -0
  281. package/src/types/agent/task.ts +21 -0
  282. package/src/types/connector/mcp.ts +205 -1
  283. package/src/types/message/index.ts +2 -0
  284. package/src/types/run/entity.ts +14 -0
  285. package/src/types/run/events.ts +56 -0
  286. package/src/types/run/store.ts +42 -0
  287. package/src/types/sandbox/index.ts +84 -15
  288. package/src/types/tool/index.ts +104 -0
  289. package/src/utils/env.ts +23 -0
@@ -1,9 +1,42 @@
1
- import { resolve } from 'node:path'
2
- import { isClearedToolResult } from '../../compaction/tool-result-editing.js'
3
1
  import { fingerprintContent } from '../../tools/builtins/content-fingerprint.js'
4
- import { WriteFileTool } from '../../tools/builtins/write-file.js'
5
- import type { Message, ToolCall } from '../../types/message/index.js'
2
+ import { ReadFileTool } from '../../tools/builtins/read-file.js'
3
+ import type { Message } from '../../types/message/index.js'
6
4
  import type { FileReadTracker } from '../../types/tool/index.js'
5
+ import {
6
+ MAX_EDIT_CALLS,
7
+ MAX_PATH_UNITS,
8
+ MAX_WITNESSED_PATHS,
9
+ type ReplayBudget,
10
+ type VisibleHistory,
11
+ createReplayBudget,
12
+ indexVisibleHistory,
13
+ knownStale,
14
+ lexicalFileKeys,
15
+ replayHop,
16
+ spend,
17
+ visibleCall,
18
+ visibleEdit,
19
+ visibleWrite,
20
+ } from './file-evidence-replay.js'
21
+
22
+ /**
23
+ * Receipt text a read entry may point at.
24
+ *
25
+ * The same class of bound as the one on a write call's arguments, and set to
26
+ * the same number for the same reason: past it the text is not read at all. A
27
+ * bigger file is simply not admitted this way — the model re-reads it, which is
28
+ * what it does today.
29
+ */
30
+ const MAX_RECEIPT_UNITS = 32_000
31
+
32
+ interface FileEvidence {
33
+ readonly path: string
34
+ /** Absent on the write-rooted entries; `'read'` on a body that is a receipt. */
35
+ readonly kind?: 'read'
36
+ readonly bodyInCall: string
37
+ readonly editsInCalls?: readonly string[]
38
+ readonly observedFingerprint: string
39
+ }
7
40
 
8
41
  /** Join visible call bodies, successful receipts and this executor's observation ledger. */
9
42
  export function describeVisibleFileEvidence(
@@ -14,52 +47,163 @@ export function describeVisibleFileEvidence(
14
47
  ): string | undefined {
15
48
  // Execution-owned witnesses survive transparent wrappers; a name alone proves nothing.
16
49
  if (!tracker.writeCallId || !tracker.fingerprint) return
17
- const calls = new Map<string, ToolCall | null>()
18
- const results = new Map<string, Message | null>()
19
- for (const message of messages) {
20
- if (message.role === 'assistant') {
21
- for (const call of message.toolCalls ?? []) {
22
- calls.set(call.id, calls.has(call.id) ? null : call)
23
- }
24
- } else if (message.role === 'tool') {
25
- results.set(message.toolCallId, results.has(message.toolCallId) ? null : message)
26
- }
27
- }
28
- const files = new Map<string, { path: string; bodyInCall: string; observedFingerprint: string }>()
29
- for (const [id, call] of calls) {
30
- const receipt = results.get(id)
31
- if (
32
- !call ||
33
- call.function.name !== 'write' ||
34
- call.metadata?.inputTruncated ||
35
- call.function.arguments.length > 32_000 ||
36
- id.length > 256 ||
37
- !receipt ||
38
- receipt.role !== 'tool' ||
39
- receipt.isError ||
40
- typeof receipt.content !== 'string' ||
41
- isClearedToolResult(receipt.content)
42
- )
43
- continue
50
+ // Lexical, as this projection has always looked entries up: a spelling that
51
+ // does not resolve to the tool's canonical key finds nothing and the path is
52
+ // simply not admitted. Writing the ledger is the side that has to key the
53
+ // way the tools do — see `file-evidence-seed.ts`.
54
+ const history = indexVisibleHistory(messages, lexicalFileKeys(workingDirectory, sandboxed))
55
+ const budget = createReplayBudget()
56
+ const files = new Map<string, FileEvidence>()
57
+ for (const [id, call] of history.calls) {
58
+ const name = call?.function.name
59
+ if (name !== 'write' && name !== 'edit' && name !== 'read') continue
44
60
  try {
45
- const input = WriteFileTool.inputSchema.safeParse(JSON.parse(call.function.arguments))
46
- if (!input.success || input.data.path.length > 512) continue
47
- const body = input.data.content ?? input.data.newStr
48
- if (typeof body !== 'string') continue
49
- const key = sandboxed ? input.data.path : resolve(workingDirectory, input.data.path)
50
- const fingerprint = fingerprintContent(body)
51
- if (tracker.writeCallId(key) !== id || tracker.fingerprint(key) !== fingerprint) continue
52
- files.delete(key)
53
- files.set(key, {
54
- path: input.data.path,
55
- bodyInCall: id,
56
- observedFingerprint: fingerprint,
57
- })
58
- if (files.size > 6) files.delete(files.keys().next().value as string)
61
+ const admitted =
62
+ name === 'write'
63
+ ? writeEvidence(id, tracker, history)
64
+ : name === 'edit'
65
+ ? chainEvidence(id, tracker, history, budget)
66
+ : readEvidence(id, tracker, history)
67
+ if (!admitted) continue
68
+ // A write-rooted entry outranks a read of the same file: it names a
69
+ // body the model composed itself, and edits can be replayed onto it.
70
+ // The ledger already withholds a read witness where one survives; this
71
+ // keeps a read that ran BEFORE the write from taking the path back.
72
+ const held = files.get(admitted.key)
73
+ if (admitted.evidence.kind === 'read' && held && held.kind !== 'read') continue
74
+ files.delete(admitted.key)
75
+ files.set(admitted.key, admitted.evidence)
76
+ if (files.size > MAX_WITNESSED_PATHS) files.delete(files.keys().next().value as string)
59
77
  } catch {
60
78
  // Malformed retained inputs or a custom tracker cannot establish evidence.
61
79
  }
62
80
  }
63
81
  if (files.size === 0) return
64
- return `Visible file evidence (this request only): each complete body remains in the named successful write call and matches the latest conversation observation. Reuse that body for a targeted edit; a read solely to recall it is unnecessary. This is NOT a fresh disk check. Built-in edit/write still compare the disk body at mutation admission and refuse observed drift; on refusal inspect the current file and replan. Missing entries establish nothing.\n${JSON.stringify([...files.values()])}`
82
+ return `Visible file evidence (this request only): each entry's current body is the complete body in the named successful write call, with the edit calls in editsInCalls — when present — applied in that order. An entry marked kind:"read" instead names a successful read call whose own receipt shows the file WHOLE, rendered with every line behind its own N<tab> prefix; that receipt is the body, and such an entry never carries editsInCalls. This runtime performed that reconstruction and checked it against its own file observation; it is not a derivation left to you. Reuse the body for a targeted edit; a read solely to recall it is unnecessary. This is NOT a fresh disk check, and after a resume the observation behind an entry may itself have been rebuilt from this conversation's own earlier calls rather than made while this process ran. Built-in edit/write still compare the disk body at mutation admission and refuse observed drift; on refusal inspect the current file and replan. Missing entries establish nothing.\n${JSON.stringify([...files.values()])}`
83
+ }
84
+
85
+ /** A full body that arrived whole in one call and is still the file's body. */
86
+ function writeEvidence(
87
+ id: string,
88
+ tracker: FileReadTracker,
89
+ history: VisibleHistory,
90
+ ): { key: string; evidence: FileEvidence } | undefined {
91
+ const written = visibleWrite(history, id)
92
+ if (!written || knownStale(tracker, written.key)) return
93
+ const fingerprint = fingerprintContent(written.body)
94
+ if (
95
+ tracker.writeCallId?.(written.key) !== id ||
96
+ tracker.fingerprint?.(written.key) !== fingerprint
97
+ )
98
+ return
99
+ return {
100
+ key: written.key,
101
+ evidence: {
102
+ path: written.path,
103
+ bodyInCall: id,
104
+ observedFingerprint: fingerprint,
105
+ },
106
+ }
107
+ }
108
+
109
+ /**
110
+ * A full body plus the visible edits since, replayed and then checked.
111
+ *
112
+ * Only the chain's TIP establishes the path: a middle hop is validated as part
113
+ * of the walk below, and admitting one on its own would claim the file stops
114
+ * at an edit later calls have already moved past. The replay runs the same
115
+ * apply core the tool ran at mutation time, over call arguments that are
116
+ * already in the conversation — no filesystem read, and the result is compared
117
+ * to the ledger's disk-derived fingerprint, never written into it.
118
+ */
119
+ function chainEvidence(
120
+ id: string,
121
+ tracker: FileReadTracker,
122
+ history: VisibleHistory,
123
+ budget: ReplayBudget,
124
+ ): { key: string; evidence: FileEvidence } | undefined {
125
+ const tip = visibleEdit(history, id)
126
+ if (!tip || knownStale(tracker, tip.key)) return
127
+ const key = tip.key
128
+ const chain = tracker.editChain?.(key)
129
+ const observed = tracker.fingerprint?.(key)
130
+ if (!chain || observed === undefined || chain.editCallIds.at(-1) !== id) return
131
+ // The call bound before the walk, the unit bound before each operation it
132
+ // pays for. Neither is measured by doing the work it exists to refuse.
133
+ if (chain.editCallIds.length > MAX_EDIT_CALLS) return
134
+ const rootId = chain.rootWriteCallId
135
+ const root = visibleWrite(history, rootId)
136
+ // A root naming a different file is an ambiguity, not a base: the ledger
137
+ // and the visible call disagree about what was written where.
138
+ if (!root || root.key !== key) return
139
+ let content = root.body
140
+ if (!spend(budget, content.length)) return
141
+ for (const editId of chain.editCallIds) {
142
+ const hop = editId === id ? tip : visibleEdit(history, editId)
143
+ if (!hop || hop.key !== key) return
144
+ // Each of this hop's operations is measured against the body it is about
145
+ // to be applied to, charged, and only then applied — so a hop over the
146
+ // ceiling is refused before it is built rather than after, and one that
147
+ // fits is never turned away for a ceiling that guessed high. A hop the
148
+ // budget refuses, or one whose anchors no longer match, reconstructs
149
+ // nothing and withholds the whole path.
150
+ const replayed = replayHop(content, hop.input, budget)
151
+ if (replayed === undefined) return
152
+ content = replayed
153
+ }
154
+ if (fingerprintContent(content) !== observed) return
155
+ return {
156
+ key,
157
+ evidence: {
158
+ path: root.path,
159
+ bodyInCall: rootId,
160
+ editsInCalls: [...chain.editCallIds],
161
+ observedFingerprint: observed,
162
+ },
163
+ }
164
+ }
165
+
166
+ /**
167
+ * A body the model can still see because a read of the whole file put it there.
168
+ *
169
+ * Structurally unlike the two above, and deliberately so. They name a body the
170
+ * model itself composed, in arguments this projection can parse and replay; this
171
+ * names a RESULT, and the only thing anyone is allowed to do with it is compare
172
+ * it. The tool fingerprinted the exact string it emitted, and the entry is
173
+ * admitted only while the receipt still fingerprints to that — so a receipt the
174
+ * output budget elided or spilled, one compaction cleared, or one changed in any
175
+ * other way withholds the path rather than pointing the model at a body that is
176
+ * no longer in front of it. Nothing here undoes the line numbering to recover
177
+ * text: the numbering is what makes the comparison conclusive, not an encoding
178
+ * to be reversed.
179
+ *
180
+ * No chain, ever. A read roots nothing, so an entry here is the file as that one
181
+ * call showed it, and the ledger drops the witness the moment an edit lands.
182
+ */
183
+ function readEvidence(
184
+ id: string,
185
+ tracker: FileReadTracker,
186
+ history: VisibleHistory,
187
+ ): { key: string; evidence: FileEvidence } | undefined {
188
+ if (!tracker.readWitness) return
189
+ const call = visibleCall(history, id, 'read')
190
+ const shown = history.results.get(id)?.content
191
+ if (!call || typeof shown !== 'string' || shown.length > MAX_RECEIPT_UNITS) return
192
+ const input = ReadFileTool.inputSchema.safeParse(JSON.parse(call.function.arguments))
193
+ if (!input.success || input.data.path.length > MAX_PATH_UNITS) return
194
+ const key = history.keyOf(input.data.path)
195
+ if (key === undefined || knownStale(tracker, key)) return
196
+ const witness = tracker.readWitness(key)
197
+ const observed = tracker.fingerprint?.(key)
198
+ if (!witness || witness.callId !== id || observed === undefined) return
199
+ if (fingerprintContent(shown) !== witness.renderedFingerprint) return
200
+ return {
201
+ key,
202
+ evidence: {
203
+ path: input.data.path,
204
+ kind: 'read',
205
+ bodyInCall: id,
206
+ observedFingerprint: observed,
207
+ },
208
+ }
65
209
  }