osborn 0.9.168 → 0.9.170

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.
@@ -79,6 +79,14 @@ export declare const NAMED_AGENTS: {
79
79
  prompt: string;
80
80
  };
81
81
  };
82
+ export declare const FAST_MODEL = "haiku";
83
+ /**
84
+ * Apply turbo override to an agents roster.
85
+ * When turbo is true returns a DEEP COPY with every agent's model set to
86
+ * FAST_MODEL. When false returns the input object unchanged (zero allocation).
87
+ * NEVER mutates the input — NAMED_AGENTS and DB-sourced rows are untouched.
88
+ */
89
+ export declare function applyTurbo(agents: Record<string, any>, turbo: boolean): Record<string, any>;
82
90
  /**
83
91
  * Claude LLM - Wraps Claude Agent SDK for LiveKit
84
92
  * Research mode: reads anything, writes only to session workspace
@@ -133,6 +141,13 @@ export declare class ClaudeLLM extends llm.LLM {
133
141
  * it was created with.
134
142
  */
135
143
  setAgents(agents: ClaudeLLMOptions['agents']): void;
144
+ /**
145
+ * Enable/disable Turbo mode. When on, the main model and every sub-agent
146
+ * spawn on FAST_MODEL. Takes effect at the next query cold start.
147
+ */
148
+ setTurbo(on: boolean): void;
149
+ /** Read-only accessor used by ClaudeLLMStream (private fields are class-scoped). */
150
+ get turbo(): boolean;
136
151
  /**
137
152
  * Set session ID to resume a specific conversation
138
153
  * Call this before sending the first message to resume from a previous session
@@ -581,6 +581,24 @@ export const NAMED_AGENTS = {
581
581
  ].join('\n'),
582
582
  },
583
583
  };
584
+ // Turbo mode — single fast model override. ONE place to update for future
585
+ // Gemini/OpenAI fast model swap. Keep this immediately after NAMED_AGENTS.
586
+ export const FAST_MODEL = 'haiku';
587
+ /**
588
+ * Apply turbo override to an agents roster.
589
+ * When turbo is true returns a DEEP COPY with every agent's model set to
590
+ * FAST_MODEL. When false returns the input object unchanged (zero allocation).
591
+ * NEVER mutates the input — NAMED_AGENTS and DB-sourced rows are untouched.
592
+ */
593
+ export function applyTurbo(agents, turbo) {
594
+ if (!turbo)
595
+ return agents;
596
+ const out = {};
597
+ for (const [name, agent] of Object.entries(agents)) {
598
+ out[name] = { ...agent, model: FAST_MODEL };
599
+ }
600
+ return out;
601
+ }
584
602
  const RESEARCH_TOOLS = [
585
603
  'Read', 'Write', 'Edit', 'Glob', 'Grep',
586
604
  'Bash', 'WebSearch', 'WebFetch',
@@ -664,6 +682,9 @@ export class ClaudeLLM extends llm.LLM {
664
682
  // Dedup guard — prevents double-firing reviewer/gate if SubagentStop fires
665
683
  // more than once for the same agent_id (e.g. retry edge cases).
666
684
  #dispatchedFor = new Set();
685
+ // Turbo mode — when true, every spawned agent (main + sub-agents) runs on
686
+ // FAST_MODEL regardless of individual model config. Default off = no-op.
687
+ #turbo = false;
667
688
  constructor(opts = {}) {
668
689
  super();
669
690
  // Session resume/continue options
@@ -823,6 +844,16 @@ export class ClaudeLLM extends llm.LLM {
823
844
  this.#opts.agents = agents;
824
845
  console.log(`🤖 Named agents ${agents ? `set (${Object.keys(agents).join(', ')})` : 'reset to built-ins'} — applies at next query cold start`);
825
846
  }
847
+ /**
848
+ * Enable/disable Turbo mode. When on, the main model and every sub-agent
849
+ * spawn on FAST_MODEL. Takes effect at the next query cold start.
850
+ */
851
+ setTurbo(on) {
852
+ this.#turbo = on;
853
+ console.log(`⚡ Turbo mode ${on ? 'ON' : 'OFF'} — main model → ${on ? FAST_MODEL : (this.#opts.model || 'claude-opus-4-8[1m]')}; applies at next query cold start`);
854
+ }
855
+ /** Read-only accessor used by ClaudeLLMStream (private fields are class-scoped). */
856
+ get turbo() { return this.#turbo; }
826
857
  /**
827
858
  * Set session ID to resume a specific conversation
828
859
  * Call this before sending the first message to resume from a previous session
@@ -1563,7 +1594,8 @@ class ClaudeLLMStream extends llm.LLMStream {
1563
1594
  permissionMode: this.#opts.permissionMode,
1564
1595
  allowedTools,
1565
1596
  // model: this.#opts.model || 'haiku', // haiku for speed with limited tools, sonnet for full research capabilities (including tool use trace in response)
1566
- model: this.#opts.model || 'claude-opus-4-8[1m]', // Opus 4.8 + [1m] → 1M context (see get model() note); prevents ~153k early compaction
1597
+ // Turbo: when on, override main model to FAST_MODEL regardless of config.
1598
+ model: this.#llmRef.turbo ? FAST_MODEL : (this.#opts.model || 'claude-opus-4-8[1m]'), // Opus 4.8 + [1m] → 1M context (see get model() note); prevents ~153k early compaction
1567
1599
  enableFileCheckpointing: true,
1568
1600
  settingSources: ['project', 'user'],
1569
1601
  extraArgs: { 'replay-user-messages': null },
@@ -1994,7 +2026,13 @@ class ClaudeLLMStream extends llm.LLMStream {
1994
2026
  // Named sub-agents — the orchestrator delegates to these specialists.
1995
2027
  // Built-in definitions live at module level (NAMED_AGENTS); per-user
1996
2028
  // DB-backed definitions (opts.agents, via set_agents) take precedence.
1997
- agents: this.#opts.agents ?? NAMED_AGENTS,
2029
+ // TURBO BYPASS: when turbo is on and no custom agents were provided,
2030
+ // opts.agents is undefined — the ?? NAMED_AGENTS fallback would skip
2031
+ // the override entirely. Explicitly apply applyTurbo(NAMED_AGENTS)
2032
+ // so built-in agents always get FAST_MODEL when turbo is on.
2033
+ agents: this.#llmRef.turbo
2034
+ ? applyTurbo(this.#opts.agents ?? NAMED_AGENTS, true)
2035
+ : (this.#opts.agents ?? NAMED_AGENTS),
1998
2036
  };
1999
2037
  // Run Claude Agent SDK query() and stream results
2000
2038
  let hasOutput = false;
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ const __dirname = dirname(__filename);
30
30
  import { createPatch } from 'diff';
31
31
  import { loadConfig, getMcpServers, getEnabledMcpServerNames, getVoiceMode, getRealtimeConfig, getDirectConfig, listAllClaudeSessions, getMostRecentSessionId, sessionExists, getSessionSummary, getConversationHistory, ensureSessionWorkspace, getSessionWorkspace, getMcpServerStatusList, buildMcpServersForKeys, listWorkspaceArtifacts } from './config.js';
32
32
  import { createSTT, createTTS, createRealtimeModelFromConfig, DIRECT_MODE_STT, DIRECT_MODE_TTS } from './voice-io.js';
33
- import { createClaudeLLM, NAMED_AGENTS } from './claude-llm.js';
33
+ import { createClaudeLLM, NAMED_AGENTS, applyTurbo } from './claude-llm.js';
34
34
  import { clearPipelineFastBrainSession, prewarmBM25Index } from './pipeline-fastbrain.js';
35
35
  import { ensureClaudeAuth } from './claude-auth.js';
36
36
  import { createSmitheryProxy, destroySmitheryProxy, parseSmitheryUrl, isSmitheryUrl, SmitheryAuthorizationError } from './smithery-proxy.js';
@@ -2239,6 +2239,9 @@ async function main() {
2239
2239
  // switch/resume) reuse them without waiting for a frontend resend. Merged
2240
2240
  // OVER the built-in NAMED_AGENTS (same-name user rows shadow built-ins).
2241
2241
  let userNamedAgents = null;
2242
+ // Turbo mode — read from set_agents handshake (data.turbo). When true every
2243
+ // agent (main + sub-agents) runs on FAST_MODEL. Default false = perfect no-op.
2244
+ let turboMode = false;
2242
2245
  // Built-ins the user has removed (tombstoned in user_agents with enabled=false).
2243
2246
  // A removed built-in disappears from the effective set but stays re-addable
2244
2247
  // from the frontend's "Available to add" list — default agents are never
@@ -3266,14 +3269,22 @@ async function main() {
3266
3269
  voiceMode: 'direct',
3267
3270
  skipTTSQueue: true,
3268
3271
  onCompactionEvent: buildOnCompactionEvent(),
3269
- // Per-user named agents survive LLM recreations (session switch/resume)
3272
+ // Per-user named agents survive LLM recreations (session switch/resume).
3273
+ // applyTurbo runs post-merge so custom models are also overridden when turbo is on.
3274
+ // When neither custom agents nor turbo are active, pass undefined so the
3275
+ // ClaudeLLM cold-start uses NAMED_AGENTS directly (the ?? NAMED_AGENTS path).
3276
+ // When turbo IS on with no custom agents, undefined would skip the override —
3277
+ // ClaudeLLM handles that internally via the turbo bypass in ClaudeLLMStream.
3270
3278
  agents: (userNamedAgents || userRemovedAgents.length) ? (() => {
3271
3279
  const base = { ...NAMED_AGENTS };
3272
3280
  for (const r of userRemovedAgents)
3273
3281
  delete base[r];
3274
- return { ...base, ...(userNamedAgents || {}) };
3282
+ return applyTurbo({ ...base, ...(userNamedAgents || {}) }, turboMode);
3275
3283
  })() : undefined,
3276
3284
  });
3285
+ // Apply turbo to the freshly created LLM so the main model also picks it up.
3286
+ // PipelineDirectLLM (llmOverride path) wraps its own ClaudeLLM and may not expose setTurbo.
3287
+ directLLM?.setTurbo?.(turboMode);
3277
3288
  currentLLM = directLLM;
3278
3289
  // Reset the session always-allow list for each new direct session
3279
3290
  sessionAlwaysAllowPaths = new Set();
@@ -6008,11 +6019,15 @@ async function main() {
6008
6019
  userNamedAgents = Object.keys(validated).length ? validated : null;
6009
6020
  // Removed built-ins (tombstones) — excluded from the effective set.
6010
6021
  userRemovedAgents = Array.isArray(data.removed) ? data.removed.map(String) : [];
6022
+ // Turbo preference from the frontend (sourced from user_settings DB row).
6023
+ turboMode = !!data.turbo;
6011
6024
  const base = { ...NAMED_AGENTS };
6012
6025
  for (const r of userRemovedAgents)
6013
6026
  delete base[r];
6014
- const merged = { ...base, ...(userNamedAgents || {}) };
6015
- const customized = !!userNamedAgents || userRemovedAgents.length > 0;
6027
+ // applyTurbo wraps AFTER the base+custom merge so custom models also get overridden.
6028
+ const merged = applyTurbo({ ...base, ...(userNamedAgents || {}) }, turboMode);
6029
+ const customized = !!userNamedAgents || userRemovedAgents.length > 0 || turboMode;
6030
+ currentLLM?.setTurbo?.(turboMode);
6016
6031
  currentLLM?.setAgents?.(customized ? merged : undefined);
6017
6032
  console.log(`🤖 set_agents: ${Object.keys(validated).length} user agent(s), ${userRemovedAgents.length} removed → effective [${Object.keys(merged).join(', ')}]`);
6018
6033
  await sendToFrontend({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "osborn",
3
- "version": "0.9.168",
3
+ "version": "0.9.170",
4
4
  "description": "Voice AI coding assistant - local agent that connects to Osborn frontend",
5
5
  "type": "module",
6
6
  "bin": {