agentfootprint 9.20.0 → 9.22.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 (181) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/README.md +1 -0
  4. package/ai-instructions/claude-code/SKILL.md +1 -1
  5. package/dist/artifacts/capability.js +131 -0
  6. package/dist/artifacts/capability.js.map +1 -0
  7. package/dist/artifacts/fileArtifacts.js +230 -0
  8. package/dist/artifacts/fileArtifacts.js.map +1 -0
  9. package/dist/artifacts/inMemoryArtifacts.js +165 -0
  10. package/dist/artifacts/inMemoryArtifacts.js.map +1 -0
  11. package/dist/artifacts/index.js +47 -0
  12. package/dist/artifacts/index.js.map +1 -0
  13. package/dist/artifacts/minting.js +79 -0
  14. package/dist/artifacts/minting.js.map +1 -0
  15. package/dist/artifacts/naming.js +64 -0
  16. package/dist/artifacts/naming.js.map +1 -0
  17. package/dist/artifacts/payload.js +113 -0
  18. package/dist/artifacts/payload.js.map +1 -0
  19. package/dist/artifacts/placement.js +86 -0
  20. package/dist/artifacts/placement.js.map +1 -0
  21. package/dist/artifacts/present.js +98 -0
  22. package/dist/artifacts/present.js.map +1 -0
  23. package/dist/artifacts/retention.js +121 -0
  24. package/dist/artifacts/retention.js.map +1 -0
  25. package/dist/artifacts/sqliteArtifacts.js +338 -0
  26. package/dist/artifacts/sqliteArtifacts.js.map +1 -0
  27. package/dist/artifacts/types.js +96 -0
  28. package/dist/artifacts/types.js.map +1 -0
  29. package/dist/artifacts/wants.js +240 -0
  30. package/dist/artifacts/wants.js.map +1 -0
  31. package/dist/core/Agent.js +73 -2
  32. package/dist/core/Agent.js.map +1 -1
  33. package/dist/core/agent/buildToolRegistry.js +30 -1
  34. package/dist/core/agent/buildToolRegistry.js.map +1 -1
  35. package/dist/core/agent/presentTool.js +59 -0
  36. package/dist/core/agent/presentTool.js.map +1 -0
  37. package/dist/core/agent/stages/toolCalls.js +347 -8
  38. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  39. package/dist/core/codeRunnerTool.js +89 -3
  40. package/dist/core/codeRunnerTool.js.map +1 -1
  41. package/dist/core/tools.js +7 -0
  42. package/dist/core/tools.js.map +1 -1
  43. package/dist/esm/adapters/types.d.ts +17 -1
  44. package/dist/esm/artifacts/capability.d.ts +93 -0
  45. package/dist/esm/artifacts/capability.js +126 -0
  46. package/dist/esm/artifacts/capability.js.map +1 -0
  47. package/dist/esm/artifacts/fileArtifacts.d.ts +58 -0
  48. package/dist/esm/artifacts/fileArtifacts.js +225 -0
  49. package/dist/esm/artifacts/fileArtifacts.js.map +1 -0
  50. package/dist/esm/artifacts/inMemoryArtifacts.d.ts +54 -0
  51. package/dist/esm/artifacts/inMemoryArtifacts.js +161 -0
  52. package/dist/esm/artifacts/inMemoryArtifacts.js.map +1 -0
  53. package/dist/esm/artifacts/index.d.ts +21 -0
  54. package/dist/esm/artifacts/index.js +21 -0
  55. package/dist/esm/artifacts/index.js.map +1 -0
  56. package/dist/esm/artifacts/minting.d.ts +29 -0
  57. package/dist/esm/artifacts/minting.js +75 -0
  58. package/dist/esm/artifacts/minting.js.map +1 -0
  59. package/dist/esm/artifacts/naming.d.ts +36 -0
  60. package/dist/esm/artifacts/naming.js +59 -0
  61. package/dist/esm/artifacts/naming.js.map +1 -0
  62. package/dist/esm/artifacts/payload.d.ts +43 -0
  63. package/dist/esm/artifacts/payload.js +105 -0
  64. package/dist/esm/artifacts/payload.js.map +1 -0
  65. package/dist/esm/artifacts/placement.d.ts +74 -0
  66. package/dist/esm/artifacts/placement.js +79 -0
  67. package/dist/esm/artifacts/placement.js.map +1 -0
  68. package/dist/esm/artifacts/present.d.ts +77 -0
  69. package/dist/esm/artifacts/present.js +94 -0
  70. package/dist/esm/artifacts/present.js.map +1 -0
  71. package/dist/esm/artifacts/retention.d.ts +72 -0
  72. package/dist/esm/artifacts/retention.js +115 -0
  73. package/dist/esm/artifacts/retention.js.map +1 -0
  74. package/dist/esm/artifacts/sqliteArtifacts.d.ts +90 -0
  75. package/dist/esm/artifacts/sqliteArtifacts.js +333 -0
  76. package/dist/esm/artifacts/sqliteArtifacts.js.map +1 -0
  77. package/dist/esm/artifacts/types.d.ts +220 -0
  78. package/dist/esm/artifacts/types.js +90 -0
  79. package/dist/esm/artifacts/types.js.map +1 -0
  80. package/dist/esm/artifacts/wants.d.ts +104 -0
  81. package/dist/esm/artifacts/wants.js +234 -0
  82. package/dist/esm/artifacts/wants.js.map +1 -0
  83. package/dist/esm/core/Agent.d.ts +8 -2
  84. package/dist/esm/core/Agent.js +73 -2
  85. package/dist/esm/core/Agent.js.map +1 -1
  86. package/dist/esm/core/agent/buildToolRegistry.d.ts +11 -1
  87. package/dist/esm/core/agent/buildToolRegistry.js +30 -1
  88. package/dist/esm/core/agent/buildToolRegistry.js.map +1 -1
  89. package/dist/esm/core/agent/presentTool.d.ts +22 -0
  90. package/dist/esm/core/agent/presentTool.js +55 -0
  91. package/dist/esm/core/agent/presentTool.js.map +1 -0
  92. package/dist/esm/core/agent/stages/toolCalls.d.ts +22 -0
  93. package/dist/esm/core/agent/stages/toolCalls.js +347 -8
  94. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  95. package/dist/esm/core/agent/types.d.ts +46 -0
  96. package/dist/esm/core/codeRunnerTool.js +89 -3
  97. package/dist/esm/core/codeRunnerTool.js.map +1 -1
  98. package/dist/esm/core/tools.d.ts +49 -0
  99. package/dist/esm/core/tools.js +7 -0
  100. package/dist/esm/core/tools.js.map +1 -1
  101. package/dist/esm/events/dispatcher.d.ts +1 -1
  102. package/dist/esm/events/dispatcher.js.map +1 -1
  103. package/dist/esm/events/payloads.d.ts +83 -0
  104. package/dist/esm/events/registry.d.ts +13 -1
  105. package/dist/esm/events/registry.js +12 -0
  106. package/dist/esm/events/registry.js.map +1 -1
  107. package/dist/esm/index.d.ts +3 -1
  108. package/dist/esm/index.js +17 -0
  109. package/dist/esm/index.js.map +1 -1
  110. package/dist/esm/lib/mcp/mcpServe.js +16 -0
  111. package/dist/esm/lib/mcp/mcpServe.js.map +1 -1
  112. package/dist/esm/lib/trace-toolpack/traceToolpack.js +4 -0
  113. package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
  114. package/dist/esm/recorders/core/ArtifactsRecorder.d.ts +22 -0
  115. package/dist/esm/recorders/core/ArtifactsRecorder.js +27 -0
  116. package/dist/esm/recorders/core/ArtifactsRecorder.js.map +1 -0
  117. package/dist/events/dispatcher.js.map +1 -1
  118. package/dist/events/registry.js +12 -0
  119. package/dist/events/registry.js.map +1 -1
  120. package/dist/index.js +43 -8
  121. package/dist/index.js.map +1 -1
  122. package/dist/lib/mcp/mcpServe.js +16 -0
  123. package/dist/lib/mcp/mcpServe.js.map +1 -1
  124. package/dist/lib/trace-toolpack/traceToolpack.js +4 -0
  125. package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
  126. package/dist/recorders/core/ArtifactsRecorder.js +31 -0
  127. package/dist/recorders/core/ArtifactsRecorder.js.map +1 -0
  128. package/dist/types/adapters/types.d.ts +17 -1
  129. package/dist/types/adapters/types.d.ts.map +1 -1
  130. package/dist/types/artifacts/capability.d.ts +94 -0
  131. package/dist/types/artifacts/capability.d.ts.map +1 -0
  132. package/dist/types/artifacts/fileArtifacts.d.ts +59 -0
  133. package/dist/types/artifacts/fileArtifacts.d.ts.map +1 -0
  134. package/dist/types/artifacts/inMemoryArtifacts.d.ts +55 -0
  135. package/dist/types/artifacts/inMemoryArtifacts.d.ts.map +1 -0
  136. package/dist/types/artifacts/index.d.ts +22 -0
  137. package/dist/types/artifacts/index.d.ts.map +1 -0
  138. package/dist/types/artifacts/minting.d.ts +30 -0
  139. package/dist/types/artifacts/minting.d.ts.map +1 -0
  140. package/dist/types/artifacts/naming.d.ts +37 -0
  141. package/dist/types/artifacts/naming.d.ts.map +1 -0
  142. package/dist/types/artifacts/payload.d.ts +44 -0
  143. package/dist/types/artifacts/payload.d.ts.map +1 -0
  144. package/dist/types/artifacts/placement.d.ts +75 -0
  145. package/dist/types/artifacts/placement.d.ts.map +1 -0
  146. package/dist/types/artifacts/present.d.ts +78 -0
  147. package/dist/types/artifacts/present.d.ts.map +1 -0
  148. package/dist/types/artifacts/retention.d.ts +73 -0
  149. package/dist/types/artifacts/retention.d.ts.map +1 -0
  150. package/dist/types/artifacts/sqliteArtifacts.d.ts +91 -0
  151. package/dist/types/artifacts/sqliteArtifacts.d.ts.map +1 -0
  152. package/dist/types/artifacts/types.d.ts +221 -0
  153. package/dist/types/artifacts/types.d.ts.map +1 -0
  154. package/dist/types/artifacts/wants.d.ts +105 -0
  155. package/dist/types/artifacts/wants.d.ts.map +1 -0
  156. package/dist/types/core/Agent.d.ts +8 -2
  157. package/dist/types/core/Agent.d.ts.map +1 -1
  158. package/dist/types/core/agent/buildToolRegistry.d.ts +11 -1
  159. package/dist/types/core/agent/buildToolRegistry.d.ts.map +1 -1
  160. package/dist/types/core/agent/presentTool.d.ts +23 -0
  161. package/dist/types/core/agent/presentTool.d.ts.map +1 -0
  162. package/dist/types/core/agent/stages/toolCalls.d.ts +22 -0
  163. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  164. package/dist/types/core/agent/types.d.ts +46 -0
  165. package/dist/types/core/agent/types.d.ts.map +1 -1
  166. package/dist/types/core/codeRunnerTool.d.ts.map +1 -1
  167. package/dist/types/core/tools.d.ts +49 -0
  168. package/dist/types/core/tools.d.ts.map +1 -1
  169. package/dist/types/events/dispatcher.d.ts +1 -1
  170. package/dist/types/events/dispatcher.d.ts.map +1 -1
  171. package/dist/types/events/payloads.d.ts +83 -0
  172. package/dist/types/events/payloads.d.ts.map +1 -1
  173. package/dist/types/events/registry.d.ts +13 -1
  174. package/dist/types/events/registry.d.ts.map +1 -1
  175. package/dist/types/index.d.ts +3 -1
  176. package/dist/types/index.d.ts.map +1 -1
  177. package/dist/types/lib/mcp/mcpServe.d.ts.map +1 -1
  178. package/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
  179. package/dist/types/recorders/core/ArtifactsRecorder.d.ts +23 -0
  180. package/dist/types/recorders/core/ArtifactsRecorder.d.ts.map +1 -0
  181. package/package.json +1 -1
