@lucid-agents/taskmarket 1.17.0 → 1.17.2
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/dist/agent-compatibility.json +1 -1
- package/dist/budget-view-XKZC3GY5.js +36 -0
- package/dist/channels-JF4Q5KG3.js +29 -0
- package/dist/chunk-52Q2DCZN.js +1099 -0
- package/dist/chunk-73RXOYME.js +185 -0
- package/dist/{chunk-3XPF2O6L.js → chunk-FRV3ZHUR.js} +5381 -6300
- package/dist/chunk-GJQUALXN.js +1062 -0
- package/dist/chunk-LDCFKFF6.js +154 -0
- package/dist/{compatibility-F3RC2GX7.js → chunk-OKZ2NRYZ.js} +5 -5
- package/dist/chunk-XXD7TWLP.js +181 -0
- package/dist/{chunk-O27J7ZPH.js → chunk-YM4S6IE4.js} +2 -1
- package/dist/compatibility-KUYGZSUC.js +19 -0
- package/dist/doctor-7TWLIJWW.js +216 -0
- package/dist/{errors-F3EGNA4F.js → errors-2L357HGA.js} +1 -1
- package/dist/index.js +317 -162
- package/dist/{launch-EZJGJJ5Y.js → launch-2U3KFTFD.js} +1414 -700
- package/dist/pi-extensions/remote-tools.cjs +103 -0
- package/dist/pi-extensions/xgate.cjs +310 -5
- package/dist/reconcile-XZR2UYSW.js +83 -0
- package/dist/status-5IMULBQQ.js +18 -0
- package/package.json +3 -3
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { createRequire as __tmCreateRequire } from 'node:module'; import { fileURLToPath as __tmFileURLToPath } from 'node:url'; import { dirname as __tmDirname } from 'node:path'; const require = __tmCreateRequire(import.meta.url); const __tmFilename = __tmFileURLToPath(import.meta.url); const __tmDirnameValue = __tmDirname(__tmFilename);
|
|
2
|
+
import {
|
|
3
|
+
buyComputeCredit,
|
|
4
|
+
fetchComputePricing,
|
|
5
|
+
listPendingComputePurchases,
|
|
6
|
+
loadComputeCreditConfig,
|
|
7
|
+
onComputeBalanceObserved,
|
|
8
|
+
readComputeCreditStatus
|
|
9
|
+
} from "./chunk-52Q2DCZN.js";
|
|
10
|
+
import {
|
|
11
|
+
AgentLaunchError
|
|
12
|
+
} from "./chunk-YM4S6IE4.js";
|
|
13
|
+
import {
|
|
14
|
+
burnRate,
|
|
15
|
+
computeLow
|
|
16
|
+
} from "./chunk-73RXOYME.js";
|
|
17
|
+
|
|
18
|
+
// ../../packages/remote-tools/dist/backend.js
|
|
19
|
+
var SANDBOX_TOOL_USER = "agent";
|
|
20
|
+
var SandboxUnavailableError = class extends Error {
|
|
21
|
+
reason;
|
|
22
|
+
constructor(reason, options) {
|
|
23
|
+
super(`Sandbox unavailable, tools are disabled (no local fallback): ${reason}`, options);
|
|
24
|
+
this.name = "SandboxUnavailableError";
|
|
25
|
+
this.reason = reason;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/lib/agent/compute.ts
|
|
30
|
+
async function readComputeView(options = {}) {
|
|
31
|
+
const warning = options.warning ?? null;
|
|
32
|
+
const empty = {
|
|
33
|
+
availableCredits: null,
|
|
34
|
+
reservedCredits: null,
|
|
35
|
+
burnCreditsPerHour: null,
|
|
36
|
+
low: warning === "low_credit" || warning === "credit_exhausted",
|
|
37
|
+
warning,
|
|
38
|
+
pendingPurchases: 0,
|
|
39
|
+
autoTopUp: null
|
|
40
|
+
};
|
|
41
|
+
let config;
|
|
42
|
+
try {
|
|
43
|
+
config = await loadComputeCreditConfig();
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return { configured: false, ...empty, error: error.message };
|
|
46
|
+
}
|
|
47
|
+
if (!config) return { configured: false, ...empty };
|
|
48
|
+
try {
|
|
49
|
+
let status = await readComputeCreditStatus();
|
|
50
|
+
if (options.observe && await options.observe({ availableCredits: status.balance.availableCredits })) {
|
|
51
|
+
status = await readComputeCreditStatus();
|
|
52
|
+
}
|
|
53
|
+
const burn = burnRate(status.debits);
|
|
54
|
+
const autoTopUp = config.autoTopUp ? {
|
|
55
|
+
thresholdCredits: config.autoTopUp.thresholdCredits,
|
|
56
|
+
amountUsd: config.autoTopUp.amountUsd,
|
|
57
|
+
maxChunksPerDay: config.autoTopUp.maxChunksPerDay
|
|
58
|
+
} : null;
|
|
59
|
+
return {
|
|
60
|
+
configured: true,
|
|
61
|
+
availableCredits: status.balance.availableCredits,
|
|
62
|
+
reservedCredits: status.balance.reservedCredits,
|
|
63
|
+
burnCreditsPerHour: burn,
|
|
64
|
+
low: computeLow({
|
|
65
|
+
availableCredits: status.balance.availableCredits,
|
|
66
|
+
burnCreditsPerHour: burn,
|
|
67
|
+
warning,
|
|
68
|
+
...autoTopUp ? { thresholdCredits: autoTopUp.thresholdCredits } : {}
|
|
69
|
+
}),
|
|
70
|
+
warning,
|
|
71
|
+
pendingPurchases: (await listPendingComputePurchases()).length,
|
|
72
|
+
autoTopUp
|
|
73
|
+
};
|
|
74
|
+
} catch (error) {
|
|
75
|
+
return {
|
|
76
|
+
configured: true,
|
|
77
|
+
...empty,
|
|
78
|
+
error: error.code ?? error.message
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function computeAllocationId() {
|
|
83
|
+
return (await loadComputeCreditConfig().catch(() => void 0))?.allocationId;
|
|
84
|
+
}
|
|
85
|
+
async function computeCreditOffer() {
|
|
86
|
+
const pricing = await fetchComputePricing();
|
|
87
|
+
return {
|
|
88
|
+
usdPerCredit: pricing.usdPerCredit,
|
|
89
|
+
denominations: pricing.denominations.map((entry) => ({
|
|
90
|
+
amountUsd: entry.amountUsd,
|
|
91
|
+
credits: entry.credits,
|
|
92
|
+
default: entry.default
|
|
93
|
+
}))
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function buyComputeChunk(amountUsd) {
|
|
97
|
+
const pricing = await fetchComputePricing();
|
|
98
|
+
const size = amountUsd ?? (pricing.denominations.find((entry) => entry.default) ?? pricing.denominations[0])?.amountUsd;
|
|
99
|
+
if (size === void 0) {
|
|
100
|
+
throw new AgentLaunchError("invalid_amount", "The API sells no compute credit sizes");
|
|
101
|
+
}
|
|
102
|
+
const bought = await buyComputeCredit({ amountUsd: size });
|
|
103
|
+
return { purchase: bought.purchase, balance: bought.balance, amountUsd: size };
|
|
104
|
+
}
|
|
105
|
+
function computeCreditObserver(log) {
|
|
106
|
+
return async (observation) => {
|
|
107
|
+
try {
|
|
108
|
+
const { topUp } = await onComputeBalanceObserved(observation);
|
|
109
|
+
if (topUp.action === "bought") log("Compute credit auto-top-up bought one chunk");
|
|
110
|
+
else if (topUp.action === "skipped")
|
|
111
|
+
log(`Compute credit auto-top-up skipped: ${topUp.reason}`);
|
|
112
|
+
return topUp.action === "bought";
|
|
113
|
+
} catch (error) {
|
|
114
|
+
log(
|
|
115
|
+
`Compute credit auto-top-up failed: ${error.code ?? error.message}`
|
|
116
|
+
);
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function insufficientCredit(error) {
|
|
122
|
+
return error instanceof SandboxUnavailableError && /\binsufficient_credit\b/.test(error.reason);
|
|
123
|
+
}
|
|
124
|
+
async function openSandbox(createBroker, observe) {
|
|
125
|
+
const first = createBroker();
|
|
126
|
+
try {
|
|
127
|
+
await first.connect("start");
|
|
128
|
+
return first;
|
|
129
|
+
} catch (error) {
|
|
130
|
+
if (!insufficientCredit(error)) throw error;
|
|
131
|
+
if (!await observe({ creditWarning: "credit_exhausted" })) {
|
|
132
|
+
throw new AgentLaunchError("insufficient_credit", error.reason);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const retry = createBroker();
|
|
136
|
+
try {
|
|
137
|
+
await retry.connect("start");
|
|
138
|
+
return retry;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (insufficientCredit(error)) throw new AgentLaunchError("insufficient_credit", error.reason);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export {
|
|
146
|
+
SANDBOX_TOOL_USER,
|
|
147
|
+
SandboxUnavailableError,
|
|
148
|
+
readComputeView,
|
|
149
|
+
computeAllocationId,
|
|
150
|
+
computeCreditOffer,
|
|
151
|
+
buyComputeChunk,
|
|
152
|
+
computeCreditObserver,
|
|
153
|
+
openSandbox
|
|
154
|
+
};
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { createRequire as __tmCreateRequire } from 'node:module'; import { fileURLToPath as __tmFileURLToPath } from 'node:url'; import { dirname as __tmDirname } from 'node:path'; const require = __tmCreateRequire(import.meta.url); const __tmFilename = __tmFileURLToPath(import.meta.url); const __tmDirnameValue = __tmDirname(__tmFilename);
|
|
2
2
|
import {
|
|
3
3
|
AgentLaunchError
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-S7SJMJ2I.js";
|
|
4
|
+
} from "./chunk-YM4S6IE4.js";
|
|
6
5
|
|
|
7
6
|
// src/lib/agent/compatibility.ts
|
|
8
7
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -123,11 +122,12 @@ function assertAgentCompatibility(options = {}) {
|
|
|
123
122
|
}
|
|
124
123
|
return runtime;
|
|
125
124
|
}
|
|
125
|
+
|
|
126
126
|
export {
|
|
127
127
|
AGENT_COMPATIBILITY,
|
|
128
128
|
agentCompatibility,
|
|
129
|
-
assertAgentCompatibility,
|
|
130
|
-
findInstalledPackage,
|
|
131
129
|
nodeVersionSupported,
|
|
132
|
-
|
|
130
|
+
findInstalledPackage,
|
|
131
|
+
piRuntime,
|
|
132
|
+
assertAgentCompatibility
|
|
133
133
|
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { createRequire as __tmCreateRequire } from 'node:module'; import { fileURLToPath as __tmFileURLToPath } from 'node:url'; import { dirname as __tmDirname } from 'node:path'; const require = __tmCreateRequire(import.meta.url); const __tmFilename = __tmFileURLToPath(import.meta.url); const __tmDirnameValue = __tmDirname(__tmFilename);
|
|
2
|
+
import {
|
|
3
|
+
computeAllocationId,
|
|
4
|
+
readComputeView
|
|
5
|
+
} from "./chunk-LDCFKFF6.js";
|
|
6
|
+
import {
|
|
7
|
+
allocationViews,
|
|
8
|
+
channelView,
|
|
9
|
+
getAgentPolicyPath,
|
|
10
|
+
openAgentChannels,
|
|
11
|
+
uncertainPurchases,
|
|
12
|
+
withdrawalHatch
|
|
13
|
+
} from "./chunk-GJQUALXN.js";
|
|
14
|
+
import {
|
|
15
|
+
SandboxListOutputSchema,
|
|
16
|
+
apiUrl
|
|
17
|
+
} from "./chunk-FRV3ZHUR.js";
|
|
18
|
+
import {
|
|
19
|
+
AgentLaunchError
|
|
20
|
+
} from "./chunk-YM4S6IE4.js";
|
|
21
|
+
import {
|
|
22
|
+
AGENT_VIEW_VERSION,
|
|
23
|
+
blockingPurchases,
|
|
24
|
+
channelLines,
|
|
25
|
+
computeLines,
|
|
26
|
+
formatUsdc
|
|
27
|
+
} from "./chunk-73RXOYME.js";
|
|
28
|
+
|
|
29
|
+
// src/lib/agent/status.ts
|
|
30
|
+
async function listSandboxes(credentials, fetchImpl = fetch) {
|
|
31
|
+
const response = await fetchImpl(`${apiUrl().replace(/\/+$/, "")}/api/sandboxes/list`, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
redirect: "error",
|
|
34
|
+
headers: { "content-type": "application/json" },
|
|
35
|
+
body: JSON.stringify(credentials),
|
|
36
|
+
signal: AbortSignal.timeout(15e3)
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
await response.body?.cancel().catch(() => void 0);
|
|
40
|
+
throw new Error(`the sandbox broker answered ${response.status}`);
|
|
41
|
+
}
|
|
42
|
+
const parsed = SandboxListOutputSchema.safeParse(await response.json());
|
|
43
|
+
if (!parsed.success) throw new Error("the sandbox list is malformed");
|
|
44
|
+
return parsed.data.sandboxes.map((s) => ({
|
|
45
|
+
sandboxId: s.sandboxId,
|
|
46
|
+
purpose: s.purpose,
|
|
47
|
+
state: s.state,
|
|
48
|
+
meteredSeconds: s.meteredSeconds,
|
|
49
|
+
lastActiveAt: s.lastActiveAt,
|
|
50
|
+
expiresAt: s.expiresAt,
|
|
51
|
+
creditWarning: s.creditWarning,
|
|
52
|
+
creditGraceUntil: s.creditGraceUntil
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
function message(error) {
|
|
56
|
+
return error.code ?? error.message;
|
|
57
|
+
}
|
|
58
|
+
async function collectAgentStatus(deps = {}) {
|
|
59
|
+
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
60
|
+
const view = {
|
|
61
|
+
version: AGENT_VIEW_VERSION,
|
|
62
|
+
kind: "taskmarket.agent.status",
|
|
63
|
+
generatedAt: now().toISOString(),
|
|
64
|
+
wallet: null,
|
|
65
|
+
policy: { state: "missing", path: getAgentPolicyPath(), models: [] },
|
|
66
|
+
channels: [],
|
|
67
|
+
purchases: { uncertain: [] },
|
|
68
|
+
inference: { blocked: false, reasons: [] },
|
|
69
|
+
allocations: [],
|
|
70
|
+
sandbox: { state: "no_wallet", sandboxes: [] },
|
|
71
|
+
compute: {
|
|
72
|
+
configured: false,
|
|
73
|
+
availableCredits: null,
|
|
74
|
+
reservedCredits: null,
|
|
75
|
+
burnCreditsPerHour: null,
|
|
76
|
+
low: false,
|
|
77
|
+
warning: null,
|
|
78
|
+
pendingPurchases: 0,
|
|
79
|
+
autoTopUp: null
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const reasons = view.inference.reasons;
|
|
83
|
+
let credentials;
|
|
84
|
+
try {
|
|
85
|
+
const opened = await (deps.openChannels ?? openAgentChannels)();
|
|
86
|
+
view.wallet = { address: opened.keystore.walletAddress };
|
|
87
|
+
credentials = { deviceId: opened.keystore.deviceId, apiToken: opened.keystore.apiToken };
|
|
88
|
+
view.policy = { state: "approved", path: view.policy.path, models: [...opened.policy.models] };
|
|
89
|
+
const statuses = /* @__PURE__ */ new Map();
|
|
90
|
+
for (const rail of opened.rails) {
|
|
91
|
+
const status = await rail.payer.channelStatus();
|
|
92
|
+
statuses.set(rail.rail.id, status);
|
|
93
|
+
const channel = await channelView(rail, status);
|
|
94
|
+
view.channels.push({ ...channel, withdrawal: withdrawalHatch(channel) });
|
|
95
|
+
}
|
|
96
|
+
for (const rail of opened.retired ?? []) {
|
|
97
|
+
const channel = await channelView(rail, void 0, { retired: true });
|
|
98
|
+
view.channels.push({ ...channel, withdrawal: withdrawalHatch(channel) });
|
|
99
|
+
}
|
|
100
|
+
view.purchases.uncertain = [
|
|
101
|
+
...await uncertainPurchases(opened.rails, statuses),
|
|
102
|
+
...await uncertainPurchases(opened.retired ?? [])
|
|
103
|
+
];
|
|
104
|
+
view.allocations = await allocationViews(opened.rails, [
|
|
105
|
+
await (deps.computeAllocation ?? computeAllocationId)()
|
|
106
|
+
]);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error instanceof AgentLaunchError && error.code === "wallet_required") {
|
|
109
|
+
reasons.push("no wallet: run taskmarket wallet import");
|
|
110
|
+
} else if (error instanceof AgentLaunchError && error.code === "setup_required") {
|
|
111
|
+
reasons.push("no approved spending policy");
|
|
112
|
+
} else {
|
|
113
|
+
view.policy = { ...view.policy, state: "invalid", error: message(error) };
|
|
114
|
+
reasons.push(`the spending policy cannot be used: ${message(error)}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const active = view.channels.filter((channel) => !channel.retired);
|
|
118
|
+
for (const id of blockingPurchases({ channels: active, unresolved: [] })) {
|
|
119
|
+
reasons.push(`purchase ${id} is unresolved: taskmarket agent reconcile ${id}`);
|
|
120
|
+
}
|
|
121
|
+
for (const channel of active) {
|
|
122
|
+
if (channel.state !== "open") reasons.push(`channel ${channel.rail} is ${channel.state}`);
|
|
123
|
+
}
|
|
124
|
+
if (credentials) {
|
|
125
|
+
try {
|
|
126
|
+
view.sandbox = {
|
|
127
|
+
state: "ok",
|
|
128
|
+
sandboxes: await (deps.listSandboxes ?? listSandboxes)(credentials)
|
|
129
|
+
};
|
|
130
|
+
} catch (error) {
|
|
131
|
+
view.sandbox = { state: "unavailable", sandboxes: [], error: message(error) };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const warning = view.sandbox.sandboxes.find((s) => s.purpose === "interactive" && s.creditWarning)?.creditWarning ?? null;
|
|
135
|
+
view.compute = await (deps.readCompute ?? readComputeView)({ warning });
|
|
136
|
+
view.inference.blocked = reasons.length > 0;
|
|
137
|
+
return view;
|
|
138
|
+
}
|
|
139
|
+
function statusLines(view) {
|
|
140
|
+
const lines = [
|
|
141
|
+
`taskmarket agent status (view v${view.version}, ${view.generatedAt})`,
|
|
142
|
+
view.wallet ? `Wallet: ${view.wallet.address}` : "Wallet: none",
|
|
143
|
+
`Spending policy: ${view.policy.state}${view.policy.models.length ? ` (${view.policy.models.join(", ")})` : ""}${view.policy.error ? `: ${view.policy.error}` : ""}`
|
|
144
|
+
];
|
|
145
|
+
for (const channel of view.channels) {
|
|
146
|
+
lines.push(...channelLines(channel));
|
|
147
|
+
if (channel.state === "blocked" || channel.state === "withdrawal_pending") {
|
|
148
|
+
lines.push(` ${channel.withdrawal.note}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (view.purchases.uncertain.length === 0) {
|
|
152
|
+
lines.push("Purchases with an unknown outcome: none");
|
|
153
|
+
} else {
|
|
154
|
+
lines.push("Purchases with an unknown outcome (never resent; reconcile them):");
|
|
155
|
+
for (const purchase of view.purchases.uncertain) {
|
|
156
|
+
lines.push(
|
|
157
|
+
` ${purchase.invocationId} on ${purchase.rail}: ${purchase.state}, at most ${formatUsdc(purchase.authorizedAtomic)}${purchase.blocking ? ", blocks new turns" : ""}`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
lines.push(
|
|
162
|
+
view.inference.blocked ? `New inference: blocked (${view.inference.reasons.join("; ")})` : "New inference: ready"
|
|
163
|
+
);
|
|
164
|
+
if (view.sandbox.state === "ok") {
|
|
165
|
+
lines.push(
|
|
166
|
+
view.sandbox.sandboxes.length === 0 ? "Sandbox: none" : `Sandbox: ${view.sandbox.sandboxes.map(
|
|
167
|
+
(s) => `${s.sandboxId} ${s.purpose} ${s.state}${s.creditWarning ? ` (${s.creditWarning})` : ""}`
|
|
168
|
+
).join("; ")}`
|
|
169
|
+
);
|
|
170
|
+
} else if (view.sandbox.state === "unavailable") {
|
|
171
|
+
lines.push(`Sandbox: unavailable (${view.sandbox.error})`);
|
|
172
|
+
}
|
|
173
|
+
lines.push(...computeLines(view.compute));
|
|
174
|
+
return lines;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export {
|
|
178
|
+
listSandboxes,
|
|
179
|
+
collectAgentStatus,
|
|
180
|
+
statusLines
|
|
181
|
+
};
|
|
@@ -2,9 +2,10 @@ import { createRequire as __tmCreateRequire } from 'node:module'; import { fileU
|
|
|
2
2
|
|
|
3
3
|
// src/lib/agent/errors.ts
|
|
4
4
|
var AgentLaunchError = class extends Error {
|
|
5
|
-
constructor(code, message) {
|
|
5
|
+
constructor(code, message, details) {
|
|
6
6
|
super(message);
|
|
7
7
|
this.code = code;
|
|
8
|
+
this.details = details;
|
|
8
9
|
this.name = "AgentLaunchError";
|
|
9
10
|
}
|
|
10
11
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createRequire as __tmCreateRequire } from 'node:module'; import { fileURLToPath as __tmFileURLToPath } from 'node:url'; import { dirname as __tmDirname } from 'node:path'; const require = __tmCreateRequire(import.meta.url); const __tmFilename = __tmFileURLToPath(import.meta.url); const __tmDirnameValue = __tmDirname(__tmFilename);
|
|
2
|
+
import {
|
|
3
|
+
AGENT_COMPATIBILITY,
|
|
4
|
+
agentCompatibility,
|
|
5
|
+
assertAgentCompatibility,
|
|
6
|
+
findInstalledPackage,
|
|
7
|
+
nodeVersionSupported,
|
|
8
|
+
piRuntime
|
|
9
|
+
} from "./chunk-OKZ2NRYZ.js";
|
|
10
|
+
import "./chunk-YM4S6IE4.js";
|
|
11
|
+
import "./chunk-S7SJMJ2I.js";
|
|
12
|
+
export {
|
|
13
|
+
AGENT_COMPATIBILITY,
|
|
14
|
+
agentCompatibility,
|
|
15
|
+
assertAgentCompatibility,
|
|
16
|
+
findInstalledPackage,
|
|
17
|
+
nodeVersionSupported,
|
|
18
|
+
piRuntime
|
|
19
|
+
};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { createRequire as __tmCreateRequire } from 'node:module'; import { fileURLToPath as __tmFileURLToPath } from 'node:url'; import { dirname as __tmDirname } from 'node:path'; const require = __tmCreateRequire(import.meta.url); const __tmFilename = __tmFileURLToPath(import.meta.url); const __tmDirnameValue = __tmDirname(__tmFilename);
|
|
2
|
+
import {
|
|
3
|
+
AGENT_COMPATIBILITY,
|
|
4
|
+
assertAgentCompatibility,
|
|
5
|
+
nodeVersionSupported
|
|
6
|
+
} from "./chunk-OKZ2NRYZ.js";
|
|
7
|
+
import {
|
|
8
|
+
listSandboxes
|
|
9
|
+
} from "./chunk-XXD7TWLP.js";
|
|
10
|
+
import "./chunk-LDCFKFF6.js";
|
|
11
|
+
import "./chunk-52Q2DCZN.js";
|
|
12
|
+
import {
|
|
13
|
+
channelView,
|
|
14
|
+
loadAgentPolicy,
|
|
15
|
+
openAgentChannels
|
|
16
|
+
} from "./chunk-GJQUALXN.js";
|
|
17
|
+
import {
|
|
18
|
+
apiUrl,
|
|
19
|
+
getX402PolicyPath,
|
|
20
|
+
keystoreExists,
|
|
21
|
+
loadKeystore,
|
|
22
|
+
loadX402Policy,
|
|
23
|
+
rpcUrlForNetwork
|
|
24
|
+
} from "./chunk-FRV3ZHUR.js";
|
|
25
|
+
import "./chunk-YM4S6IE4.js";
|
|
26
|
+
import {
|
|
27
|
+
AGENT_VIEW_VERSION
|
|
28
|
+
} from "./chunk-73RXOYME.js";
|
|
29
|
+
import "./chunk-S7SJMJ2I.js";
|
|
30
|
+
|
|
31
|
+
// src/lib/agent/doctor.ts
|
|
32
|
+
var CHAIN_IDS = { "eip155:8453": "0x2105", "eip155:84532": "0x14a34" };
|
|
33
|
+
function reason(error) {
|
|
34
|
+
return error.code ?? error.message;
|
|
35
|
+
}
|
|
36
|
+
function loopback(url) {
|
|
37
|
+
return ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
|
|
38
|
+
}
|
|
39
|
+
async function runDoctor(deps = {}) {
|
|
40
|
+
const fetchImpl = deps.fetch ?? fetch;
|
|
41
|
+
const nodeVersion = deps.nodeVersion ?? process.versions.node;
|
|
42
|
+
const apiBase = deps.apiUrl ?? apiUrl();
|
|
43
|
+
const checks = [];
|
|
44
|
+
const add = (id, status, summary) => checks.push({ id, status, summary });
|
|
45
|
+
const get = (url, init = {}) => fetchImpl(url, { redirect: "error", signal: AbortSignal.timeout(1e4), ...init });
|
|
46
|
+
add(
|
|
47
|
+
"node",
|
|
48
|
+
nodeVersionSupported(nodeVersion) ? "pass" : "fail",
|
|
49
|
+
`Node ${nodeVersion}; taskmarket agent needs ${AGENT_COMPATIBILITY.node.minimum} or later`
|
|
50
|
+
);
|
|
51
|
+
try {
|
|
52
|
+
(deps.checkRuntime ?? (() => assertAgentCompatibility({ nodeVersion: "99.0.0" })))();
|
|
53
|
+
add(
|
|
54
|
+
"runtime",
|
|
55
|
+
"pass",
|
|
56
|
+
`Bundled Pi ${AGENT_COMPATIBILITY.pi.version} and pi-xgate ${AGENT_COMPATIBILITY.piXgate.version} match this build`
|
|
57
|
+
);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
add("runtime", "fail", error.message);
|
|
60
|
+
}
|
|
61
|
+
let credentials;
|
|
62
|
+
let walletAddress;
|
|
63
|
+
if (await keystoreExists()) {
|
|
64
|
+
const keystore = await loadKeystore();
|
|
65
|
+
credentials = { deviceId: keystore.deviceId, apiToken: keystore.apiToken };
|
|
66
|
+
walletAddress = keystore.walletAddress;
|
|
67
|
+
add("wallet", "pass", `Wallet ${keystore.walletAddress} (not unlocked)`);
|
|
68
|
+
} else {
|
|
69
|
+
add("wallet", "fail", "No wallet; run taskmarket wallet import");
|
|
70
|
+
}
|
|
71
|
+
let policy;
|
|
72
|
+
try {
|
|
73
|
+
policy = await loadAgentPolicy();
|
|
74
|
+
const foreign = policy.rails.filter(
|
|
75
|
+
(rail) => walletAddress && rail.wallet.toLowerCase() !== walletAddress.toLowerCase()
|
|
76
|
+
);
|
|
77
|
+
add(
|
|
78
|
+
"policy",
|
|
79
|
+
foreign.length > 0 ? "fail" : "pass",
|
|
80
|
+
foreign.length > 0 ? `Rail ${foreign[0].id} pays from ${foreign[0].wallet}, not this wallet` : `${policy.models.length} approved model(s), ${policy.rails.length} rail(s)`
|
|
81
|
+
);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
add("policy", "fail", error.message);
|
|
84
|
+
}
|
|
85
|
+
const rpcUrls = /* @__PURE__ */ new Map();
|
|
86
|
+
if (policy) {
|
|
87
|
+
try {
|
|
88
|
+
const x402Policy = await loadX402Policy(getX402PolicyPath());
|
|
89
|
+
for (const rail of policy.rails)
|
|
90
|
+
rpcUrls.set(rail.network, rpcUrlForNetwork(x402Policy, rail.network));
|
|
91
|
+
add("payment_policy", "pass", `RPC configured for ${[...rpcUrls.keys()].join(", ")}`);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
add("payment_policy", "fail", reason(error));
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
add("payment_policy", "skip", "No spending policy to check");
|
|
97
|
+
}
|
|
98
|
+
if (policy && rpcUrls.size > 0 && walletAddress) {
|
|
99
|
+
try {
|
|
100
|
+
const opened = await openAgentChannels();
|
|
101
|
+
const problems = [];
|
|
102
|
+
for (const rail of opened.rails) {
|
|
103
|
+
const channel = await channelView(rail);
|
|
104
|
+
if (channel.pendingOperation) {
|
|
105
|
+
problems.push(
|
|
106
|
+
`${channel.rail} has an unresolved ${channel.pendingOperation.kind} ${channel.pendingOperation.id}`
|
|
107
|
+
);
|
|
108
|
+
} else if (channel.state !== "open") {
|
|
109
|
+
problems.push(`${channel.rail} is ${channel.state}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
add(
|
|
113
|
+
"channels",
|
|
114
|
+
problems.length > 0 ? "warn" : "pass",
|
|
115
|
+
problems.length > 0 ? problems.join("; ") : `${opened.rails.length} channel(s) open, nothing unresolved`
|
|
116
|
+
);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
add("channels", "fail", reason(error));
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
add("channels", "skip", "Needs a wallet and a usable spending policy");
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const response = await get(`${apiBase.replace(/\/+$/, "")}/api/compute/pricing`);
|
|
125
|
+
await response.body?.cancel().catch(() => void 0);
|
|
126
|
+
add(
|
|
127
|
+
"api",
|
|
128
|
+
response.ok ? "pass" : "fail",
|
|
129
|
+
`${new URL(apiBase).origin} answered ${response.status}`
|
|
130
|
+
);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
add("api", "fail", `${apiBase} is unreachable: ${reason(error)}`);
|
|
133
|
+
}
|
|
134
|
+
if (credentials) {
|
|
135
|
+
try {
|
|
136
|
+
const sandboxes = await listSandboxes(credentials, fetchImpl);
|
|
137
|
+
add(
|
|
138
|
+
"sandbox",
|
|
139
|
+
"pass",
|
|
140
|
+
`The sandbox broker answered; ${sandboxes.length} sandbox(es) on this wallet`
|
|
141
|
+
);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
add("sandbox", "fail", `The sandbox broker is unavailable: ${reason(error)}`);
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
add("sandbox", "skip", "Needs a wallet");
|
|
147
|
+
}
|
|
148
|
+
const api = new URL(apiBase);
|
|
149
|
+
add(
|
|
150
|
+
"host_key",
|
|
151
|
+
api.protocol === "https:" ? "pass" : loopback(api) ? "warn" : "fail",
|
|
152
|
+
api.protocol === "https:" ? "Sandbox host keys are pinned per connection (ssh-ed25519 only) from the broker over HTTPS; never trusted on first use" : loopback(api) ? "The API is a local development server without TLS; host keys are only as trustworthy as it is" : `The API ${api.origin} is not HTTPS, so the sandbox host keys it returns cannot be trusted`
|
|
153
|
+
);
|
|
154
|
+
if (policy) {
|
|
155
|
+
for (const origin of new Set(policy.rails.map((rail) => rail.origin))) {
|
|
156
|
+
try {
|
|
157
|
+
const response = await get(`${origin}/v1/models`, {
|
|
158
|
+
headers: { accept: "application/json" }
|
|
159
|
+
});
|
|
160
|
+
await response.body?.cancel().catch(() => void 0);
|
|
161
|
+
add(
|
|
162
|
+
"xgate",
|
|
163
|
+
response.ok ? "pass" : "fail",
|
|
164
|
+
`${origin} catalog answered ${response.status}`
|
|
165
|
+
);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
add("xgate", "fail", `${origin} is unreachable: ${reason(error)}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
for (const [network, url] of rpcUrls) {
|
|
171
|
+
try {
|
|
172
|
+
const response = await get(url, {
|
|
173
|
+
method: "POST",
|
|
174
|
+
headers: { "content-type": "application/json" },
|
|
175
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_chainId", params: [] })
|
|
176
|
+
});
|
|
177
|
+
const body = await response.json();
|
|
178
|
+
const expected = CHAIN_IDS[network];
|
|
179
|
+
add(
|
|
180
|
+
"rpc",
|
|
181
|
+
body.result === expected ? "pass" : "fail",
|
|
182
|
+
body.result === expected ? `${network} RPC reachable` : `${network} RPC answered chain ${String(body.result)}, expected ${expected}`
|
|
183
|
+
);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
add("rpc", "fail", `${network} RPC is unreachable: ${reason(error)}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
add("xgate", "skip", "No spending policy names an xgate origin");
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
version: AGENT_VIEW_VERSION,
|
|
193
|
+
kind: "taskmarket.agent.doctor",
|
|
194
|
+
ok: !checks.some((check) => check.status === "fail"),
|
|
195
|
+
compatibility: {
|
|
196
|
+
node: nodeVersion,
|
|
197
|
+
nodeMinimum: AGENT_COMPATIBILITY.node.minimum,
|
|
198
|
+
pi: AGENT_COMPATIBILITY.pi.version,
|
|
199
|
+
piXgate: AGENT_COMPATIBILITY.piXgate.version,
|
|
200
|
+
protocol: AGENT_COMPATIBILITY.protocol
|
|
201
|
+
},
|
|
202
|
+
checks
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function doctorLines(report) {
|
|
206
|
+
return [
|
|
207
|
+
`taskmarket agent doctor (view v${report.version}): ${report.ok ? "ready" : "problems found"}`,
|
|
208
|
+
...report.checks.map(
|
|
209
|
+
(check) => `${check.status.toUpperCase().padEnd(4)} ${check.id}: ${check.summary}`
|
|
210
|
+
)
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
export {
|
|
214
|
+
doctorLines,
|
|
215
|
+
runDoctor
|
|
216
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __tmCreateRequire } from 'node:module'; import { fileURLToPath as __tmFileURLToPath } from 'node:url'; import { dirname as __tmDirname } from 'node:path'; const require = __tmCreateRequire(import.meta.url); const __tmFilename = __tmFileURLToPath(import.meta.url); const __tmDirnameValue = __tmDirname(__tmFilename);
|
|
2
2
|
import {
|
|
3
3
|
AgentLaunchError
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YM4S6IE4.js";
|
|
5
5
|
import "./chunk-S7SJMJ2I.js";
|
|
6
6
|
export {
|
|
7
7
|
AgentLaunchError
|