agentfootprint 9.52.0 → 9.53.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 +4 -1
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/bin/agentfootprint-check-semantics.mjs +14 -0
- package/dist/core/agent/coverage/read.js +13 -0
- package/dist/core/agent/coverage/read.js.map +1 -1
- package/dist/core/agent/stages/toolCalls.js +95 -4
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/tools.js +25 -1
- package/dist/core/tools.js.map +1 -1
- package/dist/debug.js +14 -3
- package/dist/debug.js.map +1 -1
- package/dist/esm/core/agent/coverage/read.js +13 -0
- package/dist/esm/core/agent/coverage/read.js.map +1 -1
- package/dist/esm/core/agent/stages/toolCalls.js +95 -4
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/tools.d.ts +24 -0
- package/dist/esm/core/tools.js +23 -0
- package/dist/esm/core/tools.js.map +1 -1
- package/dist/esm/debug.d.ts +1 -0
- package/dist/esm/debug.js +7 -0
- package/dist/esm/debug.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +20 -0
- package/dist/esm/events/registry.d.ts +3 -1
- package/dist/esm/events/registry.js +2 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +11 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/semantics/check.d.ts +70 -0
- package/dist/esm/lib/semantics/check.js +154 -0
- package/dist/esm/lib/semantics/check.js.map +1 -0
- package/dist/esm/lib/semantics/cli.d.ts +40 -0
- package/dist/esm/lib/semantics/cli.js +148 -0
- package/dist/esm/lib/semantics/cli.js.map +1 -0
- package/dist/esm/lib/semantics/envelope.d.ts +139 -0
- package/dist/esm/lib/semantics/envelope.js +592 -0
- package/dist/esm/lib/semantics/envelope.js.map +1 -0
- package/dist/esm/lib/semantics/format.d.ts +11 -0
- package/dist/esm/lib/semantics/format.js +33 -0
- package/dist/esm/lib/semantics/format.js.map +1 -0
- package/dist/esm/lib/semantics/index.d.ts +14 -0
- package/dist/esm/lib/semantics/index.js +15 -0
- package/dist/esm/lib/semantics/index.js.map +1 -0
- package/dist/esm/lib/semantics/types.d.ts +230 -0
- package/dist/esm/lib/semantics/types.js +71 -0
- package/dist/esm/lib/semantics/types.js.map +1 -0
- package/dist/events/registry.js +2 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/index.js +65 -44
- package/dist/index.js.map +1 -1
- package/dist/lib/semantics/check.js +158 -0
- package/dist/lib/semantics/check.js.map +1 -0
- package/dist/lib/semantics/cli.js +176 -0
- package/dist/lib/semantics/cli.js.map +1 -0
- package/dist/lib/semantics/envelope.js +603 -0
- package/dist/lib/semantics/envelope.js.map +1 -0
- package/dist/lib/semantics/format.js +37 -0
- package/dist/lib/semantics/format.js.map +1 -0
- package/dist/lib/semantics/index.js +34 -0
- package/dist/lib/semantics/index.js.map +1 -0
- package/dist/lib/semantics/types.js +74 -0
- package/dist/lib/semantics/types.js.map +1 -0
- package/dist/types/core/agent/coverage/read.d.ts.map +1 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/tools.d.ts +24 -0
- package/dist/types/core/tools.d.ts.map +1 -1
- package/dist/types/debug.d.ts +1 -0
- package/dist/types/debug.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +20 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +3 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/semantics/check.d.ts +71 -0
- package/dist/types/lib/semantics/check.d.ts.map +1 -0
- package/dist/types/lib/semantics/cli.d.ts +41 -0
- package/dist/types/lib/semantics/cli.d.ts.map +1 -0
- package/dist/types/lib/semantics/envelope.d.ts +140 -0
- package/dist/types/lib/semantics/envelope.d.ts.map +1 -0
- package/dist/types/lib/semantics/format.d.ts +12 -0
- package/dist/types/lib/semantics/format.d.ts.map +1 -0
- package/dist/types/lib/semantics/index.d.ts +15 -0
- package/dist/types/lib/semantics/index.d.ts.map +1 -0
- package/dist/types/lib/semantics/types.d.ts +231 -0
- package/dist/types/lib/semantics/types.d.ts.map +1 -0
- package/package.json +2 -1
package/AGENTS.md
CHANGED
|
@@ -524,7 +524,7 @@ files `agentfootprint.tools.coverage_declared`; with
|
|
|
524
524
|
to the final answer, which is how a limit survives a model that would rather not
|
|
525
525
|
mention it.
|
|
526
526
|
|
|
527
|
-
### Observability —
|
|
527
|
+
### Observability — 102 typed events across 22 domains
|
|
528
528
|
|
|
529
529
|
```typescript
|
|
530
530
|
agent.on('agentfootprint.context.injected', (e) =>
|
package/CLAUDE.md
CHANGED
|
@@ -17,6 +17,8 @@ not in this table, search `src/index.ts` for the nearest noun before writing cod
|
|
|
17
17
|
|
|
18
18
|
| If you are about to build… | It is | Where | Since |
|
|
19
19
|
|---|---|---|---|
|
|
20
|
+
| a tool returning numbers WITH the caveats that make them honest — interval/aggregation grain, is-it-a-counter, when the world was measured, which ground was NOT covered — as typed data the model reads compactly and the record keeps whole | `semantic()` + `tools.semantics_declared` (model sees `semanticsForModel` projection; `coverage` field absorbed by the coverage()/absent() channel) | `src/lib/semantics/` | 9.53.0 |
|
|
21
|
+
| a build gate that refuses a triage/inventory tool that forgot its caveats, by tool name and field name | `checkSemantics` + `defineTool({ resultClass })` + bin `agentfootprint-check-semantics` | `src/lib/semantics/check.ts` | 9.53.0 |
|
|
20
22
|
| report progress from inside a tool — "hop 3 of 12 done", said mid-call while a long-running `execute` is still working (the record was otherwise atomic: tool_start, silence, tool_end) | `ctx.progress` + `agentfootprint.stream.tool_progress` | `src/core/tools.ts` | 9.52.0 |
|
|
21
23
|
| declaring which skills connect — the SkillMap as one named thing (the agent that mounts it is the SkillWalker; there is deliberately no walker class) | `defineSkillMap` + `SkillMap` (permanent reference-equal aliases of `skillGraph`/`SkillGraph`) | `src/lib/injection-engine/skillGraph.ts` | 9.51.0 |
|
|
22
24
|
| guarding a skill transition on state or a tool result's fields — a route condition as DATA (comparable, drawable, evidence-recorded), not an opaque predicate | `guard:` + `compileGuard` + `guard-unsatisfiable` | `src/lib/injection-engine/skillGuard.ts` | 9.51.0 |
|
|
@@ -127,7 +129,7 @@ Traps: `src/observability/` holds the finder IMPLEMENTATIONS (canonical home; `d
|
|
|
127
129
|
- **Embedder fingerprint** (8.9.0) → `Embedder.id` (optional; every shipped embedder sets one, and NONE include dims — the store appends `@<dims>` itself, so an id carrying its own size double-stamps) + `indexDocuments` defaulting `embedderId` to it + `SqliteVectorStore.reconcileFingerprint` (the only comparison site). Rule: dimensions ALWAYS decide, model ids decide only when BOTH sides named themselves — refusing on an absent name would block the majority of callers who never pass `embedderId`.
|
|
128
130
|
- **Retrieval record** (8.8.0) → FOUR stages write one object in sequence: `loadRelevant` (candidates+scores+threshold verdicts) → `pickByBudget` (re-marks admitted→over-budget/over-max-entries) → `formatDefault` (`promptFragment` + `promptPosition`) → the read mount's outputMapper lifts it to root as `retrievalEvidence_<id>`. `memoryRecallInjections` then splits ONE recall into one ActiveInjection PER CHUNK — guarded by a byte-equality check (`fragments.join('\n\n') === systemContent`) that falls back to the single injection rather than change the prompt. `rank` (score order) and `promptPosition` (picker order) are DIFFERENT and both load-bearing: joining fragments in rank order reproduces the right bytes in a sequence the model never saw.
|
|
129
131
|
- **AgentState** → all 8 stages/ files, both builders' mappers, memory-wire STRING-TYPED keys ('runIdentity'/'turnNumber'/… buildAgentChart.ts:177-180 — not refactor-safe), finalizeResult's `reliabilityFail*`/`policyHalt*` reads (rename silently kills the typed errors).
|
|
130
|
-
- **events/** →
|
|
132
|
+
- **events/** → 102 typed events across 22 domains (counts anti-drift-tested against this file — update BOTH when adding events): ALL_EVENT_TYPES exhaustiveness tests, DomainWildcard hand-list, ~42 importers (recorders, strategies, stream, commentary).
|
|
131
133
|
- **Run-configuration manifest (9.41.0)** → `agentfootprint.agent.run_configured`, the JOIN KEY that turns N runs into N labelled ARMS: one event naming the adapters/strategies in play (provider+model, reactMode, each memory's declared strategy/retrieval/embedder, window, graph posture+classifier, evidence posture, artifacts-present). Composed by the PURE `core/agent/runManifest.ts`, dispatched from `Agent.emitRunManifest()` at the END of `createExecutor` — the ONE funnel `run()` AND `resume()` share, both of which mint a fresh runId. Direct `dispatcher.dispatch` with a STATED pseudo-stage (`run-configured#0`), the `emitToolSessionReport` precedent — there is no stage yet, and `minimalMeta()` would make the one joinable-by-design event unjoinable. TWO laws, both tested: NAMES ONLY (a store is reported PRESENT and unnamed rather than identified by a directory/endpoint — `MemoryStore` and `ArtifactStore` declare no id), and ABSENT means "not configured", never a guessed `'default'`. Graph presence is read off `skillGraphNextSkill`, NOT `skillGraphCascade` (a 9.16-style mount sets no cascade and would read as "no graph"). `MemoryDefinition` gained `strategy`/`retrieval`/`embedderId` for it — declared names the compiled pipeline had closed over, the `store`-in-the-open precedent.
|
|
132
134
|
- **adapters/types.ts LLMMessage/LLMRequest** → 62 importers: tool_use round-trip (toolCalls.ts:115-135), wire assembly (callLLM.ts:150-160), providers, cache strategies, security/extractSequence, reliability loop.
|
|
133
135
|
- **Cache** → strategy registration is a MODULE SIDE EFFECT (src/index.ts:15-17); an entry point skipping that import silently falls back to NoOp. Resolved once per Agent at construction (Agent.ts:347).
|
|
@@ -144,6 +146,7 @@ Traps: `src/observability/` holds the finder IMPLEMENTATIONS (canonical home; `d
|
|
|
144
146
|
- **Skill visibility** (9.11.0) → the async half rides the tools slot's Discover stage (the ONE awaitable stage there) into a closure-shared `hiddenSkillIds`, read by the sync Compose stage — the `providerToolCache` pattern exactly. `readSkillFor` now takes `{currentSkillId?, hiddenSkillIds?}`; `ReadSkillOffer.grantable` became OPTIONAL (no graph ⇒ plain filtered catalog) and `hiddenIds` removes rows from BOTH sections. The ENUM stays the full catalog (8.5.0's law — narrowing it turns a policy refusal into a generic schema error that `toolArgValidation` raises before any gate). `skill:<id>` targets have ONE owner: `security/skillTarget.ts`.
|
|
145
147
|
- **Tool-result cap** (9.11.0) → `core/agent/toolResultCap.ts` + `ToolCallsHandlerDeps.maxToolResultChars` + the `capResults` closure applied at all FIVE `tool_end`-emitting dispatch paths in toolCalls.ts (execute, ask-resume, check-in decision, credential-consent resume, pauseHere answer). Both channels are measured separately — `result` (the event) and `modelResult` (history) — because a middleware may have already shrunk one. A new dispatch path MUST call `capResults` or it silently escapes the ceiling.
|
|
146
148
|
- **Refusing result ceiling** (9.20.0) → the PER-TOOL sibling of the cap with the OPPOSITE overflow answer: `Tool.resultCeiling {maxChars, narrowBy?}` (type + `assertResultCeiling` in core/tools.ts; measurement + refusal sentence in `core/agent/resultCeiling.ts`) REFUSES — "No data was returned" + how to narrow — never truncates (truncation reads as complete data ⇒ fabrication). Applied by the `refuseOverCeiling` closure at BOTH execute boundaries (batch loop + `resolveCredentialAndExecute`, covering all four resume paths; the pauseHere answer is a HUMAN's value, deliberately not measured), at the moment the handler's return lands — BEFORE gates/after-tool chain (read_skill-gate precedent). The payload enters NO channel; the record keeps `tools.result_refused {sizeChars, maxChars, narrowBy?, declaredStatus?}`; delivered status = `'invalid'` (routes via `onToolStatus`); an envelope's DECLARED effects are still judged (the effects channel didn't overflow) but its status is overridden; `ceilingRefused` blocks step-pointer advance on every path. Zero-cost: no `resultCeiling` ⇒ one undefined check, byte-identical.
|
|
149
|
+
- **Semantic tool results** (9.53.0) → ONE vocabulary leaf `lib/semantics/types.ts` (the toolOutcome precedent; type-only imports of coverage types — absorbed, never duplicated) + ONE rule set `semanticIssues` serving three doors: `semantic()` mint refusals, `readSemantics` strict recognition (any fault ⇒ data path byte-for-byte + dev warn — never half-applied), and `checkSemantics` findings (same codes). Dispatch wiring is the coverage/ceiling radius verbatim: `declareSemantics` closure at BOTH execute boundaries in toolCalls.ts, ordered declareCoverage → declareSemantics → refuseOverCeiling — the coverage funnel (`readCoverageResult`) grew a semantic arm so the envelope's `coverage` field flows the coverage() channel with zero boundary edits, the FULL envelope rides `tools.semantics_declared` (structuredClone-detached) BEFORE the ceiling (caveats survive an oversized refusal), and the ceiling measures the PROJECTION (`semanticsForModel`: drops marker/render/coverage-detail, composes `not_covered` FROM coverage) because that is what the model reads. `Tool.resultClass` ('triage'|'inventory', closed) validated at defineTool (`assertResultClass`, the assertResultCeiling law) and consumed ONLY by the gate. Gate = tool-lint humble-shell verbatim: core in lib/semantics/{check,format,cli}.ts, bin `agentfootprint-check-semantics.mjs`, exit 0/1/2, judges SAMPLE results (mock returns) — never executes tools. Deliberately UNCHANGED: no new scope key (the envelope is per-attempt ⇒ event channel; coverage rows reuse `coverageDeclared`), no status word, no gate flag, pause-answer paths not recognized (human values are not envelopes).
|
|
147
150
|
- **Conjunction matcher** (9.20.0) → `SkillMatch` gains `{all: [...]}` (AND of the SYNC arms only), all inside skillMatch.ts: `compileAllArm` (ONE compilation → AND predicate + flat `{kind:'all', parts}` data; intent member = teaching refusal naming the separate-rule alternative; nested `all` FLATTENED — associativity, the drop-stateful-flags normalize-to-truth precedent; empty refused), `compareWithAll` (shadows-ONLY via `partCoversProvably` part coverage — identical regex / keyword superset; plain-earlier-covers-a-part shadows a later all; NO overlap claims — a conjunction can be unsatisfiable and the specific-first layout is a design), `rawCaption` recursion (parts joined ` AND `, escaped once). Checkup/provenance/toMermaid see through it with zero changes of their own (parts are guaranteed leaves). NOTE `rawCaption` is now the EXPORTED `plainMatchCaption` (one grammar, two consumers: the mermaid label escapes it; skillExamples quotes it in prose).
|
|
148
151
|
- **Examples on start rules** (SG-G) → `examples?: readonly string[]` on `SkillEntryOptions` + BOTH `SkillStartRule` arms + `EntryDecl`; ALL the logic in skillExamples.ts (validate at the ONE funnel `builder.entry` — the config form translates through it): FOUR codes on `GraphProblemCode` proved by RUNNING the compiled predicates on a cold-start context, in declaration order. **TWO START LAWS, and the check-up may not pick one**: the declaration-order cold walk (unconditional entries claim) vs the turn-start cascade's tier-1 `firstRuleMatch` (CONDITIONAL entries only) — mounted by `.classify()` AND by `continuity: 'conversation'`, an AGENT-MOUNT option invisible at graph build. They differ in exactly one place (whether a default claims), so both are computed and an ERROR is asserted only where they AGREE: `example-shadowed-by-earlier` ERROR (earlier CONDITIONAL claimant, or both laws putting the turn elsewhere) vs `example-shadowed-by-default` WARNING (earlier UNCONDITIONAL claimant — both readings named; erroring here contradicted the live router, which routes that turn to the later rule under `continuity:'conversation'`). SEVERITY FOLLOWS PROVABILITY on `example-misses-own-rule`: ERROR for a data `match` (reads `userMessage` only ⇒ no-match holds under every context) or a THROW (turn 1 really hands it that context); WARNING for an opaque `when` (may be gated on `ctx.history.length > 0` and claim on a later turn — history survives a run, the cursor does not). Every message NAMES the judged context (iteration 1 / phrase / empty history / no cursor) and `describeCondition` has an UNCONDITIONAL arm — printing "its `when` predicate" for an entry that declares none was a message describing a graph nobody wrote. `example-unclaimed` WARNING. Ordering checks gated on the SAME `!exclusiveEntries || hasClassifier` premise as the pairwise rule checks; self-match is order-independent and always runs. `GraphCheckup` gains `notes?` (the boundary sentence — rendered by formatCheckup as `[note]`, carried through the deferred-body-contract filter) and `GraphProblem` gains `example?`. TIER LAW: tier-2 `match:{intent,examples}` examples are SCORING material (run time); rule-level `examples` are TEST material (build time only) — both lists on one rule is a teaching refusal, as are an empty/blank list and examples on an UNCONDITIONAL entry (it claims everything, so they would prove nothing). Zero-cost when unused: one `Array.some`, no notes key, byte-identical skills/edges/events.
|
|
149
152
|
|
|
@@ -252,7 +252,7 @@ const agent = Agent.create({ provider, model })
|
|
|
252
252
|
agent.on('agentfootprint.context.evaluated', (e) => console.log(e.payload.activeIds));
|
|
253
253
|
```
|
|
254
254
|
|
|
255
|
-
**
|
|
255
|
+
**102 typed events across 22 domains.** Two subscription shapes and no third:
|
|
256
256
|
`'*'` (every event) and `'agentfootprint.<domain>.*'` (one domain). **`'agentfootprint.*'`
|
|
257
257
|
is not a pattern** — TypeScript rejects it, and at runtime it would match nothing.
|
|
258
258
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* agentfootprint-check-semantics — CI gate for semantic tool results
|
|
4
|
+
* (9.53.0). Humble shell: all behavior lives in src/lib/semantics/cli.ts
|
|
5
|
+
* (unit-tested there); this wrapper only resolves the built module and maps
|
|
6
|
+
* the returned code onto process.exitCode.
|
|
7
|
+
*
|
|
8
|
+
* npx agentfootprint-check-semantics semantics-catalog.json
|
|
9
|
+
* npx agentfootprint-check-semantics semantics-catalog.json --strict
|
|
10
|
+
*
|
|
11
|
+
* Guide: docs-next/content/docs/build/semantic-results.mdx
|
|
12
|
+
*/
|
|
13
|
+
const { runCheckSemanticsCli } = await import('../dist/esm/lib/semantics/cli.js');
|
|
14
|
+
process.exitCode = await runCheckSemanticsCli(process.argv.slice(2));
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
exports.readCoverageResult = void 0;
|
|
20
|
+
const envelope_js_1 = require("../../../lib/semantics/envelope.js");
|
|
20
21
|
const absent_js_1 = require("./absent.js");
|
|
21
22
|
const ledger_js_1 = require("./ledger.js");
|
|
22
23
|
const ABSENT_STATUS = 'absent';
|
|
@@ -38,6 +39,18 @@ function readCoverageResult(value) {
|
|
|
38
39
|
],
|
|
39
40
|
};
|
|
40
41
|
}
|
|
42
|
+
// A semantic envelope's `coverage` field (9.53.0) is ABSORBED here — the
|
|
43
|
+
// one recognizer funnel — so the boundary a semantic tool declared flows
|
|
44
|
+
// through the exact channel `coverage()` uses (the `tools.coverage_declared`
|
|
45
|
+
// event, tracked state, the final-answer limits block) with zero extra
|
|
46
|
+
// wiring at any dispatch door. A semantic envelope without `coverage`
|
|
47
|
+
// declares no boundary, exactly like a bare result.
|
|
48
|
+
const sem = (0, envelope_js_1.readSemantics)(value);
|
|
49
|
+
if (sem !== undefined) {
|
|
50
|
+
if (sem.coverage === undefined)
|
|
51
|
+
return undefined;
|
|
52
|
+
return { declared: [{ kind: 'ledger', coverage: (0, envelope_js_1.coverageOfSemantics)(sem) }] };
|
|
53
|
+
}
|
|
41
54
|
const covered = (0, ledger_js_1.readCoverageLedger)(value);
|
|
42
55
|
if (covered === undefined)
|
|
43
56
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../../src/core/agent/coverage/read.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAGH,2CAA6D;AAC7D,2CAAmE;AA6BnE,MAAM,aAAa,GAAqB,QAAQ,CAAC;AAEjD;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAAC,KAAc;IAC/C,MAAM,OAAO,GAAG,IAAA,uBAAW,EAAC,KAAK,CAAC,CAAC;IACnC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO;YACL,MAAM,EAAE,aAAa;YACrB,QAAQ,EAAE;gBACR,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAA,6BAAiB,EAAC,OAAO,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,UAAU,EAAE;aACzF;SACF,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,IAAA,8BAAkB,EAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,QAAQ,GAAoB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAA,4BAAgB,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5F,MAAM,KAAK,GAAG,IAAA,uBAAW,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC7C,QAAQ,CAAC,IAAI,CAAC;QACZ,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,IAAA,6BAAiB,EAAC,KAAK,CAAC;QAClC,SAAS,EAAE,KAAK,CAAC,UAAU;KAC5B,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;AAC7C,CAAC;
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../../src/core/agent/coverage/read.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAGH,oEAAwF;AACxF,2CAA6D;AAC7D,2CAAmE;AA6BnE,MAAM,aAAa,GAAqB,QAAQ,CAAC;AAEjD;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAAC,KAAc;IAC/C,MAAM,OAAO,GAAG,IAAA,uBAAW,EAAC,KAAK,CAAC,CAAC;IACnC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO;YACL,MAAM,EAAE,aAAa;YACrB,QAAQ,EAAE;gBACR,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAA,6BAAiB,EAAC,OAAO,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,UAAU,EAAE;aACzF;SACF,CAAC;IACJ,CAAC;IACD,yEAAyE;IACzE,yEAAyE;IACzE,6EAA6E;IAC7E,uEAAuE;IACvE,sEAAsE;IACtE,oDAAoD;IACpD,MAAM,GAAG,GAAG,IAAA,2BAAa,EAAC,KAAK,CAAC,CAAC;IACjC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QACjD,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAA,iCAAmB,EAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;IAChF,CAAC;IACD,MAAM,OAAO,GAAG,IAAA,8BAAkB,EAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,QAAQ,GAAoB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAA,4BAAgB,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5F,MAAM,KAAK,GAAG,IAAA,uBAAW,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC7C,QAAQ,CAAC,IAAI,CAAC;QACZ,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,IAAA,6BAAiB,EAAC,KAAK,CAAC;QAClC,SAAS,EAAE,KAAK,CAAC,UAAU;KAC5B,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;AAC7C,CAAC;AAhCD,gDAgCC"}
|
|
@@ -69,6 +69,7 @@ const validators_js_1 = require("../validators.js");
|
|
|
69
69
|
const toolResultCap_js_1 = require("../toolResultCap.js");
|
|
70
70
|
const resultCeiling_js_1 = require("../resultCeiling.js");
|
|
71
71
|
const skillSteps_js_1 = require("../../../lib/injection-engine/skillSteps.js");
|
|
72
|
+
const envelope_js_1 = require("../../../lib/semantics/envelope.js");
|
|
72
73
|
const index_js_1 = require("../coverage/index.js");
|
|
73
74
|
const toolEffects_js_1 = require("../toolEffects.js");
|
|
74
75
|
/** Declaration order preserved, ids de-duplicated — the shape the gate's re-prompt
|
|
@@ -381,6 +382,66 @@ function buildToolCallsHandler(deps) {
|
|
|
381
382
|
scope.coverageDeclared = [...(scope.coverageDeclared ?? []), ...rows];
|
|
382
383
|
return reading.status;
|
|
383
384
|
};
|
|
385
|
+
/**
|
|
386
|
+
* The semantic envelope (9.53.0) — recognized at the SAME execute
|
|
387
|
+
* boundaries as coverage and the ceiling (one implementation, every door),
|
|
388
|
+
* AFTER `declareCoverage` (which absorbs the envelope's `coverage` field
|
|
389
|
+
* through the one coverage funnel) and BEFORE `refuseOverCeiling` (so the
|
|
390
|
+
* FULL envelope — grain, provenance, render, coverage — is on the record
|
|
391
|
+
* even when the content is refused as oversized: a caveat that died with
|
|
392
|
+
* an oversized result would be the silence the envelope exists to break).
|
|
393
|
+
*
|
|
394
|
+
* Returns the MODEL's view — the compact rendering-free projection
|
|
395
|
+
* (`semanticsForModel`: data + grain + provenance + composed `not_covered`
|
|
396
|
+
* + non-null clarify + the static note; never the marker, `render`, or the
|
|
397
|
+
* three-list coverage detail) — or `undefined` for every non-envelope
|
|
398
|
+
* value, which keeps today's path byte for byte. The full envelope rides
|
|
399
|
+
* the typed `tools.semantics_declared` event, so recordings and UIs get
|
|
400
|
+
* everything the model was spared.
|
|
401
|
+
*
|
|
402
|
+
* A value CARRYING the marker that this library cannot honor stays DATA
|
|
403
|
+
* (never half-applied — the recognition strictness law) and is dev-warned
|
|
404
|
+
* here naming its first fault; `check:semantics` names them all at build
|
|
405
|
+
* time.
|
|
406
|
+
*/
|
|
407
|
+
const declareSemantics = (scope, call, value) => {
|
|
408
|
+
const sem = (0, envelope_js_1.readSemantics)(value);
|
|
409
|
+
if (sem === undefined) {
|
|
410
|
+
const faults = (0, envelope_js_1.explainSemantics)(value);
|
|
411
|
+
if (faults !== undefined && faults.length > 0 && (0, footprintjs_1.isDevMode)()) {
|
|
412
|
+
// eslint-disable-next-line no-console
|
|
413
|
+
console.warn(`agentfootprint semantics: tool '${call.toolName}' returned a value carrying ` +
|
|
414
|
+
`af_semantics that was NOT recognized (treated as plain data): ` +
|
|
415
|
+
`${faults[0].message} (field: ${faults[0].field})` +
|
|
416
|
+
(faults.length > 1 ? ` — and ${faults.length - 1} more; run check:semantics.` : ''));
|
|
417
|
+
}
|
|
418
|
+
return undefined;
|
|
419
|
+
}
|
|
420
|
+
// Detached plain data for the record — the event must not hold a live
|
|
421
|
+
// reference into a value the tool still owns. An envelope that cannot
|
|
422
|
+
// survive structuredClone cannot ride the record (or a checkpoint), so
|
|
423
|
+
// it is declined here — data path, dev-warned — rather than half-filed.
|
|
424
|
+
let detached;
|
|
425
|
+
try {
|
|
426
|
+
detached = structuredClone(sem);
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
if ((0, footprintjs_1.isDevMode)()) {
|
|
430
|
+
// eslint-disable-next-line no-console
|
|
431
|
+
console.warn(`agentfootprint semantics: tool '${call.toolName}' returned a semantic envelope ` +
|
|
432
|
+
`that does not survive structuredClone (a function or live handle in a fact row?) ` +
|
|
433
|
+
`— treated as plain data. Envelope values must be plain data.`);
|
|
434
|
+
}
|
|
435
|
+
return undefined;
|
|
436
|
+
}
|
|
437
|
+
(0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.tools.semantics_declared', {
|
|
438
|
+
toolName: call.toolName,
|
|
439
|
+
toolCallId: call.toolCallId,
|
|
440
|
+
iteration: call.iteration,
|
|
441
|
+
semantics: detached,
|
|
442
|
+
});
|
|
443
|
+
return (0, envelope_js_1.semanticsForModel)(sem);
|
|
444
|
+
};
|
|
384
445
|
// ── Step-procedure boundary (9.18.0) — ONE implementation, five sites ──
|
|
385
446
|
// The batch loop and the four resume paths all finalize results; each
|
|
386
447
|
// calls these where its result becomes final, so a pointer can never miss
|
|
@@ -1284,7 +1345,9 @@ function buildToolCallsHandler(deps) {
|
|
|
1284
1345
|
}
|
|
1285
1346
|
}
|
|
1286
1347
|
try {
|
|
1287
|
-
const
|
|
1348
|
+
// `let`, not `const`: the semantic projection below replaces the value
|
|
1349
|
+
// on the non-envelope path exactly as the batch loop does.
|
|
1350
|
+
let result = await tool.execute(args, {
|
|
1288
1351
|
toolCallId,
|
|
1289
1352
|
iteration,
|
|
1290
1353
|
...(env.signal && { signal: env.signal }),
|
|
@@ -1310,6 +1373,12 @@ function buildToolCallsHandler(deps) {
|
|
|
1310
1373
|
// and wins over the envelope's only when the envelope declared none.
|
|
1311
1374
|
const coverageStatus = declareCoverage(scope, { toolName, toolCallId, iteration }, envelope.content);
|
|
1312
1375
|
const declaredStatus = envelope.status ?? coverageStatus;
|
|
1376
|
+
// The semantic envelope (9.53.0), on the unwrapped content — the
|
|
1377
|
+
// effects+semantics composition point: full envelope to the record,
|
|
1378
|
+
// projection to the model. BEFORE the ceiling, which must measure
|
|
1379
|
+
// what the model will actually read.
|
|
1380
|
+
const semanticView = declareSemantics(scope, { toolName, toolCallId, iteration }, envelope.content);
|
|
1381
|
+
const content = semanticView ?? envelope.content;
|
|
1313
1382
|
// The tool's own ceiling (9.20.0) measures the CONTENT — the channel
|
|
1314
1383
|
// that can overflow a context window. The DECLARED effects are small
|
|
1315
1384
|
// validated data and are still judged by the caller: a tool that
|
|
@@ -1317,7 +1386,7 @@ function buildToolCallsHandler(deps) {
|
|
|
1317
1386
|
// transition. The delivered status becomes 'invalid' (the declared
|
|
1318
1387
|
// status described a result the model never received — the
|
|
1319
1388
|
// `result_refused` event keeps what was declared).
|
|
1320
|
-
const refusal = refuseOverCeiling(scope, { toolName, toolCallId, iteration }, tool,
|
|
1389
|
+
const refusal = refuseOverCeiling(scope, { toolName, toolCallId, iteration }, tool, content, declaredStatus);
|
|
1321
1390
|
if (refusal !== undefined) {
|
|
1322
1391
|
return {
|
|
1323
1392
|
result: refusal,
|
|
@@ -1327,12 +1396,23 @@ function buildToolCallsHandler(deps) {
|
|
|
1327
1396
|
};
|
|
1328
1397
|
}
|
|
1329
1398
|
return {
|
|
1330
|
-
result:
|
|
1399
|
+
result: content,
|
|
1331
1400
|
executed: true,
|
|
1332
|
-
envelope: declaredStatus === envelope.status
|
|
1401
|
+
envelope: declaredStatus === envelope.status && semanticView === undefined
|
|
1402
|
+
? envelope
|
|
1403
|
+
: {
|
|
1404
|
+
...envelope,
|
|
1405
|
+
content,
|
|
1406
|
+
...(declaredStatus !== undefined && { status: declaredStatus }),
|
|
1407
|
+
},
|
|
1333
1408
|
};
|
|
1334
1409
|
}
|
|
1335
1410
|
const coverageStatus = declareCoverage(scope, { toolName, toolCallId, iteration }, result);
|
|
1411
|
+
// The semantic envelope (9.53.0) on this path's own execute boundary —
|
|
1412
|
+
// a resumed call's envelope is judged exactly as an inline one's.
|
|
1413
|
+
const semanticView = declareSemantics(scope, { toolName, toolCallId, iteration }, result);
|
|
1414
|
+
if (semanticView !== undefined)
|
|
1415
|
+
result = semanticView;
|
|
1336
1416
|
const refusal = refuseOverCeiling(scope, { toolName, toolCallId, iteration }, tool, result, coverageStatus);
|
|
1337
1417
|
if (refusal !== undefined) {
|
|
1338
1418
|
// Synthesized empty-effects envelope: the resume paths read the
|
|
@@ -2046,6 +2126,17 @@ function buildToolCallsHandler(deps) {
|
|
|
2046
2126
|
const coverageStatus = declareCoverage(scope, { toolName: tc.name, toolCallId: tc.id, iteration }, result);
|
|
2047
2127
|
if (toolStatus === undefined)
|
|
2048
2128
|
toolStatus = coverageStatus;
|
|
2129
|
+
// The semantic envelope (9.53.0), on the unwrapped content and
|
|
2130
|
+
// AFTER coverage (whose funnel absorbs the envelope's own
|
|
2131
|
+
// `coverage` field), BEFORE the ceiling (which must measure
|
|
2132
|
+
// what the model will actually read, and must not silently
|
|
2133
|
+
// delete grain/provenance — they are already on the record by
|
|
2134
|
+
// the time it fires). Everything downstream — governance, the
|
|
2135
|
+
// cap, history, `tool_end` — sees the compact projection; the
|
|
2136
|
+
// full envelope rides `tools.semantics_declared`.
|
|
2137
|
+
const semanticView = declareSemantics(scope, { toolName: tc.name, toolCallId: tc.id, iteration }, result);
|
|
2138
|
+
if (semanticView !== undefined)
|
|
2139
|
+
result = semanticView;
|
|
2049
2140
|
// The tool's own refusing ceiling (9.20.0) — at the execute
|
|
2050
2141
|
// boundary, BEFORE the gates and the after-tool chain, so
|
|
2051
2142
|
// governance and the agent-level cap compose over what the
|