osborn 0.9.239 → 0.9.241
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/dist/claude-auth.d.ts +15 -0
- package/dist/claude-auth.js +30 -0
- package/dist/claude-llm.js +10 -0
- package/dist/index.js +22 -1
- package/dist/status-manager.d.ts +12 -0
- package/dist/status-manager.js +19 -0
- package/package.json +1 -1
package/dist/claude-auth.d.ts
CHANGED
|
@@ -63,6 +63,21 @@ export declare function runClaudeAuthFlow(callbacks: ClaudeAuthCallbacks): {
|
|
|
63
63
|
handle: ClaudeAuthHandle;
|
|
64
64
|
done: Promise<void>;
|
|
65
65
|
};
|
|
66
|
+
/**
|
|
67
|
+
* Re-deliver the current in-flight auth prompt to a frontend that has just
|
|
68
|
+
* (re)subscribed. WHY THIS EXISTS: ensureClaudeAuth runs inside the
|
|
69
|
+
* ParticipantConnected ("User joined") handler and publishes claude_auth_*
|
|
70
|
+
* over the LiveKit reliable data channel — but that fires ~5-6s BEFORE the
|
|
71
|
+
* browser's data channel actually finishes subscribing (observed: auth_url at
|
|
72
|
+
* :01, TrackSubscribed at :07). LiveKit reliable data is NOT buffered for a
|
|
73
|
+
* peer that hasn't subscribed yet, so a no-auth user's one-shot "Connect
|
|
74
|
+
* Claude" prompt is published to nobody and the modal never appears. Calling
|
|
75
|
+
* this on TrackSubscribed (data channel confirmed up) re-delivers the exact
|
|
76
|
+
* cached state. No-op (returns false) when no flow is in-flight — i.e. the
|
|
77
|
+
* user is already authenticated — so it costs nothing on the common path.
|
|
78
|
+
* Idempotent on the frontend (re-setting the same auth status is harmless).
|
|
79
|
+
*/
|
|
80
|
+
export declare function replayInFlightAuth(send: (type: string, payload: unknown) => void): boolean;
|
|
66
81
|
/**
|
|
67
82
|
* Ensure Claude is authenticated before proceeding.
|
|
68
83
|
*
|
package/dist/claude-auth.js
CHANGED
|
@@ -485,6 +485,36 @@ export function runClaudeAuthFlow(callbacks) {
|
|
|
485
485
|
return { handle, done };
|
|
486
486
|
}
|
|
487
487
|
let inFlightAuth = null;
|
|
488
|
+
/**
|
|
489
|
+
* Re-deliver the current in-flight auth prompt to a frontend that has just
|
|
490
|
+
* (re)subscribed. WHY THIS EXISTS: ensureClaudeAuth runs inside the
|
|
491
|
+
* ParticipantConnected ("User joined") handler and publishes claude_auth_*
|
|
492
|
+
* over the LiveKit reliable data channel — but that fires ~5-6s BEFORE the
|
|
493
|
+
* browser's data channel actually finishes subscribing (observed: auth_url at
|
|
494
|
+
* :01, TrackSubscribed at :07). LiveKit reliable data is NOT buffered for a
|
|
495
|
+
* peer that hasn't subscribed yet, so a no-auth user's one-shot "Connect
|
|
496
|
+
* Claude" prompt is published to nobody and the modal never appears. Calling
|
|
497
|
+
* this on TrackSubscribed (data channel confirmed up) re-delivers the exact
|
|
498
|
+
* cached state. No-op (returns false) when no flow is in-flight — i.e. the
|
|
499
|
+
* user is already authenticated — so it costs nothing on the common path.
|
|
500
|
+
* Idempotent on the frontend (re-setting the same auth status is harmless).
|
|
501
|
+
*/
|
|
502
|
+
export function replayInFlightAuth(send) {
|
|
503
|
+
if (!inFlightAuth)
|
|
504
|
+
return false;
|
|
505
|
+
send('claude_auth_required', {
|
|
506
|
+
message: 'Claude authentication required. A login URL will appear shortly.',
|
|
507
|
+
});
|
|
508
|
+
if (inFlightAuth.lastUrl) {
|
|
509
|
+
send('claude_auth_url', { url: inFlightAuth.lastUrl });
|
|
510
|
+
}
|
|
511
|
+
if (inFlightAuth.lastStatus === 'waiting_code') {
|
|
512
|
+
send('claude_auth_waiting_code', {
|
|
513
|
+
message: 'Paste the authentication code from the browser.',
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
return true;
|
|
517
|
+
}
|
|
488
518
|
/**
|
|
489
519
|
* Ensure Claude is authenticated before proceeding.
|
|
490
520
|
*
|
package/dist/claude-llm.js
CHANGED
|
@@ -2321,6 +2321,16 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
2321
2321
|
hooks: [async (input) => {
|
|
2322
2322
|
console.log('[LIFECYCLE-PROBE] SubagentStart', JSON.stringify(input));
|
|
2323
2323
|
this.#eventEmitter.emit('agent_started', { agent_type: input?.agent_type, agent_id: input?.agent_id });
|
|
2324
|
+
// Record the dispatch as LIVE so the frontend can reconcile orphaned
|
|
2325
|
+
// "running" rows against statusManager.getActiveDispatchIds(). Without a
|
|
2326
|
+
// start-time entry the manager only knew about dispatches at completion,
|
|
2327
|
+
// so a reconcile had no authoritative live set to diff against.
|
|
2328
|
+
if (input?.agent_id) {
|
|
2329
|
+
try {
|
|
2330
|
+
statusManager.upsertDispatch(input.agent_id, { subagentType: input?.agent_type, dispatchState: 'running' });
|
|
2331
|
+
}
|
|
2332
|
+
catch { }
|
|
2333
|
+
}
|
|
2324
2334
|
return {};
|
|
2325
2335
|
}]
|
|
2326
2336
|
}],
|
package/dist/index.js
CHANGED
|
@@ -38,7 +38,8 @@ import { cleanupHousekeeping } from './housekeeping.js';
|
|
|
38
38
|
import { createSTT, createTTS } from './voice-io.js';
|
|
39
39
|
import { createClaudeLLM, NAMED_AGENTS, applyTurbo } from './claude-llm.js';
|
|
40
40
|
import { clearPipelineFastBrainSession, prewarmBM25Index } from './pipeline-fastbrain.js';
|
|
41
|
-
import { ensureClaudeAuth, applyAuthFallback } from './claude-auth.js';
|
|
41
|
+
import { ensureClaudeAuth, applyAuthFallback, replayInFlightAuth } from './claude-auth.js';
|
|
42
|
+
import { statusManager } from './status-manager.js';
|
|
42
43
|
import { createSmitheryProxy, destroySmitheryProxy, parseSmitheryUrl, isSmitheryUrl, SmitheryAuthorizationError } from './smithery-proxy.js';
|
|
43
44
|
import { DIRECT_MODE_PROMPT } from './prompts.js';
|
|
44
45
|
import { MCP_CATALOG } from './config.js';
|
|
@@ -4035,6 +4036,20 @@ async function main() {
|
|
|
4035
4036
|
room.on(RoomEvent.TrackSubscribed, (track, publication, participant) => {
|
|
4036
4037
|
try {
|
|
4037
4038
|
console.log(`📥 [ROOM-TRACK-SUBSCRIBED] participant=${participant?.identity} kind=${track?.kind} source=${publication?.source} sid=${publication?.sid} t=${new Date().toISOString()}`);
|
|
4039
|
+
// Auth-prompt race fix: the "Connect Claude" prompt is published in the
|
|
4040
|
+
// ParticipantConnected handler ~5-6s before the browser's data channel
|
|
4041
|
+
// finishes subscribing, so a no-auth user never receives it (reliable
|
|
4042
|
+
// data isn't buffered for a not-yet-subscribed peer) and the modal never
|
|
4043
|
+
// shows. TrackSubscribed means this participant's WebRTC transport (incl.
|
|
4044
|
+
// data channel) is up — re-deliver any pending auth prompt now. No-op
|
|
4045
|
+
// when already authenticated. Covers BOTH resume and new-conversation
|
|
4046
|
+
// paths (both dispatch ensureClaudeAuth in the same participant handler).
|
|
4047
|
+
const pid = participant?.identity;
|
|
4048
|
+
if (typeof pid === 'string' && pid.startsWith('user-')) {
|
|
4049
|
+
const replayed = replayInFlightAuth((type, payload) => sendToFrontend({ type, ...payload }));
|
|
4050
|
+
if (replayed)
|
|
4051
|
+
console.log(`🔑 Re-delivered pending Claude auth prompt to ${pid} on TrackSubscribed`);
|
|
4052
|
+
}
|
|
4038
4053
|
}
|
|
4039
4054
|
catch { }
|
|
4040
4055
|
});
|
|
@@ -5938,6 +5953,12 @@ async function main() {
|
|
|
5938
5953
|
processes: topProcesses,
|
|
5939
5954
|
totalCount,
|
|
5940
5955
|
memory: { usedMb, totalMb, freeMb },
|
|
5956
|
+
// Authoritative set of still-live sub-agent dispatches. The frontend
|
|
5957
|
+
// reconciles its "running" background-flow rows against this and clears
|
|
5958
|
+
// any orphan whose completion/stop event was lost (or belonged to a
|
|
5959
|
+
// now-dead agent process — this list is per-process, so it's empty
|
|
5960
|
+
// after a restart and every stale row gets swept on the next poll).
|
|
5961
|
+
activeDispatchIds: statusManager.getActiveDispatchIds(),
|
|
5941
5962
|
});
|
|
5942
5963
|
}
|
|
5943
5964
|
catch (err) {
|
package/dist/status-manager.d.ts
CHANGED
|
@@ -90,6 +90,18 @@ export declare class StatusManager {
|
|
|
90
90
|
* Get context summary for the brain
|
|
91
91
|
*/
|
|
92
92
|
getContextSummary(): string;
|
|
93
|
+
/**
|
|
94
|
+
* Dispatcher reconciliation — the agent_ids of dispatches that are still LIVE
|
|
95
|
+
* (a real sub-agent dispatch, i.e. has a subagentType, whose dispatchState has
|
|
96
|
+
* not reached a terminal 'completed'/'failed'/'rejected'). The frontend
|
|
97
|
+
* cross-checks its "running" background-flow rows against this authoritative
|
|
98
|
+
* set on each process_list poll and clears any row NOT present — self-healing
|
|
99
|
+
* the orphaned "running" cards left when a task_completed / agent_stopped event
|
|
100
|
+
* was lost to a disconnect. Because this manager is a per-process singleton, an
|
|
101
|
+
* agent restart (the common session-drop case) resets it to empty, so every
|
|
102
|
+
* stale row from the dead process is reconciled away on the next poll.
|
|
103
|
+
*/
|
|
104
|
+
getActiveDispatchIds(): string[];
|
|
93
105
|
/**
|
|
94
106
|
* Dispatcher v1 — create or update a dispatch entry keyed by tool_use_id.
|
|
95
107
|
* Creates a minimal TaskStatus shell if the id doesn't yet exist so callers
|
package/dist/status-manager.js
CHANGED
|
@@ -182,6 +182,25 @@ export class StatusManager {
|
|
|
182
182
|
getContextSummary() {
|
|
183
183
|
return this.conversationContext.slice(-5).join(' | ');
|
|
184
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Dispatcher reconciliation — the agent_ids of dispatches that are still LIVE
|
|
187
|
+
* (a real sub-agent dispatch, i.e. has a subagentType, whose dispatchState has
|
|
188
|
+
* not reached a terminal 'completed'/'failed'/'rejected'). The frontend
|
|
189
|
+
* cross-checks its "running" background-flow rows against this authoritative
|
|
190
|
+
* set on each process_list poll and clears any row NOT present — self-healing
|
|
191
|
+
* the orphaned "running" cards left when a task_completed / agent_stopped event
|
|
192
|
+
* was lost to a disconnect. Because this manager is a per-process singleton, an
|
|
193
|
+
* agent restart (the common session-drop case) resets it to empty, so every
|
|
194
|
+
* stale row from the dead process is reconciled away on the next poll.
|
|
195
|
+
*/
|
|
196
|
+
getActiveDispatchIds() {
|
|
197
|
+
return Array.from(this.tasks.values())
|
|
198
|
+
.filter(t => !!t.subagentType &&
|
|
199
|
+
t.dispatchState !== 'completed' &&
|
|
200
|
+
t.dispatchState !== 'failed' &&
|
|
201
|
+
t.dispatchState !== 'rejected')
|
|
202
|
+
.map(t => t.id);
|
|
203
|
+
}
|
|
185
204
|
/**
|
|
186
205
|
* Dispatcher v1 — create or update a dispatch entry keyed by tool_use_id.
|
|
187
206
|
* Creates a minimal TaskStatus shell if the id doesn't yet exist so callers
|