@gotcos/glasses-server 6.21.4 → 6.21.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/.env.example +3 -3
- package/CHANGELOG.md +20 -0
- package/README.md +7 -7
- package/package.json +1 -1
- package/server/index.ts +5 -6
- package/server/lib/hallucination-filter.ts +10 -0
- package/server/lib/query-job-feature.ts +4 -4
- package/server/routes/prompt-drafts.ts +30 -0
package/.env.example
CHANGED
|
@@ -28,13 +28,13 @@ BIND_HOST=0.0.0.0
|
|
|
28
28
|
# server after Wi-Fi/Tailscale changes and process restarts.
|
|
29
29
|
# COS_SERVER_INSTANCE_ID_PATH=/path/to/server-instance-id
|
|
30
30
|
|
|
31
|
-
# Build 204+
|
|
31
|
+
# Build 204+ uses server-owned durable query jobs by default. The server fsyncs an
|
|
32
32
|
# accepted prompt before returning 202, then keeps provider work running if the
|
|
33
33
|
# phone backgrounds, reloads, or changes networks. Reopening COS reattaches to
|
|
34
|
-
# the same job. Set to 0
|
|
34
|
+
# the same job. Set to 0 to send NEW prompts through the legacy
|
|
35
35
|
# streaming route; already accepted durable jobs remain readable/cancellable
|
|
36
36
|
# and drain safely.
|
|
37
|
-
# COS_DURABLE_QUERY_JOBS=
|
|
37
|
+
# COS_DURABLE_QUERY_JOBS=0
|
|
38
38
|
|
|
39
39
|
# ── THE LLM (chat) ──────────────────────────────────────────────────────
|
|
40
40
|
# Chat runs through your LOCAL agent CLI — NOT an API key:
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## 6.21.6
|
|
2
|
+
|
|
3
|
+
- Make server-owned durable query jobs the default so accepted replies keep
|
|
4
|
+
running through phone backgrounding, WebView reloads, and network handoffs.
|
|
5
|
+
- Preserve `COS_DURABLE_QUERY_JOBS=0` as the machine-wide rollback. Existing
|
|
6
|
+
accepted jobs remain recoverable and cancellable while new prompts use the
|
|
7
|
+
legacy streaming path.
|
|
8
|
+
- Publish the capability truth through authenticated health/model surfaces so
|
|
9
|
+
COS Control and the companion can independently enforce machine and device
|
|
10
|
+
preferences without changing the proven two-step cancel gesture.
|
|
11
|
+
|
|
12
|
+
## 6.21.5
|
|
13
|
+
|
|
14
|
+
- Drop the narrow Large-v3 stock-caption artifact family beginning with
|
|
15
|
+
“closed captioning provided by” from prompt dictation.
|
|
16
|
+
- When that exact HQ artifact occurs, retain the already-validated Fast
|
|
17
|
+
transcript for the same audio and report the result as degraded instead of
|
|
18
|
+
saving either the caption credit or an empty gap. All other HQ and no-speech
|
|
19
|
+
paths are unchanged.
|
|
20
|
+
|
|
1
21
|
## 6.21.4
|
|
2
22
|
|
|
3
23
|
- Preserve validated phone-photo references on Claude and Codex conversation
|
package/README.md
CHANGED
|
@@ -102,8 +102,8 @@ range is the exact Tailscale/CGNAT allocation (`100.64.0.0/10`), not all of
|
|
|
102
102
|
## What it does
|
|
103
103
|
|
|
104
104
|
- Ask anything, get a streamed answer on the lens (`/api/query`, `/v1/chat/completions`)
|
|
105
|
-
- With COS Glasses build 204+,
|
|
106
|
-
|
|
105
|
+
- With COS Glasses build 204+, server-owned durable queries are on by default:
|
|
106
|
+
accepted work survives phone backgrounding,
|
|
107
107
|
WebView reloads, and network handoffs, then reattaches without duplicate work
|
|
108
108
|
or duplicate replies
|
|
109
109
|
- Choose Opus, Fable, Sonnet, GPT Frontier, GPT Balanced, Composer 2.5 Fast, or
|
|
@@ -174,8 +174,8 @@ in the managed CLI working directory),
|
|
|
174
174
|
`COS_CURSOR_PERSIST_SESSIONS=0` (disable Cursor session resume),
|
|
175
175
|
`COS_WEATHER_DEFAULT_LAT` / `COS_WEATHER_DEFAULT_LON` /
|
|
176
176
|
`COS_WEATHER_DEFAULT_CITY` (optional home fallback when phone GPS is denied),
|
|
177
|
-
`COS_SCRIPTS_DIR` (full pipeline), `COS_DURABLE_QUERY_JOBS=
|
|
178
|
-
server-owned query recovery), and `COS_MEDIA_ROOT` (optional image-store
|
|
177
|
+
`COS_SCRIPTS_DIR` (full pipeline), `COS_DURABLE_QUERY_JOBS=0` (optional
|
|
178
|
+
machine-wide rollback for build 204+ server-owned query recovery), and `COS_MEDIA_ROOT` (optional image-store
|
|
179
179
|
location; default `~/.cos-glasses/data/media`). Your name + transcription vocabulary live in
|
|
180
180
|
`~/.cos-glasses/.cos-profile.json` (see `.cos-profile.example.json`).
|
|
181
181
|
Factory example values are ignored; add the real names, companies, acronyms,
|
|
@@ -338,10 +338,10 @@ BIND_HOST=0.0.0.0 npm run start:server
|
|
|
338
338
|
only when OpenAI playback is intentionally configured.
|
|
339
339
|
- *Photos unavailable?* — install `ffmpeg`, restart the server, and confirm `/api/health` reports `features.mediaProcessingReady: true`.
|
|
340
340
|
- *Prompt recovery unavailable?* — update with `npx --yes @gotcos/glasses-server@latest`, then confirm `/api/health` reports `features.promptRecovery: true`.
|
|
341
|
-
- *Durable query recovery unavailable?* — build 204+ requires server 6.10.0
|
|
342
|
-
|
|
341
|
+
- *Durable query recovery unavailable?* — build 204+ requires server 6.10.0+.
|
|
342
|
+
Restart once, then confirm `/api/health` reports
|
|
343
343
|
`features.durableQueryJobs: true`, protocol `1`, and state `ready`. To roll
|
|
344
|
-
back,
|
|
344
|
+
back, set `COS_DURABLE_QUERY_JOBS=0`; accepted jobs still drain while new prompts use legacy streaming.
|
|
345
345
|
- *Offline meeting recovery unavailable?* — build 209+ requires server 6.11.0+.
|
|
346
346
|
Restart once, then confirm `/api/health` reports
|
|
347
347
|
`features.localFirstMeetings: true` and
|
package/package.json
CHANGED
package/server/index.ts
CHANGED
|
@@ -432,23 +432,22 @@ listenRequiredServers(listeners).then(() => {
|
|
|
432
432
|
console.log(`[startup] Silero VAD: ${vadOk ? 'active' : 'disabled (model not found)'}`)
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
-
// Durable recovery
|
|
436
|
-
//
|
|
437
|
-
// both an already-open fresh boot and a later cross-boot release.
|
|
435
|
+
// Durable recovery starts with the admitted runtime by default. A literal
|
|
436
|
+
// COS_DURABLE_QUERY_JOBS=0 is the machine-wide rollback.
|
|
438
437
|
let admittedRuntimeStarted = false
|
|
439
438
|
const startAdmittedRuntime = () => {
|
|
440
439
|
if (admittedRuntimeStarted) return
|
|
441
440
|
admittedRuntimeStarted = true
|
|
442
441
|
|
|
443
442
|
void initQueryJobRuntime().then(health => {
|
|
444
|
-
if (process.env.COS_DURABLE_QUERY_JOBS
|
|
443
|
+
if (process.env.COS_DURABLE_QUERY_JOBS !== '0') {
|
|
445
444
|
console.log(`[COS API] Durable query jobs: ${health.store.state} · ${health.store.retainedIdentities} retained`)
|
|
446
445
|
} else {
|
|
447
|
-
console.log('[COS API] Durable query jobs: disabled
|
|
446
|
+
console.log('[COS API] Durable query jobs: disabled by COS_DURABLE_QUERY_JOBS=0')
|
|
448
447
|
}
|
|
449
448
|
}).catch(error => {
|
|
450
449
|
// The store remains degraded and rejects admission. Legacy /api/query is
|
|
451
|
-
// still mounted, so
|
|
450
|
+
// still mounted, so the kill switch is an immediate rollback.
|
|
452
451
|
console.error('[COS API] Durable query-job store unavailable:', error)
|
|
453
452
|
})
|
|
454
453
|
|
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
import { getNegativeRules, getVocabulary, getOwnerName, getWhisperCorrections } from './profile.js'
|
|
15
15
|
|
|
16
16
|
// ── Whole-chunk silence hallucinations ─────────────────────────────────────
|
|
17
|
+
const CAPTION_CREDIT_HALLUCINATION = /^\s*(?:closed\s+)?caption(?:ing|s)?\s+(?:is\s+)?provided\s+by\b/i
|
|
18
|
+
|
|
17
19
|
const KNOWN_HALLUCINATIONS = [
|
|
18
20
|
/^subtitles?\s+by\b/i,
|
|
21
|
+
CAPTION_CREDIT_HALLUCINATION,
|
|
19
22
|
/\blike\s+and\s+subscribe\b/i,
|
|
20
23
|
/\bthanks?\s+for\s+watching\b/i,
|
|
21
24
|
/\bplease\s+subscribe\b/i,
|
|
@@ -27,6 +30,13 @@ const KNOWN_HALLUCINATIONS = [
|
|
|
27
30
|
/^\s*♪+\s*[^♪\n]{0,40}\s*♪+\s*$/,
|
|
28
31
|
]
|
|
29
32
|
|
|
33
|
+
/** Narrow stock-caption detector used to retain a valid Fast draft when an HQ
|
|
34
|
+
* decode leaks a caption credit. It intentionally requires the phrase to begin
|
|
35
|
+
* the chunk so normal questions about closed captioning remain untouched. */
|
|
36
|
+
export function isCaptionCreditHallucination(text: string): boolean {
|
|
37
|
+
return CAPTION_CREDIT_HALLUCINATION.test(text)
|
|
38
|
+
}
|
|
39
|
+
|
|
30
40
|
// ── Inline "Name:" detector (session-aware in streaming, static in one-shot) ──
|
|
31
41
|
const INLINE_HALLUCINATION_THRESHOLD = 3
|
|
32
42
|
// Seed list of known Whisper "Name:" training artifacts. Empty by default — the
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { QUERY_JOB_PROTOCOL_VERSION } from './query-job-types.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Durable jobs
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Durable jobs are the public default. COS_DURABLE_QUERY_JOBS=0 is the
|
|
5
|
+
* machine-wide rollback; every other value (including unset) keeps the
|
|
6
|
+
* capability available. COS Control owns the user-facing policy switch.
|
|
7
7
|
*/
|
|
8
8
|
export function durableQueryJobsEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
|
|
9
|
-
return env.COS_DURABLE_QUERY_JOBS
|
|
9
|
+
return env.COS_DURABLE_QUERY_JOBS !== '0'
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export function durableQueryJobsCapability(): {
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
stripInlineHallucinations,
|
|
30
30
|
stripPromptDictationArtifacts,
|
|
31
31
|
isFullHallucination,
|
|
32
|
+
isCaptionCreditHallucination,
|
|
32
33
|
isBrandUrlOnly,
|
|
33
34
|
clearSessionHallucinationState,
|
|
34
35
|
applyNegativeRules,
|
|
@@ -250,6 +251,35 @@ async function transcribeChunk(draftId: string, chunkIndex: number, audio: Buffe
|
|
|
250
251
|
return text
|
|
251
252
|
} catch (err) {
|
|
252
253
|
if (err instanceof NoSpeechDetectedError) {
|
|
254
|
+
// Large-v3 can rarely replace a clipped but valid phrase with a stock
|
|
255
|
+
// caption credit. Keep the already-decoded Fast text for this one
|
|
256
|
+
// recognized failure shape instead of persisting either the artifact
|
|
257
|
+
// or an empty gap. Other no-speech results retain existing behavior.
|
|
258
|
+
if (mode === 'hq' && isCaptionCreditHallucination(err.rawText)) {
|
|
259
|
+
const fastJob = modeQualityJobs.get(modeQualityKey(draftId, chunkIndex, 'fast', hash))
|
|
260
|
+
if (fastJob) {
|
|
261
|
+
try { await fastJob } catch { /* normal no-speech path below */ }
|
|
262
|
+
}
|
|
263
|
+
const fast = loadPromptDraftMeta(draftId)?.warmTranscripts?.[String(chunkIndex)]
|
|
264
|
+
if (
|
|
265
|
+
fast
|
|
266
|
+
&& fast.hash === hash
|
|
267
|
+
&& fast.requestedMode === 'fast'
|
|
268
|
+
&& fast.actualQuality === 'fast'
|
|
269
|
+
&& fast.text.trim()
|
|
270
|
+
) {
|
|
271
|
+
if (purpose === 'final') {
|
|
272
|
+
await markPromptDraftChunkTranscript(draftId, chunkIndex, {
|
|
273
|
+
...fast,
|
|
274
|
+
requestedMode: 'hq',
|
|
275
|
+
degraded: true,
|
|
276
|
+
degradationReason: 'hq_caption_credit_hallucination',
|
|
277
|
+
}, 'final')
|
|
278
|
+
}
|
|
279
|
+
console.warn(`[prompt-draft] dropped HQ caption-credit hallucination ${draftId}/${chunkIndex}; retained Fast text`)
|
|
280
|
+
return fast.text
|
|
281
|
+
}
|
|
282
|
+
}
|
|
253
283
|
await markPromptDraftChunkTranscript(draftId, chunkIndex, {
|
|
254
284
|
text: '', hash, requestedMode: mode, actualQuality: mode, backend: 'no-speech', degraded: false,
|
|
255
285
|
}, purpose)
|