osborn 0.9.96 → 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.
|
@@ -25,10 +25,11 @@ This packaged copy ships with every machine and may lag the served version.
|
|
|
25
25
|
Check, then NOTIFY the user before updating — never silently force:
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
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)
|
|
29
29
|
LOCAL_V=$(grep -m1 '^Version:' ~/.claude/skills/browser-screen-recorder/SKILL.md 2>/dev/null | awk '{print $2}')
|
|
30
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."
|
|
31
31
|
```
|
|
32
|
+
(The /version route is a one-GET probe — cheap enough to run every session.)
|
|
32
33
|
|
|
33
34
|
If the user approves (or has pre-approved auto-updates), update the skill
|
|
34
35
|
file AND re-run the served INSTALLATION step 2 (harness bundle refresh) so
|
package/dist/claude-llm.d.ts
CHANGED
|
@@ -34,6 +34,12 @@ 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
|
}
|
|
38
44
|
export declare const NAMED_AGENTS: {
|
|
39
45
|
researcher: {
|
|
@@ -101,6 +107,14 @@ export declare class ClaudeLLM extends llm.LLM {
|
|
|
101
107
|
label(): string;
|
|
102
108
|
get model(): string;
|
|
103
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;
|
|
104
118
|
/**
|
|
105
119
|
* Set session ID to resume a specific conversation
|
|
106
120
|
* Call this before sending the first message to resume from a previous session
|
package/dist/claude-llm.js
CHANGED
|
@@ -459,6 +459,17 @@ export class ClaudeLLM extends llm.LLM {
|
|
|
459
459
|
get sessionId() {
|
|
460
460
|
return this.#sessionId;
|
|
461
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
|
+
}
|
|
462
473
|
/**
|
|
463
474
|
* Set session ID to resume a specific conversation
|
|
464
475
|
* Call this before sending the first message to resume from a previous session
|
|
@@ -1292,9 +1303,9 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
1292
1303
|
}]
|
|
1293
1304
|
},
|
|
1294
1305
|
// Named sub-agents — the orchestrator delegates to these specialists.
|
|
1295
|
-
//
|
|
1296
|
-
//
|
|
1297
|
-
agents: NAMED_AGENTS,
|
|
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,
|
|
1298
1309
|
};
|
|
1299
1310
|
// Run Claude Agent SDK query() and stream results
|
|
1300
1311
|
let hasOutput = false;
|
package/dist/index.js
CHANGED
|
@@ -1602,6 +1602,11 @@ async function main() {
|
|
|
1602
1602
|
// Empty string = anonymous / unauthenticated; uploads fall back to a
|
|
1603
1603
|
// session-only path (no user prefix).
|
|
1604
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;
|
|
1605
1610
|
let activeMeetingBotId = null; // Recall.ai bot ID if in a meeting
|
|
1606
1611
|
let activeMeetingPoller = null; // Transcript poller bound to that bot
|
|
1607
1612
|
// LIVE meeting transcript → LLM (buffered webhook finals). See recall.on('transcript').
|
|
@@ -2246,6 +2251,8 @@ async function main() {
|
|
|
2246
2251
|
voiceMode: 'direct',
|
|
2247
2252
|
skipTTSQueue: true,
|
|
2248
2253
|
onCompactionEvent: buildOnCompactionEvent(),
|
|
2254
|
+
// Per-user named agents survive LLM recreations (session switch/resume)
|
|
2255
|
+
agents: userNamedAgents ? { ...NAMED_AGENTS, ...userNamedAgents } : undefined,
|
|
2249
2256
|
});
|
|
2250
2257
|
currentLLM = directLLM;
|
|
2251
2258
|
// Reset the session always-allow list for each new direct session
|
|
@@ -4834,12 +4841,52 @@ async function main() {
|
|
|
4834
4841
|
});
|
|
4835
4842
|
}
|
|
4836
4843
|
else if (data.type === 'get_agents') {
|
|
4837
|
-
// Named sub-agents for the chat agents manager —
|
|
4838
|
-
//
|
|
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 || {}) };
|
|
4839
4847
|
await sendToFrontend({
|
|
4840
4848
|
type: 'agents_status',
|
|
4841
|
-
agents: Object.entries(
|
|
4849
|
+
agents: Object.entries(effective).map(([name, a]) => ({
|
|
4842
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,
|
|
4843
4890
|
})),
|
|
4844
4891
|
});
|
|
4845
4892
|
}
|
|
@@ -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(); }
|