@reclaimprotocol/agent 0.1.42 → 0.1.44

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.
@@ -62,6 +62,14 @@ export declare const MCP_TOOLS: {
62
62
  openWorldHint: boolean;
63
63
  };
64
64
  };
65
+ CreateAiVerificationSession: {
66
+ description: string;
67
+ inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
68
+ orgTokenOnly: boolean;
69
+ annotations: {
70
+ openWorldHint: boolean;
71
+ };
72
+ };
65
73
  CreateCallbackSubscription: {
66
74
  description: string;
67
75
  inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
@@ -182,6 +190,15 @@ export declare const MCP_TOOLS: {
182
190
  openWorldHint: boolean;
183
191
  };
184
192
  };
193
+ GetAiVerificationSession: {
194
+ description: string;
195
+ inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
196
+ orgTokenOnly: boolean;
197
+ annotations: {
198
+ readOnlyHint: boolean;
199
+ openWorldHint: boolean;
200
+ };
201
+ };
185
202
  GetMe: {
186
203
  description: string;
187
204
  inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
@@ -1,5 +1,5 @@
1
1
  // AUTO-GENERATED by packages/app/scripts/mcp-tools-gen.ts
2
- // from packages/app/openapi.yaml (spec v0.1.0, source sha256:c3421d6bcf76).
2
+ // from packages/app/openapi.yaml (spec v0.1.0, source sha256:cbe3daf2a1f3).
3
3
  // The hash catches drift the version misses (a spec can change without a
4
4
  // version bump) — do not remove it as "redundant" with the version.
5
5
  // Run `npm run openapi:gen --workspace=packages/app` to regenerate. Do not edit by hand.
@@ -119,6 +119,7 @@ export const MCP_TOOLS = {
119
119
  "revenue",
120
120
  "usage",
121
121
  "goals",
122
+ "ai-session-prompts",
122
123
  "tools",
123
124
  "agents",
124
125
  "funnel"
@@ -485,6 +486,113 @@ export const MCP_TOOLS = {
485
486
  }),
486
487
  annotations: { "openWorldHint": false },
487
488
  },
