dashclaw 2.13.0 → 2.13.1
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 +15 -8
- package/dashclaw.js +95 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# DashClaw SDK
|
|
1
|
+
# DashClaw SDK
|
|
2
2
|
|
|
3
3
|
**Minimal governance runtime for AI agents.**
|
|
4
4
|
|
|
@@ -141,14 +141,16 @@ Telegram button.
|
|
|
141
141
|
### The rule every agent author needs to know
|
|
142
142
|
|
|
143
143
|
**`waitForApproval()` must be called with the `action_id` returned by
|
|
144
|
-
`createAction()`, NOT with the
|
|
144
|
+
`createAction()`, NOT with the guard decision's id.**
|
|
145
145
|
|
|
146
146
|
These are two different records in two different tables:
|
|
147
147
|
|
|
148
|
-
| Call | Returns
|
|
149
|
-
|
|
150
|
-
| `guard()` | A row in `guard_decisions` (the decision log) | `act_gd_…` |
|
|
151
|
-
| `createAction()` | A row in `action_records` (the thing you're actually doing) | `act_…` |
|
|
148
|
+
| Call | Returns an id that refers to… | Prefix | Field on the result |
|
|
149
|
+
|---|---|---|---|
|
|
150
|
+
| `guard()` | A row in `guard_decisions` (the decision log) | `act_gd_…` | `decision_id` (canonical); `action_id` is a **deprecated alias** of the same value |
|
|
151
|
+
| `createAction()` | A row in `action_records` (the thing you're actually doing) | `act_…` | `action_id` |
|
|
152
|
+
|
|
153
|
+
> The guard result's `action_id` field is a legacy alias of `decision_id` and will be removed in a future major — read `decision_id` from `guard()`, and `action_id` from `createAction()`.
|
|
152
154
|
|
|
153
155
|
`waitForApproval()` polls `GET /api/actions/:id`, which is the
|
|
154
156
|
`action_records` table. Passing it a `guard_decisions` ID (`act_gd_…`) will
|
|
@@ -251,7 +253,7 @@ See:
|
|
|
251
253
|
|
|
252
254
|
---
|
|
253
255
|
|
|
254
|
-
## SDK Surface Area
|
|
256
|
+
## SDK Surface Area
|
|
255
257
|
|
|
256
258
|
The v2 SDK exposes the stable governance runtime plus promoted execution domains in the canonical Node client:
|
|
257
259
|
|
|
@@ -336,6 +338,11 @@ lessons.forEach(l => console.log(l.guidance));
|
|
|
336
338
|
### Messaging
|
|
337
339
|
- `sendMessage({ to, type, subject, body, threadId, urgent })` -- Send a message to another agent or broadcast.
|
|
338
340
|
- `getInbox({ type, unread, limit })` -- Retrieve inbox messages with optional filters.
|
|
341
|
+
- `getSentMessages({ type, threadId, limit })` -- Retrieve messages this agent has sent.
|
|
342
|
+
- `getMessages({ direction, type, unread, threadId, limit })` -- Retrieve messages with flexible filters.
|
|
343
|
+
- `getMessage(messageId)` -- Fetch a single message by id.
|
|
344
|
+
- `markRead(messageIds)` -- Mark messages as read for this agent (`PATCH /api/messages`, `action: 'read'`).
|
|
345
|
+
- `archiveMessages(messageIds)` -- Archive messages for this agent (`PATCH /api/messages`, `action: 'archive'`).
|
|
339
346
|
|
|
340
347
|
```javascript
|
|
341
348
|
// Send a message to another agent
|
|
@@ -604,7 +611,7 @@ If your agent supports Model Context Protocol (Claude Code, Claude Desktop, Mana
|
|
|
604
611
|
- **Open loops (3):** `dashclaw_loop_add`, `dashclaw_loop_list`, `dashclaw_loop_close` — action-scoped commitments (the "I will X later" tracker).
|
|
605
612
|
- **Learning + retrospection (3):** `dashclaw_learning_log`, `dashclaw_learning_query`, `dashclaw_decisions_recent` — log + query non-obvious decisions; recent governed-action ledger.
|
|
606
613
|
|
|
607
|
-
**
|
|
614
|
+
**6 resources:** `dashclaw://policies`, `dashclaw://capabilities`, `dashclaw://agent/{agent_id}/history`, `dashclaw://status`, `dashclaw://code-sessions/projects`, `dashclaw://code-sessions/sessions/{session_id}`.
|
|
608
615
|
|
|
609
616
|
### Agent runtime endpoints (server-side, no SDK wrapper)
|
|
610
617
|
|
package/dashclaw.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* DashClaw SDK
|
|
2
|
+
* DashClaw SDK (Stable Runtime API)
|
|
3
3
|
* Focused governance runtime client for AI agents.
|
|
4
|
+
*
|
|
5
|
+
* Version is the single source of truth in sdk/package.json — never
|
|
6
|
+
* hardcoded here, in the README header, or in app/ pages. Consumers
|
|
7
|
+
* read it at runtime via `import pkg from 'dashclaw/package.json'`.
|
|
4
8
|
*/
|
|
5
9
|
|
|
6
10
|
import { createHash } from 'crypto';
|
|
@@ -62,8 +66,16 @@ class DashClaw {
|
|
|
62
66
|
async _request(path, method = 'GET', body = null, params = null) {
|
|
63
67
|
let url = `${this.baseUrl}${path}`;
|
|
64
68
|
if (params) {
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
// Skip undefined/null values. Passing them straight into URLSearchParams
|
|
70
|
+
// serializes the literal strings "undefined"/"null", which the receiving
|
|
71
|
+
// routes treat as real filter values and match zero rows. Falsy-but-valid
|
|
72
|
+
// values (0, false, '') are preserved. Mirrors the v1 SDK behavior.
|
|
73
|
+
const qs = new URLSearchParams();
|
|
74
|
+
for (const [key, value] of Object.entries(params)) {
|
|
75
|
+
if (value !== undefined && value !== null) qs.append(key, String(value));
|
|
76
|
+
}
|
|
77
|
+
const s = qs.toString();
|
|
78
|
+
if (s) url += `?${s}`;
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
const headers = {
|
|
@@ -78,7 +90,16 @@ class DashClaw {
|
|
|
78
90
|
body: body ? JSON.stringify(body) : undefined
|
|
79
91
|
});
|
|
80
92
|
|
|
81
|
-
|
|
93
|
+
// Parse the body defensively. A non-JSON error body (a Vercel 502/504/413
|
|
94
|
+
// gateway page, a 429 rate-limit page) makes res.json() reject with a
|
|
95
|
+
// SyntaxError, which would propagate instead of the status-bearing error
|
|
96
|
+
// below and lose res.status. Fall back to {} so the real status is thrown.
|
|
97
|
+
let data = {};
|
|
98
|
+
try {
|
|
99
|
+
data = await res.json();
|
|
100
|
+
} catch {
|
|
101
|
+
data = {};
|
|
102
|
+
}
|
|
82
103
|
|
|
83
104
|
if (!res.ok) {
|
|
84
105
|
if (res.status === 403 && data.decision && data.decision.decision === 'block') {
|
|
@@ -289,7 +310,12 @@ class DashClaw {
|
|
|
289
310
|
let printedBlock = false;
|
|
290
311
|
|
|
291
312
|
while (Date.now() - startTime < timeout) {
|
|
292
|
-
|
|
313
|
+
// Return the full GET response (action + open_loops + assumptions +
|
|
314
|
+
// message_summary) so the polling fallback resolves to the same shape as
|
|
315
|
+
// the SSE fast-path above and the Python SDK. Returning only { action }
|
|
316
|
+
// dropped the related collections whenever SSE was unavailable.
|
|
317
|
+
const result = await this._request(`/api/actions/${actionId}`, 'GET');
|
|
318
|
+
const action = result.action;
|
|
293
319
|
|
|
294
320
|
if (!printedBlock) {
|
|
295
321
|
printedBlock = true;
|
|
@@ -319,14 +345,14 @@ class DashClaw {
|
|
|
319
345
|
}
|
|
320
346
|
|
|
321
347
|
if (action.status === 'pending_approval') wasPending = true;
|
|
322
|
-
if (action.approved_by) return
|
|
348
|
+
if (action.approved_by) return result;
|
|
323
349
|
if (action.status === 'failed' || action.status === 'cancelled') {
|
|
324
350
|
throw new ApprovalDeniedError(action.error_message || 'Operator denied the action.', action.status);
|
|
325
351
|
}
|
|
326
352
|
if (wasPending && action.status !== 'pending_approval') {
|
|
327
353
|
throw new Error(`Action ${actionId} left pending_approval state without explicit approval metadata (Status: ${action.status})`);
|
|
328
354
|
}
|
|
329
|
-
if (!wasPending && action.status === 'running') return
|
|
355
|
+
if (!wasPending && action.status === 'running') return result;
|
|
330
356
|
|
|
331
357
|
await new Promise(r => setTimeout(r, interval));
|
|
332
358
|
}
|
|
@@ -611,6 +637,68 @@ class DashClaw {
|
|
|
611
637
|
});
|
|
612
638
|
}
|
|
613
639
|
|
|
640
|
+
/**
|
|
641
|
+
* GET /api/messages — Fetch messages this agent has sent.
|
|
642
|
+
*/
|
|
643
|
+
async getSentMessages({ type, threadId, limit } = {}) {
|
|
644
|
+
return this._request('/api/messages', 'GET', null, {
|
|
645
|
+
agent_id: this.agentId,
|
|
646
|
+
direction: 'sent',
|
|
647
|
+
...(type && { type }),
|
|
648
|
+
...(threadId && { thread_id: threadId }),
|
|
649
|
+
...(limit && { limit }),
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* GET /api/messages — Fetch this agent's messages with flexible filters.
|
|
655
|
+
*/
|
|
656
|
+
async getMessages({ direction, type, unread, threadId, limit } = {}) {
|
|
657
|
+
return this._request('/api/messages', 'GET', null, {
|
|
658
|
+
agent_id: this.agentId,
|
|
659
|
+
...(direction && { direction }),
|
|
660
|
+
...(type && { type }),
|
|
661
|
+
...(unread != null && { unread }),
|
|
662
|
+
...(threadId && { thread_id: threadId }),
|
|
663
|
+
...(limit && { limit }),
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* GET /api/messages/:messageId — Fetch a single message by id.
|
|
669
|
+
*/
|
|
670
|
+
async getMessage(messageId) {
|
|
671
|
+
return this._request(`/api/messages/${encodeURIComponent(messageId)}`, 'GET');
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* PATCH /api/messages — Mark messages as read for this agent. Direct messages
|
|
676
|
+
* are marked read only for the target agent (or dashboard); broadcasts update
|
|
677
|
+
* read_by for this agent.
|
|
678
|
+
* @param {string[]} messageIds - Message IDs (msg_*) to mark read.
|
|
679
|
+
* @returns {Promise<{ updated: number }>}
|
|
680
|
+
*/
|
|
681
|
+
async markRead(messageIds) {
|
|
682
|
+
return this._request('/api/messages', 'PATCH', {
|
|
683
|
+
message_ids: messageIds,
|
|
684
|
+
action: 'read',
|
|
685
|
+
agent_id: this.agentId,
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* PATCH /api/messages — Archive messages for this agent.
|
|
691
|
+
* @param {string[]} messageIds - Message IDs (msg_*) to archive.
|
|
692
|
+
* @returns {Promise<{ updated: number }>}
|
|
693
|
+
*/
|
|
694
|
+
async archiveMessages(messageIds) {
|
|
695
|
+
return this._request('/api/messages', 'PATCH', {
|
|
696
|
+
message_ids: messageIds,
|
|
697
|
+
action: 'archive',
|
|
698
|
+
agent_id: this.agentId,
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
|
|
614
702
|
// ---------------------------------------------------------------------------
|
|
615
703
|
// Session Handoffs
|
|
616
704
|
// ---------------------------------------------------------------------------
|