@kivox/client 0.1.0-beta.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 +91 -0
- package/dist/index.d.ts +806 -0
- package/dist/index.js +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# KIVOX JavaScript client
|
|
2
|
+
|
|
3
|
+
`@kivox/client` is the official JavaScript/TypeScript client for interacting with KIVOX. It provides the necessary abstractions and bindings to handle sessions, real-time events, audio, and communication with agents.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Unified client for the Kivox API
|
|
8
|
+
- Conversation and voice session management
|
|
9
|
+
- WebSockets, events, and real-time state
|
|
10
|
+
- Audio recording and playback
|
|
11
|
+
- Strongly typed contracts and types in TypeScript
|
|
12
|
+
- Framework-agnostic (Svelte, React, Angular, Vue, Vanilla, etc.)
|
|
13
|
+
|
|
14
|
+
## Documentation
|
|
15
|
+
|
|
16
|
+
<https://kivox.ju4n97.workers.dev/docs/clients/kivox-js>
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# NPM
|
|
22
|
+
npm install @kivox/client
|
|
23
|
+
|
|
24
|
+
# PNPM
|
|
25
|
+
pnpm add @kivox/client
|
|
26
|
+
|
|
27
|
+
# Yarn
|
|
28
|
+
yarn add @kivox/client
|
|
29
|
+
|
|
30
|
+
# Bun
|
|
31
|
+
bun add @kivox/client
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Basic example
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { KivoxClient } from '@kivox/client';
|
|
38
|
+
|
|
39
|
+
const kivox = new KivoxClient({
|
|
40
|
+
baseUrl: 'http://localhost:8787',
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// List agents
|
|
44
|
+
const agents = await kivox.agents.list();
|
|
45
|
+
|
|
46
|
+
// Connect to an agent
|
|
47
|
+
const session = await kivox.conversations.connect({
|
|
48
|
+
agentId: '019bb51e-e45f-75e3-b828-94fdf231711e',
|
|
49
|
+
onEvent: (event) => {
|
|
50
|
+
switch (event.type) {
|
|
51
|
+
case 'response.delta.text':
|
|
52
|
+
console.log('Text:', event.chunk);
|
|
53
|
+
break;
|
|
54
|
+
case 'response.delta.audio':
|
|
55
|
+
audioPlayer.enqueue(event.audio);
|
|
56
|
+
break;
|
|
57
|
+
case 'response.complete':
|
|
58
|
+
console.log('Response complete');
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Send a message
|
|
65
|
+
session.sendText('Hello, how can you help me?');
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Authentication
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { KivoxClient } from '@kivox/client';
|
|
72
|
+
|
|
73
|
+
const kivox = new KivoxClient({
|
|
74
|
+
baseUrl: 'http://localhost:8787',
|
|
75
|
+
headers: {
|
|
76
|
+
Authorization: 'Bearer token',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Other examples
|
|
82
|
+
|
|
83
|
+
- [alpine-chat-app](https://github.com/ekisa-team/kivox/tree/main/examples/alpine-chat-app)
|
|
84
|
+
|
|
85
|
+
## Contributing
|
|
86
|
+
|
|
87
|
+
[https://github.com/ekisa-team/kivox/blob/main/CONTRIBUTING.md](https://github.com/ekisa-team/kivox/blob/main/CONTRIBUTING.md)
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
[LICENSE](https://github.com/ekisa-team/kivox/blob/main/LICENSE)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,806 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for HTTP transport.
|
|
3
|
+
*/
|
|
4
|
+
type HttpTransportConfig = {
|
|
5
|
+
/** Base URL for all requests */
|
|
6
|
+
baseUrl: string
|
|
7
|
+
/** Optional default headers */
|
|
8
|
+
headers?: Record<string, string>
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Error thrown by HTTP transport operations.
|
|
12
|
+
*/
|
|
13
|
+
declare class HttpTransportError extends Error {
|
|
14
|
+
readonly status: number;
|
|
15
|
+
readonly statusText: string;
|
|
16
|
+
readonly body?: unknown;
|
|
17
|
+
constructor(message: string, status: number, statusText: string, body?: unknown);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Shared HTTP transport layer for REST API requests.
|
|
21
|
+
* Handles request/response cycles with automatic JSON parsing.
|
|
22
|
+
*/
|
|
23
|
+
declare class HttpTransport {
|
|
24
|
+
private readonly config;
|
|
25
|
+
constructor(config: HttpTransportConfig);
|
|
26
|
+
/**
|
|
27
|
+
* Makes an HTTP request to the specified path.
|
|
28
|
+
*
|
|
29
|
+
* @param path API path (e.g., '/agents')
|
|
30
|
+
* @param init Fetch request options
|
|
31
|
+
* @returns Parsed JSON response
|
|
32
|
+
* @throws {HttpTransportError} If request fails
|
|
33
|
+
*/
|
|
34
|
+
request<T>(path: string, init?: RequestInit): Promise<T>;
|
|
35
|
+
/**
|
|
36
|
+
* Makes a GET request.
|
|
37
|
+
*/
|
|
38
|
+
get<T>(path: string, params?: Record<string, string>): Promise<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Makes a POST request.
|
|
41
|
+
*/
|
|
42
|
+
post<T>(path: string, body?: unknown): Promise<T>;
|
|
43
|
+
/**
|
|
44
|
+
* Makes a PUT request.
|
|
45
|
+
*/
|
|
46
|
+
put<T>(path: string, body?: unknown): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Makes a PATCH request.
|
|
49
|
+
*/
|
|
50
|
+
patch<T>(path: string, body?: unknown): Promise<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Makes a DELETE request.
|
|
53
|
+
*/
|
|
54
|
+
delete<T>(path: string): Promise<T>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Paginated represents a paginated response containing items and metadata.
|
|
58
|
+
*/
|
|
59
|
+
type Paginated<T> = {
|
|
60
|
+
items: T
|
|
61
|
+
total: number
|
|
62
|
+
page: number
|
|
63
|
+
page_size: number
|
|
64
|
+
total_pages: number
|
|
65
|
+
};
|
|
66
|
+
type AgentStatus = "live" | "draft" | "archived";
|
|
67
|
+
type Agent = {
|
|
68
|
+
id: string
|
|
69
|
+
template_id: string
|
|
70
|
+
config: AgentConfig
|
|
71
|
+
blueprint: AgentBlueprint
|
|
72
|
+
status: AgentStatus
|
|
73
|
+
created_at: Date
|
|
74
|
+
updated_at: Date
|
|
75
|
+
};
|
|
76
|
+
type AgentConfig = {
|
|
77
|
+
name: string
|
|
78
|
+
description: string
|
|
79
|
+
system_prompt: string
|
|
80
|
+
language: string
|
|
81
|
+
max_session_duration_minutes: number
|
|
82
|
+
max_silence_timeout_seconds: number
|
|
83
|
+
allow_interruptions: boolean
|
|
84
|
+
};
|
|
85
|
+
type AgentBlueprint<
|
|
86
|
+
NodeType = unknown,
|
|
87
|
+
EdgeType = unknown
|
|
88
|
+
> = {
|
|
89
|
+
nodes: NodeType[]
|
|
90
|
+
edges: EdgeType[]
|
|
91
|
+
};
|
|
92
|
+
type AgentCreate = Partial<Pick<Agent, "config" | "blueprint" | "status" | "template_id">>;
|
|
93
|
+
type AgentUpdate = Partial<Pick<AgentCreate, "config" | "blueprint">>;
|
|
94
|
+
type NodeType = "CONTROL.START" | "CONTROL.DIALOG" | "CONTROL.END" | "LOGICAL.EVAL" | "FUNCTION.SET_VAR" | "FUNCTION.WEBHOOK" | "FUNCTION.EMAIL_NOTIFY" | "FUNCTION.KIBOT_NOTIFY" | "FUNCTION.TRANSFER" | "FUNCTION.TERMINATE";
|
|
95
|
+
type Node = {
|
|
96
|
+
id: string
|
|
97
|
+
type: NodeType
|
|
98
|
+
position: NodePosition
|
|
99
|
+
measured: NodeDimensions
|
|
100
|
+
data: Record<string, unknown>
|
|
101
|
+
};
|
|
102
|
+
type NodePosition = {
|
|
103
|
+
x: number
|
|
104
|
+
y: number
|
|
105
|
+
};
|
|
106
|
+
type NodeDimensions = {
|
|
107
|
+
width: number
|
|
108
|
+
height: number
|
|
109
|
+
};
|
|
110
|
+
type Edge = {
|
|
111
|
+
id: string
|
|
112
|
+
source: string
|
|
113
|
+
target: string
|
|
114
|
+
label: string
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Configuration for listing agents.
|
|
118
|
+
*/
|
|
119
|
+
type AgentListParams = {
|
|
120
|
+
/** Number of results per page */
|
|
121
|
+
limit?: number
|
|
122
|
+
/** Page number (1-indexed) */
|
|
123
|
+
page?: number
|
|
124
|
+
/** Search query */
|
|
125
|
+
search?: string
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Client for interacting with KIVOX agents.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* const agents = await kivox.agents.list({ limit: 20 });
|
|
133
|
+
* const agent = await kivox.agents.get('019bb51e-e45f-75e3-b828-94fdf231711e');
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
declare class AgentClient {
|
|
137
|
+
private readonly http;
|
|
138
|
+
constructor(http: HttpTransport);
|
|
139
|
+
/**
|
|
140
|
+
* Lists all agents with optional filtering and pagination.
|
|
141
|
+
*
|
|
142
|
+
* @param params List configuration
|
|
143
|
+
* @returns Paginated list of agents
|
|
144
|
+
*/
|
|
145
|
+
list(params?: AgentListParams): Promise<Paginated<Agent[]>>;
|
|
146
|
+
/**
|
|
147
|
+
* Lists all live agents with optional filtering and pagination.
|
|
148
|
+
*
|
|
149
|
+
* @param params List configuration
|
|
150
|
+
* @returns Paginated list of live agents
|
|
151
|
+
*/
|
|
152
|
+
listLive(params?: AgentListParams): Promise<Paginated<Agent[]>>;
|
|
153
|
+
/**
|
|
154
|
+
* Lists all draft agents with optional filtering and pagination.
|
|
155
|
+
*
|
|
156
|
+
* @param params List configuration
|
|
157
|
+
* @returns Paginated list of draft agents
|
|
158
|
+
*/
|
|
159
|
+
listDraft(params?: AgentListParams): Promise<Paginated<Agent[]>>;
|
|
160
|
+
/**
|
|
161
|
+
* Lists all archived agents with optional filtering and pagination.
|
|
162
|
+
*
|
|
163
|
+
* @param params List configuration
|
|
164
|
+
* @returns Paginated list of archived agents
|
|
165
|
+
*/
|
|
166
|
+
listArchived(params?: AgentListParams): Promise<Paginated<Agent[]>>;
|
|
167
|
+
/**
|
|
168
|
+
* Gets a single agent by ID.
|
|
169
|
+
*
|
|
170
|
+
* @param id Agent ID
|
|
171
|
+
* @returns Agent details
|
|
172
|
+
*/
|
|
173
|
+
get(id: string): Promise<Agent>;
|
|
174
|
+
/**
|
|
175
|
+
* Creates a new agent.
|
|
176
|
+
*
|
|
177
|
+
* @param data Agent data
|
|
178
|
+
* @returns Created agent
|
|
179
|
+
*/
|
|
180
|
+
create(data: AgentCreate): Promise<Agent>;
|
|
181
|
+
/**
|
|
182
|
+
* Updates an existing agent.
|
|
183
|
+
*
|
|
184
|
+
* @param id Agent ID
|
|
185
|
+
* @param data Updated agent data
|
|
186
|
+
* @returns Updated agent
|
|
187
|
+
*/
|
|
188
|
+
update(id: string, data: AgentUpdate): Promise<Agent>;
|
|
189
|
+
/**
|
|
190
|
+
* Marks an agent as live.
|
|
191
|
+
*
|
|
192
|
+
* @param id Agent ID
|
|
193
|
+
* @returns Updated agent
|
|
194
|
+
*/
|
|
195
|
+
markAsLive(id: string): Promise<Agent>;
|
|
196
|
+
/**
|
|
197
|
+
* Marks an agent as draft.
|
|
198
|
+
*
|
|
199
|
+
* @param id Agent ID
|
|
200
|
+
* @returns Updated agent
|
|
201
|
+
*/
|
|
202
|
+
markAsDraft(id: string): Promise<Agent>;
|
|
203
|
+
/**
|
|
204
|
+
* Marks an agent as archived.
|
|
205
|
+
*
|
|
206
|
+
* @param id Agent ID
|
|
207
|
+
* @returns Updated agent
|
|
208
|
+
*/
|
|
209
|
+
markAsArchived(id: string): Promise<Agent>;
|
|
210
|
+
/**
|
|
211
|
+
* Deletes an agent.
|
|
212
|
+
*
|
|
213
|
+
* @param id Agent ID
|
|
214
|
+
*/
|
|
215
|
+
delete(id: string): Promise<Agent>;
|
|
216
|
+
/**
|
|
217
|
+
* Parses a list of agents with stringified config and blueprint fields.
|
|
218
|
+
*
|
|
219
|
+
* @returns List of parsed agents.
|
|
220
|
+
*/
|
|
221
|
+
private static parseAgents;
|
|
222
|
+
/**
|
|
223
|
+
* Parses an agent with stringified config and blueprint fields.
|
|
224
|
+
*
|
|
225
|
+
* @returns Agent with parsed config and blueprint.
|
|
226
|
+
*/
|
|
227
|
+
private static parseAgent;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Configuration for WebSocket transport.
|
|
231
|
+
*/
|
|
232
|
+
type WebSocketTransportConfig = {
|
|
233
|
+
/** Base WebSocket URL */
|
|
234
|
+
baseUrl: string
|
|
235
|
+
/** Optional default headers (for protocol support) */
|
|
236
|
+
headers?: Record<string, string>
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* Shared WebSocket transport layer.
|
|
240
|
+
* Provides WebSocket connection creation.
|
|
241
|
+
*/
|
|
242
|
+
declare class WebSocketTransport {
|
|
243
|
+
private readonly config;
|
|
244
|
+
constructor(config: WebSocketTransportConfig);
|
|
245
|
+
/**
|
|
246
|
+
* Creates a WebSocket connection to the specified path.
|
|
247
|
+
*
|
|
248
|
+
* @param path WebSocket path (e.g., '/conversations/websocket')
|
|
249
|
+
* @returns Raw WebSocket instance
|
|
250
|
+
*/
|
|
251
|
+
connect(path: string): WebSocket;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Represents a handshake offer initiated by the client.
|
|
255
|
+
*/
|
|
256
|
+
type ClientSessionHandshakeOffer = {
|
|
257
|
+
type: "session.handshake.offer"
|
|
258
|
+
agent_id: string
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* Signals that the client has ended the session.
|
|
262
|
+
*/
|
|
263
|
+
type ClientSessionEnd = {
|
|
264
|
+
type: "session.end"
|
|
265
|
+
conversation_id: string
|
|
266
|
+
};
|
|
267
|
+
/**
|
|
268
|
+
* Sends a text input from the client to the server.
|
|
269
|
+
*/
|
|
270
|
+
type ClientInputText = {
|
|
271
|
+
type: "input.text"
|
|
272
|
+
conversation_id: string
|
|
273
|
+
text: string
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* Indicates that the client is starting an audio input.
|
|
277
|
+
*/
|
|
278
|
+
type ClientInputAudio = {
|
|
279
|
+
type: "input.audio"
|
|
280
|
+
conversation_id: string
|
|
281
|
+
};
|
|
282
|
+
/**
|
|
283
|
+
* Represents a continuous stream of audio data from the client.
|
|
284
|
+
*/
|
|
285
|
+
type ClientInputAudioStream = {
|
|
286
|
+
type: "input.audio.stream"
|
|
287
|
+
conversation_id: string
|
|
288
|
+
};
|
|
289
|
+
/**
|
|
290
|
+
* Signals that the client has cancelled a request.
|
|
291
|
+
*/
|
|
292
|
+
type ClientRequestCancel = {
|
|
293
|
+
type: "request.cancel"
|
|
294
|
+
conversation_id: string
|
|
295
|
+
};
|
|
296
|
+
/**
|
|
297
|
+
* Union type for all messages sent from the client to the server.
|
|
298
|
+
*/
|
|
299
|
+
type ClientMessage = ClientSessionHandshakeOffer | ClientSessionEnd | ClientInputText | ClientInputAudio | ClientInputAudioStream | ClientRequestCancel;
|
|
300
|
+
/**
|
|
301
|
+
* Sent by the server when a handshake offer is accepted.
|
|
302
|
+
*/
|
|
303
|
+
type ServerSessionHandshakeAccept = {
|
|
304
|
+
type: "session.handshake.accept"
|
|
305
|
+
agent_id: string
|
|
306
|
+
conversation_id: string
|
|
307
|
+
};
|
|
308
|
+
/**
|
|
309
|
+
* Sent by the server when a handshake offer is rejected.
|
|
310
|
+
*/
|
|
311
|
+
type ServerSessionHandshakeReject = {
|
|
312
|
+
type: "session.handshake.reject"
|
|
313
|
+
reason: string
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* Signals that the session has officially started.
|
|
317
|
+
*/
|
|
318
|
+
type ServerSessionStart = {
|
|
319
|
+
type: "session.start"
|
|
320
|
+
conversation_id: string
|
|
321
|
+
start_time: number
|
|
322
|
+
end_time: number
|
|
323
|
+
max_duration_ms: number
|
|
324
|
+
};
|
|
325
|
+
/**
|
|
326
|
+
* Signals that the server has ended the session.
|
|
327
|
+
*/
|
|
328
|
+
type ServerSessionEnd = {
|
|
329
|
+
type: "session.end"
|
|
330
|
+
conversation_id: string
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* Periodic update from the server regarding session timing.
|
|
334
|
+
*/
|
|
335
|
+
type ServerSessionTick = {
|
|
336
|
+
type: "session.tick"
|
|
337
|
+
conversation_id: string
|
|
338
|
+
max_duration_ms: number
|
|
339
|
+
remaining_time_ms: number
|
|
340
|
+
elapsed_time_ms: number
|
|
341
|
+
};
|
|
342
|
+
/**
|
|
343
|
+
* Sent when a session ends due to inactivity or exceeding max duration.
|
|
344
|
+
*/
|
|
345
|
+
type ServerSessionTimeout = {
|
|
346
|
+
type: "session.timeout"
|
|
347
|
+
conversation_id: string
|
|
348
|
+
};
|
|
349
|
+
/**
|
|
350
|
+
* Signals that the server has detected the start of speech.
|
|
351
|
+
*/
|
|
352
|
+
type ServerSpeechStart = {
|
|
353
|
+
type: "speech.start"
|
|
354
|
+
conversation_id: string
|
|
355
|
+
};
|
|
356
|
+
/**
|
|
357
|
+
* Signals that the server has detected the end of speech.
|
|
358
|
+
*/
|
|
359
|
+
type ServerSpeechEnd = {
|
|
360
|
+
type: "speech.end"
|
|
361
|
+
conversation_id: string
|
|
362
|
+
};
|
|
363
|
+
/**
|
|
364
|
+
* A partial text response chunk sent by the server.
|
|
365
|
+
*/
|
|
366
|
+
type ServerResponseDeltaText = {
|
|
367
|
+
type: "response.delta.text"
|
|
368
|
+
conversation_id: string
|
|
369
|
+
chunk: string
|
|
370
|
+
};
|
|
371
|
+
/**
|
|
372
|
+
* A partial audio response chunk sent by the server.
|
|
373
|
+
*/
|
|
374
|
+
type ServerResponseDeltaAudio = {
|
|
375
|
+
type: "response.delta.audio"
|
|
376
|
+
conversation_id: string
|
|
377
|
+
size: number
|
|
378
|
+
audio: Blob
|
|
379
|
+
};
|
|
380
|
+
/**
|
|
381
|
+
* Signals that the full response (text or audio) has been delivered.
|
|
382
|
+
*/
|
|
383
|
+
type ServerResponseComplete = {
|
|
384
|
+
type: "response.complete"
|
|
385
|
+
conversation_id: string
|
|
386
|
+
};
|
|
387
|
+
/**
|
|
388
|
+
* Sent when an ongoing response is cancelled successfully.
|
|
389
|
+
*/
|
|
390
|
+
type ServerResponseCancel = {
|
|
391
|
+
type: "response.cancel"
|
|
392
|
+
conversation_id: string
|
|
393
|
+
};
|
|
394
|
+
/**
|
|
395
|
+
* Sent when an error occurs during processing a request.
|
|
396
|
+
*/
|
|
397
|
+
type ServerResponseError = {
|
|
398
|
+
type: "response.error"
|
|
399
|
+
conversation_id: string
|
|
400
|
+
code: string
|
|
401
|
+
message: string
|
|
402
|
+
};
|
|
403
|
+
/**
|
|
404
|
+
* Union type for all messages sent from the server to the client.
|
|
405
|
+
*/
|
|
406
|
+
type ServerMessage = ServerSessionHandshakeAccept | ServerSessionHandshakeReject | ServerSessionStart | ServerSessionEnd | ServerSessionTick | ServerSessionTimeout | ServerSpeechStart | ServerSpeechEnd | ServerResponseDeltaText | ServerResponseDeltaAudio | ServerResponseComplete | ServerResponseCancel | ServerResponseError;
|
|
407
|
+
/**
|
|
408
|
+
* Union type for all messages sent from the client to the server before the session is established.
|
|
409
|
+
*/
|
|
410
|
+
type ServerConnectionMessage = ServerSessionHandshakeAccept | ServerSessionHandshakeReject | ServerSessionStart;
|
|
411
|
+
/**
|
|
412
|
+
* Union type for all messages sent from the server to the client during the session lifecycle.
|
|
413
|
+
*/
|
|
414
|
+
type ServerSessionLifecycleMessage = ServerSessionEnd | ServerSessionTick | ServerSessionTimeout;
|
|
415
|
+
/**
|
|
416
|
+
* Union type for all messages sent from the server to the client during the session activity.
|
|
417
|
+
*/
|
|
418
|
+
type ServerSessionActivityMessage = ServerSpeechStart | ServerSpeechEnd | ServerResponseDeltaText | ServerResponseDeltaAudio | ServerResponseComplete | ServerResponseCancel | ServerResponseError;
|
|
419
|
+
/**
|
|
420
|
+
* Synthetic event emitted when the connection to the server is lost.
|
|
421
|
+
*/
|
|
422
|
+
type SessionConnectionLostEvent = {
|
|
423
|
+
type: "session.connection.lost"
|
|
424
|
+
conversation_id: string
|
|
425
|
+
reason: "socket_closed" | "socket_error"
|
|
426
|
+
};
|
|
427
|
+
/**
|
|
428
|
+
* Events emitted during an active session
|
|
429
|
+
*
|
|
430
|
+
* @remarks
|
|
431
|
+
* Connection messages are handled internally during connection establishment
|
|
432
|
+
* and are not exposed through the session's `onEvent` callback.
|
|
433
|
+
*/
|
|
434
|
+
type ServerSessionEvent = ServerSessionLifecycleMessage | ServerSessionActivityMessage | SessionConnectionLostEvent;
|
|
435
|
+
/**
|
|
436
|
+
* Error thrown by the transport layer.
|
|
437
|
+
*/
|
|
438
|
+
declare class ConversationTransportError extends Error {
|
|
439
|
+
readonly code: string;
|
|
440
|
+
constructor(message: string, code?: string);
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Low-level WebSocket transport for conversation protocol.
|
|
444
|
+
* Handles connection lifecycle and binary/JSON message routing.
|
|
445
|
+
*/
|
|
446
|
+
declare class ConversationTransport {
|
|
447
|
+
private;
|
|
448
|
+
private readonly _ws;
|
|
449
|
+
private _closed;
|
|
450
|
+
private _onMessage;
|
|
451
|
+
private _onBinary;
|
|
452
|
+
private _onError;
|
|
453
|
+
private _onClose;
|
|
454
|
+
constructor(_ws: WebSocket);
|
|
455
|
+
/**
|
|
456
|
+
* Waits for WebSocket to open.
|
|
457
|
+
* @throws {ConversationTransportError} If already connected or connection fails
|
|
458
|
+
*/
|
|
459
|
+
connect(): Promise<void>;
|
|
460
|
+
/**
|
|
461
|
+
* Sends a JSON message to the server.
|
|
462
|
+
* @throws {ConversationTransportError} If not connected
|
|
463
|
+
*/
|
|
464
|
+
send(message: ClientMessage): void;
|
|
465
|
+
/**
|
|
466
|
+
* Sends binary data (audio) to the server.
|
|
467
|
+
* @throws {ConversationTransportError} If not connected
|
|
468
|
+
*/
|
|
469
|
+
sendBinary(data: Blob): Promise<void>;
|
|
470
|
+
/**
|
|
471
|
+
* Registers a callback for incoming JSON messages.
|
|
472
|
+
*/
|
|
473
|
+
onMessage(handler: (msg: ServerMessage) => void): void;
|
|
474
|
+
/**
|
|
475
|
+
* Registers a callback for incoming binary data.
|
|
476
|
+
*/
|
|
477
|
+
onBinary(handler: (blob: Blob) => void): void;
|
|
478
|
+
/**
|
|
479
|
+
* Registers a callback for connection errors.
|
|
480
|
+
*/
|
|
481
|
+
onError(handler: (error: Error) => void): void;
|
|
482
|
+
/**
|
|
483
|
+
* Registers a callback for connection closure.
|
|
484
|
+
*/
|
|
485
|
+
onClose(handler: () => void): void;
|
|
486
|
+
/**
|
|
487
|
+
* Closes the WebSocket connection and cleans up resources.
|
|
488
|
+
*/
|
|
489
|
+
close(): void;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Configuration for a conversation session.
|
|
493
|
+
*/
|
|
494
|
+
type ConversationSessionConfig = {
|
|
495
|
+
/**
|
|
496
|
+
* Event handler for all server messages.
|
|
497
|
+
*
|
|
498
|
+
* @remarks
|
|
499
|
+
* Important: `response.delta.audio` events combine the audio `Blob` and the metadata.
|
|
500
|
+
*/
|
|
501
|
+
onEvent?: (event: ServerSessionEvent) => void
|
|
502
|
+
};
|
|
503
|
+
/**
|
|
504
|
+
* Represents an active conversation session with a KIVOX agent.
|
|
505
|
+
* Provides methods to send messages and audio, and a callback to handle all server events.
|
|
506
|
+
*/
|
|
507
|
+
declare class ConversationSession {
|
|
508
|
+
private;
|
|
509
|
+
private _transport;
|
|
510
|
+
private _conversationId;
|
|
511
|
+
private _maxDurationMs;
|
|
512
|
+
private _startTime;
|
|
513
|
+
private _endTime;
|
|
514
|
+
private _closed;
|
|
515
|
+
private _pendingAudioMetadata;
|
|
516
|
+
private _onEvent;
|
|
517
|
+
/** The unique conversation identifier */
|
|
518
|
+
get conversationId(): string;
|
|
519
|
+
/** Maximum session duration in milliseconds */
|
|
520
|
+
get maxDurationMs(): number;
|
|
521
|
+
/** Unix timestamp when session started */
|
|
522
|
+
get startTime(): number;
|
|
523
|
+
/** Unix timestamp when session will end */
|
|
524
|
+
get endTime(): number;
|
|
525
|
+
/** Whether the session has been closed */
|
|
526
|
+
get closed(): boolean;
|
|
527
|
+
constructor(transport: ConversationTransport, conversationId: string, maxDurationMs: number, startTime: number, endTime: number, config: ConversationSessionConfig);
|
|
528
|
+
/**
|
|
529
|
+
* Sends a text message to the agent.
|
|
530
|
+
* @param text The message text to send
|
|
531
|
+
*/
|
|
532
|
+
sendText(text: string): void;
|
|
533
|
+
/**
|
|
534
|
+
* Sends a complete audio message to the agent.
|
|
535
|
+
* @param audio Audio blob to send
|
|
536
|
+
*/
|
|
537
|
+
sendAudio(audio: Blob): void;
|
|
538
|
+
/**
|
|
539
|
+
* Streams an audio chunk to the agent (for real-time audio input).
|
|
540
|
+
* @param chunk Audio chunk to stream
|
|
541
|
+
*/
|
|
542
|
+
streamAudio(chunk: Blob): void;
|
|
543
|
+
/**
|
|
544
|
+
* Requests the session to be cancelled.
|
|
545
|
+
* The 'session.cancel' event will be triggered when complete.
|
|
546
|
+
*/
|
|
547
|
+
cancelRequest(): void;
|
|
548
|
+
/**
|
|
549
|
+
* Requests the session to end gracefully.
|
|
550
|
+
* The 'session.end' event will be triggered when complete.
|
|
551
|
+
*/
|
|
552
|
+
end(): void;
|
|
553
|
+
/**
|
|
554
|
+
* Immediately closes the session and transport.
|
|
555
|
+
* No further events will be received.
|
|
556
|
+
*/
|
|
557
|
+
close(): void;
|
|
558
|
+
}
|
|
559
|
+
type Conversation = {
|
|
560
|
+
id: string
|
|
561
|
+
agent_id: string
|
|
562
|
+
started_at: Date
|
|
563
|
+
ended_at?: Date
|
|
564
|
+
};
|
|
565
|
+
/**
|
|
566
|
+
* Configuration for listing conversations.
|
|
567
|
+
*/
|
|
568
|
+
type ConversationListParams = {
|
|
569
|
+
/** Agent ID to filter by */
|
|
570
|
+
agentId: string
|
|
571
|
+
/** Number of results per page */
|
|
572
|
+
limit?: number
|
|
573
|
+
/** Page number (1-indexed) */
|
|
574
|
+
page?: number
|
|
575
|
+
};
|
|
576
|
+
/**
|
|
577
|
+
* Extended configuration for the connect method.
|
|
578
|
+
*/
|
|
579
|
+
type ConversationConnectParams = ConversationSessionConfig & {
|
|
580
|
+
/** Agent ID to connect to */
|
|
581
|
+
agentId: string
|
|
582
|
+
/**
|
|
583
|
+
* Optional callback for connection events.
|
|
584
|
+
* Called during connection establishment, before the session is created.
|
|
585
|
+
*/
|
|
586
|
+
onConnection?: (event: ServerConnectionMessage) => void
|
|
587
|
+
};
|
|
588
|
+
/**
|
|
589
|
+
* Client for managing conversations and establishing sessions.
|
|
590
|
+
*
|
|
591
|
+
* @example
|
|
592
|
+
* ```ts
|
|
593
|
+
* // List past conversations
|
|
594
|
+
* const conversations = await kivox.conversations.list();
|
|
595
|
+
*
|
|
596
|
+
* // Connect to an agent
|
|
597
|
+
* const session = await kivox.conversations.connect({
|
|
598
|
+
* agentId: 'agent-123',
|
|
599
|
+
* onEvent: (event) => {
|
|
600
|
+
* switch (event.type) {
|
|
601
|
+
* case 'response.delta.text':
|
|
602
|
+
* console.log(event.chunk);
|
|
603
|
+
* break;
|
|
604
|
+
* case 'response.delta.audio':
|
|
605
|
+
* audioPlayer.enqueue(event.audio);
|
|
606
|
+
* break;
|
|
607
|
+
* }
|
|
608
|
+
* }
|
|
609
|
+
* });
|
|
610
|
+
*
|
|
611
|
+
* session.sendText('Hello!');
|
|
612
|
+
* ```
|
|
613
|
+
*/
|
|
614
|
+
declare class ConversationClient {
|
|
615
|
+
private readonly http;
|
|
616
|
+
private readonly ws;
|
|
617
|
+
constructor(http: HttpTransport, ws: WebSocketTransport);
|
|
618
|
+
/**
|
|
619
|
+
* Lists conversations with optional filtering and pagination.
|
|
620
|
+
*
|
|
621
|
+
* @param params List configuration
|
|
622
|
+
* @returns Paginated list of conversations
|
|
623
|
+
*/
|
|
624
|
+
list(params: ConversationListParams): Promise<Paginated<Conversation[]>>;
|
|
625
|
+
/**
|
|
626
|
+
* Gets a single conversation by ID.
|
|
627
|
+
*
|
|
628
|
+
* @param id Conversation ID
|
|
629
|
+
* @returns Conversation details
|
|
630
|
+
*/
|
|
631
|
+
get(id: string): Promise<Conversation>;
|
|
632
|
+
/**
|
|
633
|
+
* Connects to an agent and establishes a conversation session.
|
|
634
|
+
*
|
|
635
|
+
* @param params Connection configuration
|
|
636
|
+
* @returns Active conversation session
|
|
637
|
+
* @throws {Error} If handshake fails or connection is lost
|
|
638
|
+
*/
|
|
639
|
+
connect(params: ConversationConnectParams): Promise<ConversationSession>;
|
|
640
|
+
}
|
|
641
|
+
type MessageRole = "system" | "user" | "assistant";
|
|
642
|
+
type Message = {
|
|
643
|
+
id: string
|
|
644
|
+
conversation_id: string
|
|
645
|
+
role: MessageRole
|
|
646
|
+
content: string
|
|
647
|
+
created_at: Date
|
|
648
|
+
};
|
|
649
|
+
/**
|
|
650
|
+
* Configuration for listing messages.
|
|
651
|
+
*/
|
|
652
|
+
type MessageListParams = {
|
|
653
|
+
/** Conversation ID to filter by */
|
|
654
|
+
conversationId?: string
|
|
655
|
+
/** Number of results per page */
|
|
656
|
+
limit?: number
|
|
657
|
+
/** Page number (1-indexed) */
|
|
658
|
+
page?: number
|
|
659
|
+
};
|
|
660
|
+
/**
|
|
661
|
+
* Client for interacting with conversation messages.
|
|
662
|
+
*
|
|
663
|
+
* @example
|
|
664
|
+
* ```ts
|
|
665
|
+
* const messages = await kivox.messages.list({
|
|
666
|
+
* conversationId: 'conv-123'
|
|
667
|
+
* });
|
|
668
|
+
* ```
|
|
669
|
+
*/
|
|
670
|
+
declare class MessageClient {
|
|
671
|
+
private readonly http;
|
|
672
|
+
constructor(http: HttpTransport);
|
|
673
|
+
/**
|
|
674
|
+
* Lists messages with optional filtering and pagination.
|
|
675
|
+
*
|
|
676
|
+
* @param params List configuration
|
|
677
|
+
* @returns Paginated list of messages
|
|
678
|
+
*/
|
|
679
|
+
list(params?: MessageListParams): Promise<Paginated<Message[]>>;
|
|
680
|
+
/**
|
|
681
|
+
* Gets a single message by ID.
|
|
682
|
+
*
|
|
683
|
+
* @param id Message ID
|
|
684
|
+
* @returns Message details
|
|
685
|
+
*/
|
|
686
|
+
get(id: string): Promise<Message>;
|
|
687
|
+
}
|
|
688
|
+
type Template = {
|
|
689
|
+
id: string
|
|
690
|
+
name: string
|
|
691
|
+
description?: string
|
|
692
|
+
blueprint: AgentBlueprint
|
|
693
|
+
created_at: Date
|
|
694
|
+
updated_at: Date
|
|
695
|
+
};
|
|
696
|
+
type TemplateCreate = Pick<Template, "name" | "description" | "blueprint">;
|
|
697
|
+
type TemplateUpdate = Partial<TemplateCreate>;
|
|
698
|
+
/**
|
|
699
|
+
* Configuration for listing templates.
|
|
700
|
+
*/
|
|
701
|
+
type TemplateListParams = {
|
|
702
|
+
/** Number of results per page */
|
|
703
|
+
limit?: number
|
|
704
|
+
/** Page number (1-indexed) */
|
|
705
|
+
page?: number
|
|
706
|
+
};
|
|
707
|
+
/**
|
|
708
|
+
* Client for interacting with KIVOX templates.
|
|
709
|
+
*
|
|
710
|
+
* @example
|
|
711
|
+
* ```ts
|
|
712
|
+
* const templates = await kivox.templates.list();
|
|
713
|
+
* const template = await kivox.templates.get('template-123');
|
|
714
|
+
* ```
|
|
715
|
+
*/
|
|
716
|
+
declare class TemplateClient {
|
|
717
|
+
private readonly http;
|
|
718
|
+
constructor(http: HttpTransport);
|
|
719
|
+
/**
|
|
720
|
+
* Lists all templates with optional filtering and pagination.
|
|
721
|
+
*
|
|
722
|
+
* @param params List configuration
|
|
723
|
+
* @returns Paginated list of templates
|
|
724
|
+
*/
|
|
725
|
+
list(params?: TemplateListParams): Promise<Paginated<Template[]>>;
|
|
726
|
+
/**
|
|
727
|
+
* Gets a single template by ID.
|
|
728
|
+
*
|
|
729
|
+
* @param id Template ID
|
|
730
|
+
* @returns Template details
|
|
731
|
+
*/
|
|
732
|
+
get(id: string): Promise<Template>;
|
|
733
|
+
/**
|
|
734
|
+
* Creates a new template.
|
|
735
|
+
*
|
|
736
|
+
* @param data Template data
|
|
737
|
+
* @returns Created template
|
|
738
|
+
*/
|
|
739
|
+
create(data: TemplateCreate): Promise<Template>;
|
|
740
|
+
/**
|
|
741
|
+
* Updates an existing template.
|
|
742
|
+
*
|
|
743
|
+
* @param id Template ID
|
|
744
|
+
* @param data Updated template data
|
|
745
|
+
* @returns Updated template
|
|
746
|
+
*/
|
|
747
|
+
update(id: string, data: TemplateUpdate): Promise<Template>;
|
|
748
|
+
/**
|
|
749
|
+
* Deletes a template.
|
|
750
|
+
*
|
|
751
|
+
* @param id Template ID
|
|
752
|
+
*/
|
|
753
|
+
delete(id: string): Promise<void>;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Configuration for the Kivox client.
|
|
757
|
+
*/
|
|
758
|
+
type KivoxConfig = {
|
|
759
|
+
/**
|
|
760
|
+
* Base URL of your self-hosted KIVOX instance.
|
|
761
|
+
* @example 'http://localhost:8787'
|
|
762
|
+
* @example 'https://api.kivox.io'
|
|
763
|
+
*/
|
|
764
|
+
baseUrl: string
|
|
765
|
+
/**
|
|
766
|
+
* Optional headers to include with all requests.
|
|
767
|
+
* @example { Authorization: 'Bearer token' }
|
|
768
|
+
*/
|
|
769
|
+
headers?: Record<string, string>
|
|
770
|
+
};
|
|
771
|
+
/**
|
|
772
|
+
* Main KIVOX client.
|
|
773
|
+
* Provides unified access to all KIVOX resources.
|
|
774
|
+
*
|
|
775
|
+
* @example
|
|
776
|
+
* ```ts
|
|
777
|
+
* import { KivoxClient } from '@kivox/client';
|
|
778
|
+
*
|
|
779
|
+
* const kivox = new KivoxClient({
|
|
780
|
+
* baseUrl: 'http://localhost:8787',
|
|
781
|
+
* });
|
|
782
|
+
*
|
|
783
|
+
* // List agents
|
|
784
|
+
* const agents = await kivox.agents.list();
|
|
785
|
+
*
|
|
786
|
+
* // Start a conversation
|
|
787
|
+
* const session = await kivox.conversations.connect({
|
|
788
|
+
* agentId: '019bb51e-e45f-75e3-b828-94fdf231711e',
|
|
789
|
+
* onEvent: (event) => {
|
|
790
|
+
* console.log(event);
|
|
791
|
+
* }
|
|
792
|
+
* });
|
|
793
|
+
* ```
|
|
794
|
+
*/
|
|
795
|
+
declare class KivoxClient {
|
|
796
|
+
/** Agent resource client */
|
|
797
|
+
readonly agents: AgentClient;
|
|
798
|
+
/** Conversation resource client */
|
|
799
|
+
readonly conversations: ConversationClient;
|
|
800
|
+
/** Template resource client */
|
|
801
|
+
readonly templates: TemplateClient;
|
|
802
|
+
/** Message resource client */
|
|
803
|
+
readonly messages: MessageClient;
|
|
804
|
+
constructor(config: KivoxConfig);
|
|
805
|
+
}
|
|
806
|
+
export { TemplateUpdate, TemplateCreate, Template, SessionConnectionLostEvent, ServerSpeechStart, ServerSpeechEnd, ServerSessionTimeout, ServerSessionTick, ServerSessionStart, ServerSessionLifecycleMessage, ServerSessionHandshakeReject, ServerSessionHandshakeAccept, ServerSessionEvent, ServerSessionEnd, ServerSessionActivityMessage, ServerResponseError, ServerResponseDeltaText, ServerResponseDeltaAudio, ServerResponseComplete, ServerResponseCancel, ServerMessage, ServerConnectionMessage, Paginated, NodeType, NodePosition, NodeDimensions, Node, MessageRole, Message, KivoxConfig, KivoxClient, HttpTransportError, Edge, ConversationTransportError, ConversationSessionConfig, ConversationSession, Conversation, ClientSessionHandshakeOffer, ClientSessionEnd, ClientRequestCancel, ClientMessage, ClientInputText, ClientInputAudioStream, ClientInputAudio, AgentUpdate, AgentStatus, AgentCreate, AgentConfig, AgentBlueprint, Agent };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class J{http;constructor(x){this.http=x}async list(x={}){let K={limit:(x.limit??10).toString(),page:(x.page??1).toString()};if(x.search)K.search=x.search;let B=await this.http.get("/agents",K);return{...B,items:J.parseAgents(B.items)}}async listLive(x={}){let K={limit:(x.limit??10).toString(),page:(x.page??1).toString()};if(x.search)K.search=x.search;let B=await this.http.get("/agents/live",K);return{...B,items:J.parseAgents(B.items)}}async listDraft(x={}){let K={limit:(x.limit??10).toString(),page:(x.page??1).toString()};if(x.search)K.search=x.search;let B=await this.http.get("/agents/draft",K);return{...B,items:J.parseAgents(B.items)}}async listArchived(x={}){let K={limit:(x.limit??10).toString(),page:(x.page??1).toString()};if(x.search)K.search=x.search;let B=await this.http.get("/agents/archived",K);return{...B,items:J.parseAgents(B.items)}}async get(x){let K=await this.http.get(`/agents/${x}`);return J.parseAgent(K)}async create(x){let K=await this.http.post("/agents",x);return J.parseAgent(K)}async update(x,K){let B=await this.http.put(`/agents/${x}`,K);return J.parseAgent(B)}async markAsLive(x){let K=await this.http.patch(`/agents/${x}/live`);return J.parseAgent(K)}async markAsDraft(x){let K=await this.http.patch(`/agents/${x}/draft`);return J.parseAgent(K)}async markAsArchived(x){let K=await this.http.patch(`/agents/${x}/archived`);return J.parseAgent(K)}async delete(x){let K=await this.http.delete(`/agents/${x}`);return J.parseAgent(K)}static parseAgents(x){return x.map(J.parseAgent)}static parseAgent(x){return{...x,config:JSON.parse(x.config),blueprint:JSON.parse(x.blueprint)}}}class _{_transport;_conversationId;_maxDurationMs;_startTime;_endTime;_closed=!1;_pendingAudioMetadata=null;_onEvent;get conversationId(){return this._conversationId}get maxDurationMs(){return this._maxDurationMs}get startTime(){return this._startTime}get endTime(){return this._endTime}get closed(){return this._closed}constructor(x,K,B,F,Q,Y){this._transport=x,this._conversationId=K,this._maxDurationMs=B,this._startTime=F,this._endTime=Q,this._onEvent=Y.onEvent,this.#x()}sendText(x){if(this._closed){console.warn("Cannot send text: session is closed");return}this._transport.send({type:"input.text",conversation_id:this._conversationId,text:x})}sendAudio(x){if(this._closed){console.warn("Cannot send audio: session is closed");return}this._transport.send({type:"input.audio",conversation_id:this._conversationId}),this._transport.sendBinary(x)}streamAudio(x){if(this._closed){console.warn("Cannot stream audio: session is closed");return}this._transport.send({type:"input.audio.stream",conversation_id:this._conversationId}),this._transport.sendBinary(x)}cancelRequest(){if(this._closed){console.warn("Cannot cancel session: session is closed");return}this._transport.send({type:"request.cancel",conversation_id:this._conversationId})}end(){if(this._closed){console.warn("Cannot end session: session is closed");return}this._transport.send({type:"session.end",conversation_id:this._conversationId})}close(){if(this._closed)return;this._closed=!0,this._transport.close()}#x(){this._transport.onMessage((x)=>{let K=x;if(K.type==="response.delta.audio"){this._pendingAudioMetadata={conversation_id:K.conversation_id,size:K.size};return}if(K.type==="session.end"||K.type==="session.timeout"||K.type==="session.connection.lost")this._closed=!0;this._onEvent?.(K)}),this._transport.onBinary((x)=>{if(this._pendingAudioMetadata){let K={type:"response.delta.audio",conversation_id:this._pendingAudioMetadata.conversation_id,size:this._pendingAudioMetadata.size,audio:x};this._pendingAudioMetadata=null,this._onEvent?.(K)}}),this._transport.onClose(()=>{if(this._closed)return;this._closed=!0,this._onEvent?.({type:"session.connection.lost",conversation_id:this._conversationId,reason:"socket_closed"})}),this._transport.onError(()=>{if(this._closed)return;this._closed=!0,this._onEvent?.({type:"session.connection.lost",conversation_id:this._conversationId,reason:"socket_error"})})}}class Z extends Error{code;constructor(x,K="TRANSPORT_ERROR"){super(x);this.code=K;this.name="ConversationTransportError"}}class ${_ws;_closed=!1;_onMessage=null;_onBinary=null;_onError=null;_onClose=null;constructor(x){this._ws=x}async connect(){if(this._ws.readyState===WebSocket.OPEN)throw new Z("Already connected","ALREADY_CONNECTED");if(this._ws.readyState===WebSocket.CLOSING||this._ws.readyState===WebSocket.CLOSED)throw new Z("Socket is closing or closed","SOCKET_CLOSED");return new Promise((x,K)=>{let B=()=>{this._ws.removeEventListener("open",B),this._ws.removeEventListener("error",F),this.#x(),x()},F=()=>{this._ws.removeEventListener("open",B),this._ws.removeEventListener("error",F),K(new Z("Connection failed","CONNECTION_FAILED"))};this._ws.addEventListener("open",B),this._ws.addEventListener("error",F)})}send(x){if(this._ws.readyState!==WebSocket.OPEN)throw new Z("Not connected","NOT_CONNECTED");this._ws.send(JSON.stringify(x))}async sendBinary(x){if(this._ws.readyState!==WebSocket.OPEN)throw new Z("Not connected","NOT_CONNECTED");let K=await x.arrayBuffer();this._ws.send(K)}onMessage(x){this._onMessage=x}onBinary(x){this._onBinary=x}onError(x){this._onError=x}onClose(x){this._onClose=x}close(){if(this._closed)return;if(this._closed=!0,this._ws.readyState===WebSocket.OPEN||this._ws.readyState===WebSocket.CONNECTING)this._ws.close();this._onClose?.()}#x(){this._ws.addEventListener("message",(x)=>{if(x.data instanceof Blob)this._onBinary?.(x.data);else if(x.data instanceof ArrayBuffer)this._onBinary?.(new Blob([x.data]));else try{let K=JSON.parse(x.data);this._onMessage?.(K)}catch(K){console.warn("Failed to parse message:",x.data,K)}}),this._ws.addEventListener("error",()=>{if(this._closed)return;this._onError?.(new Z("WebSocket error")),this.close()}),this._ws.addEventListener("close",()=>{if(this._closed)return;this.close()})}}class z{http;ws;constructor(x,K){this.http=x;this.ws=K}async list(x){let K={limit:(x.limit??20).toString(),page:(x.page??1).toString()};return this.http.get(`/agents/${x.agentId}/conversations`,K)}async get(x){return this.http.get(`/conversations/${x}`)}async connect(x){let K=this.ws.connect("/conversations/websocket"),B=new $(K);return await B.connect(),B.send({type:"session.handshake.offer",agent_id:x.agentId}),new Promise((F,Q)=>{let Y=!1;B.onMessage((N)=>{switch(N.type){case"session.handshake.accept":x.onConnection?.(N);break;case"session.handshake.reject":Y=!0,x.onConnection?.(N),B.close(),Q(Error(`Handshake rejected: ${N.reason}`));break;case"session.start":{Y=!0,x.onConnection?.(N);let W=new _(B,N.conversation_id,N.max_duration_ms,N.start_time,N.end_time,x);F(W);break}default:break}}),B.onError((N)=>{if(!Y)Q(N)}),B.onClose(()=>{if(!Y)Q(Error("WebSocket connection lost during handshake"))})})}}function O(x){let K=new URL(x),B=K.protocol==="https:"?"wss:":"ws:";return{rest:`${K.origin}/v1`,ws:`${B}//${K.host}/v1`}}class G extends Error{status;statusText;body;constructor(x,K,B,F){super(x);this.status=K;this.statusText=B;this.body=F;this.name="HttpTransportError"}}class V{config;constructor(x){this.config=x}async request(x,K){let B=`${this.config.baseUrl}${x}`,F=await fetch(B,{...K,headers:{"Content-Type":"application/json",...this.config.headers,...K?.headers}});if(!F.ok){let Q=await F.text();throw new G(`HTTP ${F.status}: ${F.statusText}`,F.status,F.statusText,Q)}return F.json()}async get(x,K){let B=new URL(`${this.config.baseUrl}${x}`);if(K){let F=Object.entries(K);for(let[Q,Y]of F)B.searchParams.set(Q,Y)}return this.request(x+B.search,{method:"GET"})}async post(x,K){return this.request(x,{method:"POST",body:K?JSON.stringify(K):void 0})}async put(x,K){return this.request(x,{method:"PUT",body:K?JSON.stringify(K):void 0})}async patch(x,K){return this.request(x,{method:"PATCH",body:K?JSON.stringify(K):void 0})}async delete(x){return this.request(x,{method:"DELETE"})}}class X{config;constructor(x){this.config=x}connect(x){let K=`${this.config.baseUrl}${x}`;return new WebSocket(K)}}class L{http;constructor(x){this.http=x}async list(x={}){let K={limit:(x.limit??50).toString(),page:(x.page??1).toString()};if(x.conversationId)K.conversation_id=x.conversationId;return this.http.get("/messages",K)}async get(x){return this.http.get(`/messages/${x}`)}}class H{http;constructor(x){this.http=x}async list(x={}){let K={limit:(x.limit??10).toString(),page:(x.page??1).toString()};return this.http.get("/templates",K)}async get(x){return this.http.get(`/templates/${x}`)}async create(x){return this.http.post("/templates",x)}async update(x,K){return this.http.put(`/templates/${x}`,K)}async delete(x){return this.http.delete(`/templates/${x}`)}}class U{agents;conversations;templates;messages;constructor(x){let K=O(x.baseUrl),B=new V({baseUrl:K.rest,headers:x.headers}),F=new X({baseUrl:K.ws,headers:x.headers});this.agents=new J(B),this.templates=new H(B),this.conversations=new z(B,F),this.messages=new L(B)}}export{U as KivoxClient,G as HttpTransportError,Z as ConversationTransportError,_ as ConversationSession};
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kivox/client",
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"description": "JavaScript/TypeScript client for KIVOX",
|
|
5
|
+
"homepage": "https://github.com/ekisa-team/kivox#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/ekisa-team/kivox/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/ekisa-team/kivox.git"
|
|
12
|
+
},
|
|
13
|
+
"author": {
|
|
14
|
+
"name": "Juan Mesa",
|
|
15
|
+
"email": "ju4n97@proton.me",
|
|
16
|
+
"url": "https://github.com/ju4n97"
|
|
17
|
+
},
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"type": "module",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"development": "./src/index.ts",
|
|
24
|
+
"import": "./dist/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "bun run build.ts",
|
|
36
|
+
"test": "bun test",
|
|
37
|
+
"test:watch": "bun test --watch"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/bun": "latest",
|
|
41
|
+
"bun-dts": "^0.1.70",
|
|
42
|
+
"typescript": "5.9.3"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
}
|
|
47
|
+
}
|