@kuralle-syrinx/test 4.4.1 → 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.
@@ -0,0 +1,82 @@
1
+ import { type PipelineBus, type VoicePlugin, type PluginConfig } from "@kuralle-syrinx/core";
2
+ export interface FakeSTTConfig extends PluginConfig {
3
+ /** Scripted events to emit in order. */
4
+ scriptedEvents: Array<{
5
+ kind: "interim";
6
+ text: string;
7
+ } | {
8
+ kind: "final";
9
+ text: string;
10
+ confidence: number;
11
+ ts: number;
12
+ }>;
13
+ }
14
+ export declare class FakeSTT implements VoicePlugin {
15
+ private config;
16
+ private bus;
17
+ initialize(bus: PipelineBus, config: PluginConfig): Promise<void>;
18
+ /** Emit scripted events into the bus. Call after audio injection. */
19
+ emitScripted(contextId: string): Promise<void>;
20
+ close(): Promise<void>;
21
+ }
22
+ export interface FakeTTSConfig extends PluginConfig {
23
+ /** Scripted audio batches. Each batch is emitted when tts.text arrives. */
24
+ scriptedAudioBatches: Array<{
25
+ frame: {
26
+ data: Int16Array;
27
+ sampleRateHz: number;
28
+ durationMs: number;
29
+ };
30
+ final: boolean;
31
+ }>;
32
+ }
33
+ export declare class FakeTTS implements VoicePlugin {
34
+ private config;
35
+ private bus;
36
+ private batchIndex;
37
+ initialize(bus: PipelineBus, config: PluginConfig): Promise<void>;
38
+ private emitNextBatch;
39
+ close(): Promise<void>;
40
+ }
41
+ export interface FakeVADConfig extends PluginConfig {
42
+ /**
43
+ * Array of speech probabilities, one per 20ms audio frame.
44
+ * Value >= 0.5 → speech, < 0.5 → silence.
45
+ */
46
+ scriptedSpeechProbabilities: number[];
47
+ }
48
+ export declare class FakeVAD implements VoicePlugin {
49
+ private config;
50
+ private bus;
51
+ private frameIndex;
52
+ private speaking;
53
+ initialize(bus: PipelineBus, config: PluginConfig): Promise<void>;
54
+ /** Process one frame and emit VAD events based on scripted probability. */
55
+ processFrame(contextId: string): void;
56
+ close(): Promise<void>;
57
+ }
58
+ export interface FakeBridgeConfig extends PluginConfig {
59
+ /** Scripted LLM events in order. */
60
+ scriptedEvents: Array<{
61
+ kind: "text";
62
+ delta: string;
63
+ } | {
64
+ kind: "tool_call";
65
+ id: string;
66
+ name: string;
67
+ args: Record<string, unknown>;
68
+ } | {
69
+ kind: "tool_result";
70
+ id: string;
71
+ result: string;
72
+ } | {
73
+ kind: "done";
74
+ }>;
75
+ }
76
+ export declare class FakeBridge implements VoicePlugin {
77
+ private config;
78
+ private bus;
79
+ initialize(bus: PipelineBus, config: PluginConfig): Promise<void>;
80
+ private emitScripted;
81
+ close(): Promise<void>;
82
+ }
package/dist/index.js ADDED
@@ -0,0 +1,204 @@
1
+ // SPDX-License-Identifier: MIT
2
+ //
3
+ // Syrinx Kernel v2 — Test Fakes
4
+ //
5
+ // Fake implementations of VoicePlugin for testing the kernel without
6
+ // real provider connections. Each fake pushes scripted output into the bus.
7
+ import { Route } from "@kuralle-syrinx/core";
8
+ export class FakeSTT {
9
+ config = null;
10
+ bus = null;
11
+ async initialize(bus, config) {
12
+ this.bus = bus;
13
+ this.config = config;
14
+ }
15
+ /** Emit scripted events into the bus. Call after audio injection. */
16
+ async emitScripted(contextId) {
17
+ if (!this.bus || !this.config)
18
+ return;
19
+ for (const event of this.config.scriptedEvents) {
20
+ if (event.kind === "interim") {
21
+ this.bus.push(Route.Main, {
22
+ kind: "stt.interim",
23
+ contextId,
24
+ timestampMs: Date.now(),
25
+ text: event.text,
26
+ });
27
+ }
28
+ else {
29
+ this.bus.push(Route.Main, {
30
+ kind: "stt.result",
31
+ contextId,
32
+ timestampMs: event.ts,
33
+ text: event.text,
34
+ confidence: event.confidence,
35
+ });
36
+ this.bus.push(Route.Main, {
37
+ kind: "eos.turn_complete",
38
+ contextId,
39
+ timestampMs: event.ts,
40
+ text: event.text,
41
+ transcripts: [],
42
+ });
43
+ }
44
+ }
45
+ }
46
+ async close() {
47
+ this.bus = null;
48
+ this.config = null;
49
+ }
50
+ }
51
+ export class FakeTTS {
52
+ config = null;
53
+ bus = null;
54
+ batchIndex = 0;
55
+ async initialize(bus, config) {
56
+ this.bus = bus;
57
+ this.config = config;
58
+ // Listen for TTS text
59
+ bus.on("tts.text", (pkt) => {
60
+ this.emitNextBatch(pkt.contextId ?? "");
61
+ });
62
+ }
63
+ emitNextBatch(contextId) {
64
+ if (!this.bus || !this.config)
65
+ return;
66
+ const batches = this.config.scriptedAudioBatches;
67
+ if (this.batchIndex >= batches.length)
68
+ return;
69
+ const batch = batches[this.batchIndex];
70
+ const buf = new Uint8Array(batch.frame.data.buffer);
71
+ const now = Date.now();
72
+ this.bus.push(Route.Main, {
73
+ kind: "tts.audio",
74
+ contextId,
75
+ timestampMs: now,
76
+ audio: buf,
77
+ sampleRateHz: 16000,
78
+ });
79
+ if (batch.final) {
80
+ this.bus.push(Route.Main, {
81
+ kind: "tts.end",
82
+ contextId,
83
+ timestampMs: now,
84
+ });
85
+ }
86
+ this.batchIndex++;
87
+ }
88
+ async close() {
89
+ this.bus = null;
90
+ this.config = null;
91
+ }
92
+ }
93
+ export class FakeVAD {
94
+ config = null;
95
+ bus = null;
96
+ frameIndex = 0;
97
+ speaking = false;
98
+ async initialize(bus, config) {
99
+ this.bus = bus;
100
+ this.config = config;
101
+ }
102
+ /** Process one frame and emit VAD events based on scripted probability. */
103
+ processFrame(contextId) {
104
+ if (!this.bus || !this.config)
105
+ return;
106
+ const probs = this.config.scriptedSpeechProbabilities;
107
+ if (this.frameIndex >= probs.length)
108
+ return;
109
+ const prob = probs[this.frameIndex];
110
+ const isSpeech = prob >= 0.5;
111
+ const now = Date.now();
112
+ if (isSpeech && !this.speaking) {
113
+ this.speaking = true;
114
+ this.bus.push(Route.Main, {
115
+ kind: "vad.speech_started",
116
+ contextId,
117
+ timestampMs: now,
118
+ confidence: prob,
119
+ });
120
+ }
121
+ if (!isSpeech && this.speaking) {
122
+ this.speaking = false;
123
+ this.bus.push(Route.Main, {
124
+ kind: "vad.speech_ended",
125
+ contextId,
126
+ timestampMs: now,
127
+ });
128
+ }
129
+ if (isSpeech) {
130
+ this.bus.push(Route.Main, {
131
+ kind: "vad.speech_activity",
132
+ contextId,
133
+ timestampMs: now,
134
+ isAsync: true,
135
+ });
136
+ }
137
+ this.frameIndex++;
138
+ }
139
+ async close() {
140
+ this.bus = null;
141
+ this.config = null;
142
+ }
143
+ }
144
+ export class FakeBridge {
145
+ config = null;
146
+ bus = null;
147
+ async initialize(bus, config) {
148
+ this.bus = bus;
149
+ this.config = config;
150
+ // Listen for EOS turn completions
151
+ bus.on("eos.turn_complete", (pkt) => {
152
+ const eos = pkt;
153
+ this.emitScripted(eos.contextId);
154
+ });
155
+ }
156
+ emitScripted(contextId) {
157
+ if (!this.bus || !this.config)
158
+ return;
159
+ for (const event of this.config.scriptedEvents) {
160
+ switch (event.kind) {
161
+ case "text":
162
+ this.bus.push(Route.Main, {
163
+ kind: "llm.delta",
164
+ contextId,
165
+ timestampMs: Date.now(),
166
+ text: event.delta,
167
+ });
168
+ break;
169
+ case "tool_call":
170
+ this.bus.push(Route.Main, {
171
+ kind: "llm.tool_call",
172
+ contextId,
173
+ timestampMs: Date.now(),
174
+ toolId: event.id,
175
+ toolName: event.name,
176
+ toolArgs: event.args,
177
+ });
178
+ break;
179
+ case "tool_result":
180
+ this.bus.push(Route.Main, {
181
+ kind: "llm.tool_result",
182
+ contextId,
183
+ timestampMs: Date.now(),
184
+ toolId: event.id,
185
+ toolName: "",
186
+ result: event.result,
187
+ });
188
+ break;
189
+ case "done":
190
+ this.bus.push(Route.Main, {
191
+ kind: "llm.done",
192
+ contextId,
193
+ timestampMs: Date.now(),
194
+ text: "",
195
+ });
196
+ break;
197
+ }
198
+ }
199
+ }
200
+ async close() {
201
+ this.bus = null;
202
+ this.config = null;
203
+ }
204
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kuralle-syrinx/test",
3
- "version": "4.4.1",
3
+ "version": "4.5.0",
4
4
  "private": false,
5
5
  "description": "Scripted fake STT/TTS/LLM plugins for testing Syrinx voice pipelines",
6
6
  "keywords": [
@@ -22,13 +22,22 @@
22
22
  "url": "https://github.com/kuralle/syrinx/issues"
23
23
  },
24
24
  "type": "module",
25
- "main": "./src/index.ts",
26
- "types": "./src/index.ts",
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
27
  "dependencies": {
28
- "@kuralle-syrinx/core": "4.4.1"
28
+ "@kuralle-syrinx/core": "4.5.0"
29
29
  },
30
30
  "devDependencies": {
31
+ "@types/node": "^22.0.0",
31
32
  "typescript": "^5.7.0",
32
33
  "vitest": "^3.2.6"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "src",
38
+ "README.md"
39
+ ],
40
+ "scripts": {
41
+ "build": "tsc -p tsconfig.build.json"
33
42
  }
34
43
  }