@fishaudio/agent-client 0.0.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/LICENSE +21 -0
- package/README.md +45 -0
- package/dist/chunk-PEVOZB5Y.js +36 -0
- package/dist/chunk-PEVOZB5Y.js.map +1 -0
- package/dist/index.cjs +1192 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +251 -0
- package/dist/index.d.ts +251 -0
- package/dist/index.js +924 -0
- package/dist/index.js.map +1 -0
- package/dist/livekit-B62YPROC.js +207 -0
- package/dist/livekit-B62YPROC.js.map +1 -0
- package/package.json +64 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { Room } from 'livekit-client';
|
|
2
|
+
import { ToolCallSource, SessionToken, SessionLanguage, SessionOverrides } from '@fishaudio/agent-protocol';
|
|
3
|
+
export { AgentSessionCreateRequest, SessionOverrides, SessionToken, ToolCallSource } from '@fishaudio/agent-protocol';
|
|
4
|
+
|
|
5
|
+
type FishAgentErrorCode = "session_request_failed" | "agent_not_public" | "origin_forbidden" | "unsupported_transport" | "mic_permission_denied"
|
|
6
|
+
/** A requested audio device could not be activated, or the browser does not support selecting it. */
|
|
7
|
+
| "device_change_failed" | "connection_failed" | "session_expired" | "tool_failed" | "tool_timeout"
|
|
8
|
+
/** An upstream model/speech provider failed during the session. */
|
|
9
|
+
| "provider_error"
|
|
10
|
+
/** The agent runtime hit an internal error. */
|
|
11
|
+
| "internal_error";
|
|
12
|
+
declare class FishAgentError extends Error {
|
|
13
|
+
readonly code: FishAgentErrorCode;
|
|
14
|
+
/** HTTP status of the failing session request, when the error originated there. */
|
|
15
|
+
readonly statusCode?: number;
|
|
16
|
+
constructor(code: FishAgentErrorCode, message: string, options?: {
|
|
17
|
+
statusCode?: number;
|
|
18
|
+
cause?: unknown;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type SessionStatus = "connecting" | "connected" | "reconnecting" | "ended";
|
|
23
|
+
type AgentMode = "listening" | "thinking" | "speaking";
|
|
24
|
+
type EndReason = "user_hangup" | "agent_hangup" | "connection_lost";
|
|
25
|
+
interface UserTranscriptEvent {
|
|
26
|
+
/** Groups updates of one utterance; interim updates replace, they never append. */
|
|
27
|
+
segmentId: string;
|
|
28
|
+
/** Full text of the utterance so far. */
|
|
29
|
+
text: string;
|
|
30
|
+
final: boolean;
|
|
31
|
+
}
|
|
32
|
+
interface AgentResponseDeltaEvent {
|
|
33
|
+
/** Groups streaming updates of one agent speech segment. */
|
|
34
|
+
segmentId: string;
|
|
35
|
+
delta: string;
|
|
36
|
+
/** Accumulated segment text including this delta. */
|
|
37
|
+
text: string;
|
|
38
|
+
}
|
|
39
|
+
interface AgentResponseEvent {
|
|
40
|
+
segmentId: string;
|
|
41
|
+
text: string;
|
|
42
|
+
}
|
|
43
|
+
/** One transcript segment; `text` is the whole segment so far, refined in place. */
|
|
44
|
+
interface TranscriptSegment {
|
|
45
|
+
segmentId: string;
|
|
46
|
+
role: "user" | "agent";
|
|
47
|
+
text: string;
|
|
48
|
+
final: boolean;
|
|
49
|
+
}
|
|
50
|
+
interface ConversationMessage {
|
|
51
|
+
role: "user" | "agent";
|
|
52
|
+
text: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Tool-call lifecycle, forwarded for every tool the agent runs (including client
|
|
56
|
+
* tools, which complete once this client returns their result). `callId` pairs one
|
|
57
|
+
* started event with exactly one completed/failed event; terminal events repeat
|
|
58
|
+
* name/source so a listener attached mid-call can still render a full item.
|
|
59
|
+
* Emission is a session-creation option (`toolEvents`/`tool_events`, default true).
|
|
60
|
+
*/
|
|
61
|
+
interface ToolCallStartedEvent {
|
|
62
|
+
callId: string;
|
|
63
|
+
toolName: string;
|
|
64
|
+
source: ToolCallSource;
|
|
65
|
+
/** Tool arguments as a JSON string; parse only when `inputTruncated` is false. */
|
|
66
|
+
input: string;
|
|
67
|
+
inputTruncated: boolean;
|
|
68
|
+
}
|
|
69
|
+
interface ToolCallCompletedEvent {
|
|
70
|
+
callId: string;
|
|
71
|
+
toolName: string;
|
|
72
|
+
source: ToolCallSource;
|
|
73
|
+
/** Tool result as a JSON string; parse only when `outputTruncated` is false. */
|
|
74
|
+
output: string;
|
|
75
|
+
outputTruncated: boolean;
|
|
76
|
+
}
|
|
77
|
+
interface ToolCallFailedEvent {
|
|
78
|
+
callId: string;
|
|
79
|
+
toolName: string;
|
|
80
|
+
source: ToolCallSource;
|
|
81
|
+
error: string;
|
|
82
|
+
}
|
|
83
|
+
interface AgentSessionEvents {
|
|
84
|
+
connect: (event: {
|
|
85
|
+
sessionId: string;
|
|
86
|
+
}) => void;
|
|
87
|
+
disconnect: (event: {
|
|
88
|
+
reason: EndReason;
|
|
89
|
+
}) => void;
|
|
90
|
+
statusChange: (status: SessionStatus) => void;
|
|
91
|
+
modeChange: (mode: AgentMode) => void;
|
|
92
|
+
userTranscript: (event: UserTranscriptEvent) => void;
|
|
93
|
+
agentResponseDelta: (event: AgentResponseDeltaEvent) => void;
|
|
94
|
+
agentResponse: (event: AgentResponseEvent) => void;
|
|
95
|
+
/** Finalized messages only, in conversation order — the "just give me a chat log" event. */
|
|
96
|
+
message: (message: ConversationMessage) => void;
|
|
97
|
+
toolCallStarted: (event: ToolCallStartedEvent) => void;
|
|
98
|
+
toolCallCompleted: (event: ToolCallCompletedEvent) => void;
|
|
99
|
+
toolCallFailed: (event: ToolCallFailedEvent) => void;
|
|
100
|
+
error: (error: FishAgentError) => void;
|
|
101
|
+
}
|
|
102
|
+
type AgentSessionCallbacks = {
|
|
103
|
+
[K in keyof AgentSessionEvents as `on${Capitalize<K>}`]: AgentSessionEvents[K];
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
declare const DEFAULT_SERVER_URL = "https://api.fish.audio";
|
|
107
|
+
interface SessionRequestOptions {
|
|
108
|
+
/** Public agent: the SDK creates the session directly against the Fish API. */
|
|
109
|
+
agentId?: string;
|
|
110
|
+
/** Session token created by the host backend, passed through verbatim. */
|
|
111
|
+
sessionToken?: SessionToken;
|
|
112
|
+
serverUrl?: string;
|
|
113
|
+
/** Sugar for `overrides.language`; pair with a voice in that language. */
|
|
114
|
+
language?: SessionLanguage;
|
|
115
|
+
/**
|
|
116
|
+
* IANA timezone for the agent's sense of local time in this session. Omit to
|
|
117
|
+
* use the browser's timezone (sent automatically as a hint). With
|
|
118
|
+
* `sessionToken` auth the host backend chooses instead, via `timezone` on its
|
|
119
|
+
* session-creation call.
|
|
120
|
+
*/
|
|
121
|
+
timezone?: string;
|
|
122
|
+
/**
|
|
123
|
+
* The agent knows the current date and time by default. Set false to withhold
|
|
124
|
+
* both from this session's prompt. With `sessionToken` auth the host backend
|
|
125
|
+
* chooses instead, via `world_context` on its session-creation call.
|
|
126
|
+
*/
|
|
127
|
+
worldContext?: boolean;
|
|
128
|
+
/** Per-session config overrides; each field must be allow-listed on the agent. */
|
|
129
|
+
overrides?: SessionOverrides;
|
|
130
|
+
/** `{{name}}` template values for the agent's prompt and first message. */
|
|
131
|
+
dynamicVariables?: Record<string, string | number | boolean>;
|
|
132
|
+
endUserId?: string;
|
|
133
|
+
/** Caller-owned tag, stored and returned verbatim; the platform never interprets it. */
|
|
134
|
+
metadata?: Record<string, unknown>;
|
|
135
|
+
/**
|
|
136
|
+
* Stream the agent's tool-call lifecycle (toolCallStarted/Completed/Failed
|
|
137
|
+
* events, with payloads) to this session. Default true; set false when tool
|
|
138
|
+
* data must stay hidden from this client. With `sessionToken` auth the host
|
|
139
|
+
* backend chooses instead, via `tool_events` on its session-creation call.
|
|
140
|
+
*/
|
|
141
|
+
toolEvents?: boolean;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
type Listener = (...args: any[]) => void;
|
|
145
|
+
/** Minimal typed emitter; listener errors are isolated so one bad consumer can't break the session. */
|
|
146
|
+
declare class TypedEmitter<Events extends Record<keyof Events, Listener>> {
|
|
147
|
+
private readonly listeners;
|
|
148
|
+
on<K extends keyof Events>(event: K, listener: Events[K]): this;
|
|
149
|
+
off<K extends keyof Events>(event: K, listener: Events[K]): this;
|
|
150
|
+
once<K extends keyof Events>(event: K, listener: Events[K]): this;
|
|
151
|
+
protected emit<K extends keyof Events>(event: K, ...args: Parameters<Events[K]>): void;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
type ClientToolHandler = (params: Record<string, unknown>, context: {
|
|
155
|
+
callId: string;
|
|
156
|
+
toolName: string;
|
|
157
|
+
}) => unknown | Promise<unknown>;
|
|
158
|
+
|
|
159
|
+
interface AgentSessionOptions extends SessionRequestOptions {
|
|
160
|
+
clientTools?: Record<string, ClientToolHandler>;
|
|
161
|
+
clientToolTimeoutMs?: number;
|
|
162
|
+
/**
|
|
163
|
+
* Capture the microphone on start. Default true. Set false to join without
|
|
164
|
+
* requesting it (text-first UIs); the first `setMicMuted(false)` then
|
|
165
|
+
* captures — the permission prompt happens there, so call it from a user
|
|
166
|
+
* gesture.
|
|
167
|
+
*/
|
|
168
|
+
microphone?: boolean;
|
|
169
|
+
audio?: {
|
|
170
|
+
inputDeviceId?: string;
|
|
171
|
+
/** Playback device (`setSinkId`); start rejects with `device_change_failed`
|
|
172
|
+
* where output selection is unsupported (before creating a server session)
|
|
173
|
+
* or the device cannot be used (before connecting). */
|
|
174
|
+
outputDeviceId?: string;
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Hold a screen wake lock while the session is live, so long calls survive
|
|
178
|
+
* the phone trying to sleep. Default true; denial is silent. Set false to
|
|
179
|
+
* leave screen policy to the page.
|
|
180
|
+
*/
|
|
181
|
+
wakeLock?: boolean;
|
|
182
|
+
callbacks?: Partial<AgentSessionCallbacks>;
|
|
183
|
+
}
|
|
184
|
+
declare class AgentSession extends TypedEmitter<AgentSessionEvents> {
|
|
185
|
+
#private;
|
|
186
|
+
private constructor();
|
|
187
|
+
/**
|
|
188
|
+
* Obtain a session token (if needed), connect, publish the microphone and
|
|
189
|
+
* hand back a live session. Rejects with FishAgentError on session-request,
|
|
190
|
+
* permission or connect failures.
|
|
191
|
+
*/
|
|
192
|
+
static start(options: AgentSessionOptions): Promise<AgentSession>;
|
|
193
|
+
get sessionId(): string;
|
|
194
|
+
get status(): SessionStatus;
|
|
195
|
+
get mode(): AgentMode;
|
|
196
|
+
get isSpeaking(): boolean;
|
|
197
|
+
get micMuted(): boolean;
|
|
198
|
+
get endReason(): EndReason | undefined;
|
|
199
|
+
/**
|
|
200
|
+
* Snapshot of every transcript segment so far, in conversation order. Seed a
|
|
201
|
+
* consumer that subscribes after events already fired (e.g. a component
|
|
202
|
+
* mounted right after start), then apply live events by segmentId.
|
|
203
|
+
*/
|
|
204
|
+
getTranscript(): TranscriptSegment[];
|
|
205
|
+
/** `audio: false` asks the agent to answer this turn in text only (no TTS). */
|
|
206
|
+
sendUserMessage(text: string, options?: {
|
|
207
|
+
audio?: boolean;
|
|
208
|
+
}): void;
|
|
209
|
+
sendUserActivity(): void;
|
|
210
|
+
interrupt(): void;
|
|
211
|
+
registerClientTool(name: string, handler: ClientToolHandler): void;
|
|
212
|
+
/**
|
|
213
|
+
* After a `microphone: false` start, the first unmute captures and publishes
|
|
214
|
+
* the microphone — the permission prompt happens here. A denial rejects with
|
|
215
|
+
* `mic_permission_denied` and the session stays muted.
|
|
216
|
+
*/
|
|
217
|
+
setMicMuted(muted: boolean): Promise<void>;
|
|
218
|
+
/** Call from a user gesture to satisfy browser autoplay policies. */
|
|
219
|
+
startAudio(): Promise<void>;
|
|
220
|
+
/**
|
|
221
|
+
* Switch the microphone mid-call. While the mic is not captured yet
|
|
222
|
+
* (`microphone: false` start, still muted) this records the preference for
|
|
223
|
+
* the first unmute. Rejects with `device_change_failed` when the device
|
|
224
|
+
* cannot be activated, switching back to the previous microphone (best
|
|
225
|
+
* effort — the transport stops the old capture before acquiring the new).
|
|
226
|
+
*/
|
|
227
|
+
setInputDevice(deviceId: string): Promise<void>;
|
|
228
|
+
/**
|
|
229
|
+
* Route the agent's audio to an output device (`setSinkId`); pass `""` to
|
|
230
|
+
* return to the default device. Rejects with `device_change_failed` where
|
|
231
|
+
* the browser does not support output selection (common on mobile browsers)
|
|
232
|
+
* or the device cannot be used; playback stays on the previous device.
|
|
233
|
+
*/
|
|
234
|
+
setOutputDevice(deviceId: string): Promise<void>;
|
|
235
|
+
setOutputVolume(volume: number): void;
|
|
236
|
+
getOutputVolume(): number;
|
|
237
|
+
getInputVolume(): number;
|
|
238
|
+
getOutputFrequencyData(): Uint8Array;
|
|
239
|
+
getInputFrequencyData(): Uint8Array;
|
|
240
|
+
/**
|
|
241
|
+
* Escape hatch: the underlying LiveKit `Room`, for needs the session API
|
|
242
|
+
* doesn't cover (connection-quality telemetry, publishing extra tracks).
|
|
243
|
+
* Code using it couples to this SDK's transport choice and livekit-client
|
|
244
|
+
* version — prefer the session API where one exists. `undefined` after the
|
|
245
|
+
* session ends, or when a custom transport doesn't expose a room.
|
|
246
|
+
*/
|
|
247
|
+
getRoom(): Room | undefined;
|
|
248
|
+
end(): Promise<void>;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export { type AgentMode, type AgentResponseDeltaEvent, type AgentResponseEvent, AgentSession, type AgentSessionCallbacks, type AgentSessionEvents, type AgentSessionOptions, type ClientToolHandler, type ConversationMessage, DEFAULT_SERVER_URL, type EndReason, FishAgentError, type FishAgentErrorCode, type SessionStatus, type ToolCallCompletedEvent, type ToolCallFailedEvent, type ToolCallStartedEvent, type TranscriptSegment, type UserTranscriptEvent };
|