@mantle-agent/client 0.0.0-stage → 0.1.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,3 +1,82 @@
1
- # Temporary Holding Version
1
+ # @mantle-agent/client
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Client SDK for **Mantle Agent Accounts**: give an AI agent a Mantle account it can trade with inside limits its
4
+ owner sets on chain, while the owner keeps every key.
5
+
6
+ - **Agent side** (`AgentClient`, `connectAgent`): claim an account, quote, trade, read status, scheduled runs,
7
+ emergency stop. The agent never holds a private key.
8
+ - **Owner side** (`@mantle-agent/client/owner`: `OwnerClient` + flow functions): passkey signup/login, custody setup, approving an agent,
9
+ authorize / renew / revoke / withdraw, auto-run settings. Each owner operation runs step by step and can resume
10
+ from a failed step.
11
+ - **Browser** (`@mantle-agent/client/browser`): Turnkey passkey implementation of the owner's signer.
12
+
13
+ ```bash
14
+ npm install @mantle-agent/client # agent side: no other dependencies
15
+ npm install @mantle-agent/core @mantle-agent/custody viem # + owner side (@mantle-agent/client/owner)
16
+ npm install @turnkey/sdk-browser @turnkey/api-key-stamper @turnkey/crypto # + passkeys in the browser
17
+ ```
18
+
19
+ ## Agent side
20
+
21
+ ```ts
22
+ import { AgentClient, connectAgent } from "@mantle-agent/client";
23
+ import { parseEther } from "viem";
24
+
25
+ // Once: register the agent's Ed25519 key and wait for the owner to approve on the confirmation page.
26
+ const { agentId, credentials } = await connectAgent({
27
+ baseUrl: "https://agent-api.example",
28
+ agentName: "my-agent",
29
+ host: "my-app",
30
+ key: { publicKey, sign: (msg) => ed25519SignHex(msg) }, // your key storage
31
+ onClaim: (claim) => console.log(`Open ${claim.claimUrl} and confirm ${claim.userCode} (${claim.fingerprint})`),
32
+ });
33
+ // Store `credentials` securely. They are returned exactly once.
34
+
35
+ const agent = new AgentClient("https://agent-api.example", credentials);
36
+ const status = await agent.status(); // balance, remaining limits, recent trades
37
+ const trade = await agent.trade({ side: "buy", token: "0x…", amountIn: parseEther("1"), requestId: "my-unique-id" });
38
+ if (trade.status !== "confirmed") console.log(trade.errorCode, trade.error);
39
+ ```
40
+
41
+ Retry with the **same `requestId`**: the same trade is never executed twice. Errors are `ClientError` with a stable
42
+ `code` (`PER_TRADE_CAP_EXCEEDED`, `INSUFFICIENT_INVENTORY`, `SESSION_INACTIVE`, …).
43
+
44
+ Things only the owner can do are **asked for**, never done: `agent.requests.authorize(limits)`, `.renew(seconds)`,
45
+ `.revoke()`, `.withdraw({ to, asset, amount })`, `.autoRun(settings)`, `.resume()`. Each returns an `OwnerRequest`
46
+ with `confirmUrl` and the exact `summary` the owner will confirm with a passkey; `agent.requests.get(id)` tells you
47
+ when it is `completed`. `connectAgent({ …, authorize: limits })` proposes limits with the claim, so the owner claims
48
+ and authorizes in one visit.
49
+
50
+ Scheduled runs: `agent.runtime.lease(host)` → trade (pass `leaseId` to the constructor) → `agent.runtime.complete(leaseId, { llmCostUsd })`.
51
+
52
+ ## Owner side
53
+
54
+ ```ts
55
+ import { OwnerClient, signUp, logIn, ensureCustody, lookupClaim, approveClaim,
56
+ getRequest, approveRequest, runOperation, startRun, runSucceeded } from "@mantle-agent/client/owner";
57
+ import { passkeyTurnkey } from "@mantle-agent/client/browser";
58
+
59
+ const api = new OwnerClient("https://agent-api.example");
60
+ const { turnkeyOrganizationId } = await api.call("GET", "/v1/platform");
61
+ const tk = passkeyTurnkey({ parentOrgId: turnkeyOrganizationId });
62
+
63
+ let session = await logIn(api, tk); // or signUp(api, tk, name) the first time
64
+ session = await ensureCustody(api, tk, session); // once: add the platform as a restricted delegate
65
+
66
+ const claim = await lookupClaim(api, userCodeFromTheAgent);
67
+ // show claim.fingerprint and ask the owner to compare it with the agent's
68
+ const { agentId, requestId } = await approveClaim(api, tk, session, claim); // requestId: the limits proposed with the claim
69
+
70
+ // The agent asked in the chat; the owner opened its link (`/r/<requestId>`) and read `request.summary`.
71
+ const request = await getRequest(api, requestId);
72
+ const { prepared } = await approveRequest(api, requestId); // null for auto-run settings: already applied
73
+ const run = await runOperation(api, tk, session, startRun(prepared!), {
74
+ onChange: (r) => render(r.steps), // progress for the UI
75
+ });
76
+ if (!runSucceeded(run)) { /* show the failed step; call runOperation(api, tk, session, run) to retry from it */ }
77
+ ```
78
+
79
+ Everything the owner signs happens on their device with their passkey; the API verifies signatures and reads
80
+ Turnkey state back instead of trusting the page.
81
+
82
+ See the repository's `docs/integration.md` for the full picture.
@@ -0,0 +1,307 @@
1
+ import type { Address, Hex } from "viem";
2
+ import { type Fetch } from "./http.js";
3
+ export type CredentialKind = "trading" | "social" | "runtime";
4
+ export type Credentials = Record<CredentialKind, {
5
+ token: string;
6
+ expiresAt: string;
7
+ }>;
8
+ /** What the agent signs with when proving it holds the key that started a claim. */
9
+ export type AgentKey = {
10
+ /** Ed25519 public key, 32 raw bytes as hex. */
11
+ publicKey: string;
12
+ /** Ed25519 signature over `message` (UTF-8), 64 bytes as hex. */
13
+ sign(message: string): string | Promise<string>;
14
+ };
15
+ export type Claim = {
16
+ claimId: string;
17
+ claimUrl: string;
18
+ userCode: string;
19
+ fingerprint: string;
20
+ expiresAt: string;
21
+ /** Proposed limits as the owner will see them, or null. */
22
+ proposal: string[] | null;
23
+ };
24
+ export type Side = "buy" | "sell";
25
+ /** Amounts are decimal strings in wei (18 decimals), as the API returns them. */
26
+ export type Quote = {
27
+ quoteId: string;
28
+ side: Side;
29
+ adapter: Address;
30
+ token: Address;
31
+ amountIn: string;
32
+ expectedOut: string;
33
+ minAmountOut: string;
34
+ expiresAt: string;
35
+ };
36
+ export type IntentStatus = "accepted" | "submitted" | "pending" | "confirmed" | "failed" | "unknown";
37
+ export type Intent = {
38
+ intentId: string;
39
+ requestId: string;
40
+ quoteId: string;
41
+ side: Side;
42
+ token: Address;
43
+ amountIn: string;
44
+ minAmountOut: string;
45
+ status: IntentStatus;
46
+ txHash: Hex | null;
47
+ amountOut: string | null;
48
+ errorCode: string | null;
49
+ error: string | null;
50
+ createdAt: string;
51
+ updatedAt: string;
52
+ };
53
+ export type DimensionState = "active" | "expiring" | "expired" | "revoked" | "none";
54
+ export type RuntimeStatus = {
55
+ enabled: boolean;
56
+ paused: boolean;
57
+ nextRunAt: string | null;
58
+ config: {
59
+ intervalSeconds: number;
60
+ maxRunSeconds: number;
61
+ maxTradesPerRun: number;
62
+ maxTradesPerDay: number;
63
+ maxSpendPerDayWei: string;
64
+ maxLlmCostPerDayUsd: number;
65
+ };
66
+ today: {
67
+ trades: number;
68
+ spendWei: string;
69
+ llmCostUsd: number;
70
+ };
71
+ running: {
72
+ leaseId: string;
73
+ expiresAt: string;
74
+ trades: number;
75
+ } | null;
76
+ pendingCommands: {
77
+ commandId: string;
78
+ kind: string;
79
+ }[];
80
+ } | null;
81
+ export type AgentStatus = {
82
+ agent: {
83
+ agentId: string;
84
+ name: string;
85
+ status: "pending" | "active" | "stopped";
86
+ account: Address | null;
87
+ };
88
+ balanceWei: string | null;
89
+ session: {
90
+ keyHash: Hex;
91
+ state: DimensionState;
92
+ expiresAt: string;
93
+ maxSlippageBps: number;
94
+ limits: {
95
+ perTradeCap: string;
96
+ periodCap: string;
97
+ totalCap: string;
98
+ };
99
+ remaining: {
100
+ perTrade: string;
101
+ period: string;
102
+ total: string;
103
+ } | null;
104
+ } | null;
105
+ credentials: {
106
+ kind: CredentialKind;
107
+ state: DimensionState;
108
+ expiresAt: string;
109
+ lastUsedAt: string | null;
110
+ }[];
111
+ runtime: RuntimeStatus;
112
+ recentTrades: Intent[];
113
+ };
114
+ export type Lease = {
115
+ granted: false;
116
+ reason: "disabled" | "paused" | "not_due" | "budget_exhausted";
117
+ nextRunAt: string | null;
118
+ } | {
119
+ granted: true;
120
+ leaseId: string;
121
+ expiresAt: string;
122
+ budget: {
123
+ trades: number;
124
+ spendWei: string;
125
+ llmCostUsd: number;
126
+ };
127
+ commands: {
128
+ commandId: string;
129
+ kind: "pause" | "resume" | "run_now";
130
+ createdAt: string;
131
+ }[];
132
+ };
133
+ /** Session limits an agent can ask for (PRD WAL-02). Amounts in MNT wei; the owner confirms them with a passkey. */
134
+ export type SessionLimits = {
135
+ perTradeCap: bigint;
136
+ periodCap: bigint;
137
+ totalCap: bigint;
138
+ periodSeconds: number;
139
+ durationSeconds: number;
140
+ maxSlippageBps: number;
141
+ };
142
+ /** PRD V1 defaults: 2 MNT per trade, 10 MNT per 24 h, 20 MNT in total, 7 days, 2 % slippage. */
143
+ export declare const DEFAULT_SESSION_LIMITS: SessionLimits;
144
+ /** Scheduled-run budgets (PRD RUN-02/03), on top of the on-chain limits. */
145
+ export type AutoRunSettings = {
146
+ enabled: boolean;
147
+ intervalSeconds: number;
148
+ maxRunSeconds: number;
149
+ maxTradesPerRun: number;
150
+ maxTradesPerDay: number;
151
+ maxSpendPerDay: bigint;
152
+ maxLlmCostPerDayUsd: number;
153
+ };
154
+ export type OwnerRequestKind = "authorize" | "renew" | "revoke" | "withdraw" | "runtime" | "resume";
155
+ /**
156
+ * Something only the owner can do, asked for by the agent. Relay `confirmUrl` and `summary` to the owner; they
157
+ * confirm on the page with a passkey. `completed` once it took effect (on chain for signing kinds).
158
+ */
159
+ export type OwnerRequest = {
160
+ requestId: string;
161
+ agentId: string;
162
+ agentName: string;
163
+ kind: OwnerRequestKind;
164
+ status: "pending" | "approved" | "completed" | "rejected" | "expired" | "superseded";
165
+ createdBy: "agent" | "claim";
166
+ summary: string[];
167
+ warnings: string[];
168
+ confirmUrl: string;
169
+ expiresAt: string;
170
+ createdAt: string;
171
+ operation: {
172
+ operationId: string;
173
+ status: "prepared" | "submitted" | "confirmed" | "failed";
174
+ error: string | null;
175
+ } | null;
176
+ note: string | null;
177
+ };
178
+ /** Must match the API's claimProofMessage. */
179
+ export declare const claimProofMessage: (claimId: string) => string;
180
+ /**
181
+ * PRD IDN-02: register the agent key, hand the owner a link + code + fingerprint via `onClaim`, then poll with a
182
+ * proof of the key until the owner approves. Returns the credentials exactly once; store them securely.
183
+ */
184
+ export declare function connectAgent(params: {
185
+ baseUrl: string;
186
+ agentName: string;
187
+ host: string;
188
+ key: AgentKey;
189
+ /** Show this to the owner. Compare `fingerprint` with one computed locally from the key. */
190
+ onClaim: (claim: Claim) => void | Promise<void>;
191
+ /** Limits to propose: the owner confirms them right after claiming, in the same visit. */
192
+ authorize?: SessionLimits;
193
+ pollMs?: number;
194
+ fetch?: Fetch;
195
+ }): Promise<{
196
+ agentId: string;
197
+ credentials: Credentials;
198
+ }>;
199
+ /** First half of `connectAgent`: register the key and get the link + code + fingerprint for the owner. */
200
+ export declare function startClaim(params: {
201
+ baseUrl: string;
202
+ agentName: string;
203
+ host: string;
204
+ key: AgentKey;
205
+ authorize?: SessionLimits;
206
+ fetch?: Fetch;
207
+ }): Promise<Claim>;
208
+ export type ClaimResult = {
209
+ status: "pending";
210
+ expiresAt: string;
211
+ } | {
212
+ status: "exchanged";
213
+ agentId: string;
214
+ credentials: Credentials;
215
+ };
216
+ /**
217
+ * Second half of `connectAgent`, one attempt: `pending` until the owner approves, then the credentials exactly once.
218
+ * Stateless, so an agent can start a claim, end its turn, and check again later (CLAIM_EXPIRED once it lapsed).
219
+ */
220
+ export declare function exchangeClaim(params: {
221
+ baseUrl: string;
222
+ claimId: string;
223
+ key: AgentKey;
224
+ fetch?: Fetch;
225
+ }): Promise<ClaimResult>;
226
+ /**
227
+ * The agent's side of a Mantle Agent Account. It can only do what the owner authorized: trade within on-chain
228
+ * limits, read its status, manage its own scheduled runs, and stop itself. It never holds a private key.
229
+ */
230
+ export declare class AgentClient {
231
+ readonly baseUrl: string;
232
+ private readonly credentials;
233
+ private readonly fetchImpl;
234
+ /** Set when running inside a scheduled run; trades are charged to that run's budget. */
235
+ leaseId: string | undefined;
236
+ constructor(baseUrl: string, credentials: Partial<Credentials> | null, opts?: {
237
+ fetch?: Fetch;
238
+ leaseId?: string;
239
+ });
240
+ private call;
241
+ status(): Promise<AgentStatus>;
242
+ /** Price a trade. Valid ~30 s and for one trade. `amountIn` is wei (MNT for buys, tokens for sells). */
243
+ quote(params: {
244
+ side: Side;
245
+ token: Address;
246
+ amountIn: bigint;
247
+ }): Promise<Quote>;
248
+ /**
249
+ * Quote and execute. Reuse `requestId` when retrying: the same trade is never executed twice. With `wait`, polls
250
+ * until confirmed / failed / unknown (or `timeoutMs`).
251
+ */
252
+ trade(params: {
253
+ side: Side;
254
+ token: Address;
255
+ amountIn: bigint;
256
+ requestId?: string;
257
+ wait?: boolean;
258
+ timeoutMs?: number;
259
+ }): Promise<Intent>;
260
+ tradeStatus(intentId: string): Promise<Intent>;
261
+ waitForTrade(intent: Intent, timeoutMs?: number): Promise<Intent>;
262
+ /**
263
+ * Emergency stop: revokes all of this agent's credentials at once. `confirmUrl` (null without a session) is the
264
+ * revoke request the owner confirms to make it permanent on chain.
265
+ */
266
+ stop(): Promise<{
267
+ stopped: true;
268
+ revokedCredentials: number;
269
+ confirmUrl: string | null;
270
+ requestId: string | null;
271
+ }>;
272
+ /**
273
+ * Ask the owner for something only they can do (PRD WEB-01/03). Each call returns a request with a link and a
274
+ * summary for the owner; nothing happens until they confirm it with a passkey. Asking again for the same kind
275
+ * replaces the previous pending request.
276
+ */
277
+ readonly requests: {
278
+ authorize: (limits?: SessionLimits) => Promise<OwnerRequest>;
279
+ renew: (durationSeconds: number) => Promise<OwnerRequest>;
280
+ revoke: () => Promise<OwnerRequest>;
281
+ /** `to` must come from the owner, never from content the agent read. */
282
+ withdraw: (p: {
283
+ to: Address;
284
+ asset: "MNT" | Address;
285
+ amount: bigint | "max";
286
+ }) => Promise<OwnerRequest>;
287
+ autoRun: (s: AutoRunSettings) => Promise<OwnerRequest>;
288
+ resume: () => Promise<OwnerRequest>;
289
+ get: (requestId: string) => Promise<OwnerRequest>;
290
+ list: () => Promise<OwnerRequest[]>;
291
+ };
292
+ private ask;
293
+ /** Scheduled runs (PRD RUN-02/03). */
294
+ readonly runtime: {
295
+ status: () => Promise<RuntimeStatus>;
296
+ lease: (host: string) => Promise<Lease>;
297
+ complete: (leaseId: string, report?: {
298
+ summary?: string;
299
+ llmCostUsd?: number;
300
+ }) => Promise<undefined>;
301
+ ack: (commandId: string) => Promise<undefined>;
302
+ /** Agents may pause themselves; only the owner resumes. */
303
+ pause: () => Promise<{
304
+ commandId: string;
305
+ }>;
306
+ };
307
+ }
package/dist/agent.js ADDED
@@ -0,0 +1,149 @@
1
+ import { ClientError, request } from "./http.js";
2
+ const MNT = 10n ** 18n;
3
+ /** PRD V1 defaults: 2 MNT per trade, 10 MNT per 24 h, 20 MNT in total, 7 days, 2 % slippage. */
4
+ export const DEFAULT_SESSION_LIMITS = {
5
+ perTradeCap: 2n * MNT,
6
+ periodCap: 10n * MNT,
7
+ totalCap: 20n * MNT,
8
+ periodSeconds: 86_400,
9
+ durationSeconds: 7 * 86_400,
10
+ maxSlippageBps: 200,
11
+ };
12
+ const limitsJson = (l) => ({
13
+ perTradeCap: l.perTradeCap.toString(),
14
+ periodCap: l.periodCap.toString(),
15
+ totalCap: l.totalCap.toString(),
16
+ periodSeconds: l.periodSeconds,
17
+ durationSeconds: l.durationSeconds,
18
+ maxSlippageBps: l.maxSlippageBps,
19
+ });
20
+ const FINAL = new Set(["confirmed", "failed", "unknown"]);
21
+ /** Must match the API's claimProofMessage. */
22
+ export const claimProofMessage = (claimId) => `mantle-agent-claim:${claimId}`;
23
+ /**
24
+ * PRD IDN-02: register the agent key, hand the owner a link + code + fingerprint via `onClaim`, then poll with a
25
+ * proof of the key until the owner approves. Returns the credentials exactly once; store them securely.
26
+ */
27
+ export async function connectAgent(params) {
28
+ const claim = await startClaim(params);
29
+ await params.onClaim(claim);
30
+ for (;;) {
31
+ const result = await exchangeClaim({ ...params, claimId: claim.claimId });
32
+ if (result.status === "exchanged")
33
+ return result;
34
+ await new Promise((r) => setTimeout(r, params.pollMs ?? 2_000));
35
+ }
36
+ }
37
+ /** First half of `connectAgent`: register the key and get the link + code + fingerprint for the owner. */
38
+ export async function startClaim(params) {
39
+ const { body } = await request(params.fetch ?? fetch, params.baseUrl, "POST", "/v1/claims", {
40
+ body: {
41
+ agentName: params.agentName,
42
+ host: params.host,
43
+ publicKey: params.key.publicKey,
44
+ ...(params.authorize ? { authorize: limitsJson(params.authorize) } : {}),
45
+ },
46
+ });
47
+ return body;
48
+ }
49
+ /**
50
+ * Second half of `connectAgent`, one attempt: `pending` until the owner approves, then the credentials exactly once.
51
+ * Stateless, so an agent can start a claim, end its turn, and check again later (CLAIM_EXPIRED once it lapsed).
52
+ */
53
+ export async function exchangeClaim(params) {
54
+ const signature = await params.key.sign(claimProofMessage(params.claimId));
55
+ const { body } = await request(params.fetch ?? fetch, params.baseUrl, "POST", `/v1/claims/${params.claimId}/exchange`, {
56
+ body: { signature },
57
+ });
58
+ return body;
59
+ }
60
+ /**
61
+ * The agent's side of a Mantle Agent Account. It can only do what the owner authorized: trade within on-chain
62
+ * limits, read its status, manage its own scheduled runs, and stop itself. It never holds a private key.
63
+ */
64
+ export class AgentClient {
65
+ baseUrl;
66
+ credentials;
67
+ fetchImpl;
68
+ /** Set when running inside a scheduled run; trades are charged to that run's budget. */
69
+ leaseId;
70
+ constructor(baseUrl, credentials, opts = {}) {
71
+ this.baseUrl = baseUrl;
72
+ this.credentials = credentials;
73
+ this.fetchImpl = opts.fetch ?? ((...a) => fetch(...a));
74
+ this.leaseId = opts.leaseId;
75
+ }
76
+ async call(method, path, kind, opts = {}) {
77
+ const token = this.credentials?.[kind]?.token;
78
+ if (!token)
79
+ throw new ClientError("NOT_CONNECTED", "no credentials; connect the agent first");
80
+ return request(this.fetchImpl, this.baseUrl, method, path, { ...opts, token });
81
+ }
82
+ async status() {
83
+ return (await this.call("GET", "/v1/status", "trading")).body;
84
+ }
85
+ /** Price a trade. Valid ~30 s and for one trade. `amountIn` is wei (MNT for buys, tokens for sells). */
86
+ async quote(params) {
87
+ return (await this.call("POST", "/v1/quotes", "trading", { body: params })).body;
88
+ }
89
+ /**
90
+ * Quote and execute. Reuse `requestId` when retrying: the same trade is never executed twice. With `wait`, polls
91
+ * until confirmed / failed / unknown (or `timeoutMs`).
92
+ */
93
+ async trade(params) {
94
+ const quote = await this.quote(params);
95
+ const { body: intent } = await this.call("POST", "/v1/trades", "trading", {
96
+ body: { quoteId: quote.quoteId },
97
+ headers: { "idempotency-key": params.requestId ?? globalThis.crypto.randomUUID(), ...(this.leaseId ? { "x-run-lease": this.leaseId } : {}) },
98
+ });
99
+ return params.wait === false ? intent : this.waitForTrade(intent, params.timeoutMs);
100
+ }
101
+ async tradeStatus(intentId) {
102
+ return (await this.call("GET", `/v1/trades/${intentId}`, "trading")).body;
103
+ }
104
+ async waitForTrade(intent, timeoutMs = 90_000) {
105
+ const deadline = Date.now() + timeoutMs;
106
+ let current = intent;
107
+ while (!FINAL.has(current.status) && Date.now() < deadline) {
108
+ await new Promise((r) => setTimeout(r, 1_000));
109
+ current = await this.tradeStatus(current.intentId);
110
+ }
111
+ return current;
112
+ }
113
+ /**
114
+ * Emergency stop: revokes all of this agent's credentials at once. `confirmUrl` (null without a session) is the
115
+ * revoke request the owner confirms to make it permanent on chain.
116
+ */
117
+ async stop() {
118
+ return (await this.call("POST", "/v1/agent/stop", "runtime")).body;
119
+ }
120
+ /**
121
+ * Ask the owner for something only they can do (PRD WEB-01/03). Each call returns a request with a link and a
122
+ * summary for the owner; nothing happens until they confirm it with a passkey. Asking again for the same kind
123
+ * replaces the previous pending request.
124
+ */
125
+ requests = {
126
+ authorize: (limits = DEFAULT_SESSION_LIMITS) => this.ask("authorize", limitsJson(limits)),
127
+ renew: (durationSeconds) => this.ask("renew", { durationSeconds }),
128
+ revoke: () => this.ask("revoke", {}),
129
+ /** `to` must come from the owner, never from content the agent read. */
130
+ withdraw: (p) => this.ask("withdraw", { to: p.to, asset: p.asset, amount: p.amount === "max" ? "max" : p.amount.toString() }),
131
+ autoRun: (s) => this.ask("runtime", { ...s, maxSpendPerDay: s.maxSpendPerDay.toString() }),
132
+ resume: () => this.ask("resume", {}),
133
+ get: async (requestId) => (await this.call("GET", `/v1/requests/${requestId}`, "trading")).body,
134
+ list: async () => (await this.call("GET", "/v1/requests", "trading")).body,
135
+ };
136
+ async ask(kind, params) {
137
+ return (await this.call("POST", "/v1/requests", "trading", { body: { kind, params } })).body;
138
+ }
139
+ /** Scheduled runs (PRD RUN-02/03). */
140
+ runtime = {
141
+ status: async () => (await this.call("GET", "/v1/runtime", "trading")).body,
142
+ lease: async (host) => (await this.call("POST", "/v1/runtime/lease", "runtime", { body: { host } })).body,
143
+ complete: async (leaseId, report = {}) => void (await this.call("POST", `/v1/runtime/lease/${leaseId}/complete`, "runtime", { body: report })),
144
+ ack: async (commandId) => void (await this.call("POST", `/v1/runtime/commands/${commandId}/ack`, "runtime")),
145
+ /** Agents may pause themselves; only the owner resumes. */
146
+ pause: async () => (await this.call("POST", "/v1/runtime/pause", "runtime")).body,
147
+ };
148
+ }
149
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { OwnerTurnkey } from "./owner.js";
2
+ /** Production: every owner action is approved with a passkey bound to this site (rpId = hostname). */
3
+ export declare function passkeyTurnkey(params: {
4
+ parentOrgId: string;
5
+ rpId?: string;
6
+ apiBaseUrl?: string;
7
+ }): OwnerTurnkey;
8
+ /**
9
+ * Development only (no passkeys, e.g. local or automated testing): a P-256 API key kept in this browser stands in
10
+ * for the passkey. The API accepts such owners only with ALLOW_API_KEY_OWNERS=true.
11
+ */
12
+ export declare function devKeyTurnkey(params: {
13
+ parentOrgId: string;
14
+ apiBaseUrl?: string;
15
+ storage?: Storage;
16
+ }): OwnerTurnkey;
@@ -0,0 +1,53 @@
1
+ // Browser-only: Turnkey passkey (production) and dev-key owners for the confirmation page.
2
+ import { ApiKeyStamper } from "@turnkey/api-key-stamper";
3
+ import { generateP256KeyPair } from "@turnkey/crypto";
4
+ import { Turnkey, TurnkeyBrowserClient } from "@turnkey/sdk-browser";
5
+ import { rootSigner, TURNKEY_API_BASE_URL } from "@mantle-agent/custody/owner";
6
+ function fromClient(kind, client, parentOrgId, register) {
7
+ return {
8
+ kind,
9
+ register,
10
+ async stampWhoami() {
11
+ const signed = await client.stampGetWhoami({ organizationId: parentOrgId });
12
+ if (!signed)
13
+ throw new Error("could not produce a signed login request");
14
+ return signed;
15
+ },
16
+ owner: () => client,
17
+ rootSigner: (subOrgId, address) => rootSigner({ client: client, subOrgId, rootAddress: address }),
18
+ };
19
+ }
20
+ /** Production: every owner action is approved with a passkey bound to this site (rpId = hostname). */
21
+ export function passkeyTurnkey(params) {
22
+ const rpId = params.rpId ?? window.location.hostname;
23
+ const sdk = new Turnkey({ apiBaseUrl: params.apiBaseUrl ?? TURNKEY_API_BASE_URL, defaultOrganizationId: params.parentOrgId, rpId });
24
+ const client = sdk.passkeyClient();
25
+ return fromClient("passkey", client, params.parentOrgId, async (ownerName) => {
26
+ const { encodedChallenge, attestation } = await client.createUserPasskey({
27
+ publicKey: { rp: { id: rpId, name: "Mantle Agent Account" }, user: { name: ownerName, displayName: ownerName } },
28
+ });
29
+ return { passkey: { authenticatorName: `passkey-${Date.now()}`, challenge: encodedChallenge, attestation } };
30
+ });
31
+ }
32
+ const DEV_KEY_STORAGE = "mantle-agent:dev-owner-key";
33
+ /**
34
+ * Development only (no passkeys, e.g. local or automated testing): a P-256 API key kept in this browser stands in
35
+ * for the passkey. The API accepts such owners only with ALLOW_API_KEY_OWNERS=true.
36
+ */
37
+ export function devKeyTurnkey(params) {
38
+ const storage = params.storage ?? window.localStorage;
39
+ let saved = storage.getItem(DEV_KEY_STORAGE);
40
+ if (!saved) {
41
+ const kp = generateP256KeyPair();
42
+ saved = JSON.stringify({ publicKey: kp.publicKey, privateKey: kp.privateKey });
43
+ storage.setItem(DEV_KEY_STORAGE, saved);
44
+ }
45
+ const key = JSON.parse(saved);
46
+ const client = new TurnkeyBrowserClient({
47
+ stamper: new ApiKeyStamper({ apiPublicKey: key.publicKey, apiPrivateKey: key.privateKey }),
48
+ apiBaseUrl: params.apiBaseUrl ?? TURNKEY_API_BASE_URL,
49
+ organizationId: params.parentOrgId,
50
+ });
51
+ return fromClient("dev-key", client, params.parentOrgId, async () => ({ apiPublicKey: key.publicKey }));
52
+ }
53
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * A failure with the Mantle Agent API's stable error code (or a local one such as NOT_CONNECTED or
3
+ * API_UNREACHABLE). React to `code`, not to the message.
4
+ */
5
+ export declare class ClientError extends Error {
6
+ readonly code: string;
7
+ readonly details?: unknown | undefined;
8
+ readonly status?: number | undefined;
9
+ constructor(code: string, message: string, details?: unknown | undefined, status?: number | undefined);
10
+ }
11
+ export type Fetch = typeof fetch;
12
+ export type RequestOptions = {
13
+ token?: string | null;
14
+ body?: unknown;
15
+ headers?: Record<string, string>;
16
+ };
17
+ /** JSON request against the API; non-2xx responses become ClientError with the API's code. */
18
+ export declare function request<T>(fetchImpl: Fetch, baseUrl: string, method: "GET" | "POST", path: string, opts?: RequestOptions): Promise<{
19
+ status: number;
20
+ body: T;
21
+ }>;