@nexalink/carecompass-sdk 0.3.0-beta.15 → 0.5.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.
@@ -0,0 +1,121 @@
1
+ export const CARECOMPASS_COMPLIANCE_PRESETS = {
2
+ // Standard is intentionally non-mutating for existing integrations. Detection
3
+ // can still drive a safety callback when the host opts into one.
4
+ standard: {
5
+ auditEnabled: false,
6
+ phiAction: "allow",
7
+ replacement: "[REDACTED]",
8
+ },
9
+ // Healthcare protects browser-visible requests and retains metadata-only audit
10
+ // records. It is the recommended starting point for PHI-oriented deployments.
11
+ healthcare: {
12
+ auditEnabled: true,
13
+ phiAction: "redact",
14
+ replacement: "[REDACTED]",
15
+ },
16
+ // Strict is appropriate when the host must stop detectable PHI before it leaves
17
+ // the browser. It may reject legitimate identifier-bearing workflow requests.
18
+ strict: {
19
+ auditEnabled: true,
20
+ phiAction: "block",
21
+ replacement: "[REDACTED]",
22
+ },
23
+ };
24
+ const PHI_PATTERNS = [
25
+ { category: "email", pattern: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi },
26
+ { category: "ssn", pattern: /\b\d{3}-\d{2}-\d{4}\b/g },
27
+ {
28
+ category: "phone",
29
+ pattern: /(?:\+1[ .-]?)?(?:\(?\d{3}\)?[ .-]?)\d{3}[ .-]\d{4}\b/g,
30
+ },
31
+ {
32
+ category: "date_of_birth",
33
+ pattern: /\b(?:dob|date of birth|birth date)\s*[:#-]?\s*(?:\d{1,2}[/-]\d{1,2}[/-]\d{2,4}|\d{4}[/-]\d{1,2}[/-]\d{1,2})\b/gi,
34
+ },
35
+ {
36
+ category: "medical_record_number",
37
+ pattern: /\b(?:mrn|medical record(?: number)?)\s*[:#-]?\s*[A-Z0-9-]{3,}\b/gi,
38
+ },
39
+ {
40
+ category: "member_id",
41
+ pattern: /\b(?:member|patient|policy|subscriber)(?:\s+(?:id|number))?\s*[:#-]?\s*[A-Z0-9-]{3,}\b/gi,
42
+ },
43
+ ];
44
+ const PHI_CATEGORIES = new Set([
45
+ "date_of_birth",
46
+ "email",
47
+ "medical_record_number",
48
+ "member_id",
49
+ "phone",
50
+ "ssn",
51
+ ]);
52
+ const validMatches = (value, matches) => matches
53
+ .filter((match) => PHI_CATEGORIES.has(match.category) &&
54
+ Number.isInteger(match.start) &&
55
+ Number.isInteger(match.end) &&
56
+ match.start >= 0 &&
57
+ match.end > match.start &&
58
+ match.end <= value.length)
59
+ .sort((a, b) => a.start - b.start || b.end - a.end)
60
+ .filter((match, index, sorted) => index === 0 || match.start >= sorted[index - 1].end);
61
+ export const detectCareCompassPhi = (value) => {
62
+ const matches = [];
63
+ for (const { category, pattern } of PHI_PATTERNS) {
64
+ pattern.lastIndex = 0;
65
+ for (const match of value.matchAll(pattern)) {
66
+ const start = match.index;
67
+ if (start === undefined)
68
+ continue;
69
+ matches.push({ category, start, end: start + match[0].length });
70
+ }
71
+ }
72
+ return validMatches(value, matches);
73
+ };
74
+ export const redactCareCompassPhi = (value, matches, replacement) => {
75
+ let redacted = value;
76
+ for (const match of [...matches].sort((a, b) => b.start - a.start)) {
77
+ redacted = `${redacted.slice(0, match.start)}${replacement}${redacted.slice(match.end)}`;
78
+ }
79
+ return redacted;
80
+ };
81
+ export const resolveCareCompassCompliancePolicy = (config) => {
82
+ const preset = config?.preset ?? "standard";
83
+ const defaults = CARECOMPASS_COMPLIANCE_PRESETS[preset];
84
+ return {
85
+ preset,
86
+ auditEnabled: config?.audit?.enabled ?? defaults.auditEnabled,
87
+ phiAction: config?.phi?.action ?? defaults.phiAction,
88
+ replacement: config?.phi?.replacement ?? defaults.replacement,
89
+ };
90
+ };
91
+ export const phiSummary = (matches) => ({
92
+ categories: [...new Set(matches.map((match) => match.category))].sort(),
93
+ count: matches.length,
94
+ });
95
+ export const sanitizeCareCompassValue = (value, source, policy, hooks) => {
96
+ if (typeof value === "string") {
97
+ const matches = validMatches(value, (hooks?.detect ?? detectCareCompassPhi)(value, { source }));
98
+ if (policy.phiAction !== "redact" || matches.length === 0) {
99
+ return { matches, value };
100
+ }
101
+ return {
102
+ matches,
103
+ value: (hooks?.redact ?? redactCareCompassPhi)(value, matches, policy.replacement),
104
+ };
105
+ }
106
+ if (Array.isArray(value)) {
107
+ const entries = value.map((entry) => sanitizeCareCompassValue(entry, source, policy, hooks));
108
+ return {
109
+ matches: entries.flatMap((entry) => entry.matches),
110
+ value: entries.map((entry) => entry.value),
111
+ };
112
+ }
113
+ if (value && typeof value === "object") {
114
+ const entries = Object.entries(value).map(([key, entry]) => [key, sanitizeCareCompassValue(entry, source, policy, hooks)]);
115
+ return {
116
+ matches: entries.flatMap(([, entry]) => entry.matches),
117
+ value: Object.fromEntries(entries.map(([key, entry]) => [key, entry.value])),
118
+ };
119
+ }
120
+ return { matches: [], value };
121
+ };
@@ -1,5 +1,35 @@
1
+ import React from "react";
2
+ import { type CareCompassContext, type CareCompassCore, type CareCompassCoreEvent, type CareCompassCoreOptions, type CareCompassCoreSnapshot, type CareCompassMessage, type CareCompassSendMessageOptions } from "./core.js";
3
+ import type { CareCompassRuntimeTokenProvider } from "./client.js";
1
4
  import type { CareCompassConfig } from "./schema.js";
2
- export declare function CareCompassEmbed({ config, pollIntervalMs, }: {
5
+ import type { CareCompassAuditListener, CareCompassSafetyListener } from "./compliance.js";
6
+ export type CareCompassChatProps = {
3
7
  config: CareCompassConfig;
8
+ initialContext?: CareCompassContext;
9
+ onAuditEvent?: CareCompassAuditListener;
10
+ onEvent?: (event: CareCompassCoreEvent) => void;
11
+ onSafetyEvent?: CareCompassSafetyListener;
4
12
  pollIntervalMs?: number;
5
- }): import("react/jsx-runtime").JSX.Element;
13
+ renderMessage?: (message: CareCompassMessage) => React.ReactNode;
14
+ retryLabel?: string;
15
+ runtimeTokenProvider?: CareCompassRuntimeTokenProvider;
16
+ };
17
+ /** Options for the headless React hook. Keep object-valued options stable with
18
+ * `useMemo` when the calling component rerenders. */
19
+ export type UseCareCompassOptions = CareCompassCoreOptions;
20
+ export type CareCompassReactController = {
21
+ core: CareCompassCore;
22
+ snapshot: CareCompassCoreSnapshot;
23
+ sendMessage: (prompt: string, options?: CareCompassSendMessageOptions) => Promise<CareCompassCoreSnapshot>;
24
+ streamMessage: CareCompassCore["streamMessage"];
25
+ retryLast: CareCompassCore["retryLast"];
26
+ reset: CareCompassCore["reset"];
27
+ setContext: CareCompassCore["setContext"];
28
+ };
29
+ /**
30
+ * React adapter for the headless CareCompass core. It owns the core lifecycle
31
+ * and subscribes React to its snapshots, leaving hosts free to render any UI.
32
+ */
33
+ export declare function useCareCompass(config: CareCompassConfig, options?: UseCareCompassOptions): CareCompassReactController;
34
+ export declare function CareCompassChat({ config, initialContext, onAuditEvent, onEvent, onSafetyEvent, pollIntervalMs, renderMessage, retryLabel, runtimeTokenProvider, }: CareCompassChatProps): React.JSX.Element;
35
+ export declare const CareCompassEmbed: typeof CareCompassChat;
package/dist/component.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from "react";
3
- import { createCareCompassClient } from "./client.js";
3
+ import { createCareCompassCore, } from "./core.js";
4
+ import { CareCompassMarkdown } from "./markdown.js";
4
5
  import { CARECOMPASS_TELEMETRY_ERROR_CODES, CARECOMPASS_TELEMETRY_EVENTS, createCareCompassTelemetry, } from "./telemetry.js";
5
6
  // The embed should fail closed inside the host page: show the configured
6
7
  // fallback text, capture sanitized telemetry, and avoid crashing the integrator.
@@ -25,71 +26,115 @@ class CareCompassErrorBoundary extends React.Component {
25
26
  return this.props.children;
26
27
  }
27
28
  }
28
- function CareCompassEmbedContent({ config, telemetry, pollIntervalMs = 1500, }) {
29
- const client = React.useMemo(() => createCareCompassClient(config), [config]);
30
- const [messages, setMessages] = React.useState([
31
- {
32
- id: "welcome",
33
- role: "assistant",
34
- text: config.prompt.welcomeMessage,
35
- },
29
+ /**
30
+ * React adapter for the headless CareCompass core. It owns the core lifecycle
31
+ * and subscribes React to its snapshots, leaving hosts free to render any UI.
32
+ */
33
+ export function useCareCompass(config, options = {}) {
34
+ const { compliance, fetcher, initialContext, now, onAuditEvent, onSafetyEvent, pollIntervalMs, runtimeTokenProvider, timeoutMs, } = options;
35
+ const core = React.useMemo(() => createCareCompassCore(config, {
36
+ compliance,
37
+ fetcher,
38
+ initialContext,
39
+ now,
40
+ onAuditEvent,
41
+ onSafetyEvent,
42
+ pollIntervalMs,
43
+ runtimeTokenProvider,
44
+ timeoutMs,
45
+ }), [
46
+ compliance,
47
+ config,
48
+ fetcher,
49
+ initialContext,
50
+ now,
51
+ onAuditEvent,
52
+ onSafetyEvent,
53
+ pollIntervalMs,
54
+ runtimeTokenProvider,
55
+ timeoutMs,
36
56
  ]);
57
+ const [snapshot, setSnapshot] = React.useState(() => core.getSnapshot());
58
+ React.useEffect(() => {
59
+ const unsubscribe = core.subscribe(setSnapshot);
60
+ setSnapshot(core.getSnapshot());
61
+ return () => {
62
+ unsubscribe();
63
+ core.dispose();
64
+ };
65
+ }, [core]);
66
+ return React.useMemo(() => ({
67
+ core,
68
+ snapshot,
69
+ sendMessage: core.sendMessage,
70
+ streamMessage: core.streamMessage,
71
+ retryLast: core.retryLast,
72
+ reset: core.reset,
73
+ setContext: core.setContext,
74
+ }), [core, snapshot]);
75
+ }
76
+ function CareCompassChatContent({ config, initialContext, onAuditEvent, onEvent, onSafetyEvent, telemetry, pollIntervalMs = 1500, renderMessage, retryLabel = "Retry", runtimeTokenProvider, }) {
77
+ const core = React.useMemo(() => createCareCompassCore(config, {
78
+ initialContext,
79
+ onAuditEvent,
80
+ onSafetyEvent,
81
+ pollIntervalMs,
82
+ runtimeTokenProvider,
83
+ }), [
84
+ config,
85
+ initialContext,
86
+ onAuditEvent,
87
+ onSafetyEvent,
88
+ pollIntervalMs,
89
+ runtimeTokenProvider,
90
+ ]);
91
+ const [snapshot, setSnapshot] = React.useState(() => core.getSnapshot());
37
92
  const [input, setInput] = React.useState("");
38
- const [loading, setLoading] = React.useState(false);
39
- const [error, setError] = React.useState(null);
40
93
  React.useEffect(() => {
41
94
  telemetry.capture(CARECOMPASS_TELEMETRY_EVENTS.COMPONENT_RENDERED);
42
95
  telemetry.capture(CARECOMPASS_TELEMETRY_EVENTS.COMPONENT_OPENED);
96
+ const unsubscribe = core.subscribe(setSnapshot);
97
+ setSnapshot(core.getSnapshot());
43
98
  return () => {
99
+ unsubscribe();
100
+ core.dispose();
44
101
  telemetry.capture(CARECOMPASS_TELEMETRY_EVENTS.COMPONENT_CLOSED);
45
102
  };
46
- }, [telemetry]);
103
+ }, [core, telemetry]);
47
104
  async function sendMessage(event) {
48
105
  event.preventDefault();
49
106
  const prompt = input.trim();
50
- if (!prompt || loading)
107
+ if (!prompt || snapshot.loading)
51
108
  return;
52
109
  setInput("");
53
- setError(null);
54
- setLoading(true);
55
- setMessages((current) => [
56
- ...current,
57
- { id: `user-${Date.now()}`, role: "user", text: prompt },
58
- ]);
59
110
  try {
60
- const { jobId } = await client.ask({ prompt });
61
- const startedAt = Date.now();
62
- // The backend returns a job immediately, so the component polls until it
63
- // sees a terminal state or reaches the same timeout tracked by telemetry.
64
- while (Date.now() - startedAt < 120_000) {
65
- const status = await client.status(jobId);
66
- if (status.status === "complete" && status.result) {
67
- setMessages((current) => [
68
- ...current,
69
- {
70
- id: `assistant-${Date.now()}`,
71
- role: "assistant",
72
- text: status.result ?? "",
73
- },
74
- ]);
75
- return;
76
- }
77
- if (status.status === "failed") {
78
- throw new Error(status.result ?? config.labels.errorMessage);
79
- }
80
- await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
111
+ core.recordWidgetAction();
112
+ for await (const coreEvent of core.streamMessage(prompt)) {
113
+ onEvent?.(coreEvent);
81
114
  }
82
- client.recordInferenceTimeout(jobId, Date.now() - startedAt);
83
- throw new Error("CareCompass request timed out.");
84
115
  }
85
- catch (err) {
86
- setError(err?.message ??
87
- config.labels.errorMessage);
116
+ catch {
117
+ // The core snapshot already carries the user-visible error and retry
118
+ // state. Swallow here so host pages do not see unhandled form errors.
88
119
  }
89
- finally {
90
- setLoading(false);
120
+ }
121
+ async function retryMessage() {
122
+ try {
123
+ core.recordWidgetAction();
124
+ await core.retryLast();
125
+ }
126
+ catch {
127
+ // The core owns the visible retry failure state.
91
128
  }
92
129
  }
130
+ const messageContent = (message) => {
131
+ if (renderMessage)
132
+ return renderMessage(message);
133
+ if (message.role === "assistant") {
134
+ return _jsx(CareCompassMarkdown, { text: message.text });
135
+ }
136
+ return message.text;
137
+ };
93
138
  return (_jsxs("section", { "aria-label": config.labels.title, style: {
94
139
  "--carecompass-primary": config.theme.primaryColor,
95
140
  "--carecompass-bg": config.theme.backgroundColor,
@@ -118,7 +163,7 @@ function CareCompassEmbedContent({ config, telemetry, pollIntervalMs = 1500, })
118
163
  gap: 12,
119
164
  overflowY: "auto",
120
165
  padding: 16,
121
- }, children: [messages.map((message) => (_jsx("div", { style: {
166
+ }, children: [snapshot.messages.map((message) => (_jsx("div", { style: {
122
167
  alignSelf: message.role === "user" ? "flex-end" : "flex-start",
123
168
  background: message.role === "user"
124
169
  ? "var(--carecompass-primary)"
@@ -127,14 +172,14 @@ function CareCompassEmbedContent({ config, telemetry, pollIntervalMs = 1500, })
127
172
  color: message.role === "user" ? "#ffffff" : "inherit",
128
173
  maxInlineSize: "82%",
129
174
  padding: "10px 12px",
130
- whiteSpace: "pre-wrap",
131
- }, children: message.text }, message.id))), loading ? (_jsx("div", { style: { fontSize: 13, opacity: 0.72 }, children: "Thinking..." })) : null] }), _jsxs("form", { onSubmit: sendMessage, style: {
175
+ whiteSpace: message.role === "user" ? "pre-wrap" : "normal",
176
+ }, children: messageContent(message) }, message.id))), snapshot.loading ? (_jsx("div", { style: { fontSize: 13, opacity: 0.72 }, children: "Thinking..." })) : null] }), _jsxs("form", { onSubmit: sendMessage, style: {
132
177
  borderTop: "1px solid color-mix(in srgb, var(--carecompass-text) 12%, transparent)",
133
178
  display: "flex",
134
179
  flexDirection: "column",
135
180
  gap: 8,
136
181
  padding: 12,
137
- }, children: [_jsxs("div", { style: { display: "flex", gap: 8 }, children: [_jsx("input", { "aria-label": config.labels.placeholder, disabled: loading, onChange: (event) => setInput(event.currentTarget.value), placeholder: config.labels.placeholder, style: {
182
+ }, children: [_jsxs("div", { style: { display: "flex", gap: 8 }, children: [_jsx("input", { "aria-label": config.labels.placeholder, disabled: snapshot.loading, onChange: (event) => setInput(event.currentTarget.value), placeholder: config.labels.placeholder, style: {
138
183
  border: "1px solid color-mix(in srgb, var(--carecompass-text) 16%, transparent)",
139
184
  borderRadius: 8,
140
185
  color: "inherit",
@@ -142,20 +187,36 @@ function CareCompassEmbedContent({ config, telemetry, pollIntervalMs = 1500, })
142
187
  font: "inherit",
143
188
  minInlineSize: 0,
144
189
  padding: "10px 12px",
145
- }, value: input }), _jsx("button", { disabled: loading || !input.trim(), style: {
190
+ }, value: input }), _jsx("button", { disabled: snapshot.loading || !input.trim(), style: {
146
191
  background: "var(--carecompass-primary)",
147
192
  border: 0,
148
193
  borderRadius: 8,
149
194
  color: "#ffffff",
150
- cursor: loading ? "not-allowed" : "pointer",
195
+ cursor: snapshot.loading ? "not-allowed" : "pointer",
151
196
  font: "inherit",
152
197
  fontWeight: 700,
153
198
  padding: "0 14px",
154
- }, type: "submit", children: config.labels.sendButton })] }), error ? (_jsx("div", { role: "alert", style: { color: "#b91c1c", fontSize: 12 }, children: error })) : null, _jsx("div", { style: { fontSize: 11, opacity: 0.7 }, children: config.labels.disclaimer })] })] }));
199
+ }, type: "submit", children: config.labels.sendButton })] }), snapshot.error ? (_jsxs("div", { role: "alert", style: {
200
+ alignItems: "center",
201
+ color: "#b91c1c",
202
+ display: "flex",
203
+ flexWrap: "wrap",
204
+ fontSize: 12,
205
+ gap: 8,
206
+ }, children: [_jsx("span", { children: snapshot.error.message }), snapshot.canRetry ? (_jsx("button", { onClick: retryMessage, style: {
207
+ background: "transparent",
208
+ border: "1px solid color-mix(in srgb, #b91c1c 40%, transparent)",
209
+ borderRadius: 6,
210
+ color: "#b91c1c",
211
+ cursor: "pointer",
212
+ font: "inherit",
213
+ padding: "4px 8px",
214
+ }, type: "button", children: retryLabel })) : null] })) : null, _jsx("div", { style: { fontSize: 11, opacity: 0.7 }, children: config.labels.disclaimer })] })] }));
155
215
  }
