@weaccelerateinc/agent-sdk 0.12.0 → 0.14.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/README.md CHANGED
@@ -1,13 +1,17 @@
1
- # @weaccelerateinc/agent-sdk 0.12.0
1
+ # @weaccelerateinc/agent-sdk 0.14.0
2
2
 
3
- SDK 0.12.0 adds opt-in Browser Use run-created fill-only checkout, exact additional-extension policies, and private WhatsApp adapters with durable sent-receipt reconciliation. The platform must implement durable owner/session/viewer fences and qualify its provider. Existing connector defaults and the 0.11.0 customer-final-click purchase contract remain. The approved extension ZIP is unchanged; its compatibility metadata includes 0.12.0.
3
+ SDK 0.14.0 adds `client.checkouts.erase(id, binding)` for account deletion and negotiated `number_required` hints in private chat. Erasure retains cleanup ownership until browser retirement succeeds. A false or absent card hint does not establish readiness; verification can still require CVV or full card details.
4
+
5
+ SDK 0.14.0 also lets authenticated integrations attach their customer-owned Browser Use browser without a separate merchant opt-in or an inventory of other installed extensions. Accelerate verifies its own extension, ownership and run binding. The run-created flow remains fill-only with private verification, durable scheduling/viewer fences, replay protection and cleanup. The approved extension ZIP is unchanged; its compatibility metadata includes 0.14.0.
6
+
7
+ The browser-attachment baseline requires migration 004 and its matching gateway/reaper. For the 0.14.0 card hint, deploy the updated managed service before the wallet card-number passthrough and deploy the API flag in the same target environment. Then install this SDK. SDK 0.12.0 retains its original opt-in and inventory checks. The customer controls its browser and other extensions; Accelerate does not claim isolation from them.
4
8
 
5
9
  Version 0.11.0 is a breaking release: **Accelerate never sends the final payment click.** A purchase arms one short click, the customer's agent performs it once through its own browser connection (`BrowserConnectorHost.performFinalClick`) in the customer's existing browser, then Accelerate observes the outcome. Purchase requires `final_click_actor:'customer'` and that host; the managed Kernel browser is fill-only. `client.checkouts.submit` rejects locally with `customer_click_required`. See [customer-owned final click](../../docs/customer-final-click.md). Release 0.10.3 keeps its existing behavior. Merchant layouts remain limited to the qualified sandbox page; this SDK release does not by itself qualify any merchant layout, a service deployment or production payments.
6
10
 
7
- Server-only ESM SDK with TypeScript declarations, Node 22+, zero runtime dependencies. New partners use their existing browser and explicitly select `managed_review_v2`, which continues an armed fill immediately after private CVV verification. Existing callers keep `managed_review_v1` unless they opt in. Public npm releases use `@weaccelerateinc/agent-sdk`; install an exact available version with `npm install @weaccelerateinc/agent-sdk@0.12.0`. Check `npm view @weaccelerateinc/agent-sdk@0.12.0 version` to confirm registry availability. The package remains `UNLICENSED`.
11
+ Server-only ESM SDK with TypeScript declarations, Node 22+, zero runtime dependencies. New partners use their existing browser and explicitly select `managed_review_v2`, which continues an armed fill immediately after private CVV verification. Existing callers keep `managed_review_v1` unless they opt in. Public npm releases use `@weaccelerateinc/agent-sdk`; install an exact available version with `npm install @weaccelerateinc/agent-sdk@0.14.0`. Check `npm view @weaccelerateinc/agent-sdk@0.14.0 version` to confirm registry availability. The package remains `UNLICENSED`.
8
12
 
9
13
  ```sh
10
- npm install --ignore-scripts @weaccelerateinc/agent-sdk@0.12.0
14
+ npm install --ignore-scripts @weaccelerateinc/agent-sdk@0.14.0
11
15
  npx --no-install accelerate-agent init ./partner-demo --browser existing
12
16
  ```
13
17
 
@@ -28,7 +28,9 @@
28
28
  "0.10.3",
29
29
  "0.10.4",
