@ctchealth/plato-sdk 0.0.20 → 0.0.22

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
@@ -17,7 +17,7 @@ All API requests require authentication via a client token. Pass a pre-signed JW
17
17
  - Comprehensive event system for call management
18
18
  - Type-safe API with full TypeScript support
19
19
  - Medical training simulation configuration
20
- - Simulation persistence and recovery across page reloads
20
+ - Simulation persistence across page reloads
21
21
 
22
22
  ## Installation
23
23
 
@@ -294,22 +294,32 @@ Uploads a PDF file for slide analysis. The file will be uploaded to S3 and analy
294
294
 
295
295
  - **Latin-only file names:** The PDF file name must contain only Latin characters. Non-latin characters in the file name are not supported.
296
296
  - **Maximum 100 pages:** PDF files cannot exceed 100 pages.
297
- - **No duplicate content:** Uploading a PDF with identical content to an already uploaded file is not allowed. Duplicates are detected based on file content, not file name.
297
+ - **No duplicate content:** Uploading a PDF with identical content that was already uploaded by your organization throws an error. Duplicates are detected based on file content, not file name, and are scoped per organization.
298
298
 
299
299
  **Example:**
300
300
 
301
301
  ```typescript
302
- // Upload a PDF file from an input element
302
+ import { PdfAlreadyExistsError } from 'plato-sdk';
303
+
303
304
  const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
304
305
  const file = fileInput.files?.[0];
305
306
 
306
307
  if (file) {
307
- const pdfId = await client.uploadPdfSlides(file);
308
- console.log('PDF upload initiated, ID:', pdfId);
309
-
310
- // Now you can immediately check the status using the returned ID
311
- const status = await client.checkPdfStatus(pdfId);
312
- console.log('Initial status:', status);
308
+ try {
309
+ const pdfId = await client.uploadPdfSlides(file);
310
+ console.log('PDF uploaded, ID:', pdfId);
311
+ // Poll status until analysis completes
312
+ } catch (error) {
313
+ if (error instanceof PdfAlreadyExistsError) {
314
+ // Inform the user this PDF already exists in their organization
315
+ console.error(
316
+ 'This PDF has already been uploaded by your organization. PDF ID:',
317
+ error.pdfId
318
+ );
319
+ } else {
320
+ console.error('Upload failed:', error.message);
321
+ }
322
+ }
313
323
  }
314
324
  ```
315
325
 
@@ -599,6 +609,7 @@ const inProgress = simulations.find(
599
609
  );
600
610
  ```
601
611
 
612
+ <!--
602
613
  ## Call Recovery
603
614
 
604
615
  The SDK automatically handles call recovery in case of page refreshes or browser closures during active calls. This ensures that call data is never lost and all calls get properly processed by the backend, even if the page is refreshed while a call is in progress.
@@ -900,6 +911,7 @@ A: The `recoverAbandonedCall()` method returns `true` when a call is recovered.
900
911
  **Q: What if the backend is down during recovery?**
901
912
 
902
913
  A: The recovery attempt is logged and the stored state is cleared to prevent infinite retries. The SDK continues working normally. Recovery failures are graceful and don't break the app.
914
+ -->
903
915
 
904
916
  ## Event System
905
917
 
@@ -914,6 +926,7 @@ The SDK provides a comprehensive event system for managing voice calls:
914
926
  - `message`: Triggered when a message is received (contains transcript and metadata)
915
927
  - `volume-level`: Triggered with volume level updates (number)
916
928
  - `error`: Triggered when an error occurs
929
+ - `call-ended-reason`: Triggered just before `call-end` with the reason the call was terminated (e.g. silence timeout). Use this to show the user a contextual message immediately
917
930
  - `call-details-ready`: Triggered when post-call processing completes and call details are available (includes full `CallDTO` with transcript, summary, ratings, and evaluation)
918
931
 
919
932
  ### Event Usage
@@ -939,6 +952,29 @@ call.on('call-details-ready', callDetails => {
939
952
  });
940
953
  ```
941
954
 
