osborn 0.9.177 → 0.9.178
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/claude-llm.js +1 -1
- package/dist/voice-io.js +2 -2
- package/package.json +1 -1
- package/tests/voice-io-stt-config.test.ts +177 -0
package/dist/claude-llm.js
CHANGED
|
@@ -167,7 +167,7 @@ ensureCompactionSettings();
|
|
|
167
167
|
// (1M) window; without it opus runs at its 200K default. NOTE: 1M activation
|
|
168
168
|
// also depends on account entitlement (auto on Team seats; else usage credits).
|
|
169
169
|
process.env.ENABLE_1M_CONTEXT = '1';
|
|
170
|
-
process.env.CLAUDE_AUTOCOMPACT_PCT_OVERRIDE = '
|
|
170
|
+
process.env.CLAUDE_AUTOCOMPACT_PCT_OVERRIDE = '60';
|
|
171
171
|
// Research mode tools — full research capabilities
|
|
172
172
|
// Named sub-agents — the orchestrator delegates to these specialists. Each has
|
|
173
173
|
// a specific role, model, and tool set. Module-level + exported so the HTTP
|
package/dist/voice-io.js
CHANGED
|
@@ -131,8 +131,8 @@ export const DEFAULT_VOICE_IO_CONFIG = {
|
|
|
131
131
|
export const DIRECT_MODE_STT = {
|
|
132
132
|
// provider: 'groq-whisper', model: 'whisper-large-v3-turbo', // Batch — needs VAD
|
|
133
133
|
// provider: 'openai-whisper', model: 'whisper-1', // Batch — needs VAD
|
|
134
|
-
provider: 'deepgram', model: 'nova-3', language: 'en',
|
|
135
|
-
|
|
134
|
+
// provider: 'deepgram', model: 'nova-3', language: 'en', // Streaming, silence-based endpointing
|
|
135
|
+
provider: 'deepgram-flux', model: 'flux-general-en', language: 'en', // Streaming, ML-based turn detection (requires Deepgram V2 access)
|
|
136
136
|
};
|
|
137
137
|
export const DIRECT_MODE_TTS = {
|
|
138
138
|
// provider: 'deepgram', model: 'aura-2-asteria-en', // WebSocket-based: handles TTS abort cleanly (no unrecoverable crash on interruption)
|
package/package.json
CHANGED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression tests for voice-io.ts STT configuration
|
|
3
|
+
*
|
|
4
|
+
* Scope: covers the 0.9.175 → 0.9.177 change that switches DIRECT_MODE_STT
|
|
5
|
+
* from deepgram-flux (ML turn detection) back to deepgram (silence-based
|
|
6
|
+
* endpointing), due to Flux V2 keepalive timeout bug (~30s of silence kills
|
|
7
|
+
* the connection).
|
|
8
|
+
*
|
|
9
|
+
* Derived from: requirements in CLAUDE.md (Three Voice Modes), voice-io.ts
|
|
10
|
+
* interface definitions, and the documented bug. NOT derived from the diff.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { strict as assert } from 'node:assert'
|
|
14
|
+
|
|
15
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
// Inline the minimal types — avoid importing from the module which requires
|
|
17
|
+
// live LK plugins (can't instantiate in a unit test without credentials).
|
|
18
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
19
|
+
interface STTConfig {
|
|
20
|
+
provider: 'deepgram' | 'deepgram-flux' | 'groq-whisper' | 'openai-whisper'
|
|
21
|
+
model?: string
|
|
22
|
+
language?: string
|
|
23
|
+
eotThreshold?: number
|
|
24
|
+
eotTimeoutMs?: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
28
|
+
// Read the compiled output so we get the real runtime values, not just TS types
|
|
29
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
30
|
+
// We import from the transpiled dist to avoid plugin side-effects at import time.
|
|
31
|
+
// If dist is missing, fall back to a direct static-analysis of the source file.
|
|
32
|
+
|
|
33
|
+
let DIRECT_MODE_STT_PROVIDER: string | undefined
|
|
34
|
+
let DIRECT_MODE_STT_MODEL: string | undefined
|
|
35
|
+
let DIRECT_MODE_STT_LANG: string | undefined
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
// dist/voice-io.js is the compiled output of the build step
|
|
39
|
+
const mod = await import('../dist/voice-io.js')
|
|
40
|
+
const cfg: STTConfig = mod.DIRECT_MODE_STT
|
|
41
|
+
DIRECT_MODE_STT_PROVIDER = cfg.provider
|
|
42
|
+
DIRECT_MODE_STT_MODEL = cfg.model
|
|
43
|
+
DIRECT_MODE_STT_LANG = cfg.language
|
|
44
|
+
} catch (e) {
|
|
45
|
+
// Fallback: parse source file statically to extract the active provider line
|
|
46
|
+
const { readFileSync } = await import('node:fs')
|
|
47
|
+
const { fileURLToPath } = await import('node:url')
|
|
48
|
+
const { dirname, join } = await import('node:path')
|
|
49
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
50
|
+
const src = readFileSync(join(here, '../src/voice-io.ts'), 'utf8')
|
|
51
|
+
|
|
52
|
+
// Find the non-commented active provider line in DIRECT_MODE_STT
|
|
53
|
+
const providerMatch = src.match(
|
|
54
|
+
/export const DIRECT_MODE_STT[\s\S]*?^\s+provider:\s*'([^']+)'/m
|
|
55
|
+
)
|
|
56
|
+
const modelMatch = src.match(
|
|
57
|
+
/export const DIRECT_MODE_STT[\s\S]*?model:\s*'([^']+)'/m
|
|
58
|
+
)
|
|
59
|
+
const langMatch = src.match(
|
|
60
|
+
/export const DIRECT_MODE_STT[\s\S]*?language:\s*'([^']+)'/m
|
|
61
|
+
)
|
|
62
|
+
DIRECT_MODE_STT_PROVIDER = providerMatch?.[1]
|
|
63
|
+
DIRECT_MODE_STT_MODEL = modelMatch?.[1]
|
|
64
|
+
DIRECT_MODE_STT_LANG = langMatch?.[1]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
68
|
+
// Tests
|
|
69
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
let passed = 0
|
|
72
|
+
let failed = 0
|
|
73
|
+
|
|
74
|
+
function test(name: string, fn: () => void) {
|
|
75
|
+
try {
|
|
76
|
+
fn()
|
|
77
|
+
console.log(` ✅ ${name}`)
|
|
78
|
+
passed++
|
|
79
|
+
} catch (err: any) {
|
|
80
|
+
console.error(` ❌ ${name}`)
|
|
81
|
+
console.error(` ${err.message}`)
|
|
82
|
+
failed++
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log('\n=== voice-io STT config regression tests ===\n')
|
|
87
|
+
|
|
88
|
+
// ── 1. Provider must be deepgram (not deepgram-flux) ──────────────────────────
|
|
89
|
+
test('DIRECT_MODE_STT.provider is "deepgram" (not deepgram-flux)', () => {
|
|
90
|
+
assert.equal(
|
|
91
|
+
DIRECT_MODE_STT_PROVIDER,
|
|
92
|
+
'deepgram',
|
|
93
|
+
`Expected provider "deepgram" but got "${DIRECT_MODE_STT_PROVIDER}". ` +
|
|
94
|
+
'deepgram-flux has a known keepalive timeout bug (silent ~30s kills the connection).'
|
|
95
|
+
)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('DIRECT_MODE_STT.provider is NOT "deepgram-flux"', () => {
|
|
99
|
+
assert.notEqual(
|
|
100
|
+
DIRECT_MODE_STT_PROVIDER,
|
|
101
|
+
'deepgram-flux',
|
|
102
|
+
'deepgram-flux must not be the active provider — ' +
|
|
103
|
+
'Flux V2 has silent keepalive timeout bug (~30s silence kills connection).'
|
|
104
|
+
)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// ── 2. Model and language ──────────────────────────────────────────────────────
|
|
108
|
+
test('DIRECT_MODE_STT.model is "nova-3"', () => {
|
|
109
|
+
assert.equal(
|
|
110
|
+
DIRECT_MODE_STT_MODEL,
|
|
111
|
+
'nova-3',
|
|
112
|
+
`Expected model "nova-3" but got "${DIRECT_MODE_STT_MODEL}".`
|
|
113
|
+
)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
test('DIRECT_MODE_STT.language is "en"', () => {
|
|
117
|
+
assert.equal(
|
|
118
|
+
DIRECT_MODE_STT_LANG,
|
|
119
|
+
'en',
|
|
120
|
+
`Expected language "en" but got "${DIRECT_MODE_STT_LANG}".`
|
|
121
|
+
)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
// ── 3. STTConfig type-level: provider values are the expected set ─────────────
|
|
125
|
+
// (These are compile-time guarantees verified at build time, but we assert
|
|
126
|
+
// them at runtime too so future changes surface here.)
|
|
127
|
+
test('DIRECT_MODE_STT provider is one of the valid union members', () => {
|
|
128
|
+
const validProviders = ['deepgram', 'deepgram-flux', 'groq-whisper', 'openai-whisper']
|
|
129
|
+
assert.ok(
|
|
130
|
+
validProviders.includes(DIRECT_MODE_STT_PROVIDER!),
|
|
131
|
+
`provider "${DIRECT_MODE_STT_PROVIDER}" is not in valid set: ${validProviders.join(', ')}`
|
|
132
|
+
)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// ── 4. Backward-compat: createSTT deepgram path shape ────────────────────────
|
|
136
|
+
// We verify the source still has the deepgram case in createSTT so the switch
|
|
137
|
+
// won't hit the `default: throw` path at runtime.
|
|
138
|
+
test('createSTT source still contains deepgram case (backward compat)', async () => {
|
|
139
|
+
const { readFileSync } = await import('node:fs')
|
|
140
|
+
const { fileURLToPath } = await import('node:url')
|
|
141
|
+
const { dirname, join } = await import('node:path')
|
|
142
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
143
|
+
const src = readFileSync(join(here, '../src/voice-io.ts'), 'utf8')
|
|
144
|
+
assert.ok(
|
|
145
|
+
src.includes("case 'deepgram':"),
|
|
146
|
+
"createSTT source must still contain case 'deepgram' — removing it would throw at runtime"
|
|
147
|
+
)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
test('createSTT source still contains deepgram-flux case (backward compat)', async () => {
|
|
151
|
+
const { readFileSync } = await import('node:fs')
|
|
152
|
+
const { fileURLToPath } = await import('node:url')
|
|
153
|
+
const { dirname, join } = await import('node:path')
|
|
154
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
155
|
+
const src = readFileSync(join(here, '../src/voice-io.ts'), 'utf8')
|
|
156
|
+
assert.ok(
|
|
157
|
+
src.includes("case 'deepgram-flux':"),
|
|
158
|
+
"createSTT source must still contain case 'deepgram-flux' — it must remain selectable via config"
|
|
159
|
+
)
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
// ── 5. deepgram endpointing value in createSTT ────────────────────────────────
|
|
163
|
+
test('createSTT deepgram case uses 550ms endpointing (mid-sentence fragment prevention)', async () => {
|
|
164
|
+
const { readFileSync } = await import('node:fs')
|
|
165
|
+
const { fileURLToPath } = await import('node:url')
|
|
166
|
+
const { dirname, join } = await import('node:path')
|
|
167
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
168
|
+
const src = readFileSync(join(here, '../src/voice-io.ts'), 'utf8')
|
|
169
|
+
assert.ok(
|
|
170
|
+
src.includes('endpointing: 550'),
|
|
171
|
+
'createSTT deepgram case must use endpointing: 550ms to prevent mid-sentence transcript fragments'
|
|
172
|
+
)
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
// ── Summary ───────────────────────────────────────────────────────────────────
|
|
176
|
+
console.log(`\n--- ${passed + failed} tests: ${passed} passed, ${failed} failed ---\n`)
|
|
177
|
+
if (failed > 0) process.exit(1)
|