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.
- package/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/README.md +1 -0
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/dist/artifacts/capability.js +131 -0
- package/dist/artifacts/capability.js.map +1 -0
- package/dist/artifacts/fileArtifacts.js +230 -0
- package/dist/artifacts/fileArtifacts.js.map +1 -0
- package/dist/artifacts/inMemoryArtifacts.js +165 -0
- package/dist/artifacts/inMemoryArtifacts.js.map +1 -0
- package/dist/artifacts/index.js +47 -0
- package/dist/artifacts/index.js.map +1 -0
- package/dist/artifacts/minting.js +79 -0
- package/dist/artifacts/minting.js.map +1 -0
- package/dist/artifacts/naming.js +64 -0
- package/dist/artifacts/naming.js.map +1 -0
- package/dist/artifacts/payload.js +113 -0
- package/dist/artifacts/payload.js.map +1 -0
- package/dist/artifacts/placement.js +86 -0
- package/dist/artifacts/placement.js.map +1 -0
- package/dist/artifacts/present.js +98 -0
- package/dist/artifacts/present.js.map +1 -0
- package/dist/artifacts/retention.js +121 -0
- package/dist/artifacts/retention.js.map +1 -0
- package/dist/artifacts/sqliteArtifacts.js +338 -0
- package/dist/artifacts/sqliteArtifacts.js.map +1 -0
- package/dist/artifacts/types.js +96 -0
- package/dist/artifacts/types.js.map +1 -0
- package/dist/artifacts/wants.js +240 -0
- package/dist/artifacts/wants.js.map +1 -0
- package/dist/core/Agent.js +73 -2
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/agent/buildToolRegistry.js +30 -1
- package/dist/core/agent/buildToolRegistry.js.map +1 -1
- package/dist/core/agent/presentTool.js +59 -0
- package/dist/core/agent/presentTool.js.map +1 -0
- package/dist/core/agent/stages/toolCalls.js +347 -8
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/codeRunnerTool.js +89 -3
- package/dist/core/codeRunnerTool.js.map +1 -1
- package/dist/core/tools.js +7 -0
- package/dist/core/tools.js.map +1 -1
- package/dist/esm/adapters/types.d.ts +17 -1
- package/dist/esm/artifacts/capability.d.ts +93 -0
- package/dist/esm/artifacts/capability.js +126 -0
- package/dist/esm/artifacts/capability.js.map +1 -0
- package/dist/esm/artifacts/fileArtifacts.d.ts +58 -0
- package/dist/esm/artifacts/fileArtifacts.js +225 -0
- package/dist/esm/artifacts/fileArtifacts.js.map +1 -0
- package/dist/esm/artifacts/inMemoryArtifacts.d.ts +54 -0
- package/dist/esm/artifacts/inMemoryArtifacts.js +161 -0
- package/dist/esm/artifacts/inMemoryArtifacts.js.map +1 -0
- package/dist/esm/artifacts/index.d.ts +21 -0
- package/dist/esm/artifacts/index.js +21 -0
- package/dist/esm/artifacts/index.js.map +1 -0
- package/dist/esm/artifacts/minting.d.ts +29 -0
- package/dist/esm/artifacts/minting.js +75 -0
- package/dist/esm/artifacts/minting.js.map +1 -0
- package/dist/esm/artifacts/naming.d.ts +36 -0
- package/dist/esm/artifacts/naming.js +59 -0
- package/dist/esm/artifacts/naming.js.map +1 -0
- package/dist/esm/artifacts/payload.d.ts +43 -0
- package/dist/esm/artifacts/payload.js +105 -0
- package/dist/esm/artifacts/payload.js.map +1 -0
- package/dist/esm/artifacts/placement.d.ts +74 -0
- package/dist/esm/artifacts/placement.js +79 -0
- package/dist/esm/artifacts/placement.js.map +1 -0
- package/dist/esm/artifacts/present.d.ts +77 -0
- package/dist/esm/artifacts/present.js +94 -0
- package/dist/esm/artifacts/present.js.map +1 -0
- package/dist/esm/artifacts/retention.d.ts +72 -0
- package/dist/esm/artifacts/retention.js +115 -0
- package/dist/esm/artifacts/retention.js.map +1 -0
- package/dist/esm/artifacts/sqliteArtifacts.d.ts +90 -0
- package/dist/esm/artifacts/sqliteArtifacts.js +333 -0
- package/dist/esm/artifacts/sqliteArtifacts.js.map +1 -0
- package/dist/esm/artifacts/types.d.ts +220 -0
- package/dist/esm/artifacts/types.js +90 -0
- package/dist/esm/artifacts/types.js.map +1 -0
- package/dist/esm/artifacts/wants.d.ts +104 -0
- package/dist/esm/artifacts/wants.js +234 -0
- package/dist/esm/artifacts/wants.js.map +1 -0
- package/dist/esm/core/Agent.d.ts +8 -2
- package/dist/esm/core/Agent.js +73 -2
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/agent/buildToolRegistry.d.ts +11 -1
- package/dist/esm/core/agent/buildToolRegistry.js +30 -1
- package/dist/esm/core/agent/buildToolRegistry.js.map +1 -1
- package/dist/esm/core/agent/presentTool.d.ts +22 -0
- package/dist/esm/core/agent/presentTool.js +55 -0
- package/dist/esm/core/agent/presentTool.js.map +1 -0
- package/dist/esm/core/agent/stages/toolCalls.d.ts +22 -0
- package/dist/esm/core/agent/stages/toolCalls.js +347 -8
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/agent/types.d.ts +46 -0
- package/dist/esm/core/codeRunnerTool.js +89 -3
- package/dist/esm/core/codeRunnerTool.js.map +1 -1
- package/dist/esm/core/tools.d.ts +49 -0
- package/dist/esm/core/tools.js +7 -0
- package/dist/esm/core/tools.js.map +1 -1
- package/dist/esm/events/dispatcher.d.ts +1 -1
- package/dist/esm/events/dispatcher.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +83 -0
- package/dist/esm/events/registry.d.ts +13 -1
- package/dist/esm/events/registry.js +12 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +17 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/mcp/mcpServe.js +16 -0
- package/dist/esm/lib/mcp/mcpServe.js.map +1 -1
- package/dist/esm/lib/trace-toolpack/traceToolpack.js +4 -0
- package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
- package/dist/esm/recorders/core/ArtifactsRecorder.d.ts +22 -0
- package/dist/esm/recorders/core/ArtifactsRecorder.js +27 -0
- package/dist/esm/recorders/core/ArtifactsRecorder.js.map +1 -0
- package/dist/events/dispatcher.js.map +1 -1
- package/dist/events/registry.js +12 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/index.js +43 -8
- package/dist/index.js.map +1 -1
- package/dist/lib/mcp/mcpServe.js +16 -0
- package/dist/lib/mcp/mcpServe.js.map +1 -1
- package/dist/lib/trace-toolpack/traceToolpack.js +4 -0
- package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
- package/dist/recorders/core/ArtifactsRecorder.js +31 -0
- package/dist/recorders/core/ArtifactsRecorder.js.map +1 -0
- package/dist/types/adapters/types.d.ts +17 -1
- package/dist/types/adapters/types.d.ts.map +1 -1
- package/dist/types/artifacts/capability.d.ts +94 -0
- package/dist/types/artifacts/capability.d.ts.map +1 -0
- package/dist/types/artifacts/fileArtifacts.d.ts +59 -0
- package/dist/types/artifacts/fileArtifacts.d.ts.map +1 -0
- package/dist/types/artifacts/inMemoryArtifacts.d.ts +55 -0
- package/dist/types/artifacts/inMemoryArtifacts.d.ts.map +1 -0
- package/dist/types/artifacts/index.d.ts +22 -0
- package/dist/types/artifacts/index.d.ts.map +1 -0
- package/dist/types/artifacts/minting.d.ts +30 -0
- package/dist/types/artifacts/minting.d.ts.map +1 -0
- package/dist/types/artifacts/naming.d.ts +37 -0
- package/dist/types/artifacts/naming.d.ts.map +1 -0
- package/dist/types/artifacts/payload.d.ts +44 -0
- package/dist/types/artifacts/payload.d.ts.map +1 -0
- package/dist/types/artifacts/placement.d.ts +75 -0
- package/dist/types/artifacts/placement.d.ts.map +1 -0
- package/dist/types/artifacts/present.d.ts +78 -0
- package/dist/types/artifacts/present.d.ts.map +1 -0
- package/dist/types/artifacts/retention.d.ts +73 -0
- package/dist/types/artifacts/retention.d.ts.map +1 -0
- package/dist/types/artifacts/sqliteArtifacts.d.ts +91 -0
- package/dist/types/artifacts/sqliteArtifacts.d.ts.map +1 -0
- package/dist/types/artifacts/types.d.ts +221 -0
- package/dist/types/artifacts/types.d.ts.map +1 -0
- package/dist/types/artifacts/wants.d.ts +105 -0
- package/dist/types/artifacts/wants.d.ts.map +1 -0
- package/dist/types/core/Agent.d.ts +8 -2
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/agent/buildToolRegistry.d.ts +11 -1
- package/dist/types/core/agent/buildToolRegistry.d.ts.map +1 -1
- package/dist/types/core/agent/presentTool.d.ts +23 -0
- package/dist/types/core/agent/presentTool.d.ts.map +1 -0
- package/dist/types/core/agent/stages/toolCalls.d.ts +22 -0
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/agent/types.d.ts +46 -0
- package/dist/types/core/agent/types.d.ts.map +1 -1
- package/dist/types/core/codeRunnerTool.d.ts.map +1 -1
- package/dist/types/core/tools.d.ts +49 -0
- package/dist/types/core/tools.d.ts.map +1 -1
- package/dist/types/events/dispatcher.d.ts +1 -1
- package/dist/types/events/dispatcher.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +83 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +13 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/mcp/mcpServe.d.ts.map +1 -1
- package/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
- package/dist/types/recorders/core/ArtifactsRecorder.d.ts +23 -0
- package/dist/types/recorders/core/ArtifactsRecorder.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* artifacts — barrel.
|
|
4
|
+
*
|
|
5
|
+
* The claim-check store: shapes + the five-verb port (`types`), the ref
|
|
6
|
+
* grammar (`naming`), the payload laws (`payload`), the eviction law
|
|
7
|
+
* (`retention`), the shared put pipeline (`minting`), three adapters, the
|
|
8
|
+
* `ctx.artifacts` capability (`capability`) — and the Phase-2 data legs:
|
|
9
|
+
* ref arguments at dispatch (`wants`), the hand-to-the-screen verb
|
|
10
|
+
* (`present`), and the placement threshold (`placement`). See README.md in
|
|
11
|
+
* this folder for the one-job map and the import direction.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.placedToolResult = exports.placedResultKind = exports.isPlacedToolResult = exports.assertArtifactPlacement = exports.presentArtifact = exports.PRESENT_TOOL_NAME = exports.wantsNeedsStoreRefusal = exports.resolveToolWants = exports.assertToolWants = exports.unconfiguredArtifacts = exports.bindArtifacts = exports.UnreadableArtifactStoreError = exports.sqliteArtifacts = exports.UnreadableArtifactFileError = exports.fileArtifacts = exports.DEFAULT_IN_MEMORY_ARTIFACT_RETENTION = exports.inMemoryArtifacts = exports.mintArtifactRef = exports.isArtifactRef = exports.ARTIFACT_REF_PREFIX = exports.UnknownParentRefError = exports.InvalidArtifactError = exports.ArtifactIntegrityError = void 0;
|
|
15
|
+
var types_js_1 = require("./types.js");
|
|
16
|
+
Object.defineProperty(exports, "ArtifactIntegrityError", { enumerable: true, get: function () { return types_js_1.ArtifactIntegrityError; } });
|
|
17
|
+
Object.defineProperty(exports, "InvalidArtifactError", { enumerable: true, get: function () { return types_js_1.InvalidArtifactError; } });
|
|
18
|
+
Object.defineProperty(exports, "UnknownParentRefError", { enumerable: true, get: function () { return types_js_1.UnknownParentRefError; } });
|
|
19
|
+
var naming_js_1 = require("./naming.js");
|
|
20
|
+
Object.defineProperty(exports, "ARTIFACT_REF_PREFIX", { enumerable: true, get: function () { return naming_js_1.ARTIFACT_REF_PREFIX; } });
|
|
21
|
+
Object.defineProperty(exports, "isArtifactRef", { enumerable: true, get: function () { return naming_js_1.isArtifactRef; } });
|
|
22
|
+
Object.defineProperty(exports, "mintArtifactRef", { enumerable: true, get: function () { return naming_js_1.mintArtifactRef; } });
|
|
23
|
+
var inMemoryArtifacts_js_1 = require("./inMemoryArtifacts.js");
|
|
24
|
+
Object.defineProperty(exports, "inMemoryArtifacts", { enumerable: true, get: function () { return inMemoryArtifacts_js_1.inMemoryArtifacts; } });
|
|
25
|
+
Object.defineProperty(exports, "DEFAULT_IN_MEMORY_ARTIFACT_RETENTION", { enumerable: true, get: function () { return inMemoryArtifacts_js_1.DEFAULT_IN_MEMORY_ARTIFACT_RETENTION; } });
|
|
26
|
+
var fileArtifacts_js_1 = require("./fileArtifacts.js");
|
|
27
|
+
Object.defineProperty(exports, "fileArtifacts", { enumerable: true, get: function () { return fileArtifacts_js_1.fileArtifacts; } });
|
|
28
|
+
Object.defineProperty(exports, "UnreadableArtifactFileError", { enumerable: true, get: function () { return fileArtifacts_js_1.UnreadableArtifactFileError; } });
|
|
29
|
+
var sqliteArtifacts_js_1 = require("./sqliteArtifacts.js");
|
|
30
|
+
Object.defineProperty(exports, "sqliteArtifacts", { enumerable: true, get: function () { return sqliteArtifacts_js_1.sqliteArtifacts; } });
|
|
31
|
+
Object.defineProperty(exports, "UnreadableArtifactStoreError", { enumerable: true, get: function () { return sqliteArtifacts_js_1.UnreadableArtifactStoreError; } });
|
|
32
|
+
var capability_js_1 = require("./capability.js");
|
|
33
|
+
Object.defineProperty(exports, "bindArtifacts", { enumerable: true, get: function () { return capability_js_1.bindArtifacts; } });
|
|
34
|
+
Object.defineProperty(exports, "unconfiguredArtifacts", { enumerable: true, get: function () { return capability_js_1.unconfiguredArtifacts; } });
|
|
35
|
+
var wants_js_1 = require("./wants.js");
|
|
36
|
+
Object.defineProperty(exports, "assertToolWants", { enumerable: true, get: function () { return wants_js_1.assertToolWants; } });
|
|
37
|
+
Object.defineProperty(exports, "resolveToolWants", { enumerable: true, get: function () { return wants_js_1.resolveToolWants; } });
|
|
38
|
+
Object.defineProperty(exports, "wantsNeedsStoreRefusal", { enumerable: true, get: function () { return wants_js_1.wantsNeedsStoreRefusal; } });
|
|
39
|
+
var present_js_1 = require("./present.js");
|
|
40
|
+
Object.defineProperty(exports, "PRESENT_TOOL_NAME", { enumerable: true, get: function () { return present_js_1.PRESENT_TOOL_NAME; } });
|
|
41
|
+
Object.defineProperty(exports, "presentArtifact", { enumerable: true, get: function () { return present_js_1.presentArtifact; } });
|
|
42
|
+
var placement_js_1 = require("./placement.js");
|
|
43
|
+
Object.defineProperty(exports, "assertArtifactPlacement", { enumerable: true, get: function () { return placement_js_1.assertArtifactPlacement; } });
|
|
44
|
+
Object.defineProperty(exports, "isPlacedToolResult", { enumerable: true, get: function () { return placement_js_1.isPlacedToolResult; } });
|
|
45
|
+
Object.defineProperty(exports, "placedResultKind", { enumerable: true, get: function () { return placement_js_1.placedResultKind; } });
|
|
46
|
+
Object.defineProperty(exports, "placedToolResult", { enumerable: true, get: function () { return placement_js_1.placedToolResult; } });
|
|
47
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAEH,uCAgBoB;AAflB,kHAAA,sBAAsB,OAAA;AACtB,gHAAA,oBAAoB,OAAA;AACpB,iHAAA,qBAAqB,OAAA;AAcvB,yCAAkF;AAAzE,gHAAA,mBAAmB,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,4GAAA,eAAe,OAAA;AAE5D,+DAKgC;AAJ9B,yHAAA,iBAAiB,OAAA;AACjB,4IAAA,oCAAoC,OAAA;AAItC,uDAI4B;AAH1B,iHAAA,aAAa,OAAA;AACb,+HAAA,2BAA2B,OAAA;AAG7B,2DAK8B;AAJ5B,qHAAA,eAAe,OAAA;AACf,kIAAA,4BAA4B,OAAA;AAI9B,iDAUyB;AATvB,8GAAA,aAAa,OAAA;AACb,sHAAA,qBAAqB,OAAA;AASvB,uCAOoB;AANlB,2GAAA,eAAe,OAAA;AACf,4GAAA,gBAAgB,OAAA;AAChB,kHAAA,sBAAsB,OAAA;AAKxB,2CAMsB;AALpB,+GAAA,iBAAiB,OAAA;AACjB,6GAAA,eAAe,OAAA;AAKjB,+CAOwB;AANtB,uHAAA,uBAAuB,OAAA;AACvB,kHAAA,kBAAkB,OAAA;AAClB,gHAAA,gBAAgB,OAAA;AAChB,gHAAA,gBAAgB,OAAA"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* artifacts/minting — the shared half of every adapter's `put`.
|
|
4
|
+
*
|
|
5
|
+
* Validate the input, prove the parents, measure the bytes, compute the
|
|
6
|
+
* digest when asked, mint the ref, stamp the meta. Three adapters call this
|
|
7
|
+
* one pipeline so a put refused by `inMemoryArtifacts` is refused in the same
|
|
8
|
+
* words by `sqliteArtifacts` — one law, three storage mechanics.
|
|
9
|
+
*
|
|
10
|
+
* What stays with the adapter: holding the bytes, applying the retention
|
|
11
|
+
* plan, answering the other four verbs.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.prepareArtifact = void 0;
|
|
15
|
+
const naming_js_1 = require("./naming.js");
|
|
16
|
+
const payload_js_1 = require("./payload.js");
|
|
17
|
+
const retention_js_1 = require("./retention.js");
|
|
18
|
+
const types_js_1 = require("./types.js");
|
|
19
|
+
/**
|
|
20
|
+
* Validate a put and build the meta it mints.
|
|
21
|
+
*
|
|
22
|
+
* @param input the caller's put.
|
|
23
|
+
* @param resolveParent scope-bound existence check for parent validation.
|
|
24
|
+
* @param retention the adapter's policy — stamps `expiresAt` (stated, never sprung).
|
|
25
|
+
* @param now the adapter's clock, injected so tests own time.
|
|
26
|
+
* @throws InvalidArtifactError for input this library cannot store faithfully.
|
|
27
|
+
* @throws UnknownParentRefError for a parent that does not resolve in scope.
|
|
28
|
+
*/
|
|
29
|
+
async function prepareArtifact(input, resolveParent, retention, now) {
|
|
30
|
+
if (typeof input.kind !== 'string' || input.kind.trim() === '') {
|
|
31
|
+
throw new types_js_1.InvalidArtifactError(`kind is ${JSON.stringify(input.kind)}. kind is the consumer vocabulary a redeemer ` +
|
|
32
|
+
`decides from ('dataset/rows', 'chart/spec') — a blank one makes every head() useless. ` +
|
|
33
|
+
`Name what this artifact IS.`);
|
|
34
|
+
}
|
|
35
|
+
if (typeof input.mediaType !== 'string' || input.mediaType.trim() === '') {
|
|
36
|
+
throw new types_js_1.InvalidArtifactError(`mediaType is ${JSON.stringify(input.mediaType)}. Name the payload's MIME type ` +
|
|
37
|
+
`('application/json', 'text/csv', …) so a consumer can decode without guessing.`);
|
|
38
|
+
}
|
|
39
|
+
if (input.expiresAt !== undefined &&
|
|
40
|
+
(!Number.isFinite(input.expiresAt) || input.expiresAt <= now)) {
|
|
41
|
+
throw new types_js_1.InvalidArtifactError(`expiresAt = ${String(input.expiresAt)} is not a future unix-ms timestamp. An artifact ` +
|
|
42
|
+
`born expired would resolve for nobody; state a future time, or omit the field.`);
|
|
43
|
+
}
|
|
44
|
+
if (input.digest !== undefined && input.digest !== 'sha-256') {
|
|
45
|
+
throw new types_js_1.InvalidArtifactError(`digest = ${JSON.stringify(input.digest)} is not an algorithm this store computes. ` +
|
|
46
|
+
`'sha-256' is the one shipped; omit the field for no digest.`);
|
|
47
|
+
}
|
|
48
|
+
// Parents are FACTS, proven at birth — a foreign key that cannot dangle.
|
|
49
|
+
if (input.parentRefs !== undefined && input.parentRefs.length > 0) {
|
|
50
|
+
const unresolved = [];
|
|
51
|
+
for (const parent of input.parentRefs) {
|
|
52
|
+
if (!(0, naming_js_1.isArtifactRef)(parent) || !(await resolveParent(parent)))
|
|
53
|
+
unresolved.push(parent);
|
|
54
|
+
}
|
|
55
|
+
if (unresolved.length > 0)
|
|
56
|
+
throw new types_js_1.UnknownParentRefError(unresolved);
|
|
57
|
+
}
|
|
58
|
+
// Measure (and refuse the unserializable) BEFORE minting, so a refused put
|
|
59
|
+
// never burns a ref.
|
|
60
|
+
const bytes = (0, payload_js_1.measureArtifactBytes)(input.data);
|
|
61
|
+
const digest = input.digest === 'sha-256' ? await (0, payload_js_1.computeArtifactDigest)(input.data) : undefined;
|
|
62
|
+
const expiresAt = (0, retention_js_1.resolveExpiresAt)(input.expiresAt, retention, now);
|
|
63
|
+
const meta = {
|
|
64
|
+
ref: (0, naming_js_1.mintArtifactRef)(),
|
|
65
|
+
kind: input.kind,
|
|
66
|
+
mediaType: input.mediaType,
|
|
67
|
+
bytes,
|
|
68
|
+
createdAt: now,
|
|
69
|
+
...(input.label !== undefined && { label: input.label }),
|
|
70
|
+
...(digest !== undefined && { digest }),
|
|
71
|
+
...(expiresAt !== undefined && { expiresAt }),
|
|
72
|
+
...(input.origin !== undefined && { origin: input.origin }),
|
|
73
|
+
...(input.parentRefs !== undefined &&
|
|
74
|
+
input.parentRefs.length > 0 && { parentRefs: [...input.parentRefs] }),
|
|
75
|
+
};
|
|
76
|
+
return { meta, bytes };
|
|
77
|
+
}
|
|
78
|
+
exports.prepareArtifact = prepareArtifact;
|
|
79
|
+
//# sourceMappingURL=minting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"minting.js","sourceRoot":"","sources":["../../src/artifacts/minting.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* artifacts/naming — the ONE owner of the ref grammar.
|
|
4
|
+
*
|
|
5
|
+
* `art_` + 22 crypto-random base62 chars = 26 chars the model can speak
|
|
6
|
+
* cheaply and copy reliably. The grammar lives in exactly one module (the
|
|
7
|
+
* `branchSegment.ts` precedent upstream): mint here, recognize here, and
|
|
8
|
+
* nowhere else — an adapter that parses refs with its own regex is a design
|
|
9
|
+
* smell this header exists to refuse.
|
|
10
|
+
*
|
|
11
|
+
* NEVER content-addressed. The digest is metadata on {@link ArtifactMeta};
|
|
12
|
+
* making content the key would collide two tenants' identical bytes into one
|
|
13
|
+
* object (an isolation bug wearing a dedup win) and could never name two
|
|
14
|
+
* generations of "the current dataset". Randomness comes from
|
|
15
|
+
* `globalThis.crypto` — present in every supported Node and every browser —
|
|
16
|
+
* so minting works wherever the in-memory adapter does.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.isArtifactRef = exports.mintArtifactRef = exports.ARTIFACT_REF_PREFIX = void 0;
|
|
20
|
+
/** The prefix every minted ref carries. */
|
|
21
|
+
exports.ARTIFACT_REF_PREFIX = 'art_';
|
|
22
|
+
/** Random chars after the prefix. 62^22 ≈ 2^131 — collision is not a case. */
|
|
23
|
+
const RANDOM_LENGTH = 22;
|
|
24
|
+
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
25
|
+
/** The full shape, anchored: `art_` + exactly 22 base62 chars. */
|
|
26
|
+
const REF_PATTERN = /^art_[A-Za-z0-9]{22}$/;
|
|
27
|
+
/**
|
|
28
|
+
* Mint a fresh, opaque, never-content-derived ref.
|
|
29
|
+
*
|
|
30
|
+
* Rejection sampling keeps the distribution uniform (256 % 62 ≠ 0, so a bare
|
|
31
|
+
* modulo would bias the low end of the alphabet — cosmetically fine,
|
|
32
|
+
* cryptographically sloppy, and cheap to do right).
|
|
33
|
+
*/
|
|
34
|
+
function mintArtifactRef() {
|
|
35
|
+
const out = [];
|
|
36
|
+
const bytes = new Uint8Array(RANDOM_LENGTH * 2);
|
|
37
|
+
while (out.length < RANDOM_LENGTH) {
|
|
38
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
39
|
+
for (const b of bytes) {
|
|
40
|
+
// 248 = 4 * 62: the largest multiple of 62 below 256. Values at or
|
|
41
|
+
// above it are re-drawn instead of folded onto the alphabet unevenly.
|
|
42
|
+
if (b >= 248)
|
|
43
|
+
continue;
|
|
44
|
+
out.push(ALPHABET[b % ALPHABET.length]);
|
|
45
|
+
if (out.length === RANDOM_LENGTH)
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return `${exports.ARTIFACT_REF_PREFIX}${out.join('')}`;
|
|
50
|
+
}
|
|
51
|
+
exports.mintArtifactRef = mintArtifactRef;
|
|
52
|
+
/**
|
|
53
|
+
* Is this string a well-formed artifact ref?
|
|
54
|
+
*
|
|
55
|
+
* Structural, total, and the ONLY recognizer. Adapters call it before any
|
|
56
|
+
* ref touches a filesystem path or a SQL parameter: refs are minted so a
|
|
57
|
+
* traversal payload cannot arrive by construction — and this asserts it
|
|
58
|
+
* anyway, because "cannot happen" is a claim, not a defence.
|
|
59
|
+
*/
|
|
60
|
+
function isArtifactRef(candidate) {
|
|
61
|
+
return typeof candidate === 'string' && REF_PATTERN.test(candidate);
|
|
62
|
+
}
|
|
63
|
+
exports.isArtifactRef = isArtifactRef;
|
|
64
|
+
//# sourceMappingURL=naming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.js","sourceRoot":"","sources":["../../src/artifacts/naming.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAIH,2CAA2C;AAC9B,QAAA,mBAAmB,GAAG,MAAM,CAAC;AAE1C,8EAA8E;AAC9E,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB,MAAM,QAAQ,GAAG,gEAAgE,CAAC;AAElF,kEAAkE;AAClE,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAE5C;;;;;;GAMG;AACH,SAAgB,eAAe;IAC7B,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC;IAChD,OAAO,GAAG,CAAC,MAAM,GAAG,aAAa,EAAE,CAAC;QAClC,UAAU,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACzC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,mEAAmE;YACnE,sEAAsE;YACtE,IAAI,CAAC,IAAI,GAAG;gBAAE,SAAS;YACvB,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YACxC,IAAI,GAAG,CAAC,MAAM,KAAK,aAAa;gBAAE,MAAM;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,2BAAmB,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AACjD,CAAC;AAdD,0CAcC;AAED;;;;;;;GAOG;AACH,SAAgB,aAAa,CAAC,SAAkB;IAC9C,OAAO,OAAO,SAAS,KAAK,QAAQ,IAAI,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACtE,CAAC;AAFD,sCAEC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* artifacts/payload — one owner for how a payload is measured, carried and
|
|
4
|
+
* digested.
|
|
5
|
+
*
|
|
6
|
+
* Three adapters store the same three payload shapes (string, `Uint8Array`,
|
|
7
|
+
* JSON value). If each measured or serialized on its own, `bytes` on the meta
|
|
8
|
+
* could disagree with what a digest was computed over, and a digest written by
|
|
9
|
+
* one adapter would not verify in another. So the laws live once, here:
|
|
10
|
+
*
|
|
11
|
+
* • `measure` — `bytes` is the UTF-8 length of text/JSON, the byteLength of
|
|
12
|
+
* binary. The number a consumer decides from, computed one way.
|
|
13
|
+
* • `encode/decode` — the durable adapters persist ONE envelope
|
|
14
|
+
* (`text` / `binary` base64 / `json`), so a file written by
|
|
15
|
+
* `fileArtifacts` is legible to a debugging human and identical in law to
|
|
16
|
+
* a row written by `sqliteArtifacts`.
|
|
17
|
+
* • `digest` — sha-256 over the SAME canonical bytes `measure` counts, via
|
|
18
|
+
* `globalThis.crypto.subtle` (browser + Node, zero dependencies).
|
|
19
|
+
*
|
|
20
|
+
* A payload JSON cannot carry (a function, a bigint, `undefined`, a cyclic
|
|
21
|
+
* object) is refused BY NAME at put — storing an approximation and returning
|
|
22
|
+
* it later as the real thing is the exact accepted-and-silently-wrong failure
|
|
23
|
+
* a claim check exists to prevent.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.decodeArtifactData = exports.encodeArtifactData = exports.computeArtifactDigest = exports.measureArtifactBytes = exports.canonicalPayloadBytes = void 0;
|
|
27
|
+
const types_js_1 = require("./types.js");
|
|
28
|
+
const textEncoder = new TextEncoder();
|
|
29
|
+
const textDecoder = new TextDecoder();
|
|
30
|
+
/**
|
|
31
|
+
* The canonical bytes of a payload — what `bytes` counts and what a digest
|
|
32
|
+
* is computed over. Throws {@link InvalidArtifactError} for a value that
|
|
33
|
+
* cannot be carried faithfully.
|
|
34
|
+
*/
|
|
35
|
+
function canonicalPayloadBytes(data) {
|
|
36
|
+
if (data instanceof Uint8Array)
|
|
37
|
+
return data;
|
|
38
|
+
if (typeof data === 'string')
|
|
39
|
+
return textEncoder.encode(data);
|
|
40
|
+
let serialized;
|
|
41
|
+
try {
|
|
42
|
+
serialized = JSON.stringify(data);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
throw new types_js_1.InvalidArtifactError(`the payload cannot be JSON-serialized (${err instanceof Error ? err.message : String(err)}). ` +
|
|
46
|
+
`Store a string, a Uint8Array, or a JSON-serializable value — an approximation of ` +
|
|
47
|
+
`anything else would be returned later as if it were the real thing.`);
|
|
48
|
+
}
|
|
49
|
+
if (serialized === undefined) {
|
|
50
|
+
throw new types_js_1.InvalidArtifactError(`the payload serializes to nothing (undefined, a function, or a symbol). ` +
|
|
51
|
+
`JSON cannot carry it, so the store will not pretend to. Store a string, a ` +
|
|
52
|
+
`Uint8Array, or a JSON-serializable value.`);
|
|
53
|
+
}
|
|
54
|
+
return textEncoder.encode(serialized);
|
|
55
|
+
}
|
|
56
|
+
exports.canonicalPayloadBytes = canonicalPayloadBytes;
|
|
57
|
+
/** Payload size in bytes — UTF-8 for text/JSON, byteLength for binary. */
|
|
58
|
+
function measureArtifactBytes(data) {
|
|
59
|
+
return canonicalPayloadBytes(data).byteLength;
|
|
60
|
+
}
|
|
61
|
+
exports.measureArtifactBytes = measureArtifactBytes;
|
|
62
|
+
/** `sha-256:<hex>` over the canonical bytes. */
|
|
63
|
+
async function computeArtifactDigest(data) {
|
|
64
|
+
const bytes = canonicalPayloadBytes(data);
|
|
65
|
+
// `subtle.digest` wants an ArrayBuffer-backed view; copy defensively so a
|
|
66
|
+
// Uint8Array over a SharedArrayBuffer cannot reach it.
|
|
67
|
+
const buffer = new Uint8Array(bytes).buffer;
|
|
68
|
+
const hash = new Uint8Array(await globalThis.crypto.subtle.digest('SHA-256', buffer));
|
|
69
|
+
let hex = '';
|
|
70
|
+
for (const b of hash)
|
|
71
|
+
hex += b.toString(16).padStart(2, '0');
|
|
72
|
+
return `sha-256:${hex}`;
|
|
73
|
+
}
|
|
74
|
+
exports.computeArtifactDigest = computeArtifactDigest;
|
|
75
|
+
/** Encode for durable storage. Validates exactly as `measure` does. */
|
|
76
|
+
function encodeArtifactData(data) {
|
|
77
|
+
if (data instanceof Uint8Array)
|
|
78
|
+
return { shape: 'binary', value: toBase64(data) };
|
|
79
|
+
if (typeof data === 'string')
|
|
80
|
+
return { shape: 'text', value: data };
|
|
81
|
+
// canonicalPayloadBytes carries the refusal for unserializable values.
|
|
82
|
+
return { shape: 'json', value: textDecoder.decode(canonicalPayloadBytes(data)) };
|
|
83
|
+
}
|
|
84
|
+
exports.encodeArtifactData = encodeArtifactData;
|
|
85
|
+
/** Decode what {@link encodeArtifactData} wrote. Total over its own output. */
|
|
86
|
+
function decodeArtifactData(encoded) {
|
|
87
|
+
switch (encoded.shape) {
|
|
88
|
+
case 'text':
|
|
89
|
+
return encoded.value;
|
|
90
|
+
case 'binary':
|
|
91
|
+
return fromBase64(encoded.value);
|
|
92
|
+
case 'json':
|
|
93
|
+
return JSON.parse(encoded.value);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.decodeArtifactData = decodeArtifactData;
|
|
97
|
+
// Buffer-free base64, so the in-file law works in a browser bundle too.
|
|
98
|
+
function toBase64(bytes) {
|
|
99
|
+
let binary = '';
|
|
100
|
+
const CHUNK = 0x8000;
|
|
101
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
102
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
|
|
103
|
+
}
|
|
104
|
+
return btoa(binary);
|
|
105
|
+
}
|
|
106
|
+
function fromBase64(value) {
|
|
107
|
+
const binary = atob(value);
|
|
108
|
+
const bytes = new Uint8Array(binary.length);
|
|
109
|
+
for (let i = 0; i < binary.length; i++)
|
|
110
|
+
bytes[i] = binary.charCodeAt(i);
|
|
111
|
+
return bytes;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=payload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payload.js","sourceRoot":"","sources":["../../src/artifacts/payload.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* artifacts/placement — the placement threshold (Phase 2, Leg 3).
|
|
4
|
+
*
|
|
5
|
+
* An OPTIONAL operator dial on the agent's artifacts wiring:
|
|
6
|
+
* `Agent.create({ artifacts: { store, placement: { maxInlineChars: N } } })`.
|
|
7
|
+
* A tool result whose finalized text exceeds the threshold is checked into
|
|
8
|
+
* the store (kind `tool-result/<toolName>`) and the model receives the claim
|
|
9
|
+
* ticket instead — a SHORT substitute naming ref + meta + how to consume it.
|
|
10
|
+
* The whole 879,073-token failure class, retired by configuration.
|
|
11
|
+
*
|
|
12
|
+
* PRECEDENCE with the other two ceilings, stated once and owned here:
|
|
13
|
+
* 1. the tool's own `resultCeiling` (the AUTHOR's refusal) is judged FIRST,
|
|
14
|
+
* at the execute boundary — a refused result is a short teaching
|
|
15
|
+
* sentence, so placement never sees the payload at all;
|
|
16
|
+
* 2. placement (the OPERATOR's ref-ing) is judged next, on what the
|
|
17
|
+
* after-tool governance chain let through — a rule that already
|
|
18
|
+
* summarized a huge result is measured on what it produced;
|
|
19
|
+
* 3. the agent-level `maxToolResultChars` truncation net runs LAST — with
|
|
20
|
+
* placement on it measures the ticket, so it should now rarely fire.
|
|
21
|
+
*
|
|
22
|
+
* A placed result is a TICKET, not a refusal: declared effects are still
|
|
23
|
+
* judged and procedure steps advance normally — the result ARRIVED; it just
|
|
24
|
+
* travels by reference. The decision is never silent: the mint lands as
|
|
25
|
+
* `agentfootprint.artifacts.minted` (origin joining it to the tool call) and
|
|
26
|
+
* the substitution states itself in the result the model reads.
|
|
27
|
+
*
|
|
28
|
+
* This module is the PURE half — the dial shape, its build-time refusals,
|
|
29
|
+
* the measure rule (shared with both ceilings: strings as-is, everything
|
|
30
|
+
* else `safeStringify`d by the caller), and the substitute composer. The
|
|
31
|
+
* dispatch layer owns the mint and the events.
|
|
32
|
+
*/
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.placedToolResult = exports.isPlacedToolResult = exports.placedResultKind = exports.assertArtifactPlacement = void 0;
|
|
35
|
+
/**
|
|
36
|
+
* Refuse a placement dial this library cannot honor, where it is configured
|
|
37
|
+
* — never at the first oversized result of the first run.
|
|
38
|
+
*/
|
|
39
|
+
function assertArtifactPlacement(site, placement) {
|
|
40
|
+
if (placement === undefined)
|
|
41
|
+
return;
|
|
42
|
+
const value = placement.maxInlineChars;
|
|
43
|
+
if (!Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
|
|
44
|
+
throw new Error(`${site}: artifacts.placement.maxInlineChars must be a positive whole number of ` +
|
|
45
|
+
`characters, and ${String(value)} is not one. It is the threshold over which a tool ` +
|
|
46
|
+
`result is checked into the artifact store and the model reads the claim ticket ` +
|
|
47
|
+
`instead. To turn placement OFF, omit \`placement\` — absent means results are never ` +
|
|
48
|
+
`measured and never placed, exactly as before.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.assertArtifactPlacement = assertArtifactPlacement;
|
|
52
|
+
/** The kind vocabulary a placement mint declares: `tool-result/<toolName>`.
|
|
53
|
+
* Honest — it says exactly what the payload is and which tool produced it —
|
|
54
|
+
* and it is what a `wants` declaration or a `present` call names to consume
|
|
55
|
+
* the placed result. */
|
|
56
|
+
function placedResultKind(toolName) {
|
|
57
|
+
return `tool-result/${toolName}`;
|
|
58
|
+
}
|
|
59
|
+
exports.placedResultKind = placedResultKind;
|
|
60
|
+
/** Type guard for consumers reading `tool_end.result` or a tool message. */
|
|
61
|
+
function isPlacedToolResult(value) {
|
|
62
|
+
return (typeof value === 'object' &&
|
|
63
|
+
value !== null &&
|
|
64
|
+
value.placed === true &&
|
|
65
|
+
typeof value.ref === 'string' &&
|
|
66
|
+
typeof value.reason === 'string');
|
|
67
|
+
}
|
|
68
|
+
exports.isPlacedToolResult = isPlacedToolResult;
|
|
69
|
+
/** Compose the ticket from the mint the dispatch layer performed. */
|
|
70
|
+
function placedToolResult(toolName, meta, sizeChars, maxInlineChars) {
|
|
71
|
+
return {
|
|
72
|
+
placed: true,
|
|
73
|
+
ref: meta.ref,
|
|
74
|
+
kind: meta.kind,
|
|
75
|
+
mediaType: meta.mediaType,
|
|
76
|
+
bytes: meta.bytes,
|
|
77
|
+
reason: `${toolName} returned ${sizeChars} chars, over the ${maxInlineChars}-char placement ` +
|
|
78
|
+
`threshold, so the full result was stored as artifact '${meta.ref}' ` +
|
|
79
|
+
`(${meta.kind}) instead of entering this conversation. Route the ref: pass the ` +
|
|
80
|
+
`string '${meta.ref}' to a tool whose argument wants '${meta.kind}', or call ` +
|
|
81
|
+
`present({ ref: '${meta.ref}', as: … }) to hand it to the screen. Do not retype or ` +
|
|
82
|
+
`summarize content you have not read.`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
exports.placedToolResult = placedToolResult;
|
|
86
|
+
//# sourceMappingURL=placement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placement.js","sourceRoot":"","sources":["../../src/artifacts/placement.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;;;AAeH;;;GAGG;AACH,SAAgB,uBAAuB,CACrC,IAAY,EACZ,SAAwC;IAExC,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO;IACpC,MAAM,KAAK,GAAG,SAAS,CAAC,cAAc,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,0EAA0E;YAC/E,mBAAmB,MAAM,CAAC,KAAK,CAAC,qDAAqD;YACrF,iFAAiF;YACjF,sFAAsF;YACtF,+CAA+C,CAClD,CAAC;IACJ,CAAC;AACH,CAAC;AAfD,0DAeC;AAED;;;yBAGyB;AACzB,SAAgB,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,eAAe,QAAQ,EAAE,CAAC;AACnC,CAAC;AAFD,4CAEC;AAqBD,4EAA4E;AAC5E,SAAgB,kBAAkB,CAAC,KAAc;IAC/C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACb,KAA8B,CAAC,MAAM,KAAK,IAAI;QAC/C,OAAQ,KAA2B,CAAC,GAAG,KAAK,QAAQ;QACpD,OAAQ,KAA8B,CAAC,MAAM,KAAK,QAAQ,CAC3D,CAAC;AACJ,CAAC;AARD,gDAQC;AAED,qEAAqE;AACrE,SAAgB,gBAAgB,CAC9B,QAAgB,EAChB,IAAkB,EAClB,SAAiB,EACjB,cAAsB;IAEtB,OAAO;QACL,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EACJ,GAAG,QAAQ,aAAa,SAAS,oBAAoB,cAAc,kBAAkB;YACrF,yDAAyD,IAAI,CAAC,GAAG,IAAI;YACrE,IAAI,IAAI,CAAC,IAAI,mEAAmE;YAChF,WAAW,IAAI,CAAC,GAAG,qCAAqC,IAAI,CAAC,IAAI,aAAa;YAC9E,mBAAmB,IAAI,CAAC,GAAG,yDAAyD;YACpF,sCAAsC;KACzC,CAAC;AACJ,CAAC;AApBD,4CAoBC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* artifacts/present — the hand-to-the-screen verb (Phase 2, Leg 2).
|
|
4
|
+
*
|
|
5
|
+
* `present({ ref, as, label? })` is how the model finishes an analytics
|
|
6
|
+
* answer WITHOUT serializing what the screen will show: it names the ticket
|
|
7
|
+
* (`ref`), the consumer vocabulary for how to render it (`as: 'bar-chart'`,
|
|
8
|
+
* `'table'`, …), and optionally the human title. The framework `head`s the
|
|
9
|
+
* ref under the run's own scope and the RESULT carries a DESCRIPTION
|
|
10
|
+
* SNAPSHOT — `{ kind, mediaType, bytes, label }` — so the claim ticket
|
|
11
|
+
* describes the parcel: a conversation reloaded after the artifact expired
|
|
12
|
+
* can still render an honest placeholder from history alone ("Chart —
|
|
13
|
+
* 'Q3 sales by region' (bar-chart, 41 KB) — expired; re-run to regenerate"),
|
|
14
|
+
* because the snapshot lives INSIDE the tool result, the one thing provider
|
|
15
|
+
* message history keeps typed and durable. Never a blank pane.
|
|
16
|
+
*
|
|
17
|
+
* `as` is deliberately NOT validated against a component registry — that
|
|
18
|
+
* registry is a later phase (the frontend leg); until then the value is
|
|
19
|
+
* stored as data and travels on the `artifacts.presented` event exactly as
|
|
20
|
+
* spoken.
|
|
21
|
+
*
|
|
22
|
+
* This module is the PURE half — the tool's name/schema constants, the
|
|
23
|
+
* snapshot shape, and the resolution over the five-verb port. The tool SHELL
|
|
24
|
+
* (a placeholder whose result the agent loop overwrites — the `skip_step`
|
|
25
|
+
* pattern) lives in core, which is also where the typed
|
|
26
|
+
* `agentfootprint.artifacts.presented` event is emitted. Core wires
|
|
27
|
+
* artifacts; never the reverse.
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.presentArtifact = exports.PRESENT_TOOL_NAME = void 0;
|
|
31
|
+
/**
|
|
32
|
+
* The reserved name of the auto-attached tool. Reserved ONLY when a store is
|
|
33
|
+
* attached (the `read_skill` seam): a storeless agent may keep its own
|
|
34
|
+
* `present`, because the framework attaches nothing there.
|
|
35
|
+
*/
|
|
36
|
+
exports.PRESENT_TOOL_NAME = 'present';
|
|
37
|
+
/** How many live refs a miss refusal lists. A lesson, not a catalog. */
|
|
38
|
+
const PRESENT_LIST_LIMIT = 10;
|
|
39
|
+
/** `art_h7Kq… [chart/spec · 41210 bytes · 'Q3 sales']` — one listed ref. */
|
|
40
|
+
function describeRef(meta) {
|
|
41
|
+
return `${meta.ref} [${meta.kind} · ${meta.bytes} bytes${meta.label !== undefined ? ` · '${meta.label}'` : ''}]`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve one `present` call over the port — ONE law for every dispatch
|
|
45
|
+
* door. `head`, never `get`: presenting is the render-by-ref decision, and
|
|
46
|
+
* the screen pays for the bytes later, under its own identity.
|
|
47
|
+
*/
|
|
48
|
+
async function presentArtifact(store, scope, args) {
|
|
49
|
+
const ref = args.ref;
|
|
50
|
+
const as = args.as;
|
|
51
|
+
if (typeof ref !== 'string' || ref.trim().length === 0) {
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
refusal: `present needs \`ref\` — the art_… ticket of the artifact to hand to the screen. ` +
|
|
55
|
+
`Store the data first (a tool that mints, or the placement threshold), then present ` +
|
|
56
|
+
`its ref.`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (typeof as !== 'string' || as.trim().length === 0) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
refusal: `present needs \`as\` — the consumer vocabulary for how the screen should render ` +
|
|
63
|
+
`'${ref}' (e.g. 'bar-chart', 'table', 'image'). Say what it is; the screen picks ` +
|
|
64
|
+
`the renderer.`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const meta = await store.head(scope, ref);
|
|
68
|
+
if (meta === null) {
|
|
69
|
+
const page = await store.list(scope, { limit: PRESENT_LIST_LIMIT });
|
|
70
|
+
const listing = page.artifacts.length === 0
|
|
71
|
+
? `Nothing is live in this run's scope right now — store the data first, then present ` +
|
|
72
|
+
`its ref.`
|
|
73
|
+
: `Live refs in scope: ${page.artifacts.map(describeRef).join(', ')}.`;
|
|
74
|
+
return {
|
|
75
|
+
ok: false,
|
|
76
|
+
missedRef: ref,
|
|
77
|
+
refusal: `present('${ref}') found nothing under that ref in this run's scope — expired, ` +
|
|
78
|
+
`swept, or never stored here. Nothing was presented. ${listing}`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const label = typeof args.label === 'string' && args.label.trim().length > 0 ? args.label : meta.label;
|
|
82
|
+
return {
|
|
83
|
+
ok: true,
|
|
84
|
+
result: {
|
|
85
|
+
presented: true,
|
|
86
|
+
ref: meta.ref,
|
|
87
|
+
as,
|
|
88
|
+
snapshot: {
|
|
89
|
+
kind: meta.kind,
|
|
90
|
+
mediaType: meta.mediaType,
|
|
91
|
+
bytes: meta.bytes,
|
|
92
|
+
...(label !== undefined && { label }),
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
exports.presentArtifact = presentArtifact;
|
|
98
|
+
//# sourceMappingURL=present.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"present.js","sourceRoot":"","sources":["../../src/artifacts/present.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;;;AAIH;;;;GAIG;AACU,QAAA,iBAAiB,GAAG,SAAS,CAAC;AAyC3C,wEAAwE;AACxE,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAE9B,4EAA4E;AAC5E,SAAS,WAAW,CAAC,IAAkB;IACrC,OAAO,GAAG,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,KAAK,SAC9C,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EACpD,GAAG,CAAC;AACN,CAAC;AAED;;;;GAIG;AACI,KAAK,UAAU,eAAe,CACnC,KAAoB,EACpB,KAAoB,EACpB,IAAuC;IAEvC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;IACrB,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;IACnB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EACL,kFAAkF;gBAClF,qFAAqF;gBACrF,UAAU;SACb,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EACL,kFAAkF;gBAClF,IAAI,GAAG,2EAA2E;gBAClF,eAAe;SAClB,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC1C,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;QACpE,MAAM,OAAO,GACX,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YACzB,CAAC,CAAC,qFAAqF;gBACrF,UAAU;YACZ,CAAC,CAAC,uBAAuB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QAC3E,OAAO;YACL,EAAE,EAAE,KAAK;YACT,SAAS,EAAE,GAAG;YACd,OAAO,EACL,YAAY,GAAG,iEAAiE;gBAChF,uDAAuD,OAAO,EAAE;SACnE,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GACT,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;IAC3F,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE;YACN,SAAS,EAAE,IAAI;YACf,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,EAAE;YACF,QAAQ,EAAE;gBACR,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,CAAC;aACtC;SACF;KACF,CAAC;AACJ,CAAC;AAzDD,0CAyDC"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* artifacts/retention — the one owner of the eviction law.
|
|
4
|
+
*
|
|
5
|
+
* Three adapters, one rule for what leaves a scope and why. Each adapter
|
|
6
|
+
* supplies its rows; this module decides — a pure plan over plain facts, so
|
|
7
|
+
* the law is testable without a store and cannot fork into three dialects.
|
|
8
|
+
*
|
|
9
|
+
* The policy is three independent dials, all per scope:
|
|
10
|
+
* • `ttlMs` — every artifact gets `expiresAt = createdAt + ttl`
|
|
11
|
+
* stamped AT MINT (expiry is stated, never sprung),
|
|
12
|
+
* and expired rows are swept when the scope is next
|
|
13
|
+
* touched by a put.
|
|
14
|
+
* • `maxBytesPerScope`— a byte budget; least-recently-ACCESSED leaves first
|
|
15
|
+
* (an artifact under active render must not be the
|
|
16
|
+
* next one evicted — the innerRunRecords recency law).
|
|
17
|
+
* • `maxCountPerScope`— a row budget, same eviction order.
|
|
18
|
+
*
|
|
19
|
+
* Every eviction is a FACT the plan returns ({@link SweptArtifact}), because
|
|
20
|
+
* the put that triggered it reports them upward and the capability layer puts
|
|
21
|
+
* each one on the record. A store that made room silently would be lying by
|
|
22
|
+
* omission.
|
|
23
|
+
*
|
|
24
|
+
* A payload bigger than the whole byte budget is REFUSED at the door (the
|
|
25
|
+
* plan says so; the adapter throws by name) — evicting an entire scope to
|
|
26
|
+
* admit one oversized object would trade everything for something that may
|
|
27
|
+
* itself not fit.
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.resolveExpiresAt = exports.planRetention = exports.assertRetention = void 0;
|
|
31
|
+
/**
|
|
32
|
+
* Validate a retention policy at construction — a dial that cannot bind
|
|
33
|
+
* (zero, negative, NaN) is refused where it was written, not discovered as
|
|
34
|
+
* an always-empty store at the first put.
|
|
35
|
+
*/
|
|
36
|
+
function assertRetention(adapter, retention) {
|
|
37
|
+
if (retention === undefined)
|
|
38
|
+
return;
|
|
39
|
+
const dials = [
|
|
40
|
+
['ttlMs', retention.ttlMs],
|
|
41
|
+
['maxBytesPerScope', retention.maxBytesPerScope],
|
|
42
|
+
['maxCountPerScope', retention.maxCountPerScope],
|
|
43
|
+
];
|
|
44
|
+
for (const [name, value] of dials) {
|
|
45
|
+
if (value === undefined)
|
|
46
|
+
continue;
|
|
47
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
48
|
+
throw new TypeError(`[artifacts] ${adapter}: retention.${name} = ${String(value)} cannot bind. ` +
|
|
49
|
+
`Each dial is a positive number, or absent — omitting it is how "no limit" is said.`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.assertRetention = assertRetention;
|
|
54
|
+
/**
|
|
55
|
+
* Plan what must leave a scope so that `incomingBytes` may enter.
|
|
56
|
+
*
|
|
57
|
+
* Pure: reads rows, returns facts, mutates nothing. Rows may arrive in any
|
|
58
|
+
* order; eviction order here is least-recently-accessed first.
|
|
59
|
+
*/
|
|
60
|
+
function planRetention(rows, incomingBytes, retention, now) {
|
|
61
|
+
const swept = [];
|
|
62
|
+
const sweep = (row, reason) => {
|
|
63
|
+
swept.push({ ref: row.ref, reason, kind: row.kind, bytes: row.bytes });
|
|
64
|
+
};
|
|
65
|
+
// 1 — the calendar: expired rows leave regardless of budgets.
|
|
66
|
+
const live = [];
|
|
67
|
+
for (const row of rows) {
|
|
68
|
+
if (row.expiresAt !== undefined && row.expiresAt <= now)
|
|
69
|
+
sweep(row, 'ttl');
|
|
70
|
+
else
|
|
71
|
+
live.push(row);
|
|
72
|
+
}
|
|
73
|
+
if (retention === undefined)
|
|
74
|
+
return { swept };
|
|
75
|
+
const { maxBytesPerScope, maxCountPerScope } = retention;
|
|
76
|
+
if (maxBytesPerScope !== undefined && incomingBytes > maxBytesPerScope) {
|
|
77
|
+
return {
|
|
78
|
+
swept,
|
|
79
|
+
refusal: `the payload is ${incomingBytes} bytes and this store's byte budget per scope is ` +
|
|
80
|
+
`${maxBytesPerScope}. Evicting everything else would not make it fit, so it is ` +
|
|
81
|
+
`refused instead of admitted by force. Store something smaller, or build the ` +
|
|
82
|
+
`store with a larger maxBytesPerScope.`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// Least-recently-accessed first — ties broken by ref for determinism.
|
|
86
|
+
live.sort((a, b) => a.lastAccessedAt - b.lastAccessedAt || (a.ref < b.ref ? -1 : 1));
|
|
87
|
+
// 2 — the row budget (the incoming row occupies one slot).
|
|
88
|
+
if (maxCountPerScope !== undefined) {
|
|
89
|
+
let count = live.length + 1;
|
|
90
|
+
while (count > maxCountPerScope && live.length > 0) {
|
|
91
|
+
sweep(live.shift(), 'max-count');
|
|
92
|
+
count--;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// 3 — the byte budget (the incoming bytes already proved they can fit).
|
|
96
|
+
if (maxBytesPerScope !== undefined) {
|
|
97
|
+
let total = live.reduce((sum, row) => sum + row.bytes, 0) + incomingBytes;
|
|
98
|
+
while (total > maxBytesPerScope && live.length > 0) {
|
|
99
|
+
const evicted = live.shift();
|
|
100
|
+
sweep(evicted, 'max-bytes');
|
|
101
|
+
total -= evicted.bytes;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return { swept };
|
|
105
|
+
}
|
|
106
|
+
exports.planRetention = planRetention;
|
|
107
|
+
/**
|
|
108
|
+
* The `expiresAt` a mint gets: the caller's own statement and the store's
|
|
109
|
+
* ttl, whichever comes SOONER. A store may tighten a promise, never extend
|
|
110
|
+
* one — extending would overrule the only party who knows the data.
|
|
111
|
+
*/
|
|
112
|
+
function resolveExpiresAt(callerExpiresAt, retention, now) {
|
|
113
|
+
const fromTtl = retention?.ttlMs !== undefined ? now + retention.ttlMs : undefined;
|
|
114
|
+
if (callerExpiresAt === undefined)
|
|
115
|
+
return fromTtl;
|
|
116
|
+
if (fromTtl === undefined)
|
|
117
|
+
return callerExpiresAt;
|
|
118
|
+
return Math.min(callerExpiresAt, fromTtl);
|
|
119
|
+
}
|
|
120
|
+
exports.resolveExpiresAt = resolveExpiresAt;
|
|
121
|
+
//# sourceMappingURL=retention.js.map
|