@nexalink/carecompass-sdk 0.4.0-beta.15 → 0.6.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 CHANGED
@@ -79,7 +79,7 @@ Nexalink-hosted CareCompass APIs
79
79
  CareCompass AI runtime
80
80
  ```
81
81
 
82
- The browser receives only public embed configuration: tenant identifier, environment, public embed key, allowed origins, branding, labels, theme, placement, and approved prompt settings.
82
+ The browser receives only public embed configuration: tenant identifier, environment, public embed key, allowed origins, endpoint, model preferences, feature flags, branding, labels, theme, placement, compliance, and approved prompt settings.
83
83
 
84
84
  Secret API keys stay in CLI, server-side, or trusted setup workflows. The browser never receives model credentials or Nexalink API keys.
85
85
 
@@ -97,6 +97,7 @@ The core manages:
97
97
  - loading, error, timeout, and retry state
98
98
  - context injection
99
99
  - subscriptions for custom renderers
100
+ - PHI preflight, safety callbacks, and metadata-only audit trails
100
101
  - endpoint calls and telemetry integration
101
102
 
102
103
  ```ts
@@ -172,7 +173,177 @@ Custom message rendering:
172
173
  />
173
174
  ```
174
175
 
175
- ### 3. Existing Embed Compatibility
176
+ ### RCM coding-assistance pilot workflow
177
+
178
+ The RCM kit is a narrow, structured coding-review workflow built on the same
179
+ headless core, compliance preflight, and metadata-only audit events. It returns
180
+ candidate codes for qualified human review; it never makes a final coding,
181
+ billing, claim-submission, diagnosis, or treatment decision.
182
+
183
+ The SDK sends `workflow: "rcm-coding-assistance"` as an explicit top-level ask
184
+ field. The hosted runtime authorizes the workflow from the issued embed key and
185
+ server-side tenant entitlement. Values in user context do not authorize a
186
+ workflow.
187
+
188
+ Development and staging RCM requests must include `claimContext.stage` set to
189
+ the configured SDK environment (`"development"` or `"staging"`). Production
190
+ may omit the field. The hosted runtime validates any supplied value against the
191
+ authenticated key environment; this marker never grants workflow access.
192
+
193
+ For the hosted RCM path, configure the tenant's RCM policy corpus in the
194
+ CareCompass tenant portal before embedding: an authorized administrator must
195
+ have an executed BAA, enable the RCM entitlement, set up the corpus, upload a
196
+ customer-owned policy version, explicitly approve it, and wait for ingestion to
197
+ become active. The browser sends structured encounter context only; it never
198
+ sends a corpus ID, policy text, or policy references.
199
+
200
+ ```tsx
201
+ import {
202
+ CARECOMPASS_RCM_SYNTHETIC_DEMO,
203
+ RcmCodingAssistant,
204
+ } from "@nexalink/carecompass-sdk/rcm";
205
+
206
+ <RcmCodingAssistant
207
+ config={config}
208
+ initialInput={CARECOMPASS_RCM_SYNTHETIC_DEMO}
209
+ workflowOptions={{
210
+ customerRules: { requirePolicySupport: true },
211
+ retrieval: "hosted",
212
+ }}
213
+ onAuditEvent={(event) => hostAudit(event)}
214
+ onSafetyEvent={(event) => hostSafetyMonitor(event)}
215
+ />;
216
+ ```
217
+
218
+ The included demo input is synthetic and contains no patient data. Its same-day
219
+ observation scenario is designed to retrieve the official CMS E/M evidence for
220
+ CPT 99236 from the Nexalink base corpus. Tenant policies may supplement the
221
+ base, but the runtime still requires an approved, active corpus and grounded
222
+ citations before returning a candidate.
223
+
224
+ A production tenant must have an executed BAA, an RCM entitlement, and a
225
+ healthy active corpus; otherwise the hosted workflow fails closed with a
226
+ structured human-review escalation.
227
+
228
+ In hosted mode, the result's `policyReferences` are the sanitized citations
229
+ resolved by the runtime. Render those citations alongside a coder-review
230
+ suggestion. A `review_required` result requires policy support; empty retrieval,
231
+ invalid citations, guardrail intervention, or invalid JSON becomes an
232
+ `abstain`/`escalate` result with no recommendations. Hosts receive the normal
233
+ metadata-only audit and safety events, including authorization, retrieval,
234
+ validation, and escalation outcomes.
235
+
236
+ For a customer-managed trusted retrieval boundary, pass an `RcmPolicyRetriever`
237
+ instead of `"hosted"`. Its `approvedCorpusIds` allowlist is enforced by the SDK;
238
+ unapproved or missing references produce a human-review escalation.
239
+
240
+ To evaluate the pilot, compare **manual research minutes per case** before and
241
+ after assisted, human-reviewed use. The target is to measure a 25% or greater
242
+ reduction, not to make or submit a coding decision.
243
+
244
+ ### 3. React Hook
245
+
246
+ Use `useCareCompass` when your React app needs its own visual design but does
247
+ not want to manage subscriptions, retries, or teardown by hand.
248
+
249
+ ```tsx
250
+ import { useCareCompass } from "@nexalink/carecompass-sdk/react";
251
+ import config from "./carecompass/carecompass.config.json";
252
+
253
+ export function CareCompassPanel() {
254
+ const { snapshot, sendMessage, retryLast } = useCareCompass(config, {
255
+ initialContext: { workflow: "member-portal" },
256
+ onSafetyEvent: (event) => monitorSafety(event),
257
+ });
258
+
259
+ return (
260
+ <section>
261
+ {snapshot.messages.map((message) => (
262
+ <p key={message.id}>{message.text}</p>
263
+ ))}
264
+ <button
265
+ disabled={snapshot.loading}
266
+ onClick={() => void sendMessage("Find an in-network doctor")}
267
+ >
268
+ Find care
269
+ </button>
270
+ {snapshot.canRetry && (
271
+ <button onClick={() => void retryLast()}>Retry</button>
272
+ )}
273
+ </section>
274
+ );
275
+ }
276
+ ```
277
+
278
+ The hook returns the underlying `core` for audit export, safety/audit
279
+ subscriptions, tool/widget events, and the lifecycle `streamMessage` API.
280
+
281
+ ### 4. Web Component (Vue-compatible)
282
+
283
+ The Web Component is rendered directly from the headless core and exposes a
284
+ standard custom-element property, making it a good fit for Vue, Angular, CMS
285
+ shells, and mixed-framework pages without requiring a React runtime. Register
286
+ it only in the browser.
287
+
288
+ ```ts
289
+ import { defineCareCompassElement } from "@nexalink/carecompass-sdk/web-component";
290
+
291
+ defineCareCompassElement();
292
+ ```
293
+
294
+ ```vue
295
+ <script setup lang="ts">
296
+ import { onMounted, ref } from "vue";
297
+ import { defineCareCompassElement } from "@nexalink/carecompass-sdk/web-component";
298
+ import config from "./carecompass/carecompass.config.json";
299
+
300
+ const chat = ref<HTMLElement & { config?: typeof config }>();
301
+ onMounted(() => {
302
+ defineCareCompassElement();
303
+ if (chat.value) chat.value.config = config;
304
+ });
305
+ </script>
306
+
307
+ <template><carecompass-chat ref="chat" /></template>
308
+ ```
309
+
310
+ For static hosts, the element also accepts a JSON `config` attribute. Prefer the
311
+ property assignment above in application code: it avoids HTML escaping and keeps
312
+ the configuration in your typed build pipeline.
313
+
314
+ ### 5. Script-tag Quickstart
315
+
316
+ The existing `mountCareCompass` path remains supported for quick static pages
317
+ and CMS integrations. Generate a script snippet from the same config:
318
+
319
+ ```ts
320
+ import { generateCareCompassSnippet } from "@nexalink/carecompass-sdk";
321
+
322
+ const html = generateCareCompassSnippet(config, { mode: "cdn" });
323
+ ```
324
+
325
+ The generated module calls `mountCareCompass` and does not require a React app.
326
+
327
+ ### 6. Iframe Fallback
328
+
329
+ Use an iframe when the host page needs strong CSS/JavaScript isolation or cannot
330
+ run a module script. The CLI `init` flow generates an iframe page, or you can
331
+ create the host markup with `generateCareCompassIframeSnippet(config)`.
332
+
333
+ ```ts
334
+ import { generateCareCompassIframeSnippet } from "@nexalink/carecompass-sdk";
335
+
336
+ const html = generateCareCompassIframeSnippet(config, {
337
+ src: "/carecompass/carecompass-embed.html",
338
+ });
339
+ ```
340
+
341
+ An iframe isolates page styles and scripts, but it adds a separate document for
342
+ focus management, analytics, responsive sizing, and host-to-widget context.
343
+ Choose the React hook or Web Component when the assistant needs rich in-page
344
+ coordination; choose the iframe for constrained or high-isolation environments.
345
+
346
+ ### 7. Existing Embed Compatibility
176
347
 
177
348
  Existing embed integrations can keep using the root package exports.
178
349
 
@@ -192,6 +363,40 @@ import config from "./carecompass/carecompass.config.json";
192
363
  mountCareCompass(document.getElementById("carecompass-root"), config);
193
364
  ```
