@statewavedev/sdk 0.9.0 → 0.10.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 +65 -1
- package/dist/client.d.ts +30 -1
- package/dist/client.js +72 -0
- package/dist/types.d.ts +136 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,12 @@ Official TypeScript SDK for [Statewave](https://github.com/smaramwbc/statewave)
|
|
|
12
12
|
|
|
13
13
|
> ⚠️ **v0.9.0 is a breaking change.** The entire SDK surface — request params *and* response fields — is now idiomatic **camelCase** (`subjectId`, `maxTokens`, `createdAt`, `receiptId`, …). The wire protocol is unchanged; the client maps to/from the server's snake_case transparently. `payload`, `metadata`, and `provenance` are passed through verbatim — their inner keys are never rewritten. See [CHANGELOG](CHANGELOG.md#090) for the full rename table and migration steps.
|
|
14
14
|
|
|
15
|
+
> **New to Statewave?** This SDK is a thin client for a running **Statewave
|
|
16
|
+
> server**. If you don't have one yet, the
|
|
17
|
+
> [Getting Started guide](https://github.com/smaramwbc/statewave-docs/blob/main/getting-started.md)
|
|
18
|
+
> brings one up with Docker Compose in about 5 minutes. Every example below
|
|
19
|
+
> assumes a server reachable at `http://localhost:8100`.
|
|
20
|
+
|
|
15
21
|
## Install
|
|
16
22
|
|
|
17
23
|
```bash
|
|
@@ -145,6 +151,59 @@ console.log(updated.sensitivityLabels); // → ["financial", "pii"]
|
|
|
145
151
|
|
|
146
152
|
Receipts and the policy engine cooperate: every assembly call records its policy decisions into `receipt.policy.filtersApplied` (one entry per memory the policy fired on) and `receipt.policy.filtersSkipped` (per-rule summary of what didn't fire). In `log_only` mode (the tenant default) the receipt is the full audit trail without filtering; under `enforce` denied memories are dropped before they reach the assembly and the deny is still recorded. See [`receipts.md`](https://github.com/smaramwbc/statewave-docs/blob/main/receipts.md) and [`sensitivity-labels.md`](https://github.com/smaramwbc/statewave-docs/blob/main/sensitivity-labels.md) for the full schemas and policy YAML format.
|
|
147
153
|
|
|
154
|
+
## Support-agent endpoints
|
|
155
|
+
|
|
156
|
+
Statewave's support wedge — customer health scoring, SLA tracking, resolution state, and structured escalation briefs — is exposed through ergonomic SDK methods (server v0.6+).
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { StatewaveClient } from "@statewavedev/sdk";
|
|
160
|
+
|
|
161
|
+
const sw = new StatewaveClient("http://localhost:8100");
|
|
162
|
+
|
|
163
|
+
// Customer health score (0–100) with the explainable factors behind it.
|
|
164
|
+
const health = await sw.getHealth("customer:globex");
|
|
165
|
+
console.log(`${health.score}/100 — ${health.state}`);
|
|
166
|
+
for (const f of health.factors) {
|
|
167
|
+
console.log(` ${f.signal}: ${f.impact >= 0 ? "+" : ""}${f.impact} (${f.detail})`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// SLA metrics — first-response / resolution times and breach counts.
|
|
171
|
+
// Thresholds are optional; they default server-side to 5 min / 24 h.
|
|
172
|
+
const sla = await sw.getSLA({
|
|
173
|
+
subjectId: "customer:globex",
|
|
174
|
+
firstResponseThresholdMinutes: 10,
|
|
175
|
+
resolutionThresholdHours: 48,
|
|
176
|
+
});
|
|
177
|
+
console.log(`${sla.resolvedSessions}/${sla.totalSessions} resolved, ${sla.resolutionBreachCount} SLA breaches`);
|
|
178
|
+
|
|
179
|
+
// Track resolution state for a session (upserts by subject + session).
|
|
180
|
+
await sw.createResolution({
|
|
181
|
+
subjectId: "customer:globex",
|
|
182
|
+
sessionId: "ticket-8842",
|
|
183
|
+
status: "resolved",
|
|
184
|
+
resolutionSummary: "Issued refund for the duplicate charge",
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// List resolutions, optionally filtered by status.
|
|
188
|
+
const openItems = await sw.listResolutions({
|
|
189
|
+
subjectId: "customer:globex",
|
|
190
|
+
status: "open",
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Generate a handoff context pack for escalation or shift change.
|
|
194
|
+
// `handoffNotes` is a pre-rendered markdown brief for human or LLM use.
|
|
195
|
+
const handoff = await sw.createHandoff({
|
|
196
|
+
subjectId: "customer:globex",
|
|
197
|
+
sessionId: "ticket-8842",
|
|
198
|
+
reason: "escalation",
|
|
199
|
+
callerId: "agent-7",
|
|
200
|
+
callerType: "support_agent",
|
|
201
|
+
});
|
|
202
|
+
console.log(handoff.handoffNotes);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`getHealth`, `getSLA`, `createResolution`, `listResolutions`, and `createHandoff` respect the same auth, tenant-scoping, and retry behaviour as the rest of the client. `createHandoff` shares `getContext`'s caller-identity gate — when the tenant config sets `require_caller_identity: true`, both `callerId` and `callerType` are mandatory.
|
|
206
|
+
|
|
148
207
|
## Error handling
|
|
149
208
|
|
|
150
209
|
```typescript
|
|
@@ -189,8 +248,13 @@ All response types are fully typed:
|
|
|
189
248
|
- `ListSubjectsResult` — paginated subject listing
|
|
190
249
|
- `Receipt` + `ReceiptSelectedEntry` + `ReceiptPolicy` + `ReceiptOutput` — state-assembly audit artifact (v0.8) and its nested shapes
|
|
191
250
|
- `ReceiptList` — cursor-paginated receipt listing
|
|
251
|
+
- `Health` + `HealthFactor` — customer health score and its explainable factors
|
|
252
|
+
- `SLASummary` + `SessionSLA` — SLA metrics, aggregate and per-session
|
|
253
|
+
- `Handoff` + `ResolutionSummaryItem` — handoff context pack and its prior-resolution items
|
|
254
|
+
- `Resolution` — resolution tracking record
|
|
255
|
+
- `HealthState` / `ResolutionStatus` — string-literal status unions
|
|
192
256
|
|
|
193
|
-
Param types: `CreateEpisodeParams`, `SearchMemoriesParams`, `GetContextParams`, `ListReceiptsParams`, `SetMemoryLabelsParams`
|
|
257
|
+
Param types: `CreateEpisodeParams`, `SearchMemoriesParams`, `GetContextParams`, `ListReceiptsParams`, `SetMemoryLabelsParams`, `GetSLAParams`, `CreateHandoffParams`, `CreateResolutionParams`, `ListResolutionsParams`
|
|
194
258
|
|
|
195
259
|
## Running tests
|
|
196
260
|
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BatchCreateResult, ClientOptions, CompileJob, CompileResult, ContextBundle, CreateEpisodeParams, DeleteResult, Episode, GetContextParams, ListReceiptsParams, ListSubjectsResult, Memory, Receipt, ReceiptList, SearchMemoriesParams, SearchResult, SetMemoryLabelsParams, Timeline } from "./types.js";
|
|
1
|
+
import type { BatchCreateResult, ClientOptions, CompileJob, CompileResult, ContextBundle, CreateEpisodeParams, CreateHandoffParams, CreateResolutionParams, DeleteResult, Episode, GetContextParams, GetSLAParams, Handoff, Health, ListReceiptsParams, ListResolutionsParams, ListSubjectsResult, Memory, Receipt, ReceiptList, Resolution, SLASummary, SearchMemoriesParams, SearchResult, SetMemoryLabelsParams, Timeline } from "./types.js";
|
|
2
2
|
/** Structured error from the Statewave API. */
|
|
3
3
|
export declare class StatewaveAPIError extends Error {
|
|
4
4
|
readonly statusCode: number;
|
|
@@ -47,6 +47,35 @@ export declare class StatewaveClient {
|
|
|
47
47
|
* to fetch the next page.
|
|
48
48
|
*/
|
|
49
49
|
listReceipts(params: ListReceiptsParams): Promise<ReceiptList>;
|
|
50
|
+
/**
|
|
51
|
+
* Compute the customer health score (0–100) for a subject, with the
|
|
52
|
+
* explainable factors that drove it. Backs proactive risk triage.
|
|
53
|
+
*/
|
|
54
|
+
getHealth(subjectId: string): Promise<Health>;
|
|
55
|
+
/**
|
|
56
|
+
* Compute SLA metrics for a subject — first-response and resolution
|
|
57
|
+
* times plus breach flags, aggregated across the subject's sessions.
|
|
58
|
+
* Both thresholds fall back to the server defaults (5 minutes /
|
|
59
|
+
* 24 hours) when omitted.
|
|
60
|
+
*/
|
|
61
|
+
getSLA(params: GetSLAParams): Promise<SLASummary>;
|
|
62
|
+
/**
|
|
63
|
+
* Generate a handoff context pack — a structured escalation brief for
|
|
64
|
+
* shift change or agent transfer. Same caller-identity gate as
|
|
65
|
+
* `getContext`: when the tenant sets `require_caller_identity: true`,
|
|
66
|
+
* both `callerId` and `callerType` are mandatory.
|
|
67
|
+
*/
|
|
68
|
+
createHandoff(params: CreateHandoffParams): Promise<Handoff>;
|
|
69
|
+
/**
|
|
70
|
+
* Create or update a resolution record for a support session.
|
|
71
|
+
* Upserts by `subjectId` + `sessionId`.
|
|
72
|
+
*/
|
|
73
|
+
createResolution(params: CreateResolutionParams): Promise<Resolution>;
|
|
74
|
+
/**
|
|
75
|
+
* List resolution records for a subject, optionally filtered to a
|
|
76
|
+
* single status.
|
|
77
|
+
*/
|
|
78
|
+
listResolutions(params: ListResolutionsParams): Promise<Resolution[]>;
|
|
50
79
|
getTimeline(subjectId: string): Promise<Timeline>;
|
|
51
80
|
deleteSubject(subjectId: string): Promise<DeleteResult>;
|
|
52
81
|
listSubjects(params?: {
|
package/dist/client.js
CHANGED
|
@@ -195,6 +195,78 @@ export class StatewaveClient {
|
|
|
195
195
|
qs.set("limit", String(params.limit));
|
|
196
196
|
return this.get(`/v1/receipts?${qs}`);
|
|
197
197
|
}
|
|
198
|
+
// -- Support: health, SLA, handoff, resolutions ----------------------
|
|
199
|
+
/**
|
|
200
|
+
* Compute the customer health score (0–100) for a subject, with the
|
|
201
|
+
* explainable factors that drove it. Backs proactive risk triage.
|
|
202
|
+
*/
|
|
203
|
+
async getHealth(subjectId) {
|
|
204
|
+
return this.get(`/v1/subjects/${encodeURIComponent(subjectId)}/health`);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Compute SLA metrics for a subject — first-response and resolution
|
|
208
|
+
* times plus breach flags, aggregated across the subject's sessions.
|
|
209
|
+
* Both thresholds fall back to the server defaults (5 minutes /
|
|
210
|
+
* 24 hours) when omitted.
|
|
211
|
+
*/
|
|
212
|
+
async getSLA(params) {
|
|
213
|
+
const qs = new URLSearchParams();
|
|
214
|
+
if (params.firstResponseThresholdMinutes !== undefined) {
|
|
215
|
+
qs.set("first_response_threshold_minutes", String(params.firstResponseThresholdMinutes));
|
|
216
|
+
}
|
|
217
|
+
if (params.resolutionThresholdHours !== undefined) {
|
|
218
|
+
qs.set("resolution_threshold_hours", String(params.resolutionThresholdHours));
|
|
219
|
+
}
|
|
220
|
+
const query = qs.toString();
|
|
221
|
+
return this.get(`/v1/subjects/${encodeURIComponent(params.subjectId)}/sla${query ? `?${query}` : ""}`);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Generate a handoff context pack — a structured escalation brief for
|
|
225
|
+
* shift change or agent transfer. Same caller-identity gate as
|
|
226
|
+
* `getContext`: when the tenant sets `require_caller_identity: true`,
|
|
227
|
+
* both `callerId` and `callerType` are mandatory.
|
|
228
|
+
*/
|
|
229
|
+
async createHandoff(params) {
|
|
230
|
+
return this.post("/v1/handoff", {
|
|
231
|
+
subjectId: params.subjectId,
|
|
232
|
+
sessionId: params.sessionId,
|
|
233
|
+
...(params.reason !== undefined && { reason: params.reason }),
|
|
234
|
+
...(params.maxTokens !== undefined && { maxTokens: params.maxTokens }),
|
|
235
|
+
...(params.emitReceipt !== undefined && { emitReceipt: params.emitReceipt }),
|
|
236
|
+
...(params.queryId !== undefined && { queryId: params.queryId }),
|
|
237
|
+
...(params.taskId !== undefined && { taskId: params.taskId }),
|
|
238
|
+
...(params.parentReceiptId !== undefined && {
|
|
239
|
+
parentReceiptId: params.parentReceiptId,
|
|
240
|
+
}),
|
|
241
|
+
...(params.callerId !== undefined && { callerId: params.callerId }),
|
|
242
|
+
...(params.callerType !== undefined && { callerType: params.callerType }),
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Create or update a resolution record for a support session.
|
|
247
|
+
* Upserts by `subjectId` + `sessionId`.
|
|
248
|
+
*/
|
|
249
|
+
async createResolution(params) {
|
|
250
|
+
return this.post("/v1/resolutions", {
|
|
251
|
+
subjectId: params.subjectId,
|
|
252
|
+
sessionId: params.sessionId,
|
|
253
|
+
...(params.status !== undefined && { status: params.status }),
|
|
254
|
+
...(params.resolutionSummary !== undefined && {
|
|
255
|
+
resolutionSummary: params.resolutionSummary,
|
|
256
|
+
}),
|
|
257
|
+
...(params.metadata !== undefined && { metadata: params.metadata }),
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* List resolution records for a subject, optionally filtered to a
|
|
262
|
+
* single status.
|
|
263
|
+
*/
|
|
264
|
+
async listResolutions(params) {
|
|
265
|
+
const qs = new URLSearchParams({ subject_id: params.subjectId });
|
|
266
|
+
if (params.status !== undefined)
|
|
267
|
+
qs.set("status", params.status);
|
|
268
|
+
return this.get(`/v1/resolutions?${qs}`);
|
|
269
|
+
}
|
|
198
270
|
async getTimeline(subjectId) {
|
|
199
271
|
return this.get(`/v1/timeline?subject_id=${encodeURIComponent(subjectId)}`);
|
|
200
272
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -166,6 +166,95 @@ export interface CompileJob {
|
|
|
166
166
|
memories?: Memory[];
|
|
167
167
|
error?: string;
|
|
168
168
|
}
|
|
169
|
+
/** Support health-state bucket. */
|
|
170
|
+
export type HealthState = "healthy" | "watch" | "at_risk";
|
|
171
|
+
/** Resolution lifecycle status. */
|
|
172
|
+
export type ResolutionStatus = "open" | "resolved" | "unresolved";
|
|
173
|
+
/** One explainable factor behind a customer health score. */
|
|
174
|
+
export interface HealthFactor {
|
|
175
|
+
/** Stable signal identifier, e.g. `sla_resolution_breaches`. */
|
|
176
|
+
signal: string;
|
|
177
|
+
/** Signed score contribution — a negative impact drags the score down. */
|
|
178
|
+
impact: number;
|
|
179
|
+
/** Human-readable explanation of the factor. */
|
|
180
|
+
detail: string;
|
|
181
|
+
}
|
|
182
|
+
/** Customer health score (0–100) with the factors that drove it. */
|
|
183
|
+
export interface Health {
|
|
184
|
+
subjectId: string;
|
|
185
|
+
score: number;
|
|
186
|
+
state: HealthState;
|
|
187
|
+
factors: HealthFactor[];
|
|
188
|
+
}
|
|
189
|
+
/** SLA metrics for a single support session. */
|
|
190
|
+
export interface SessionSLA {
|
|
191
|
+
sessionId: string;
|
|
192
|
+
/** `resolved` | `open`. */
|
|
193
|
+
status: string;
|
|
194
|
+
firstMessageAt: string | null;
|
|
195
|
+
firstResponseAt: string | null;
|
|
196
|
+
resolvedAt: string | null;
|
|
197
|
+
firstResponseSeconds: number | null;
|
|
198
|
+
resolutionSeconds: number | null;
|
|
199
|
+
openDurationSeconds: number | null;
|
|
200
|
+
firstResponseBreached: boolean;
|
|
201
|
+
resolutionBreached: boolean;
|
|
202
|
+
}
|
|
203
|
+
/** Aggregate SLA metrics for a subject across all of its sessions. */
|
|
204
|
+
export interface SLASummary {
|
|
205
|
+
subjectId: string;
|
|
206
|
+
totalSessions: number;
|
|
207
|
+
resolvedSessions: number;
|
|
208
|
+
openSessions: number;
|
|
209
|
+
avgFirstResponseSeconds: number | null;
|
|
210
|
+
avgResolutionSeconds: number | null;
|
|
211
|
+
firstResponseBreachCount: number;
|
|
212
|
+
resolutionBreachCount: number;
|
|
213
|
+
sessions: SessionSLA[];
|
|
214
|
+
}
|
|
215
|
+
/** A prior resolution surfaced inside a handoff brief. */
|
|
216
|
+
export interface ResolutionSummaryItem {
|
|
217
|
+
sessionId: string;
|
|
218
|
+
status: string;
|
|
219
|
+
summary: string | null;
|
|
220
|
+
resolvedAt: string | null;
|
|
221
|
+
}
|
|
222
|
+
/** Structured escalation brief — the handoff context pack. */
|
|
223
|
+
export interface Handoff {
|
|
224
|
+
subjectId: string;
|
|
225
|
+
sessionId: string;
|
|
226
|
+
reason: string;
|
|
227
|
+
generatedAt: string;
|
|
228
|
+
customerSummary: string;
|
|
229
|
+
activeIssue: string;
|
|
230
|
+
attemptedSteps: string[];
|
|
231
|
+
keyFacts: string[];
|
|
232
|
+
resolutionHistory: ResolutionSummaryItem[];
|
|
233
|
+
recentContext: string[];
|
|
234
|
+
healthScore: number | null;
|
|
235
|
+
healthState: HealthState | null;
|
|
236
|
+
healthFactors: HealthFactor[];
|
|
237
|
+
/** Pre-rendered markdown brief, ready for human or LLM consumption. */
|
|
238
|
+
handoffNotes: string;
|
|
239
|
+
tokenEstimate: number;
|
|
240
|
+
provenance: Record<string, unknown>;
|
|
241
|
+
/** ULID of the state-assembly receipt, when one was emitted. */
|
|
242
|
+
receiptId?: string | null;
|
|
243
|
+
/** True iff a receipt was successfully written for this call. */
|
|
244
|
+
receiptEmitted?: boolean;
|
|
245
|
+
}
|
|
246
|
+
/** Resolution tracking record for a support session. */
|
|
247
|
+
export interface Resolution {
|
|
248
|
+
id: string;
|
|
249
|
+
subjectId: string;
|
|
250
|
+
sessionId: string;
|
|
251
|
+
status: ResolutionStatus;
|
|
252
|
+
resolutionSummary: string | null;
|
|
253
|
+
resolvedAt: string | null;
|
|
254
|
+
metadata: Record<string, unknown>;
|
|
255
|
+
createdAt: string;
|
|
256
|
+
updatedAt: string;
|
|
257
|
+
}
|
|
169
258
|
export interface CreateEpisodeParams {
|
|
170
259
|
subjectId: string;
|
|
171
260
|
source: string;
|
|
@@ -213,6 +302,53 @@ export interface SetMemoryLabelsParams {
|
|
|
213
302
|
*/
|
|
214
303
|
sensitivityLabels: string[];
|
|
215
304
|
}
|
|
305
|
+
export interface GetSLAParams {
|
|
306
|
+
subjectId: string;
|
|
307
|
+
/** First-response SLA threshold in minutes (server default: 5). */
|
|
308
|
+
firstResponseThresholdMinutes?: number;
|
|
309
|
+
/** Resolution SLA threshold in hours (server default: 24). */
|
|
310
|
+
resolutionThresholdHours?: number;
|
|
311
|
+
}
|
|
312
|
+
export interface CreateHandoffParams {
|
|
313
|
+
subjectId: string;
|
|
314
|
+
/** Session being handed off. */
|
|
315
|
+
sessionId: string;
|
|
316
|
+
/** Why the handoff is happening (server default: "escalation"). */
|
|
317
|
+
reason?: string;
|
|
318
|
+
/** Token budget for the assembled brief. */
|
|
319
|
+
maxTokens?: number;
|
|
320
|
+
/**
|
|
321
|
+
* Opt in to emitting a state-assembly receipt for this call. The
|
|
322
|
+
* tenant config can also force emission on or off independently of
|
|
323
|
+
* this flag.
|
|
324
|
+
*/
|
|
325
|
+
emitReceipt?: boolean;
|
|
326
|
+
queryId?: string;
|
|
327
|
+
taskId?: string;
|
|
328
|
+
parentReceiptId?: string;
|
|
329
|
+
/**
|
|
330
|
+
* Caller identity consumed by the sensitivity-label policy layer
|
|
331
|
+
* (#50). When the tenant config sets `require_caller_identity: true`,
|
|
332
|
+
* both `callerId` and `callerType` are mandatory.
|
|
333
|
+
*/
|
|
334
|
+
callerId?: string;
|
|
335
|
+
callerType?: string;
|
|
336
|
+
}
|
|
337
|
+
export interface CreateResolutionParams {
|
|
338
|
+
subjectId: string;
|
|
339
|
+
sessionId: string;
|
|
340
|
+
/** Lifecycle status (server default: "open"). */
|
|
341
|
+
status?: ResolutionStatus;
|
|
342
|
+
/** Short human summary of how the session was resolved. */
|
|
343
|
+
resolutionSummary?: string;
|
|
344
|
+
/** Free-form caller-owned bag; inner keys round-trip verbatim. */
|
|
345
|
+
metadata?: Record<string, unknown>;
|
|
346
|
+
}
|
|
347
|
+
export interface ListResolutionsParams {
|
|
348
|
+
subjectId: string;
|
|
349
|
+
/** Filter to a single status. Omit to list every resolution. */
|
|
350
|
+
status?: ResolutionStatus;
|
|
351
|
+
}
|
|
216
352
|
export interface ClientOptions {
|
|
217
353
|
baseUrl?: string;
|
|
218
354
|
apiKey?: string;
|