@aiqa/sdk 2.1.0-develop.3 → 2.1.0-develop.5

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
@@ -10,20 +10,27 @@ A TypeScript/JavaScript SDK for interacting with the AIQA WebSocket service. Thi
10
10
  - [API Reference](#api-reference)
11
11
  - [Connection Management](#connection-management)
12
12
  - [Application Management](#application-management)
13
- - [Recording Management](#recording-management)
14
13
  - [Fact Management](#fact-management)
14
+ - [Recording Management](#recording-management)
15
15
  - [Event Handling](#event-handling)
16
16
  - [Verification lifecycle](#verification-lifecycle)
17
17
  - [Types](#types)
18
+ - [Application](#application)
19
+ - [ApplicationVerificationSummary](#applicationverificationsummary)
20
+ - [ApplicationVerificationStatus](#applicationverificationstatus)
21
+ - [ApplicationFact](#applicationfact)
18
22
  - [AddFactResult](#addfactresult)
19
23
  - [VerificationStatus](#verificationstatus)
20
24
  - [FactVerifiedPayload](#factverifiedpayload)
25
+ - [ApplicationFactInput](#applicationfactinput)
21
26
  - [FlagFactResult](#flagfactresult)
27
+ - [ConversationLanguage](#conversationlanguage)
22
28
  - [UpdateConversationInput](#updateconversationinput)
23
29
  - [UpdateConversationResult](#updateconversationresult)
24
30
  - [Examples](#examples)
25
31
  - [Error Handling](#error-handling)
26
- - [Semantic Versioning](#semantic-versioning)
32
+ - [Version Requirements](#version-requirements)
33
+ - [License](#license)
27
34
 
28
35
  ## Installation
29
36
 
@@ -65,6 +72,15 @@ sdk.on("error", (error) => {
65
72
  new AiQaSdk(applicationId, applicationSecret, url?)
66
73
  ```
67
74
 
75
+ **Parameters:**
76
+
77
+ - `applicationId: string` - your application id
78
+ - `applicationSecret: string` - your application secret
79
+ - `url?: string` - the AIQA service endpoint. Always pass it; the default
80
+ only works for local development.
81
+
82
+ The constructor throws if either credential is empty.
83
+
68
84
  ## API Reference
69
85
 
70
86
  ### Connection Management
@@ -73,6 +89,11 @@ new AiQaSdk(applicationId, applicationSecret, url?)
73
89
 
74
90
  Establishes a WebSocket connection to the AIQA service.
75
91
 
92
+ **Returns:**
93
+
94
+ - `void` — connection progress is reported through the `connect`,
95
+ `authenticated`, and `error` events.
96
+
76
97
  ```typescript
77
98
  sdk.connect();
78
99
  ```
@@ -81,6 +102,10 @@ sdk.connect();
81
102
 
82
103
  Closes the WebSocket connection.
83
104
 
105
+ **Returns:**
106
+
107
+ - `void`
108
+
84
109
  ```typescript
85
110
  sdk.disconnect();
86
111
  ```
@@ -89,20 +114,73 @@ sdk.disconnect();
89
114
 
90
115
  #### `getApplication()`
91
116
 
92
- Returns the cached application loaded during authentication.
93
- If authentication hasn't completed yet, this throws. Use the `authenticated` event to know when it's ready.
117
+ Returns the application, its conversation participants, and how the call is
118
+ going so far.
119
+
120
+ **Returns:**
121
+
122
+ - `Promise<`[`Application`](#application)`>`
123
+
124
+ ```typescript
125
+ {
126
+ application_id: string;
127
+ client_name: string;
128
+ client_phone_number: string;
129
+ agent_id: string;
130
+ agent_first_name: string;
131
+ agent_last_name: string;
132
+ verification?: ApplicationVerificationSummary;
133
+ }
134
+ ```
135
+
136
+ Wait for the `authenticated` event before calling it: until authentication
137
+ has completed, and whenever the connection is down, it **rejects**.
138
+ `client_name`, `client_phone_number` and `agent_id` normally carry any change
139
+ you made with `updateConversation()` earlier in the call — see
140
+ [Reading `verification`](#reading-verification) for the exception.
141
+ `agent_first_name` and `agent_last_name` come back empty; use
142
+ `updateConversation({ agentName })` if you need to record an agent's name.
94
143
 
95
144
  ```typescript
96
145
  const application = await sdk.getApplication();
146
+
147
+ console.log(application.application_id, application.client_name);
148
+
149
+ if (application.verification) {
150
+ const v = application.verification;
151
+ console.log(v.status, `${v.count_errors} errors`);
152
+ }
97
153
  ```
98
154
 
155
+ ##### Reading `verification`
156
+
157
+ The numbers change during a call. A fact counts as pending from the moment you
158
+ add it until its result arrives, so call `getApplication()` again whenever you
159
+ want current figures.
160
+
161
+ **A fact that was never asked and came back wrong is counted twice: once in
162
+ `count_not_asked` and once in `count_errors`.** That is ordinary, not an edge
163
+ case, and `count_total` also includes every fact that is still pending. So no
164
+ subtraction from `count_total` gives you a reliable number of facts that
165
+ passed. To show one, count the facts whose `verification_status` is `matched`
166
+ in [`getFacts()`](#getfacts).
167
+
168
+ `status` summarises the answers only, so a call where nothing was asked reads
169
+ `no_errors`. Read `count_pending` and `count_not_asked` if your UI cares
170
+ whether the call is complete.
171
+
172
+ `verification` is not always there. When it is missing, there is no summary for
173
+ this call — treat that as unknown rather than as all zeros, and note that
174
+ the identity fields alongside it may then be the ones from when you
175
+ authenticated, without an `updateConversation()` you made since.
176
+
99
177
  #### `setConversationProduct(product)`
100
178
 
101
179
  Sets the conversation product using a valid product code.
102
180
 
103
181
  **Parameters:**
104
182
 
105
- - `product: string` - product code (from the `service.code` catalog)
183
+ - `product: string` - product code; the accepted values for your account are listed in the AIQA dashboard
106
184
 
107
185
  **Returns:**
108
186
 
@@ -154,8 +232,9 @@ change.
154
232
  | `agentGroups` | `string[]` | 32 × 128 | entries cannot contain a comma |
155
233
 
156
234
  Every string (including each `agentGroups` entry) must be non-empty;
157
- surrounding whitespace is trimmed. `null` is rejected — omit the field
158
- instead. At least one field is required.
235
+ surrounding whitespace is trimmed first, so a value of only spaces is
236
+ rejected. `null` is rejected — omit the field instead. At least one field is
237
+ required, and any field not in the table is rejected.
159
238
 
160
239
  **Returns:**
161
240
 
@@ -174,18 +253,23 @@ console.log(result.success, result.conversation.policy_number);
174
253
 
175
254
  #### `addFact(fact)`
176
255
 
177
- Adds a fact to the active application and waits for the **terminal**
178
- verification verdict (Promise-based). The Promise resolves with an
256
+ Adds a fact to the active application and waits for the **final**
257
+ verification result. The Promise resolves with an
179
258
  [`AddFactResult`](#addfactresult); subscribe to the
180
- [`FACT_VERIFIED`](#event-handling) broadcast event to render progress
259
+ [`FACT_VERIFIED`](#event-handling) event to show progress
181
260
  (`awaiting_question`, `awaiting_answer`, `partial`,
182
261
  `pending_confirmation_matched`, `pending_confirmation_unmatched`)
183
262
  while you wait.
184
263
 
185
- `addFact()` does not throw on verification failure — an unmatched
186
- fact resolves with `is_valid_answer: false` and (where the backend
187
- provides it) `verification_status: "unmatched"`.
188
- Reject paths are reserved for transport / protocol errors.
264
+ A failed verification is not an error: an unmatched fact resolves with
265
+ `is_valid_answer: false` and, where present, `verification_status: "unmatched"`.
266
+ The Promise rejects only when the request itself fails — a dropped connection,
267
+ a timeout, a rejected payload.
268
+
269
+ **Returns:**
270
+
271
+ - `Promise<`[`AddFactResult`](#addfactresult)`>` — resolves once the fact
272
+ reaches a final `verification_status`.
189
273
 
190
274
  **Parameters:**
191
275
 
@@ -195,11 +279,10 @@ Reject paths are reserved for transport / protocol errors.
195
279
  id: string;
196
280
  /**
197
281
  * Optional. Stable identifier for the underlying question, shared across
198
- * applications and conversations. When provided it is used to look up (or
199
- * create) the matching question row in the database instead of `id`. When
200
- * omitted, `id` is used (legacy behavior).
282
+ * applications and conversations. When provided it identifies the
283
+ * question instead of `id`. When omitted, `id` is used.
201
284
  *
202
- * Keep this consistent across calls for the "same" question — see
285
+ * Keep it consistent across calls for the "same" question — see
203
286
  * "Question identity and questionId" below.
204
287
  */
205
288
  questionId?: string;
@@ -207,14 +290,12 @@ Reject paths are reserved for transport / protocol errors.
207
290
  expected_answer: any;
208
291
  answer_format: { type: "STRING" }
209
292
  /**
210
- * Optional. Use this to attach your own identifiers to a fact so your UI
211
- * can map the server response back to the right field or component.
212
- * For example, store a form field ID, a section name, or any internal
213
- * reference you need — the server stores it as-is and returns it unchanged
214
- * in getFacts().
293
+ * Optional. Your own identifiers for this fact — a form field ID, a
294
+ * section name, anything that lets your UI map the result back to the
295
+ * right place. getFacts() returns it unchanged.
215
296
  *
216
- * Constraints: all keys and values must be strings; each value is limited
217
- * to 1024 characters. Payloads that exceed this limit are rejected.
297
+ * Keys and values must all be strings, and each value is limited to 1024
298
+ * characters. A payload that breaks either rule is rejected.
218
299
  */
219
300
  metadata?: Record<string, string>
220
301
  }
@@ -231,50 +312,48 @@ const result = await sdk.addFact({
231
312
  });
232
313
 
233
314
  if (result.is_valid_answer) {
234
- // verification_status will be "matched".
315
+ // verification_status, when present, is "matched".
235
316
  console.log("matched:", result.ai_answer);
236
317
  } else {
237
- // verification_status will be "unmatched". matched_components /
238
- // missing_components describe what the partial-match heuristics
239
- // were able to extract.
318
+ // verification_status, when present, is "unmatched". matched_components /
319
+ // missing_components describe which parts of the expected answer
320
+ // were and were not found.
240
321
  console.log("unmatched:", result.missing_components);
241
322
  }
242
323
  ```
243
324
 
244
325
  ##### Question identity and `questionId`
245
326
 
246
- `id` identifies an instance of a fact within a single conversation. `questionId`
247
- is an optional field that identifies the underlying question across every
248
- application and conversation that asks it. They're separated so you can give
249
- each fact instance its own `id` (e.g. a per-call uuid) while still pointing at a
250
- stable question identity.
251
-
252
- Two server-side features are scoped per question identity:
253
-
254
- - **Accuracy improvements.** Per-question signals (flags, model tweaks, fuzzy
255
- matches) accumulate against the question row. Splitting the same logical
256
- question across multiple identities splits these signals and resets the
257
- accuracy gains you've already earned.
258
- - **Remaps from the management dashboard.** When an operator remaps a question
259
- in the dashboard, the remap is stored on the question row. A subsequent call
260
- with a different identity won't pick up the remap.
261
-
262
- The "question identity" the server uses is `questionId` if you sent one,
263
- otherwise `id`. So:
264
-
265
- - If your `id` is already stable across calls for the same logical question,
266
- omitting `questionId` is fine — both features above still work, just keyed off
267
- `id`.
268
- - If your `id` varies per call (per-call uuid, ephemeral instance id, etc.),
269
- send a stable `questionId`. Otherwise each call looks like a new question and
270
- you lose the features above.
271
- - Once you've picked an identity for a question, don't change it. If you must
272
- rename, coordinate with the team owning the dashboard so remaps and
273
- historical signals can be migrated.
327
+ `id` identifies one fact within a single conversation. `questionId` identifies
328
+ the underlying question across every application and conversation that asks it.
329
+ They are separate fields so you can give each fact its own `id` — a per-call
330
+ uuid, say — while still pointing at a stable question.
331
+
332
+ The question identity is `questionId` when you send one, otherwise `id`.
333
+ Anything AIQA has tuned for a question is attached to that identity: the
334
+ corrections that decide how its answers are read, the phrasings that count as
335
+ asking it, the outcome of reviewing facts you flagged. A call that arrives
336
+ under a different identity gets none of it. So:
337
+
338
+ - If your `id` is already stable across calls for the same question, omitting
339
+ `questionId` is fine — the identity is then your `id`.
340
+ - If your `id` varies per call (a per-call uuid, an ephemeral instance id),
341
+ send a stable `questionId`. Otherwise every call looks like a brand-new
342
+ question.
343
+ - Once you have picked an identity for a question, don't change it. If you have
344
+ to rename one, contact AIQA support first so the tuning can move with it.
274
345
 
275
346
  #### `getFacts()`
276
347
 
277
- Retrieves all facts for the application (Promise-based). Each fact includes a `metadata` field containing whatever was passed to `addFact()`. Facts added without `metadata` return `{}`.
348
+ Retrieves every fact on the application, whatever state it is in. Each one
349
+ carries the `metadata` you passed to `addFact()`, or `{}` if you passed none.
350
+ This is also where to count facts by outcome — for a pass count, count the ones
351
+ whose `verification_status` is `matched`.
352
+
353
+ **Returns:**
354
+
355
+ - `Promise<`[`ApplicationFact[]`](#applicationfact)`>` — each fact with its
356
+ current `question_status` and `verification_status`.
278
357
 
279
358
  ```typescript
280
359
  const facts = await sdk.getFacts();
@@ -285,7 +364,7 @@ facts.forEach((fact) => {
285
364
 
286
365
  #### `flagFact(factId)`
287
366
 
288
- Flags a fact for human review. Creates a signal that allow AIQA to improve review quality.
367
+ Flags a fact for human review.
289
368
 
290
369
  **Parameters:**
291
370
 
@@ -304,7 +383,11 @@ console.log(result.success); // true
304
383
 
305
384
  #### `startRecording()`
306
385
 
307
- Starts audio recording (Promise-based).
386
+ Starts audio recording.
387
+
388
+ **Returns:**
389
+
390
+ - `Promise<boolean>` — `true` once the server has started recording.
308
391
 
309
392
  ```typescript
310
393
  const started = await sdk.startRecording();
@@ -312,7 +395,11 @@ const started = await sdk.startRecording();
312
395
 
313
396
  #### `stopRecording()`
314
397
 
315
- Stops audio recording (Promise-based).
398
+ Stops audio recording.
399
+
400
+ **Returns:**
401
+
402
+ - `Promise<boolean>` — `true` once the server has stopped recording.
316
403
 
317
404
  ```typescript
318
405
  const stopped = await sdk.stopRecording();
@@ -320,7 +407,11 @@ const stopped = await sdk.stopRecording();
320
407
 
321
408
  #### `isRecordingNow()`
322
409
 
323
- Checks if recording is currently active (Promise-based).
410
+ Checks if recording is currently active.
411
+
412
+ **Returns:**
413
+
414
+ - `Promise<boolean>` — `true` while a recording is in progress.
324
415
 
325
416
  ```typescript
326
417
  const isRecording = await sdk.isRecordingNow();
@@ -332,23 +423,26 @@ const isRecording = await sdk.isRecordingNow();
332
423
 
333
424
  Registers an event listener. Call `connect()` before `on()`.
334
425
 
426
+ **Returns:**
427
+
428
+ - `void`
429
+
335
430
  **Available Events:**
336
431
 
337
- - `connect` - Socket.IO connection established
338
- - `disconnect` - Socket.IO connection closed
339
- - `close` - Socket.IO connection closed
340
- - `error` - Connection or socket error
341
- - `reconnect_attempt` - Socket.IO reconnection attempt
342
- - `reconnect_error` - Socket.IO reconnection error
343
- - `reconnect_failed` - Socket.IO reconnection failed
344
- - `authenticated` - Local event fired after successful authentication (provides Application object)
345
- - `app_version` - Server event with version requirements `{ min, max }`
346
- - `FACT_VERIFIED` - Broadcast event fired on **every** verification
347
- state transition (both non-terminal progress and terminal verdicts)
348
- for **every** fact in the active conversation. Payload shape:
349
- [`FactVerifiedPayload`](#factverifiedpayload). Use this to render
350
- live verification progress in your UI; `addFact()`'s Promise only
351
- resolves on the terminal state.
432
+ - `connect` - connection established
433
+ - `disconnect` - connection closed
434
+ - `close` - connection closed
435
+ - `error` - connection or socket error
436
+ - `reconnect_attempt` - reconnection attempt
437
+ - `reconnect_error` - reconnection attempt failed
438
+ - `reconnect_failed` - reconnection gave up
439
+ - `authenticated` - authentication succeeded; receives the
440
+ [`Application`](#application)
441
+ - `app_version` - the SDK version range the service supports, `{ min, max }`
442
+ - `FACT_VERIFIED` - fires on **every** verification state change, progress and
443
+ final result alike, for **every** fact in the conversation. Payload:
444
+ [`FactVerifiedPayload`](#factverifiedpayload). Use it to show live progress;
445
+ `addFact()`'s Promise resolves only on the final result.
352
446
 
353
447
  ```typescript
354
448
  sdk.connect();
@@ -366,6 +460,19 @@ sdk.on("FACT_VERIFIED", (payload) => {
366
460
  });
367
461
  ```
368
462
 
463
+ #### `off(eventName, callback?)`
464
+
465
+ Removes an event listener. Omit `callback` to remove every listener
466
+ registered for the event.
467
+
468
+ **Returns:**
469
+
470
+ - `void`
471
+
472
+ ```typescript
473
+ sdk.off("connect");
474
+ ```
475
+
369
476
  ## Verification lifecycle
370
477
 
371
478
  A single `addFact()` call walks through a sequence of states emitted
@@ -377,56 +484,103 @@ processing
377
484
  └─> awaiting_answer (asked, customer hasn't answered yet)
378
485
  └─> partial (partial evidence — e.g. "305" of "30521")
379
486
  └─> pending_confirmation_matched
380
- (backend has a match but is holding a settling
381
- window for mid-answer clarifications like
382
- spellings or "I mean…" corrections)
487
+ (a match is held briefly in case the customer
488
+ corrects it mid-answer — spellings, "I mean…")
383
489
  └─> pending_confirmation_unmatched
384
- (same, but for a held unmatched verdict)
490
+ (same, but for a held unmatched answer)
385
491
  │
386
492
  ▼
387
- matched | unmatched ← terminal
493
+ matched | unmatched ← final
388
494
  ```
389
495
 
390
- Rules for consumers:
496
+ Rules:
391
497
 
392
- - **`addFact()` resolves only on a terminal state** (`matched`,
393
- `unmatched`). Render progress from the
394
- `FACT_VERIFIED` event, render the final verdict from the Promise
395
- result.
396
- - **Treat unknown `verification_status` strings as `processing`.**
397
- The enum is additive — older SDK builds must fall through gracefully
398
- when the backend ships a new state.
399
- - **`pending_confirmation_*` is never terminal.** The wire-visible
400
- latency penalty is bounded by `settling_window_ms` on the server
401
- (default 2000 ms). The held verdict can flip — that's the whole
402
- point — so don't treat it as a commit.
403
-
404
- #### `off(eventName, callback?)`
405
-
406
- Removes an event listener.
407
-
408
- ```typescript
409
- sdk.off("connect");
410
- ```
498
+ - **`addFact()` resolves only on a final state** (`matched`,
499
+ `unmatched`). Show progress from the `FACT_VERIFIED` event, show the final
500
+ result from the Promise.
501
+ - **Handle a `verification_status` you don't recognize as `processing`.**
502
+ - **`pending_confirmation_*` is never final.** The answer can still change,
503
+ so don't show it as a decision.
504
+ - **A fact can be revised after `addFact()` has resolved.** If you keep its
505
+ result on screen for the rest of the call, leave your `FACT_VERIFIED`
506
+ listener attached and always show the latest state for that `factId`.
411
507
 
412
508
  ## Types
413
509
 
414
510
  ### Application
415
511
 
512
+ Returned by [`getApplication()`](#getapplication): the application, the two
513
+ participants of the conversation, and how the call is going so far.
514
+
416
515
  ```typescript
417
516
  type Application = {
418
517
  application_id: string;
419
518
  client_name: string;
420
519
  client_phone_number: string;
421
520
  agent_id: string;
422
- agent_first_name: string;
423
- agent_last_name: string;
521
+ agent_first_name: string; // comes back empty
522
+ agent_last_name: string; // comes back empty
523
+ // Missing when there is no summary for the call — not the same as zeros.
524
+ // See "Reading verification" above.
525
+ verification?: ApplicationVerificationSummary;
424
526
  };
425
527
  ```
426
528
 
529
+ ### ApplicationVerificationSummary
530
+
531
+ ```typescript
532
+ type ApplicationVerificationSummary = {
533
+ status: ApplicationVerificationStatus;
534
+
535
+ // Facts whose answer did not match the expected one.
536
+ count_errors: number;
537
+
538
+ // The facts in count_errors that you sent with critical: true.
539
+ count_critical_errors: number;
540
+
541
+ // Every fact on the application, checked or not. The other counters are
542
+ // subsets of it and can overlap each other, so no subtraction from
543
+ // count_total gives you a pass count.
544
+ count_total: number;
545
+
546
+ // Facts whose question was never asked. Does not include the ones still
547
+ // waiting for a result — those are count_pending. It does overlap
548
+ // count_errors: a fact never asked that came back wrong is in both.
549
+ count_not_asked: number;
550
+
551
+ // The facts in count_not_asked that you sent with critical: true.
552
+ count_critical_not_asked: number;
553
+
554
+ // Facts added but not yet resolved. Most of the call's facts sit here early
555
+ // on and move out as their results arrive.
556
+ count_pending: number;
557
+
558
+ // Facts flagged as suspicious when the call is reviewed — for instance the
559
+ // agent leading the customer to the expected answer. Independent of the
560
+ // answer: a matched fact can be flagged. Reads 0 while the call is running.
561
+ count_suspicious: number;
562
+ };
563
+ ```
564
+
565
+ ### ApplicationVerificationStatus
566
+
567
+ Overall result for the whole call, based on the answers. Distinct from
568
+ [`VerificationStatus`](#verificationstatus), which describes a single fact.
569
+ Questions that were never asked do not raise it.
570
+
571
+ ```typescript
572
+ type ApplicationVerificationStatus =
573
+ // At least one fact you sent with critical: true failed.
574
+ | "critical_errors"
575
+ // At least one fact failed, none of them critical.
576
+ | "errors"
577
+ // No fact has failed — which is not the same as "everything was asked".
578
+ | "no_errors";
579
+ ```
580
+
427
581
  ### ApplicationFact
428
582
 
429
- Returned by `getFacts()`. Extends `ApplicationFactInput` and adds server-side fields.
583
+ Returned by `getFacts()`. Extends `ApplicationFactInput` with the fields the service fills in.
430
584
 
431
585
  ```typescript
432
586
  type ApplicationFact = ApplicationFactInput & {
@@ -434,13 +588,14 @@ type ApplicationFact = ApplicationFactInput & {
434
588
  question_status: "searching" | "asked" | "not_asked";
435
589
  verification_status: VerificationStatus;
436
590
  flagged: boolean; // true once flagFact() has been called for this fact
437
- metadata: Record<string, string>; // always present; {} when not set on addFact
591
+ // metadata is inherited from ApplicationFactInput, where it is optional.
592
+ // getFacts() always fills it in: {} for a fact you added without one.
438
593
  };
439
594
  ```
440
595
 
441
596
  ### AddFactResult
442
597
 
443
- Resolved value of `addFact()`. Only emitted at the terminal verification
598
+ Resolved value of `addFact()`. Only sent once the fact reaches its final
444
599
  state — see [Verification lifecycle](#verification-lifecycle).
445
600
 
446
601
  ```typescript
@@ -458,31 +613,27 @@ interface AddFactResult {
458
613
  question_asked?: boolean;
459
614
 
460
615
  /**
461
- * 0–1 (or 0–100 — scale matches the configured similarity method).
462
- * Similarity between the agent's utterance and the expected question.
616
+ * How closely the agent's utterance matched the expected question, on a
617
+ * 0–1 or a 0–100 scale. Higher is closer.
463
618
  */
464
619
  question_match_score?: number;
465
620
 
466
621
  /**
467
- * 0–1 score derived from how well the customer's answer matched expected.
468
- * Populated by the verification queue from partial-match heuristics
469
- * (numeric-prefix ratio, matched-components ratio).
622
+ * 0–1 score for how closely the customer's answer matched the expected one.
623
+ * Undefined when there is no partial signal to score.
470
624
  */
471
625
  answer_match_score?: number;
472
626
 
473
627
  /**
474
- * Top-level state at terminal resolution. Always one of `matched`
475
- * or `unmatched` because the `addFact()` Promise only
476
- * resolves on terminals. Optional during the rollout window for
477
- * backwards compatibility with older backends.
628
+ * The final state: `matched` or `unmatched` whenever it is present.
629
+ * Fall back to `is_valid_answer` when it is missing.
478
630
  */
479
631
  verification_status?: VerificationStatus;
480
632
 
481
633
  /**
482
- * Per-fact partial-match breakdown carried through from the
483
- * verification queue's component-wise comparators. For numeric-prefix
484
- * facts these are `["prefix"]` / `["suffix"]`; future work will
485
- * generalise to addresses, names, dates, etc.
634
+ * Component labels describing which parts of the expected answer
635
+ * matched. Currently `["prefix"]` / `["suffix"]` for numeric facts;
636
+ * treat the set as open-ended.
486
637
  */
487
638
  matched_components?: string[];
488
639
  missing_components?: string[];
@@ -505,16 +656,15 @@ type VerificationStatus =
505
656
  | "unmatched";
506
657
  ```
507
658
 
508
- The enum is additive: consumers that `switch` on this value MUST
509
- treat unknown strings as `"processing"` so older SDK builds keep
510
- working after the backend ships a new state. See the
511
- [Verification lifecycle](#verification-lifecycle) for the transitions
512
- and which states are terminal.
659
+ Code that `switch`es on this value must treat any string it doesn't
660
+ recognize as `"processing"`. See the
661
+ [Verification lifecycle](#verification-lifecycle) for the transitions and
662
+ which states are final.
513
663
 
514
664
  ### FactVerifiedPayload
515
665
 
516
- Payload of the `FACT_VERIFIED` broadcast event. Same shape as
517
- `AddFactResult` plus the `factId` / `success` / `error` envelope.
666
+ Payload of the `FACT_VERIFIED` event: which fact the update is about, its
667
+ current state, and the full [`AddFactResult`](#addfactresult) shape in `data`.
518
668
 
519
669
  ```typescript
520
670
  interface FactVerifiedPayload {
@@ -525,7 +675,7 @@ interface FactVerifiedPayload {
525
675
  answer_match_score?: number;
526
676
  matched_components?: string[];
527
677
  missing_components?: string[];
528
- /** Same shape as AddFactResult so the same renderer handles both. */
678
+ /** Inner payload, same shape as AddFactResult. */
529
679
  data?: AddFactResult;
530
680
  error?: string;
531
681
  }
@@ -538,12 +688,12 @@ type ApplicationFactInput = {
538
688
  id: string;
539
689
  /**
540
690
  * Optional. Stable identifier for the underlying question, shared across
541
- * applications and conversations. Used to look up (or create) the matching
542
- * question row in the database when provided. When omitted, `id` is used.
691
+ * applications and conversations. When provided it identifies the question
692
+ * instead of `id`. When omitted, `id` is used.
543
693
  *
544
- * Keep this consistent across calls — accuracy improvements and remaps
545
- * configured in the management dashboard are scoped per `questionId`. See
546
- * "Question identity and questionId" under `addFact()`.
694
+ * Keep it consistent across calls: whatever AIQA has tuned for a question is
695
+ * attached to this identity. See "Question identity and questionId" under
696
+ * `addFact()`.
547
697
  */
548
698
  questionId?: string;
549
699
  question: string;
@@ -564,21 +714,18 @@ type ApplicationFactInput = {
564
714
  category_id?: string;
565
715
  category_name?: string;
566
716
  language?: string;
717
+ // Mark the question critical: its failures land in count_critical_errors,
718
+ // and one of them sets status to "critical_errors".
567
719
  critical?: boolean;
568
720
  is_skipped?: boolean;
569
721
  /**
570
- * Optional. Attach your own identifiers to a fact so your UI can map the
571
- * server response back to the right field or component — for example a form
572
- * field ID, a section name, or any internal reference you need.
573
- *
574
- * The server stores this value encrypted alongside the fact and returns it
575
- * unchanged in getFacts(). It is never inspected, indexed, or used for
576
- * verification logic.
722
+ * Optional. Your own identifiers for this fact — a form field ID, a section
723
+ * name, anything that lets your UI map the result back to the right place.
724
+ * getFacts() returns it unchanged (as {} for a fact you added without one),
725
+ * and it plays no part in verification.
577
726
  *
578
- * Constraints:
579
- * - All keys and values must be strings.
580
- * - Each individual value is limited to 1024 characters.
581
- * - Payloads that violate either constraint are rejected by the server.
727
+ * Keys and values must all be strings, and each value is limited to 1024
728
+ * characters. A payload that breaks either rule is rejected.
582
729
  */
583
730
  metadata?: Record<string, string>;
584
731
  };
@@ -648,55 +795,6 @@ type UpdateConversationResult = {
648
795
  };
649
796
  ```
650
797
 
651
- ### FactUpdateEvent
652
-
653
- ```typescript
654
- type FactUpdateEvent = {
655
- fact_id: string;
656
- question_id?: string;
657
- status:
658
- | "asked"
659
- | "answered_detected"
660
- | "agent_answered"
661
- | "verification_pending"
662
- | "verified"
663
- | "failed";
664
- detectedAnswer?: any;
665
- agentAnswer?: any;
666
- verifiedAnswer?: any;
667
- };
668
- ```
669
-
670
- ## Semantic Versioning
671
-
672
- Version bumps are automated with semantic commits and `semantic-release` in Bitbucket Pipelines:
673
-
674
- - `master` creates stable releases.
675
- - `develop` creates prereleases on the `develop` channel (for example `1.2.3-develop.1`).
676
-
677
- ### Commit types and version bump
678
-
679
- - `fix: ...` -> patch bump (`0.0.6` -> `0.0.7`)
680
- - `feat: ...` -> minor bump (`0.0.6` -> `0.1.0`)
681
- - `feat!: ...` or commit body with `BREAKING CHANGE:` -> major bump (`0.0.6` -> `1.0.0`)
682
- - `chore: ...`
683
- - Other commit types (for example `docs:`, `chore:`) do not trigger a release by default.
684
-
685
- ### Examples
686
-
687
- ```text
688
- fix: handle socket timeout error
689
- feat: add isRecordingNow helper
690
- feat!: change addFact response contract
691
- ```
692
-
693
- ### Pipeline requirements
694
-
695
- Set these repository variables so the release step can push tags/commits and publish to npm:
696
-
697
- - `BB_TOKEN_BASIC_AUTH` with value `user:token`
698
- - `NPM_TOKEN` with publish access to `@aiqa/sdk`
699
-
700
798
  ## Examples
701
799
 
702
800
  ### Complete Example: Recording Session
@@ -713,8 +811,9 @@ const sdk = new AiQaSdk(
713
811
 
714
812
  sdk.connect();
715
813
 
716
- sdk.on("connect", async () => {
717
- console.log("Connected!");
814
+ // getApplication() is only available once authentication has completed.
815
+ sdk.on("authenticated", async () => {
816
+ console.log("Authenticated!");
718
817
 
719
818
  try {
720
819
  const application = await sdk.getApplication();
@@ -732,7 +831,7 @@ sdk.on("connect", async () => {
732
831
  );
733
832
  });
734
833
 
735
- // Add a fact (Promise resolves at the terminal verdict)
834
+ // Add a fact (the Promise resolves once verification finishes)
736
835
  const result = await sdk.addFact({
737
836
  id: "q1",
738
837
  question: "What is your name?",
@@ -743,7 +842,7 @@ sdk.on("connect", async () => {
743
842
  });
744
843
 
745
844
  console.log(
746
- "Terminal verdict:",
845
+ "Final result:",
747
846
  result.verification_status,
748
847
  "is_valid_answer:",
749
848
  result.is_valid_answer,
@@ -779,14 +878,15 @@ try {
779
878
 
780
879
  ### Common Error Scenarios
781
880
 
782
- 1. **Connection Errors**: Fired through the `error` event
783
- 2. **Version Mismatch**: Thrown when the server version is incompatible
784
- 3. **Invalid Data**: Returned as rejected promises
785
- 4. **Network Issues**: Handled through reconnection events
881
+ 1. **Connection errors** - reported through the `error` event.
882
+ 2. **Unsupported SDK version** - the SDK disconnects and reports it through
883
+ the `error` event.
884
+ 3. **Invalid data** - the method's Promise rejects.
885
+ 4. **Network drops** - reported through the `reconnect_*` events.
786
886
 
787
887
  ## Version Requirements
788
888
 
789
- The server emits an `app_version` payload with `{ min, max }` supported SDK versions. If the current SDK version is outside that range, the SDK disconnects and emits an `error` event.
889
+ If your SDK version is outside the range the service supports, the SDK disconnects and emits an `error` event. The supported range arrives on the `app_version` event as `{ min, max }`.
790
890
 
791
891
  ## License
792
892