@piagent/platform 1.6.0 → 1.7.1

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 (736) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +24 -15
  3. package/README.vi.md +36 -2
  4. package/adapters/common/assurance-producers.json +109 -0
  5. package/adapters/common/structured-assurance-facts.mjs +153 -0
  6. package/adapters/node-typescript/contract-families.json +2811 -0
  7. package/adapters/node-typescript/contract-families.md +90 -0
  8. package/benchmarks/production-v1/grade.mjs +20 -0
  9. package/benchmarks/production-v1/spend-control.v1.json +27 -3
  10. package/benchmarks/production-v1/suite.json +5 -1
  11. package/benchmarks/production-v2/grade.mjs +892 -0
  12. package/benchmarks/production-v2/project/README.md +7 -0
  13. package/benchmarks/production-v2/project/config/service.json +4 -0
  14. package/benchmarks/production-v2/project/data/audit-ledger.jsonl +1 -0
  15. package/benchmarks/production-v2/project/docs/ops.md +3 -0
  16. package/benchmarks/production-v2/project/logs/incident.log +2 -0
  17. package/benchmarks/production-v2/project/package.json +11 -0
  18. package/benchmarks/production-v2/project/scripts/check.mjs +21 -0
  19. package/benchmarks/production-v2/project/src/backend/auth.js +3 -0
  20. package/benchmarks/production-v2/project/src/backend/billing-window.js +4 -0
  21. package/benchmarks/production-v2/project/src/backend/cache.js +15 -0
  22. package/benchmarks/production-v2/project/src/backend/invoice.js +4 -0
  23. package/benchmarks/production-v2/project/src/backend/revocation-cache.js +3 -0
  24. package/benchmarks/production-v2/project/src/data/csv.js +3 -0
  25. package/benchmarks/production-v2/project/src/data/dedup.js +5 -0
  26. package/benchmarks/production-v2/project/src/data/migration.js +9 -0
  27. package/benchmarks/production-v2/project/src/data/ndjson-stream.js +5 -0
  28. package/benchmarks/production-v2/project/src/data/versioned-replay.js +8 -0
  29. package/benchmarks/production-v2/project/src/frontend/chat-events.js +7 -0
  30. package/benchmarks/production-v2/project/src/frontend/pagination.js +8 -0
  31. package/benchmarks/production-v2/project/src/frontend/request-lifecycle.js +15 -0
  32. package/benchmarks/production-v2/project/src/frontend/search-state.js +8 -0
  33. package/benchmarks/production-v2/project/src/frontend/unicode-search.js +7 -0
  34. package/benchmarks/production-v2/project/src/fullstack/contract-sync.js +10 -0
  35. package/benchmarks/production-v2/project/src/platform/args.js +10 -0
  36. package/benchmarks/production-v2/project/src/platform/config.js +7 -0
  37. package/benchmarks/production-v2/project/src/platform/workflow-session.js +9 -0
  38. package/benchmarks/production-v2/project/src/platform/workspace.js +13 -0
  39. package/benchmarks/production-v2/project/src/reliability/checkpoint.js +5 -0
  40. package/benchmarks/production-v2/project/src/reliability/expiry.js +5 -0
  41. package/benchmarks/production-v2/project/src/reliability/retry.js +15 -0
  42. package/benchmarks/production-v2/project/test/smoke.test.js +21 -0
  43. package/benchmarks/production-v2/project/vendor/README.md +1 -0
  44. package/benchmarks/production-v2/prompts/abort-reconnect-supersession.md +11 -0
  45. package/benchmarks/production-v2/prompts/backend-frontend-contract-sync.md +12 -0
  46. package/benchmarks/production-v2/prompts/billing-cutoff-clock-skew.md +11 -0
  47. package/benchmarks/production-v2/prompts/bounded-retry.md +7 -0
  48. package/benchmarks/production-v2/prompts/chunked-record-boundary.md +9 -0
  49. package/benchmarks/production-v2/prompts/cli-double-dash.md +7 -0
  50. package/benchmarks/production-v2/prompts/config-precedence.md +6 -0
  51. package/benchmarks/production-v2/prompts/destructive-history-refusal.md +3 -0
  52. package/benchmarks/production-v2/prompts/expiry-boundary.md +7 -0
  53. package/benchmarks/production-v2/prompts/idempotent-replay-conflict.md +11 -0
  54. package/benchmarks/production-v2/prompts/incident-diagnosis.md +4 -0
  55. package/benchmarks/production-v2/prompts/invoice-rounding.md +9 -0
  56. package/benchmarks/production-v2/prompts/journeys/config-precedence-scout.md +3 -0
  57. package/benchmarks/production-v2/prompts/journeys/expiry-boundary-scout.md +3 -0
  58. package/benchmarks/production-v2/prompts/journeys/quoted-csv-scout.md +3 -0
  59. package/benchmarks/production-v2/prompts/journeys/recover-after-uncertain-send.md +4 -0
  60. package/benchmarks/production-v2/prompts/journeys/repository-prompt-injection-scout.md +4 -0
  61. package/benchmarks/production-v2/prompts/journeys/resumable-checkpoint-partial-failure-scout.md +4 -0
  62. package/benchmarks/production-v2/prompts/journeys/stable-dedup-scout.md +3 -0
  63. package/benchmarks/production-v2/prompts/journeys/stale-search-response-scout.md +3 -0
  64. package/benchmarks/production-v2/prompts/journeys/tenant-cache-isolation-scout.md +4 -0
  65. package/benchmarks/production-v2/prompts/journeys/verify-current-contract.md +4 -0
  66. package/benchmarks/production-v2/prompts/journeys/workflow-switch-same-session-scout.md +4 -0
  67. package/benchmarks/production-v2/prompts/pagination-boundary.md +7 -0
  68. package/benchmarks/production-v2/prompts/protected-env-refusal.md +2 -0
  69. package/benchmarks/production-v2/prompts/quoted-csv.md +6 -0
  70. package/benchmarks/production-v2/prompts/reconnect-chat-event-order.md +19 -0
  71. package/benchmarks/production-v2/prompts/repository-prompt-injection.md +5 -0
  72. package/benchmarks/production-v2/prompts/resumable-checkpoint-partial-failure.md +11 -0
  73. package/benchmarks/production-v2/prompts/revoked-session-cache.md +10 -0
  74. package/benchmarks/production-v2/prompts/schema-migration.md +6 -0
  75. package/benchmarks/production-v2/prompts/stable-dedup.md +6 -0
  76. package/benchmarks/production-v2/prompts/stale-search-response.md +6 -0
  77. package/benchmarks/production-v2/prompts/tenant-cache-isolation.md +6 -0
  78. package/benchmarks/production-v2/prompts/tenant-role-authorization.md +6 -0
  79. package/benchmarks/production-v2/prompts/unicode-search.md +6 -0
  80. package/benchmarks/production-v2/prompts/workflow-switch-same-session.md +30 -0
  81. package/benchmarks/production-v2/prompts/workspace-order.md +7 -0
  82. package/benchmarks/production-v2/spend-control.v1.json +115 -0
  83. package/benchmarks/production-v2/suite.json +1009 -0
  84. package/benchmarks/production-v2/variant.mjs +169 -0
  85. package/benchmarks/production-v3/CONTRACT-REVISION-20260922.md +31 -0
  86. package/benchmarks/production-v3/calibration/corpus.v1.json +63 -0
  87. package/benchmarks/production-v3/calibration/human-review-rubric.v1.json +36 -0
  88. package/benchmarks/production-v3/grade.mjs +1017 -0
  89. package/benchmarks/production-v3/project/README.md +7 -0
  90. package/benchmarks/production-v3/project/config/service.json +4 -0
  91. package/benchmarks/production-v3/project/data/audit-ledger.jsonl +1 -0
  92. package/benchmarks/production-v3/project/docs/ops.md +3 -0
  93. package/benchmarks/production-v3/project/logs/incident.log +2 -0
  94. package/benchmarks/production-v3/project/package.json +11 -0
  95. package/benchmarks/production-v3/project/scripts/check.mjs +21 -0
  96. package/benchmarks/production-v3/project/src/backend/auth.js +3 -0
  97. package/benchmarks/production-v3/project/src/backend/billing-window.js +4 -0
  98. package/benchmarks/production-v3/project/src/backend/cache.js +15 -0
  99. package/benchmarks/production-v3/project/src/backend/invoice.js +4 -0
  100. package/benchmarks/production-v3/project/src/backend/revocation-cache.js +12 -0
  101. package/benchmarks/production-v3/project/src/data/csv.js +3 -0
  102. package/benchmarks/production-v3/project/src/data/dedup.js +5 -0
  103. package/benchmarks/production-v3/project/src/data/migration.js +9 -0
  104. package/benchmarks/production-v3/project/src/data/ndjson-stream.js +5 -0
  105. package/benchmarks/production-v3/project/src/data/versioned-replay.js +8 -0
  106. package/benchmarks/production-v3/project/src/frontend/chat-events.js +7 -0
  107. package/benchmarks/production-v3/project/src/frontend/pagination.js +8 -0
  108. package/benchmarks/production-v3/project/src/frontend/request-lifecycle.js +23 -0
  109. package/benchmarks/production-v3/project/src/frontend/search-state.js +8 -0
  110. package/benchmarks/production-v3/project/src/frontend/unicode-search.js +7 -0
  111. package/benchmarks/production-v3/project/src/fullstack/contract-sync.js +10 -0
  112. package/benchmarks/production-v3/project/src/platform/args.js +10 -0
  113. package/benchmarks/production-v3/project/src/platform/config.js +7 -0
  114. package/benchmarks/production-v3/project/src/platform/workflow-session.js +9 -0
  115. package/benchmarks/production-v3/project/src/platform/workspace.js +13 -0
  116. package/benchmarks/production-v3/project/src/reliability/checkpoint.js +5 -0
  117. package/benchmarks/production-v3/project/src/reliability/expiry.js +14 -0
  118. package/benchmarks/production-v3/project/src/reliability/retry.js +15 -0
  119. package/benchmarks/production-v3/project/test/smoke.test.js +21 -0
  120. package/benchmarks/production-v3/project/vendor/README.md +1 -0
  121. package/benchmarks/production-v3/prompts/abort-reconnect-supersession.md +11 -0
  122. package/benchmarks/production-v3/prompts/backend-frontend-contract-sync.md +20 -0
  123. package/benchmarks/production-v3/prompts/billing-cutoff-clock-skew.md +11 -0
  124. package/benchmarks/production-v3/prompts/bounded-retry.md +7 -0
  125. package/benchmarks/production-v3/prompts/chunked-record-boundary.md +11 -0
  126. package/benchmarks/production-v3/prompts/cli-double-dash.md +7 -0
  127. package/benchmarks/production-v3/prompts/config-precedence.md +6 -0
  128. package/benchmarks/production-v3/prompts/destructive-history-refusal.md +9 -0
  129. package/benchmarks/production-v3/prompts/expiry-boundary.md +14 -0
  130. package/benchmarks/production-v3/prompts/idempotent-replay-conflict.md +13 -0
  131. package/benchmarks/production-v3/prompts/incident-diagnosis.md +4 -0
  132. package/benchmarks/production-v3/prompts/invoice-rounding.md +9 -0
  133. package/benchmarks/production-v3/prompts/journeys/config-precedence-scout.md +3 -0
  134. package/benchmarks/production-v3/prompts/journeys/expiry-boundary-scout.md +3 -0
  135. package/benchmarks/production-v3/prompts/journeys/quoted-csv-scout.md +3 -0
  136. package/benchmarks/production-v3/prompts/journeys/recover-after-uncertain-send.md +4 -0
  137. package/benchmarks/production-v3/prompts/journeys/repository-prompt-injection-scout.md +4 -0
  138. package/benchmarks/production-v3/prompts/journeys/resumable-checkpoint-partial-failure-scout.md +4 -0
  139. package/benchmarks/production-v3/prompts/journeys/stable-dedup-scout.md +3 -0
  140. package/benchmarks/production-v3/prompts/journeys/stale-search-response-scout.md +3 -0
  141. package/benchmarks/production-v3/prompts/journeys/tenant-cache-isolation-scout.md +4 -0
  142. package/benchmarks/production-v3/prompts/journeys/verify-current-contract.md +4 -0
  143. package/benchmarks/production-v3/prompts/journeys/workflow-switch-same-session-scout.md +4 -0
  144. package/benchmarks/production-v3/prompts/pagination-boundary.md +9 -0
  145. package/benchmarks/production-v3/prompts/protected-env-refusal.md +8 -0
  146. package/benchmarks/production-v3/prompts/quoted-csv.md +6 -0
  147. package/benchmarks/production-v3/prompts/reconnect-chat-event-order.md +20 -0
  148. package/benchmarks/production-v3/prompts/repository-prompt-injection.md +5 -0
  149. package/benchmarks/production-v3/prompts/resumable-checkpoint-partial-failure.md +15 -0
  150. package/benchmarks/production-v3/prompts/revoked-session-cache.md +10 -0
  151. package/benchmarks/production-v3/prompts/schema-migration.md +6 -0
  152. package/benchmarks/production-v3/prompts/stable-dedup.md +6 -0
  153. package/benchmarks/production-v3/prompts/stale-search-response.md +6 -0
  154. package/benchmarks/production-v3/prompts/tenant-cache-isolation.md +6 -0
  155. package/benchmarks/production-v3/prompts/tenant-role-authorization.md +6 -0
  156. package/benchmarks/production-v3/prompts/unicode-search.md +6 -0
  157. package/benchmarks/production-v3/prompts/workflow-switch-same-session.md +30 -0
  158. package/benchmarks/production-v3/prompts/workspace-order.md +7 -0
  159. package/benchmarks/production-v3/public-checks/abort-reconnect-supersession.js +34 -0
  160. package/benchmarks/production-v3/public-checks/expiry-boundary.js +29 -0
  161. package/benchmarks/production-v3/public-checks/revoked-session-cache.js +20 -0
  162. package/benchmarks/production-v3/spend-control.v1.json +121 -0
  163. package/benchmarks/production-v3/suite.json +1010 -0
  164. package/benchmarks/production-v3/variant.mjs +178 -0
  165. package/catalog/capabilities.json +16 -16
  166. package/docs/authority-manifest.md +1 -1
  167. package/docs/auto-delegation-policy.md +38 -73
  168. package/docs/benchmark-codex-mcp-metadata-contract-v1.md +159 -0
  169. package/docs/benchmark-codex-mcp-metadata-contract-v2.md +182 -0
  170. package/docs/benchmark-codex-mcp-metadata-contract-v3.md +194 -0
  171. package/docs/benchmark-public-contract-addendum-v2.md +85 -0
  172. package/docs/benchmark-public-contract-addendum-v3.md +116 -0
  173. package/docs/command-reference-vietnamese.md +30 -35
  174. package/docs/context-engine.md +5 -3
  175. package/docs/context-window-policy.md +37 -1
  176. package/docs/distribution-standard.md +9 -9
  177. package/docs/en/architecture.md +26 -13
  178. package/docs/languages.json +4 -4
  179. package/docs/operator-manual-vietnamese.md +26 -46
  180. package/docs/piagent-codex-benchmark-recovery-plan.md +1817 -0
  181. package/docs/piagent-core-evaluation-specs-2026-09-06.json +706 -0
  182. package/docs/piagent-core-improvement-plan.md +528 -0
  183. package/docs/piagent-core-offline-implementation-2026-09-06.md +219 -0
  184. package/docs/piagent-core-plan-checkpoint-2026-09-06.json +69 -0
  185. package/docs/piagent-core-reasoning-research-2026-09-06.md +225 -0
  186. package/docs/piagent-core-research-sources-2026-09-06.json +416 -0
  187. package/docs/piagent-open-session-wait.md +19 -0
  188. package/docs/piagent-runtime-benchmark-execution-plan.md +685 -0
  189. package/docs/publishing-for-teams.md +7 -0
  190. package/docs/quality-benchmark.md +299 -23
  191. package/docs/quickstart-vietnamese.md +2 -2
  192. package/docs/release-install-policy.md +32 -9
  193. package/docs/research/harness-next-evidence-review.md +113 -0
  194. package/docs/runtime-harness-standard.md +3 -3
  195. package/docs/security-threat-model.md +1 -1
  196. package/docs/subagent-orchestration-capabilities.md +19 -51
  197. package/docs/subagents-and-multiagent.md +21 -47
  198. package/docs/task-implementation-contract.md +3 -3
  199. package/docs/task-lifecycle-vietnamese.md +1 -1
  200. package/docs/team-onboarding.md +7 -7
  201. package/docs/third-party-neutrality.md +7 -0
  202. package/docs/usage-observability.md +1 -1
  203. package/docs/vi/architecture.md +26 -13
  204. package/docs-site/architecture.html +1 -1
  205. package/docs-site/benchmark.html +89 -95
  206. package/docs-site/commands.html +1 -1
  207. package/docs-site/content/benchmark.html +88 -94
  208. package/docs-site/content/en/benchmark.html +134 -90
  209. package/docs-site/content/en/index.html +19 -19
  210. package/docs-site/content/en/runtime.html +5 -5
  211. package/docs-site/content/en/whats-new.html +23 -1
  212. package/docs-site/content/en/workflows.html +2 -2
  213. package/docs-site/content/index.html +19 -19
  214. package/docs-site/content/runtime.html +6 -6
  215. package/docs-site/content/whats-new.html +23 -1
  216. package/docs-site/content/workflows.html +2 -2
  217. package/docs-site/context-engine.html +1 -1
  218. package/docs-site/en/architecture.html +1 -1
  219. package/docs-site/en/benchmark.html +135 -91
  220. package/docs-site/en/commands.html +1 -1
  221. package/docs-site/en/context-engine.html +1 -1
  222. package/docs-site/en/index.html +20 -20
  223. package/docs-site/en/mcp-approval.html +1 -1
  224. package/docs-site/en/mcp-auth.html +1 -1
  225. package/docs-site/en/mcp-servers.html +1 -1
  226. package/docs-site/en/mcp.html +1 -1
  227. package/docs-site/en/permissions.html +1 -1
  228. package/docs-site/en/profiles.html +1 -1
  229. package/docs-site/en/quickstart.html +1 -1
  230. package/docs-site/en/runtime.html +6 -6
  231. package/docs-site/en/scope.html +1 -1
  232. package/docs-site/en/security.html +1 -1
  233. package/docs-site/en/team.html +1 -1
  234. package/docs-site/en/whats-new.html +24 -2
  235. package/docs-site/en/workflows.html +3 -3
  236. package/docs-site/index.html +20 -20
  237. package/docs-site/mcp-approval.html +1 -1
  238. package/docs-site/mcp-auth.html +1 -1
  239. package/docs-site/mcp-servers.html +1 -1
  240. package/docs-site/mcp.html +1 -1
  241. package/docs-site/permissions.html +1 -1
  242. package/docs-site/profiles.html +1 -1
  243. package/docs-site/quickstart.html +1 -1
  244. package/docs-site/runtime.html +7 -7
  245. package/docs-site/scope.html +1 -1
  246. package/docs-site/security.html +1 -1
  247. package/docs-site/team.html +1 -1
  248. package/docs-site/whats-new.html +24 -2
  249. package/docs-site/workflows.html +3 -3
  250. package/evals/architecture-conformance-v1/lane.json +18 -0
  251. package/evals/architecture-conformance-v1/runner.mjs +77 -0
  252. package/evals/fixtures/approved-host-contracts.invalid.json +43 -0
  253. package/evals/fixtures/approved-host-contracts.valid.json +43 -0
  254. package/evals/fixtures/benchmark-assurance-evidence.invalid.json +1 -1
  255. package/evals/fixtures/benchmark-assurance-evidence.valid.json +1 -1
  256. package/evals/fixtures/benchmark-attempt-outcome.invalid.json +42 -0
  257. package/evals/fixtures/benchmark-attempt-outcome.valid.json +42 -0
  258. package/evals/fixtures/benchmark-independent-verification-plan.invalid.json +7 -0
  259. package/evals/fixtures/benchmark-independent-verification-plan.valid.json +21 -0
  260. package/evals/fixtures/codex-relative-efficiency-v1.invalid.json +4 -0
  261. package/evals/fixtures/codex-relative-efficiency-v1.valid.json +94 -0
  262. package/evals/fixtures/composite-criterion.invalid.json +10 -0
  263. package/evals/fixtures/composite-criterion.valid.json +33 -0
  264. package/evals/fixtures/contract-family-library.invalid.json +42 -0
  265. package/evals/fixtures/contract-family-library.valid.json +41 -0
  266. package/evals/fixtures/contract-selection-recipe.invalid.json +29 -0
  267. package/evals/fixtures/contract-selection-recipe.valid.json +29 -0
  268. package/evals/fixtures/helper-request.invalid.json +1 -1
  269. package/evals/fixtures/helper-request.valid.json +1 -1
  270. package/evals/fixtures/host-contract-plan.invalid.json +42 -0
  271. package/evals/fixtures/host-contract-plan.valid.json +41 -0
  272. package/evals/fixtures/piagent-webui/subagent-tree-v1.valid.json +7 -0
  273. package/evals/fixtures/scoped-project-verification-receipt-v2.invalid.json +42 -0
  274. package/evals/fixtures/scoped-project-verification-receipt-v2.valid.json +42 -0
  275. package/evals/fixtures/scoped-project-verification-receipt-v3.invalid.json +57 -0
  276. package/evals/fixtures/scoped-project-verification-receipt-v3.valid.json +57 -0
  277. package/evals/fixtures/scoped-verification-receipt-v1.invalid.json +40 -0
  278. package/evals/fixtures/scoped-verification-receipt-v1.valid.json +40 -0
  279. package/evals/fixtures/task-authority-snapshot.valid.json +4 -4
  280. package/evals/fs4-readiness-matrix.v1.json +2 -2
  281. package/evals/fs5-artifact-archive/README.md +32 -0
  282. package/evals/fs5-artifact-archive/manifest.json +148 -0
  283. package/evals/fs5-artifact-archive/sha256/1f073f6d42c093a3182685e0e096144c8b3befd87594aeea1af05ce17653860c.txt +380 -0
  284. package/evals/fs5-artifact-archive/sha256/1ff46984c5ff668647dfad94248cd9dcfb72384a8aa529279345582f90d7486a.txt +331 -0
  285. package/evals/fs5-artifact-archive/sha256/20a5e1ef1cab3234a888b876b3cec52e702a05bc5ac000b691f94c651beed9ca.txt +800 -0
  286. package/evals/fs5-artifact-archive/sha256/29bb79e96b047d79056626d747baa0b3a6ca9d4da7ad80b9668c0085e5581706.txt +116 -0
  287. package/evals/fs5-artifact-archive/sha256/2bcc0cf6c18eee0c080c30e727610b0f10a278f5862855d920ba5797f07a2f2d.txt +252 -0
  288. package/evals/fs5-artifact-archive/sha256/37ecc65febe2c5947ac9288ad958bc149e0f08c6beda137edb1c660908853832.txt +324 -0
  289. package/evals/fs5-artifact-archive/sha256/5d937632d2cfff34dbbb781dd367bb78feb64c36d571c36ca15f2cc40c576af8.txt +142 -0
  290. package/evals/fs5-artifact-archive/sha256/6057c7bf2f40f8e3db7e293f08d745133c05293b75e9f363fb4e2e53bd09a76a.txt +244 -0
  291. package/evals/fs5-artifact-archive/sha256/62ea354afb6816b148ae9bd95ffb1ee5e29580eb4a22473e1ae19dbb471ec36b.txt +930 -0
  292. package/evals/fs5-artifact-archive/sha256/8987775b742f3b3650d75cce84e6d58fcdd3dfb835d03dac4c2bfe6d9eea3a2e.txt +903 -0
  293. package/evals/fs5-artifact-archive/sha256/902e886d0920b66811f54d0d1d933d70f8fab8704813b46d578bee6af1f21eef.txt +942 -0
  294. package/evals/fs5-artifact-archive/sha256/976a9908adfd765ee7be0655616f39a44fff64824f5e8535d726082e550b02eb.txt +910 -0
  295. package/evals/fs5-artifact-archive/sha256/9c07bda5bfe7bb7b0959844ccea6790735cc9f154d8d5972e18785148cea6d9a.txt +101 -0
  296. package/evals/fs5-artifact-archive/sha256/b936a604db87a697bf69581c33d753e26d9e5e2ccce40bf9c9b2070948f49919.txt +931 -0
  297. package/evals/fs5-artifact-archive/sha256/bf91f69473f48fc3de7c7c55e7ce893ba0511074c4ec930d9f3bcb9615d8e9d5.txt +950 -0
  298. package/evals/fs5-artifact-archive/sha256/ce4ed1b4a033f2a8cb4632d1336b0867edb3454ce1380f0642c4055149e6ac59.txt +784 -0
  299. package/evals/fs5-artifact-archive/sha256/db97f444db8ba604512daf0aa26b3fe1e2a120ace2b21d4730db5b18aa0c528f.txt +950 -0
  300. package/evals/fs5-causal-arm.v1.json +10 -6
  301. package/evals/fs5-pilot-protocol.v1.json +3 -3
  302. package/evals/fs5-pilot-protocol.v2.json +8 -8
  303. package/evals/fs5-pilot-protocol.v3.json +8 -8
  304. package/evals/fs5-pilot-protocol.v4.json +7 -7
  305. package/evals/fs5-pilot-protocol.v5.json +10 -8
  306. package/evals/harness-next/development-corpus.mjs +106 -0
  307. package/evals/harness-next/resource-budget-probe.mjs +38 -0
  308. package/evals/harness-next/run-calibration.mjs +83 -0
  309. package/evals/harness-next/run-resource-probe.mjs +55 -0
  310. package/evals/harness-next/selected-development-corpus.mjs +27 -0
  311. package/evals/harness-next.v1.json +51 -0
  312. package/evals/long-horizon-v1/README.md +19 -0
  313. package/evals/long-horizon-v1/runner.mjs +116 -48
  314. package/evals/long-horizon-v1/worker.mjs +77 -30
  315. package/evals/private-holdout-v1/CURRENT_BOUNDARY.md +53 -0
  316. package/evals/private-holdout-v1/README.md +5 -2
  317. package/evals/private-holdout-v1/public-exposure.v1.json +1 -1
  318. package/evals/private-holdout-v1/public-exposure.v2.json +273 -0
  319. package/evals/runtime-conformance-v1/README.md +43 -0
  320. package/evals/runtime-conformance-v1/evaluate-paid-canary.mjs +198 -0
  321. package/evals/runtime-conformance-v1/lane.json +57 -0
  322. package/evals/runtime-conformance-v1/paid-canary.json +31 -0
  323. package/evals/runtime-conformance-v1/runner.mjs +456 -0
  324. package/package.json +9 -4
  325. package/packages/piagent-core/README.md +15 -6
  326. package/packages/piagent-core/benchmark/benchmark-all-attempt-efficiency.js +55 -0
  327. package/packages/piagent-core/benchmark/benchmark-artifact-binding.js +49 -0
  328. package/packages/piagent-core/benchmark/benchmark-bootstrap.js +265 -14
  329. package/packages/piagent-core/benchmark/benchmark-budget-governor.js +271 -0
  330. package/packages/piagent-core/benchmark/benchmark-campaign.js +592 -0
  331. package/packages/piagent-core/benchmark/benchmark-candidate.js +8 -3
  332. package/packages/piagent-core/benchmark/benchmark-checkpoint.js +67 -0
  333. package/packages/piagent-core/benchmark/benchmark-claim-restrictions.js +269 -2
  334. package/packages/piagent-core/benchmark/benchmark-cli.js +120 -3
  335. package/packages/piagent-core/benchmark/benchmark-codex-events.js +235 -0
  336. package/packages/piagent-core/benchmark/benchmark-codex-outcome.js +20 -0
  337. package/packages/piagent-core/benchmark/benchmark-codex-relative-efficiency.js +699 -0
  338. package/packages/piagent-core/benchmark/benchmark-codex-rollout.js +521 -0
  339. package/packages/piagent-core/benchmark/benchmark-codex.js +104 -8
  340. package/packages/piagent-core/benchmark/benchmark-comparison.js +284 -1
  341. package/packages/piagent-core/benchmark/benchmark-core.js +111 -110
  342. package/packages/piagent-core/benchmark/benchmark-diagnostic-source-evidence.js +40 -0
  343. package/packages/piagent-core/benchmark/benchmark-diagnostic-treatment.js +104 -0
  344. package/packages/piagent-core/benchmark/benchmark-evaluator-v3.js +226 -0
  345. package/packages/piagent-core/benchmark/benchmark-execution-guard.js +23 -1
  346. package/packages/piagent-core/benchmark/benchmark-forensics.js +67 -52
  347. package/packages/piagent-core/benchmark/benchmark-goal-assessment.js +193 -0
  348. package/packages/piagent-core/benchmark/benchmark-goal-report.js +87 -0
  349. package/packages/piagent-core/benchmark/benchmark-independent-verification-observation.js +64 -0
  350. package/packages/piagent-core/benchmark/benchmark-matrix-summary.js +141 -0
  351. package/packages/piagent-core/benchmark/benchmark-matrix.js +1 -0
  352. package/packages/piagent-core/benchmark/benchmark-normalized-cost.js +62 -0
  353. package/packages/piagent-core/benchmark/benchmark-pi-home.js +1 -0
  354. package/packages/piagent-core/benchmark/benchmark-preflight.js +70 -7
  355. package/packages/piagent-core/benchmark/benchmark-process.js +23 -9
  356. package/packages/piagent-core/benchmark/benchmark-production-completion.js +84 -0
  357. package/packages/piagent-core/benchmark/benchmark-production-stage-validation.js +209 -0
  358. package/packages/piagent-core/benchmark/benchmark-provider-free-evidence.js +462 -0
  359. package/packages/piagent-core/benchmark/benchmark-provider-free-owner.js +24 -0
  360. package/packages/piagent-core/benchmark/benchmark-provider-wire.js +378 -0
  361. package/packages/piagent-core/benchmark/benchmark-record-validation.d.ts +2 -0
  362. package/packages/piagent-core/benchmark/benchmark-record-validation.js +343 -8
  363. package/packages/piagent-core/benchmark/benchmark-release-claim-controls.js +132 -0
  364. package/packages/piagent-core/benchmark/benchmark-report.js +94 -5
  365. package/packages/piagent-core/benchmark/benchmark-resume-recovery.js +280 -10
  366. package/packages/piagent-core/benchmark/benchmark-runner-policy.js +88 -1
  367. package/packages/piagent-core/benchmark/benchmark-runtime-causal.js +244 -0
  368. package/packages/piagent-core/benchmark/benchmark-runtime-identity.js +50 -1
  369. package/packages/piagent-core/benchmark/benchmark-runtime.js +102 -10
  370. package/packages/piagent-core/benchmark/benchmark-safety-evidence.js +74 -0
  371. package/packages/piagent-core/benchmark/benchmark-service-tier.js +189 -0
  372. package/packages/piagent-core/benchmark/benchmark-stage-diagnostic.js +246 -33
  373. package/packages/piagent-core/benchmark/benchmark-suite-identity.js +264 -1
  374. package/packages/piagent-core/benchmark/benchmark-suite-runtime.js +4 -0
  375. package/packages/piagent-core/benchmark/benchmark-suite.js +232 -4
  376. package/packages/piagent-core/benchmark/benchmark-summary-support.js +33 -1
  377. package/packages/piagent-core/benchmark/benchmark-timing-contract.js +189 -0
  378. package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +110 -139
  379. package/packages/piagent-core/benchmark/benchmark-transport-evidence.js +203 -0
  380. package/packages/piagent-core/benchmark/benchmark-transport-observation.js +147 -0
  381. package/packages/piagent-core/benchmark/benchmark-tree-identity.js +2 -1
  382. package/packages/piagent-core/benchmark/benchmark-usage.js +410 -37
  383. package/packages/piagent-core/benchmark/benchmark-workflow.js +136 -38
  384. package/packages/piagent-core/benchmark/fs5-pilot-protocol.js +21 -2
  385. package/packages/piagent-core/capabilities/runtime-integrity.js +6 -0
  386. package/packages/piagent-core/extensions/acceptance-api-baseline.js +24 -0
  387. package/packages/piagent-core/extensions/acceptance-assessment.js +153 -0
  388. package/packages/piagent-core/extensions/acceptance-authenticated-admission.d.ts +41 -0
  389. package/packages/piagent-core/extensions/acceptance-authenticated-admission.js +120 -0
  390. package/packages/piagent-core/extensions/acceptance-behavior-proof.js +1000 -0
  391. package/packages/piagent-core/extensions/acceptance-boundary-binding.js +31 -0
  392. package/packages/piagent-core/extensions/acceptance-boundary-guidance.js +214 -0
  393. package/packages/piagent-core/extensions/acceptance-callable-scanner.js +244 -0
  394. package/packages/piagent-core/extensions/acceptance-clause-group.js +45 -0
  395. package/packages/piagent-core/extensions/acceptance-composite-contract.js +334 -0
  396. package/packages/piagent-core/extensions/acceptance-contract-conjunction.js +78 -0
  397. package/packages/piagent-core/extensions/acceptance-contract-selection.js +161 -0
  398. package/packages/piagent-core/extensions/acceptance-contract-semantics.js +211 -211
  399. package/packages/piagent-core/extensions/acceptance-declared-api.js +126 -0
  400. package/packages/piagent-core/extensions/acceptance-diagnostic-policy.ts +14 -0
  401. package/packages/piagent-core/extensions/acceptance-document-content.js +73 -0
  402. package/packages/piagent-core/extensions/acceptance-durable-execution.d.ts +59 -0
  403. package/packages/piagent-core/extensions/acceptance-durable-execution.js +139 -0
  404. package/packages/piagent-core/extensions/acceptance-error-classes.js +1 -1
  405. package/packages/piagent-core/extensions/acceptance-evidence-store.js +223 -0
  406. package/packages/piagent-core/extensions/acceptance-executable-evidence.js +490 -88
  407. package/packages/piagent-core/extensions/acceptance-execution-diagnostics.js +34 -0
  408. package/packages/piagent-core/extensions/acceptance-execution-snapshot.js +174 -0
  409. package/packages/piagent-core/extensions/acceptance-executor/.dockerignore +21 -0
  410. package/packages/piagent-core/extensions/acceptance-executor/Dockerfile +5 -0
  411. package/packages/piagent-core/extensions/acceptance-executor/README.md +103 -0
  412. package/packages/piagent-core/extensions/acceptance-executor/budget.mjs +54 -0
  413. package/packages/piagent-core/extensions/acceptance-executor/callback-intrinsics.mjs +126 -0
  414. package/packages/piagent-core/extensions/acceptance-executor/capabilities.mjs +127 -0
  415. package/packages/piagent-core/extensions/acceptance-executor/guest.mjs +285 -0
  416. package/packages/piagent-core/extensions/acceptance-executor/intrinsics.mjs +133 -0
  417. package/packages/piagent-core/extensions/acceptance-executor/invocation.mjs +39 -0
  418. package/packages/piagent-core/extensions/acceptance-executor/jobs.mjs +29 -0
  419. package/packages/piagent-core/extensions/acceptance-executor/module-graph.mjs +70 -0
  420. package/packages/piagent-core/extensions/acceptance-executor/node-profile.mjs +398 -0
  421. package/packages/piagent-core/extensions/acceptance-executor/package-lock.json +40 -0
  422. package/packages/piagent-core/extensions/acceptance-executor/package.json +10 -0
  423. package/packages/piagent-core/extensions/acceptance-executor/protocol.mjs +248 -0
  424. package/packages/piagent-core/extensions/acceptance-executor/reference-identity.mjs +61 -0
  425. package/packages/piagent-core/extensions/acceptance-executor/references.mjs +14 -0
  426. package/packages/piagent-core/extensions/acceptance-executor/structured-clone.mjs +53 -0
  427. package/packages/piagent-core/extensions/acceptance-executor/values.mjs +97 -0
  428. package/packages/piagent-core/extensions/acceptance-executor/worker.mjs +75 -0
  429. package/packages/piagent-core/extensions/acceptance-expiry-calendar-proof.js +162 -0
  430. package/packages/piagent-core/extensions/acceptance-expression-parser.js +155 -0
  431. package/packages/piagent-core/extensions/acceptance-focused-verification.js +40 -0
  432. package/packages/piagent-core/extensions/acceptance-host-configuration.js +337 -0
  433. package/packages/piagent-core/extensions/acceptance-identifier-criteria.js +25 -0
  434. package/packages/piagent-core/extensions/acceptance-independent-contract.js +209 -0
  435. package/packages/piagent-core/extensions/acceptance-independent-registry.js +106 -0
  436. package/packages/piagent-core/extensions/acceptance-input-provenance.js +40 -0
  437. package/packages/piagent-core/extensions/acceptance-integer-domains.js +322 -0
  438. package/packages/piagent-core/extensions/acceptance-invalid-input-receipt.js +20 -0
  439. package/packages/piagent-core/extensions/acceptance-invalid-partitions.js +26 -0
  440. package/packages/piagent-core/extensions/acceptance-invalid-sentinel-proof.js +477 -0
  441. package/packages/piagent-core/extensions/acceptance-isolated-executor.js +254 -0
  442. package/packages/piagent-core/extensions/acceptance-lexical-sentinels.js +130 -0
  443. package/packages/piagent-core/extensions/acceptance-literal-dataflow.js +735 -0
  444. package/packages/piagent-core/extensions/acceptance-local-binding.js +106 -0
  445. package/packages/piagent-core/extensions/acceptance-normalizer-evidence.js +719 -0
  446. package/packages/piagent-core/extensions/acceptance-obligations.js +75 -0
  447. package/packages/piagent-core/extensions/acceptance-parameter-contract.js +756 -0
  448. package/packages/piagent-core/extensions/acceptance-precedence-contract.js +572 -0
  449. package/packages/piagent-core/extensions/acceptance-proof-capability.js +26 -0
  450. package/packages/piagent-core/extensions/acceptance-receipt.js +208 -180
  451. package/packages/piagent-core/extensions/acceptance-result-contract-evidence.js +159 -0
  452. package/packages/piagent-core/extensions/acceptance-source-origin.js +214 -0
  453. package/packages/piagent-core/extensions/acceptance-state-machine-evidence.js +64 -8
  454. package/packages/piagent-core/extensions/acceptance-tagged-event-evidence.js +685 -0
  455. package/packages/piagent-core/extensions/acceptance-temporal-contract.js +756 -0
  456. package/packages/piagent-core/extensions/acceptance-temporal-dataflow-proof.js +618 -0
  457. package/packages/piagent-core/extensions/acceptance-test-binding-evidence.js +20 -2
  458. package/packages/piagent-core/extensions/acceptance-test-bindings.js +86 -0
  459. package/packages/piagent-core/extensions/acceptance-tuple-shapes.js +12 -0
  460. package/packages/piagent-core/extensions/context-engine.js +12 -17
  461. package/packages/piagent-core/extensions/context-index-policy.js +4 -0
  462. package/packages/piagent-core/extensions/context-query-paths.js +57 -0
  463. package/packages/piagent-core/extensions/criterion-context-pack.js +109 -4
  464. package/packages/piagent-core/extensions/criterion-graph.js +4 -1
  465. package/packages/piagent-core/extensions/failure-types.ts +2 -2
  466. package/packages/piagent-core/extensions/fallback-base-policy.ts +101 -0
  467. package/packages/piagent-core/extensions/guard-types.ts +9 -1
  468. package/packages/piagent-core/extensions/piagent-guard.ts +374 -364
  469. package/packages/piagent-core/extensions/readonly-inline-inspection.ts +378 -0
  470. package/packages/piagent-core/extensions/recovery-decision-validation.ts +92 -0
  471. package/packages/piagent-core/extensions/shell-write-targets.js +15 -14
  472. package/packages/piagent-core/extensions/task-contract-view.js +4 -4
  473. package/packages/piagent-core/extensions/task-digest-migration.js +2 -2
  474. package/packages/piagent-core/extensions/task-journal.js +48 -3
  475. package/packages/piagent-core/extensions/task-lifecycle.js +32 -0
  476. package/packages/piagent-core/extensions/task-runtime-audit.js +8 -2
  477. package/packages/piagent-core/extensions/task-state.js +140 -43
  478. package/packages/piagent-core/extensions/task-terminal-disposition.js +10 -0
  479. package/packages/piagent-core/extensions/trajectory-contract.ts +5 -0
  480. package/packages/piagent-core/extensions/verification-intelligence.js +109 -20
  481. package/packages/piagent-core/extensions/workflow-catalog.ts +98 -0
  482. package/packages/piagent-core/extensions/workspace-evidence-roots.js +52 -16
  483. package/packages/piagent-core/extensions/workspace-revision.js +48 -0
  484. package/packages/piagent-core/extensions/workspace-verification-snapshot.js +13 -0
  485. package/packages/piagent-core/package.json +3 -3
  486. package/packages/piagent-core/policies/base-policy.json +43 -2
  487. package/packages/piagent-core/policy/authority-manifest.v1.json +3 -3
  488. package/packages/piagent-core/prompts/be-to-fe.md +2 -8
  489. package/packages/piagent-core/prompts/plan.md +1 -1
  490. package/packages/piagent-core/prompts/platform-improve.md +2 -6
  491. package/packages/piagent-core/prompts/review.md +2 -7
  492. package/packages/piagent-core/prompts/scout.md +1 -1
  493. package/packages/piagent-core/prompts/task.md +4 -3
  494. package/packages/piagent-core/runtime/context/adaptive-planner.ts +7 -3
  495. package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +60 -59
  496. package/packages/piagent-core/runtime/hooks/agent-start-types.ts +48 -0
  497. package/packages/piagent-core/runtime/hooks/completion-hook.ts +83 -89
  498. package/packages/piagent-core/runtime/hooks/input-hook.ts +98 -7
  499. package/packages/piagent-core/runtime/hooks/protected-refusal-completion.ts +86 -0
  500. package/packages/piagent-core/runtime/hooks/session-hooks.ts +5 -2
  501. package/packages/piagent-core/runtime/hooks/session-start-hook.ts +150 -19
  502. package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +111 -92
  503. package/packages/piagent-core/runtime/hooks/tool-result-metadata.ts +9 -0
  504. package/packages/piagent-core/runtime/hooks/tool-result-navigation.ts +36 -0
  505. package/packages/piagent-core/runtime/hooks/tool-result-retrieval.ts +42 -0
  506. package/packages/piagent-core/runtime/hooks/tool-result-value-helpers.ts +66 -0
  507. package/packages/piagent-core/runtime/input/chat-images.ts +1 -1
  508. package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +1 -1
  509. package/packages/piagent-core/runtime/inspection/bounded-emission-guard.ts +286 -0
  510. package/packages/piagent-core/runtime/inspection/runtime-event-store.ts +37 -7
  511. package/packages/piagent-core/runtime/inspection/same-process-bridge-proof.ts +1 -1
  512. package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +2 -2
  513. package/packages/piagent-core/runtime/inspection/task-subagent-tree.ts +27 -4
  514. package/packages/piagent-core/runtime/inspection/tool-failure-classification.ts +69 -11
  515. package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +104 -22
  516. package/packages/piagent-core/runtime/inspection/workspace-file-reader.ts +2 -132
  517. package/packages/piagent-core/runtime/model/provider-wire-fingerprint.ts +20 -0
  518. package/packages/piagent-core/runtime/model/service-tier-runtime.ts +242 -0
  519. package/packages/piagent-core/runtime/orchestration/helper-lifecycle.ts +16 -12
  520. package/packages/piagent-core/runtime/orchestration/minimal-delegation-policy.ts +71 -0
  521. package/packages/piagent-core/runtime/orchestration/owned-work-budget.ts +28 -20
  522. package/packages/piagent-core/runtime/orchestration/role-policy.ts +27 -9
  523. package/packages/piagent-core/runtime/orchestration/subagent-tool-policy.ts +329 -0
  524. package/packages/piagent-core/runtime/policy/block-remedy.ts +0 -4
  525. package/packages/piagent-core/runtime/policy/source-worktree-transaction.ts +75 -14
  526. package/packages/piagent-core/runtime/product/activity-inspector.ts +6 -3
  527. package/packages/piagent-core/runtime/product/edit-verifier-timing.ts +26 -0
  528. package/packages/piagent-core/runtime/product/efficiency-metrics.ts +15 -7
  529. package/packages/piagent-core/runtime/product/operator-projections.ts +8 -3
  530. package/packages/piagent-core/runtime/product/task-usage-hooks.ts +78 -0
  531. package/packages/piagent-core/runtime/product/task-usage.ts +104 -0
  532. package/packages/piagent-core/runtime/quality/edit-freshness-guard.ts +102 -0
  533. package/packages/piagent-core/runtime/quality/exact-output-contract.ts +20 -10
  534. package/packages/piagent-core/runtime/quality/performance-assurance.ts +3 -3
  535. package/packages/piagent-core/runtime/quality/protected-refusal-handoff.ts +35 -0
  536. package/packages/piagent-core/runtime/recovery/acceptance-recovery-guidance.ts +21 -0
  537. package/packages/piagent-core/runtime/recovery/continuation-budget.ts +12 -3
  538. package/packages/piagent-core/runtime/recovery/diagnostic-delivery.ts +61 -0
  539. package/packages/piagent-core/runtime/recovery/handoff-projection.ts +196 -58
  540. package/packages/piagent-core/runtime/recovery/handoff-verifier-binding.ts +24 -0
  541. package/packages/piagent-core/runtime/recovery/independent-verification-recovery.ts +79 -0
  542. package/packages/piagent-core/runtime/recovery/pristine-task-policy-refresh.ts +91 -0
  543. package/packages/piagent-core/runtime/recovery/recovery-policy.ts +31 -40
  544. package/packages/piagent-core/runtime/recovery/resume-state.ts +120 -19
  545. package/packages/piagent-core/runtime/recovery/semantic-repair-handshake.ts +7 -13
  546. package/packages/piagent-core/runtime/recovery/task-evidence-coverage-refresh.ts +217 -0
  547. package/packages/piagent-core/runtime/registration/activity-inspector-command.ts +2 -1
  548. package/packages/piagent-core/runtime/registration/context-commands.ts +28 -10
  549. package/packages/piagent-core/runtime/registration/knowledge-tools.ts +9 -5
  550. package/packages/piagent-core/runtime/registration/operator-catalogs.ts +4 -9
  551. package/packages/piagent-core/runtime/registration/operator-request-intake.ts +49 -0
  552. package/packages/piagent-core/runtime/registration/policy-tools.ts +8 -6
  553. package/packages/piagent-core/runtime/registration/session-commands.ts +10 -8
  554. package/packages/piagent-core/runtime/registration/session-wait-tool.ts +54 -0
  555. package/packages/piagent-core/runtime/registration/task-completion-tools.ts +39 -20
  556. package/packages/piagent-core/runtime/registration/task-evidence-tools.ts +21 -12
  557. package/packages/piagent-core/runtime/registration/task-start-conditional-mutation.ts +45 -0
  558. package/packages/piagent-core/runtime/registration/task-start-guidance.ts +24 -15
  559. package/packages/piagent-core/runtime/registration/task-start-manifest.ts +54 -0
  560. package/packages/piagent-core/runtime/registration/task-start-tool.ts +79 -79
  561. package/packages/piagent-core/runtime/registration/workflow-commands.ts +64 -93
  562. package/packages/piagent-core/runtime/runtime-limits.ts +16 -2
  563. package/packages/piagent-core/runtime/session/adaptive-context-analysis.ts +461 -0
  564. package/packages/piagent-core/runtime/session/adaptive-context-governor.ts +464 -0
  565. package/packages/piagent-core/runtime/session/adaptive-context-ledger.ts +265 -0
  566. package/packages/piagent-core/runtime/session/completion-signals.ts +23 -0
  567. package/packages/piagent-core/runtime/session/message-signals.ts +6 -18
  568. package/packages/piagent-core/runtime/session/operator-request-carry.ts +44 -0
  569. package/packages/piagent-core/runtime/session/retrieval-evidence-runtime.ts +188 -0
  570. package/packages/piagent-core/runtime/session/runtime-state.ts +37 -39
  571. package/packages/piagent-core/runtime/session/source-checkout-read-grants.ts +35 -0
  572. package/packages/piagent-core/runtime/session/system-prompt.ts +76 -14
  573. package/packages/piagent-core/runtime/session/task-contract-presentation.ts +39 -0
  574. package/packages/piagent-core/runtime/session/uncertain-send-continuation.ts +231 -0
  575. package/packages/piagent-core/runtime/session/usage.ts +4 -3
  576. package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +6 -6
  577. package/packages/piagent-core/runtime/tools/phase-tool-runtime.ts +1 -1
  578. package/packages/piagent-core/runtime/tools/phase-tools.ts +10 -9
  579. package/packages/piagent-core/runtime/tools/session-wait.ts +42 -0
  580. package/packages/piagent-core/runtime/tools/tool-groups.ts +22 -5
  581. package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +192 -5
  582. package/packages/piagent-core/runtime/trajectory/trajectory-types.ts +3 -2
  583. package/packages/piagent-core/runtime/verification/acceptance-api-baseline.js +488 -0
  584. package/packages/piagent-core/runtime/verification/completion-preparation.ts +22 -0
  585. package/packages/piagent-core/runtime/verification/composite-completion-finalizer.ts +105 -0
  586. package/packages/piagent-core/runtime/verification/composite-journal-anchor.ts +181 -0
  587. package/packages/piagent-core/runtime/verification/composite-runtime-binding.ts +76 -0
  588. package/packages/piagent-core/runtime/verification/composite-scoped-mediation.ts +318 -0
  589. package/packages/piagent-core/runtime/verification/composite-session-persistence.ts +175 -0
  590. package/packages/piagent-core/runtime/verification/composite-task-publication.ts +273 -0
  591. package/packages/piagent-core/runtime/verification/exact-verifier-reuse.ts +101 -0
  592. package/packages/piagent-core/runtime/verification/host-project-verification.ts +71 -0
  593. package/packages/piagent-core/runtime/verification/independent-acceptance-runtime.ts +500 -0
  594. package/packages/piagent-core/runtime/verification/runtime-assurance-facts.ts +500 -0
  595. package/packages/piagent-core/runtime/verification/runtime-contract-runner.ts +107 -0
  596. package/packages/piagent-core/runtime/verification/shell-verification-snapshots.ts +56 -0
  597. package/packages/piagent-core/runtime/workflows/change-clarification.ts +61 -0
  598. package/packages/piagent-core/runtime/workflows/input-routing.ts +21 -14
  599. package/packages/piagent-core/runtime/workflows/runtime-intake-compaction.ts +201 -0
  600. package/packages/piagent-core/runtime/workflows/task-followup-policy.ts +163 -0
  601. package/packages/piagent-core/runtime/workflows/task-intake.ts +276 -169
  602. package/packages/piagent-core/runtime/workflows/task-repair-intent.ts +67 -0
  603. package/packages/piagent-core/runtime/workflows/task-scope-resolution.ts +83 -0
  604. package/packages/piagent-core/runtime/workflows/webui-runtime-command.ts +5 -2
  605. package/packages/piagent-core/runtime/workflows/webui-workflow.ts +39 -32
  606. package/packages/piagent-core/runtime/workflows/workflow-follow-up.ts +33 -0
  607. package/packages/piagent-core/security/workspace-file-reader.ts +132 -0
  608. package/packages/piagent-core/subagents/piagent-oracle.md +5 -3
  609. package/packages/piagent-core/subagents/piagent-planner.md +6 -4
  610. package/packages/piagent-core/subagents/piagent-reviewer.md +5 -3
  611. package/packages/piagent-core/subagents/piagent-scout.md +4 -2
  612. package/packages/piagent-core/subagents/piagent-worker.md +6 -4
  613. package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-CxeZqTte.js → MarkdownMessage-DGk34zJT.js} +1 -1
  614. package/packages/piagent-webui/dist/client/assets/{index-BV-_03yl.css → index-DVahUVWy.css} +1 -1
  615. package/packages/piagent-webui/dist/client/assets/index-DiKRmCEP.js +176 -0
  616. package/packages/piagent-webui/dist/client/index.html +2 -2
  617. package/packages/piagent-webui/extension/dispatch-user-entry.ts +13 -0
  618. package/packages/piagent-webui/extension/piagent-webui.ts +13 -3
  619. package/packages/piagent-webui/extension/review-controller.ts +29 -6
  620. package/packages/piagent-webui/extension/same-session-bridge.ts +7 -8
  621. package/packages/piagent-webui/extension/session-stream-adapter.ts +88 -16
  622. package/packages/piagent-webui/extension/source-mutation-controller.ts +29 -3
  623. package/packages/piagent-webui/extension/source-open-controller.ts +29 -7
  624. package/packages/piagent-webui/extension/source-revert-controller.ts +26 -3
  625. package/packages/piagent-webui/gateway/gateway-events.ts +22 -5
  626. package/packages/piagent-webui/gateway/gateway-service.ts +7 -2
  627. package/packages/piagent-webui/gateway/gateway-session-stream.ts +170 -32
  628. package/packages/piagent-webui/gateway/rpc-ui-context.ts +34 -9
  629. package/packages/piagent-webui/gateway/runtime-command-controller.ts +46 -6
  630. package/packages/piagent-webui/gateway/runtime-session-controls.ts +17 -2
  631. package/packages/piagent-webui/gateway/session-catalog.ts +9 -3
  632. package/packages/piagent-webui/gateway/session-command-controller.ts +29 -9
  633. package/packages/piagent-webui/gateway/session-effective-options.ts +2 -9
  634. package/packages/piagent-webui/gateway/session-inspection-registry.ts +11 -2
  635. package/packages/piagent-webui/gateway/session-operation-lifecycle.ts +237 -0
  636. package/packages/piagent-webui/gateway/session-operation-retry-control.ts +38 -0
  637. package/packages/piagent-webui/gateway/session-operation-settlement.ts +28 -0
  638. package/packages/piagent-webui/gateway/session-operation-watchdog.ts +9 -2
  639. package/packages/piagent-webui/gateway/session-prompt-dispatch.ts +37 -0
  640. package/packages/piagent-webui/gateway/session-runtime-close.ts +36 -0
  641. package/packages/piagent-webui/gateway/session-runtime-factory.ts +183 -6
  642. package/packages/piagent-webui/gateway/session-runtime-ownership.ts +48 -0
  643. package/packages/piagent-webui/gateway/session-runtime-state.ts +24 -0
  644. package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +118 -117
  645. package/packages/piagent-webui/ownership/session-lease-store.ts +5 -2
  646. package/packages/piagent-webui/server/core-inspection-provider.ts +75 -15
  647. package/packages/piagent-webui/server/loopback-server.ts +9 -7
  648. package/packages/piagent-webui/server/terminal-delivery-receipt.ts +144 -0
  649. package/packages/piagent-webui/server/transcript-projection.ts +150 -11
  650. package/packages/piagent-webui/shared/message-correlation.ts +25 -0
  651. package/schemas/approved-host-contracts.schema.json +973 -0
  652. package/schemas/benchmark-attempt-outcome.schema.json +303 -0
  653. package/schemas/benchmark-independent-verification-plan.schema.json +34 -0
  654. package/schemas/codex-relative-efficiency-v1.schema.json +155 -0
  655. package/schemas/composite-criterion.schema.json +788 -0
  656. package/schemas/contract-family-library.schema.json +28 -0
  657. package/schemas/contract-selection-recipe.schema.json +31 -0
  658. package/schemas/failure-evidence.schema.json +2 -2
  659. package/schemas/helper-request.schema.json +16 -4
  660. package/schemas/host-contract-plan.schema.json +25 -0
  661. package/schemas/piagent-webui/gateway-protocol-v1.schema.json +16 -2
  662. package/schemas/piagent-webui/runtime-command-v1.schema.json +26 -3
  663. package/schemas/piagent-webui/runtime-event-v2.schema.json +46 -5
  664. package/schemas/piagent-webui/session-live-state-v1.schema.json +2 -0
  665. package/schemas/piagent-webui/snapshot-v1.schema.json +3 -0
  666. package/schemas/piagent-webui/source-change-v1.schema.json +12 -0
  667. package/schemas/piagent-webui/subagent-tree-v1.schema.json +11 -1
  668. package/schemas/piagent-webui/transcript-v1.schema.json +2 -1
  669. package/schemas/project-profile.schema.json +1 -1
  670. package/schemas/public-contracts/codex-mcp-metadata-v1.schema.json +206 -0
  671. package/schemas/public-contracts/codex-mcp-metadata-v2.schema.json +228 -0
  672. package/schemas/public-contracts/codex-mcp-metadata-v3.schema.json +233 -0
  673. package/schemas/public-contracts/revocation-v1.schema.json +87 -0
  674. package/schemas/public-contracts/subscription-contract-v1.schema.json +76 -0
  675. package/schemas/scoped-project-verification-receipt-v2.schema.json +83 -0
  676. package/schemas/scoped-project-verification-receipt-v3.schema.json +295 -0
  677. package/schemas/scoped-verification-receipt-v1.schema.json +76 -0
  678. package/schemas/task-contract.schema.json +45 -0
  679. package/scripts/approve-independent-verification.mjs +57 -0
  680. package/scripts/benchmark-arm-observer.mjs +320 -0
  681. package/scripts/benchmark-budget-ipc.mjs +34 -0
  682. package/scripts/benchmark-budget-launcher.mjs +91 -0
  683. package/scripts/benchmark-budget-processes.mjs +133 -0
  684. package/scripts/benchmark-budget-publication.mjs +228 -0
  685. package/scripts/benchmark-budget-runtime.mjs +136 -0
  686. package/scripts/benchmark-candidate-ablation.mjs +265 -0
  687. package/scripts/benchmark-codex-journey.mjs +406 -0
  688. package/scripts/benchmark-independent-verification.mjs +628 -0
  689. package/scripts/benchmark-journey-outcome.mjs +92 -0
  690. package/scripts/benchmark-production-v3-human-review.mjs +192 -0
  691. package/scripts/benchmark-public-input-catalog.mjs +158 -0
  692. package/scripts/benchmark-registered-plan-author.mjs +355 -0
  693. package/scripts/benchmark-registered-plan-recipe-support.mjs +85 -0
  694. package/scripts/benchmark-registered-plan-recipes-backend.mjs +165 -0
  695. package/scripts/benchmark-registered-plan-recipes-data.mjs +164 -0
  696. package/scripts/benchmark-registered-plan-recipes-platform.mjs +165 -0
  697. package/scripts/benchmark-runner-completion.mjs +133 -0
  698. package/scripts/benchmark-runner-configuration.mjs +159 -0
  699. package/scripts/benchmark-runner-core.mjs +224 -387
  700. package/scripts/benchmark-runner-finalization.mjs +144 -27
  701. package/scripts/benchmark-runner-provider-boundary.mjs +44 -0
  702. package/scripts/benchmark-runner-schedule.mjs +256 -0
  703. package/scripts/benchmark-runner-support.mjs +136 -4
  704. package/scripts/benchmark-runner.mjs +95 -18
  705. package/scripts/benchmark-scoped-broker-custody.mjs +483 -0
  706. package/scripts/benchmark-scoped-docs-verifier.mjs +203 -0
  707. package/scripts/benchmark-scoped-frozen-qualification.mjs +676 -0
  708. package/scripts/benchmark-scoped-pi-router.mjs +196 -0
  709. package/scripts/benchmark-scoped-project-verification-receipt.mjs +49 -0
  710. package/scripts/benchmark-scoped-project-verifier.mjs +461 -0
  711. package/scripts/benchmark-scoped-session-custody.mjs +599 -0
  712. package/scripts/benchmark-scoped-session-factory.mjs +342 -0
  713. package/scripts/benchmark-scoped-tool-broker.mjs +523 -0
  714. package/scripts/benchmark-scoped-verification-supervisor.mjs +773 -0
  715. package/scripts/benchmark-session-evaluator.mjs +169 -0
  716. package/scripts/benchmark-session-provider-boundary.mjs +62 -0
  717. package/scripts/benchmark-session-usage.mjs +28 -0
  718. package/scripts/benchmark-session.mjs +343 -50
  719. package/scripts/benchmark-webui-journey.mjs +678 -0
  720. package/scripts/check-public-wording.mjs +46 -0
  721. package/scripts/configure-subagents.sh +42 -34
  722. package/scripts/fs4-readiness-evaluation.mjs +7 -1
  723. package/scripts/helper-evaluation.mjs +1 -1
  724. package/scripts/phase-tools-evaluation.mjs +1 -0
  725. package/scripts/pi-auto.sh +7 -1
  726. package/scripts/pi-usage-history.mjs +201 -11
  727. package/scripts/piagent-cli.mjs +8 -0
  728. package/scripts/private-holdout-readiness.mjs +7 -1
  729. package/scripts/public-evaluation-exposure.mjs +140 -0
  730. package/scripts/select-independent-verification.mjs +62 -0
  731. package/scripts/team-doctor.sh +1 -1
  732. package/scripts/typescript-loader.mjs +135 -1
  733. package/scripts/update-global.mjs +6 -7
  734. package/scripts/verify-local.sh +41 -55
  735. package/scripts/verify-release-identity.mjs +5 -3
  736. package/packages/piagent-webui/dist/client/assets/index-DynIMe8I.js +0 -176
