dsh-realtime-agent 0.2.7 → 0.2.8
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/lib/index.d.ts +20 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +53 -7
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +75 -8
package/lib/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import Schema from '@deepseek-ai/schemastery';
|
|
24
24
|
import type { Context } from '@deepseek-ai/cordis';
|
|
25
|
-
import type { RealtimeDelegationSettlement, RealtimeSession, RealtimeSessionHandlers } from 'dsh-realtime';
|
|
25
|
+
import type { RealtimeDelegationProgress, RealtimeDelegationSettlement, RealtimeSession, RealtimeSessionHandlers } from 'dsh-realtime';
|
|
26
26
|
import { type DelegationAppend, type DelegationAsker } from './bridge.ts';
|
|
27
27
|
import { TranscriptBuffer } from './transcript.ts';
|
|
28
28
|
import type { DelegationAnswer, DelegationRequest, RealtimeAgentConfig, RealtimeSessionRequestOutcome, RealtimeVoiceStatus } from './types.ts';
|
|
@@ -52,6 +52,18 @@ declare module '@deepseek-ai/cordis' {
|
|
|
52
52
|
* user's ear without any of them re-deriving why the turn produced nothing.
|
|
53
53
|
*/
|
|
54
54
|
'realtime-agent/delegation-settled'(settlement: RealtimeDelegationSettlement): void;
|
|
55
|
+
/**
|
|
56
|
+
* One step of a delegated turn, on its way to an ear or to the model's own context.
|
|
57
|
+
*
|
|
58
|
+
* Emitted by whichever application is running the turn, as the steps happen — it is the only thing that
|
|
59
|
+
* knows what the turn is doing. This plugin appends it, because it holds the session: `commentary` is
|
|
60
|
+
* spoken aloud, `thinking` is carried silently, and the choice is the emitter's.
|
|
61
|
+
*
|
|
62
|
+
* A step for a delegation this plugin is **not** waiting on is dropped rather than appended: the
|
|
63
|
+
* provider only accepts an append for a delegation it knows, and a finished turn's words must not be
|
|
64
|
+
* spoken into a conversation that has moved on.
|
|
65
|
+
*/
|
|
66
|
+
'realtime-agent/delegation-progress'(progress: RealtimeDelegationProgress): void;
|
|
55
67
|
/**
|
|
56
68
|
* Output audio: PCM16 in the session's declared output format.
|
|
57
69
|
*
|
|
@@ -158,6 +170,13 @@ export interface HandlerDeps {
|
|
|
158
170
|
* whether a speaker ever rendered it. See the seam's session contract and invariant 6.
|
|
159
171
|
*/
|
|
160
172
|
readonly onAcknowledged: (append: DelegationAppend, delegationId: string) => void;
|
|
173
|
+
/**
|
|
174
|
+
* Called once a delegation arrives, before it is answered, with the session it is being answered on — so
|
|
175
|
+
* a caller can tell which turns are still waiting, and *where* each one is waiting.
|
|
176
|
+
*/
|
|
177
|
+
readonly onDelegationStarted?: (delegationId: string, session: RealtimeSession) => void;
|
|
178
|
+
/** Called once a delegation has finished, however it ended. */
|
|
179
|
+
readonly onDelegationSettled?: (delegationId: string) => void;
|
|
161
180
|
}
|
|
162
181
|
/**
|
|
163
182
|
* Build the session handlers.
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAsB,4BAA4B,EAAE,eAAe,EAAE,uBAAuB,EAAsB,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -65,9 +65,12 @@ export function createHandlers(deps) {
|
|
|
65
65
|
// would be a failure raised from inside a handler, which is the worst place to raise one.
|
|
66
66
|
if (session === undefined)
|
|
67
67
|
return;
|
|
68
|
+
// Marked waiting before the answer is dispatched, so a step that arrives while the turn is running is
|
|
69
|
+
// appended rather than dropped for having beaten this line.
|
|
70
|
+
deps.onDelegationStarted?.(delegation.id, session);
|
|
68
71
|
// Handlers are synchronous, so the answer is dispatched rather than awaited. A rejection is
|
|
69
72
|
// reported rather than thrown: an unanswered delegation is already the failure path.
|
|
70
|
-
void answerDelegation(session, delegation, deps.transcript.lines(), deps.ask, deps.timeoutMs(), deps.onAcknowledged).catch(deps.onSessionError);
|
|
73
|
+
void answerDelegation(session, delegation, deps.transcript.lines(), deps.ask, deps.timeoutMs(), deps.onAcknowledged).catch(deps.onSessionError).finally(() => { deps.onDelegationSettled?.(delegation.id); });
|
|
71
74
|
},
|
|
72
75
|
onAudio: (pcm16) => { deps.onAudio(pcm16); },
|
|
73
76
|
onClosed: () => { deps.onClosed(); },
|
|
@@ -139,6 +142,24 @@ export function apply(ctx, config) {
|
|
|
139
142
|
]);
|
|
140
143
|
yield () => { release(); };
|
|
141
144
|
}, 'realtime-agent.settings');
|
|
145
|
+
/**
|
|
146
|
+
* The one place an acknowledgement can honestly be recorded: the seam's appends resolve on the provider's
|
|
147
|
+
* confirmation, not on the send. Note what is deliberately absent beside it — no entry anywhere claims the
|
|
148
|
+
* audio was heard, which is the pair invariant 6 exists to keep apart. Shared with the narration path, so
|
|
149
|
+
* a spoken step and an answer are accounted for by the same rule.
|
|
150
|
+
*/
|
|
151
|
+
const onAcknowledged = (append, delegationId) => {
|
|
152
|
+
journal.record('append.acknowledged', { append, delegationId });
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* The delegations still waiting for an answer, with the session each one is being answered on.
|
|
156
|
+
*
|
|
157
|
+
* The session is stored *with* the id rather than read back from the plugin when a step arrives, and that
|
|
158
|
+
* is not a micro-optimisation: it collapses two conditions into one. "Nothing is waiting on this" and
|
|
159
|
+
* "there is no session to speak into" cannot drift apart into two guards, one of which — the session
|
|
160
|
+
* dropped while its id is still waiting — no sequence of events can actually produce.
|
|
161
|
+
*/
|
|
162
|
+
const waiting = new Map();
|
|
142
163
|
const handlers = createHandlers({
|
|
143
164
|
transcript,
|
|
144
165
|
session: () => session,
|
|
@@ -146,6 +167,7 @@ export function apply(ctx, config) {
|
|
|
146
167
|
timeoutMs: () => live.delegationTimeoutMs,
|
|
147
168
|
onClosed: () => {
|
|
148
169
|
session = undefined;
|
|
170
|
+
waiting.clear();
|
|
149
171
|
journal.record('session.closed', {});
|
|
150
172
|
},
|
|
151
173
|
onSessionError: (error) => {
|
|
@@ -160,13 +182,37 @@ export function apply(ctx, config) {
|
|
|
160
182
|
// Handed to the transport: all the host can observe, and no more (invariant 6).
|
|
161
183
|
journal.record('speech.sent', { bytes: String(pcm16.byteLength) });
|
|
162
184
|
},
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
// anywhere claims the audio was heard, which is the pair invariant 6 exists to keep apart.
|
|
167
|
-
journal.record('append.acknowledged', { append, delegationId });
|
|
168
|
-
},
|
|
185
|
+
onDelegationStarted: (delegationId, current) => { waiting.set(delegationId, current); },
|
|
186
|
+
onDelegationSettled: (delegationId) => { waiting.delete(delegationId); },
|
|
187
|
+
onAcknowledged,
|
|
169
188
|
});
|
|
189
|
+
/**
|
|
190
|
+
* Narrate a delegated turn's steps, on the session that is running it.
|
|
191
|
+
*
|
|
192
|
+
* A contribution like any other, so the fiber that registered it releases it. The emitter decides whether
|
|
193
|
+
* a step is spoken or silent — this half only carries it, because the session belongs here and nowhere
|
|
194
|
+
* else does.
|
|
195
|
+
*
|
|
196
|
+
* A failed append is a **dropped step**, not a broken turn: it is recorded so it is not silent, and it
|
|
197
|
+
* must not be confused with an answer that never arrived.
|
|
198
|
+
*/
|
|
199
|
+
ctx.effect(function* () {
|
|
200
|
+
const dispose = ctx.on('realtime-agent/delegation-progress', (progress) => {
|
|
201
|
+
// One condition, not two: the session a turn is waiting on *is* the authorisation to speak into it, and
|
|
202
|
+
// it travels with the delegation. A step for anything else has nowhere to go — the provider refuses an
|
|
203
|
+
// append for an id it does not know, and a finished turn's words must not be spoken into the next one.
|
|
204
|
+
const current = waiting.get(progress.id);
|
|
205
|
+
if (current === undefined)
|
|
206
|
+
return;
|
|
207
|
+
const append = progress.channel === 'commentary'
|
|
208
|
+
? current.appendCommentary(progress.text, progress.id)
|
|
209
|
+
: current.appendThinking(progress.text, progress.id);
|
|
210
|
+
void append
|
|
211
|
+
.then(() => { onAcknowledged(progress.channel, progress.id); })
|
|
212
|
+
.catch(() => { journal.record('progress.dropped', { id: progress.id, channel: progress.channel }); });
|
|
213
|
+
});
|
|
214
|
+
yield () => { dispose(); };
|
|
215
|
+
}, 'realtime-agent.progress');
|
|
170
216
|
/**
|
|
171
217
|
* Open a session, or return the one already open.
|
|
172
218
|
*
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAG7C,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAA+C,MAAM,aAAa,CAAA;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAG7C,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAA+C,MAAM,aAAa,CAAA;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAuFlD,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,iBAAiB,EAAwB,MAAM,aAAa,CAAA;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,oBAAoB,EAAsB,MAAM,YAAY,CAAA;AAErE,wDAAwD;AACxD,MAAM,CAAC,MAAM,IAAI,GAAG,gBAAgB,CAAA;AAEpC,sFAAsF;AACtF,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;AAE3C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,WAAW,CAAC,gDAAgD,CAAC;IAC9G,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,wBAAwB,CAAC;IAClF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,mDAAmD,CAAC;IACvG,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,2CAA2C,CAAC;IACtG,SAAS,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,6CAA6C,CAAC;IACrG,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,kCAAkC,CAAC;IACpG,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,gDAAgD,CAAC;CACjH,CAAC,CAAA;AAwCF;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAiB;IAC9C,OAAO;QACL,YAAY,EAAE,CAAC,QAA4B,EAAQ,EAAE;YACnD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;QACtE,CAAC;QACD,YAAY,EAAE,CAAC,UAA8B,EAAQ,EAAE;YACrD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;YAC9B,gGAAgG;YAChG,0FAA0F;YAC1F,IAAI,OAAO,KAAK,SAAS;gBAAE,OAAM;YACjC,sGAAsG;YACtG,4DAA4D;YAC5D,IAAI,CAAC,mBAAmB,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;YAClD,4FAA4F;YAC5F,qFAAqF;YACrF,KAAK,gBAAgB,CACnB,OAAO,EACP,UAAU,EACV,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,EACvB,IAAI,CAAC,GAAG,EACR,IAAI,CAAC,SAAS,EAAE,EAChB,IAAI,CAAC,cAAc,CACpB,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;QAC3F,CAAC;QACD,OAAO,EAAE,CAAC,KAAiB,EAAQ,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC;QAC7D,QAAQ,EAAE,GAAS,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA,CAAC,CAAC;QACzC,OAAO,EAAE,CAAC,KAAY,EAAQ,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC;KAChE,CAAA;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,YAAY,CAAC,KAAa,EAAE,KAAa;IAChD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,aAAa,CAAC,GAAG,KAAK,kCAAkC,EAAE,oBAAoB,CAAC,eAAe,CAAC,CAAA;IAC3G,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,MAA2B;IAC7D,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAA;IAEpC;;;;;;;OAOG;IACH,MAAM,IAAI,GAAG,EAAE,mBAAmB,EAAE,MAAM,CAAC,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,CAAC,kBAAkB,EAAE,CAAA;IAE/G,MAAM,UAAU,GAAG,IAAI,gBAAgB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;IACtE,IAAI,OAAoC,CAAA;IAExC,sGAAsG;IACtG,qGAAqG;IACrG,iDAAiD;IACjD,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;QAClB,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;YACnD;gBACE,KAAK,EAAE,qBAAqB;gBAC5B,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,MAAM;gBACb,QAAQ,EAAE,gDAAgD;gBAC1D,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,mBAAmB;gBACnC,GAAG,EAAE,CAAC,KAAa,EAAE,EAAE,GAAG,IAAI,CAAC,mBAAmB,GAAG,YAAY,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAA,CAAC,CAAC;aAClG;YACD;gBACE,KAAK,EAAE,oBAAoB;gBAC3B,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,MAAM;gBACb,QAAQ,EAAE,6DAA6D;gBACvE,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,kBAAkB;gBAClC,GAAG,EAAE,CAAC,KAAa,EAAE,EAAE,GAAG,IAAI,CAAC,kBAAkB,GAAG,YAAY,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAA,CAAC,CAAC;aAChG;YACD;gBACE,KAAK,EAAE,WAAW;gBAClB,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,SAAS;gBAChB,QAAQ,EAAE,6CAA6C;gBACvD,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS;aAC5B;SACF,CAAC,CAAA;QACF,MAAM,GAAG,EAAE,GAAG,OAAO,EAAE,CAAA,CAAC,CAAC,CAAA;IAC3B,CAAC,EAAE,yBAAyB,CAAC,CAAA;IAE7B;;;;;OAKG;IACH,MAAM,cAAc,GAAG,CAAC,MAAwB,EAAE,YAAoB,EAAQ,EAAE;QAC9E,OAAO,CAAC,MAAM,CAAC,qBAAqB,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAA;IACjE,CAAC,CAAA;IAED;;;;;;;OAOG;IACH,MAAM,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAA;IAElD,MAAM,QAAQ,GAAG,cAAc,CAAC;QAC9B,UAAU;QACV,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO;QACtB,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,2BAA2B,EAAE,OAAO,CAAC;QAChE,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,mBAAmB;QACzC,QAAQ,EAAE,GAAG,EAAE;YACb,OAAO,GAAG,SAAS,CAAA;YACnB,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAA;QACtC,CAAC;QACD,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE;YACxB,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAA;YACvC,+FAA+F;YAC/F,gGAAgG;YAChG,8FAA8F;YAC9F,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;QACzD,CAAC;QACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjB,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAA;YACvC,gFAAgF;YAChF,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QACpE,CAAC;QACD,mBAAmB,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA,CAAC,CAAC;QACtF,mBAAmB,EAAE,CAAC,YAAY,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA,CAAC,CAAC;QACvE,cAAc;KACf,CAAC,CAAA;IAEF;;;;;;;;;OASG;IACH,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;QAClB,MAAM,OAAO,GAAG,GAAG,CAAC,EAAE,CAAC,oCAAoC,EAAE,CAAC,QAAoC,EAAE,EAAE;YACpG,wGAAwG;YACxG,uGAAuG;YACvG,uGAAuG;YACvG,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;YACxC,IAAI,OAAO,KAAK,SAAS;gBAAE,OAAM;YACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,KAAK,YAAY;gBAC9C,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;gBACtD,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAA;YACtD,KAAK,MAAM;iBACR,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAA,CAAC,CAAC,CAAC;iBAC7D,KAAK,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;QACxG,CAAC,CAAC,CAAA;QACF,MAAM,GAAG,EAAE,GAAG,OAAO,EAAE,CAAA,CAAC,CAAC,CAAA;IAC3B,CAAC,EAAE,yBAAyB,CAAC,CAAA;IAE7B;;;;;OAKG;IACH,MAAM,IAAI,GAAG,KAAK,IAA8B,EAAE;QAChD,MAAM,OAAO,GAAG,OAAO,CAAA;QACvB,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,OAAO,CAAA;QACzC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;YACxC,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,GAAG,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;YAC5D,GAAG,MAAM,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE;YACjF,QAAQ;SACT,CAAC,CAAA;QACF,OAAO,GAAG,MAAM,CAAA;QAChB,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;QACpF,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;IAED;;;;;OAKG;IACH,MAAM,IAAI,GAAG,KAAK,IAAmB,EAAE;QACrC,MAAM,OAAO,GAAG,OAAO,CAAA;QACvB,OAAO,GAAG,SAAS,CAAA;QACnB,MAAM,OAAO,EAAE,KAAK,EAAE,CAAA;IACxB,CAAC,CAAA;IAED;;;;;;OAMG;IACH,MAAM,MAAM,GAAG,GAAwB,EAAE;QACvC,MAAM,OAAO,GAAG,OAAO,CAAA;QACvB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO;gBACL,IAAI,EAAE,KAAK;gBACX,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,GAAG,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;aAC7D,CAAA;QACH,CAAC;QACD,OAAO;YACL,IAAI,EAAE,IAAI;YACV,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ;YAClC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK;YAC5B,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE;YAC9E,SAAS,EAAE,OAAO,CAAC,EAAE;SACtB,CAAA;IACH,CAAC,CAAA;IAED;;;;;;;;;OASG;IACH,MAAM,UAAU,GAAG,CAAC,KAAc,EAA0B,EAAE;QAC5D,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;YACnC,OAAO;gBACL,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,GAAG,KAAK,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE;aAC7E,CAAA;QACH,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE,CAAA;IACtE,CAAC,CAAA;IAED;;;;;;;;;OASG;IACH,MAAM,cAAc,GAAG,KAAK,EAAE,OAA+B,EAA0C,EAAE;QACvG,IAAI,CAAC;YACH,MAAM,OAAO,EAAE,CAAA;YACf,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAA;QACtC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAc,CAAC,CAAA;YAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAA;QACnE,CAAC;IACH,CAAC,CAAA;IAED,oGAAoG;IACpG,kEAAkE;IAClE,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;QAClB,MAAM,SAAS,GAAG,oBAAoB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;aAClF,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAA;QACpD,MAAM,GAAG,EAAE,GAAG,KAAK,MAAM,OAAO,IAAI,SAAS;YAAE,OAAO,EAAE,CAAA,CAAC,CAAC,CAAA;IAC5D,CAAC,EAAE,sBAAsB,CAAC,CAAA;IAE1B,qGAAqG;IACrG,sGAAsG;IACtG,sFAAsF;IACtF,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;QAClB,MAAM,OAAO,GAAG,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,KAAiB,EAAE,EAAE;YACjE,MAAM,OAAO,GAAG,OAAO,CAAA;YACvB,6FAA6F;YAC7F,uEAAuE;YACvE,IAAI,OAAO,KAAK,SAAS;gBAAE,OAAM;YACjC,IAAI,CAAC;gBACH,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;YAC1B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,gGAAgG;gBAChG,8FAA8F;gBAC9F,4BAA4B;gBAC5B,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAc,CAAC,CAAA;YAClD,CAAC;QACH,CAAC,CAAC,CAAA;QACF,MAAM,GAAG,EAAE,GAAG,OAAO,EAAE,CAAA,CAAC,CAAC,CAAA;IAC3B,CAAC,EAAE,oBAAoB,CAAC,CAAA;IAExB,qGAAqG;IACrG,sGAAsG;IACtG,iGAAiG;IACjG,0DAA0D;IAC1D,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;QAClB,MAAM,SAAS,GAAG;YAChB,GAAG,CAAC,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YAClE,GAAG,CAAC,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YACjE,+FAA+F;YAC/F,+FAA+F;YAC/F,GAAG,CAAC,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC;SAChD,CAAA;QACD,MAAM,GAAG,EAAE,GAAG,KAAK,MAAM,OAAO,IAAI,SAAS;YAAE,OAAO,EAAE,CAAA,CAAC,CAAC,CAAA;IAC5D,CAAC,EAAE,iCAAiC,CAAC,CAAA;IAErC,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,gGAAgG;QAChG,iEAAiE;QACjE,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;IAClF,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-realtime-agent",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "Delegation bridge for the dsh-realtime seam: answers what the voice model delegates, or says plainly that it cannot.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"registry": "https://registry.npmjs.org"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"dsh-realtime": "^0.2.
|
|
45
|
+
"dsh-realtime": "^0.2.4"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@deepseek-ai/cordis": "^4.0.3",
|
package/src/index.ts
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
import Schema from '@deepseek-ai/schemastery'
|
|
25
25
|
import type { Context } from '@deepseek-ai/cordis'
|
|
26
|
-
import type { RealtimeDelegation, RealtimeDelegationSettlement, RealtimeSession, RealtimeSessionHandlers, RealtimeTranscript } from 'dsh-realtime'
|
|
26
|
+
import type { RealtimeDelegation, RealtimeDelegationProgress, RealtimeDelegationSettlement, RealtimeSession, RealtimeSessionHandlers, RealtimeTranscript } from 'dsh-realtime'
|
|
27
27
|
import { REALTIME_ERROR_CODES, RealtimeError } from 'dsh-realtime'
|
|
28
28
|
import { answerDelegation, type DelegationAppend, type DelegationAsker } from './bridge.ts'
|
|
29
29
|
import { voiceToolDefinitions } from './tools.ts'
|
|
@@ -56,6 +56,18 @@ declare module '@deepseek-ai/cordis' {
|
|
|
56
56
|
* user's ear without any of them re-deriving why the turn produced nothing.
|
|
57
57
|
*/
|
|
58
58
|
'realtime-agent/delegation-settled'(settlement: RealtimeDelegationSettlement): void
|
|
59
|
+
/**
|
|
60
|
+
* One step of a delegated turn, on its way to an ear or to the model's own context.
|
|
61
|
+
*
|
|
62
|
+
* Emitted by whichever application is running the turn, as the steps happen — it is the only thing that
|
|
63
|
+
* knows what the turn is doing. This plugin appends it, because it holds the session: `commentary` is
|
|
64
|
+
* spoken aloud, `thinking` is carried silently, and the choice is the emitter's.
|
|
65
|
+
*
|
|
66
|
+
* A step for a delegation this plugin is **not** waiting on is dropped rather than appended: the
|
|
67
|
+
* provider only accepts an append for a delegation it knows, and a finished turn's words must not be
|
|
68
|
+
* spoken into a conversation that has moved on.
|
|
69
|
+
*/
|
|
70
|
+
'realtime-agent/delegation-progress'(progress: RealtimeDelegationProgress): void
|
|
59
71
|
/**
|
|
60
72
|
* Output audio: PCM16 in the session's declared output format.
|
|
61
73
|
*
|
|
@@ -159,6 +171,13 @@ export interface HandlerDeps {
|
|
|
159
171
|
* whether a speaker ever rendered it. See the seam's session contract and invariant 6.
|
|
160
172
|
*/
|
|
161
173
|
readonly onAcknowledged: (append: DelegationAppend, delegationId: string) => void
|
|
174
|
+
/**
|
|
175
|
+
* Called once a delegation arrives, before it is answered, with the session it is being answered on — so
|
|
176
|
+
* a caller can tell which turns are still waiting, and *where* each one is waiting.
|
|
177
|
+
*/
|
|
178
|
+
readonly onDelegationStarted?: (delegationId: string, session: RealtimeSession) => void
|
|
179
|
+
/** Called once a delegation has finished, however it ended. */
|
|
180
|
+
readonly onDelegationSettled?: (delegationId: string) => void
|
|
162
181
|
}
|
|
163
182
|
|
|
164
183
|
/**
|
|
@@ -176,6 +195,9 @@ export function createHandlers(deps: HandlerDeps): RealtimeSessionHandlers {
|
|
|
176
195
|
// A delegation cannot be answered into a session that is gone. Speaking into a closed transport
|
|
177
196
|
// would be a failure raised from inside a handler, which is the worst place to raise one.
|
|
178
197
|
if (session === undefined) return
|
|
198
|
+
// Marked waiting before the answer is dispatched, so a step that arrives while the turn is running is
|
|
199
|
+
// appended rather than dropped for having beaten this line.
|
|
200
|
+
deps.onDelegationStarted?.(delegation.id, session)
|
|
179
201
|
// Handlers are synchronous, so the answer is dispatched rather than awaited. A rejection is
|
|
180
202
|
// reported rather than thrown: an unanswered delegation is already the failure path.
|
|
181
203
|
void answerDelegation(
|
|
@@ -185,7 +207,7 @@ export function createHandlers(deps: HandlerDeps): RealtimeSessionHandlers {
|
|
|
185
207
|
deps.ask,
|
|
186
208
|
deps.timeoutMs(),
|
|
187
209
|
deps.onAcknowledged,
|
|
188
|
-
).catch(deps.onSessionError)
|
|
210
|
+
).catch(deps.onSessionError).finally(() => { deps.onDelegationSettled?.(delegation.id) })
|
|
189
211
|
},
|
|
190
212
|
onAudio: (pcm16: Uint8Array): void => { deps.onAudio(pcm16) },
|
|
191
213
|
onClosed: (): void => { deps.onClosed() },
|
|
@@ -263,6 +285,26 @@ export function apply(ctx: Context, config: RealtimeAgentConfig): void {
|
|
|
263
285
|
yield () => { release() }
|
|
264
286
|
}, 'realtime-agent.settings')
|
|
265
287
|
|
|
288
|
+
/**
|
|
289
|
+
* The one place an acknowledgement can honestly be recorded: the seam's appends resolve on the provider's
|
|
290
|
+
* confirmation, not on the send. Note what is deliberately absent beside it — no entry anywhere claims the
|
|
291
|
+
* audio was heard, which is the pair invariant 6 exists to keep apart. Shared with the narration path, so
|
|
292
|
+
* a spoken step and an answer are accounted for by the same rule.
|
|
293
|
+
*/
|
|
294
|
+
const onAcknowledged = (append: DelegationAppend, delegationId: string): void => {
|
|
295
|
+
journal.record('append.acknowledged', { append, delegationId })
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* The delegations still waiting for an answer, with the session each one is being answered on.
|
|
300
|
+
*
|
|
301
|
+
* The session is stored *with* the id rather than read back from the plugin when a step arrives, and that
|
|
302
|
+
* is not a micro-optimisation: it collapses two conditions into one. "Nothing is waiting on this" and
|
|
303
|
+
* "there is no session to speak into" cannot drift apart into two guards, one of which — the session
|
|
304
|
+
* dropped while its id is still waiting — no sequence of events can actually produce.
|
|
305
|
+
*/
|
|
306
|
+
const waiting = new Map<string, RealtimeSession>()
|
|
307
|
+
|
|
266
308
|
const handlers = createHandlers({
|
|
267
309
|
transcript,
|
|
268
310
|
session: () => session,
|
|
@@ -270,6 +312,7 @@ export function apply(ctx: Context, config: RealtimeAgentConfig): void {
|
|
|
270
312
|
timeoutMs: () => live.delegationTimeoutMs,
|
|
271
313
|
onClosed: () => {
|
|
272
314
|
session = undefined
|
|
315
|
+
waiting.clear()
|
|
273
316
|
journal.record('session.closed', {})
|
|
274
317
|
},
|
|
275
318
|
onSessionError: (error) => {
|
|
@@ -284,14 +327,38 @@ export function apply(ctx: Context, config: RealtimeAgentConfig): void {
|
|
|
284
327
|
// Handed to the transport: all the host can observe, and no more (invariant 6).
|
|
285
328
|
journal.record('speech.sent', { bytes: String(pcm16.byteLength) })
|
|
286
329
|
},
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
// anywhere claims the audio was heard, which is the pair invariant 6 exists to keep apart.
|
|
291
|
-
journal.record('append.acknowledged', { append, delegationId })
|
|
292
|
-
},
|
|
330
|
+
onDelegationStarted: (delegationId, current) => { waiting.set(delegationId, current) },
|
|
331
|
+
onDelegationSettled: (delegationId) => { waiting.delete(delegationId) },
|
|
332
|
+
onAcknowledged,
|
|
293
333
|
})
|
|
294
334
|
|
|
335
|
+
/**
|
|
336
|
+
* Narrate a delegated turn's steps, on the session that is running it.
|
|
337
|
+
*
|
|
338
|
+
* A contribution like any other, so the fiber that registered it releases it. The emitter decides whether
|
|
339
|
+
* a step is spoken or silent — this half only carries it, because the session belongs here and nowhere
|
|
340
|
+
* else does.
|
|
341
|
+
*
|
|
342
|
+
* A failed append is a **dropped step**, not a broken turn: it is recorded so it is not silent, and it
|
|
343
|
+
* must not be confused with an answer that never arrived.
|
|
344
|
+
*/
|
|
345
|
+
ctx.effect(function* () {
|
|
346
|
+
const dispose = ctx.on('realtime-agent/delegation-progress', (progress: RealtimeDelegationProgress) => {
|
|
347
|
+
// One condition, not two: the session a turn is waiting on *is* the authorisation to speak into it, and
|
|
348
|
+
// it travels with the delegation. A step for anything else has nowhere to go — the provider refuses an
|
|
349
|
+
// append for an id it does not know, and a finished turn's words must not be spoken into the next one.
|
|
350
|
+
const current = waiting.get(progress.id)
|
|
351
|
+
if (current === undefined) return
|
|
352
|
+
const append = progress.channel === 'commentary'
|
|
353
|
+
? current.appendCommentary(progress.text, progress.id)
|
|
354
|
+
: current.appendThinking(progress.text, progress.id)
|
|
355
|
+
void append
|
|
356
|
+
.then(() => { onAcknowledged(progress.channel, progress.id) })
|
|
357
|
+
.catch(() => { journal.record('progress.dropped', { id: progress.id, channel: progress.channel }) })
|
|
358
|
+
})
|
|
359
|
+
yield () => { dispose() }
|
|
360
|
+
}, 'realtime-agent.progress')
|
|
361
|
+
|
|
295
362
|
/**
|
|
296
363
|
* Open a session, or return the one already open.
|
|
297
364
|
*
|