@jungjaehoon/mama-core 2.4.1 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/README.md +76 -239
  2. package/db/migrations/030-case-first-memory-substrate.sql +13 -98
  3. package/db/migrations/034-add-connector-event-scope-columns.sql +9 -13
  4. package/db/migrations/039-add-connector-event-operator-ingest-seq.sql +9 -95
  5. package/db/migrations/062-refresh-connector-event-sequences.sql +9 -113
  6. package/db/migrations/063-refresh-legacy-connector-event-updates.sql +9 -32
  7. package/db/migrations/067-add-connector-event-source-entity-id.sql +9 -13
  8. package/db/migrations/069-create-registry-nodes.sql +52 -0
  9. package/db/migrations/070-record-identity.sql +35 -0
  10. package/db/migrations/071-service-operation-origins.sql +187 -0
  11. package/db/migrations/072-observation-versions.sql +29 -0
  12. package/db/migrations/073-registry-corrections.sql +45 -0
  13. package/db/migrations/074-work-graph-ref-kinds.sql +39 -0
  14. package/db/migrations/075-agent-judgments.sql +58 -0
  15. package/db/migrations/076-scoped-checkpoint-bindings.sql +15 -0
  16. package/db/migrations/077-legacy-record-kind.sql +6 -0
  17. package/db/migrations/078-source-ingest-commands.sql +18 -0
  18. package/db/migrations/079-twin-edge-relations.sql +43 -0
  19. package/db/migrations/080-restore-duration-days.sql +7 -0
  20. package/db/migrations/081-mailbox.sql +61 -0
  21. package/db/migrations/082-commitments-row-id.sql +12 -0
  22. package/db/migrations/083-observation-is-the-evidence.sql +49 -0
  23. package/db/migrations/084-scope-kind-is-not-the-cores-to-list.sql +34 -0
  24. package/db/migrations/085-a-migration-has-a-source.sql +37 -0
  25. package/db/migrations/086-the-mailbox-is-generic.sql +110 -0
  26. package/db/migrations/087-mailbox-payload.sql +5 -0
  27. package/db/migrations/088-native-input-journal.sql +14 -0
  28. package/db/migrations/089-native-turn-receipt-lookup.sql +3 -0
  29. package/db/migrations/090-model-run-native-inputs.sql +29 -0
  30. package/db/migrations/091-native-turn-results.sql +11 -0
  31. package/db/migrations/092-restore-decision-fts.sql +34 -0
  32. package/db/migrations/093-native-turn-primary-kind.sql +14 -0
  33. package/db/migrations/094-commitment-run-provenance.sql +9 -0
  34. package/db/migrations/095-model-run-native-input-identity.sql +39 -0
  35. package/db/migrations/096-drop-connector-event-index-fts.sql +9 -0
  36. package/db/migrations/097-native-input-json-validity.sql +37 -0
  37. package/db/migrations/098-workflow-memory-kind.sql +105 -0
  38. package/db/migrations/099-commitment-revision-graph.sql +2 -0
  39. package/dist/action-contracts.d.ts +212 -0
  40. package/dist/action-contracts.js +10 -0
  41. package/dist/api/catalog.d.ts +118 -0
  42. package/dist/api/catalog.js +1756 -0
  43. package/dist/api/dispatch.d.ts +76 -0
  44. package/dist/api/dispatch.js +372 -0
  45. package/dist/canonicalize.d.ts +2 -2
  46. package/dist/canonicalize.js +3 -3
  47. package/dist/client/client.d.ts +33 -0
  48. package/dist/client/client.js +123 -0
  49. package/dist/client/ipc.d.ts +81 -0
  50. package/dist/client/ipc.js +314 -0
  51. package/dist/db-adapter/base-adapter.d.ts +6 -66
  52. package/dist/db-adapter/base-adapter.js +6 -6
  53. package/dist/db-adapter/index.d.ts +5 -5
  54. package/dist/db-adapter/index.js +2 -5
  55. package/dist/db-adapter/node-sqlite-adapter.d.ts +85 -15
  56. package/dist/db-adapter/node-sqlite-adapter.js +1985 -570
  57. package/dist/db-manager.d.ts +53 -97
  58. package/dist/db-manager.js +121 -603
  59. package/dist/embedding/embedder.d.ts +132 -0
  60. package/dist/embedding/embedder.js +299 -0
  61. package/dist/identity/principal-repository.d.ts +2 -2
  62. package/dist/index.d.ts +43 -58
  63. package/dist/index.js +97 -145
  64. package/dist/{context-compile/channel-grant.d.ts → knowledge/access.d.ts} +12 -17
  65. package/dist/knowledge/access.js +663 -0
  66. package/dist/knowledge/case-errors.d.ts +31 -0
  67. package/dist/knowledge/case-errors.js +40 -0
  68. package/dist/{cases/search-rollup.d.ts → knowledge/case-search-rollup.d.ts} +5 -4
  69. package/dist/{cases/search-rollup.js → knowledge/case-search-rollup.js} +6 -8
  70. package/dist/{cases/store.d.ts → knowledge/case-store.d.ts} +3 -6
  71. package/dist/{cases/store.js → knowledge/case-store.js} +7 -42
  72. package/dist/{cases/timeline-range.d.ts → knowledge/case-timeline-range.d.ts} +3 -3
  73. package/dist/{cases/timeline-range.js → knowledge/case-timeline-range.js} +47 -25
  74. package/dist/{cases/types.d.ts → knowledge/case-types.d.ts} +8 -2
  75. package/dist/{cases/types.js → knowledge/case-types.js} +1 -1
  76. package/dist/knowledge/commitment-revision-migration.d.ts +4 -0
  77. package/dist/knowledge/commitment-revision-migration.js +50 -0
  78. package/dist/knowledge/commitments.d.ts +192 -0
  79. package/dist/knowledge/commitments.js +386 -0
  80. package/dist/knowledge/decision-edges.d.ts +70 -0
  81. package/dist/knowledge/decision-edges.js +123 -0
  82. package/dist/{agent-graph/types.d.ts → knowledge/graph-query.d.ts} +80 -70
  83. package/dist/knowledge/graph-query.js +1585 -0
  84. package/dist/knowledge/identity.d.ts +16 -0
  85. package/dist/knowledge/identity.js +22 -0
  86. package/dist/knowledge/index.d.ts +47 -0
  87. package/dist/knowledge/index.js +90 -0
  88. package/dist/knowledge/judgment-edge.d.ts +6 -0
  89. package/dist/knowledge/judgment-edge.js +22 -0
  90. package/dist/knowledge/judgments.d.ts +118 -0
  91. package/dist/knowledge/judgments.js +802 -0
  92. package/dist/knowledge/observations.d.ts +160 -0
  93. package/dist/knowledge/observations.js +449 -0
  94. package/dist/knowledge/question-type.d.ts +34 -0
  95. package/dist/knowledge/question-type.js +70 -0
  96. package/dist/{search → knowledge}/ranker-features.js +1 -1
  97. package/dist/{search → knowledge}/search-quality.d.ts +0 -1
  98. package/dist/knowledge/search.d.ts +38 -0
  99. package/dist/knowledge/search.js +91 -0
  100. package/dist/knowledge/source-ingest.d.ts +65 -0
  101. package/dist/knowledge/source-ingest.js +174 -0
  102. package/dist/{edges/types.d.ts → knowledge/twin-edge-types.d.ts} +31 -4
  103. package/dist/{edges/types.js → knowledge/twin-edge-types.js} +13 -2
  104. package/dist/knowledge/work-dates.d.ts +49 -0
  105. package/dist/knowledge/work-dates.js +120 -0
  106. package/dist/mama-api.d.ts +114 -778
  107. package/dist/mama-api.js +313 -2461
  108. package/dist/memory/api.d.ts +264 -24
  109. package/dist/memory/api.js +1633 -843
  110. package/dist/memory/bootstrap-builder.d.ts +2 -1
  111. package/dist/memory/bootstrap-builder.js +5 -5
  112. package/dist/memory/channel-summary-state-store.d.ts +3 -2
  113. package/dist/memory/channel-summary-state-store.js +53 -51
  114. package/dist/memory/channel-summary-store.d.ts +5 -3
  115. package/dist/memory/channel-summary-store.js +3 -8
  116. package/dist/memory/dashboard-read.d.ts +46 -0
  117. package/dist/memory/dashboard-read.js +94 -0
  118. package/dist/memory/event-store.d.ts +3 -3
  119. package/dist/memory/event-store.js +3 -10
  120. package/dist/memory/finding-store.d.ts +3 -2
  121. package/dist/memory/finding-store.js +2 -7
  122. package/dist/memory/graph-read.d.ts +52 -0
  123. package/dist/memory/graph-read.js +130 -0
  124. package/dist/memory/judgment-types.d.ts +394 -0
  125. package/dist/memory/judgment-types.js +16 -0
  126. package/dist/memory/provenance-audit.d.ts +5 -2
  127. package/dist/memory/provenance-audit.js +8 -14
  128. package/dist/memory/provenance-live.d.ts +141 -0
  129. package/dist/memory/provenance-live.js +409 -0
  130. package/dist/memory/provenance-query.d.ts +5 -4
  131. package/dist/memory/provenance-query.js +21 -29
  132. package/dist/memory/provenance-resolver.d.ts +191 -0
  133. package/dist/memory/provenance-resolver.js +155 -0
  134. package/dist/memory/provenance.d.ts +1 -11
  135. package/dist/memory/provenance.js +2 -33
  136. package/dist/memory/recall-sanitize.d.ts +55 -0
  137. package/dist/memory/recall-sanitize.js +144 -0
  138. package/dist/memory/secret-filter.d.ts +32 -0
  139. package/dist/memory/secret-filter.js +126 -0
  140. package/dist/memory/truth-store.d.ts +2 -1
  141. package/dist/memory/truth-store.js +1 -4
  142. package/dist/memory/types.d.ts +74 -24
  143. package/dist/memory/types.js +75 -5
  144. package/dist/memory/write-adapters.d.ts +98 -0
  145. package/dist/memory/write-adapters.js +242 -0
  146. package/dist/operations/owner-action-effects.d.ts +53 -0
  147. package/dist/operations/owner-action-effects.js +96 -0
  148. package/dist/provenance/source-ref.d.ts +1 -1
  149. package/dist/provenance/source-ref.js +0 -2
  150. package/dist/registry/corrections.d.ts +31 -0
  151. package/dist/registry/corrections.js +332 -0
  152. package/dist/registry/record-identity.d.ts +49 -0
  153. package/dist/registry/record-identity.js +133 -0
  154. package/dist/registry/store.d.ts +101 -0
  155. package/dist/registry/store.js +395 -0
  156. package/dist/registry/types.d.ts +28 -0
  157. package/dist/registry/types.js +5 -0
  158. package/dist/relevance-scorer.js +2 -2
  159. package/dist/runtime/agent-event-bus.d.ts +50 -0
  160. package/dist/runtime/agent-event-bus.js +101 -0
  161. package/dist/runtime/drivers/claude-cli-wrapper.d.ts +152 -0
  162. package/dist/runtime/drivers/claude-cli-wrapper.js +375 -0
  163. package/dist/runtime/drivers/claude-effort.d.ts +4 -0
  164. package/dist/runtime/drivers/claude-effort.js +16 -0
  165. package/dist/runtime/drivers/cli-arg-redaction.d.ts +2 -0
  166. package/dist/runtime/drivers/cli-arg-redaction.js +18 -0
  167. package/dist/runtime/drivers/cli-secret-redaction.d.ts +17 -0
  168. package/dist/runtime/drivers/cli-secret-redaction.js +126 -0
  169. package/dist/runtime/drivers/codex-app-server-process.d.ts +277 -0
  170. package/dist/runtime/drivers/codex-app-server-process.js +2342 -0
  171. package/dist/runtime/drivers/codex-auxiliary-tools.d.ts +17 -0
  172. package/dist/runtime/drivers/codex-auxiliary-tools.js +267 -0
  173. package/dist/runtime/drivers/codex-home.d.ts +20 -0
  174. package/dist/runtime/drivers/codex-home.js +674 -0
  175. package/dist/runtime/drivers/codex-thread-registry.d.ts +63 -0
  176. package/dist/runtime/drivers/codex-thread-registry.js +433 -0
  177. package/dist/runtime/drivers/persistent-cli-adapter.d.ts +160 -0
  178. package/dist/runtime/drivers/persistent-cli-adapter.js +396 -0
  179. package/dist/runtime/drivers/persistent-cli-process.d.ts +425 -0
  180. package/dist/runtime/drivers/persistent-cli-process.js +1529 -0
  181. package/dist/runtime/drivers/types.d.ts +456 -0
  182. package/dist/runtime/drivers/types.js +110 -0
  183. package/dist/runtime/mailbox.d.ts +223 -0
  184. package/dist/runtime/mailbox.js +582 -0
  185. package/dist/runtime/model-run-store.d.ts +28 -0
  186. package/dist/{model-runs/store.js → runtime/model-run-store.js} +81 -41
  187. package/dist/{model-runs/types.d.ts → runtime/model-run-types.d.ts} +33 -4
  188. package/dist/{model-runs/types.js → runtime/model-run-types.js} +1 -1
  189. package/dist/runtime/native-effect-observer.d.ts +22 -0
  190. package/dist/runtime/native-effect-observer.js +103 -0
  191. package/dist/runtime/native-input-journal.d.ts +46 -0
  192. package/dist/runtime/native-input-journal.js +308 -0
  193. package/dist/runtime/native-prompt.d.ts +118 -0
  194. package/dist/runtime/native-prompt.js +496 -0
  195. package/dist/runtime/native-session.d.ts +10 -0
  196. package/dist/{agent-graph/index.js → runtime/native-session.js} +9 -6
  197. package/dist/runtime/native-tool-trace-observer.d.ts +5 -0
  198. package/dist/runtime/native-tool-trace-observer.js +65 -0
  199. package/dist/runtime/native-turn.d.ts +272 -0
  200. package/dist/runtime/native-turn.js +1041 -0
  201. package/dist/runtime/operations.d.ts +236 -0
  202. package/dist/runtime/operations.js +565 -0
  203. package/dist/runtime/post-tool-handler.d.ts +74 -0
  204. package/dist/runtime/post-tool-handler.js +137 -0
  205. package/dist/runtime/prompt-layers.d.ts +126 -0
  206. package/dist/runtime/prompt-layers.js +239 -0
  207. package/dist/runtime/runtime-process.d.ts +102 -0
  208. package/dist/runtime/runtime-process.js +206 -0
  209. package/dist/runtime/runtime.d.ts +278 -0
  210. package/dist/runtime/runtime.js +563 -0
  211. package/dist/runtime/session-pool.d.ts +176 -0
  212. package/dist/runtime/session-pool.js +369 -0
  213. package/dist/runtime/stimulus-payload.d.ts +5 -0
  214. package/dist/runtime/stimulus-payload.js +50 -0
  215. package/dist/runtime/subagent-bridge.d.ts +24 -0
  216. package/dist/{agent-graph/types.js → runtime/subagent-bridge.js} +1 -1
  217. package/dist/runtime/text-completion.d.ts +22 -0
  218. package/dist/{agent-situation/types.js → runtime/text-completion.js} +1 -1
  219. package/dist/runtime/token-estimator.d.ts +25 -0
  220. package/dist/runtime/token-estimator.js +75 -0
  221. package/dist/runtime/tool-trace-store.d.ts +22 -0
  222. package/dist/{model-runs → runtime}/tool-trace-store.js +46 -27
  223. package/dist/runtime/trace-summary.d.ts +5 -0
  224. package/dist/runtime/trace-summary.js +74 -0
  225. package/dist/runtime/turn-text.d.ts +23 -0
  226. package/dist/runtime/turn-text.js +41 -0
  227. package/dist/storage/database.d.ts +67 -0
  228. package/dist/storage/database.js +158 -0
  229. package/package.json +20 -34
  230. package/dist/agent-graph/alias-write.d.ts +0 -3
  231. package/dist/agent-graph/alias-write.js +0 -234
  232. package/dist/agent-graph/entity-resolve.d.ts +0 -3
  233. package/dist/agent-graph/entity-resolve.js +0 -271
  234. package/dist/agent-graph/errors.d.ts +0 -4
  235. package/dist/agent-graph/errors.js +0 -11
  236. package/dist/agent-graph/graph-query.d.ts +0 -5
  237. package/dist/agent-graph/graph-query.js +0 -360
  238. package/dist/agent-graph/index.d.ts +0 -6
  239. package/dist/agent-situation/builder.d.ts +0 -8
  240. package/dist/agent-situation/builder.js +0 -239
  241. package/dist/agent-situation/cache-key.d.ts +0 -4
  242. package/dist/agent-situation/cache-key.js +0 -64
  243. package/dist/agent-situation/index.d.ts +0 -7
  244. package/dist/agent-situation/index.js +0 -28
  245. package/dist/agent-situation/packet-store.d.ts +0 -27
  246. package/dist/agent-situation/packet-store.js +0 -228
  247. package/dist/agent-situation/ranking-policy.d.ts +0 -18
  248. package/dist/agent-situation/ranking-policy.js +0 -75
  249. package/dist/agent-situation/source-readers.d.ts +0 -52
  250. package/dist/agent-situation/source-readers.js +0 -300
  251. package/dist/agent-situation/types.d.ts +0 -195
  252. package/dist/cases/wiki-page-index.d.ts +0 -37
  253. package/dist/cases/wiki-page-index.js +0 -201
  254. package/dist/config-loader.d.ts +0 -68
  255. package/dist/config-loader.js +0 -239
  256. package/dist/connectors/event-index.d.ts +0 -24
  257. package/dist/connectors/event-index.js +0 -245
  258. package/dist/connectors/raw-query.d.ts +0 -40
  259. package/dist/connectors/raw-query.js +0 -412
  260. package/dist/connectors/types.d.ts +0 -117
  261. package/dist/connectors/types.js +0 -3
  262. package/dist/context-compile/boundary-defaults.d.ts +0 -12
  263. package/dist/context-compile/boundary-defaults.js +0 -105
  264. package/dist/context-compile/channel-grant.js +0 -66
  265. package/dist/context-compile/compiler-policy.d.ts +0 -39
  266. package/dist/context-compile/compiler-policy.js +0 -147
  267. package/dist/context-compile/compiler.d.ts +0 -18
  268. package/dist/context-compile/compiler.js +0 -404
  269. package/dist/context-compile/index.d.ts +0 -10
  270. package/dist/context-compile/index.js +0 -26
  271. package/dist/context-compile/packet-store.d.ts +0 -8
  272. package/dist/context-compile/packet-store.js +0 -239
  273. package/dist/context-compile/ref.d.ts +0 -7
  274. package/dist/context-compile/ref.js +0 -102
  275. package/dist/context-compile/source-readers.d.ts +0 -70
  276. package/dist/context-compile/source-readers.js +0 -840
  277. package/dist/context-compile/types.d.ts +0 -155
  278. package/dist/context-compile/types.js +0 -11
  279. package/dist/context-compile/visibility.d.ts +0 -21
  280. package/dist/context-compile/visibility.js +0 -224
  281. package/dist/decision-tracker.d.ts +0 -206
  282. package/dist/decision-tracker.js +0 -481
  283. package/dist/edges/ref-validation.d.ts +0 -7
  284. package/dist/edges/ref-validation.js +0 -321
  285. package/dist/edges/store.d.ts +0 -8
  286. package/dist/edges/store.js +0 -129
  287. package/dist/embedding-client.d.ts +0 -28
  288. package/dist/embedding-client.js +0 -53
  289. package/dist/embedding-server/index.d.ts +0 -67
  290. package/dist/embedding-server/index.js +0 -405
  291. package/dist/embedding-server/mobile/auth.d.ts +0 -44
  292. package/dist/embedding-server/mobile/auth.js +0 -150
  293. package/dist/embedding-server/mobile/daemon.d.ts +0 -129
  294. package/dist/embedding-server/mobile/daemon.js +0 -313
  295. package/dist/embedding-server/mobile/output-parser.d.ts +0 -115
  296. package/dist/embedding-server/mobile/output-parser.js +0 -241
  297. package/dist/embedding-server/mobile/session-api.d.ts +0 -57
  298. package/dist/embedding-server/mobile/session-api.js +0 -261
  299. package/dist/embedding-server/mobile/session-manager.d.ts +0 -138
  300. package/dist/embedding-server/mobile/session-manager.js +0 -378
  301. package/dist/embedding-server/mobile/websocket-handler.d.ts +0 -137
  302. package/dist/embedding-server/mobile/websocket-handler.js +0 -486
  303. package/dist/embeddings.d.ts +0 -68
  304. package/dist/embeddings.js +0 -244
  305. package/dist/entities/audit-metrics.d.ts +0 -68
  306. package/dist/entities/audit-metrics.js +0 -124
  307. package/dist/entities/candidate-generator.d.ts +0 -8
  308. package/dist/entities/candidate-generator.js +0 -24
  309. package/dist/entities/entity-linked-decision-counts.d.ts +0 -2
  310. package/dist/entities/entity-linked-decision-counts.js +0 -29
  311. package/dist/entities/entity-list.d.ts +0 -22
  312. package/dist/entities/entity-list.js +0 -3
  313. package/dist/entities/entity-orphan-list.d.ts +0 -17
  314. package/dist/entities/entity-orphan-list.js +0 -3
  315. package/dist/entities/entity-search.d.ts +0 -20
  316. package/dist/entities/entity-search.js +0 -3
  317. package/dist/entities/errors.d.ts +0 -55
  318. package/dist/entities/errors.js +0 -100
  319. package/dist/entities/lineage-store.d.ts +0 -28
  320. package/dist/entities/lineage-store.js +0 -204
  321. package/dist/entities/normalization.d.ts +0 -14
  322. package/dist/entities/normalization.js +0 -63
  323. package/dist/entities/policy-store.d.ts +0 -8
  324. package/dist/entities/policy-store.js +0 -75
  325. package/dist/entities/policy-types.d.ts +0 -72
  326. package/dist/entities/policy-types.js +0 -59
  327. package/dist/entities/projection.d.ts +0 -8
  328. package/dist/entities/projection.js +0 -82
  329. package/dist/entities/provenance-query.d.ts +0 -32
  330. package/dist/entities/provenance-query.js +0 -3
  331. package/dist/entities/read-identity.d.ts +0 -31
  332. package/dist/entities/read-identity.js +0 -264
  333. package/dist/entities/recall-bridge.d.ts +0 -5
  334. package/dist/entities/recall-bridge.js +0 -171
  335. package/dist/entities/resolution-engine.d.ts +0 -8
  336. package/dist/entities/resolution-engine.js +0 -3
  337. package/dist/entities/rollback-preview.d.ts +0 -35
  338. package/dist/entities/rollback-preview.js +0 -3
  339. package/dist/entities/source-locator.d.ts +0 -3
  340. package/dist/entities/source-locator.js +0 -32
  341. package/dist/entities/store.d.ts +0 -69
  342. package/dist/entities/store.js +0 -544
  343. package/dist/entities/types.d.ts +0 -166
  344. package/dist/entities/types.js +0 -30
  345. package/dist/memory/extraction-prompt.d.ts +0 -4
  346. package/dist/memory/extraction-prompt.js +0 -89
  347. package/dist/memory/scope-backfill.d.ts +0 -14
  348. package/dist/memory/scope-backfill.js +0 -3
  349. package/dist/memory/scope-store.d.ts +0 -4
  350. package/dist/memory/scope-store.js +0 -9
  351. package/dist/memory-store.d.ts +0 -87
  352. package/dist/memory-store.js +0 -78
  353. package/dist/model-runs/store.d.ts +0 -13
  354. package/dist/model-runs/tool-trace-store.d.ts +0 -8
  355. package/dist/notification-manager.d.ts +0 -7
  356. package/dist/notification-manager.js +0 -12
  357. package/dist/outcome-tracker.d.ts +0 -151
  358. package/dist/outcome-tracker.js +0 -271
  359. package/dist/query-intent.d.ts +0 -23
  360. package/dist/query-intent.js +0 -114
  361. package/dist/runtime/trusted-provenance.d.ts +0 -3
  362. package/dist/runtime/trusted-provenance.js +0 -6
  363. package/dist/search/question-type.d.ts +0 -5
  364. package/dist/search/question-type.js +0 -41
  365. package/dist/test-utils.d.ts +0 -80
  366. package/dist/test-utils.js +0 -218
  367. package/dist/tier-validator.d.ts +0 -43
  368. package/dist/tier-validator.js +0 -159
  369. package/dist/time-formatter.d.ts +0 -25
  370. package/dist/time-formatter.js +0 -93
  371. /package/dist/{search → knowledge}/feedback-store.d.ts +0 -0
  372. /package/dist/{search → knowledge}/feedback-store.js +0 -0
  373. /package/dist/{search → knowledge}/ranker-features.d.ts +0 -0
  374. /package/dist/{search → knowledge}/ranker-rescore.d.ts +0 -0
  375. /package/dist/{search → knowledge}/ranker-rescore.js +0 -0
  376. /package/dist/{search → knowledge}/ranker-trainer.d.ts +0 -0
  377. /package/dist/{search → knowledge}/ranker-trainer.js +0 -0
  378. /package/dist/{search → knowledge}/search-quality.js +0 -0