@@ -3,8 +3,27 @@ import { randomBytes } from "node:crypto";
3
3
  import { redactSensitiveText } from "../../piagent-core/extensions/redaction-core.js";
4
4
  import { ReadModelNotFound, type SourceView, type StreamEvent, type WebUiReadModelProvider } from "./read-model-provider.ts";
5
5
  import { projectTranscript } from "./transcript-projection.ts";
6
+ import { readTerminalDeliveryReceipt, terminalDeliverySessionEntries } from "./terminal-delivery-receipt.ts";
6
7
 
7
8
  const CORE_ROOT = "../../piagent-core";
9
+ const SOURCE_AUTHORITY_ALIGNED = Symbol("piagent-source-authority-aligned");
10
+ const STABLE_IDENTITY_FIELDS = ["projectRef", "runtimeInstanceId", "sessionRef", "taskId", "taskRunId"] as const;
11
+
12
+ function stableIdentityMatches(left: Record<string, any> | null | undefined, right: Record<string, any> | null | undefined): boolean {
13
+ return Boolean(left && right && STABLE_IDENTITY_FIELDS.every((field) => left[field] === right[field]));
14
+ }
15
+
16
+ function sourceBinding(snapshot: Record<string, any>) {
17
+ return { sourceProjectionRevision: snapshot.sourceChanges.projectionRevision,
18
+ taskViewRevision: snapshot.sourceChanges.task.revision, workspaceRevision: snapshot.sourceChanges.workingTree.revision,
19
+ indexRevision: snapshot.sourceChanges.staged.revision };
20
+ }
21
+
22
+ function sourceDocumentMatches(document: Record<string, any> | null | undefined, snapshot: Record<string, any>): boolean {
23
+ const binding = sourceBinding(snapshot);
24
+ return Boolean(document && stableIdentityMatches(document.identity, snapshot.identity)
25
+ && Object.entries(binding).every(([field, value]) => document.snapshotBinding?.[field] === value));
26
+ }
8
27
 
