osuite 2.9.0 → 2.9.2

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/dashclaw.js DELETED
@@ -1,988 +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
- const PCAA_CHECKPOINTS = [
23
- {
24
- id: 'pre_action_admissibility',
25
- title: 'Pre-action admissibility',
26
- summary: 'Evaluate whether the proposed action is allowed, simulated first, blocked, or approval-gated before side effects happen.',
27
- sdkMethod: 'guard',
28
- },
29
- {
30
- id: 'action_open',
31
- title: 'Action open',
32
- summary: 'Create the portable action record that becomes the trust object for replay, scoring, and proof.',
33
- sdkMethod: 'createAction',
34
- },
35
- {
36
- id: 'assumption_capture',
37
- title: 'Assumption capture',
38
- summary: 'Record what the runtime believed or depended on so operators can replay the reasoning boundary later.',
39
- sdkMethod: 'recordAssumption',
40
- },
41
- {
42
- id: 'approval_checkpoint',
43
- title: 'Approval checkpoint',
44
- summary: 'Pause, wait, or externally hold execution when policy requires a human checkpoint.',
45
- sdkMethod: 'waitForApproval',
46
- },
47
- {
48
- id: 'outcome_closure',
49
- title: 'Outcome closure',
50
- summary: 'Write the final result, evidence, and status so the action certificate closes cleanly.',
51
- sdkMethod: 'updateOutcome',
52
- },
53
- ];
54
-
55
- function toPercent(numerator, denominator) {
56
- if (!denominator || denominator <= 0) return 0;
57
- return Math.max(0, Math.min(100, Math.round((numerator / denominator) * 100)));
58
- }
59
-
60
- function resolveRouteDecision({ action = null, proofBundle = null } = {}) {
61
- return (
62
- proofBundle?.route_decision
63
- || proofBundle?.action_certificate?.route_decision
64
- || action?.policy_snapshot?.effective_decision
65
- || null
66
- );
67
- }
68
-
69
- function resolveOutcomeStatus(status) {
70
- const normalized = String(status || '').toLowerCase();
71
- if (['completed', 'failed', 'blocked', 'cancelled', 'denied'].includes(normalized)) return 'complete';
72
- if (['running', 'pending', 'pending_approval'].includes(normalized)) return 'pending';
73
- return 'inactive';
74
- }
75
-
76
- function buildPcaaCheckpointStates({ action = null, trace = null, proofBundle = null } = {}) {
77
- const routeDecision = resolveRouteDecision({ action, proofBundle });
78
- const assumptionCount = Number(
79
- trace?.trace?.assumptions?.total
80
- ?? trace?.assumptions?.total
81
- ?? (Array.isArray(trace?.assumptions) ? trace.assumptions.length : 0),
82
- );
83
- const approvalTriggered = ['require_approval', 'require_dual_approval', 'simulate_first', 'warn', 'block']
84
- .includes(String(routeDecision || '').toLowerCase())
85
- || String(action?.status || '').toLowerCase() === 'pending_approval';
86
- const approvalComplete = Boolean(
87
- action?.approved_by
88
- || action?.approved_at
89
- || (Array.isArray(proofBundle?.approvals) && proofBundle.approvals.length > 0),
90
- );
91
- const outcomeStatus = resolveOutcomeStatus(action?.status);
92
-
93
- return PCAA_CHECKPOINTS.map((checkpoint) => {
94
- if (checkpoint.id === 'pre_action_admissibility') {
95
- return {
96
- ...checkpoint,
97
- status: routeDecision ? 'complete' : 'inactive',
98
- value: routeDecision || 'not evaluated',
99
- };
100
- }
101
-
102
- if (checkpoint.id === 'action_open') {
103
- return {
104
- ...checkpoint,
105
- status: action?.action_id ? 'complete' : 'inactive',
106
- value: action?.action_id || '--',
107
- };
108
- }
109
-
110
- if (checkpoint.id === 'assumption_capture') {
111
- return {
112
- ...checkpoint,
113
- status: assumptionCount > 0 ? 'complete' : 'inactive',
114
- value: assumptionCount > 0 ? `${assumptionCount} recorded` : 'none recorded',
115
- };
116
- }
117
-
118
- if (checkpoint.id === 'approval_checkpoint') {
119
- return {
120
- ...checkpoint,
121
- status: approvalComplete ? 'complete' : approvalTriggered ? 'active' : 'inactive',
122
- value: approvalComplete ? 'approved' : approvalTriggered ? (routeDecision || 'active') : 'not required',
123
- };
124
- }
125
-
126
- return {
127
- ...checkpoint,
128
- status: outcomeStatus,
129
- value: action?.status || '--',
130
- };
131
- });
132
- }
133
-
134
- class DashClaw {
135
- /**
136
- * @param {Object} options
137
- * @param {string} options.baseUrl - DashClaw base URL
138
- * @param {string} options.apiKey - API key for authentication
139
- * @param {string} options.agentId - Unique identifier for this agent
140
- */
141
- constructor({ baseUrl, apiKey, agentId, agentKeyId = null, provenanceVersion = 'dc-prov-v1' }) {
142
- if (!baseUrl) throw new Error('baseUrl is required');
143
- if (!apiKey) throw new Error('apiKey is required');
144
- if (!agentId) throw new Error('agentId is required');
145
-
146
- this.baseUrl = baseUrl.replace(/\/$/, '');
147
- this.apiKey = apiKey;
148
- this.agentId = agentId;
149
- this.agentKeyId = agentKeyId;
150
- this.provenanceVersion = provenanceVersion;
151
- }
152
-
153
- _withProvenance(payload = {}) {
154
- const body = { ...payload };
155
- const signature = body.agentSignature || body.agent_signature || body._signature || null;
156
-
157
- delete body.agentSignature;
158
- delete body.agent_signature;
159
-
160
- if (signature) {
161
- body._signature = signature;
162
- }
163
-
164
- if (body.agent_key_id === undefined && this.agentKeyId) {
165
- body.agent_key_id = this.agentKeyId;
166
- }
167
-
168
- if (body.provenance_version === undefined && this.provenanceVersion) {
169
- body.provenance_version = this.provenanceVersion;
170
- }
171
-
172
- return body;
173
- }
174
-
175
- async _request(path, method = 'GET', body = null, params = null, options = {}) {
176
- let url = `${this.baseUrl}${path}`;
177
- if (params) {
178
- const qs = new URLSearchParams(params).toString();
179
- if (qs) url += `?${qs}`;
180
- }
181
-
182
- const headers = {
183
- 'Content-Type': 'application/json',
184
- 'x-api-key': this.apiKey
185
- };
186
-
187
- const res = await fetch(url, {
188
- method,
189
- headers,
190
- body: body ? JSON.stringify(body) : undefined
191
- });
192
-
193
- let data = {};
194
- if (typeof res.text === 'function') {
195
- const text = await res.text();
196
- data = text ? JSON.parse(text) : {};
197
- } else if (typeof res.json === 'function') {
198
- data = await res.json();
199
- }
200
- const allowedStatuses = new Set(options.allowStatuses || []);
201
-
202
- if (!res.ok && !allowedStatuses.has(res.status)) {
203
- if (res.status === 403 && data.decision && data.decision.decision === 'block') {
204
- throw new GuardBlockedError(data.decision);
205
- }
206
-
207
- // Prioritize reason (from governance blocks) over generic error field
208
- const errorMessage = data.reason || data.error || `Request failed with status ${res.status}`;
209
- const err = new Error(errorMessage);
210
- err.status = res.status;
211
- err.details = data.details;
212
- err.decision = data;
213
- throw err;
214
- }
215
-
216
- return data;
217
- }
218
-
219
- /**
220
- * POST /api/guard — "Can I do X?"
221
- * @param {Object} context
222
- * @returns {Promise<{decision: 'allow'|'block'|'require_approval', action_id: string, reason: string, signals: string[]}>}
223
- */
224
- async guard(context) {
225
- return this._request('/api/guard', 'POST', this._withProvenance({
226
- ...context,
227
- agent_id: context.agent_id || this.agentId,
228
- }));
229
- }
230
-
231
- /**
232
- * POST /api/actions — "I am attempting X."
233
- */
234
- async createAction(action) {
235
- return this._request('/api/actions', 'POST', this._withProvenance({
236
- ...action,
237
- agent_id: this.agentId,
238
- }));
239
- }
240
-
241
- /**
242
- * PATCH /api/actions/:id — "X finished with result Y."
243
- */
244
- async updateOutcome(actionId, outcome) {
245
- return this._request(`/api/actions/${actionId}`, 'PATCH', {
246
- ...outcome,
247
- timestamp_end: outcome.timestamp_end || new Date().toISOString()
248
- });
249
- }
250
-
251
- /**
252
- * GET /api/actions/:id — Fetch a single action by ID.
253
- */
254
- async getAction(actionId) {
255
- return this._request(`/api/actions/${actionId}`, 'GET');
256
- }
257
-
258
- /**
259
- * GET /api/actions/:id/trace — Fetch replay trace, assumptions, loops, and root-cause indicators.
260
- */
261
- async getActionTrace(actionId) {
262
- return this._request(`/api/actions/${actionId}/trace`, 'GET');
263
- }
264
-
265
- /**
266
- * GET /api/actions?status=pending_approval — List actions awaiting approval.
267
- */
268
- async getPendingApprovals(limit = 20, offset = 0) {
269
- return this._request('/api/actions', 'GET', null, {
270
- status: 'pending_approval',
271
- limit,
272
- offset,
273
- });
274
- }
275
-
276
- /**
277
- * POST /api/actions/:id/approve — Approve or deny an action.
278
- * @param {string} actionId
279
- * @param {'allow'|'deny'} decision
280
- * @param {string} [reasoning]
281
- */
282
- async approveAction(actionId, decision, reasoning) {
283
- const body = { decision };
284
- if (reasoning) body.reasoning = reasoning;
285
- return this._request(`/api/approvals/${actionId}`, 'POST', body);
286
- }
287
-
288
- /**
289
- * POST /api/assumptions — "I believe Z is true while doing X."
290
- */
291
- async recordAssumption(assumption) {
292
- return this._request('/api/assumptions', 'POST', assumption);
293
- }
294
-
295
- /**
296
- * GET /api/actions/:id — Polling helper for human approval.
297
- */
298
- async waitForApproval(actionId, { timeout = 300000, interval = 5000 } = {}) {
299
- const startTime = Date.now();
300
- let wasPending = false;
301
- let printedBlock = false;
302
-
303
- while (Date.now() - startTime < timeout) {
304
- const { action } = await this._request(`/api/actions/${actionId}`, 'GET');
305
-
306
- // Print structured approval block on first fetch
307
- if (!printedBlock) {
308
- printedBlock = true;
309
- try {
310
- const actionType = action.action_type || 'unknown';
311
- const riskScore = action.risk_score != null ? String(action.risk_score) : '-';
312
- const goal = action.declared_goal || '-';
313
- const agent = action.agent_id || this.agentId;
314
- const replayUrl = `${this.baseUrl}/replay/${actionId}`;
315
-
316
- const lines = [
317
- '\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',
318
- ` Action ID: ${actionId}`,
319
- ` Agent: ${agent}`,
320
- ` Action: ${actionType}`,
321
- ' Policy: require_approval',
322
- ` Risk Score: ${riskScore}`,
323
- ` Goal: ${goal}`,
324
- '',
325
- ` Replay: ${replayUrl}`,
326
- '',
327
- ' Waiting for approval... (Ctrl+C to abort)',
328
- '\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',
329
- ];
330
- process.stdout.write('\n' + lines.join('\n') + '\n\n');
331
- } catch (_) {
332
- // Rendering failure must not prevent the wait from proceeding
333
- }
334
- }
335
-
336
- if (action.status === 'pending_approval') {
337
- wasPending = true;
338
- }
339
-
340
- // Explicitly unblocked by approval metadata.
341
- // API key / CLI approvals may not have a human user id, so approved_at is
342
- // also treated as authoritative approval evidence.
343
- if (action.approved_by || action.approved_at) return action;
344
-
345
- // Denial cases
346
- if (action.status === 'failed' || action.status === 'cancelled') {
347
- throw new ApprovalDeniedError(action.error_message || 'Operator denied the action.', action.status);
348
- }
349
-
350
- // Requirement 4: If an action leaves pending_approval without approval metadata, throw an error.
351
- // This prevents "auto-approval" bugs where status is changed by non-approval paths.
352
- if (wasPending && action.status !== 'pending_approval') {
353
- throw new Error(`Action ${actionId} left pending_approval state without explicit approval metadata (Status: ${action.status})`);
354
- }
355
-
356
- // If allowed directly (never intercepted), return immediately
357
- if (!wasPending && action.status === 'running') {
358
- return { action };
359
- }
360
-
361
- await new Promise(r => setTimeout(r, interval));
362
- }
363
- throw new Error(`Timed out waiting for approval of action ${actionId}`);
364
- }
365
-
366
- /**
367
- * Subscribe to real-time SSE events from the OSuite server.
368
- * Uses fetch-based SSE parsing for Node 18+ compatibility.
369
- */
370
- events({ reconnect = true, maxRetries = Infinity, retryInterval = 3000 } = {}) {
371
- const url = `${this.baseUrl}/api/stream`;
372
- const handlers = new Map();
373
- let closed = false;
374
- let controller = null;
375
- let lastEventId = null;
376
- let retryCount = 0;
377
-
378
- const emit = (eventType, data) => {
379
- const callbacks = handlers.get(eventType) || [];
380
- for (const callback of callbacks) {
381
- try {
382
- callback(data);
383
- } catch {
384
- // Event handlers are intentionally isolated from stream health
385
- }
386
- }
387
- };
388
-
389
- const connect = async () => {
390
- controller = new AbortController();
391
- const headers = { 'x-api-key': this.apiKey };
392
- if (lastEventId) headers['last-event-id'] = lastEventId;
393
-
394
- const res = await fetch(url, {
395
- headers,
396
- signal: controller.signal,
397
- });
398
-
399
- if (!res.ok) {
400
- throw new Error(`SSE connection failed: ${res.status} ${res.statusText}`);
401
- }
402
-
403
- retryCount = 0;
404
-
405
- const reader = res.body.getReader();
406
- const decoder = new TextDecoder();
407
- let buffer = '';
408
- let currentEvent = null;
409
- let currentData = '';
410
-
411
- while (!closed) {
412
- const { done, value } = await reader.read();
413
- if (done) break;
414
- buffer += decoder.decode(value, { stream: true });
415
-
416
- const lines = buffer.split('\n');
417
- buffer = lines.pop() || '';
418
-
419
- for (const line of lines) {
420
- if (line.startsWith('id: ')) {
421
- lastEventId = line.slice(4).trim();
422
- } else if (line.startsWith('event: ')) {
423
- currentEvent = line.slice(7).trim();
424
- } else if (line.startsWith('data: ')) {
425
- currentData += line.slice(6);
426
- } else if (line.startsWith(':')) {
427
- continue;
428
- } else if (line === '' && currentEvent) {
429
- if (currentData) {
430
- try {
431
- emit(currentEvent, JSON.parse(currentData));
432
- } catch {
433
- // Ignore malformed frames to keep the stream alive
434
- }
435
- }
436
- currentEvent = null;
437
- currentData = '';
438
- } else if (line === '') {
439
- currentEvent = null;
440
- currentData = '';
441
- }
442
- }
443
- }
444
- };
445
-
446
- const connectLoop = async () => {
447
- while (!closed) {
448
- try {
449
- await connect();
450
- } catch (error) {
451
- if (closed) return;
452
- emit('error', error);
453
- }
454
-
455
- if (closed) return;
456
- if (!reconnect || retryCount >= maxRetries) {
457
- emit('error', new Error('SSE stream ended'));
458
- return;
459
- }
460
-
461
- retryCount += 1;
462
- emit('reconnecting', { attempt: retryCount, maxRetries });
463
- await new Promise((resolve) => setTimeout(resolve, retryInterval));
464
- }
465
- };
466
-
467
- const connectionPromise = connectLoop();
468
-
469
- const handle = {
470
- on(eventType, callback) {
471
- if (!handlers.has(eventType)) handlers.set(eventType, []);
472
- handlers.get(eventType).push(callback);
473
- return handle;
474
- },
475
- close() {
476
- closed = true;
477
- if (controller) controller.abort();
478
- },
479
- _promise: connectionPromise,
480
- };
481
-
482
- return handle;
483
- }
484
-
485
- /**
486
- * POST /api/agents/heartbeat
487
- */
488
- async heartbeat(status = 'online', metadata = null) {
489
- return this._request('/api/agents/heartbeat', 'POST', {
490
- agent_id: this.agentId,
491
- status,
492
- metadata
493
- });
494
- }
495
-
496
- /**
497
- * POST /api/agents/connections
498
- */
499
- async reportConnections(connections) {
500
- return this._request('/api/agents/connections', 'POST', {
501
- agent_id: this.agentId,
502
- connections
503
- });
504
- }
505
-
506
- /**
507
- * POST /api/actions/loops
508
- */
509
- async registerOpenLoop(actionId, loopType, description, metadata = null) {
510
- return this._request('/api/actions/loops', 'POST', {
511
- action_id: actionId,
512
- loop_type: loopType,
513
- description,
514
- metadata
515
- });
516
- }
517
-
518
- /**
519
- * PATCH /api/actions/loops/:id
520
- */
521
- async resolveOpenLoop(loopId, status, resolution = null) {
522
- return this._request(`/api/actions/loops/${loopId}`, 'PATCH', {
523
- status,
524
- resolution
525
- });
526
- }
527
-
528
- /**
529
- * GET /api/actions/signals
530
- */
531
- async getSignals() {
532
- return this._request('/api/actions/signals');
533
- }
534
-
535
- /**
536
- * GET /api/governance/proof — Fetch operator-facing or bundle-form governance proof.
537
- */
538
- async getGovernanceProof({ actionId = null, format = null } = {}) {
539
- return this._request('/api/governance/proof', 'GET', null, {
540
- ...(actionId ? { action_id: actionId } : {}),
541
- ...(format ? { format } : {}),
542
- });
543
- }
544
-
545
- /**
546
- * GET /api/governance/proof?format=bundle — Fetch machine-readable PCAA / proof bundle output.
547
- */
548
- async getGovernanceProofBundle({ actionId = null } = {}) {
549
- return this.getGovernanceProof({ actionId, format: 'bundle' });
550
- }
551
-
552
- /**
553
- * POST /api/governance/proof/verify — Verify one action attestation and proof bundle.
554
- */
555
- async verifyGovernanceProof(actionId, { throwOnInvalid = false } = {}) {
556
- return this._request(
557
- '/api/governance/proof/verify',
558
- 'POST',
559
- { action_id: actionId },
560
- null,
561
- throwOnInvalid ? {} : { allowStatuses: [422] },
562
- );
563
- }
564
-
565
- /**
566
- * GET /api/compliance/evidence — Fetch live evidence aggregates for PCAA / compliance.
567
- */
568
- async getComplianceEvidence({ window = '30d' } = {}) {
569
- return this._request('/api/compliance/evidence', 'GET', null, { window });
570
- }
571
-
572
- /**
573
- * GET /api/proof/export — Fetch a portable proof export by action or bundle id.
574
- */
575
- async exportProof({ actionId = null, bundleId = null } = {}) {
576
- if (!actionId && !bundleId) {
577
- throw new Error('actionId or bundleId is required');
578
- }
579
- return this._request('/api/proof/export', 'GET', null, {
580
- ...(actionId ? { action_id: actionId } : {}),
581
- ...(bundleId ? { bundle_id: bundleId } : {}),
582
- });
583
- }
584
-
585
- /**
586
- * Build the same PCAA health summary used by the workspace banner.
587
- */
588
- async getPcaaHealth({ window = '30d', agentId = null } = {}) {
589
- const [actionsStats, complianceEvidence] = await Promise.all([
590
- this._request('/api/actions/stats', 'GET', null, {
591
- ...(agentId ? { agent_id: agentId } : {}),
592
- }),
593
- this.getComplianceEvidence({ window }),
594
- ]);
595
-
596
- const evidence = complianceEvidence?.evidence || {};
597
- const totalActions = Number(actionsStats?.total || 0);
598
- const recordedActions = Number(evidence.action_records_total || 0);
599
- const approvals = Number(evidence.approval_requests || actionsStats?.approval || 0);
600
- const proofBundles = Number(evidence.proof_bundles_total || 0);
601
- const completeBundles = Number(evidence.complete_proof_bundles || 0);
602
-
603
- return {
604
- totalActions,
605
- recordedActions,
606
- approvals,
607
- proofBundles,
608
- completeBundles,
609
- checkpointCoverage: toPercent(recordedActions, totalActions || recordedActions || 1),
610
- approvalRate: toPercent(approvals, totalActions || approvals || 1),
611
- evidenceCompletion: toPercent(completeBundles, proofBundles || completeBundles || 1),
612
- window,
613
- generatedAt: complianceEvidence?.generated_at || new Date().toISOString(),
614
- };
615
- }
616
-
617
- /**
618
- * Fetch one action's PCAA view: action, trace, proof bundle, export bundle, and derived checkpoints.
619
- */
620
- async getPcaaAction(actionId) {
621
- const [actionPayload, trace, proofBundle, proofExport] = await Promise.all([
622
- this.getAction(actionId),
623
- this.getActionTrace(actionId),
624
- this.getGovernanceProofBundle({ actionId }),
625
- this.exportProof({ actionId }).catch((error) => {
626
- if (error?.status === 404) return null;
627
- throw error;
628
- }),
629
- ]);
630
-
631
- const action = actionPayload?.action || actionPayload || null;
632
- return {
633
- action,
634
- trace,
635
- proofBundle,
636
- proofExport,
637
- checkpoints: buildPcaaCheckpointStates({ action, trace, proofBundle }),
638
- };
639
- }
640
-
641
- /**
642
- * GET /api/learning/analytics/velocity
643
- */
644
- async getLearningVelocity(lookbackDays = 30) {
645
- return this._request('/api/learning/analytics/velocity', 'GET', null, {
646
- agent_id: this.agentId,
647
- lookback_days: lookbackDays
648
- });
649
- }
650
-
651
- /**
652
- * GET /api/learning/analytics/curves
653
- */
654
- async getLearningCurves(lookbackDays = 60) {
655
- return this._request('/api/learning/analytics/curves', 'GET', null, {
656
- agent_id: this.agentId,
657
- lookback_days: lookbackDays
658
- });
659
- }
660
-
661
- /**
662
- * GET /api/learning/lessons — Fetch consolidated lessons from scored outcomes.
663
- */
664
- async getLessons({ actionType, limit } = {}) {
665
- return this._request('/api/learning/lessons', 'GET', null, {
666
- agent_id: this.agentId,
667
- ...(actionType && { action_type: actionType }),
668
- ...(limit && { limit }),
669
- });
670
- }
671
-
672
- /**
673
- * POST /api/prompts/render
674
- */
675
- async renderPrompt({ template_id, version_id, variables, record = false }) {
676
- return this._request('/api/prompts/render', 'POST', {
677
- template_id,
678
- version_id,
679
- variables,
680
- agent_id: this.agentId,
681
- record
682
- });
683
- }
684
-
685
- /**
686
- * POST /api/evaluations/scorers
687
- */
688
- async createScorer(name, scorer_type, config = null, description = null) {
689
- return this._request('/api/evaluations/scorers', 'POST', {
690
- name,
691
- scorer_type,
692
- config,
693
- description
694
- });
695
- }
696
-
697
- /**
698
- * POST /api/scoring/profiles
699
- */
700
- async createScoringProfile(profile) {
701
- return this._request('/api/scoring/profiles', 'POST', profile);
702
- }
703
-
704
- /**
705
- * GET /api/scoring/profiles
706
- */
707
- async listScoringProfiles(filters = {}) {
708
- return this._request('/api/scoring/profiles', 'GET', null, filters);
709
- }
710
-
711
- /**
712
- * GET /api/scoring/profiles/:id
713
- */
714
- async getScoringProfile(profileId) {
715
- return this._request(`/api/scoring/profiles/${profileId}`, 'GET');
716
- }
717
-
718
- /**
719
- * PATCH /api/scoring/profiles/:id
720
- */
721
- async updateScoringProfile(profileId, updates) {
722
- return this._request(`/api/scoring/profiles/${profileId}`, 'PATCH', updates);
723
- }
724
-
725
- /**
726
- * DELETE /api/scoring/profiles/:id
727
- */
728
- async deleteScoringProfile(profileId) {
729
- return this._request(`/api/scoring/profiles/${profileId}`, 'DELETE');
730
- }
731
-
732
- /**
733
- * POST /api/scoring/profiles/:id/dimensions
734
- */
735
- async addScoringDimension(profileId, dimension) {
736
- return this._request(`/api/scoring/profiles/${profileId}/dimensions`, 'POST', dimension);
737
- }
738
-
739
- /**
740
- * PATCH /api/scoring/profiles/:id/dimensions/:dimId
741
- */
742
- async updateScoringDimension(profileId, dimensionId, updates) {
743
- return this._request(`/api/scoring/profiles/${profileId}/dimensions/${dimensionId}`, 'PATCH', updates);
744
- }
745
-
746
- /**
747
- * DELETE /api/scoring/profiles/:id/dimensions/:dimId
748
- */
749
- async deleteScoringDimension(profileId, dimensionId) {
750
- return this._request(`/api/scoring/profiles/${profileId}/dimensions/${dimensionId}`, 'DELETE');
751
- }
752
-
753
- /**
754
- * POST /api/scoring/score — score a single action against a profile
755
- */
756
- async scoreWithProfile(profileId, action) {
757
- return this._request('/api/scoring/score', 'POST', { profile_id: profileId, action });
758
- }
759
-
760
- /**
761
- * POST /api/scoring/score — batch score multiple actions against a profile
762
- */
763
- async batchScoreWithProfile(profileId, actions) {
764
- return this._request('/api/scoring/score', 'POST', { profile_id: profileId, actions });
765
- }
766
-
767
- /**
768
- * GET /api/scoring/score — list stored profile scores
769
- */
770
- async getProfileScores(filters = {}) {
771
- return this._request('/api/scoring/score', 'GET', null, filters);
772
- }
773
-
774
- /**
775
- * GET /api/scoring/score?view=stats — aggregate stats for a profile
776
- */
777
- async getProfileScoreStats(profileId) {
778
- return this._request('/api/scoring/score', 'GET', null, { profile_id: profileId, view: 'stats' });
779
- }
780
-
781
- /**
782
- * POST /api/scoring/risk-templates
783
- */
784
- async createRiskTemplate(template) {
785
- return this._request('/api/scoring/risk-templates', 'POST', template);
786
- }
787
-
788
- /**
789
- * GET /api/scoring/risk-templates
790
- */
791
- async listRiskTemplates(filters = {}) {
792
- return this._request('/api/scoring/risk-templates', 'GET', null, filters);
793
- }
794
-
795
- /**
796
- * PATCH /api/scoring/risk-templates/:id
797
- */
798
- async updateRiskTemplate(templateId, updates) {
799
- return this._request(`/api/scoring/risk-templates/${templateId}`, 'PATCH', updates);
800
- }
801
-
802
- /**
803
- * DELETE /api/scoring/risk-templates/:id
804
- */
805
- async deleteRiskTemplate(templateId) {
806
- return this._request(`/api/scoring/risk-templates/${templateId}`, 'DELETE');
807
- }
808
-
809
- /**
810
- * POST /api/scoring/calibrate — analyze historical data and suggest dimension thresholds
811
- */
812
- async autoCalibrate(options = {}) {
813
- return this._request('/api/scoring/calibrate', 'POST', options);
814
- }
815
-
816
- // ---------------------------------------------------------------------------
817
- // Agent Messaging
818
- // ---------------------------------------------------------------------------
819
-
820
- /**
821
- * POST /api/messages — Send a message to another agent or the dashboard.
822
- */
823
- async sendMessage({ to, type, subject, body, threadId, urgent, actionId }) {
824
- return this._request('/api/messages', 'POST', {
825
- from_agent_id: this.agentId,
826
- to_agent_id: to,
827
- message_type: type,
828
- subject,
829
- body,
830
- thread_id: threadId,
831
- urgent,
832
- action_id: actionId,
833
- });
834
- }
835
-
836
- /**
837
- * Create a scoped action context that auto-tags messages and assumptions
838
- * with the given action_id.
839
- * @param {string} actionId - The action_id to attach to all operations
840
- * @returns {{ sendMessage, recordAssumption, updateOutcome }}
841
- */
842
- actionContext(actionId) {
843
- return {
844
- sendMessage: ({ to, type, subject, body, threadId, urgent }) => {
845
- return this.sendMessage({ to, type, subject, body, threadId, urgent, actionId });
846
- },
847
- recordAssumption: (assumption) => {
848
- return this.recordAssumption({ ...assumption, action_id: actionId });
849
- },
850
- updateOutcome: (outcome) => {
851
- return this.updateOutcome(actionId, outcome);
852
- },
853
- };
854
- }
855
-
856
- /**
857
- * GET /api/messages — Fetch this agent's inbox.
858
- */
859
- async getInbox({ type, unread, limit } = {}) {
860
- return this._request('/api/messages', 'GET', null, {
861
- agent_id: this.agentId,
862
- direction: 'inbox',
863
- ...(type && { type }),
864
- ...(unread != null && { unread }),
865
- ...(limit && { limit }),
866
- });
867
- }
868
-
869
- // ---------------------------------------------------------------------------
870
- // Session Handoffs
871
- // ---------------------------------------------------------------------------
872
-
873
- /**
874
- * POST /api/handoffs — Create a session handoff record.
875
- */
876
- async createHandoff(handoff) {
877
- return this._request('/api/handoffs', 'POST', {
878
- agent_id: this.agentId,
879
- ...handoff,
880
- });
881
- }
882
-
883
- /**
884
- * GET /api/handoffs — Fetch the most recent handoff for this agent.
885
- */
886
- async getLatestHandoff() {
887
- return this._request('/api/handoffs', 'GET', null, {
888
- agent_id: this.agentId,
889
- latest: 'true',
890
- });
891
- }
892
-
893
- // ---------------------------------------------------------------------------
894
- // Security Scanning
895
- // ---------------------------------------------------------------------------
896
-
897
- /**
898
- * POST /api/security/prompt-injection — Scan text for prompt injection attacks.
899
- */
900
- async scanPromptInjection(text, { source } = {}) {
901
- return this._request('/api/security/prompt-injection', 'POST', {
902
- text,
903
- source,
904
- agent_id: this.agentId,
905
- });
906
- }
907
-
908
- // ---------------------------------------------------------------------------
909
- // User Feedback
910
- // ---------------------------------------------------------------------------
911
-
912
- /**
913
- * POST /api/feedback — Submit user feedback linked to an action.
914
- */
915
- async submitFeedback({ action_id, rating, comment, category, tags, metadata }) {
916
- return this._request('/api/feedback', 'POST', {
917
- action_id,
918
- agent_id: this.agentId,
919
- rating,
920
- comment,
921
- category,
922
- tags,
923
- metadata,
924
- });
925
- }
926
-
927
- // ---------------------------------------------------------------------------
928
- // Context Threads
929
- // ---------------------------------------------------------------------------
930
-
931
- /**
932
- * POST /api/context/threads — Create a reasoning context thread.
933
- */
934
- async createThread(thread) {
935
- return this._request('/api/context/threads', 'POST', {
936
- agent_id: this.agentId,
937
- ...thread,
938
- });
939
- }
940
-
941
- /**
942
- * POST /api/context/threads/:id/entries — Append a reasoning step.
943
- */
944
- async addThreadEntry(threadId, content, entryType) {
945
- return this._request(`/api/context/threads/${threadId}/entries`, 'POST', {
946
- content,
947
- entry_type: entryType,
948
- });
949
- }
950
-
951
- /**
952
- * PATCH /api/context/threads/:id — Close a reasoning thread.
953
- */
954
- async closeThread(threadId, summary) {
955
- return this._request(`/api/context/threads/${threadId}`, 'PATCH', {
956
- status: 'closed',
957
- ...(summary ? { summary } : {}),
958
- });
959
- }
960
-
961
- // ---------------------------------------------------------------------------
962
- // Bulk Sync
963
- // ---------------------------------------------------------------------------
964
-
965
- /**
966
- * POST /api/sync — Bulk state sync for periodic updates or bootstrap.
967
- */
968
- async syncState(state) {
969
- return this._request('/api/sync', 'POST', {
970
- agent_id: this.agentId,
971
- ...state,
972
- });
973
- }
974
- }
975
-
976
- const OSuite = DashClaw;
977
- const Osuite = DashClaw;
978
-
979
- export default OSuite;
980
- export {
981
- DashClaw,
982
- OSuite,
983
- Osuite,
984
- ApprovalDeniedError,
985
- GuardBlockedError,
986
- PCAA_CHECKPOINTS,
987
- buildPcaaCheckpointStates,
988
- };