@kuralle-syrinx/core 4.4.0 → 4.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/dist/audio/alaw.d.ts +3 -0
- package/dist/audio/alaw.d.ts.map +1 -0
- package/dist/audio/alaw.js +53 -0
- package/dist/audio/alaw.js.map +1 -0
- package/dist/audio/g722.d.ts +39 -0
- package/dist/audio/g722.d.ts.map +1 -0
- package/dist/audio/g722.js +286 -0
- package/dist/audio/g722.js.map +1 -0
- package/dist/audio/index.d.ts +7 -0
- package/dist/audio/index.d.ts.map +1 -0
- package/dist/audio/index.js +8 -0
- package/dist/audio/index.js.map +1 -0
- package/dist/audio/loudness.d.ts +13 -0
- package/dist/audio/loudness.d.ts.map +1 -0
- package/dist/audio/loudness.js +65 -0
- package/dist/audio/loudness.js.map +1 -0
- package/dist/audio/mulaw.d.ts +3 -0
- package/dist/audio/mulaw.d.ts.map +1 -0
- package/dist/audio/mulaw.js +39 -0
- package/dist/audio/mulaw.js.map +1 -0
- package/dist/audio/pcm.d.ts +5 -0
- package/dist/audio/pcm.d.ts.map +1 -0
- package/dist/audio/pcm.js +40 -0
- package/dist/audio/pcm.js.map +1 -0
- package/dist/audio/resample.d.ts +12 -0
- package/dist/audio/resample.d.ts.map +1 -0
- package/dist/audio/resample.js +157 -0
- package/dist/audio/resample.js.map +1 -0
- package/dist/audio-envelope.d.ts +23 -0
- package/dist/audio-envelope.d.ts.map +1 -0
- package/dist/audio-envelope.js +114 -0
- package/dist/audio-envelope.js.map +1 -0
- package/dist/confidence-to-wait.d.ts +12 -0
- package/dist/confidence-to-wait.d.ts.map +1 -0
- package/dist/confidence-to-wait.js +18 -0
- package/dist/confidence-to-wait.js.map +1 -0
- package/dist/conversation-event.d.ts +19 -0
- package/dist/conversation-event.d.ts.map +1 -0
- package/dist/conversation-event.js +44 -0
- package/dist/conversation-event.js.map +1 -0
- package/dist/error-handler.d.ts +35 -0
- package/dist/error-handler.d.ts.map +1 -0
- package/dist/error-handler.js +136 -0
- package/dist/error-handler.js.map +1 -0
- package/dist/idle-timeout.d.ts +69 -0
- package/dist/idle-timeout.d.ts.map +1 -0
- package/dist/idle-timeout.js +149 -0
- package/dist/idle-timeout.js.map +1 -0
- package/dist/incremental-unit.d.ts +17 -0
- package/dist/incremental-unit.d.ts.map +1 -0
- package/dist/incremental-unit.js +5 -0
- package/dist/incremental-unit.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/init-chain.d.ts +35 -0
- package/dist/init-chain.d.ts.map +1 -0
- package/dist/init-chain.js +102 -0
- package/dist/init-chain.js.map +1 -0
- package/dist/init-stage-order.d.ts +5 -0
- package/dist/init-stage-order.d.ts.map +1 -0
- package/dist/init-stage-order.js +74 -0
- package/dist/init-stage-order.js.map +1 -0
- package/dist/interaction-coordinator.d.ts +45 -0
- package/dist/interaction-coordinator.d.ts.map +1 -0
- package/dist/interaction-coordinator.js +197 -0
- package/dist/interaction-coordinator.js.map +1 -0
- package/dist/interaction-policy.d.ts +103 -0
- package/dist/interaction-policy.d.ts.map +1 -0
- package/dist/interaction-policy.js +6 -0
- package/dist/interaction-policy.js.map +1 -0
- package/dist/iu-ledger.d.ts +39 -0
- package/dist/iu-ledger.d.ts.map +1 -0
- package/dist/iu-ledger.js +90 -0
- package/dist/iu-ledger.js.map +1 -0
- package/dist/latency-filler-fixtures.d.ts +7 -0
- package/dist/latency-filler-fixtures.d.ts.map +1 -0
- package/dist/latency-filler-fixtures.js +10 -0
- package/dist/latency-filler-fixtures.js.map +1 -0
- package/dist/latency-filler.d.ts +29 -0
- package/dist/latency-filler.d.ts.map +1 -0
- package/dist/latency-filler.js +102 -0
- package/dist/latency-filler.js.map +1 -0
- package/dist/mode-switcher.d.ts +24 -0
- package/dist/mode-switcher.d.ts.map +1 -0
- package/dist/mode-switcher.js +83 -0
- package/dist/mode-switcher.js.map +1 -0
- package/dist/observability-observer.d.ts +36 -0
- package/dist/observability-observer.d.ts.map +1 -0
- package/dist/observability-observer.js +141 -0
- package/dist/observability-observer.js.map +1 -0
- package/dist/observability.d.ts +68 -0
- package/dist/observability.d.ts.map +1 -0
- package/dist/observability.js +70 -0
- package/dist/observability.js.map +1 -0
- package/dist/packet-factories.d.ts +58 -0
- package/dist/packet-factories.d.ts.map +1 -0
- package/dist/packet-factories.js +181 -0
- package/dist/packet-factories.js.map +1 -0
- package/dist/packets.d.ts +532 -0
- package/dist/packets.d.ts.map +1 -0
- package/dist/packets.js +51 -0
- package/dist/packets.js.map +1 -0
- package/dist/pipeline-bus.d.ts +92 -0
- package/dist/pipeline-bus.d.ts.map +1 -0
- package/dist/pipeline-bus.js +294 -0
- package/dist/pipeline-bus.js.map +1 -0
- package/dist/plugin-contract.d.ts +73 -0
- package/dist/plugin-contract.d.ts.map +1 -0
- package/dist/plugin-contract.js +30 -0
- package/dist/plugin-contract.js.map +1 -0
- package/dist/policies/defer.d.ts +11 -0
- package/dist/policies/defer.d.ts.map +1 -0
- package/dist/policies/defer.js +13 -0
- package/dist/policies/defer.js.map +1 -0
- package/dist/policies/rule-based.d.ts +35 -0
- package/dist/policies/rule-based.d.ts.map +1 -0
- package/dist/policies/rule-based.js +130 -0
- package/dist/policies/rule-based.js.map +1 -0
- package/dist/pricing.d.ts +34 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +108 -0
- package/dist/pricing.js.map +1 -0
- package/dist/primary-speaker-fixtures.d.ts +12 -0
- package/dist/primary-speaker-fixtures.d.ts.map +1 -0
- package/dist/primary-speaker-fixtures.js +37 -0
- package/dist/primary-speaker-fixtures.js.map +1 -0
- package/dist/primary-speaker-gate.d.ts +42 -0
- package/dist/primary-speaker-gate.d.ts.map +1 -0
- package/dist/primary-speaker-gate.js +178 -0
- package/dist/primary-speaker-gate.js.map +1 -0
- package/dist/provider-fallback.d.ts +28 -0
- package/dist/provider-fallback.d.ts.map +1 -0
- package/dist/provider-fallback.js +72 -0
- package/dist/provider-fallback.js.map +1 -0
- package/dist/reasoner-hedge.d.ts +21 -0
- package/dist/reasoner-hedge.d.ts.map +1 -0
- package/dist/reasoner-hedge.js +170 -0
- package/dist/reasoner-hedge.js.map +1 -0
- package/dist/reasoner-route.d.ts +24 -0
- package/dist/reasoner-route.d.ts.map +1 -0
- package/dist/reasoner-route.js +87 -0
- package/dist/reasoner-route.js.map +1 -0
- package/dist/reasoner-session-store.d.ts +18 -0
- package/dist/reasoner-session-store.d.ts.map +1 -0
- package/dist/reasoner-session-store.js +21 -0
- package/dist/reasoner-session-store.js.map +1 -0
- package/dist/reasoner.d.ts +97 -0
- package/dist/reasoner.d.ts.map +1 -0
- package/dist/reasoner.js +9 -0
- package/dist/reasoner.js.map +1 -0
- package/dist/retry.d.ts +31 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +83 -0
- package/dist/retry.js.map +1 -0
- package/dist/scheduler.d.ts +11 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +20 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/spend-cap.d.ts +27 -0
- package/dist/spend-cap.d.ts.map +1 -0
- package/dist/spend-cap.js +38 -0
- package/dist/spend-cap.js.map +1 -0
- package/dist/tts-playout-clock.d.ts +43 -0
- package/dist/tts-playout-clock.d.ts.map +1 -0
- package/dist/tts-playout-clock.js +125 -0
- package/dist/tts-playout-clock.js.map +1 -0
- package/dist/turn-arbiter.d.ts +41 -0
- package/dist/turn-arbiter.d.ts.map +1 -0
- package/dist/turn-arbiter.js +259 -0
- package/dist/turn-arbiter.js.map +1 -0
- package/dist/voice-agent-session-util.d.ts +60 -0
- package/dist/voice-agent-session-util.d.ts.map +1 -0
- package/dist/voice-agent-session-util.js +204 -0
- package/dist/voice-agent-session-util.js.map +1 -0
- package/dist/voice-agent-session.d.ts +435 -0
- package/dist/voice-agent-session.d.ts.map +1 -0
- package/dist/voice-agent-session.js +1597 -0
- package/dist/voice-agent-session.js.map +1 -0
- package/dist/voice-text.d.ts +46 -0
- package/dist/voice-text.d.ts.map +1 -0
- package/dist/voice-text.js +209 -0
- package/dist/voice-text.js.map +1 -0
- package/package.json +19 -6
- package/src/audio/alaw.test.ts +87 -0
- package/src/audio/audio.test.ts +285 -0
- package/src/audio/g722.test.ts +149 -0
- package/src/audio/loudness.test.ts +58 -0
- package/src/audio-envelope.test.ts +167 -0
- package/src/confidence-to-wait.test.ts +21 -0
- package/src/error-handler.test.ts +56 -0
- package/src/hedge-throwing-backend.test.ts +46 -0
- package/src/interaction-coordinator.test.ts +529 -0
- package/src/iu-ledger.test.ts +276 -0
- package/src/latency-filler.test.ts +62 -0
- package/src/observability-observer.test.ts +248 -0
- package/src/observability.test.ts +94 -0
- package/src/packet-factories.test.ts +126 -0
- package/src/pipeline-bus.g10.test.ts +145 -0
- package/src/pipeline-bus.test.ts +211 -0
- package/src/policies/defer.test.ts +86 -0
- package/src/policies/rule-based.test.ts +334 -0
- package/src/pricing.test.ts +226 -0
- package/src/primary-speaker-gate.test.ts +150 -0
- package/src/provider-fallback.test.ts +87 -0
- package/src/reasoner-hedge.test.ts +361 -0
- package/src/reasoner-route.test.ts +248 -0
- package/src/reasoner.test.ts +69 -0
- package/src/retry.test.ts +83 -0
- package/src/route-throwing-spec.test.ts +44 -0
- package/src/spend-cap.test.ts +114 -0
- package/src/tts-playout-clock.test.ts +125 -0
- package/src/turn-arbiter.characterization.test.ts +477 -0
- package/src/turn-arbiter.test.ts +762 -0
- package/src/voice-agent-session.test.ts +4165 -0
- package/src/voice-text.test.ts +156 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
//
|
|
3
|
+
// Syrinx Kernel v2 — Incremental-Unit ledger (IU substrate, RFC incremental-unit-substrate)
|
|
4
|
+
export class InMemoryIuLedger {
|
|
5
|
+
onEvent;
|
|
6
|
+
maxContexts;
|
|
7
|
+
byCtx = new Map();
|
|
8
|
+
constructor(onEvent = () => { }, maxContexts = 256) {
|
|
9
|
+
this.onEvent = onEvent;
|
|
10
|
+
this.maxContexts = maxContexts;
|
|
11
|
+
}
|
|
12
|
+
add(iu) {
|
|
13
|
+
const ctx = iu.id.contextId;
|
|
14
|
+
if (!this.byCtx.has(ctx) && this.byCtx.size >= this.maxContexts) {
|
|
15
|
+
const oldest = this.byCtx.keys().next().value;
|
|
16
|
+
if (oldest !== undefined)
|
|
17
|
+
this.byCtx.delete(oldest);
|
|
18
|
+
}
|
|
19
|
+
this.ctxMap(ctx).set(iu.id.iuId, iu);
|
|
20
|
+
}
|
|
21
|
+
commit(id, prefix) {
|
|
22
|
+
const ctxMap = this.byCtx.get(id.contextId);
|
|
23
|
+
if (!ctxMap) {
|
|
24
|
+
this.onEvent({ kind: "unknown_iu", op: "commit", id });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const iu = ctxMap.get(id.iuId);
|
|
28
|
+
if (!iu) {
|
|
29
|
+
this.onEvent({ kind: "unknown_iu", op: "commit", id });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (iu.state !== "hypothesized") {
|
|
33
|
+
this.onEvent({ kind: "terminal_op", op: "commit", id, state: iu.state });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
iu.state = "committed";
|
|
37
|
+
if (prefix) {
|
|
38
|
+
iu.committedPrefix = prefix;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
revoke(id) {
|
|
42
|
+
const ctxMap = this.byCtx.get(id.contextId);
|
|
43
|
+
if (!ctxMap) {
|
|
44
|
+
this.onEvent({ kind: "unknown_iu", op: "revoke", id });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const iu = ctxMap.get(id.iuId);
|
|
48
|
+
if (!iu) {
|
|
49
|
+
this.onEvent({ kind: "unknown_iu", op: "revoke", id });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (iu.state !== "hypothesized") {
|
|
53
|
+
this.onEvent({ kind: "terminal_op", op: "revoke", id, state: iu.state });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
iu.state = "revoked";
|
|
57
|
+
}
|
|
58
|
+
get(id) {
|
|
59
|
+
const ctxMap = this.byCtx.get(id.contextId);
|
|
60
|
+
if (!ctxMap) {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
return ctxMap.get(id.iuId);
|
|
64
|
+
}
|
|
65
|
+
latest(contextId, kind) {
|
|
66
|
+
const ctxMap = this.byCtx.get(contextId);
|
|
67
|
+
if (!ctxMap) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
let found;
|
|
71
|
+
for (const iu of ctxMap.values()) {
|
|
72
|
+
if (iu.kind === kind) {
|
|
73
|
+
found = iu;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return found;
|
|
77
|
+
}
|
|
78
|
+
clear(contextId) {
|
|
79
|
+
this.byCtx.delete(contextId);
|
|
80
|
+
}
|
|
81
|
+
ctxMap(contextId) {
|
|
82
|
+
let map = this.byCtx.get(contextId);
|
|
83
|
+
if (!map) {
|
|
84
|
+
map = new Map();
|
|
85
|
+
this.byCtx.set(contextId, map);
|
|
86
|
+
}
|
|
87
|
+
return map;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=iu-ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"iu-ledger.js","sourceRoot":"","sources":["../src/iu-ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface LatencyFillerFixture {
|
|
2
|
+
readonly id: string;
|
|
3
|
+
readonly userText: string;
|
|
4
|
+
readonly expectedConnective: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const LATENCY_FILLER_FIXTURES: readonly LatencyFillerFixture[];
|
|
7
|
+
//# sourceMappingURL=latency-filler-fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latency-filler-fixtures.d.ts","sourceRoot":"","sources":["../src/latency-filler-fixtures.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC;AAED,eAAO,MAAM,uBAAuB,EAAE,SAAS,oBAAoB,EAKzD,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
//
|
|
3
|
+
// Labeled utterances for latency-filler connective selection tests.
|
|
4
|
+
export const LATENCY_FILLER_FIXTURES = [
|
|
5
|
+
{ id: "question", userText: "Can I still add Biology 101?", expectedConnective: "Well," },
|
|
6
|
+
{ id: "thanks", userText: "Thanks for checking that.", expectedConnective: "Right," },
|
|
7
|
+
{ id: "statement-0", userText: "I need the late add form.", expectedConnective: "So," },
|
|
8
|
+
{ id: "statement-1", userText: "My hold is blocking registration.", expectedConnective: "Well," },
|
|
9
|
+
];
|
|
10
|
+
//# sourceMappingURL=latency-filler-fixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latency-filler-fixtures.js","sourceRoot":"","sources":["../src/latency-filler-fixtures.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,oEAAoE;AAQpE,MAAM,CAAC,MAAM,uBAAuB,GAAoC;IACtE,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,8BAA8B,EAAE,kBAAkB,EAAE,OAAO,EAAE;IACzF,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,QAAQ,EAAE;IACrF,EAAE,EAAE,EAAE,aAAa,EAAE,QAAQ,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,KAAK,EAAE;IACvF,EAAE,EAAE,EAAE,aAAa,EAAE,QAAQ,EAAE,mCAAmC,EAAE,kBAAkB,EAAE,OAAO,EAAE;CACzF,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const LATENCY_FILLER_CONNECTIVES: readonly ["So,", "Well,", "Right,", "Okay,", "Hmm,"];
|
|
2
|
+
export type LatencyFillerConnective = (typeof LATENCY_FILLER_CONNECTIVES)[number];
|
|
3
|
+
export interface LatencyFillerState {
|
|
4
|
+
readonly text: string;
|
|
5
|
+
active: boolean;
|
|
6
|
+
spliced: boolean;
|
|
7
|
+
cancelled: boolean;
|
|
8
|
+
readonly startedAtMs: number;
|
|
9
|
+
}
|
|
10
|
+
export interface LatencyFillerConfig {
|
|
11
|
+
readonly enabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare class LatencyFillerController {
|
|
14
|
+
private readonly enabled;
|
|
15
|
+
private turnIndex;
|
|
16
|
+
private readonly states;
|
|
17
|
+
constructor(config?: LatencyFillerConfig);
|
|
18
|
+
isEnabled(): boolean;
|
|
19
|
+
start(contextId: string, userText: string, nowMs?: number): string | null;
|
|
20
|
+
getState(contextId: string): LatencyFillerState | undefined;
|
|
21
|
+
isActive(contextId: string): boolean;
|
|
22
|
+
isFillerOnly(contextId: string): boolean;
|
|
23
|
+
spliceLlmDelta(contextId: string, delta: string): string;
|
|
24
|
+
cancel(contextId: string): LatencyFillerState | null;
|
|
25
|
+
clear(contextId: string): void;
|
|
26
|
+
}
|
|
27
|
+
export declare function selectLatencyFillerConnective(userText: string, turnIndex: number): string;
|
|
28
|
+
export declare function stripRedundantFillerPrefix(fillerText: string, llmText: string): string;
|
|
29
|
+
//# sourceMappingURL=latency-filler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latency-filler.d.ts","sourceRoot":"","sources":["../src/latency-filler.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,0BAA0B,sDAM7B,CAAC;AAEX,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAElF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyC;gBAEpD,MAAM,GAAE,mBAAwB;IAI5C,SAAS,IAAI,OAAO;IAIpB,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAa,GAAG,MAAM,GAAG,IAAI;IAe7E,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI3D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAKpC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAKxC,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAOxD,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAQpD,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAG/B;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAMzF;AAQD,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAqBtF"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
//
|
|
3
|
+
// VE-03 / G24 — latency-hiding dual-track filler (DDTSR direction).
|
|
4
|
+
// Emits a short discourse connective at endpoint while the main LLM spins up.
|
|
5
|
+
export const LATENCY_FILLER_CONNECTIVES = [
|
|
6
|
+
"So,",
|
|
7
|
+
"Well,",
|
|
8
|
+
"Right,",
|
|
9
|
+
"Okay,",
|
|
10
|
+
"Hmm,",
|
|
11
|
+
];
|
|
12
|
+
export class LatencyFillerController {
|
|
13
|
+
enabled;
|
|
14
|
+
turnIndex = 0;
|
|
15
|
+
states = new Map();
|
|
16
|
+
constructor(config = {}) {
|
|
17
|
+
this.enabled = config.enabled === true;
|
|
18
|
+
}
|
|
19
|
+
isEnabled() {
|
|
20
|
+
return this.enabled;
|
|
21
|
+
}
|
|
22
|
+
start(contextId, userText, nowMs = Date.now()) {
|
|
23
|
+
if (!this.enabled)
|
|
24
|
+
return null;
|
|
25
|
+
if (this.states.has(contextId))
|
|
26
|
+
return null;
|
|
27
|
+
const text = selectLatencyFillerConnective(userText, this.turnIndex);
|
|
28
|
+
this.turnIndex += 1;
|
|
29
|
+
this.states.set(contextId, {
|
|
30
|
+
text,
|
|
31
|
+
active: true,
|
|
32
|
+
spliced: false,
|
|
33
|
+
cancelled: false,
|
|
34
|
+
startedAtMs: nowMs,
|
|
35
|
+
});
|
|
36
|
+
return text;
|
|
37
|
+
}
|
|
38
|
+
getState(contextId) {
|
|
39
|
+
return this.states.get(contextId);
|
|
40
|
+
}
|
|
41
|
+
isActive(contextId) {
|
|
42
|
+
const state = this.states.get(contextId);
|
|
43
|
+
return state?.active === true && state.cancelled !== true;
|
|
44
|
+
}
|
|
45
|
+
isFillerOnly(contextId) {
|
|
46
|
+
const state = this.states.get(contextId);
|
|
47
|
+
return state?.active === true && state.spliced !== true && state.cancelled !== true;
|
|
48
|
+
}
|
|
49
|
+
spliceLlmDelta(contextId, delta) {
|
|
50
|
+
const state = this.states.get(contextId);
|
|
51
|
+
if (!state || state.cancelled || state.spliced)
|
|
52
|
+
return delta;
|
|
53
|
+
state.spliced = true;
|
|
54
|
+
return stripRedundantFillerPrefix(state.text, delta);
|
|
55
|
+
}
|
|
56
|
+
cancel(contextId) {
|
|
57
|
+
const state = this.states.get(contextId);
|
|
58
|
+
if (!state || state.cancelled)
|
|
59
|
+
return null;
|
|
60
|
+
state.cancelled = true;
|
|
61
|
+
state.active = false;
|
|
62
|
+
return state;
|
|
63
|
+
}
|
|
64
|
+
clear(contextId) {
|
|
65
|
+
this.states.delete(contextId);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function selectLatencyFillerConnective(userText, turnIndex) {
|
|
69
|
+
const trimmed = userText.trim().toLowerCase();
|
|
70
|
+
if (trimmed.endsWith("?"))
|
|
71
|
+
return "Well,";
|
|
72
|
+
if (/\b(thanks|thank you)\b/.test(trimmed))
|
|
73
|
+
return "Right,";
|
|
74
|
+
const pool = LATENCY_FILLER_CONNECTIVES;
|
|
75
|
+
return pool[((turnIndex % pool.length) + pool.length) % pool.length];
|
|
76
|
+
}
|
|
77
|
+
function fillerPrefixBoundary(lowerBody, prefixLen) {
|
|
78
|
+
if (prefixLen >= lowerBody.length)
|
|
79
|
+
return true;
|
|
80
|
+
const next = lowerBody[prefixLen];
|
|
81
|
+
return /[\s,.!?…:;—\-]/.test(next);
|
|
82
|
+
}
|
|
83
|
+
export function stripRedundantFillerPrefix(fillerText, llmText) {
|
|
84
|
+
const fillerWord = fillerText.replace(/[.,!?…\s]+$/g, "").trim().toLowerCase();
|
|
85
|
+
if (!fillerWord)
|
|
86
|
+
return llmText;
|
|
87
|
+
const body = llmText.trimStart();
|
|
88
|
+
const lowerBody = body.toLowerCase();
|
|
89
|
+
if (lowerBody.startsWith(fillerWord) && fillerPrefixBoundary(lowerBody, fillerWord.length)) {
|
|
90
|
+
let rest = body.slice(fillerWord.length);
|
|
91
|
+
rest = rest.replace(/^[\s,]+/, "");
|
|
92
|
+
return rest;
|
|
93
|
+
}
|
|
94
|
+
const withPunct = `${fillerWord},`;
|
|
95
|
+
if (lowerBody.startsWith(withPunct) && fillerPrefixBoundary(lowerBody, withPunct.length)) {
|
|
96
|
+
let rest = body.slice(withPunct.length);
|
|
97
|
+
rest = rest.replace(/^[\s,]+/, "");
|
|
98
|
+
return rest;
|
|
99
|
+
}
|
|
100
|
+
return llmText;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=latency-filler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latency-filler.js","sourceRoot":"","sources":["../src/latency-filler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PipelineBus } from "./pipeline-bus.js";
|
|
2
|
+
import type { ModeSwitchRequestedPacket } from "./packets.js";
|
|
3
|
+
import { type InitStep as InitStepType } from "./init-chain.js";
|
|
4
|
+
export interface ModeSwitchHandlers {
|
|
5
|
+
/** Steps to run when switching from text to audio mode. */
|
|
6
|
+
textToAudioSteps: InitStepType[];
|
|
7
|
+
/** Steps to run when switching from audio to text mode (teardown). */
|
|
8
|
+
audioToTextCleanups: Array<() => Promise<void>>;
|
|
9
|
+
}
|
|
10
|
+
export declare class ModeSwitcher {
|
|
11
|
+
private currentMode;
|
|
12
|
+
private readonly bus;
|
|
13
|
+
private handlers;
|
|
14
|
+
constructor(bus: PipelineBus, initialMode?: "text" | "audio");
|
|
15
|
+
/** Register the init/teardown steps. Call once during session setup. */
|
|
16
|
+
register(handlers: ModeSwitchHandlers): void;
|
|
17
|
+
/** Get the current mode. */
|
|
18
|
+
get mode(): "text" | "audio";
|
|
19
|
+
/** Handle a mode switch request from the bus. */
|
|
20
|
+
handleSwitchRequested(pkt: ModeSwitchRequestedPacket): Promise<void>;
|
|
21
|
+
private switchToAudio;
|
|
22
|
+
private switchToText;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=mode-switcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode-switcher.d.ts","sourceRoot":"","sources":["../src/mode-switcher.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAgB,KAAK,QAAQ,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAM9E,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,gBAAgB,EAAE,YAAY,EAAE,CAAC;IACjC,sEAAsE;IACtE,mBAAmB,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CACjD;AAMD,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAmC;gBAEvC,GAAG,EAAE,WAAW,EAAE,WAAW,GAAE,MAAM,GAAG,OAAiB;IAKrE,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI;IAI5C,4BAA4B;IAC5B,IAAI,IAAI,IAAI,MAAM,GAAG,OAAO,CAE3B;IAED,iDAAiD;IAC3C,qBAAqB,CAAC,GAAG,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;YAe5D,aAAa;YAoBb,YAAY;CAmB3B"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
//
|
|
3
|
+
// Syrinx Kernel v2 — Mode Switcher
|
|
4
|
+
//
|
|
5
|
+
// Handles text ↔ audio mode transitions mid-session.
|
|
6
|
+
// Text→Audio: serial init of audio pipeline (STT, TTS, VAD, EOS, Denoiser)
|
|
7
|
+
// Audio→Text: confirm text mode immediately, teardown audio components in background
|
|
8
|
+
//
|
|
9
|
+
// Design decision: audio→text confirms immediately so the user can send text
|
|
10
|
+
// without waiting for STT/TTS/VAD/EOS WebSocket connections to close.
|
|
11
|
+
import { Route } from "./pipeline-bus.js";
|
|
12
|
+
import { runInitChain } from "./init-chain.js";
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Switcher
|
|
15
|
+
// =============================================================================
|
|
16
|
+
export class ModeSwitcher {
|
|
17
|
+
currentMode;
|
|
18
|
+
bus;
|
|
19
|
+
handlers = null;
|
|
20
|
+
constructor(bus, initialMode = "audio") {
|
|
21
|
+
this.bus = bus;
|
|
22
|
+
this.currentMode = initialMode;
|
|
23
|
+
}
|
|
24
|
+
/** Register the init/teardown steps. Call once during session setup. */
|
|
25
|
+
register(handlers) {
|
|
26
|
+
this.handlers = handlers;
|
|
27
|
+
}
|
|
28
|
+
/** Get the current mode. */
|
|
29
|
+
get mode() {
|
|
30
|
+
return this.currentMode;
|
|
31
|
+
}
|
|
32
|
+
/** Handle a mode switch request from the bus. */
|
|
33
|
+
async handleSwitchRequested(pkt) {
|
|
34
|
+
if (pkt.mode === this.currentMode)
|
|
35
|
+
return;
|
|
36
|
+
if (!this.handlers)
|
|
37
|
+
return;
|
|
38
|
+
if (pkt.mode === "audio") {
|
|
39
|
+
await this.switchToAudio(pkt.contextId);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
await this.switchToText(pkt.contextId);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Private
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
async switchToAudio(contextId) {
|
|
49
|
+
if (!this.handlers)
|
|
50
|
+
return;
|
|
51
|
+
try {
|
|
52
|
+
await runInitChain(this.bus, this.handlers.textToAudioSteps);
|
|
53
|
+
this.currentMode = "audio";
|
|
54
|
+
const completed = {
|
|
55
|
+
kind: "mode.switch_completed",
|
|
56
|
+
contextId,
|
|
57
|
+
timestampMs: Date.now(),
|
|
58
|
+
mode: "audio",
|
|
59
|
+
};
|
|
60
|
+
this.bus.push(Route.Main, completed);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
// Init chain already emitted init.failed — re-throw for session handler
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async switchToText(contextId) {
|
|
68
|
+
// Confirm text mode immediately — don't wait for teardown
|
|
69
|
+
this.currentMode = "text";
|
|
70
|
+
const completed = {
|
|
71
|
+
kind: "mode.switch_completed",
|
|
72
|
+
contextId,
|
|
73
|
+
timestampMs: Date.now(),
|
|
74
|
+
mode: "text",
|
|
75
|
+
};
|
|
76
|
+
this.bus.push(Route.Main, completed);
|
|
77
|
+
// Teardown audio components in background
|
|
78
|
+
if (this.handlers?.audioToTextCleanups) {
|
|
79
|
+
void Promise.allSettled(this.handlers.audioToTextCleanups.map((fn) => fn()));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=mode-switcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode-switcher.js","sourceRoot":"","sources":["../src/mode-switcher.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,mCAAmC;AACnC,EAAE;AACF,qDAAqD;AACrD,2EAA2E;AAC3E,qFAAqF;AACrF,EAAE;AACF,6EAA6E;AAC7E,sEAAsE;AAGtE,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAK1C,OAAO,EAAE,YAAY,EAAiC,MAAM,iBAAiB,CAAC;AAa9E,gFAAgF;AAChF,WAAW;AACX,gFAAgF;AAEhF,MAAM,OAAO,YAAY;IACf,WAAW,CAAmB;IACrB,GAAG,CAAc;IAC1B,QAAQ,GAA8B,IAAI,CAAC;IAEnD,YAAY,GAAgB,EAAE,cAAgC,OAAO;QACnE,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED,wEAAwE;IACxE,QAAQ,CAAC,QAA4B;QACnC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,4BAA4B;IAC5B,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,iDAAiD;IACjD,KAAK,CAAC,qBAAqB,CAAC,GAA8B;QACxD,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,WAAW;YAAE,OAAO;QAC1C,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE3B,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACzB,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,UAAU;IACV,8EAA8E;IAEtE,KAAK,CAAC,aAAa,CAAC,SAAiB;QAC3C,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE3B,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;YAC7D,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC;YAE3B,MAAM,SAAS,GAA8B;gBAC3C,IAAI,EAAE,uBAAuB;gBAC7B,SAAS;gBACT,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;gBACvB,IAAI,EAAE,OAAO;aACd,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,wEAAwE;YACxE,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,SAAiB;QAC1C,0DAA0D;QAC1D,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC;QAE1B,MAAM,SAAS,GAA8B;YAC3C,IAAI,EAAE,uBAAuB;YAC7B,SAAS;YACT,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;YACvB,IAAI,EAAE,MAAM;SACb,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAErC,0CAA0C;QAC1C,IAAI,IAAI,CAAC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;YACvC,KAAK,OAAO,CAAC,UAAU,CACrB,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CACpD,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type PipelineBus } from "./pipeline-bus.js";
|
|
2
|
+
import { type MetricsExporter, type ObservabilityLayer } from "./observability.js";
|
|
3
|
+
export interface ObservabilityDims {
|
|
4
|
+
readonly provider: string;
|
|
5
|
+
readonly model: string;
|
|
6
|
+
readonly region: string;
|
|
7
|
+
readonly layer?: ObservabilityLayer;
|
|
8
|
+
}
|
|
9
|
+
export interface ObservabilityObserverDeps {
|
|
10
|
+
readonly bus: PipelineBus;
|
|
11
|
+
readonly exporter: MetricsExporter;
|
|
12
|
+
readonly sessionId: string;
|
|
13
|
+
readonly dims: ObservabilityDims;
|
|
14
|
+
readonly getContextId: () => string;
|
|
15
|
+
}
|
|
16
|
+
export declare class ObservabilityObserver {
|
|
17
|
+
private readonly deps;
|
|
18
|
+
private readonly boundaryTimes;
|
|
19
|
+
private readonly stageDims;
|
|
20
|
+
private readonly agentStartedEmitted;
|
|
21
|
+
private readonly unsubscribes;
|
|
22
|
+
constructor(deps: ObservabilityObserverDeps);
|
|
23
|
+
wire(disposers?: Array<() => void>): void;
|
|
24
|
+
dispose(): void;
|
|
25
|
+
private speechId;
|
|
26
|
+
private onVadSpeechStarted;
|
|
27
|
+
private onVadSpeechEnded;
|
|
28
|
+
private onTurnComplete;
|
|
29
|
+
private onTtsAudio;
|
|
30
|
+
private onTtsEnd;
|
|
31
|
+
private onInterruptDetected;
|
|
32
|
+
private emitBoundary;
|
|
33
|
+
private mergeStageDims;
|
|
34
|
+
private dimsFor;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=observability-observer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observability-observer.d.ts","sourceRoot":"","sources":["../src/observability-observer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAkB,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAYnG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,kBAAkB,CAAC;CACrC;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,MAAM,MAAM,CAAC;CACrC;AAKD,qBAAa,qBAAqB;IAMpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoC;IAClE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAC1D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IACzD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyB;gBAEzB,IAAI,EAAE,yBAAyB;IAE5D,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI;IA8BzC,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,YAAY;IAqDpB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,OAAO;CAahB"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import { Route } from "./pipeline-bus.js";
|
|
3
|
+
import { monotonicNowMs } from "./observability.js";
|
|
4
|
+
import * as make from "./packet-factories.js";
|
|
5
|
+
export class ObservabilityObserver {
|
|
6
|
+
deps;
|
|
7
|
+
boundaryTimes = new Map();
|
|
8
|
+
stageDims = new Map();
|
|
9
|
+
agentStartedEmitted = new Set();
|
|
10
|
+
unsubscribes = [];
|
|
11
|
+
constructor(deps) {
|
|
12
|
+
this.deps = deps;
|
|
13
|
+
}
|
|
14
|
+
wire(disposers) {
|
|
15
|
+
const reg = (unsub) => {
|
|
16
|
+
this.unsubscribes.push(unsub);
|
|
17
|
+
disposers?.push(unsub);
|
|
18
|
+
};
|
|
19
|
+
reg(this.deps.bus.on("vad.speech_started", (pkt) => this.onVadSpeechStarted(pkt)));
|
|
20
|
+
reg(this.deps.bus.on("vad.speech_ended", (pkt) => this.onVadSpeechEnded(pkt)));
|
|
21
|
+
reg(this.deps.bus.on("eos.turn_complete", (pkt) => this.onTurnComplete(pkt)));
|
|
22
|
+
reg(this.deps.bus.on("tts.audio", (pkt) => this.onTtsAudio(pkt)));
|
|
23
|
+
reg(this.deps.bus.on("tts.end", (pkt) => this.onTtsEnd(pkt)));
|
|
24
|
+
reg(this.deps.bus.on("interrupt.detected", (pkt) => this.onInterruptDetected(pkt)));
|
|
25
|
+
}
|
|
26
|
+
dispose() {
|
|
27
|
+
for (const unsub of this.unsubscribes)
|
|
28
|
+
unsub();
|
|
29
|
+
this.unsubscribes.length = 0;
|
|
30
|
+
this.boundaryTimes.clear();
|
|
31
|
+
this.stageDims.clear();
|
|
32
|
+
this.agentStartedEmitted.clear();
|
|
33
|
+
}
|
|
34
|
+
speechId(contextId) {
|
|
35
|
+
return contextId || this.deps.getContextId();
|
|
36
|
+
}
|
|
37
|
+
onVadSpeechStarted(pkt) {
|
|
38
|
+
this.emitBoundary(this.speechId(pkt.contextId), "user_started_speaking");
|
|
39
|
+
}
|
|
40
|
+
onVadSpeechEnded(pkt) {
|
|
41
|
+
this.emitBoundary(this.speechId(pkt.contextId), "user_stopped_speaking");
|
|
42
|
+
}
|
|
43
|
+
onTurnComplete(pkt) {
|
|
44
|
+
const provider = pkt.transcripts[0]?.provider;
|
|
45
|
+
if (provider)
|
|
46
|
+
this.mergeStageDims(this.speechId(pkt.contextId), provider);
|
|
47
|
+
this.emitBoundary(this.speechId(pkt.contextId), "agent_thinking");
|
|
48
|
+
}
|
|
49
|
+
onTtsAudio(pkt) {
|
|
50
|
+
const id = pkt.contextId;
|
|
51
|
+
if (pkt.provider)
|
|
52
|
+
this.mergeStageDims(id, pkt.provider);
|
|
53
|
+
if (this.agentStartedEmitted.has(id))
|
|
54
|
+
return;
|
|
55
|
+
this.agentStartedEmitted.add(id);
|
|
56
|
+
this.emitBoundary(id, "agent_started_speaking");
|
|
57
|
+
}
|
|
58
|
+
onTtsEnd(pkt) {
|
|
59
|
+
this.emitBoundary(this.speechId(pkt.contextId), "agent_audio_done");
|
|
60
|
+
}
|
|
61
|
+
onInterruptDetected(pkt) {
|
|
62
|
+
this.stageDims.set(this.speechId(pkt.contextId), {
|
|
63
|
+
...this.stageDims.get(this.speechId(pkt.contextId)),
|
|
64
|
+
cancelled: true,
|
|
65
|
+
});
|
|
66
|
+
this.emitBoundary(this.speechId(pkt.contextId), "interruption", true);
|
|
67
|
+
}
|
|
68
|
+
emitBoundary(speechId, boundary, cancelled = false) {
|
|
69
|
+
const now = monotonicNowMs();
|
|
70
|
+
let times = this.boundaryTimes.get(speechId);
|
|
71
|
+
if (!times) {
|
|
72
|
+
times = {};
|
|
73
|
+
this.boundaryTimes.set(speechId, times);
|
|
74
|
+
}
|
|
75
|
+
const dims = this.dimsFor(speechId, cancelled);
|
|
76
|
+
const tags = {
|
|
77
|
+
provider: dims.provider,
|
|
78
|
+
model: dims.model,
|
|
79
|
+
region: dims.region,
|
|
80
|
+
cancelled: dims.cancelled ? "true" : "false",
|
|
81
|
+
layer: dims.layer ?? "conversation",
|
|
82
|
+
};
|
|
83
|
+
if (boundary === "agent_started_speaking") {
|
|
84
|
+
const stopped = times.user_stopped_speaking;
|
|
85
|
+
if (stopped !== undefined) {
|
|
86
|
+
const delta = now - stopped;
|
|
87
|
+
if (delta >= 0)
|
|
88
|
+
this.deps.exporter.observeHistogram("v2v_ms", delta, tags);
|
|
89
|
+
}
|
|
90
|
+
const thinking = times.agent_thinking;
|
|
91
|
+
if (thinking !== undefined) {
|
|
92
|
+
const delta = now - thinking;
|
|
93
|
+
if (delta >= 0)
|
|
94
|
+
this.deps.exporter.observeHistogram("thinking_ms", delta, tags);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else if (boundary === "agent_audio_done") {
|
|
98
|
+
const started = times.agent_started_speaking;
|
|
99
|
+
if (started !== undefined) {
|
|
100
|
+
const delta = now - started;
|
|
101
|
+
if (delta >= 0)
|
|
102
|
+
this.deps.exporter.observeHistogram("agent_speech_ms", delta, tags);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
times[boundary] = now;
|
|
106
|
+
this.deps.bus.push(Route.Background, make.turnBoundary(speechId, Date.now(), {
|
|
107
|
+
boundary,
|
|
108
|
+
sessionId: this.deps.sessionId,
|
|
109
|
+
speechId,
|
|
110
|
+
monotonicMs: now,
|
|
111
|
+
provider: dims.provider,
|
|
112
|
+
model: dims.model,
|
|
113
|
+
region: dims.region,
|
|
114
|
+
cancelled: dims.cancelled || undefined,
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
mergeStageDims(speechId, provider) {
|
|
118
|
+
const current = this.stageDims.get(speechId) ?? {};
|
|
119
|
+
this.stageDims.set(speechId, {
|
|
120
|
+
...current,
|
|
121
|
+
provider: readString(provider["name"], readString(provider["provider"], current.provider)),
|
|
122
|
+
model: readString(provider["model"], current.model),
|
|
123
|
+
region: readString(provider["region"], current.region),
|
|
124
|
+
cancelled: typeof provider["cancelled"] === "boolean" ? provider["cancelled"] : current.cancelled,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
dimsFor(speechId, cancelled) {
|
|
128
|
+
const stage = this.stageDims.get(speechId) ?? {};
|
|
129
|
+
return {
|
|
130
|
+
provider: stage.provider ?? this.deps.dims.provider,
|
|
131
|
+
model: stage.model ?? this.deps.dims.model,
|
|
132
|
+
region: stage.region ?? this.deps.dims.region,
|
|
133
|
+
layer: stage.layer ?? this.deps.dims.layer ?? "conversation",
|
|
134
|
+
cancelled: cancelled || stage.cancelled === true,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function readString(value, fallback) {
|
|
139
|
+
return typeof value === "string" && value.length > 0 ? value : fallback;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=observability-observer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observability-observer.js","sourceRoot":"","sources":["../src/observability-observer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { TurnBoundaryEventPacket } from "./packets.js";
|
|
2
|
+
/** Monotonic clock immune to system-clock adjustments; ms since an arbitrary origin. */
|
|
3
|
+
export declare function monotonicNowMs(): number;
|
|
4
|
+
export type ObservabilityLayer = "infrastructure" | "conversation";
|
|
5
|
+
export type TurnLocalizationVerdict = ObservabilityLayer | "none";
|
|
6
|
+
export interface TurnLocalizationSignals {
|
|
7
|
+
readonly infrastructureBreached: boolean;
|
|
8
|
+
readonly conversationFlagged: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function localizeTurn(signals: TurnLocalizationSignals): TurnLocalizationVerdict;
|
|
11
|
+
/** One step of a reconstructed turn timeline, with elapsed ms since the prior boundary. */
|
|
12
|
+
export interface TurnTimelineStep {
|
|
13
|
+
readonly boundary: TurnBoundaryEventPacket["boundary"];
|
|
14
|
+
readonly speechId: string;
|
|
15
|
+
readonly monotonicMs: number;
|
|
16
|
+
/** ms since the previous boundary in this reconstruction (0 for the first). */
|
|
17
|
+
readonly sincePrevMs: number;
|
|
18
|
+
readonly cancelled: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Incident reconstruction (VE-07.5): given the `obs.turn_boundary` events for one
|
|
22
|
+
* session id, return the ordered turn timeline with inter-boundary deltas so a
|
|
23
|
+
* developer can replay what happened from a single session id.
|
|
24
|
+
*/
|
|
25
|
+
export declare function reconstructTurnTimeline(events: readonly TurnBoundaryEventPacket[], sessionId: string, speechId?: string): TurnTimelineStep[];
|
|
26
|
+
export interface MetricTags {
|
|
27
|
+
readonly [key: string]: string | undefined;
|
|
28
|
+
readonly layer?: ObservabilityLayer;
|
|
29
|
+
}
|
|
30
|
+
export interface SpanHandle {
|
|
31
|
+
end(tags?: MetricTags): void;
|
|
32
|
+
}
|
|
33
|
+
/** Export seam — implementations (Prometheus/OTel) live in optional packages, NOT here. */
|
|
34
|
+
export interface MetricsExporter {
|
|
35
|
+
observeHistogram(name: string, valueMs: number, tags: MetricTags): void;
|
|
36
|
+
/**
|
|
37
|
+
* A monotonic count (tokens, characters, audio-seconds). Counters, not histograms:
|
|
38
|
+
* usage sums to a bill, latency distributes to a percentile — different instruments.
|
|
39
|
+
* Optional so an existing exporter that predates it still satisfies the interface;
|
|
40
|
+
* producers call it as `exporter.observeCounter?.(...)`.
|
|
41
|
+
*/
|
|
42
|
+
observeCounter?(name: string, value: number, tags: MetricTags): void;
|
|
43
|
+
startSpan(name: string, tags: MetricTags): SpanHandle;
|
|
44
|
+
}
|
|
45
|
+
/** Default no-op exporter (core never depends on a backend). */
|
|
46
|
+
export declare const noopMetricsExporter: MetricsExporter;
|
|
47
|
+
/** In-memory exporter for tests + incident reconstruction. */
|
|
48
|
+
export declare class InMemoryMetricsExporter implements MetricsExporter {
|
|
49
|
+
readonly histograms: Array<{
|
|
50
|
+
name: string;
|
|
51
|
+
valueMs: number;
|
|
52
|
+
tags: MetricTags;
|
|
53
|
+
}>;
|
|
54
|
+
readonly counters: Array<{
|
|
55
|
+
name: string;
|
|
56
|
+
value: number;
|
|
57
|
+
tags: MetricTags;
|
|
58
|
+
}>;
|
|
59
|
+
readonly spans: Array<{
|
|
60
|
+
name: string;
|
|
61
|
+
tags: MetricTags;
|
|
62
|
+
durationMs?: number;
|
|
63
|
+
}>;
|
|
64
|
+
observeHistogram(name: string, valueMs: number, tags: MetricTags): void;
|
|
65
|
+
observeCounter(name: string, value: number, tags: MetricTags): void;
|
|
66
|
+
startSpan(name: string, tags: MetricTags): SpanHandle;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=observability.d.ts.map
|