@absol-labs/agent 0.7.3 → 0.9.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.
Files changed (80) hide show
  1. package/README.md +19 -4
  2. package/dist/discovery/registry.d.ts +110 -305
  3. package/dist/discovery/registry.d.ts.map +1 -1
  4. package/dist/discovery/registry.js +141 -318
  5. package/dist/discovery/registry.js.map +1 -1
  6. package/dist/frameworks/agentkit.d.ts.map +1 -1
  7. package/dist/frameworks/agentkit.js +23 -6
  8. package/dist/frameworks/agentkit.js.map +1 -1
  9. package/dist/gateway/caller-auth-gateway.d.ts +103 -2
  10. package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
  11. package/dist/gateway/caller-auth-gateway.js +176 -19
  12. package/dist/gateway/caller-auth-gateway.js.map +1 -1
  13. package/dist/gateway/http-server.d.ts +12 -0
  14. package/dist/gateway/http-server.d.ts.map +1 -1
  15. package/dist/gateway/http-server.js +45 -1
  16. package/dist/gateway/http-server.js.map +1 -1
  17. package/dist/index.d.ts +3 -3
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +3 -3
  20. package/dist/index.js.map +1 -1
  21. package/dist/wallet/autonomous-wallet-store.d.ts +123 -0
  22. package/dist/wallet/autonomous-wallet-store.d.ts.map +1 -0
  23. package/dist/wallet/autonomous-wallet-store.js +318 -0
  24. package/dist/wallet/autonomous-wallet-store.js.map +1 -0
  25. package/dist/wallet/autonomous-wallet.d.ts +14 -39
  26. package/dist/wallet/autonomous-wallet.d.ts.map +1 -1
  27. package/dist/wallet/autonomous-wallet.js +12 -145
  28. package/dist/wallet/autonomous-wallet.js.map +1 -1
  29. package/dist/wallet/cdp-sdk.d.ts +23 -0
  30. package/dist/wallet/cdp-sdk.d.ts.map +1 -0
  31. package/dist/wallet/cdp-sdk.js +27 -0
  32. package/dist/wallet/cdp-sdk.js.map +1 -0
  33. package/dist/wallet/encrypted-file-credential-store.d.ts +41 -0
  34. package/dist/wallet/encrypted-file-credential-store.d.ts.map +1 -0
  35. package/dist/wallet/encrypted-file-credential-store.js +221 -0
  36. package/dist/wallet/encrypted-file-credential-store.js.map +1 -0
  37. package/dist/wallet/provider.d.ts +1 -1
  38. package/dist/wallet/provider.d.ts.map +1 -1
  39. package/dist/wallet/provider.js +8 -3
  40. package/dist/wallet/provider.js.map +1 -1
  41. package/dist/wallet/secret-service-probe.d.ts +56 -0
  42. package/dist/wallet/secret-service-probe.d.ts.map +1 -0
  43. package/dist/wallet/secret-service-probe.js +407 -0
  44. package/dist/wallet/secret-service-probe.js.map +1 -0
  45. package/dist/zktls/reclaim-js-sdk.d.ts +24 -0
  46. package/dist/zktls/reclaim-js-sdk.d.ts.map +1 -0
  47. package/dist/zktls/reclaim-js-sdk.js +29 -0
  48. package/dist/zktls/reclaim-js-sdk.js.map +1 -0
  49. package/dist/zktls/reclaim.d.ts +14 -2
  50. package/dist/zktls/reclaim.d.ts.map +1 -1
  51. package/dist/zktls/reclaim.js +29 -6
  52. package/dist/zktls/reclaim.js.map +1 -1
  53. package/dist/zktls/t2-delivery-proof.d.ts +8 -1
  54. package/dist/zktls/t2-delivery-proof.d.ts.map +1 -1
  55. package/dist/zktls/t2-delivery-proof.js +22 -6
  56. package/dist/zktls/t2-delivery-proof.js.map +1 -1
  57. package/docs/agent-layer.md +150 -0
  58. package/docs/autonomous-privy-wallet.md +133 -0
  59. package/docs/crewai.md +70 -0
  60. package/docs/eliza.md +109 -0
  61. package/docs/langchain.md +63 -0
  62. package/docs/mcp-hosted.md +137 -0
  63. package/docs/privy-embedded-wallet.md +102 -0
  64. package/docs/quickstart.md +370 -0
  65. package/docs/threat-model.md +160 -0
  66. package/package.json +19 -6
  67. package/src/discovery/registry.ts +242 -414
  68. package/src/frameworks/agentkit.ts +24 -5
  69. package/src/gateway/caller-auth-gateway.ts +281 -15
  70. package/src/gateway/http-server.ts +64 -0
  71. package/src/index.ts +24 -0
  72. package/src/wallet/autonomous-wallet-store.ts +487 -0
  73. package/src/wallet/autonomous-wallet.ts +57 -224
  74. package/src/wallet/cdp-sdk.ts +33 -0
  75. package/src/wallet/encrypted-file-credential-store.ts +341 -0
  76. package/src/wallet/provider.ts +16 -9
  77. package/src/wallet/secret-service-probe.ts +487 -0
  78. package/src/zktls/reclaim-js-sdk.ts +50 -0
  79. package/src/zktls/reclaim.ts +57 -23
  80. package/src/zktls/t2-delivery-proof.ts +28 -10