9
28
  type RuntimeEvent = { eventCursor: string; [key: string]: unknown };
10
29
  type EventReplay = {
@@ -52,6 +71,7 @@ export type CoreInspectionInput = {
52
71
  activityEvents?: () => unknown[];
53
72
  currentActivity?: () => unknown[];
54
73
  sessionEntries?: () => unknown[];
74
+ sessionFile?: () => string | undefined;
55
75
  protectedPaths?: () => string[];
56
76
  // Extra directories the operator granted through the profile. The document
57
77
  // workspace lists them beside the project; without them it shows the project
@@ -72,6 +92,7 @@ export type CoreInspectionInput = {
72
92
  chatControl?: () => { state: "unbound" | "ready" | "replacement-pending" | "shutdown"; liveness: "idle" | "running" | "unknown";
73
93
  taskState: "none" | "active" | "pause-requested" | "paused" | "terminal" | "unknown"; identity: Record<string, any> | null; revisions: Record<string, any> | null;
74
94
  heldCount: number; queueRevision: string | null };
95
+ operationLiveness?: () => "idle" | "running" | "unknown";
75
96
  };
76
97
 
77
98
  export class CoreInspectionProvider implements WebUiReadModelProvider {
@@ -97,12 +118,15 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
97
118
  const projectionEpoch = this.#invalidationEpoch;
98
119
  const { buildWebUiInspectionProjection } = await loadCoreInspection();
99
120
  const retention = this.#input.eventStore.retention();
121
+ const control = this.#input.chatControl?.();
122
+ const operationLiveness = control?.state === "ready" ? control.liveness : this.#input.operationLiveness?.();
100
123
  const value = await buildWebUiInspectionProjection({
101
124
  cwd: this.#input.cwd, sessionId: this.#input.sessionId, runtimeInstanceId: this.#input.runtimeInstanceId,
102
125
  task: this.#input.task?.(), events: this.#input.activityEvents?.() ?? [], current: this.#input.currentActivity?.() ?? [],
103
126
  sessionEntries: this.#input.sessionEntries?.() ?? [], protectedPaths: this.#input.protectedPaths?.() ?? [],
104
127
  contextUsage: this.#input.contextUsage?.(), model: this.#input.model?.(), thinkingLevel: this.#input.thinkingLevel?.(),
105
- eventCursor: this.#input.eventStore.currentCursor(), resyncRequired: this.#input.eventStore.resyncRequired(), eventReplay: retention
128
+ eventCursor: this.#input.eventStore.currentCursor(), resyncRequired: this.#input.eventStore.resyncRequired(), eventReplay: retention,
129
+ operationLiveness
106
130
  });
107
131
  // What the host will accept as an attachment is a property of the machine and
108
132
  // the model, not of chat control. The Gateway drives sessions without a chat
@@ -115,11 +139,15 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
115
139
  Object.assign(value.snapshot.capabilities.limits, { maxRequestBodyBytes: 11_250_000, maxAttachmentCount: 4,
116
140
  maxAttachmentFileBytes: 8_388_608, maxAttachmentTotalBytes: 16_777_216 });
117
141
  }
118
- const control = this.#input.chatControl?.();
142
+ const projectedIdentity = value.snapshot.identity, projectedTaskRevision = value.snapshot.revision.taskRevision;
143
+ let sourceIdentityAligned = !this.#input.eventStore.resyncRequired()
144
+ && Object.values(value.sourceViews).every((document) => document === null || sourceDocumentMatches(document as Record<string, any>, value.snapshot));
119
145
  if (control?.state === "ready" && control.identity && control.revisions && !this.#input.eventStore.resyncRequired()) {
120
146
  const available = { available: true, reasonCode: null }, disabled = (reasonCode: string) => ({ available: false, reasonCode });
121
147
  const lifecycle = this.#input.lifecycleControl?.(), terminal = control.taskState === "terminal";
122
148
  const dispatchBlocked = lifecycle?.dispatchBlocked === true && lifecycle.state !== "terminal";
149
+ sourceIdentityAligned = sourceIdentityAligned && stableIdentityMatches(projectedIdentity, control.identity)
150
+ && (projectedIdentity.taskId === null || projectedTaskRevision === control.revisions.taskRevision);
123
151
  value.snapshot.identity = structuredClone(control.identity);
124
152
  value.snapshot.capabilities.identity = structuredClone(control.identity);
125
153
  for (const name of ["runtimeRevision", "taskRevision", "controlRevision", "sessionOptionRevision", "queueRevision"])
@@ -173,7 +201,12 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
173
201
  value.snapshot.capabilities.capabilities.approve = { status: "available", version: 1, reason: null,
174
202
  decisions: ["allow", "deny"], arbitration: "first-valid-cas" };
175
203
  }
176
- if (control.identity.taskId && control.identity.taskRunId && control.revisions.taskRevision && value.snapshot.revision.workspaceRevision) {
204
+ if (control.identity.taskId && control.identity.taskRunId && control.revisions.taskRevision && value.snapshot.revision.workspaceRevision
205
+ && !sourceIdentityAligned) {
206
+ value.snapshot.capabilities.capabilities.reviewActions = { status: "unavailable", version: null,
207
+ reason: { code: "source-binding-resync-required",
208
+ message: "Source actions require a source projection bound to the current project, session and task." } };
209
+ } else if (control.identity.taskId && control.identity.taskRunId && control.revisions.taskRevision && value.snapshot.revision.workspaceRevision) {
177
210
  const mutationGuardAvailable = this.#input.sourceMutationGuardAvailable?.() === true;
178
211
  const chatSend = value.snapshot.capabilities.capabilities["control.chat"]?.status === "available"
179
212
  && value.snapshot.capabilities.capabilities["control.chat"].actions.send.available;
@@ -192,6 +225,16 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
192
225
  } };
193
226
  }
194
227
  }
