@jivaai/agent-chat-typescript 0.1.0 → 0.1.1

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
@@ -1,793 +1,873 @@
1
- # Jiva.ai Agent Chat - TypeScript SDK
2
-
3
- A comprehensive TypeScript SDK for integrating with Jiva.ai's agentic workflows. This library provides a simple, type-safe interface for building conversational AI applications powered by Jiva.ai's agentic workflow engine.
4
-
5
- ## Features
6
-
7
- - 🤖 **Full Agentic Workflow Integration** - Seamlessly interact with Jiva.ai's agentic workflows
8
- - 💬 **Conversational Interface** - Support for multi-turn conversations with context
9
- - 📤 **Asset Upload Support** - Upload files, text, and tables to satisfy agent requirements
10
- - 🔄 **Automatic Polling** - Handles async workflow execution with automatic polling
11
- - 📡 **Real-Time Updates** - Subscribe to live agent updates via Server-Sent Events (SSE)
12
- - 🎯 **Type-Safe** - Full TypeScript support with comprehensive type definitions
13
- - 📝 **Built-in Logging** - Configurable logging for debugging and monitoring
14
-
15
- ## Quick Start
16
-
17
- ### 1. Installation
18
-
19
- If you're using this package from npm:
20
-
21
- ```bash
22
- npm install @jivaai/agent-chat-typescript
23
- ```
24
-
25
- If you're using this package directly from the repository:
26
-
27
- ```bash
28
- cd agent-chat/typescript
29
- npm install
30
- npm run build
31
- ```
32
-
33
- ### 2. Get Your Credentials
34
-
35
- Before you can use the SDK, you'll need to obtain the following from your Jiva.ai platform project:
36
-
37
- 1. **Main Chat Workflow ID** - The workflow ID for your agent chat backend
38
- 2. **API Key** - Your API key for authentication
39
- 3. **Upload Cache Workflow IDs** - Workflow IDs for:
40
- - File Upload Cache
41
- - Text Upload Cache
42
- - Table Upload Cache
43
-
44
- These can be found in your Jiva.ai platform project settings. The upload cache workflows are typically created alongside your main chat workflow.
45
-
46
- ### 3. Create a Client Instance
47
-
48
- ```typescript
49
- import { JivaApiClient } from '@jivaai/agent-chat-typescript';
50
-
51
- const client = new JivaApiClient({
52
- // Required: Main chat workflow configuration
53
- apiKey: 'your-api-key',
54
- workflowId: 'your-workflow-id',
55
- workflowVersion: '0', // Optional, defaults to "0"
56
-
57
- // Required: Upload cache workflow IDs
58
- fileUploadCacheWorkflowId: 'file-cache-workflow-id',
59
- textUploadCacheWorkflowId: 'text-cache-workflow-id',
60
- tableUploadCacheWorkflowId: 'table-cache-workflow-id',
61
-
62
- // Optional: Upload cache versions (default to workflowVersion or "0")
63
- fileUploadCacheVersion: '0',
64
- textUploadCacheVersion: '0',
65
- tableUploadCacheVersion: '0',
66
-
67
- // Optional: Separate API keys for upload caches (default to apiKey)
68
- fileUploadCacheApiKey: 'file-cache-api-key',
69
- textUploadCacheApiKey: 'text-cache-api-key',
70
- tableUploadCacheApiKey: 'table-cache-api-key',
71
-
72
- // Optional: Custom base URLs (for testing or different environments)
73
- baseUrl: 'https://api.jiva.ai/public-api/workflow',
74
- socketBaseUrl: 'https://api.jiva.ai/public-api',
75
-
76
- // Optional: Logging configuration
77
- logging: {
78
- level: 'info', // 'debug' | 'info' | 'warn' | 'error' | 'silent'
79
- enabled: true,
80
- },
81
- });
82
- ```
83
-
84
- ### 4. Start a Conversation
85
-
86
- ```typescript
87
- // Initiate a conversation with the agent
88
- const response = await client.initiateConversation({
89
- sessionId: 'user-123-thread-1', // Unique session ID per user/thread
90
- message: 'create a professional RFQ document', // obviously, this needs to be relevant to your agent
91
- mode: 'CHAT_REQUEST',
92
- });
93
-
94
- // Handle the response
95
- if (response.error) {
96
- console.error('Error:', response.error);
97
- } else if (response.data) {
98
- const conversationData = response.data.json.default;
99
-
100
- if (conversationData.state === 'OK') {
101
- console.log('Success:', conversationData.message);
102
-
103
- // Process execution results
104
- if (conversationData.executions) {
105
- conversationData.executions.forEach((exec) => {
106
- console.log(`Execution: ${exec.response} (${exec.type})`);
107
- });
108
- }
109
- } else if (conversationData.state === 'ERROR') {
110
- console.error('Error:', response.data.errorMessages);
111
- }
112
- }
113
- ```
114
-
115
- That's it! The SDK automatically handles:
116
- - ✅ Async workflow execution (polling when state is `RUNNING`)
117
- - ✅ Error handling
118
- - ✅ Response parsing
119
-
120
- ## How the API Works
121
-
122
- ### Architecture Overview
123
-
124
- The Jiva.ai Agent Chat SDK communicates with Jiva.ai's agentic workflow engine through REST APIs and Server-Sent Events (SSE):
125
-
126
- 1. **Main Chat Workflow** - Handles conversation requests and agent interactions
127
- 2. **Upload Cache Workflows** - Store uploaded assets (files, text, tables) that agents can reference
128
- 3. **EventSource (SSE)** - Provides real-time updates during agent processing
129
-
130
- ### Request Flow
131
-
132
- ```
133
- ┌─────────────┐
134
- │ Your App │
135
- └──────┬──────┘
136
-
137
- │ 1. initiateConversation()
138
-
139
- ┌─────────────────────────┐
140
- │ JivaApiClient │
141
- │ - Validates request │
142
- │ - Sends POST request │
143
- └──────┬──────────────────┘
144
-
145
- │ 2. POST /workflow/{workflowId}/{version}/invoke
146
-
147
- ┌─────────────────────────┐
148
- │ Jiva.ai API │
149
- │ - Processes request │
150
- │ - Returns state: │
151
- │ • OK (immediate) │
152
- │ • RUNNING (async) │
153
- │ • ERROR │
154
- └──────┬──────────────────┘
155
-
156
- │ 3. If RUNNING, auto-poll
157
-
158
- ┌─────────────────────────┐
159
- │ Polling (automatic) │
160
- │ - Polls every 1s │
161
- │ - Max 30 attempts │
162
- │ - Returns when complete │
163
- └─────────────────────────┘
164
- ```
165
-
166
- ### Response States
167
-
168
- The API returns responses with different states:
169
-
170
- - **OK** - Request processed immediately, result is available
171
- - **RUNNING** - Request is being processed asynchronously (SDK automatically polls)
172
- - **PARTIAL_OK** - Partial results are available
173
- - **ERROR** - Request failed with an error
174
-
175
- ### Response Modes
176
-
177
- - **CHAT_RESPONSE** - Normal response with execution results
178
- - **SCREEN_RESPONSE** - Response indicating that assets are required (check `screens` array)
179
-
180
- ## Usage Guide
181
-
182
- ### Basic Conversation
183
-
184
- The simplest way to interact with the agent:
185
-
186
- ```typescript
187
- const response = await client.initiateConversation({
188
- sessionId: 'user-123-thread-1',
189
- message: 'Hello, what can you help me with?',
190
- mode: 'CHAT_REQUEST',
191
- });
192
-
193
- if (response.data?.json.default.state === 'OK') {
194
- console.log('Agent response:', response.data.json.default.message);
195
- }
196
- ```
197
-
198
- ### Conversations with Context
199
-
200
- Provide conversation history for context-aware interactions:
201
-
202
- ```typescript
203
- const response = await client.initiateConversation(
204
- [
205
- {
206
- sessionId: 'user-123-thread-1',
207
- message: 'RFQs are generally single-pagers',
208
- mode: 'CHAT_REQUEST',
209
- },
210
- {
211
- sessionId: 'user-123-thread-1',
212
- message: 'ok',
213
- mode: 'CHAT_RESPONSE',
214
- },
215
- {
216
- sessionId: 'user-123-thread-1',
217
- message: 'create a professional RFQ document',
218
- mode: 'CHAT_REQUEST',
219
- },
220
- ],
221
- {
222
- maxAttempts: 30, // Optional: max polling attempts (default: 30)
223
- pollInterval: 1000, // Optional: polling interval in ms (default: 1000)
224
- }
225
- );
226
- ```
227
-
228
- **Important Notes:**
229
- - All messages must have the same `sessionId`
230
- - `CHAT_REQUEST` and `CHAT_RESPONSE` must alternate in the array
231
- - The first message can be either `CHAT_REQUEST` or `CHAT_RESPONSE`
232
-
233
- ### Handling Screen Responses
234
-
235
- Sometimes the agent requires additional assets (like files) to complete a request. When this happens, the response will have `mode: 'SCREEN_RESPONSE'` and include a `screens` array.
236
-
237
- ```typescript
238
- const response = await client.initiateConversation({
239
- sessionId: 'session-123',
240
- message: 'create a professional RFQ document',
241
- mode: 'CHAT_REQUEST',
242
- });
243
-
244
- if (response.data?.json.default.mode === 'SCREEN_RESPONSE') {
245
- const screens = response.data.json.default.screens;
246
-
247
- screens?.forEach((screen) => {
248
- console.log(`Screen ${screen.nodeId}: ${screen.asset.message}`);
249
- console.log(`Asset type: ${screen.asset.type}`);
250
-
251
- if (screen.asset.type === 'FILE_UPLOAD') {
252
- // Upload file and satisfy the screen (see below)
253
- }
254
- });
255
- }
256
- ```
257
-
258
- ### Uploading Assets
259
-
260
- The SDK provides methods to upload files, text, and tables. These methods return an `assetId` that can be used to satisfy screen responses.
261
-
262
- #### Uploading a File
263
-
264
- ```typescript
265
- // In browser environments, you can upload File or Blob objects
266
- const file = new File(['file content'], 'document.pdf', {
267
- type: 'application/pdf'
268
- });
269
-
270
- const uploadResponse = await client.uploadFile(file);
271
-
272
- if (uploadResponse.data) {
273
- const assetId = uploadResponse.data.strings.default;
274
- console.log('File uploaded, assetId:', assetId);
275
- // Cache this assetId for later use with the same sessionId
276
- }
277
- ```
278
-
279
- ```typescript
280
- // In Node.js environments, provide base64 string directly
281
- const base64String = 'base64-encoded-file-content';
282
- const uploadResponse = await client.uploadFile(base64String);
283
-
284
- const assetId = uploadResponse.data?.strings.default;
285
- ```
286
-
287
- #### Uploading Text
288
-
289
- ```typescript
290
- const textResponse = await client.uploadText(
291
- 'This is the text content to upload'
292
- );
293
-
294
- const assetId = textResponse.data?.strings.default;
295
- ```
296
-
297
- #### Uploading Table Data
298
-
299
- ```typescript
300
- const tableData = [
301
- { name: 'John', age: 30, city: 'New York' },
302
- { name: 'Jane', age: 25, city: 'Boston' },
303
- { name: 'Bob', age: 35, city: 'Chicago' },
304
- ];
305
-
306
- const tableResponse = await client.uploadTable(tableData);
307
-
308
- const assetId = tableResponse.data?.strings.default;
309
- ```
310
-
311
- ### Satisfying Screen Responses
312
-
313
- After uploading assets and receiving an `assetId`, you can satisfy the screen by including `nodeId`, `field`, and `assetId` in your follow-up request:
314
-
315
- ```typescript
316
- // 1. Make initial request
317
- const response = await client.initiateConversation({
318
- sessionId: 'session-123',
319
- message: 'create a professional RFQ document',
320
- mode: 'CHAT_REQUEST',
321
- });
322
-
323
- // 2. Check for screen response
324
- if (response.data?.json.default.mode === 'SCREEN_RESPONSE') {
325
- const screen = response.data.json.default.screens?.[0];
326
-
327
- if (screen?.asset.type === 'FILE_UPLOAD') {
328
- // 3. Upload the file
329
- const file = /* get file from user */;
330
- const uploadResponse = await client.uploadFile(file);
331
-
332
- if (uploadResponse.data) {
333
- const assetId = uploadResponse.data.strings.default;
334
-
335
- // 4. Satisfy the screen with the uploaded asset
336
- const followUp = await client.initiateConversation({
337
- sessionId: 'session-123',
338
- message: 'create a professional RFQ document',
339
- mode: 'CHAT_REQUEST',
340
- nodeId: screen.nodeId,
341
- field: screen.field,
342
- assetId: assetId,
343
- });
344
- }
345
- }
346
- }
347
- ```
348
-
349
- **Important Notes:**
350
- - All three fields (`nodeId`, `field`, `assetId`) must be provided together when satisfying a screen
351
- - The `nodeId` and `field` come from the `screens` array in the `SCREEN_RESPONSE`
352
- - The `assetId` comes from uploading to File Upload Cache, Text Upload Cache, or Table Upload Cache endpoints
353
- - Asset IDs should be cached on your backend - they can be reused for the same `sessionId`
354
- - Asset semantics are session-specific: an asset for one `sessionId` may not be valid for another
355
-
356
- ### Real-Time Updates with EventSource
357
-
358
- Subscribe to real-time updates from the agent using Server-Sent Events (SSE). This allows you to receive live updates as the agent processes requests, including thinking messages, execution results, and progress updates.
359
-
360
- ```typescript
361
- // Subscribe to real-time updates for a session
362
- const es = client.subscribeToSocket(
363
- 'session-123', // Session ID
364
- {
365
- onOpen: () => {
366
- console.log('EventSource connected');
367
- },
368
- onMessage: (message) => {
369
- console.log('Message:', message.message);
370
- console.log('Types:', message.types);
371
-
372
- // Handle different message types
373
- if (message.types.includes('AGENT_THINKING')) {
374
- console.log('Agent is thinking...');
375
- } else if (message.types.includes('AGENT_COMPLETED')) {
376
- console.log('Agent completed successfully');
377
- } else if (message.types.includes('CONTENT_DELTA')) {
378
- // Streaming content
379
- process.stdout.write(message.message);
380
- } else if (message.types.includes('FINAL_RESULT')) {
381
- console.log('Final result:', message.message);
382
- }
383
- },
384
- onClose: (event) => {
385
- console.log('EventSource closed:', event.reason);
386
- },
387
- onError: (error) => {
388
- console.error('EventSource error:', error);
389
- },
390
- onReconnect: (attempt) => {
391
- console.log(`Reconnecting... (attempt ${attempt})`);
392
- },
393
- },
394
- {
395
- autoReconnect: true, // Automatically reconnect on disconnect
396
- reconnectInterval: 3000, // Wait 3 seconds between reconnection attempts
397
- maxReconnectAttempts: 10, // Maximum number of reconnection attempts
398
- }
399
- );
400
-
401
- // Close the connection when done
402
- es.close();
403
- ```
404
-
405
- #### Socket Message Types
406
-
407
- The socket can send various message types. Here are some common ones:
408
-
409
- - **AGENT_STARTED** - Agent has begun processing
410
- - **AGENT_THINKING** - Agent is analyzing and planning
411
- - **AGENT_COMPLETED** - Agent finished successfully
412
- - **AGENT_FAILED** - Agent encountered an error
413
- - **CONTENT_DELTA** - Incremental text content (streaming)
414
- - **CONTENT_COMPLETE** - Full text content block
415
- - **EXECUTION_CALL_STARTED** - Agent is invoking a pipeline
416
- - **EXECUTION_CALL_RESULT** - Result from an execution
417
- - **FINAL_RESULT** - Final output from the pipeline
418
- - **PROGRESS_UPDATE** - Progress percentage or status
419
- - **TOKEN_USAGE** - Token consumption metrics
420
- - **ERROR** - Error message with details
421
- - **KEEPALIVE** - Heartbeat to keep connection alive
422
-
423
- And many more. See the full list in the type definitions.
424
-
425
- #### Socket Options
426
-
427
- - **autoReconnect** (default: `true`) - Automatically attempt to reconnect on disconnect
428
- - **reconnectInterval** (default: `3000`) - Delay in milliseconds between reconnection attempts
429
- - **maxReconnectAttempts** (default: `10`) - Maximum number of reconnection attempts before giving up
430
-
431
- #### Example: Real-Time Chat with EventSource
432
-
433
- ```typescript
434
- // Start a conversation
435
- const response = await client.initiateConversation({
436
- sessionId: 'session-123',
437
- message: 'create a professional RFQ document',
438
- mode: 'CHAT_REQUEST',
439
- });
440
-
441
- // Subscribe to real-time updates
442
- const es = client.subscribeToSocket('session-123', {
443
- onMessage: (message) => {
444
- if (message.types.includes('CONTENT_DELTA')) {
445
- // Stream content to user
446
- updateUI(message.message);
447
- } else if (message.types.includes('AGENT_COMPLETED')) {
448
- console.log('Agent finished processing');
449
- es.close();
450
- } else if (message.types.includes('ERROR')) {
451
- console.error('Error:', message.message);
452
- es.close();
453
- }
454
- },
455
- });
456
- ```
457
-
458
- **Note:**
459
- - The EventSource URL is constructed from the `socketBaseUrl` (defaults to `https://api.jiva.ai/public-api`) and follows the pattern: `{socketBaseUrl}/workflow-chat/{workflowId}/{sessionId}`
460
- - API endpoints follow the pattern: `{baseUrl}/{workflowId}/{version}/invoke` where version defaults to "0"
461
- - For test environments, you can set custom `baseUrl` and version numbers in the client configuration
462
-
463
- ### Manual Polling
464
-
465
- If you need to manually poll for a result (e.g., for multiple IDs simultaneously), you can use the `poll()` method:
466
-
467
- ```typescript
468
- // Poll for a specific execution ID
469
- const pollResponse = await client.poll(
470
- {
471
- sessionId: 'user-123-thread-1', // Required: session ID from original request
472
- id: 'exec-456', // Required: ID from the RUNNING response
473
- mode: 'POLL_REQUEST', // Required: must be POLL_REQUEST
474
- },
475
- (data) => {
476
- // Success callback (optional)
477
- console.log('State:', data.json.default.state);
478
- if (data.json.default.logs) {
479
- console.log('Logs:', data.json.default.logs);
480
- }
481
- if (data.json.default.executions) {
482
- data.json.default.executions.forEach((exec) => {
483
- console.log(`Execution state: ${exec.output.state}`);
484
- console.log(`Output: ${exec.output.response} (${exec.output.type})`);
485
- });
486
- }
487
- },
488
- (error) => {
489
- // Error callback (optional)
490
- console.error('Error:', error);
491
- }
492
- );
493
-
494
- // Handle the response
495
- if (pollResponse.error) {
496
- console.error('Poll failed:', pollResponse.error);
497
- } else if (pollResponse.data) {
498
- const pollData = pollResponse.data.json.default;
499
-
500
- if (pollData.state === 'OK') {
501
- console.log('Processing complete!');
502
- } else if (pollData.state === 'RUNNING') {
503
- console.log('Still processing...');
504
- // Poll again after recommended 1 second delay
505
- } else if (pollData.state === 'PARTIAL_OK') {
506
- console.log('Partial results available');
507
- } else if (pollData.state === 'ERROR') {
508
- console.error('Error:', pollResponse.data.errorMessages);
509
- }
510
- }
511
- ```
512
-
513
- **Note**: Only 1 sessionId can be polled per call. If you need to poll multiple IDs, make separate API calls simultaneously. The recommended polling frequency is 1 second to avoid being blacklisted.
514
-
515
- ### Using Promises (without callbacks)
516
-
517
- All methods return promises, so you can use async/await or `.then()`:
518
-
519
- ```typescript
520
- // The methods return promises, so you can use async/await or .then()
521
- const response = await client.post({ message: 'Hello' });
522
-
523
- if (response.error) {
524
- console.error('Error:', response.error);
525
- } else {
526
- console.log('Data:', response.data);
527
- }
528
- ```
529
-
530
- ### Logging
531
-
532
- The SDK includes built-in logging with different log levels. By default, logging is enabled and uses:
533
- - **Production**: `warn` level (warnings and errors only)
534
- - **Development**: `debug` level (all messages)
535
-
536
- You can configure logging in the client initialization:
537
-
538
- ```typescript
539
- const client = new JivaApiClient({
540
- apiKey: 'your-api-key',
541
- workflowId: 'your-workflow-id',
542
- // ... other config ...
543
- logging: {
544
- level: 'debug', // 'debug' | 'info' | 'warn' | 'error' | 'silent'
545
- enabled: true, // Enable/disable logging
546
- },
547
- });
548
- ```
549
-
550
- **Log Levels:**
551
- - `debug`: Detailed information (URLs, payloads, responses) - most verbose
552
- - `info`: General flow information (method calls, state changes)
553
- - `warn`: Warnings (retries, fallbacks, timeouts)
554
- - `error`: Errors (API errors, network errors)
555
- - `silent`: No logging output
556
-
557
- **Using a Custom Logger:**
558
-
559
- You can provide your own logger implementation:
560
-
561
- ```typescript
562
- import { Logger } from '@jivaai/agent-chat-typescript';
563
-
564
- const customLogger: Logger = {
565
- debug(message: string, ...args: unknown[]): void {
566
- // Your custom debug logging
567
- },
568
- info(message: string, ...args: unknown[]): void {
569
- // Your custom info logging
570
- },
571
- warn(message: string, ...args: unknown[]): void {
572
- // Your custom warn logging
573
- },
574
- error(message: string, ...args: unknown[]): void {
575
- // Your custom error logging
576
- },
577
- };
578
-
579
- const client = new JivaApiClient({
580
- apiKey: 'your-api-key',
581
- workflowId: 'your-workflow-id',
582
- // ... other config ...
583
- logging: {
584
- logger: customLogger,
585
- level: 'info',
586
- },
587
- });
588
- ```
589
-
590
- **Disable Logging:**
591
-
592
- ```typescript
593
- const client = new JivaApiClient({
594
- apiKey: 'your-api-key',
595
- workflowId: 'your-workflow-id',
596
- // ... other config ...
597
- logging: {
598
- enabled: false, // Disable all logging
599
- },
600
- });
601
- ```
602
-
603
- ### Using Custom Base URL (for testing)
604
-
605
- ```typescript
606
- const testClient = new JivaApiClient({
607
- apiKey: 'test-api-key',
608
- workflowId: 'test-workflow-id',
609
- fileUploadCacheWorkflowId: 'test-file-cache-workflow-id',
610
- textUploadCacheWorkflowId: 'test-text-cache-workflow-id',
611
- tableUploadCacheWorkflowId: 'test-table-cache-workflow-id',
612
- baseUrl: 'https://test-api.example.com/workflow',
613
- socketBaseUrl: 'https://test-api.example.com',
614
- });
615
- ```
616
-
617
- ## Development
618
-
619
- ### Build
620
-
621
- ```bash
622
- npm run build
623
- ```
624
-
625
- This compiles TypeScript to JavaScript in the `dist/` directory.
626
-
627
- ### Test
628
-
629
- ```bash
630
- npm test
631
- ```
632
-
633
- Run tests in watch mode:
634
-
635
- ```bash
636
- npm run test:watch
637
- ```
638
-
639
- Run only end-to-end tests:
640
-
641
- ```bash
642
- npm test -- e2e.test.ts
643
- ```
644
-
645
- Run integration tests (requires local Jiva.ai instance):
646
-
647
- ```bash
648
- # Remove .skip from describe block in integration.test.ts first
649
- npm test -- integration.test.ts
650
- ```
651
-
652
- Run integration tests (they are skipped by default):
653
-
654
- ```bash
655
- # On Unix/Linux/Mac:
656
- RUN_INTEGRATION_TESTS=true npm test -- integration.test.ts
657
-
658
- # On Windows (PowerShell):
659
- $env:RUN_INTEGRATION_TESTS="true"; npm test -- integration.test.ts
660
-
661
- # On Windows (CMD):
662
- set RUN_INTEGRATION_TESTS=true && npm test -- integration.test.ts
663
- ```
664
-
665
- **Note**: Integration tests are skipped by default and require a running local Jiva.ai instance. They will only run when `RUN_INTEGRATION_TESTS=true` is explicitly set.
666
-
667
- ### Lint
668
-
669
- ```bash
670
- npm run lint
671
- ```
672
-
673
- ## Project Structure
674
-
675
- ```
676
- typescript/
677
- ├── src/ # Source code
678
- │ ├── __tests__/ # Test files
679
- │ ├── api.ts # Main API client implementation
680
- │ ├── types.ts # TypeScript type definitions
681
- │ ├── logger.ts # Logging utilities
682
- │ └── index.ts # Main entry point
683
- ├── dist/ # Compiled output (generated)
684
- ├── package.json # Dependencies and scripts
685
- ├── tsconfig.json # TypeScript configuration
686
- └── jest.config.js # Jest test configuration
687
- ```
688
-
689
- ## API Reference
690
-
691
- ### JivaApiClient
692
-
693
- Main client class for interacting with the Jiva.ai Agent Chat API.
694
-
695
- #### Constructor
696
-
697
- ```typescript
698
- new JivaApiClient(config: ApiConfig)
699
- ```
700
-
701
- #### Methods
702
-
703
- ##### `initiateConversation(request, options?, onSuccess?, onError?)`
704
-
705
- Initiates a conversation with the Jiva.ai agent.
706
-
707
- - **request**: `InitiateConversationRequest | InitiateConversationWithContext` - Single message or array of messages
708
- - **options**: `PollingOptions` (optional) - Polling configuration
709
- - **onSuccess**: `SuccessCallback<ConversationResponse>` (optional) - Success callback
710
- - **onError**: `ErrorCallback` (optional) - Error callback
711
- - **Returns**: `Promise<ApiResponse<ConversationResponse>>`
712
-
713
- ##### `poll(request, onSuccess?, onError?)`
714
-
715
- Manually polls for the status of a running conversation.
716
-
717
- - **request**: `PollRequest` - Poll request with sessionId, id, and mode
718
- - **onSuccess**: `SuccessCallback<PollResponse>` (optional) - Success callback
719
- - **onError**: `ErrorCallback` (optional) - Error callback
720
- - **Returns**: `Promise<ApiResponse<PollResponse>>`
721
-
722
- ##### `uploadFile(file, onSuccess?, onError?)`
723
-
724
- Uploads a file to the File Upload Cache.
725
-
726
- - **file**: `File | Blob | string` - File to upload (File/Blob in browser, base64 string in Node.js)
727
- - **onSuccess**: `SuccessCallback<UploadResponse>` (optional) - Success callback
728
- - **onError**: `ErrorCallback` (optional) - Error callback
729
- - **Returns**: `Promise<ApiResponse<UploadResponse>>`
730
-
731
- ##### `uploadText(text, onSuccess?, onError?)`
732
-
733
- Uploads text to the Text Upload Cache.
734
-
735
- - **text**: `string` - Text content to upload
736
- - **onSuccess**: `SuccessCallback<UploadResponse>` (optional) - Success callback
737
- - **onError**: `ErrorCallback` (optional) - Error callback
738
- - **Returns**: `Promise<ApiResponse<UploadResponse>>`
739
-
740
- ##### `uploadTable(tableData, onSuccess?, onError?)`
741
-
742
- Uploads table data to the Table Upload Cache.
743
-
744
- - **tableData**: `Record<string, unknown>[]` - Table data to upload
745
- - **onSuccess**: `SuccessCallback<UploadResponse>` (optional) - Success callback
746
- - **onError**: `ErrorCallback` (optional) - Error callback
747
- - **Returns**: `Promise<ApiResponse<UploadResponse>>`
748
-
749
- ##### `subscribeToSocket(sessionId, callbacks?, options?)`
750
-
751
- Creates a Server-Sent Events (SSE) connection to subscribe to real-time agent updates.
752
-
753
- - **sessionId**: `string` - Session ID to subscribe to
754
- - **callbacks**: `SocketCallbacks` (optional) - Event callbacks
755
- - **options**: `SocketOptions` (optional) - Socket connection options
756
- - **Returns**: `{ url: string; close: () => void; readyState: number }`
757
-
758
- ##### `get(endpoint?, onSuccess?, onError?)`
759
-
760
- Makes a GET request to the API.
761
-
762
- - **endpoint**: `string` (optional) - Endpoint path
763
- - **onSuccess**: `SuccessCallback` (optional) - Success callback
764
- - **onError**: `ErrorCallback` (optional) - Error callback
765
- - **Returns**: `Promise<ApiResponse<T>>`
766
-
767
- ##### `post(payload?, endpoint?, onSuccess?, onError?)`
768
-
769
- Makes a POST request to the API.
770
-
771
- - **payload**: `Record<string, unknown>` (optional) - JSON payload
772
- - **endpoint**: `string` (optional) - Endpoint path
773
- - **onSuccess**: `SuccessCallback` (optional) - Success callback
774
- - **onError**: `ErrorCallback` (optional) - Error callback
775
- - **Returns**: `Promise<ApiResponse<T>>`
776
-
777
- ## Type Definitions
778
-
779
- All TypeScript types are exported from the main entry point. Key types include:
780
-
781
- - `ApiConfig` - Client configuration
782
- - `InitiateConversationRequest` - Single conversation message
783
- - `InitiateConversationWithContext` - Array of conversation messages
784
- - `ConversationResponse` - Response from conversation request
785
- - `PollRequest` - Poll request payload
786
- - `PollResponse` - Poll response payload
787
- - `UploadResponse` - Upload response payload
788
- - `SocketMessage` - Real-time socket message
789
- - `SocketCallbacks` - Socket event callbacks
790
- - `SocketOptions` - Socket connection options
791
- - `Logger` - Custom logger interface
792
-
793
- See `src/types.ts` for complete type definitions.
1
+ # Jiva.ai Agent Chat - TypeScript SDK
2
+
3
+ A comprehensive TypeScript SDK for integrating with Jiva.ai's agentic workflows. This library provides a simple, type-safe interface for building conversational AI applications powered by Jiva.ai's agentic workflow engine.
4
+
5
+ ## Features
6
+
7
+ - 🤖 **Full Agentic Workflow Integration** - Seamlessly interact with Jiva.ai's agentic workflows
8
+ - 💬 **Conversational Interface** - Support for multi-turn conversations with context
9
+ - 📤 **Asset Upload Support** - Upload files, text, and tables to satisfy agent requirements
10
+ - 🔄 **Automatic Polling** - Handles async workflow execution with automatic polling
11
+ - 📡 **Real-Time Updates** - Subscribe to live agent updates via Server-Sent Events (SSE)
12
+ - 🎯 **Type-Safe** - Full TypeScript support with comprehensive type definitions
13
+ - 📝 **Built-in Logging** - Configurable logging for debugging and monitoring
14
+
15
+ ## Quick Start
16
+
17
+ ### 1. Installation
18
+
19
+ If you're using this package from npm:
20
+
21
+ ```bash
22
+ npm install @jivaai/agent-chat-typescript
23
+ ```
24
+
25
+ If you're using this package directly from the repository:
26
+
27
+ ```bash
28
+ cd agent-chat/typescript
29
+ npm install
30
+ npm run build
31
+ ```
32
+
33
+ ### 2. Get Your Credentials
34
+
35
+ Before you can use the SDK, you'll need to obtain the following from your Jiva.ai platform project:
36
+
37
+ 1. **Main Chat Workflow ID** - The workflow ID for your agent chat backend
38
+ 2. **API Key** - Your API key for authentication
39
+ 3. **Upload Cache Workflow IDs** - Workflow IDs for:
40
+ - File Upload Cache
41
+ - Text Upload Cache
42
+ - Table Upload Cache
43
+
44
+ These can be found in your Jiva.ai platform project settings. The upload cache workflows are typically created alongside your main chat workflow.
45
+
46
+ ### 3. Create a Client Instance
47
+
48
+ ```typescript
49
+ import { JivaApiClient } from '@jivaai/agent-chat-typescript';
50
+
51
+ const client = new JivaApiClient({
52
+ // Required: Main chat workflow configuration
53
+ apiKey: 'your-api-key',
54
+ workflowId: 'your-workflow-id',
55
+ workflowVersion: '0', // Optional, defaults to "0"
56
+
57
+ // Required: Upload cache workflow IDs
58
+ fileUploadCacheWorkflowId: 'file-cache-workflow-id',
59
+ textUploadCacheWorkflowId: 'text-cache-workflow-id',
60
+ tableUploadCacheWorkflowId: 'table-cache-workflow-id',
61
+
62
+ // Optional: Upload cache versions (default to workflowVersion or "0")
63
+ fileUploadCacheVersion: '0',
64
+ textUploadCacheVersion: '0',
65
+ tableUploadCacheVersion: '0',
66
+
67
+ // Optional: Separate API keys for upload caches (default to apiKey)
68
+ fileUploadCacheApiKey: 'file-cache-api-key',
69
+ textUploadCacheApiKey: 'text-cache-api-key',
70
+ tableUploadCacheApiKey: 'table-cache-api-key',
71
+
72
+ // Optional: Custom base URLs (for testing or different environments)
73
+ baseUrl: 'https://api.jiva.ai/public-api/workflow',
74
+ socketBaseUrl: 'https://api.jiva.ai/public-api',
75
+
76
+ // Optional: Logging configuration
77
+ logging: {
78
+ level: 'info', // 'debug' | 'info' | 'warn' | 'error' | 'silent'
79
+ enabled: true,
80
+ },
81
+ });
82
+ ```
83
+
84
+ ### 4. Start a Conversation
85
+
86
+ ```typescript
87
+ // Initiate a conversation with the agent
88
+ const response = await client.initiateConversation({
89
+ sessionId: 'user-123-thread-1', // Unique session ID per user/thread
90
+ message: 'create a professional RFQ document', // obviously, this needs to be relevant to your agent
91
+ mode: 'CHAT_REQUEST',
92
+ });
93
+
94
+ // Handle the response
95
+ if (response.error) {
96
+ console.error('Error:', response.error);
97
+ } else if (response.data) {
98
+ const conversationData = response.data.json.default;
99
+
100
+ if (conversationData.state === 'OK') {
101
+ console.log('Success:', conversationData.message);
102
+
103
+ // Process execution results
104
+ if (conversationData.executions) {
105
+ conversationData.executions.forEach((exec) => {
106
+ console.log(`Execution: ${exec.response} (${exec.type})`);
107
+ });
108
+ }
109
+ } else if (conversationData.state === 'ERROR') {
110
+ console.error('Error:', response.data.errorMessages);
111
+ }
112
+ }
113
+ ```
114
+
115
+ That's it! The SDK automatically handles:
116
+ - ✅ Async workflow execution (polling when state is `RUNNING`)
117
+ - ✅ Error handling
118
+ - ✅ Response parsing
119
+
120
+ ## How the API Works
121
+
122
+ ### Architecture Overview
123
+
124
+ The Jiva.ai Agent Chat SDK communicates with Jiva.ai's agentic workflow engine through REST APIs and Server-Sent Events (SSE):
125
+
126
+ 1. **Main Chat Workflow** - Handles conversation requests and agent interactions
127
+ 2. **Upload Cache Workflows** - Store uploaded assets (files, text, tables) that agents can reference
128
+ 3. **EventSource (SSE)** - Provides real-time updates during agent processing
129
+
130
+ ### Request Flow
131
+
132
+ ```
133
+ ┌─────────────┐
134
+ │ Your App │
135
+ └──────┬──────┘
136
+
137
+ │ 1. initiateConversation()
138
+
139
+ ┌─────────────────────────┐
140
+ │ JivaApiClient │
141
+ │ - Validates request │
142
+ │ - Sends POST request │
143
+ └──────┬──────────────────┘
144
+
145
+ │ 2. POST /workflow/{workflowId}/{version}/invoke
146
+
147
+ ┌─────────────────────────┐
148
+ │ Jiva.ai API │
149
+ │ - Processes request │
150
+ │ - Returns state: │
151
+ │ • OK (immediate) │
152
+ │ • RUNNING (async) │
153
+ │ • ERROR │
154
+ └──────┬──────────────────┘
155
+
156
+ │ 3. If RUNNING, auto-poll
157
+
158
+ ┌─────────────────────────┐
159
+ │ Polling (automatic) │
160
+ │ - Polls every 1s │
161
+ │ - Max 30 attempts │
162
+ │ - Returns when complete │
163
+ └─────────────────────────┘
164
+ ```
165
+
166
+ ### Response States
167
+
168
+ The API returns responses with different states:
169
+
170
+ - **OK** - Request processed immediately, result is available
171
+ - **RUNNING** - Request is being processed asynchronously (SDK automatically polls)
172
+ - **PARTIAL_OK** - Partial results are available
173
+ - **ERROR** - Request failed with an error
174
+
175
+ ### Response Modes
176
+
177
+ - **CHAT_RESPONSE** - Normal response with execution results
178
+ - **SCREEN_RESPONSE** - Response indicating that assets are required (check `screens` array)
179
+
180
+ ## Usage Guide
181
+
182
+ ### Basic Conversation
183
+
184
+ The simplest way to interact with the agent:
185
+
186
+ ```typescript
187
+ const response = await client.initiateConversation({
188
+ sessionId: 'user-123-thread-1',
189
+ message: 'Hello, what can you help me with?',
190
+ mode: 'CHAT_REQUEST',
191
+ });
192
+
193
+ if (response.data?.json.default.state === 'OK') {
194
+ console.log('Agent response:', response.data.json.default.message);
195
+ }
196
+ ```
197
+
198
+ ### Conversations with Context
199
+
200
+ Provide conversation history for context-aware interactions:
201
+
202
+ ```typescript
203
+ const response = await client.initiateConversation(
204
+ [
205
+ {
206
+ sessionId: 'user-123-thread-1',
207
+ message: 'RFQs are generally single-pagers',
208
+ mode: 'CHAT_REQUEST',
209
+ },
210
+ {
211
+ sessionId: 'user-123-thread-1',
212
+ message: 'ok',
213
+ mode: 'CHAT_RESPONSE',
214
+ },
215
+ {
216
+ sessionId: 'user-123-thread-1',
217
+ message: 'create a professional RFQ document',
218
+ mode: 'CHAT_REQUEST',
219
+ },
220
+ ],
221
+ {
222
+ maxAttempts: 30, // Optional: max polling attempts (default: 30)
223
+ pollInterval: 1000, // Optional: polling interval in ms (default: 1000)
224
+ }
225
+ );
226
+ ```
227
+
228
+ **Important Notes:**
229
+ - All messages must have the same `sessionId`
230
+ - `CHAT_REQUEST` and `CHAT_RESPONSE` must alternate in the array
231
+ - The first message can be either `CHAT_REQUEST` or `CHAT_RESPONSE`
232
+
233
+ ### Handling Screen Responses
234
+
235
+ Sometimes the agent requires additional assets (like files) to complete a request. When this happens, the response will have `mode: 'SCREEN_RESPONSE'` and include a `screens` array.
236
+
237
+ ```typescript
238
+ const response = await client.initiateConversation({
239
+ sessionId: 'session-123',
240
+ message: 'create a professional RFQ document',
241
+ mode: 'CHAT_REQUEST',
242
+ });
243
+
244
+ if (response.data?.json.default.mode === 'SCREEN_RESPONSE') {
245
+ const screens = response.data.json.default.screens;
246
+
247
+ screens?.forEach((screen) => {
248
+ console.log(`Screen ${screen.nodeId}: ${screen.asset.message}`);
249
+ console.log(`Asset type: ${screen.asset.type}`);
250
+
251
+ if (screen.asset.type === 'FILE_UPLOAD') {
252
+ // Upload file and satisfy the screen (see below)
253
+ }
254
+ });
255
+ }
256
+ ```
257
+
258
+ ### Uploading Assets
259
+
260
+ The SDK provides methods to upload files, text, and tables. These methods return an `assetId` that can be used to satisfy screen responses.
261
+
262
+ #### Uploading a File
263
+
264
+ ```typescript
265
+ // In browser environments, you can upload File or Blob objects
266
+ const file = new File(['file content'], 'document.pdf', {
267
+ type: 'application/pdf'
268
+ });
269
+
270
+ const uploadResponse = await client.uploadFile(file);
271
+
272
+ if (uploadResponse.data) {
273
+ const assetId = uploadResponse.data.strings.default;
274
+ console.log('File uploaded, assetId:', assetId);
275
+ // Cache this assetId for later use with the same sessionId
276
+ }
277
+ ```
278
+
279
+ ```typescript
280
+ // In Node.js environments, provide base64 string directly
281
+ const base64String = 'base64-encoded-file-content';
282
+ const uploadResponse = await client.uploadFile(base64String);
283
+
284
+ const assetId = uploadResponse.data?.strings.default;
285
+ ```
286
+
287
+ #### Uploading Text
288
+
289
+ ```typescript
290
+ const textResponse = await client.uploadText(
291
+ 'This is the text content to upload'
292
+ );
293
+
294
+ const assetId = textResponse.data?.strings.default;
295
+ ```
296
+
297
+ #### Uploading Table Data
298
+
299
+ ```typescript
300
+ const tableData = [
301
+ { name: 'John', age: 30, city: 'New York' },
302
+ { name: 'Jane', age: 25, city: 'Boston' },
303
+ { name: 'Bob', age: 35, city: 'Chicago' },
304
+ ];
305
+
306
+ const tableResponse = await client.uploadTable(tableData);
307
+
308
+ const assetId = tableResponse.data?.strings.default;
309
+ ```
310
+
311
+ ### Satisfying Screen Responses
312
+
313
+ After uploading assets and receiving an `assetId`, you can satisfy the screen by including `nodeId`, `field`, and `assetId` in your follow-up request:
314
+
315
+ ```typescript
316
+ // 1. Make initial request
317
+ const response = await client.initiateConversation({
318
+ sessionId: 'session-123',
319
+ message: 'create a professional RFQ document',
320
+ mode: 'CHAT_REQUEST',
321
+ });
322
+
323
+ // 2. Check for screen response
324
+ if (response.data?.json.default.mode === 'SCREEN_RESPONSE') {
325
+ const screen = response.data.json.default.screens?.[0];
326
+
327
+ if (screen?.asset.type === 'FILE_UPLOAD') {
328
+ // 3. Upload the file
329
+ const file = /* get file from user */;
330
+ const uploadResponse = await client.uploadFile(file);
331
+
332
+ if (uploadResponse.data) {
333
+ const assetId = uploadResponse.data.strings.default;
334
+
335
+ // 4. Satisfy the screen with the uploaded asset
336
+ const followUp = await client.initiateConversation({
337
+ sessionId: 'session-123',
338
+ message: 'create a professional RFQ document',
339
+ mode: 'CHAT_REQUEST',
340
+ nodeId: screen.nodeId,
341
+ field: screen.field,
342
+ assetId: assetId,
343
+ });
344
+ }
345
+ }
346
+ }
347
+ ```
348
+
349
+ **Important Notes:**
350
+ - All three fields (`nodeId`, `field`, `assetId`) must be provided together when satisfying a screen
351
+ - The `nodeId` and `field` come from the `screens` array in the `SCREEN_RESPONSE`
352
+ - The `assetId` comes from uploading to File Upload Cache, Text Upload Cache, or Table Upload Cache endpoints
353
+ - Asset IDs should be cached on your backend - they can be reused for the same `sessionId`
354
+ - Asset semantics are session-specific: an asset for one `sessionId` may not be valid for another
355
+
356
+ ### Real-Time Updates with EventSource
357
+
358
+ Subscribe to real-time updates from the agent using Server-Sent Events (SSE). This allows you to receive live updates as the agent processes requests, including thinking messages, execution results, and progress updates.
359
+
360
+ ```typescript
361
+ // Subscribe to real-time updates for a session
362
+ const es = client.subscribeToSocket(
363
+ 'session-123', // Session ID
364
+ {
365
+ onOpen: () => {
366
+ console.log('EventSource connected');
367
+ },
368
+ onMessage: (message) => {
369
+ console.log('Message:', message.message);
370
+ console.log('Types:', message.types);
371
+
372
+ // Handle different message types
373
+ if (message.types.includes('AGENT_THINKING')) {
374
+ console.log('Agent is thinking...');
375
+ } else if (message.types.includes('AGENT_COMPLETED')) {
376
+ console.log('Agent completed successfully');
377
+ } else if (message.types.includes('CONTENT_DELTA')) {
378
+ // Streaming content
379
+ process.stdout.write(message.message);
380
+ } else if (message.types.includes('FINAL_RESULT')) {
381
+ console.log('Final result:', message.message);
382
+ }
383
+ },
384
+ onClose: (event) => {
385
+ console.log('EventSource closed:', event.reason);
386
+ },
387
+ onError: (error) => {
388
+ console.error('EventSource error:', error);
389
+ },
390
+ onReconnect: (attempt) => {
391
+ console.log(`Reconnecting... (attempt ${attempt})`);
392
+ },
393
+ },
394
+ {
395
+ autoReconnect: true, // Automatically reconnect on disconnect
396
+ reconnectInterval: 3000, // Wait 3 seconds between reconnection attempts
397
+ maxReconnectAttempts: 10, // Maximum number of reconnection attempts
398
+ }
399
+ );
400
+
401
+ // Close the connection when done
402
+ es.close();
403
+ ```
404
+
405
+ #### Socket Message Types
406
+
407
+ The socket can send various message types. Here are some common ones:
408
+
409
+ - **AGENT_STARTED** - Agent has begun processing
410
+ - **AGENT_THINKING** - Agent is analyzing and planning
411
+ - **AGENT_COMPLETED** - Agent finished successfully
412
+ - **AGENT_FAILED** - Agent encountered an error
413
+ - **CONTENT_DELTA** - Incremental text content (streaming)
414
+ - **CONTENT_COMPLETE** - Full text content block
415
+ - **EXECUTION_CALL_STARTED** - Agent is invoking a pipeline
416
+ - **EXECUTION_CALL_RESULT** - Result from an execution
417
+ - **FINAL_RESULT** - Final output from the pipeline
418
+ - **PROGRESS_UPDATE** - Progress percentage or status
419
+ - **TOKEN_USAGE** - Token consumption metrics
420
+ - **ERROR** - Error message with details
421
+ - **KEEPALIVE** - Heartbeat to keep connection alive
422
+
423
+ And many more. See the full list in the type definitions.
424
+
425
+ #### Socket Options
426
+
427
+ - **autoReconnect** (default: `true`) - Automatically attempt to reconnect on disconnect
428
+ - **reconnectInterval** (default: `3000`) - Delay in milliseconds between reconnection attempts
429
+ - **maxReconnectAttempts** (default: `10`) - Maximum number of reconnection attempts before giving up
430
+
431
+ #### Example: Real-Time Chat with EventSource
432
+
433
+ ```typescript
434
+ // Start a conversation
435
+ const response = await client.initiateConversation({
436
+ sessionId: 'session-123',
437
+ message: 'create a professional RFQ document',
438
+ mode: 'CHAT_REQUEST',
439
+ });
440
+
441
+ // Subscribe to real-time updates
442
+ const es = client.subscribeToSocket('session-123', {
443
+ onMessage: (message) => {
444
+ if (message.types.includes('CONTENT_DELTA')) {
445
+ // Stream content to user
446
+ updateUI(message.message);
447
+ } else if (message.types.includes('AGENT_COMPLETED')) {
448
+ console.log('Agent finished processing');
449
+ es.close();
450
+ } else if (message.types.includes('ERROR')) {
451
+ console.error('Error:', message.message);
452
+ es.close();
453
+ }
454
+ },
455
+ });
456
+ ```
457
+
458
+ **Note:**
459
+ - The EventSource URL is constructed from the `socketBaseUrl` (defaults to `https://api.jiva.ai/public-api`) and follows the pattern: `{socketBaseUrl}/workflow-chat/{workflowId}/{sessionId}`
460
+ - API endpoints follow the pattern: `{baseUrl}/{workflowId}/{version}/invoke` where version defaults to "0"
461
+ - For test environments, you can set custom `baseUrl` and version numbers in the client configuration
462
+
463
+ ### Manual Polling
464
+
465
+ If you need to manually poll for a result (e.g., for multiple IDs simultaneously), you can use the `poll()` method:
466
+
467
+ ```typescript
468
+ // Poll for a specific execution ID
469
+ const pollResponse = await client.poll(
470
+ {
471
+ sessionId: 'user-123-thread-1', // Required: session ID from original request
472
+ id: 'exec-456', // Required: ID from the RUNNING response
473
+ mode: 'POLL_REQUEST', // Required: must be POLL_REQUEST
474
+ },
475
+ (data) => {
476
+ // Success callback (optional)
477
+ console.log('State:', data.json.default.state);
478
+ if (data.json.default.logs) {
479
+ console.log('Logs:', data.json.default.logs);
480
+ }
481
+ if (data.json.default.executions) {
482
+ data.json.default.executions.forEach((exec) => {
483
+ console.log(`Execution state: ${exec.output.state}`);
484
+ console.log(`Output: ${exec.output.response} (${exec.output.type})`);
485
+ });
486
+ }
487
+ },
488
+ (error) => {
489
+ // Error callback (optional)
490
+ console.error('Error:', error);
491
+ }
492
+ );
493
+
494
+ // Handle the response
495
+ if (pollResponse.error) {
496
+ console.error('Poll failed:', pollResponse.error);
497
+ } else if (pollResponse.data) {
498
+ const pollData = pollResponse.data.json.default;
499
+
500
+ if (pollData.state === 'OK') {
501
+ console.log('Processing complete!');
502
+ } else if (pollData.state === 'RUNNING') {
503
+ console.log('Still processing...');
504
+ // Poll again after recommended 1 second delay
505
+ } else if (pollData.state === 'PARTIAL_OK') {
506
+ console.log('Partial results available');
507
+ } else if (pollData.state === 'ERROR') {
508
+ console.error('Error:', pollResponse.data.errorMessages);
509
+ }
510
+ }
511
+ ```
512
+
513
+ **Note**: Only 1 sessionId can be polled per call. If you need to poll multiple IDs, make separate API calls simultaneously. The recommended polling frequency is 1 second to avoid being blacklisted.
514
+
515
+ ### Checking Completion Status
516
+
517
+ When polling for workflow execution results, you can use `checkCompletionStatus()` to determine if all executions within a poll response have completed. This is useful for custom polling logic where you want to check if all sub-executions are finished.
518
+
519
+ ```typescript
520
+ // Poll for a specific execution ID
521
+ const pollResponse = await client.poll({
522
+ sessionId: 'user-123-thread-1',
523
+ id: 'exec-456',
524
+ mode: 'POLL_REQUEST',
525
+ });
526
+
527
+ if (pollResponse.data) {
528
+ // Check if all executions are complete
529
+ const isComplete = client.checkCompletionStatus(pollResponse.data);
530
+
531
+ if (isComplete) {
532
+ console.log('All executions have completed');
533
+ // Process final results
534
+ } else {
535
+ console.log('Some executions are still pending');
536
+ // Continue polling
537
+ }
538
+ }
539
+ ```
540
+
541
+ **How it works:**
542
+ - Returns `true` if all executions are complete (not in `PENDING` state)
543
+ - Returns `false` if any execution is still `PENDING` or if the response structure is invalid
544
+ - Handles both response formats:
545
+ - Newer format: `json.default.data[0].executions` (array format with data property)
546
+ - Older format: `json.default.executions` (direct format)
547
+ - If no executions array is found, it considers the response complete (returns `true`)
548
+
549
+ **Example with custom polling loop:**
550
+
551
+ ```typescript
552
+ async function pollUntilComplete(sessionId: string, executionId: string) {
553
+ let isComplete = false;
554
+ let attempts = 0;
555
+ const maxAttempts = 30;
556
+
557
+ while (!isComplete && attempts < maxAttempts) {
558
+ const pollResponse = await client.poll({
559
+ sessionId,
560
+ id: executionId,
561
+ mode: 'POLL_REQUEST',
562
+ });
563
+
564
+ if (pollResponse.error) {
565
+ throw new Error(pollResponse.error);
566
+ }
567
+
568
+ if (pollResponse.data) {
569
+ isComplete = client.checkCompletionStatus(pollResponse.data);
570
+
571
+ if (!isComplete) {
572
+ // Wait before next poll
573
+ await new Promise(resolve => setTimeout(resolve, 1000));
574
+ }
575
+ }
576
+
577
+ attempts++;
578
+ }
579
+
580
+ if (!isComplete) {
581
+ throw new Error('Polling timeout: executions did not complete');
582
+ }
583
+
584
+ return pollResponse.data;
585
+ }
586
+ ```
587
+
588
+ ### Using Promises (without callbacks)
589
+
590
+ All methods return promises, so you can use async/await or `.then()`:
591
+
592
+ ```typescript
593
+ // The methods return promises, so you can use async/await or .then()
594
+ const response = await client.post({ message: 'Hello' });
595
+
596
+ if (response.error) {
597
+ console.error('Error:', response.error);
598
+ } else {
599
+ console.log('Data:', response.data);
600
+ }
601
+ ```
602
+
603
+ ### Logging
604
+
605
+ The SDK includes built-in logging with different log levels. By default, logging is enabled and uses:
606
+ - **Production**: `warn` level (warnings and errors only)
607
+ - **Development**: `debug` level (all messages)
608
+
609
+ You can configure logging in the client initialization:
610
+
611
+ ```typescript
612
+ const client = new JivaApiClient({
613
+ apiKey: 'your-api-key',
614
+ workflowId: 'your-workflow-id',
615
+ // ... other config ...
616
+ logging: {
617
+ level: 'debug', // 'debug' | 'info' | 'warn' | 'error' | 'silent'
618
+ enabled: true, // Enable/disable logging
619
+ },
620
+ });
621
+ ```
622
+
623
+ **Log Levels:**
624
+ - `debug`: Detailed information (URLs, payloads, responses) - most verbose
625
+ - `info`: General flow information (method calls, state changes)
626
+ - `warn`: Warnings (retries, fallbacks, timeouts)
627
+ - `error`: Errors (API errors, network errors)
628
+ - `silent`: No logging output
629
+
630
+ **Using a Custom Logger:**
631
+
632
+ You can provide your own logger implementation:
633
+
634
+ ```typescript
635
+ import { Logger } from '@jivaai/agent-chat-typescript';
636
+
637
+ const customLogger: Logger = {
638
+ debug(message: string, ...args: unknown[]): void {
639
+ // Your custom debug logging
640
+ },
641
+ info(message: string, ...args: unknown[]): void {
642
+ // Your custom info logging
643
+ },
644
+ warn(message: string, ...args: unknown[]): void {
645
+ // Your custom warn logging
646
+ },
647
+ error(message: string, ...args: unknown[]): void {
648
+ // Your custom error logging
649
+ },
650
+ };
651
+
652
+ const client = new JivaApiClient({
653
+ apiKey: 'your-api-key',
654
+ workflowId: 'your-workflow-id',
655
+ // ... other config ...
656
+ logging: {
657
+ logger: customLogger,
658
+ level: 'info',
659
+ },
660
+ });
661
+ ```
662
+
663
+ **Disable Logging:**
664
+
665
+ ```typescript
666
+ const client = new JivaApiClient({
667
+ apiKey: 'your-api-key',
668
+ workflowId: 'your-workflow-id',
669
+ // ... other config ...
670
+ logging: {
671
+ enabled: false, // Disable all logging
672
+ },
673
+ });
674
+ ```
675
+
676
+ ### Using Custom Base URL (for testing)
677
+
678
+ ```typescript
679
+ const testClient = new JivaApiClient({
680
+ apiKey: 'test-api-key',
681
+ workflowId: 'test-workflow-id',
682
+ fileUploadCacheWorkflowId: 'test-file-cache-workflow-id',
683
+ textUploadCacheWorkflowId: 'test-text-cache-workflow-id',
684
+ tableUploadCacheWorkflowId: 'test-table-cache-workflow-id',
685
+ baseUrl: 'https://test-api.example.com/workflow',
686
+ socketBaseUrl: 'https://test-api.example.com',
687
+ });
688
+ ```
689
+
690
+ ## Development
691
+
692
+ ### Build
693
+
694
+ ```bash
695
+ npm run build
696
+ ```
697
+
698
+ This compiles TypeScript to JavaScript in the `dist/` directory.
699
+
700
+ ### Test
701
+
702
+ ```bash
703
+ npm test
704
+ ```
705
+
706
+ Run tests in watch mode:
707
+
708
+ ```bash
709
+ npm run test:watch
710
+ ```
711
+
712
+ Run only end-to-end tests:
713
+
714
+ ```bash
715
+ npm test -- e2e.test.ts
716
+ ```
717
+
718
+ Run integration tests (requires local Jiva.ai instance):
719
+
720
+ ```bash
721
+ # Remove .skip from describe block in integration.test.ts first
722
+ npm test -- integration.test.ts
723
+ ```
724
+
725
+ Run integration tests (they are skipped by default):
726
+
727
+ ```bash
728
+ # On Unix/Linux/Mac:
729
+ RUN_INTEGRATION_TESTS=true npm test -- integration.test.ts
730
+
731
+ # On Windows (PowerShell):
732
+ $env:RUN_INTEGRATION_TESTS="true"; npm test -- integration.test.ts
733
+
734
+ # On Windows (CMD):
735
+ set RUN_INTEGRATION_TESTS=true && npm test -- integration.test.ts
736
+ ```
737
+
738
+ **Note**: Integration tests are skipped by default and require a running local Jiva.ai instance. They will only run when `RUN_INTEGRATION_TESTS=true` is explicitly set.
739
+
740
+ ### Lint
741
+
742
+ ```bash
743
+ npm run lint
744
+ ```
745
+
746
+ ## Project Structure
747
+
748
+ ```
749
+ typescript/
750
+ ├── src/ # Source code
751
+ │ ├── __tests__/ # Test files
752
+ │ ├── api.ts # Main API client implementation
753
+ │ ├── types.ts # TypeScript type definitions
754
+ │ ├── logger.ts # Logging utilities
755
+ │ └── index.ts # Main entry point
756
+ ├── dist/ # Compiled output (generated)
757
+ ├── package.json # Dependencies and scripts
758
+ ├── tsconfig.json # TypeScript configuration
759
+ └── jest.config.js # Jest test configuration
760
+ ```
761
+
762
+ ## API Reference
763
+
764
+ ### JivaApiClient
765
+
766
+ Main client class for interacting with the Jiva.ai Agent Chat API.
767
+
768
+ #### Constructor
769
+
770
+ ```typescript
771
+ new JivaApiClient(config: ApiConfig)
772
+ ```
773
+
774
+ #### Methods
775
+
776
+ ##### `initiateConversation(request, options?, onSuccess?, onError?)`
777
+
778
+ Initiates a conversation with the Jiva.ai agent.
779
+
780
+ - **request**: `InitiateConversationRequest | InitiateConversationWithContext` - Single message or array of messages
781
+ - **options**: `PollingOptions` (optional) - Polling configuration
782
+ - **onSuccess**: `SuccessCallback<ConversationResponse>` (optional) - Success callback
783
+ - **onError**: `ErrorCallback` (optional) - Error callback
784
+ - **Returns**: `Promise<ApiResponse<ConversationResponse>>`
785
+
786
+ ##### `poll(request, onSuccess?, onError?)`
787
+
788
+ Manually polls for the status of a running conversation.
789
+
790
+ - **request**: `PollRequest` - Poll request with sessionId, id, and mode
791
+ - **onSuccess**: `SuccessCallback<PollResponse>` (optional) - Success callback
792
+ - **onError**: `ErrorCallback` (optional) - Error callback
793
+ - **Returns**: `Promise<ApiResponse<PollResponse>>`
794
+
795
+ ##### `uploadFile(file, onSuccess?, onError?)`
796
+
797
+ Uploads a file to the File Upload Cache.
798
+
799
+ - **file**: `File | Blob | string` - File to upload (File/Blob in browser, base64 string in Node.js)
800
+ - **onSuccess**: `SuccessCallback<UploadResponse>` (optional) - Success callback
801
+ - **onError**: `ErrorCallback` (optional) - Error callback
802
+ - **Returns**: `Promise<ApiResponse<UploadResponse>>`
803
+
804
+ ##### `uploadText(text, onSuccess?, onError?)`
805
+
806
+ Uploads text to the Text Upload Cache.
807
+
808
+ - **text**: `string` - Text content to upload
809
+ - **onSuccess**: `SuccessCallback<UploadResponse>` (optional) - Success callback
810
+ - **onError**: `ErrorCallback` (optional) - Error callback
811
+ - **Returns**: `Promise<ApiResponse<UploadResponse>>`
812
+
813
+ ##### `uploadTable(tableData, onSuccess?, onError?)`
814
+
815
+ Uploads table data to the Table Upload Cache.
816
+
817
+ - **tableData**: `Record<string, unknown>[]` - Table data to upload
818
+ - **onSuccess**: `SuccessCallback<UploadResponse>` (optional) - Success callback
819
+ - **onError**: `ErrorCallback` (optional) - Error callback
820
+ - **Returns**: `Promise<ApiResponse<UploadResponse>>`
821
+
822
+ ##### `subscribeToSocket(sessionId, callbacks?, options?)`
823
+
824
+ Creates a Server-Sent Events (SSE) connection to subscribe to real-time agent updates.
825
+
826
+ - **sessionId**: `string` - Session ID to subscribe to
827
+ - **callbacks**: `SocketCallbacks` (optional) - Event callbacks
828
+ - **options**: `SocketOptions` (optional) - Socket connection options
829
+ - **Returns**: `{ url: string; close: () => void; readyState: number }`
830
+
831
+ ##### `get(endpoint?, onSuccess?, onError?)`
832
+
833
+ Makes a GET request to the API.
834
+
835
+ - **endpoint**: `string` (optional) - Endpoint path
836
+ - **onSuccess**: `SuccessCallback` (optional) - Success callback
837
+ - **onError**: `ErrorCallback` (optional) - Error callback
838
+ - **Returns**: `Promise<ApiResponse<T>>`
839
+
840
+ ##### `post(payload?, endpoint?, onSuccess?, onError?)`
841
+
842
+ Makes a POST request to the API.
843
+
844
+ - **payload**: `Record<string, unknown>` (optional) - JSON payload
845
+ - **endpoint**: `string` (optional) - Endpoint path
846
+ - **onSuccess**: `SuccessCallback` (optional) - Success callback
847
+ - **onError**: `ErrorCallback` (optional) - Error callback
848
+ - **Returns**: `Promise<ApiResponse<T>>`
849
+
850
+ ## Type Definitions
851
+
852
+ All TypeScript types are exported from the main entry point. Key types include:
853
+
854
+ - `ApiConfig` - Client configuration
855
+ - `InitiateConversationRequest` - Single conversation message
856
+ - `InitiateConversationWithContext` - Array of conversation messages
857
+ - `ConversationResponse` - Response from conversation request
858
+ - `PollRequest` - Poll request payload
859
+ - `PollResponse` - Poll response payload
860
+ - `UploadResponse` - Upload response payload
861
+ - `SocketMessage` - Real-time socket message
862
+ - `SocketCallbacks` - Socket event callbacks
863
+ - `SocketOptions` - Socket connection options
864
+ - `Logger` - Custom logger interface
865
+
866
+ See `src/types.ts` for complete type definitions.
867
+
868
+ # Installing on npm
869
+
870
+ ```
871
+ npm login
872
+ npm publish
873
+ ```