agentfootprint 7.23.0 → 7.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +34 -0
  2. package/dist/adapters/hosting/agentcore.js +112 -1
  3. package/dist/adapters/hosting/agentcore.js.map +1 -1
  4. package/dist/core/agent/AgentBuilder.js +117 -1
  5. package/dist/core/agent/AgentBuilder.js.map +1 -1
  6. package/dist/core/agent/act.js +143 -0
  7. package/dist/core/agent/act.js.map +1 -0
  8. package/dist/core/agent/middleware/index.js +5 -0
  9. package/dist/core/agent/middleware/index.js.map +1 -1
  10. package/dist/core/agent/middleware/ledger.js +7 -0
  11. package/dist/core/agent/middleware/ledger.js.map +1 -1
  12. package/dist/core/agent/middleware/outcomes.js +9 -2
  13. package/dist/core/agent/middleware/outcomes.js.map +1 -1
  14. package/dist/core/agent/middleware/runChain.js +97 -3
  15. package/dist/core/agent/middleware/runChain.js.map +1 -1
  16. package/dist/core/agent/middleware/types.js +30 -0
  17. package/dist/core/agent/middleware/types.js.map +1 -1
  18. package/dist/core/agent/moments.js +53 -0
  19. package/dist/core/agent/moments.js.map +1 -0
  20. package/dist/core/agent/stages/toolCalls.js +130 -7
  21. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  22. package/dist/esm/adapters/hosting/agentcore.d.ts +50 -1
  23. package/dist/esm/adapters/hosting/agentcore.js +110 -0
  24. package/dist/esm/adapters/hosting/agentcore.js.map +1 -1
  25. package/dist/esm/core/agent/AgentBuilder.d.ts +71 -0
  26. package/dist/esm/core/agent/AgentBuilder.js +117 -1
  27. package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
  28. package/dist/esm/core/agent/act.d.ts +69 -0
  29. package/dist/esm/core/agent/act.js +139 -0
  30. package/dist/esm/core/agent/act.js.map +1 -0
  31. package/dist/esm/core/agent/middleware/index.d.ts +6 -1
  32. package/dist/esm/core/agent/middleware/index.js +5 -0
  33. package/dist/esm/core/agent/middleware/index.js.map +1 -1
  34. package/dist/esm/core/agent/middleware/ledger.d.ts +6 -0
  35. package/dist/esm/core/agent/middleware/ledger.js +7 -0
  36. package/dist/esm/core/agent/middleware/ledger.js.map +1 -1
  37. package/dist/esm/core/agent/middleware/outcomes.d.ts +15 -0
  38. package/dist/esm/core/agent/middleware/outcomes.js +9 -2
  39. package/dist/esm/core/agent/middleware/outcomes.js.map +1 -1
  40. package/dist/esm/core/agent/middleware/runChain.d.ts +47 -0
  41. package/dist/esm/core/agent/middleware/runChain.js +95 -2
  42. package/dist/esm/core/agent/middleware/runChain.js.map +1 -1
  43. package/dist/esm/core/agent/middleware/types.d.ts +132 -10
  44. package/dist/esm/core/agent/middleware/types.js +30 -0
  45. package/dist/esm/core/agent/middleware/types.js.map +1 -1
  46. package/dist/esm/core/agent/moments.d.ts +55 -0
  47. package/dist/esm/core/agent/moments.js +49 -0
  48. package/dist/esm/core/agent/moments.js.map +1 -0
  49. package/dist/esm/core/agent/stages/toolCalls.d.ts +6 -1
  50. package/dist/esm/core/agent/stages/toolCalls.js +131 -8
  51. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  52. package/dist/esm/events/payloads.d.ts +4 -0
  53. package/dist/esm/hosting/errors.d.ts +44 -2
  54. package/dist/esm/hosting/errors.js +63 -0
  55. package/dist/esm/hosting/errors.js.map +1 -1
  56. package/dist/esm/hosting/headers.d.ts +16 -0
  57. package/dist/esm/hosting/headers.js +24 -0
  58. package/dist/esm/hosting/headers.js.map +1 -0
  59. package/dist/esm/hosting/httpHost.d.ts +70 -4
  60. package/dist/esm/hosting/httpHost.js +211 -47
  61. package/dist/esm/hosting/httpHost.js.map +1 -1
  62. package/dist/esm/hosting/index.d.ts +23 -8
  63. package/dist/esm/hosting/index.js +21 -6
  64. package/dist/esm/hosting/index.js.map +1 -1
  65. package/dist/esm/hosting/nodeHost.d.ts +23 -0
  66. package/dist/esm/hosting/nodeHost.js +21 -1
  67. package/dist/esm/hosting/nodeHost.js.map +1 -1
  68. package/dist/esm/hosting/types.d.ts +212 -6
  69. package/dist/esm/hosting/types.js +7 -5
  70. package/dist/esm/hosting/types.js.map +1 -1
  71. package/dist/esm/hosting/webSocketConversation.d.ts +101 -0
  72. package/dist/esm/hosting/webSocketConversation.js +341 -0
  73. package/dist/esm/hosting/webSocketConversation.js.map +1 -0
  74. package/dist/esm/hosting/webSocketFrames.d.ts +164 -0
  75. package/dist/esm/hosting/webSocketFrames.js +284 -0
  76. package/dist/esm/hosting/webSocketFrames.js.map +1 -0
  77. package/dist/esm/hosting-providers.d.ts +7 -2
  78. package/dist/esm/hosting-providers.js +7 -2
  79. package/dist/esm/hosting-providers.js.map +1 -1
  80. package/dist/esm/index.d.ts +3 -1
  81. package/dist/esm/index.js +7 -0
  82. package/dist/esm/index.js.map +1 -1
  83. package/dist/esm/lib/mcp/mcpServe.js +25 -1
  84. package/dist/esm/lib/mcp/mcpServe.js.map +1 -1
  85. package/dist/hosting/errors.js +66 -1
  86. package/dist/hosting/errors.js.map +1 -1
  87. package/dist/hosting/headers.js +28 -0
  88. package/dist/hosting/headers.js.map +1 -0
  89. package/dist/hosting/httpHost.js +211 -47
  90. package/dist/hosting/httpHost.js.map +1 -1
  91. package/dist/hosting/index.js +23 -6
  92. package/dist/hosting/index.js.map +1 -1
  93. package/dist/hosting/nodeHost.js +20 -0
  94. package/dist/hosting/nodeHost.js.map +1 -1
  95. package/dist/hosting/types.js +7 -5
  96. package/dist/hosting/types.js.map +1 -1
  97. package/dist/hosting/webSocketConversation.js +345 -0
  98. package/dist/hosting/webSocketConversation.js.map +1 -0
  99. package/dist/hosting/webSocketFrames.js +297 -0
  100. package/dist/hosting/webSocketFrames.js.map +1 -0
  101. package/dist/hosting-providers.js +8 -2
  102. package/dist/hosting-providers.js.map +1 -1
  103. package/dist/index.js +12 -2
  104. package/dist/index.js.map +1 -1
  105. package/dist/lib/mcp/mcpServe.js +24 -0
  106. package/dist/lib/mcp/mcpServe.js.map +1 -1
  107. package/dist/types/adapters/hosting/agentcore.d.ts +50 -1
  108. package/dist/types/adapters/hosting/agentcore.d.ts.map +1 -1
  109. package/dist/types/core/agent/AgentBuilder.d.ts +71 -0
  110. package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
  111. package/dist/types/core/agent/act.d.ts +70 -0
  112. package/dist/types/core/agent/act.d.ts.map +1 -0
  113. package/dist/types/core/agent/middleware/index.d.ts +6 -1
  114. package/dist/types/core/agent/middleware/index.d.ts.map +1 -1
  115. package/dist/types/core/agent/middleware/ledger.d.ts +6 -0
  116. package/dist/types/core/agent/middleware/ledger.d.ts.map +1 -1
  117. package/dist/types/core/agent/middleware/outcomes.d.ts +15 -0
  118. package/dist/types/core/agent/middleware/outcomes.d.ts.map +1 -1
  119. package/dist/types/core/agent/middleware/runChain.d.ts +47 -0
  120. package/dist/types/core/agent/middleware/runChain.d.ts.map +1 -1
  121. package/dist/types/core/agent/middleware/types.d.ts +132 -10
  122. package/dist/types/core/agent/middleware/types.d.ts.map +1 -1
  123. package/dist/types/core/agent/moments.d.ts +56 -0
  124. package/dist/types/core/agent/moments.d.ts.map +1 -0
  125. package/dist/types/core/agent/stages/toolCalls.d.ts +6 -1
  126. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  127. package/dist/types/events/payloads.d.ts +4 -0
  128. package/dist/types/events/payloads.d.ts.map +1 -1
  129. package/dist/types/hosting/errors.d.ts +44 -2
  130. package/dist/types/hosting/errors.d.ts.map +1 -1
  131. package/dist/types/hosting/headers.d.ts +17 -0
  132. package/dist/types/hosting/headers.d.ts.map +1 -0
  133. package/dist/types/hosting/httpHost.d.ts +70 -4
  134. package/dist/types/hosting/httpHost.d.ts.map +1 -1
  135. package/dist/types/hosting/index.d.ts +23 -8
  136. package/dist/types/hosting/index.d.ts.map +1 -1
  137. package/dist/types/hosting/nodeHost.d.ts +23 -0
  138. package/dist/types/hosting/nodeHost.d.ts.map +1 -1
  139. package/dist/types/hosting/types.d.ts +212 -6
  140. package/dist/types/hosting/types.d.ts.map +1 -1
  141. package/dist/types/hosting/webSocketConversation.d.ts +102 -0
  142. package/dist/types/hosting/webSocketConversation.d.ts.map +1 -0
  143. package/dist/types/hosting/webSocketFrames.d.ts +165 -0
  144. package/dist/types/hosting/webSocketFrames.d.ts.map +1 -0
  145. package/dist/types/hosting-providers.d.ts +7 -2
  146. package/dist/types/hosting-providers.d.ts.map +1 -1
  147. package/dist/types/index.d.ts +3 -1
  148. package/dist/types/index.d.ts.map +1 -1
  149. package/dist/types/lib/mcp/mcpServe.d.ts.map +1 -1
  150. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;AAEH,6CAAiD;AAAxC,oGAAA,KAAK,OAAA;AAAE,kGAAA,GAAG,OAAA;AAAE,mGAAA,IAAI,OAAA;AACzB,yCAA4E;AAAnE,+GAAA,kBAAkB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;AAEH,6CAAiD;AAAxC,oGAAA,KAAK,OAAA;AAAE,kGAAA,GAAG,OAAA;AAAE,mGAAA,IAAI,OAAA;AACzB,yCAA4E;AAAnE,+GAAA,kBAAkB,OAAA"}