30
30
  "0.11.0",
31
- "0.12.0"
31
+ "0.12.0",
32
+ "0.13.0",
33
+ "0.14.0"
32
34
  ],
33
35
  "executor_contract": "accelerate_manual_checkout_v1"
34
36
  },
@@ -27,7 +27,9 @@
27
27
  "0.10.3",
28
28
  "0.10.4",
29
29
  "0.11.0",
30
- "0.12.0"
30
+ "0.12.0",
31
+ "0.13.0",
32
+ "0.14.0"
31
33
  ],
32
34
  "executor_contract": "accelerate_manual_checkout_v1"
33
35
  },
@@ -1,6 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
2
 
3
- const SDK_VERSION = '0.12.0';
3
+ const SDK_VERSION = '0.14.0';
4
4
  const EXECUTOR_CONTRACT = 'accelerate_manual_checkout_v1';
5
5
  const BRIDGE_PROTOCOL = 'accelerate_extension_bridge_v1';
6
6
  const LEGACY_SHA256 = '65574cbb27ab344687963f72a136f2653551b57458b284e486946b27699099c8';
@@ -42,14 +42,14 @@ export function createBrowserUseHost(options: {
42
42
  merchantId: string;
43
43
  extensionId: string;
44
44
  /** Primary runtime ID pinned in durable operator installation configuration.
45
- * Required for run-created or multi-extension mode; stable across host restarts. */
45
+ * Required when the resolved browser has run provenance; stable across host restarts. */
46
46
  extensionRuntimeId?: string;
47
47
  extensionRelease: ApprovedExtensionRelease;
48
48
  host: BrowserUsePlatformHost;
49
- /** Requires a durable owned run reservation and a fence covering all session runs and queued work.
50
- * The executor must separately enable this merchant. Default false. */
49
+ /** @deprecated Ignored. Run-created browsers require a durable owned reservation,
50
+ * a pinned extensionRuntimeId and a fence covering all session runs and queued work. */
51
51
  allowRunCreatedBrowsers?: boolean;
52
- /** Complete additional extension set approved for this merchant/provider. This is not qualification evidence. */
52
+ /** @deprecated Ignored. The customer manages its other browser extensions. */
53
53
  additionalExtensions?: ReadonlyArray<Readonly<{ id: string; runtimeId: string; version: string }>>;
54
54
  fetchImpl?: typeof fetch;
55
55
  /** Test clock only. */
@@ -45,23 +45,14 @@ const freeze = value => {
45
45
  };
46
46
 
47
47
  export function createBrowserUseHost(configuration = {}) {
48
+ // Legacy opt-in and extension-inventory options remain accepted but have no effect.
48
49
  exact(configuration, ['apiKey', 'merchantId', 'extensionId', 'extensionRelease', 'host'], ['fetchImpl', 'now', 'allowRunCreatedBrowsers', 'additionalExtensions', 'extensionRuntimeId']);
49
- const { apiKey, merchantId, extensionId, host, fetchImpl = fetch, now = Date.now,
50
- allowRunCreatedBrowsers = false, additionalExtensions = [], extensionRuntimeId } = configuration;
50
+ const { apiKey, merchantId, extensionId, host, fetchImpl = fetch, now = Date.now, extensionRuntimeId } = configuration;
51
51
  check(typeof apiKey === 'string' && apiKey.length >= 16 && apiKey.length <= 500 && !/[\u0000-\u0020\u007f]/u.test(apiKey) &&
52
52
  UUID.test(merchantId) && UUID.test(extensionId) && typeof fetchImpl === 'function' && typeof now === 'function' && host &&
53
53
  ['resolveOwnedBrowser', 'drainAndFence', 'bindCheckout', 'resolveCheckoutBrowser', 'inspectDocument', 'confirmLocalCleanup']
54
54
  .every(key => typeof host[key] === 'function'), 'configuration_invalid');
55
- check(typeof allowRunCreatedBrowsers === 'boolean' && Array.isArray(additionalExtensions) && additionalExtensions.length <= 2, 'configuration_invalid');
56
55
  check(extensionRuntimeId === undefined || RUNTIME.test(extensionRuntimeId), 'configuration_invalid');
57
- check(!(allowRunCreatedBrowsers || additionalExtensions.length) || RUNTIME.test(extensionRuntimeId ?? ''), 'configuration_invalid');
58
- const extensionIds = new Set([extensionId]), runtimes = new Set();
59
- const extras = additionalExtensions.map(value => {
60
- exact(value, ['id', 'runtimeId', 'version']);
61
- check(UUID.test(value.id) && RUNTIME.test(value.runtimeId) && typeof value.version === 'string' &&
62
- /^\d+(?:\.\d+){0,3}$/u.test(value.version) && !extensionIds.has(value.id) && !runtimes.has(value.runtimeId), 'configuration_invalid');
63
- extensionIds.add(value.id); runtimes.add(value.runtimeId); return Object.freeze({ ...value });
64
- });
65
56
  let release;
66
57
  try { release = validateApprovedExtensionRelease(configuration.extensionRelease); }
67
58
  catch { throw new AccelerateError('configuration_invalid'); }
@@ -81,7 +72,8 @@ export function createBrowserUseHost(configuration = {}) {
81
72
  catch { throw new AccelerateError('permission_denied'); }
82
73
  let provenance;
83
74
  if (Object.hasOwn(document.browser, 'provenance')) {
84
- check(allowRunCreatedBrowsers || cleanup && typeof document.fence_id === 'string' && document.fence_id.length > 0, 'permission_denied');
75
+ check(RUNTIME.test(extensionRuntimeId ?? ''), 'configuration_invalid');
76
+ check(!cleanup || typeof document.fence_id === 'string' && document.fence_id.length > 0, 'permission_denied');
85
77
  try { provenance = browserUseRunProvenance(document.browser.provenance); }
86
78
  catch { throw new AccelerateError('permission_denied'); }
87
79
  }
@@ -139,23 +131,23 @@ export function createBrowserUseHost(configuration = {}) {
139
131
  metadata.accelerate_extension_sha256 === release.artifact.sha256 && metadata.accelerate_extension_version === release.extension_version) &&
140
132
  typeof value.timeoutAt === 'string' && Number.isFinite(Date.parse(value.timeoutAt)) &&
141
133
  (requiredStatus === 'stopped' || Date.parse(value.timeoutAt) > now()) &&
142
- Array.isArray(value.extensions) && value.extensions.length === extras.length + 1 &&
143
- new Set(value.extensions.map(item => item?.id)).size === value.extensions.length &&
144
- new Set(value.extensions.map(item => item?.runtimeId)).size === value.extensions.length);
145
- const primary = value.extensions.find(item => item?.id === extensionId);
146
- check(primary?.version === release.extension_version && RUNTIME.test(primary?.runtimeId ?? '') &&
147
- extras.every(expected => value.extensions.some(item => ['id', 'version', 'runtimeId'].every(key => item?.[key] === expected[key]))));
134
+ Array.isArray(value.extensions));
135
+ const primaries = value.extensions.filter(item => item?.id === extensionId);
136
+ check(primaries.length === 1);
137
+ const primary = primaries[0];
138
+ check(primary.version === release.extension_version && RUNTIME.test(primary.runtimeId ?? '') &&
139
+ !value.extensions.some(item => item !== primary && item?.runtimeId === primary.runtimeId));
148
140
  check(extensionRuntimeId === undefined || primary.runtimeId === extensionRuntimeId);
149
141
  // Deliberately project away provider CDP/viewer URLs and unknown response fields.
150
142
  const read = freeze({ expires_at: value.timeoutAt, runtime_id: primary.runtimeId });
151
143
  if (!options.withConnection) return read;
152
144
  check(typeof value.cdpUrl === 'string' && value.cdpUrl.length <= 2048 && typeof value.startedAt === 'string');
153
145
  return freeze({ ...read, connection: freeze({ id: value.id, status: value.status, cdpUrl: value.cdpUrl, startedAt: value.startedAt,
154
- timeoutAt: value.timeoutAt, recordingAvailable: false,
146
+ timeoutAt: value.timeoutAt, recordingAvailable: false, accelerate_extension_id: extensionId,
155
147
  metadata: binding.provenance ? {} : Object.fromEntries(['accelerate_merchant_id', 'accelerate_owner_user_id',
156
148
  'accelerate_workspace_id', 'accelerate_custody_mode', 'accelerate_agent_extension_id',
157
149
  'accelerate_extension_sha256', 'accelerate_extension_version'].map(key => [key, metadata[key]])),
158
- extensions: value.extensions.map(item => ({ id: item.id, runtimeId: item.runtimeId, version: item.version })),
150
+ extensions: [{ id: extensionId, runtimeId: primary.runtimeId, version: primary.version }],
159
151
  ...runEvidence }) });
160
152
  } catch {
161
153
  throw new AccelerateError(options.signal?.aborted ? 'request_cancelled' : 'integration_unavailable');
package/index.d.ts CHANGED
@@ -81,6 +81,12 @@ export type CheckoutReconciliationRequest = {
81
81
  currency?: 'USD';
82
82
  source: string;
83
83
  };
84
+ /** Derive from your server's authenticated owner, never model input. */
85
+ export interface CheckoutErasureRequest {
86
+ customer_id: string;
87
+ workspace_id: string;
88
+ conversation_id?: string;
89
+ }
84
90
  /** Server-owned existing browser, resolved from the authenticated application's
85
91
  * durable browser record. Never accept this binding from model arguments.
86
92
  * The customer backend retains provider access; this is not private-from-creation custody. */
@@ -166,9 +172,13 @@ export interface CreateCheckout {
166
172
  * Send it on every create. It is held in memory for this checkout and never stored. */
167
173
  browser_resource?: ClientBrowserResource;
168
174
  }
169
- /** The fields of Browser Use `GET /api/v4/browsers/{id}` that Accelerate needs. */
175
+ /** Private projection of Browser Use `GET /api/v4/browsers/{id}`, with the
176
+ * Accelerate extension selected by the authenticated backend. */
170
177
  export interface ClientBrowserResource {
171
178
  id: string;
179
+ /** Accelerate extension selected from the backend's durable installation configuration.
180
+ * Other extensions in the customer-owned browser are outside this projection. */
181
+ accelerate_extension_id?: string;
172
182
  status: 'active';
173
183
  cdpUrl: string;
174
184
  startedAt: string;
@@ -261,6 +271,11 @@ export class AccelerateClient {
261
271
  /** Backend only: observe the customer's click once. Dispatch claims are not sent; never retry. */
262
272
  completeFinalClick(id: CheckoutId, input: { revision: number; arm_id: string }, options?: RequestOptions): Promise<Checkout>;
263
273
  cancel(id: CheckoutId, options?: RequestOptions): Promise<Checkout>;
274
+ /** Server only, for a deleted customer: erase a closed checkout's encrypted record, idempotency key and review binding.
275
+ * The binding must match creation; chat checkouts also need conversation_id. An open checkout is refused with
276
+ * checkout_active unless it has expired, and an unreconciled purchase submit with reconciliation_required.
277
+ * A checkout that is already gone reports erased. Hash-only browser run claims are kept. */
278
+ erase(id: CheckoutId, input: CheckoutErasureRequest, options?: RequestOptions): Promise<{ erased: true }>;
264
279
  /** Records one merchant result after submit. Repeating the same input returns the same result; different input is refused. */
265
280
  reconcile(id: CheckoutId, input: CheckoutReconciliationRequest, options?: RequestOptions): Promise<ReconciledCheckout>;
266
281
  };
package/index.js CHANGED
@@ -22,7 +22,8 @@ const ERROR_CODES = new Set(['invalid_input', 'unauthorized', 'permission_denied
22
22
  'checkout_busy', 'store_unavailable', 'store_integrity_error', 'selection_rejected', 'upstream_invalid',
23
23
  'upstream_request_invalid', 'upstream_response_invalid', 'configuration_error', 'configuration_invalid',
24
24
  'route_not_found', 'method_not_allowed', 'json_required', 'invalid_json', 'request_too_large', 'checkout_event_unconfirmed',
25
- 'reconciliation_unavailable', 'reconciliation_mismatch', 'reconciliation_conflict', 'customer_click_required', 'final_click_in_progress']);
25
+ 'reconciliation_unavailable', 'reconciliation_mismatch', 'reconciliation_conflict', 'customer_click_required', 'final_click_in_progress',
26
+ 'checkout_active', 'reconciliation_required']);
26
27
  const MESSAGES = {
27
28
  invalid_input: 'Invalid Accelerate client request.',
28
29
  invalid_response: 'Accelerate returned an unrecognized private response.',
@@ -76,6 +77,10 @@ for (const [codes, message, nextAction] of [
76
77
  'The order does not match the approved quote. Nothing was recorded. Check the merchant order.', 'reconcile_order'],
77
78
  [['reconciliation_conflict'],
78
79
  'A different result is already recorded for this checkout. It cannot be replaced.', 'check_status'],
80
+ [['checkout_active'],
81
+ 'This checkout is still open and was not erased. Cancel it, then erase it.', 'check_status'],
82
+ [['reconciliation_required'],
83
+ 'This purchase has an unreconciled submit outcome and was kept. Reconcile the merchant order before erasing it.', 'reconcile_order'],
79
84
  ]) for (const code of codes) GUIDANCE[code] = Object.freeze({ message, nextAction });
80
85
 
81
86
  /** Safe diagnostics only: no response body, URL, credentials, cause or provider stack. */
@@ -269,6 +274,10 @@ function retirementInspectionInput(input) {
269
274
  const { revision, ...scope } = input;
270
275
  return { ...creationInspectionInput(scope), revision: integer(revision, 1, 2147483647) };
271
276
  }
277
+ function erasureResponse(value) {
278
+ keys(value, ['erased'], ['erased'], 'invalid_response'); check(value.erased === true, 'invalid_response');
279
+ return Object.freeze({ erased: true });
280
+ }
272
281
  function retirementInspectionResponse(value, id, input) {
273
282
  if (value?.confirmed === false) { keys(value, ['confirmed'], undefined, 'invalid_response'); return value; }
274
283
  keys(value, ['confirmed', 'checkout_id', 'revision', 'status', 'purpose', 'approval_policy', 'submit_allowed',
@@ -398,6 +407,12 @@ export class AccelerateClient {
398
407
  return result;
399
408
  },
400
409
  cancel: async (id, options) => this.#request('POST', checkoutId(id), '/cancel', {}, options),
410
+ erase: async (id, input, options) => {
411
+ keys(input, ['customer_id', 'workspace_id', 'conversation_id'], ['customer_id', 'workspace_id']);
412
+ string(input.customer_id, 500); string(input.workspace_id, 500);
413
+ if (input.conversation_id !== undefined) string(input.conversation_id, 500);
414
+ return this.#request('POST', checkoutId(id), '/erase', { ...input }, options);
415
+ },
401
416
  reconcile: async (id, input, options) => {
402
417
  const body = reconciliationInput(input);
403
418
  const result = await this.#request('POST', checkoutId(id), '/reconcile', body, options);
@@ -480,7 +495,7 @@ export class AccelerateClient {
480
495
  check(options.signal === undefined || options.signal instanceof AbortSignal);
481
496
  const controller = new AbortController();
482
497
  const milliseconds = connection ? 45000 : ['/inspect-creation', '/inspect-retirement'].includes(suffix) ? 60000 : id === null ? 245000 : ({ '/fill': 235000, '/details': 125000, '/verify-quote': 125000, '/approval': 125000,
483
- '/final-click/arm': 20000, '/final-click/complete': 125000, '/browser': 85000, '/cancel': 45000, '/reconcile': 45000, '': 45000 })[suffix];
498
+ '/final-click/arm': 20000, '/final-click/complete': 125000, '/browser': 85000, '/cancel': 45000, '/erase': 45000, '/reconcile': 45000, '': 45000 })[suffix];
484
499
  const timer = setTimeout(() => controller.abort(), milliseconds); timer.unref?.();
485
500
  const signal = AbortSignal.any([controller.signal, ...(options.signal ? [options.signal] : [])]);
486
501
  const url = connection ? `${this.#origin}/v1/connection` :
@@ -500,7 +515,7 @@ export class AccelerateClient {
500
515
  if (!response.ok) throw new AccelerateError(ERROR_CODES.has(value?.error?.code) ? value.error.code : 'request_failed', response.status,
501
516
  response.headers.get('x-accelerate-support-reference'));
502
517
  return connection ? connectionResponse(value, this.#merchantId) : suffix === '/browser' ? browserResponse(value) :
503
- suffix === '/verify-quote' ? verifiedQuoteResponse(value, id, body) : suffix === '/final-click/arm' ? finalClickArmResponse(value, body) : suffix === '/inspect-creation' ? creationInspectionResponse(value, body) : suffix === '/inspect-retirement' ? retirementInspectionResponse(value, id, body) : statusResponse(value, id, {
518
+ suffix === '/verify-quote' ? verifiedQuoteResponse(value, id, body) : suffix === '/final-click/arm' ? finalClickArmResponse(value, body) : suffix === '/inspect-creation' ? creationInspectionResponse(value, body) : suffix === '/inspect-retirement' ? retirementInspectionResponse(value, id, body) : suffix === '/erase' ? erasureResponse(value) : statusResponse(value, id, {
504
519
  create: id === null, origin: this.#origin, loopback: this.#loopback });
505
520
  } catch (error) {
506
521
  Promise.resolve(response?.body?.cancel()).catch(() => {});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weaccelerateinc/agent-sdk",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Server-only payment SDK, existing-browser connectors and private host adapters for agent platforms",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -1,15 +1,15 @@
1
1
  # Existing-browser payment starter
2
2
 
3
- SDK 0.12.0, explicit `managed_review_v2`, `customer_backend_trusted`. Newly generated existing-browser apps default to `purpose:'purchase'` with the submit tool enabled. The matching service must support this profile; publishing the SDK does not deploy the service or qualify a merchant layout. Your platform creates its browser and installs the approved extension. This starter attaches that same browser at payment; it never creates a replacement. The older `accelerate-agent init <dir>` starter still selects Accelerate-managed Kernel custody and its fill-only default.
3
+ SDK 0.14.0, explicit `managed_review_v2`, `customer_backend_trusted`. Newly generated existing-browser apps default to `purpose:'purchase'` with the submit tool enabled. The matching service must support this profile; publishing the SDK does not deploy the service or qualify a merchant layout. Your platform creates its browser and installs the approved extension. This starter attaches that same browser at payment; it never creates a replacement. The older `accelerate-agent init <dir>` starter still selects Accelerate-managed Kernel custody and its fill-only default.
4
4
 
5
5
  ## Run without credentials
6
6
 
7
- Once Accelerate supplies the matching verified 0.12.0 archive, install it, then:
7
+ Once Accelerate supplies the matching verified 0.14.0 archive, install it, then:
8
8
 
9
9
  ```sh
10
10
  npx --no-install accelerate-agent init ./partner-demo --browser existing
11
11
  cd partner-demo
12
- npm install /secure/downloads/weaccelerateinc-agent-sdk-0.12.0.tgz
12
+ npm install /secure/downloads/weaccelerateinc-agent-sdk-0.14.0.tgz
13
13
  npm test
14
14
  npm run smoke
15
15
  ```
@@ -12,7 +12,7 @@
12
12
  "test": "node --test tests/*.test.mjs"
13
13
  },
14
14
  "dependencies": {
15
- "@weaccelerateinc/agent-sdk": "0.12.0",
15
+ "@weaccelerateinc/agent-sdk": "0.14.0",
16
16
  "@modelcontextprotocol/server": "2.3.1"
17
17
  },
18
18
  "devDependencies": {
@@ -225,7 +225,7 @@ export function createSyntheticDependencies({ purpose = 'sandbox_fill_only', pro
225
225
  artifact: { format: 'zip', sha256: 'a'.repeat(64), bytes: 1234 },
226
226
  bridge: { protocol: 'accelerate_extension_bridge_v1', sha256: 'b'.repeat(64) },
227
227
  capabilities: { manual_card_fill: true, document_bound_single_use: true, autosave_disabled: true, automatic_submit: false, maximum_retention_ms: 480000 },
228
- compatibility: { sdk_versions: ['0.10.1', '0.10.2', '0.10.3', '0.10.4', '0.11.0', '0.12.0'], executor_contract: 'accelerate_manual_checkout_v1' },
228
+ compatibility: { sdk_versions: ['0.10.1', '0.10.2', '0.10.3', '0.10.4', '0.11.0', '0.12.0', '0.13.0', '0.14.0'], executor_contract: 'accelerate_manual_checkout_v1' },
229
229
  qualifications: [{ provider: 'connector', scope: 'synthetic_only', evidence: 'docs/evidence/synthetic-starter.json' }],
230
230
  }; // Fake metadata for this in-process fixture only; never load it in live mode.
231
231
  const browser = { owner: context, browser: { provider: 'connector', connector_id: 'synthetic_cdp', browser_id: 'existing:browser:1', custody_mode: 'customer_backend_trusted' },
package/private-chat.d.ts CHANGED
@@ -22,7 +22,11 @@ export interface PrivateChatState {
22
22
  handled: boolean;
23
23
  /** Provider message ID was previously processed. No external operation was repeated. */
24
24
  duplicate: boolean;
25
- cards: Array<{ choice: number; last4: string | null; brand: string | null }>;
25
+ cards: Array<{ choice: number; last4: string | null; brand: string | null;
26
+ /** Customer number entry is known to be required. The customer adds it in their Accelerate wallet, then replies refresh.
27
+ * A false or omitted flag does not establish readiness. Saved-card verification may require CVV alone or full card details.
28
+ * Present only when true; older services never send it. */
29
+ number_required?: boolean }>;
26
30
  addresses: Array<{ choice: number; label: string | null; city?: string | null; state?: string | null; postal_code_mask?: string | null }>;
27
31
  identity_field?: 'first_name' | 'last_name' | 'email';
28
32
  /** Fixed feedback for an incomplete wallet selection; never contains the customer's reply. */
package/private-chat.js CHANGED
@@ -58,8 +58,9 @@ function state(value, expectedId) {
58
58
  if (checkout.card !== undefined) card(checkout.card); if (checkout.address !== undefined) address(checkout.address); if (checkout.quote !== undefined) quote(checkout.quote);
59
59
  check(stages.has(value.stage) && typeof value.handled === 'boolean' && typeof value.duplicate === 'boolean' &&
60
60
  Array.isArray(value.cards) && value.cards.length <= 100 && Array.isArray(value.addresses) && value.addresses.length <= 100, 'invalid_response');
61
- for (const [index, choice] of value.cards.entries()) { keys(choice, ['choice', 'last4', 'brand'], undefined, 'invalid_response');
62
- check(choice.choice === index + 1, 'invalid_response'); card({ last4: choice.last4, brand: choice.brand }); }
61
+ for (const [index, choice] of value.cards.entries()) { keys(choice, ['choice', 'last4', 'brand', 'number_required'], ['choice', 'last4', 'brand'], 'invalid_response');
62
+ check(choice.choice === index + 1 && (choice.number_required === undefined || typeof choice.number_required === 'boolean'), 'invalid_response');
63
+ card({ last4: choice.last4, brand: choice.brand }); }
63
64
  for (const [index, choice] of value.addresses.entries()) { keys(choice, ['choice', 'label', 'city', 'state', 'postal_code_mask'], ['choice', 'label'], 'invalid_response');
64
65
  check(choice.choice === index + 1, 'invalid_response'); const { choice: _, ...mask } = choice; address(mask); }
65
66
  check(value.stage === 'selection_required' || value.cards.length === 0 && value.addresses.length === 0, 'invalid_response');
@@ -138,7 +139,7 @@ export function renderPrivateChatState(value, options) {
138
139
  response.selection_error
139
140
  ? addressRequired ? 'Choose which saved address to use with your card. Include both choice numbers.' : 'That card or address choice is unavailable. Choose from the previous list.'
140
141
  : multiple ? 'Choose your Accelerate wallet details:' : 'Choose your Accelerate wallet card:',
141
- ...(!response.selection_error ? response.cards.map(choice => `Card ${choice.choice}: ${choice.brand ?? 'Card'} •••• ${choice.last4 ?? 'unavailable'}`) : []),
142
+ ...(!response.selection_error ? response.cards.map(choice => `Card ${choice.choice}: ${choice.brand ?? 'Card'} •••• ${choice.last4 ?? 'unavailable'}${choice.number_required ? ' (add its card number in your Accelerate wallet first, then reply refresh)' : ''}`) : []),
142
143
  ...(!response.selection_error || addressRequired ? addressChoices : []), instructions,
143
144
  'Reply cancel to stop. Do not send card numbers or expiration dates.',
144
145
  ].join('\n'); break;
@@ -279,7 +280,8 @@ export class AcceleratePrivateChatClient {
279
280
  try {
280
281
  signal.throwIfAborted();
281
282
  response = await bounded(this.#fetch(url, { method: 'POST', redirect: 'error', cache: 'no-store', credentials: 'omit', referrerPolicy: 'no-referrer', signal,
282
- headers: { Authorization: `Bearer ${this.#apiKey}`, 'X-Accelerate-Merchant-Id': this.#merchantId, Accept: 'application/json', 'Content-Type': 'application/json' }, body }));
283
+ headers: { Authorization: `Bearer ${this.#apiKey}`, 'X-Accelerate-Merchant-Id': this.#merchantId, 'X-Accelerate-Card-Requirements': 'v1',
284
+ Accept: 'application/json', 'Content-Type': 'application/json' }, body }));
283
285
  body = '';
284
286
  if (action === 'review' && response.ok) {
285
287
  check(!response.redirected && response.status === 200 && (!response.url || response.url === url) && /^image\/png(?:\s*;|$)/i.test(response.headers.get('content-type') ?? ''), 'invalid_response');
package/starter/README.md CHANGED
@@ -6,12 +6,12 @@ The default runnable mode is **synthetic**. It uses the real SDK, managed MCP ad
6
6
 
7
7
  ## Install and run
8
8
 
9
- Requires Node.js 22 or newer. Install the exact SDK 0.9.0 archive and checksum supplied by Accelerate; [release distribution](https://github.com/weaccelerateinc/accelerate-agent-sdk/blob/main/docs/releases.md) records verified availability. Do not assume npm publication.
9
+ Requires Node.js 22 or newer. Install the exact SDK 0.14.0 archive and checksum supplied by Accelerate; [release distribution](https://github.com/weaccelerateinc/accelerate/blob/main/products/agent-sdk/docs/releases.md) records verified availability. Do not assume npm publication.
10
10
 
11
11
  ```sh
12
12
  npx --no-install accelerate-agent init ./accelerate-demo
13
13
  cd accelerate-demo
14
- npm install /absolute/path/to/accelerate-agent-sdk-0.9.0.tgz
14
+ npm install /absolute/path/to/weaccelerateinc-agent-sdk-0.14.0.tgz
15
15
  npm test
16
16
  npm run smoke
17
17
  ```
@@ -12,7 +12,7 @@
12
12
  "test": "node --test tests/*.test.mjs"
13
13
  },
14
14
  "dependencies": {
15
- "@weaccelerateinc/agent-sdk": "0.12.0",
15
+ "@weaccelerateinc/agent-sdk": "0.14.0",
16
16
  "@modelcontextprotocol/server": "2.3.1"
17
17
  },
18
18
  "devDependencies": {