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
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check:semantics CLI core (9.53.0 — the build gate).
|
|
3
|
+
*
|
|
4
|
+
* Pattern: humble shell (the tool-lint `cli.ts` precedent) —
|
|
5
|
+
* `bin/agentfootprint-check-semantics.mjs` is a 2-line wrapper;
|
|
6
|
+
* ALL behavior (arg parsing, catalog coercion, report, exit code)
|
|
7
|
+
* lives here so it is unit-testable without spawning a process.
|
|
8
|
+
* Role: `src/lib/semantics/`. Reads ONE JSON file of tools + sample
|
|
9
|
+
* results, prints a report, returns the process exit code:
|
|
10
|
+
* 0 — report.ok (and, under --strict, zero warnings)
|
|
11
|
+
* 1 — findings failed the gate
|
|
12
|
+
* 2 — usage / input error (bad flags, unreadable file,
|
|
13
|
+
* unrecognized JSON shape, unknown resultClass)
|
|
14
|
+
*
|
|
15
|
+
* Consumers wire it beside their other gates (the `check:tools` convention):
|
|
16
|
+
*
|
|
17
|
+
* "check:semantics": "node scripts/dump-semantics-catalog.mjs && agentfootprint-check-semantics semantics-catalog.json"
|
|
18
|
+
*
|
|
19
|
+
* The catalog is sample results — what your MOCK tools return — because the
|
|
20
|
+
* gate judges result shapes, and a build must never run tools that touch
|
|
21
|
+
* live systems. A mock catalog is something this ecosystem already has
|
|
22
|
+
* everywhere the check matters.
|
|
23
|
+
*/
|
|
24
|
+
import { checkSemantics } from './check.js';
|
|
25
|
+
import { formatSemanticsReport } from './format.js';
|
|
26
|
+
import { RESULT_CLASSES } from './types.js';
|
|
27
|
+
const USAGE = `usage: agentfootprint-check-semantics <semantics-catalog.json> [options]
|
|
28
|
+
|
|
29
|
+
<semantics-catalog.json> JSON file of tools + sample results. Accepted shapes:
|
|
30
|
+
[{ name, resultClass?, results: [...] }]
|
|
31
|
+
[{ name, resultClass?, result: ... }] (single sample)
|
|
32
|
+
{ tools: [...] } (either row shape)
|
|
33
|
+
|
|
34
|
+
resultClass ∈ { ${RESULT_CLASSES.join(', ')} } — the class
|
|
35
|
+
declared on defineTool({ resultClass }); omit for tools
|
|
36
|
+
with no class rules (envelope rules still apply).
|
|
37
|
+
|
|
38
|
+
--strict warnings also fail the gate
|
|
39
|
+
--json print the full report as JSON instead of text
|
|
40
|
+
|
|
41
|
+
exit codes: 0 ok · 1 findings failed the gate · 2 usage/input error`;
|
|
42
|
+
/**
|
|
43
|
+
* Normalize the accepted JSON shapes to the checker's catalog. Throws (with
|
|
44
|
+
* a shape description) on unrecognized input — the CLI maps that to exit
|
|
45
|
+
* code 2. `resultClass` values are passed through untouched; the checker is
|
|
46
|
+
* the one owner of the closed-set refusal.
|
|
47
|
+
*/
|
|
48
|
+
export function coerceSemanticsCatalog(json) {
|
|
49
|
+
const list = Array.isArray(json)
|
|
50
|
+
? json
|
|
51
|
+
: json !== null &&
|
|
52
|
+
typeof json === 'object' &&
|
|
53
|
+
Array.isArray(json.tools)
|
|
54
|
+
? json.tools
|
|
55
|
+
: undefined;
|
|
56
|
+
if (list === undefined) {
|
|
57
|
+
throw new Error('expected a JSON array of { name, resultClass?, results } rows or { tools: [...] }');
|
|
58
|
+
}
|
|
59
|
+
return list.map((raw, index) => {
|
|
60
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
61
|
+
throw new Error(`tools[${index}] is not an object`);
|
|
62
|
+
}
|
|
63
|
+
const entry = raw;
|
|
64
|
+
const name = entry.name;
|
|
65
|
+
if (typeof name !== 'string' || name.length === 0) {
|
|
66
|
+
throw new Error(`tools[${index}] has no string 'name'`);
|
|
67
|
+
}
|
|
68
|
+
const results = Array.isArray(entry.results)
|
|
69
|
+
? entry.results
|
|
70
|
+
: 'result' in entry
|
|
71
|
+
? [entry.result]
|
|
72
|
+
: undefined;
|
|
73
|
+
if (results === undefined) {
|
|
74
|
+
throw new Error(`tools[${index}] ('${name}') has neither 'results' (an array of sample results) nor ` +
|
|
75
|
+
`'result' (one sample) — the gate judges sample results; a mock tool's return is ` +
|
|
76
|
+
`the natural sample.`);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
name,
|
|
80
|
+
...(entry.resultClass !== undefined
|
|
81
|
+
? { resultClass: entry.resultClass }
|
|
82
|
+
: {}),
|
|
83
|
+
results,
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Run the gate CLI. Returns the exit code (never calls `process.exit` — the
|
|
89
|
+
* bin wrapper assigns it to `process.exitCode`).
|
|
90
|
+
*/
|
|
91
|
+
export async function runCheckSemanticsCli(argv, io = {
|
|
92
|
+
// eslint-disable-next-line no-console
|
|
93
|
+
stdout: (line) => console.log(line),
|
|
94
|
+
// eslint-disable-next-line no-console
|
|
95
|
+
stderr: (line) => console.error(line),
|
|
96
|
+
}) {
|
|
97
|
+
let file;
|
|
98
|
+
let strict = false;
|
|
99
|
+
let json = false;
|
|
100
|
+
for (const arg of argv) {
|
|
101
|
+
if (arg === '--strict')
|
|
102
|
+
strict = true;
|
|
103
|
+
else if (arg === '--json')
|
|
104
|
+
json = true;
|
|
105
|
+
else if (arg === '--help' || arg === '-h') {
|
|
106
|
+
io.stderr(USAGE);
|
|
107
|
+
return 2;
|
|
108
|
+
}
|
|
109
|
+
else if (arg.startsWith('-')) {
|
|
110
|
+
io.stderr(`unknown flag '${arg}'\n\n${USAGE}`);
|
|
111
|
+
return 2;
|
|
112
|
+
}
|
|
113
|
+
else if (file === undefined)
|
|
114
|
+
file = arg;
|
|
115
|
+
else {
|
|
116
|
+
io.stderr(`unexpected extra argument '${arg}'\n\n${USAGE}`);
|
|
117
|
+
return 2;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (file === undefined) {
|
|
121
|
+
io.stderr(USAGE);
|
|
122
|
+
return 2;
|
|
123
|
+
}
|
|
124
|
+
let report;
|
|
125
|
+
try {
|
|
126
|
+
// Lazy node:fs import (browser-compat — the tool-lint precedent):
|
|
127
|
+
// `agentfootprint/observe` re-exports this module, and a top-level
|
|
128
|
+
// node:fs import detonates a browser bundle at module-eval. The CLI
|
|
129
|
+
// path is the only consumer that touches the filesystem.
|
|
130
|
+
const { readFile } = await import('node:fs/promises');
|
|
131
|
+
const catalog = coerceSemanticsCatalog(JSON.parse(await readFile(file, 'utf8')));
|
|
132
|
+
report = checkSemantics(catalog);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
io.stderr(`agentfootprint-check-semantics: ${file}: ${error.message}`);
|
|
136
|
+
return 2;
|
|
137
|
+
}
|
|
138
|
+
if (json)
|
|
139
|
+
io.stdout(JSON.stringify(report, null, 2));
|
|
140
|
+
else
|
|
141
|
+
io.stdout(formatSemanticsReport(report));
|
|
142
|
+
if (!report.ok)
|
|
143
|
+
return 1;
|
|
144
|
+
if (strict && report.findings.length > 0)
|
|
145
|
+
return 1;
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../../src/lib/semantics/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* semantics/envelope — minting, recognizing and projecting the semantic
|
|
3
|
+
* tool-result envelope (9.53.0).
|
|
4
|
+
*
|
|
5
|
+
* Pattern: minted by a helper, RECOGNIZED by the framework (the `absent()` /
|
|
6
|
+
* tool-effects precedent). A return shape the framework does not
|
|
7
|
+
* understand is a convention, and a convention cannot ride the
|
|
8
|
+
* record, feed a UI, or be refused by a build gate.
|
|
9
|
+
* Role: lib/ layer, pure. The dispatch loop calls `readSemantics` at the
|
|
10
|
+
* execute boundary; `semantic()` is what a tool author writes;
|
|
11
|
+
* `checkSemantics` (check.ts) judges the same shapes offline.
|
|
12
|
+
* Emits: N/A (the caller emits `agentfootprint.tools.semantics_declared`).
|
|
13
|
+
*
|
|
14
|
+
* ## Two views of one envelope — the design decision, stated
|
|
15
|
+
*
|
|
16
|
+
* The MODEL reads a compact, rendering-free projection
|
|
17
|
+
* ({@link semanticsForModel}): the data (`series`/`facts`/`edges`), the
|
|
18
|
+
* caveats that must travel with it (`grain`, `provenance`), the composed
|
|
19
|
+
* `not_covered` prose, a non-null `clarify`, and the static note. Dropped
|
|
20
|
+
* from the model's view: the `af_semantics` marker (machine-only), `render`
|
|
21
|
+
* (a UI hint — the tool never renders, and a model parroting rendering
|
|
22
|
+
* directives is noise), the three-list `coverage` detail (it rides the
|
|
23
|
+
* coverage channel and the record; the model reads the composed
|
|
24
|
+
* `not_covered` lines instead), and a `clarify: null` (a stated non-question
|
|
25
|
+
* is a fact for the record, not something the model acts on).
|
|
26
|
+
*
|
|
27
|
+
* The RECORD gets everything: the full envelope — render, coverage,
|
|
28
|
+
* marker and all — lands on the `tools.semantics_declared` event BEFORE the
|
|
29
|
+
* result ceiling is measured, so grain and provenance survive to recordings
|
|
30
|
+
* and UIs even when the content itself is refused as oversized. The
|
|
31
|
+
* `coverage` field is additionally declared through the SAME channel the
|
|
32
|
+
* `coverage()` primitive uses (`tools.coverage_declared`, tracked state, the
|
|
33
|
+
* final-answer limits block) — absorbed, never duplicated.
|
|
34
|
+
*
|
|
35
|
+
* ## One rule set, two doors
|
|
36
|
+
*
|
|
37
|
+
* `semantic()` refuses a declaration this vocabulary cannot honor at the
|
|
38
|
+
* CALL SITE (the `absent()` law) — so a minted envelope is honest by
|
|
39
|
+
* construction: series carry their grain, data carries its provenance,
|
|
40
|
+
* counter-looking aggregations state `is_counter`. `semanticIssues()` judges
|
|
41
|
+
* the RENDERED shape — the same rules over a value somebody may have built
|
|
42
|
+
* by hand — and is what recognition and the `check:semantics` gate both
|
|
43
|
+
* stand on. Recognition is STRICT (the zero-cost guarantee): a marker-
|
|
44
|
+
* bearing value with any issue is NOT recognized — it keeps its bytes on
|
|
45
|
+
* the data path (dev-warned, and named field-by-field by the gate), because
|
|
46
|
+
* this library does not half-apply a shape it cannot fully honor.
|
|
47
|
+
*/
|
|
48
|
+
import type { Coverage } from '../../core/agent/coverage/types.js';
|
|
49
|
+
import { type SemanticCoverage, type SemanticDeclaration, type ToolSemantics } from './types.js';
|
|
50
|
+
/** The codes an envelope can be faulted with — shared by recognition (any
|
|
51
|
+
* issue ⇒ not recognized) and the `check:semantics` gate (issues become
|
|
52
|
+
* findings under these same names). */
|
|
53
|
+
export type SemanticIssueCode = 'malformed-semantics' | 'series-without-grain' | 'counter-aggregation-unstated' | 'data-without-provenance';
|
|
54
|
+
/** One fault, naming the field so a refusal can teach and a gate can point. */
|
|
55
|
+
export interface SemanticIssue {
|
|
56
|
+
readonly code: SemanticIssueCode;
|
|
57
|
+
/** The offending / missing field, dot-pathed ('grain.is_counter'). */
|
|
58
|
+
readonly field: string;
|
|
59
|
+
readonly message: string;
|
|
60
|
+
}
|
|
61
|
+
/** Whole-token match against {@link COUNTER_AGGREGATION_WORDS}, singular or
|
|
62
|
+
* plural, case-insensitive — 'sum' and 'Counts' look like counters,
|
|
63
|
+
* 'summary' does not. */
|
|
64
|
+
export declare function isCounterLookingAggregation(aggregation: string): boolean;
|
|
65
|
+
/** Compose the `not_covered` prose lines FROM coverage — the one derivation,
|
|
66
|
+
* used by the mint and by the drift check, so the two can never disagree. */
|
|
67
|
+
export declare function composeNotCovered(coverage: SemanticCoverage): readonly string[];
|
|
68
|
+
/**
|
|
69
|
+
* Judge one RENDERED envelope shape against the whole rule set. Empty = a
|
|
70
|
+
* well-formed envelope this library can honor. Non-empty = the faults, each
|
|
71
|
+
* naming its field.
|
|
72
|
+
*
|
|
73
|
+
* Called with values that carry the marker; on anything else it reports the
|
|
74
|
+
* missing marker rather than guessing.
|
|
75
|
+
*/
|
|
76
|
+
export declare function semanticIssues(value: unknown): readonly SemanticIssue[];
|
|
77
|
+
/**
|
|
78
|
+
* Say "here is typed data, with the caveats that make it honest" in a shape
|
|
79
|
+
* the framework recognizes, the record keeps whole, and a build gate can
|
|
80
|
+
* refuse.
|
|
81
|
+
*
|
|
82
|
+
* Returns the value a tool's `execute` should return. The framework
|
|
83
|
+
* recognizes it at the dispatch boundary: the MODEL reads the compact
|
|
84
|
+
* projection ({@link semanticsForModel}), the FULL envelope rides the typed
|
|
85
|
+
* `agentfootprint.tools.semantics_declared` event, and a declared `coverage`
|
|
86
|
+
* flows through the same channel `coverage()` uses.
|
|
87
|
+
*
|
|
88
|
+
* Refuses (throws, at the call site — the `absent()` law) any declaration
|
|
89
|
+
* this vocabulary cannot honor: series without grain, data without
|
|
90
|
+
* provenance, a counter-looking aggregation with `is_counter` unstated, and
|
|
91
|
+
* every malformed shape — each refusal names the field and the fix.
|
|
92
|
+
*
|
|
93
|
+
* @example a per-port IOPS tool
|
|
94
|
+
* return semantic({
|
|
95
|
+
* series: rows.map((r) => ({ t: r.time, entity: r.port, metric: 'avg_iops', value: r.iops })),
|
|
96
|
+
* grain: { interval: '30m', aggregation: 'avg', is_counter: false },
|
|
97
|
+
* provenance: { measured_at: latestSampleTime, source: 'InfluxDB SwitchPortStats' },
|
|
98
|
+
* coverage: {
|
|
99
|
+
* checked: ['shq-fab-a: all 48 FC ports'],
|
|
100
|
+
* notChecked: [{ what: 'the peer fabric', why: 'this collector is scoped to one fabric' }],
|
|
101
|
+
* },
|
|
102
|
+
* render: { default: 'table', columns: ['entity', 'value'], sort: 'value desc' },
|
|
103
|
+
* });
|
|
104
|
+
*/
|
|
105
|
+
export declare function semantic(decl: SemanticDeclaration): ToolSemantics;
|
|
106
|
+
/**
|
|
107
|
+
* Recognize (or decline to recognize) a value as a semantic envelope —
|
|
108
|
+
* STRICT, and the strictness is the zero-cost guarantee. Only a plain object
|
|
109
|
+
* whose `af_semantics` is exactly `true` AND that passes the whole rule set
|
|
110
|
+
* qualifies; every other value any tool has ever returned takes the path it
|
|
111
|
+
* always took, byte for byte.
|
|
112
|
+
*
|
|
113
|
+
* `undefined` means "not an envelope this library can honor" — a marker-
|
|
114
|
+
* bearing value with faults stays DATA (never half-applied); the dispatch
|
|
115
|
+
* loop dev-warns it and `check:semantics` names every fault.
|
|
116
|
+
*/
|
|
117
|
+
export declare function readSemantics(value: unknown): ToolSemantics | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* Name what is wrong with a value that CARRIES the marker but was not
|
|
120
|
+
* recognized. `undefined` for values without the marker (they are data, not
|
|
121
|
+
* near-misses) and for well-formed envelopes. Diagnosis only — never changes
|
|
122
|
+
* what any value does.
|
|
123
|
+
*/
|
|
124
|
+
export declare function explainSemantics(value: unknown): readonly SemanticIssue[] | undefined;
|
|
125
|
+
/**
|
|
126
|
+
* The MODEL's view of one recognized envelope — compact and rendering-free.
|
|
127
|
+
*
|
|
128
|
+
* Keeps: the data (`series`/`facts`/`edges`), the caveats that must travel
|
|
129
|
+
* with it (`grain`, `provenance`), the composed `not_covered` prose, a
|
|
130
|
+
* non-null `clarify`, and the static note. Drops: the marker, `render`
|
|
131
|
+
* (UI hint), the three-list `coverage` detail (rides the coverage channel
|
|
132
|
+
* and the record), and a `clarify: null`. Shallow-copied so the history
|
|
133
|
+
* entry is not the object the tool still holds.
|
|
134
|
+
*/
|
|
135
|
+
export declare function semanticsForModel(sem: ToolSemantics): Record<string, unknown>;
|
|
136
|
+
/** The envelope's coverage in the normalized three-list shape the coverage
|
|
137
|
+
* machinery reads — how `readCoverageResult` absorbs a semantic envelope's
|
|
138
|
+
* boundary into the one coverage channel. */
|
|
139
|
+
export declare function coverageOfSemantics(sem: ToolSemantics): Coverage;
|