@kivox/client 0.1.0-beta.16 → 0.1.0-beta.18

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,10 +1,10 @@
1
- # KIVOX JavaScript client
1
+ # Kivox JavaScript client
2
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.
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
4
 
5
5
  ## Features
6
6
 
7
- - Unified client for the KIVOX API
7
+ - Unified client for the Kivox API
8
8
  - Conversation and voice session management
9
9
  - WebSockets, events, and real-time state
10
10
  - Audio recording and playback
package/dist/index.d.ts CHANGED
@@ -68,8 +68,8 @@ type Agent = {
68
68
  id: string
69
69
  template_id: string
70
70
  config: AgentConfig
71
- blueprint: AgentBlueprint
72
71
  variables: AgentVariable[]
72
+ ork_source: string
73
73
  status: AgentStatus
74
74
  created_at: Date
75
75
  updated_at: Date
@@ -83,13 +83,6 @@ type AgentConfig = {
83
83
  max_silence_timeout_seconds: number
84
84
  allow_interruptions: boolean
85
85
  };
86
- type AgentBlueprint<
87
- NodeType = unknown,
88
- EdgeType = unknown
89
- > = {
90
- nodes: NodeType[]
91
- edges: EdgeType[]
92
- };
93
86
  type AgentVariable = {
94
87
  key: string
95
88
  value: string
@@ -97,8 +90,12 @@ type AgentVariable = {
97
90
  is_secret: boolean
98
91
  description: string
99
92
  };
100
- type AgentCreate = Partial<Pick<Agent, "config" | "blueprint" | "variables" | "status" | "template_id">>;
101
- type AgentUpdate = Partial<Pick<AgentCreate, "config" | "blueprint" | "variables">>;
93
+ type AgentCreate = Partial<Pick<Agent, "config" | "variables" | "ork_source" | "status" | "template_id">>;
94
+ type AgentUpdate = Partial<Pick<AgentCreate, "config" | "variables" | "ork_source">>;
95
+ type AgentCompilationDiagnostic = {
96
+ errors: string[]
97
+ warnings: string[]
98
+ };
102
99
  /**
103
100
  * Configuration for listing agents.
104
101
  */
@@ -111,7 +108,7 @@ type AgentListParams = {
111
108
  search?: string
112
109
  };
113
110
  /**
114
- * Client for interacting with KIVOX agents.
111
+ * Client for interacting with Kivox agents.
115
112
  *
116
113
  * @example
117
114
  * ```ts
@@ -200,6 +197,14 @@ declare class AgentClient {
200
197
  */
201
198
  delete(id: string): Promise<Agent>;
202
199
  /**
200
+ * Compiles the Ork source code of an agent.
201
+ *
202
+ * @param id Agent ID
203
+ * @param orkSource Updated Ork source code. If not provided, the current Ork source code is used.
204
+ * @returns Compiled agent
205
+ */
206
+ compile(id: string, orkSource?: string): Promise<AgentCompilationDiagnostic>;
207
+ /**
203
208
  * Parses a list of agents with stringified config and blueprint fields.
204
209
  *
205
210
  * @returns List of parsed agents.
@@ -325,6 +330,7 @@ type ServerAudioDelta = {
325
330
  */
326
331
  type ServerTurnComplete = {
327
332
  type: "turn_complete"
333
+ stats: UsageStats
328
334
  };
329
335
  /**
330
336
  * Signals that the conversation flow reached its exit node.
@@ -332,6 +338,7 @@ type ServerTurnComplete = {
332
338
  */
333
339
  type ServerFlowComplete = {
334
340
  type: "flow_complete"
341
+ stats: UsageStats
335
342
  };
336
343
  /**
337
344
  * Represents a non-fatal execution or protocol error.
@@ -357,7 +364,19 @@ type ServerTick = {
357
364
  */
358
365
  type ServerSessionClosed = {
359
366
  type: "session_closed"
360
- reason: "flow_complete" | "ended_by_agent" | "ended_by_user" | "timeout" | "connection_closed" | "error"
367
+ reason: string
368
+ stats: UsageStats
369
+ };
370
+ /**
371
+ * Snapshot of runtime resource consumption.
372
+ */
373
+ type UsageStats = {
374
+ http_calls: number
375
+ http_limit: number
376
+ llm_calls: number
377
+ llm_limit: number
378
+ steps: number
379
+ steps_limit: number
361
380
  };
362
381
  /**
363
382
  * Union type for all messages sent from the server to the client.
@@ -458,7 +477,7 @@ type ConversationSessionConfig = {
458
477
  onEvent?: (event: ServerSessionEvent) => void
459
478
  };
460
479
  /**
461
- * Represents an active, real-time conversation session with a KIVOX agent.
480
+ * Represents an active, real-time conversation session with a Kivox agent.
462
481
  * Provides methods to dispatch user inputs and lifecycle commands, as well as tracking basic session state.
463
482
  */
464
483
  declare class ConversationSession {
@@ -567,7 +586,7 @@ type ConversationConnectParams = ConversationSessionConfig & {
567
586
  *
568
587
  * @example
569
588
  * ```ts
570
- * // Connect to a KIVOX agent
589
+ * // Connect to a Kivox agent
571
590
  * const session = await kivox.conversations.connect({
572
591
  * agentId: 'agent-123',
573
592
  * onEvent: (event) => {
@@ -666,11 +685,11 @@ type Template = {
666
685
  id: string
667
686
  name: string
668
687
  description?: string
669
- blueprint: AgentBlueprint
688
+ ork_source: string
670
689
  created_at: Date
671
690
  updated_at: Date
672
691
  };
673
- type TemplateCreate = Pick<Template, "name" | "description" | "blueprint">;
692
+ type TemplateCreate = Pick<Template, "name" | "description" | "ork_source">;
674
693
  type TemplateUpdate = Partial<TemplateCreate>;
675
694
  /**
676
695
  * Configuration for listing templates.
@@ -682,7 +701,7 @@ type TemplateListParams = {
682
701
  page?: number
683
702
  };
684
703
  /**
685
- * Client for interacting with KIVOX templates.
704
+ * Client for interacting with Kivox templates.
686
705
  *
687
706
  * @example
688
707
  * ```ts
@@ -730,11 +749,11 @@ declare class TemplateClient {
730
749
  delete(id: string): Promise<void>;
731
750
  }
732
751
  /**
733
- * Configuration for the KIVOX client.
752
+ * Configuration for the Kivox client.
734
753
  */
735
754
  type KivoxConfig = {
736
755
  /**
737
- * Base URL of your self-hosted KIVOX instance.
756
+ * Base URL of your self-hosted Kivox instance.
738
757
  * @example 'http://localhost:8787'
739
758
  * @example 'https://api.kivox.io'
740
759
  */
@@ -746,8 +765,8 @@ type KivoxConfig = {
746
765
  headers?: Record<string, string>
747
766
  };
748
767
  /**
749
- * Main KIVOX client.
750
- * Provides unified access to all KIVOX resources.
768
+ * Main Kivox client.
769
+ * Provides unified access to all Kivox resources.
751
770
  *
752
771
  * @example
753
772
  * ```ts
@@ -780,18 +799,17 @@ declare class KivoxClient {
780
799
  readonly messages: MessageClient;
781
800
  constructor(config: KivoxConfig);
782
801
  }
783
- import { AgentBlueprint as AgentBlueprint2, AgentConfig as AgentConfig2, AgentVariable as AgentVariable2 } from "@kivox/client";
784
802
  declare const REGEX_VARIABLE: RegExp;
785
803
  /**
786
804
  * Extracts all variable references from config and blueprint.
787
805
  */
788
- declare function extractAllVariables(config: AgentConfig2, blueprint: AgentBlueprint2<Record<string, unknown>, Record<string, unknown>>): string[];
806
+ declare function extractAllVariables(config: AgentConfig): string[];
789
807
  /**
790
808
  * Replaces variable references with their values
791
809
  */
792
- declare function interpolateVariables(text: string, variables: AgentVariable2[]): string;
810
+ declare function interpolateVariables(text: string, variables: AgentVariable[]): string;
793
811
  /**
794
812
  * Checks if a string contains any variable references.
795
813
  */
796
814
  declare function hasVariables(text: string): boolean;
797
- export { interpolateVariables, hasVariables, extractAllVariables, TemplateUpdate, TemplateCreate, Template, SessionConnectionLostEvent, ServerTurnComplete, ServerTick, ServerTextFull, ServerTextDelta, ServerSessionEvent, ServerSessionClosed, ServerMessage, ServerHandshakeOK, ServerHandshakeError, ServerFlowComplete, ServerError, ServerConnectionMessage, ServerAudioDelta, REGEX_VARIABLE, Paginated, MessageRole, Message, KivoxConfig, KivoxClient, HttpTransportError, ConversationTransportError, ConversationSessionConfig, ConversationSession, Conversation, ClientMessage, ClientInputText, ClientInputAudioStream, ClientInputAudio, ClientHandshake, ClientEndSession, ClientCancel, AgentVariable, AgentUpdate, AgentStatus, AgentCreate, AgentConfig, AgentBlueprint, Agent };
815
+ export { interpolateVariables, hasVariables, extractAllVariables, UsageStats, TemplateUpdate, TemplateCreate, Template, SessionConnectionLostEvent, ServerTurnComplete, ServerTick, ServerTextFull, ServerTextDelta, ServerSessionEvent, ServerSessionClosed, ServerMessage, ServerHandshakeOK, ServerHandshakeError, ServerFlowComplete, ServerError, ServerConnectionMessage, ServerAudioDelta, REGEX_VARIABLE, Paginated, MessageRole, Message, KivoxConfig, KivoxClient, HttpTransportError, ConversationTransportError, ConversationSessionConfig, ConversationSession, Conversation, ClientMessage, ClientInputText, ClientInputAudioStream, ClientInputAudio, ClientHandshake, ClientEndSession, ClientCancel, AgentVariable, AgentUpdate, AgentStatus, AgentCreate, AgentConfig, AgentCompilationDiagnostic, Agent };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- class Z{http;constructor(K){this.http=K}async list(K={}){let J={limit:(K.limit??10).toString(),page:(K.page??1).toString()};if(K.search)J.search=K.search;let Q=await this.http.get("/agents",J);return{...Q,items:Z.parseAgents(Q.items)}}async listLive(K={}){let J={limit:(K.limit??10).toString(),page:(K.page??1).toString()};if(K.search)J.search=K.search;let Q=await this.http.get("/agents/live",J);return{...Q,items:Z.parseAgents(Q.items)}}async listDraft(K={}){let J={limit:(K.limit??10).toString(),page:(K.page??1).toString()};if(K.search)J.search=K.search;let Q=await this.http.get("/agents/draft",J);return{...Q,items:Z.parseAgents(Q.items)}}async listArchived(K={}){let J={limit:(K.limit??10).toString(),page:(K.page??1).toString()};if(K.search)J.search=K.search;let Q=await this.http.get("/agents/archived",J);return{...Q,items:Z.parseAgents(Q.items)}}async get(K){let J=await this.http.get(`/agents/${K}`);return Z.parseAgent(J)}async create(K){let J=await this.http.post("/agents",K);return Z.parseAgent(J)}async update(K,J){let Q=await this.http.put(`/agents/${K}`,J);return Z.parseAgent(Q)}async markAsLive(K){let J=await this.http.patch(`/agents/${K}/live`);return Z.parseAgent(J)}async markAsDraft(K){let J=await this.http.patch(`/agents/${K}/draft`);return Z.parseAgent(J)}async markAsArchived(K){let J=await this.http.patch(`/agents/${K}/archived`);return Z.parseAgent(J)}async delete(K){let J=await this.http.delete(`/agents/${K}`);return Z.parseAgent(J)}static parseAgents(K){return K.map(Z.parseAgent)}static parseAgent(K){return{...K,config:JSON.parse(K.config),blueprint:JSON.parse(K.blueprint),variables:JSON.parse(K.variables)}}}class O{_transport;_conversationId;_closed=!1;_onEvent;_pendingAudioMetadata=null;_remainingMs=0;_elapsedMs=0;get conversationId(){return this._conversationId}get remainingMs(){return this._remainingMs}get elapsedMs(){return this._elapsedMs}get closed(){return this._closed}constructor(K,J,Q){this._transport=K,this._conversationId=J,this._onEvent=Q.onEvent,this.#K()}sendText(K){if(this._closed){console.warn("Cannot send text: session is closed");return}this._transport.send({type:"input_text",text:K})}sendAudio(K){if(this._closed){console.warn("Cannot send audio: session is closed");return}this._transport.send({type:"input_audio"}),this._transport.sendBinary(K)}streamAudio(K){if(this._closed){console.warn("Cannot stream audio: session is closed");return}this._transport.send({type:"input_audio_stream"}),this._transport.sendBinary(K)}cancelRequest(){if(this._closed){console.warn("Cannot cancel request: session is closed");return}this._transport.send({type:"cancel"})}end(){if(this._closed){console.warn("Cannot end session: session is closed");return}this._transport.send({type:"end"})}close(){if(this._closed)return;this._closed=!0,this._transport.close()}#K(){this._transport.onMessage((K)=>{let J=K;if(J.type==="audio_delta"){this._pendingAudioMetadata={size:J.size};return}if(J.type==="tick")this._remainingMs=J.remaining_ms,this._elapsedMs=J.elapsed_ms;if(J.type==="session_closed")this._closed=!0;this._onEvent?.(J)}),this._transport.onBinary((K)=>{if(this._pendingAudioMetadata){let J={type:"audio_delta",size:this._pendingAudioMetadata.size,audio:K};this._pendingAudioMetadata=null,this._onEvent?.(J)}}),this._transport.onClose(()=>{if(this._closed)return;this._closed=!0,this._onEvent?.({type:"connection_lost",reason:"socket_closed"})}),this._transport.onError(()=>{if(this._closed)return;this._closed=!0,this._onEvent?.({type:"connection_lost",reason:"socket_error"})})}}class z extends Error{code;constructor(K,J="TRANSPORT_ERROR"){super(K);this.code=J;this.name="ConversationTransportError"}}class X{_ws;_closed=!1;_onMessage=null;_onBinary=null;_onError=null;_onClose=null;constructor(K){this._ws=K}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((K,J)=>{let Q=()=>{this._ws.removeEventListener("open",Q),this._ws.removeEventListener("error",Y),this.#K(),K()},Y=()=>{this._ws.removeEventListener("open",Q),this._ws.removeEventListener("error",Y),J(new z("Connection failed","CONNECTION_FAILED"))};this._ws.addEventListener("open",Q),this._ws.addEventListener("error",Y)})}send(K){if(this._ws.readyState!==WebSocket.OPEN)throw new z("Not connected","NOT_CONNECTED");this._ws.send(JSON.stringify(K))}async sendBinary(K){if(this._ws.readyState!==WebSocket.OPEN)throw new z("Not connected","NOT_CONNECTED");let J=await K.arrayBuffer();this._ws.send(J)}onMessage(K){this._onMessage=K}onBinary(K){this._onBinary=K}onError(K){this._onError=K}onClose(K){this._onClose=K}close(){if(this._closed)return;if(this._closed=!0,this._ws.readyState===WebSocket.OPEN||this._ws.readyState===WebSocket.CONNECTING)this._ws.close();this._onClose?.()}#K(){this._ws.addEventListener("message",(K)=>{if(K.data instanceof Blob)this._onBinary?.(K.data);else if(K.data instanceof ArrayBuffer)this._onBinary?.(new Blob([K.data]));else if(typeof K.data==="string")try{let J=JSON.parse(K.data);this._onMessage?.(J)}catch(J){console.warn("Failed to parse JSON message:",K.data,J)}}),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 _{http;ws;constructor(K,J){this.http=K;this.ws=J}async list(K){let J={limit:(K.limit??20).toString(),page:(K.page??1).toString()};return this.http.get(`/agents/${K.agentId}/conversations`,J)}async get(K){return this.http.get(`/conversations/${K}`)}async connect(K){let J=this.ws.connect("/conversations/websocket"),Q=new X(J);return await Q.connect(),Q.send({type:"handshake",agent_id:K.agentId}),new Promise((Y,$)=>{let B=!1;Q.onMessage((N)=>{switch(N.type){case"handshake_ok":B=!0,K.onConnection?.(N),Y(new O(Q,N.conversation_id,K));break;case"handshake_error":B=!0,K.onConnection?.(N),Q.close(),$(Error(`Handshake rejected: ${N.reason}`));break;default:break}}),Q.onError((N)=>{if(!B)$(N)}),Q.onClose(()=>{if(!B)$(Error("WebSocket connection lost during handshake"))})})}}function M(K){let J=new URL(K),Q=J.protocol==="https:"?"wss:":"ws:";return{rest:`${J.origin}/v1`,ws:`${Q}//${J.host}/v1`}}class x extends Error{status;statusText;body;constructor(K,J,Q,Y){super(K);this.status=J;this.statusText=Q;this.body=Y;this.name="HttpTransportError"}}class D{config;constructor(K){this.config=K}async request(K,J){let Q=`${this.config.baseUrl}${K}`,Y=await fetch(Q,{...J,headers:{"Content-Type":"application/json",...this.config.headers,...J?.headers}});if(!Y.ok){let $=await Y.text();throw new x(`HTTP ${Y.status}: ${Y.statusText}`,Y.status,Y.statusText,$)}return Y.json()}async get(K,J){let Q=new URL(`${this.config.baseUrl}${K}`);if(J){let Y=Object.entries(J);for(let[$,B]of Y)Q.searchParams.set($,B)}return this.request(K+Q.search,{method:"GET"})}async post(K,J){return this.request(K,{method:"POST",body:J?JSON.stringify(J):void 0})}async put(K,J){return this.request(K,{method:"PUT",body:J?JSON.stringify(J):void 0})}async patch(K,J){return this.request(K,{method:"PATCH",body:J?JSON.stringify(J):void 0})}async delete(K){return this.request(K,{method:"DELETE"})}}class H{config;constructor(K){this.config=K}connect(K){let J=`${this.config.baseUrl}${K}`;return new WebSocket(J)}}class U{http;constructor(K){this.http=K}async list(K={}){let J={limit:(K.limit??50).toString(),page:(K.page??1).toString()};if(K.conversationId)J.conversation_id=K.conversationId;return this.http.get("/messages",J)}async get(K){return this.http.get(`/messages/${K}`)}}class F{http;constructor(K){this.http=K}async list(K={}){let J={limit:(K.limit??10).toString(),page:(K.page??1).toString()};return this.http.get("/templates",J)}async get(K){return this.http.get(`/templates/${K}`)}async create(K){return this.http.post("/templates",K)}async update(K,J){return this.http.put(`/templates/${K}`,J)}async delete(K){return this.http.delete(`/templates/${K}`)}}class W{agents;conversations;templates;messages;constructor(K){let J=M(K.baseUrl),Q=new D({baseUrl:J.rest,headers:K.headers}),Y=new H({baseUrl:J.ws,headers:K.headers});this.agents=new Z(Q),this.templates=new F(Q),this.conversations=new _(Q,Y),this.messages=new U(Q)}}var L=/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g;function j(K){let J=new Set,Q;while((Q=L.exec(K))!==null){let Y=Q[1];if(!Y)continue;J.add(Y)}return J}function G(K,J){if(typeof K==="string"){let Q=j(K);for(let Y of Q)J.add(Y)}else if(Array.isArray(K))for(let Q of K)G(Q,J);else if(typeof K==="object"&&K!==null){let Q=Object.values(K);for(let Y of Q)G(Y,J)}}function v(K,J){let Q=new Set;G(K,Q);for(let Y of J.nodes)if(Y.data)G(Y.data,Q);for(let Y of J.edges)if(Y.data)G(Y.data,Q);return Array.from(Q).toSorted()}function d(K,J){let Q=new Map(J.map((Y)=>[Y.key,Y.value]));return K.replace(L,(Y,$)=>{return Q.get($)??Y})}function m(K){return L.test(K)}export{d as interpolateVariables,m as hasVariables,v as extractAllVariables,L as REGEX_VARIABLE,W as KivoxClient,x as HttpTransportError,z as ConversationTransportError,O as ConversationSession};
1
+ class z{http;constructor(_){this.http=_}async list(_={}){let x={limit:(_.limit??10).toString(),page:(_.page??1).toString()};if(_.search)x.search=_.search;let D=await this.http.get("/agents",x);return{...D,items:z.parseAgents(D.items)}}async listLive(_={}){let x={limit:(_.limit??10).toString(),page:(_.page??1).toString()};if(_.search)x.search=_.search;let D=await this.http.get("/agents/live",x);return{...D,items:z.parseAgents(D.items)}}async listDraft(_={}){let x={limit:(_.limit??10).toString(),page:(_.page??1).toString()};if(_.search)x.search=_.search;let D=await this.http.get("/agents/draft",x);return{...D,items:z.parseAgents(D.items)}}async listArchived(_={}){let x={limit:(_.limit??10).toString(),page:(_.page??1).toString()};if(_.search)x.search=_.search;let D=await this.http.get("/agents/archived",x);return{...D,items:z.parseAgents(D.items)}}async get(_){let x=await this.http.get(`/agents/${_}`);return z.parseAgent(x)}async create(_){let x=await this.http.post("/agents",_);return z.parseAgent(x)}async update(_,x){let D=await this.http.put(`/agents/${_}`,x);return z.parseAgent(D)}async markAsLive(_){let x=await this.http.patch(`/agents/${_}/live`);return z.parseAgent(x)}async markAsDraft(_){let x=await this.http.patch(`/agents/${_}/draft`);return z.parseAgent(x)}async markAsArchived(_){let x=await this.http.patch(`/agents/${_}/archived`);return z.parseAgent(x)}async delete(_){let x=await this.http.delete(`/agents/${_}`);return z.parseAgent(x)}async compile(_,x){return await this.http.post(`/agents/${_}/compile`,{ork_source:x})}static parseAgents(_){return _.map(z.parseAgent)}static parseAgent(_){return{..._,config:JSON.parse(_.config),variables:JSON.parse(_.variables)}}}class ${_transport;_conversationId;_closed=!1;_onEvent;_pendingAudioMetadata=null;_remainingMs=0;_elapsedMs=0;get conversationId(){return this._conversationId}get remainingMs(){return this._remainingMs}get elapsedMs(){return this._elapsedMs}get closed(){return this._closed}constructor(_,x,D){this._transport=_,this._conversationId=x,this._onEvent=D.onEvent,this.#_()}sendText(_){if(this._closed){console.warn("Cannot send text: session is closed");return}this._transport.send({type:"input_text",text:_})}sendAudio(_){if(this._closed){console.warn("Cannot send audio: session is closed");return}this._transport.send({type:"input_audio"}),this._transport.sendBinary(_)}streamAudio(_){if(this._closed){console.warn("Cannot stream audio: session is closed");return}this._transport.send({type:"input_audio_stream"}),this._transport.sendBinary(_)}cancelRequest(){if(this._closed){console.warn("Cannot cancel request: session is closed");return}this._transport.send({type:"cancel"})}end(){if(this._closed){console.warn("Cannot end session: session is closed");return}this._transport.send({type:"end"})}close(){if(this._closed)return;this._closed=!0,this._transport.close()}#_(){this._transport.onMessage((_)=>{let x=_;if(x.type==="audio_delta"){this._pendingAudioMetadata={size:x.size};return}if(x.type==="tick")this._remainingMs=x.remaining_ms,this._elapsedMs=x.elapsed_ms;if(x.type==="session_closed")this._closed=!0;this._onEvent?.(x)}),this._transport.onBinary((_)=>{if(this._pendingAudioMetadata){let x={type:"audio_delta",size:this._pendingAudioMetadata.size,audio:_};this._pendingAudioMetadata=null,this._onEvent?.(x)}}),this._transport.onClose(()=>{if(this._closed)return;this._closed=!0,this._onEvent?.({type:"connection_lost",reason:"socket_closed"})}),this._transport.onError(()=>{if(this._closed)return;this._closed=!0,this._onEvent?.({type:"connection_lost",reason:"socket_error"})})}}class Q extends Error{code;constructor(_,x="TRANSPORT_ERROR"){super(_);this.code=x;this.name="ConversationTransportError"}}class N{_ws;_closed=!1;_onMessage=null;_onBinary=null;_onError=null;_onClose=null;constructor(_){this._ws=_}async connect(){if(this._ws.readyState===WebSocket.OPEN)throw new Q("Already connected","ALREADY_CONNECTED");if(this._ws.readyState===WebSocket.CLOSING||this._ws.readyState===WebSocket.CLOSED)throw new Q("Socket is closing or closed","SOCKET_CLOSED");return new Promise((_,x)=>{let D=()=>{this._ws.removeEventListener("open",D),this._ws.removeEventListener("error",K),this.#_(),_()},K=()=>{this._ws.removeEventListener("open",D),this._ws.removeEventListener("error",K),x(new Q("Connection failed","CONNECTION_FAILED"))};this._ws.addEventListener("open",D),this._ws.addEventListener("error",K)})}send(_){if(this._ws.readyState!==WebSocket.OPEN)throw new Q("Not connected","NOT_CONNECTED");this._ws.send(JSON.stringify(_))}async sendBinary(_){if(this._ws.readyState!==WebSocket.OPEN)throw new Q("Not connected","NOT_CONNECTED");let x=await _.arrayBuffer();this._ws.send(x)}onMessage(_){this._onMessage=_}onBinary(_){this._onBinary=_}onError(_){this._onError=_}onClose(_){this._onClose=_}close(){if(this._closed)return;if(this._closed=!0,this._ws.readyState===WebSocket.OPEN||this._ws.readyState===WebSocket.CONNECTING)this._ws.close();this._onClose?.()}#_(){this._ws.addEventListener("message",(_)=>{if(_.data instanceof Blob)this._onBinary?.(_.data);else if(_.data instanceof ArrayBuffer)this._onBinary?.(new Blob([_.data]));else if(typeof _.data==="string")try{let x=JSON.parse(_.data);this._onMessage?.(x)}catch(x){console.warn("Failed to parse JSON message:",_.data,x)}}),this._ws.addEventListener("error",()=>{if(this._closed)return;this._onError?.(new Q("WebSocket error")),this.close()}),this._ws.addEventListener("close",()=>{if(this._closed)return;this.close()})}}class B{http;ws;constructor(_,x){this.http=_;this.ws=x}async list(_){let x={limit:(_.limit??20).toString(),page:(_.page??1).toString()};return this.http.get(`/agents/${_.agentId}/conversations`,x)}async get(_){return this.http.get(`/conversations/${_}`)}async connect(_){let x=this.ws.connect("/conversations/websocket"),D=new N(x);return await D.connect(),D.send({type:"handshake",agent_id:_.agentId}),new Promise((K,J)=>{let Z=!1;D.onMessage((Y)=>{switch(Y.type){case"handshake_ok":Z=!0,_.onConnection?.(Y),K(new $(D,Y.conversation_id,_));break;case"handshake_error":Z=!0,_.onConnection?.(Y),D.close(),J(Error(`Handshake rejected: ${Y.reason}`));break;default:break}}),D.onError((Y)=>{if(!Z)J(Y)}),D.onClose(()=>{if(!Z)J(Error("WebSocket connection lost during handshake"))})})}}function L(_){let x=new URL(_),D=x.protocol==="https:"?"wss:":"ws:";return{rest:`${x.origin}/v1`,ws:`${D}//${x.host}/v1`}}class M extends Error{status;statusText;body;constructor(_,x,D,K){super(_);this.status=x;this.statusText=D;this.body=K;this.name="HttpTransportError"}}class O{config;constructor(_){this.config=_}async request(_,x){let D=`${this.config.baseUrl}${_}`,K=await fetch(D,{...x,headers:{"Content-Type":"application/json",...this.config.headers,...x?.headers}});if(!K.ok){let J=await K.text();throw new M(`HTTP ${K.status}: ${K.statusText}`,K.status,K.statusText,J)}return K.json()}async get(_,x){let D=new URL(`${this.config.baseUrl}${_}`);if(x){let K=Object.entries(x);for(let[J,Z]of K)D.searchParams.set(J,Z)}return this.request(_+D.search,{method:"GET"})}async post(_,x){return this.request(_,{method:"POST",body:x?JSON.stringify(x):void 0})}async put(_,x){return this.request(_,{method:"PUT",body:x?JSON.stringify(x):void 0})}async patch(_,x){return this.request(_,{method:"PATCH",body:x?JSON.stringify(x):void 0})}async delete(_){return this.request(_,{method:"DELETE"})}}class X{config;constructor(_){this.config=_}connect(_){let x=`${this.config.baseUrl}${_}`;return new WebSocket(x)}}class F{http;constructor(_){this.http=_}async list(_={}){let x={limit:(_.limit??50).toString(),page:(_.page??1).toString()};if(_.conversationId)x.conversation_id=_.conversationId;return this.http.get("/messages",x)}async get(_){return this.http.get(`/messages/${_}`)}}class G{http;constructor(_){this.http=_}async list(_={}){let x={limit:(_.limit??10).toString(),page:(_.page??1).toString()};return this.http.get("/templates",x)}async get(_){return this.http.get(`/templates/${_}`)}async create(_){return this.http.post("/templates",_)}async update(_,x){return this.http.put(`/templates/${_}`,x)}async delete(_){return this.http.delete(`/templates/${_}`)}}class P{agents;conversations;templates;messages;constructor(_){let x=L(_.baseUrl),D=new O({baseUrl:x.rest,headers:_.headers}),K=new X({baseUrl:x.ws,headers:_.headers});this.agents=new z(D),this.templates=new G(D),this.conversations=new B(D,K),this.messages=new F(D)}}var H=/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g;function W(_){let x=new Set,D;while((D=H.exec(_))!==null){let K=D[1];if(!K)continue;x.add(K)}return x}function U(_,x){if(typeof _==="string"){let D=W(_);for(let K of D)x.add(K)}else if(Array.isArray(_))for(let D of _)U(D,x);else if(typeof _==="object"&&_!==null){let D=Object.values(_);for(let K of D)U(K,x)}}function h(_){let x=new Set;return U(_,x),Array.from(x).toSorted()}function v(_,x){let D=new Map(x.map((K)=>[K.key,K.value]));return _.replace(H,(K,J)=>{return D.get(J)??K})}function m(_){return H.test(_)}export{v as interpolateVariables,m as hasVariables,h as extractAllVariables,H as REGEX_VARIABLE,P as KivoxClient,M as HttpTransportError,Q as ConversationTransportError,$ as ConversationSession};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kivox/client",
3
- "version": "0.1.0-beta.16",
4
- "description": "JavaScript/TypeScript client for KIVOX",
3
+ "version": "0.1.0-beta.18",
4
+ "description": "JavaScript/TypeScript client for Kivox",
5
5
  "homepage": "https://github.com/ekisa-team/kivox#readme",
6
6
  "bugs": {
7
7
  "url": "https://github.com/ekisa-team/kivox/issues"
@@ -15,7 +15,6 @@
15
15
  "email": "ju4n97@proton.me",
16
16
  "url": "https://github.com/ju4n97"
17
17
  },
18
- "sideEffects": false,
19
18
  "type": "module",
20
19
  "exports": {
21
20
  ".": {