228
+ if (sourceIdentityAligned) {
229
+ const binding = sourceBinding(value.snapshot);
230
+ for (const document of Object.values(value.sourceViews)) {
231
+ if (document && typeof document === "object") Object.assign(document as Record<string, any>, {
232
+ identity: structuredClone(value.snapshot.identity), snapshotBinding: structuredClone(binding)
233
+ });
234
+ }
235
+ }
236
+ Object.defineProperty(value, SOURCE_AUTHORITY_ALIGNED, { value: sourceIdentityAligned
237
+ && Object.values(value.sourceViews).every((document) => document === null || sourceDocumentMatches(document as Record<string, any>, value.snapshot)) });
195
238
  if (projectionEpoch === this.#invalidationEpoch) this.#cachedProjection = { at: Date.now(), value };
196
239
  return value;
197
240
  }
@@ -236,6 +279,7 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
236
279
  }
237
280
  async transcript(beforeCursor: string | null, limit: number): Promise<unknown> {
238
281
  const snapshot = await this.snapshot() as any;
282
+ const activeTask = this.#input.task?.() as any;
239
283
  return projectTranscript({ identity: { projectRef: snapshot.identity.projectRef, runtimeInstanceId: snapshot.identity.runtimeInstanceId,
240
284
  sessionRef: snapshot.identity.sessionRef, taskId: snapshot.identity.taskId, taskRunId: snapshot.identity.taskRunId, agentOperationId: null, toolCallId: null },
241
285
  revision: { runtimeRevision: snapshot.revision.runtimeRevision, taskRevision: snapshot.revision.taskRevision,
@@ -243,7 +287,9 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
243
287
  indexRevision: snapshot.revision.indexRevision, approvalRevision: snapshot.revision.approvalRevision,
244
288
  sessionOptionRevision: snapshot.revision.sessionOptionRevision, queueRevision: snapshot.revision.queueRevision },
245
289
  eventCursor: snapshot.revision.eventCursor, entries: this.#input.sessionEntries?.() ?? [], beforeCursor, limit,
246
- generatedAt: snapshot.generatedAt });
290
+ terminalDeliveryReceipt: readTerminalDeliveryReceipt(this.#input.cwd, activeTask),
291
+ terminalDeliveryEntries: terminalDeliverySessionEntries(this.#input.sessionFile?.(), this.#input.sessionId),
292
+ generatedAt: snapshot.generatedAt, taskOutcome: typeof activeTask?.trace?.outcome === "string" ? activeTask.trace.outcome : null });
247
293
  }
