@reclaimprotocol/agent 0.1.36 → 0.1.38
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 +8 -8
- package/lib/authoring/backend.d.ts +12 -1
- package/lib/authoring/backend.js +3 -0
- package/lib/authoring/tools.js +33 -5
- package/lib/authoring/util.d.ts +43 -0
- package/lib/authoring/util.js +54 -0
- package/lib/cdp/chrome-for-testing.d.ts +14 -0
- package/lib/cdp/chrome-for-testing.js +43 -0
- package/lib/cdp/geo.d.ts +3 -0
- package/lib/cdp/geo.js +27 -15
- package/lib/cdp/launcher.d.ts +79 -1
- package/lib/cdp/launcher.js +244 -24
- package/lib/logger.js +3 -1
- package/lib/mcp/instructions.js +3 -3
- package/lib/mcp/start.js +17 -2
- package/lib/mcp/tools/agent/attach.d.ts +6 -0
- package/lib/mcp/tools/agent/attach.js +58 -118
- package/lib/mcp/tools/agent/build.js +8 -0
- package/lib/mcp/tools/agent/capture.js +33 -10
- package/lib/mcp/tools/agent/check-attestor.js +15 -7
- package/lib/mcp/tools/agent/draft-tools.d.ts +3 -0
- package/lib/mcp/tools/agent/draft-tools.js +170 -0
- package/lib/mcp/tools/agent/example-app.d.ts +2 -0
- package/lib/mcp/tools/agent/example-app.js +167 -0
- package/lib/mcp/tools/agent/pod-proof.js +5 -1
- package/lib/mcp/tools/agent/proof.d.ts +28 -0
- package/lib/mcp/tools/agent/proof.js +72 -0
- package/lib/mcp/tools/agent/shared.d.ts +8 -1
- package/lib/mcp/tools/agent/shared.js +98 -19
- package/lib/mcp/tools/agent/start-integration.d.ts +2 -1
- package/lib/mcp/tools/agent/start-integration.js +10 -6
- package/lib/mcp/tools/authenticate/authenticate.d.ts +48 -10
- package/lib/mcp/tools/authenticate/authenticate.js +212 -116
- package/lib/mcp/tools/authenticate/build.d.ts +2 -2
- package/lib/mcp/tools/authenticate/build.js +6 -3
- package/lib/mcp/tools/authenticate/builder-access.js +5 -2
- package/lib/mcp/tools/authenticate/eth-key.d.ts +13 -2
- package/lib/mcp/tools/authenticate/eth-key.js +29 -5
- package/lib/mcp/tools/authenticate/index.d.ts +1 -1
- package/lib/mcp/tools/authenticate/index.js +1 -1
- package/lib/mcp/tools/authenticate/issue-org-keypair.d.ts +10 -0
- package/lib/mcp/tools/authenticate/issue-org-keypair.js +82 -0
- package/lib/mcp/tools/authenticate/oauth-config.d.ts +31 -0
- package/lib/mcp/tools/authenticate/oauth-config.js +67 -0
- package/lib/mcp/tools/authenticate/resolve-owner-key.d.ts +4 -5
- package/lib/mcp/tools/authenticate/resolve-owner-key.js +40 -36
- package/lib/mcp/tools/authenticate/session-cache.d.ts +25 -1
- package/lib/mcp/tools/authenticate/session-cache.js +95 -4
- package/lib/mcp/tools/mode/mode.js +6 -6
- package/lib/old/login-cdp.js +2 -3
- package/lib/proof/attestor.js +2 -3
- package/lib/proof/check-attestor.d.ts +12 -2
- package/lib/proof/check-attestor.js +40 -10
- package/lib/proof/check-matchers.d.ts +36 -0
- package/lib/proof/check-matchers.js +161 -0
- package/lib/proof/zk-files.d.ts +50 -11
- package/lib/proof/zk-files.js +259 -63
- package/lib/provider/draft.d.ts +24 -1
- package/lib/provider/draft.js +135 -0
- package/lib/provider/matcher.js +171 -4
- package/package.json +6 -4
- package/skill/SKILL.builder.md +7 -2
- package/skill/SKILL.common.md +90 -70
- package/skill/SKILL.old.md +3 -3
- package/skill/builder-mode.md +35 -5
- package/skill/old-mode.md +18 -13
- package/skill/start-integration.md +50 -33
- package/skill/verification-client-integration.md +21 -6
- package/src/authoring/backend.ts +12 -1
- package/src/authoring/tools.ts +48 -7
- package/src/authoring/util.ts +64 -0
- package/src/cdp/chrome-for-testing.ts +66 -0
- package/src/cdp/geo.ts +36 -21
- package/src/cdp/launcher.ts +328 -24
- package/src/logger.ts +3 -1
- package/src/mcp/instructions.ts +3 -3
- package/src/mcp/start.ts +20 -1
- package/src/mcp/tools/agent/attach.ts +65 -128
- package/src/mcp/tools/agent/build.ts +9 -0
- package/src/mcp/tools/agent/capture.ts +54 -11
- package/src/mcp/tools/agent/check-attestor.ts +15 -7
- package/src/mcp/tools/agent/draft-tools.ts +234 -0
- package/src/mcp/tools/agent/example-app.ts +227 -0
- package/src/mcp/tools/agent/pod-proof.ts +5 -1
- package/src/mcp/tools/agent/proof.ts +110 -1
- package/src/mcp/tools/agent/shared.ts +130 -19
- package/src/mcp/tools/agent/start-integration.ts +10 -6
- package/src/mcp/tools/authenticate/authenticate.ts +276 -131
- package/src/mcp/tools/authenticate/build.ts +6 -3
- package/src/mcp/tools/authenticate/builder-access.ts +5 -2
- package/src/mcp/tools/authenticate/eth-key.ts +41 -7
- package/src/mcp/tools/authenticate/index.ts +1 -1
- package/src/mcp/tools/authenticate/issue-org-keypair.ts +106 -0
- package/src/mcp/tools/authenticate/oauth-config.ts +85 -0
- package/src/mcp/tools/authenticate/resolve-owner-key.ts +42 -39
- package/src/mcp/tools/authenticate/session-cache.ts +125 -5
- package/src/mcp/tools/mode/mode.ts +6 -6
- package/src/old/login-cdp.ts +2 -3
- package/src/proof/attestor.ts +2 -3
- package/src/proof/check-attestor.ts +55 -12
- package/src/proof/check-matchers.ts +227 -0
- package/src/proof/zk-files.ts +357 -65
- package/src/provider/draft.ts +215 -7
- package/src/provider/matcher.ts +237 -4
|
@@ -14,11 +14,11 @@ import {
|
|
|
14
14
|
import { suggestCountryFromIp } from '../../../cdp/geo.ts'
|
|
15
15
|
import {
|
|
16
16
|
defaultProfileDir,
|
|
17
|
-
|
|
17
|
+
launchLocalBrowser,
|
|
18
|
+
type LocalBrowser,
|
|
18
19
|
waitForCdpReady,
|
|
19
20
|
} from '../../../cdp/launcher.ts'
|
|
20
21
|
import type { ConfigStore } from '../../../config/store.ts'
|
|
21
|
-
import { defaultConfigPath } from '../../../config/store.ts'
|
|
22
22
|
import { defineTool, type RegisteredTool } from '../../server.ts'
|
|
23
23
|
import { ensureLiveViewUrl } from './live-view-url.ts'
|
|
24
24
|
|
|
@@ -60,6 +60,8 @@ export interface AttachState {
|
|
|
60
60
|
viewerPort?: number
|
|
61
61
|
/** Whether the runtime image had to be downloaded on this attach. */
|
|
62
62
|
imagePulled?: boolean
|
|
63
|
+
/** `dedicated` mode: the browser this attach launched, if it launched one. */
|
|
64
|
+
launched?: Omit<LocalBrowser, 'process'>
|
|
63
65
|
disposeRemote?: () => Promise<void>
|
|
64
66
|
}
|
|
65
67
|
|
|
@@ -85,94 +87,15 @@ interface AttachArgs {
|
|
|
85
87
|
viewerPort?: number
|
|
86
88
|
}
|
|
87
89
|
|
|
88
|
-
/** Browser sources returned when the caller omits `mode`. Keep selection detail
|
|
89
|
-
* here instead of repeating it in the always-loaded tool description. */
|
|
90
|
-
const BROWSER_OPTIONS = [
|
|
91
|
-
{
|
|
92
|
-
mode: 'dedicated',
|
|
93
|
-
useCase: 'Working on your own machine',
|
|
94
|
-
label: 'Local Chrome, launched for you',
|
|
95
|
-
detail:
|
|
96
|
-
'Launches Chrome with a dedicated profile under '
|
|
97
|
-
+ '~/.reclaim/chrome-profile. Nothing to set up, and the profile '
|
|
98
|
-
+ 'persists, so a site you sign in to stays signed in. The easiest '
|
|
99
|
-
+ 'choice when you are doing the work yourself.',
|
|
100
|
-
requires: [],
|
|
101
|
-
liveView: 'None, and none needed — the browser is on your screen.',
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
mode: 'attach',
|
|
105
|
-
useCase: 'Working on your own machine',
|
|
106
|
-
label: 'The Chrome you already have open',
|
|
107
|
-
detail:
|
|
108
|
-
'Connects to a Chrome you started yourself, keeping the tabs, '
|
|
109
|
-
+ 'extensions and logins already in it. That Chrome must have been '
|
|
110
|
-
+ 'started with BOTH --remote-debugging-port AND a non-default '
|
|
111
|
-
+ '--user-data-dir: since Chrome 136 the debug flag is silently '
|
|
112
|
-
+ 'ignored on the default profile.',
|
|
113
|
-
requires: ['port (default 9222)'],
|
|
114
|
-
liveView: 'None, and none needed — the browser is on your screen.',
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
mode: 'container',
|
|
118
|
-
useCase: 'Someone else has to sign in, or you need a phone',
|
|
119
|
-
label: 'Reclaim runtime in Docker — free, runs on your machine',
|
|
120
|
-
detail:
|
|
121
|
-
'Runs the Reclaim browser runtime (the same image the remote browser '
|
|
122
|
-
+ 'uses) as a container on this machine, and gives you a link you can '
|
|
123
|
-
+ 'send to whoever holds the account. They open it in any browser, '
|
|
124
|
-
+ 'including a phone, and can see and click in it. Free — it is your '
|
|
125
|
-
+ 'Docker and your bandwidth. Costs a 432 MB first-run download and '
|
|
126
|
-
+ 'about 2 GB of RAM. The image is amd64, so Apple Silicon runs it '
|
|
127
|
-
+ 'translated. OrbStack handles that itself; Docker Desktop needs '
|
|
128
|
-
+ 'Rosetta enabled.',
|
|
129
|
-
requires: ['Docker running'],
|
|
130
|
-
liveView:
|
|
131
|
-
'Built in. This call returns a local `viewerUrl`, and '
|
|
132
|
-
+ 'share_browser_view turns that into a public link for the person '
|
|
133
|
-
+ 'helping you.',
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
mode: 'builder',
|
|
137
|
-
useCase: 'Someone else has to sign in, or you need a phone',
|
|
138
|
-
label: 'Remote browser, hosted by Reclaim — CHARGEABLE',
|
|
139
|
-
detail:
|
|
140
|
-
'A browser allocated in Reclaim\'s cloud, billed against the '
|
|
141
|
-
+ 'organization\'s quota. Nothing to install, and the shareable link '
|
|
142
|
-
+ 'comes back immediately. It is also the only way to browse a site '
|
|
143
|
-
+ 'from a SPECIFIC COUNTRY — its whole egress is routed there. '
|
|
144
|
-
+ 'Geolocation is optional: omit countryCode to be offered a '
|
|
145
|
-
+ 'suggestion, or pass skipCountry to allocate without geo-routing.',
|
|
146
|
-
requires: [
|
|
147
|
-
'Builder authentication',
|
|
148
|
-
'orgId (auto-resolved when you have only one)',
|
|
149
|
-
'quota — this one costs money',
|
|
150
|
-
],
|
|
151
|
-
liveView:
|
|
152
|
-
'Included. This call returns a hosted liveViewUrl to pass on; '
|
|
153
|
-
+ 'share_browser_view does not apply.',
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
mode: 'custom',
|
|
157
|
-
useCase: 'Advanced',
|
|
158
|
-
label: 'A CDP endpoint you supply',
|
|
159
|
-
detail:
|
|
160
|
-
'Connects to any ws:// or wss:// CDP websocket — a browser you run '
|
|
161
|
-
+ 'elsewhere, or another tool\'s. The URL is treated as a credential: '
|
|
162
|
-
+ 'never logged, persisted, or returned. Only pick this if you were '
|
|
163
|
-
+ 'given an endpoint and know why.',
|
|
164
|
-
requires: ['cdpUrl'],
|
|
165
|
-
liveView:
|
|
166
|
-
'None, unless you pass your own liveViewUrl alongside the cdpUrl.',
|
|
167
|
-
},
|
|
168
|
-
] as const
|
|
169
|
-
|
|
170
90
|
interface AttachDependencies {
|
|
171
91
|
connectLocal: typeof connectCdp
|
|
172
92
|
connectRemote: typeof connectCdpUrl
|
|
173
93
|
/** Injected so container mode is testable without Docker installed. */
|
|
174
94
|
dockerAvailable: typeof dockerAvailable
|
|
175
95
|
startContainer: typeof startContainer
|
|
96
|
+
/** Injected so the default launch is testable without a real browser. */
|
|
97
|
+
launchLocal: typeof launchLocalBrowser
|
|
98
|
+
waitForCdp: typeof waitForCdpReady
|
|
176
99
|
}
|
|
177
100
|
|
|
178
101
|
const DEFAULT_DEPENDENCIES: AttachDependencies = {
|
|
@@ -180,6 +103,8 @@ const DEFAULT_DEPENDENCIES: AttachDependencies = {
|
|
|
180
103
|
connectRemote: connectCdpUrl,
|
|
181
104
|
dockerAvailable,
|
|
182
105
|
startContainer,
|
|
106
|
+
launchLocal: launchLocalBrowser,
|
|
107
|
+
waitForCdp: waitForCdpReady,
|
|
183
108
|
}
|
|
184
109
|
|
|
185
110
|
export function attachTool(
|
|
@@ -197,16 +122,15 @@ export function attachTool(
|
|
|
197
122
|
{
|
|
198
123
|
name: 'attach_browser',
|
|
199
124
|
description:
|
|
200
|
-
'
|
|
201
|
-
+ '
|
|
202
|
-
+ '
|
|
203
|
-
+ '
|
|
204
|
-
+ '
|
|
205
|
-
+ '
|
|
206
|
-
+ '
|
|
207
|
-
+ '`builder`
|
|
208
|
-
+ '
|
|
209
|
-
+ 'selection, geolocation, and lifecycle.',
|
|
125
|
+
'Opens a visible browser on the developer\'s own machine for '
|
|
126
|
+
+ 'sign-in and capture. Call it with no arguments and do not ask '
|
|
127
|
+
+ 'which browser to use: it launches installed Chrome (else '
|
|
128
|
+
+ 'Chromium, Edge, or a one-time Chrome for Testing download) with '
|
|
129
|
+
+ 'the persistent Reclaim profile. Pass `mode` only when the '
|
|
130
|
+
+ 'developer explicitly asks for that mode: `attach` (their running '
|
|
131
|
+
+ 'Chrome on `port`), `container` (Docker), `custom` (`cdpUrl`), or '
|
|
132
|
+
+ '`builder` (billed). Never offer or pick those yourself. See '
|
|
133
|
+
+ 'how_it_works({ topic: "browser" }).',
|
|
210
134
|
inputSchema: {
|
|
211
135
|
type: 'object',
|
|
212
136
|
properties: {
|
|
@@ -215,6 +139,9 @@ export function attachTool(
|
|
|
215
139
|
enum: [
|
|
216
140
|
'dedicated', 'attach', 'container', 'builder', 'custom',
|
|
217
141
|
],
|
|
142
|
+
description:
|
|
143
|
+
'Omit for the default local browser (`dedicated`). Set '
|
|
144
|
+
+ 'only to a mode the developer explicitly asked for.',
|
|
218
145
|
},
|
|
219
146
|
attachMode: {
|
|
220
147
|
type: 'string',
|
|
@@ -256,32 +183,12 @@ export function attachTool(
|
|
|
256
183
|
},
|
|
257
184
|
async(parsed) => {
|
|
258
185
|
const persisted = state.config.read()?.browser_agent
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
// quota,
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
const mode = parsed.mode ?? parsed.attachMode
|
|
266
|
-
if(!mode) {
|
|
267
|
-
return {
|
|
268
|
-
needsChoice: true,
|
|
269
|
-
message:
|
|
270
|
-
'Ask FIRST whether they will be doing this themselves or '
|
|
271
|
-
+ 'someone else has to sign in — that answer decides half the '
|
|
272
|
-
+ 'list. Themselves: `dedicated` or `attach`. Someone else, or '
|
|
273
|
-
+ 'a phone-only site: `container` (free, needs Docker) or '
|
|
274
|
-
+ '`builder` (no install, chargeable) — the only two that give '
|
|
275
|
-
+ 'you a link to send. Then present the matching options and '
|
|
276
|
-
+ 'call attach_browser again with the `mode` they pick. Do not '
|
|
277
|
-
+ 'pick one for them.',
|
|
278
|
-
options: BROWSER_OPTIONS,
|
|
279
|
-
...(persisted?.attachMode
|
|
280
|
-
? { previouslyUsed: persisted.attachMode }
|
|
281
|
-
: {}),
|
|
282
|
-
configPath: defaultConfigPath(),
|
|
283
|
-
}
|
|
284
|
-
}
|
|
186
|
+
// The default is a visible browser on the developer's own machine,
|
|
187
|
+
// with no question first. Every other mode costs something (Docker,
|
|
188
|
+
// quota, the developer's own profile) and is used only when the
|
|
189
|
+
// developer asked for it by name, so a persisted choice is never
|
|
190
|
+
// reapplied either.
|
|
191
|
+
const mode = parsed.mode ?? parsed.attachMode ?? 'dedicated'
|
|
285
192
|
|
|
286
193
|
let orgId = parsed.orgId
|
|
287
194
|
if(mode === 'builder' && !orgId) {
|
|
@@ -397,7 +304,17 @@ export function attachTool(
|
|
|
397
304
|
...(next.countryCode ? { countryCode: next.countryCode } : {}),
|
|
398
305
|
...(next.containerName ? { containerName: next.containerName } : {}),
|
|
399
306
|
...(canShare ? { liveViewAvailable: true } : {}),
|
|
307
|
+
...(next.launched ? { browser: next.launched.source } : {}),
|
|
400
308
|
_notes: [
|
|
309
|
+
...(next.launched?.source === 'chrome-for-testing'
|
|
310
|
+
? ['Launched Chrome for Testing'
|
|
311
|
+
+ (next.launched.downloaded
|
|
312
|
+
? ', downloaded just now into ~/.reclaim/browsers (later '
|
|
313
|
+
+ 'launches reuse it)'
|
|
314
|
+
: ' from ~/.reclaim/browsers')
|
|
315
|
+
+ `, because: ${next.launched.fallbackReason}. Mention `
|
|
316
|
+
+ 'this to the developer in one line.']
|
|
317
|
+
: []),
|
|
401
318
|
...(next.imagePulled
|
|
402
319
|
? ['The browser runtime image was downloaded just now (about '
|
|
403
320
|
+ '432 MB, about 1.3 GB on disk). Mention it — later attaches '
|
|
@@ -421,9 +338,12 @@ export function attachTool(
|
|
|
421
338
|
: []),
|
|
422
339
|
...(!localView && !hostedView
|
|
423
340
|
? ['This browser has no live view: it runs on the developer\'s '
|
|
424
|
-
+ 'own machine, so they watch it by looking at it.
|
|
425
|
-
+ '
|
|
426
|
-
+ '
|
|
341
|
+
+ 'own machine, so they watch it by looking at it. Do not '
|
|
342
|
+
+ 'offer other modes. Tell the developer once, as a side '
|
|
343
|
+
+ 'note, that if a volunteer is helping them sign in, a '
|
|
344
|
+
+ 'shareable link can be set up (`container` mode and '
|
|
345
|
+
+ 'share_browser_view); do not ask or set it up unless they '
|
|
346
|
+
+ 'ask.']
|
|
427
347
|
: []),
|
|
428
348
|
],
|
|
429
349
|
}
|
|
@@ -532,15 +452,27 @@ async function connect(
|
|
|
532
452
|
}
|
|
533
453
|
|
|
534
454
|
const port = parsed.port ?? persisted?.port ?? 9222
|
|
455
|
+
let launched: AttachState['launched']
|
|
535
456
|
if(mode === 'dedicated') {
|
|
536
457
|
try {
|
|
537
|
-
|
|
458
|
+
// Reuse the browser an earlier attach launched on this port.
|
|
459
|
+
await dependencies.waitForCdp(port, 500)
|
|
538
460
|
} catch{
|
|
539
|
-
|
|
540
|
-
|
|
461
|
+
const browser = await dependencies
|
|
462
|
+
.launchLocal({ port, profileDir: defaultProfileDir() })
|
|
463
|
+
// The browser outlives this attach on purpose, so its process handle
|
|
464
|
+
// is not kept.
|
|
465
|
+
launched = {
|
|
466
|
+
binary: browser.binary,
|
|
467
|
+
source: browser.source,
|
|
468
|
+
downloaded: browser.downloaded,
|
|
469
|
+
...(browser.fallbackReason
|
|
470
|
+
? { fallbackReason: browser.fallbackReason }
|
|
471
|
+
: {}),
|
|
472
|
+
}
|
|
541
473
|
}
|
|
542
474
|
} else {
|
|
543
|
-
await
|
|
475
|
+
await dependencies.waitForCdp(port, 2_000).catch(() => {
|
|
544
476
|
throw new Error(
|
|
545
477
|
`attach mode: nothing answering CDP on port ${port}. Chrome must `
|
|
546
478
|
+ `be launched with --remote-debugging-port=${port} AND `
|
|
@@ -550,7 +482,12 @@ async function connect(
|
|
|
550
482
|
})
|
|
551
483
|
}
|
|
552
484
|
|
|
553
|
-
return {
|
|
485
|
+
return {
|
|
486
|
+
handles: await dependencies.connectLocal(port),
|
|
487
|
+
mode,
|
|
488
|
+
port,
|
|
489
|
+
...(launched ? { launched } : {}),
|
|
490
|
+
}
|
|
554
491
|
}
|
|
555
492
|
|
|
556
493
|
async function disposeState(state: AttachState) {
|
|
@@ -18,7 +18,9 @@ import { analyzeTool } from './analyze.ts'
|
|
|
18
18
|
import { type AttachState, attachTool } from './attach.ts'
|
|
19
19
|
import { type CaptureStore, captureTools, resetCaptures } from './capture.ts'
|
|
20
20
|
import { checkAttestorTool } from './check-attestor.ts'
|
|
21
|
+
import { draftTools } from './draft-tools.ts'
|
|
21
22
|
import { listTabsTool } from './eval.ts'
|
|
23
|
+
import { exampleAppTool } from './example-app.ts'
|
|
22
24
|
import { howItWorksTool } from './how-it-works.ts'
|
|
23
25
|
import { liveViewTools } from './live-view.ts'
|
|
24
26
|
import { podProofTools } from './pod-proof.ts'
|
|
@@ -92,8 +94,15 @@ export function buildAgentTools(
|
|
|
92
94
|
tools.push(t)
|
|
93
95
|
}
|
|
94
96
|
|
|
97
|
+
// check_matchers / update_draft: offline matcher check + in-place draft
|
|
98
|
+
// edits, keyed by captureId like run_proof_via_pod.
|
|
99
|
+
for(const t of draftTools(state.captures)) {
|
|
100
|
+
tools.push(t)
|
|
101
|
+
}
|
|
102
|
+
|
|
95
103
|
if(client) {
|
|
96
104
|
tools.push(startIntegrationTool())
|
|
105
|
+
tools.push(exampleAppTool())
|
|
97
106
|
tools.push(createVersionFromCaptureTool(
|
|
98
107
|
client, state.attach, state.captures,
|
|
99
108
|
))
|
|
@@ -3,6 +3,12 @@ import {
|
|
|
3
3
|
type KeptScriptRef,
|
|
4
4
|
makeDraftStore,
|
|
5
5
|
} from '../../../authoring/index.ts'
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_MAX_CHARS,
|
|
8
|
+
TEXT_WINDOW_PROPERTIES,
|
|
9
|
+
textWindow,
|
|
10
|
+
type TextWindowArgs,
|
|
11
|
+
} from '../../../authoring/util.ts'
|
|
6
12
|
import { type CaptureSession, startCapture } from '../../../cdp/capture.ts'
|
|
7
13
|
import { defineTool, type RegisteredTool } from '../../server.ts'
|
|
8
14
|
import type { AttachState } from './attach.ts'
|
|
@@ -19,6 +25,14 @@ export interface CaptureEntry {
|
|
|
19
25
|
drafts: DraftStore
|
|
20
26
|
}
|
|
21
27
|
|
|
28
|
+
interface GetRequestArgs {
|
|
29
|
+
captureId: string
|
|
30
|
+
requestId: string
|
|
31
|
+
maxChars?: number
|
|
32
|
+
offset?: number
|
|
33
|
+
full?: boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
22
36
|
export interface CaptureStore extends KeptScriptRef {
|
|
23
37
|
sessions: Map<string, CaptureEntry>
|
|
24
38
|
activeTab?: string
|
|
@@ -96,26 +110,32 @@ export function captureTools(
|
|
|
96
110
|
},
|
|
97
111
|
)
|
|
98
112
|
|
|
99
|
-
const getTool = defineTool<
|
|
113
|
+
const getTool = defineTool<GetRequestArgs>(
|
|
100
114
|
{
|
|
101
115
|
name: 'get_request',
|
|
102
116
|
description:
|
|
103
|
-
'Returns the
|
|
104
|
-
+ '
|
|
105
|
-
+
|
|
106
|
-
+ '
|
|
107
|
-
+ '
|
|
117
|
+
'Returns the headers and bodies of one captured request, to inspect '
|
|
118
|
+
+ 'a candidate that `find_requests_containing` ranked. Each body is '
|
|
119
|
+
+ `cut to ${DEFAULT_MAX_CHARS} characters by default; a cut body `
|
|
120
|
+
+ 'comes with `requestBodyTruncation` or `responseBodyTruncation` '
|
|
121
|
+
+ '(total size and `nextOffset`). Page with `offset`, or pass '
|
|
122
|
+
+ '`maxChars` or `full`. Unlike the other tools, headers are raw: '
|
|
123
|
+
+ 'cookie and authorization values are visible. Read them for '
|
|
124
|
+
+ 'diagnosis; do not repeat them to the developer or write them to '
|
|
125
|
+
+ 'a file.',
|
|
108
126
|
inputSchema: {
|
|
109
127
|
type: 'object',
|
|
110
128
|
properties: {
|
|
111
129
|
captureId: { type: 'string' },
|
|
112
130
|
requestId: { type: 'string' },
|
|
131
|
+
...TEXT_WINDOW_PROPERTIES,
|
|
113
132
|
},
|
|
114
133
|
required: ['captureId', 'requestId'],
|
|
115
134
|
},
|
|
116
135
|
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
117
136
|
},
|
|
118
|
-
async(
|
|
137
|
+
async(args) => {
|
|
138
|
+
const { captureId, requestId } = args
|
|
119
139
|
const entry = captures.sessions.get(captureId)
|
|
120
140
|
if(!entry) {
|
|
121
141
|
throw new Error(`no capture ${captureId}`)
|
|
@@ -126,14 +146,37 @@ export function captureTools(
|
|
|
126
146
|
throw new Error(`no request ${requestId} in capture ${captureId}`)
|
|
127
147
|
}
|
|
128
148
|
|
|
149
|
+
const { requestBody, responseBody, ...meta } = r
|
|
129
150
|
const body = entry.session.bodies.get(requestId)
|
|
130
|
-
|
|
131
|
-
|
|
151
|
+
const result = {
|
|
152
|
+
...meta,
|
|
153
|
+
...windowed('requestBody', requestBody, args),
|
|
154
|
+
...windowed(
|
|
155
|
+
'responseBody', body.available ? body.body : responseBody, args,
|
|
156
|
+
),
|
|
132
157
|
}
|
|
133
|
-
|
|
134
|
-
|
|
158
|
+
return body.available
|
|
159
|
+
? { ...result, bodyAvailable: true }
|
|
160
|
+
: { ...result, bodyAvailable: false, reason: body.reason }
|
|
135
161
|
},
|
|
136
162
|
)
|
|
137
163
|
|
|
138
164
|
return [startTool, stopTool, getTool]
|
|
139
165
|
}
|
|
166
|
+
|
|
167
|
+
/** `{ [key]: text window }`, plus `[key]Truncation` when the window cut it. */
|
|
168
|
+
function windowed(
|
|
169
|
+
key: 'requestBody' | 'responseBody',
|
|
170
|
+
text: string | undefined,
|
|
171
|
+
args: TextWindowArgs,
|
|
172
|
+
) {
|
|
173
|
+
if(text === undefined) {
|
|
174
|
+
return {}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const { text: part, truncation } = textWindow(text, args)
|
|
178
|
+
return {
|
|
179
|
+
[key]: part,
|
|
180
|
+
...(truncation ? { [`${key}Truncation`]: truncation } : {}),
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -20,13 +20,21 @@ export function checkAttestorTool(
|
|
|
20
20
|
+ 'seconds (about 8 when healthy). Call it once when you set up a '
|
|
21
21
|
+ 'new provider build, and after `run_proof` fails with a network '
|
|
22
22
|
+ 'error. Returns `{ ok, attestorUrl, durationMs, '
|
|
23
|
-
+ 'extractedParameters, error, errorKind }`.
|
|
24
|
-
+ '
|
|
25
|
-
+ '
|
|
26
|
-
+ '
|
|
27
|
-
+ '
|
|
28
|
-
+ '
|
|
29
|
-
+ '
|
|
23
|
+
+ 'extractedParameters, error, errorKind, proofFiles }`. '
|
|
24
|
+
+ '`proofFiles` is the proof file download state: `{ status }` is '
|
|
25
|
+
+ '`idle`, `ready`, `downloading` (with `method`, `elapsedMs`, and '
|
|
26
|
+
+ '`bytesDownloaded`/`totalBytes` when known), or `failed` (with '
|
|
27
|
+
+ '`reason`). If `ok` is true, the attestor is fine and a failing '
|
|
28
|
+
+ 'proof points to the target site. If `errorKind` is '
|
|
29
|
+
+ '`proof-files-downloading`, the one-time proof file download is '
|
|
30
|
+
+ 'still running and the attestor was not contacted: call this tool '
|
|
31
|
+
+ 'again shortly; do not report a network problem. If it is '
|
|
32
|
+
+ '`proof-files-failed`, the download failed: tell the developer '
|
|
33
|
+
+ '`error` (usually no access to github.com or '
|
|
34
|
+
+ 'raw.githubusercontent.com). If it is `attestor-unreachable`, the '
|
|
35
|
+
+ 'proof files are ready but this machine cannot reach the attestor '
|
|
36
|
+
+ '(network, VPN, firewall, or proxy): tell the developer. If it is '
|
|
37
|
+
+ '`setup-failed`, other local setup failed: report `error`. If it is '
|
|
30
38
|
+ '`attestor-error`, the attestor rejected the claim: report '
|
|
31
39
|
+ '`error`.',
|
|
32
40
|
inputSchema: {
|