package/docs/eliza.md ADDED
@@ -0,0 +1,109 @@
1
+ # ElizaOS Plugin
2
+
3
+ Metrik ships a real ElizaOS plugin so an Eliza agent can **hire verified services**,
4
+ monitor them, and reclaim unspent funds out of the box — without ever bypassing the
5
+ signed spend mandate. It reuses the exact same SDK client and mandate budget-guard as
6
+ the Coinbase AgentKit action provider (`src/frameworks/agentkit.ts`); the business logic
7
+ is not forked.
8
+
9
+ > _x402 proves the payment, Metrik proves the delivery._
10
+
11
+ The plugin lives in [`src/frameworks/eliza.ts`](../src/frameworks/eliza.ts).
12
+
13
+ ## Actions
14
+
15
+ | Action (Eliza name) | What it does |
16
+ | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
17
+ | `HIRE_VERIFIED_SERVICE` | Escrow USDC on Base for a per-second, oracle-verified delivery stream to a seller. Fails closed **before any transaction** if the hire would breach the signed mandate. |
18
+ | `CHECK_STREAM_STATUS` | Read verified accrual, current state, and claimable/reclaimable USDC. In V2, failed or unproven intervals do not advance entitlement; buyer close or expiry ends the session. Sets `shouldStop` when the stream is no longer `active`. |
19
+ | `RECLAIM_UNSPENT` | Return unspent escrowed USDC to the buyer (optionally `closeFirst`), under the original mandate and the V2 checkpoint / escape-window rules. |
20
+ | `CLOSE_STREAM` | Finalize accrual and halt further payment, under the original mandate. |
21
+
22
+ ## Install
23
+
24
+ `@elizaos/core` is a peer of `@absol-labs/agent`.
25
+
26
+ ```bash
27
+ pnpm add @absol-labs/agent @elizaos/core
28
+ ```
29
+
30
+ ## Env
31
+
32
+ The plugin needs a signing wallet + an SDK client pointed at the Metrik escrow. On
33
+ testnet you may pass a raw private key; in production inject a Coinbase CDP wallet
34
+ instead (`createWalletBackedAgentClient` accepts either).
35
+
36
+ ```
37
+ METRIK_AGENT_RPC_URL Base Sepolia RPC URL
38
+ METRIK_AGENT_ESCROW Metrik escrow contract address (0x...)
39
+ METRIK_AGENT_USDC Settlement USDC token address (0x...)
40
+ METRIK_AGENT_PRIVATE_KEY Agent signing key (testnet only)
41
+ ```
42
+
43
+ ## Add the plugin to a character
44
+
45
+ The Metrik plugin is a **factory** — it needs a wallet-backed client — so it is built
46
+ programmatically and attached to the agent, rather than referenced by a bare package
47
+ name (the runtime cannot inject a funded wallet into a string-named plugin). A full,
48
+ runnable-shaped example lives in
49
+ [`examples/metrik-character.ts`](../examples/metrik-character.ts).
50
+
51
+ ```ts
52
+ import { http } from "viem";
53
+ import { baseSepolia } from "viem/chains";
54
+ import { createMetrikElizaPlugin } from "@absol-labs/agent/eliza";
55
+ import { createWalletBackedAgentClient } from "@absol-labs/agent";
56
+
57
+ const { agentClient } = await createWalletBackedAgentClient(
58
+ {
59
+ chain: baseSepolia,
60
+ transport: http(process.env.METRIK_AGENT_RPC_URL!),
61
+ escrow: process.env.METRIK_AGENT_ESCROW! as `0x${string}`,
62
+ usdc: process.env.METRIK_AGENT_USDC! as `0x${string}`,
63
+ settlementTarget: {
64
+ chainId: baseSepolia.id,
65
+ escrow: process.env.METRIK_AGENT_ESCROW! as `0x${string}`,
66
+ },
67
+ },
68
+ { privateKey: process.env.METRIK_AGENT_PRIVATE_KEY as `0x${string}` },
69
+ );
70
+
71
+ const metrikPlugin = createMetrikElizaPlugin({ agentClient });
72
+
73
+ export default {
74
+ agents: [
75
+ {
76
+ character: { name: "Metrik Buyer", plugins: [] },
77
+ plugins: [metrikPlugin],
78
+ },
79
+ ],
80
+ };
81
+ ```
82
+
83
+ ## Action envelope
84
+
85
+ Eliza actions receive a namespaced payload under `content.metrik`. Build it with
86
+ `createMetrikElizaContent()` rather than hand-rolling the envelope:
87
+
88
+ ```ts
89
+ import { createMetrikElizaContent } from "@absol-labs/agent/eliza";
90
+
91
+ const hire = createMetrikElizaContent("HIRE_VERIFIED_SERVICE", {
92
+ operator: "0x2222222222222222222222222222222222222222", // seller payout wallet
93
+ serviceRef: "0x1111...1111", // bytes32 service id the oracle verifies
94
+ budgetUsdc: "90000000", // atomic units, 6 decimals
95
+ ratePerSecondUsdc: "1000000",
96
+ maxDurationSeconds: 3600,
97
+ signedMandate, // owner-signed spend mandate
98
+ });
99
+ ```
100
+
101
+ `RECLAIM_UNSPENT` and `CLOSE_STREAM` take `{ streamId, signedMandate }`
102
+ (`RECLAIM_UNSPENT` also accepts `closeFirst`). `CHECK_STREAM_STATUS` takes `{ streamId }`.
103
+
104
+ ## Publishing
105
+
106
+ The plugin is publish-ready under `@absol-labs/agent`. Submitting it to the ElizaOS
107
+ plugin **registry** (or an npm publish) requires registry/npm credentials and a
108
+ registry PR — those steps are human-gated and are **not** performed by this package.
109
+ See the PR description for the follow-up.
@@ -0,0 +1,63 @@
1
+ # LangChain Adapter
2
+
3
+ The Phase 2 LangChain surface is a small, mandate-gated toolset built on the
4
+ existing agent client:
5
+
6
+ - `hire_verified_service`
7
+ - `check_stream_status`
8
+ - `reclaim_unspent`
9
+
10
+ Create them with [`createLangChainVerifiedStreamTools()`](../src/frameworks/langchain.ts).
11
+
12
+ ## Safety model
13
+
14
+ - `hire_verified_service` checks the signed mandate before any stream open.
15
+ - `reclaim_unspent` passes the same signed-mandate context into the agent client,
16
+ which re-checks authorization before the SDK can write.
17
+ - `check_stream_status` is read-only and also returns `shouldStop` for a closed
18
+ stream. In V2, verification gaps do not auto-pause the stream; the buyer must
19
+ explicitly close it to end further exposure.
20
+
21
+ ## Example loop
22
+
23
+ ```ts
24
+ import { createLangChainVerifiedStreamTools } from "@absol-labs/agent/langchain";
25
+
26
+ const tools = createLangChainVerifiedStreamTools({
27
+ agentClient,
28
+ now: () => Math.floor(Date.now() / 1000),
29
+ mandateStateResolver: {
30
+ getSpentSoFarUsdc: async () => spentSoFarUsdc,
31
+ getRevokedMandateIds: async () => revokedMandateIds,
32
+ },
33
+ });
34
+
35
+ const opened = await tools.hire.invoke({
36
+ operator: "0xYourOperator",
37
+ serviceRef: "0xYourServiceRef",
38
+ budgetUsdc: "90000000",
39
+ ratePerSecondUsdc: "1000000",
40
+ maxDurationSeconds: 3600,
41
+ signedMandate,
42
+ });
43
+
44
+ for (;;) {
45
+ const status = await tools.status.invoke({ streamId: opened.streamId });
46
+ if (status.shouldStop) break;
47
+ await new Promise((resolve) => setTimeout(resolve, 10_000));
48
+ }
49
+
50
+ await tools.reclaim.invoke({
51
+ streamId: opened.streamId,
52
+ closeFirst: true,
53
+ signedMandate,
54
+ });
55
+ ```
56
+
57
+ ## Reviewer checklist
58
+
59
+ 1. Provide a real `VerifiedStreamAgentClient` or compatible wrapper.
60
+ 2. Provide a real signed mandate plus resolver-backed cumulative-spend /
61
+ revocation state.
62
+ 3. Use `status.shouldStop` to halt work when the stream is no longer active.
63
+ 4. Reclaim explicitly through `reclaim_unspent` when the task ends or quality drops.
@@ -0,0 +1,137 @@
1
+ # Hosted MCP over Streamable HTTP
2
+
3
+ The agent lane ships two MCP transports over the **same** tool set
4
+ (`hire_verified_service`, `check_stream_status`, `reclaim_unspent`, `list_streams`,
5
+ and the optional `prove_https_response`):
6
+
7
+ - **stdio** (`src/mcp/stdio.ts`, `pnpm mcp:stdio`) — local dev, one process per
8
+ caller. Unchanged.
9
+ - **Streamable HTTP** (`src/mcp/http.ts` + `src/mcp/http-server.ts`,
10
+ `pnpm mcp:http`) — a hosted, **multi-tenant**, per-caller-authenticated
11
+ endpoint suitable for deployment. This document covers the HTTP transport.
12
+
13
+ The HTTP transport uses the MCP SDK's `StreamableHTTPServerTransport` (the
14
+ current remote transport; the deprecated HTTP+SSE transport is not used). It
15
+ speaks the standard Streamable HTTP session contract: `POST /mcp` for JSON-RPC
16
+ requests (an `initialize` opens a session and the server returns an
17
+ `Mcp-Session-Id` header), `GET /mcp` for the server→client SSE stream, and
18
+ `DELETE /mcp` to end a session — all carrying the `Mcp-Session-Id` header once a
19
+ session exists.
20
+
21
+ ## Security model (fail-closed)
22
+
23
+ - **Per-caller auth before anything runs.** Every request must carry
24
+ `Authorization: Bearer <token>`. A missing or invalid token is rejected with
25
+ `401` **before** any MCP session is created or any tool executes — so an
26
+ unauthenticated request can never move funds or read another caller's state.
27
+ - **Constant-time token comparison.** Tokens are compared via SHA-256 +
28
+ `crypto.timingSafeEqual` across all configured tenants with no early exit;
29
+ tokens are never logged.
30
+ - **Tenant isolation.** Each valid token maps to its **own** tenant context —
31
+ its own wallet-backed agent client and its own stream registry. One caller
32
+ can never drive another caller's funds or observe another caller's streams.
33
+ MCP sessions are bound to the tenant that opened them: presenting another
34
+ tenant's `Mcp-Session-Id` is rejected with `403`; an unknown session id is
35
+ `404`.
36
+ - **Refuses to run open.** If no tenants/tokens are configured, the server
37
+ throws before binding — it will never serve an unauthenticated endpoint.
38
+ - **No stack traces leak.** Errors are returned as generic JSON-RPC error
39
+ envelopes; internal detail stays server-side.
40
+ - **CORS** is off by default (same-origin / non-browser clients). Set
41
+ `METRIK_MCP_ALLOWED_ORIGINS` to opt specific browser origins in.
42
+
43
+ ## Environment contract
44
+
45
+ | Variable | Required | Default | Meaning |
46
+ | ---------------------------- | -------- | --------- | ---------------------------------------------------------------------- |
47
+ | `METRIK_MCP_TENANTS` | **yes** | — | JSON array of tenant configs (below). Empty/missing ⇒ refuse to start. |
48
+ | `PORT` / `METRIK_MCP_PORT` | no | `8080` | Listen port. |
49
+ | `METRIK_MCP_HOST` | no | `0.0.0.0` | Bind host. |
50
+ | `METRIK_MCP_PATH` | no | `/mcp` | MCP endpoint path. |
51
+ | `METRIK_MCP_ALLOWED_ORIGINS` | no | _(none)_ | Comma-separated CORS origins, or `*`. |
52
+
53
+ Each entry in `METRIK_MCP_TENANTS` is:
54
+
55
+ ```jsonc
56
+ {
57
+ "id": "acme", // stable tenant id (routing/logging only)
58
+ "token": "<secret-bearer>", // the caller's bearer token — never logged
59
+ "env": {
60
+ // optional: layered over the process env to
61
+ "METRIK_AGENT_CDP_OWNER_NAME": "acme-agent", // build THIS tenant's wallet
62
+ },
63
+ }
64
+ ```
65
+
66
+ A tenant's `env` is merged over the process environment and used to build that
67
+ tenant's isolated, wallet-backed agent client via the same
68
+ `METRIK_AGENT_*` / wallet / Reclaim variables the stdio server uses
69
+ (`METRIK_AGENT_RPC_URL`, `METRIK_AGENT_ESCROW`, `METRIK_AGENT_USDC`,
70
+ `METRIK_AGENT_PRIVATE_KEY` **or** the `CDP_*` wallet vars, etc. — see
71
+ `src/mcp/server.ts` and `src/wallet/provider.ts`). Tenants that share the same
72
+ network but need distinct wallets override only the wallet vars in their `env`.
73
+
74
+ > Provide tokens and wallet secrets through your host's secret manager / env UI.
75
+ > Never commit them, and never bake them into the image.
76
+
77
+ ## Run it
78
+
79
+ ```bash
80
+ export METRIK_AGENT_RPC_URL="https://base-sepolia.example/rpc"
81
+ export METRIK_AGENT_ESCROW="0x21948a5E6AE8d9A3D1050791AB6138657Fb54286"
82
+ export METRIK_AGENT_USDC="0x036CbD53842c5426634e7929541eC2318f3dCF7e"
83
+ # ... wallet vars (private key or CDP) ...
84
+ export METRIK_MCP_TENANTS='[{"id":"acme","token":"REPLACE_WITH_SECRET"}]'
85
+ export PORT=8080
86
+
87
+ pnpm mcp:http # dev (tsx)
88
+ # or, from a build:
89
+ node dist/mcp/http-server.js
90
+ ```
91
+
92
+ The process binds `0.0.0.0:$PORT` and logs only its address (never secrets).
93
+ `SIGINT`/`SIGTERM` trigger a graceful shutdown of all live sessions.
94
+
95
+ ## Connect an MCP client
96
+
97
+ Point any Streamable HTTP MCP client at `http(s)://<host>:<port>/mcp` with the
98
+ tenant's bearer token. With the TypeScript SDK:
99
+
100
+ ```ts
101
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
102
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
103
+
104
+ const transport = new StreamableHTTPClientTransport(
105
+ new URL("https://mcp.example.com/mcp"),
106
+ {
107
+ requestInit: {
108
+ headers: { Authorization: `Bearer ${process.env.METRIK_MCP_TOKEN}` },
109
+ },
110
+ },
111
+ );
112
+ const client = new Client({ name: "my-agent", version: "1.0.0" });
113
+ await client.connect(transport);
114
+ await client.listTools();
115
+ await client.callTool({ name: "list_streams", arguments: {} });
116
+ ```
117
+
118
+ Claude Desktop / other config-driven clients: add a remote MCP server pointing
119
+ at the `/mcp` URL and set the `Authorization: Bearer <token>` header. The
120
+ transport handles the session id, POST/GET/DELETE lifecycle automatically.
121
+
122
+ ## Programmatic embedding
123
+
124
+ The transport is also exported from the package root for hosting inside another
125
+ service:
126
+
127
+ - `createHostedMcpHttpServer({ resolver, path?, allowedOrigins? })` — build a
128
+ Node `http.Server` around a `TenantResolver`; `listen(port, host)` /
129
+ `close()`.
130
+ - `StaticTenantResolver` — constant-time, in-memory resolver over a list of
131
+ `HostedMcpTenant`s.
132
+ - `parseHostedMcpServerConfig(env)` / `createHostedMcpTenants(config)` /
133
+ `startHostedMcpHttpServerFromEnv(env)` — the env-driven wiring used by
134
+ `pnpm mcp:http`.
135
+
136
+ Supply your own `TenantResolver` to source tokens/tenants from a database or a
137
+ secrets service instead of env.
@@ -0,0 +1,102 @@
1
+ # Privy embedded-wallet integration
2
+
3
+ `@absol-labs/agent` provides a small, provider-neutral adapter for a
4
+ user-owned Privy embedded **EOA**. The site or host application must first
5
+ authenticate the user with Privy's client SDK and obtain that user's EIP-1193
6
+ wallet provider. The agent package does not authenticate users, create wallets
7
+ from an app id alone, receive an app secret, or persist key material.
8
+
9
+ ```ts
10
+ import { http } from "viem";
11
+ import { baseSepolia } from "viem/chains";
12
+ import {
13
+ createWalletBackedAgentClient,
14
+ type PrivyEip1193Provider,
15
+ } from "@absol-labs/agent";
16
+
17
+ // The authenticated Privy wallet/session is created by the host application.
18
+ const provider: PrivyEip1193Provider =
19
+ await host.getAuthenticatedPrivyProvider();
20
+ const address = await host.getAuthenticatedPrivyAddress();
21
+
22
+ const { wallet, agentClient } = await createWalletBackedAgentClient(
23
+ {
24
+ chain: baseSepolia,
25
+ // The Privy mode replaces this transport with the authenticated provider
26
+ // so writes use eth_sendTransaction. It remains the default for other modes.
27
+ transport: http(process.env.BASE_SEPOLIA_RPC_URL!),
28
+ escrow: "0x…",
29
+ usdc: "0x…",
30
+ },
31
+ {
32
+ privy: {
33
+ appId: "your-public-privy-app-id",
34
+ address,
35
+ provider,
36
+ chainId: 84532,
37
+ },
38
+ },
39
+ );
40
+
41
+ // `wallet.account` is a viem-compatible JSON-RPC EOA. Every autonomous write
42
+ // still goes through the signed Metrik spend-mandate checks in agentClient.
43
+ await wallet.account.signMessage({ message: "user-approved test" });
44
+ ```
45
+
46
+ The adapter verifies Base Sepolia (`chainId: 84532`) and the configured address
47
+ against `eth_chainId` and `eth_accounts` before construction and before every
48
+ `personal_sign` or `eth_signTypedData_v4` request. Contract writes are sent
49
+ through the same authenticated provider with `eth_sendTransaction`; the adapter
50
+ does not claim access to raw transaction signatures. A network or account switch
51
+ fails closed with `PrivyEmbeddedWalletError`.
52
+
53
+ ## Headless external-agent session
54
+
55
+ The Metrik dApp can attach a Privy additional signer under a non-empty Privy policy,
56
+ collect an owner-signed Metrik spend mandate, and exchange those approvals for a
57
+ short-lived broker token. An external agent adapts the copied session JSON without any
58
+ Privy app secret or wallet key:
59
+
60
+ ```ts
61
+ import {
62
+ createPrivySessionProvider,
63
+ createWalletBackedAgentClient,
64
+ } from "@absol-labs/agent";
65
+
66
+ const session = JSON.parse(process.env.METRIK_AGENT_SESSION_JSON!);
67
+ const provider = createPrivySessionProvider({
68
+ brokerUrl: session.brokerUrl,
69
+ sessionToken: session.sessionToken,
70
+ address: session.address,
71
+ });
72
+
73
+ const { agentClient } = await createWalletBackedAgentClient(sdkConfig, {
74
+ privy: {
75
+ appId: session.appId,
76
+ address: session.address,
77
+ provider,
78
+ chainId: session.chainId,
79
+ },
80
+ });
81
+ ```
82
+
83
+ The broker permits only bounded USDC approval, V2 stream open/close/reclaim, and
84
+ short-lived invocation-capability signatures for an active buyer stream. It stores a
85
+ hash—not the plaintext—of the session token. Revoked or expired sessions fail closed.
86
+ It asks Privy to sponsor only the first successful write in the session.
87
+
88
+ ## Boundary and limitations
89
+
90
+ - The adapter supports a user-owned Privy EOA only.
91
+ - It does not claim ERC-4337, EIP-1271, or smart-account support.
92
+ - The browser adapter alone does not provide headless access. Headless operation requires
93
+ the deployed broker, a real Privy additional-signer policy, and user approval in the dApp.
94
+ - The provider must implement the standard `eth_sendTransaction` EIP-1193 path.
95
+ In Privy mode, `createWalletBackedAgentClient` replaces the SDK transport with
96
+ that authenticated provider so a separate public RPC cannot bypass the wallet.
97
+ - The host must keep the Privy app secret and any authorization material
98
+ server-side. Only the public app id belongs in browser configuration.
99
+
100
+ Do not use an unauthenticated or arbitrary EIP-1193 provider as a substitute
101
+ for Privy's authenticated user wallet. Do not put a Privy app secret in
102
+ `PrivyEmbeddedWalletConfig`.