@lumavox/client 0.2.0 → 0.5.0
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 +8 -3
- package/dist/client.d.ts +5 -6
- package/dist/client.js +2 -2
- package/dist/conversation.d.ts +15 -6
- package/dist/conversation.js +17 -9
- package/dist/events.d.ts +41 -2
- package/dist/gen/index.d.ts +1 -1
- package/dist/gen/types.gen.d.ts +46 -0
- package/dist/protocol.gen.d.ts +5 -2
- package/dist/protocol.gen.js +5 -2
- package/dist/socket.js +6 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,15 +80,16 @@ key, dials, authenticates, and from then on:
|
|
|
80
80
|
connection limit, 0.5 s for anything else, ±20 % jitter, final after
|
|
81
81
|
five in a row — and **rests** after the edge hangs up on a quiet
|
|
82
82
|
connection (4007), dialling again on the next `send`;
|
|
83
|
-
- **watches**:
|
|
84
|
-
and dialled
|
|
83
|
+
- **watches**: it pings after 30 s with nothing from the edge, and a
|
|
84
|
+
minute with nothing — no `pong` — is a dead socket, dropped and dialled
|
|
85
|
+
again;
|
|
85
86
|
- publishes `snapshot` — `state`, `ready`, the `turn` (its text, chunks,
|
|
86
87
|
mood, tool, knowledge), `caption`, `relation`, `queued` — with
|
|
87
88
|
`subscribe(fn)`.
|
|
88
89
|
|
|
89
90
|
| Handler | Frame |
|
|
90
91
|
|---|---|
|
|
91
|
-
| `onReady` `onTurnStart` `onHeard` `onHeardPartial` `onKnowledge` `onMood` `onThought` `onText` `onChunk` `onToolStart` `onToolEnd` `onUsage` `onMuted` `onAudioStart` `onAudioEnd` `onTranscript` `onDone` `onInterrupted` `onError` | the wire's frame, as it is |
|
|
92
|
+
| `onReady` `onTurnStart` `onHeard` `onHeardPartial` `onKnowledge` `onMood` `onThought` `onText` `onChunk` `onToolStart` `onToolEnd` `onToolConfirm` `onUsage` `onMuted` `onAudioStart` `onAudioEnd` `onTranscript` `onDone` `onInterrupted` `onError` | the wire's frame, as it is |
|
|
92
93
|
| `onAudio` | `{ pcm, chunk, turn, sample_rate, channels }`: raw 16-bit PCM, never copied |
|
|
93
94
|
| `onRelation` | the relationship, each change once |
|
|
94
95
|
| `onState` | `connecting` `ready` `busy` `reconnecting` `dormant` `closed` |
|
|
@@ -100,6 +101,10 @@ key, dials, authenticates, and from then on:
|
|
|
100
101
|
With no `onAudio` handler every turn asks for no speech, so nothing pays
|
|
101
102
|
for audio nobody hears; `connect`'s `{ speech }` overrides that.
|
|
102
103
|
|
|
104
|
+
A tool marked "ask first" sends `tool.confirm` and does not run:
|
|
105
|
+
`confirmTool(callId, yes)` answers with the person's tap — a turn of
|
|
106
|
+
theirs, queued as `send` is, which runs the tool first on a yes.
|
|
107
|
+
|
|
103
108
|
### Speaking
|
|
104
109
|
|
|
105
110
|
```ts
|
package/dist/client.d.ts
CHANGED
|
@@ -78,14 +78,13 @@ export interface Sessions {
|
|
|
78
78
|
extract(id: string, options?: RequestOptions): Promise<CompactionInfo>;
|
|
79
79
|
}
|
|
80
80
|
export interface Facts {
|
|
81
|
+
/** Everything remembered about the person, oldest first, 200 a page. */
|
|
82
|
+
list(options?: RequestOptions): AsyncGenerator<FactInfo, void, undefined>;
|
|
81
83
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* route pages.
|
|
84
|
+
* One page of them, 100 by default; `cursor` is the `next_cursor` of the
|
|
85
|
+
* page before.
|
|
85
86
|
*/
|
|
86
|
-
|
|
87
|
-
/** One page of them, as the route answers it. */
|
|
88
|
-
page(options?: RequestOptions): Promise<FactPage>;
|
|
87
|
+
page(options?: RequestOptions, cursor?: string): Promise<FactPage>;
|
|
89
88
|
/** Forget one: `true`, or `false` when it is already gone. */
|
|
90
89
|
delete(id: string, options?: RequestOptions): Promise<boolean>;
|
|
91
90
|
/** Forget everything about the person: how many facts went. Their conversations stay. */
|
package/dist/client.js
CHANGED
|
@@ -76,7 +76,7 @@ export function createClient(options) {
|
|
|
76
76
|
/** One page of the list at `path`. */
|
|
77
77
|
const read = (path, params = {}, request) => send({ method: "GET", path, query: { ...params } }, request);
|
|
78
78
|
const page = (params = {}, request) => read("/v1/agent/sessions", params, request);
|
|
79
|
-
const factPage = (request, cursor) => read("/v1/agent/facts", { cursor }, request);
|
|
79
|
+
const factPage = (request, cursor, limit) => read("/v1/agent/facts", { limit, cursor }, request);
|
|
80
80
|
const relationPage = (params = {}, request) => read("/v1/agent/relations", params, request);
|
|
81
81
|
const get = (id, params = {}, request) => send({ method: "GET", path: sessionPath(id), query: { ...params } }, request);
|
|
82
82
|
return {
|
|
@@ -102,7 +102,7 @@ export function createClient(options) {
|
|
|
102
102
|
extract: (id, request) => send({ method: "POST", path: sessionPath(id, "/extract") }, request),
|
|
103
103
|
},
|
|
104
104
|
facts: {
|
|
105
|
-
list: (request) => pages((cursor) => factPage(request, cursor)),
|
|
105
|
+
list: (request) => pages((cursor) => factPage(request, cursor, PAGE)),
|
|
106
106
|
page: factPage,
|
|
107
107
|
delete: (id, request) => done(send({ method: "DELETE", path: `/v1/agent/facts/${segment(id)}` }, request)),
|
|
108
108
|
deleteAll: (request) => send({ method: "DELETE", path: "/v1/agent/facts" }, request),
|
package/dist/conversation.d.ts
CHANGED
|
@@ -22,10 +22,12 @@
|
|
|
22
22
|
* had it — audio sent for it would close the socket (4011).
|
|
23
23
|
* - **Speech is not paid for unheard**: with no `onAudio` handler every
|
|
24
24
|
* turn says `speech: false`, unless `connect`'s options say otherwise.
|
|
25
|
-
* - **A watchdog
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* - **A watchdog that pings**: after 30 s with nothing from the edge it
|
|
26
|
+
* sends `ping` (`KEEPALIVE_PING`, which the edge's runtime answers with
|
|
27
|
+
* its object asleep), and past a minute with nothing at all — no `pong`
|
|
28
|
+
* to two pings — the socket is dead (half-open, after a phone changed
|
|
29
|
+
* networks): it is dropped and dialled again. A ping never resets the
|
|
30
|
+
* edge's idle timer.
|
|
29
31
|
* - **The app's handlers cannot break it**: one that throws is rethrown on
|
|
30
32
|
* its own (`call`), after the state it was told about is in place.
|
|
31
33
|
*
|
|
@@ -140,6 +142,8 @@ export interface ConversationHandlers {
|
|
|
140
142
|
onChunk?: On<"text.chunk">;
|
|
141
143
|
onToolStart?: On<"tool.start">;
|
|
142
144
|
onToolEnd?: On<"tool.end">;
|
|
145
|
+
/** A tool that asks first waits for the person: answer with `confirmTool`. */
|
|
146
|
+
onToolConfirm?: On<"tool.confirm">;
|
|
143
147
|
onUsage?: On<"usage">;
|
|
144
148
|
onMuted?: On<"muted">;
|
|
145
149
|
onAudioStart?: On<"audio.start">;
|
|
@@ -236,7 +240,6 @@ export declare class Conversation {
|
|
|
236
240
|
private deadline;
|
|
237
241
|
private watchdog;
|
|
238
242
|
private heardAt;
|
|
239
|
-
private saidAt;
|
|
240
243
|
constructor(setup: Setup);
|
|
241
244
|
/** What is known now. A new object on every change: compare by identity. */
|
|
242
245
|
get snapshot(): Snapshot;
|
|
@@ -249,6 +252,12 @@ export declare class Conversation {
|
|
|
249
252
|
* 1 to 32,000 characters, or it is `dropped: refused` here.
|
|
250
253
|
*/
|
|
251
254
|
send(text: string, options?: TurnOptions): Promise<TurnOutcome>;
|
|
255
|
+
/**
|
|
256
|
+
* Answer a `tool.confirm` with the person's tap: a turn of theirs — "Yes."
|
|
257
|
+
* or "No." in the transcript — which runs the tool first on a yes.
|
|
258
|
+
* Queued as `send` is; never rejects.
|
|
259
|
+
*/
|
|
260
|
+
confirmTool(callId: string, yes: boolean, options?: TurnOptions): Promise<TurnOutcome>;
|
|
252
261
|
/**
|
|
253
262
|
* Open a recording at `rate`, which must be one of `RECORDING_RATES`.
|
|
254
263
|
* Answers its id. A recording already open is abandoned, as the edge
|
|
@@ -277,7 +286,7 @@ export declare class Conversation {
|
|
|
277
286
|
cancel(): void;
|
|
278
287
|
/** Stop speaking, and let the turn finish: the rest of the reply is never spoken, nor billed. */
|
|
279
288
|
mute(): void;
|
|
280
|
-
/** Liveness only: answered with `pong`, and never counted as activity. Not needed — the SDK
|
|
289
|
+
/** Liveness only: answered with `pong`, and never counted as activity. Not needed — the SDK pings after 30 s of silence itself. */
|
|
281
290
|
ping(): void;
|
|
282
291
|
/**
|
|
283
292
|
* Dial now: the app came to the foreground, the network came back. A
|
package/dist/conversation.js
CHANGED
|
@@ -26,6 +26,7 @@ const HANDLER = {
|
|
|
26
26
|
"text.chunk": "onChunk",
|
|
27
27
|
"tool.start": "onToolStart",
|
|
28
28
|
"tool.end": "onToolEnd",
|
|
29
|
+
"tool.confirm": "onToolConfirm",
|
|
29
30
|
usage: "onUsage",
|
|
30
31
|
muted: "onMuted",
|
|
31
32
|
"audio.start": "onAudioStart",
|
|
@@ -106,7 +107,6 @@ export class Conversation {
|
|
|
106
107
|
this.deadline = null;
|
|
107
108
|
this.watchdog = null;
|
|
108
109
|
this.heardAt = 0;
|
|
109
|
-
this.saidAt = 0;
|
|
110
110
|
this.sessionId = setup.sessionId;
|
|
111
111
|
this.setup = setup;
|
|
112
112
|
this.speech =
|
|
@@ -139,6 +139,14 @@ export class Conversation {
|
|
|
139
139
|
}
|
|
140
140
|
return this.enqueue({ type: "user_message", text }, options);
|
|
141
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Answer a `tool.confirm` with the person's tap: a turn of theirs — "Yes."
|
|
144
|
+
* or "No." in the transcript — which runs the tool first on a yes.
|
|
145
|
+
* Queued as `send` is; never rejects.
|
|
146
|
+
*/
|
|
147
|
+
confirmTool(callId, yes, options = {}) {
|
|
148
|
+
return this.enqueue({ type: "tool.confirmed", call_id: callId, yes }, options);
|
|
149
|
+
}
|
|
142
150
|
/**
|
|
143
151
|
* Open a recording at `rate`, which must be one of `RECORDING_RATES`.
|
|
144
152
|
* Answers its id. A recording already open is abandoned, as the edge
|
|
@@ -204,7 +212,6 @@ export class Conversation {
|
|
|
204
212
|
recording.held.push(data.slice(0));
|
|
205
213
|
else if (recording.socket === this.generation && this.socket) {
|
|
206
214
|
this.socket.sendBinary(data);
|
|
207
|
-
this.saidAt = Date.now();
|
|
208
215
|
}
|
|
209
216
|
return true;
|
|
210
217
|
}
|
|
@@ -251,7 +258,7 @@ export class Conversation {
|
|
|
251
258
|
mute() {
|
|
252
259
|
this.socket?.send({ type: "mute" });
|
|
253
260
|
}
|
|
254
|
-
/** Liveness only: answered with `pong`, and never counted as activity. Not needed — the SDK
|
|
261
|
+
/** Liveness only: answered with `pong`, and never counted as activity. Not needed — the SDK pings after 30 s of silence itself. */
|
|
255
262
|
ping() {
|
|
256
263
|
this.socket?.send({ type: "ping" });
|
|
257
264
|
}
|
|
@@ -324,14 +331,16 @@ export class Conversation {
|
|
|
324
331
|
this.finish(0, "The socket could not be opened.", true, error);
|
|
325
332
|
return;
|
|
326
333
|
}
|
|
327
|
-
this.heardAt =
|
|
334
|
+
this.heardAt = Date.now();
|
|
328
335
|
this.socketReady = false;
|
|
329
336
|
this.deadline = setTimeout(() => this.drop(generation, "The connection never became ready."), READY_DEADLINE_MS);
|
|
330
337
|
this.watchdog = setInterval(() => {
|
|
331
|
-
const quiet = Date.now() -
|
|
338
|
+
const quiet = Date.now() - this.heardAt;
|
|
332
339
|
if (quiet > 2 * KEEPALIVE_SECONDS * 1000) {
|
|
333
340
|
this.drop(generation, "Nothing came from the edge for a minute.");
|
|
334
341
|
}
|
|
342
|
+
else if (quiet >= KEEPALIVE_SECONDS * 1000)
|
|
343
|
+
this.ping();
|
|
335
344
|
}, KEEPALIVE_SECONDS * 500);
|
|
336
345
|
}
|
|
337
346
|
/** A socket given up on from this side: lost as a dropped network is (1006). */
|
|
@@ -686,14 +695,14 @@ export class Conversation {
|
|
|
686
695
|
next.resolve(dropped(recording.dropped ?? "closed"));
|
|
687
696
|
continue;
|
|
688
697
|
}
|
|
689
|
-
// A message
|
|
690
|
-
|
|
698
|
+
// A message or a tap — a turn with no recording of its own — abandons
|
|
699
|
+
// an open recording, at the edge and here.
|
|
700
|
+
if (!recording && this.open) {
|
|
691
701
|
this.abandon("cancelled");
|
|
692
702
|
}
|
|
693
703
|
this.inFlight = next;
|
|
694
704
|
next.sent += 1;
|
|
695
705
|
this.socket.send(next.frame);
|
|
696
|
-
this.saidAt = Date.now();
|
|
697
706
|
this.emit({ turn: FRESH });
|
|
698
707
|
}
|
|
699
708
|
this.emit({ queued: this.queue.length });
|
|
@@ -719,7 +728,6 @@ export class Conversation {
|
|
|
719
728
|
}
|
|
720
729
|
said(recording) {
|
|
721
730
|
recording.socket = this.generation;
|
|
722
|
-
this.saidAt = Date.now();
|
|
723
731
|
}
|
|
724
732
|
/** A recording's words are still to come: a partial is a caption. */
|
|
725
733
|
listening() {
|
package/dist/events.d.ts
CHANGED
|
@@ -85,11 +85,46 @@ export interface TextChunkFrame extends Frame<"text.chunk">, InTurn {
|
|
|
85
85
|
export interface ThoughtDeltaFrame extends Frame<"thought.delta">, InTurn {
|
|
86
86
|
text: string;
|
|
87
87
|
}
|
|
88
|
+
/** Who runs a tool: the platform's own, your server's, or your app's. */
|
|
89
|
+
export type ToolKind = "platform" | "webhook" | "app";
|
|
90
|
+
/** The model called a tool; its `tool.end` follows. */
|
|
88
91
|
export interface ToolStartFrame extends Frame<"tool.start">, InTurn {
|
|
89
92
|
name: string;
|
|
93
|
+
kind: ToolKind;
|
|
94
|
+
/** Your tool's call, `call_…`; `null` for the platform's own. */
|
|
95
|
+
call_id: string | null;
|
|
90
96
|
}
|
|
97
|
+
/** A tool's call is over: whether it answered, and how long it took. */
|
|
91
98
|
export interface ToolEndFrame extends Frame<"tool.end">, InTurn {
|
|
92
99
|
name: string;
|
|
100
|
+
kind: ToolKind;
|
|
101
|
+
call_id: string | null;
|
|
102
|
+
ok: boolean;
|
|
103
|
+
ms: number;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* A tool marked "ask first" waits for the person's yes: the agent asks in
|
|
107
|
+
* its own words, and `confirmTool(call_id, yes)` answers with a tap.
|
|
108
|
+
*/
|
|
109
|
+
export interface ToolConfirmFrame extends Frame<"tool.confirm">, InTurn {
|
|
110
|
+
call_id: string;
|
|
111
|
+
name: string;
|
|
112
|
+
arguments: Record<string, unknown>;
|
|
113
|
+
}
|
|
114
|
+
/** One call of your tool in a turn, as `turn.done` and the transcript keep it. */
|
|
115
|
+
export interface ToolCall {
|
|
116
|
+
call_id: string;
|
|
117
|
+
name: string;
|
|
118
|
+
kind: "webhook" | "app";
|
|
119
|
+
arguments: Record<string, unknown>;
|
|
120
|
+
/** What it answered, as the model read it (16 KB at most); `null` for none. */
|
|
121
|
+
result: unknown;
|
|
122
|
+
ok: boolean;
|
|
123
|
+
/** What failed, as the model was told; `null` when nothing did. */
|
|
124
|
+
error: string | null;
|
|
125
|
+
ms: number;
|
|
126
|
+
/** Which of the reply's rounds, 1 to 3; 0 for a call the person confirmed with a tap. */
|
|
127
|
+
round: number;
|
|
93
128
|
}
|
|
94
129
|
export interface KnowledgeEntry {
|
|
95
130
|
entry_id: string;
|
|
@@ -157,6 +192,8 @@ export interface TurnDoneFrame extends Frame<"turn.done">, InTurn {
|
|
|
157
192
|
chunks_spoken: number;
|
|
158
193
|
heard: string | null;
|
|
159
194
|
heard_seconds: number | null;
|
|
195
|
+
/** Your tools it called, in order. */
|
|
196
|
+
tool_calls: ToolCall[];
|
|
160
197
|
timings: TurnTimings;
|
|
161
198
|
}
|
|
162
199
|
/** The turn ended early; what was written before it stopped still stands. */
|
|
@@ -186,8 +223,9 @@ export interface ErrorFrame extends Frame<"error"> {
|
|
|
186
223
|
/** The recording it refused or failed. */
|
|
187
224
|
recording_id: string | null;
|
|
188
225
|
}
|
|
189
|
-
/** The answer to `ping`,
|
|
190
|
-
export interface PongFrame
|
|
226
|
+
/** The answer to `ping`, from the edge's runtime: the one frame with no `seq`. */
|
|
227
|
+
export interface PongFrame {
|
|
228
|
+
type: "pong";
|
|
191
229
|
}
|
|
192
230
|
/**
|
|
193
231
|
* Every event, by name. **Exhaustive**: a name in the vocabulary with no
|
|
@@ -206,6 +244,7 @@ export type ServerFrames = Exhaustive<{
|
|
|
206
244
|
"thought.delta": ThoughtDeltaFrame;
|
|
207
245
|
"tool.start": ToolStartFrame;
|
|
208
246
|
"tool.end": ToolEndFrame;
|
|
247
|
+
"tool.confirm": ToolConfirmFrame;
|
|
209
248
|
knowledge: KnowledgeFrame;
|
|
210
249
|
"audio.start": AudioStartFrame;
|
|
211
250
|
"audio.end": AudioEndFrame;
|
package/dist/gen/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export type { ClientOptions, CompactionInfo, CompactRequest, CompactSessionData, CompactSessionError, CompactSessionErrors, CompactSessionResponse, CompactSessionResponses, CreateSessionData, CreateSessionError, CreateSessionErrors, CreateSessionResponse, CreateSessionResponses, DeleteAllFactsData, DeleteAllFactsError, DeleteAllFactsErrors, DeleteAllFactsResponse, DeleteAllFactsResponses, DeleteFactData, DeleteFactError, DeleteFactErrors, DeleteFactResponse, DeleteFactResponses, DeleteSessionData, DeleteSessionError, DeleteSessionErrors, DeleteSessionResponse, DeleteSessionResponses, ErrorCode, ErrorInfo, ErrorResponse, ExtractSessionFactsData, ExtractSessionFactsError, ExtractSessionFactsErrors, ExtractSessionFactsResponse, ExtractSessionFactsResponses, FactInfo, FactPage, FactsDeleted, GetSessionData, GetSessionError, GetSessionErrors, GetSessionResponse, GetSessionResponses, KnowledgeCitation, KnowledgeLookupInfo, ListFactsData, ListFactsError, ListFactsErrors, ListFactsResponse, ListFactsResponses, ListRelationsData, ListRelationsError, ListRelationsErrors, ListRelationsResponse, ListRelationsResponses, ListSessionsData, ListSessionsError, ListSessionsErrors, ListSessionsResponse, ListSessionsResponses, MessageInfo, MessageKnowledge, MessagePage, RelationInfo, RelationPage, SessionCreateRequest, SessionDetail, SessionInfo, SessionPage, ValidationIssue } from './types.gen.js';
|
|
1
|
+
export type { ClientOptions, CompactionInfo, CompactRequest, CompactSessionData, CompactSessionError, CompactSessionErrors, CompactSessionResponse, CompactSessionResponses, CreateSessionData, CreateSessionError, CreateSessionErrors, CreateSessionResponse, CreateSessionResponses, DeleteAllFactsData, DeleteAllFactsError, DeleteAllFactsErrors, DeleteAllFactsResponse, DeleteAllFactsResponses, DeleteFactData, DeleteFactError, DeleteFactErrors, DeleteFactResponse, DeleteFactResponses, DeleteSessionData, DeleteSessionError, DeleteSessionErrors, DeleteSessionResponse, DeleteSessionResponses, ErrorCode, ErrorInfo, ErrorResponse, ExtractSessionFactsData, ExtractSessionFactsError, ExtractSessionFactsErrors, ExtractSessionFactsResponse, ExtractSessionFactsResponses, FactInfo, FactPage, FactsDeleted, GetSessionData, GetSessionError, GetSessionErrors, GetSessionResponse, GetSessionResponses, KnowledgeCitation, KnowledgeLookupInfo, ListFactsData, ListFactsError, ListFactsErrors, ListFactsResponse, ListFactsResponses, ListRelationsData, ListRelationsError, ListRelationsErrors, ListRelationsResponse, ListRelationsResponses, ListSessionsData, ListSessionsError, ListSessionsErrors, ListSessionsResponse, ListSessionsResponses, MessageInfo, MessageKnowledge, MessagePage, MessageToolCall, RelationInfo, RelationPage, SessionCreateRequest, SessionDetail, SessionInfo, SessionPage, ValidationIssue } from './types.gen.js';
|
package/dist/gen/types.gen.d.ts
CHANGED
|
@@ -89,6 +89,10 @@ export type MessageInfo = {
|
|
|
89
89
|
*/
|
|
90
90
|
mood_intensity: number | null;
|
|
91
91
|
role: 'user' | 'assistant';
|
|
92
|
+
/**
|
|
93
|
+
* On a reply: the calls of your tools it made, in order, each with its arguments and what it answered. Empty when it called none, and on the person's messages.
|
|
94
|
+
*/
|
|
95
|
+
tool_calls: Array<MessageToolCall>;
|
|
92
96
|
};
|
|
93
97
|
export type MessageKnowledge = {
|
|
94
98
|
lookups: Array<KnowledgeLookupInfo>;
|
|
@@ -114,6 +118,40 @@ export type KnowledgeCitation = {
|
|
|
114
118
|
score: number;
|
|
115
119
|
title: string;
|
|
116
120
|
};
|
|
121
|
+
export type MessageToolCall = {
|
|
122
|
+
/**
|
|
123
|
+
* The call's id, `call_…`: what your server or app was sent.
|
|
124
|
+
*/
|
|
125
|
+
call_id: string;
|
|
126
|
+
name: string;
|
|
127
|
+
kind: 'webhook' | 'app';
|
|
128
|
+
/**
|
|
129
|
+
* What the model called it with.
|
|
130
|
+
*/
|
|
131
|
+
arguments: {
|
|
132
|
+
[key: string]: unknown;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* What it answered, as the model read it — its JSON, or its text, cut at 16 KB. Null when it answered nothing.
|
|
136
|
+
*/
|
|
137
|
+
result?: unknown;
|
|
138
|
+
/**
|
|
139
|
+
* It answered in time, with a 2xx or a result.
|
|
140
|
+
*/
|
|
141
|
+
ok: boolean;
|
|
142
|
+
/**
|
|
143
|
+
* What failed, as the model was told — or, for a tool that asks first, that it waited for the person's yes. Null when nothing did.
|
|
144
|
+
*/
|
|
145
|
+
error: string | null;
|
|
146
|
+
/**
|
|
147
|
+
* How long it took.
|
|
148
|
+
*/
|
|
149
|
+
ms: number;
|
|
150
|
+
/**
|
|
151
|
+
* Which of the reply's rounds of calls, 1 to 3; 0 for a call the person confirmed with a tap.
|
|
152
|
+
*/
|
|
153
|
+
round: number;
|
|
154
|
+
};
|
|
117
155
|
export type RelationInfo = {
|
|
118
156
|
agent_id: string;
|
|
119
157
|
/**
|
|
@@ -597,6 +635,14 @@ export type ListFactsData = {
|
|
|
597
635
|
* Optional, and only ever the key's own end user — their `eu_...` id or your own id for them. Anybody else is a 403.
|
|
598
636
|
*/
|
|
599
637
|
end_user_id?: string;
|
|
638
|
+
/**
|
|
639
|
+
* How many to answer, 1 to 200.
|
|
640
|
+
*/
|
|
641
|
+
limit?: number;
|
|
642
|
+
/**
|
|
643
|
+
* The `next_cursor` of the page before.
|
|
644
|
+
*/
|
|
645
|
+
cursor?: string;
|
|
600
646
|
};
|
|
601
647
|
url: '/v1/agent/facts';
|
|
602
648
|
};
|
package/dist/protocol.gen.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/** The protocol, sent as the WebSocket subprotocol and echoed on `ready`. */
|
|
2
2
|
export declare const PROTOCOL = "ino.v2";
|
|
3
3
|
/** Every frame a client may send; the edge closes on any other (4009). */
|
|
4
|
-
export declare const CLIENT_VERBS: readonly ["auth", "user_message", "user_audio.start", "user_audio.end", "cancel", "mute", "ping"];
|
|
4
|
+
export declare const CLIENT_VERBS: readonly ["auth", "user_message", "user_audio.start", "user_audio.end", "cancel", "mute", "ping", "tool.confirmed"];
|
|
5
5
|
export type ClientVerb = (typeof CLIENT_VERBS)[number];
|
|
6
6
|
/** Every event the edge sends. */
|
|
7
|
-
export declare const SERVER_EVENTS: readonly ["ready", "turn.start", "heard", "heard.partial", "transcript", "mood", "text.delta", "text.chunk", "thought.delta", "tool.start", "tool.end", "knowledge", "audio.start", "audio.end", "muted", "relation", "usage", "turn.done", "interrupted", "error", "pong"];
|
|
7
|
+
export declare const SERVER_EVENTS: readonly ["ready", "turn.start", "heard", "heard.partial", "transcript", "mood", "text.delta", "text.chunk", "thought.delta", "tool.start", "tool.end", "tool.confirm", "knowledge", "audio.start", "audio.end", "muted", "relation", "usage", "turn.done", "interrupted", "error", "pong"];
|
|
8
8
|
export type ServerEventName = (typeof SERVER_EVENTS)[number];
|
|
9
9
|
/** The events that end a turn: exactly one of them ends every turn. */
|
|
10
10
|
export declare const TERMINAL_EVENTS: readonly ["turn.done", "interrupted"];
|
|
11
|
+
/** A `ping` of exactly this text is answered by the edge's runtime with `KEEPALIVE_PONG`, which has no `seq`. */
|
|
12
|
+
export declare const KEEPALIVE_PING = "{\"type\":\"ping\"}";
|
|
13
|
+
export declare const KEEPALIVE_PONG = "{\"type\":\"pong\"}";
|
|
11
14
|
/** The edge's close codes by name: `CLOSE.auth_timeout === 4001`. */
|
|
12
15
|
export declare const CLOSE: {
|
|
13
16
|
readonly auth_timeout: 4001;
|
package/dist/protocol.gen.js
CHANGED
|
@@ -5,11 +5,14 @@
|
|
|
5
5
|
/** The protocol, sent as the WebSocket subprotocol and echoed on `ready`. */
|
|
6
6
|
export const PROTOCOL = "ino.v2";
|
|
7
7
|
/** Every frame a client may send; the edge closes on any other (4009). */
|
|
8
|
-
export const CLIENT_VERBS = ["auth", "user_message", "user_audio.start", "user_audio.end", "cancel", "mute", "ping"];
|
|
8
|
+
export const CLIENT_VERBS = ["auth", "user_message", "user_audio.start", "user_audio.end", "cancel", "mute", "ping", "tool.confirmed"];
|
|
9
9
|
/** Every event the edge sends. */
|
|
10
|
-
export const SERVER_EVENTS = ["ready", "turn.start", "heard", "heard.partial", "transcript", "mood", "text.delta", "text.chunk", "thought.delta", "tool.start", "tool.end", "knowledge", "audio.start", "audio.end", "muted", "relation", "usage", "turn.done", "interrupted", "error", "pong"];
|
|
10
|
+
export const SERVER_EVENTS = ["ready", "turn.start", "heard", "heard.partial", "transcript", "mood", "text.delta", "text.chunk", "thought.delta", "tool.start", "tool.end", "tool.confirm", "knowledge", "audio.start", "audio.end", "muted", "relation", "usage", "turn.done", "interrupted", "error", "pong"];
|
|
11
11
|
/** The events that end a turn: exactly one of them ends every turn. */
|
|
12
12
|
export const TERMINAL_EVENTS = ["turn.done", "interrupted"];
|
|
13
|
+
/** A `ping` of exactly this text is answered by the edge's runtime with `KEEPALIVE_PONG`, which has no `seq`. */
|
|
14
|
+
export const KEEPALIVE_PING = "{\"type\":\"ping\"}";
|
|
15
|
+
export const KEEPALIVE_PONG = "{\"type\":\"pong\"}";
|
|
13
16
|
/** The edge's close codes by name: `CLOSE.auth_timeout === 4001`. */
|
|
14
17
|
export const CLOSE = {
|
|
15
18
|
auth_timeout: 4001,
|
package/dist/socket.js
CHANGED
|
@@ -52,15 +52,13 @@ export function dial(options) {
|
|
|
52
52
|
options.onWarning({ type: "unreadable", what: "text" });
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
got: frame.seq,
|
|
61
|
-
});
|
|
55
|
+
// Every frame is numbered but `pong`, the edge's runtime's.
|
|
56
|
+
const { seq } = frame;
|
|
57
|
+
if (typeof seq === "number") {
|
|
58
|
+
if (lastSeq !== null && seq !== lastSeq + 1) {
|
|
59
|
+
options.onWarning({ type: "gap", expected: lastSeq + 1, got: seq });
|
|
62
60
|
}
|
|
63
|
-
lastSeq =
|
|
61
|
+
lastSeq = seq;
|
|
64
62
|
}
|
|
65
63
|
if (frame.type === "audio.start")
|
|
66
64
|
window = frame;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumavox/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Talk to Lumavox agents from a browser, a React Native app or Node, with an end user's ephemeral key: conversations on the agent's socket, sessions, memory and relations. Zero dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|