@yeaft/webchat-agent 0.1.1091 → 0.1.1093
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/connection/message-router.js +4 -1
- package/package.json +1 -1
- package/yeaft/sub-agent/runner.js +21 -14
- package/yeaft/web-bridge.js +73 -0
|
@@ -38,7 +38,7 @@ import { loadMcpServers, updateMcpConfig } from '../mcp.js';
|
|
|
38
38
|
import { getLlmConfig, updateLlmConfig, getYeaftSettings, updateYeaftSettings, getSearchSettings, updateSearchSettings, fetchTavilyUsage } from '../yeaft/config-api.js';
|
|
39
39
|
import { discoverLlmModels } from '../llm-model-discovery.js';
|
|
40
40
|
import { fetchModelsDev } from '../yeaft/llm/models-dev.js';
|
|
41
|
-
import { handleYeaftSessionSend, handleYeaftModeSwitch, handleYeaftModelSwitch, resetYeaftSession, handleYeaftLoadHistory, handleYeaftLoadMoreHistory, handleYeaftAbortThread, handleYeaftAbortAll, handleYeaftAbortTurn, handleYeaftVpSubscribe, handleYeaftVpCreate, handleYeaftVpUpdate, handleYeaftVpDelete, handleYeaftVpRead, handleYeaftListSessions, handleYeaftCreateSession, handleYeaftRenameSession, handleYeaftUpdateSession, handleYeaftUpdateSessionConfig, handleYeaftArchiveSession, handleYeaftDeleteSession, handleYeaftSessionAddMember, handleYeaftSessionRemoveMember, handleYeaftSessionSetDefaultVp, handleYeaftScanWorkdirSessions, handleYeaftRestoreSession, handleYeaftDreamTrigger, handleYeaftFetchToolStats, handleYeaftFetchDebugHistory, handleYeaftMcpList, handleYeaftMcpAdd, handleYeaftMcpRemove, handleYeaftMcpReload, broadcastLanguageChange, broadcastYeaftSessionSnapshotEager } from '../yeaft/web-bridge.js';
|
|
41
|
+
import { handleYeaftSessionSend, handleYeaftSubAgentPrompt, handleYeaftModeSwitch, handleYeaftModelSwitch, resetYeaftSession, handleYeaftLoadHistory, handleYeaftLoadMoreHistory, handleYeaftAbortThread, handleYeaftAbortAll, handleYeaftAbortTurn, handleYeaftVpSubscribe, handleYeaftVpCreate, handleYeaftVpUpdate, handleYeaftVpDelete, handleYeaftVpRead, handleYeaftListSessions, handleYeaftCreateSession, handleYeaftRenameSession, handleYeaftUpdateSession, handleYeaftUpdateSessionConfig, handleYeaftArchiveSession, handleYeaftDeleteSession, handleYeaftSessionAddMember, handleYeaftSessionRemoveMember, handleYeaftSessionSetDefaultVp, handleYeaftScanWorkdirSessions, handleYeaftRestoreSession, handleYeaftDreamTrigger, handleYeaftFetchToolStats, handleYeaftFetchDebugHistory, handleYeaftMcpList, handleYeaftMcpAdd, handleYeaftMcpRemove, handleYeaftMcpReload, broadcastLanguageChange, broadcastYeaftSessionSnapshotEager } from '../yeaft/web-bridge.js';
|
|
42
42
|
import { startYeaftStatusRefresh, refreshYeaftStatus } from '../yeaft/status-cache.js';
|
|
43
43
|
|
|
44
44
|
export async function handleMessage(msg) {
|
|
@@ -655,6 +655,9 @@ export async function handleMessage(msg) {
|
|
|
655
655
|
case 'yeaft_session_send':
|
|
656
656
|
handleYeaftSessionSend(msg);
|
|
657
657
|
break;
|
|
658
|
+
case 'yeaft_sub_agent_prompt':
|
|
659
|
+
handleYeaftSubAgentPrompt(msg);
|
|
660
|
+
break;
|
|
658
661
|
|
|
659
662
|
// wave-6b: manual dream trigger from VP detail page
|
|
660
663
|
case 'yeaft_dream_trigger':
|
package/package.json
CHANGED
|
@@ -274,13 +274,19 @@ async function driveSubAgent(agent, subEngine, vpPersona, deps) {
|
|
|
274
274
|
? deps.idleAbandonMs : IDLE_ABANDON_MS;
|
|
275
275
|
|
|
276
276
|
const wrapEvt = (evt) => ({ ...evt, agentId: agent.id, agentName: agent.name });
|
|
277
|
+
let lastTaskLogRefreshAt = 0;
|
|
278
|
+
const refreshTaskLog = ({ force = false } = {}) => {
|
|
279
|
+
if (!agent.taskId || !deps.taskManager || !agent.parentSessionId) return;
|
|
280
|
+
const now = Date.now();
|
|
281
|
+
if (!force && now - lastTaskLogRefreshAt < 250) return;
|
|
282
|
+
lastTaskLogRefreshAt = now;
|
|
283
|
+
try { deps.taskManager.refreshTaskLog(agent.parentSessionId, agent.taskId); } catch { /* ignore */ }
|
|
284
|
+
};
|
|
277
285
|
|
|
278
286
|
const emit = (evt) => {
|
|
279
287
|
const wrapped = wrapEvt(evt);
|
|
280
288
|
try { agent.outputLog?.write(wrapped); } catch { /* ignore log failures */ }
|
|
281
|
-
|
|
282
|
-
try { deps.taskManager.refreshTaskLog(agent.parentSessionId, agent.taskId); } catch { /* ignore */ }
|
|
283
|
-
}
|
|
289
|
+
refreshTaskLog({ force: true });
|
|
284
290
|
if (onEvent) {
|
|
285
291
|
try { onEvent(agent.id, wrapped); } catch { /* ignore listener errors */ }
|
|
286
292
|
}
|
|
@@ -360,15 +366,14 @@ async function driveSubAgent(agent, subEngine, vpPersona, deps) {
|
|
|
360
366
|
// the bump.
|
|
361
367
|
bumpLivenessFromEvent(agent.liveness, evt);
|
|
362
368
|
|
|
363
|
-
// Mirror every raw event to the durable log
|
|
364
|
-
//
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
// and can leave users staring at an "idle" preview before the parent
|
|
368
|
-
// VP consumes the completed task result.
|
|
369
|
+
// Mirror every raw event to the durable log. We still keep
|
|
370
|
+
// `sub_agent_event` text_delta suppressed so the inline transcript
|
|
371
|
+
// card remains result-oriented, but task-backed sub-agents refresh
|
|
372
|
+
// their task log so the Session status pane can show a live stream.
|
|
369
373
|
if (agent.outputLog) {
|
|
370
374
|
try { agent.outputLog.write(wrapEvt(evt)); } catch { /* ignore */ }
|
|
371
375
|
}
|
|
376
|
+
refreshTaskLog({ force: evt?.type !== 'text_delta' });
|
|
372
377
|
if (onEvent && evt?.type !== 'text_delta') {
|
|
373
378
|
try { onEvent(agent.id, wrapEvt(evt)); } catch { /* ignore listener errors */ }
|
|
374
379
|
}
|
|
@@ -460,12 +465,14 @@ async function driveSubAgent(agent, subEngine, vpPersona, deps) {
|
|
|
460
465
|
return;
|
|
461
466
|
}
|
|
462
467
|
|
|
463
|
-
// Turn complete cleanly. Task-backed sub-agents are one-shot
|
|
468
|
+
// Turn complete cleanly. Task-backed sub-agents are usually one-shot
|
|
464
469
|
// background tasks: once they produce their mission result, complete
|
|
465
470
|
// the agent/task instead of letting the idle watchdog later mark the
|
|
466
|
-
// already-delivered work as abandoned.
|
|
467
|
-
//
|
|
468
|
-
|
|
471
|
+
// already-delivered work as abandoned. If the user queued a follow-up
|
|
472
|
+
// while the turn was running, keep the driver alive and immediately
|
|
473
|
+
// continue into the next prompt instead of dropping that input.
|
|
474
|
+
const hasQueuedFollowUp = Array.isArray(agent.pendingPrompts) && agent.pendingPrompts.length > 0;
|
|
475
|
+
if (agent.taskId && deps.taskManager && agent.parentSessionId && !hasQueuedFollowUp) {
|
|
469
476
|
transitionTerminal(agent, STATUS.COMPLETED, {
|
|
470
477
|
diagnostic: 'task_turn_complete',
|
|
471
478
|
deps,
|
|
@@ -473,7 +480,7 @@ async function driveSubAgent(agent, subEngine, vpPersona, deps) {
|
|
|
473
480
|
emit({ type: 'sub_agent_turn_end', content: assistantText, status: STATUS.COMPLETED });
|
|
474
481
|
return;
|
|
475
482
|
}
|
|
476
|
-
emit({ type: 'sub_agent_turn_end', content: assistantText, status: STATUS.IDLE });
|
|
483
|
+
emit({ type: 'sub_agent_turn_end', content: assistantText, status: hasQueuedFollowUp ? STATUS.RUNNING : STATUS.IDLE });
|
|
477
484
|
}
|
|
478
485
|
} finally {
|
|
479
486
|
if (wallTimeWatchdog) clearTimeout(wallTimeWatchdog);
|
package/yeaft/web-bridge.js
CHANGED
|
@@ -69,6 +69,8 @@ import { createVpStatusBroker } from './vp-status-broker.js';
|
|
|
69
69
|
import { classifyThread as defaultClassifyThread, fallbackTitle } from './vp/thread-classifier.js';
|
|
70
70
|
import { listMcpServers, upsertMcpServer, removeMcpServer } from './config-api.js';
|
|
71
71
|
import { buildMcpFlattenedTools } from './tools/mcp-tools.js';
|
|
72
|
+
import { getAgentRegistry, agentBelongsToScope } from './tools/agent.js';
|
|
73
|
+
import { isPromptableAgentStatus } from './sub-agent/status.js';
|
|
72
74
|
|
|
73
75
|
/** @type {import('./session.js').Session | null} */
|
|
74
76
|
let session = null;
|
|
@@ -4314,6 +4316,74 @@ export async function handleYeaftFetchDebugHistory(msg = {}) {
|
|
|
4314
4316
|
});
|
|
4315
4317
|
}
|
|
4316
4318
|
|
|
4319
|
+
export function handleYeaftSubAgentPrompt(msg) {
|
|
4320
|
+
const sessionId = typeof msg?.sessionId === 'string' ? msg.sessionId.trim() : '';
|
|
4321
|
+
const taskId = typeof msg?.taskId === 'string' ? msg.taskId.trim() : '';
|
|
4322
|
+
const subAgentId = typeof msg?.subAgentId === 'string' ? msg.subAgentId.trim() : '';
|
|
4323
|
+
const message = typeof msg?.message === 'string' ? msg.message.trim() : '';
|
|
4324
|
+
const clientPromptId = typeof msg?.clientPromptId === 'string' ? msg.clientPromptId.trim() : '';
|
|
4325
|
+
const fail = (error) => {
|
|
4326
|
+
sendSessionEvent({
|
|
4327
|
+
type: 'yeaft_sub_agent_prompt_result',
|
|
4328
|
+
success: false,
|
|
4329
|
+
taskId: taskId || null,
|
|
4330
|
+
subAgentId: subAgentId || null,
|
|
4331
|
+
clientPromptId: clientPromptId || null,
|
|
4332
|
+
error,
|
|
4333
|
+
}, sessionId ? { sessionId } : undefined);
|
|
4334
|
+
};
|
|
4335
|
+
|
|
4336
|
+
if (!sessionId || !taskId || !subAgentId || !message) {
|
|
4337
|
+
fail('sessionId, taskId, subAgentId and message are required');
|
|
4338
|
+
return;
|
|
4339
|
+
}
|
|
4340
|
+
const task = session?.taskManager?.getTask?.(sessionId, taskId) || null;
|
|
4341
|
+
if (!task || task.kind !== 'sub_agent' || task.status !== 'running' || task.runtime?.subAgentId !== subAgentId) {
|
|
4342
|
+
fail('sub-agent task not found');
|
|
4343
|
+
return;
|
|
4344
|
+
}
|
|
4345
|
+
|
|
4346
|
+
const agent = getAgentRegistry().get(subAgentId);
|
|
4347
|
+
const scope = {
|
|
4348
|
+
sessionId,
|
|
4349
|
+
parentVpId: task.ownerVpId || null,
|
|
4350
|
+
parentThreadId: task.source?.threadId || 'main',
|
|
4351
|
+
};
|
|
4352
|
+
if (!agent || !agentBelongsToScope(agent, scope)) {
|
|
4353
|
+
fail('sub-agent not found');
|
|
4354
|
+
return;
|
|
4355
|
+
}
|
|
4356
|
+
if (!isPromptableAgentStatus(agent.status)) {
|
|
4357
|
+
fail(`sub-agent status "${agent.status}" does not accept prompts`);
|
|
4358
|
+
return;
|
|
4359
|
+
}
|
|
4360
|
+
|
|
4361
|
+
if (!Array.isArray(agent.pendingPrompts)) agent.pendingPrompts = [];
|
|
4362
|
+
agent.pendingPrompts.push(message);
|
|
4363
|
+
if (!Array.isArray(agent.messages)) agent.messages = [];
|
|
4364
|
+
agent.messages.push({ role: 'user', content: message, timestamp: Date.now() });
|
|
4365
|
+
if (agent.status === 'idle' || agent.status === 'created') agent.status = 'running';
|
|
4366
|
+
|
|
4367
|
+
try {
|
|
4368
|
+
agent.outputLog?.write?.({
|
|
4369
|
+
type: 'user_prompt',
|
|
4370
|
+
agentId: agent.id,
|
|
4371
|
+
agentName: agent.name,
|
|
4372
|
+
content: message,
|
|
4373
|
+
});
|
|
4374
|
+
session?.taskManager?.refreshTaskLog?.(sessionId, taskId);
|
|
4375
|
+
} catch { /* prompt queueing must not depend on log refresh */ }
|
|
4376
|
+
|
|
4377
|
+
sendSessionEvent({
|
|
4378
|
+
type: 'yeaft_sub_agent_prompt_result',
|
|
4379
|
+
success: true,
|
|
4380
|
+
taskId,
|
|
4381
|
+
subAgentId,
|
|
4382
|
+
clientPromptId: clientPromptId || null,
|
|
4383
|
+
pending: agent.pendingPrompts.length,
|
|
4384
|
+
}, { sessionId, vpId: task.ownerVpId || null, threadId: task.source?.threadId || null });
|
|
4385
|
+
}
|
|
4386
|
+
|
|
4317
4387
|
/** Deprecated mode switch — Yeaft is single-mode. */
|
|
4318
4388
|
export function handleYeaftModeSwitch(_msg) {
|
|
4319
4389
|
console.warn('[Yeaft] yeaft_mode_switch is deprecated and ignored — Yeaft now runs in a single unified mode.');
|
|
@@ -5022,6 +5092,9 @@ export async function handleYeaftMcpReload(msg = {}) {
|
|
|
5022
5092
|
}
|
|
5023
5093
|
|
|
5024
5094
|
export const __testHooks = {
|
|
5095
|
+
setSessionForTest(nextSession) {
|
|
5096
|
+
session = nextSession || null;
|
|
5097
|
+
},
|
|
5025
5098
|
resetAbortState() {
|
|
5026
5099
|
turnAbortCtrls.clear();
|
|
5027
5100
|
turnAbortMeta.clear();
|