955
+ ## Detecting Why a Call Ended
956
+
957
+ The `call-ended-reason` event fires **just before** `call-end`, giving you the reason the call was terminated in time to update the UI before any post-call processing begins.
958
+
959
+ ### Usage
960
+
961
+ ```typescript
962
+ call.on('call-ended-reason', ({ reason, isInactivity }) => {
963
+ // reason — raw string from the platform, e.g. "silence-timed-out"
964
+ // isInactivity — true when reason contains "silence" or "inactivity"
965
+ });
966
+ ```
967
+
968
+ ### Known Reason Values
969
+
970
+ | `reason` | `isInactivity` | When it occurs |
971
+ | --------------------- | -------------- | ------------------------------------------------------- |
972
+ | `silence-timed-out` | `true` | No speech detected within the configured silence window |
973
+ | `customer-ended-call` | `false` | The user clicked "End Call" |
974
+ | `pipeline-error` | `false` | An internal platform error terminated the call |
975
+
976
+ > **Note:** The `reason` field reflects the raw value from the underlying voice platform. New values may be introduced over time. Always handle unknown reasons gracefully by falling back to a generic message.
977
+
942
978
  ## Automatic Post-Call Feedback
943
979
 
944
980
  The SDK automatically fetches detailed call information after each call ends and completes post-call processing. This includes comprehensive feedback such as transcript, summary, evaluation metrics, strengths, weaknesses, and ratings.