@@ -17,6 +17,12 @@
17
17
  * disagreement from a lie into a record. Every slice taken afterwards can
18
18
  * then find the moment the value changed and who changed it.
19
19
  *
20
+ * The same reasoning covers the `'after-tool'` moment from the other side. A
21
+ * result the model was not allowed to read still HAPPENED — the tool ran, the
22
+ * side effect landed — so the refusal row carries the real result. A run that
23
+ * dropped it would record an agent that called a tool and got nothing back,
24
+ * which is not what occurred.
25
+ *
20
26
  * This is not a redaction layer, and it is not trying to be one. For the
21
27
  * `'input'` phase in particular, the ledger row is the ONLY copy of the
22
28
  * pre-scrub text anywhere in the run — the seed stage commits the
@@ -46,6 +52,7 @@ function recordDecisions(scope, rows) {
46
52
  for (const row of rows) {
47
53
  (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.middleware.decision', {
48
54
  middleware: row.middleware,
55
+ moment: row.moment,
49
56
  at: row.at,
50
57
  ...(row.phase !== undefined && { phase: row.phase }),
51
58
  ...(row.toolName !== undefined && { toolName: row.toolName }),
@@ -1 +1 @@
1
- {"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/ledger.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;;;AAEH,uEAAiE;AASjE;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,KAAkB,EAAE,IAAmC;IACrF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC9B,MAAM,IAAI,GAAI,KAAK,CAAC,mBAAiE,IAAI,EAAE,CAAC;IAC5F,2EAA2E;IAC3E,4EAA4E;IAC5E,yEAAyE;IACzE,KAAK,CAAC,mBAAmB,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;IAC/C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAA,wBAAS,EAAC,KAAK,EAAE,oCAAoC,EAAE;YACrD,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC7D,GAAG,CAAC,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC;YACnE,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;SAC/C,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AApBD,0CAoBC"}
1
+ {"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/ledger.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;;;AAEH,uEAAiE;AASjE;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,KAAkB,EAAE,IAAmC;IACrF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC9B,MAAM,IAAI,GAAI,KAAK,CAAC,mBAAiE,IAAI,EAAE,CAAC;IAC5F,2EAA2E;IAC3E,4EAA4E;IAC5E,yEAAyE;IACzE,KAAK,CAAC,mBAAmB,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;IAC/C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAA,wBAAS,EAAC,KAAK,EAAE,oCAAoC,EAAE;YACrD,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC7D,GAAG,CAAC,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC;YACnE,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;SAC/C,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AArBD,0CAqBC"}
@@ -18,8 +18,9 @@
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.ask = exports.deny = exports.allow = void 0;
20
20
  function allow(value, why) {
21
- if (value === undefined)
22
- return { kind: 'allow' };
21
+ if (value === undefined) {
22
+ return typeof why === 'string' && why.length > 0 ? { kind: 'allow', why } : { kind: 'allow' };
23
+ }
23
24
  if (typeof why !== 'string' || why.length === 0) {
24
25
  throw new Error('allow(value, why): a transform must say why. Pass a short reason — it is what the ' +
25
26
  'ledger shows next to the before/after pair. To pass the value through unchanged, ' +
@@ -34,6 +35,12 @@ exports.allow = allow;
34
35
  * For a tool the reason reaches the model verbatim, as the tool's result,
35
36
  * and the loop continues — the agent gets to adapt. For a message it
36
37
  * surfaces as a `MessageDeniedError`.
38
+ *
39
+ * At the after-tool moment it means "the model does not get to read this" — the
40
+ * tool has already run, so the refusal replaces what the model reads while
41
+ * the run keeps the real result in the ledger. Refusing there hides an answer
42
+ * from the model; it cannot un-happen a side effect, and it does not pretend
43
+ * to.
37
44
  */
38
45
  function deny(reason) {
39
46
  if (typeof reason !== 'string' || reason.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"outcomes.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/outcomes.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAcH,SAAgB,KAAK,CAAI,KAAS,EAAE,GAAY;IAC9C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAClD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CACb,oFAAoF;YAClF,mFAAmF;YACnF,iCAAiC,CACpC,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACvC,CAAC;AAVD,sBAUC;AAED;;;;;;GAMG;AACH,SAAgB,IAAI,CAAC,MAAc;IACjC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CACb,mFAAmF;YACjF,qEAAqE,CACxE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAClC,CAAC;AARD,oBAQC;AAED;;;;;;;;GAQG;AACH,SAAgB,GAAG,CAAC,OAAmB;IACrC,IACE,OAAO,KAAK,IAAI;QAChB,OAAO,OAAO,KAAK,QAAQ;QAC3B,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ;QACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAC7B,CAAC;QACD,MAAM,IAAI,KAAK,CACb,uFAAuF;YACrF,gDAAgD,CACnD,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC;AAbD,kBAaC"}
1
+ {"version":3,"file":"outcomes.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/outcomes.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAuBH,SAAgB,KAAK,CAAI,KAAS,EAAE,GAAY;IAC9C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAChG,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CACb,oFAAoF;YAClF,mFAAmF;YACnF,iCAAiC,CACpC,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACvC,CAAC;AAZD,sBAYC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,IAAI,CAAC,MAAc;IACjC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CACb,mFAAmF;YACjF,qEAAqE,CACxE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAClC,CAAC;AARD,oBAQC;AAED;;;;;;;;GAQG;AACH,SAAgB,GAAG,CAAC,OAAmB;IACrC,IACE,OAAO,KAAK,IAAI;QAChB,OAAO,OAAO,KAAK,QAAQ;QAC3B,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ;QACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAC7B,CAAC;QACD,MAAM,IAAI,KAAK,CACb,uFAAuF;YACrF,gDAAgD,CACnD,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC;AAbD,kBAaC"}
@@ -26,9 +26,19 @@
26
26
  * permission gate has always applied to a checker that throws: a
27
27
  * governance layer whose failure mode is "allow" is not a governance
28
28
  * layer.
29
+ *
30
+ * **The result comes back through the onion.** `runToolAfterChain` walks the
31
+ * SAME list in reverse, so the first-declared link gets the first word about
32
+ * the call and the last word about the result. An outer rule is the one that
33
+ * sees what every inner rule already did — which is the only order in which
34
+ * "wrap" means anything.
35
+ *
36
+ * **A link that has no hook for a moment files no row.** It did not decide;
37
+ * saying it allowed would be inventing a decision, and the ledger's whole
38
+ * value is that a row means somebody looked.
29
39
  */
30
40
  Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.runMessageChain = exports.runToolChain = void 0;
41
+ exports.runMessageChain = exports.runToolAfterChain = exports.runToolChain = void 0;
32
42
  /** Walk the tool chain. Never throws — a throwing link becomes a denial. */
33
43
  async function runToolChain(chain, input) {
34
44
  const decisions = [];
@@ -36,8 +46,13 @@ async function runToolChain(chain, input) {
36
46
  let args = input.args;
37
47
  for (let i = input.startIndex ?? 0; i < chain.length; i++) {
38
48
  const mw = chain[i];
49
+ // A result-only link takes no part in dispatch — and files no row here,
50
+ // because it did not decide anything about this call.
51
+ if (typeof mw.onToolCall !== 'function')
52
+ continue;
39
53
  const row = (extra) => ({
40
54
  middleware: mw.name,
55
+ moment: 'before-tool',
41
56
  at: 'tool',
42
57
  toolName: input.toolName,
43
58
  toolCallId: input.toolCallId,
@@ -94,12 +109,90 @@ async function runToolChain(chain, input) {
94
109
  decisions.push(row({ changed: true, ...(outcome.why && { why: outcome.why }), before, after: args }));
95
110
  }
96
111
  else {
97
- decisions.push(row({}));
112
+ // `allow(undefined, why)` — nothing moved, and the link said why it was
113
+ // comfortable. The reason belongs on the row of the call it permitted.
114
+ decisions.push(row(outcome.why ? { why: outcome.why } : {}));
98
115
  }
99
116
  }
100
117
  return { kind: 'allow', args, decisions };
101
118
  }
102
119
  exports.runToolChain = runToolChain;
120
+ /**
121
+ * Walk the chain BACKWARDS over a finished call. Never throws — a throwing
122
+ * link becomes a denial, which at this moment means the model reads the
123
+ * reason instead of the result.
124
+ *
125
+ * Only called for a call that actually executed. A call the chain denied, or
126
+ * one still waiting on a person, has no result to decide about, and asking a
127
+ * rule about a result that does not exist would be the same fabrication the
128
+ * outcome union exists to prevent.
129
+ */
130
+ async function runToolAfterChain(chain, input) {
131
+ const decisions = [];
132
+ const real = input.result;
133
+ let result = real;
134
+ // Reverse: first-declared saw the call first, so it sees the result last.
135
+ for (let i = chain.length - 1; i >= 0; i--) {
136
+ const mw = chain[i];
137
+ const hook = mw.onToolResult;
138
+ if (typeof hook !== 'function')
139
+ continue;
140
+ const row = (extra) => ({
141
+ middleware: mw.name,
142
+ moment: 'after-tool',
143
+ at: 'tool',
144
+ toolName: input.toolName,
145
+ toolCallId: input.toolCallId,
146
+ iteration: input.iteration,
147
+ outcome: 'allow',
148
+ changed: false,
149
+ ...extra,
150
+ });
151
+ let outcome;
152
+ try {
153
+ outcome = await hook.call(mw, {
154
+ toolName: input.toolName,
155
+ ...(input.toolSource !== undefined && { toolSource: input.toolSource }),
156
+ toolCallId: input.toolCallId,
157
+ iteration: input.iteration,
158
+ args: input.args,
159
+ result,
160
+ ...(input.error === true && { error: true }),
161
+ history: input.history,
162
+ ...(input.identity && { identity: input.identity }),
163
+ ...(input.signal && { signal: input.signal }),
164
+ });
165
+ }
166
+ catch (err) {
167
+ const reason = `middleware '${mw.name}' threw: ${err instanceof Error ? err.message : String(err)}`;
168
+ decisions.push(row({ outcome: 'deny', changed: true, why: reason, before: result, after: reason }));
169
+ return { kind: 'deny', reason, middleware: mw.name, result: real, decisions };
170
+ }
171
+ if (outcome.kind === 'deny') {
172
+ // `changed: true` on purpose: unlike a refusal before dispatch, this one
173
+ // DOES replace something. The real result rides `before` — often the
174
+ // only copy of it in the run.
175
+ decisions.push(row({
176
+ outcome: 'deny',
177
+ changed: true,
178
+ why: outcome.reason,
179
+ before: result,
180
+ after: outcome.reason,
181
+ }));
182
+ return { kind: 'deny', reason: outcome.reason, middleware: mw.name, result: real, decisions };
183
+ }
184
+ if (outcome.value !== undefined) {
185
+ const before = result;
186
+ result = outcome.value;
187
+ decisions.push(row({ changed: true, ...(outcome.why && { why: outcome.why }), before, after: result }));
188
+ }
189
+ else {
190
+ decisions.push(row(outcome.why ? { why: outcome.why } : {}));
191
+ }
192
+ }
193
+ return { kind: 'allow', result, decisions };
194
+ }
195
+ exports.runToolAfterChain = runToolAfterChain;
103
196
  /** Walk the message chain. Never throws — a throwing link becomes a denial. */
104
197
  async function runMessageChain(chain, input) {
105
198
  const decisions = [];
@@ -107,6 +200,7 @@ async function runMessageChain(chain, input) {
107
200
  for (const mw of chain) {
108
201
  const row = (extra) => ({
109
202
  middleware: mw.name,
203
+ moment: input.phase,
110
204
  at: 'message',
111
205
  phase: input.phase,
112
206
  iteration: input.iteration,
@@ -139,7 +233,7 @@ async function runMessageChain(chain, input) {
139
233
  decisions.push(row({ changed: true, ...(outcome.why && { why: outcome.why }), before, after: content }));
140
234
  }
141
235
  else {
142
- decisions.push(row({}));
236
+ decisions.push(row(outcome.why ? { why: outcome.why } : {}));
143
237
  }
144
238
  }
145
239
  return { kind: 'allow', content, decisions };
@@ -1 +1 @@
1
- {"version":3,"file":"runChain.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/runChain.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runChain.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/runChain.ts"],"names":[],"mappings":"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"}
@@ -36,6 +36,36 @@
36
36
  * `checkIn` and `askHuman` already go through. `MessageOutcome` does not,
37
37
  * because the message boundary is a plain stage, and inventing a second
38
38
  * pause to give it one would be a worse answer than not offering it.
39
+ * `ToolResultOutcome` does not either — see below.
40
+ *
41
+ * ## The two moments of a tool call
42
+ *
43
+ * A tool middleware may speak twice about one call:
44
+ *
45
+ * `onToolCall` BEFORE dispatch — about the call. Three verbs.
46
+ * `onToolResult` AFTER the tool ran, before its result enters the history
47
+ * or reaches the model — about the result. Two verbs.
48
+ *
49
+ * Each hook is named for what it RECEIVES; the moments they sit at are named
50
+ * `'before-tool'` and `'after-tool'` (and `.act()`'s keys after those).
51
+ *
52
+ * Either hook alone is a whole middleware; a link with only `onToolResult`
53
+ * does not take part in dispatch at all. The chain walks the two moments in **onion
54
+ * order**: the first-declared link sees the CALL first and the RESULT last —
55
+ * first word going in, last word coming out — which is the order that lets an
56
+ * outer rule inspect what every inner rule already did.
57
+ *
58
+ * **There is no `ask` at the after-tool moment.** Not because the machinery is missing —
59
+ * the dispatch loop pauses perfectly well — but because the tool has ALREADY
60
+ * RUN. A person woken to answer a question about a side effect that already
61
+ * happened cannot prevent it; the honest verbs there are "let the result
62
+ * through" and "do not let the model see it", and both are available now. The
63
+ * business cases this was measured against — authorize before, hide from the
64
+ * model, annotate the result, attach a fact through a context trigger — none
65
+ * of them needed a person at that moment. This is a refusal, not an oversight,
66
+ * and it is written here so evidence can promote it later: bring a case that
67
+ * genuinely needs a human at the after-tool moment and the arm can be added, on the
68
+ * pause machinery that already exists.
39
69
  */
40
70
  Object.defineProperty(exports, "__esModule", { value: true });
41
71
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/agent/middleware/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ /**
3
+ * moments — PUBLIC. The five places in the loop where a rule may speak.
4
+ *
5
+ * Pattern: Closed enumeration + a mechanical name mapping, with the mapping
6
+ * pinned by the compiler rather than by memory.
7
+ * Role: core/ layer. `LoopMoment` is the vocabulary `.act()` is keyed on
8
+ * and the vocabulary every ledger row now stamps itself with, so a
9
+ * person asking "where in the loop did this happen?" and a person
10
+ * asking "where in the loop can I intervene?" are reading the same
11
+ * five words.
12
+ * Emits: N/A (types + one pure function).
13
+ *
14
+ * ## Why the list is here and not inside `.act()`
15
+ *
16
+ * A bundle whose keys ARE the moments is only honest while the two sets
17
+ * agree. Keep the list of moments in the options type and the sixth moment
18
+ * ships with no key and nothing notices; keep it here, derive the key names
19
+ * from it, and the day a moment is added the build fails inside `act.ts`
20
+ * naming the key nobody wrote. That is the same trick `conformSource` plays
21
+ * on the outside world, turned inward on ourselves.
22
+ *
23
+ * The mapping between the two spellings is mechanical — kebab in the record
24
+ * (`'before-tool'`, which reads as a phase), camel in the bundle
25
+ * (`beforeTool`, which reads as a property) — and `actKeyFor` is its runtime
26
+ * twin, so the validator that decides which keys `.act()` accepts is
27
+ * DERIVED from this list rather than typed out beside it.
28
+ */
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.actKeyFor = exports.LOOP_MOMENTS = void 0;
31
+ /**
32
+ * Every moment of one agent turn where a rule may act, in the order the loop
33
+ * reaches them.
34
+ *
35
+ * ```
36
+ * input → [ window → … LLM … → before-tool → tool → after-tool ]* → output
37
+ * ```
38
+ *
39
+ * `watch` attends all five and more; `act` attends exactly these. The
40
+ * difference is what a rule may DO there — an observer reports, a rule
41
+ * changes what happens next.
42
+ */
43
+ exports.LOOP_MOMENTS = ['input', 'before-tool', 'after-tool', 'window', 'output'];
44
+ /**
45
+ * The runtime twin of {@link ActKey}. `.act()`'s accepted key set is built
46
+ * from this over `LOOP_MOMENTS`, so an unknown key is refused by a rule that
47
+ * cannot fall behind the list it is derived from.
48
+ */
49
+ function actKeyFor(moment) {
50
+ return moment.replace(/-(.)/g, (_match, c) => c.toUpperCase());
51
+ }
52
+ exports.actKeyFor = actKeyFor;
53
+ //# sourceMappingURL=moments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moments.js","sourceRoot":"","sources":["../../../src/core/agent/moments.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;;;AAEH;;;;;;;;;;;GAWG;AACU,QAAA,YAAY,GAAG,CAAC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAehG;;;;GAIG;AACH,SAAgB,SAAS,CAAC,MAAkB;IAC1C,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAW,CAAC;AACnF,CAAC;AAFD,8BAEC"}
@@ -24,7 +24,7 @@
24
24
  * Gate order for one call, and why it is this order:
25
25
  *
26
26
  * permission → MIDDLEWARE CHAIN → arg validation → check-in →
27
- * credentials → execute
27
+ * credentials → execute → THE CHAIN AGAIN, BACKWARDS (`onToolResult`)
28
28
  *
29
29
  * The chain sits after the permission gate so an existing checker still
30
30
  * decides first (a denial there means no middleware runs), and before arg
@@ -34,6 +34,11 @@
34
34
  * pauses on the SAME wire `checkIn` uses; the human's answer is a
35
35
  * decision, not a result, so the chain resumes and the REAL tool runs.
36
36
  *
37
+ * The last step is the same chain walked BACKWARDS over the result, before it
38
+ * becomes history — so the first-declared rule has the first word about the
39
+ * call and the last word about the answer. It runs only for a call that
40
+ * executed: everything the gates above refuse has no result to decide about.
41
+ *
37
42
  * `read_skill` is the auto-attached activation tool — when the LLM
38
43
  * calls it with a valid Skill id, the next InjectionEngine pass
39
44
  * activates that Skill (lifetime: turn).
@@ -73,6 +78,45 @@ function buildToolCallsHandler(deps) {
73
78
  const cached = providerToolCache?.current ?? [];
74
79
  return cached.find((t) => t.schema.name === toolName);
75
80
  };
81
+ /**
82
+ * The after-tool moment: the chain's last word, on a call that RAN.
83
+ *
84
+ * Called from all three dispatch sites (the loop, an approved ask, an
85
+ * approved check-in) and from nowhere else — every one of them has just
86
+ * executed a tool, which is the entire precondition. A call the chain
87
+ * denied, a call whose args were rejected, a call whose credential never
88
+ * issued and a call still waiting on a person have no result, and asking a
89
+ * rule about a result that does not exist would be the same fabrication the
90
+ * outcome union removes.
91
+ *
92
+ * Returns what the MODEL reads. The real result stays with the caller for
93
+ * `stream.tool_end`, so an event stream keeps reporting what the tool
94
+ * returned while the history carries what the rules allowed through — and
95
+ * the ledger row beside them says which is which.
96
+ */
97
+ const afterMoment = async (scope, call) => {
98
+ const chain = deps.toolMiddleware ?? [];
99
+ // No `onToolResult` hook anywhere in the chain → no walk, no rows, no await
100
+ // beyond the ones this dispatch already made. An agent whose middleware
101
+ // only governs calls is byte-identical to one built before this moment
102
+ // existed.
103
+ if (!chain.some((mw) => typeof mw.onToolResult === 'function'))
104
+ return call.result;
105
+ const verdict = await (0, runChain_js_1.runToolAfterChain)(chain, {
106
+ toolName: call.toolName,
107
+ ...(call.tool?.source !== undefined && { toolSource: call.tool.source }),
108
+ toolCallId: call.toolCallId,
109
+ iteration: call.iteration,
110
+ args: call.args,
111
+ result: call.result,
112
+ ...(call.error === true && { error: true }),
113
+ history: call.history,
114
+ ...(call.identity && { identity: call.identity }),
115
+ ...(call.signal && { signal: call.signal }),
116
+ });
117
+ (0, ledger_js_1.recordDecisions)(scope, verdict.decisions);
118
+ return verdict.kind === 'deny' ? verdict.reason : verdict.result;
119
+ };
76
120
  // Resolve a tool's declared credential (declare-and-push) and execute it,
77
121
  // emitting the same credential.* events as the main loop. Used by the
78
122
  // check-in RESUME path when a human APPROVES — the tool never ran at pause
@@ -137,16 +181,24 @@ function buildToolCallsHandler(deps) {
137
181
  hasCredentials,
138
182
  ...(resolvedCredential && { credential: resolvedCredential }),
139
183
  });
140
- return { result };
184
+ return { result, executed: true };
141
185
  }
142
186
  catch (err) {
143
187
  if ((0, pause_js_1.isPauseRequest)(err)) {
144
188
  return {
145
189
  result: `tool '${toolName}' requested a pause while resuming an approved check-in, which is not supported`,
146
190
  error: true,
191
+ // It ran — a tool that asked to pause had already started work.
192
+ executed: true,
147
193
  };
148
194
  }
149
- return { result: err instanceof Error ? err.message : String(err), error: true };
195
+ // A tool that threw still RAN, and may have done half its work; the
196
+ // after-tool moment exists precisely for the rules that care about that.
197
+ return {
198
+ result: err instanceof Error ? err.message : String(err),
199
+ error: true,
200
+ executed: true,
201
+ };
150
202
  }
151
203
  };
152
204
  return {
@@ -234,6 +286,8 @@ function buildToolCallsHandler(deps) {
234
286
  // answer to "what did this call really run with".
235
287
  let callArgs = tc.args;
236
288
  let denied = false;
289
+ /** True once `tool.execute` has been entered — see `afterMoment`. */
290
+ let executed = false;
237
291
  let haltContext;
238
292
  if (permissionChecker) {
239
293
  try {
@@ -500,6 +554,10 @@ function buildToolCallsHandler(deps) {
500
554
  try {
501
555
  if (!tool)
502
556
  throw new Error(`Unknown tool: ${tc.name}`);
557
+ // Set BEFORE the await: a tool that throws has still run, and a
558
+ // tool that does not exist has not. This flag is the entire
559
+ // precondition of the after-tool moment below.
560
+ executed = true;
503
561
  result = await tool.execute(callArgs, {
504
562
  toolCallId: tc.id,
505
563
  iteration,
@@ -559,6 +617,24 @@ function buildToolCallsHandler(deps) {
559
617
  }
560
618
  }
561
619
  }
620
+ // ── The after-tool moment ────────────────────────────────────────
621
+ // Last thing before the result becomes history, and only for a call
622
+ // that ran. `modelResult` is what the model reads; `result` stays the
623
+ // truth about the tool and is what `stream.tool_end` reports.
624
+ const modelResult = executed
625
+ ? await afterMoment(scope, {
626
+ ...(tool && { tool }),
627
+ toolName: tc.name,
628
+ toolCallId: tc.id,
629
+ iteration,
630
+ args: callArgs,
631
+ result,
632
+ ...(error === true && { error: true }),
633
+ history: newHistory,
634
+ ...(runIdentity && { identity: runIdentity }),
635
+ ...(env.signal && { signal: env.signal }),
636
+ })
637
+ : result;
562
638
  const durationMs = Date.now() - startMs;
563
639
  (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.stream.tool_end', {
564
640
  toolCallId: tc.id,
@@ -566,7 +642,7 @@ function buildToolCallsHandler(deps) {
566
642
  durationMs,
567
643
  ...(error === true && { error: true }),
568
644
  });
569
- const resultStr = typeof result === 'string' ? result : (0, validators_js_1.safeStringify)(result);
645
+ const resultStr = typeof modelResult === 'string' ? modelResult : (0, validators_js_1.safeStringify)(modelResult);
570
646
  newHistory.push({
571
647
  role: 'tool',
572
648
  content: resultStr,
@@ -673,12 +749,16 @@ function buildToolCallsHandler(deps) {
673
749
  ? input
674
750
  : (0, checkin_js_1.checkInDeclined)({ by: 'unknown', note: 'resume input was not a CheckInDecision' });
675
751
  let result;
752
+ /** What the model reads. Differs from `result` only when a rule at the
753
+ * after-tool moment transformed or withheld it. */
754
+ let modelResult;
676
755
  let error;
677
756
  if (!decision.approved) {
678
757
  result = decision.note ? `declined by human: ${decision.note}` : 'declined by human';
679
758
  (0, ledger_js_1.recordDecisions)(scope, [
680
759
  {
681
760
  middleware: askedBy,
761
+ moment: 'before-tool',
682
762
  at: 'tool',
683
763
  toolName,
684
764
  toolCallId,
@@ -693,6 +773,7 @@ function buildToolCallsHandler(deps) {
693
773
  (0, ledger_js_1.recordDecisions)(scope, [
694
774
  {
695
775
  middleware: askedBy,
776
+ moment: 'before-tool',
696
777
  at: 'tool',
697
778
  toolName,
698
779
  toolCallId,
@@ -747,9 +828,30 @@ function buildToolCallsHandler(deps) {
747
828
  const dispatched = await resolveCredentialAndExecute(scope, tool, toolName, rest.args, toolCallId, iteration, env);
748
829
  result = dispatched.result;
749
830
  error = dispatched.error;
831
+ // The tool ran on this side of the pause, so the chain gets its
832
+ // last word here too — a rule about results cannot be skipped by
833
+ // routing a call through a human.
834
+ if (dispatched.executed === true) {
835
+ modelResult = await afterMoment(scope, {
836
+ ...(tool && { tool }),
837
+ toolName,
838
+ toolCallId,
839
+ iteration,
840
+ args: rest.args,
841
+ result,
842
+ ...(error === true && { error: true }),
843
+ history: [...scope.history],
844
+ ...(scope.runIdentity && { identity: scope.runIdentity }),
845
+ ...(env.signal && { signal: env.signal }),
846
+ });
847
+ }
750
848
  }
751
849
  }
752
- const askResultStr = typeof result === 'string' ? result : (0, validators_js_1.safeStringify)(result);
850
+ // `modelResult` is only set where the after-tool moment ran; everywhere
851
+ // else the two are the same value.
852
+ if (modelResult === undefined)
853
+ modelResult = result;
854
+ const askResultStr = typeof modelResult === 'string' ? modelResult : (0, validators_js_1.safeStringify)(modelResult);
753
855
  const askHistory = [
754
856
  ...scope.history,
755
857
  { role: 'tool', content: askResultStr, toolCallId, toolName },
@@ -803,17 +905,38 @@ function buildToolCallsHandler(deps) {
803
905
  ...(decision.note !== undefined && { note: decision.note }),
804
906
  });
805
907
  let result;
908
+ /** What the model reads — see the ask path above. */
909
+ let modelResult;
806
910
  let error;
807
911
  if (decision.approved) {
808
912
  const env = scope.$getEnv();
809
- const dispatched = await resolveCredentialAndExecute(scope, lookupTool(toolName), toolName, args, toolCallId, iteration, env);
913
+ const tool = lookupTool(toolName);
914
+ const dispatched = await resolveCredentialAndExecute(scope, tool, toolName, args, toolCallId, iteration, env);
810
915
  result = dispatched.result;
811
916
  error = dispatched.error;
917
+ // Consent moved the execution to this side of the pause; the rules
918
+ // about results move with it.
919
+ if (dispatched.executed === true) {
920
+ modelResult = await afterMoment(scope, {
921
+ ...(tool && { tool }),
922
+ toolName,
923
+ toolCallId,
924
+ iteration,
925
+ args,
926
+ result,
927
+ ...(error === true && { error: true }),
928
+ history: [...scope.history],
929
+ ...(scope.runIdentity && { identity: scope.runIdentity }),
930
+ ...(env.signal && { signal: env.signal }),
931
+ });
932
+ }
812
933
  }
813
934
  else {
814
935
  result = decision.note ? `declined by human: ${decision.note}` : 'declined by human';
815
936
  }
816
- const decisionResultStr = typeof result === 'string' ? result : (0, validators_js_1.safeStringify)(result);
937
+ if (modelResult === undefined)
938
+ modelResult = result;
939
+ const decisionResultStr = typeof modelResult === 'string' ? modelResult : (0, validators_js_1.safeStringify)(modelResult);
817
940
  const decisionHistory = [
818
941
  ...scope.history,
819
942
  { role: 'tool', content: decisionResultStr, toolCallId, toolName },