osborn 0.9.96 → 0.9.98
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,16 @@ 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;
|
|
1610
|
+
// Built-ins the user has removed (tombstoned in user_agents with enabled=false).
|
|
1611
|
+
// A removed built-in disappears from the effective set but stays re-addable
|
|
1612
|
+
// from the frontend's "Available to add" list — default agents are never
|
|
1613
|
+
// gone forever, matching the skill-catalog pattern.
|
|
1614
|
+
let userRemovedAgents = [];
|
|
1605
1615
|
let activeMeetingBotId = null; // Recall.ai bot ID if in a meeting
|
|
1606
1616
|
let activeMeetingPoller = null; // Transcript poller bound to that bot
|
|
1607
1617
|
// LIVE meeting transcript → LLM (buffered webhook finals). See recall.on('transcript').
|
|
@@ -2246,6 +2256,13 @@ async function main() {
|
|
|
2246
2256
|
voiceMode: 'direct',
|
|
2247
2257
|
skipTTSQueue: true,
|
|
2248
2258
|
onCompactionEvent: buildOnCompactionEvent(),
|
|
2259
|
+
// Per-user named agents survive LLM recreations (session switch/resume)
|
|
2260
|
+
agents: (userNamedAgents || userRemovedAgents.length) ? (() => {
|
|
2261
|
+
const base = { ...NAMED_AGENTS };
|
|
2262
|
+
for (const r of userRemovedAgents)
|
|
2263
|
+
delete base[r];
|
|
2264
|
+
return { ...base, ...(userNamedAgents || {}) };
|
|
2265
|
+
})() : undefined,
|
|
2249
2266
|
});
|
|
2250
2267
|
currentLLM = directLLM;
|
|
2251
2268
|
// Reset the session always-allow list for each new direct session
|
|
@@ -4834,12 +4851,61 @@ async function main() {
|
|
|
4834
4851
|
});
|
|
4835
4852
|
}
|
|
4836
4853
|
else if (data.type === 'get_agents') {
|
|
4837
|
-
// Named sub-agents for the chat agents manager —
|
|
4838
|
-
//
|
|
4854
|
+
// Named sub-agents for the chat agents manager — built-ins (minus any
|
|
4855
|
+
// user-removed) merged with per-user DB-backed definitions.
|
|
4856
|
+
const effectiveBase = { ...NAMED_AGENTS };
|
|
4857
|
+
for (const r of userRemovedAgents)
|
|
4858
|
+
delete effectiveBase[r];
|
|
4859
|
+
const effective = { ...effectiveBase, ...(userNamedAgents || {}) };
|
|
4839
4860
|
await sendToFrontend({
|
|
4840
4861
|
type: 'agents_status',
|
|
4841
|
-
agents: Object.entries(
|
|
4862
|
+
agents: Object.entries(effective).map(([name, a]) => ({
|
|
4842
4863
|
name, description: a.description, model: a.model, tools: a.tools,
|
|
4864
|
+
custom: !!userNamedAgents && name in userNamedAgents,
|
|
4865
|
+
})),
|
|
4866
|
+
});
|
|
4867
|
+
}
|
|
4868
|
+
else if (data.type === 'set_agents') {
|
|
4869
|
+
// Per-user named agents from the DB (frontend fetches its user_agents
|
|
4870
|
+
// rows and sends them here after agent_ready, and again after edits).
|
|
4871
|
+
// Validated + merged over built-ins, applied via setAgents(). SDK
|
|
4872
|
+
// constraint: takes effect at the next query cold start — a live
|
|
4873
|
+
// subprocess keeps the agents it started with.
|
|
4874
|
+
const MODELS = new Set(['sonnet', 'opus', 'haiku', 'fable', 'inherit']);
|
|
4875
|
+
const rows = Array.isArray(data.agents) ? data.agents : [];
|
|
4876
|
+
const validated = {};
|
|
4877
|
+
for (const r of rows) {
|
|
4878
|
+
const name = String(r?.name || '').trim().toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
4879
|
+
const description = String(r?.description || '').trim();
|
|
4880
|
+
const prompt = String(r?.prompt || '').trim();
|
|
4881
|
+
if (!name || !description || !prompt)
|
|
4882
|
+
continue;
|
|
4883
|
+
if (prompt.length > 6000) {
|
|
4884
|
+
console.warn(`🤖 set_agents: '${name}' prompt >6KB — skipped`);
|
|
4885
|
+
continue;
|
|
4886
|
+
}
|
|
4887
|
+
validated[name] = {
|
|
4888
|
+
description,
|
|
4889
|
+
prompt,
|
|
4890
|
+
...(Array.isArray(r.tools) && r.tools.length ? { tools: r.tools.map(String) } : {}),
|
|
4891
|
+
...(r.model && (MODELS.has(r.model) || /^claude-/.test(r.model)) ? { model: String(r.model) } : {}),
|
|
4892
|
+
};
|
|
4893
|
+
}
|
|
4894
|
+
userNamedAgents = Object.keys(validated).length ? validated : null;
|
|
4895
|
+
// Removed built-ins (tombstones) — excluded from the effective set.
|
|
4896
|
+
userRemovedAgents = Array.isArray(data.removed) ? data.removed.map(String) : [];
|
|
4897
|
+
const base = { ...NAMED_AGENTS };
|
|
4898
|
+
for (const r of userRemovedAgents)
|
|
4899
|
+
delete base[r];
|
|
4900
|
+
const merged = { ...base, ...(userNamedAgents || {}) };
|
|
4901
|
+
const customized = !!userNamedAgents || userRemovedAgents.length > 0;
|
|
4902
|
+
currentLLM?.setAgents?.(customized ? merged : undefined);
|
|
4903
|
+
console.log(`🤖 set_agents: ${Object.keys(validated).length} user agent(s), ${userRemovedAgents.length} removed → effective [${Object.keys(merged).join(', ')}]`);
|
|
4904
|
+
await sendToFrontend({
|
|
4905
|
+
type: 'agents_status',
|
|
4906
|
+
agents: Object.entries(merged).map(([name, a]) => ({
|
|
4907
|
+
name, description: a.description, model: a.model, tools: a.tools,
|
|
4908
|
+
custom: !!userNamedAgents && name in userNamedAgents,
|
|
4843
4909
|
})),
|
|
4844
4910
|
});
|
|
4845
4911
|
}
|
|
@@ -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(); }
|