qati-sdk 1.0.5 → 1.1.0
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 +505 -20
- package/dist/index.cjs +490 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +842 -116
- package/dist/index.d.ts +842 -116
- package/dist/index.js +487 -60
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ The main feature groups on the client are:
|
|
|
12
12
|
- `client.trustState` — read risk and trust scores for users or other entities.
|
|
13
13
|
- `client.advisory` — list persisted advisories for the tenant (with filters and pagination).
|
|
14
14
|
- `client.explain` — fetch a composite explain / attribution payload for a single entity (by entity key).
|
|
15
|
+
- `client.mccEvaluation` — list, retrieve, and manually trigger MCC evaluation traces (keyset pagination).
|
|
15
16
|
- `client.events` — send telemetry events to the ingestion pipeline.
|
|
16
17
|
- `client.webhooks` — manage webhook endpoints for a tenant (register, list, update, delete, trigger test delivery).
|
|
17
18
|
- `client.quotas` — read and configure numeric caps (entities, monthly events, rate) for a tenant.
|
|
@@ -168,6 +169,134 @@ try {
|
|
|
168
169
|
}
|
|
169
170
|
```
|
|
170
171
|
|
|
172
|
+
## Query API: MCC evaluation traces
|
|
173
|
+
|
|
174
|
+
MCC (Multi-Candidate Commit) evaluation traces record how the scoring engine evaluated candidate actions for an entity — branch scores, predicted risk tiers, constraint failures, and the selected commit. Use `client.mccEvaluation` to query persisted traces or run a manual evaluation against an entity's latest trust state via the Query API.
|
|
175
|
+
|
|
176
|
+
Endpoints:
|
|
177
|
+
|
|
178
|
+
- `GET /v1/mcc/evaluations` — list with optional filters and **keyset pagination**
|
|
179
|
+
- `GET /v1/mcc/evaluations/{evaluation_id}` — fetch one trace by id
|
|
180
|
+
- `POST /v1/mcc/evaluate` — run MCC-Lite against the entity's latest trust state and persist the trace
|
|
181
|
+
|
|
182
|
+
Pagination uses a cursor, not an offset. Pass `after_id` from the previous page's `next_cursor`; when `next_cursor` is `null`, you have reached the last page.
|
|
183
|
+
|
|
184
|
+
### List evaluations for an entity
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { Session } from 'qati-sdk';
|
|
188
|
+
|
|
189
|
+
const session = new Session();
|
|
190
|
+
const client = session.createClient();
|
|
191
|
+
try {
|
|
192
|
+
const page = await client.mccEvaluation.list({
|
|
193
|
+
entityKey: 'SESSION:conv-abc',
|
|
194
|
+
limit: 50,
|
|
195
|
+
});
|
|
196
|
+
console.log(page.total_count, page.evaluations.length);
|
|
197
|
+
for (const ev of page.evaluations) {
|
|
198
|
+
console.log(ev.evaluation_id, ev.commit_type, ev.degraded);
|
|
199
|
+
}
|
|
200
|
+
} finally {
|
|
201
|
+
await client.close();
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Optional filters: `entity_key`, `since`, `until` (inclusive bounds on `created_at` as `Date` or ISO-8601 string), and `limit` (server caps at 100).
|
|
206
|
+
|
|
207
|
+
### Paginate through all evaluations
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
import { Session } from 'qati-sdk';
|
|
211
|
+
|
|
212
|
+
const session = new Session();
|
|
213
|
+
const client = session.createClient();
|
|
214
|
+
try {
|
|
215
|
+
let page = await client.mccEvaluation.list({
|
|
216
|
+
entity_key: 'USER:user-123',
|
|
217
|
+
limit: 50,
|
|
218
|
+
});
|
|
219
|
+
const allIds: string[] = [];
|
|
220
|
+
|
|
221
|
+
while (true) {
|
|
222
|
+
for (const ev of page.evaluations) {
|
|
223
|
+
allIds.push(ev.evaluation_id);
|
|
224
|
+
}
|
|
225
|
+
if (!page.next_cursor) break;
|
|
226
|
+
page = await client.mccEvaluation.list({
|
|
227
|
+
entity_key: 'USER:user-123',
|
|
228
|
+
limit: 50,
|
|
229
|
+
after_id: page.next_cursor,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
console.log(`Fetched ${allIds.length} evaluation ids`);
|
|
234
|
+
} finally {
|
|
235
|
+
await client.close();
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Get one evaluation by id
|
|
240
|
+
|
|
241
|
+
Returns the full trace including `evaluated_branches`, `selected_branch`, residuals, and version metadata. A missing id raises `QatiNotFoundError`.
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
import { Session, QatiNotFoundError } from 'qati-sdk';
|
|
245
|
+
|
|
246
|
+
const session = new Session();
|
|
247
|
+
const client = session.createClient();
|
|
248
|
+
try {
|
|
249
|
+
const evaluationId = '550e8400-e29b-41d4-a716-446655440000';
|
|
250
|
+
try {
|
|
251
|
+
const trace = await client.mccEvaluation.get(evaluationId);
|
|
252
|
+
const branch = trace.selected_branch ?? trace.evaluated_branches[0];
|
|
253
|
+
if (branch) {
|
|
254
|
+
console.log(
|
|
255
|
+
trace.entity_key,
|
|
256
|
+
branch.action_type,
|
|
257
|
+
branch.predicted_risk_tier,
|
|
258
|
+
branch.branch_score,
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
} catch (e) {
|
|
262
|
+
if (e instanceof QatiNotFoundError) {
|
|
263
|
+
console.log('Evaluation not found');
|
|
264
|
+
} else {
|
|
265
|
+
throw e;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
} finally {
|
|
269
|
+
await client.close();
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Trigger a manual evaluation
|
|
274
|
+
|
|
275
|
+
Runs MCC-Lite against the entity's current trust state, persists the trace, and returns the full `MCCEvaluation`. Requires an existing trust state for the entity; otherwise raises `QatiNotFoundError`.
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
import { Session, QatiNotFoundError } from 'qati-sdk';
|
|
279
|
+
|
|
280
|
+
const session = new Session();
|
|
281
|
+
const client = session.createClient();
|
|
282
|
+
try {
|
|
283
|
+
try {
|
|
284
|
+
const trace = await client.mccEvaluation.evaluate('USER:alice');
|
|
285
|
+
console.log(trace.evaluation_id, trace.commit_type, trace.degraded);
|
|
286
|
+
} catch (e) {
|
|
287
|
+
if (e instanceof QatiNotFoundError) {
|
|
288
|
+
console.log('Trust state not found for entity');
|
|
289
|
+
} else {
|
|
290
|
+
throw e;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
} finally {
|
|
294
|
+
await client.close();
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Types `MCCEvaluation`, `MCCEvaluationListResponse`, `MCCBranchEvaluation`, and `ListMccEvaluationsOptions` are exported from `qati-sdk`.
|
|
299
|
+
|
|
171
300
|
## Webhooks
|
|
172
301
|
|
|
173
302
|
`client.webhooks` manages webhook endpoints for a specific tenant. All methods require `tenantId` as their first argument — resolve it once with `client.tenant.verifyCredentials()` and reuse the value.
|
|
@@ -279,7 +408,11 @@ const client = session.createClient();
|
|
|
279
408
|
try {
|
|
280
409
|
const creds = await client.tenant.verifyCredentials();
|
|
281
410
|
const quota = await client.quotas.get(creds.tenant_id);
|
|
282
|
-
console.log(
|
|
411
|
+
console.log(
|
|
412
|
+
quota.max_tracked_entities,
|
|
413
|
+
quota.max_monthly_events,
|
|
414
|
+
quota.max_events_per_second,
|
|
415
|
+
);
|
|
283
416
|
} finally {
|
|
284
417
|
await client.close();
|
|
285
418
|
}
|
|
@@ -367,15 +500,65 @@ const v1Event = (signalPayload: object, extra: object = {}) => {
|
|
|
367
500
|
};
|
|
368
501
|
```
|
|
369
502
|
|
|
503
|
+
### Canonical scalar hashing (`stableHash`)
|
|
504
|
+
|
|
505
|
+
Several payload fields store a hash of sensitive text (`action_hash`, `device_fingerprint_hash`, `query_hash`, `retrieval_hash`, `retrieved_context_hash`, `user_comment_hash`). Use the exported **`stableHash`** helper so your client matches the server canonical format:
|
|
506
|
+
|
|
507
|
+
1. Unicode **NFC** normalization
|
|
508
|
+
2. Strip outer whitespace, **lowercase**
|
|
509
|
+
3. SHA-256 over UTF-8 bytes
|
|
510
|
+
4. Prefix with `sha256:` (for example `sha256:2c26b46b…`)
|
|
511
|
+
|
|
512
|
+
Empty, whitespace-only, or null/undefined input returns `undefined` — omit the field from the payload rather than hashing empty strings.
|
|
513
|
+
|
|
514
|
+
```ts
|
|
515
|
+
import { stableHash } from 'qati-sdk';
|
|
516
|
+
|
|
517
|
+
const action = 'SELECT id FROM users LIMIT 10';
|
|
518
|
+
const actionHash = stableHash(action); // sha256:…
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
On the Python SDK, use the same algorithm via `qati_lib.utils.crypto.stable_hash` (the server reference implementation).
|
|
522
|
+
|
|
370
523
|
### Available signal types
|
|
371
524
|
|
|
525
|
+
All **17** v1 signal types have a matching `create*Event` builder exported from `qati-sdk`. Each builder validates `signal_payload` with **Zod** and returns a `RawEventRequest`. Required fields must be supplied; optional fields may be omitted (defaults apply where defined).
|
|
526
|
+
|
|
527
|
+
| Signal type | Builder | Notes |
|
|
528
|
+
| -------------------- | ----------------------------- | ------------------------------------------- |
|
|
529
|
+
| `TRANSACTION` | `createTransactionEvent` | Financial / data-access transactions |
|
|
530
|
+
| `AUTH` | `createAuthEvent` | Login and MFA outcomes |
|
|
531
|
+
| `BEHAVIOR` | `createBehaviorEvent` | Requires `behavior_type`, `deviation_score` |
|
|
532
|
+
| `ANOMALY_FLAG` | `createAnomalyFlagEvent` | Requires `anomaly_type`, `severity` |
|
|
533
|
+
| `NETWORK_EVENT` | `createNetworkEvent` | IP/ASN reputation and threat scores |
|
|
534
|
+
| `MODEL_OUTPUT` | `createModelOutputEvent` | LLM output quality metrics |
|
|
535
|
+
| `SYSTEM_TELEMETRY` | `createSystemTelemetryEvent` | Infra and OT telemetry |
|
|
536
|
+
| `API_CALL` | `createApiCallEvent` | HTTP API invocation audit |
|
|
537
|
+
| `WORKFLOW_ACTION` | `createWorkflowActionEvent` | Multi-step workflow governance |
|
|
538
|
+
| `TOOL_CALL` | `createToolCallEvent` | Post-execution tool invocation |
|
|
539
|
+
| `TOOL_CALL_PROPOSED` | `createToolCallProposedEvent` | **Pre-execution** tool proposal gate |
|
|
540
|
+
| `SESSION` | `createSessionEvent` | Conversation/session lifecycle |
|
|
541
|
+
| `PROMPT_INPUT` | `createPromptInputEvent` | User prompt risk signals |
|
|
542
|
+
| `RAG_RETRIEVAL` | `createRagRetrievalEvent` | Retrieval quality and trust |
|
|
543
|
+
| `CONTEXT_INTEGRITY` | `createContextIntegrityEvent` | Prompt/context conflict detection |
|
|
544
|
+
| `POLICY_EVENT` | `createPolicyEvent` | Policy check outcomes |
|
|
545
|
+
| `USER_FEEDBACK` | `createUserFeedbackEvent` | End-user feedback on responses |
|
|
546
|
+
|
|
372
547
|
#### Transaction
|
|
373
548
|
|
|
374
549
|
```ts
|
|
375
550
|
import { createTransactionEvent, type TransactionSignalEvent } from 'qati-sdk';
|
|
376
551
|
|
|
377
552
|
const raw = createTransactionEvent(
|
|
378
|
-
v1Event({
|
|
553
|
+
v1Event({
|
|
554
|
+
amount: 99.99,
|
|
555
|
+
currency: 'USD',
|
|
556
|
+
channel: 'ECOM',
|
|
557
|
+
bulk_export: false,
|
|
558
|
+
contains_phi: false,
|
|
559
|
+
safety_critical: false,
|
|
560
|
+
authorized: true,
|
|
561
|
+
}) as TransactionSignalEvent,
|
|
379
562
|
);
|
|
380
563
|
```
|
|
381
564
|
|
|
@@ -386,9 +569,13 @@ import { createAuthEvent, type AuthSignalEvent } from 'qati-sdk';
|
|
|
386
569
|
|
|
387
570
|
const raw = createAuthEvent(
|
|
388
571
|
v1Event({
|
|
389
|
-
result: '
|
|
390
|
-
auth_method: '
|
|
572
|
+
result: 'SUCCESS',
|
|
573
|
+
auth_method: 'MFA_TOTP',
|
|
391
574
|
mfa_used: true,
|
|
575
|
+
mfa_bypassed: false,
|
|
576
|
+
failed_attempts: 0,
|
|
577
|
+
unusual_location: false,
|
|
578
|
+
after_hours_login: false,
|
|
392
579
|
}) as AuthSignalEvent,
|
|
393
580
|
);
|
|
394
581
|
```
|
|
@@ -401,7 +588,14 @@ import { createModelOutputEvent, type ModelOutputSignalEvent } from 'qati-sdk';
|
|
|
401
588
|
const raw = createModelOutputEvent(
|
|
402
589
|
v1Event({
|
|
403
590
|
citation_rate: 0.95,
|
|
591
|
+
expected_citation_rate: 0.9,
|
|
592
|
+
policy_violations: 0,
|
|
593
|
+
tool_call_inconsistency: 0.02,
|
|
404
594
|
eval_window_n: 1000,
|
|
595
|
+
hallucination_risk_score: 0.05,
|
|
596
|
+
grounding_score: 0.88,
|
|
597
|
+
contains_unsupported_claims: false,
|
|
598
|
+
finish_reason: 'STOP',
|
|
405
599
|
}) as ModelOutputSignalEvent,
|
|
406
600
|
);
|
|
407
601
|
```
|
|
@@ -419,31 +613,55 @@ const raw = createSystemTelemetryEvent(
|
|
|
419
613
|
metric_name: 'p99_latency_ms',
|
|
420
614
|
value: 120.0,
|
|
421
615
|
baseline: 80.0,
|
|
616
|
+
window_seconds: 60,
|
|
617
|
+
error_rate: 0.01,
|
|
618
|
+
firmware_hash_changed: false,
|
|
619
|
+
expected_hash_match: true,
|
|
620
|
+
sensor_deviation_score: 0.1,
|
|
422
621
|
}) as SystemTelemetrySignalEvent,
|
|
423
622
|
);
|
|
424
623
|
```
|
|
425
624
|
|
|
426
625
|
#### Anomaly flag
|
|
427
626
|
|
|
428
|
-
`severity`
|
|
627
|
+
`severity` and `anomaly_type` are required. Optional device and volume fields support agent/session abuse patterns.
|
|
429
628
|
|
|
430
629
|
```ts
|
|
431
630
|
import { createAnomalyFlagEvent, type AnomalyFlagSignalEvent } from 'qati-sdk';
|
|
631
|
+
import { stableHash } from 'qati-sdk';
|
|
432
632
|
|
|
433
633
|
const raw = createAnomalyFlagEvent(
|
|
434
|
-
v1Event({
|
|
634
|
+
v1Event({
|
|
635
|
+
severity: 0.85,
|
|
636
|
+
anomaly_type: 'HIGH_VOLUME_SESSION',
|
|
637
|
+
metric_name: 'requests_per_minute',
|
|
638
|
+
metric_value: 42,
|
|
639
|
+
threshold: 10,
|
|
640
|
+
window_seconds: 60,
|
|
641
|
+
device_trust_state: 'UNVERIFIED',
|
|
642
|
+
device_fingerprint_hash: stableHash('device-fingerprint-payload'),
|
|
643
|
+
request_count: 42,
|
|
644
|
+
baseline_request_count: 10,
|
|
645
|
+
volume_ratio: 4.2,
|
|
646
|
+
}) as AnomalyFlagSignalEvent,
|
|
435
647
|
);
|
|
436
648
|
```
|
|
437
649
|
|
|
438
650
|
#### Behavior
|
|
439
651
|
|
|
440
|
-
`deviation_score` must be between 0 and 1.
|
|
441
|
-
|
|
442
652
|
```ts
|
|
443
653
|
import { createBehaviorEvent, type BehaviorSignalEvent } from 'qati-sdk';
|
|
444
654
|
|
|
445
655
|
const raw = createBehaviorEvent(
|
|
446
|
-
v1Event({
|
|
656
|
+
v1Event({
|
|
657
|
+
behavior_type: 'chat_cadence',
|
|
658
|
+
deviation_score: 0.72,
|
|
659
|
+
current_value: 18,
|
|
660
|
+
baseline_value: 5,
|
|
661
|
+
unit: 'prompts_per_minute',
|
|
662
|
+
baseline_window_seconds: 3600,
|
|
663
|
+
current_window_seconds: 60,
|
|
664
|
+
}) as BehaviorSignalEvent,
|
|
447
665
|
);
|
|
448
666
|
```
|
|
449
667
|
|
|
@@ -455,12 +673,271 @@ import { createNetworkEvent, type NetworkSignalEvent } from 'qati-sdk';
|
|
|
455
673
|
const raw = createNetworkEvent(
|
|
456
674
|
v1Event({
|
|
457
675
|
ip: '198.51.100.10',
|
|
676
|
+
asn: 24940,
|
|
677
|
+
country: 'US',
|
|
458
678
|
reputation_score: 0.2,
|
|
459
679
|
threat_score: 0.7,
|
|
680
|
+
is_datacenter: true,
|
|
681
|
+
is_untrusted_segment: false,
|
|
682
|
+
asn_reputation: 0.15,
|
|
460
683
|
}) as NetworkSignalEvent,
|
|
461
684
|
);
|
|
462
685
|
```
|
|
463
686
|
|
|
687
|
+
#### Tool call (executed)
|
|
688
|
+
|
|
689
|
+
```ts
|
|
690
|
+
import { createToolCallEvent, type ToolCallSignalEvent } from 'qati-sdk';
|
|
691
|
+
|
|
692
|
+
const raw = createToolCallEvent(
|
|
693
|
+
v1Event({
|
|
694
|
+
tool_name: 'search_docs',
|
|
695
|
+
tool_category: 'RETRIEVAL',
|
|
696
|
+
action: 'query',
|
|
697
|
+
authorized: true,
|
|
698
|
+
safety_critical: false,
|
|
699
|
+
external_side_effect: false,
|
|
700
|
+
tool_call_success: true,
|
|
701
|
+
latency_ms: 120,
|
|
702
|
+
argument_risk_score: 0.1,
|
|
703
|
+
records_accessed: 3,
|
|
704
|
+
contains_sensitive_data: false,
|
|
705
|
+
contains_phi: false,
|
|
706
|
+
sensitive_data_involved: false,
|
|
707
|
+
sensitive_domain: false,
|
|
708
|
+
}) as ToolCallSignalEvent,
|
|
709
|
+
);
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
#### Tool call proposed (pre-execution)
|
|
713
|
+
|
|
714
|
+
Use **`TOOL_CALL_PROPOSED`** before a tool runs to record governance metadata. **`action_hash`** is required when the action text is sensitive; compute it with `stableHash(action)`.
|
|
715
|
+
|
|
716
|
+
```ts
|
|
717
|
+
import {
|
|
718
|
+
createToolCallProposedEvent,
|
|
719
|
+
stableHash,
|
|
720
|
+
type ToolCallProposedSignalEvent,
|
|
721
|
+
} from 'qati-sdk';
|
|
722
|
+
|
|
723
|
+
const action = 'SELECT id, email FROM users LIMIT 10';
|
|
724
|
+
|
|
725
|
+
const raw = createToolCallProposedEvent(
|
|
726
|
+
v1Event({
|
|
727
|
+
tool_name: 'db_query',
|
|
728
|
+
tool_category: 'DATABASE',
|
|
729
|
+
action,
|
|
730
|
+
action_hash: stableHash(action)!,
|
|
731
|
+
authorized: false,
|
|
732
|
+
approval_required: true,
|
|
733
|
+
approval_missing: true,
|
|
734
|
+
approval_type: 'HUMAN',
|
|
735
|
+
argument_risk_score: 0.85,
|
|
736
|
+
argument_risk_reasons: ['bulk_pii_access'],
|
|
737
|
+
contains_sensitive_data: true,
|
|
738
|
+
data_scope: 'ORGANIZATION',
|
|
739
|
+
action_scope: 'ORGANIZATION',
|
|
740
|
+
execution_pending: true,
|
|
741
|
+
rollback_available: false,
|
|
742
|
+
}) as ToolCallProposedSignalEvent,
|
|
743
|
+
);
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
#### Session
|
|
747
|
+
|
|
748
|
+
```ts
|
|
749
|
+
import { createSessionEvent, type SessionSignalEvent } from 'qati-sdk';
|
|
750
|
+
|
|
751
|
+
const raw = createSessionEvent(
|
|
752
|
+
v1Event({
|
|
753
|
+
session_status: 'ACTIVE',
|
|
754
|
+
session_age_seconds: 300,
|
|
755
|
+
turn_count: 12,
|
|
756
|
+
messages_last_minute: 8,
|
|
757
|
+
conversation_id: 'conv-abc',
|
|
758
|
+
message_count: 24,
|
|
759
|
+
window_seconds: 300,
|
|
760
|
+
cadence_deviation: 0.4,
|
|
761
|
+
inter_message_interval_ms: 1500,
|
|
762
|
+
}) as SessionSignalEvent,
|
|
763
|
+
);
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
#### Prompt input
|
|
767
|
+
|
|
768
|
+
```ts
|
|
769
|
+
import {
|
|
770
|
+
createPromptInputEvent,
|
|
771
|
+
stableHash,
|
|
772
|
+
type PromptInputSignalEvent,
|
|
773
|
+
} from 'qati-sdk';
|
|
774
|
+
|
|
775
|
+
const prompt = 'Summarize the last three support tickets.';
|
|
776
|
+
const promptHash = stableHash(prompt)?.replace(/^sha256:/, '');
|
|
777
|
+
|
|
778
|
+
const raw = createPromptInputEvent(
|
|
779
|
+
v1Event({
|
|
780
|
+
prompt_length_chars: prompt.length,
|
|
781
|
+
conversation_turn_index: 3,
|
|
782
|
+
contains_instruction_override: false,
|
|
783
|
+
contains_tool_request: true,
|
|
784
|
+
contains_secret_request: false,
|
|
785
|
+
prompt_injection_score: 0.05,
|
|
786
|
+
prompt_hash: promptHash,
|
|
787
|
+
rapid_repeat: false,
|
|
788
|
+
prompt_sequence_index: 3,
|
|
789
|
+
}) as PromptInputSignalEvent,
|
|
790
|
+
);
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
#### RAG retrieval
|
|
794
|
+
|
|
795
|
+
```ts
|
|
796
|
+
import {
|
|
797
|
+
createRagRetrievalEvent,
|
|
798
|
+
stableHash,
|
|
799
|
+
type RagRetrievalSignalEvent,
|
|
800
|
+
} from 'qati-sdk';
|
|
801
|
+
|
|
802
|
+
const bundle = 'doc-1|doc-2|doc-3';
|
|
803
|
+
|
|
804
|
+
const raw = createRagRetrievalEvent(
|
|
805
|
+
v1Event({
|
|
806
|
+
retriever_id: 'retriever-prod',
|
|
807
|
+
query_hash: stableHash('customer refund policy'),
|
|
808
|
+
documents_retrieved: 3,
|
|
809
|
+
top_k: 5,
|
|
810
|
+
average_relevance_score: 0.82,
|
|
811
|
+
source_trust_score: 0.9,
|
|
812
|
+
lowest_source_trust_score: 0.7,
|
|
813
|
+
untrusted_source_count: 0,
|
|
814
|
+
retrieved_context_tokens: 1200,
|
|
815
|
+
context_injection_score: 0.02,
|
|
816
|
+
document_ids: ['doc-1', 'doc-2', 'doc-3'],
|
|
817
|
+
retrieval_hash: stableHash(bundle),
|
|
818
|
+
contains_sensitive_data: false,
|
|
819
|
+
}) as RagRetrievalSignalEvent,
|
|
820
|
+
);
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
#### Context integrity
|
|
824
|
+
|
|
825
|
+
```ts
|
|
826
|
+
import {
|
|
827
|
+
createContextIntegrityEvent,
|
|
828
|
+
stableHash,
|
|
829
|
+
type ContextIntegritySignalEvent,
|
|
830
|
+
} from 'qati-sdk';
|
|
831
|
+
|
|
832
|
+
const raw = createContextIntegrityEvent(
|
|
833
|
+
v1Event({
|
|
834
|
+
context_source: 'RETRIEVED_DOCUMENT',
|
|
835
|
+
instruction_conflict_detected: true,
|
|
836
|
+
untrusted_instruction_detected: false,
|
|
837
|
+
context_priority_violation: false,
|
|
838
|
+
context_drift_score: 0.35,
|
|
839
|
+
prompt_injection_score: 0.12,
|
|
840
|
+
retrieved_context_hash: stableHash('assembled-context-bundle'),
|
|
841
|
+
untrusted_source_count: 1,
|
|
842
|
+
source_trust_score: 0.6,
|
|
843
|
+
contains_instruction_override: false,
|
|
844
|
+
}) as ContextIntegritySignalEvent,
|
|
845
|
+
);
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
#### API call
|
|
849
|
+
|
|
850
|
+
```ts
|
|
851
|
+
import { createApiCallEvent, type ApiCallSignalEvent } from 'qati-sdk';
|
|
852
|
+
|
|
853
|
+
const raw = createApiCallEvent(
|
|
854
|
+
v1Event({
|
|
855
|
+
service_id: 'payments-api',
|
|
856
|
+
endpoint: '/v1/transfers',
|
|
857
|
+
method: 'POST',
|
|
858
|
+
status_code: 201,
|
|
859
|
+
authorized: true,
|
|
860
|
+
authentication_present: true,
|
|
861
|
+
external_side_effect: true,
|
|
862
|
+
records_modified: 1,
|
|
863
|
+
contains_sensitive_data: true,
|
|
864
|
+
latency_ms: 85,
|
|
865
|
+
retry_count: 0,
|
|
866
|
+
}) as ApiCallSignalEvent,
|
|
867
|
+
);
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
#### Workflow action
|
|
871
|
+
|
|
872
|
+
```ts
|
|
873
|
+
import {
|
|
874
|
+
createWorkflowActionEvent,
|
|
875
|
+
type WorkflowActionSignalEvent,
|
|
876
|
+
} from 'qati-sdk';
|
|
877
|
+
|
|
878
|
+
const raw = createWorkflowActionEvent(
|
|
879
|
+
v1Event({
|
|
880
|
+
workflow_name: 'payment_approval',
|
|
881
|
+
workflow_id: 'wf-001',
|
|
882
|
+
workflow_type: 'approval',
|
|
883
|
+
action_name: 'submit_wire_transfer',
|
|
884
|
+
action_category: 'FINANCIAL',
|
|
885
|
+
action_stage: 'PROPOSED',
|
|
886
|
+
actor_type: 'AI_AGENT',
|
|
887
|
+
approval_required: true,
|
|
888
|
+
approval_missing: true,
|
|
889
|
+
approval_type: 'DUAL_CONTROL',
|
|
890
|
+
financially_material: true,
|
|
891
|
+
financial_amount: 50000,
|
|
892
|
+
financial_currency: 'USD',
|
|
893
|
+
data_scope: 'ORGANIZATION',
|
|
894
|
+
action_scope: 'EXTERNAL',
|
|
895
|
+
contains_sensitive_data: true,
|
|
896
|
+
}) as WorkflowActionSignalEvent,
|
|
897
|
+
);
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
#### Policy event
|
|
901
|
+
|
|
902
|
+
```ts
|
|
903
|
+
import { createPolicyEvent, type PolicyEventSignalEvent } from 'qati-sdk';
|
|
904
|
+
|
|
905
|
+
const raw = createPolicyEvent(
|
|
906
|
+
v1Event({
|
|
907
|
+
policy_check_name: 'content_safety',
|
|
908
|
+
policy_category: 'SAFETY',
|
|
909
|
+
policy_result: 'WARN',
|
|
910
|
+
severity: 0.4,
|
|
911
|
+
blocked: false,
|
|
912
|
+
violation_count: 1,
|
|
913
|
+
policy_confidence: 0.92,
|
|
914
|
+
redaction_applied: true,
|
|
915
|
+
}) as PolicyEventSignalEvent,
|
|
916
|
+
);
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
#### User feedback
|
|
920
|
+
|
|
921
|
+
```ts
|
|
922
|
+
import {
|
|
923
|
+
createUserFeedbackEvent,
|
|
924
|
+
stableHash,
|
|
925
|
+
type UserFeedbackSignalEvent,
|
|
926
|
+
} from 'qati-sdk';
|
|
927
|
+
|
|
928
|
+
const raw = createUserFeedbackEvent(
|
|
929
|
+
v1Event({
|
|
930
|
+
feedback_type: 'THUMBS_DOWN',
|
|
931
|
+
reported_issue: true,
|
|
932
|
+
issue_type: 'hallucination',
|
|
933
|
+
severity: 0.7,
|
|
934
|
+
response_id: 'resp-123',
|
|
935
|
+
user_comment_hash: stableHash('The cited regulation does not exist.'),
|
|
936
|
+
conversation_id: 'conv-abc',
|
|
937
|
+
}) as UserFeedbackSignalEvent,
|
|
938
|
+
);
|
|
939
|
+
```
|
|
940
|
+
|
|
464
941
|
Note: At this point `raw` is an in-memory object. Nothing has been sent over the network yet. Proceed to Step 5 to deliver it.
|
|
465
942
|
|
|
466
943
|
### Canonical wire shape (`RawEventRequest` / `BaseEvent`)
|
|
@@ -653,7 +1130,12 @@ const v1Event = (signalPayload: object, extra: object = {}) => {
|
|
|
653
1130
|
};
|
|
654
1131
|
|
|
655
1132
|
try {
|
|
656
|
-
createAnomalyFlagEvent(
|
|
1133
|
+
createAnomalyFlagEvent(
|
|
1134
|
+
v1Event({
|
|
1135
|
+
severity: 2.0,
|
|
1136
|
+
anomaly_type: 'NEW_DEVICE',
|
|
1137
|
+
}) as AnomalyFlagSignalEvent,
|
|
1138
|
+
);
|
|
657
1139
|
} catch (e) {
|
|
658
1140
|
if (e instanceof ZodError) console.log(e.issues);
|
|
659
1141
|
}
|
|
@@ -674,15 +1156,18 @@ Transient failures are retried automatically for **`POST /v1/events:batch`** acc
|
|
|
674
1156
|
|
|
675
1157
|
## Appendix: API surface (compact)
|
|
676
1158
|
|
|
677
|
-
| Symbol
|
|
678
|
-
|
|
|
679
|
-
| `Session`
|
|
680
|
-
| `Client`
|
|
681
|
-
| `client.
|
|
682
|
-
|
|
|
683
|
-
| `client.
|
|
684
|
-
| `
|
|
685
|
-
|
|
|
686
|
-
|
|
|
1159
|
+
| Symbol | Role |
|
|
1160
|
+
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1161
|
+
| `Session` | `new Session(config?)`, `session.config`, `session.createClient(httpClients?)`. |
|
|
1162
|
+
| `Client` | Namespaces: `tenant`, `trustState`, `advisory`, `explain`, `mccEvaluation`, `events`, `webhooks`, `quotas`; `await client.close()`. |
|
|
1163
|
+
| `client.mccEvaluation` | `list(options?)`, `get(evaluationId)`, `evaluate(entityKey)`. Keyset pagination via `after_id` / `next_cursor` (no offset). |
|
|
1164
|
+
| MCC types | `MCCEvaluation`, `MCCEvaluationListResponse`, `MCCBranchEvaluation`, `ListMccEvaluationsOptions` — exported from `qati-sdk`. |
|
|
1165
|
+
| `client.events` | `enqueue`, `flush`, `shutdown`, `pendingCount`, `onIngestionFailure`. |
|
|
1166
|
+
| `client.webhooks` | `list(tenantId)`, `create(tenantId, body)`, `patch(tenantId, webhookId, body)`, `delete(tenantId, webhookId)`, `test(tenantId, webhookId)`. |
|
|
1167
|
+
| `client.quotas` | `get(tenantId)`, `upsert(tenantId, body)`. |
|
|
1168
|
+
| `create*Event` | All 17 v1 builders — `createTransactionEvent`, `createAuthEvent`, `createBehaviorEvent`, `createAnomalyFlagEvent`, `createNetworkEvent`, `createModelOutputEvent`, `createSystemTelemetryEvent`, `createApiCallEvent`, `createWorkflowActionEvent`, `createToolCallEvent`, **`createToolCallProposedEvent`**, `createSessionEvent`, `createPromptInputEvent`, `createRagRetrievalEvent`, `createContextIntegrityEvent`, `createPolicyEvent`, `createUserFeedbackEvent` — exported from `qati-sdk`. |
|
|
1169
|
+
| `stableHash` | Canonical scalar string hashing (`sha256:` prefix); use for hash payload fields. |
|
|
1170
|
+
| Config | `resolveQatiConfig`, `parseQatiConfig`, `baseUrlFor`, types `QatiConfigInput` / `QatiConfigOutput`. |
|
|
1171
|
+
| Errors | `QatiSDKError`, `QatiAPIError`, `QatiAuthError`, `QatiNotFoundError`, `QatiRateLimitError`, `QatiServerError`, `QatiConfigError`. |
|
|
687
1172
|
|
|
688
1173
|
`HttpClient.request(...)` exists for advanced use; prefer resource methods for application code.
|