@clawpump/claw-agent 0.1.7 → 0.1.9
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/agent/.mailmap +4 -0
- package/agent/apps/desktop/README.md +3 -3
- package/agent/apps/desktop/assets/icon.icns +0 -0
- package/agent/apps/desktop/assets/icon.ico +0 -0
- package/agent/apps/desktop/assets/icon.png +0 -0
- package/agent/apps/desktop/electron/backend-ready.cjs +2 -2
- package/agent/apps/desktop/electron/dashboard-token.cjs +3 -3
- package/agent/apps/desktop/electron/hardening.cjs +1 -1
- package/agent/apps/desktop/electron/main.cjs +65 -65
- package/agent/apps/desktop/index.html +1 -1
- package/agent/apps/desktop/package.json +11 -11
- package/agent/apps/desktop/public/apple-touch-icon.png +0 -0
- package/agent/apps/desktop/public/claw-mark.png +0 -0
- package/agent/apps/desktop/scripts/set-exe-identity.cjs +2 -2
- package/agent/apps/desktop/src/app/chat/composer/controls.tsx +2 -0
- package/agent/apps/desktop/src/app/chat/composer/index.tsx +10 -0
- package/agent/apps/desktop/src/app/chat/composer/pod-credits.tsx +49 -0
- package/agent/apps/desktop/src/app/chat/index.tsx +1 -1
- package/agent/apps/desktop/src/app/chat/sidebar/index.tsx +4 -2
- package/agent/apps/desktop/src/app/desktop-controller.tsx +18 -0
- package/agent/apps/desktop/src/app/gateway/hooks/use-gateway-request.ts +1 -1
- package/agent/apps/desktop/src/app/messaging/index.tsx +5 -5
- package/agent/apps/desktop/src/app/routes.ts +9 -1
- package/agent/apps/desktop/src/app/session/hooks/use-message-stream.ts +3 -3
- package/agent/apps/desktop/src/app/settings/constants.ts +5 -5
- package/agent/apps/desktop/src/app/settings/model-settings.tsx +1 -1
- package/agent/apps/desktop/src/app/settings/providers-settings.tsx +46 -1
- package/agent/apps/desktop/src/app/settings/uninstall-section.tsx +5 -5
- package/agent/apps/desktop/src/app/types.ts +9 -1
- package/agent/apps/desktop/src/app/wallet/index.tsx +244 -0
- package/agent/apps/desktop/src/app/x402/index.tsx +162 -0
- package/agent/apps/desktop/src/components/assistant-ui/thread.tsx +1 -1
- package/agent/apps/desktop/src/components/brand-mark.tsx +2 -2
- package/agent/apps/desktop/src/components/chat/intro-copy.jsonl +6 -6
- package/agent/apps/desktop/src/components/chat/intro.tsx +4 -4
- package/agent/apps/desktop/src/components/model-picker.tsx +64 -4
- package/agent/apps/desktop/src/components/pod-setup-dialog.tsx +227 -0
- package/agent/apps/desktop/src/hermes.ts +109 -3
- package/agent/apps/desktop/src/i18n/en.ts +80 -78
- package/agent/apps/desktop/src/i18n/ja.ts +82 -82
- package/agent/apps/desktop/src/i18n/runtime.test.ts +2 -2
- package/agent/apps/desktop/src/i18n/zh-hant.ts +82 -82
- package/agent/apps/desktop/src/i18n/zh.ts +87 -87
- package/agent/apps/desktop/src/lib/desktop-fs.ts +1 -1
- package/agent/apps/desktop/src/lib/desktop-slash-commands.ts +4 -4
- package/agent/apps/desktop/src/store/composer.ts +7 -0
- package/agent/apps/desktop/src/store/onboarding.ts +5 -5
- package/agent/apps/desktop/src/themes/presets.ts +54 -54
- package/agent/cli.py +184 -10
- package/agent/hermes_cli/distribution.py +188 -8
- package/agent/hermes_cli/providers.py +29 -0
- package/agent/hermes_cli/web_server.py +403 -34
- package/agent/plugins/model-providers/usepod/__init__.py +7 -1
- package/agent/scripts/release.py +1 -0
- package/agent/web/public/claw-logo.png +0 -0
- package/agent/web/src/App.tsx +6 -4
- package/agent/web/src/components/ChatSidebar.tsx +5 -0
- package/agent/web/src/components/ModelPickerDialog.tsx +28 -1
- package/agent/web/src/components/PodCredits.tsx +57 -0
- package/agent/web/src/components/PodSetupDialog.tsx +240 -0
- package/agent/web/src/lib/api.ts +135 -0
- package/agent/web/src/pages/AgentMailPage.tsx +684 -0
- package/agent/web/src/pages/WalletPage.tsx +53 -5
- package/package.json +1 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { api } from "@/lib/api";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Compact "Pod $X.XX" credits pill, shown next to the model badge only when the
|
|
6
|
+
* active provider is UsePod (Pod). Polls /api/clawpump/pod/status; keeps the
|
|
7
|
+
* last value so a transient probe failure never blanks it. Mirrors the desktop
|
|
8
|
+
* PodCredits.
|
|
9
|
+
*/
|
|
10
|
+
export default function PodCredits({ provider }: { provider: string }) {
|
|
11
|
+
const isPod = provider === "usepod";
|
|
12
|
+
const [balance, setBalance] = useState<number | null>(null);
|
|
13
|
+
const [connected, setConnected] = useState(false);
|
|
14
|
+
const lastBalance = useRef<number | null>(null);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!isPod) return;
|
|
18
|
+
let cancelled = false;
|
|
19
|
+
const tick = () => {
|
|
20
|
+
void api
|
|
21
|
+
.getPodStatus()
|
|
22
|
+
.then((r) => {
|
|
23
|
+
if (cancelled) return;
|
|
24
|
+
setConnected(!!r.connected);
|
|
25
|
+
if (r.balance_usdc != null) {
|
|
26
|
+
lastBalance.current = r.balance_usdc;
|
|
27
|
+
setBalance(r.balance_usdc);
|
|
28
|
+
} else if (lastBalance.current != null) {
|
|
29
|
+
setBalance(lastBalance.current);
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
.catch(() => undefined);
|
|
33
|
+
};
|
|
34
|
+
tick();
|
|
35
|
+
const id = window.setInterval(tick, 60_000);
|
|
36
|
+
return () => {
|
|
37
|
+
cancelled = true;
|
|
38
|
+
window.clearInterval(id);
|
|
39
|
+
};
|
|
40
|
+
}, [isPod]);
|
|
41
|
+
|
|
42
|
+
if (!isPod || !connected) return null;
|
|
43
|
+
|
|
44
|
+
const low = balance != null && balance < 0.5;
|
|
45
|
+
return (
|
|
46
|
+
<span
|
|
47
|
+
title={balance != null ? `Pod credits: $${balance.toFixed(4)} USDC` : "Pod connected"}
|
|
48
|
+
className={`inline-flex shrink-0 items-center gap-1 rounded-md border px-1.5 py-0.5 text-[0.6875rem] font-medium ${
|
|
49
|
+
low
|
|
50
|
+
? "border-amber-500/40 bg-amber-500/10 text-amber-300"
|
|
51
|
+
: "border-emerald-500/30 bg-emerald-500/10 text-emerald-300"
|
|
52
|
+
}`}
|
|
53
|
+
>
|
|
54
|
+
⚡ {balance != null ? `$${balance.toFixed(2)}` : "Pod"}
|
|
55
|
+
</span>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { Zap } from "lucide-react";
|
|
3
|
+
import { api } from "@/lib/api";
|
|
4
|
+
import type { AgentWalletBalance } from "@/lib/api";
|
|
5
|
+
import { Button } from "@nous-research/ui/ui/components/button";
|
|
6
|
+
import { Input } from "@nous-research/ui/ui/components/input";
|
|
7
|
+
import { Select, SelectOption } from "@nous-research/ui/ui/components/select";
|
|
8
|
+
import { Spinner } from "@nous-research/ui/ui/components/spinner";
|
|
9
|
+
|
|
10
|
+
const DEFAULT_AMOUNT = "5";
|
|
11
|
+
|
|
12
|
+
const walletLabel = (w: AgentWalletBalance): string =>
|
|
13
|
+
w.name ||
|
|
14
|
+
(w.wallet_address
|
|
15
|
+
? `${w.wallet_address.slice(0, 4)}…${w.wallet_address.slice(-4)}`
|
|
16
|
+
: w.agent_id);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* One-screen Pod setup for the web dashboard: pick a ClawPump agent wallet, pick
|
|
20
|
+
* an amount, confirm. `usepod_provision` registers + funds a pod from that wallet
|
|
21
|
+
* on-chain in one call, and the backend switches the session onto Pod as the
|
|
22
|
+
* provider. The single confirm is the on-chain USDC spend; everything else is
|
|
23
|
+
* prefilled. Mirrors the desktop PodSetupDialog.
|
|
24
|
+
*/
|
|
25
|
+
export default function PodSetupDialog({
|
|
26
|
+
onClose,
|
|
27
|
+
onProvisioned,
|
|
28
|
+
}: {
|
|
29
|
+
onClose: () => void;
|
|
30
|
+
onProvisioned: (model: string) => void;
|
|
31
|
+
}) {
|
|
32
|
+
const [wallets, setWallets] = useState<AgentWalletBalance[] | null>(null);
|
|
33
|
+
const [loadError, setLoadError] = useState<string | null>(null);
|
|
34
|
+
const [agentId, setAgentId] = useState("");
|
|
35
|
+
const [amount, setAmount] = useState(DEFAULT_AMOUNT);
|
|
36
|
+
const [busy, setBusy] = useState(false);
|
|
37
|
+
const [error, setError] = useState<string | null>(null);
|
|
38
|
+
const [done, setDone] = useState<{
|
|
39
|
+
model: string;
|
|
40
|
+
amount: number;
|
|
41
|
+
signature?: string;
|
|
42
|
+
fundingError?: string;
|
|
43
|
+
} | null>(null);
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
let cancelled = false;
|
|
47
|
+
void api
|
|
48
|
+
.getWalletBalances()
|
|
49
|
+
.then((r) => {
|
|
50
|
+
if (cancelled) return;
|
|
51
|
+
const rows = (r.wallets ?? []).filter((w) => w.agent_id);
|
|
52
|
+
setWallets(rows);
|
|
53
|
+
if (rows.length > 0) {
|
|
54
|
+
const best = [...rows].sort(
|
|
55
|
+
(a, b) => (b.usdc_balance ?? 0) - (a.usdc_balance ?? 0),
|
|
56
|
+
)[0];
|
|
57
|
+
setAgentId(best.agent_id);
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
.catch((e) => !cancelled && setLoadError(e instanceof Error ? e.message : "Failed to load wallets"));
|
|
61
|
+
return () => {
|
|
62
|
+
cancelled = true;
|
|
63
|
+
};
|
|
64
|
+
}, []);
|
|
65
|
+
|
|
66
|
+
const rows = wallets ?? [];
|
|
67
|
+
const selected = rows.find((w) => w.agent_id === agentId) ?? null;
|
|
68
|
+
const amountNum = Number(amount);
|
|
69
|
+
const balance = selected?.usdc_balance ?? 0;
|
|
70
|
+
const insufficient = Number.isFinite(amountNum) && amountNum > 0 && amountNum > balance;
|
|
71
|
+
const canFund =
|
|
72
|
+
!busy && Boolean(agentId) && Number.isFinite(amountNum) && amountNum > 0 && !insufficient;
|
|
73
|
+
|
|
74
|
+
const heading = useMemo(() => (done ? "Pod ready" : "Set up Pod"), [done]);
|
|
75
|
+
|
|
76
|
+
// Ref guard: setBusy is async, so a fast double-click could fire two
|
|
77
|
+
// provisions (= double on-chain spend) before the disabled state re-renders.
|
|
78
|
+
const submitting = useRef(false);
|
|
79
|
+
|
|
80
|
+
const fund = async () => {
|
|
81
|
+
if (!canFund || submitting.current) return;
|
|
82
|
+
submitting.current = true;
|
|
83
|
+
setBusy(true);
|
|
84
|
+
setError(null);
|
|
85
|
+
try {
|
|
86
|
+
const res = await api.provisionPod(agentId, amountNum);
|
|
87
|
+
if (!res.ok || !res.model) {
|
|
88
|
+
setError(res.error || res.funding_error || "Pod setup failed. Check the wallet balance and try again.");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Show the "Pod ready" view; the actual session switch + close happens on
|
|
92
|
+
// Done (onProvisioned), because the switch unmounts this dialog.
|
|
93
|
+
setDone({
|
|
94
|
+
amount: amountNum,
|
|
95
|
+
model: res.model,
|
|
96
|
+
signature: res.signature,
|
|
97
|
+
fundingError: res.funding_error || undefined,
|
|
98
|
+
});
|
|
99
|
+
} catch (e) {
|
|
100
|
+
setError(e instanceof Error ? e.message : "Pod setup failed.");
|
|
101
|
+
} finally {
|
|
102
|
+
setBusy(false);
|
|
103
|
+
submitting.current = false;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<div
|
|
109
|
+
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
|
|
110
|
+
onClick={() => {
|
|
111
|
+
if (busy) return;
|
|
112
|
+
// After a successful provision, dismissing applies the switch (same as
|
|
113
|
+
// Done) so a backdrop click doesn't silently skip using the new Pod.
|
|
114
|
+
if (done) onProvisioned(done.model);
|
|
115
|
+
else onClose();
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
<div
|
|
119
|
+
className="w-full max-w-md rounded-lg border border-border bg-card shadow-xl"
|
|
120
|
+
onClick={(e) => e.stopPropagation()}
|
|
121
|
+
>
|
|
122
|
+
<div className="flex items-center gap-2 border-b border-border px-4 py-3">
|
|
123
|
+
<Zap className="h-4 w-4 text-primary" />
|
|
124
|
+
<h2 className="text-sm font-semibold">
|
|
125
|
+
{done?.fundingError ? "Pod created — funding failed" : heading}
|
|
126
|
+
</h2>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
{done ? (
|
|
130
|
+
<div className="flex flex-col gap-3 p-4">
|
|
131
|
+
{done.fundingError ? (
|
|
132
|
+
<div className="rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-3 text-sm">
|
|
133
|
+
<div className="font-semibold text-amber-300">⚠ Pod created but not funded</div>
|
|
134
|
+
<div className="mt-0.5 text-muted-foreground">
|
|
135
|
+
The on-chain deposit didn’t confirm ({done.fundingError}). The pod (
|
|
136
|
+
<span className="font-mono">{done.model}</span>) is selected but has no balance — it
|
|
137
|
+
may settle shortly, or run Set up Pod again to top it up.
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
) : (
|
|
141
|
+
<div className="rounded-md border border-emerald-500/30 bg-emerald-500/10 px-3 py-3 text-sm">
|
|
142
|
+
<div className="font-semibold text-emerald-300">⚡ Using Pod</div>
|
|
143
|
+
<div className="mt-0.5 text-muted-foreground">
|
|
144
|
+
Funded <span className="font-mono">${done.amount.toFixed(2)} USDC</span> · model{" "}
|
|
145
|
+
<span className="font-mono">{done.model}</span>. New chats run on Pod automatically.
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
)}
|
|
149
|
+
{done.signature && (
|
|
150
|
+
<a
|
|
151
|
+
className="text-xs text-primary hover:underline"
|
|
152
|
+
href={`https://solscan.io/tx/${done.signature}`}
|
|
153
|
+
rel="noreferrer"
|
|
154
|
+
target="_blank"
|
|
155
|
+
>
|
|
156
|
+
View funding transaction ↗
|
|
157
|
+
</a>
|
|
158
|
+
)}
|
|
159
|
+
<div className="flex justify-end">
|
|
160
|
+
<Button onClick={() => onProvisioned(done.model)}>Done</Button>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
) : (
|
|
164
|
+
<>
|
|
165
|
+
<div className="flex flex-col gap-4 p-4">
|
|
166
|
+
<p className="text-xs leading-relaxed text-muted-foreground">
|
|
167
|
+
Fund a private inference Pod from a ClawPump agent wallet and use it as your model
|
|
168
|
+
provider. You only pay for what you use — the Pod holds a prepaid USDC balance.
|
|
169
|
+
</p>
|
|
170
|
+
|
|
171
|
+
{wallets === null ? (
|
|
172
|
+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
173
|
+
<Spinner className="text-xs" /> Loading your wallets…
|
|
174
|
+
</div>
|
|
175
|
+
) : loadError || rows.length === 0 ? (
|
|
176
|
+
<div className="rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-xs text-amber-300">
|
|
177
|
+
{loadError ||
|
|
178
|
+
"No ClawPump agent wallets found. Create one in the ClawPump dashboard first."}
|
|
179
|
+
</div>
|
|
180
|
+
) : (
|
|
181
|
+
<>
|
|
182
|
+
<label className="flex flex-col gap-1.5 text-sm">
|
|
183
|
+
<span className="font-medium">Pay from wallet</span>
|
|
184
|
+
<Select value={agentId} onValueChange={setAgentId}>
|
|
185
|
+
{rows.map((w) => (
|
|
186
|
+
<SelectOption key={w.agent_id} value={w.agent_id}>
|
|
187
|
+
{`${walletLabel(w)} — $${(w.usdc_balance ?? 0).toFixed(2)} USDC`}
|
|
188
|
+
</SelectOption>
|
|
189
|
+
))}
|
|
190
|
+
</Select>
|
|
191
|
+
</label>
|
|
192
|
+
|
|
193
|
+
<label className="flex flex-col gap-1.5 text-sm">
|
|
194
|
+
<span className="font-medium">Amount to fund (USDC)</span>
|
|
195
|
+
<Input
|
|
196
|
+
type="number"
|
|
197
|
+
min="0"
|
|
198
|
+
step="1"
|
|
199
|
+
value={amount}
|
|
200
|
+
onChange={(e) => setAmount(e.target.value)}
|
|
201
|
+
/>
|
|
202
|
+
<span className="text-xs text-muted-foreground">
|
|
203
|
+
Wallet balance: <span className="font-mono">${balance.toFixed(2)} USDC</span>
|
|
204
|
+
</span>
|
|
205
|
+
</label>
|
|
206
|
+
|
|
207
|
+
{insufficient && (
|
|
208
|
+
<div className="rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-xs text-amber-300">
|
|
209
|
+
Not enough USDC in this wallet for ${amountNum.toFixed(2)}. Pick a smaller amount.
|
|
210
|
+
</div>
|
|
211
|
+
)}
|
|
212
|
+
{error && (
|
|
213
|
+
<div className="rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive">
|
|
214
|
+
{error}
|
|
215
|
+
</div>
|
|
216
|
+
)}
|
|
217
|
+
</>
|
|
218
|
+
)}
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
<div className="flex justify-end gap-2 border-t border-border px-4 py-3">
|
|
222
|
+
<Button variant="outline" disabled={busy} onClick={onClose}>
|
|
223
|
+
Cancel
|
|
224
|
+
</Button>
|
|
225
|
+
<Button disabled={!canFund} onClick={() => void fund()}>
|
|
226
|
+
{busy ? (
|
|
227
|
+
<span className="flex items-center gap-2">
|
|
228
|
+
<Spinner className="text-xs" /> Funding Pod…
|
|
229
|
+
</span>
|
|
230
|
+
) : (
|
|
231
|
+
`Fund $${Number.isFinite(amountNum) ? amountNum.toFixed(2) : "0.00"} & use Pod`
|
|
232
|
+
)}
|
|
233
|
+
</Button>
|
|
234
|
+
</div>
|
|
235
|
+
</>
|
|
236
|
+
)}
|
|
237
|
+
</div>
|
|
238
|
+
</div>
|
|
239
|
+
);
|
|
240
|
+
}
|
package/agent/web/src/lib/api.ts
CHANGED
|
@@ -313,6 +313,8 @@ function appendProfileParam(url: string, profile?: string): string {
|
|
|
313
313
|
export interface AgentWalletBalance {
|
|
314
314
|
agent_id: string;
|
|
315
315
|
name?: string | null;
|
|
316
|
+
avatar_url?: string | null;
|
|
317
|
+
token_mint?: string | null;
|
|
316
318
|
wallet_address: string | null;
|
|
317
319
|
sol_balance: number | null;
|
|
318
320
|
usdc_balance: number | null;
|
|
@@ -341,6 +343,19 @@ export interface WalletTransferResponse {
|
|
|
341
343
|
result?: unknown;
|
|
342
344
|
}
|
|
343
345
|
|
|
346
|
+
export interface PodStatusResponse {
|
|
347
|
+
connected: boolean;
|
|
348
|
+
balance_usdc?: number | null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export interface PodProvisionResponse {
|
|
352
|
+
ok: boolean;
|
|
353
|
+
model?: string;
|
|
354
|
+
signature?: string;
|
|
355
|
+
funding_error?: string;
|
|
356
|
+
error?: string;
|
|
357
|
+
}
|
|
358
|
+
|
|
344
359
|
export interface X402Pricing {
|
|
345
360
|
network?: string;
|
|
346
361
|
asset?: string;
|
|
@@ -369,6 +384,86 @@ export interface X402SearchResponse {
|
|
|
369
384
|
results: X402Result[];
|
|
370
385
|
}
|
|
371
386
|
|
|
387
|
+
// ── Agent Mail (AgentMail, via the ClawPump MCP) ───────────────────────
|
|
388
|
+
export interface MailInbox {
|
|
389
|
+
id: string;
|
|
390
|
+
agentId: string;
|
|
391
|
+
provider: string;
|
|
392
|
+
inboxId: string;
|
|
393
|
+
emailAddress: string;
|
|
394
|
+
username: string;
|
|
395
|
+
domain: string;
|
|
396
|
+
webhookId: string | null;
|
|
397
|
+
verified: boolean;
|
|
398
|
+
status: string;
|
|
399
|
+
createdAt: string;
|
|
400
|
+
updatedAt: string;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export interface MailMessage {
|
|
404
|
+
id: string;
|
|
405
|
+
agentId: string;
|
|
406
|
+
inboxId: string;
|
|
407
|
+
messageId: string;
|
|
408
|
+
threadId: string | null;
|
|
409
|
+
direction: "inbound" | "outbound";
|
|
410
|
+
fromAddress: string | null;
|
|
411
|
+
toAddresses: string[];
|
|
412
|
+
ccAddresses: string[];
|
|
413
|
+
subject: string | null;
|
|
414
|
+
textBody: string | null;
|
|
415
|
+
htmlBody: string | null;
|
|
416
|
+
preview: string | null;
|
|
417
|
+
read: boolean;
|
|
418
|
+
agentmailCreatedAt: string | null;
|
|
419
|
+
createdAt: string;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export interface MailAddressResponse {
|
|
423
|
+
ok: boolean;
|
|
424
|
+
error?: string;
|
|
425
|
+
has_inbox: boolean;
|
|
426
|
+
inbox: MailInbox | null;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export interface MailMessagesResponse {
|
|
430
|
+
ok: boolean;
|
|
431
|
+
error?: string;
|
|
432
|
+
messages: MailMessage[];
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export interface MailMessageResponse {
|
|
436
|
+
ok: boolean;
|
|
437
|
+
error?: string;
|
|
438
|
+
message: MailMessage | null;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export interface MailCreateResponse {
|
|
442
|
+
ok: boolean;
|
|
443
|
+
error?: string;
|
|
444
|
+
inbox?: MailInbox | null;
|
|
445
|
+
alreadyExisted?: boolean;
|
|
446
|
+
note?: string | null;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
export interface MailSendBody {
|
|
450
|
+
agent_id: string;
|
|
451
|
+
to: string[];
|
|
452
|
+
subject: string;
|
|
453
|
+
text?: string;
|
|
454
|
+
html?: string;
|
|
455
|
+
cc?: string[];
|
|
456
|
+
bcc?: string[];
|
|
457
|
+
reply_to?: string;
|
|
458
|
+
confirm: boolean;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export interface MailSendResponse {
|
|
462
|
+
ok: boolean;
|
|
463
|
+
error?: string;
|
|
464
|
+
result?: unknown;
|
|
465
|
+
}
|
|
466
|
+
|
|
372
467
|
export const api = {
|
|
373
468
|
getStatus: () => fetchJSON<StatusResponse>("/api/status"),
|
|
374
469
|
getWalletBalances: () =>
|
|
@@ -381,6 +476,46 @@ export const api = {
|
|
|
381
476
|
headers: { "Content-Type": "application/json" },
|
|
382
477
|
body: JSON.stringify(body),
|
|
383
478
|
}),
|
|
479
|
+
|
|
480
|
+
// ── UsePod "Pod" — pay-as-you-go inference funded from a ClawPump wallet ──
|
|
481
|
+
getPodStatus: () =>
|
|
482
|
+
fetchJSON<PodStatusResponse>("/api/clawpump/pod/status"),
|
|
483
|
+
provisionPod: (agentId: string, amount: number) =>
|
|
484
|
+
fetchJSON<PodProvisionResponse>("/api/clawpump/pod/provision", {
|
|
485
|
+
method: "POST",
|
|
486
|
+
headers: { "Content-Type": "application/json" },
|
|
487
|
+
body: JSON.stringify({ agent_id: agentId, amount }),
|
|
488
|
+
}),
|
|
489
|
+
|
|
490
|
+
// ── Agent Mail (AgentMail) ─────────────────────────────────────────
|
|
491
|
+
// Every call carries an explicit agent_id — the MCP requires it once the
|
|
492
|
+
// account has more than one agent.
|
|
493
|
+
getMailAddress: (agentId: string) =>
|
|
494
|
+
fetchJSON<MailAddressResponse>(
|
|
495
|
+
`/api/mail/address?agent_id=${encodeURIComponent(agentId)}`,
|
|
496
|
+
),
|
|
497
|
+
listMail: (opts: { agentId: string; direction?: "inbound" | "outbound"; limit?: number }) => {
|
|
498
|
+
const qs = new URLSearchParams({ agent_id: opts.agentId });
|
|
499
|
+
if (opts.direction) qs.set("direction", opts.direction);
|
|
500
|
+
if (opts.limit) qs.set("limit", String(opts.limit));
|
|
501
|
+
return fetchJSON<MailMessagesResponse>(`/api/mail/messages?${qs.toString()}`);
|
|
502
|
+
},
|
|
503
|
+
readMail: (messageId: string, agentId: string) =>
|
|
504
|
+
fetchJSON<MailMessageResponse>(
|
|
505
|
+
`/api/mail/message?message_id=${encodeURIComponent(messageId)}&agent_id=${encodeURIComponent(agentId)}`,
|
|
506
|
+
),
|
|
507
|
+
createInbox: (body: { agent_id: string; username?: string; confirm: boolean }) =>
|
|
508
|
+
fetchJSON<MailCreateResponse>("/api/mail/create", {
|
|
509
|
+
method: "POST",
|
|
510
|
+
headers: { "Content-Type": "application/json" },
|
|
511
|
+
body: JSON.stringify(body),
|
|
512
|
+
}),
|
|
513
|
+
sendMail: (body: MailSendBody) =>
|
|
514
|
+
fetchJSON<MailSendResponse>("/api/mail/send", {
|
|
515
|
+
method: "POST",
|
|
516
|
+
headers: { "Content-Type": "application/json" },
|
|
517
|
+
body: JSON.stringify(body),
|
|
518
|
+
}),
|
|
384
519
|
/**
|
|
385
520
|
* Identity probe for the dashboard auth gate (Phase 7).
|
|
386
521
|
*
|