dsh-realtime-agent 0.2.4 → 0.2.6

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Travis Driessen
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/lib/bridge.d.ts CHANGED
@@ -26,6 +26,8 @@ export interface DelegationAsker {
26
26
  * @returns the text, or a marked prefix of it no longer than `maxChars`.
27
27
  */
28
28
  export declare function boundAppend(text: string, maxChars?: number): string;
29
+ /** Which channel an append went out on. What an acknowledgement names, and what it does not. */
30
+ export type DelegationAppend = 'commentary' | 'thinking';
29
31
  /**
30
32
  * Answer one delegation, or tell the model plainly that it could not be answered.
31
33
  *
@@ -35,7 +37,8 @@ export declare function boundAppend(text: string, maxChars?: number): string;
35
37
  * @param transcript - the conversation so far, as the responder will see it.
36
38
  * @param ask - how to reach a responder.
37
39
  * @param timeoutMs - bound on waiting for one.
40
+ * @param onAcknowledged - called once per accepted append, which is not once per thing heard.
38
41
  * @returns a promise settling once the session has been answered.
39
42
  */
40
- export declare function answerDelegation(session: Pick<RealtimeSession, 'id' | 'appendCommentary' | 'appendThinking'>, delegation: RealtimeDelegation, transcript: readonly AgentTranscriptLine[], ask: DelegationAsker, timeoutMs: number): Promise<void>;
43
+ export declare function answerDelegation(session: Pick<RealtimeSession, 'id' | 'appendCommentary' | 'appendThinking'>, delegation: RealtimeDelegation, transcript: readonly AgentTranscriptLine[], ask: DelegationAsker, timeoutMs: number, onAcknowledged: (append: DelegationAppend, delegationId: string) => void): Promise<void>;
41
44
  //# sourceMappingURL=bridge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9F,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE1F;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,sDAAiD,CAAA;AAK/E;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAA;CACnG;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAyB,GAAG,MAAM,CAKrF;AAmBD;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,kBAAkB,GAAG,gBAAgB,CAAC,EAC5E,UAAU,EAAE,kBAAkB,EAC9B,UAAU,EAAE,SAAS,mBAAmB,EAAE,EAC1C,GAAG,EAAE,eAAe,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9F,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE1F;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,sDAAiD,CAAA;AAK/E;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAA;CACnG;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAyB,GAAG,MAAM,CAKrF;AAmBD,gGAAgG;AAChG,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,UAAU,CAAA;AAExD;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,kBAAkB,GAAG,gBAAgB,CAAC,EAC5E,UAAU,EAAE,kBAAkB,EAC9B,UAAU,EAAE,SAAS,mBAAmB,EAAE,EAC1C,GAAG,EAAE,eAAe,EACpB,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,GACvE,OAAO,CAAC,IAAI,CAAC,CAkCf"}
package/lib/bridge.js CHANGED
@@ -52,9 +52,10 @@ function settled(ask, request) {
52
52
  * @param transcript - the conversation so far, as the responder will see it.
53
53
  * @param ask - how to reach a responder.
54
54
  * @param timeoutMs - bound on waiting for one.
55
+ * @param onAcknowledged - called once per accepted append, which is not once per thing heard.
55
56
  * @returns a promise settling once the session has been answered.
56
57
  */
57
- export async function answerDelegation(session, delegation, transcript, ask, timeoutMs) {
58
+ export async function answerDelegation(session, delegation, transcript, ask, timeoutMs, onAcknowledged) {
58
59
  const request = {
59
60
  id: delegation.id,
60
61
  offsetMs: delegation.offsetMs,
@@ -68,14 +69,22 @@ export async function answerDelegation(session, delegation, transcript, ask, tim
68
69
  });
69
70
  const answer = await Promise.race([settled(ask, request), expired]);
70
71
  const text = typeof answer?.text === 'string' ? answer.text.trim() : '';
72
+ // Every append below awaits the provider's acknowledgement rather than the send — that is the seam's
73
+ // session contract, written that way for a measured reason. So a resolved await **is** the
74
+ // acknowledgement, and this is the only honest place to record one. What it is not is delivery:
75
+ // nothing here says a speaker rendered anything, and keeping those two apart is the whole of
76
+ // invariant 6 — and the reason the fault-injection matrix has a row for exactly this pair.
71
77
  if (text.length === 0) {
72
78
  await session.appendCommentary(UNANSWERED_NOTICE, delegation.id);
79
+ onAcknowledged('commentary', delegation.id);
73
80
  return;
74
81
  }
75
82
  if (answer?.mode === 'spoken') {
76
83
  await session.appendCommentary(boundAppend(text), delegation.id);
84
+ onAcknowledged('commentary', delegation.id);
77
85
  return;
78
86
  }
79
87
  await session.appendThinking(boundAppend(text), delegation.id);
88
+ onAcknowledged('thinking', delegation.id);
80
89
  }
81
90
  //# sourceMappingURL=bridge.js.map
package/lib/bridge.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAiD,MAAM,cAAc,CAAA;AAG9F;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,8CAA8C,CAAA;AAE/E,iGAAiG;AACjG,MAAM,iBAAiB,GAAG,cAAc,CAAA;AAWxC;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,QAAQ,GAAW,gBAAgB;IAC3E,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAA;IACxC,mFAAmF;IACnF,IAAI,QAAQ,IAAI,iBAAiB,CAAC,MAAM;QAAE,OAAO,iBAAiB,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;IACrF,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,GAAG,iBAAiB,CAAA;AAC/E,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,OAAO,CAAC,GAAoB,EAAE,OAA0B;IAC/D,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACnC,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAA4E,EAC5E,UAA8B,EAC9B,UAA0C,EAC1C,GAAoB,EACpB,SAAiB;IAEjB,MAAM,OAAO,GAAsB;QACjC,EAAE,EAAE,UAAU,CAAC,EAAE;QACjB,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,UAAU;QACV,SAAS,EAAE,OAAO,CAAC,EAAE;KACtB,CAAA;IAED,kGAAkG;IAClG,4DAA4D;IAC5D,MAAM,OAAO,GAAG,IAAI,OAAO,CAAY,CAAC,OAAO,EAAE,EAAE;QACjD,UAAU,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,KAAK,EAAE,CAAA;IAC7D,CAAC,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAA;IACnE,MAAM,IAAI,GAAG,OAAO,MAAM,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAEvE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,OAAO,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,UAAU,CAAC,EAAE,CAAC,CAAA;QAChE,OAAM;IACR,CAAC;IACD,IAAI,MAAM,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,OAAO,CAAC,gBAAgB,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC,CAAA;QAChE,OAAM;IACR,CAAC;IACD,MAAM,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC,CAAA;AAChE,CAAC"}
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -23,7 +23,7 @@
23
23
  import Schema from '@deepseek-ai/schemastery';
24
24
  import type { Context } from '@deepseek-ai/cordis';
25
25
  import type { RealtimeDelegationSettlement, RealtimeSession, RealtimeSessionHandlers } from 'dsh-realtime';
26
- import { type DelegationAsker } from './bridge.ts';
26
+ import { type DelegationAppend, type DelegationAsker } from './bridge.ts';
27
27
  import { TranscriptBuffer } from './transcript.ts';
28
28
  import type { DelegationAnswer, DelegationRequest, RealtimeAgentConfig } from './types.ts';
29
29
  declare module '@deepseek-ai/cordis' {
@@ -133,6 +133,13 @@ export interface HandlerDeps {
133
133
  readonly onSessionError: (error: Error) => void;
134
134
  /** Where output audio is delivered. Called once per provider delta. */
135
135
  readonly onAudio: (pcm16: Uint8Array) => void;
136
+ /**
137
+ * Where an accepted append is reported.
138
+ *
139
+ * An acknowledgement, not a delivery: it says the provider took the append, and nothing about
140
+ * whether a speaker ever rendered it. See the seam's session contract and invariant 6.
141
+ */
142
+ readonly onAcknowledged: (append: DelegationAppend, delegationId: string) => void;
136
143
  }
137
144
  /**
138
145
  * Build the session handlers.
@@ -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;AAClJ,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AAEpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAE1F,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,MAAM;QACd;;;;;;WAMG;QACH,2BAA2B,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAA;QAC7H,2EAA2E;QAC3E,sBAAsB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;QAC1C;;;;;;;;;;;;WAYG;QACH,mCAAmC,CAAC,UAAU,EAAE,4BAA4B,GAAG,IAAI,CAAA;QACnF;;;;;;WAMG;QACH,sBAAsB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;QAC/C;;;;;;WAMG;QACH,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;QAC7C;;;;;;WAMG;QACH,sBAAsB,IAAI,IAAI,CAAA;QAC9B;;;;;WAKG;QACH,qBAAqB,IAAI,IAAI,CAAA;KAC9B;CACF;AAED,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAErE,wDAAwD;AACxD,eAAO,MAAM,IAAI,mBAAmB,CAAA;AAEpC,sFAAsF;AACtF,eAAO,MAAM,MAAM,UAAwB,CAAA;AAE3C;;;;;;GAMG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;aAQjB,CAAA;AAEF,yGAAyG;AACzG,MAAM,WAAW,WAAW;IAC1B,wCAAwC;IACxC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAA;IACrC,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,MAAM,eAAe,GAAG,SAAS,CAAA;IACnD,gCAAgC;IAChC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAA;IAC7B,gCAAgC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,kDAAkD;IAClD,QAAQ,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAC/C,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CAC9C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,uBAAuB,CAmBzE;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAgGrE"}
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;AAClJ,OAAO,EAAoB,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AAE3F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAE1F,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,MAAM;QACd;;;;;;WAMG;QACH,2BAA2B,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAA;QAC7H,2EAA2E;QAC3E,sBAAsB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;QAC1C;;;;;;;;;;;;WAYG;QACH,mCAAmC,CAAC,UAAU,EAAE,4BAA4B,GAAG,IAAI,CAAA;QACnF;;;;;;WAMG;QACH,sBAAsB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;QAC/C;;;;;;WAMG;QACH,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;QAC7C;;;;;;WAMG;QACH,sBAAsB,IAAI,IAAI,CAAA;QAC9B;;;;;WAKG;QACH,qBAAqB,IAAI,IAAI,CAAA;KAC9B;CACF;AAED,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAErE,wDAAwD;AACxD,eAAO,MAAM,IAAI,mBAAmB,CAAA;AAEpC,sFAAsF;AACtF,eAAO,MAAM,MAAM,UAAwB,CAAA;AAE3C;;;;;;GAMG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;aAQjB,CAAA;AAEF,yGAAyG;AACzG,MAAM,WAAW,WAAW;IAC1B,wCAAwC;IACxC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAA;IACrC,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,MAAM,eAAe,GAAG,SAAS,CAAA;IACnD,gCAAgC;IAChC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAA;IAC7B,gCAAgC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,kDAAkD;IAClD,QAAQ,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAC/C,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAA;CAClF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,uBAAuB,CAyBzE;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAwHrE"}
package/lib/index.js CHANGED
@@ -66,8 +66,7 @@ export function createHandlers(deps) {
66
66
  return;
67
67
  // Handlers are synchronous, so the answer is dispatched rather than awaited. A rejection is
68
68
  // reported rather than thrown: an unanswered delegation is already the failure path.
69
- void answerDelegation(session, delegation, deps.transcript.lines(), deps.ask, deps.timeoutMs)
70
- .catch(deps.onSessionError);
69
+ void answerDelegation(session, delegation, deps.transcript.lines(), deps.ask, deps.timeoutMs, deps.onAcknowledged).catch(deps.onSessionError);
71
70
  },
72
71
  onAudio: (pcm16) => { deps.onAudio(pcm16); },
73
72
  onClosed: () => { deps.onClosed(); },
@@ -81,15 +80,38 @@ export function createHandlers(deps) {
81
80
  */
82
81
  export function apply(ctx, config) {
83
82
  const transcript = new TranscriptBuffer(config.maxTranscriptChars);
83
+ // This plugin owns the session, so it is the only one that can honestly write these entries. The audio
84
+ // route emits a *request* to open a session and deliberately records nothing for it: recording a
85
+ // request as an event is how a journal starts lying.
86
+ const journal = ctx.realtime.journal;
84
87
  let session;
85
88
  const handlers = createHandlers({
86
89
  transcript,
87
90
  session: () => session,
88
91
  ask: request => ctx.serial('realtime-agent/delegation', request),
89
92
  timeoutMs: config.delegationTimeoutMs,
90
- onClosed: () => { session = undefined; },
91
- onSessionError: (error) => { ctx.emit('realtime-agent/error', error); },
92
- onAudio: (pcm16) => { ctx.emit('realtime-agent/audio', pcm16); },
93
+ onClosed: () => {
94
+ session = undefined;
95
+ journal.record('session.closed', {});
96
+ },
97
+ onSessionError: (error) => {
98
+ ctx.emit('realtime-agent/error', error);
99
+ // The class, never the message. A provider error can carry the key it refused, and this plugin
100
+ // holds no credential to redact against — so it records the category and leaves the text to the
101
+ // plugin that does. Naming the setting instead of repeating the value, applied to a log line.
102
+ journal.record('session.failed', { class: error.name });
103
+ },
104
+ onAudio: (pcm16) => {
105
+ ctx.emit('realtime-agent/audio', pcm16);
106
+ // Handed to the transport: all the host can observe, and no more (invariant 6).
107
+ journal.record('speech.sent', { bytes: String(pcm16.byteLength) });
108
+ },
109
+ onAcknowledged: (append, delegationId) => {
110
+ // The one place an acknowledgement can honestly be recorded: the seam's appends resolve on the
111
+ // provider's confirmation, not on the send. Note what is deliberately absent beside it — no entry
112
+ // anywhere claims the audio was heard, which is the pair invariant 6 exists to keep apart.
113
+ journal.record('append.acknowledged', { append, delegationId });
114
+ },
93
115
  });
94
116
  /**
95
117
  * Open a session, or return the one already open.
@@ -109,6 +131,7 @@ export function apply(ctx, config) {
109
131
  handlers,
110
132
  });
111
133
  session = opened;
134
+ journal.record('session.opened', { provider: config.provider, model: config.model });
112
135
  return opened;
113
136
  };
114
137
  /**
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-realtime-agent",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
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",
@@ -41,12 +41,8 @@
41
41
  "access": "public",
42
42
  "registry": "https://registry.npmjs.org"
43
43
  },
44
- "scripts": {
45
- "build": "tsc -b",
46
- "typecheck": "tsc -b --dry"
47
- },
48
44
  "dependencies": {
49
- "dsh-realtime": "workspace:^"
45
+ "dsh-realtime": "^0.2.2"
50
46
  },
51
47
  "peerDependencies": {
52
48
  "@deepseek-ai/cordis": "^4.0.3",
@@ -57,5 +53,9 @@
57
53
  "@deepseek-ai/cordis": "^4.0.4",
58
54
  "@deepseek-ai/dsh-tools": "^0.2.0-rc.2",
59
55
  "@deepseek-ai/schemastery": "^3.18.4"
56
+ },
57
+ "scripts": {
58
+ "build": "tsc -b",
59
+ "typecheck": "tsc -b --dry"
60
60
  }
61
- }
61
+ }
package/src/bridge.ts CHANGED
@@ -55,6 +55,9 @@ function settled(ask: DelegationAsker, request: DelegationRequest): Promise<Dele
55
55
  }
56
56
  }
57
57
 
58
+ /** Which channel an append went out on. What an acknowledgement names, and what it does not. */
59
+ export type DelegationAppend = 'commentary' | 'thinking'
60
+
58
61
  /**
59
62
  * Answer one delegation, or tell the model plainly that it could not be answered.
60
63
  *
@@ -64,6 +67,7 @@ function settled(ask: DelegationAsker, request: DelegationRequest): Promise<Dele
64
67
  * @param transcript - the conversation so far, as the responder will see it.
65
68
  * @param ask - how to reach a responder.
66
69
  * @param timeoutMs - bound on waiting for one.
70
+ * @param onAcknowledged - called once per accepted append, which is not once per thing heard.
67
71
  * @returns a promise settling once the session has been answered.
68
72
  */
69
73
  export async function answerDelegation(
@@ -72,6 +76,7 @@ export async function answerDelegation(
72
76
  transcript: readonly AgentTranscriptLine[],
73
77
  ask: DelegationAsker,
74
78
  timeoutMs: number,
79
+ onAcknowledged: (append: DelegationAppend, delegationId: string) => void,
75
80
  ): Promise<void> {
76
81
  const request: DelegationRequest = {
77
82
  id: delegation.id,
@@ -89,13 +94,21 @@ export async function answerDelegation(
89
94
  const answer = await Promise.race([settled(ask, request), expired])
90
95
  const text = typeof answer?.text === 'string' ? answer.text.trim() : ''
91
96
 
97
+ // Every append below awaits the provider's acknowledgement rather than the send — that is the seam's
98
+ // session contract, written that way for a measured reason. So a resolved await **is** the
99
+ // acknowledgement, and this is the only honest place to record one. What it is not is delivery:
100
+ // nothing here says a speaker rendered anything, and keeping those two apart is the whole of
101
+ // invariant 6 — and the reason the fault-injection matrix has a row for exactly this pair.
92
102
  if (text.length === 0) {
93
103
  await session.appendCommentary(UNANSWERED_NOTICE, delegation.id)
104
+ onAcknowledged('commentary', delegation.id)
94
105
  return
95
106
  }
96
107
  if (answer?.mode === 'spoken') {
97
108
  await session.appendCommentary(boundAppend(text), delegation.id)
109
+ onAcknowledged('commentary', delegation.id)
98
110
  return
99
111
  }
100
112
  await session.appendThinking(boundAppend(text), delegation.id)
113
+ onAcknowledged('thinking', delegation.id)
101
114
  }
package/src/index.ts CHANGED
@@ -24,7 +24,7 @@
24
24
  import Schema from '@deepseek-ai/schemastery'
25
25
  import type { Context } from '@deepseek-ai/cordis'
26
26
  import type { RealtimeDelegation, RealtimeDelegationSettlement, RealtimeSession, RealtimeSessionHandlers, RealtimeTranscript } from 'dsh-realtime'
27
- import { answerDelegation, type DelegationAsker } from './bridge.ts'
27
+ import { answerDelegation, type DelegationAppend, type DelegationAsker } from './bridge.ts'
28
28
  import { voiceToolDefinitions } from './tools.ts'
29
29
  import { TranscriptBuffer } from './transcript.ts'
30
30
  import type { DelegationAnswer, DelegationRequest, RealtimeAgentConfig } from './types.ts'
@@ -133,6 +133,13 @@ export interface HandlerDeps {
133
133
  readonly onSessionError: (error: Error) => void
134
134
  /** Where output audio is delivered. Called once per provider delta. */
135
135
  readonly onAudio: (pcm16: Uint8Array) => void
136
+ /**
137
+ * Where an accepted append is reported.
138
+ *
139
+ * An acknowledgement, not a delivery: it says the provider took the append, and nothing about
140
+ * whether a speaker ever rendered it. See the seam's session contract and invariant 6.
141
+ */
142
+ readonly onAcknowledged: (append: DelegationAppend, delegationId: string) => void
136
143
  }
137
144
 
138
145
  /**
@@ -152,8 +159,14 @@ export function createHandlers(deps: HandlerDeps): RealtimeSessionHandlers {
152
159
  if (session === undefined) return
153
160
  // Handlers are synchronous, so the answer is dispatched rather than awaited. A rejection is
154
161
  // reported rather than thrown: an unanswered delegation is already the failure path.
155
- void answerDelegation(session, delegation, deps.transcript.lines(), deps.ask, deps.timeoutMs)
156
- .catch(deps.onSessionError)
162
+ void answerDelegation(
163
+ session,
164
+ delegation,
165
+ deps.transcript.lines(),
166
+ deps.ask,
167
+ deps.timeoutMs,
168
+ deps.onAcknowledged,
169
+ ).catch(deps.onSessionError)
157
170
  },
158
171
  onAudio: (pcm16: Uint8Array): void => { deps.onAudio(pcm16) },
159
172
  onClosed: (): void => { deps.onClosed() },
@@ -168,6 +181,10 @@ export function createHandlers(deps: HandlerDeps): RealtimeSessionHandlers {
168
181
  */
169
182
  export function apply(ctx: Context, config: RealtimeAgentConfig): void {
170
183
  const transcript = new TranscriptBuffer(config.maxTranscriptChars)
184
+ // This plugin owns the session, so it is the only one that can honestly write these entries. The audio
185
+ // route emits a *request* to open a session and deliberately records nothing for it: recording a
186
+ // request as an event is how a journal starts lying.
187
+ const journal = ctx.realtime.journal
171
188
  let session: RealtimeSession | undefined
172
189
 
173
190
  const handlers = createHandlers({
@@ -175,9 +192,28 @@ export function apply(ctx: Context, config: RealtimeAgentConfig): void {
175
192
  session: () => session,
176
193
  ask: request => ctx.serial('realtime-agent/delegation', request),
177
194
  timeoutMs: config.delegationTimeoutMs,
178
- onClosed: () => { session = undefined },
179
- onSessionError: (error) => { ctx.emit('realtime-agent/error', error) },
180
- onAudio: (pcm16) => { ctx.emit('realtime-agent/audio', pcm16) },
195
+ onClosed: () => {
196
+ session = undefined
197
+ journal.record('session.closed', {})
198
+ },
199
+ onSessionError: (error) => {
200
+ ctx.emit('realtime-agent/error', error)
201
+ // The class, never the message. A provider error can carry the key it refused, and this plugin
202
+ // holds no credential to redact against — so it records the category and leaves the text to the
203
+ // plugin that does. Naming the setting instead of repeating the value, applied to a log line.
204
+ journal.record('session.failed', { class: error.name })
205
+ },
206
+ onAudio: (pcm16) => {
207
+ ctx.emit('realtime-agent/audio', pcm16)
208
+ // Handed to the transport: all the host can observe, and no more (invariant 6).
209
+ journal.record('speech.sent', { bytes: String(pcm16.byteLength) })
210
+ },
211
+ onAcknowledged: (append, delegationId) => {
212
+ // The one place an acknowledgement can honestly be recorded: the seam's appends resolve on the
213
+ // provider's confirmation, not on the send. Note what is deliberately absent beside it — no entry
214
+ // anywhere claims the audio was heard, which is the pair invariant 6 exists to keep apart.
215
+ journal.record('append.acknowledged', { append, delegationId })
216
+ },
181
217
  })
182
218
 
183
219
  /**
@@ -197,6 +233,7 @@ export function apply(ctx: Context, config: RealtimeAgentConfig): void {
197
233
  handlers,
198
234
  })
199
235
  session = opened
236
+ journal.record('session.opened', { provider: config.provider, model: config.model })
200
237
  return opened
201
238
  }
202
239