dashclaw 4.1.1 → 4.2.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 +68 -0
- package/dashclaw.js +114 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1075,6 +1075,74 @@ x402 and auth metadata are recorded on the provider (`auth_metadata`); no paymen
|
|
|
1075
1075
|
|
|
1076
1076
|
---
|
|
1077
1077
|
|
|
1078
|
+
## x402 Spend Governance
|
|
1079
|
+
|
|
1080
|
+
Register x402 providers, govern individual purchases through the guard loop, and record spend for audit. The agent executes the actual x402 call itself — DashClaw records the provider, governs the purchase intent, and keeps a tamper-evident ledger of agent spend. DashClaw never holds a wallet.
|
|
1081
|
+
|
|
1082
|
+
```js
|
|
1083
|
+
// Register a paid provider
|
|
1084
|
+
const { provider } = await claw.createProvider({
|
|
1085
|
+
name: 'Exa Search',
|
|
1086
|
+
category: 'research',
|
|
1087
|
+
base_url: 'https://api.exa.ai',
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
// Add an endpoint to the provider
|
|
1091
|
+
await claw.createProviderEndpoint(provider.provider_id, {
|
|
1092
|
+
name: 'Search',
|
|
1093
|
+
endpoint_url: 'https://api.exa.ai/search',
|
|
1094
|
+
default_price: 0.01,
|
|
1095
|
+
sensitivity_level: 'low',
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
// Govern + record a purchase (call guard, then agent executes x402)
|
|
1099
|
+
const { action, purchase, decision } = await claw.recordPurchase({
|
|
1100
|
+
agent_id: 'research-agent',
|
|
1101
|
+
provider: provider.provider_id,
|
|
1102
|
+
declared_goal: 'Find recent papers on quantum computing',
|
|
1103
|
+
purchase_reason: 'Context gap: no local data for period 2025-01-01..2026-01-01',
|
|
1104
|
+
context_gap: 'No papers in knowledge base for the requested window',
|
|
1105
|
+
expected_value: 'Retrieve 10+ relevant citations',
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
if (action.status === 'pending_approval') {
|
|
1109
|
+
await claw.waitForApproval(action.id);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
// Agent executes the x402 call, then records the result
|
|
1113
|
+
const x402Result = { summary: 'Found 14 papers', data: { count: 14 }, url: 'https://...' };
|
|
1114
|
+
await claw.recordPurchaseResult(action.id, x402Result);
|
|
1115
|
+
|
|
1116
|
+
// Or self-report a SETTLED payment in ONE call — when you pay OUTSIDE a
|
|
1117
|
+
// governance hook (e.g. a native-shell agentcash wrapper) and just need the
|
|
1118
|
+
// spend on Spend → x402. The server resolves/auto-registers the provider from
|
|
1119
|
+
// `provider`, so you don't register one first.
|
|
1120
|
+
const settled = await claw.recordX402Purchase({
|
|
1121
|
+
agent_id: 'research-agent',
|
|
1122
|
+
provider: 'stableenrich.dev', // name/origin
|
|
1123
|
+
spend: 0.007, // settled USD
|
|
1124
|
+
transaction_hash: '0xabc…',
|
|
1125
|
+
request_id: 'req_123',
|
|
1126
|
+
});
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
- `claw.listProviders(filters?)` -- GET /api/x402/providers
|
|
1130
|
+
- `claw.createProvider(data)` -- POST /api/x402/providers
|
|
1131
|
+
- `claw.getProvider(id)` -- GET /api/x402/providers/:id
|
|
1132
|
+
- `claw.updateProvider(id, patch)` -- PATCH /api/x402/providers/:id
|
|
1133
|
+
- `claw.listProviderEndpoints(id)` -- GET /api/x402/providers/:id/endpoints
|
|
1134
|
+
- `claw.createProviderEndpoint(id, data)` -- POST /api/x402/providers/:id/endpoints
|
|
1135
|
+
- `claw.recordPurchase(data)` -- POST /api/x402/purchases (guard-gated; returns `{ action, purchase, decision }`)
|
|
1136
|
+
- `claw.listPurchases(filters?)` -- GET /api/x402/purchases
|
|
1137
|
+
- `claw.recordPurchaseResult(actionId, result)` -- POST /api/artifacts (attaches the x402 result snapshot to the purchase action via `source_action_id`)
|
|
1138
|
+
- `claw.recordX402Purchase({ agent_id, provider, spend, transaction_hash?, request_id?, ... })` -- one call: govern + record the purchase, mark it succeeded, and attach the receipt. Use for the **pay-outside-a-hook** self-report pattern. Python parity: `record_x402_purchase(...)`.
|
|
1139
|
+
|
|
1140
|
+
> **Note:** `recordPurchaseResult` is Node-only. It is a convenience wrapper over `POST /api/artifacts` — Python callers post directly to that endpoint with `artifact_type: 'x402_purchase_result'` and `source_action_id` set to the `act_` id from `record_purchase`. (`recordX402Purchase` / `record_x402_purchase` exist in both SDKs and handle the receipt internally.)
|
|
1141
|
+
|
|
1142
|
+
> **Operator surface (no SDK wrapper):** The platform also exposes `GET /api/finops/spend?lens=fleet|claude-code` — a read-only operator rollup that aggregates agent LLM cost + x402 purchases (Fleet lens) or Code Sessions cost (Claude-Code lens). It is a presentation layer backed by repository functions (`getFleetSpend` / `getClaudeCodeSpend`), **not** an SDK method, so it does not appear in the method count. Query it directly over HTTP.
|
|
1143
|
+
|
|
1144
|
+
---
|
|
1145
|
+
|
|
1078
1146
|
## Hosted provisioning (operator surface — not an SDK method)
|
|
1079
1147
|
|
|
1080
1148
|
When `DASHCLAW_HOSTED=true` the deployment exposes `/api/hosted/*` routes for one-click trial provisioning. These are operator-facing routes, not SDK methods — they produce the API key the SDK consumes.
|
package/dashclaw.js
CHANGED
|
@@ -1420,6 +1420,120 @@ class DashClaw {
|
|
|
1420
1420
|
async invokeRegisteredAgent({ registered_agent_id, capability_id, agent_id, payload, declared_goal } = {}) {
|
|
1421
1421
|
return this._request('/api/agents/invoke', 'POST', { registered_agent_id, capability_id, agent_id, payload, declared_goal });
|
|
1422
1422
|
}
|
|
1423
|
+
|
|
1424
|
+
// ---------------------------------------------------------------------------
|
|
1425
|
+
// x402 spend governance — provider registry + governed paid acquisition.
|
|
1426
|
+
// The agent executes the actual x402 call itself; these methods register
|
|
1427
|
+
// providers and record/govern the spend. DashClaw never holds a wallet.
|
|
1428
|
+
// ---------------------------------------------------------------------------
|
|
1429
|
+
|
|
1430
|
+
/** GET /api/x402/providers — list registered providers. */
|
|
1431
|
+
async listProviders(filters = {}) {
|
|
1432
|
+
return this._request('/api/x402/providers', 'GET', null, filters);
|
|
1433
|
+
}
|
|
1434
|
+
/** POST /api/x402/providers — register a paid provider. */
|
|
1435
|
+
async createProvider(data = {}) {
|
|
1436
|
+
return this._request('/api/x402/providers', 'POST', data);
|
|
1437
|
+
}
|
|
1438
|
+
/** GET /api/x402/providers/:id — provider detail + endpoints. */
|
|
1439
|
+
async getProvider(id) {
|
|
1440
|
+
return this._request(`/api/x402/providers/${id}`, 'GET');
|
|
1441
|
+
}
|
|
1442
|
+
/** PATCH /api/x402/providers/:id — update a provider. */
|
|
1443
|
+
async updateProvider(id, patch = {}) {
|
|
1444
|
+
return this._request(`/api/x402/providers/${id}`, 'PATCH', patch);
|
|
1445
|
+
}
|
|
1446
|
+
/** GET /api/x402/providers/:id/endpoints — list a provider's endpoints. */
|
|
1447
|
+
async listProviderEndpoints(id) {
|
|
1448
|
+
return this._request(`/api/x402/providers/${id}/endpoints`, 'GET');
|
|
1449
|
+
}
|
|
1450
|
+
/** POST /api/x402/providers/:id/endpoints — add an endpoint. */
|
|
1451
|
+
async createProviderEndpoint(id, data = {}) {
|
|
1452
|
+
return this._request(`/api/x402/providers/${id}/endpoints`, 'POST', data);
|
|
1453
|
+
}
|
|
1454
|
+
/**
|
|
1455
|
+
* POST /api/x402/purchases — govern + record a paid acquisition.
|
|
1456
|
+
* Required: agent_id, provider, declared_goal, purchase_reason, context_gap, expected_value.
|
|
1457
|
+
* Returns { action, purchase, decision }; branch on action.status (running | pending_approval).
|
|
1458
|
+
*/
|
|
1459
|
+
async recordPurchase(data = {}) {
|
|
1460
|
+
return this._request('/api/x402/purchases', 'POST', data);
|
|
1461
|
+
}
|
|
1462
|
+
/** GET /api/x402/purchases — list governed purchases. */
|
|
1463
|
+
async listPurchases(filters = {}) {
|
|
1464
|
+
return this._request('/api/x402/purchases', 'GET', null, filters);
|
|
1465
|
+
}
|
|
1466
|
+
/**
|
|
1467
|
+
* POST /api/artifacts — attach the x402 result snapshot to its purchase action.
|
|
1468
|
+
* Reuses the existing artifacts endpoint; links by source_action_id so the
|
|
1469
|
+
* snapshot appears in that action's evidence bundle.
|
|
1470
|
+
* @param {string} actionId - the act_ id returned by recordPurchase
|
|
1471
|
+
* @param {Object} result - { summary?, data?, url? }
|
|
1472
|
+
*/
|
|
1473
|
+
async recordPurchaseResult(actionId, result = {}) {
|
|
1474
|
+
return this._request('/api/artifacts', 'POST', {
|
|
1475
|
+
artifact_type: 'x402_purchase_result',
|
|
1476
|
+
name: `x402 result ${actionId}`,
|
|
1477
|
+
description: result.summary || null,
|
|
1478
|
+
content_json: result.data ?? {},
|
|
1479
|
+
content_url: result.url || null,
|
|
1480
|
+
source_action_id: actionId,
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Convenience: record a SETTLED x402 payment end-to-end in one call — govern +
|
|
1485
|
+
* record the purchase, mark it succeeded, and (when given) attach the on-chain
|
|
1486
|
+
* receipt. Use this when your agent pays OUTSIDE an OpenClaw governance hook
|
|
1487
|
+
* (e.g. a Codex/native-shell agentcash wrapper) and must self-report so the
|
|
1488
|
+
* spend lands on Spend → x402. The server resolves/auto-registers the provider
|
|
1489
|
+
* from `provider`, so you do NOT register one first. Only call this for a
|
|
1490
|
+
* settled payment — a free quote or a failed call has nothing to record.
|
|
1491
|
+
*
|
|
1492
|
+
* @param {Object} p
|
|
1493
|
+
* @param {string} p.agent_id
|
|
1494
|
+
* @param {string} p.provider - provider name/origin, e.g. "stableenrich.dev"
|
|
1495
|
+
* @param {number} p.spend - settled USD amount (> 0)
|
|
1496
|
+
* @param {string} [p.declared_goal]
|
|
1497
|
+
* @param {string} [p.purchase_reason]
|
|
1498
|
+
* @param {string} [p.context_gap]
|
|
1499
|
+
* @param {string} [p.expected_value]
|
|
1500
|
+
* @param {string} [p.transaction_hash] - on-chain tx hash (receipt evidence)
|
|
1501
|
+
* @param {string} [p.request_id]
|
|
1502
|
+
* @param {string} [p.currency='USDC']
|
|
1503
|
+
* @param {string} [p.payment_method='x402']
|
|
1504
|
+
* @returns {Promise<{ action, purchase, decision, outcome }>}
|
|
1505
|
+
*/
|
|
1506
|
+
async recordX402Purchase({
|
|
1507
|
+
agent_id, provider, spend,
|
|
1508
|
+
declared_goal, purchase_reason, context_gap, expected_value,
|
|
1509
|
+
transaction_hash, request_id, currency = 'USDC', payment_method = 'x402',
|
|
1510
|
+
} = {}) {
|
|
1511
|
+
const origin = provider;
|
|
1512
|
+
const res = await this.recordPurchase({
|
|
1513
|
+
agent_id,
|
|
1514
|
+
provider: origin,
|
|
1515
|
+
declared_goal: declared_goal || `x402 capability call to ${origin}`,
|
|
1516
|
+
purchase_reason: purchase_reason || `Paid x402 capability call to ${origin}`,
|
|
1517
|
+
context_gap: context_gap || `Capability gated behind payment at ${origin}`,
|
|
1518
|
+
expected_value: expected_value || `Paid result from ${origin}`,
|
|
1519
|
+
spend_amount: spend,
|
|
1520
|
+
cost_estimate: spend,
|
|
1521
|
+
currency,
|
|
1522
|
+
payment_method,
|
|
1523
|
+
});
|
|
1524
|
+
const actionId = res?.action?.action_id ?? res?.action?.id;
|
|
1525
|
+
let outcome = null;
|
|
1526
|
+
if (actionId) {
|
|
1527
|
+
outcome = await this.reportActionSuccess(actionId, `x402 settled: $${spend} ${currency} at ${origin}`);
|
|
1528
|
+
if (transaction_hash || request_id) {
|
|
1529
|
+
await this.recordPurchaseResult(actionId, {
|
|
1530
|
+
summary: `x402 settled: $${spend} ${currency} at ${origin}`,
|
|
1531
|
+
data: { origin, transactionHash: transaction_hash, requestId: request_id },
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
return { action: res?.action, purchase: res?.purchase, decision: res?.decision, outcome };
|
|
1536
|
+
}
|
|
1423
1537
|
}
|
|
1424
1538
|
|
|
1425
1539
|
export { DashClaw, ApprovalDeniedError, GuardBlockedError };
|