194
365
 
366
+ ### Production runtime tokens
367
+
368
+ Production embeds require a fresh runtime token from an integrator-controlled
369
+ backend-for-frontend (BFF). Do not place a Nexalink API key, runtime-token
370
+ secret, or a reusable token in `carecompass.config.json` or browser code.
371
+
372
+ Provide `runtimeTokenProvider`; the SDK calls it before validation, every
373
+ inference request, and every status poll. The provider should call your BFF,
374
+ which holds the Nexalink API key and obtains a short-lived token for the
375
+ current browser origin and workflow.
376
+
377
+ ```tsx
378
+ const runtimeTokenProvider = async ({ workflow }: { workflow?: string }) => {
379
+ const response = await fetch("/api/carecompass/runtime-token", {
380
+ method: "POST",
381
+ credentials: "same-origin",
382
+ headers: { "content-type": "application/json" },
383
+ body: JSON.stringify({ workflow }),
384
+ });
385
+ if (!response.ok) throw new Error("Could not authorize CareCompass.");
386
+ return ((await response.json()) as { token: string }).token;
387
+ };
388
+
389
+ <CareCompassEmbed
390
+ config={config}
391
+ runtimeTokenProvider={runtimeTokenProvider}
392
+ />;
393
+ ```
394
+
395
+ For static hosts, pass the provider as the third argument to
396
+ `mountCareCompass`. For Web Components, assign it to the
397
+ `runtimeTokenProvider` property before setting `config`. Production requests
398
+ fail closed when the provider is absent, fails, or returns an empty token.
399
+
195
400
  ## Quick Start
