osborn 0.9.95 → 0.9.97
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.
|
@@ -13,15 +13,23 @@ capture, DevTools diagnostics, and metrics. It can speak into the page's mic
|
|
|
13
13
|
(synthesized on the fly), hear and transcribe what it plays back, click via a
|
|
14
14
|
natural-language brain, and improvise conversations. Works on any website.
|
|
15
15
|
|
|
16
|
+
USE IT BROADLY — not just for tests: MANDATORY for debugging anything
|
|
17
|
+
web-reachable (real browser + DevTools on camera + /logs, never debug a
|
|
18
|
+
frontend blind) and for verifying deployed web changes (journey + clip, or it
|
|
19
|
+
is a claim, not a verification). Also: reproducing user issues (mobile view),
|
|
20
|
+
the meeting-canvas cast source, site research, voice testing. Every use
|
|
21
|
+
returns media — review it and deliver it to the user, no silent runs.
|
|
22
|
+
|
|
16
23
|
## UPDATE CHECK (notify-first, run before major runs)
|
|
17
24
|
This packaged copy ships with every machine and may lag the served version.
|
|
18
25
|
Check, then NOTIFY the user before updating — never silently force:
|
|
19
26
|
|
|
20
27
|
```bash
|
|
21
|
-
SERVED_V=$(curl -sf --max-time 10 https://www.voice-native.com/api/browser-screen-recorder |
|
|
28
|
+
SERVED_V=$(curl -sf --max-time 10 https://www.voice-native.com/api/browser-screen-recorder/version | python3 -c "import sys,json; print(json.load(sys.stdin)['version'])" 2>/dev/null)
|
|
22
29
|
LOCAL_V=$(grep -m1 '^Version:' ~/.claude/skills/browser-screen-recorder/SKILL.md 2>/dev/null | awk '{print $2}')
|
|
23
30
|
[ -n "$SERVED_V" ] && [ "$SERVED_V" != "$LOCAL_V" ] && echo "UPDATE AVAILABLE: browser-screen-recorder v${LOCAL_V:-none} -> v$SERVED_V — tell the user what's new and ask before updating (curl -sS https://www.voice-native.com/api/browser-screen-recorder -o ~/.claude/skills/browser-screen-recorder/SKILL.md), then refresh the harness bundle per the served INSTALLATION."
|
|
24
31
|
```
|
|
32
|
+
(The /version route is a one-GET probe — cheap enough to run every session.)
|
|
25
33
|
|
|
26
34
|
If the user approves (or has pre-approved auto-updates), update the skill
|
|
27
35
|
file AND re-run the served INSTALLATION step 2 (harness bundle refresh) so
|
package/dist/claude-llm.d.ts
CHANGED
|
@@ -34,7 +34,33 @@ export interface ClaudeLLMOptions {
|
|
|
34
34
|
skillNames?: string[];
|
|
35
35
|
trigger?: string;
|
|
36
36
|
}) => void;
|
|
37
|
+
agents?: Record<string, {
|
|
38
|
+
description: string;
|
|
39
|
+
prompt: string;
|
|
40
|
+
tools?: string[];
|
|
41
|
+
model?: string;
|
|
42
|
+
}>;
|
|
37
43
|
}
|
|
44
|
+
export declare const NAMED_AGENTS: {
|
|
45
|
+
researcher: {
|
|
46
|
+
description: string;
|
|
47
|
+
tools: string[];
|
|
48
|
+
model: string;
|
|
49
|
+
prompt: string;
|
|
50
|
+
};
|
|
51
|
+
reasoner: {
|
|
52
|
+
description: string;
|
|
53
|
+
tools: string[];
|
|
54
|
+
model: string;
|
|
55
|
+
prompt: string;
|
|
56
|
+
};
|
|
57
|
+
writer: {
|
|
58
|
+
description: string;
|
|
59
|
+
tools: string[];
|
|
60
|
+
model: string;
|
|
61
|
+
prompt: string;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
38
64
|
/**
|
|
39
65
|
* Claude LLM - Wraps Claude Agent SDK for LiveKit
|
|
40
66
|
* Research mode: reads anything, writes only to session workspace
|
|
@@ -81,6 +107,14 @@ export declare class ClaudeLLM extends llm.LLM {
|
|
|
81
107
|
label(): string;
|
|
82
108
|
get model(): string;
|
|
83
109
|
get sessionId(): string | null;
|
|
110
|
+
/**
|
|
111
|
+
* Set per-user named agents (DB-backed, from the frontend's set_agents).
|
|
112
|
+
* Synced to #opts so ClaudeLLMStream picks them up when the persistent
|
|
113
|
+
* query is created. SDK constraint: takes effect at the NEXT query cold
|
|
114
|
+
* start (session start/resume/switch) — a live subprocess keeps the agents
|
|
115
|
+
* it was created with.
|
|
116
|
+
*/
|
|
117
|
+
setAgents(agents: ClaudeLLMOptions['agents']): void;
|
|
84
118
|
/**
|
|
85
119
|
* Set session ID to resume a specific conversation
|
|
86
120
|
* Call this before sending the first message to resume from a previous session
|
package/dist/claude-llm.js
CHANGED
|
@@ -121,6 +121,128 @@ function loadAllSkills(_workingDir) {
|
|
|
121
121
|
return `<available-skills>\n${[...skillMap.values()].join('\n\n---\n\n')}\n</available-skills>`;
|
|
122
122
|
}
|
|
123
123
|
// Research mode tools — full research capabilities
|
|
124
|
+
// Named sub-agents — the orchestrator delegates to these specialists. Each has
|
|
125
|
+
// a specific role, model, and tool set. Module-level + exported so the HTTP
|
|
126
|
+
// API (/agents) and the frontend agents manager can list them without
|
|
127
|
+
// duplicating the definitions. The query options reference this same object.
|
|
128
|
+
export const NAMED_AGENTS = {
|
|
129
|
+
researcher: {
|
|
130
|
+
description: [
|
|
131
|
+
'Information gathering agent (Sonnet). Use for: codebase exploration, web research,',
|
|
132
|
+
'finding patterns, reading multiple files, searching for examples.',
|
|
133
|
+
'Returns structured findings — does NOT make decisions or edit files.',
|
|
134
|
+
'Use this for ANY task that needs more than 2 tool calls to gather information.',
|
|
135
|
+
].join(' '),
|
|
136
|
+
tools: ['Read', 'Glob', 'Grep', 'Bash', 'WebSearch', 'WebFetch', 'Task'],
|
|
137
|
+
model: 'sonnet',
|
|
138
|
+
prompt: [
|
|
139
|
+
'You are Osborn\'s research agent. Your job is information gathering — thorough, structured, factual.',
|
|
140
|
+
'',
|
|
141
|
+
'## Your role',
|
|
142
|
+
'Gather information the main agent needs to answer the user\'s question or make a decision.',
|
|
143
|
+
'You are a scout — go find things, read them carefully, and report back.',
|
|
144
|
+
'',
|
|
145
|
+
'## How to work',
|
|
146
|
+
'1. Understand what information is needed and why.',
|
|
147
|
+
'2. Search broadly first (Glob, Grep, WebSearch), then read deeply (Read specific files).',
|
|
148
|
+
'3. For large investigations, use the Task tool to run parallel searches.',
|
|
149
|
+
'4. Cap yourself at 5-8 tool calls unless the task clearly requires more.',
|
|
150
|
+
'',
|
|
151
|
+
'## What to return',
|
|
152
|
+
'Structured findings with specifics:',
|
|
153
|
+
'- File paths and line numbers where you found relevant code',
|
|
154
|
+
'- Exact values, configs, versions — not paraphrases',
|
|
155
|
+
'- Direct quotes from documentation or web sources',
|
|
156
|
+
'- What you looked for but did NOT find (negative results matter)',
|
|
157
|
+
'',
|
|
158
|
+
'## What NOT to do',
|
|
159
|
+
'- Do NOT make recommendations or decisions — just surface facts',
|
|
160
|
+
'- Do NOT edit or write any files',
|
|
161
|
+
'- Do NOT run destructive commands (no rm, no git push, no npm publish)',
|
|
162
|
+
'- If you need clarification, ask the main agent — it will relay to the user if needed',
|
|
163
|
+
].join('\n'),
|
|
164
|
+
},
|
|
165
|
+
reasoner: {
|
|
166
|
+
description: [
|
|
167
|
+
'Deep reasoning agent (Opus). Use for: architecture decisions, complex problem analysis,',
|
|
168
|
+
'tradeoff evaluation, generating implementation plans, understanding hard problems.',
|
|
169
|
+
'Slow but thorough — only use for genuinely complex problems that need careful thought.',
|
|
170
|
+
'Does NOT edit files — returns a clear plan for the writer agent to execute.',
|
|
171
|
+
].join(' '),
|
|
172
|
+
tools: ['Read', 'Glob', 'Grep', 'WebSearch', 'WebFetch'],
|
|
173
|
+
model: 'opus',
|
|
174
|
+
prompt: [
|
|
175
|
+
'You are Osborn\'s reasoning agent. Your job is deep analysis, architectural thinking, and decision-making.',
|
|
176
|
+
'',
|
|
177
|
+
'## Your role',
|
|
178
|
+
'Think hard about complex problems. Consider multiple approaches. Identify risks and edge cases.',
|
|
179
|
+
'Return a clear, opinionated recommendation with reasoning — not just a list of options.',
|
|
180
|
+
'',
|
|
181
|
+
'## How to work',
|
|
182
|
+
'1. Read and understand the full context before forming an opinion.',
|
|
183
|
+
'2. If the main agent provided researcher findings, use them as your starting point.',
|
|
184
|
+
'3. Consider at least 2-3 alternative approaches before recommending one.',
|
|
185
|
+
'4. Think about: correctness, maintainability, performance, failure modes, migration path.',
|
|
186
|
+
'5. Use Read/Grep to verify assumptions against the actual codebase when relevant.',
|
|
187
|
+
'',
|
|
188
|
+
'## What to return',
|
|
189
|
+
'- RECOMMENDATION: what to do (one clear answer, not "it depends")',
|
|
190
|
+
'- REASONING: why this approach wins over alternatives (2-3 sentences)',
|
|
191
|
+
'- PLAN: step-by-step implementation instructions specific enough for the writer agent',
|
|
192
|
+
'- RISKS: what could go wrong and how to mitigate',
|
|
193
|
+
'- If the problem is genuinely ambiguous, say what additional information would resolve it',
|
|
194
|
+
'',
|
|
195
|
+
'## What NOT to do',
|
|
196
|
+
'- Do NOT edit or write files — return a plan for the writer agent',
|
|
197
|
+
'- Do NOT give wishy-washy "both options are valid" non-answers — commit to a recommendation',
|
|
198
|
+
'- If you need more information, ask the main agent to delegate to the researcher',
|
|
199
|
+
].join('\n'),
|
|
200
|
+
},
|
|
201
|
+
writer: {
|
|
202
|
+
description: [
|
|
203
|
+
'Execution agent with file write/edit permissions (Sonnet).',
|
|
204
|
+
'Handles ALL file operations: code, config, docs, scripts, data files.',
|
|
205
|
+
'VERIFY-FIRST workflow: checks assumptions before making changes, runs tests after.',
|
|
206
|
+
'If anything is unclear, asks the main agent for clarification before touching files.',
|
|
207
|
+
].join(' '),
|
|
208
|
+
tools: ['Read', 'Write', 'Edit', 'MultiEdit', 'Bash', 'Glob', 'Grep', 'NotebookRead', 'NotebookEdit'],
|
|
209
|
+
model: 'sonnet',
|
|
210
|
+
prompt: [
|
|
211
|
+
'You are Osborn\'s writer agent. You execute file changes with a verify-first approach.',
|
|
212
|
+
'',
|
|
213
|
+
'## Your role',
|
|
214
|
+
'Handle ALL file operations — code, config, documentation, scripts, data files.',
|
|
215
|
+
'You are the only agent that writes. The main agent and reasoner produce plans; you execute them.',
|
|
216
|
+
'',
|
|
217
|
+
'## VERIFY-FIRST workflow (mandatory)',
|
|
218
|
+
'',
|
|
219
|
+
'### Step 1: Verify assumptions',
|
|
220
|
+
'1. Read the files you\'re about to modify. Confirm they match what the plan expects.',
|
|
221
|
+
'2. If the plan references specific code patterns, grep to confirm they exist.',
|
|
222
|
+
'3. If applicable, run the current test suite or build to confirm the starting state works.',
|
|
223
|
+
'4. If ANYTHING has drifted from the plan (file moved, code refactored, dependency changed):',
|
|
224
|
+
' STOP and report back to the main agent. Do NOT improvise.',
|
|
225
|
+
'',
|
|
226
|
+
'### Step 2: Clarify unknowns',
|
|
227
|
+
'1. If the plan is vague or ambiguous — ask the main agent a specific clarifying question.',
|
|
228
|
+
' Examples: "Which config format — YAML or JSON?", "New file or extend existing auth.ts?"',
|
|
229
|
+
'2. The main agent will answer from context or relay to the user.',
|
|
230
|
+
'3. Do NOT guess. One clear question is better than a wrong assumption.',
|
|
231
|
+
'4. Restate what you will do before doing it: which files, what changes, in what order.',
|
|
232
|
+
'',
|
|
233
|
+
'### Step 3: Execute changes',
|
|
234
|
+
'- Make ONLY the changes described in the plan.',
|
|
235
|
+
'- Do NOT refactor adjacent code, fix unrelated issues, add unrequested comments/docs.',
|
|
236
|
+
'- If you hit an unexpected issue, STOP and report to the main agent.',
|
|
237
|
+
'',
|
|
238
|
+
'### Step 4: Verify results',
|
|
239
|
+
'1. Run tests if available (npm test, pytest, cargo test, etc.).',
|
|
240
|
+
'2. Run the build if applicable (npm run build, tsc --noEmit, etc.).',
|
|
241
|
+
'3. If tests or build fail: attempt to fix the issue you introduced. Re-run.',
|
|
242
|
+
'4. Report: files changed, what changed in each, test results, any failures.',
|
|
243
|
+
].join('\n'),
|
|
244
|
+
},
|
|
245
|
+
};
|
|
124
246
|
const RESEARCH_TOOLS = [
|
|
125
247
|
'Read', 'Write', 'Edit', 'Glob', 'Grep',
|
|
126
248
|
'Bash', 'WebSearch', 'WebFetch',
|
|
@@ -337,6 +459,17 @@ export class ClaudeLLM extends llm.LLM {
|
|
|
337
459
|
get sessionId() {
|
|
338
460
|
return this.#sessionId;
|
|
339
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* Set per-user named agents (DB-backed, from the frontend's set_agents).
|
|
464
|
+
* Synced to #opts so ClaudeLLMStream picks them up when the persistent
|
|
465
|
+
* query is created. SDK constraint: takes effect at the NEXT query cold
|
|
466
|
+
* start (session start/resume/switch) — a live subprocess keeps the agents
|
|
467
|
+
* it was created with.
|
|
468
|
+
*/
|
|
469
|
+
setAgents(agents) {
|
|
470
|
+
this.#opts.agents = agents;
|
|
471
|
+
console.log(`🤖 Named agents ${agents ? `set (${Object.keys(agents).join(', ')})` : 'reset to built-ins'} — applies at next query cold start`);
|
|
472
|
+
}
|
|
340
473
|
/**
|
|
341
474
|
* Set session ID to resume a specific conversation
|
|
342
475
|
* Call this before sending the first message to resume from a previous session
|
|
@@ -1169,126 +1302,10 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
1169
1302
|
}]
|
|
1170
1303
|
}]
|
|
1171
1304
|
},
|
|
1172
|
-
// Named sub-agents —
|
|
1173
|
-
//
|
|
1174
|
-
agents
|
|
1175
|
-
|
|
1176
|
-
description: [
|
|
1177
|
-
'Information gathering agent (Sonnet). Use for: codebase exploration, web research,',
|
|
1178
|
-
'finding patterns, reading multiple files, searching for examples.',
|
|
1179
|
-
'Returns structured findings — does NOT make decisions or edit files.',
|
|
1180
|
-
'Use this for ANY task that needs more than 2 tool calls to gather information.',
|
|
1181
|
-
].join(' '),
|
|
1182
|
-
tools: ['Read', 'Glob', 'Grep', 'Bash', 'WebSearch', 'WebFetch', 'Task'],
|
|
1183
|
-
model: 'sonnet',
|
|
1184
|
-
prompt: [
|
|
1185
|
-
'You are Osborn\'s research agent. Your job is information gathering — thorough, structured, factual.',
|
|
1186
|
-
'',
|
|
1187
|
-
'## Your role',
|
|
1188
|
-
'Gather information the main agent needs to answer the user\'s question or make a decision.',
|
|
1189
|
-
'You are a scout — go find things, read them carefully, and report back.',
|
|
1190
|
-
'',
|
|
1191
|
-
'## How to work',
|
|
1192
|
-
'1. Understand what information is needed and why.',
|
|
1193
|
-
'2. Search broadly first (Glob, Grep, WebSearch), then read deeply (Read specific files).',
|
|
1194
|
-
'3. For large investigations, use the Task tool to run parallel searches.',
|
|
1195
|
-
'4. Cap yourself at 5-8 tool calls unless the task clearly requires more.',
|
|
1196
|
-
'',
|
|
1197
|
-
'## What to return',
|
|
1198
|
-
'Structured findings with specifics:',
|
|
1199
|
-
'- File paths and line numbers where you found relevant code',
|
|
1200
|
-
'- Exact values, configs, versions — not paraphrases',
|
|
1201
|
-
'- Direct quotes from documentation or web sources',
|
|
1202
|
-
'- What you looked for but did NOT find (negative results matter)',
|
|
1203
|
-
'',
|
|
1204
|
-
'## What NOT to do',
|
|
1205
|
-
'- Do NOT make recommendations or decisions — just surface facts',
|
|
1206
|
-
'- Do NOT edit or write any files',
|
|
1207
|
-
'- Do NOT run destructive commands (no rm, no git push, no npm publish)',
|
|
1208
|
-
'- If you need clarification, ask the main agent — it will relay to the user if needed',
|
|
1209
|
-
].join('\n'),
|
|
1210
|
-
},
|
|
1211
|
-
reasoner: {
|
|
1212
|
-
description: [
|
|
1213
|
-
'Deep reasoning agent (Opus). Use for: architecture decisions, complex problem analysis,',
|
|
1214
|
-
'tradeoff evaluation, generating implementation plans, understanding hard problems.',
|
|
1215
|
-
'Slow but thorough — only use for genuinely complex problems that need careful thought.',
|
|
1216
|
-
'Does NOT edit files — returns a clear plan for the writer agent to execute.',
|
|
1217
|
-
].join(' '),
|
|
1218
|
-
tools: ['Read', 'Glob', 'Grep', 'WebSearch', 'WebFetch'],
|
|
1219
|
-
model: 'opus',
|
|
1220
|
-
prompt: [
|
|
1221
|
-
'You are Osborn\'s reasoning agent. Your job is deep analysis, architectural thinking, and decision-making.',
|
|
1222
|
-
'',
|
|
1223
|
-
'## Your role',
|
|
1224
|
-
'Think hard about complex problems. Consider multiple approaches. Identify risks and edge cases.',
|
|
1225
|
-
'Return a clear, opinionated recommendation with reasoning — not just a list of options.',
|
|
1226
|
-
'',
|
|
1227
|
-
'## How to work',
|
|
1228
|
-
'1. Read and understand the full context before forming an opinion.',
|
|
1229
|
-
'2. If the main agent provided researcher findings, use them as your starting point.',
|
|
1230
|
-
'3. Consider at least 2-3 alternative approaches before recommending one.',
|
|
1231
|
-
'4. Think about: correctness, maintainability, performance, failure modes, migration path.',
|
|
1232
|
-
'5. Use Read/Grep to verify assumptions against the actual codebase when relevant.',
|
|
1233
|
-
'',
|
|
1234
|
-
'## What to return',
|
|
1235
|
-
'- RECOMMENDATION: what to do (one clear answer, not "it depends")',
|
|
1236
|
-
'- REASONING: why this approach wins over alternatives (2-3 sentences)',
|
|
1237
|
-
'- PLAN: step-by-step implementation instructions specific enough for the writer agent',
|
|
1238
|
-
'- RISKS: what could go wrong and how to mitigate',
|
|
1239
|
-
'- If the problem is genuinely ambiguous, say what additional information would resolve it',
|
|
1240
|
-
'',
|
|
1241
|
-
'## What NOT to do',
|
|
1242
|
-
'- Do NOT edit or write files — return a plan for the writer agent',
|
|
1243
|
-
'- Do NOT give wishy-washy "both options are valid" non-answers — commit to a recommendation',
|
|
1244
|
-
'- If you need more information, ask the main agent to delegate to the researcher',
|
|
1245
|
-
].join('\n'),
|
|
1246
|
-
},
|
|
1247
|
-
writer: {
|
|
1248
|
-
description: [
|
|
1249
|
-
'Execution agent with file write/edit permissions (Sonnet).',
|
|
1250
|
-
'Handles ALL file operations: code, config, docs, scripts, data files.',
|
|
1251
|
-
'VERIFY-FIRST workflow: checks assumptions before making changes, runs tests after.',
|
|
1252
|
-
'If anything is unclear, asks the main agent for clarification before touching files.',
|
|
1253
|
-
].join(' '),
|
|
1254
|
-
tools: ['Read', 'Write', 'Edit', 'MultiEdit', 'Bash', 'Glob', 'Grep', 'NotebookRead', 'NotebookEdit'],
|
|
1255
|
-
model: 'sonnet',
|
|
1256
|
-
prompt: [
|
|
1257
|
-
'You are Osborn\'s writer agent. You execute file changes with a verify-first approach.',
|
|
1258
|
-
'',
|
|
1259
|
-
'## Your role',
|
|
1260
|
-
'Handle ALL file operations — code, config, documentation, scripts, data files.',
|
|
1261
|
-
'You are the only agent that writes. The main agent and reasoner produce plans; you execute them.',
|
|
1262
|
-
'',
|
|
1263
|
-
'## VERIFY-FIRST workflow (mandatory)',
|
|
1264
|
-
'',
|
|
1265
|
-
'### Step 1: Verify assumptions',
|
|
1266
|
-
'1. Read the files you\'re about to modify. Confirm they match what the plan expects.',
|
|
1267
|
-
'2. If the plan references specific code patterns, grep to confirm they exist.',
|
|
1268
|
-
'3. If applicable, run the current test suite or build to confirm the starting state works.',
|
|
1269
|
-
'4. If ANYTHING has drifted from the plan (file moved, code refactored, dependency changed):',
|
|
1270
|
-
' STOP and report back to the main agent. Do NOT improvise.',
|
|
1271
|
-
'',
|
|
1272
|
-
'### Step 2: Clarify unknowns',
|
|
1273
|
-
'1. If the plan is vague or ambiguous — ask the main agent a specific clarifying question.',
|
|
1274
|
-
' Examples: "Which config format — YAML or JSON?", "New file or extend existing auth.ts?"',
|
|
1275
|
-
'2. The main agent will answer from context or relay to the user.',
|
|
1276
|
-
'3. Do NOT guess. One clear question is better than a wrong assumption.',
|
|
1277
|
-
'4. Restate what you will do before doing it: which files, what changes, in what order.',
|
|
1278
|
-
'',
|
|
1279
|
-
'### Step 3: Execute changes',
|
|
1280
|
-
'- Make ONLY the changes described in the plan.',
|
|
1281
|
-
'- Do NOT refactor adjacent code, fix unrelated issues, add unrequested comments/docs.',
|
|
1282
|
-
'- If you hit an unexpected issue, STOP and report to the main agent.',
|
|
1283
|
-
'',
|
|
1284
|
-
'### Step 4: Verify results',
|
|
1285
|
-
'1. Run tests if available (npm test, pytest, cargo test, etc.).',
|
|
1286
|
-
'2. Run the build if applicable (npm run build, tsc --noEmit, etc.).',
|
|
1287
|
-
'3. If tests or build fail: attempt to fix the issue you introduced. Re-run.',
|
|
1288
|
-
'4. Report: files changed, what changed in each, test results, any failures.',
|
|
1289
|
-
].join('\n'),
|
|
1290
|
-
},
|
|
1291
|
-
},
|
|
1305
|
+
// Named sub-agents — the orchestrator delegates to these specialists.
|
|
1306
|
+
// Built-in definitions live at module level (NAMED_AGENTS); per-user
|
|
1307
|
+
// DB-backed definitions (opts.agents, via set_agents) take precedence.
|
|
1308
|
+
agents: this.#opts.agents ?? NAMED_AGENTS,
|
|
1292
1309
|
};
|
|
1293
1310
|
// Run Claude Agent SDK query() and stream results
|
|
1294
1311
|
let hasOutput = false;
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,7 @@ const __dirname = dirname(__filename);
|
|
|
29
29
|
import { createPatch } from 'diff';
|
|
30
30
|
import { loadConfig, getMcpServers, getEnabledMcpServerNames, getVoiceMode, getRealtimeConfig, getDirectConfig, listAllClaudeSessions, getMostRecentSessionId, sessionExists, getSessionSummary, getConversationHistory, ensureSessionWorkspace, getSessionWorkspace, getMcpServerStatusList, buildMcpServersForKeys, listWorkspaceArtifacts } from './config.js';
|
|
31
31
|
import { createSTT, createTTS, createRealtimeModelFromConfig, DIRECT_MODE_STT, DIRECT_MODE_TTS } from './voice-io.js';
|
|
32
|
-
import { createClaudeLLM } from './claude-llm.js';
|
|
32
|
+
import { createClaudeLLM, NAMED_AGENTS } from './claude-llm.js';
|
|
33
33
|
import { clearPipelineFastBrainSession, prewarmBM25Index } from './pipeline-fastbrain.js';
|
|
34
34
|
import { ensureClaudeAuth } from './claude-auth.js';
|
|
35
35
|
import { createSmitheryProxy, destroySmitheryProxy, parseSmitheryUrl, isSmitheryUrl, SmitheryAuthorizationError } from './smithery-proxy.js';
|
|
@@ -286,6 +286,30 @@ function startApiServer(workingDir, port) {
|
|
|
286
286
|
}
|
|
287
287
|
return;
|
|
288
288
|
}
|
|
289
|
+
if (req.method === 'GET' && url.pathname === '/skills') {
|
|
290
|
+
// Installed skills — same list the chat's get_skills data-channel message
|
|
291
|
+
// returns, exposed over HTTP so the DASHBOARD (no LiveKit connection) can
|
|
292
|
+
// render the skills manager too. process.cwd() === sessionBaseDir (the
|
|
293
|
+
// osborn install dir where .claude/skills lives — see main()).
|
|
294
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
295
|
+
res.end(JSON.stringify({ skills: loadSkillsList(process.cwd()) }));
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (req.method === 'GET' && url.pathname === '/agents') {
|
|
299
|
+
// Named sub-agents (researcher/reasoner/writer) — definitions come from
|
|
300
|
+
// claude-llm.ts NAMED_AGENTS (single source of truth, same object the SDK
|
|
301
|
+
// query uses). Prompts are omitted: the UI manager needs role/model/tools,
|
|
302
|
+
// not the full instruction text.
|
|
303
|
+
const agents = Object.entries(NAMED_AGENTS).map(([name, a]) => ({
|
|
304
|
+
name,
|
|
305
|
+
description: a.description,
|
|
306
|
+
model: a.model,
|
|
307
|
+
tools: a.tools,
|
|
308
|
+
}));
|
|
309
|
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
|
310
|
+
res.end(JSON.stringify({ agents }));
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
289
313
|
if (req.method === 'GET' && url.pathname === '/health') {
|
|
290
314
|
// Include osborn version — primary signal used by machines.readInstalledOsbornVersion()
|
|
291
315
|
// to detect which agent version is running. Without this the consumer falls back to
|
|
@@ -1578,6 +1602,11 @@ async function main() {
|
|
|
1578
1602
|
// Empty string = anonymous / unauthenticated; uploads fall back to a
|
|
1579
1603
|
// session-only path (no user prefix).
|
|
1580
1604
|
let currentUserId = '';
|
|
1605
|
+
// Per-user named agents (DB-backed) — sent by the frontend via set_agents
|
|
1606
|
+
// after agent_ready. Kept here so agent-side LLM recreations (session
|
|
1607
|
+
// switch/resume) reuse them without waiting for a frontend resend. Merged
|
|
1608
|
+
// OVER the built-in NAMED_AGENTS (same-name user rows shadow built-ins).
|
|
1609
|
+
let userNamedAgents = null;
|
|
1581
1610
|
let activeMeetingBotId = null; // Recall.ai bot ID if in a meeting
|
|
1582
1611
|
let activeMeetingPoller = null; // Transcript poller bound to that bot
|
|
1583
1612
|
// LIVE meeting transcript → LLM (buffered webhook finals). See recall.on('transcript').
|
|
@@ -2222,6 +2251,8 @@ async function main() {
|
|
|
2222
2251
|
voiceMode: 'direct',
|
|
2223
2252
|
skipTTSQueue: true,
|
|
2224
2253
|
onCompactionEvent: buildOnCompactionEvent(),
|
|
2254
|
+
// Per-user named agents survive LLM recreations (session switch/resume)
|
|
2255
|
+
agents: userNamedAgents ? { ...NAMED_AGENTS, ...userNamedAgents } : undefined,
|
|
2225
2256
|
});
|
|
2226
2257
|
currentLLM = directLLM;
|
|
2227
2258
|
// Reset the session always-allow list for each new direct session
|
|
@@ -4118,6 +4149,9 @@ async function main() {
|
|
|
4118
4149
|
enabledMcpServers: enabledMcpNames,
|
|
4119
4150
|
workingDirectory: workingDir,
|
|
4120
4151
|
skills: loadSkillsList(sessionBaseDir),
|
|
4152
|
+
namedAgents: Object.entries(NAMED_AGENTS).map(([name, a]) => ({
|
|
4153
|
+
name, description: a.description, model: a.model, tools: a.tools,
|
|
4154
|
+
})),
|
|
4121
4155
|
});
|
|
4122
4156
|
};
|
|
4123
4157
|
const readyInterval = setInterval(sendReady, 2000);
|
|
@@ -4806,6 +4840,56 @@ async function main() {
|
|
|
4806
4840
|
skills: loadSkillsList(sessionBaseDir),
|
|
4807
4841
|
});
|
|
4808
4842
|
}
|
|
4843
|
+
else if (data.type === 'get_agents') {
|
|
4844
|
+
// Named sub-agents for the chat agents manager — built-ins merged with
|
|
4845
|
+
// any per-user DB-backed definitions (prompts omitted from the list).
|
|
4846
|
+
const effective = { ...NAMED_AGENTS, ...(userNamedAgents || {}) };
|
|
4847
|
+
await sendToFrontend({
|
|
4848
|
+
type: 'agents_status',
|
|
4849
|
+
agents: Object.entries(effective).map(([name, a]) => ({
|
|
4850
|
+
name, description: a.description, model: a.model, tools: a.tools,
|
|
4851
|
+
custom: !!userNamedAgents && name in userNamedAgents,
|
|
4852
|
+
})),
|
|
4853
|
+
});
|
|
4854
|
+
}
|
|
4855
|
+
else if (data.type === 'set_agents') {
|
|
4856
|
+
// Per-user named agents from the DB (frontend fetches its user_agents
|
|
4857
|
+
// rows and sends them here after agent_ready, and again after edits).
|
|
4858
|
+
// Validated + merged over built-ins, applied via setAgents(). SDK
|
|
4859
|
+
// constraint: takes effect at the next query cold start — a live
|
|
4860
|
+
// subprocess keeps the agents it started with.
|
|
4861
|
+
const MODELS = new Set(['sonnet', 'opus', 'haiku', 'fable', 'inherit']);
|
|
4862
|
+
const rows = Array.isArray(data.agents) ? data.agents : [];
|
|
4863
|
+
const validated = {};
|
|
4864
|
+
for (const r of rows) {
|
|
4865
|
+
const name = String(r?.name || '').trim().toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
4866
|
+
const description = String(r?.description || '').trim();
|
|
4867
|
+
const prompt = String(r?.prompt || '').trim();
|
|
4868
|
+
if (!name || !description || !prompt)
|
|
4869
|
+
continue;
|
|
4870
|
+
if (prompt.length > 6000) {
|
|
4871
|
+
console.warn(`🤖 set_agents: '${name}' prompt >6KB — skipped`);
|
|
4872
|
+
continue;
|
|
4873
|
+
}
|
|
4874
|
+
validated[name] = {
|
|
4875
|
+
description,
|
|
4876
|
+
prompt,
|
|
4877
|
+
...(Array.isArray(r.tools) && r.tools.length ? { tools: r.tools.map(String) } : {}),
|
|
4878
|
+
...(r.model && (MODELS.has(r.model) || /^claude-/.test(r.model)) ? { model: String(r.model) } : {}),
|
|
4879
|
+
};
|
|
4880
|
+
}
|
|
4881
|
+
userNamedAgents = Object.keys(validated).length ? validated : null;
|
|
4882
|
+
const merged = { ...NAMED_AGENTS, ...(userNamedAgents || {}) };
|
|
4883
|
+
currentLLM?.setAgents?.(userNamedAgents ? merged : undefined);
|
|
4884
|
+
console.log(`🤖 set_agents: ${Object.keys(validated).length} user agent(s) → effective set [${Object.keys(merged).join(', ')}]`);
|
|
4885
|
+
await sendToFrontend({
|
|
4886
|
+
type: 'agents_status',
|
|
4887
|
+
agents: Object.entries(merged).map(([name, a]) => ({
|
|
4888
|
+
name, description: a.description, model: a.model, tools: a.tools,
|
|
4889
|
+
custom: !!userNamedAgents && name in userNamedAgents,
|
|
4890
|
+
})),
|
|
4891
|
+
});
|
|
4892
|
+
}
|
|
4809
4893
|
else if (data.type === 'skill_add') {
|
|
4810
4894
|
const skillName = (data.name || '').trim().toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
4811
4895
|
const skillContent = (data.content || '').trim();
|
|
@@ -62,6 +62,7 @@ export declare class PipelineDirectLLM extends llm.LLM {
|
|
|
62
62
|
};
|
|
63
63
|
getMcpServers(): Record<string, import("@anthropic-ai/claude-agent-sdk").McpServerConfig>;
|
|
64
64
|
setMcpServers(s: any): void;
|
|
65
|
+
setAgents(a: any): void;
|
|
65
66
|
interruptAgent(): Promise<boolean>;
|
|
66
67
|
abortAgent(): void;
|
|
67
68
|
rewindAgent(checkpointId?: string): Promise<boolean>;
|
|
@@ -53,6 +53,7 @@ export class PipelineDirectLLM extends llm.LLM {
|
|
|
53
53
|
getPendingPermission() { return this.#claudeLLM.getPendingPermission(); }
|
|
54
54
|
getMcpServers() { return this.#claudeLLM.getMcpServers(); }
|
|
55
55
|
setMcpServers(s) { this.#claudeLLM.setMcpServers(s); }
|
|
56
|
+
setAgents(a) { this.#claudeLLM.setAgents(a); }
|
|
56
57
|
// Agent control — proxied to ClaudeLLM for fast brain access
|
|
57
58
|
async interruptAgent() { return this.#claudeLLM.interruptQuery(); }
|
|
58
59
|
abortAgent() { this.#claudeLLM.abortQuery(); }
|