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.
Files changed (3) hide show
  1. package/README.md +71 -49
  2. package/dashclaw.js +146 -13
  3. 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, GuardBlockedError } from 'dashclaw';
25
+ import { DashClaw } from 'dashclaw';
19
26
 
20
27
  const claw = new DashClaw({
21
- baseUrl: process.env.DASHCLAW_BASE_URL,
28
+ baseUrl: 'https://dashclaw.io',
22
29
  apiKey: process.env.DASHCLAW_API_KEY,
23
30
  agentId: 'my-agent'
24
31
  });
25
32
 
26
- async function runAgentTask() {
27
- // 1. GUARD: Ask for permission
28
- // Intercepts intent and evaluates vs. organization policies.
29
- const decision = await claw.guard({
30
- action_type: 'deploy',
31
- risk_score: 85
32
- });
33
-
34
- // 2. RECORD: Log the attempt
35
- // Promotes guarded intent into a recorded action record.
36
- const action = await claw.createAction({
37
- action_type: 'deploy',
38
- declared_goal: 'Deploying latest build'
39
- });
40
-
41
- try {
42
- // 3. VERIFY: Record assumptions
43
- // Tracks beliefs to detect reasoning drift later.
44
- await claw.recordAssumption({
45
- action_id: action.action_id,
46
- assumption: 'The staging tests passed.'
47
- });
48
-
49
- // Execute the real-world action here...
50
- // await deploy();
51
-
52
- // 4. OUTCOME: Log the evidence
53
- await claw.updateOutcome(action.action_id, { status: 'completed' });
54
-
55
- } catch (err) {
56
- await claw.updateOutcome(action.action_id, { status: 'failed', error: err.message });
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
- const res = await this._request('/api/actions', 'POST', {
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
- if (action.status === 'running' || action.status === 'completed') return action;
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dashclaw",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "Minimal governance runtime for AI agents. Intercept, govern, and verify agent actions.",
5
5
  "type": "module",
6
6
  "publishConfig": {