dashclaw 2.1.1 → 2.1.3
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 +71 -49
- package/dashclaw.js +146 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# DashClaw SDK (v2)
|
|
1
|
+
# DashClaw SDK (v2.1.2)
|
|
2
2
|
|
|
3
3
|
**Minimal governance runtime for AI agents.**
|
|
4
4
|
|
|
@@ -6,70 +6,102 @@ The DashClaw SDK provides the infrastructure to intercept, govern, and verify ag
|
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
9
|
+
### Node.js
|
|
9
10
|
```bash
|
|
10
11
|
npm install dashclaw
|
|
11
12
|
```
|
|
12
13
|
|
|
14
|
+
### Python
|
|
15
|
+
```bash
|
|
16
|
+
pip install dashclaw
|
|
17
|
+
```
|
|
18
|
+
|
|
13
19
|
## The Governance Loop
|
|
14
20
|
|
|
15
21
|
DashClaw v2 is designed around a single 4-step loop.
|
|
16
22
|
|
|
23
|
+
### Node.js
|
|
17
24
|
```javascript
|
|
18
|
-
import { DashClaw
|
|
25
|
+
import { DashClaw } from 'dashclaw';
|
|
19
26
|
|
|
20
27
|
const claw = new DashClaw({
|
|
21
|
-
baseUrl:
|
|
28
|
+
baseUrl: 'https://dashclaw.io',
|
|
22
29
|
apiKey: process.env.DASHCLAW_API_KEY,
|
|
23
30
|
agentId: 'my-agent'
|
|
24
31
|
});
|
|
25
32
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
33
|
+
// 1. Ask permission
|
|
34
|
+
const res = await claw.guard({ action_type: 'deploy' });
|
|
35
|
+
|
|
36
|
+
// 2. Log intent
|
|
37
|
+
const { action_id } = await claw.createAction({ action_type: 'deploy' });
|
|
38
|
+
|
|
39
|
+
// 3. Log evidence
|
|
40
|
+
await claw.recordAssumption({ action_id, assumption: 'Tests passed' });
|
|
41
|
+
|
|
42
|
+
// 4. Update result
|
|
43
|
+
await claw.updateOutcome(action_id, { status: 'completed' });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Python
|
|
47
|
+
```python
|
|
48
|
+
from dashclaw import DashClaw
|
|
49
|
+
|
|
50
|
+
claw = DashClaw(
|
|
51
|
+
base_url="https://dashclaw.io",
|
|
52
|
+
api_key="your_api_key",
|
|
53
|
+
agent_id="my-agent"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# 1. Ask permission
|
|
57
|
+
res = claw.guard({"action_type": "deploy"})
|
|
58
|
+
|
|
59
|
+
# 2. Log intent
|
|
60
|
+
action = claw.create_action(action_type="deploy")
|
|
61
|
+
action_id = action["action_id"]
|
|
62
|
+
|
|
63
|
+
# 3. Log evidence
|
|
64
|
+
claw.record_assumption({"action_id": action_id, "assumption": "Tests passed"})
|
|
65
|
+
|
|
66
|
+
# 4. Update result
|
|
67
|
+
claw.update_outcome(action_id, status="completed")
|
|
59
68
|
```
|
|
60
69
|
|
|
61
70
|
---
|
|
62
71
|
|
|
63
|
-
## SDK Surface Area (v2)
|
|
72
|
+
## SDK Surface Area (v2.1.2)
|
|
64
73
|
|
|
65
|
-
The v2 SDK is optimized for stability and zero-overhead governance:
|
|
74
|
+
The v2.1.2 SDK is optimized for stability and zero-overhead governance:
|
|
66
75
|
|
|
76
|
+
### Core Runtime
|
|
67
77
|
- `guard(context)` — Policy evaluation ("Can I do X?")
|
|
68
78
|
- `createAction(action)` — Lifecycle tracking ("I am doing X")
|
|
69
79
|
- `updateOutcome(id, outcome)` — Result recording ("X finished with Y")
|
|
70
80
|
- `recordAssumption(assumption)` — Integrity tracking ("I believe Z while doing X")
|
|
71
81
|
- `waitForApproval(id)` — Polling helper for human-in-the-loop approvals
|
|
72
82
|
|
|
83
|
+
### Decision Integrity
|
|
84
|
+
- `registerOpenLoop(actionId, type, desc)` — Register unresolved dependencies.
|
|
85
|
+
- `resolveOpenLoop(loopId, status, res)` — Resolve pending loops.
|
|
86
|
+
- `getSignals()` — Get current risk signals across all agents.
|
|
87
|
+
|
|
88
|
+
### Swarm & Connectivity
|
|
89
|
+
- `heartbeat(status, metadata)` — Report agent presence and health.
|
|
90
|
+
- `reportConnections(connections)` — Report active provider connections.
|
|
91
|
+
|
|
92
|
+
### Learning & Optimization
|
|
93
|
+
- `getLearningVelocity()` — Track agent improvement rate.
|
|
94
|
+
- `getLearningCurves()` — Measure efficiency gains per action type.
|
|
95
|
+
- `renderPrompt(context)` — Fetch rendered prompt templates from DashClaw.
|
|
96
|
+
|
|
97
|
+
### Compliance & Audit
|
|
98
|
+
- `createScorer(name, type, config)` — Define automated evaluations.
|
|
99
|
+
- `createScoringProfile(profile)` — Weighted quality scoring.
|
|
100
|
+
- `mapCompliance(framework)` — Map behavior to regulatory controls.
|
|
101
|
+
- `getProofReport(format)` — Generate audit-ready evidence exports.
|
|
102
|
+
- `getActivityLogs(filters)` — Query the immutable audit trail.
|
|
103
|
+
- `createWebhook(url, events)` — Real-time event exfiltration.
|
|
104
|
+
|
|
73
105
|
---
|
|
74
106
|
|
|
75
107
|
## Error Handling
|
|
@@ -83,17 +115,7 @@ DashClaw uses standard HTTP status codes and custom error classes:
|
|
|
83
115
|
|
|
84
116
|
## Legacy SDK (v1)
|
|
85
117
|
|
|
86
|
-
If you require legacy features (Calendar, Messages, Workflows, etc.), the v1 SDK is available via the `legacy` sub-path
|
|
87
|
-
|
|
88
|
-
```javascript
|
|
89
|
-
// ESM
|
|
90
|
-
import { DashClaw } from 'dashclaw/legacy';
|
|
91
|
-
|
|
92
|
-
// CommonJS
|
|
93
|
-
const { DashClaw } = require('dashclaw/legacy');
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
*Note: Legacy features are now considered "Extensions" and require these routes to be enabled on your DashClaw server.*
|
|
118
|
+
If you require legacy features (Calendar, Messages, Workflows, etc.), the v1 SDK is available via the `legacy` sub-path in Node.js or via the full client in Python.
|
|
97
119
|
|
|
98
120
|
---
|
|
99
121
|
|
package/dashclaw.js
CHANGED
|
@@ -72,9 +72,6 @@ class DashClaw {
|
|
|
72
72
|
/**
|
|
73
73
|
* POST /api/guard — "Can I do X?"
|
|
74
74
|
* @param {Object} context
|
|
75
|
-
* @param {string} context.action - Action type (e.g. "deploy")
|
|
76
|
-
* @param {string} [context.intent] - What the action aims to do
|
|
77
|
-
* @param {number} [context.risk_score] - Risk score 0-100
|
|
78
75
|
* @returns {Promise<{decision: 'allow'|'block'|'require_approval', action_id: string, reason: string, signals: string[]}>}
|
|
79
76
|
*/
|
|
80
77
|
async guard(context) {
|
|
@@ -86,23 +83,16 @@ class DashClaw {
|
|
|
86
83
|
|
|
87
84
|
/**
|
|
88
85
|
* POST /api/actions — "I am attempting X."
|
|
89
|
-
* @param {Object} action
|
|
90
|
-
* @param {string} action.action_type - e.g. "deploy"
|
|
91
|
-
* @param {string} action.declared_goal - e.g. "deploy to production"
|
|
92
|
-
* @returns {Promise<{action: Object, action_id: string}>}
|
|
93
86
|
*/
|
|
94
87
|
async createAction(action) {
|
|
95
|
-
|
|
88
|
+
return this._request('/api/actions', 'POST', {
|
|
96
89
|
...action,
|
|
97
90
|
agent_id: this.agentId,
|
|
98
91
|
});
|
|
99
|
-
return res;
|
|
100
92
|
}
|
|
101
93
|
|
|
102
94
|
/**
|
|
103
95
|
* PATCH /api/actions/:id — "X finished with result Y."
|
|
104
|
-
* @param {string} actionId
|
|
105
|
-
* @param {Object} outcome
|
|
106
96
|
*/
|
|
107
97
|
async updateOutcome(actionId, outcome) {
|
|
108
98
|
return this._request(`/api/actions/${actionId}`, 'PATCH', {
|
|
@@ -113,7 +103,6 @@ class DashClaw {
|
|
|
113
103
|
|
|
114
104
|
/**
|
|
115
105
|
* POST /api/assumptions — "I believe Z is true while doing X."
|
|
116
|
-
* @param {Object} assumption
|
|
117
106
|
*/
|
|
118
107
|
async recordAssumption(assumption) {
|
|
119
108
|
return this._request('/api/assumptions', 'POST', assumption);
|
|
@@ -126,14 +115,158 @@ class DashClaw {
|
|
|
126
115
|
const startTime = Date.now();
|
|
127
116
|
while (Date.now() - startTime < timeout) {
|
|
128
117
|
const { action } = await this._request(`/api/actions/${actionId}`, 'GET');
|
|
129
|
-
|
|
118
|
+
|
|
119
|
+
// Explicitly unblocked by approval metadata
|
|
120
|
+
if (action.approved_by) return action;
|
|
121
|
+
|
|
122
|
+
// Denial cases
|
|
130
123
|
if (action.status === 'failed' || action.status === 'cancelled') {
|
|
131
124
|
throw new ApprovalDeniedError(action.error_message || 'Operator denied the action.', action.status);
|
|
132
125
|
}
|
|
126
|
+
|
|
127
|
+
// Requirement 4: If an action leaves pending_approval without approval metadata, throw an error.
|
|
128
|
+
// This prevents "auto-approval" bugs where status is changed by non-approval paths.
|
|
129
|
+
if (action.status !== 'pending_approval') {
|
|
130
|
+
throw new Error(`Action ${actionId} left pending_approval state without explicit approval metadata (Status: ${action.status})`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
133
|
await new Promise(r => setTimeout(r, interval));
|
|
134
134
|
}
|
|
135
135
|
throw new Error(`Timed out waiting for approval of action ${actionId}`);
|
|
136
136
|
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* POST /api/agents/heartbeat
|
|
140
|
+
*/
|
|
141
|
+
async heartbeat(status = 'online', metadata = null) {
|
|
142
|
+
return this._request('/api/agents/heartbeat', 'POST', {
|
|
143
|
+
agent_id: this.agentId,
|
|
144
|
+
status,
|
|
145
|
+
metadata
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* POST /api/agents/connections
|
|
151
|
+
*/
|
|
152
|
+
async reportConnections(connections) {
|
|
153
|
+
return this._request('/api/agents/connections', 'POST', {
|
|
154
|
+
agent_id: this.agentId,
|
|
155
|
+
connections
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* POST /api/actions/loops
|
|
161
|
+
*/
|
|
162
|
+
async registerOpenLoop(actionId, loopType, description, metadata = null) {
|
|
163
|
+
return this._request('/api/actions/loops', 'POST', {
|
|
164
|
+
action_id: actionId,
|
|
165
|
+
loop_type: loopType,
|
|
166
|
+
description,
|
|
167
|
+
metadata
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* PATCH /api/actions/loops/:id
|
|
173
|
+
*/
|
|
174
|
+
async resolveOpenLoop(loopId, status, resolution = null) {
|
|
175
|
+
return this._request(`/api/actions/loops/${loopId}`, 'PATCH', {
|
|
176
|
+
status,
|
|
177
|
+
resolution
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* GET /api/actions/signals
|
|
183
|
+
*/
|
|
184
|
+
async getSignals() {
|
|
185
|
+
return this._request('/api/actions/signals');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* GET /api/learning/analytics/velocity
|
|
190
|
+
*/
|
|
191
|
+
async getLearningVelocity(lookbackDays = 30) {
|
|
192
|
+
return this._request('/api/learning/analytics/velocity', 'GET', null, {
|
|
193
|
+
agent_id: this.agentId,
|
|
194
|
+
lookback_days: lookbackDays
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* GET /api/learning/analytics/curves
|
|
200
|
+
*/
|
|
201
|
+
async getLearningCurves(lookbackDays = 60) {
|
|
202
|
+
return this._request('/api/learning/analytics/curves', 'GET', null, {
|
|
203
|
+
agent_id: this.agentId,
|
|
204
|
+
lookback_days: lookbackDays
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* POST /api/prompts/render
|
|
210
|
+
*/
|
|
211
|
+
async renderPrompt({ template_id, version_id, variables, record = false }) {
|
|
212
|
+
return this._request('/api/prompts/render', 'POST', {
|
|
213
|
+
template_id,
|
|
214
|
+
version_id,
|
|
215
|
+
variables,
|
|
216
|
+
agent_id: this.agentId,
|
|
217
|
+
record
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* POST /api/evaluations/scorers
|
|
223
|
+
*/
|
|
224
|
+
async createScorer(name, scorer_type, config = null, description = null) {
|
|
225
|
+
return this._request('/api/evaluations/scorers', 'POST', {
|
|
226
|
+
name,
|
|
227
|
+
scorer_type,
|
|
228
|
+
config,
|
|
229
|
+
description
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* POST /api/scoring/profiles
|
|
235
|
+
*/
|
|
236
|
+
async createScoringProfile(profile) {
|
|
237
|
+
return this._request('/api/scoring/profiles', 'POST', profile);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* GET /api/compliance/map
|
|
242
|
+
*/
|
|
243
|
+
async mapCompliance(framework) {
|
|
244
|
+
return this._request(`/api/compliance/map`, 'GET', null, { framework });
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* GET /api/policies/proof
|
|
249
|
+
*/
|
|
250
|
+
async getProofReport(format = 'json') {
|
|
251
|
+
return this._request('/api/policies/proof', 'GET', null, { format });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* GET /api/activity
|
|
256
|
+
*/
|
|
257
|
+
async getActivityLogs(filters = {}) {
|
|
258
|
+
return this._request('/api/activity', 'GET', null, filters);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* POST /api/webhooks
|
|
263
|
+
*/
|
|
264
|
+
async createWebhook(url, events = null) {
|
|
265
|
+
return this._request('/api/webhooks', 'POST', {
|
|
266
|
+
url,
|
|
267
|
+
events
|
|
268
|
+
});
|
|
269
|
+
}
|
|
137
270
|
}
|
|
138
271
|
|
|
139
272
|
export { DashClaw, ApprovalDeniedError, GuardBlockedError };
|