@reclaimprotocol/agent 0.1.4 → 0.1.6
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 +5 -5
- package/lib/authoring/backend.d.ts +71 -0
- package/lib/authoring/backend.js +24 -0
- package/lib/authoring/find.d.ts +3 -0
- package/lib/authoring/find.js +54 -0
- package/lib/authoring/index.d.ts +4 -0
- package/lib/authoring/index.js +6 -0
- package/lib/authoring/propose.d.ts +3 -0
- package/lib/authoring/propose.js +109 -0
- package/lib/authoring/replay.d.ts +10 -0
- package/lib/authoring/replay.js +34 -0
- package/lib/authoring/tools.d.ts +16 -0
- package/lib/authoring/tools.js +193 -0
- package/lib/authoring/util.d.ts +27 -0
- package/lib/authoring/util.js +21 -0
- package/lib/cdp/capture-engine.js +1 -1
- package/lib/consts.d.ts +6 -1
- package/lib/consts.js +9 -2
- package/lib/mcp/api/operations.gen.js +46 -18
- package/lib/mcp/server.d.ts +2 -25
- package/lib/mcp/server.js +4 -17
- package/lib/mcp/start.js +4 -2
- package/lib/mcp/tools/agent/analyze.js +3 -3
- package/lib/mcp/tools/agent/build.d.ts +4 -4
- package/lib/mcp/tools/agent/build.js +13 -15
- package/lib/mcp/tools/agent/capture.d.ts +13 -1
- package/lib/mcp/tools/agent/capture.js +18 -85
- package/lib/mcp/tools/agent/eval.d.ts +5 -2
- package/lib/mcp/tools/agent/eval.js +11 -121
- package/lib/mcp/tools/agent/find.d.ts +10 -3
- package/lib/mcp/tools/agent/find.js +25 -31
- package/lib/mcp/tools/agent/proof.d.ts +13 -3
- package/lib/mcp/tools/agent/proof.js +81 -132
- package/lib/mcp/tools/agent/propose.d.ts +10 -9
- package/lib/mcp/tools/agent/propose.js +87 -64
- package/lib/mcp/tools/agent/publish.js +2 -2
- package/lib/mcp/tools/agent/replay.d.ts +10 -3
- package/lib/mcp/tools/agent/replay.js +29 -36
- package/lib/mcp/tools/agent/session.d.ts +1 -3
- package/lib/mcp/tools/agent/session.js +5 -5
- package/lib/mcp/tools/agent/shared.d.ts +8 -0
- package/lib/mcp/tools/agent/shared.js +125 -0
- package/lib/old/client.d.ts +35 -0
- package/lib/old/client.js +18 -0
- package/lib/old/login-cdp.d.ts +24 -0
- package/lib/old/login-cdp.js +28 -3
- package/lib/old/sdk-client.d.ts +39 -0
- package/lib/old/sdk-client.js +85 -0
- package/lib/old/to-register.d.ts +69 -0
- package/lib/old/to-register.js +52 -2
- package/lib/old/tools/build.d.ts +6 -1
- package/lib/old/tools/build.js +11 -1
- package/lib/old/tools/get-provider-info.d.ts +16 -0
- package/lib/old/tools/get-provider-info.js +73 -0
- package/lib/old/tools/get-version-config.d.ts +17 -0
- package/lib/old/tools/get-version-config.js +47 -0
- package/lib/old/tools/publish.js +189 -2
- package/lib/old/tools/update-provider-metadata.d.ts +16 -0
- package/lib/old/tools/update-provider-metadata.js +61 -0
- package/lib/proof/attestor.d.ts +6 -3
- package/lib/proof/attestor.js +10 -1
- package/lib/proof/debug-response-dump.d.ts +4 -0
- package/lib/proof/debug-response-dump.js +55 -0
- package/lib/proof/patch-domhandler.d.ts +1 -0
- package/lib/proof/patch-domhandler.js +59 -0
- package/lib/proof/proof-core.d.ts +1 -1
- package/lib/proof/proof-core.js +1 -1
- package/lib/proof/zk-files.js +7 -6
- package/lib/provider/dom-xpath.d.ts +17 -0
- package/lib/provider/dom-xpath.js +187 -0
- package/lib/provider/draft.d.ts +30 -2
- package/lib/provider/draft.js +117 -28
- package/lib/provider/index.d.ts +4 -0
- package/lib/provider/index.js +7 -0
- package/lib/provider/injection-doc.js +6 -0
- package/lib/provider/matcher.d.ts +17 -20
- package/lib/provider/matcher.js +394 -280
- package/lib/provider/schema.d.ts +7 -5
- package/lib/tools/registry.d.ts +50 -0
- package/lib/tools/registry.js +49 -0
- package/package.json +9 -1
- package/skill/SKILL.builder.md +55 -32
- package/skill/SKILL.old.md +20 -12
- package/skill/builder-mode.md +1 -1
- package/skill/injection-api.md +117 -0
- package/src/authoring/backend.ts +98 -0
- package/src/authoring/index.ts +20 -0
- package/src/authoring/tools.ts +273 -0
- package/src/authoring/util.ts +42 -0
- package/src/cdp/capture-engine.ts +1 -1
- package/src/consts.ts +15 -2
- package/src/mcp/api/operations.gen.ts +46 -18
- package/src/mcp/server.ts +9 -39
- package/src/mcp/start.ts +4 -1
- package/src/mcp/tools/agent/analyze.ts +3 -3
- package/src/mcp/tools/agent/build.ts +13 -21
- package/src/mcp/tools/agent/capture.ts +31 -115
- package/src/mcp/tools/agent/eval.ts +19 -155
- package/src/mcp/tools/agent/find.ts +33 -36
- package/src/mcp/tools/agent/proof.ts +87 -160
- package/src/mcp/tools/agent/propose.ts +93 -85
- package/src/mcp/tools/agent/publish.ts +2 -2
- package/src/mcp/tools/agent/replay.ts +32 -42
- package/src/mcp/tools/agent/session.ts +4 -5
- package/src/mcp/tools/agent/shared.ts +152 -0
- package/src/old/client.ts +56 -0
- package/src/old/login-cdp.ts +28 -3
- package/src/old/sdk-client.ts +105 -0
- package/src/old/to-register.ts +98 -6
- package/src/old/tools/build.ts +12 -0
- package/src/old/tools/get-provider-info.ts +91 -0
- package/src/old/tools/get-version-config.ts +56 -0
- package/src/old/tools/publish.ts +244 -1
- package/src/old/tools/update-provider-metadata.ts +72 -0
- package/src/proof/attestor.ts +16 -4
- package/src/proof/debug-response-dump.ts +70 -0
- package/src/proof/patch-domhandler.ts +68 -0
- package/src/proof/proof-core.ts +1 -1
- package/src/proof/zk-files.ts +7 -6
- package/src/provider/dom-xpath.ts +225 -0
- package/src/provider/draft.ts +168 -35
- package/src/provider/index.ts +8 -0
- package/src/provider/injection-doc.ts +6 -0
- package/src/provider/matcher.ts +477 -357
- package/src/provider/schema.ts +7 -5
- package/src/tools/registry.ts +92 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type RegisteredTool } from '../../server.ts';
|
|
2
2
|
import type { AttachState } from './attach.ts';
|
|
3
|
-
|
|
3
|
+
/** The one browser tool that isn't session-bound: enumerate tabs so the caller
|
|
4
|
+
* can pick one to `start_capture` on. Navigate/eval/wait are the shared
|
|
5
|
+
* authoring tools (keyed by captureId — see `shared.ts`). */
|
|
6
|
+
export declare function listTabsTool(attachRef: {
|
|
4
7
|
current?: AttachState;
|
|
5
|
-
}): RegisteredTool
|
|
8
|
+
}): RegisteredTool;
|
|
@@ -1,127 +1,17 @@
|
|
|
1
1
|
import { listTabs } from "../../../cdp/tabs.js";
|
|
2
2
|
import { defineTool } from "../../server.js";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/** The one browser tool that isn't session-bound: enumerate tabs so the caller
|
|
4
|
+
* can pick one to `start_capture` on. Navigate/eval/wait are the shared
|
|
5
|
+
* authoring tools (keyed by captureId — see `shared.ts`). */
|
|
6
|
+
export function listTabsTool(attachRef) {
|
|
7
|
+
return defineTool({
|
|
8
|
+
name: 'list_tabs',
|
|
9
|
+
description: 'List open Chrome tabs.',
|
|
10
|
+
inputSchema: { type: 'object', properties: {} },
|
|
11
|
+
}, async () => {
|
|
5
12
|
if (!attachRef.current) {
|
|
6
13
|
throw new Error('Not attached. Call attach_chrome first.');
|
|
7
14
|
}
|
|
8
|
-
return attachRef.current;
|
|
9
|
-
};
|
|
10
|
-
return [
|
|
11
|
-
defineTool({
|
|
12
|
-
name: 'list_tabs',
|
|
13
|
-
description: 'List open Chrome tabs.',
|
|
14
|
-
inputSchema: { type: 'object', properties: {} },
|
|
15
|
-
}, async () => {
|
|
16
|
-
const attached = requireAttached();
|
|
17
|
-
return { tabs: await listTabs(attached.port) };
|
|
18
|
-
}),
|
|
19
|
-
defineTool({
|
|
20
|
-
name: 'eval_in_page',
|
|
21
|
-
description: 'Run a JS expression in a tab via Runtime.evaluate ' +
|
|
22
|
-
'and return the result. ' +
|
|
23
|
-
'Useful for reading visible values from the DOM.',
|
|
24
|
-
inputSchema: {
|
|
25
|
-
type: 'object',
|
|
26
|
-
properties: {
|
|
27
|
-
tabId: { type: 'string' },
|
|
28
|
-
expression: { type: 'string' },
|
|
29
|
-
},
|
|
30
|
-
required: ['tabId', 'expression'],
|
|
31
|
-
},
|
|
32
|
-
}, async ({ tabId, expression }) => {
|
|
33
|
-
const attached = requireAttached();
|
|
34
|
-
const { Runtime } = await attached.handles.attachToTab(tabId);
|
|
35
|
-
const result = await Runtime.evaluate({
|
|
36
|
-
expression,
|
|
37
|
-
returnByValue: true,
|
|
38
|
-
});
|
|
39
|
-
if (result.exceptionDetails) {
|
|
40
|
-
return { error: result.exceptionDetails.text };
|
|
41
|
-
}
|
|
42
|
-
return { value: result.result.value };
|
|
43
|
-
}),
|
|
44
|
-
defineTool({
|
|
45
|
-
name: 'navigate',
|
|
46
|
-
description: 'Navigate a tab to a URL via Page.navigate, ' +
|
|
47
|
-
'waiting for the load event. ' +
|
|
48
|
-
'Use this to drive the browser yourself ' +
|
|
49
|
-
'instead of asking the developer to navigate. ' +
|
|
50
|
-
'Returns the final URL after navigation ' +
|
|
51
|
-
'(which may differ from the requested URL due to redirects).',
|
|
52
|
-
inputSchema: {
|
|
53
|
-
type: 'object',
|
|
54
|
-
properties: {
|
|
55
|
-
tabId: { type: 'string' },
|
|
56
|
-
url: { type: 'string' },
|
|
57
|
-
timeoutMs: { type: 'number' },
|
|
58
|
-
},
|
|
59
|
-
required: ['tabId', 'url'],
|
|
60
|
-
},
|
|
61
|
-
}, async ({ tabId, url, timeoutMs }) => {
|
|
62
|
-
const attached = requireAttached();
|
|
63
|
-
const { Page, Runtime } = await attached.handles.attachToTab(tabId);
|
|
64
|
-
await Page.enable();
|
|
65
|
-
const loadPromise = new Promise((resolve) => {
|
|
66
|
-
Page.loadEventFired(() => resolve());
|
|
67
|
-
});
|
|
68
|
-
const nav = await Page.navigate({ url });
|
|
69
|
-
if (nav.errorText) {
|
|
70
|
-
return { ok: false, error: nav.errorText };
|
|
71
|
-
}
|
|
72
|
-
const t = timeoutMs ?? 30_000;
|
|
73
|
-
const raced = await Promise.race([
|
|
74
|
-
loadPromise.then(() => 'loaded'),
|
|
75
|
-
new Promise((resolve) => setTimeout(() => resolve('timeout'), t)),
|
|
76
|
-
]);
|
|
77
|
-
const final = await Runtime.evaluate({
|
|
78
|
-
expression: 'location.href',
|
|
79
|
-
returnByValue: true,
|
|
80
|
-
});
|
|
81
|
-
return {
|
|
82
|
-
ok: true,
|
|
83
|
-
loadStatus: raced,
|
|
84
|
-
finalUrl: final.result.value,
|
|
85
|
-
};
|
|
86
|
-
}),
|
|
87
|
-
defineTool({
|
|
88
|
-
name: 'wait_for_page',
|
|
89
|
-
description: 'Poll a JS expression in a tab until it ' +
|
|
90
|
-
'returns truthy (or timeout). ' +
|
|
91
|
-
'Use this for steps that require the ' +
|
|
92
|
-
'developer to do something in the browser — ' +
|
|
93
|
-
'most commonly waiting for them to finish logging in. ' +
|
|
94
|
-
'Pass an expression that ' +
|
|
95
|
-
'evaluates true once the desired state is reached, e.g. ' +
|
|
96
|
-
'`!!document.querySelector' +
|
|
97
|
-
'(\'summary[aria-label*="View profile"]\')`' +
|
|
98
|
-
' for GitHub post-login.',
|
|
99
|
-
inputSchema: {
|
|
100
|
-
type: 'object',
|
|
101
|
-
properties: {
|
|
102
|
-
tabId: { type: 'string' },
|
|
103
|
-
expression: { type: 'string' },
|
|
104
|
-
timeoutMs: { type: 'number' },
|
|
105
|
-
pollMs: { type: 'number' },
|
|
106
|
-
},
|
|
107
|
-
required: ['tabId', 'expression'],
|
|
108
|
-
},
|
|
109
|
-
}, async ({ tabId, expression, timeoutMs, pollMs }) => {
|
|
110
|
-
const attached = requireAttached();
|
|
111
|
-
const { Runtime } = await attached.handles.attachToTab(tabId);
|
|
112
|
-
const deadline = Date.now() + (timeoutMs ?? 120_000);
|
|
113
|
-
const interval = pollMs ?? 1000;
|
|
114
|
-
while (Date.now() < deadline) {
|
|
115
|
-
const r = await Runtime.evaluate({ expression, returnByValue: true });
|
|
116
|
-
if (r.exceptionDetails) {
|
|
117
|
-
return { matched: false, error: r.exceptionDetails.text };
|
|
118
|
-
}
|
|
119
|
-
if (r.result.value) {
|
|
120
|
-
return { matched: true, value: r.result.value };
|
|
121
|
-
}
|
|
122
|
-
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
123
|
-
}
|
|
124
|
-
return { matched: false, reason: 'timeout' };
|
|
125
|
-
}),
|
|
126
|
-
];
|
|
15
|
+
return { tabs: await listTabs(attachRef.current.port) };
|
|
16
|
+
});
|
|
127
17
|
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `find_requests_containing` — search captured responses for any encoding of a
|
|
3
|
+
* value and rank the requests that return it. Authored once as a plain
|
|
4
|
+
* {@link RegisteredTool}; the MCP and cloud loop each pass their own backend
|
|
5
|
+
* resolver (see authoring/tools.ts / shared.ts). Server-side: response bodies
|
|
6
|
+
* stay here, only metadata + a short snippet leave.
|
|
7
|
+
*/
|
|
8
|
+
import { type ResolveBackend } from '../../../authoring/util.ts';
|
|
9
|
+
import { type RegisteredTool } from '../../../tools/registry.ts';
|
|
10
|
+
export declare function findTool(resolveBackend: ResolveBackend): RegisteredTool;
|
|
@@ -1,29 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `find_requests_containing` — search captured responses for any encoding of a
|
|
3
|
+
* value and rank the requests that return it. Authored once as a plain
|
|
4
|
+
* {@link RegisteredTool}; the MCP and cloud loop each pass their own backend
|
|
5
|
+
* resolver (see authoring/tools.ts / shared.ts). Server-side: response bodies
|
|
6
|
+
* stay here, only metadata + a short snippet leave.
|
|
7
|
+
*/
|
|
8
|
+
import { objectSchema, publicRequest, } from "../../../authoring/util.js";
|
|
1
9
|
import { normalizeCandidates } from "../../../provider/normalize.js";
|
|
2
|
-
import { defineTool } from "
|
|
3
|
-
export function findTool(
|
|
10
|
+
import { defineTool } from "../../../tools/registry.js";
|
|
11
|
+
export function findTool(resolveBackend) {
|
|
4
12
|
return defineTool({
|
|
5
13
|
name: 'find_requests_containing',
|
|
6
|
-
description: 'Search captured responses for any encoding of `value
|
|
7
|
-
'Returns a ranked candidate list '
|
|
8
|
-
'
|
|
9
|
-
'Server-side; bodies stay here.',
|
|
10
|
-
inputSchema: {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
value: { type: 'string' },
|
|
15
|
-
limit: { type: 'number' },
|
|
16
|
-
},
|
|
17
|
-
required: ['captureId', 'value'],
|
|
18
|
-
},
|
|
19
|
-
}, async ({ captureId, value, limit }) => {
|
|
20
|
-
const session = captures.sessions.get(captureId);
|
|
21
|
-
if (!session) {
|
|
22
|
-
throw new Error(`no capture ${captureId}`);
|
|
23
|
-
}
|
|
24
|
-
const variants = normalizeCandidates(value);
|
|
14
|
+
description: 'Search captured responses for any encoding of `value` (raw, '
|
|
15
|
+
+ 'URL/JSON/HTML-escaped, …). Returns a ranked candidate list with '
|
|
16
|
+
+ 'the matched variant, score, and a short snippet — used to locate '
|
|
17
|
+
+ 'the request that returns a target. Server-side; bodies stay here.',
|
|
18
|
+
inputSchema: objectSchema({ value: { type: 'string' }, limit: { type: 'number' } }, ['value']),
|
|
19
|
+
}, async (args) => {
|
|
20
|
+
const backend = resolveBackend(args);
|
|
21
|
+
const variants = normalizeCandidates(String(args.value));
|
|
25
22
|
const ranked = [];
|
|
26
|
-
for (const r of
|
|
23
|
+
for (const r of backend.capture.requests.values()) {
|
|
27
24
|
if (!r.responseBody) {
|
|
28
25
|
continue;
|
|
29
26
|
}
|
|
@@ -40,21 +37,18 @@ export function findTool(captures) {
|
|
|
40
37
|
if (!hit) {
|
|
41
38
|
continue;
|
|
42
39
|
}
|
|
43
|
-
//
|
|
44
|
-
const score = (r.contentType.includes('json') ? 10 : 0)
|
|
45
|
-
Math.max(0, 5 - Math.log10(Math.max(r.size, 1)));
|
|
40
|
+
// Prefer JSON responses + smaller bodies (likely API endpoints).
|
|
41
|
+
const score = (r.contentType.includes('json') ? 10 : 0)
|
|
42
|
+
+ Math.max(0, 5 - Math.log10(Math.max(r.size, 1)));
|
|
46
43
|
ranked.push({
|
|
47
|
-
|
|
48
|
-
url: r.url,
|
|
49
|
-
method: r.method,
|
|
50
|
-
status: r.status,
|
|
51
|
-
contentType: r.contentType,
|
|
44
|
+
...publicRequest(r),
|
|
52
45
|
matchedVariant: hit.variant,
|
|
53
46
|
snippet: hit.snippet,
|
|
54
47
|
score,
|
|
55
48
|
});
|
|
56
49
|
}
|
|
57
50
|
ranked.sort((a, b) => b.score - a.score);
|
|
58
|
-
|
|
51
|
+
const limit = Number(args.limit) || 10;
|
|
52
|
+
return { candidates: ranked.slice(0, limit) };
|
|
59
53
|
});
|
|
60
54
|
}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { type ProofResult } from '../../../proof/attestor.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The MCP's rich `run_proof` view: persist the full claim to disk, return
|
|
4
|
+
* identifier + extractedParameters + a prettified claim (request dropped, byte
|
|
5
|
+
* arrays as base64) + trimmed logs, and — under `RECLAIM_AGENT_TRACE=1` — a
|
|
6
|
+
* forensic run dump. This is the developer-facing shape; the cloud backend
|
|
7
|
+
* projects the same {@link ProofResult} to a lean summary instead.
|
|
8
|
+
*/
|
|
9
|
+
export declare function shapeRichProofResult(result: ProofResult, opts: {
|
|
10
|
+
provider: unknown;
|
|
11
|
+
hasSecrets: boolean;
|
|
12
|
+
attestorUrl?: string;
|
|
13
|
+
}): Record<string, unknown>;
|
|
@@ -2,8 +2,7 @@ import { mkdirSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { agentTraceEnabled } from "../../../consts.js";
|
|
4
4
|
import { reclaimHomeDirPath } from "../../../paths.js";
|
|
5
|
-
import {
|
|
6
|
-
import { defineTool } from "../../server.js";
|
|
5
|
+
import { tailLogs, warnsAndErrors, } from "../../../proof/attestor.js";
|
|
7
6
|
function claimsDir() {
|
|
8
7
|
return join(reclaimHomeDirPath(), 'claims');
|
|
9
8
|
}
|
|
@@ -73,138 +72,88 @@ function isLikelyByteArray(v) {
|
|
|
73
72
|
}
|
|
74
73
|
return true;
|
|
75
74
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
'sentParams the SDK saw post-substitution, ' +
|
|
92
|
-
'FULL attestor log stream, result) to ' +
|
|
93
|
-
'~/.reclaim/proof-runs/<timestamp>.json and ' +
|
|
94
|
-
'returns the path as `runLogPath`. ' +
|
|
95
|
-
'`attestorUrl` overrides the default attestor URL only when the dev ' +
|
|
96
|
-
'supplies a specific ' +
|
|
97
|
-
'alternative — do NOT invent backup URLs ' +
|
|
98
|
-
'(there is one live public attestor right now; ' +
|
|
99
|
-
'surface real errors to the dev instead of guessing). ' +
|
|
100
|
-
'`ownerAddress` (the credential to sign with) is REQUIRED — ' +
|
|
101
|
-
'call resolve_owner_key first to obtain it, then pass it here. ' +
|
|
102
|
-
'errorKind="missing-owner-key" means that address has no known ' +
|
|
103
|
-
'private key; re-run resolve_owner_key or issue/import a credential.',
|
|
104
|
-
inputSchema: {
|
|
105
|
-
type: 'object',
|
|
106
|
-
properties: {
|
|
107
|
-
provider: { type: 'object', properties: {} },
|
|
108
|
-
secretParamsRef: { type: 'string' },
|
|
109
|
-
attestorUrl: { type: 'string' },
|
|
110
|
-
ownerAddress: {
|
|
111
|
-
type: 'string',
|
|
112
|
-
pattern: '^0x[0-9a-fA-F]{40}$',
|
|
113
|
-
description: 'ETH address of the credential to sign the claim with. ' +
|
|
114
|
-
'Get it from resolve_owner_key first. The private key is ' +
|
|
115
|
-
'resolved locally (cache / env / .env) — never passed here.',
|
|
116
|
-
},
|
|
117
|
-
},
|
|
118
|
-
required: ['provider', 'ownerAddress'],
|
|
119
|
-
},
|
|
120
|
-
}, async ({ provider, secretParamsRef, attestorUrl, ownerAddress }) => {
|
|
121
|
-
let resolved = {};
|
|
122
|
-
if (secretParamsRef !== undefined) {
|
|
123
|
-
const r = secrets.resolve(secretParamsRef);
|
|
124
|
-
if (!r) {
|
|
125
|
-
throw new Error(`unknown secretParamsRef "${secretParamsRef}" — ` +
|
|
126
|
-
'the MCP server has restarted or reset_session was called. ' +
|
|
127
|
-
'Re-run propose_provider to mint a fresh ref.');
|
|
128
|
-
}
|
|
129
|
-
resolved = r;
|
|
130
|
-
}
|
|
131
|
-
const result = await runAttestorProof(provider, resolved, { attestorUrl, ownerAddress });
|
|
132
|
-
// Persist the full claim to disk for the dev to inspect/share.
|
|
133
|
-
let claimPath;
|
|
134
|
-
if (result.proof !== undefined && result.proof !== null) {
|
|
135
|
-
try {
|
|
136
|
-
mkdirSync(claimsDir(), { recursive: true });
|
|
137
|
-
claimPath = join(claimsDir(), `${Date.now()}.json`);
|
|
138
|
-
writeFileSync(claimPath, JSON.stringify(result.proof, null, 2), 'utf8');
|
|
139
|
-
}
|
|
140
|
-
catch {
|
|
141
|
-
// Persistence is best-effort; don't fail the proof for it.
|
|
142
|
-
claimPath = undefined;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
const out = {
|
|
146
|
-
verified: result.verified,
|
|
147
|
-
extractedValue: result.extractedValue,
|
|
148
|
-
extractedParameters: result.extractedParameters,
|
|
149
|
-
};
|
|
150
|
-
if (result.identifier !== undefined) {
|
|
151
|
-
out.identifier = result.identifier;
|
|
152
|
-
}
|
|
153
|
-
if (result.owner !== undefined) {
|
|
154
|
-
out.owner = result.owner;
|
|
155
|
-
}
|
|
156
|
-
if (claimPath !== undefined) {
|
|
157
|
-
out.claimPath = claimPath;
|
|
158
|
-
}
|
|
159
|
-
if (result.proof !== undefined && result.proof !== null) {
|
|
160
|
-
out.claim = prettifyClaim(result.proof);
|
|
161
|
-
}
|
|
162
|
-
if (result.error !== undefined) {
|
|
163
|
-
out.error = result.error;
|
|
164
|
-
}
|
|
165
|
-
if (result.errorKind !== undefined) {
|
|
166
|
-
out.errorKind = result.errorKind;
|
|
75
|
+
/**
|
|
76
|
+
* The MCP's rich `run_proof` view: persist the full claim to disk, return
|
|
77
|
+
* identifier + extractedParameters + a prettified claim (request dropped, byte
|
|
78
|
+
* arrays as base64) + trimmed logs, and — under `RECLAIM_AGENT_TRACE=1` — a
|
|
79
|
+
* forensic run dump. This is the developer-facing shape; the cloud backend
|
|
80
|
+
* projects the same {@link ProofResult} to a lean summary instead.
|
|
81
|
+
*/
|
|
82
|
+
export function shapeRichProofResult(result, opts) {
|
|
83
|
+
// Persist the full claim to disk for the dev to inspect/share.
|
|
84
|
+
let claimPath;
|
|
85
|
+
if (result.proof !== undefined && result.proof !== null) {
|
|
86
|
+
try {
|
|
87
|
+
mkdirSync(claimsDir(), { recursive: true });
|
|
88
|
+
claimPath = join(claimsDir(), `${Date.now()}.json`);
|
|
89
|
+
writeFileSync(claimPath, JSON.stringify(result.proof, null, 2), 'utf8');
|
|
167
90
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
? warnsAndErrors(result.attestorLogs)
|
|
172
|
-
: tailLogs(result.attestorLogs);
|
|
173
|
-
if (out.attestorLogs.length === 0) {
|
|
174
|
-
delete out.attestorLogs;
|
|
175
|
-
}
|
|
91
|
+
catch {
|
|
92
|
+
// Persistence is best-effort; don't fail the proof for it.
|
|
93
|
+
claimPath = undefined;
|
|
176
94
|
}
|
|
177
|
-
|
|
178
|
-
|
|
95
|
+
}
|
|
96
|
+
const out = {
|
|
97
|
+
verified: result.verified,
|
|
98
|
+
extractedValue: result.extractedValue,
|
|
99
|
+
extractedParameters: result.extractedParameters,
|
|
100
|
+
};
|
|
101
|
+
if (result.identifier !== undefined) {
|
|
102
|
+
out.identifier = result.identifier;
|
|
103
|
+
}
|
|
104
|
+
if (result.owner !== undefined) {
|
|
105
|
+
out.owner = result.owner;
|
|
106
|
+
}
|
|
107
|
+
if (claimPath !== undefined) {
|
|
108
|
+
out.claimPath = claimPath;
|
|
109
|
+
}
|
|
110
|
+
if (result.proof !== undefined && result.proof !== null) {
|
|
111
|
+
out.claim = prettifyClaim(result.proof);
|
|
112
|
+
}
|
|
113
|
+
if (result.error !== undefined) {
|
|
114
|
+
out.error = result.error;
|
|
115
|
+
}
|
|
116
|
+
if (result.errorKind !== undefined) {
|
|
117
|
+
out.errorKind = result.errorKind;
|
|
118
|
+
}
|
|
119
|
+
// Trim the LLM-visible logs — full stream goes to runLogPath.
|
|
120
|
+
if (result.attestorLogs !== undefined && result.attestorLogs.length > 0) {
|
|
121
|
+
out.attestorLogs = result.verified
|
|
122
|
+
? warnsAndErrors(result.attestorLogs)
|
|
123
|
+
: tailLogs(result.attestorLogs);
|
|
124
|
+
if (out.attestorLogs.length === 0) {
|
|
125
|
+
delete out.attestorLogs;
|
|
179
126
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
127
|
+
}
|
|
128
|
+
if (result.sentParams !== undefined) {
|
|
129
|
+
out.sentParams = result.sentParams;
|
|
130
|
+
}
|
|
131
|
+
// Persist a diagnostic dump for forensics — gated behind
|
|
132
|
+
// RECLAIM_AGENT_TRACE=1 (matches the attestor logger capture). Off by
|
|
133
|
+
// default since happy-path runs don't need it; turn on when investigating
|
|
134
|
+
// proof failures and the file at runLogPath will carry the input provider,
|
|
135
|
+
// sentParams, full attestor log stream, and result.
|
|
136
|
+
if (agentTraceEnabled()) {
|
|
137
|
+
const runLogPath = writeProofRunDump({
|
|
138
|
+
provider: opts.provider,
|
|
139
|
+
hasSecretParamsRef: opts.hasSecrets,
|
|
140
|
+
attestorUrl: opts.attestorUrl,
|
|
141
|
+
result: {
|
|
142
|
+
verified: result.verified,
|
|
143
|
+
error: result.error,
|
|
144
|
+
errorKind: result.errorKind,
|
|
145
|
+
extractedValue: result.extractedValue,
|
|
146
|
+
extractedParameters: result.extractedParameters,
|
|
147
|
+
identifier: result.identifier,
|
|
148
|
+
owner: result.owner,
|
|
149
|
+
sentParams: result.sentParams,
|
|
150
|
+
attestorLogs: result.attestorLogs,
|
|
151
|
+
claimPath,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
if (runLogPath !== undefined) {
|
|
155
|
+
out.runLogPath = runLogPath;
|
|
207
156
|
}
|
|
208
|
-
|
|
209
|
-
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
210
159
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `propose_provider` — draft a provider (recipe + captured secrets) from ONE
|
|
3
|
+
* captured request, one match + redaction per target value. Authored once as a
|
|
4
|
+
* plain {@link RegisteredTool}; hosts pass their own backend resolver. The
|
|
5
|
+
* draft (recipe + real secret header values) is held server-side under an
|
|
6
|
+
* opaque `draftId`; the result carries only the secret-free provider.
|
|
7
|
+
*/
|
|
8
|
+
import { type ResolveBackend } from '../../../authoring/util.ts';
|
|
9
|
+
import { type RegisteredTool } from '../../../tools/registry.ts';
|
|
10
|
+
export declare function proposeTool(resolveBackend: ResolveBackend): RegisteredTool;
|