@tcpcore1/verifier 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +465 -2
- package/bin/tcpcore.js +35 -0
- package/dist/adapters/aws-bedrock-agents.d.ts +46 -0
- package/dist/adapters/aws-bedrock-agents.d.ts.map +1 -0
- package/dist/adapters/aws-bedrock-agents.js +179 -0
- package/dist/adapters/aws-bedrock-agents.js.map +1 -0
- package/dist/adapters/claude-code.d.ts +40 -0
- package/dist/adapters/claude-code.d.ts.map +1 -0
- package/dist/adapters/claude-code.js +159 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/crewai.d.ts +48 -0
- package/dist/adapters/crewai.d.ts.map +1 -0
- package/dist/adapters/crewai.js +140 -0
- package/dist/adapters/crewai.js.map +1 -0
- package/dist/adapters/cursor.d.ts +48 -0
- package/dist/adapters/cursor.d.ts.map +1 -0
- package/dist/adapters/cursor.js +192 -0
- package/dist/adapters/cursor.js.map +1 -0
- package/dist/adapters/custom-http.d.ts +30 -0
- package/dist/adapters/custom-http.d.ts.map +1 -0
- package/dist/adapters/custom-http.js +50 -0
- package/dist/adapters/custom-http.js.map +1 -0
- package/dist/adapters/deepseek-harness.d.ts +38 -0
- package/dist/adapters/deepseek-harness.d.ts.map +1 -0
- package/dist/adapters/deepseek-harness.js +134 -0
- package/dist/adapters/deepseek-harness.js.map +1 -0
- package/dist/adapters/google-vertex-agents.d.ts +34 -0
- package/dist/adapters/google-vertex-agents.d.ts.map +1 -0
- package/dist/adapters/google-vertex-agents.js +149 -0
- package/dist/adapters/google-vertex-agents.js.map +1 -0
- package/dist/adapters/index.d.ts +21 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +62 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/langchain.d.ts +62 -0
- package/dist/adapters/langchain.d.ts.map +1 -0
- package/dist/adapters/langchain.js +199 -0
- package/dist/adapters/langchain.js.map +1 -0
- package/dist/adapters/langgraph.d.ts +31 -0
- package/dist/adapters/langgraph.d.ts.map +1 -0
- package/dist/adapters/langgraph.js +58 -0
- package/dist/adapters/langgraph.js.map +1 -0
- package/dist/adapters/microsoft-autogen.d.ts +34 -0
- package/dist/adapters/microsoft-autogen.d.ts.map +1 -0
- package/dist/adapters/microsoft-autogen.js +128 -0
- package/dist/adapters/microsoft-autogen.js.map +1 -0
- package/dist/adapters/openai-assistants.d.ts +34 -0
- package/dist/adapters/openai-assistants.d.ts.map +1 -0
- package/dist/adapters/openai-assistants.js +126 -0
- package/dist/adapters/openai-assistants.js.map +1 -0
- package/dist/adapters/tool-call.d.ts +76 -0
- package/dist/adapters/tool-call.d.ts.map +1 -0
- package/dist/adapters/tool-call.js +167 -0
- package/dist/adapters/tool-call.js.map +1 -0
- package/dist/adapters/types.d.ts +57 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +66 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/args.d.ts +35 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +131 -0
- package/dist/args.js.map +1 -0
- package/dist/checks/registry.d.ts +61 -0
- package/dist/checks/registry.d.ts.map +1 -0
- package/dist/checks/registry.js +38 -0
- package/dist/checks/registry.js.map +1 -0
- package/dist/cli.d.ts +40 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +236 -0
- package/dist/cli.js.map +1 -0
- package/dist/errors.d.ts +23 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +40 -0
- package/dist/errors.js.map +1 -0
- package/dist/facts/materialise.d.ts +47 -0
- package/dist/facts/materialise.d.ts.map +1 -0
- package/dist/facts/materialise.js +74 -0
- package/dist/facts/materialise.js.map +1 -0
- package/dist/facts/parse.d.ts +62 -0
- package/dist/facts/parse.d.ts.map +1 -0
- package/dist/facts/parse.js +174 -0
- package/dist/facts/parse.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/merkle.d.ts +65 -0
- package/dist/merkle.d.ts.map +1 -0
- package/dist/merkle.js +81 -0
- package/dist/merkle.js.map +1 -0
- package/dist/render/html.d.ts +16 -0
- package/dist/render/html.d.ts.map +1 -0
- package/dist/render/html.js +63 -0
- package/dist/render/html.js.map +1 -0
- package/dist/render/human.d.ts +29 -0
- package/dist/render/human.d.ts.map +1 -0
- package/dist/render/human.js +105 -0
- package/dist/render/human.js.map +1 -0
- package/dist/render/json.d.ts +12 -0
- package/dist/render/json.d.ts.map +1 -0
- package/dist/render/json.js +13 -0
- package/dist/render/json.js.map +1 -0
- package/dist/session/canonical.d.ts +66 -0
- package/dist/session/canonical.d.ts.map +1 -0
- package/dist/session/canonical.js +102 -0
- package/dist/session/canonical.js.map +1 -0
- package/dist/session/parse.d.ts +64 -0
- package/dist/session/parse.d.ts.map +1 -0
- package/dist/session/parse.js +299 -0
- package/dist/session/parse.js.map +1 -0
- package/dist/session/types.d.ts +79 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +15 -0
- package/dist/session/types.js.map +1 -0
- package/dist/vendor/claim-graph/text.d.ts +150 -0
- package/dist/vendor/claim-graph/text.d.ts.map +1 -0
- package/dist/vendor/claim-graph/text.js +337 -0
- package/dist/vendor/claim-graph/text.js.map +1 -0
- package/dist/vendor/truth-kernel/merkle.d.ts +246 -0
- package/dist/vendor/truth-kernel/merkle.d.ts.map +1 -0
- package/dist/vendor/truth-kernel/merkle.js +404 -0
- package/dist/vendor/truth-kernel/merkle.js.map +1 -0
- package/dist/vendor/truth-kernel/types.d.ts +252 -0
- package/dist/vendor/truth-kernel/types.d.ts.map +1 -0
- package/dist/vendor/truth-kernel/types.js +158 -0
- package/dist/vendor/truth-kernel/types.js.map +1 -0
- package/dist/vendor/truth-kernel/verify.d.ts +153 -0
- package/dist/vendor/truth-kernel/verify.d.ts.map +1 -0
- package/dist/vendor/truth-kernel/verify.js +266 -0
- package/dist/vendor/truth-kernel/verify.js.map +1 -0
- package/dist/verify/engine.d.ts +92 -0
- package/dist/verify/engine.d.ts.map +1 -0
- package/dist/verify/engine.js +368 -0
- package/dist/verify/engine.js.map +1 -0
- package/dist/verify/report.d.ts +87 -0
- package/dist/verify/report.d.ts.map +1 -0
- package/dist/verify/report.js +11 -0
- package/dist/verify/report.js.map +1 -0
- package/examples/clean-facts.jsonl +2 -0
- package/examples/clean-session.jsonl +3 -0
- package/examples/facts.jsonl +3 -0
- package/examples/mid-session-retraction.jsonl +3 -0
- package/examples/one-fabricated.jsonl +3 -0
- package/package.json +55 -4
- package/spec/facts-v1.md +84 -0
- package/spec/tcpcore-v1.md +143 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TCPcore
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,466 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tcpcore1/verifier
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Did the agent's claimed actions follow from the facts it was given?**
|
|
4
|
+
|
|
5
|
+
`tcpcore verify` reads a session log and a set of typed facts, and answers that question
|
|
6
|
+
action by action. It prints four numbers, the findings behind them, and a Merkle root over
|
|
7
|
+
the session so a report can be pasted into a review and re-checked later.
|
|
8
|
+
|
|
9
|
+
No account, no server, no model. One command, one report, exit codes a CI job can branch on.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @tcpcore1/verifier verify examples/one-fabricated.jsonl --facts examples/facts.jsonl
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
That command runs against a file in this package, and it exits `1` because the second action
|
|
16
|
+
cites a fact that is not in the facts file. There is nothing to prepare, no service to start
|
|
17
|
+
and no capture to make first.
|
|
18
|
+
|
|
19
|
+
> The package is published as `@tcpcore1/verifier` because that is the scope this
|
|
20
|
+
> workspace owns. The bin is called `tcpcore` and does not change with the scope, so
|
|
21
|
+
> `npx @tcpcore1/verifier …` and a globally installed `tcpcore …` are the same command.
|
|
22
|
+
> **No publish has been performed from this repository.** That is the operator's action.
|
|
23
|
+
>
|
|
24
|
+
> The package has **no runtime dependencies**. The parts of the truth kernel it needs (the
|
|
25
|
+
> Merkle tree, the fact types, `AdversarialVerifier`) are copied into `src/vendor/` at build
|
|
26
|
+
> time by `scripts/bundle-kernel.mjs`, because the kernel is not on npm and a published
|
|
27
|
+
> tarball may not declare a `workspace:` dependency. A parity test asserts the copy produces
|
|
28
|
+
> byte-identical Merkle roots to the kernel; see [The Merkle roots](#the-merkle-roots).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## The three examples
|
|
33
|
+
|
|
34
|
+
`examples/` ships with the package, so all three of these run from a fresh install. Every
|
|
35
|
+
file's first line carries a `_note` saying the session is synthetic - a real agent that does
|
|
36
|
+
not log grounding facts will show more `ungrounded` than grounded, and that is the tool
|
|
37
|
+
working, not the tool failing.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# 1. Nothing to find: two actions, both grounded. Exit 0.
|
|
41
|
+
npx @tcpcore1/verifier verify examples/clean-session.jsonl --facts examples/clean-facts.jsonl
|
|
42
|
+
|
|
43
|
+
# 2. One citation of a fact that does not exist. Exit 1.
|
|
44
|
+
npx @tcpcore1/verifier verify examples/one-fabricated.jsonl --facts examples/facts.jsonl
|
|
45
|
+
|
|
46
|
+
# 3. A fact in force when it was cited, withdrawn later in the same session. Exit 1.
|
|
47
|
+
npx @tcpcore1/verifier verify examples/mid-session-retraction.jsonl --facts examples/facts.jsonl
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The second command prints:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
tcpcore verify - examples/one-fabricated.jsonl
|
|
54
|
+
3 fact(s) from examples/facts.jsonl, session example-one-fabricated
|
|
55
|
+
|
|
56
|
+
2 actions
|
|
57
|
+
1 grounded
|
|
58
|
+
1 fabricated <- accusations
|
|
59
|
+
0 retracted
|
|
60
|
+
0 ungrounded <- the tool could not adjudicate
|
|
61
|
+
|
|
62
|
+
fabricated:
|
|
63
|
+
a2 billing.apply_discount 2026-11-03T09:00:20.000Z
|
|
64
|
+
cites fact f-annual-discount, which is not in the facts file
|
|
65
|
+
cites: f-annual-discount (declared)
|
|
66
|
+
|
|
67
|
+
merkle (tcpcore.merkle.sha256.v1)
|
|
68
|
+
actions 36bdb02e9721d4350f888f7da5efdb42e711687dce1a28df15ff478ac286c5bd
|
|
69
|
+
citations c433fb55f3c8a8df20e9e82771d14fa8c55278c088f01df29d51eb6f872daca0
|
|
70
|
+
|
|
71
|
+
exit 1 - 1 fabricated: 1 citation(s) of a fact that does not exist
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The third prints `1 retracted`, naming `f-refund-window`, and the reason spells out both
|
|
75
|
+
times: _in force at 2026-11-03T09:15:00.000Z and retracted at 2026-11-03T09:30:00.000Z, later
|
|
76
|
+
in the session_. That is the cascade the report exists to make visible.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## The two commands a contributor needs
|
|
81
|
+
|
|
82
|
+
`fixtures/` is the test corpus, not part of the published package: every adapter has a committed
|
|
83
|
+
fixture and a test that pins its mapping, and `fixtures/sessions/langchain.tcpcore.jsonl` is the
|
|
84
|
+
golden output of the `langchain` adapter. The `*.tcpcore.jsonl` names are the fixtures' own and
|
|
85
|
+
predate the versioned format name; the format they contain is `tcpcore.session.v1`.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# 1. Verify the committed example: seven actions, and every branch of the report.
|
|
89
|
+
npx tsx src/index.ts verify fixtures/sessions/langchain.tcpcore.jsonl \
|
|
90
|
+
--facts fixtures/facts/acme.jsonl
|
|
91
|
+
|
|
92
|
+
# 2. Adapt a framework log into the canonical format, then verify it.
|
|
93
|
+
npx tsx src/index.ts adapt fixtures/claude-code/transcript.jsonl --from claude-code \
|
|
94
|
+
-o /tmp/session.jsonl
|
|
95
|
+
npx tsx src/index.ts verify /tmp/session.jsonl --facts fixtures/facts/acme.jsonl
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The output of the first command is:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
7 actions
|
|
102
|
+
2 grounded
|
|
103
|
+
2 fabricated <- accusations
|
|
104
|
+
1 retracted
|
|
105
|
+
2 ungrounded <- the tool could not adjudicate
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
then the findings, each naming the fact it contradicts or rests on, then the two roots,
|
|
109
|
+
then `exit 1`.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## The headline is four numbers, always
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
147 actions
|
|
117
|
+
132 grounded
|
|
118
|
+
4 fabricated <- accusations
|
|
119
|
+
0 retracted
|
|
120
|
+
11 ungrounded <- the tool could not adjudicate
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Not "4 hallucinations found". A developer who reads **4 fabricated** without **11
|
|
124
|
+
ungrounded** beside it will over-trust the report and under-invest in the logging this tool
|
|
125
|
+
needs in order to see more. `ungrounded` means the tool could not adjudicate the action - the
|
|
126
|
+
log did not say which facts it rested on, or it withheld the result. That number is the
|
|
127
|
+
tool's honesty about its own blind spot, and burying it would make the report look more
|
|
128
|
+
certain than it is.
|
|
129
|
+
|
|
130
|
+
The four categories:
|
|
131
|
+
|
|
132
|
+
| Category | Meaning | Fails the run? |
|
|
133
|
+
| ------------ | -------------------------------------------------------------------------------------------------------------- | -------------------- |
|
|
134
|
+
| `grounded` | Every cited fact exists and was in force when the action happened. | no |
|
|
135
|
+
| `fabricated` | A cited fact does not exist in the facts file, **or** the truth kernel contradicted the action's stated claim. | **yes** |
|
|
136
|
+
| `retracted` | Every citation exists, but at least one was withdrawn - before the action, or later in the same session. | **yes** |
|
|
137
|
+
| `ungrounded` | Nothing to adjudicate: no citation and no supplied facts, or the source log redacted the result. | only with `--strict` |
|
|
138
|
+
|
|
139
|
+
`ungrounded` is a fourth bucket rather than a third category of failure, because folding it
|
|
140
|
+
into `grounded` is the "silence is a pass" inversion and folding it into `fabricated` accuses
|
|
141
|
+
the agent of a lie it did not tell.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## `tcpcore-v1.jsonl` - the session format (v1)
|
|
146
|
+
|
|
147
|
+
A session file is named for its format version: **`tcpcore-v1.jsonl`**. The older unversioned
|
|
148
|
+
name `tcpcore.jsonl` is accepted too - the format is identified by the `schema` literal inside
|
|
149
|
+
the file (`"tcpcore.session.v1"`), not by the filename, so both names parse identically. The
|
|
150
|
+
versioned name is the one to write today; `spec/tcpcore-v1.md` is the normative document.
|
|
151
|
+
|
|
152
|
+
**A v2 will be added**, as `tcpcore-v2.jsonl` with `"schema": "tcpcore.session.v2"`. The
|
|
153
|
+
verifier will accept v1 and v2 **for one major release**, long enough to migrate without a
|
|
154
|
+
flag day; after that, v1 input is refused by name rather than reinterpreted. Until then there
|
|
155
|
+
is no extension mechanism: a new field is a new version, and `args` is the place for anything
|
|
156
|
+
a tool call carries.
|
|
157
|
+
|
|
158
|
+
One JSON object per line, UTF-8, LF. An optional first line is a header; every other line is
|
|
159
|
+
one action.
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{"type":"session","schema":"tcpcore.session.v1","sessionId":"cc-session-1"}
|
|
163
|
+
{"id":"run_3","action":"billing.read_invoice","ts":"2026-11-03T09:00:10.000Z","args":{"orderId":"O-1","grounding":["f-price-acme"]},"result":{"amount":400},"grounding":["f-price-acme"]}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Action fields
|
|
167
|
+
|
|
168
|
+
| Field | Type | Required | Meaning |
|
|
169
|
+
| ----------- | ----------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
170
|
+
| `action` | string | **yes** | The operation name: `read_file`, `run_tests`, `refund.create`. The claim of having done something. |
|
|
171
|
+
| `ts` | string | **yes** | `YYYY-MM-DDTHH:MM:SS.sssZ`, exactly. The retraction check is a time comparison, so only one spelling is accepted. |
|
|
172
|
+
| `args` | object | **yes** | The structured input. An object, because a tool call has named parameters. |
|
|
173
|
+
| `result` | any JSON | **yes** | What the tool returned. `null`, `""` and `{}` stay distinct: "no output", "empty output" and "empty object" are three different facts. |
|
|
174
|
+
| `grounding` | string[] | no (`[]`) | Fact ids this action rests on. |
|
|
175
|
+
| `id` | string | no (`a1`, `a2`, …) | Stable handle used in the report. Must be unique. |
|
|
176
|
+
| `claim` | object | no | `{subject, predicate, object}`: a structured assertion, adjudicated by the truth kernel. |
|
|
177
|
+
| `agent` | string | no | Which agent or sub-agent produced it. |
|
|
178
|
+
| `turn` | integer ≥ 1 | no | Attribution only; never decisive. |
|
|
179
|
+
|
|
180
|
+
### Header fields
|
|
181
|
+
|
|
182
|
+
`type` must be `"session"`; `schema` must be `"tcpcore.session.v1"`; `sessionId` and `agent`
|
|
183
|
+
are optional. A header that is not the first line is refused.
|
|
184
|
+
|
|
185
|
+
`_note` is optional and is the one field that carries no semantics: a free-form string, allowed
|
|
186
|
+
on the header and nowhere else. No root commits to the header and no verdict reads it, so it
|
|
187
|
+
cannot change a finding - it is how a shipped example states in the file itself that it is
|
|
188
|
+
synthetic. On an action it is still an unknown key, because every action field is hashed and a
|
|
189
|
+
field outside the hash is a field that can be edited without the root noticing.
|
|
190
|
+
|
|
191
|
+
### Rules, and why each one is a rule
|
|
192
|
+
|
|
193
|
+
- **Unknown keys are refused**, naming the key and the line. A permissive parser is a silent
|
|
194
|
+
pass at the format layer: it accepts `"grouding"`, drops it, and reports the agent as
|
|
195
|
+
ungrounded because of our typo.
|
|
196
|
+
- **Timestamps must not go backwards.** The retraction check compares `ts` against
|
|
197
|
+
`retractedAt`; a file with no causal order would still produce confident verdicts.
|
|
198
|
+
- **A session with no actions is invalid input (exit 2).** A verification run over nothing is
|
|
199
|
+
not a pass.
|
|
200
|
+
- **A blank line is skipped** - it carries no information, and hand-edited JSONL collects
|
|
201
|
+
trailing newlines.
|
|
202
|
+
|
|
203
|
+
## `facts-v1.jsonl` - the facts format (v1)
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
{
|
|
207
|
+
"id": "f-seat-limit",
|
|
208
|
+
"subject": "acme",
|
|
209
|
+
"predicate": "max_seats",
|
|
210
|
+
"object": "25",
|
|
211
|
+
"ts": "2026-01-05T00:00:00.000Z",
|
|
212
|
+
"source": { "name": "Acme master agreement 2026, schedule 2", "quote": "not more than 25 seats" },
|
|
213
|
+
"factType": "CONSTRAINT"
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
| Field | Required | Meaning |
|
|
218
|
+
| -------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
219
|
+
| `id` | **yes** | What `grounding` cites. Unique across the file. |
|
|
220
|
+
| `subject`, `predicate`, `object` | **yes** | The triple the kernel compares. |
|
|
221
|
+
| `ts` | **yes** | When the fact was recorded, in canonical UTC. |
|
|
222
|
+
| `source` | no | `{name, url?, quote?}`. A bare string is refused: an unquoted, unlinked source is not evidence. |
|
|
223
|
+
| `status` | no | One of the kernel's five. Defaults to **`VERIFIED` when a `source` is present and `ASSERTED` when it is not** - the kernel's own rule, applied rather than invented. |
|
|
224
|
+
| `factType` | no | One of the six. Defaults to `ASSERTION`, the one type that can never make a claim fail. |
|
|
225
|
+
| `retractedAt` | iff `status: RETRACTED` | When it was withdrawn. Required, because "withdrawn before the agent acted" and "withdrawn afterwards" are different findings. |
|
|
226
|
+
|
|
227
|
+
## How a claim is judged
|
|
228
|
+
|
|
229
|
+
For each action, the citations are the set the agent **declared** (`args.grounding`), or - if
|
|
230
|
+
it declared none - the facts the session had already **supplied** to it, accumulated from
|
|
231
|
+
calls to tools named with `--fact-tool`. Declared citations replace the context rather than
|
|
232
|
+
adding to it: an agent that names its evidence has told us which facts it used, and padding
|
|
233
|
+
that list with everything it ever saw would let one irrelevant fact decide the verdict.
|
|
234
|
+
|
|
235
|
+
Each citation is judged against the facts file:
|
|
236
|
+
|
|
237
|
+
| Condition | Finding |
|
|
238
|
+
| ---------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
|
239
|
+
| the fact id is not in the facts file | **fabricated** |
|
|
240
|
+
| `status: RETRACTED`, `retractedAt <= ts` | **retracted** (before the action) |
|
|
241
|
+
| `status: RETRACTED`, `retractedAt > ts` | **retracted** (_cascade_: in force then, withdrawn later in the session) |
|
|
242
|
+
| `status: SUPERSEDED` | grounded, with a note - the kernel's own rule is that a superseded fact was in force in its version |
|
|
243
|
+
| otherwise | grounded |
|
|
244
|
+
|
|
245
|
+
When an action also carries a `claim`, the fact set is presented to
|
|
246
|
+
`@tcpcore1/truth-kernel`'s `AdversarialVerifier` - reached as a generated copy under
|
|
247
|
+
`src/vendor/truth-kernel/`, for the reason given under [The Merkle roots](#the-merkle-roots) -
|
|
248
|
+
and its verdict is folded in: `CONTRADICTED`
|
|
249
|
+
makes the action **fabricated** and names the fact that decided it, `SILENT` falls back to the
|
|
250
|
+
grounding finding. The comparison rules - normalised text, equal number sets, `CONSTRAINT` and
|
|
251
|
+
`POLICY` checked before support, a `DEFINITION` of non-existence outranking everything,
|
|
252
|
+
retracted facts silent - are the kernel's, not a second copy of them.
|
|
253
|
+
|
|
254
|
+
An action's category is the worst of its findings, in the order
|
|
255
|
+
`fabricated > retracted > ungrounded > grounded` - the same "a conflict's safe reading is the
|
|
256
|
+
refusal" order the API's verdict gate uses for approvals.
|
|
257
|
+
|
|
258
|
+
## The Merkle roots
|
|
259
|
+
|
|
260
|
+
Two roots, both computed by the truth kernel's `corpusRoot` - the same construction that
|
|
261
|
+
commits a published corpus, with its `0x00`/`0x01` domain bytes, sorted leaves and odd-node
|
|
262
|
+
promotion. **This package contains no Merkle implementation of its own**; it hashes records and
|
|
263
|
+
calls the kernel's helper. A second tree would be a divergence waiting to happen, and this
|
|
264
|
+
repository has been bitten by exactly that.
|
|
265
|
+
|
|
266
|
+
The kernel is not on npm, so "calls the kernel's helper" is delivered as a generated copy:
|
|
267
|
+
`scripts/bundle-kernel.mjs` rewrites `packages/truth-kernel/src/merkle.ts` into
|
|
268
|
+
`src/vendor/truth-kernel/merkle.ts` on every build, and the copy carries a banner naming its
|
|
269
|
+
source and forbidding hand edits. Two tests keep that honest, and they are the reason a copy is
|
|
270
|
+
safe here: `src/__tests__/merkle-parity.test.ts` asserts this package's roots are
|
|
271
|
+
**byte-identical** to the kernel's over empty input, one leaf, two leaves, an odd count,
|
|
272
|
+
unicode content and JSON containing a nested array; and
|
|
273
|
+
`packages/truth-kernel/src/__tests__/merkle-parity.test.ts` makes the same assertion from the
|
|
274
|
+
kernel's side, so a change to the kernel's tree fails the kernel's own suite rather than the
|
|
275
|
+
next build. `src/__tests__/vendor-drift.test.ts` fails if any vendored copy stops being a fresh
|
|
276
|
+
copy of its source.
|
|
277
|
+
|
|
278
|
+
- **`actions`** commits to every field of every action. This is the tamper-evident one:
|
|
279
|
+
change one byte of an argument, a result or a citation and the root changes.
|
|
280
|
+
- **`citations`** commits to the _set_ of fact ids the session cites, deduplicated - the value
|
|
281
|
+
a second party can compare against a fact set they obtained elsewhere.
|
|
282
|
+
|
|
283
|
+
Because `corpusRoot` sorts its leaves, both roots commit to a multiset and not to line order.
|
|
284
|
+
For citations that is exactly right. For actions it means a file with the same actions and
|
|
285
|
+
the same `ts` values in a different line order shares a root - which is correct, because the
|
|
286
|
+
session's semantics are the (action, ts) pairs.
|
|
287
|
+
|
|
288
|
+
To use the root as a tamper check, paste it into a review and re-run with it:
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
tcpcore verify session.jsonl --facts facts.jsonl --expect-root <64 hex>
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
A mismatch exits `1` and prints both roots.
|
|
295
|
+
|
|
296
|
+
## Exit codes
|
|
297
|
+
|
|
298
|
+
| Code | Meaning |
|
|
299
|
+
| ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
300
|
+
| `0` | Every action grounded, or ungrounded without `--strict`. |
|
|
301
|
+
| `1` | At least one **fabricated**, at least one **retracted**, or the session does not match `--expect-root`. |
|
|
302
|
+
| `2` | Invalid input: unreadable file, bad JSON, schema violation, unknown flag or adapter, duplicate id, a `RETRACTED` fact with no `retractedAt`, or a session with no actions. |
|
|
303
|
+
|
|
304
|
+
`2` also covers an internal error, deliberately: a crash must never be read as a verdict, and
|
|
305
|
+
a CI job that saw `1` must not have to wonder whether the tool or the agent failed. The message
|
|
306
|
+
says `internal error`, so a human can tell them apart.
|
|
307
|
+
|
|
308
|
+
`retracted` fails the run because a report that reads green while a cited fact was withdrawn
|
|
309
|
+
mid-session is the exact defect this tool exists to find. `--strict` is the only path on which
|
|
310
|
+
`ungrounded` becomes fatal.
|
|
311
|
+
|
|
312
|
+
## CLI
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
tcpcore verify <session.jsonl> --facts <facts.jsonl>
|
|
316
|
+
[--json] [--out <path>] [--html <path>] [--merkle]
|
|
317
|
+
[--expect-root <64 hex>] [--strict] [--fact-tool <name>]...
|
|
318
|
+
tcpcore adapt <input|url> --from <adapter> [-o session.jsonl]
|
|
319
|
+
tcpcore adapt --list
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
- `--json` prints the machine-readable report (schema: `tcpcore.report.v1`).
|
|
323
|
+
- `--out` writes that JSON report to a file; the human summary stays on the terminal.
|
|
324
|
+
- `--html` writes a self-contained page, no JavaScript, no external stylesheet - a report that
|
|
325
|
+
needs a CDN to render is not evidence.
|
|
326
|
+
- `--merkle` also prints the per-action leaves, in the order the tree sorts them.
|
|
327
|
+
- `--fact-tool` names a tool whose results supply facts. **Repeatable.** The verifier reads
|
|
328
|
+
fact ids from `{"facts": [{"id": "..."}]}` in that tool's result, and refuses a result it
|
|
329
|
+
cannot read rather than reporting every later action as ungrounded.
|
|
330
|
+
|
|
331
|
+
## Adapters
|
|
332
|
+
|
|
333
|
+
`tcpcore adapt` maps a framework's own log into `tcpcore-v1.jsonl`. Every adapter is a real
|
|
334
|
+
mapping module with a committed fixture and a test, and every row below states **where the
|
|
335
|
+
knowledge of that format came from**. This build ships **eleven** adapters: the five of Wave 0
|
|
336
|
+
and the six of W1.3. **Exactly one of the eleven is `captured`** - the DeepSeek Harness one,
|
|
337
|
+
from a real session store on the machine this was built on. The other ten are `documented`
|
|
338
|
+
against a pinned package, type definition or doc page, named in the row and in
|
|
339
|
+
`fixtures/PROVENANCE.md`. None is `inferred`.
|
|
340
|
+
|
|
341
|
+
| Adapter | Format followed | Provenance | What it cannot express |
|
|
342
|
+
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
343
|
+
| `langchain` | `@langchain/core@1.3.3` `StreamEvent` (`dist/tracers/event_stream.d.ts:42-85`), `astreamEvents` v2 | **documented** (pinned type definition) | A `StreamEvent` has **no timestamp**, so each capture line must carry its own `"at"`; a log without them is refused, never dated with the verifier's clock. |
|
|
344
|
+
| `langgraph` | `@langchain/langgraph@1.6.0` `streamEvents` v2 (`dist/pregel/types.d.ts:19`, `dist/pregel/index.d.ts:493-498`), `metadata.langgraph_node` | **documented** (pinned type definition) | Only `streamEvents` v2 is read. `updates`-mode chunks carry no timestamp and no run id, and the v3 protocol's shape was not verifiable here, so both are refused by name. |
|
|
345
|
+
| `claude-code` | Claude Code session transcript JSONL (hooks' `transcript_path`; third-party field reference) | **documented** (third-party; not re-verified) | Anthropic does not publish the transcript schema and there was no Claude Code install to capture from. A `tool_use` with no `tool_result` is refused rather than reported as grounded or failed. |
|
|
346
|
+
| `deepseek-harness` | DeepSeek Harness v4 session log, verified field by field from a real capture | **captured** (redacted fixture) | The on-disk log is multi-frame zstd and Node decompresses only the first frame, so the input must be `zstd -d`'d first; a compressed file is refused rather than partially read. |
|
|
347
|
+
| `cursor` | Cursor agent hooks (`cursor.com/docs/hooks`): generic `preToolUse` / `postToolUse` / `postToolUseFailure` payloads with `tool_name`, `tool_input`, `tool_output`, `isError` | **documented** (`cursor.com/docs/hooks`) | Hooks carry no call id, so pairing is by conversation, tool name and order; an unmatched payload **or two outstanding calls to one tool in one conversation** is refused rather than paired by guess. MCP output redaction is described below. |
|
|
348
|
+
| `openai-assistants` | Assistants API run steps (`openai@7.47.0`, `resources/beta/threads/runs/steps.d.ts`): `FunctionToolCall.function.{name,arguments,output}`, `created_at` in seconds | **documented** (pinned type definition) | Only function calls. `file_search` carries no arguments and `code_interpreter` carries code, so both are refused; a `null` output means the outputs were never submitted and is refused too. |
|
|
349
|
+
| `aws-bedrock-agents` | Trace parts (`@aws-sdk/client-bedrock-agent-runtime@3.1161.0`, `dist-types/models/models_0.d.ts:3595`): `orchestrationTrace.invocationInput` / `.observation` | **documented** (pinned type definition) | Trace parts carry no call id, so pairing is positional **and interleaved invocations are refused** rather than mispaired: a trace it accepts is a trace it could pair. Parameters are name-to-string, so a declared grounding cannot be expressed at all. |
|
|
350
|
+
| `google-vertex-agents` | ADK session events (`google-adk@2.13.0`, `google/adk/events/event.py`): `content.parts[].function_call` / `function_response` | **documented** (pinned wheel source) | A call is paired by invocation and function name; two outstanding calls to one function are refused as ambiguous, and a call with no response (a long-running tool) is refused. |
|
|
351
|
+
| `microsoft-autogen` | `autogen_core` structured logging (`autogen-core@0.7.5`, `autogen_core/logging.py:160-199`): `{"type":"ToolCall","tool_name","arguments","result","agent_id"}` | **documented** (pinned wheel source) | The event payload carries **no timestamp**, so every line must carry `ts`/`timestamp`/`asctime`; a line without one is refused rather than dated with the verifier clock. |
|
|
352
|
+
| `crewai` | Event bus (`crewai 1.15.34`): `ToolUsageStartedEvent` / `ToolUsageFinishedEvent` / `ToolUsageErrorEvent` from `docs.crewai.com` and `lib/crewai/src/crewai/events/` | **documented** (docs + GitHub source, fetched this wave) | Only the event bus is read - see below. A started tool with no finished event is refused, and a tool-reported `failure` has no representation in the canonical format. |
|
|
353
|
+
| `custom-http` | Canonical JSONL over a file or an HTTP GET (`spec/tcpcore-v1.md`) | **documented** (specified by us) | It reads canonical records and nothing else: a producer must emit `tcpcore.session.v1` actions itself. A JSON array body is refused, because line framing is part of the format. |
|
|
354
|
+
|
|
355
|
+
Provenance, in one line each: **captured** means a real log from that framework was used;
|
|
356
|
+
**documented** means the format was read from a pinned package, type definition or doc page,
|
|
357
|
+
named in the row; **inferred** means neither was available and the README would say so. No
|
|
358
|
+
adapter in this build is `inferred`.
|
|
359
|
+
|
|
360
|
+
### CrewAI: the event bus, not `TaskOutput`
|
|
361
|
+
|
|
362
|
+
CrewAI also exposes `CrewOutput` / `TaskOutput.tools_used[]`, and it is the smaller surface to
|
|
363
|
+
read. It is not used here, because each entry is `{ tool, input, output }` and **`input` is a
|
|
364
|
+
string** - the model's raw tool-call text. A string is not a structured argument set: mapping it
|
|
365
|
+
would mean parsing prose to invent `args`, which is exactly the coercion this format refuses.
|
|
366
|
+
The event bus carries `tool_args` as a dict and the tool's own `output`, so it is the surface
|
|
367
|
+
that already speaks in structured claims. `tool_usage_finished` is the unit mapped (it carries
|
|
368
|
+
`tool_name`, `tool_args`, `started_at` and `output`), and `started_at` is the action's
|
|
369
|
+
timestamp.
|
|
370
|
+
|
|
371
|
+
### custom-http: the escape hatch
|
|
372
|
+
|
|
373
|
+
The twelfth framework should not need a twelfth module. `tcpcore adapt <url> --from custom-http`
|
|
374
|
+
performs one HTTP GET (ten-second timeout, 5 MB body cap, non-2xx is invalid input) and reads
|
|
375
|
+
canonical JSONL; a file path works the same way. It is a reader, not a service, and it validates
|
|
376
|
+
through the same parser as a hand-written session, so an unknown key fails with the same message
|
|
377
|
+
it would anywhere else.
|
|
378
|
+
|
|
379
|
+
### Cursor and redacted MCP output
|
|
380
|
+
|
|
381
|
+
Cursor's `postToolUse` hook **redacts MCP tool output** for HTTP MCP servers - it receives
|
|
382
|
+
`{"redacted": true}` (with `isError` when known) instead of the result. Sessions that rely on
|
|
383
|
+
MCP therefore report more `ungrounded` actions than grounded. This is a limitation of Cursor's
|
|
384
|
+
logging, not of the verifier: when the log redacts the result, the action is marked
|
|
385
|
+
`ungrounded` rather than `fabricated`, so the report stays honest about what it cannot
|
|
386
|
+
adjudicate.
|
|
387
|
+
|
|
388
|
+
The reserved result shape `{"redacted": true}` is how that reaches the report: the adapter
|
|
389
|
+
passes the hook's payload through unchanged, and the engine treats an action that would
|
|
390
|
+
otherwise be grounded as ungrounded. A fabricated or retracted citation still wins, because
|
|
391
|
+
those findings come from the grounding, which the log did give us.
|
|
392
|
+
|
|
393
|
+
### The third-party-hooks question
|
|
394
|
+
|
|
395
|
+
Cursor's "Third Party Hooks" page documents that Cursor **loads Claude Code hook
|
|
396
|
+
configurations** and maps hook names and response formats. It says nothing about the _input
|
|
397
|
+
payload_ matching Claude Code's. So the conclusion is **configuration compatibility, not
|
|
398
|
+
payload compatibility**: `claude-code.ts` reads a transcript, `cursor.ts` reads hook payloads,
|
|
399
|
+
and they are two independent parsers that share the tool-call mapping in `adapters/tool-call.ts`
|
|
400
|
+
rather than an envelope.
|
|
401
|
+
|
|
402
|
+
## What this does not prove
|
|
403
|
+
|
|
404
|
+
- **It does not prove an adapter is right.** Eleven adapters, **one `captured`**, **ten
|
|
405
|
+
`documented`**, and **no adapter silently guesses**: where a framework's log does not carry
|
|
406
|
+
what the format needs, the adapter refuses with a message naming the field rather than
|
|
407
|
+
inventing a value, and where a pairing would be ambiguous - two Bedrock invocations before an
|
|
408
|
+
observation, two Cursor calls to one tool in one conversation - it refuses the trace instead
|
|
409
|
+
of pairing it by guess. **A `documented` adapter is a claim about a document, not about your
|
|
410
|
+
logs**: it was written against a pinned package, type definition or doc page, and if the real
|
|
411
|
+
format differs the adapter fails on the field rather than mapping around it.
|
|
412
|
+
- **It does not prove the facts are true.** A fact is a typed assertion with a source; a
|
|
413
|
+
source can be wrong. Verify against a kernel full of `VERIFIED` facts and the report is a
|
|
414
|
+
statement about well-sourced beliefs, not about reality.
|
|
415
|
+
- **It does not judge whether a citation is apt.** An agent can cite a real, live, irrelevant
|
|
416
|
+
fact and be reported `grounded`. Detecting that needs semantic entailment, which is unsolved;
|
|
417
|
+
self-declared citations are marked `declared: true` so a reader can see which claims rest on
|
|
418
|
+
the agent's own account of its evidence.
|
|
419
|
+
- **It does not extract claims from prose.** Claims and grounding come only from structured
|
|
420
|
+
fields. An adapter that guessed would manufacture the findings the tool exists to detect.
|
|
421
|
+
- **It does not replay publication history.** The fact set is treated as one corpus in force.
|
|
422
|
+
"Which version was current at time T" is the kernel's question, and it has its own model for
|
|
423
|
+
it.
|
|
424
|
+
- **It does not detect a deleted action.** The roots commit to the actions that are in the
|
|
425
|
+
file. A session with a line removed is a different session with a different root - which is
|
|
426
|
+
what `--expect-root` is for - but nothing in a single log can prove that nothing was removed
|
|
427
|
+
before the root was computed.
|
|
428
|
+
- **It does not replace reading the findings.** Four numbers are a summary. The value is in the
|
|
429
|
+
lines that name the action and the fact.
|
|
430
|
+
- **Plausible-zero detection is not in this build.** The design's W1.4 checks ("claimed zero
|
|
431
|
+
issues but checked no files", "claimed success but returned an empty result", "claimed to
|
|
432
|
+
have run tests but never invoked a test tool", "claimed to have read a file but never called
|
|
433
|
+
read") need semantics this wave does not have. The report carries a `plausibleZero` array,
|
|
434
|
+
empty, and the registry it will be filled from; a session with no actions is refused
|
|
435
|
+
outright, which is the plausible-zero rule applied to the session itself.
|
|
436
|
+
|
|
437
|
+
## Development
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
pnpm --filter @tcpcore1/verifier build # bundle the kernel, then tsc -> dist
|
|
441
|
+
pnpm --filter @tcpcore1/verifier typecheck
|
|
442
|
+
pnpm --filter @tcpcore1/verifier test # vitest run --silent
|
|
443
|
+
pnpm --filter @tcpcore1/verifier check:vendor # is src/vendor a fresh copy of the kernel?
|
|
444
|
+
pnpm --filter @tcpcore1/verifier check:tarball # pack, extract, refuse a tarball that cannot install
|
|
445
|
+
npx eslint packages/verifier
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
`build` runs `node scripts/bundle-kernel.mjs` before `tsc`, so `src/vendor/` is rewritten from
|
|
449
|
+
`packages/truth-kernel` and `packages/claim-graph` on every build. Never edit `src/vendor/`: the
|
|
450
|
+
copy is generated, it says so in its header, and `src/__tests__/vendor-drift.test.ts` fails if
|
|
451
|
+
it stops being a fresh copy. `prepublishOnly` runs both checks, so a stale copy or a tarball
|
|
452
|
+
carrying a `workspace:`/`file:` dependency cannot be published.
|
|
453
|
+
|
|
454
|
+
Adding this package to a checkout needs one `pnpm install`: `@tcpcore1/truth-kernel` is a
|
|
455
|
+
**devDependency** (tests and typecheck import the real kernel; consumers never install it), and
|
|
456
|
+
the workspace link plus the `pnpm-lock.yaml` importer entry have to exist. The lockfile change is
|
|
457
|
+
the operator's - and moving a dependency between `dependencies` and `devDependencies` in
|
|
458
|
+
`package.json` requires regenerating that importer, because CI installs with
|
|
459
|
+
`--frozen-lockfile`.
|
|
460
|
+
|
|
461
|
+
## Licence
|
|
462
|
+
|
|
463
|
+
MIT. See [LICENSE](./LICENSE).
|
|
464
|
+
|
|
465
|
+
Every committed fixture states where its shape came from; see
|
|
466
|
+
[`fixtures/PROVENANCE.md`](./fixtures/PROVENANCE.md).
|
package/bin/tcpcore.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `tcpcore` bin shim.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately tiny: it resolves the built entry point and, if the package has not
|
|
6
|
+
* been built, says which command builds it. That failure is the one a developer
|
|
7
|
+
* hits after `npm i` from a git checkout, and "Cannot find module" is a worse
|
|
8
|
+
* message than the two lines below.
|
|
9
|
+
*
|
|
10
|
+
* Nothing else lives here. Every decision - argv, exit codes, output - belongs in
|
|
11
|
+
* `src/`, where it is importable and testable. A bin that contains logic is a bin
|
|
12
|
+
* whose logic cannot be unit-tested.
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync } from 'node:fs';
|
|
15
|
+
import { dirname, join } from 'node:path';
|
|
16
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
17
|
+
|
|
18
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const entry = join(here, '..', 'dist', 'index.js');
|
|
20
|
+
|
|
21
|
+
if (!existsSync(entry)) {
|
|
22
|
+
process.stderr.write(
|
|
23
|
+
[
|
|
24
|
+
'tcpcore is not built yet.',
|
|
25
|
+
'',
|
|
26
|
+
' pnpm --filter @tcpcore1/verifier build',
|
|
27
|
+
'',
|
|
28
|
+
`Expected: ${entry}`,
|
|
29
|
+
'',
|
|
30
|
+
].join('\n'),
|
|
31
|
+
);
|
|
32
|
+
process.exit(2);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
await import(pathToFileURL(entry).href);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Bedrock Agents adapter: the `trace` parts of an `InvokeAgent` response, or
|
|
3
|
+
* `GetAgentTrace` output.
|
|
4
|
+
*
|
|
5
|
+
* ## The format, and where it was read
|
|
6
|
+
*
|
|
7
|
+
* `@aws-sdk/client-bedrock-agent-runtime@3.1161.0`,
|
|
8
|
+
* `dist-types/models/models_0.d.ts`:
|
|
9
|
+
*
|
|
10
|
+
* - `TracePart { sessionId?, trace?: Trace, callerChain?, eventTime?: Date,
|
|
11
|
+
* collaboratorName?, agentId?, agentAliasId?, agentVersion? }` (line 3595)
|
|
12
|
+
* - `Trace` is a tagged union (line 3460); the interesting arm is
|
|
13
|
+
* `trace.orchestrationTrace`, itself a union carrying `invocationInput`,
|
|
14
|
+
* `observation` or `rationale`.
|
|
15
|
+
* - `orchestrationTrace.invocationInput.actionGroupInvocationInput`:
|
|
16
|
+
* `{ actionGroupName, verb, apiPath, parameters?: Parameter[], requestBody?, … }`
|
|
17
|
+
* - `orchestrationTrace.observation.actionGroupInvocationOutput: { text?, metadata? }`
|
|
18
|
+
* - `Parameter { name?, type?, value? }`
|
|
19
|
+
*
|
|
20
|
+
* ## Pairing: positional, and refusing to guess
|
|
21
|
+
*
|
|
22
|
+
* **The trace parts carry no call id**, so an invocation is paired with the next
|
|
23
|
+
* `actionGroupInvocationOutput` in file order. Every case where that pairing would be a
|
|
24
|
+
* guess is a hard error:
|
|
25
|
+
*
|
|
26
|
+
* - an invocation with no following observation (the outcome is unknown);
|
|
27
|
+
* - an observation with no preceding invocation (the call is missing);
|
|
28
|
+
* - **a second invocation before the first observation** - interleaved calls cannot be
|
|
29
|
+
* paired positionally, and a guessed pairing would put one call's output against
|
|
30
|
+
* another call's claim *silently*, which is the one failure this package exists to
|
|
31
|
+
* find in other people's output and must not produce itself.
|
|
32
|
+
*
|
|
33
|
+
* So the contract is narrow and true: **a trace this adapter accepts is a trace it could
|
|
34
|
+
* pair.** It refuses to verify a trace it would have to guess about.
|
|
35
|
+
*
|
|
36
|
+
* ## Events that are not actions
|
|
37
|
+
*
|
|
38
|
+
* `rationale` (the agent's reasoning), `modelInvocationInput`/`Output` (prompt
|
|
39
|
+
* plumbing), `preProcessingTrace`, `postProcessingTrace`, `guardrailTrace` and
|
|
40
|
+
* `failureTrace` are not mapped. They are not claims about what was done, and turning
|
|
41
|
+
* a rationale into an action would invent one.
|
|
42
|
+
*/
|
|
43
|
+
import { type Adapter } from './types.js';
|
|
44
|
+
/** The Bedrock Agents adapter. */
|
|
45
|
+
export declare const awsBedrockAgentsAdapter: Adapter;
|
|
46
|
+
//# sourceMappingURL=aws-bedrock-agents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aws-bedrock-agents.d.ts","sourceRoot":"","sources":["../../src/adapters/aws-bedrock-agents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAIH,OAAO,EAAyB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AA4BjE,kCAAkC;AAClC,eAAO,MAAM,uBAAuB,EAAE,OA4IrC,CAAC"}
|