osborn 0.9.104 → 0.9.106
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/.claude/skills/meetings/SKILL.md +11 -8
- package/dist/claude-llm.js +11 -0
- package/dist/index.js +23 -1
- package/package.json +1 -1
|
@@ -91,16 +91,19 @@ When a chunk says **`YOU WERE ADDRESSED`**, people in the meeting are WAITING
|
|
|
91
91
|
for your voice. Measured failure (2026-08-01): notes-writing inside the reply
|
|
92
92
|
turn pushed speech→reply past 30 seconds ("very very delayed").
|
|
93
93
|
|
|
94
|
-
**Mandatory turn shape when addressed:**
|
|
95
|
-
1. **
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
**Mandatory turn shape when addressed (0.9.106+):**
|
|
95
|
+
1. **Just ANSWER in plain text — your words are spoken into the meeting
|
|
96
|
+
automatically.** The regular voice pipeline is redirected to the meeting
|
|
97
|
+
for addressed turns; do NOT use Bash/curl to speak (that adds a slow tool
|
|
98
|
+
roundtrip and can eat your tool budget). 1–2 short conversational
|
|
99
|
+
sentences, text first, before any tool call.
|
|
98
100
|
2. **THEN** delegate note-taking / research to the writer/researcher
|
|
99
101
|
sub-agents in the background as usual.
|
|
100
|
-
3. If you genuinely need a fact before answering,
|
|
101
|
-
("Good question — one second while I check"),
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
3. If you genuinely need a fact before answering, SAY a holding line first
|
|
103
|
+
("Good question — one second while I check"), look it up, then continue in
|
|
104
|
+
plain text. Never leave the room in silence while you work.
|
|
105
|
+
(The `/canvas say` curl remains for NON-addressed cases: when the voice-native
|
|
106
|
+
user says "tell the meeting X", or proactive announcements.)
|
|
104
107
|
|
|
105
108
|
## Browse requests while CASTING a live stream — drive the ENGINE, not the canvas
|
|
106
109
|
|
package/dist/claude-llm.js
CHANGED
|
@@ -990,6 +990,17 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
990
990
|
loadAllSkills(this.#opts.sessionBaseDir || this.#opts.workingDirectory || process.cwd()),
|
|
991
991
|
].filter(Boolean).join('\n\n'),
|
|
992
992
|
canUseTool: async (toolName, input, _options) => {
|
|
993
|
+
// Auto-approve Bash calls to the agent's OWN local API (/canvas,
|
|
994
|
+
// /tts) — how the agent SPEAKS into a meeting. A spoken reply must
|
|
995
|
+
// never wait on a permission dialog. Localhost-only, own endpoints
|
|
996
|
+
// only, no shell chaining — not a general curl allowance.
|
|
997
|
+
if (toolName === 'Bash') {
|
|
998
|
+
const cmd = String(input?.command || '');
|
|
999
|
+
if (/^\s*curl\b[^;&|]*https?:\/\/(localhost|127\.0\.0\.1):\d+\/(canvas|tts)\b/.test(cmd) && !/[;&|]/.test(cmd)) {
|
|
1000
|
+
console.log(`✅ Auto-approved Bash → own API (canvas/tts speak path)`);
|
|
1001
|
+
return { behavior: 'allow', updatedInput: input };
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
993
1004
|
// Auto-approve writes to session workspace (but block spec.md and library/ — fast brain manages those)
|
|
994
1005
|
if (toolName === 'Write' || toolName === 'Edit') {
|
|
995
1006
|
const filePath = String(input?.file_path || '');
|
package/dist/index.js
CHANGED
|
@@ -1617,6 +1617,10 @@ async function main() {
|
|
|
1617
1617
|
// gone forever, matching the skill-catalog pattern.
|
|
1618
1618
|
let userRemovedAgents = [];
|
|
1619
1619
|
let activeMeetingBotId = null; // Recall.ai bot ID if in a meeting
|
|
1620
|
+
// While set (Date.now() < value), the agent's streaming tts_say output is
|
|
1621
|
+
// REDIRECTED into the meeting canvas instead of suppressed — the regular
|
|
1622
|
+
// voice pipeline reused with the meeting as the sink (latency fix).
|
|
1623
|
+
let meetingAddressedUntil = 0;
|
|
1620
1624
|
let activeMeetingPoller = null; // Transcript poller bound to that bot
|
|
1621
1625
|
// LIVE meeting transcript → LLM (buffered webhook finals). See recall.on('transcript').
|
|
1622
1626
|
const meetingTranscriptBuffer = [];
|
|
@@ -1628,8 +1632,17 @@ async function main() {
|
|
|
1628
1632
|
if (!meetingTranscriptBuffer.length || !currentLLM)
|
|
1629
1633
|
return;
|
|
1630
1634
|
const turns = meetingTranscriptBuffer.splice(0); // drain
|
|
1635
|
+
if (addressed) {
|
|
1636
|
+
// REUSE the regular voice pipeline (2026-08-01 latency fix): during an
|
|
1637
|
+
// addressed turn the agent's normal streaming tts_say output is REDIRECTED
|
|
1638
|
+
// to the canvas (see the tts_say handler) — same speak path as regular
|
|
1639
|
+
// mode, sink = meeting. The old prompt made the agent compose a Bash curl
|
|
1640
|
+
// (extra LLM tool roundtrip, ate the 3-call budget, sometimes lost the
|
|
1641
|
+
// reply entirely) — measured as most of the 5-8s reply lag.
|
|
1642
|
+
meetingAddressedUntil = Date.now() + 90_000;
|
|
1643
|
+
}
|
|
1631
1644
|
const header = addressed
|
|
1632
|
-
? `[MEETING — ${botId}] — YOU WERE ADDRESSED.
|
|
1645
|
+
? `[MEETING — ${botId}] — YOU WERE ADDRESSED. Reply now in PLAIN TEXT — your words are spoken into the meeting automatically (do NOT use Bash/curl to speak). One or two short conversational sentences first; then, if needed, delegate notes/research in the background.`
|
|
1633
1646
|
: `[MEETING — ${botId}]:`;
|
|
1634
1647
|
// Prepend + consume any interruption context (bot was cut off mid-sentence).
|
|
1635
1648
|
const interrupt = meetingInterruptContext ? `${meetingInterruptContext}\n` : '';
|
|
@@ -2494,6 +2507,15 @@ async function main() {
|
|
|
2494
2507
|
// re-captures in the same room → feedback). Set by PipelineDirectLLM.chat()
|
|
2495
2508
|
// when the turn is a [MEETING —] chunk. Normal user turns are unaffected.
|
|
2496
2509
|
if (directLLM.suppressMeetingTTS) {
|
|
2510
|
+
// ADDRESSED turn → REDIRECT the normal streaming reply into the meeting
|
|
2511
|
+
// (reuse of the regular speak path; no Bash roundtrip). Silent-observer
|
|
2512
|
+
// turns stay suppressed as before.
|
|
2513
|
+
if (activeMeetingBotId && Date.now() < meetingAddressedUntil) {
|
|
2514
|
+
console.log(`🔊➡️📽️ tts_say → canvas (addressed meeting turn): "${data.text.slice(0, 60)}"`);
|
|
2515
|
+
pushCanvas({ kind: 'say', text: data.text });
|
|
2516
|
+
markMeetingSpeaking(data.text);
|
|
2517
|
+
return;
|
|
2518
|
+
}
|
|
2497
2519
|
console.log(`🔇 tts_say suppressed (meeting turn — response goes to /canvas, not browser): "${data.text.slice(0, 60)}"`);
|
|
2498
2520
|
return;
|
|
2499
2521
|
}
|