@estuary-ai/sdk 0.1.21 → 0.1.23

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 estuary.ai
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 estuary.ai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@estuary-ai/sdk)](https://www.npmjs.com/package/@estuary-ai/sdk)
4
4
 
5
- TypeScript SDK for the [Estuary](https://www.estuary-ai.com) real-time AI conversation platform. Build applications with persistent AI characters that remember, hear, and see.
5
+ Web SDK for the [Estuary](https://www.estuary-ai.com) real-time AI conversation platform. Build applications with persistent AI characters that remember, hear, and see.
6
6
 
7
7
  ## Installation
8
8
 
@@ -242,7 +242,7 @@ interface EstuaryConfig {
242
242
 
243
243
  ## Exports
244
244
 
245
- Key exports for TypeScript users:
245
+ Key exports:
246
246
 
247
247
  ```typescript
248
248
  // Client
@@ -26,5 +26,5 @@ var EstuaryError = class extends Error {
26
26
  };
27
27
 
28
28
  export { ErrorCode, EstuaryError };
29
- //# sourceMappingURL=chunk-6M5LSBMK.mjs.map
30
- //# sourceMappingURL=chunk-6M5LSBMK.mjs.map
29
+ //# sourceMappingURL=chunk-W5QYPYX3.mjs.map
30
+ //# sourceMappingURL=chunk-W5QYPYX3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts"],"names":["ErrorCode"],"mappings":";AAAO,IAAK,SAAA,qBAAAA,UAAAA,KAAL;AACL,EAAAA,WAAA,mBAAA,CAAA,GAAoB,mBAAA;AACpB,EAAAA,WAAA,aAAA,CAAA,GAAc,aAAA;AACd,EAAAA,WAAA,oBAAA,CAAA,GAAqB,oBAAA;AACrB,EAAAA,WAAA,gBAAA,CAAA,GAAiB,gBAAA;AACjB,EAAAA,WAAA,qBAAA,CAAA,GAAsB,qBAAA;AACtB,EAAAA,WAAA,sBAAA,CAAA,GAAuB,sBAAA;AACvB,EAAAA,WAAA,kBAAA,CAAA,GAAmB,kBAAA;AACnB,EAAAA,WAAA,qBAAA,CAAA,GAAsB,qBAAA;AACtB,EAAAA,WAAA,mBAAA,CAAA,GAAoB,mBAAA;AACpB,EAAAA,WAAA,eAAA,CAAA,GAAgB,eAAA;AAChB,EAAAA,WAAA,YAAA,CAAA,GAAa,YAAA;AACb,EAAAA,WAAA,SAAA,CAAA,GAAU,SAAA;AAZA,EAAA,OAAAA,UAAAA;AAAA,CAAA,EAAA,SAAA,IAAA,EAAA;AAeL,IAAM,YAAA,GAAN,cAA2B,KAAA,CAAM;AAAA,EAC7B,IAAA;AAAA,EACA,OAAA;AAAA,EAET,WAAA,CAAY,IAAA,EAAiB,OAAA,EAAiB,OAAA,EAAmB;AAC/D,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,cAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AACF","file":"chunk-W5QYPYX3.mjs","sourcesContent":["export enum ErrorCode {\n CONNECTION_FAILED = 'CONNECTION_FAILED',\n AUTH_FAILED = 'AUTH_FAILED',\n CONNECTION_TIMEOUT = 'CONNECTION_TIMEOUT',\n QUOTA_EXCEEDED = 'QUOTA_EXCEEDED',\n VOICE_NOT_SUPPORTED = 'VOICE_NOT_SUPPORTED',\n VOICE_ALREADY_ACTIVE = 'VOICE_ALREADY_ACTIVE',\n VOICE_NOT_ACTIVE = 'VOICE_NOT_ACTIVE',\n LIVEKIT_UNAVAILABLE = 'LIVEKIT_UNAVAILABLE',\n MICROPHONE_DENIED = 'MICROPHONE_DENIED',\n NOT_CONNECTED = 'NOT_CONNECTED',\n REST_ERROR = 'REST_ERROR',\n UNKNOWN = 'UNKNOWN',\n}\n\nexport class EstuaryError extends Error {\n readonly code: ErrorCode;\n readonly details?: unknown;\n\n constructor(code: ErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = 'EstuaryError';\n this.code = code;\n this.details = details;\n }\n}\n"]}
package/dist/index.d.mts CHANGED
@@ -13,7 +13,7 @@ interface EstuaryConfig {
13
13
  autoReconnect?: boolean;
14
14
  /** Max reconnect attempts (default: 5) */
15
15
  maxReconnectAttempts?: number;
16
- /** Delay between reconnect attempts in ms (default: 2000) */
16
+ /** Base delay between reconnect attempts in ms (default: 2000). Actual delay is baseDelay × attemptNumber (linear backoff). */
17
17
  reconnectDelayMs?: number;
18
18
  /** Enable debug logging (default: false) */
19
19
  debug?: boolean;
@@ -82,14 +82,23 @@ interface CameraCaptureRequest {
82
82
  }
83
83
  interface MemoryData {
84
84
  id: string;
85
+ userId: string;
86
+ agentId: string;
87
+ playerId: string;
85
88
  content: string;
86
89
  memoryType: string;
87
90
  confidence: number;
88
91
  status: string;
89
92
  sourceConversationId: string;
90
93
  sourceQuote?: string;
94
+ source?: string;
91
95
  topic?: string;
92
- createdAt: string;
96
+ secondaryTopics?: string[];
97
+ lastAccessedAt?: string | null;
98
+ accessCount?: number;
99
+ extractedAt?: string | null;
100
+ createdAt?: string | null;
101
+ updatedAt?: string | null;
93
102
  }
94
103
  interface MemoryUpdatedEvent {
95
104
  agentId: string;
@@ -100,6 +109,16 @@ interface MemoryUpdatedEvent {
100
109
  newMemories: MemoryData[];
101
110
  timestamp: string;
102
111
  }
112
+ interface CharacterInfo {
113
+ id: string;
114
+ name: string;
115
+ tagline: string | null;
116
+ avatar: string | null;
117
+ modelUrl: string | null;
118
+ modelPreviewUrl: string | null;
119
+ modelStatus: string | null;
120
+ sourceImageUrl: string | null;
121
+ }
103
122
  interface CharacterAction {
104
123
  /** Action name (e.g., "follow_user", "sit", "look_at") */
105
124
  name: string;
@@ -162,7 +181,7 @@ interface MemorySearchOptions {
162
181
  limit?: number;
163
182
  }
164
183
  interface MemoryListResponse {
165
- memories: Record<string, unknown>[];
184
+ memories: MemoryData[];
166
185
  total: number;
167
186
  limit: number;
168
187
  offset: number;
@@ -170,36 +189,93 @@ interface MemoryListResponse {
170
189
  interface MemoryTimelineResponse {
171
190
  timeline: {
172
191
  date: string;
173
- memories: Record<string, unknown>[];
192
+ memories: MemoryData[];
174
193
  }[];
175
194
  totalMemories: number;
176
195
  groupBy: string;
177
196
  }
178
197
  interface MemoryStatsResponse {
179
- [key: string]: unknown;
198
+ totalActive: number;
199
+ totalSuperseded: number;
200
+ totalDecayed: number;
201
+ byType: Record<string, number>;
202
+ coreFacts: number;
203
+ }
204
+ interface MemoryGraphNode {
205
+ id: string;
206
+ type: 'user' | 'cluster' | 'memory' | 'entity';
207
+ label?: string;
208
+ /** Cluster fields */
209
+ level?: number;
210
+ memoryCount?: number;
211
+ typeDistribution?: Record<string, number>;
212
+ expanded?: boolean;
213
+ parentClusterId?: string | null;
214
+ childClusterIds?: string[];
215
+ labelPending?: boolean;
216
+ /** Memory fields */
217
+ memoryType?: string;
218
+ content?: string;
219
+ confidence?: number;
220
+ clusterId?: string;
221
+ sourceQuote?: string | null;
222
+ sourceConversationId?: string | null;
223
+ createdAt?: string | null;
224
+ accessCount?: number;
225
+ /** Entity fields */
226
+ entityType?: string | null;
227
+ name?: string;
228
+ mentionCount?: number;
229
+ extraData?: Record<string, string>;
230
+ }
231
+ interface MemoryGraphEdge {
232
+ source: string;
233
+ target: string;
234
+ type: 'has_cluster' | 'contains' | 'mentions' | 'relationship';
235
+ relationshipType?: string;
236
+ label?: string | null;
237
+ confidence?: number;
180
238
  }
181
239
  interface MemoryGraphResponse {
182
- nodes: Record<string, unknown>[];
183
- edges: Record<string, unknown>[];
184
- stats: Record<string, unknown>;
240
+ nodes: MemoryGraphNode[];
241
+ edges: MemoryGraphEdge[];
242
+ stats: {
243
+ totalMemories: number;
244
+ totalEntities: number;
245
+ clusterCount: number;
246
+ clusters: Record<string, number>;
247
+ };
248
+ stale?: boolean;
185
249
  }
186
250
  interface MemorySearchResponse {
187
251
  results: {
188
- memory: Record<string, unknown>;
252
+ memory: MemoryData;
189
253
  score: number;
190
254
  similarityScore: number;
191
255
  }[];
192
256
  query: string;
193
257
  total: number;
194
258
  }
259
+ interface CoreFact {
260
+ id: string;
261
+ userId: string;
262
+ agentId: string;
263
+ playerId: string;
264
+ factKey: string;
265
+ factValue: string;
266
+ sourceMemoryId?: string | null;
267
+ createdAt?: string | null;
268
+ updatedAt?: string | null;
269
+ }
195
270
  interface CoreFactsResponse {
196
- coreFacts: Record<string, unknown>[];
271
+ coreFacts: CoreFact[];
197
272
  }
198
273
 
199
274
  declare class RestClient {
200
275
  private baseUrl;
201
276
  private apiKey;
202
- constructor(baseUrl: string, apiKey: string);
277
+ private timeoutMs;
278
+ constructor(baseUrl: string, apiKey: string, timeoutMs?: number);
203
279
  get<T>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
204
280
  post<T>(path: string, body?: unknown): Promise<T>;
205
281
  delete<T>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
@@ -243,6 +319,7 @@ declare class EstuaryClient extends TypedEventEmitter<EstuaryEventMap> {
243
319
  private voiceManager;
244
320
  private audioPlayer;
245
321
  private _memory;
322
+ private _character;
246
323
  private _sessionInfo;
247
324
  private actionParsers;
248
325
  private _hasAutoInterrupted;
@@ -250,6 +327,8 @@ declare class EstuaryClient extends TypedEventEmitter<EstuaryEventMap> {
250
327
  constructor(config: EstuaryConfig);
251
328
  /** Memory API client for querying memories, graphs, and facts */
252
329
  get memory(): MemoryClient;
330
+ /** Fetch character details including 3D model and avatar URLs. */
331
+ getCharacter(characterId?: string): Promise<CharacterInfo>;
253
332
  /** Current session info (null if not connected) */
254
333
  get session(): SessionInfo | null;
255
334
  /** Current connection state */
@@ -259,8 +338,8 @@ declare class EstuaryClient extends TypedEventEmitter<EstuaryEventMap> {
259
338
  /** Connect to the Estuary server and authenticate */
260
339
  connect(): Promise<SessionInfo>;
261
340
  /** Disconnect from the server */
262
- disconnect(): void;
263
- /** Send a text message to the character */
341
+ disconnect(): Promise<void>;
342
+ /** Send a text message to the character. Defaults to textOnly=true (no TTS audio response). Pass textOnly=false to receive voice audio. */
264
343
  sendText(text: string, textOnly?: boolean): void;
265
344
  /** Interrupt the current bot response */
266
345
  interrupt(messageId?: string): void;
@@ -275,11 +354,14 @@ declare class EstuaryClient extends TypedEventEmitter<EstuaryEventMap> {
275
354
  /** Start voice input (requests microphone permission) */
276
355
  startVoice(): Promise<void>;
277
356
  /** Stop voice input */
278
- stopVoice(): void;
357
+ stopVoice(): Promise<void>;
279
358
  /** Toggle microphone mute */
280
359
  toggleMute(): void;
281
360
  /** Whether the microphone is muted */
282
361
  get isMuted(): boolean;
362
+ /** Get/set suppressMicDuringPlayback at runtime (no reconnect needed) */
363
+ get suppressMicDuringPlayback(): boolean;
364
+ set suppressMicDuringPlayback(enabled: boolean);
283
365
  /** Whether voice is currently active */
284
366
  get isVoiceActive(): boolean;
285
367
  private ensureConnected;
@@ -328,4 +410,12 @@ declare function parseActions(text: string): {
328
410
  cleanText: string;
329
411
  };
330
412
 
331
- export { type BotResponse, type BotVoice, type CameraCaptureRequest, type CharacterAction, ConnectionState, type CoreFactsResponse, ErrorCode, EstuaryClient, type EstuaryConfig, EstuaryError, type EstuaryEventMap, type InterruptData, type LiveKitTokenResponse, MemoryClient, type MemoryData, type MemoryGraphOptions, type MemoryGraphResponse, type MemoryListOptions, type MemoryListResponse, type MemorySearchOptions, type MemorySearchResponse, type MemoryStatsResponse, type MemoryTimelineOptions, type MemoryTimelineResponse, type MemoryUpdatedEvent, type ParsedAction, type QuotaExceededData, type SessionInfo, type SttResponse, type VoiceManager, type VoiceTransport, parseActions };
413
+ declare class CharacterClient {
414
+ private rest;
415
+ constructor(rest: RestClient);
416
+ /** Fetch character details including 3D model and avatar URLs. */
417
+ getCharacter(characterId: string): Promise<CharacterInfo>;
418
+ dispose(): void;
419
+ }
420
+
421
+ export { type BotResponse, type BotVoice, type CameraCaptureRequest, type CharacterAction, CharacterClient, type CharacterInfo, ConnectionState, type CoreFact, type CoreFactsResponse, ErrorCode, EstuaryClient, type EstuaryConfig, EstuaryError, type EstuaryEventMap, type InterruptData, type LiveKitTokenResponse, MemoryClient, type MemoryData, type MemoryGraphEdge, type MemoryGraphNode, type MemoryGraphOptions, type MemoryGraphResponse, type MemoryListOptions, type MemoryListResponse, type MemorySearchOptions, type MemorySearchResponse, type MemoryStatsResponse, type MemoryTimelineOptions, type MemoryTimelineResponse, type MemoryUpdatedEvent, type ParsedAction, type QuotaExceededData, type SessionInfo, type SttResponse, type VoiceManager, type VoiceTransport, parseActions };
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ interface EstuaryConfig {
13
13
  autoReconnect?: boolean;
14
14
  /** Max reconnect attempts (default: 5) */
15
15
  maxReconnectAttempts?: number;
16
- /** Delay between reconnect attempts in ms (default: 2000) */
16
+ /** Base delay between reconnect attempts in ms (default: 2000). Actual delay is baseDelay × attemptNumber (linear backoff). */
17
17
  reconnectDelayMs?: number;
18
18
  /** Enable debug logging (default: false) */
19
19
  debug?: boolean;
@@ -82,14 +82,23 @@ interface CameraCaptureRequest {
82
82
  }
83
83
  interface MemoryData {
84
84
  id: string;
85
+ userId: string;
86
+ agentId: string;
87
+ playerId: string;
85
88
  content: string;
86
89
  memoryType: string;
87
90
  confidence: number;
88
91
  status: string;
89
92
  sourceConversationId: string;
90
93
  sourceQuote?: string;
94
+ source?: string;
91
95
  topic?: string;
92
- createdAt: string;
96
+ secondaryTopics?: string[];
97
+ lastAccessedAt?: string | null;
98
+ accessCount?: number;
99
+ extractedAt?: string | null;
100
+ createdAt?: string | null;
101
+ updatedAt?: string | null;
93
102
  }
94
103
  interface MemoryUpdatedEvent {
95
104
  agentId: string;
@@ -100,6 +109,16 @@ interface MemoryUpdatedEvent {
100
109
  newMemories: MemoryData[];
101
110
  timestamp: string;
102
111
  }
112
+ interface CharacterInfo {
113
+ id: string;
114
+ name: string;
115
+ tagline: string | null;
116
+ avatar: string | null;
117
+ modelUrl: string | null;
118
+ modelPreviewUrl: string | null;
119
+ modelStatus: string | null;
120
+ sourceImageUrl: string | null;
121
+ }
103
122
  interface CharacterAction {
104
123
  /** Action name (e.g., "follow_user", "sit", "look_at") */
105
124
  name: string;
@@ -162,7 +181,7 @@ interface MemorySearchOptions {
162
181
  limit?: number;
163
182
  }
164
183
  interface MemoryListResponse {
165
- memories: Record<string, unknown>[];
184
+ memories: MemoryData[];
166
185
  total: number;
167
186
  limit: number;
168
187
  offset: number;
@@ -170,36 +189,93 @@ interface MemoryListResponse {
170
189
  interface MemoryTimelineResponse {
171
190
  timeline: {
172
191
  date: string;
173
- memories: Record<string, unknown>[];
192
+ memories: MemoryData[];
174
193
  }[];
175
194
  totalMemories: number;
176
195
  groupBy: string;
177
196
  }
178
197
  interface MemoryStatsResponse {
179
- [key: string]: unknown;
198
+ totalActive: number;
199
+ totalSuperseded: number;
200
+ totalDecayed: number;
201
+ byType: Record<string, number>;
202
+ coreFacts: number;
203
+ }
204
+ interface MemoryGraphNode {
205
+ id: string;
206
+ type: 'user' | 'cluster' | 'memory' | 'entity';
207
+ label?: string;
208
+ /** Cluster fields */
209
+ level?: number;
210
+ memoryCount?: number;
211
+ typeDistribution?: Record<string, number>;
212
+ expanded?: boolean;
213
+ parentClusterId?: string | null;
214
+ childClusterIds?: string[];
215
+ labelPending?: boolean;
216
+ /** Memory fields */
217
+ memoryType?: string;
218
+ content?: string;
219
+ confidence?: number;
220
+ clusterId?: string;
221
+ sourceQuote?: string | null;
222
+ sourceConversationId?: string | null;
223
+ createdAt?: string | null;
224
+ accessCount?: number;
225
+ /** Entity fields */
226
+ entityType?: string | null;
227
+ name?: string;
228
+ mentionCount?: number;
229
+ extraData?: Record<string, string>;
230
+ }
231
+ interface MemoryGraphEdge {
232
+ source: string;
233
+ target: string;
234
+ type: 'has_cluster' | 'contains' | 'mentions' | 'relationship';
235
+ relationshipType?: string;
236
+ label?: string | null;
237
+ confidence?: number;
180
238
  }
181
239
  interface MemoryGraphResponse {
182
- nodes: Record<string, unknown>[];
183
- edges: Record<string, unknown>[];
184
- stats: Record<string, unknown>;
240
+ nodes: MemoryGraphNode[];
241
+ edges: MemoryGraphEdge[];
242
+ stats: {
243
+ totalMemories: number;
244
+ totalEntities: number;
245
+ clusterCount: number;
246
+ clusters: Record<string, number>;
247
+ };
248
+ stale?: boolean;
185
249
  }
186
250
  interface MemorySearchResponse {
187
251
  results: {
188
- memory: Record<string, unknown>;
252
+ memory: MemoryData;
189
253
  score: number;
190
254
  similarityScore: number;
191
255
  }[];
192
256
  query: string;
193
257
  total: number;
194
258
  }
259
+ interface CoreFact {
260
+ id: string;
261
+ userId: string;
262
+ agentId: string;
263
+ playerId: string;
264
+ factKey: string;
265
+ factValue: string;
266
+ sourceMemoryId?: string | null;
267
+ createdAt?: string | null;
268
+ updatedAt?: string | null;
269
+ }
195
270
  interface CoreFactsResponse {
196
- coreFacts: Record<string, unknown>[];
271
+ coreFacts: CoreFact[];
197
272
  }
198
273
 
199
274
  declare class RestClient {
200
275
  private baseUrl;
201
276
  private apiKey;
202
- constructor(baseUrl: string, apiKey: string);
277
+ private timeoutMs;
278
+ constructor(baseUrl: string, apiKey: string, timeoutMs?: number);
203
279
  get<T>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
204
280
  post<T>(path: string, body?: unknown): Promise<T>;
205
281
  delete<T>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
@@ -243,6 +319,7 @@ declare class EstuaryClient extends TypedEventEmitter<EstuaryEventMap> {
243
319
  private voiceManager;
244
320
  private audioPlayer;
245
321
  private _memory;
322
+ private _character;
246
323
  private _sessionInfo;
247
324
  private actionParsers;
248
325
  private _hasAutoInterrupted;
@@ -250,6 +327,8 @@ declare class EstuaryClient extends TypedEventEmitter<EstuaryEventMap> {
250
327
  constructor(config: EstuaryConfig);
251
328
  /** Memory API client for querying memories, graphs, and facts */
252
329
  get memory(): MemoryClient;
330
+ /** Fetch character details including 3D model and avatar URLs. */
331
+ getCharacter(characterId?: string): Promise<CharacterInfo>;
253
332
  /** Current session info (null if not connected) */
254
333
  get session(): SessionInfo | null;
255
334
  /** Current connection state */
@@ -259,8 +338,8 @@ declare class EstuaryClient extends TypedEventEmitter<EstuaryEventMap> {
259
338
  /** Connect to the Estuary server and authenticate */
260
339
  connect(): Promise<SessionInfo>;
261
340
  /** Disconnect from the server */
262
- disconnect(): void;
263
- /** Send a text message to the character */
341
+ disconnect(): Promise<void>;
342
+ /** Send a text message to the character. Defaults to textOnly=true (no TTS audio response). Pass textOnly=false to receive voice audio. */
264
343
  sendText(text: string, textOnly?: boolean): void;
265
344
  /** Interrupt the current bot response */
266
345
  interrupt(messageId?: string): void;
@@ -275,11 +354,14 @@ declare class EstuaryClient extends TypedEventEmitter<EstuaryEventMap> {
275
354
  /** Start voice input (requests microphone permission) */
276
355
  startVoice(): Promise<void>;
277
356
  /** Stop voice input */
278
- stopVoice(): void;
357
+ stopVoice(): Promise<void>;
279
358
  /** Toggle microphone mute */
280
359
  toggleMute(): void;
281
360
  /** Whether the microphone is muted */
282
361
  get isMuted(): boolean;
362
+ /** Get/set suppressMicDuringPlayback at runtime (no reconnect needed) */
363
+ get suppressMicDuringPlayback(): boolean;
364
+ set suppressMicDuringPlayback(enabled: boolean);
283
365
  /** Whether voice is currently active */
284
366
  get isVoiceActive(): boolean;
285
367
  private ensureConnected;
@@ -328,4 +410,12 @@ declare function parseActions(text: string): {
328
410
  cleanText: string;
329
411
  };
330
412
 
331
- export { type BotResponse, type BotVoice, type CameraCaptureRequest, type CharacterAction, ConnectionState, type CoreFactsResponse, ErrorCode, EstuaryClient, type EstuaryConfig, EstuaryError, type EstuaryEventMap, type InterruptData, type LiveKitTokenResponse, MemoryClient, type MemoryData, type MemoryGraphOptions, type MemoryGraphResponse, type MemoryListOptions, type MemoryListResponse, type MemorySearchOptions, type MemorySearchResponse, type MemoryStatsResponse, type MemoryTimelineOptions, type MemoryTimelineResponse, type MemoryUpdatedEvent, type ParsedAction, type QuotaExceededData, type SessionInfo, type SttResponse, type VoiceManager, type VoiceTransport, parseActions };
413
+ declare class CharacterClient {
414
+ private rest;
415
+ constructor(rest: RestClient);
416
+ /** Fetch character details including 3D model and avatar URLs. */
417
+ getCharacter(characterId: string): Promise<CharacterInfo>;
418
+ dispose(): void;
419
+ }
420
+
421
+ export { type BotResponse, type BotVoice, type CameraCaptureRequest, type CharacterAction, CharacterClient, type CharacterInfo, ConnectionState, type CoreFact, type CoreFactsResponse, ErrorCode, EstuaryClient, type EstuaryConfig, EstuaryError, type EstuaryEventMap, type InterruptData, type LiveKitTokenResponse, MemoryClient, type MemoryData, type MemoryGraphEdge, type MemoryGraphNode, type MemoryGraphOptions, type MemoryGraphResponse, type MemoryListOptions, type MemoryListResponse, type MemorySearchOptions, type MemorySearchResponse, type MemoryStatsResponse, type MemoryTimelineOptions, type MemoryTimelineResponse, type MemoryUpdatedEvent, type ParsedAction, type QuotaExceededData, type SessionInfo, type SttResponse, type VoiceManager, type VoiceTransport, parseActions };
package/dist/index.js CHANGED
@@ -44,11 +44,7 @@ var init_errors = __esm({
44
44
  }
45
45
  });
46
46
 
47
- // src/voice/websocket-voice.ts
48
- var websocket_voice_exports = {};
49
- __export(websocket_voice_exports, {
50
- WebSocketVoiceManager: () => WebSocketVoiceManager
51
- });
47
+ // src/audio/audio-utils.ts
52
48
  function resample(input, fromRate, toRate) {
53
49
  const ratio = fromRate / toRate;
54
50
  const outputLength = Math.round(input.length / ratio);
@@ -80,10 +76,21 @@ function uint8ArrayToBase64(bytes) {
80
76
  }
81
77
  return Buffer.from(bytes).toString("base64");
82
78
  }
79
+ var init_audio_utils = __esm({
80
+ "src/audio/audio-utils.ts"() {
81
+ }
82
+ });
83
+
84
+ // src/voice/websocket-voice.ts
85
+ var websocket_voice_exports = {};
86
+ __export(websocket_voice_exports, {
87
+ WebSocketVoiceManager: () => WebSocketVoiceManager
88
+ });
83
89
  var WebSocketVoiceManager;
84
90
  var init_websocket_voice = __esm({
85
91
  "src/voice/websocket-voice.ts"() {
86
92
  init_errors();
93
+ init_audio_utils();
87
94
  WebSocketVoiceManager = class {
88
95
  socketManager;
89
96
  sampleRate;
@@ -770,12 +777,15 @@ async function createVoiceManager(transport, socketManager, sampleRate, logger)
770
777
 
771
778
  // src/rest/rest-client.ts
772
779
  init_errors();
780
+ var DEFAULT_TIMEOUT_MS = 1e4;
773
781
  var RestClient = class {
774
782
  baseUrl;
775
783
  apiKey;
776
- constructor(baseUrl, apiKey) {
784
+ timeoutMs;
785
+ constructor(baseUrl, apiKey, timeoutMs = DEFAULT_TIMEOUT_MS) {
777
786
  this.baseUrl = baseUrl.replace(/\/+$/, "");
778
787
  this.apiKey = apiKey;
788
+ this.timeoutMs = timeoutMs;
779
789
  }
780
790
  async get(path, params) {
781
791
  const url = this.buildUrl(path, params);
@@ -810,7 +820,11 @@ var RestClient = class {
810
820
  async request(url, init) {
811
821
  const headers = new Headers(init.headers);
812
822
  headers.set("X-API-Key", this.apiKey);
813
- const response = await fetch(url, { ...init, headers });
823
+ const response = await fetch(url, {
824
+ ...init,
825
+ headers,
826
+ signal: AbortSignal.timeout(this.timeoutMs)
827
+ });
814
828
  if (!response.ok) {
815
829
  let detail;
816
830
  try {
@@ -866,6 +880,30 @@ var MemoryClient = class {
866
880
  }
867
881
  };
868
882
 
883
+ // src/rest/character-client.ts
884
+ var CharacterClient = class {
885
+ rest;
886
+ constructor(rest) {
887
+ this.rest = rest;
888
+ }
889
+ /** Fetch character details including 3D model and avatar URLs. */
890
+ async getCharacter(characterId) {
891
+ const raw = await this.rest.get(`/api/agents/${characterId}`);
892
+ return {
893
+ id: raw.id,
894
+ name: raw.name,
895
+ tagline: raw.tagline ?? null,
896
+ avatar: raw.avatar ?? null,
897
+ modelUrl: raw.modelUrl ?? null,
898
+ modelPreviewUrl: raw.modelPreviewUrl ?? null,
899
+ modelStatus: raw.modelStatus ?? null,
900
+ sourceImageUrl: raw.sourceImageUrl ?? null
901
+ };
902
+ }
903
+ dispose() {
904
+ }
905
+ };
906
+
869
907
  // src/audio/audio-player.ts
870
908
  var AudioPlayer = class {
871
909
  sampleRate;
@@ -1116,6 +1154,7 @@ var EstuaryClient = class extends TypedEventEmitter {
1116
1154
  voiceManager = null;
1117
1155
  audioPlayer = null;
1118
1156
  _memory;
1157
+ _character;
1119
1158
  _sessionInfo = null;
1120
1159
  actionParsers = /* @__PURE__ */ new Map();
1121
1160
  _hasAutoInterrupted = false;
@@ -1128,11 +1167,16 @@ var EstuaryClient = class extends TypedEventEmitter {
1128
1167
  this.forwardSocketEvents();
1129
1168
  const restClient = new RestClient(config.serverUrl, config.apiKey);
1130
1169
  this._memory = new MemoryClient(restClient, config.characterId, config.playerId);
1170
+ this._character = new CharacterClient(restClient);
1131
1171
  }
1132
1172
  /** Memory API client for querying memories, graphs, and facts */
1133
1173
  get memory() {
1134
1174
  return this._memory;
1135
1175
  }
1176
+ /** Fetch character details including 3D model and avatar URLs. */
1177
+ async getCharacter(characterId) {
1178
+ return this._character.getCharacter(characterId ?? this.config.characterId);
1179
+ }
1136
1180
  /** Current session info (null if not connected) */
1137
1181
  get session() {
1138
1182
  return this._sessionInfo;
@@ -1153,20 +1197,20 @@ var EstuaryClient = class extends TypedEventEmitter {
1153
1197
  return session;
1154
1198
  }
1155
1199
  /** Disconnect from the server */
1156
- disconnect() {
1200
+ async disconnect() {
1157
1201
  this.logger.info("Disconnecting...");
1158
1202
  if (this._autoInterruptGraceTimer) {
1159
1203
  clearTimeout(this._autoInterruptGraceTimer);
1160
1204
  this._autoInterruptGraceTimer = null;
1161
1205
  }
1162
- this.stopVoice();
1206
+ await this.stopVoice();
1163
1207
  this.audioPlayer?.dispose();
1164
1208
  this.audioPlayer = null;
1165
1209
  this.socketManager.disconnect();
1166
1210
  this._sessionInfo = null;
1167
1211
  }
1168
- /** Send a text message to the character */
1169
- sendText(text, textOnly = false) {
1212
+ /** Send a text message to the character. Defaults to textOnly=true (no TTS audio response). Pass textOnly=false to receive voice audio. */
1213
+ sendText(text, textOnly = true) {
1170
1214
  this.ensureConnected();
1171
1215
  this.socketManager.emitEvent("text", { text, textOnly });
1172
1216
  }
@@ -1244,9 +1288,9 @@ var EstuaryClient = class extends TypedEventEmitter {
1244
1288
  this.emit("voiceStarted");
1245
1289
  }
1246
1290
  /** Stop voice input */
1247
- stopVoice() {
1291
+ async stopVoice() {
1248
1292
  if (this.voiceManager?.isActive) {
1249
- this.voiceManager.stop();
1293
+ await this.voiceManager.stop();
1250
1294
  this.voiceManager.dispose();
1251
1295
  this.voiceManager = null;
1252
1296
  this.emit("voiceStopped");
@@ -1263,6 +1307,13 @@ var EstuaryClient = class extends TypedEventEmitter {
1263
1307
  get isMuted() {
1264
1308
  return this.voiceManager?.isMuted ?? false;
1265
1309
  }
1310
+ /** Get/set suppressMicDuringPlayback at runtime (no reconnect needed) */
1311
+ get suppressMicDuringPlayback() {
1312
+ return this.config.suppressMicDuringPlayback ?? false;
1313
+ }
1314
+ set suppressMicDuringPlayback(enabled) {
1315
+ this.config.suppressMicDuringPlayback = enabled;
1316
+ }
1266
1317
  /** Whether voice is currently active */
1267
1318
  get isVoiceActive() {
1268
1319
  return this.voiceManager?.isActive ?? false;