@@ -0,0 +1,1041 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NativeSessionRunner = void 0;
4
+ exports.formatLastUserMessage = formatLastUserMessage;
5
+ exports.createNativeSessionRunner = createNativeSessionRunner;
6
+ const types_js_1 = require("./drivers/types.js");
7
+ const native_effect_observer_js_1 = require("./native-effect-observer.js");
8
+ const prompt_layers_js_1 = require("./prompt-layers.js");
9
+ const turn_text_js_1 = require("./turn-text.js");
10
+ const native_prompt_js_1 = require("./native-prompt.js");
11
+ const debug_logger_js_1 = require("../debug-logger.js");
12
+ const canonicalize_js_1 = require("../canonicalize.js");
13
+ const node_crypto_1 = require("node:crypto");
14
+ const node_fs_1 = require("node:fs");
15
+ const node_path_1 = require("node:path");
16
+ const logger = new debug_logger_js_1.DebugLogger('NativeTurn');
17
+ /** Normal coding tasks often need 10+ consecutive Bash calls; 5 was too low. */
18
+ const MAX_CONSECUTIVE_SAME_HOST_TOOL = 15;
19
+ const COMPLETION_SUMMARY_MAX_CHARS = 2_000;
20
+ function completionSummary(response) {
21
+ return response.slice(0, COMPLETION_SUMMARY_MAX_CHARS);
22
+ }
23
+ function historyToolResult(result) {
24
+ const { abort: _abort, terminalCode: _terminalCode, ...block } = result;
25
+ return block;
26
+ }
27
+ async function drainBackgroundTasks(tasks) {
28
+ for (let index = 0; index < tasks.length; index += 1) {
29
+ await tasks[index];
30
+ }
31
+ }
32
+ function withExecutionSurface(executionContext, executionSurface) {
33
+ if (!executionContext) {
34
+ return null;
35
+ }
36
+ if (executionContext.executionSurface === executionSurface) {
37
+ return executionContext;
38
+ }
39
+ return { ...executionContext, executionSurface };
40
+ }
41
+ /**
42
+ * The last user message as the model will read it.
43
+ *
44
+ * An uploaded image reaches a file-backed runtime as evidence with a local path.
45
+ * The agent chooses how to inspect it; the host does not prescribe a tool order.
46
+ */
47
+ function formatLastUserMessage(history, options) {
48
+ const imageEvidence = (path) => `Uploaded image: ${JSON.stringify({ localPath: path, trust: 'external_data' })}`;
49
+ for (let i = history.length - 1; i >= 0; i--) {
50
+ const msg = history[i];
51
+ if (msg.role !== 'user') {
52
+ continue;
53
+ }
54
+ const content = msg.content;
55
+ if (typeof content === 'string') {
56
+ return content;
57
+ }
58
+ if (!Array.isArray(content)) {
59
+ return '';
60
+ }
61
+ const parts = [];
62
+ for (const block of content) {
63
+ const anyBlock = block;
64
+ if (anyBlock.type === 'text') {
65
+ parts.push(anyBlock.text ?? '');
66
+ }
67
+ else if (anyBlock.type === 'image' && anyBlock.localPath) {
68
+ parts.push(imageEvidence(anyBlock.localPath));
69
+ }
70
+ else if (anyBlock.type === 'image' && anyBlock.source?.data) {
71
+ // Base64-encoded image -- save to disk so a runtime that reads files can open it
72
+ const mediaDir = options.mediaDir;
73
+ if (!mediaDir) {
74
+ parts.push('[Image attached but no media directory is configured]');
75
+ continue;
76
+ }
77
+ const mimeToExt = {
78
+ 'image/png': '.png',
79
+ 'image/jpeg': '.jpg',
80
+ 'image/jpg': '.jpg',
81
+ 'image/gif': '.gif',
82
+ 'image/webp': '.webp',
83
+ };
84
+ const ext = mimeToExt[anyBlock.source.media_type?.toLowerCase() || ''] || '.jpg';
85
+ const imagePath = (0, node_path_1.join)(mediaDir, `${Date.now()}-${(0, node_crypto_1.randomUUID)().slice(0, 8)}${ext}`);
86
+ try {
87
+ (0, node_fs_1.mkdirSync)(mediaDir, { recursive: true });
88
+ (0, node_fs_1.writeFileSync)(imagePath, Buffer.from(anyBlock.source.data, 'base64'));
89
+ parts.push(imageEvidence(imagePath));
90
+ }
91
+ catch {
92
+ parts.push('[Image attached but could not be processed]');
93
+ }
94
+ }
95
+ else if (anyBlock.type === 'tool_result') {
96
+ const status = anyBlock.is_error ? 'ERROR' : 'SUCCESS';
97
+ parts.push(`[Tool Result: ${status}]\n${anyBlock.content}`);
98
+ }
99
+ else if (anyBlock.type === 'tool_use') {
100
+ parts.push(`[Tool Call: ${anyBlock.name}]\nInput: ${JSON.stringify(anyBlock.input, null, 2)}`);
101
+ }
102
+ }
103
+ return parts.join('\n');
104
+ }
105
+ return '';
106
+ }
107
+ /**
108
+ * The entry a consumer holds: one session's runs, serialized on its lane.
109
+ */
110
+ class NativeSessionRunner {
111
+ host;
112
+ stopped = false;
113
+ activeSteerBindings = new Map();
114
+ /**
115
+ * What a native child started by a run on this session needs. Keyed by session key,
116
+ * overwritten by each run on that session, and dropped once the run finished and no
117
+ * child of it is still registered.
118
+ */
119
+ subagentRunContexts = new Map();
120
+ nextCallerTurnId = 0;
121
+ // Keep only child ownership numbers across turns, not old authority or run contexts.
122
+ callerChildOwners = new Map();
123
+ constructor(host) {
124
+ this.host = host;
125
+ }
126
+ /** Retire native context only. Durable input, results and knowledge remain owned by the host. */
127
+ async resetSession(sessionKey) {
128
+ const reset = async () => {
129
+ if (this.stopped)
130
+ throw new Error('Native session is stopped');
131
+ const entry = this.host.sessionPool.peekSession(sessionKey);
132
+ if (entry.busy)
133
+ throw new Error('Cannot reset a busy native session');
134
+ if (!this.host.agent.resetSession)
135
+ throw new Error('Native runner does not support session reset');
136
+ await this.host.agent.resetSession(entry.sessionId, sessionKey);
137
+ this.host.sessionPool.invalidateSession(sessionKey);
138
+ this.callerChildOwners.delete(sessionKey);
139
+ this.subagentRunContexts.delete(sessionKey);
140
+ };
141
+ if (this.host.useLanes && this.host.lanes) {
142
+ await this.host.lanes.enqueueWithSession(sessionKey, reset, this.host.globalLaneFor?.(sessionKey), { priority: 0 });
143
+ }
144
+ else {
145
+ await reset();
146
+ }
147
+ }
148
+ /** Use the current turn's authority. Steering cannot replace its policy or open a new turn. */
149
+ async steer(content, target, sessionKey, beforeSend) {
150
+ if (this.stopped)
151
+ throw new Error('Native session is stopped');
152
+ if (target.backend !== this.host.backend)
153
+ throw new Error('Native steering backend mismatch');
154
+ if (!this.host.agent.steer)
155
+ throw new Error('This harness does not support native steering');
156
+ const binding = this.activeSteerBindings.get(sessionKey);
157
+ if (this.host.onSteeredInput) {
158
+ if (!binding ||
159
+ binding.receipt.backend !== 'codex' ||
160
+ target.backend !== 'codex' ||
161
+ binding.receipt.sessionId !== target.sessionId ||
162
+ binding.receipt.turnId !== target.turnId) {
163
+ throw new types_js_1.NativeSteeringTargetUnavailableError();
164
+ }
165
+ }
166
+ return this.host.agent.steer(content, target, {
167
+ sessionKey,
168
+ beforeSend: () => {
169
+ beforeSend?.();
170
+ binding?.markShared();
171
+ },
172
+ });
173
+ }
174
+ /** Run one turn from text. */
175
+ async run(prompt, request) {
176
+ return this.runTurn([{ type: 'text', text: prompt }], request);
177
+ }
178
+ /**
179
+ * Run one turn from content blocks.
180
+ *
181
+ * Per-call session key wins over the instance default: overlapping runs on a shared
182
+ * session must never depend on mutated state to pick their lane.
183
+ */
184
+ async runTurn(content, request) {
185
+ const { host } = this;
186
+ if (host.useLanes && host.lanes) {
187
+ const sessionKey = request?.sessionKey ?? host.turnPolicy(request).channelKey;
188
+ if (request?.onQueued && !host.lanes.hasSessionWork) {
189
+ logger.warn('Native queue notice is unavailable on this lane provider');
190
+ }
191
+ else if (request?.onQueued && host.lanes.hasSessionWork?.(sessionKey)) {
192
+ try {
193
+ request.onQueued();
194
+ }
195
+ catch (error) {
196
+ logger.warn(`Native queue notice failed: ${error instanceof Error ? error.message : String(error)}`);
197
+ }
198
+ }
199
+ return host.lanes.enqueueWithSession(sessionKey, () => this.runTurnInternal(content, request), host.globalLaneFor?.(sessionKey), { priority: request?.lanePriority ?? 0 });
200
+ }
201
+ return this.runTurnInternal(content, request);
202
+ }
203
+ /**
204
+ * Close the harness. The runner that opened the process is the one that closes it;
205
+ * queued work is given a bounded moment to drain first.
206
+ */
207
+ async stop() {
208
+ if (this.stopped)
209
+ return;
210
+ this.stopped = true;
211
+ try {
212
+ await this.host.agent.stop();
213
+ const lanes = this.host.lanes;
214
+ if (lanes) {
215
+ const waitUntil = Date.now() + 5000;
216
+ while (lanes.getTotalQueueSize() > 0 && Date.now() < waitUntil) {
217
+ await new Promise((resolve) => setTimeout(resolve, 50));
218
+ }
219
+ }
220
+ // NOTE: sessionPool is a shared singleton -- do NOT dispose here. The runtime's
221
+ // own shutdown owns it.
222
+ }
223
+ catch (error) {
224
+ console.error('Error during native session cleanup:', error);
225
+ }
226
+ }
227
+ /**
228
+ * Run the tools one model turn asked for.
229
+ *
230
+ * The guards, the abort, the metrics and the history shape are the same whatever a
231
+ * tool does; what it does is `callTool`.
232
+ */
233
+ async runToolCalls(content, stopAfterSuccessfulTools = [], executionContext = null, runScope = { tier: 1 }) {
234
+ const { host } = this;
235
+ const modelToolContext = withExecutionSurface(executionContext, 'model_tool');
236
+ const reactiveInternalContext = withExecutionSurface(executionContext, 'reactive_internal');
237
+ const toolUseBlocks = content.filter((block) => block.type === 'tool_use');
238
+ const results = [];
239
+ for (const toolUse of toolUseBlocks) {
240
+ let result;
241
+ let isError = false;
242
+ let abort = false;
243
+ let terminalCode;
244
+ runScope.streamCallbacks?.onToolUse?.(toolUse.name, toolUse.input);
245
+ const toolStart = Date.now();
246
+ try {
247
+ const prelude = (await host.toolPrelude?.(toolUse.name, toolUse.input, reactiveInternalContext)) ?? '';
248
+ const toolResult = await host.callTool(toolUse.name, toolUse.input, modelToolContext);
249
+ const toolResultRecord = toolResult;
250
+ result = JSON.stringify(toolResult, null, 2);
251
+ const hasSuccess = toolResult !== null && typeof toolResult === 'object' && 'success' in toolResultRecord;
252
+ if (hasSuccess && toolResultRecord.success === false) {
253
+ isError = true;
254
+ }
255
+ abort = toolResultRecord?.abort === true;
256
+ terminalCode =
257
+ abort &&
258
+ toolResultRecord.retryable === false &&
259
+ (0, types_js_1.isHostToolTerminalCode)(toolResultRecord.code)
260
+ ? toolResultRecord.code
261
+ : undefined;
262
+ if (prelude) {
263
+ result = `${prelude}\n\n---\n\n${result}`;
264
+ }
265
+ runScope.onToolUse?.(toolUse.name, toolUse.input, toolResult);
266
+ host.postToolHandler?.processInBackground(toolUse.name, toolUse.input, toolResult, reactiveInternalContext);
267
+ runScope.streamCallbacks?.onToolComplete?.(toolUse.name, toolUse.id, isError);
268
+ host.onMetric?.('tool_duration_ms', Date.now() - toolStart, {
269
+ tool: toolUse.name,
270
+ error: String(isError),
271
+ });
272
+ }
273
+ catch (error) {
274
+ isError = true;
275
+ result = error instanceof Error ? error.message : String(error);
276
+ runScope.onToolUse?.(toolUse.name, toolUse.input, { error: result });
277
+ host.onMetric?.('tool_duration_ms', Date.now() - toolStart, {
278
+ tool: toolUse.name,
279
+ error: 'true',
280
+ });
281
+ runScope.streamCallbacks?.onToolComplete?.(toolUse.name, toolUse.id, true);
282
+ }
283
+ results.push({
284
+ type: 'tool_result',
285
+ tool_use_id: toolUse.id,
286
+ content: result,
287
+ is_error: isError,
288
+ ...(abort ? { abort: true } : {}),
289
+ ...(terminalCode ? { terminalCode } : {}),
290
+ });
291
+ if (abort) {
292
+ break;
293
+ }
294
+ if (!isError && stopAfterSuccessfulTools.includes(toolUse.name)) {
295
+ break;
296
+ }
297
+ }
298
+ return results;
299
+ }
300
+ /**
301
+ * One dynamic-tool bridge. The same-signature loop guard is private to the bridge, so a parent and its children
302
+ * never share a counter. `recordExchange` is the ONLY way a bridge writes to a
303
+ * conversation: a child passes none and therefore cannot touch the parent's history.
304
+ */
305
+ buildHostToolBridge(params) {
306
+ let consecutiveToolCalls = 0;
307
+ let lastToolSignature = '';
308
+ return {
309
+ tools: params.tools,
310
+ execute: async (call) => {
311
+ const callSignal = call.signal ?? new AbortController().signal;
312
+ callSignal.throwIfAborted();
313
+ const toolSignature = (0, canonicalize_js_1.canonicalizeJSON)({ name: call.name, input: call.input });
314
+ const nextConsecutiveCount = toolSignature === lastToolSignature ? consecutiveToolCalls + 1 : 1;
315
+ if (nextConsecutiveCount >= params.maxConsecutiveSameTool) {
316
+ return {
317
+ content: `Infinite loop detected: Tool "${call.name}" called ${nextConsecutiveCount} times consecutively`,
318
+ isError: true,
319
+ abort: true,
320
+ };
321
+ }
322
+ consecutiveToolCalls = nextConsecutiveCount;
323
+ lastToolSignature = toolSignature;
324
+ const toolUse = {
325
+ type: 'tool_use',
326
+ id: call.callId,
327
+ name: call.name,
328
+ input: call.input,
329
+ };
330
+ params.recordExchange?.assistant(toolUse);
331
+ const executionContext = params.executionContext();
332
+ const callExecutionContext = executionContext
333
+ ? {
334
+ ...executionContext,
335
+ gatewayCallId: call.callId,
336
+ signal: callSignal,
337
+ }
338
+ : null;
339
+ const [toolResult] = await this.runToolCalls([toolUse], [...params.stopAfterSuccessfulTools], callExecutionContext, params.runScope);
340
+ if (!toolResult) {
341
+ callSignal.throwIfAborted();
342
+ return {
343
+ content: `Native tool "${call.name}" returned no result`,
344
+ isError: true,
345
+ abort: true,
346
+ };
347
+ }
348
+ if (!toolResult.terminalCode) {
349
+ callSignal.throwIfAborted();
350
+ }
351
+ params.recordExchange?.result(toolResult);
352
+ return {
353
+ content: toolResult.content,
354
+ isError: toolResult.is_error === true,
355
+ abort: toolResult.abort === true,
356
+ terminalCode: toolResult.terminalCode,
357
+ stop: toolResult.is_error !== true && params.stopAfterSuccessfulTools.includes(call.name),
358
+ };
359
+ },
360
+ };
361
+ }
362
+ /**
363
+ * Give one native child its OWN authority.
364
+ *
365
+ * A parent's bridge closes over authority issued for the PARENT, which the child
366
+ * cannot renew - inheriting it meant a long delegated run losing every tool mid-flight
367
+ * and still reporting "done". So the child gets: its own model run under the parent's,
368
+ * its own authority from the host issuer, its own execution context, and its own
369
+ * bridge counters. When no issuer is reachable it gets nothing and says so - the
370
+ * process refuses its calls rather than quietly borrowing.
371
+ */
372
+ async createSubagentBridge(info) {
373
+ return this.createChildRun(info);
374
+ }
375
+ /** Both native dynamic tools and an attributed socket call use this child run. */
376
+ async createChildRun(info) {
377
+ const { host } = this;
378
+ const context = this.subagentRunContexts.get(info.sessionKey);
379
+ if (!context) {
380
+ console.warn(`[NativeTurn] subagent authority unavailable: no run context for session ${info.sessionKey} ` +
381
+ `(thread=${info.agentThreadId})`);
382
+ return null;
383
+ }
384
+ if (context.runFinished) {
385
+ // Only a child announced DURING the run inherits that run's issuer. A finished run
386
+ // stays reachable while a sibling is live; it must not mint authority hours later.
387
+ console.warn(`[NativeTurn] subagent authority refused: run for session ${info.sessionKey} already ended ` +
388
+ `(thread=${info.agentThreadId})`);
389
+ return null;
390
+ }
391
+ // Claimed synchronously: the parent's finally must not drop the context while this
392
+ // factory is still awaiting authority or a model run.
393
+ context.activeChildren += 1;
394
+ const abandon = (reason) => {
395
+ console.warn(reason);
396
+ this.releaseSubagentRunContext(info.sessionKey, context);
397
+ return null;
398
+ };
399
+ // A child asks the host for the same authority the parent asked for.
400
+ const issuer = context.request?.prepareAccess;
401
+ if (!issuer) {
402
+ return abandon(`[NativeTurn] subagent authority unavailable: no host authority for ${info.sessionKey} ` +
403
+ `(thread=${info.agentThreadId})`);
404
+ }
405
+ let access;
406
+ try {
407
+ access = await issuer();
408
+ }
409
+ catch (error) {
410
+ return abandon(`[NativeTurn] subagent authority issuance failed thread=${info.agentThreadId}: ${error instanceof Error ? error.message : String(error)}`);
411
+ }
412
+ if (!access) {
413
+ return abandon(`[NativeTurn] subagent authority unavailable: the host stated none ` +
414
+ `(thread=${info.agentThreadId})`);
415
+ }
416
+ const childRequest = {
417
+ ...(context.request ?? {}),
418
+ access,
419
+ prepareAccess: undefined,
420
+ parentModelRunId: context.parentModelRunId,
421
+ sourceMessageRef: `subagent:${info.agentThreadId}`,
422
+ // A child's own run cannot claim its parent's accepted mailbox input.
423
+ nativeInputId: undefined,
424
+ };
425
+ let modelRunId;
426
+ try {
427
+ if (!host.modelRun) {
428
+ return abandon(`[NativeTurn] subagent model run unavailable: no model-run port ` +
429
+ `(thread=${info.agentThreadId})`);
430
+ }
431
+ modelRunId = await host.modelRun.begin(childRequest, context.cliSessionId);
432
+ }
433
+ catch (error) {
434
+ return abandon(`[NativeTurn] subagent model run could not begin thread=${info.agentThreadId}: ${error instanceof Error ? error.message : String(error)}`);
435
+ }
436
+ const childTasks = [];
437
+ const backgroundTasks = {
438
+ register(task) {
439
+ const observedTask = Promise.resolve(task);
440
+ observedTask.catch(() => {
441
+ // Re-thrown later by the child's release drain.
442
+ });
443
+ childTasks.push(observedTask);
444
+ },
445
+ };
446
+ let childContext;
447
+ let bridge;
448
+ // The child's model run is already OPEN. Anything that throws while assembling its
449
+ // context or bridge must fail that run and release the parent's context, or the run
450
+ // stays `running` forever and the context stays pinned by a child that never existed.
451
+ try {
452
+ const base = host.executionContext({
453
+ ...childRequest,
454
+ modelRunId,
455
+ });
456
+ childContext = base
457
+ ? {
458
+ ...base,
459
+ backgroundTasks,
460
+ subagentThreadId: info.agentThreadId,
461
+ }
462
+ : null;
463
+ // The child's own run scope: no stream callbacks, no onTurn, no onToolUse. Its work
464
+ // is not this run's turns, and the parent's model run is already committed by then.
465
+ const runScope = { tier: context.tier };
466
+ bridge = this.buildHostToolBridge({
467
+ tools: context.tools,
468
+ runScope,
469
+ executionContext: () => childContext,
470
+ stopAfterSuccessfulTools: [],
471
+ maxConsecutiveSameTool: MAX_CONSECUTIVE_SAME_HOST_TOOL,
472
+ });
473
+ }
474
+ catch (error) {
475
+ const summary = error instanceof Error ? error.message : String(error);
476
+ try {
477
+ await host.modelRun.fail(modelRunId, `subagent authority could not be assembled: ${summary}`);
478
+ }
479
+ catch (failError) {
480
+ logger.warn(`Failed to mark subagent model run ${modelRunId} failed: ${failError instanceof Error ? failError.message : String(failError)}`);
481
+ }
482
+ return abandon(`[NativeTurn] subagent authority could not be assembled thread=${info.agentThreadId}: ${summary}`);
483
+ }
484
+ let released = false;
485
+ return {
486
+ bridge,
487
+ executionContext: childContext,
488
+ release: async (outcome) => {
489
+ if (released) {
490
+ return;
491
+ }
492
+ released = true;
493
+ try {
494
+ await drainBackgroundTasks(childTasks);
495
+ }
496
+ catch (error) {
497
+ logger.warn(`subagent background drain failed: ${error instanceof Error ? error.message : String(error)}`);
498
+ }
499
+ try {
500
+ if (outcome.status === 'completed') {
501
+ await host.modelRun?.commit(modelRunId, `subagent ${info.agentPath || info.agentThreadId} completed`);
502
+ }
503
+ else {
504
+ // `unknown` is not success: the run is marked failed with the reason so the
505
+ // ledger never carries a completion nobody confirmed.
506
+ await host.modelRun?.fail(modelRunId, outcome.error ?? `subagent ${outcome.status}`);
507
+ }
508
+ }
509
+ catch (error) {
510
+ logger.warn(`subagent model run ${modelRunId} could not be closed: ${error instanceof Error ? error.message : String(error)}`);
511
+ }
512
+ this.releaseSubagentRunContext(info.sessionKey, context);
513
+ },
514
+ };
515
+ }
516
+ /** Resolve a harness caller only against a currently dispatched turn. */
517
+ async withToolCaller(caller, execute) {
518
+ if (!caller ||
519
+ typeof caller.session_id !== 'string' ||
520
+ !caller.session_id ||
521
+ typeof caller.tool_use_id !== 'string' ||
522
+ !caller.tool_use_id ||
523
+ (caller.agent_id !== undefined &&
524
+ (typeof caller.agent_id !== 'string' || !caller.agent_id)) ||
525
+ (caller.agent_type !== undefined && typeof caller.agent_type !== 'string')) {
526
+ throw new Error('Invalid native tool caller');
527
+ }
528
+ const entry = [...this.subagentRunContexts.entries()].find(([, context]) => !context.runFinished && context.nativeSessionId === caller.session_id);
529
+ if (!entry)
530
+ throw new Error('Native tool caller has no matching active turn');
531
+ const [sessionKey, context] = entry;
532
+ if (caller.agent_id !== undefined) {
533
+ const owners = this.callerChildOwners.get(sessionKey);
534
+ const owner = owners?.turns.get(caller.agent_id);
535
+ if (owner !== undefined && owner !== context.callerTurnId) {
536
+ throw new Error('Native child caller belongs to a different turn');
537
+ }
538
+ owners?.turns.set(caller.agent_id, context.callerTurnId);
539
+ }
540
+ const call = (async () => {
541
+ let executionContext = context.executionContext();
542
+ if (caller.agent_id !== undefined) {
543
+ let child = context.callerChildren.get(caller.agent_id);
544
+ if (!child) {
545
+ child = this.createChildRun({
546
+ sessionKey,
547
+ parentThreadId: caller.session_id,
548
+ agentThreadId: caller.agent_id,
549
+ agentPath: caller.agent_type ?? caller.agent_id,
550
+ });
551
+ // Store the promise before awaiting: concurrent calls share exactly one child.
552
+ context.callerChildren.set(caller.agent_id, child);
553
+ }
554
+ const run = await child;
555
+ if (!run)
556
+ throw new Error('Native child authority could not be created');
557
+ executionContext = run.executionContext;
558
+ }
559
+ if (!executionContext)
560
+ throw new Error('Native tool caller has no execution context');
561
+ return execute({ ...executionContext, gatewayCallId: caller.tool_use_id });
562
+ })();
563
+ context.callerCalls.add(call);
564
+ try {
565
+ return await call;
566
+ }
567
+ finally {
568
+ context.callerCalls.delete(call);
569
+ }
570
+ }
571
+ async settleCallerRuns(context, outcome) {
572
+ // Dynamic-tool children are settled by their native driver's own terminal events.
573
+ if (!context || this.host.backend !== 'claude')
574
+ return;
575
+ context.runFinished = true;
576
+ await Promise.allSettled(context.callerCalls);
577
+ await Promise.all([...context.callerChildren.values()].map(async (pending) => {
578
+ const child = await pending;
579
+ await child?.release(outcome);
580
+ }));
581
+ }
582
+ /** Drop a run's subagent context once the run finished and no child still holds it. */
583
+ releaseSubagentRunContext(sessionKey, context) {
584
+ context.activeChildren = Math.max(0, context.activeChildren - 1);
585
+ if (context.runFinished &&
586
+ context.activeChildren === 0 &&
587
+ this.subagentRunContexts.get(sessionKey) === context) {
588
+ this.subagentRunContexts.delete(sessionKey);
589
+ }
590
+ }
591
+ /** The run itself, with no queue around it. */
592
+ async runTurnInternal(content, request) {
593
+ const { host } = this;
594
+ if (this.stopped) {
595
+ throw new types_js_1.AgentError('Agent loop is stopping', 'AGENT_STOPPED', undefined, false);
596
+ }
597
+ // Queue wait consumes no execution authority: only a host-supplied statement
598
+ // can name this run's grant, and it is asked for after both lane waits. The
599
+ // statement is kept reachable (rather than cleared) because a native child
600
+ // spawned later asks the same host the same question.
601
+ if (request?.prepareAccess) {
602
+ request = { ...request, access: await request.prepareAccess() };
603
+ if (this.stopped) {
604
+ throw new types_js_1.AgentError('Agent loop is stopping', 'AGENT_STOPPED', undefined, false);
605
+ }
606
+ }
607
+ if (request?.prepareContent) {
608
+ const admitted = await request.prepareContent();
609
+ content = admitted.content;
610
+ request = {
611
+ ...request,
612
+ procedureRefs: admitted.procedureRefs,
613
+ prepareContent: undefined,
614
+ };
615
+ if (this.stopped) {
616
+ throw new types_js_1.AgentError('Agent loop is stopping', 'AGENT_STOPPED', undefined, false);
617
+ }
618
+ }
619
+ if (host.projectRequest && request) {
620
+ request = host.projectRequest(request);
621
+ }
622
+ const runScope = {
623
+ streamCallbacks: request?.streamCallbacks,
624
+ tier: 1,
625
+ onTurn: request?.onTurn ?? host.onTurn,
626
+ onToolUse: request?.onToolUse ?? host.onToolUse,
627
+ };
628
+ const history = [];
629
+ const runPrompt = request?.ownerJournalPrompt ??
630
+ content.map((block) => (block.type === 'text' ? block.text : `[${block.type}]`)).join('\n');
631
+ const totalUsage = { input_tokens: 0, output_tokens: 0 };
632
+ // Budget accounting is separate from totalUsage (a published field): it includes cache
633
+ // creation and cache reads, which are the bulk of a re-sent context and the cost being
634
+ // bounded - a budget that ignored them would not have stopped a 4.28M-token run.
635
+ let budgetTokens = 0;
636
+ let stoppedBy;
637
+ let turn = 0;
638
+ let stopReason = 'end_turn';
639
+ let ownedModelRunId = null;
640
+ let ownedModelRunCommitted = false;
641
+ let nativeEffects = new native_effect_observer_js_1.NativeEffectReplayBoundary();
642
+ const pendingBackgroundTasks = [];
643
+ const backgroundTasks = {
644
+ register(task) {
645
+ const observedTask = Promise.resolve(task);
646
+ observedTask.catch(() => {
647
+ // Re-thrown later by drainBackgroundTasks; attach now to prevent unhandled rejections.
648
+ });
649
+ pendingBackgroundTasks.push(observedTask);
650
+ },
651
+ };
652
+ const withRunLocals = (context) => context
653
+ ? {
654
+ ...context,
655
+ backgroundTasks,
656
+ procedureStimulus: runPrompt,
657
+ procedureRefs: request?.procedureRefs,
658
+ }
659
+ : null;
660
+ let toolExecutionContext = withRunLocals(host.executionContext(request));
661
+ // Track this run's tier for prompt sizing.
662
+ const rawTier = request?.tier ?? 1;
663
+ runScope.tier = rawTier === 1 || rawTier === 2 || rawTier === 3 ? rawTier : 1;
664
+ // Infinite loop prevention
665
+ const MAX_CONSECUTIVE_SAME_TOOL = MAX_CONSECUTIVE_SAME_HOST_TOOL;
666
+ const policy = host.turnPolicy(request);
667
+ if (policy.restrictedReadRoots && host.backend !== 'codex') {
668
+ throw new Error('Native restricted read roots require the Codex backend');
669
+ }
670
+ if (policy.nativeCwd && host.backend !== 'codex') {
671
+ throw new Error('Native working directory override requires the Codex backend');
672
+ }
673
+ const channelKey = policy.channelKey;
674
+ let activeSteerBinding;
675
+ if (host.onSteeredInput) {
676
+ const observer = runScope.streamCallbacks;
677
+ runScope.streamCallbacks = {
678
+ ...observer,
679
+ onAccepted: (receipt) => {
680
+ observer?.onAccepted?.(receipt);
681
+ let shared = false;
682
+ const binding = {
683
+ receipt,
684
+ markShared: () => {
685
+ if (shared)
686
+ return;
687
+ toolExecutionContext = host.onSteeredInput(toolExecutionContext);
688
+ shared = true;
689
+ },
690
+ };
691
+ activeSteerBinding = binding;
692
+ this.activeSteerBindings.set(channelKey, binding);
693
+ },
694
+ };
695
+ }
696
+ const compose = (layers) => (0, prompt_layers_js_1.composeLayers)(layers, (message) => logger.warn(message));
697
+ // The context object THIS run created, compared by identity before the finally marks
698
+ // it finished: a later run on the same session key replaces the map entry.
699
+ let ownedSubagentRunContext;
700
+ const callerSpawnNames = new Map();
701
+ const bindCallerChild = (agentId) => {
702
+ const context = ownedSubagentRunContext;
703
+ const owners = this.callerChildOwners.get(channelKey);
704
+ if (!context || !owners || owners.nativeSessionId !== context.nativeSessionId)
705
+ return;
706
+ // A delayed launch event from an older turn cannot undo an explicit later resume.
707
+ if ((owners.turns.get(agentId) ?? 0) <= context.callerTurnId) {
708
+ owners.turns.set(agentId, context.callerTurnId);
709
+ }
710
+ };
711
+ const callerObserver = runScope.streamCallbacks;
712
+ runScope.streamCallbacks = {
713
+ ...callerObserver,
714
+ onInputDispatch: (input) => {
715
+ if (ownedSubagentRunContext)
716
+ ownedSubagentRunContext.nativeSessionId = input.sessionId;
717
+ if (host.backend === 'claude' &&
718
+ this.callerChildOwners.get(channelKey)?.nativeSessionId !== input.sessionId) {
719
+ this.callerChildOwners.set(channelKey, {
720
+ nativeSessionId: input.sessionId,
721
+ turns: new Map(),
722
+ aliases: new Map(),
723
+ });
724
+ }
725
+ callerObserver?.onInputDispatch?.(input);
726
+ },
727
+ onSubagentStart: (info) => {
728
+ bindCallerChild(info.agentThreadId);
729
+ const name = callerSpawnNames.get(info.itemId);
730
+ const owners = this.callerChildOwners.get(channelKey);
731
+ if (name && owners && owners.nativeSessionId === ownedSubagentRunContext?.nativeSessionId) {
732
+ owners.aliases.set(name, info.agentThreadId);
733
+ }
734
+ callerObserver?.onSubagentStart?.(info);
735
+ },
736
+ onToolUse: (name, input) => {
737
+ if (host.backend === 'claude') {
738
+ if (name === 'Agent' &&
739
+ typeof input.name === 'string' &&
740
+ typeof input.nativeToolUseId === 'string') {
741
+ callerSpawnNames.set(input.nativeToolUseId, input.name);
742
+ }
743
+ // Claude 2.1.x resumes through SendMessage, addressed by native ID or
744
+ // a name resolved from the observed Agent launch, before child calls run.
745
+ if (name === 'SendMessage' && typeof input.to === 'string') {
746
+ const owners = this.callerChildOwners.get(channelKey);
747
+ bindCallerChild(owners?.aliases.get(input.to) ?? input.to);
748
+ }
749
+ }
750
+ callerObserver?.onToolUse?.(name, input);
751
+ },
752
+ };
753
+ // Use session pool for conversation continuity
754
+ // IMPORTANT: if the caller passes a session id, use it directly to avoid double-locking
755
+ let sessionIsNew = request?.resumeSession === undefined ? true : !request.resumeSession;
756
+ let ownedSession = false;
757
+ // Claude PersistentCLI: process alive -> CONTINUE (stdin message), process dead -> NEW.
758
+ // Codex: durable runtime session alive -> CONTINUE, missing -> NEW.
759
+ const isCodex = host.backend === 'codex';
760
+ const isDurableRuntime = isCodex;
761
+ const tracksSessionPolicy = isDurableRuntime || host.backend === 'claude';
762
+ // --tools is part of the spawned surface: a different grant on the same session
763
+ // must respawn the process instead of inheriting a stale tool list.
764
+ const effectiveSessionPolicyFingerprint = host.backend === 'claude' && policy.sessionPolicyFingerprint !== undefined
765
+ ? `${policy.sessionPolicyFingerprint}::tools=${policy.nativeTools ?? 'default'}`
766
+ : policy.sessionPolicyFingerprint;
767
+ let resolvedCliSessionId = request?.cliSessionId ?? null;
768
+ if (request?.cliSessionId) {
769
+ // Session routing travels per prompt() call via resolvedCliSessionId - no
770
+ // shared-adapter mutation (setSessionId re-pointed channelKey/currentProcess
771
+ // across awaits, cross-wiring concurrent lanes).
772
+ }
773
+ else if (request?.freshSession) {
774
+ // Stateless lanes: session context is a cache, not persistence - every run
775
+ // self-gathers and recalls; carrying prior runs' gather dumps only grows the
776
+ // context (measured 146s -> 521s over 3 days; owner decision 2026-07-16).
777
+ const cliSessionId = host.sessionPool.resetSession(channelKey);
778
+ sessionIsNew = true;
779
+ ownedSession = true;
780
+ resolvedCliSessionId = cliSessionId;
781
+ }
782
+ else {
783
+ // The native lane serializes this session before the pool is acquired.
784
+ // A busy entry means another caller holds it outside this lane: reusing
785
+ // and then releasing that entry would steal its session identity.
786
+ const { sessionId: cliSessionId, isNew, busy } = host.sessionPool.getSession(channelKey);
787
+ if (busy) {
788
+ throw new types_js_1.AgentError('Native session is busy outside its lane', 'CLI_ERROR', undefined, true);
789
+ }
790
+ sessionIsNew = isNew;
791
+ ownedSession = true;
792
+ resolvedCliSessionId = cliSessionId;
793
+ }
794
+ // A run record is opened for EVERY turn this entry runs, with two exceptions that
795
+ // are both stated rather than inferred: the caller already owns a run, or the
796
+ // driver says it cannot stand behind one. Tool routing is not one of them.
797
+ const callerOwnsModelRun = Boolean(request?.modelRunId);
798
+ const runnerReportsRuns = host.agent.reportsModelRuns !== false;
799
+ try {
800
+ if (!callerOwnsModelRun && runnerReportsRuns && host.modelRun) {
801
+ ownedModelRunId = await host.modelRun.begin(request, resolvedCliSessionId);
802
+ request?.onModelRunStarted?.(ownedModelRunId);
803
+ if (ownedModelRunId) {
804
+ toolExecutionContext = withRunLocals(host.executionContext({
805
+ ...(request ?? {}),
806
+ modelRunId: ownedModelRunId,
807
+ }));
808
+ }
809
+ }
810
+ if (callerOwnsModelRun)
811
+ request?.onModelRunStarted?.(request.modelRunId);
812
+ let nativeObserver;
813
+ try {
814
+ nativeObserver = host.createNativeEffectObserver?.(toolExecutionContext);
815
+ }
816
+ catch {
817
+ logger.warn('[NativeTurn] native observation setup failed');
818
+ }
819
+ nativeEffects = new native_effect_observer_js_1.NativeEffectReplayBoundary(nativeObserver);
820
+ // This run's bridge is ITS OWN: the loop guards, the emergency budget, the history
821
+ // writes and the turn observers all belong to this run. A native child gets a
822
+ // separate bridge - sharing this closure let a child trip the parent's loop guard
823
+ // and append its traces to the parent's committed model run.
824
+ const hostToolDefinitions = host.hostToolDefinitions(request);
825
+ const hostToolBridge = isDurableRuntime && host.isGatewayMode
826
+ ? this.buildHostToolBridge({
827
+ tools: hostToolDefinitions,
828
+ runScope,
829
+ executionContext: () => toolExecutionContext,
830
+ stopAfterSuccessfulTools: request?.stopAfterSuccessfulTools ?? [],
831
+ maxConsecutiveSameTool: MAX_CONSECUTIVE_SAME_TOOL,
832
+ // A durable runtime does not return completed host exchanges, so record
833
+ // them here: it reports the paired custom-tool exchange from its event
834
+ // stream and this entry appends it exactly once.
835
+ ...(isCodex
836
+ ? {
837
+ recordExchange: {
838
+ assistant: (toolUse) => {
839
+ history.push({ role: 'assistant', content: [toolUse] });
840
+ runScope.onTurn?.({
841
+ turn,
842
+ role: 'assistant',
843
+ content: [toolUse],
844
+ stopReason: 'tool_use',
845
+ });
846
+ },
847
+ result: (toolResult) => {
848
+ const persistedToolResult = historyToolResult(toolResult);
849
+ history.push({ role: 'user', content: [persistedToolResult] });
850
+ runScope.onTurn?.({
851
+ turn,
852
+ role: 'user',
853
+ content: [persistedToolResult],
854
+ });
855
+ },
856
+ },
857
+ }
858
+ : {}),
859
+ })
860
+ : undefined;
861
+ if ((hostToolBridge && isCodex) || host.backend === 'claude') {
862
+ // A child can be announced during this run and outlive it, so what its authority
863
+ // needs is recorded now, per session key, and dropped when nothing needs it.
864
+ // A previous run's context object stays referenced by ITS still-live children, so
865
+ // this run starts its own count rather than inheriting one it can never settle.
866
+ ownedSubagentRunContext = {
867
+ request: request ? { ...request } : undefined,
868
+ parentModelRunId: ownedModelRunId ?? request?.modelRunId ?? null,
869
+ cliSessionId: resolvedCliSessionId,
870
+ tools: hostToolDefinitions,
871
+ tier: runScope.tier,
872
+ activeChildren: 0,
873
+ runFinished: false,
874
+ callerTurnId: ++this.nextCallerTurnId,
875
+ executionContext: () => toolExecutionContext,
876
+ callerChildren: new Map(),
877
+ callerCalls: new Set(),
878
+ };
879
+ this.subagentRunContexts.set(channelKey, ownedSubagentRunContext);
880
+ }
881
+ // Reset StopContinuation state for this channel to prevent leaking
882
+ // retry counts from previous invocations
883
+ // The input remains a user message; native compaction/continuation owns subsequent work.
884
+ history.push({ role: 'user', content });
885
+ const carry = {
886
+ turn,
887
+ stopReason,
888
+ stoppedBy,
889
+ budgetTokens,
890
+ resolvedCliSessionId,
891
+ sessionIsNew,
892
+ };
893
+ await (0, native_prompt_js_1.runNativePrompt)(carry, {
894
+ channelKey,
895
+ claudeNativeTools: policy.nativeTools,
896
+ effectiveSessionPolicyFingerprint,
897
+ restrictedReadRoots: policy.restrictedReadRoots,
898
+ nativeCwd: policy.nativeCwd,
899
+ history,
900
+ prepareSessionContent: request?.prepareSessionContent,
901
+ hostToolBridge,
902
+ isCodex,
903
+ isDurableRuntime,
904
+ nativeEffects,
905
+ ownedModelRunId,
906
+ standingPolicy: policy.standingPolicy === true,
907
+ systemPrompt: compose(policy.systemLayers),
908
+ reanchor: policy.reanchorLayers
909
+ ? async () => compose(await policy.reanchorLayers())
910
+ : undefined,
911
+ resumeInstructions: policy.resumeLayers
912
+ ? async () => compose(await policy.resumeLayers())
913
+ : undefined,
914
+ runScope,
915
+ toolExecutionContext,
916
+ totalUsage,
917
+ tracksSessionPolicy,
918
+ }, request ?? {}, {
919
+ agent: host.agent,
920
+ backend: host.backend,
921
+ model: host.model,
922
+ runTokenBudget: host.runTokenBudget,
923
+ sessionPool: host.sessionPool,
924
+ onBudgetStop: host.onBudgetStop,
925
+ onTokenUsage: host.onTokenUsage,
926
+ onMetric: host.onMetric,
927
+ formatLastMessageOnly: (messages) => formatLastUserMessage(messages, { mediaDir: host.inboundMediaDir }),
928
+ });
929
+ ({ turn, stopReason, stoppedBy, budgetTokens, resolvedCliSessionId, sessionIsNew } = carry);
930
+ const finalResponse = (0, turn_text_js_1.extractTextResponse)(history);
931
+ const result = {
932
+ ...(stoppedBy ? { stoppedBy } : {}),
933
+ response: finalResponse,
934
+ turns: turn,
935
+ history,
936
+ totalUsage,
937
+ stopReason,
938
+ modelRunId: ownedModelRunId ?? request?.modelRunId ?? null,
939
+ modelRunProvenance: (ownedModelRunId ?? request?.modelRunId) ? 'available' : 'backend_no_run',
940
+ };
941
+ await this.settleCallerRuns(ownedSubagentRunContext, stoppedBy
942
+ ? { status: 'interrupted', error: `parent stopped: ${stoppedBy}` }
943
+ : { status: 'completed' });
944
+ // Draining background work and committing the run are separate failures and get
945
+ // separate catches. Sharing one meant a rejected background task skipped the commit
946
+ // and was then reported as `commit_failed` - naming a failure that was never even
947
+ // attempted, which is the exact habit this provenance state exists to break.
948
+ try {
949
+ await drainBackgroundTasks(pendingBackgroundTasks);
950
+ }
951
+ catch (backgroundError) {
952
+ logger.warn(`background task drain failed: ${backgroundError instanceof Error ? backgroundError.message : String(backgroundError)}`);
953
+ }
954
+ try {
955
+ if (ownedModelRunId && host.modelRun) {
956
+ await host.modelRun.commit(ownedModelRunId, completionSummary(finalResponse), totalUsage.input_tokens + totalUsage.output_tokens);
957
+ ownedModelRunCommitted = true;
958
+ }
959
+ }
960
+ catch (commitError) {
961
+ logger.warn(`model run commit failed: ${commitError instanceof Error ? commitError.message : String(commitError)}`);
962
+ }
963
+ if (ownedModelRunId && !ownedModelRunCommitted) {
964
+ // The response still stands - the turn happened and the owner should get it.
965
+ // What does NOT stand is the handle: the run record may be left uncommitted, so
966
+ // returning its id would hand out provenance that cannot be resolved. Report the
967
+ // answer, withhold the claim, and say which kind of absence this is - an
968
+ // uncommitted record is a durability failure to repair, not the ordinary case of
969
+ // a backend that reports no run at all.
970
+ //
971
+ // Deliberately NOT marked failed. The run did not fail; writing its completion
972
+ // did. Relabelling a successful run as failed would tidy the state by recording
973
+ // something untrue, and an existing test pins that decision. The orphan stays
974
+ // visible, and the reason below is what a repair pass keys on.
975
+ result.modelRunId = null;
976
+ result.modelRunProvenance = 'commit_failed';
977
+ logger.error(`Model run ${ownedModelRunId} may remain uncommitted; provenance reported as commit_failed`);
978
+ }
979
+ try {
980
+ await host.onRunFinished?.({
981
+ request,
982
+ result,
983
+ channelKey,
984
+ modelRunId: ownedModelRunId,
985
+ prompt: runPrompt,
986
+ response: finalResponse,
987
+ });
988
+ }
989
+ catch (observerError) {
990
+ logger.error(`Run-finished observer failed: ${observerError instanceof Error ? observerError.message : String(observerError)}`);
991
+ }
992
+ if (stoppedBy) {
993
+ // Budget interruption is returned structurally; keep admission uncertain.
994
+ nativeEffects.failure(new Error('Native run stopped by token budget'));
995
+ }
996
+ else {
997
+ nativeEffects.finished();
998
+ }
999
+ return result;
1000
+ }
1001
+ catch (error) {
1002
+ await this.settleCallerRuns(ownedSubagentRunContext, {
1003
+ status: 'failed',
1004
+ error: error instanceof Error ? error.message : String(error),
1005
+ });
1006
+ if (ownedModelRunId && !ownedModelRunCommitted && host.modelRun) {
1007
+ try {
1008
+ const summary = error instanceof Error ? error.message : String(error);
1009
+ await host.modelRun.fail(ownedModelRunId, summary, totalUsage.input_tokens + totalUsage.output_tokens);
1010
+ }
1011
+ catch (failError) {
1012
+ logger.warn(`Failed to mark model run ${ownedModelRunId} failed: ${failError instanceof Error ? failError.message : String(failError)}`);
1013
+ }
1014
+ }
1015
+ throw nativeEffects.failure(error);
1016
+ }
1017
+ finally {
1018
+ if (activeSteerBinding && this.activeSteerBindings.get(channelKey) === activeSteerBinding) {
1019
+ this.activeSteerBindings.delete(channelKey);
1020
+ }
1021
+ // A child that outlives this run still needs its authority recipe, so the context is
1022
+ // dropped only once the run finished AND no child of it is still registered.
1023
+ if (ownedSubagentRunContext) {
1024
+ ownedSubagentRunContext.runFinished = true;
1025
+ if (ownedSubagentRunContext.activeChildren === 0 &&
1026
+ this.subagentRunContexts.get(channelKey) === ownedSubagentRunContext) {
1027
+ this.subagentRunContexts.delete(channelKey);
1028
+ }
1029
+ }
1030
+ // Always release the session lock, even on error, but only if we own it.
1031
+ if (ownedSession) {
1032
+ host.sessionPool.releaseSession(channelKey);
1033
+ }
1034
+ }
1035
+ }
1036
+ }
1037
+ exports.NativeSessionRunner = NativeSessionRunner;
1038
+ function createNativeSessionRunner(host) {
1039
+ return new NativeSessionRunner(host);
1040
+ }
1041
+ //# sourceMappingURL=native-turn.js.map