489
+ "CreateAiVerificationSession": {
490
+ description: "Start an AI verification session from a prompt\n\nStarts an AI verification session from a plain-language prompt and optional dataPoints/loginUrls; returns the session with verificationUrl to share with the user. Needs the org token and at least one callback subscription (409 otherwise). No provider or org keypair needed: Builder manages the AI app key. Poll with get_ai_verification_session or wait_for_ai_session.",
491
+ inputSchema: toZod({
492
+ "type": "object",
493
+ "properties": {
494
+ "params": {
495
+ "type": "object",
496
+ "properties": {}
497
+ },
498
+ "query": {
499
+ "type": "object",
500
+ "properties": {}
501
+ },
502
+ "body": {
503
+ "type": "object",
504
+ "additionalProperties": false,
505
+ "description": "Body for `POST /verifications/ai-sessions`. Send a `prompt`, at least one entry in `dataPoints`, or both.",
506
+ "properties": {
507
+ "prompt": {
508
+ "type": "string",
509
+ "minLength": 0,
510
+ "maxLength": 10000,
511
+ "description": "What to verify, in plain language, such as \"verify I'm a student at Manipal University\". Required unless `dataPoints` has at least one item. Builder rejects a prompt that contains credentials, card numbers, instructions for the AI, or a sensitive claim. The prompt and the data point lines together can't exceed 10,000 characters."
512
+ },
513
+ "dataPoints": {
514
+ "type": "array",
515
+ "maxItems": 32,
516
+ "description": "The values to verify. Required unless you send a `prompt`. Names must be unique, and at least one data point must be required (its `isOptional` is `false` or absent). When you send data points, Builder keeps them and adds only optional data points that the prompt implies. When you send none, Builder chooses the data points from the prompt. Every required data point must appear in the verified proofs. If one is missing, the session ends as `rejected` with `reasonCode` `missing-data-points`.",
517
+ "items": {
518
+ "type": "object",
519
+ "additionalProperties": false,
520
+ "required": [
521
+ "name",
522
+ "description"
523
+ ],
524
+ "properties": {
525
+ "name": {
526
+ "type": "string",
527
+ "maxLength": 64,
528
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$",
529
+ "description": "Name of the value, such as `username`. Starts with a letter or underscore, followed by up to 63 letters, digits, or underscores."
530
+ },
531
+ "description": {
532
+ "type": "string",
533
+ "minLength": 1,
534
+ "maxLength": 300,
535
+ "description": "What the value is and why it proves the claim."
536
+ },
537
+ "isOptional": {
538
+ "type": "boolean",
539
+ "description": "Defaults to `false`. If `true`, the claim can be proven without this value, and the proofs can omit it. If `false` or absent, the data point is required, and a session whose proofs omit it ends as `rejected` with `reasonCode` `missing-data-points`."
540
+ }
541
+ }
542
+ }
543
+ },
544
+ "loginUrls": {
545
+ "type": "array",
546
+ "maxItems": 10,
547
+ "description": "Pages where the user signs in, such as `https://portal.example.edu/login`. Builder shows them first as candidates with source `caller`, and skips the web search. Each URL must use `http` or `https`, can't contain credentials, and must resolve to a public host.",
548
+ "items": {
549
+ "type": "string",
550
+ "format": "uri",
551
+ "maxLength": 2048
552
+ }
553
+ },
554
+ "isEmailVerificationAllowed": {
555
+ "type": "boolean",
556
+ "description": "Defaults to `false`. If `true`, the share page offers the user a choice to verify using email instead of signing in. If you omit it, the page doesn't offer that choice."
557
+ },
558
+ "context": {
559
+ "type": "object",
560
+ "maxProperties": 50,
561
+ "additionalProperties": true,
562
+ "description": "Values you already know, such as `{\"fullName\": \"Asha Rao\"}`. Builder merges them over the values the prompt states and returns the result in `context`. Must not contain `attestationNonce` or `attestationNonceData`; bind those after you create the session. Also must not contain `reclaimSessionId`, `extractedParameters`, or `builderSessionId`. Omit if you have none."
563
+ },
564
+ "verificationClientUrl": {
565
+ "type": "string",
566
+ "description": "Base URL of the registered verification client the user verifies with, as for `POST /verifications/sessions`. Builder charges this client's quota pool. If you omit it, Builder uses the default (`portals`) client.",
567
+ "maxLength": 2000,
568
+ "pattern": "^https?://"
569
+ },
570
+ "geoLocation": {
571
+ "type": "string",
572
+ "description": "ISO 3166-1 alpha-2 country code, such as `IN`. Builder searches the web from this country (Google's `gl` parameter), so portals for that country rank first. If you omit it, the search has no country preference.",
573
+ "minLength": 2,
574
+ "maxLength": 2,
575
+ "pattern": "^[A-Za-z]{2}$"
576
+ }
577
+ }
578
+ },
579
+ "orgToken": {
580
+ "type": "string",
581
+ "pattern": "^rorg_",
582
+ "maxLength": 200,
583
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
584
+ }
585
+ },
586
+ "required": [
587
+ "params",
588
+ "query",
589
+ "body"
590
+ ],
591
+ "additionalProperties": false
592
+ }),
593
+ orgTokenOnly: true,
594
+ annotations: { "openWorldHint": false },
595
+ },
488
596
  "CreateCallbackSubscription": {
489
597
  description: "Register a callback subscription\n\nRegisters a destination for verification results on the organization\nthe presented `OrgToken` resolves to. At least one subscription must\nexist for the org before you can create a verification session.\nDelivery is scoped by org: terminal results are ECIES-encrypted to the\norg's eth public key when its `canEncryptResult` is enabled (see\n`PUT /orgs/{orgId}/keypair`), else delivered as plaintext.\n\nTo receive results at a URL, send `callbackUrl` and `events`. Builder\nPOSTs each delivery to that URL.\n\nTo read results without a public URL during local development, send\n`deliveryMode: \"pull\"`. Builder keeps the deliveries and you read them\nwith `GET /verifications/callback-events`. A pull subscription is a\n90-second lease: it receives events and satisfies the session-creation\ncheck only while the lease is unexpired. Send the same request about\nevery 30 seconds to renew it, and call\n`POST /verifications/callback-listener/release` when you stop. Production\nneeds a webhook subscription. An org has at most one pull subscription.\nIf it already exists, Builder renews it and returns it with status 200.\nIf the body includes `events`, they replace the subscription's events;\nif it omits them, the existing events are kept.\n",
490
598
  inputSchema: toZod({
@@ -5274,6 +5382,48 @@ export const MCP_TOOLS = {
5274
5382
  }),
5275
5383
  annotations: { "readOnlyHint": true, "openWorldHint": false },
5276
5384
  },
5385
+ "GetAiVerificationSession": {
5386
+ description: "Get what an AI verification session's prompt resolved to\n\nGets what the AI session's lookup found: status resolving|ready|started|failed, candidates (login pages), merged dataPoints, error. Use get_verification_session for the overall outcome.",
5387
+ inputSchema: toZod({
5388
+ "type": "object",
5389
+ "properties": {
5390
+ "params": {
5391
+ "type": "object",
5392
+ "properties": {
5393
+ "sessionId": {
5394
+ "type": "string",
5395
+ "format": "uuid",
5396
+ "description": "Verification session id (UUID v7 when supported). Also echoed in the result payload as `reclaimSessionId`."
5397
+ }
5398
+ },
5399
+ "required": [
5400
+ "sessionId"
5401
+ ],
5402
+ "additionalProperties": false
5403
+ },
5404
+ "query": {
5405
+ "type": "object",
5406
+ "properties": {}
5407
+ },
5408
+ "body": {
5409
+ "type": "object"
5410
+ },
5411
+ "orgToken": {
5412
+ "type": "string",
5413
+ "pattern": "^rorg_",
5414
+ "maxLength": 200,
5415
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
5416
+ }
5417
+ },
5418
+ "required": [
5419
+ "params",
5420
+ "query"
5421
+ ],
5422
+ "additionalProperties": false
5423
+ }),
5424
+ orgTokenOnly: true,
5425
+ annotations: { "readOnlyHint": true, "openWorldHint": false },
5426
+ },
5277
5427
  "GetMe": {
5278
5428
  description: "Get the authenticated user\n\nGets the authenticated caller's own profile: id, email, and name. Requires a signed-in user session, not an OrgToken. Use it to confirm who the current credentials belong to.",
5279
5429
  inputSchema: toZod({
@@ -39,6 +39,7 @@ const SHARED_TOPIC_FILES = {
39
39
  /** Detailed topics that exist only in Builder mode. */
40
40
  const BUILDER_TOPIC_FILES = {
41
41
  'contributions': 'community-contributions.md',
42
+ 'ai-sessions': 'ai-sessions.md',
42
43
  'integration': 'verification-client-integration.md',
43
44
  };
44
45
  /** One line per topic, shown in the `how_it_works` index so a caller can pick
@@ -67,6 +68,9 @@ const TOPIC_SUMMARIES = {
67
68
  + 'providers, and going live.',
68
69
  'discover': 'Reusing existing providers: finding, resolving, copying one '
69
70
  + 'that needs changes, and creating a verification session.',
71
+ 'ai-sessions': 'The first route for a backend integration: prove a claim '
72
+ + 'about a user\'s account with create_ai_verification_session, no '
73
+ + 'provider or capture. Setup, backend code, and when to fall back.',
70
74
  'integration': 'After start_integration: org key and keypair, callback '
71
75
  + '(local proxy_callback_events or deployed webhook), frontend and '
72
76
  + 'backend over the HTTP session API, js-sdk projects, trying a '
@@ -278,7 +278,14 @@ export function createVersionFromCaptureTool(client, attachRef, kept) {
278
278
  },
279
279
  interceptorSettings: {
280
280
  type: 'string',
281
- description: 'Free-form JSON config for the chosen interceptor.',
281
+ description: 'Free-form JSON config for the chosen interceptor, '
282
+ + 'as a JSON object string. For HAWKEYE in the '
283
+ + 'in-app SDK: {"interceptionMethod": PROXY | '
284
+ + 'GETTER_SETTER | DIRECT_REPLACEMENT}, plus '
285
+ + 'optional disableFormIntercept and '
286
+ + 'delayFormSubmitForFetch. Try GETTER_SETTER when '
287
+ + 'the in-app page stalls but Portals works; see '
288
+ + 'topic interception.',
282
289
  },
283
290
  isDocumentRequestReplayEnabled: {
284
291
  type: 'boolean',
@@ -5,6 +5,7 @@ interface StartIntegrationArgs {
5
5
  userRequest?: string;
6
6
  orgId?: string;
7
7
  providerIds?: string[];
8
+ route?: 'ai-session' | 'provider';
8
9
  }
9
10
  /**
10
11
  * Returns the plan a coding agent follows to add Reclaim verification to the
@@ -11,7 +11,10 @@ export function startIntegrationTool() {
11
11
  return defineTool({
12
12
  name: 'start_integration',
13
13
  description: 'Returns a step-by-step plan for adding Reclaim verification to the '
14
- + 'current codebase: sign in to Builder, attach the browser, capture, '
14
+ + 'current codebase. Recommends Builder AI sessions first: no '
15
+ + 'provider to build, just a prompt and data points. Use route '
16
+ + '"provider" to fall back to provider authoring, which is what '
17
+ + 'this describes: sign in to Builder, attach the browser, capture, '
15
18
  + 'and prove the provider first, then set up the app (session route, '
16
19
  + 'callback, Verify button, local event proxy) after the proof or '
17
20
  + 'while waiting on the developer, bootstrapping from the '
@@ -46,7 +49,15 @@ export function startIntegrationTool() {
46
49
  type: 'array',
47
50
  maxItems: 10,
48
51
  items: { type: 'string' },
49
- description: 'Existing provider IDs to use. Omit to build a new provider.',
52
+ description: 'Existing provider IDs to use. Implies route "provider".',
53
+ },
54
+ route: {
55
+ type: 'string',
56
+ enum: ['ai-session', 'provider'],
57
+ description: '"ai-session" (default when providerIds is empty) plans a '
58
+ + 'Builder AI session. "provider" (default with providerIds) '
59
+ + 'plans provider authoring; use it as the fallback when an '
60
+ + 'AI session cannot prove the claim.',
50
61
  },
51
62
  },
52
63
  },
@@ -63,7 +74,13 @@ export function renderStartIntegration(args) {
63
74
  orgId: args.orgId,
64
75
  providerIds,
65
76
  };
66
- const template = readFileSync(fileURLToPath(new URL('../../../../skill/start-integration.md', import.meta.url)), 'utf8');
77
+ // An explicit route wins, so 'ai-session' ignores providerIds.
78
+ const route = args.route
79
+ ?? (providerIds ? 'provider' : 'ai-session');
80
+ const file = route === 'ai-session'
81
+ ? 'start-ai-session-integration.md'
82
+ : 'start-integration.md';
83
+ const template = readFileSync(fileURLToPath(new URL(`../../../../skill/${file}`, import.meta.url)), 'utf8');
67
84
  return template
68
85
  // Keep a conditional block only when its input was given (or not given).
69
86
  .replace(/<!-- (if|ifnot):(\w+) -->\n([\s\S]*?)<!-- endif -->\n/g, (_, kind, name, body) => {
@@ -1,6 +1,7 @@
1
1
  import { proxyCallbackEventsTool } from "./proxy-callback-events.js";
2
2
  import { readCallbackEventsTool } from "./read-callback-events.js";
3
3
  import { verificationResultTool } from "./result.js";
4
+ import { waitForAiSessionTool } from "./wait-for-ai-session.js";
4
5
  /**
5
6
  * Builder-mode verification tools: higher-level orchestrations over the
6
7
  * generated API surface. `get_verification_result` authenticates with the org
@@ -18,5 +19,6 @@ export function buildVerificationTools() {
18
19
  verificationResultTool(),
19
20
  readCallbackEventsTool(),
20
21
  proxyCallbackEventsTool(),
22
+ waitForAiSessionTool(),
21
23
  ];
22
24
  }
@@ -0,0 +1,46 @@
1
+ import { type RegisteredTool } from '../../server.ts';
2
+ type LookupStatus = 'resolving' | 'ready' | 'started' | 'failed';
3
+ type Lookup = {
4
+ status: LookupStatus;
5
+ error?: {
6
+ title?: string;
7
+ status?: number;
8
+ detail?: string;
9
+ };
10
+ dataPoints?: {
11
+ name: string;
12
+ isOptional: boolean;
13
+ }[];
14
+ candidates?: {
15
+ loginUrl: string;
16
+ source: string;
17
+ confidence: number;
18
+ }[];
19
+ };
20
+ type SessionState = {
21
+ status: string;
22
+ callbackDeliveryStatus?: string;
23
+ verificationUrl?: string;
24
+ };
25
+ type SessionEvent = {
26
+ event: string;
27
+ eventData?: Record<string, unknown>;
28
+ };
29
+ /** The three reads the tool needs. Injectable for tests. */
30
+ export type AiSessionApi = {
31
+ getLookup(sessionId: string): Promise<Lookup>;
32
+ getSession(sessionId: string): Promise<SessionState>;
33
+ listEvents(sessionId: string): Promise<SessionEvent[]>;
34
+ };
35
+ type Deps = {
36
+ createApi?: (orgToken?: string) => AiSessionApi;
37
+ sleep?: (ms: number) => Promise<void>;
38
+ now?: () => number;
39
+ };
40
+ /**
41
+ * `wait_for_ai_session` — polls an AI verification session (lookup, session
42
+ * status, and recent events) until something notable happens, and returns a
43
+ * compact, value-free summary with a `next` step and a fallback verdict.
44
+ */
45
+ export declare function waitForAiSessionTool(deps?: Deps): RegisteredTool;
46
+ export {};
@@ -0,0 +1,228 @@
1
+ import { isProblemError, ReclaimClient } from '@reclaimprotocol/client/api';
2
+ import { apiUrl } from "../../../consts.js";
3
+ import { defineTool } from "../../server.js";
4
+ import { resolveOrgSecret } from "./result.js";
5
+ const POLL_MS = 2000;
6
+ const DEFAULT_TIMEOUT_S = 120;
7
+ const MAX_TIMEOUT_S = 600;
8
+ const MAX_EVENTS = 5;
9
+ const FALLBACK_HINT = 'Retry once with adjusted `dataPoints` or `loginUrls`. '
10
+ + 'If that fails too, fall back to the provider route: call '
11
+ + '`start_integration` with `route: \'provider\'`.';
12
+ /**
13
+ * `wait_for_ai_session` — polls an AI verification session (lookup, session
14
+ * status, and recent events) until something notable happens, and returns a
15
+ * compact, value-free summary with a `next` step and a fallback verdict.
16
+ */
17
+ export function waitForAiSessionTool(deps = {}) {
18
+ const createApi = deps.createApi ?? defaultApi;
19
+ const sleep = deps.sleep ?? defaultSleep;
20
+ const now = deps.now ?? Date.now;
21
+ return defineTool({
22
+ name: 'wait_for_ai_session',
23
+ description: 'Waits for an AI verification session and returns a summary. '
24
+ + 'Polls every 2 seconds until the lookup is ready or failed, or '
25
+ + 'the session ends, or the timeout passes. Set `untilTerminal` to '
26
+ + 'keep waiting until the session ends, for example after you share '
27
+ + 'the verification URL. The result has the lookup state, the session '
28
+ + 'status, recent event types, and `next`: `share_url`, '
29
+ + '`waiting_for_user`, `waiting_for_lookup`, `done`, or `none`. '
30
+ + 'When `fallback.recommended` is true, follow its `reason`. '
31
+ + 'Authenticates with the org API key: `orgToken`, else '
32
+ + '`RECLAIM_ORG_SECRET`, else the key saved by `issue_org_token`.',
33
+ inputSchema: {
34
+ type: 'object',
35
+ required: ['sessionId'],
36
+ properties: {
37
+ sessionId: {
38
+ type: 'string',
39
+ description: 'The session ID from `create_ai_verification_session`.',
40
+ },
41
+ timeoutSeconds: {
42
+ type: 'integer',
43
+ minimum: 1,
44
+ maximum: MAX_TIMEOUT_S,
45
+ description: `How long to wait. Default ${DEFAULT_TIMEOUT_S}, `
46
+ + `maximum ${MAX_TIMEOUT_S}.`,
47
+ },
48
+ untilTerminal: {
49
+ type: 'boolean',
50
+ description: 'If true, return only when the session ends or '
51
+ + 'the lookup fails, not when the lookup is ready.',
52
+ },
53
+ orgToken: {
54
+ type: 'string',
55
+ pattern: '^rorg_',
56
+ maxLength: 200,
57
+ description: 'The organization API key (`rorg_…`). Defaults to '
58
+ + 'the MCP server\'s RECLAIM_ORG_SECRET, then the key saved by '
59
+ + '`issue_org_token`. Never echo it back to the user.',
60
+ },
61
+ },
62
+ },
63
+ annotations: { readOnlyHint: true, openWorldHint: true },
64
+ }, async (args) => {
65
+ const api = createApi(args.orgToken);
66
+ const timeoutS = Math.min(Math.max(args.timeoutSeconds ?? DEFAULT_TIMEOUT_S, 1), MAX_TIMEOUT_S);
67
+ const deadline = now() + timeoutS * 1000;
68
+ let lookup = { status: 'resolving' };
69
+ let session = { status: 'pending' };
70
+ while (true) {
71
+ lookup = await tolerate(() => api.getLookup(args.sessionId), lookup);
72
+ session = await tolerate(() => api.getSession(args.sessionId), session);
73
+ const terminal = session.status !== 'pending';
74
+ const failed = lookup.status === 'failed';
75
+ const notable = !args.untilTerminal && lookup.status !== 'resolving';
76
+ const timedOut = now() >= deadline;
77
+ if (terminal || failed || notable || timedOut) {
78
+ const events = await tolerate(() => api.listEvents(args.sessionId), []);
79
+ const settled = terminal || failed || notable;
80
+ return summarize(lookup, session, events, timedOut && !settled);
81
+ }
82
+ await sleep(POLL_MS);
83
+ }
84
+ });
85
+ }
86
+ function summarize(lookup, session, events, timedOut) {
87
+ const recent = events.slice(-MAX_EVENTS).map((item) => {
88
+ const reasonCode = reasonCodeOf(item.eventData);
89
+ return reasonCode
90
+ ? { event: item.event, reasonCode }
91
+ : { event: item.event };
92
+ });
93
+ const reasonCodes = recent.flatMap((item) => ('reasonCode' in item ? [item.reasonCode] : []));
94
+ let next;
95
+ let fallbackReason;
96
+ if (lookup.status === 'failed') {
97
+ const status = lookup.error?.status;
98
+ const why = status === 404
99
+ ? 'No login page was found.'
100
+ : status === 422
101
+ ? 'The prompt is not a request Reclaim can verify.'
102
+ : status === 503
103
+ ? 'The AI model or web search stayed unavailable.'
104
+ : 'The lookup failed.';
105
+ next = 'none';
106
+ fallbackReason = `${why} ${FALLBACK_HINT}`;
107
+ }
108
+ else if (session.status === 'success') {
109
+ next = 'done';
110
+ }
111
+ else if (session.status === 'pending') {
112
+ next = lookup.status === 'ready'
113
+ ? 'share_url'
114
+ : lookup.status === 'started'
115
+ ? 'waiting_for_user'
116
+ : 'waiting_for_lookup';
117
+ }
118
+ else {
119
+ next = 'none';
120
+ if (session.status === 'rejected') {
121
+ const code = reasonCodes.at(-1);
122
+ fallbackReason = `The session was rejected${code ? ` (${code})` : ''}. `
123
+ + FALLBACK_HINT;
124
+ }
125
+ else if (session.status === 'error' || session.status === 'expired') {
126
+ fallbackReason = `The session ended with status ${session.status}. `
127
+ + FALLBACK_HINT;
128
+ }
129
+ }
130
+ return {
131
+ lookup: {
132
+ status: lookup.status,
133
+ ...(lookup.candidates && {
134
+ candidates: lookup.candidates.map((item) => ({
135
+ loginUrl: item.loginUrl,
136
+ source: item.source,
137
+ confidence: item.confidence,
138
+ })),
139
+ }),
140
+ ...(lookup.dataPoints && {
141
+ dataPoints: lookup.dataPoints.map((item) => ({
142
+ name: item.name,
143
+ isOptional: item.isOptional,
144
+ })),
145
+ }),
146
+ ...(lookup.error && {
147
+ error: {
148
+ title: lookup.error.title,
149
+ status: lookup.error.status,
150
+ detail: lookup.error.detail,
151
+ },
152
+ }),
153
+ },
154
+ session: {
155
+ status: session.status,
156
+ callbackDeliveryStatus: session.callbackDeliveryStatus,
157
+ events: recent,
158
+ },
159
+ next,
160
+ ...(next === 'share_url' && session.verificationUrl
161
+ ? { verificationUrl: session.verificationUrl }
162
+ : {}),
163
+ ...(fallbackReason
164
+ ? { fallback: { recommended: true, reason: fallbackReason } }
165
+ : {}),
166
+ ...(timedOut ? { timedOut: true } : {}),
167
+ };
168
+ }
169
+ function defaultSleep(ms) {
170
+ return new Promise((resolve) => setTimeout(resolve, ms));
171
+ }
172
+ function reasonCodeOf(data) {
173
+ const direct = data?.reasonCode;
174
+ if (typeof direct === 'string') {
175
+ return direct;
176
+ }
177
+ const problem = data?.problem;
178
+ if (problem && typeof problem === 'object' && 'reasonCode' in problem) {
179
+ return typeof problem.reasonCode === 'string'
180
+ ? problem.reasonCode
181
+ : undefined;
182
+ }
183
+ return undefined;
184
+ }
185
+ /** Keeps the last good value across transient errors (network, 5xx, 429). */
186
+ async function tolerate(read, previous) {
187
+ try {
188
+ return await read();
189
+ }
190
+ catch (err) {
191
+ if (err instanceof TypeError) {
192
+ return previous;
193
+ }
194
+ if (isProblemError(err)) {
195
+ const code = err.output.statusCode;
196
+ if (code >= 500 || code === 429) {
197
+ return previous;
198
+ }
199
+ }
200
+ throw err;
201
+ }
202
+ }
203
+ function defaultApi(orgToken) {
204
+ const client = new ReclaimClient({
205
+ baseUrl: apiUrl(),
206
+ token: resolveOrgSecret(orgToken),
207
+ });
208
+ return {
209
+ async getLookup(sessionId) {
210
+ const res = await client.call('GetAiVerificationSession', {
211
+ params: { sessionId },
212
+ });
213
+ return res.data;
214
+ },
215
+ async getSession(sessionId) {
216
+ const res = await client.call('GetVerificationSession', {
217
+ params: { sessionId },
218
+ });
219
+ return res.data;
220
+ },
221
+ async listEvents(sessionId) {
222
+ const res = await client.call('ListVerificationEvents', {
223
+ params: { sessionId },
224
+ });
225
+ return res.data.items;
226
+ },
227
+ };
228
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@reclaimprotocol/agent",
3
3
  "title": "Reclaim Agent",
4
- "version": "0.1.42",
4
+ "version": "0.1.44",
5
5
  "description": "Reclaim Protocol tools for AI coding agents. Reclaim lets your app verify data points about its users, such as a follower count, an account balance, or an order history. This package is the Reclaim MCP server: it gives your agent the tools to find, build, test, and fix data verification providers by capturing and replaying browser requests, drafting provider recipes, running zkTLS proofs, and publishing provider versions.",
6
6
  "type": "module",
7
7
  "main": "./lib/index.js",
@@ -84,7 +84,7 @@
84
84
  "@noble/hashes": "^2.2.0",
85
85
  "@puppeteer/browsers": "3.2.4",
86
86
  "@reclaimprotocol/attestor-core": "^5.1.6",
87
- "@reclaimprotocol/client": "0.1.42",
87
+ "@reclaimprotocol/client": "0.1.44",
88
88
  "@reclaimprotocol/tls": "^0.1.3",
89
89
  "chrome-remote-interface": "^0.33.0",
90
90
  "domhandler": "^6.0.0",
@@ -444,12 +444,21 @@ one, or doesn't know what a site supports. Otherwise build a new provider.
444
444
  question; don't guess.
445
445
  5. To try them: `create_verification_session({ providers: [{ providerId }, …],
446
446
  context, verificationClientUrl })` with EVERY resolved provider id and the
447
- collected context. Topic `integration` ("Try a provider without an app")
447
+ collected context. A session opens only in the client it was created for:
448
+ for an in-app SDK or add-to-app host, pass
449
+ `https://build.reclaimprotocol.org/share/inapp-sdk`; omitted, it is a
450
+ Portal session. For a native app, read the README of the
451
+ [iOS SDK](https://github.com/reclaimprotocol/reclaim-inapp-ios-sdk#readme)
452
+ or the
453
+ [Android SDK](https://github.com/reclaimprotocol/reclaim-inapp-android-sdk#readme)
454
+ before writing app code. Topic `integration` ("Try a provider without an app")
448
455
  covers the callback and polling, and the integration steps.
449
456
 
450
457
  `merge.mergeable` only signals the set *could* collapse into one provider. Pass
451
458
  them all; the Builder runs them in one session.
452
459
 
460
+ <!-- topic: ai-sessions -->
461
+
453
462
  <!-- topic: integration -->
454
463
 
455
464
  <!-- topic: never-do -->