osborn 0.9.221 → 0.9.223
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/embedder.js +2 -2
- package/dist/env-keys.d.ts +27 -0
- package/dist/env-keys.js +47 -0
- package/dist/index.js +11 -0
- package/dist/session-store.d.ts +3 -0
- package/dist/session-store.js +43 -1
- package/package.json +1 -1
package/dist/embedder.js
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
*
|
|
16
16
|
* Model cache honors TRANSFORMERS_CACHE / HF_HOME so it can be baked into the image.
|
|
17
17
|
*/
|
|
18
|
-
import { EMBED_DIM } from './session-store.js';
|
|
19
|
-
const MODEL_ID =
|
|
18
|
+
import { EMBED_DIM, EMBED_MODEL } from './session-store.js';
|
|
19
|
+
const MODEL_ID = EMBED_MODEL;
|
|
20
20
|
let pipelinePromise = null;
|
|
21
21
|
let disabled = false;
|
|
22
22
|
/** Quantize a normalized float32 embedding to int8[dim] (×127, clamped). */
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* env-keys.ts — the agent's source-of-truth list of environment variables it
|
|
3
|
+
* expects to find in process.env at runtime, mirroring the frontend's
|
|
4
|
+
* platform-env.ts injection spec.
|
|
5
|
+
*
|
|
6
|
+
* Today the agent reads these directly from process.env (some explicitly, some
|
|
7
|
+
* implicitly via the LiveKit plugin SDKs which read env internally). This module
|
|
8
|
+
* gives that set ONE name so:
|
|
9
|
+
* • a future runtime path can hydrate process.env from a cloud/user config
|
|
10
|
+
* layer before the plugins read it, using this list as the set to fetch, and
|
|
11
|
+
* • startup can log which expected keys are missing for diagnosis.
|
|
12
|
+
*
|
|
13
|
+
* Keep in sync with frontend/src/lib/platform-env.ts (PLATFORM_ENV_SPEC).
|
|
14
|
+
*/
|
|
15
|
+
export interface AgentEnvKey {
|
|
16
|
+
key: string;
|
|
17
|
+
required: boolean;
|
|
18
|
+
/** true = read directly via process.env.X in agent source; false = consumed
|
|
19
|
+
* implicitly by a plugin SDK (Deepgram/Soniox/Gemini realtime) reading env. */
|
|
20
|
+
explicit: boolean;
|
|
21
|
+
description: string;
|
|
22
|
+
}
|
|
23
|
+
export declare const AGENT_ENV_KEYS: AgentEnvKey[];
|
|
24
|
+
/** Keys the agent treats as required — absence should be surfaced at startup. */
|
|
25
|
+
export declare const REQUIRED_AGENT_ENV_KEYS: string[];
|
|
26
|
+
/** Return the required keys that are missing from the given env (default process.env). */
|
|
27
|
+
export declare function missingRequiredEnv(env?: NodeJS.ProcessEnv): string[];
|
package/dist/env-keys.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* env-keys.ts — the agent's source-of-truth list of environment variables it
|
|
3
|
+
* expects to find in process.env at runtime, mirroring the frontend's
|
|
4
|
+
* platform-env.ts injection spec.
|
|
5
|
+
*
|
|
6
|
+
* Today the agent reads these directly from process.env (some explicitly, some
|
|
7
|
+
* implicitly via the LiveKit plugin SDKs which read env internally). This module
|
|
8
|
+
* gives that set ONE name so:
|
|
9
|
+
* • a future runtime path can hydrate process.env from a cloud/user config
|
|
10
|
+
* layer before the plugins read it, using this list as the set to fetch, and
|
|
11
|
+
* • startup can log which expected keys are missing for diagnosis.
|
|
12
|
+
*
|
|
13
|
+
* Keep in sync with frontend/src/lib/platform-env.ts (PLATFORM_ENV_SPEC).
|
|
14
|
+
*/
|
|
15
|
+
export const AGENT_ENV_KEYS = [
|
|
16
|
+
// Voice transport
|
|
17
|
+
{ key: 'LIVEKIT_URL', required: true, explicit: true, description: 'LiveKit server URL.' },
|
|
18
|
+
{ key: 'LIVEKIT_API_KEY', required: true, explicit: true, description: 'LiveKit API key.' },
|
|
19
|
+
{ key: 'LIVEKIT_API_SECRET', required: true, explicit: true, description: 'LiveKit API secret.' },
|
|
20
|
+
// STT / inference (plugin-consumed unless noted)
|
|
21
|
+
{ key: 'DEEPGRAM_API_KEY', required: true, explicit: false, description: 'Deepgram STT (LiveKit plugin).' },
|
|
22
|
+
{ key: 'SONIOX_API_KEY', required: false, explicit: false, description: 'Soniox STT (LiveKit plugin).' },
|
|
23
|
+
{ key: 'GROQ_API_KEY', required: false, explicit: true, description: 'Groq fast-brain inference.' },
|
|
24
|
+
{ key: 'OPENAI_API_KEY', required: true, explicit: true, description: 'OpenAI realtime + pipeline.' },
|
|
25
|
+
{ key: 'GOOGLE_API_KEY', required: false, explicit: false, description: 'Google Gemini realtime (plugin).' },
|
|
26
|
+
// LLM auth (Claude vs OpenRouter switch)
|
|
27
|
+
{ key: 'ANTHROPIC_API_KEY', required: false, explicit: true, description: 'Anthropic/Claude auth (per-user; may be OAuth file instead).' },
|
|
28
|
+
{ key: 'OPENROUTER_API_KEY', required: false, explicit: true, description: 'OpenRouter model routing.' },
|
|
29
|
+
// Integrations
|
|
30
|
+
{ key: 'RECALL_API_KEY', required: false, explicit: true, description: 'Recall.ai meeting bot.' },
|
|
31
|
+
{ key: 'RECALL_REGION', required: false, explicit: true, description: 'Recall.ai region.' },
|
|
32
|
+
{ key: 'SMITHERY_API_KEY', required: false, explicit: true, description: 'Smithery hosted-MCP catalog.' },
|
|
33
|
+
// Platform / infra
|
|
34
|
+
{ key: 'OSBORN_API_PORT', required: true, explicit: true, description: 'Agent HTTP server port.' },
|
|
35
|
+
{ key: 'OSBORN_CWD', required: false, explicit: true, description: 'Agent working directory.' },
|
|
36
|
+
{ key: 'OSBORN_SYNC_TOKEN', required: false, explicit: true, description: 'Session export/import auth token.' },
|
|
37
|
+
{ key: 'OSBORN_FRONTEND_URL', required: false, explicit: true, description: 'Frontend base URL for artifact upload.' },
|
|
38
|
+
{ key: 'DEV_DOMAIN', required: false, explicit: true, description: 'Wildcard dev-routing domain.' },
|
|
39
|
+
];
|
|
40
|
+
/** Keys the agent treats as required — absence should be surfaced at startup. */
|
|
41
|
+
export const REQUIRED_AGENT_ENV_KEYS = AGENT_ENV_KEYS
|
|
42
|
+
.filter((k) => k.required)
|
|
43
|
+
.map((k) => k.key);
|
|
44
|
+
/** Return the required keys that are missing from the given env (default process.env). */
|
|
45
|
+
export function missingRequiredEnv(env = process.env) {
|
|
46
|
+
return REQUIRED_AGENT_ENV_KEYS.filter((k) => !env[k]);
|
|
47
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -40,6 +40,7 @@ import { DIRECT_MODE_PROMPT } from './prompts.js';
|
|
|
40
40
|
import { MCP_CATALOG } from './config.js';
|
|
41
41
|
import { getRecallClient } from './recall-client.js';
|
|
42
42
|
import { MeetingTranscriptPoller } from './meeting-transcript-poller.js';
|
|
43
|
+
import { missingRequiredEnv } from './env-keys.js';
|
|
43
44
|
import { llm } from '@livekit/agents';
|
|
44
45
|
// ============================================================
|
|
45
46
|
// PIPELINE MODE: STT (Deepgram) → Claude Agent SDK → TTS
|
|
@@ -1816,6 +1817,16 @@ async function main() {
|
|
|
1816
1817
|
console.error('\nSet these in your .env file or environment.');
|
|
1817
1818
|
process.exit(1);
|
|
1818
1819
|
}
|
|
1820
|
+
// Non-fatal diagnostic: surface any OTHER expected-required keys that are
|
|
1821
|
+
// missing (per the shared env-keys.ts manifest — mirror of the frontend's
|
|
1822
|
+
// platform-env.ts injection spec). The LiveKit trio above is the only
|
|
1823
|
+
// hard-fail; the rest degrade gracefully (a plugin falls back, a feature
|
|
1824
|
+
// no-ops), so we log rather than exit — but a missing OPENAI/DEEPGRAM key is
|
|
1825
|
+
// the usual root cause of "voice works but STT/realtime is dead", worth naming.
|
|
1826
|
+
const missingEnv = missingRequiredEnv().filter((k) => !['LIVEKIT_URL', 'LIVEKIT_API_KEY', 'LIVEKIT_API_SECRET'].includes(k));
|
|
1827
|
+
if (missingEnv.length > 0) {
|
|
1828
|
+
console.warn(`⚠️ Missing expected env keys (non-fatal): ${missingEnv.join(', ')}`);
|
|
1829
|
+
}
|
|
1819
1830
|
// Parse CLI args
|
|
1820
1831
|
const cliArgs = parseArgs();
|
|
1821
1832
|
// Load configuration
|
package/dist/session-store.d.ts
CHANGED
|
@@ -30,6 +30,9 @@
|
|
|
30
30
|
import Database from 'better-sqlite3';
|
|
31
31
|
export declare const STORE_VERSION = 1;
|
|
32
32
|
export declare const EMBED_DIM = 384;
|
|
33
|
+
/** Canonical embed model id — the single source of truth (embedder.ts imports this).
|
|
34
|
+
* Recorded in meta.embed_model so a model swap is detected as a stale store. */
|
|
35
|
+
export declare const EMBED_MODEL: string;
|
|
33
36
|
/** An embedder turns text into int8[EMBED_DIM] vectors (quantized, normalized). */
|
|
34
37
|
export type Embedder = (texts: string[]) => Promise<Int8Array[] | null>;
|
|
35
38
|
export interface RecallHit {
|
package/dist/session-store.js
CHANGED
|
@@ -39,6 +39,9 @@ import { getSessionPaths, getSessionSubAgents, projectPathToSlug } from './sessi
|
|
|
39
39
|
// ============================================================
|
|
40
40
|
export const STORE_VERSION = 1;
|
|
41
41
|
export const EMBED_DIM = 384;
|
|
42
|
+
/** Canonical embed model id — the single source of truth (embedder.ts imports this).
|
|
43
|
+
* Recorded in meta.embed_model so a model swap is detected as a stale store. */
|
|
44
|
+
export const EMBED_MODEL = process.env.OSBORN_EMBED_MODEL || 'Xenova/all-MiniLM-L6-v2';
|
|
42
45
|
// ============================================================
|
|
43
46
|
// PATHS
|
|
44
47
|
// ============================================================
|
|
@@ -64,6 +67,41 @@ export function openStore(dbPath) {
|
|
|
64
67
|
sqliteVec.load(db);
|
|
65
68
|
db.pragma('journal_mode = WAL');
|
|
66
69
|
db.pragma('synchronous = NORMAL');
|
|
70
|
+
// ── Migration gate ──────────────────────────────────────────────
|
|
71
|
+
// The derived tables (content/fts/vec/sources) are a re-derivable cache of the
|
|
72
|
+
// JSONL, which is the source of truth. If this DB was built by a different
|
|
73
|
+
// STORE_VERSION, EMBED_DIM, or embed model, the cache is stale — most fatally the
|
|
74
|
+
// vec table is fixed at its old dimension, so queries embedded at the new dim throw
|
|
75
|
+
// or return garbage. Detect that and drop the derived tables + reset offsets; the
|
|
76
|
+
// next updateSessionStore() rebuilds them fresh from the JSONL at offset 0.
|
|
77
|
+
//
|
|
78
|
+
// A store with NO recorded embed_model (i.e. predating this stamp) is treated as
|
|
79
|
+
// NOT stale — otherwise the first rollout of this code would wipe every existing DB.
|
|
80
|
+
// We only wipe on a real mismatch, never on absence.
|
|
81
|
+
const hasMeta = db
|
|
82
|
+
.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='meta'`)
|
|
83
|
+
.get();
|
|
84
|
+
if (hasMeta) {
|
|
85
|
+
const readMeta = db.prepare('SELECT value FROM meta WHERE key = ?');
|
|
86
|
+
const prevVersion = readMeta.get('version')?.value ?? null;
|
|
87
|
+
const prevDim = readMeta.get('embed_dim')?.value ?? null;
|
|
88
|
+
const prevModel = readMeta.get('embed_model')?.value ?? null;
|
|
89
|
+
const stale = (prevVersion != null && prevVersion !== String(STORE_VERSION)) ||
|
|
90
|
+
(prevDim != null && prevDim !== String(EMBED_DIM)) ||
|
|
91
|
+
(prevModel != null && prevModel !== EMBED_MODEL);
|
|
92
|
+
if (stale) {
|
|
93
|
+
console.warn(`⚠️ recall store ${dbPath} is stale ` +
|
|
94
|
+
`(version ${prevVersion}→${STORE_VERSION}, dim ${prevDim}→${EMBED_DIM}, ` +
|
|
95
|
+
`model ${prevModel}→${EMBED_MODEL}) — rebuilding derived tables from JSONL`);
|
|
96
|
+
db.exec(`
|
|
97
|
+
DROP TABLE IF EXISTS content;
|
|
98
|
+
DROP TABLE IF EXISTS fts;
|
|
99
|
+
DROP TABLE IF EXISTS vec;
|
|
100
|
+
DROP TABLE IF EXISTS sources;
|
|
101
|
+
DELETE FROM meta WHERE key IN ('version', 'embed_dim', 'embed_model');
|
|
102
|
+
`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
67
105
|
db.exec(`
|
|
68
106
|
CREATE TABLE IF NOT EXISTS content (
|
|
69
107
|
id INTEGER PRIMARY KEY,
|
|
@@ -94,9 +132,13 @@ export function openStore(dbPath) {
|
|
|
94
132
|
|
|
95
133
|
CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT);
|
|
96
134
|
`);
|
|
97
|
-
|
|
135
|
+
// INSERT OR REPLACE (not IGNORE) so a rebuilt store restamps its identity; the
|
|
136
|
+
// migration gate above cleared these rows on a stale open, so this writes the
|
|
137
|
+
// current version/dim/model that the freshly-created tables were built for.
|
|
138
|
+
const setMeta = db.prepare('INSERT OR REPLACE INTO meta(key, value) VALUES (?, ?)');
|
|
98
139
|
setMeta.run('version', String(STORE_VERSION));
|
|
99
140
|
setMeta.run('embed_dim', String(EMBED_DIM));
|
|
141
|
+
setMeta.run('embed_model', EMBED_MODEL);
|
|
100
142
|
return db;
|
|
101
143
|
}
|
|
102
144
|
// ============================================================
|