@atrib/trace 0.5.14 → 0.5.15
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/README.md +3 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +62 -17
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @atrib/trace
|
|
2
2
|
|
|
3
|
-
MCP server exposing the `trace` tool, walks a record's `informed_by` chain backward to surface the
|
|
3
|
+
MCP server exposing the `trace` tool, walks a record's `informed_by` chain backward to surface the signed relationship path that led to it.
|
|
4
4
|
|
|
5
|
-
Closes the consumer-side cognitive-loop primitive: recall returns raw records; trace returns the
|
|
5
|
+
Closes the consumer-side cognitive-loop primitive: recall returns raw records; trace returns the declared-relationship trace, so an agent asking "why did I do X?" can see "X was claimed to be informed by Y, which was claimed to be informed by Z" without manually walking `informed_by` hash-by-hash.
|
|
6
6
|
|
|
7
7
|
## Tools
|
|
8
8
|
|
|
@@ -43,7 +43,7 @@ mcp__atrib-trace__trace_forward({ // FORWARD — what was informed by this?
|
|
|
43
43
|
}
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
- `trace` walks `informed_by` BACKWARD (toward
|
|
46
|
+
- `trace` walks `informed_by` BACKWARD (toward declared ancestors). Answers "what did the signer claim informed this record?"
|
|
47
47
|
- `trace_forward` walks `informed_by` FORWARD (records that cited this one). Answers "I made decision X, what did I do because of it?" The dual of `trace`. Same input schema, same response shape.
|
|
48
48
|
- For forward walks, `next_informed_by` carries the CHILDREN visited at the next hop (records citing this one) rather than this record's own informed_by — field name kept for shape-compat with `trace`.
|
|
49
49
|
|
package/dist/index.d.ts
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* informed_by chain backward to surface the reasoning chain that led to it.
|
|
4
4
|
*
|
|
5
5
|
* Closes the consumer-side cognitive-loop primitive: recall returns raw
|
|
6
|
-
* records; trace returns the
|
|
7
|
-
* I do X?" can see "X
|
|
8
|
-
* manually walking informed_by hash-by-hash.
|
|
6
|
+
* records; trace returns the declared-relationship path, so an agent asking
|
|
7
|
+
* "why did I do X?" can see "X claimed Y as input, and Y claimed Z as input"
|
|
8
|
+
* without manually walking informed_by hash-by-hash.
|
|
9
9
|
*
|
|
10
10
|
* Reads only the local mirror (~/.atrib/records/*.jsonl) for v1, same scope
|
|
11
11
|
* as recall. v2 will fall back to log.atrib.dev/v1/lookup/<hash> for hashes
|
|
@@ -42,6 +42,8 @@ interface CompactVisited {
|
|
|
42
42
|
model_name?: string;
|
|
43
43
|
prompt_version?: string;
|
|
44
44
|
topics?: string[];
|
|
45
|
+
intent?: string;
|
|
46
|
+
rationale?: string;
|
|
45
47
|
/**
|
|
46
48
|
* First 200 chars of the record's human-readable content, derived
|
|
47
49
|
* per event_type from the @atrib/mcp normative shapes (D086):
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* informed_by chain backward to surface the reasoning chain that led to it.
|
|
5
5
|
*
|
|
6
6
|
* Closes the consumer-side cognitive-loop primitive: recall returns raw
|
|
7
|
-
* records; trace returns the
|
|
8
|
-
* I do X?" can see "X
|
|
9
|
-
* manually walking informed_by hash-by-hash.
|
|
7
|
+
* records; trace returns the declared-relationship path, so an agent asking
|
|
8
|
+
* "why did I do X?" can see "X claimed Y as input, and Y claimed Z as input"
|
|
9
|
+
* without manually walking informed_by hash-by-hash.
|
|
10
10
|
*
|
|
11
11
|
* Reads only the local mirror (~/.atrib/records/*.jsonl) for v1, same scope
|
|
12
12
|
* as recall. v2 will fall back to log.atrib.dev/v1/lookup/<hash> for hashes
|
|
@@ -15,30 +15,55 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
17
17
|
import { z } from 'zod';
|
|
18
|
-
import { resolveEnvContextId, logReadPrimitiveCall
|
|
18
|
+
import { resolveEnvContextId, logReadPrimitiveCall } from '@atrib/mcp';
|
|
19
19
|
import { loadAllRecords } from './storage.js';
|
|
20
20
|
import { traceBackward, traceForward } from './trace.js';
|
|
21
21
|
const SHA256_REF_PATTERN = /^sha256:[0-9a-f]{64}$/;
|
|
22
22
|
const HEX_32_PATTERN = /^[0-9a-f]{32}$/;
|
|
23
23
|
const TraceInput = z.object({
|
|
24
|
-
record_hash: z
|
|
24
|
+
record_hash: z
|
|
25
|
+
.string()
|
|
26
|
+
.regex(SHA256_REF_PATTERN)
|
|
27
|
+
.describe("The 'sha256:<64-hex>' record_hash to start from. Walks backward via " +
|
|
25
28
|
'informed_by edges from this record.'),
|
|
26
|
-
context_id: z
|
|
29
|
+
context_id: z
|
|
30
|
+
.string()
|
|
31
|
+
.regex(HEX_32_PATTERN)
|
|
32
|
+
.optional()
|
|
33
|
+
.describe('Optional 32-hex context_id scope. When set, edges crossing into a ' +
|
|
27
34
|
'different context_id surface as dangling rather than expanding the ' +
|
|
28
35
|
'walk. Defaults to process.env.ATRIB_CONTEXT_ID when valid; omit at ' +
|
|
29
36
|
'the env-var level to walk cross-context. Used by Inspect-style ' +
|
|
30
|
-
|
|
31
|
-
depth: z
|
|
37
|
+
"harnesses to keep each arm's trace inside its own context per D072."),
|
|
38
|
+
depth: z
|
|
39
|
+
.number()
|
|
40
|
+
.int()
|
|
41
|
+
.min(0)
|
|
42
|
+
.max(10)
|
|
43
|
+
.optional()
|
|
44
|
+
.describe('Maximum hop count from the starting record. Use 0 to return only ' +
|
|
32
45
|
'the start record. Defaults to 3. Bounded ' +
|
|
33
46
|
'at 10 to keep responses tractable; deeper chains should be walked ' +
|
|
34
47
|
'in pieces by re-rooting at a returned upstream hash.'),
|
|
35
|
-
max_nodes: z
|
|
48
|
+
max_nodes: z
|
|
49
|
+
.number()
|
|
50
|
+
.int()
|
|
51
|
+
.min(1)
|
|
52
|
+
.max(500)
|
|
53
|
+
.optional()
|
|
54
|
+
.describe('Hard cap on total visited records. Defaults to 200. Prevents pathological ' +
|
|
36
55
|
'fan-out (a record with hundreds of informed_by entries) from exploding ' +
|
|
37
56
|
'the response.'),
|
|
38
|
-
compact: z
|
|
57
|
+
compact: z
|
|
58
|
+
.boolean()
|
|
59
|
+
.optional()
|
|
60
|
+
.describe('When true (the default), per-record output omits signature/content_id/' +
|
|
39
61
|
'spec_version/chain_root to keep the response small. Set false for full ' +
|
|
40
62
|
'record bytes (useful for re-verification).'),
|
|
41
|
-
include_content: z
|
|
63
|
+
include_content: z
|
|
64
|
+
.boolean()
|
|
65
|
+
.optional()
|
|
66
|
+
.describe('When true and compact=true, include the D062 local mirror body as ' +
|
|
42
67
|
'local_content and local_producer on each visited record. Defaults false ' +
|
|
43
68
|
'so trace stays cheap for ordinary causal walks.'),
|
|
44
69
|
});
|
|
@@ -65,8 +90,17 @@ export function summarizeSidecar(loadedRecord) {
|
|
|
65
90
|
out.model_name = c['model_name'];
|
|
66
91
|
if (c && typeof c['prompt_version'] === 'string')
|
|
67
92
|
out.prompt_version = c['prompt_version'];
|
|
93
|
+
if (c && typeof c['intent'] === 'string') {
|
|
94
|
+
out.intent = c['intent'].length > 200 ? c['intent'].slice(0, 197) + '...' : c['intent'];
|
|
95
|
+
}
|
|
96
|
+
if (c && typeof c['rationale'] === 'string') {
|
|
97
|
+
out.rationale =
|
|
98
|
+
c['rationale'].length > 200 ? c['rationale'].slice(0, 197) + '...' : c['rationale'];
|
|
99
|
+
}
|
|
68
100
|
if (c && Array.isArray(c['topics'])) {
|
|
69
|
-
out.topics = c['topics']
|
|
101
|
+
out.topics = c['topics']
|
|
102
|
+
.filter((t) => typeof t === 'string')
|
|
103
|
+
.slice(0, 6);
|
|
70
104
|
}
|
|
71
105
|
// Per-event_type human-readable text. The `what` slot here is generic
|
|
72
106
|
// (it's the human-scannable summary regardless of event_type); the
|
|
@@ -146,8 +180,9 @@ export function extractRecordHashFieldsFromMcpResult(result) {
|
|
|
146
180
|
const seen = new Set();
|
|
147
181
|
const pattern = /^sha256:[0-9a-f]{64}$/;
|
|
148
182
|
const content = result?.content;
|
|
149
|
-
const text = Array.isArray(content) &&
|
|
150
|
-
|
|
183
|
+
const text = Array.isArray(content) &&
|
|
184
|
+
typeof content[0]?.text === 'string'
|
|
185
|
+
? content[0].text
|
|
151
186
|
: undefined;
|
|
152
187
|
let root = result;
|
|
153
188
|
if (text) {
|
|
@@ -202,7 +237,7 @@ export async function createAtribTraceServer() {
|
|
|
202
237
|
}
|
|
203
238
|
mcp.registerTool('trace', {
|
|
204
239
|
title: 'trace informed_by chain backward',
|
|
205
|
-
description:
|
|
240
|
+
description: "Walk a record's informed_by chain backward to surface the reasoning " +
|
|
206
241
|
'chain that led to it. Reads from the local signed-record mirror ' +
|
|
207
242
|
'(~/.atrib/records/*.jsonl). Returns the records visited, parent links ' +
|
|
208
243
|
'so the caller can reconstruct the tree, and dangling hashes (records ' +
|
|
@@ -226,7 +261,12 @@ export async function createAtribTraceServer() {
|
|
|
226
261
|
...(contextId ? { contextId } : {}),
|
|
227
262
|
});
|
|
228
263
|
return {
|
|
229
|
-
content: [
|
|
264
|
+
content: [
|
|
265
|
+
{
|
|
266
|
+
type: 'text',
|
|
267
|
+
text: JSON.stringify(buildPayload(result, byHash, compact, includeContent), null, 2),
|
|
268
|
+
},
|
|
269
|
+
],
|
|
230
270
|
};
|
|
231
271
|
}, extractRecordHashFieldsFromMcpResult));
|
|
232
272
|
// Sibling tool: forward walk (records that cited THIS one). Mirrors
|
|
@@ -254,7 +294,12 @@ export async function createAtribTraceServer() {
|
|
|
254
294
|
...(contextId ? { contextId } : {}),
|
|
255
295
|
});
|
|
256
296
|
return {
|
|
257
|
-
content: [
|
|
297
|
+
content: [
|
|
298
|
+
{
|
|
299
|
+
type: 'text',
|
|
300
|
+
text: JSON.stringify(buildPayload(result, byHash, compact, includeContent), null, 2),
|
|
301
|
+
},
|
|
302
|
+
],
|
|
258
303
|
};
|
|
259
304
|
}, extractRecordHashFieldsFromMcpResult));
|
|
260
305
|
return { mcp };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atrib/trace",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "MCP server for atrib. Walks informed_by chains backward from a record_hash to surface the
|
|
3
|
+
"version": "0.5.15",
|
|
4
|
+
"description": "MCP server for atrib. Walks informed_by chains backward from a record_hash to surface the signed relationship path that produced it.",
|
|
5
5
|
"author": "atrib <hello@atrib.dev>",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"atrib",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"cognitive-primitive",
|
|
14
14
|
"trace",
|
|
15
15
|
"provenance",
|
|
16
|
-
"
|
|
16
|
+
"lineage"
|
|
17
17
|
],
|
|
18
18
|
"homepage": "https://atrib.dev",
|
|
19
19
|
"license": "Apache-2.0",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
27
27
|
"zod": "^3.25.76",
|
|
28
|
-
"@atrib/mcp": "0.17.
|
|
28
|
+
"@atrib/mcp": "0.17.6"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^25.9.2",
|