osuite 2.8.1 → 2.9.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/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 DashClaw
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/dashclaw.js DELETED
@@ -1,628 +0,0 @@
1
- /**
2
- * DashClaw SDK v2 (Stable Runtime API)
3
- * Focused governance runtime client for AI agents.
4
- */
5
-
6
- class ApprovalDeniedError extends Error {
7
- constructor(message, decision) {
8
- super(message);
9
- this.name = 'ApprovalDeniedError';
10
- this.decision = decision;
11
- }
12
- }
13
-
14
- class GuardBlockedError extends Error {
15
- constructor(decision) {
16
- super(decision.reason || 'Action blocked by policy');
17
- this.name = 'GuardBlockedError';
18
- this.decision = decision;
19
- }
20
- }
21
-
22
- class DashClaw {
23
- /**
24
- * @param {Object} options
25
- * @param {string} options.baseUrl - DashClaw base URL
26
- * @param {string} options.apiKey - API key for authentication
27
- * @param {string} options.agentId - Unique identifier for this agent
28
- */
29
- constructor({ baseUrl, apiKey, agentId, agentKeyId = null, provenanceVersion = 'dc-prov-v1' }) {
30
- if (!baseUrl) throw new Error('baseUrl is required');
31
- if (!apiKey) throw new Error('apiKey is required');
32
- if (!agentId) throw new Error('agentId is required');
33
-
34
- this.baseUrl = baseUrl.replace(/\/$/, '');
35
- this.apiKey = apiKey;
36
- this.agentId = agentId;
37
- this.agentKeyId = agentKeyId;
38
- this.provenanceVersion = provenanceVersion;
39
- }
40
-
41
- _withProvenance(payload = {}) {
42
- const body = { ...payload };
43
- const signature = body.agentSignature || body.agent_signature || body._signature || null;
44
-
45
- delete body.agentSignature;
46
- delete body.agent_signature;
47
-
48
- if (signature) {
49
- body._signature = signature;
50
- }
51
-
52
- if (body.agent_key_id === undefined && this.agentKeyId) {
53
- body.agent_key_id = this.agentKeyId;
54
- }
55
-
56
- if (body.provenance_version === undefined && this.provenanceVersion) {
57
- body.provenance_version = this.provenanceVersion;
58
- }
59
-
60
- return body;
61
- }
62
-
63
- async _request(path, method = 'GET', body = null, params = null) {
64
- let url = `${this.baseUrl}${path}`;
65
- if (params) {
66
- const qs = new URLSearchParams(params).toString();
67
- if (qs) url += `?${qs}`;
68
- }
69
-
70
- const headers = {
71
- 'Content-Type': 'application/json',
72
- 'x-api-key': this.apiKey
73
- };
74
-
75
- const res = await fetch(url, {
76
- method,
77
- headers,
78
- body: body ? JSON.stringify(body) : undefined
79
- });
80
-
81
- const data = await res.json();
82
-
83
- if (!res.ok) {
84
- if (res.status === 403 && data.decision && data.decision.decision === 'block') {
85
- throw new GuardBlockedError(data.decision);
86
- }
87
-
88
- // Prioritize reason (from governance blocks) over generic error field
89
- const errorMessage = data.reason || data.error || `Request failed with status ${res.status}`;
90
- const err = new Error(errorMessage);
91
- err.status = res.status;
92
- err.details = data.details;
93
- err.decision = data;
94
- throw err;
95
- }
96
-
97
- return data;
98
- }
99
-
100
- /**
101
- * POST /api/guard — "Can I do X?"
102
- * @param {Object} context
103
- * @returns {Promise<{decision: 'allow'|'block'|'require_approval', action_id: string, reason: string, signals: string[]}>}
104
- */
105
- async guard(context) {
106
- return this._request('/api/guard', 'POST', this._withProvenance({
107
- ...context,
108
- agent_id: context.agent_id || this.agentId,
109
- }));
110
- }
111
-
112
- /**
113
- * POST /api/actions — "I am attempting X."
114
- */
115
- async createAction(action) {
116
- return this._request('/api/actions', 'POST', this._withProvenance({
117
- ...action,
118
- agent_id: this.agentId,
119
- }));
120
- }
121
-
122
- /**
123
- * PATCH /api/actions/:id — "X finished with result Y."
124
- */
125
- async updateOutcome(actionId, outcome) {
126
- return this._request(`/api/actions/${actionId}`, 'PATCH', {
127
- ...outcome,
128
- timestamp_end: outcome.timestamp_end || new Date().toISOString()
129
- });
130
- }
131
-
132
- /**
133
- * GET /api/actions/:id — Fetch a single action by ID.
134
- */
135
- async getAction(actionId) {
136
- return this._request(`/api/actions/${actionId}`, 'GET');
137
- }
138
-
139
- /**
140
- * GET /api/actions?status=pending_approval — List actions awaiting approval.
141
- */
142
- async getPendingApprovals(limit = 20, offset = 0) {
143
- return this._request('/api/actions', 'GET', null, {
144
- status: 'pending_approval',
145
- limit,
146
- offset,
147
- });
148
- }
149
-
150
- /**
151
- * POST /api/actions/:id/approve — Approve or deny an action.
152
- * @param {string} actionId
153
- * @param {'allow'|'deny'} decision
154
- * @param {string} [reasoning]
155
- */
156
- async approveAction(actionId, decision, reasoning) {
157
- const body = { decision };
158
- if (reasoning) body.reasoning = reasoning;
159
- return this._request(`/api/approvals/${actionId}`, 'POST', body);
160
- }
161
-
162
- /**
163
- * POST /api/assumptions — "I believe Z is true while doing X."
164
- */
165
- async recordAssumption(assumption) {
166
- return this._request('/api/assumptions', 'POST', assumption);
167
- }
168
-
169
- /**
170
- * GET /api/actions/:id — Polling helper for human approval.
171
- */
172
- async waitForApproval(actionId, { timeout = 300000, interval = 5000 } = {}) {
173
- const startTime = Date.now();
174
- let wasPending = false;
175
- let printedBlock = false;
176
-
177
- while (Date.now() - startTime < timeout) {
178
- const { action } = await this._request(`/api/actions/${actionId}`, 'GET');
179
-
180
- // Print structured approval block on first fetch
181
- if (!printedBlock) {
182
- printedBlock = true;
183
- try {
184
- const actionType = action.action_type || 'unknown';
185
- const riskScore = action.risk_score != null ? String(action.risk_score) : '-';
186
- const goal = action.declared_goal || '-';
187
- const agent = action.agent_id || this.agentId;
188
- const replayUrl = `${this.baseUrl}/replay/${actionId}`;
189
-
190
- const lines = [
191
- '\u2554\u2550\u2550 DashClaw Approval Required \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557',
192
- ` Action ID: ${actionId}`,
193
- ` Agent: ${agent}`,
194
- ` Action: ${actionType}`,
195
- ' Policy: require_approval',
196
- ` Risk Score: ${riskScore}`,
197
- ` Goal: ${goal}`,
198
- '',
199
- ` Replay: ${replayUrl}`,
200
- '',
201
- ' Waiting for approval... (Ctrl+C to abort)',
202
- '\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d',
203
- ];
204
- process.stdout.write('\n' + lines.join('\n') + '\n\n');
205
- } catch (_) {
206
- // Rendering failure must not prevent the wait from proceeding
207
- }
208
- }
209
-
210
- if (action.status === 'pending_approval') {
211
- wasPending = true;
212
- }
213
-
214
- // Explicitly unblocked by approval metadata.
215
- // API key / CLI approvals may not have a human user id, so approved_at is
216
- // also treated as authoritative approval evidence.
217
- if (action.approved_by || action.approved_at) return action;
218
-
219
- // Denial cases
220
- if (action.status === 'failed' || action.status === 'cancelled') {
221
- throw new ApprovalDeniedError(action.error_message || 'Operator denied the action.', action.status);
222
- }
223
-
224
- // Requirement 4: If an action leaves pending_approval without approval metadata, throw an error.
225
- // This prevents "auto-approval" bugs where status is changed by non-approval paths.
226
- if (wasPending && action.status !== 'pending_approval') {
227
- throw new Error(`Action ${actionId} left pending_approval state without explicit approval metadata (Status: ${action.status})`);
228
- }
229
-
230
- // If allowed directly (never intercepted), return immediately
231
- if (!wasPending && action.status === 'running') {
232
- return { action };
233
- }
234
-
235
- await new Promise(r => setTimeout(r, interval));
236
- }
237
- throw new Error(`Timed out waiting for approval of action ${actionId}`);
238
- }
239
-
240
- /**
241
- * POST /api/agents/heartbeat
242
- */
243
- async heartbeat(status = 'online', metadata = null) {
244
- return this._request('/api/agents/heartbeat', 'POST', {
245
- agent_id: this.agentId,
246
- status,
247
- metadata
248
- });
249
- }
250
-
251
- /**
252
- * POST /api/agents/connections
253
- */
254
- async reportConnections(connections) {
255
- return this._request('/api/agents/connections', 'POST', {
256
- agent_id: this.agentId,
257
- connections
258
- });
259
- }
260
-
261
- /**
262
- * POST /api/actions/loops
263
- */
264
- async registerOpenLoop(actionId, loopType, description, metadata = null) {
265
- return this._request('/api/actions/loops', 'POST', {
266
- action_id: actionId,
267
- loop_type: loopType,
268
- description,
269
- metadata
270
- });
271
- }
272
-
273
- /**
274
- * PATCH /api/actions/loops/:id
275
- */
276
- async resolveOpenLoop(loopId, status, resolution = null) {
277
- return this._request(`/api/actions/loops/${loopId}`, 'PATCH', {
278
- status,
279
- resolution
280
- });
281
- }
282
-
283
- /**
284
- * GET /api/actions/signals
285
- */
286
- async getSignals() {
287
- return this._request('/api/actions/signals');
288
- }
289
-
290
- /**
291
- * GET /api/learning/analytics/velocity
292
- */
293
- async getLearningVelocity(lookbackDays = 30) {
294
- return this._request('/api/learning/analytics/velocity', 'GET', null, {
295
- agent_id: this.agentId,
296
- lookback_days: lookbackDays
297
- });
298
- }
299
-
300
- /**
301
- * GET /api/learning/analytics/curves
302
- */
303
- async getLearningCurves(lookbackDays = 60) {
304
- return this._request('/api/learning/analytics/curves', 'GET', null, {
305
- agent_id: this.agentId,
306
- lookback_days: lookbackDays
307
- });
308
- }
309
-
310
- /**
311
- * GET /api/learning/lessons — Fetch consolidated lessons from scored outcomes.
312
- */
313
- async getLessons({ actionType, limit } = {}) {
314
- return this._request('/api/learning/lessons', 'GET', null, {
315
- agent_id: this.agentId,
316
- ...(actionType && { action_type: actionType }),
317
- ...(limit && { limit }),
318
- });
319
- }
320
-
321
- /**
322
- * POST /api/prompts/render
323
- */
324
- async renderPrompt({ template_id, version_id, variables, record = false }) {
325
- return this._request('/api/prompts/render', 'POST', {
326
- template_id,
327
- version_id,
328
- variables,
329
- agent_id: this.agentId,
330
- record
331
- });
332
- }
333
-
334
- /**
335
- * POST /api/evaluations/scorers
336
- */
337
- async createScorer(name, scorer_type, config = null, description = null) {
338
- return this._request('/api/evaluations/scorers', 'POST', {
339
- name,
340
- scorer_type,
341
- config,
342
- description
343
- });
344
- }
345
-
346
- /**
347
- * POST /api/scoring/profiles
348
- */
349
- async createScoringProfile(profile) {
350
- return this._request('/api/scoring/profiles', 'POST', profile);
351
- }
352
-
353
- /**
354
- * GET /api/scoring/profiles
355
- */
356
- async listScoringProfiles(filters = {}) {
357
- return this._request('/api/scoring/profiles', 'GET', null, filters);
358
- }
359
-
360
- /**
361
- * GET /api/scoring/profiles/:id
362
- */
363
- async getScoringProfile(profileId) {
364
- return this._request(`/api/scoring/profiles/${profileId}`, 'GET');
365
- }
366
-
367
- /**
368
- * PATCH /api/scoring/profiles/:id
369
- */
370
- async updateScoringProfile(profileId, updates) {
371
- return this._request(`/api/scoring/profiles/${profileId}`, 'PATCH', updates);
372
- }
373
-
374
- /**
375
- * DELETE /api/scoring/profiles/:id
376
- */
377
- async deleteScoringProfile(profileId) {
378
- return this._request(`/api/scoring/profiles/${profileId}`, 'DELETE');
379
- }
380
-
381
- /**
382
- * POST /api/scoring/profiles/:id/dimensions
383
- */
384
- async addScoringDimension(profileId, dimension) {
385
- return this._request(`/api/scoring/profiles/${profileId}/dimensions`, 'POST', dimension);
386
- }
387
-
388
- /**
389
- * PATCH /api/scoring/profiles/:id/dimensions/:dimId
390
- */
391
- async updateScoringDimension(profileId, dimensionId, updates) {
392
- return this._request(`/api/scoring/profiles/${profileId}/dimensions/${dimensionId}`, 'PATCH', updates);
393
- }
394
-
395
- /**
396
- * DELETE /api/scoring/profiles/:id/dimensions/:dimId
397
- */
398
- async deleteScoringDimension(profileId, dimensionId) {
399
- return this._request(`/api/scoring/profiles/${profileId}/dimensions/${dimensionId}`, 'DELETE');
400
- }
401
-
402
- /**
403
- * POST /api/scoring/score — score a single action against a profile
404
- */
405
- async scoreWithProfile(profileId, action) {
406
- return this._request('/api/scoring/score', 'POST', { profile_id: profileId, action });
407
- }
408
-
409
- /**
410
- * POST /api/scoring/score — batch score multiple actions against a profile
411
- */
412
- async batchScoreWithProfile(profileId, actions) {
413
- return this._request('/api/scoring/score', 'POST', { profile_id: profileId, actions });
414
- }
415
-
416
- /**
417
- * GET /api/scoring/score — list stored profile scores
418
- */
419
- async getProfileScores(filters = {}) {
420
- return this._request('/api/scoring/score', 'GET', null, filters);
421
- }
422
-
423
- /**
424
- * GET /api/scoring/score?view=stats — aggregate stats for a profile
425
- */
426
- async getProfileScoreStats(profileId) {
427
- return this._request('/api/scoring/score', 'GET', null, { profile_id: profileId, view: 'stats' });
428
- }
429
-
430
- /**
431
- * POST /api/scoring/risk-templates
432
- */
433
- async createRiskTemplate(template) {
434
- return this._request('/api/scoring/risk-templates', 'POST', template);
435
- }
436
-
437
- /**
438
- * GET /api/scoring/risk-templates
439
- */
440
- async listRiskTemplates(filters = {}) {
441
- return this._request('/api/scoring/risk-templates', 'GET', null, filters);
442
- }
443
-
444
- /**
445
- * PATCH /api/scoring/risk-templates/:id
446
- */
447
- async updateRiskTemplate(templateId, updates) {
448
- return this._request(`/api/scoring/risk-templates/${templateId}`, 'PATCH', updates);
449
- }
450
-
451
- /**
452
- * DELETE /api/scoring/risk-templates/:id
453
- */
454
- async deleteRiskTemplate(templateId) {
455
- return this._request(`/api/scoring/risk-templates/${templateId}`, 'DELETE');
456
- }
457
-
458
- /**
459
- * POST /api/scoring/calibrate — analyze historical data and suggest dimension thresholds
460
- */
461
- async autoCalibrate(options = {}) {
462
- return this._request('/api/scoring/calibrate', 'POST', options);
463
- }
464
-
465
- // ---------------------------------------------------------------------------
466
- // Agent Messaging
467
- // ---------------------------------------------------------------------------
468
-
469
- /**
470
- * POST /api/messages — Send a message to another agent or the dashboard.
471
- */
472
- async sendMessage({ to, type, subject, body, threadId, urgent, actionId }) {
473
- return this._request('/api/messages', 'POST', {
474
- from_agent_id: this.agentId,
475
- to_agent_id: to,
476
- message_type: type,
477
- subject,
478
- body,
479
- thread_id: threadId,
480
- urgent,
481
- action_id: actionId,
482
- });
483
- }
484
-
485
- /**
486
- * Create a scoped action context that auto-tags messages and assumptions
487
- * with the given action_id.
488
- * @param {string} actionId - The action_id to attach to all operations
489
- * @returns {{ sendMessage, recordAssumption, updateOutcome }}
490
- */
491
- actionContext(actionId) {
492
- return {
493
- sendMessage: ({ to, type, subject, body, threadId, urgent }) => {
494
- return this.sendMessage({ to, type, subject, body, threadId, urgent, actionId });
495
- },
496
- recordAssumption: (assumption) => {
497
- return this.recordAssumption({ ...assumption, action_id: actionId });
498
- },
499
- updateOutcome: (outcome) => {
500
- return this.updateOutcome(actionId, outcome);
501
- },
502
- };
503
- }
504
-
505
- /**
506
- * GET /api/messages — Fetch this agent's inbox.
507
- */
508
- async getInbox({ type, unread, limit } = {}) {
509
- return this._request('/api/messages', 'GET', null, {
510
- agent_id: this.agentId,
511
- direction: 'inbox',
512
- ...(type && { type }),
513
- ...(unread != null && { unread }),
514
- ...(limit && { limit }),
515
- });
516
- }
517
-
518
- // ---------------------------------------------------------------------------
519
- // Session Handoffs
520
- // ---------------------------------------------------------------------------
521
-
522
- /**
523
- * POST /api/handoffs — Create a session handoff record.
524
- */
525
- async createHandoff(handoff) {
526
- return this._request('/api/handoffs', 'POST', {
527
- agent_id: this.agentId,
528
- ...handoff,
529
- });
530
- }
531
-
532
- /**
533
- * GET /api/handoffs — Fetch the most recent handoff for this agent.
534
- */
535
- async getLatestHandoff() {
536
- return this._request('/api/handoffs', 'GET', null, {
537
- agent_id: this.agentId,
538
- latest: 'true',
539
- });
540
- }
541
-
542
- // ---------------------------------------------------------------------------
543
- // Security Scanning
544
- // ---------------------------------------------------------------------------
545
-
546
- /**
547
- * POST /api/security/prompt-injection — Scan text for prompt injection attacks.
548
- */
549
- async scanPromptInjection(text, { source } = {}) {
550
- return this._request('/api/security/prompt-injection', 'POST', {
551
- text,
552
- source,
553
- agent_id: this.agentId,
554
- });
555
- }
556
-
557
- // ---------------------------------------------------------------------------
558
- // User Feedback
559
- // ---------------------------------------------------------------------------
560
-
561
- /**
562
- * POST /api/feedback — Submit user feedback linked to an action.
563
- */
564
- async submitFeedback({ action_id, rating, comment, category, tags, metadata }) {
565
- return this._request('/api/feedback', 'POST', {
566
- action_id,
567
- agent_id: this.agentId,
568
- rating,
569
- comment,
570
- category,
571
- tags,
572
- metadata,
573
- });
574
- }
575
-
576
- // ---------------------------------------------------------------------------
577
- // Context Threads
578
- // ---------------------------------------------------------------------------
579
-
580
- /**
581
- * POST /api/context/threads — Create a reasoning context thread.
582
- */
583
- async createThread(thread) {
584
- return this._request('/api/context/threads', 'POST', {
585
- agent_id: this.agentId,
586
- ...thread,
587
- });
588
- }
589
-
590
- /**
591
- * POST /api/context/threads/:id/entries — Append a reasoning step.
592
- */
593
- async addThreadEntry(threadId, content, entryType) {
594
- return this._request(`/api/context/threads/${threadId}/entries`, 'POST', {
595
- content,
596
- entry_type: entryType,
597
- });
598
- }
599
-
600
- /**
601
- * PATCH /api/context/threads/:id — Close a reasoning thread.
602
- */
603
- async closeThread(threadId, summary) {
604
- return this._request(`/api/context/threads/${threadId}`, 'PATCH', {
605
- status: 'closed',
606
- ...(summary ? { summary } : {}),
607
- });
608
- }
609
-
610
- // ---------------------------------------------------------------------------
611
- // Bulk Sync
612
- // ---------------------------------------------------------------------------
613
-
614
- /**
615
- * POST /api/sync — Bulk state sync for periodic updates or bootstrap.
616
- */
617
- async syncState(state) {
618
- return this._request('/api/sync', 'POST', {
619
- agent_id: this.agentId,
620
- ...state,
621
- });
622
- }
623
- }
624
-
625
- const OSuite = DashClaw;
626
-
627
- export default OSuite;
628
- export { DashClaw, OSuite, ApprovalDeniedError, GuardBlockedError };