@@ -41,13 +41,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
41
41
  exports.buildToolRegistry = void 0;
42
42
  const skillTools_js_1 = require("../../lib/injection-engine/skillTools.js");
43
43
  const skillSteps_js_1 = require("../../lib/injection-engine/skillSteps.js");
44
+ const present_js_1 = require("../../artifacts/present.js");
45
+ const presentTool_js_1 = require("./presentTool.js");
44
46
  const tools_js_1 = require("../tools.js");
45
47
  /**
46
48
  * Compose the augmented tool registry from the static `.tool()`
47
49
  * registry + the agent's injections (skills only). Throws on tool-
48
50
  * name collisions across sources.
49
51
  */
50
- function buildToolRegistry(registry, injections) {
52
+ function buildToolRegistry(registry, injections, options = {}) {
51
53
  const skills = injections.filter((i) => i.flavor === 'skill');
52
54
  // Collect skill tools, deduping by name when the SAME Tool reference
53
55
  // is shared across skills. Different Tool implementations under the
@@ -91,9 +93,36 @@ function buildToolRegistry(registry, injections) {
91
93
  ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
92
94
  [{ name: 'read_skill', tool: (0, skillTools_js_1.buildReadSkillTool)(skills) }]
93
95
  : [];
96
+ // ── `present` — the hand-to-the-screen tool (9.22.0) ────────────────
97
+ // Auto-attached as a FULL citizen (schema offered + dispatchable) ONLY
98
+ // when a store is attached — the read_skill seam. The name is reserved
99
+ // the moment the store is: a consumer tool already holding 'present'
100
+ // would silently win the dispatch map and the model's presentations
101
+ // would run somebody else's function — accepted-and-silently-wrong, so
102
+ // it is refused by name (the skip_step law). Without a store, nothing
103
+ // here runs and a consumer's own 'present' is nobody's business.
104
+ const presentEntries = [];
105
+ if (options.hasArtifactStore === true) {
106
+ const holders = [
107
+ ...registry.map((e) => e.name),
108
+ ...skillToolEntries.map((e) => e.name),
109
+ ...sharedSkillTools.keys(),
110
+ ];
111
+ if (holders.includes(present_js_1.PRESENT_TOOL_NAME)) {
112
+ throw new Error(`Agent: tool name '${present_js_1.PRESENT_TOOL_NAME}' is reserved when an artifact store is ` +
113
+ `attached — the framework auto-attaches the hand-to-the-screen tool under that ` +
114
+ `name, and a same-named tool would silently take over the model's presentations. ` +
115
+ `Rename your tool, or drop the \`artifacts\` store.`);
116
+ }
117
+ presentEntries.push({
118
+ name: present_js_1.PRESENT_TOOL_NAME,
119
+ tool: (0, presentTool_js_1.buildPresentTool)(),
120
+ });
121
+ }
94
122
  const augmentedRegistry = [
95
123
  ...registry,
96
124
  ...readSkillEntries,
125
+ ...presentEntries,
97
126
  ...skillToolEntries,
98
127
  ];
99
128
  // Final cross-source name-uniqueness check: static .tool() vs
@@ -1 +1 @@
1
- {"version":3,"file":"buildToolRegistry.js","sourceRoot":"","sources":["../../../src/core/agent/buildToolRegistry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"buildToolRegistry.js","sourceRoot":"","sources":["../../../src/core/agent/buildToolRegistry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ /**
3
+ * presentTool — the SHELL of the auto-attached `present` tool (9.22.0).
4
+ *
5
+ * Pattern: the `skip_step` placeholder, exactly. The tool here carries the
6
+ * schema the model reads; the AUTHORITATIVE work — `head` the ref under the
7
+ * run's scope, compose the description-snapshot result, emit
8
+ * `agentfootprint.artifacts.presented` — lives in the tool-calls stage
9
+ * (`applyPresent` in `stages/toolCalls.ts`), which OVERWRITES this
10
+ * placeholder's result. Bookkeeping lives where the batch order lives: the
11
+ * stage owns the scope, the store, and the typed emit channel; a tool's
12
+ * execute owns none of them.
13
+ *
14
+ * Attached by `buildToolRegistry` ONLY when a store is attached (the
15
+ * `read_skill` seam): a storeless agent never sees the tool, never reserves
16
+ * the name, and is byte-identical.
17
+ *
18
+ * The pure half — `PRESENT_TOOL_NAME`, `presentArtifact`, the snapshot
19
+ * shapes — lives in `src/artifacts/present.ts`, which cannot import core.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.buildPresentTool = void 0;
23
+ const present_js_1 = require("../../artifacts/present.js");
24
+ const tools_js_1 = require("../tools.js");
25
+ /** Build the placeholder `present` tool. See the module header. */
26
+ function buildPresentTool() {
27
+ return (0, tools_js_1.defineTool)({
28
+ name: present_js_1.PRESENT_TOOL_NAME,
29
+ description: 'Hand a stored artifact to the screen instead of writing its contents out. Pass the ' +
30
+ "art_… ref and say how to render it (as: 'bar-chart', 'table', 'image', …); the " +
31
+ 'screen redeems the ref itself. Use this to finish an answer whose substance is data ' +
32
+ 'you stored — never retype what the store already holds.',
33
+ inputSchema: {
34
+ type: 'object',
35
+ properties: {
36
+ ref: {
37
+ type: 'string',
38
+ description: 'The art_… ref of the stored artifact to present.',
39
+ },
40
+ as: {
41
+ type: 'string',
42
+ description: "Consumer vocabulary for how the screen should render it: 'bar-chart', 'table', " +
43
+ "'image', 'markdown', … Say what it is; the screen picks the renderer.",
44
+ },
45
+ label: {
46
+ type: 'string',
47
+ description: "Optional human title for this presentation (e.g. 'Q3 sales by region').",
48
+ },
49
+ },
50
+ required: ['ref', 'as'],
51
+ additionalProperties: false,
52
+ },
53
+ execute: () => 'present noted. (Raw placeholder — the agent loop replaces this result with the ' +
54
+ 'description snapshot; reading it verbatim means the runner that dispatched present ' +
55
+ 'has no artifact store behind it.)',
56
+ });
57
+ }
58
+ exports.buildPresentTool = buildPresentTool;
59
+ //# sourceMappingURL=presentTool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentTool.js","sourceRoot":"","sources":["../../../src/core/agent/presentTool.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;AAEH,2DAA+D;AAC/D,0CAAoD;AAEpD,mEAAmE;AACnE,SAAgB,gBAAgB;IAC9B,OAAO,IAAA,qBAAU,EAAsD;QACrE,IAAI,EAAE,8BAAiB;QACvB,WAAW,EACT,qFAAqF;YACrF,iFAAiF;YACjF,sFAAsF;YACtF,yDAAyD;QAC3D,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,GAAG,EAAE;oBACH,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,kDAAkD;iBAChE;gBACD,EAAE,EAAE;oBACF,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,iFAAiF;wBACjF,uEAAuE;iBAC1E;gBACD,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,yEAAyE;iBACvF;aACF;YACD,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC;YACvB,oBAAoB,EAAE,KAAK;SAC5B;QACD,OAAO,EAAE,GAAG,EAAE,CACZ,iFAAiF;YACjF,qFAAqF;YACrF,mCAAmC;KACtC,CAAoB,CAAC;AACxB,CAAC;AAlCD,4CAkCC"}
@@ -52,6 +52,10 @@ const extractSequence_js_1 = require("../../../security/extractSequence.js");
52
52
  const skillTarget_js_1 = require("../../../security/skillTarget.js");
53
53
  const routingPolicy_js_1 = require("../../../lib/injection-engine/routingPolicy.js");
54
54
  const types_js_2 = require("../../../identity/types.js");
55
+ const capability_js_1 = require("../../../artifacts/capability.js");
56
+ const wants_js_1 = require("../../../artifacts/wants.js");
57
+ const present_js_1 = require("../../../artifacts/present.js");
58
+ const placement_js_1 = require("../../../artifacts/placement.js");
55
59
  const consent_js_1 = require("../../../identity/consent.js");
56
60
  const pause_js_1 = require("../../pause.js");
57
61
  const checkin_js_1 = require("../../checkin.js");
@@ -640,6 +644,248 @@ function buildToolCallsHandler(deps) {
640
644
  },
641
645
  };
642
646
  };
647
+ /**
648
+ * `ctx.artifacts` + `ctx.hasArtifacts` for one dispatch — the claim-check
649
+ * capability, shaped exactly like `ctx.credentials` (9.21.0).
650
+ *
651
+ * The SCOPE is `scope.runIdentity` — the tuple the seed stage committed and
652
+ * memory already scopes on (an anonymous run isolates to its own runId, a
653
+ * session-bound run to its sessionId, an identity-carrying run to the
654
+ * caller's tenant/principal). Composed HERE, where the tool cannot reach:
655
+ * the capability closes over it, so a ref alone opens nothing and a tool
656
+ * can never widen the scope it resolves under. Detached to a plain object
657
+ * so the store never holds a live scope proxy.
658
+ *
659
+ * Every fact the capability reports rides the ordinary emit channel via
660
+ * `typedEmit`, mid-stage, carrying the real runtimeStageId — collected
661
+ * during traversal, exactly like `credential.failed`. Payload bytes never
662
+ * enter an event; the facts are meta only.
663
+ *
664
+ * With NO store attached the capability is the fail-closed teacher and no
665
+ * runIdentity read happens — a storeless agent's trace stays byte-identical.
666
+ */
667
+ const toolArtifacts = (scope, toolName, toolCallId) => {
668
+ const onEvent = (fact) => {
669
+ switch (fact.type) {
670
+ case 'minted': {
671
+ const meta = fact.meta;
672
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.artifacts.minted', {
673
+ ref: meta.ref,
674
+ kind: meta.kind,
675
+ mediaType: meta.mediaType,
676
+ bytes: meta.bytes,
677
+ ...(meta.label !== undefined && { label: meta.label }),
678
+ ...(meta.digest !== undefined && { digest: meta.digest }),
679
+ ...(meta.expiresAt !== undefined && { expiresAt: meta.expiresAt }),
680
+ ...(meta.origin !== undefined && { origin: meta.origin }),
681
+ ...(meta.parentRefs !== undefined && { parentRefs: meta.parentRefs }),
682
+ tool: toolName,
683
+ });
684
+ return;
685
+ }
686
+ case 'resolved':
687
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.artifacts.resolved', {
688
+ ref: fact.ref,
689
+ via: fact.via,
690
+ kind: fact.kind,
691
+ bytes: fact.bytes,
692
+ tool: toolName,
693
+ });
694
+ return;
695
+ case 'expired':
696
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.artifacts.expired', {
697
+ ref: fact.swept.ref,
698
+ reason: fact.swept.reason,
699
+ kind: fact.swept.kind,
700
+ bytes: fact.swept.bytes,
701
+ tool: toolName,
702
+ });
703
+ return;
704
+ case 'refused':
705
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.artifacts.refused', {
706
+ op: fact.op,
707
+ reason: fact.reason,
708
+ ...(fact.ref !== undefined && { ref: fact.ref }),
709
+ ...(fact.detail !== undefined && { detail: fact.detail }),
710
+ tool: toolName,
711
+ });
712
+ return;
713
+ }
714
+ };
715
+ const store = deps.artifactStore;
716
+ if (store === undefined) {
717
+ return { artifacts: (0, capability_js_1.unconfiguredArtifacts)(onEvent), hasArtifacts: false };
718
+ }
719
+ const facts = deps.currentRun?.();
720
+ const artifacts = (0, capability_js_1.bindArtifacts)(store, runScopeOf(scope), {
721
+ origin: { ...(facts?.runId !== undefined && { runId: facts.runId }), toolCallId },
722
+ onEvent,
723
+ });
724
+ return { artifacts, hasArtifacts: true };
725
+ };
726
+ /**
727
+ * The run's artifact scope — `scope.runIdentity`, detached to a plain
728
+ * object so no store or resolver ever holds a live scope proxy. ONE
729
+ * composition shared by the capability binding, `wants` resolution,
730
+ * `present`, and placement: four doors, one isolation rule, no drift.
731
+ */
732
+ const runScopeOf = (scope) => {
733
+ const identity = scope.runIdentity;
734
+ return {
735
+ conversationId: identity.conversationId,
736
+ ...(identity.tenant !== undefined && { tenant: identity.tenant }),
737
+ ...(identity.principal !== undefined && { principal: identity.principal }),
738
+ };
739
+ };
740
+ // ── Ref ARGUMENTS at dispatch (9.22.0, Leg 1) — ONE resolver, every door ──
741
+ // The batch loop and `resolveCredentialAndExecute` (the resume paths) both
742
+ // dispatch tools; each calls this BEFORE credential resolution — never
743
+ // acquire credentials for a call that won't run — so a declared ref is
744
+ // judged identically whichever door the call came through. Success rides
745
+ // the existing `artifacts.resolved` (one event per resolved argument);
746
+ // refusals ride `artifacts.refused` with `op: 'dispatch'`, and the tool is
747
+ // NOT executed — the model reads the teaching refusal instead.
748
+ const resolveWantsAtDispatch = async (scope, toolName, wants, args) => {
749
+ const store = deps.artifactStore;
750
+ if (store === undefined) {
751
+ // Statically registered tools are refused at BUILD; this serves the
752
+ // doors that only meet the tool at dispatch (provider-served tools).
753
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.artifacts.refused', {
754
+ op: 'dispatch',
755
+ reason: 'no-store',
756
+ detail: `tool '${toolName}' declares wants but no artifact store is attached`,
757
+ tool: toolName,
758
+ });
759
+ return { ok: false, refusal: (0, wants_js_1.wantsNeedsStoreRefusal)(toolName, wants) };
760
+ }
761
+ const verdict = await (0, wants_js_1.resolveToolWants)(store, runScopeOf(scope), toolName, wants, args);
762
+ if (!verdict.ok) {
763
+ for (const refusal of verdict.refusals) {
764
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.artifacts.refused', {
765
+ op: 'dispatch',
766
+ reason: refusal.reason,
767
+ ...(refusal.ref !== undefined && { ref: refusal.ref }),
768
+ detail: refusal.detail,
769
+ tool: toolName,
770
+ });
771
+ }
772
+ return { ok: false, refusal: verdict.refusal };
773
+ }
774
+ for (const { meta } of verdict.resolved) {
775
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.artifacts.resolved', {
776
+ ref: meta.ref,
777
+ via: 'get',
778
+ kind: meta.kind,
779
+ bytes: meta.bytes,
780
+ tool: toolName,
781
+ });
782
+ }
783
+ return {
784
+ ok: true,
785
+ args: verdict.args,
786
+ // Absent when nothing resolved (no declared arg was passed): absent
787
+ // and empty are different facts, and `ctx.wanted` keeps them apart.
788
+ ...(verdict.resolved.length > 0 && { wanted: verdict.wanted }),
789
+ };
790
+ };
791
+ // ── The `present` tool's authoritative result (9.22.0, Leg 2) ──────────
792
+ // The skip_step pattern: the auto-attached placeholder ran; the stage —
793
+ // which owns the scope, the store and the emit channel — OVERWRITES its
794
+ // result with the description snapshot (or the teaching refusal), so
795
+ // governance rules and the caps compose over what the model will read.
796
+ const applyPresent = async (scope, call) => {
797
+ const store = deps.artifactStore;
798
+ if (store === undefined) {
799
+ // Unreachable through the Agent (the tool is only attached beside a
800
+ // store) — kept for the same reason the placeholder text exists.
801
+ return {
802
+ ok: false,
803
+ text: 'present has no artifact store behind it here; nothing was presented.',
804
+ };
805
+ }
806
+ const outcome = await (0, present_js_1.presentArtifact)(store, runScopeOf(scope), call.args);
807
+ if (!outcome.ok) {
808
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.artifacts.refused', {
809
+ op: 'dispatch',
810
+ reason: outcome.missedRef !== undefined ? 'missing-or-expired' : 'invalid-input',
811
+ ...(outcome.missedRef !== undefined && { ref: outcome.missedRef }),
812
+ detail: outcome.refusal,
813
+ tool: present_js_1.PRESENT_TOOL_NAME,
814
+ });
815
+ return { ok: false, text: outcome.refusal };
816
+ }
817
+ const { ref, as, snapshot } = outcome.result;
818
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.artifacts.resolved', {
819
+ ref,
820
+ via: 'head',
821
+ kind: snapshot.kind,
822
+ bytes: snapshot.bytes,
823
+ tool: present_js_1.PRESENT_TOOL_NAME,
824
+ });
825
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.artifacts.presented', {
826
+ ref,
827
+ as,
828
+ snapshot: { ...snapshot },
829
+ toolCallId: call.toolCallId,
830
+ iteration: call.iteration,
831
+ });
832
+ // The snapshot lives INSIDE the tool result — the one thing provider
833
+ // history keeps typed and durable — so a reloaded conversation can
834
+ // re-draw the pane, or state honestly why it can't.
835
+ return { ok: true, text: (0, validators_js_1.safeStringify)(outcome.result) };
836
+ };
837
+ // ── The placement threshold (9.22.0, Leg 3) — ONE judge, every door ────
838
+ // Called beside every `capResults` site, on the FINALIZED values (after
839
+ // the tool's own resultCeiling, after the after-tool chain) and before the
840
+ // truncation net — the stated precedence: author's refusal first, then the
841
+ // operator's ref-ing, then the last-resort net (which then measures the
842
+ // ticket). A placed result is a TICKET, not a refusal: the caller's
843
+ // effects/step bookkeeping proceeds exactly as if the payload had landed.
844
+ const placeResults = async (scope, call, values, eligible) => {
845
+ const placement = deps.placement;
846
+ if (placement === undefined || deps.artifactStore === undefined || !eligible)
847
+ return values;
848
+ const text = typeof values.modelResult === 'string'
849
+ ? values.modelResult
850
+ : (0, validators_js_1.safeStringify)(values.modelResult);
851
+ if (text.length <= placement.maxInlineChars)
852
+ return values;
853
+ const bound = toolArtifacts(scope, call.toolName, call.toolCallId);
854
+ let meta;
855
+ try {
856
+ // The payload stored is the EXACT text the model would have read —
857
+ // byte-faithful, so a consumer redeems precisely what was displaced.
858
+ // `mediaType` states what that text is: a JSON serialization when the
859
+ // tool returned a value, plain text when it returned a string.
860
+ meta = await bound.artifacts.put({
861
+ kind: (0, placement_js_1.placedResultKind)(call.toolName),
862
+ mediaType: typeof values.modelResult === 'string' ? 'text/plain' : 'application/json',
863
+ data: text,
864
+ label: `${call.toolName} result`,
865
+ });
866
+ }
867
+ catch (err) {
868
+ // The store could not take it (a payload over the whole scope budget,
869
+ // say). The refusal is already on the record via the capability sink;
870
+ // the honest fallback is today's path — the truncation net still
871
+ // measures what placement could not lift. Named in dev mode.
872
+ if ((0, footprintjs_1.isDevMode)()) {
873
+ // eslint-disable-next-line no-console
874
+ console.warn(`agentfootprint placement: tool '${call.toolName}' result (${text.length} chars) ` +
875
+ `exceeded the ${placement.maxInlineChars}-char threshold but could not be ` +
876
+ `stored: ${err instanceof Error ? err.message : String(err)}`);
877
+ }
878
+ return values;
879
+ }
880
+ const substitute = (0, placement_js_1.placedToolResult)(call.toolName, meta, text.length, placement.maxInlineChars);
881
+ return {
882
+ // One ticket when the two channels carry one value — the capResults
883
+ // law. A chain-transformed `result` keeps its own truth and meets the
884
+ // truncation net below, exactly as before.
885
+ result: values.result === values.modelResult ? substitute : values.result,
886
+ modelResult: substitute,
887
+ };
888
+ };
643
889
  /**
644
890
  * Fire the `'call'`-scoped cleanups this tool call registered.
645
891
  *
@@ -746,6 +992,18 @@ function buildToolCallsHandler(deps) {
746
992
  const resolveCredentialAndExecute = async (scope, tool, toolName, args, toolCallId, iteration, env) => {
747
993
  if (!tool)
748
994
  return { result: `Unknown tool: ${toolName}`, error: true };
995
+ // Declared artifact arguments (9.22.0) — the same resolution the batch
996
+ // loop applies, at this door: a resumed call's refs are judged exactly
997
+ // as an inline call's, BEFORE credentials, and a refusal means the tool
998
+ // does not run.
999
+ let wantedMeta;
1000
+ if (tool.wants !== undefined) {
1001
+ const resolution = await resolveWantsAtDispatch(scope, toolName, tool.wants, args);
1002
+ if (!resolution.ok)
1003
+ return { result: resolution.refusal, error: true };
1004
+ args = resolution.args;
1005
+ wantedMeta = resolution.wanted;
1006
+ }
749
1007
  const runIdentity = scope.runIdentity;
750
1008
  let resolvedCredential;
751
1009
  const need = tool.needs;
@@ -817,6 +1075,8 @@ function buildToolCallsHandler(deps) {
817
1075
  credentials: reportingCredentials(credentials, scope, toolName),
818
1076
  hasCredentials,
819
1077
  ...(resolvedCredential && { credential: resolvedCredential }),
1078
+ ...toolArtifacts(scope, toolName, toolCallId),
1079
+ ...(wantedMeta !== undefined && { wanted: wantedMeta }),
820
1080
  ...sessionContext(scope, toolName, toolCallId),
821
1081
  });
822
1082
  await endCall(toolCallId);
@@ -1325,6 +1585,29 @@ function buildToolCallsHandler(deps) {
1325
1585
  }
1326
1586
  }
1327
1587
  if (!denied && !argsRejected) {
1588
+ // ── Declared artifact arguments (9.22.0) ──────────────────────
1589
+ // The `needs` precedent applied to data: resolve the tool's
1590
+ // declared `wants` refs BEFORE credential resolution (never
1591
+ // acquire credentials for a call that won't run) and BEFORE
1592
+ // execute — a stale/unknown/wrong-kind ref never reaches the
1593
+ // tool; the model reads a teaching refusal listing the live refs
1594
+ // of the wanted kind. On success `callArgs` carries the RESOLVED
1595
+ // DATA and `ctx.wanted` the claim tickets. Tools without `wants`
1596
+ // take the exact path they always took.
1597
+ let wantedMeta;
1598
+ let wantsBlocked = false;
1599
+ if (tool?.wants !== undefined) {
1600
+ const resolution = await resolveWantsAtDispatch(scope, tc.name, tool.wants, callArgs);
1601
+ if (resolution.ok) {
1602
+ callArgs = resolution.args;
1603
+ wantedMeta = resolution.wanted;
1604
+ }
1605
+ else {
1606
+ wantsBlocked = true;
1607
+ error = true;
1608
+ result = resolution.refusal;
1609
+ }
1610
+ }
1328
1611
  // Declare-and-push: resolve the tool's declared credential BEFORE
1329
1612
  // invoking, and inject it as ctx.credential. On consent-required or
1330
1613
  // failure, surface the reason to the LLM (tool result) + emit; the
@@ -1332,7 +1615,7 @@ function buildToolCallsHandler(deps) {
1332
1615
  // throws is surfaced, not retried).
1333
1616
  let resolvedCredential;
1334
1617
  let credentialBlocked = false;
1335
- const need = tool?.needs;
1618
+ const need = wantsBlocked ? undefined : tool?.needs;
1336
1619
  if (need) {
1337
1620
  (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.credential.requested', {
1338
1621
  service: need.credential,
@@ -1427,7 +1710,7 @@ function buildToolCallsHandler(deps) {
1427
1710
  result = `credential error for '${need.credential}': ${reason}`;
1428
1711
  }
1429
1712
  }
1430
- if (!credentialBlocked) {
1713
+ if (!credentialBlocked && !wantsBlocked) {
1431
1714
  try {
1432
1715
  if (!tool)
1433
1716
  throw new Error(`Unknown tool: ${tc.name}`);
@@ -1442,6 +1725,8 @@ function buildToolCallsHandler(deps) {
1442
1725
  credentials: reportingCredentials(credentials, scope, tc.name),
1443
1726
  hasCredentials,
1444
1727
  ...(resolvedCredential && { credential: resolvedCredential }),
1728
+ ...toolArtifacts(scope, tc.name, tc.id),
1729
+ ...(wantedMeta !== undefined && { wanted: wantedMeta }),
1445
1730
  ...sessionContext(scope, tc.name, tc.id),
1446
1731
  });
1447
1732
  // The typed effects channel (9.19.0): a recognized envelope is
@@ -1586,6 +1871,23 @@ function buildToolCallsHandler(deps) {
1586
1871
  if (deps.stepPlanFor && tc.name === skillSteps_js_1.SKIP_STEP_TOOL_NAME && !error && !denied) {
1587
1872
  result = applySkipStep(scope, { args: callArgs, toolCallId: tc.id, iteration });
1588
1873
  }
1874
+ // ── present bookkeeping (9.22.0) ───────────────────────────────
1875
+ // Same mechanism as skip_step: the auto-attached placeholder ran;
1876
+ // the stage overwrites its result with the description snapshot (or
1877
+ // the teaching refusal) BEFORE the after-tool moment, so governance
1878
+ // and the caps compose over what the model will actually read. A
1879
+ // miss is an errored call: the model holds no presentation, and a
1880
+ // procedure step whose tool presented nothing must not advance.
1881
+ if (deps.artifactStore && tc.name === present_js_1.PRESENT_TOOL_NAME && executed && !error && !denied) {
1882
+ const presented = await applyPresent(scope, {
1883
+ args: callArgs,
1884
+ toolCallId: tc.id,
1885
+ iteration,
1886
+ });
1887
+ result = presented.text;
1888
+ if (!presented.ok)
1889
+ error = true;
1890
+ }
1589
1891
  // ── The after-tool moment ────────────────────────────────────────
1590
1892
  // Last thing before the result becomes history, and only for a call
1591
1893
  // that ran. `modelResult` is what the model reads; `result` stays the
@@ -1604,10 +1906,19 @@ function buildToolCallsHandler(deps) {
1604
1906
  ...(env.signal && { signal: env.signal }),
1605
1907
  })
1606
1908
  : result;
1909
+ // Placement next (9.22.0) — the operator's ref-ing, judged on what
1910
+ // the chain let through (a rule that already summarized a huge
1911
+ // result is measured on what it produced, the same reasoning as the
1912
+ // cap). Over the threshold, the payload is checked into the store
1913
+ // and BOTH channels carry the ticket; the truncation net below then
1914
+ // measures the ticket. A refused/denied/errored call is never
1915
+ // placed: a refusal is already short, and 'tool-result/<name>' must
1916
+ // never claim an error is the tool's result.
1917
+ const placedValues = await placeResults(scope, { toolName: tc.name, toolCallId: tc.id, iteration }, { result, modelResult: rawModelResult }, executed && !error && !denied && !ceilingRefused);
1607
1918
  // The ceiling, last — after the tool, after the chain. A rule that
1608
1919
  // already summarized a huge result is measured on what it produced, so
1609
1920
  // the cap composes with governance rather than pre-empting it.
1610
- const capped = capResults(tc.name, { result, modelResult: rawModelResult });
1921
+ const capped = capResults(tc.name, placedValues);
1611
1922
  const modelResult = capped.modelResult;
1612
1923
  const durationMs = Date.now() - startMs;
1613
1924
  (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.stream.tool_end', {
@@ -1929,6 +2240,22 @@ function buildToolCallsHandler(deps) {
1929
2240
  if (deps.stepPlanFor && toolName === skillSteps_js_1.SKIP_STEP_TOOL_NAME && stepToolRan) {
1930
2241
  result = applySkipStep(scope, { args: rest.args, toolCallId, iteration });
1931
2242
  }
2243
+ // present behind a middleware ask, approved (9.22.0): same
2244
+ // overwrite the batch loop applies — the snapshot (or refusal)
2245
+ // replaces the placeholder before the chain's last word. A miss
2246
+ // is an errored call here too.
2247
+ if (deps.artifactStore && toolName === present_js_1.PRESENT_TOOL_NAME && stepToolRan) {
2248
+ const presented = await applyPresent(scope, {
2249
+ args: rest.args,
2250
+ toolCallId,
2251
+ iteration,
2252
+ });
2253
+ result = presented.text;
2254
+ if (!presented.ok) {
2255
+ error = true;
2256
+ stepToolRan = false;
2257
+ }
2258
+ }
1932
2259
  // The tool ran on this side of the pause, so the chain gets its
1933
2260
  // last word here too — a rule about results cannot be skipped by
1934
2261
  // routing a call through a human.
@@ -1952,7 +2279,11 @@ function buildToolCallsHandler(deps) {
1952
2279
  // else the two are the same value.
1953
2280
  if (modelResult === undefined)
1954
2281
  modelResult = result;
1955
- const askCapped = capResults(toolName, { result, modelResult });
2282
+ // Placement then the truncation net — the batch loop's precedence,
2283
+ // kept on this door (a resumed result is as placeable as an inline
2284
+ // one; `stepToolRan` is exactly "ran clean").
2285
+ const askPlaced = await placeResults(scope, { toolName, toolCallId, iteration }, { result, modelResult }, stepToolRan);
2286
+ const askCapped = capResults(toolName, askPlaced);
1956
2287
  modelResult = askCapped.modelResult;
1957
2288
  let askResultStr = typeof modelResult === 'string' ? modelResult : (0, validators_js_1.safeStringify)(modelResult);
1958
2289
  // Step boundary (9.18.0) — a result finalized HERE is as final as one
@@ -2073,7 +2404,9 @@ function buildToolCallsHandler(deps) {
2073
2404
  }
2074
2405
  if (modelResult === undefined)
2075
2406
  modelResult = result;
2076
- const decisionCapped = capResults(toolName, { result, modelResult });
2407
+ // Placement then the truncation net — the batch loop's precedence.
2408
+ const decisionPlaced = await placeResults(scope, { toolName, toolCallId, iteration }, { result, modelResult }, stepToolRan);
2409
+ const decisionCapped = capResults(toolName, decisionPlaced);
2077
2410
  modelResult = decisionCapped.modelResult;
2078
2411
  let decisionResultStr = typeof modelResult === 'string' ? modelResult : (0, validators_js_1.safeStringify)(modelResult);
2079
2412
  // Step boundary (9.18.0) — an approved consequential step (a checkIn
@@ -2165,7 +2498,9 @@ function buildToolCallsHandler(deps) {
2165
2498
  }
2166
2499
  if (modelResult === undefined)
2167
2500
  modelResult = result;
2168
- const consentCapped = capResults(toolName, { result, modelResult });
2501
+ // Placement then the truncation net — the batch loop's precedence.
2502
+ const consentPlaced = await placeResults(scope, { toolName, toolCallId, iteration }, { result, modelResult }, dispatched.executed === true && error !== true && dispatched.ceilingRefused !== true);
2503
+ const consentCapped = capResults(toolName, consentPlaced);
2169
2504
  modelResult = consentCapped.modelResult;
2170
2505
  let consentResultStr = typeof modelResult === 'string' ? modelResult : (0, validators_js_1.safeStringify)(modelResult);
2171
2506
  // Step boundary (9.18.0) — a step tool that waited on 3LO consent
@@ -2269,8 +2604,12 @@ function buildToolCallsHandler(deps) {
2269
2604
  });
2270
2605
  // A person's answer is measured too. The cap is about what one turn can
2271
2606
  // afford to carry, and a pasted transcript costs a window exactly as much
2272
- // as a tool's rows do.
2273
- const pauseCapped = capResults(toolName, { result: input, modelResult: rawPauseResult });
2607
+ // as a tool's rows do — which is also why PLACEMENT judges it: the
2608
+ // handler's contract makes the answer the tool's result, so a pasted
2609
+ // 500KB transcript is checked in as `tool-result/<tool>` and the model
2610
+ // routes the ticket.
2611
+ const pausePlaced = await placeResults(scope, { toolName, toolCallId, iteration }, { result: input, modelResult: rawPauseResult }, true);
2612
+ const pauseCapped = capResults(toolName, pausePlaced);
2274
2613
  const modelResult = pauseCapped.modelResult;
2275
2614
  let resultStr = typeof modelResult === 'string' ? modelResult : (0, validators_js_1.safeStringify)(modelResult);
2276
2615
  // Step boundary (9.18.0) — THE HITL step ("ask a human, then export"):