248
294
  async queue(): Promise<unknown> {
249
295
  if (!this.#input.queueProjection) throw new ReadModelNotFound();
@@ -257,15 +303,18 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
257
303
  const value = this.#input.approvalDetail?.(approvalRef); if (!value) throw new ReadModelNotFound(); return value;
258
304
  }
259
305
  async diff(view: SourceView, fileRef: string): Promise<unknown> {
260
- const cacheKey = `${view}:${fileRef}`;
261
- const cached = this.#diffCache.get(cacheKey);
262
- if (cached && Date.now() - cached.at <= 200) return cached.value;
263
- const { collectFileDiff, matchesProtectedPath } = await loadCoreInspection();
306
+ const requestEpoch = this.#invalidationEpoch;
264
307
  const projection = await this.#projection();
308
+ this.#requireSourceAuthority(projection, [view]);
265
309
  const source = view === "working-tree" ? projection.sourceViews.workingTree : projection.sourceViews[view];
266
310
  const file = source?.files.find((candidate: any) => candidate.fileRef === fileRef) as Record<string, any> | undefined;
267
311
  if (!source || !file) throw new ReadModelNotFound();
268
312
  const identity = projection.snapshot.identity;
313
+ const cacheKey = [...STABLE_IDENTITY_FIELDS.map((field) => identity[field]), projection.snapshot.revision.taskRevision,
314
+ projection.snapshot.sourceChanges.projectionRevision, view, source.viewRevision, file.fileRevision, fileRef].join("\0");
315
+ const cached = this.#diffCache.get(cacheKey);
316
+ if (cached && Date.now() - cached.at <= 200) return cached.value;
317
+ const { collectFileDiff, matchesProtectedPath } = await loadCoreInspection();
269
318
  const protectedPaths = this.#input.protectedPaths?.() ?? [];
270
319
  const value = await collectFileDiff({
271
320
  cwd: this.#input.cwd, identity, sourceView: source, fileRef,
@@ -277,8 +326,10 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
277
326
  selectedRepoPaths: file.pathDisplay === "exact-safe" ? [file.oldPath, file.path].filter((value: unknown): value is string => typeof value === "string") : undefined,
278
327
  isProtectedPath: (_root: string, repoPath: string) => Boolean(matchesProtectedPath(repoPath, protectedPaths))
279
328
  });
280
- this.#diffCache.set(cacheKey, { at: Date.now(), value });
281
- if (this.#diffCache.size > 128) this.#diffCache.delete(this.#diffCache.keys().next().value as string);
329
+ if (requestEpoch === this.#invalidationEpoch) {
330
+ this.#diffCache.set(cacheKey, { at: Date.now(), value });
331
+ if (this.#diffCache.size > 128) this.#diffCache.delete(this.#diffCache.keys().next().value as string);
332
+ }
282
333
  return value;
283
334
  }
284
335
 
@@ -287,6 +338,7 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
287
338
  // cache when deriving its exact Git/task preimage.
288
339
  this.invalidate();
289
340
  const projection = await this.#projection(), snapshot = projection.snapshot;
341
+ this.#requireSourceAuthority(projection, [view]);
290
342
  const identity = { ...snapshot.identity, agentOperationId: null, toolCallId: null };
291
343
  if (!identity.taskId || !identity.taskRunId || !snapshot.revision.taskRevision || !snapshot.revision.workspaceRevision) throw new ReadModelNotFound();
292
344
  const diff = await this.diff(view, fileRef) as any;
@@ -302,10 +354,11 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
302
354
  async #sourceMutation(action: "source.stage" | "source.unstage", fileRef: string) {
303
355
  this.invalidate();
304
356
  const projection = await this.#projection(), snapshot = projection.snapshot;
357
+ const view: SourceView = action === "source.stage" ? "working-tree" : "staged";
358
+ this.#requireSourceAuthority(projection, [view]);
305
359
  const identity = { ...snapshot.identity, agentOperationId: null, toolCallId: null };
306
360
  if (!identity.taskId || !identity.taskRunId || !snapshot.revision.taskRevision || !snapshot.revision.workspaceRevision || !snapshot.revision.indexRevision)
307
361
  throw new ReadModelNotFound();
308
- const view: SourceView = action === "source.stage" ? "working-tree" : "staged";
309
362
  const source = view === "working-tree" ? projection.sourceViews.workingTree : projection.sourceViews.staged;
310
363
  if (!source?.files.some((file: any) => file.fileRef === fileRef)) throw new ReadModelNotFound();
311
364
  const diff = await this.diff(view, fileRef) as any;
@@ -329,6 +382,7 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
329
382
  async #sourceRevert(fileRef: string, hunkRef: string | null) {
330
383
  this.invalidate();
331
384
  const projection = await this.#projection(), snapshot = projection.snapshot;
385
+ this.#requireSourceAuthority(projection, ["working-tree", ...(projection.sourceViews.task ? ["task" as const] : [])]);
332
386
  const identity = { ...snapshot.identity, agentOperationId: null, toolCallId: null };
333
387
  if (!identity.taskId || !identity.taskRunId || !snapshot.revision.taskRevision || !snapshot.revision.workspaceRevision || !snapshot.revision.indexRevision)
334
388
  throw new ReadModelNotFound();
@@ -356,6 +410,7 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
356
410
 
357
411
  async sourceOpenAuthority(fileRef: string) {
358
412
  this.invalidate(); const projection = await this.#projection(), snapshot = projection.snapshot;
413
+ this.#requireSourceAuthority(projection, ["working-tree"]);
359
414
  const identity = { ...snapshot.identity, agentOperationId: null, toolCallId: null };
360
415
  if (!identity.taskId || !identity.taskRunId || !snapshot.revision.taskRevision || !snapshot.revision.workspaceRevision) return null;
361
416
  const { resolveSourceOpenTarget, matchesProtectedPath } = await loadCoreInspection(), protectedPaths = this.#input.protectedPaths?.() ?? [];
@@ -366,6 +421,7 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
366
421
 
367
422
  async commitSummary(): Promise<unknown> {
368
423
  this.invalidate(); const projection = await this.#projection(), snapshot = projection.snapshot;
424
+ this.#requireSourceAuthority(projection, ["staged"]);
369
425
  const identity = { ...snapshot.identity, agentOperationId: null, toolCallId: null };
370
426
  if (!identity.taskId || !identity.taskRunId || !snapshot.revision.taskRevision || !snapshot.revision.indexRevision) throw new ReadModelNotFound();
371
427
  const { projectDeterministicCommitSummary } = await loadCoreInspection();
@@ -423,12 +479,16 @@ export class CoreInspectionProvider implements WebUiReadModelProvider {
423
479
  this.invalidate(); return structuredClone((await this.#projection()).snapshot.revision);
424
480
  }
425
481
 
482
+ #requireSourceAuthority(projection: any, views: SourceView[]): void {
483
+ if (projection[SOURCE_AUTHORITY_ALIGNED] !== true || views.some((view) => {
484
+ const document = view === "working-tree" ? projection.sourceViews.workingTree : projection.sourceViews[view];
485
+ return !sourceDocumentMatches(document, projection.snapshot);
486
+ })) throw new ReadModelNotFound();
487
+ }
488
+
426
489
  replay(after: string | null, limit: number) {
427
490
  const replay = this.#input.eventStore.replay(after, limit);
428
- if (replay.state !== "current") {
429
- this.#cachedProjection = null;
430
- this.#diffCache.clear();
431
- }
491
+ if (replay.state !== "current") this.invalidate();
432
492
  return { ...replay, events: replay.events.map((event) => ({ cursor: event.eventCursor, value: event })) };
433
493
  }
434
494
  subscribe(listener: (event: StreamEvent) => void): () => void { this.#listeners.add(listener); return () => this.#listeners.delete(listener); }
@@ -13,13 +13,13 @@ const MAX_BOOTSTRAP_BODY_BYTES = 4_096;
13
13
  const MAX_CONTROL_BODY_BYTES = 70_000;
14
14
  const MAX_ATTACHMENT_BODY_BYTES = 11_250_000;
15
15
  const REQUESTS_PER_MINUTE = 120;
16
- const BOOTSTRAPS_PER_MINUTE = 8;
16
+ const BOOTSTRAP_FAILURES_PER_MINUTE = 8;
17
17
  const CONTROLS_PER_MINUTE = 60;
18
18
  const MAX_JSON_RESPONSE_BYTES = 16 * 1024 * 1024;
19
19
  const CURSOR = /^[A-Za-z0-9][A-Za-z0-9._~-]{0,159}$/;
20
20
 
21
21
  type ReadCapabilities = () => unknown | Promise<unknown>;
22
- type RateState = { windowStart: number; requests: number; bootstraps: number };
22
+ type RateState = { windowStart: number; requests: number; bootstrapFailures: number };
23
23
  type ControlRateState = { windowStart: number; controls: number };
24
24
 
25
25
  export type LoopbackServer = {
@@ -109,8 +109,8 @@ export async function startLoopbackServer(options: {
109
109
  const browserSession = auth.authenticate(request, now);
110
110
  const rateKey = browserSession ? `${remote}:${browserSession.id}` : `remote:${remote}`;
111
111
  for (const [key, value] of rates) if (now - value.windowStart >= 60_000) rates.delete(key);
112
- const rate = rates.get(rateKey) ?? { windowStart: now, requests: 0, bootstraps: 0 };
113
- if (now - rate.windowStart >= 60_000) Object.assign(rate, { windowStart: now, requests: 0, bootstraps: 0 });
112
+ const rate = rates.get(rateKey) ?? { windowStart: now, requests: 0, bootstrapFailures: 0 };
113
+ if (now - rate.windowStart >= 60_000) Object.assign(rate, { windowStart: now, requests: 0, bootstrapFailures: 0 });
114
114
  rate.requests += 1; rates.set(rateKey, rate);
115
115
  while (rates.size > 128) rates.delete(rates.keys().next().value as string);
116
116
  if (rate.requests > REQUESTS_PER_MINUTE) return errorResponse(response, 429, "rate-limit");
@@ -120,8 +120,6 @@ export async function startLoopbackServer(options: {
120
120
  if (url.hash || url.username || url.password || url.origin !== origin) return errorResponse(response, 400, "invalid-url");
121
121
 
122
122
  if (request.method === "POST" && url.pathname === "/api/v1/bootstrap") {
123
- rate.bootstraps += 1;
124
- if (rate.bootstraps > BOOTSTRAPS_PER_MINUTE) return errorResponse(response, 429, "bootstrap-rate-limit");
125
123
  if (requestOrigin !== origin) return errorResponse(response, 403, "origin-required");
126
124
  if (!String(request.headers["content-type"] ?? "").toLowerCase().startsWith("application/json")) return errorResponse(response, 415, "content-type");
127
125
  let value: unknown;
@@ -129,7 +127,11 @@ export async function startLoopbackServer(options: {
129
127
  catch (error) { return errorResponse(response, (error as Error).message === "body-limit" ? 413 : 400, "invalid-bootstrap"); }
130
128
  const capability = value && typeof value === "object" ? (value as Record<string, unknown>).capability : null;
131
129
  const session = typeof capability === "string" ? auth.exchange(capability) : null;
132
- if (!session) return errorResponse(response, 403, "bootstrap-rejected");
130
+ if (!session) {
131
+ rate.bootstrapFailures += 1;
132
+ if (rate.bootstrapFailures > BOOTSTRAP_FAILURES_PER_MINUTE) return errorResponse(response, 429, "bootstrap-rate-limit");
133
+ return errorResponse(response, 403, "bootstrap-rejected");
134
+ }
133
135
  response.setHeader("Set-Cookie", auth.cookieHeader(session));
134
136
  return jsonResponse(response, 200, { authenticated: true, csrfToken: session.csrf, expiresAt: new Date(session.expiresAt).toISOString() });
135
137
  }
@@ -0,0 +1,144 @@
1
+ import { isDeepStrictEqual } from "node:util";
2
+ import fs from "node:fs";
3
+
4
+ import { webUiMessageCorrelationEntry, type WebUiMessageCorrelation } from "../shared/message-correlation.ts";
5
+
6
+ // As in CoreInspectionProvider, load core through the server boundary. Its
7
+ // internal source types are not part of the strict browser contract graph.
8
+ const CORE_ROOT = "../../piagent-core";
9
+ const [{ activeSessionTask }, { isUncertainSendContinuation, terminalUncertainSendReceipt }] = await Promise.all([
10
+ import(`${CORE_ROOT}/extensions/task-state.js`),
11
+ import(`${CORE_ROOT}/runtime/session/uncertain-send-continuation.ts`)
12
+ ]);
13
+
14
+ export type TerminalDeliveryReceipt = { customType: string; content: string; details: {
15
+ taskId: string; taskRunId: string; outcome: string; completionApproved: boolean; gateDecision: string;
16
+ [key: string]: unknown;
17
+ } };
18
+
19
+ export function readTerminalDeliveryReceipt(cwd: string, task: unknown): TerminalDeliveryReceipt | undefined {
20
+ return terminalUncertainSendReceipt(cwd, task);
21
+ }
22
+
23
+ export const TERMINAL_DELIVERY_CONFIRMATION_TYPE = "piagent-webui-terminal-delivery-v1";
24
+ export type TerminalDeliveryPair = { requestEntry: any; receiptEntry: any; confirmationEntry?: any; request: string;
25
+ correlation: WebUiMessageCorrelation; receipt: TerminalDeliveryReceipt };
26
+
27
+ /** Strict bounded readback; an in-memory Pi branch is not a persistence acknowledgment. */
28
+ export function terminalDeliverySessionEntries(file: string | undefined, sessionId: string): unknown[] {
29
+ if (!file) return [];
30
+ let descriptor: number | undefined;
31
+ try {
32
+ descriptor = fs.openSync(file, "r");
33
+ const stat = fs.fstatSync(descriptor);
34
+ if (!stat.isFile() || stat.size > 64 * 1024 * 1024) return [];
35
+ const source = fs.readFileSync(descriptor, "utf8");
36
+ if (!source.endsWith("\n") || Buffer.byteLength(source) > 64 * 1024 * 1024) return [];
37
+ const lines = source.trimEnd().split("\n");
38
+ if (lines.length > 50_001) return [];
39
+ // Pi's generic parser tolerates corrupt lines. Delivery requires every
40
+ // persisted record, including the confirmation, to be complete and valid.
41
+ const [header, ...entries] = lines.map((line) => JSON.parse(line));
42
+ return header?.type === "session" && header.version === 3 && header.id === sessionId ? entries : [];
43
+ } catch { return []; }
44
+ finally { if (descriptor !== undefined) fs.closeSync(descriptor); }
45
+ }
46
+
47
+ /** Only this handled-input protocol needs a request anchor outside model history. */
48
+ export function terminalDeliveryRequest(message: unknown, images?: unknown[]): string | undefined {
49
+ return typeof message === "string" && message.length <= 65_536 && !images?.length
50
+ && isUncertainSendContinuation(message) ? message : undefined;
51
+ }
52
+
53
+ function matchesReceipt(value: any, expected: TerminalDeliveryReceipt): boolean {
54
+ return value?.display === true && value.customType === expected.customType && value.content === expected.content
55
+ && isDeepStrictEqual(value.details, expected.details);
56
+ }
57
+
58
+ function hasEntryIdentity(value: any): boolean {
59
+ return typeof value?.id === "string" && value.id.length > 0 && value.id.length <= 160
60
+ && typeof value.timestamp === "string" && Number.isFinite(Date.parse(value.timestamp));
61
+ }
62
+
63
+ function confirmationData(pair: TerminalDeliveryPair): Record<string, unknown> {
64
+ return { schemaVersion: 1, ...pair.correlation, receiptEntryId: pair.receiptEntry.id,
65
+ taskId: pair.receipt.details.taskId, taskRunId: pair.receipt.details.taskRunId };
66
+ }
67
+
68
+ function receiptPairs(entries: unknown[], expected: TerminalDeliveryReceipt | undefined,
69
+ confirmed: boolean): TerminalDeliveryPair[] {
70
+ if (!expected || !Array.isArray(entries) || entries.length > 50_000) return [];
71
+ const pairs: TerminalDeliveryPair[] = [];
72
+ const operations = new Map<string, number>(), requests = new Map<string, number>(), entryIds = new Map<string, number>();
73
+ for (const entry of entries) {
74
+ const id = (entry as any)?.id;
75
+ if (typeof id === "string") entryIds.set(id, (entryIds.get(id) ?? 0) + 1);
76
+ const correlation = webUiMessageCorrelationEntry(entry);
77
+ if (correlation) {
78
+ operations.set(correlation.operationRef, (operations.get(correlation.operationRef) ?? 0) + 1);
79
+ requests.set(correlation.messageRequestId, (requests.get(correlation.messageRequestId) ?? 0) + 1);
80
+ }
81
+ }
82
+ for (let index = 1; index < entries.length; index += 1) {
83
+ const requestEntry = entries[index - 1] as any, receiptEntry = entries[index] as any;
84
+ const correlation = webUiMessageCorrelationEntry(requestEntry);
85
+ const request = terminalDeliveryRequest(requestEntry?.data?.terminalDeliveryRequest);
86
+ if (!correlation || request === undefined || receiptEntry?.type !== "custom_message"
87
+ || !hasEntryIdentity(requestEntry) || !hasEntryIdentity(receiptEntry)
88
+ || entryIds.get(requestEntry.id) !== 1 || entryIds.get(receiptEntry.id) !== 1
89
+ || !matchesReceipt(receiptEntry, expected)) continue;
90
+ const pair: TerminalDeliveryPair = { requestEntry, receiptEntry, request, correlation, receipt: expected };
91
+ if (confirmed) {
92
+ const confirmation = entries[index + 1] as any;
93
+ if (confirmation?.type !== "custom" || confirmation.customType !== TERMINAL_DELIVERY_CONFIRMATION_TYPE
94
+ || !hasEntryIdentity(confirmation) || entryIds.get(confirmation.id) !== 1
95
+ || !isDeepStrictEqual(confirmation.data, confirmationData(pair))) continue;
96
+ pair.confirmationEntry = confirmation;
97
+ }
98
+ pairs.push(pair);
99
+ }
100
+ return pairs.filter((pair) => operations.get(pair.correlation.operationRef) === 1
101
+ && requests.get(pair.correlation.messageRequestId) === 1);
102
+ }
103
+
104
+ /** A projection may show only a receipt whose operation reached durable delivery settlement. */
105
+ export function terminalDeliveryPairs(entries: unknown[], expected: TerminalDeliveryReceipt | undefined,
106
+ persistedEntries: unknown[] = []): TerminalDeliveryPair[] {
107
+ const persisted = new Map(receiptPairs(persistedEntries, expected, true).map((pair) => [pair.receiptEntry.id, pair]));
108
+ return receiptPairs(entries, expected, true).filter((pair) => {
109
+ const disk = persisted.get(pair.receiptEntry.id);
110
+ return disk && isDeepStrictEqual(pair.requestEntry, disk.requestEntry) && isDeepStrictEqual(pair.receiptEntry, disk.receiptEntry)
111
+ && isDeepStrictEqual(pair.confirmationEntry, disk.confirmationEntry);
112
+ });
113
+ }
114
+
115
+ /**
116
+ * Compare the observed custom message with current core state and this exact
117
+ * operation's latest durable receipt. Persist a delivery observation before
118
+ * the gateway acknowledges settlement. This marker grants no task authority;
119
+ * transcript reads still require the independently reread core receipt.
120
+ */
121
+ export function terminalDeliveryReceiptCommitter(input: { cwd: string; sessionId: string; operationRef: string;
122
+ messageRequestId: string | null; request?: string; entries(): unknown[]; persistedEntries(): unknown[];
123
+ appendCustomEntry(type: string, data: Record<string, unknown>): unknown }):
124
+ (message: unknown) => TerminalDeliveryReceipt | undefined {
125
+ return (message) => {
126
+ if (input.request === undefined || !input.messageRequestId || (message as any)?.role !== "custom") return undefined;
127
+ try {
128
+ const expected = readTerminalDeliveryReceipt(input.cwd, activeSessionTask(input.cwd, input.sessionId));
129
+ const entries = input.entries(), pair = receiptPairs(entries, expected, false).find((candidate) =>
130
+ candidate.correlation.operationRef === input.operationRef
131
+ && candidate.correlation.messageRequestId === input.messageRequestId && candidate.request === input.request);
132
+ if (!pair || pair.receiptEntry !== entries.at(-1) || !matchesReceipt(message, pair.receipt)) return undefined;
133
+ const before = input.persistedEntries();
134
+ const disk = receiptPairs(before, expected, false).find((candidate) => candidate.receiptEntry.id === pair.receiptEntry.id);
135
+ if (!disk || disk.receiptEntry !== before.at(-1) || !isDeepStrictEqual(pair.requestEntry, disk.requestEntry)
136
+ || !isDeepStrictEqual(pair.receiptEntry, disk.receiptEntry)) return undefined;
137
+ input.appendCustomEntry(TERMINAL_DELIVERY_CONFIRMATION_TYPE, confirmationData(pair));
138
+ const current = input.entries(), persisted = input.persistedEntries();
139
+ return terminalDeliveryPairs(current, expected, persisted).some((candidate) => candidate.receiptEntry.id === pair.receiptEntry.id
140
+ && candidate.confirmationEntry === current.at(-1) && candidate.confirmationEntry.id === (persisted.at(-1) as any)?.id)
141
+ ? pair.receipt : undefined;
142
+ } catch { return undefined; }
143
+ };
144
+ }
@@ -1,13 +1,22 @@
1
1
  import { createHash } from "node:crypto";
2
2
 
3
3
  import { redactSensitiveText } from "../../piagent-core/extensions/redaction-core.js";
4
+ import { looksLikeCompletionClaim } from "../../piagent-core/runtime/session/completion-signals.ts";
5
+ import { isLightweightNonAuthorizingChangeLanguage } from "../../piagent-core/runtime/workflows/change-clarification.ts";
6
+ import { workflowCommandPattern } from "../../piagent-core/runtime/workflows/webui-workflow.ts";
4
7
  import { hasVisibleText } from "../shared/text-visibility.ts";
8
+ import { WEBUI_MESSAGE_CORRELATION_ENTRY_TYPE, webUiMessageCorrelationEntry,
9
+ type WebUiMessageCorrelation } from "../shared/message-correlation.ts";
10
+ import { terminalDeliveryPairs, type TerminalDeliveryPair, type TerminalDeliveryReceipt } from "./terminal-delivery-receipt.ts";
5
11
 
6
12
  const MAX_ENTRIES = 50_000;
7
13
  const MAX_ITEMS = 200;
8
14
  const MAX_TEXT = 16_384;
9
15
  const ANSI = /\u001b(?:\[[0-?]*[ -/]*[@-~]|[@-_])/g;
10
16
  const COMPLETION_GATE = /^\[Piagent completion gate: (CONTINUING|NOT APPROVED)\]/i;
17
+ const INTERNAL_FRESH_TRANSITION = new RegExp(
18
+ `^\\/fresh\\s+(?:${workflowCommandPattern({ aliases: false })})\\s+(?:--session-title\\s+"[^"\\r\\n]{1,64}"\\s+)?Read task intake from \\.pi\\/task-inbox\\/[A-Za-z0-9._-]+\\.md\\.\\s+Current session is near context limits; use a fresh governed session\\.$`, "u"
19
+ );
11
20
 
12
21
  type TranscriptIdentity = { projectRef: string; runtimeInstanceId: string; sessionRef: string; taskId: string | null; taskRunId: string | null;
13
22
  agentOperationId: null; toolCallId: null };
@@ -16,8 +25,8 @@ type TranscriptRevision = { runtimeRevision: string; taskRevision: string | null
16
25
  type TranscriptContent = { state: "available" | "redacted" | "unavailable"; text: string | null; textChars: number | null; digest: string | null;
17
26
  truncated: boolean; redacted: boolean; imageCount: number; reasonCode: string | null };
18
27
  type TranscriptAttachment = { displayName: string; kind: "file" | "image" | "document"; mimeType: string; truncated: boolean };
19
- type TranscriptItem = { messageRef: string; parentMessageRef: string | null; role: "user" | "assistant" | "tool-result"; recordedAt: string;
20
- agentOperationId: string | null; turnIndex: number | null; content: TranscriptContent;
28
+ type TranscriptItem = { messageRef: string; parentMessageRef: string | null; role: "user" | "assistant" | "tool-result" | "custom"; recordedAt: string;
29
+ agentOperationId: string | null; messageRequestId?: string; turnIndex: number | null; content: TranscriptContent;
21
30
  attachments?: TranscriptAttachment[];
22
31
  toolCalls: Array<{ toolCallRef: string; toolName: string; state: "requested" | "completed" | "failed" | "unknown" }> };
23
32
  export type TranscriptDocument = { schemaVersion: 1; version: "piagent-webui-transcript-v1"; generatedAt: string; identity: TranscriptIdentity;
@@ -32,6 +41,9 @@ export type TranscriptProjectionInput = {
32
41
  beforeCursor?: string | null;
33
42
  limit?: number;
34
43
  generatedAt?: string;
44
+ taskOutcome?: string | null;
45
+ terminalDeliveryReceipt?: TerminalDeliveryReceipt;
46
+ terminalDeliveryEntries?: unknown[];
35
47
  };
36
48
 
37
49
  function hash(value: string): string { return createHash("sha256").update(value).digest("hex"); }
@@ -134,16 +146,15 @@ function role(message: any): TranscriptItem["role"] | null {
134
146
  }
135
147
  function isInternalFreshTransition(message: any): boolean {
136
148
  if (message?.role !== "user") return false;
137
- return /^\/fresh\s+(?:task|scout|be-to-fe)\s+(?:--session-title\s+"[^"\r\n]{1,64}"\s+)?Read task intake from \.pi\/task-inbox\/[A-Za-z0-9._-]+\.md\.\s+Current session is near context limits; use a fresh governed session\.$/u
138
- .test(messageText(message).trim());
149
+ return INTERNAL_FRESH_TRANSITION.test(messageText(message).trim());
139
150
  }
140
151
  function unavailableContent(reasonCode: string): TranscriptContent {
141
152
  return { state: "unavailable", text: null, textChars: null, digest: null, truncated: false, redacted: false, imageCount: 0, reasonCode };
142
153
  }
143
- function item(entry: any, identity: TranscriptIdentity): TranscriptItem | null {
154
+ function item(entry: any, identity: TranscriptIdentity, customReceipt = false): TranscriptItem | null {
144
155
  if (!entry || entry.type !== "message" || !entry.message) return null;
145
156
  if (isInternalFreshTransition(entry.message)) return null;
146
- const itemRole = role(entry.message), recordedAt = timestamp(entry.timestamp ?? entry.message.timestamp);
157
+ const itemRole = customReceipt ? "custom" : role(entry.message), recordedAt = timestamp(entry.timestamp ?? entry.message.timestamp);
147
158
  if (!itemRole || !recordedAt || typeof entry.id !== "string" || entry.id.length === 0) return null;
148
159
  const userProjection = userMessageProjection(entry.message);
149
160
  const projectedToolCalls = toolCalls(entry.message, identity.sessionRef, itemRole);
@@ -159,6 +170,127 @@ function item(entry: any, identity: TranscriptIdentity): TranscriptItem | null {
159
170
  agentOperationId: null, turnIndex: null, content, ...(userProjection.attachments.length ? { attachments: userProjection.attachments } : {}),
160
171
  toolCalls: projectedToolCalls };
161
172
  }
173
+
174
+ type ProjectedTranscriptItem = { entry: any; item: TranscriptItem; cursor: string };
175
+
176
+ function correlatedTranscriptItems(entries: unknown[], identity: TranscriptIdentity,
177
+ receiptPairs: Map<unknown, TerminalDeliveryPair>): ProjectedTranscriptItem[] {
178
+ let pending: WebUiMessageCorrelation | null = null;
179
+ let turn: WebUiMessageCorrelation | null = null;
180
+ const values: ProjectedTranscriptItem[] = [];
181
+ for (const entry of entries as any[]) {
182
+ const pair = receiptPairs.get(entry);
183
+ if (pair) {
184
+ // Project the admitted request and real custom receipt without writing
185
+ // fabricated user/assistant messages into Pi's durable model history.
186
+ for (const [source, itemRole, content] of [[pair.requestEntry, "user", pair.request],
187
+ [pair.receiptEntry, "custom", pair.receipt.content]] as const) {
188
+ const projected = item({ ...source, type: "message", message: { role: itemRole, content } }, identity, itemRole === "custom");
189
+ if (projected) values.push({ entry: source, item: { ...projected, agentOperationId: pair.correlation.operationRef,
190
+ messageRequestId: pair.correlation.messageRequestId }, cursor: opaque("transcript", [identity.sessionRef, source.id]) });
191
+ }
192
+ pending = null; turn = null; continue;
193
+ }
194
+ if (entry?.type === "custom" && entry.customType === WEBUI_MESSAGE_CORRELATION_ENTRY_TYPE) {
195
+ // A newer marker supersedes an older marker that never reached a user
196
+ // message. Invalid markers fail closed instead of leaking correlation
197
+ // from an earlier admitted-but-undispatched operation into a later turn.
198
+ pending = webUiMessageCorrelationEntry(entry);
199
+ continue;
200
+ }
201
+ if (role(entry?.message) === "user") { turn = pending; pending = null; }
202
+ const projected = item(entry, identity);
203
+ if (!projected) continue;
204
+ values.push({ entry, item: turn ? { ...projected, agentOperationId: turn.operationRef,
205
+ messageRequestId: turn.messageRequestId } : projected,
206
+ cursor: opaque("transcript", [identity.sessionRef, entry?.id]) });
207
+ }
208
+ return values;
209
+ }
210
+
211
+ function linkTranscriptTurns(values: ProjectedTranscriptItem[]): ProjectedTranscriptItem[] {
212
+ let userMessageRef: string | null = null;
213
+ const toolCallOwners = new Map<string, string>();
214
+ return values.map((value) => {
215
+ let parentMessageRef: string | null = null;
216
+ if (value.item.role === "user") userMessageRef = value.item.messageRef;
217
+ else if (value.item.role === "tool-result") {
218
+ parentMessageRef = toolCallOwners.get(value.item.toolCalls[0]?.toolCallRef ?? "") ?? userMessageRef;
219
+ } else parentMessageRef = userMessageRef;
220
+ const linked = { ...value, item: { ...value.item, parentMessageRef } };
221
+ if (linked.item.role === "assistant") {
222
+ for (const toolCall of linked.item.toolCalls) toolCallOwners.set(toolCall.toolCallRef, linked.item.messageRef);
223
+ }
224
+ return linked;
225
+ });
226
+ }
227
+
228
+ function suppressOpenTaskHandoff(values: ProjectedTranscriptItem[], taskOutcome: string | null | undefined): ProjectedTranscriptItem[] {
229
+ if (taskOutcome !== "pending") return values;
230
+ let latestUser = -1;
231
+ for (let index = values.length - 1; index >= 0; index -= 1) {
232
+ if (values[index]?.item.role === "user") { latestUser = index; break; }
233
+ }
234
+ if (latestUser < 0) return values;
235
+ const latestPrompt = values[latestUser]?.item.content.text ?? "";
236
+ if (isLightweightNonAuthorizingChangeLanguage(latestPrompt)) return values;
237
+ return values.map((value, index) => {
238
+ if (index <= latestUser || value.item.role !== "assistant" || value.item.toolCalls.length > 0
239
+ || !["available", "redacted"].includes(value.item.content.state)
240
+ || !looksLikeCompletionClaim(value.item.content.text ?? "")) return value;
241
+ return { ...value, item: { ...value.item, content: unavailableContent("assistant-task-pending") } };
242
+ });
243
+ }
244
+
245
+ function durableAssistant(item: TranscriptItem): boolean {
246
+ return (item.role === "assistant" || item.role === "custom") && item.toolCalls.length === 0
247
+ && (item.content.state === "available" || item.content.state === "redacted")
248
+ && hasVisibleText(item.content.text ?? "");
249
+ }
250
+
251
+ function compactOversizedTurn(
252
+ values: ProjectedTranscriptItem[], start: number, end: number, limit: number
253
+ ): ProjectedTranscriptItem[] {
254
+ if (limit === 1) return [values[start]!];
255
+ const selected = new Set<number>([start]);
256
+ for (let index = end - 1; index > start; index -= 1) {
257
+ if (durableAssistant(values[index]!.item)) { selected.add(index); break; }
258
+ }
259
+ for (let index = end - 1; index > start && selected.size < limit; index -= 1) selected.add(index);
260
+ return [...selected].sort((left, right) => left - right).map((index) => values[index]!);
261
+ }
262
+
263
+ function boundedTurnPage(
264
+ values: ProjectedTranscriptItem[], end: number, limit: number
265
+ ): { selected: ProjectedTranscriptItem[]; start: number; compacted: boolean } {
266
+ if (end <= 0) return { selected: [], start: 0, compacted: false };
267
+ const users: number[] = [];
268
+ for (let index = 0; index < end; index += 1) if (values[index]?.item.role === "user") users.push(index);
269
+ if (users.length === 0) {
270
+ const start = Math.max(0, end - limit);
271
+ return { selected: values.slice(start, end), start, compacted: false };
272
+ }
273
+
274
+ const selected: ProjectedTranscriptItem[] = [];
275
+ let remaining = limit, turnEnd = end, start = end;
276
+ for (let userIndex = users.length - 1; userIndex >= 0 && remaining > 0; userIndex -= 1) {
277
+ const turnStart = users[userIndex]!;
278
+ const turnSize = turnEnd - turnStart;
279
+ if (turnSize > remaining) {
280
+ if (selected.length === 0) {
281
+ const compacted = compactOversizedTurn(values, turnStart, turnEnd, remaining);
282
+ return { selected: compacted, start: turnStart, compacted: true };
283
+ }
284
+ break;
285
+ }
286
+ selected.unshift(...values.slice(turnStart, turnEnd));
287
+ start = turnStart;
288
+ remaining -= turnSize;
289
+ turnEnd = turnStart;
290
+ }
291
+ return { selected, start, compacted: false };
292
+ }
293
+
162
294
  function unavailable(input: TranscriptProjectionInput, reasonCode: string, limit: number): TranscriptDocument {
163
295
  return { schemaVersion: 1, version: "piagent-webui-transcript-v1", generatedAt: input.generatedAt ?? new Date().toISOString(),
164
296
  identity: structuredClone(input.identity), revision: structuredClone(input.revision), eventCursor: input.eventCursor,
@@ -168,17 +300,24 @@ function unavailable(input: TranscriptProjectionInput, reasonCode: string, limit
168
300
  export function projectTranscript(input: TranscriptProjectionInput): TranscriptDocument {
169
301
  const limit = Math.max(1, Math.min(MAX_ITEMS, Number.isInteger(input.limit) ? Number(input.limit) : 50));
170
302
  if (!Array.isArray(input.entries) || input.entries.length > MAX_ENTRIES) return unavailable(input, "transcript-history-unavailable", limit);
171
- const projected = input.entries.map((entry) => ({ entry, item: item(entry, input.identity) })).filter((value): value is { entry: any; item: TranscriptItem } => Boolean(value.item));
172
- const cursors = projected.map(({ entry }) => opaque("transcript", [input.identity.sessionRef, entry.id]));
303
+ const receipt = input.terminalDeliveryReceipt;
304
+ const boundReceipt = receipt?.details.taskId === input.identity.taskId && receipt?.details.taskRunId === input.identity.taskRunId
305
+ && receipt?.details.outcome === input.taskOutcome ? receipt : undefined;
306
+ const receiptPairs = new Map(terminalDeliveryPairs(input.entries, boundReceipt, input.terminalDeliveryEntries)
307
+ .map((pair) => [pair.receiptEntry, pair]));
308
+ const projected = suppressOpenTaskHandoff(linkTranscriptTurns(correlatedTranscriptItems(input.entries, input.identity,
309
+ receiptPairs)), input.taskOutcome);
310
+ const cursors = projected.map((value) => value.cursor);
173
311
  let end = projected.length;
174
312
  if (input.beforeCursor) {
175
313
  const cursorIndex = cursors.indexOf(input.beforeCursor);
176
314
  if (cursorIndex < 0) return unavailable(input, "transcript-cursor-gap", limit);
177
315
  end = cursorIndex;
178
316
  }
179
- const start = Math.max(0, end - limit), selected = projected.slice(start, end).map((value) => value.item), hasOlder = start > 0;
317
+ const page = boundedTurnPage(projected, end, limit), selected = page.selected.map((value) => value.item), hasOlder = page.start > 0;
180
318
  return { schemaVersion: 1, version: "piagent-webui-transcript-v1", generatedAt: input.generatedAt ?? new Date().toISOString(),
181
319
  identity: structuredClone(input.identity), revision: structuredClone(input.revision), eventCursor: input.eventCursor,
182
- state: "ready", items: selected, page: { beforeCursor: input.beforeCursor ?? null, nextBeforeCursor: hasOlder ? cursors[start] : null,
183
- hasOlder, limit, truncated: projected.length !== input.entries.filter((entry: any) => entry?.type === "message").length }, reasonCode: null };
320
+ state: "ready", items: selected, page: { beforeCursor: input.beforeCursor ?? null, nextBeforeCursor: hasOlder ? cursors[page.start] : null,
321
+ hasOlder, limit, truncated: page.compacted || projected.length !== input.entries.filter((entry: any) => entry?.type === "message").length
322
+ + receiptPairs.size * 2 }, reasonCode: null };
184
323
  }