156
- export function CareCompassEmbed({ config, pollIntervalMs = 1500, }) {
216
+ export function CareCompassChat({ config, initialContext, onAuditEvent, onEvent, onSafetyEvent, pollIntervalMs = 1500, renderMessage, retryLabel, runtimeTokenProvider, }) {
157
217
  // Telemetry is scoped to the validated public config; no per-message content
158
218
  // is passed through this component-level telemetry object.
159
219
  const telemetry = React.useMemo(() => createCareCompassTelemetry(config), [config]);
160
- return (_jsx(CareCompassErrorBoundary, { config: config, telemetry: telemetry, children: _jsx(CareCompassEmbedContent, { config: config, pollIntervalMs: pollIntervalMs, telemetry: telemetry }) }));
220
+ return (_jsx(CareCompassErrorBoundary, { config: config, telemetry: telemetry, children: _jsx(CareCompassChatContent, { config: config, initialContext: initialContext, onAuditEvent: onAuditEvent, onEvent: onEvent, onSafetyEvent: onSafetyEvent, pollIntervalMs: pollIntervalMs, renderMessage: renderMessage, retryLabel: retryLabel, runtimeTokenProvider: runtimeTokenProvider, telemetry: telemetry }) }));
161
221
  }
222
+ export const CareCompassEmbed = CareCompassChat;
package/dist/core.d.ts ADDED
@@ -0,0 +1,95 @@
1
+ import { type CareCompassRuntimeTokenProvider, type CareCompassStatusResponse, type CareCompassWorkflowId } from "./client.js";
2
+ import { type CareCompassAuditEvent, type CareCompassAuditListener, type CareCompassComplianceRuntimeOptions, type CareCompassSafetyDecision, type CareCompassSafetyListener } from "./compliance.js";
3
+ import type { CareCompassConfig } from "./schema.js";
4
+ type Fetcher = typeof fetch;
5
+ export type CareCompassContext = Record<string, unknown>;
6
+ export type CareCompassMessage = {
7
+ id: string;
8
+ role: "user" | "assistant";
9
+ text: string;
10
+ createdAt: number;
11
+ status: "complete" | "failed" | "pending";
12
+ retrieval?: CareCompassStatusResponse["retrieval"];
13
+ };
14
+ export type CareCompassLifecyclePhase = "idle" | "submitting" | "streaming" | "complete" | "error" | "disposed";
15
+ export type CareCompassCoreErrorCode = "request_failed" | "safety_blocked" | "timeout" | "disposed";
16
+ export type CareCompassCoreError = {
17
+ code: CareCompassCoreErrorCode;
18
+ message: string;
19
+ };
20
+ export type CareCompassRetryMetadata = {
21
+ prompt: string;
22
+ requestId?: string;
23
+ workflow?: CareCompassWorkflowId;
24
+ context: CareCompassContext;
25
+ attempts: number;
26
+ };
27
+ export type CareCompassCoreSnapshot = {
28
+ messages: CareCompassMessage[];
29
+ phase: CareCompassLifecyclePhase;
30
+ loading: boolean;
31
+ error: CareCompassCoreError | null;
32
+ context: CareCompassContext;
33
+ canRetry: boolean;
34
+ retry: CareCompassRetryMetadata | null;
35
+ activeJobId: string | null;
36
+ };
37
+ export type CareCompassCoreEvent = {
38
+ type: "message_submitted";
39
+ message: CareCompassMessage;
40
+ snapshot: CareCompassCoreSnapshot;
41
+ } | {
42
+ type: "status";
43
+ jobId: string;
44
+ status: CareCompassStatusResponse["status"];
45
+ snapshot: CareCompassCoreSnapshot;
46
+ } | {
47
+ type: "message_completed";
48
+ message: CareCompassMessage;
49
+ snapshot: CareCompassCoreSnapshot;
50
+ } | {
51
+ type: "error";
52
+ error: CareCompassCoreError;
53
+ snapshot: CareCompassCoreSnapshot;
54
+ } | {
55
+ type: "context_updated";
56
+ snapshot: CareCompassCoreSnapshot;
57
+ } | {
58
+ type: "reset";
59
+ snapshot: CareCompassCoreSnapshot;
60
+ };
61
+ export type CareCompassCoreOptions = {
62
+ compliance?: CareCompassComplianceRuntimeOptions;
63
+ fetcher?: Fetcher;
64
+ initialContext?: CareCompassContext;
65
+ now?: () => number;
66
+ onAuditEvent?: CareCompassAuditListener;
67
+ onSafetyEvent?: CareCompassSafetyListener;
68
+ pollIntervalMs?: number;
69
+ runtimeTokenProvider?: CareCompassRuntimeTokenProvider;
70
+ timeoutMs?: number;
71
+ };
72
+ export type CareCompassSendMessageOptions = {
73
+ /** Reuse this value only when retrying the same hosted submission. */
74
+ requestId?: string;
75
+ workflow?: CareCompassWorkflowId;
76
+ context?: CareCompassContext;
77
+ };
78
+ export type CareCompassCore = {
79
+ exportAuditTrail: () => CareCompassAuditEvent[];
80
+ getSnapshot: () => CareCompassCoreSnapshot;
81
+ recordSafetyDecision: (decision: Exclude<CareCompassSafetyDecision, "redacted" | "blocked">, source?: "tool_call" | "widget_action") => void;
82
+ recordToolCall: (outcome?: "completed" | "failed") => void;
83
+ recordWidgetAction: (outcome?: "recorded" | "completed") => void;
84
+ subscribe: (listener: (snapshot: CareCompassCoreSnapshot) => void) => () => void;
85
+ subscribeAudit: (listener: CareCompassAuditListener) => () => void;
86
+ subscribeSafety: (listener: CareCompassSafetyListener) => () => void;
87
+ setContext: (context: CareCompassContext | ((current: CareCompassContext) => CareCompassContext)) => void;
88
+ sendMessage: (prompt: string, options?: CareCompassSendMessageOptions) => Promise<CareCompassCoreSnapshot>;
89
+ streamMessage: (prompt: string, options?: CareCompassSendMessageOptions) => AsyncIterable<CareCompassCoreEvent>;
90
+ retryLast: () => Promise<CareCompassCoreSnapshot>;
91
+ reset: () => void;
92
+ dispose: () => void;
93
+ };
94
+ export declare function createCareCompassCore(config: CareCompassConfig, options?: CareCompassCoreOptions): CareCompassCore;
95
+ export {};