@@ -1118,10 +1154,22 @@ call.on('call-details-ready', callDetails => {
1118
1154
 
1119
1155
  ### Timing Considerations
1120
1156
 
1157
+ - `call-ended-reason`: Fires immediately before `call-end`, with the reason the call stopped
1121
1158
  - `call-end`: Fires immediately when the call stops
1122
1159
  - `call-details-ready`: Fires after backend processing completes (typically 2-5 seconds after call ends)
1123
1160
 
1124
- Plan your UX accordingly—show a loading/processing state between these two events.
1161
+ Plan your UX accordingly—show a contextual end message on `call-ended-reason`, then a loading/processing state until `call-details-ready` arrives.
1162
+
1163
+ ### Call Duration and Data Availability
1164
+
1165
+ The quality of data returned in `call-details-ready` depends on the duration of the call:
1166
+
1167
+ | Call duration | Behaviour |
1168
+ | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1169
+ | **< ~15 seconds** | `call-details-ready` fires immediately after `call-end` with whatever the database currently holds. Fields like `transcript`, `summary`, `score`, `strengths`, and `weaknesses` will typically be empty or zero — the call was too short to generate a meaningful analysis. |
1170
+ | **≥ ~15 seconds** | The SDK polls the backend until Vapi's post-call analysis is ready (transcript present), then emits `call-details-ready` with the fully populated `CallDTO`. |
1171
+
1172
+ > **Note:** The ~15 second threshold accounts for the Vapi connection handshake (typically 1–5 seconds) plus a minimum amount of conversation time required for analysis to be generated. Always handle empty fields gracefully regardless of call length.
1125
1173
 
1126
1174
  ## Data Types
1127
1175
 
@@ -1429,6 +1477,49 @@ try {
1429
1477
  }
1430
1478
  ```
1431
1479
 
1480
+ ### PDF Already Exists Error
1481
+
1482
+ When a PDF with identical content has already been uploaded by your organization, `uploadPdfSlides()` throws a `PdfAlreadyExistsError`. The error exposes the `pdfId` of the existing record so you can use it directly without re-uploading.
1483
+
1484
+ ```typescript
1485
+ import { PdfAlreadyExistsError } from 'plato-sdk';
1486
+
1487
+ try {
1488
+ const pdfId = await client.uploadPdfSlides(file);
1489
+ } catch (error) {
1490
+ if (error instanceof PdfAlreadyExistsError) {
1491
+ console.log('PDF already exists, using existing ID:', error.pdfId);
1492
+ } else {
1493
+ console.error('Upload failed:', error.message);
1494
+ }
1495
+ }
1496
+ ```
1497
+
1498
+ ### Concurrency Limit Error
1499
+
1500
+ When the platform has reached its maximum number of simultaneous active calls, `startCall()` throws a `CallConcurrencyLimitError`. This is a platform-wide limit, not user-specific. You should catch this specifically and show the user a clear message rather than a generic error.
1501
+
1502
+ ```typescript
1503
+ import { CallConcurrencyLimitError } from 'plato-sdk';
1504
+
1505
+ const handleStartCall = async (simulationId: string) => {
1506
+ try {
1507
+ const call = await platoClient.startCall(simulationId);
1508
+
1509
+ call.on('call-start', () => setCallActive(true));
1510
+ call.on('call-end', () => setCallActive(false));
1511
+ } catch (error) {
1512
+ if (error instanceof CallConcurrencyLimitError) {
1513
+ setErrorMessage(
1514
+ 'The platform has reached its maximum number of simultaneous calls. Please try again in a moment.'
1515
+ );
1516
+ } else {
1517
+ setErrorMessage('Failed to start call. Please try again.');
1518
+ }
1519
+ }
1520
+ };
1521
+ ```
1522
+
1432
1523
  ## Support
1433
1524
 
1434
1525
  For support and questions, please contact the development team.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctchealth/plato-sdk",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "dependencies": {
5
5
  "tslib": "^2.3.0",
6
6
  "@vapi-ai/web": "2.1.8",
package/src/index.d.ts CHANGED
@@ -12,3 +12,4 @@
12
12
  * For internal use only.
13
13
  */
14
14
  export * from './lib/plato-sdk';
15
+ export { CallConcurrencyLimitError, PdfAlreadyExistsError } from './lib/utils';
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PdfAlreadyExistsError = exports.CallConcurrencyLimitError = void 0;
3
4
  const tslib_1 = require("tslib");
4
5
  /**
5
6
  * Copyright (c) 2025 ctcHealth. All rights reserved.
@@ -15,4 +16,7 @@ const tslib_1 = require("tslib");
15
16
  * For internal use only.
16
17
  */
17
18
  tslib_1.__exportStar(require("./lib/plato-sdk"), exports);
19
+ var utils_1 = require("./lib/utils");
20
+ Object.defineProperty(exports, "CallConcurrencyLimitError", { enumerable: true, get: function () { return utils_1.CallConcurrencyLimitError; } });
21
+ Object.defineProperty(exports, "PdfAlreadyExistsError", { enumerable: true, get: function () { return utils_1.PdfAlreadyExistsError; } });
18
22
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/plato-sdk/src/index.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;GAYG;AACH,0DAAgC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/plato-sdk/src/index.ts"],"names":[],"mappings":";;;;AAAA;;;;;;;;;;;;GAYG;AACH,0DAAgC;AAChC,qCAA+E;AAAtE,kHAAA,yBAAyB,OAAA;AAAE,8GAAA,qBAAqB,OAAA"}
@@ -125,10 +125,6 @@ export interface CallDTO {
125
125
  * call ID obtained
126
126
  */
127
127
  callId: string;
128
- /**
129
- * call User ID
130
- */
131
- platoUserId: string;
132
128
  /**
133
129
  * call Assistant ID
134
130
  */
@@ -245,9 +241,10 @@ export interface PresignedPost {
245
241
  * Response for requesting a PDF upload.
246
242
  */
247
243
  export interface RequestPdfUploadResponse {
248
- presignedPost: PresignedPost;
244
+ presignedPost?: PresignedPost;
249
245
  objectKey: string;
250
246
  pdfId: string;
247
+ alreadyExists?: boolean;
251
248
  }
252
249
  /**
253
250
  * Persona description within simulation briefing
@@ -327,17 +324,6 @@ export interface CheckPdfStatusResponse {
327
324
  processedBatches: number[];
328
325
  totalBatches?: number;
329
326
  }
330
- export declare enum PdfSlidesSortField {
331
- CREATED_AT = "createdAt",
332
- FILENAME = "originalFilename",
333
- TOTAL_SLIDES = "totalSlides"
334
- }
335
- export declare class PdfSlidesAnalysisQueryDto {
336
- limit?: RecordingsLimit;
337
- page?: number;
338
- sort?: SortOrder;
339
- sortBy?: PdfSlidesSortField;
340
- }
341
327
  export interface SlideAnalysis {
342
328
  slideNumber: number;
343
329
  title?: string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PdfSlidesAnalysisQueryDto = exports.PdfSlidesSortField = exports.PdfSlidesStatus = exports.RecommendationPriority = exports.CreationPhase = exports.SimulationRecordingsDto = exports.RecordingStatus = exports.SortOrder = exports.SimulationRecordingsQueryDto = exports.CreateSimulationDto = exports.ProductConfig = exports.CharacterCreateDto = exports.ContextDto = exports.ProfessionalProfileDto = exports.PersonalityAndBehaviourDto = exports.AvatarLanguage = exports.AssistantVoiceGender = exports.SegmentType = exports.PracticeType = exports.YearOfExperience = void 0;
3
+ exports.PdfSlidesStatus = exports.RecommendationPriority = exports.CreationPhase = exports.SimulationRecordingsDto = exports.RecordingStatus = exports.SortOrder = exports.SimulationRecordingsQueryDto = exports.CreateSimulationDto = exports.ProductConfig = exports.CharacterCreateDto = exports.ContextDto = exports.ProfessionalProfileDto = exports.PersonalityAndBehaviourDto = exports.AvatarLanguage = exports.AssistantVoiceGender = exports.SegmentType = exports.PracticeType = exports.YearOfExperience = void 0;
4
4
  /**
5
5
  * Copyright (c) 2025 ctcHealth. All rights reserved.
6
6
  *
@@ -159,17 +159,4 @@ var PdfSlidesStatus;
159
159
  PdfSlidesStatus["COMPLETED"] = "completed";
160
160
  PdfSlidesStatus["FAILED"] = "failed";
161
161
  })(PdfSlidesStatus || (exports.PdfSlidesStatus = PdfSlidesStatus = {}));
162
- var PdfSlidesSortField;
163
- (function (PdfSlidesSortField) {
164
- PdfSlidesSortField["CREATED_AT"] = "createdAt";
165
- PdfSlidesSortField["FILENAME"] = "originalFilename";
166
- PdfSlidesSortField["TOTAL_SLIDES"] = "totalSlides";
167
- })(PdfSlidesSortField || (exports.PdfSlidesSortField = PdfSlidesSortField = {}));
168
- class PdfSlidesAnalysisQueryDto {
169
- limit;
170
- page;
171
- sort;
172
- sortBy;
173
- }
174
- exports.PdfSlidesAnalysisQueryDto = PdfSlidesAnalysisQueryDto;
175
162
  //# sourceMappingURL=plato-intefaces.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plato-intefaces.js","sourceRoot":"","sources":["../../../../../libs/plato-sdk/src/lib/plato-intefaces.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plato-intefaces.js","sourceRoot":"","sources":["../../../../../libs/plato-sdk/src/lib/plato-intefaces.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { CallDTO, CreateSimulationDto, CreationPhase, SimulationRecordingsDto, SimulationRecordingsQueryDto, SimulationDetailsDto, RecommendationsResponseDto, PdfSlidesDto, PdfSlideDto, PdfSlidesAnalysisQueryDto, CheckPdfStatusResponse, AssistantImageDto } from './plato-intefaces';
1
+ import { CallDTO, CreateSimulationDto, CreationPhase, SimulationRecordingsDto, SimulationRecordingsQueryDto, SimulationDetailsDto, RecommendationsResponseDto, PdfSlideDto, CheckPdfStatusResponse, AssistantImageDto } from './plato-intefaces';
2
2
  export interface ApiClientConfig {
3
3
  baseUrl: string;
4
4
  jwtToken: string;
@@ -36,17 +36,19 @@ export interface CallEventMap {
36
36
  };
37
37
  'volume-level': number;
38
38
  'call-details-ready': CallDTO;
39
+ 'call-ended-reason': {
40
+ reason: string;
41
+ isInactivity: boolean;
42
+ };
39
43
  }
40
44
  export type CallEventNames = keyof CallEventMap;
41
45
  export type CallEventListener<K extends CallEventNames> = (payload: CallEventMap[K]) => void;
42
46
  export declare class PlatoApiClient {
43
47
  private config;
44
- private static readonly ACTIVE_CALL_STORAGE_KEY;
45
48
  private http;
46
49
  private eventListeners;
47
50
  private callControllerInstance?;
48
51
  private eventsAttached;
49
- private currentCallId?;
50
52
  private vapiEventNames;
51
53
  eventNames: CallEventNames[];
52
54
  constructor(config: ApiClientConfig);
@@ -79,66 +81,6 @@ export declare class PlatoApiClient {
79
81
  * Internal: Emit SDK-specific events that are not part of Vapi.
80
82
  */
81
83
  private emit;
82
- /**
83
- * Store active call state in localStorage for recovery purposes.
84
- * @private
85
- */
86
- private storeCallState;
87
- /**
88
- * Retrieve active call state from localStorage.
89
- * Validates the stored data and clears it if invalid.
90
- * @private
91
- * @returns The stored call state or null if not found or invalid
92
- */
93
- private getStoredCallState;
94
- /**
95
- * Clear active call state from localStorage.
96
- * @private
97
- */
98
- private clearCallState;
99
- /**
100
- * Check if a stored call is considered abandoned based on age.
101
- * Calls older than 5 minutes are considered abandoned.
102
- * @private
103
- * @param state The call state to check
104
- * @returns true if the call is abandoned, false otherwise
105
- */
106
- private isCallAbandoned;
107
- /**
108
- * Recover and clean up any abandoned calls from previous sessions.
109
- *
110
- * This method should be called during application initialization,
111
- * typically in ngOnInit() or useEffect(). It detects calls that were
112
- * active when the page was last refreshed and notifies the backend
113
- * to process them if they're older than 5 minutes.
114
- *
115
- * The backend endpoint is idempotent, so calling this method multiple
116
- * times for the same call is safe.
117
- *
118
- * @returns Promise<boolean> - true if an abandoned call was recovered and processed
119
- *
120
- * @example
121
- * // In Angular component
122
- * async ngOnInit(): Promise<void> {
123
- * const recovered = await this.platoClient.recoverAbandonedCall();
124
- * if (recovered) {
125
- * console.log('Recovered abandoned call from previous session');
126
- * }
127
- * }
128
- *
129
- * @example
130
- * // In React component
131
- * useEffect(() => {
132
- * platoClient.recoverAbandonedCall()
133
- * .then(recovered => {
134
- * if (recovered) {
135
- * console.log('Recovered abandoned call');
136
- * }
137
- * })
138
- * .catch(console.error);
139
- * }, []);
140
- */
141
- recoverAbandonedCall(): Promise<boolean>;
142
84
  createSimulation(createSimulationParams: CreateSimulationDto): Promise<{
143
85
  simulationId: string;
144
86
  phase: CreationPhase;
@@ -164,27 +106,19 @@ export declare class PlatoApiClient {
164
106
  * Remove all listeners for all call events.
165
107
  */
166
108
  private removeAllEventListeners;
109
+ /**
110
+ * Starts a call for the given simulation.
111
+ * Polls the backend after call-end until the call is finalized, then emits 'call-details-ready'.
112
+ */
167
113
  startCall(simulationId: string): Promise<{
168
114
  stopCall: () => void;
169
115
  callId: string;
170
- /**
171
- * Subscribe to call events for this call with strict typing.
172
- * @param event Event name
173
- * @param listener Listener function
174
- */
175
116
  on: <K extends CallEventNames>(event: K, listener: CallEventListener<K>) => void;
176
- /**
177
- * Unsubscribe from call events for this call with strict typing.
178
- * @param event Event name
179
- * @param listener Listener function
180
- */
181
117
  off: <K extends CallEventNames>(event: K, listener: CallEventListener<K>) => void;
182
118
  }>;
183
- private onCallEnded;
184
119
  private createCall;
185
120
  uploadPdfSlides(file: File | Blob): Promise<string>;
186
121
  getRecommendations(): Promise<RecommendationsResponseDto>;
187
- getSlidesAnalysis(queryParams: PdfSlidesAnalysisQueryDto): Promise<PdfSlidesDto[]>;
188
122
  getSlideAnalysis(id: string): Promise<PdfSlideDto>;
189
123
  deleteSlideAnalysis(id: string): Promise<void>;
190
124
  checkPdfStatus(id: string): Promise<CheckPdfStatusResponse>;