196
401
 
197
402
  Live regulated use requires Nexalink onboarding, issued credentials, and BAA coverage where PHI may be involved. The package is publicly installable for developer convenience, but runtime access is credentialed.
@@ -249,6 +454,17 @@ npx @nexalink/carecompass-sdk doctor --config carecompass/carecompass.config.jso
249
454
  "welcomeMessage": "How can I help?",
250
455
  "allowUserContext": false
251
456
  },
457
+ "compliance": {
458
+ "preset": "healthcare"
459
+ },
460
+ "model": {
461
+ "id": "care-navigation-v2",
462
+ "version": "2026-07"
463
+ },
464
+ "featureFlags": {
465
+ "care-plan-summary": true,
466
+ "provider-search": true
467
+ },
252
468
  "placement": {
253
469
  "mode": "inline"
254
470
  },
@@ -256,6 +472,72 @@ npx @nexalink/carecompass-sdk doctor --config carecompass/carecompass.config.jso
256
472
  }
257
473
  ```
258
474
 
475
+ ## Compliance Controls And Audit Trails
476
+
477
+ Compliance controls are local SDK preflight checks, not a substitute for Nexalink runtime guardrails, a BAA, or the host application's own HIPAA program. They detect common direct identifiers (email addresses, US phone numbers, SSNs, DOBs, member/policy IDs, and MRNs) in messages, responses, and string-valued context before the SDK stores or sends them.
478
+
479
+ Choose a preset in public SDK configuration, then override only the behavior you need:
480
+
481
+ | Preset | PHI behavior | Audit retention | Tradeoff |
482
+ | ------------ | --------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------- |
483
+ | `standard` | Detects and emits a `policy_sensitive` safety callback; does not modify requests. | Off | Preserves existing SDK behavior; the host must opt into audit retention. |
484
+ | `healthcare` | Replaces detected values with `[REDACTED]` before requests and UI state. | On | Recommended default for PHI-oriented browser integrations; local detection cannot identify every form of PHI. |
485
+ | `strict` | Blocks a request or response with detectable PHI. | On | Stronger browser-side control, but legitimate identifier-bearing workflows need a host-approved alternative. |
486
+
487
+ ```ts
488
+ import { createCareCompassCore } from "@nexalink/carecompass-sdk/core";
489
+
490
+ const core = createCareCompassCore({
491
+ ...config,
492
+ compliance: {
493
+ preset: "healthcare",
494
+ phi: { replacement: "[PHI REMOVED]" },
495
+ },
496
+ });
497
+
498
+ const unsubscribeAudit = core.subscribeAudit((event) => {
499
+ // Persist to your audit system. Events contain type, outcome, timestamp,
500
+ // source, PHI category/count, and a generated ID—never message text,
501
+ // context values, identifiers, or raw errors.
502
+ persistAuditEvent(event);
503
+ });
504
+
505
+ const unsubscribeSafety = core.subscribeSafety((event) => {
506
+ // `blocked`, `redacted`, `escalated`, or `policy_sensitive` with only
507
+ // source plus PHI category/count for safe monitoring.
508
+ monitorSafetyEvent(event);
509
+ });
510
+
511
+ // Export a copy of the in-memory, metadata-only audit trail on demand.
512
+ const auditTrail = core.exportAuditTrail();
513
+
514
+ unsubscribeAudit();
515
+ unsubscribeSafety();
516
+ ```
517
+
518
+ For host-owned tools and UI actions that happen outside the core request lifecycle, add their metadata-only events explicitly:
519
+
520
+ ```ts
521
+ core.recordToolCall("completed");
522
+ core.recordWidgetAction();
523
+ core.recordSafetyDecision("escalated");
524
+ ```
525
+
526
+ If your organization has an approved detector or redaction format, pass it through `createCareCompassCore` options. These hooks receive the raw value only inside your host application; the SDK still emits only PHI categories and counts in audit and safety events.
527
+
528
+ ```ts
529
+ const core = createCareCompassCore(config, {
530
+ compliance: {
531
+ phi: {
532
+ detect: (value) => approvedPhiDetector(value),
533
+ redact: (value, matches) => approvedRedactor(value, matches),
534
+ },
535
+ },
536
+ });
537
+ ```
538
+
539
+ The React UI kit accepts `onAuditEvent` and `onSafetyEvent` with the same safe payloads. Its submit and retry actions are automatically represented as widget audit events when auditing is enabled.
540
+
259
541
  ## Credential Model
260
542
 
261
543
  CareCompass uses two key types:
@@ -316,7 +598,7 @@ The SDK is designed to keep sensitive operational details out of the browser:
316
598
  - no secret API keys in frontend config
317
599
  - no model endpoint credentials in browser code
318
600
  - no customer-managed telemetry switches in runtime config
319
- - no prompt, response, chat history, user context, PHI/PII, credentials, raw errors, stack traces, CLI arguments, terminal input, or file paths in SDK telemetry
601
+ - no prompt, response, chat history, user context, PHI/PII, payer, tenant, deployment, session, or user identifiers, credentials, raw errors, stack traces, CLI arguments, terminal input, or file paths in SDK telemetry
320
602
  - generated snippets escape serialized config
321
603
  - default React rendering escapes raw HTML
322
604
 
package/dist/cli.js CHANGED
File without changes
package/dist/client.d.ts CHANGED
@@ -1,21 +1,51 @@
1
1
  import { type CareCompassConfig } from "./schema.js";
2
2
  export type CareCompassAskRequest = {
3
3
  prompt: string;
4
+ /** Stable client-generated id used to make a submit/retry idempotent. */
5
+ requestId?: string;
6
+ workflow?: CareCompassWorkflowId;
4
7
  sessionId?: string;
5
8
  userContext?: Record<string, unknown>;
6
9
  };
10
+ export type CareCompassWorkflowId = "rcm-coding-assistance";
7
11
  export type CareCompassAskResponse = {
8
12
  jobId: string;
9
13
  };
14
+ export type CareCompassRetrievalReference = {
15
+ referenceId: string;
16
+ documentId: string;
17
+ title: string;
18
+ version: string;
19
+ excerpt: string;
20
+ };
21
+ export type CareCompassRetrievalMetadata = {
22
+ corpusId: string;
23
+ corpusVersion: string;
24
+ outcome: string;
25
+ latencyMs: number;
26
+ references: CareCompassRetrievalReference[];
27
+ };
10
28
  export type CareCompassStatusResponse = {
11
29
  status: "queued" | "running" | "complete" | "failed";
12
30
  result?: string;
31
+ retrieval?: CareCompassRetrievalMetadata;
13
32
  };
14
33
  type Fetcher = typeof fetch;
15
- export declare function createCareCompassClient(inputConfig: CareCompassConfig, options?: {
34
+ export type CareCompassRuntimeTokenRequest = {
35
+ payerId: string;
36
+ environment: CareCompassConfig["environment"];
37
+ embedKey: string;
38
+ workflow?: CareCompassWorkflowId;
39
+ jobId?: string;
40
+ };
41
+ /** Obtains a short-lived production token from the integrator's BFF. */
42
+ export type CareCompassRuntimeTokenProvider = (request: CareCompassRuntimeTokenRequest) => Promise<string> | string;
43
+ export type CareCompassClientOptions = {
16
44
  fetcher?: Fetcher;
17
45
  now?: () => number;
18
- }): {
46
+ runtimeTokenProvider?: CareCompassRuntimeTokenProvider;
47
+ };
48
+ export declare function createCareCompassClient(inputConfig: CareCompassConfig, options?: CareCompassClientOptions): {
19
49
  validateConfig: () => Promise<{
20
50
  ok: true;
21
51
  }>;
package/dist/client.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { validateCareCompassConfig } from "./schema.js";
2
2
  import { CARECOMPASS_TELEMETRY_ERROR_CODES, CARECOMPASS_TELEMETRY_EVENTS, createCareCompassTelemetry, } from "./telemetry.js";
3
+ import { CARECOMPASS_SDK_VERSION } from "./version.js";
3
4
  // Internal error metadata keeps telemetry classification separate from messages,
4
5
  // which may include user-visible API details that should not be emitted.
5
6
  class CareCompassClientError extends Error {
@@ -105,6 +106,30 @@ export function createCareCompassClient(inputConfig, options = {}) {
105
106
  "x-carecompass-environment": config.environment,
106
107
  };
107
108
  const jobStartedAt = new Map();
109
+ const jobWorkflows = new Map();
110
+ async function requestHeaders(request = {}) {
111
+ if (config.environment !== "production")
112
+ return headers;
113
+ if (!options.runtimeTokenProvider) {
114
+ throw new CareCompassClientError("Production CareCompass embeds require a runtimeTokenProvider backed by your server.", CARECOMPASS_TELEMETRY_ERROR_CODES.AUTHENTICATION_FAILED, "authentication");
115
+ }
116
+ let token;
117
+ try {
118
+ token = await options.runtimeTokenProvider({
119
+ payerId: config.payerId,
120
+ environment: config.environment,
121
+ embedKey: config.embedKey,
122
+ ...request,
123
+ });
124
+ }
125
+ catch {
126
+ throw new CareCompassClientError("CareCompass runtime authorization could not be obtained.", CARECOMPASS_TELEMETRY_ERROR_CODES.AUTHENTICATION_FAILED, "authentication");
127
+ }
128
+ if (typeof token !== "string" || !token.trim()) {
129
+ throw new CareCompassClientError("CareCompass runtime authorization could not be obtained.", CARECOMPASS_TELEMETRY_ERROR_CODES.AUTHENTICATION_FAILED, "authentication");
130
+ }
131
+ return { ...headers, "x-carecompass-runtime-token": token.trim() };
132
+ }
108
133
  telemetry.capture(CARECOMPASS_TELEMETRY_EVENTS.SDK_INITIALIZED);
109
134
  telemetry.capture(CARECOMPASS_TELEMETRY_EVENTS.THEME_LOADED);
110
135
  telemetry.capture(CARECOMPASS_TELEMETRY_EVENTS.PROMPT_CONFIGURATION_LOADED);
@@ -137,7 +162,7 @@ export function createCareCompassClient(inputConfig, options = {}) {
137
162
  try {
138
163
  const response = await send(joinUrl(config.apiBaseUrl, "/api/carecompass/embed/config/validate"), {
139
164
  method: "POST",
140
- headers,
165
+ headers: await requestHeaders(),
141
166
  body: JSON.stringify({ config }),
142
167
  });
143
168
  const result = await parseJson(response);
@@ -155,18 +180,27 @@ export function createCareCompassClient(inputConfig, options = {}) {
155
180
  try {
156
181
  const response = await send(joinUrl(config.apiBaseUrl, "/api/carecompass/embed/ask"), {
157
182
  method: "POST",
158
- headers,
183
+ headers: await requestHeaders({ workflow: request.workflow }),
159
184
  body: JSON.stringify({
160
185
  prompt: request.prompt,
186
+ requestId: request.requestId,
187
+ workflow: request.workflow,
161
188
  sessionId: request.sessionId,
189
+ sdkVersion: CARECOMPASS_SDK_VERSION,
190
+ applicationSurface: config.deploymentTarget,
162
191
  userContext: request.userContext,
163
192
  promptConfig: config.prompt,
193
+ // Public routing preferences; the hosted runtime validates model
194
+ // availability and may ignore disabled feature flags.
195
+ model: config.model,
196
+ featureFlags: config.featureFlags,
164
197
  }),
165
198
  });
166
199
  const result = await parseJson(response);
167
200
  // Status polling is asynchronous, so retain the submit timestamp until
168
201
  // the final job state lets telemetry report end-to-end latency.
169
202
  jobStartedAt.set(result.jobId, startedAt);
203
+ jobWorkflows.set(result.jobId, request.workflow);
170
204
  return result;
171
205
  }
172
206
  catch (error) {
@@ -177,16 +211,23 @@ export function createCareCompassClient(inputConfig, options = {}) {
177
211
  status: async (jobId) => {
178
212
  const startedAt = jobStartedAt.get(jobId) ?? now();
179
213
  try {
180
- const response = await send(joinUrl(config.apiBaseUrl, `/api/carecompass/embed/status/${encodeURIComponent(jobId)}`), { headers });
214
+ const response = await send(joinUrl(config.apiBaseUrl, `/api/carecompass/embed/status/${encodeURIComponent(jobId)}`), {
215
+ headers: await requestHeaders({
216
+ jobId,
217
+ workflow: jobWorkflows.get(jobId),
218
+ }),
219
+ });
181
220
  const result = await parseJson(response);
182
221
  if (result.status === "complete") {
183
222
  jobStartedAt.delete(jobId);
223
+ jobWorkflows.delete(jobId);
184
224
  telemetry.capture(CARECOMPASS_TELEMETRY_EVENTS.INFERENCE_SUCCEEDED, {
185
225
  durationMs: now() - startedAt,
186
226
  });
187
227
  }
188
228
  else if (result.status === "failed") {
189
229
  jobStartedAt.delete(jobId);
230
+ jobWorkflows.delete(jobId);
190
231
  telemetry.capture(CARECOMPASS_TELEMETRY_EVENTS.INFERENCE_FAILED, {
191
232
  durationMs: now() - startedAt,
192
233
  errorCode: CARECOMPASS_TELEMETRY_ERROR_CODES.INFERENCE_FAILED,
@@ -197,6 +238,7 @@ export function createCareCompassClient(inputConfig, options = {}) {
197
238
  }
198
239
  catch (error) {
199
240
  jobStartedAt.delete(jobId);
241
+ jobWorkflows.delete(jobId);
200
242
  captureInferenceFailure(telemetry, error, now() - startedAt);
201
243
  throw error;
202
244
  }
@@ -0,0 +1,69 @@
1
+ import type { CareCompassComplianceConfig } from "./schema.js";
2
+ /** The identifier categories detected by the SDK's local PHI preflight. */
3
+ export type CareCompassPhiCategory = "date_of_birth" | "email" | "medical_record_number" | "member_id" | "phone" | "ssn";
4
+ export type CareCompassPhiMatch = {
5
+ category: CareCompassPhiCategory;
6
+ start: number;
7
+ end: number;
8
+ };
9
+ export type CareCompassPhiSource = "message" | "response" | "context";
10
+ export type CareCompassPhiDetectionContext = {
11
+ source: CareCompassPhiSource;
12
+ };
13
+ export type CareCompassPhiDetector = (value: string, context: CareCompassPhiDetectionContext) => CareCompassPhiMatch[];
14
+ export type CareCompassPhiRedactor = (value: string, matches: CareCompassPhiMatch[], replacement: string) => string;
15
+ export type CareCompassPhiHooks = {
16
+ /** Replaces the built-in detector. The hook receives raw content; never emit it. */
17
+ detect?: CareCompassPhiDetector;
18
+ /** Replaces the built-in redactor. The hook receives raw content; never emit it. */
19
+ redact?: CareCompassPhiRedactor;
20
+ };
21
+ export type CareCompassComplianceRuntimeOptions = {
22
+ phi?: CareCompassPhiHooks;
23
+ };
24
+ export type CareCompassCompliancePreset = "standard" | "healthcare" | "strict";
25
+ export type CareCompassPhiAction = "allow" | "redact" | "block";
26
+ export type CareCompassCompliancePolicy = {
27
+ auditEnabled: boolean;
28
+ phiAction: CareCompassPhiAction;
29
+ preset: CareCompassCompliancePreset;
30
+ replacement: string;
31
+ };
32
+ export declare const CARECOMPASS_COMPLIANCE_PRESETS: Readonly<Record<CareCompassCompliancePreset, Omit<CareCompassCompliancePolicy, "preset">>>;
33
+ export type CareCompassAuditEventType = "message" | "tool_call" | "widget_action" | "error" | "safety_decision";
34
+ export type CareCompassAuditOutcome = "submitted" | "completed" | "failed" | "blocked" | "redacted" | "escalated" | "recorded";
35
+ export type CareCompassAuditSource = CareCompassPhiSource | "tool_call" | "widget_action";
36
+ export type CareCompassAuditEvent = {
37
+ id: string;
38
+ occurredAt: number;
39
+ outcome: CareCompassAuditOutcome;
40
+ phi: {
41
+ categories: CareCompassPhiCategory[];
42
+ count: number;
43
+ };
44
+ source?: CareCompassAuditSource;
45
+ type: CareCompassAuditEventType;
46
+ };
47
+ export type CareCompassSafetyDecision = "blocked" | "escalated" | "redacted" | "policy_sensitive";
48
+ export type CareCompassSafetyEvent = {
49
+ decision: CareCompassSafetyDecision;
50
+ occurredAt: number;
51
+ phi: {
52
+ categories: CareCompassPhiCategory[];
53
+ count: number;
54
+ };
55
+ source: CareCompassPhiSource | "tool_call" | "widget_action";
56
+ };
57
+ export type CareCompassAuditListener = (event: CareCompassAuditEvent) => void;
58
+ export type CareCompassSafetyListener = (event: CareCompassSafetyEvent) => void;
59
+ export declare const detectCareCompassPhi: CareCompassPhiDetector;
60
+ export declare const redactCareCompassPhi: CareCompassPhiRedactor;
61
+ export declare const resolveCareCompassCompliancePolicy: (config: CareCompassComplianceConfig | undefined) => CareCompassCompliancePolicy;
62
+ export declare const phiSummary: (matches: CareCompassPhiMatch[]) => {
63
+ categories: CareCompassPhiCategory[];
64
+ count: number;
65
+ };
66
+ export declare const sanitizeCareCompassValue: (value: unknown, source: CareCompassPhiSource, policy: CareCompassCompliancePolicy, hooks: CareCompassPhiHooks | undefined) => {
67
+ matches: CareCompassPhiMatch[];
68
+ value: unknown;
69
+ };