agentfootprint 9.51.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 +21 -1
- package/CLAUDE.md +6 -2
- package/ai-instructions/claude-code/SKILL.md +18 -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 +141 -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 +141 -4
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/tools.d.ts +64 -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 +49 -0
- package/dist/esm/events/registry.d.ts +5 -1
- package/dist/esm/events/registry.js +4 -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/mcp/mcpServe.js +10 -0
- package/dist/esm/lib/mcp/mcpServe.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/esm/lib/trace-toolpack/traceToolpack.js +6 -0
- package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
- package/dist/events/registry.js +4 -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/mcp/mcpServe.js +10 -0
- package/dist/lib/mcp/mcpServe.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/lib/trace-toolpack/traceToolpack.js +6 -0
- package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
- 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 +64 -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 +49 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +5 -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/mcp/mcpServe.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/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* semantics/format — rendering one {@link SemanticsReport} for a terminal.
|
|
3
|
+
*
|
|
4
|
+
* Pattern: the tool-lint `format.ts` sibling — pure string building, no IO.
|
|
5
|
+
* Role: lib/ layer, pure.
|
|
6
|
+
* Emits: N/A.
|
|
7
|
+
*/
|
|
8
|
+
function findingLine(f) {
|
|
9
|
+
const mark = f.severity === 'error' ? '✗' : '⚠';
|
|
10
|
+
const where = f.resultIndex !== undefined ? ` result ${f.resultIndex + 1}` : '';
|
|
11
|
+
return ` ${mark} ${f.tool}${where} [${f.code}] field: ${f.field}\n ${f.message}`;
|
|
12
|
+
}
|
|
13
|
+
/** Render the report. Every finding names its tool and its field — the two
|
|
14
|
+
* facts a build log must carry for the fix to be a one-line edit. */
|
|
15
|
+
export function formatSemanticsReport(report) {
|
|
16
|
+
const errors = report.findings.filter((f) => f.severity === 'error');
|
|
17
|
+
const warnings = report.findings.filter((f) => f.severity === 'warning');
|
|
18
|
+
const lines = [
|
|
19
|
+
`check:semantics — ${report.checkedTools} tool${report.checkedTools === 1 ? '' : 's'}, ` +
|
|
20
|
+
`${report.checkedResults} sample result${report.checkedResults === 1 ? '' : 's'}`,
|
|
21
|
+
];
|
|
22
|
+
if (report.findings.length === 0) {
|
|
23
|
+
lines.push(' ✓ every sampled result honors the semantic vocabulary and its class rules');
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
for (const f of report.findings)
|
|
27
|
+
lines.push(findingLine(f));
|
|
28
|
+
}
|
|
29
|
+
lines.push(`${report.ok ? 'ok' : 'FAILED'} — ${errors.length} error${errors.length === 1 ? '' : 's'}, ` +
|
|
30
|
+
`${warnings.length} warning${warnings.length === 1 ? '' : 's'}`);
|
|
31
|
+
return lines.join('\n');
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../../../src/lib/semantics/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,SAAS,WAAW,CAAC,CAAmB;IACtC,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAChD,MAAM,KAAK,GAAG,CAAC,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;AAC3F,CAAC;AAED;sEACsE;AACtE,MAAM,UAAU,qBAAqB,CAAC,MAAuB;IAC3D,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IACzE,MAAM,KAAK,GAAa;QACtB,qBAAqB,MAAM,CAAC,YAAY,QAAQ,MAAM,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI;YACtF,GAAG,MAAM,CAAC,cAAc,iBAAiB,MAAM,CAAC,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;KACpF,CAAC;IACF,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,6EAA6E,CAAC,CAAC;IAC5F,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,KAAK,CAAC,IAAI,CACR,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI;QAC1F,GAAG,QAAQ,CAAC,MAAM,WAAW,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAClE,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The semantic tool-result envelope + the `check:semantics` gate (9.53.0).
|
|
3
|
+
*
|
|
4
|
+
* The door: the main barrel publishes the AUTHORING half (`semantic()`, the
|
|
5
|
+
* recognizer, the vocabulary) — what a tool author writes and what a
|
|
6
|
+
* consumer reading raw results needs; `/observe` (via debug.ts) publishes
|
|
7
|
+
* the GATE half (`checkSemantics`, the CLI core, the formatter) — beside
|
|
8
|
+
* tool-lint, its pattern sibling. See README.md for the arguments.
|
|
9
|
+
*/
|
|
10
|
+
export { composeNotCovered, coverageOfSemantics, explainSemantics, isCounterLookingAggregation, readSemantics, semantic, semanticIssues, semanticsForModel, type SemanticIssue, type SemanticIssueCode, } from './envelope.js';
|
|
11
|
+
export { checkSemantics, type SemanticsCatalogEntry, type SemanticsFinding, type SemanticsFindingCode, type SemanticsReport, } from './check.js';
|
|
12
|
+
export { formatSemanticsReport } from './format.js';
|
|
13
|
+
export { coerceSemanticsCatalog, runCheckSemanticsCli, type SemanticsCliIO } from './cli.js';
|
|
14
|
+
export { COUNTER_AGGREGATION_WORDS, RESULT_CLASSES, SEMANTICS_MARKER, SEMANTICS_NOTE, type SemanticClarify, type SemanticCoverage, type SemanticDeclaration, type SemanticEdge, type SemanticFact, type SemanticGrain, type SemanticProvenance, type SemanticRender, type SemanticSeriesPoint, type ToolResultClass, type ToolSemantics, } from './types.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The semantic tool-result envelope + the `check:semantics` gate (9.53.0).
|
|
3
|
+
*
|
|
4
|
+
* The door: the main barrel publishes the AUTHORING half (`semantic()`, the
|
|
5
|
+
* recognizer, the vocabulary) — what a tool author writes and what a
|
|
6
|
+
* consumer reading raw results needs; `/observe` (via debug.ts) publishes
|
|
7
|
+
* the GATE half (`checkSemantics`, the CLI core, the formatter) — beside
|
|
8
|
+
* tool-lint, its pattern sibling. See README.md for the arguments.
|
|
9
|
+
*/
|
|
10
|
+
export { composeNotCovered, coverageOfSemantics, explainSemantics, isCounterLookingAggregation, readSemantics, semantic, semanticIssues, semanticsForModel, } from './envelope.js';
|
|
11
|
+
export { checkSemantics, } from './check.js';
|
|
12
|
+
export { formatSemanticsReport } from './format.js';
|
|
13
|
+
export { coerceSemanticsCatalog, runCheckSemanticsCli } from './cli.js';
|
|
14
|
+
export { COUNTER_AGGREGATION_WORDS, RESULT_CLASSES, SEMANTICS_MARKER, SEMANTICS_NOTE, } from './types.js';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/lib/semantics/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,2BAA2B,EAC3B,aAAa,EACb,QAAQ,EACR,cAAc,EACd,iBAAiB,GAGlB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,cAAc,GAKf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAuB,MAAM,UAAU,CAAC;AAE7F,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,gBAAgB,EAChB,cAAc,GAYf,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* semantics/types — the semantic tool-result vocabulary, as a PURE leaf
|
|
3
|
+
* (9.53.0, the `toolOutcome.ts` precedent).
|
|
4
|
+
*
|
|
5
|
+
* WHY IT LIVES HERE. Two sides read these words and neither may own the
|
|
6
|
+
* other: the agent loop's dispatch boundary (core/agent/stages/toolCalls.ts)
|
|
7
|
+
* recognizes the envelope at run time, and the `check:semantics` build gate
|
|
8
|
+
* (lib/semantics/check.ts) judges the same shapes with no agent anywhere in
|
|
9
|
+
* sight. Declaring the vocabulary in a leaf both sides import keeps the
|
|
10
|
+
* dependency pointing the right way — the loop and the gate depend on the
|
|
11
|
+
* words, never on each other.
|
|
12
|
+
*
|
|
13
|
+
* The one exception to "zero imports" is TYPE-ONLY and deliberate: the
|
|
14
|
+
* envelope's `coverage` field ABSORBS the existing coverage vocabulary
|
|
15
|
+
* (`CoverageItem` / `CoverageInput`, core/agent/coverage/types.ts — itself a
|
|
16
|
+
* pure-data leaf) instead of duplicating it. Two spellings of "ground this
|
|
17
|
+
* result does not cover" would eventually disagree; type-only imports erase
|
|
18
|
+
* at runtime, so this module stays a runtime leaf.
|
|
19
|
+
*
|
|
20
|
+
* ## What the envelope is
|
|
21
|
+
*
|
|
22
|
+
* A tool that answers "how many IOPS did fc1/3 do last hour?" today returns
|
|
23
|
+
* prose or an ad-hoc object, and every caveat that makes the number honest —
|
|
24
|
+
* the collection interval, whether the values are counters that must not be
|
|
25
|
+
* summed, when the world was actually measured, which clusters were not
|
|
26
|
+
* collected — is re-implemented by hand inside every tool and held in place
|
|
27
|
+
* by review. Culture scales to one disciplined author; it does not scale to
|
|
28
|
+
* a hundred tools. The semantic envelope makes those caveats TYPED DATA that
|
|
29
|
+
* travel with the values, so honesty is inherited, not re-authored — and so
|
|
30
|
+
* a build gate can refuse a triage tool that forgot its own limits.
|
|
31
|
+
*
|
|
32
|
+
* It is a SIBLING recognizer beside the effects envelope and the coverage
|
|
33
|
+
* primitives — its own reserved marker (`af_semantics`, the
|
|
34
|
+
* `af_absent`/`af_coverage` family), never new keys on the effects envelope.
|
|
35
|
+
* The three compose on one result: `{ content: semantic({…}), effects: […],
|
|
36
|
+
* status }` is a tool that returns typed data AND proposes a transition.
|
|
37
|
+
*/
|
|
38
|
+
import type { CoverageDeclaration, CoverageItem } from '../../core/agent/coverage/types.js';
|
|
39
|
+
/**
|
|
40
|
+
* The reserved key that makes a semantic envelope recognizable. Reserved
|
|
41
|
+
* vocabulary on the tool-result wire (the `af_absent` / `af_coverage`
|
|
42
|
+
* precedent): a plain object carrying `af_semantics: true` that validates
|
|
43
|
+
* cleanly is an envelope; every other value any tool has ever returned keeps
|
|
44
|
+
* its bytes.
|
|
45
|
+
*/
|
|
46
|
+
export declare const SEMANTICS_MARKER = "af_semantics";
|
|
47
|
+
/**
|
|
48
|
+
* One measured point. `t` is the tool's own clock words (an ISO string or an
|
|
49
|
+
* epoch number — the library never reinterprets it), `entity` is what was
|
|
50
|
+
* measured, `metric` names the measurement, `value` is the reading.
|
|
51
|
+
*/
|
|
52
|
+
export interface SemanticSeriesPoint {
|
|
53
|
+
readonly t: string | number;
|
|
54
|
+
readonly entity: string;
|
|
55
|
+
readonly metric: string;
|
|
56
|
+
readonly value: number | string | boolean | null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* One row of typed facts about one entity. The columns are the tool's own —
|
|
60
|
+
* this library requires only that every row says WHAT it is about.
|
|
61
|
+
*/
|
|
62
|
+
export interface SemanticFact {
|
|
63
|
+
readonly entity: string;
|
|
64
|
+
readonly [field: string]: unknown;
|
|
65
|
+
}
|
|
66
|
+
/** One typed relationship — "this VM rides that datastore", "this zone
|
|
67
|
+
* contains that WWPN". `kind` names the relationship in the tool's words. */
|
|
68
|
+
export interface SemanticEdge {
|
|
69
|
+
readonly from: string;
|
|
70
|
+
readonly to: string;
|
|
71
|
+
readonly kind: string;
|
|
72
|
+
readonly [field: string]: unknown;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The grain — what one value MEANS, stated when it is not what a reader
|
|
76
|
+
* would assume. This is the field that stops a model from adding
|
|
77
|
+
* `jobs_local` to `jobs_replicated_in` and announcing a fleet size nobody
|
|
78
|
+
* has.
|
|
79
|
+
*/
|
|
80
|
+
export interface SemanticGrain {
|
|
81
|
+
/** The collection interval the values live on ('30m', '1h', 'daily'). */
|
|
82
|
+
readonly interval?: string;
|
|
83
|
+
/** How the values were folded ('avg', 'max', 'sum', 'count', …). */
|
|
84
|
+
readonly aggregation?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Whether the values are counters. MUST be stated (true or false) whenever
|
|
87
|
+
* `aggregation` is counter-looking (see
|
|
88
|
+
* {@link COUNTER_AGGREGATION_WORDS}): summing two counters double-counts,
|
|
89
|
+
* and a reader cannot tell a counter from a gauge by looking at a number.
|
|
90
|
+
*/
|
|
91
|
+
readonly is_counter?: boolean;
|
|
92
|
+
/** What was folded away ('per-port rows collapsed to per-switch'). */
|
|
93
|
+
readonly collapsed?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Where the values came from and how old they are. `measured_at` is when the
|
|
97
|
+
* WORLD was measured — not when the tool ran; a tool that reads a nightly
|
|
98
|
+
* export and answers in 4ms is serving yesterday.
|
|
99
|
+
*/
|
|
100
|
+
export interface SemanticProvenance {
|
|
101
|
+
/** When the world was measured (the tool's own clock words). Required
|
|
102
|
+
* whenever the envelope carries `series` or `facts`. */
|
|
103
|
+
readonly measured_at: string;
|
|
104
|
+
/** How stale the data was when the tool answered, in seconds. */
|
|
105
|
+
readonly age_seconds?: number;
|
|
106
|
+
/** The system of record the values were read from. Required with
|
|
107
|
+
* `measured_at`. */
|
|
108
|
+
readonly source: string;
|
|
109
|
+
/** For file-fed collectors: the export the values rode in on. */
|
|
110
|
+
readonly source_export_date?: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The ask-vs-answer decision, as data. A tool that matched three volumes for
|
|
114
|
+
* one WWN should not pick one silently — it should hand the question and the
|
|
115
|
+
* candidates back, typed, so the loop (or a UI) can ask.
|
|
116
|
+
*/
|
|
117
|
+
export interface SemanticClarify {
|
|
118
|
+
readonly question: string;
|
|
119
|
+
/** The candidates the question is choosing between. May be empty — an open
|
|
120
|
+
* question is still a question. */
|
|
121
|
+
readonly candidates: readonly unknown[];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Rendering HINTS — the tool never renders. A UI that understands them draws
|
|
125
|
+
* a better table; one that does not loses nothing, because everything load-
|
|
126
|
+
* bearing is in the data fields. Dropped from the model's view entirely.
|
|
127
|
+
*/
|
|
128
|
+
export interface SemanticRender {
|
|
129
|
+
/** The default presentation ('table', 'chart', 'prose', …). A hint. */
|
|
130
|
+
readonly default: string;
|
|
131
|
+
/** Column order for a tabular view. */
|
|
132
|
+
readonly columns?: readonly string[];
|
|
133
|
+
/** Sort hint ('avg_iops desc'). */
|
|
134
|
+
readonly sort?: string;
|
|
135
|
+
/** A note about what filtering already happened ('replicas excluded'). */
|
|
136
|
+
readonly filter_note?: string;
|
|
137
|
+
/** Chart-shape hint ('line per entity'). */
|
|
138
|
+
readonly chart_hint?: string;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The envelope's coverage, normalized — the SAME three-list vocabulary the
|
|
142
|
+
* `coverage()` / `absent()` primitives speak (checked / not checked / cannot
|
|
143
|
+
* cover), in the snake_case spelling every rendered tool shape uses because
|
|
144
|
+
* a model reads it more often than code does. Declared through
|
|
145
|
+
* {@link SemanticDeclaration.coverage} with the exact `CoverageDeclaration`
|
|
146
|
+
* input the `coverage()` primitive takes; the dispatch loop declares it
|
|
147
|
+
* through the same channel (`tools.coverage_declared`, tracked state, the
|
|
148
|
+
* final-answer limits block) — absorbed, never duplicated.
|
|
149
|
+
*/
|
|
150
|
+
export interface SemanticCoverage {
|
|
151
|
+
readonly checked?: readonly CoverageItem[];
|
|
152
|
+
readonly not_checked?: readonly CoverageItem[];
|
|
153
|
+
readonly cannot_cover?: readonly CoverageItem[];
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* What a tool author passes to `semantic()`. At least one of `series`,
|
|
157
|
+
* `facts`, `edges` or a non-null `clarify` must be present — an envelope
|
|
158
|
+
* with no data and no question declares nothing.
|
|
159
|
+
*
|
|
160
|
+
* `not_covered` is deliberately NOT here: the prose list on the rendered
|
|
161
|
+
* envelope is DERIVED from `coverage` (not checked + cannot cover), so the
|
|
162
|
+
* two can never disagree. Declaring coverage is how not_covered is said.
|
|
163
|
+
*/
|
|
164
|
+
export interface SemanticDeclaration {
|
|
165
|
+
readonly series?: readonly SemanticSeriesPoint[];
|
|
166
|
+
readonly facts?: readonly SemanticFact[];
|
|
167
|
+
readonly edges?: readonly SemanticEdge[];
|
|
168
|
+
readonly grain?: SemanticGrain;
|
|
169
|
+
readonly provenance?: SemanticProvenance;
|
|
170
|
+
/** The coverage()-vocabulary declaration this envelope absorbs. */
|
|
171
|
+
readonly coverage?: CoverageDeclaration;
|
|
172
|
+
/** `null` states "ambiguity was considered; there is none" — a fact, kept
|
|
173
|
+
* on the record. Omit the field to say nothing. */
|
|
174
|
+
readonly clarify?: SemanticClarify | null;
|
|
175
|
+
readonly render?: SemanticRender;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The rendered semantic envelope — the exact object a tool hands back.
|
|
179
|
+
* Field names are snake_case and English on purpose (the `ToolAbsence`
|
|
180
|
+
* precedent): this value is read by a language model far more often than by
|
|
181
|
+
* code, and `af_semantics` is the only field that exists for the machine.
|
|
182
|
+
*/
|
|
183
|
+
export interface ToolSemantics {
|
|
184
|
+
readonly af_semantics: true;
|
|
185
|
+
readonly series?: readonly SemanticSeriesPoint[];
|
|
186
|
+
readonly facts?: readonly SemanticFact[];
|
|
187
|
+
readonly edges?: readonly SemanticEdge[];
|
|
188
|
+
readonly grain?: SemanticGrain;
|
|
189
|
+
readonly provenance?: SemanticProvenance;
|
|
190
|
+
readonly coverage?: SemanticCoverage;
|
|
191
|
+
/** DERIVED from `coverage` (not checked + cannot cover), one prose line
|
|
192
|
+
* per item — never author-set, so the list and the lists cannot drift. */
|
|
193
|
+
readonly not_covered?: readonly string[];
|
|
194
|
+
readonly clarify?: SemanticClarify | null;
|
|
195
|
+
readonly render?: SemanticRender;
|
|
196
|
+
/** The static sentence. Never interpolated — see `envelope.ts`. */
|
|
197
|
+
readonly note: string;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* The declared class of a tool's RESULTS — what kind of answer this tool
|
|
201
|
+
* gives, stated by whoever wrote it (`defineTool({ resultClass })`; the
|
|
202
|
+
* `capabilities` law: declared, never inferred). The `check:semantics` gate
|
|
203
|
+
* keys its per-class rules on it:
|
|
204
|
+
*
|
|
205
|
+
* • `'triage'` — a verdict about health or fault. Every sample result must
|
|
206
|
+
* declare coverage: a triage that cannot say what it did NOT check turns
|
|
207
|
+
* "everything looks fine" into a claim about ground it never stood on.
|
|
208
|
+
* • `'inventory'` — a population listing. Every sample result must declare
|
|
209
|
+
* coverage ("4 of 5 clusters"), and one with `facts` but no `render`
|
|
210
|
+
* hint is warned at.
|
|
211
|
+
*
|
|
212
|
+
* Two classes, deliberately closed: each carries a rule the gate can PROVE.
|
|
213
|
+
* A class with no rule would be dead vocabulary.
|
|
214
|
+
*/
|
|
215
|
+
export type ToolResultClass = 'triage' | 'inventory';
|
|
216
|
+
/** The closed set, as data — validators and docs read one list. */
|
|
217
|
+
export declare const RESULT_CLASSES: readonly ToolResultClass[];
|
|
218
|
+
/**
|
|
219
|
+
* Aggregation words that suggest the values are counters — the words that
|
|
220
|
+
* make `grain.is_counter` REQUIRED (stated true or false). Matched as whole
|
|
221
|
+
* tokens, singular or plural, case-insensitive.
|
|
222
|
+
*/
|
|
223
|
+
export declare const COUNTER_AGGREGATION_WORDS: readonly string[];
|
|
224
|
+
/**
|
|
225
|
+
* The static sentence every semantic envelope carries in the model's view.
|
|
226
|
+
* Never interpolated (the `ABSENCE_NOTE` law): everything else the model
|
|
227
|
+
* reads is the tool's own data, and a note that quoted any of it back would
|
|
228
|
+
* hand the evidence corpus a second copy of values it already indexes.
|
|
229
|
+
*/
|
|
230
|
+
export declare const SEMANTICS_NOTE: string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* semantics/types — the semantic tool-result vocabulary, as a PURE leaf
|
|
3
|
+
* (9.53.0, the `toolOutcome.ts` precedent).
|
|
4
|
+
*
|
|
5
|
+
* WHY IT LIVES HERE. Two sides read these words and neither may own the
|
|
6
|
+
* other: the agent loop's dispatch boundary (core/agent/stages/toolCalls.ts)
|
|
7
|
+
* recognizes the envelope at run time, and the `check:semantics` build gate
|
|
8
|
+
* (lib/semantics/check.ts) judges the same shapes with no agent anywhere in
|
|
9
|
+
* sight. Declaring the vocabulary in a leaf both sides import keeps the
|
|
10
|
+
* dependency pointing the right way — the loop and the gate depend on the
|
|
11
|
+
* words, never on each other.
|
|
12
|
+
*
|
|
13
|
+
* The one exception to "zero imports" is TYPE-ONLY and deliberate: the
|
|
14
|
+
* envelope's `coverage` field ABSORBS the existing coverage vocabulary
|
|
15
|
+
* (`CoverageItem` / `CoverageInput`, core/agent/coverage/types.ts — itself a
|
|
16
|
+
* pure-data leaf) instead of duplicating it. Two spellings of "ground this
|
|
17
|
+
* result does not cover" would eventually disagree; type-only imports erase
|
|
18
|
+
* at runtime, so this module stays a runtime leaf.
|
|
19
|
+
*
|
|
20
|
+
* ## What the envelope is
|
|
21
|
+
*
|
|
22
|
+
* A tool that answers "how many IOPS did fc1/3 do last hour?" today returns
|
|
23
|
+
* prose or an ad-hoc object, and every caveat that makes the number honest —
|
|
24
|
+
* the collection interval, whether the values are counters that must not be
|
|
25
|
+
* summed, when the world was actually measured, which clusters were not
|
|
26
|
+
* collected — is re-implemented by hand inside every tool and held in place
|
|
27
|
+
* by review. Culture scales to one disciplined author; it does not scale to
|
|
28
|
+
* a hundred tools. The semantic envelope makes those caveats TYPED DATA that
|
|
29
|
+
* travel with the values, so honesty is inherited, not re-authored — and so
|
|
30
|
+
* a build gate can refuse a triage tool that forgot its own limits.
|
|
31
|
+
*
|
|
32
|
+
* It is a SIBLING recognizer beside the effects envelope and the coverage
|
|
33
|
+
* primitives — its own reserved marker (`af_semantics`, the
|
|
34
|
+
* `af_absent`/`af_coverage` family), never new keys on the effects envelope.
|
|
35
|
+
* The three compose on one result: `{ content: semantic({…}), effects: […],
|
|
36
|
+
* status }` is a tool that returns typed data AND proposes a transition.
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* The reserved key that makes a semantic envelope recognizable. Reserved
|
|
40
|
+
* vocabulary on the tool-result wire (the `af_absent` / `af_coverage`
|
|
41
|
+
* precedent): a plain object carrying `af_semantics: true` that validates
|
|
42
|
+
* cleanly is an envelope; every other value any tool has ever returned keeps
|
|
43
|
+
* its bytes.
|
|
44
|
+
*/
|
|
45
|
+
export const SEMANTICS_MARKER = 'af_semantics';
|
|
46
|
+
/** The closed set, as data — validators and docs read one list. */
|
|
47
|
+
export const RESULT_CLASSES = ['triage', 'inventory'];
|
|
48
|
+
/**
|
|
49
|
+
* Aggregation words that suggest the values are counters — the words that
|
|
50
|
+
* make `grain.is_counter` REQUIRED (stated true or false). Matched as whole
|
|
51
|
+
* tokens, singular or plural, case-insensitive.
|
|
52
|
+
*/
|
|
53
|
+
export const COUNTER_AGGREGATION_WORDS = [
|
|
54
|
+
'sum',
|
|
55
|
+
'count',
|
|
56
|
+
'total',
|
|
57
|
+
'cumulative',
|
|
58
|
+
'counter',
|
|
59
|
+
'delta',
|
|
60
|
+
];
|
|
61
|
+
/**
|
|
62
|
+
* The static sentence every semantic envelope carries in the model's view.
|
|
63
|
+
* Never interpolated (the `ABSENCE_NOTE` law): everything else the model
|
|
64
|
+
* reads is the tool's own data, and a note that quoted any of it back would
|
|
65
|
+
* hand the evidence corpus a second copy of values it already indexes.
|
|
66
|
+
*/
|
|
67
|
+
export const SEMANTICS_NOTE = 'Typed data, not prose. `grain` and `provenance` are caveats that travel with the ' +
|
|
68
|
+
'numbers: check `is_counter` before summing values from a series, read `measured_at` ' +
|
|
69
|
+
'(and `age_seconds`) as how old the data is, and treat everything under `not_covered` ' +
|
|
70
|
+
'as ground this result does NOT cover — a clean look here says nothing about it.';
|
|
71
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/lib/semantics/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAIH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAsL/C,mEAAmE;AACnE,MAAM,CAAC,MAAM,cAAc,GAA+B,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AAElF;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAsB;IAC1D,KAAK;IACL,OAAO;IACP,OAAO;IACP,YAAY;IACZ,SAAS;IACT,OAAO;CACR,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GACzB,mFAAmF;IACnF,sFAAsF;IACtF,uFAAuF;IACvF,iFAAiF,CAAC"}
|
|
@@ -1517,6 +1517,12 @@ const OFFLINE_CONTEXT = {
|
|
|
1517
1517
|
// Offline has no run to scope refs to; the capability teaches, never lies.
|
|
1518
1518
|
artifacts: unconfiguredArtifacts(),
|
|
1519
1519
|
hasArtifacts: false,
|
|
1520
|
+
// Offline has no stage to emit from and no dispatcher to reach (9.52.0);
|
|
1521
|
+
// a progress report is dropped rather than refused, because losing telemetry
|
|
1522
|
+
// is not a reason to fail a call that is doing its work.
|
|
1523
|
+
progress: () => {
|
|
1524
|
+
/* nowhere to file it offline — see the note above */
|
|
1525
|
+
},
|
|
1520
1526
|
teardownScopes: [],
|
|
1521
1527
|
onTeardown: () => {
|
|
1522
1528
|
throw new Error('callTraceTool: onTeardown is not honoured offline — `ctx.teardownScopes` is empty, ' +
|