@yeaft/webchat-agent 1.0.532 → 1.0.533
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 +85 -1
- package/index.js +21 -11
- package/local-runtime/server/handlers/agent-sync.js +8 -2
- package/local-runtime/server/handlers/client-misc.js +40 -0
- package/local-runtime/server/ws-agent.js +2 -0
- package/local-runtime/version.json +1 -1
- package/local-runtime/web/app.bundle.js +19 -7
- package/local-runtime/web/app.bundle.js.gz +0 -0
- package/local-runtime/web/index.html +1 -1
- package/package.json +1 -1
- package/yeaft/config-api.js +30 -0
- package/yeaft/config.js +1 -0
- package/yeaft/session.js +3 -2
- package/yeaft/work-center/bridge.js +11 -1
- package/yeaft/work-center/feature.js +24 -7
|
@@ -26,7 +26,7 @@ import { sendToServer, flushMessageBuffer } from './buffer.js';
|
|
|
26
26
|
import { sendAgentMetricsSnapshot } from '../metrics.js';
|
|
27
27
|
import { handleRestartAgent, handleUpgradeAgent } from './upgrade.js';
|
|
28
28
|
import { loadMcpServers, updateMcpConfig } from '../mcp.js';
|
|
29
|
-
import { getLlmConfig, updateLlmConfig, getYeaftSettings, updateYeaftSettings, getPluginConfig, updatePluginConfig, getTelemetrySettings, updateTelemetrySettings, getSearchSettings, updateSearchSettings, fetchTavilyUsage } from '../yeaft/config-api.js';
|
|
29
|
+
import { getLlmConfig, updateLlmConfig, getYeaftSettings, updateYeaftSettings, getPluginConfig, updatePluginConfig, getTelemetrySettings, updateTelemetrySettings, getWorkCenterFeatureSettings, updateWorkCenterFeatureSettings, getSearchSettings, updateSearchSettings, fetchTavilyUsage } from '../yeaft/config-api.js';
|
|
30
30
|
import { loadConfig } from '../yeaft/config.js';
|
|
31
31
|
import { mutateAgentConfig } from '../yeaft/config-store.js';
|
|
32
32
|
import { discoverLlmModels } from '../llm-model-discovery.js';
|
|
@@ -96,6 +96,68 @@ export function applyRegisteredTransport(msg) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
let workCenterFeatureTransition = Promise.resolve();
|
|
100
|
+
|
|
101
|
+
export async function applyWorkCenterFeatureUpdate(msg, dependencies = {}) {
|
|
102
|
+
const run = async () => {
|
|
103
|
+
const update = dependencies.updateWorkCenterFeatureSettings || updateWorkCenterFeatureSettings;
|
|
104
|
+
const getSettings = dependencies.getWorkCenterFeatureSettings || getWorkCenterFeatureSettings;
|
|
105
|
+
const bridge = dependencies.bridge || await import('../yeaft/work-center/bridge.js');
|
|
106
|
+
const refreshCapabilities = dependencies.refreshAgentCapabilities || ctx.refreshAgentCapabilities;
|
|
107
|
+
const yeaftDir = dependencies.yeaftDir ?? ctx.CONFIG?.yeaftDir;
|
|
108
|
+
// Read inside the transition queue so the previous request is observable.
|
|
109
|
+
const previous = getSettings(yeaftDir);
|
|
110
|
+
const persisted = update(msg.settings || {}, yeaftDir);
|
|
111
|
+
if (persisted.error) return { ...persisted, persisted: false, effective: previous.enabled === true };
|
|
112
|
+
|
|
113
|
+
bridge.setWorkCenterFeatureEnabled(persisted.enabled);
|
|
114
|
+
try {
|
|
115
|
+
if (persisted.enabled) await bridge.bootWorkCenter();
|
|
116
|
+
else await bridge.shutdownWorkCenter();
|
|
117
|
+
if (ctx.CONFIG) ctx.CONFIG.workCenterEnabled = persisted.enabled;
|
|
118
|
+
ctx.workCenterStartupError = null;
|
|
119
|
+
await refreshCapabilities?.();
|
|
120
|
+
return {
|
|
121
|
+
...persisted,
|
|
122
|
+
persisted: true,
|
|
123
|
+
effective: persisted.enabled,
|
|
124
|
+
sessionTools: persisted.enabled ? 'new_sessions_only' : 'disabled_immediately',
|
|
125
|
+
};
|
|
126
|
+
} catch (error) {
|
|
127
|
+
const rollback = previous.error ? previous : update({ enabled: previous.enabled === true }, yeaftDir);
|
|
128
|
+
const restored = !rollback.error;
|
|
129
|
+
let rollbackRuntimeError = null;
|
|
130
|
+
if (restored) {
|
|
131
|
+
bridge.setWorkCenterFeatureEnabled(previous.enabled === true);
|
|
132
|
+
try {
|
|
133
|
+
if (previous.enabled === true) await bridge.bootWorkCenter();
|
|
134
|
+
else await bridge.shutdownWorkCenter();
|
|
135
|
+
} catch (rollbackError) {
|
|
136
|
+
rollbackRuntimeError = rollbackError?.message || String(rollbackError);
|
|
137
|
+
bridge.setWorkCenterFeatureEnabled(false);
|
|
138
|
+
}
|
|
139
|
+
if (ctx.CONFIG) ctx.CONFIG.workCenterEnabled = previous.enabled === true && !rollbackRuntimeError;
|
|
140
|
+
try { await refreshCapabilities?.(); } catch { /* original transition error remains authoritative */ }
|
|
141
|
+
} else {
|
|
142
|
+
bridge.setWorkCenterFeatureEnabled(false);
|
|
143
|
+
if (ctx.CONFIG) ctx.CONFIG.workCenterEnabled = false;
|
|
144
|
+
}
|
|
145
|
+
const effective = restored && !rollbackRuntimeError ? previous.enabled === true : false;
|
|
146
|
+
return {
|
|
147
|
+
...persisted,
|
|
148
|
+
enabled: restored ? previous.enabled === true : persisted.enabled,
|
|
149
|
+
error: `Failed to apply Work Center runtime transition: ${error?.message || error}${rollbackRuntimeError ? `; rollback runtime failed: ${rollbackRuntimeError}` : ''}`,
|
|
150
|
+
persisted: !restored,
|
|
151
|
+
effective,
|
|
152
|
+
rolledBack: restored && !rollbackRuntimeError,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const result = workCenterFeatureTransition.then(run, run);
|
|
157
|
+
workCenterFeatureTransition = result.catch(() => {});
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
|
|
99
161
|
export async function handleMessage(msg) {
|
|
100
162
|
if (await handleBrowserRuntimeMessage(msg)) return;
|
|
101
163
|
switch (msg.type) {
|
|
@@ -532,6 +594,28 @@ export async function handleMessage(msg) {
|
|
|
532
594
|
break;
|
|
533
595
|
}
|
|
534
596
|
|
|
597
|
+
|
|
598
|
+
case 'get_work_center_feature_settings': {
|
|
599
|
+
const settings = getWorkCenterFeatureSettings(ctx.CONFIG?.yeaftDir);
|
|
600
|
+
sendToServer({
|
|
601
|
+
type: 'work_center_feature_settings', requestId: msg.requestId, clientId: msg.clientId, ...settings,
|
|
602
|
+
effective: ctx.CONFIG?.workCenterEnabled === true,
|
|
603
|
+
...(ctx.workCenterStartupError ? { runtimeError: ctx.workCenterStartupError } : {}),
|
|
604
|
+
});
|
|
605
|
+
break;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
case 'update_work_center_feature_settings': {
|
|
609
|
+
let result;
|
|
610
|
+
try {
|
|
611
|
+
result = await applyWorkCenterFeatureUpdate(msg);
|
|
612
|
+
} catch (error) {
|
|
613
|
+
result = { error: `Failed to apply Work Center setting: ${error?.message || error}`, persisted: false, effective: ctx.CONFIG?.workCenterEnabled === true };
|
|
614
|
+
}
|
|
615
|
+
sendToServer({ type: 'work_center_feature_settings_updated', requestId: msg.requestId, clientId: msg.clientId, ...result });
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
|
|
535
619
|
// Search settings (web-search backend + Tavily key) — read/write the
|
|
536
620
|
// `search` section of config.json. `get_tavily_usage` hits Tavily's
|
|
537
621
|
// /usage endpoint with the saved key and is fired from the UI only
|
package/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
} from './upgrade-command.js';
|
|
26
26
|
import { loadConfig as loadYeaftConfig } from './yeaft/config.js';
|
|
27
27
|
import { initYeaftDir } from './yeaft/init.js';
|
|
28
|
-
import { isWorkCenterEnabled } from './yeaft/work-center/feature.js';
|
|
28
|
+
import { isWorkCenterEnabled, startWorkCenterFeature } from './yeaft/work-center/feature.js';
|
|
29
29
|
import { updateBrowserRuntimeSettings } from './yeaft/config-api.js';
|
|
30
30
|
import { bootBrowserRuntime, shutdownBrowserRuntime } from './browser-runtime/index.js';
|
|
31
31
|
import {
|
|
@@ -139,7 +139,7 @@ const CONFIG = {
|
|
|
139
139
|
workDir: WORK_DIR,
|
|
140
140
|
yeaftDir: YEAFT_DIR,
|
|
141
141
|
telemetry: loadYeaftConfig({ dir: YEAFT_DIR }).telemetry,
|
|
142
|
-
workCenterEnabled: isWorkCenterEnabled(),
|
|
142
|
+
workCenterEnabled: isWorkCenterEnabled(process.env, loadYeaftConfig({ dir: YEAFT_DIR })),
|
|
143
143
|
reconnectInterval: fileConfig.reconnectInterval,
|
|
144
144
|
agentSecret,
|
|
145
145
|
// 显式禁用的工具(非 MCP 相关)
|
|
@@ -177,9 +177,9 @@ async function detectCapabilities() {
|
|
|
177
177
|
// agent build can speak plaintext WS frames. New servers see this and
|
|
178
178
|
// flip `agent.encryptOutbound = false`, stopping outbound encryption
|
|
179
179
|
// to this peer. Old servers ignore the unknown capability token.
|
|
180
|
-
const capabilities = ['background_tasks', 'file_editor', 'ping_session', 'plaintext-ok', 'workbench_session_routes', 'workbench_request_correlation', 'workbench_terminal_cleanup_fence', 'workbench_file_content_chunks', 'workbench_video_stream', 'session_history_search', 'session_history_outline', 'session_history_window_prefetch', 'file_reference_resolution', 'response_image_preview', 'yeaft_plugins', 'yeaft_managed_skills', 'settings_request_correlation'];
|
|
180
|
+
const capabilities = ['background_tasks', 'file_editor', 'ping_session', 'plaintext-ok', 'workbench_session_routes', 'workbench_request_correlation', 'workbench_terminal_cleanup_fence', 'workbench_file_content_chunks', 'workbench_video_stream', 'session_history_search', 'session_history_outline', 'session_history_window_prefetch', 'file_reference_resolution', 'response_image_preview', 'yeaft_plugins', 'yeaft_managed_skills', 'settings_request_correlation', 'work_center_feature_settings'];
|
|
181
181
|
capabilities.push(getAgentUpgradeCapability());
|
|
182
|
-
if (
|
|
182
|
+
if (ctx.CONFIG?.workCenterEnabled === true) {
|
|
183
183
|
capabilities.push('work_center', 'work_center_message_v2');
|
|
184
184
|
if (process.platform === 'linux') capabilities.push('work_item_attachments');
|
|
185
185
|
}
|
|
@@ -193,6 +193,12 @@ async function detectCapabilities() {
|
|
|
193
193
|
return capabilities;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
ctx.refreshAgentCapabilities = async () => {
|
|
197
|
+
ctx.agentCapabilities = await detectCapabilities();
|
|
198
|
+
ctx.sendToServer?.({ type: 'agent_capabilities_updated', capabilities: ctx.agentCapabilities });
|
|
199
|
+
return ctx.agentCapabilities;
|
|
200
|
+
};
|
|
201
|
+
|
|
196
202
|
// 确保依赖已安装。node-pty 已被 @homebridge/node-pty-prebuilt-multiarch
|
|
197
203
|
// 取代(regular dep + 全平台预编译),不再需要 optionalDependency 的特判。
|
|
198
204
|
async function ensureDependencies() {
|
|
@@ -459,7 +465,6 @@ process.on('SIGTERM', async () => {
|
|
|
459
465
|
} catch (err) {
|
|
460
466
|
console.warn(`[BrowserRuntime] startup probe failed: ${err?.message || err}`);
|
|
461
467
|
}
|
|
462
|
-
ctx.agentCapabilities = await detectCapabilities();
|
|
463
468
|
// Prime the models.dev community catalog so the Yeaft engine's *synchronous*
|
|
464
469
|
// hot path (engine.js / config.js / cli.js all read context-window inline)
|
|
465
470
|
// can resolve real per-model limits without bubbling async up through every
|
|
@@ -472,16 +477,21 @@ process.on('SIGTERM', async () => {
|
|
|
472
477
|
} catch (err) {
|
|
473
478
|
console.warn(`[Agent] models.dev prime failed (will use config/defaults): ${err?.message || err}`);
|
|
474
479
|
}
|
|
475
|
-
if (
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
480
|
+
if (ctx.CONFIG?.workCenterEnabled === true) {
|
|
481
|
+
const bridge = await import('./yeaft/work-center/bridge.js');
|
|
482
|
+
const startup = await startWorkCenterFeature(true, bridge.bootWorkCenter);
|
|
483
|
+
ctx.CONFIG.workCenterEnabled = startup.effective;
|
|
484
|
+
ctx.workCenterStartupError = startup.runtimeError;
|
|
485
|
+
if (startup.effective) {
|
|
479
486
|
console.log('[Agent] Work Center watcher started');
|
|
480
|
-
}
|
|
481
|
-
|
|
487
|
+
} else {
|
|
488
|
+
bridge.setWorkCenterFeatureEnabled(false);
|
|
489
|
+
console.warn(`[Agent] Work Center failed to start: ${startup.runtimeError}`);
|
|
482
490
|
}
|
|
483
491
|
} else {
|
|
484
492
|
console.log('[Agent] Work Center disabled; watcher not started');
|
|
485
493
|
}
|
|
494
|
+
// Runtime capabilities must reflect the effective startup state.
|
|
495
|
+
ctx.agentCapabilities = await detectCapabilities();
|
|
486
496
|
connect();
|
|
487
497
|
})();
|
|
@@ -409,14 +409,20 @@ export async function handleAgentSync(agentId, agent, msg) {
|
|
|
409
409
|
// Local telemetry settings relay. Only bounded config is forwarded;
|
|
410
410
|
// trace payloads stay on the Agent.
|
|
411
411
|
case 'telemetry_settings':
|
|
412
|
-
case 'telemetry_settings_updated':
|
|
412
|
+
case 'telemetry_settings_updated':
|
|
413
|
+
case 'work_center_feature_settings':
|
|
414
|
+
case 'work_center_feature_settings_updated': {
|
|
413
415
|
const operation = msg.type === 'yeaft_plugins_updated'
|
|
414
416
|
? 'plugins:update'
|
|
415
417
|
: msg.type === 'yeaft_plugins'
|
|
416
418
|
? 'plugins:load'
|
|
417
419
|
: msg.type === 'telemetry_settings_updated'
|
|
418
420
|
? 'telemetry:update'
|
|
419
|
-
: '
|
|
421
|
+
: msg.type === 'telemetry_settings'
|
|
422
|
+
? 'telemetry:load'
|
|
423
|
+
: msg.type === 'work_center_feature_settings_updated'
|
|
424
|
+
? 'work-center-feature:update'
|
|
425
|
+
: 'work-center-feature:load';
|
|
420
426
|
await sendAgentSettingsReply(agentId, agent, operation, msg, { ...msg, agentId });
|
|
421
427
|
break;
|
|
422
428
|
}
|
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
// builds without this capability may still inherit the installed package cwd.
|
|
20
20
|
export const SAFE_REMOTE_UPGRADE_CAPABILITY = 'remote_upgrade_safe';
|
|
21
21
|
export const CONTAINER_AGENT_CAPABILITY = 'container_agent';
|
|
22
|
+
export const WORK_CENTER_FEATURE_SETTINGS_CAPABILITY = 'work_center_feature_settings';
|
|
23
|
+
export const WORK_CENTER_FEATURE_SETTINGS_UNSUPPORTED_ERROR = 'This Agent must be upgraded to manage Work Center settings.';
|
|
22
24
|
export const CONTAINER_IMAGE_UPGRADE_REASON = 'container_image_upgrade_required';
|
|
23
25
|
export { YEAFT_PLUGINS_CAPABILITY, YEAFT_PLUGINS_UNSUPPORTED_ERROR };
|
|
24
26
|
|
|
@@ -52,6 +54,19 @@ async function forwardRegisteredAgentRequest({ client, clientId, agentId, operat
|
|
|
52
54
|
return false;
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
|
|
58
|
+
async function rejectUnsupportedWorkCenterFeatureSettings(client, msg, agentId) {
|
|
59
|
+
await sendToWebClient(client, {
|
|
60
|
+
type: msg.type === 'update_work_center_feature_settings'
|
|
61
|
+
? 'work_center_feature_settings_updated'
|
|
62
|
+
: 'work_center_feature_settings',
|
|
63
|
+
agentId,
|
|
64
|
+
requestId: msg.requestId || null,
|
|
65
|
+
error: WORK_CENTER_FEATURE_SETTINGS_UNSUPPORTED_ERROR,
|
|
66
|
+
unsupported: true,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
55
70
|
export function requiresManualUpgradeBridge(capabilities, platform = null) {
|
|
56
71
|
if (Array.isArray(capabilities) && capabilities.includes(SAFE_REMOTE_UPGRADE_CAPABILITY)) return false;
|
|
57
72
|
const normalizedPlatform = typeof platform === 'string' ? platform.trim().toLowerCase() : '';
|
|
@@ -352,6 +367,31 @@ export async function handleClientMisc(clientId, client, msg, checkAgentAccess)
|
|
|
352
367
|
break;
|
|
353
368
|
}
|
|
354
369
|
|
|
370
|
+
|
|
371
|
+
case 'get_work_center_feature_settings': {
|
|
372
|
+
const a = msg.agentId || client.currentAgent;
|
|
373
|
+
if (!a || !await checkAgentAccess(a)) break;
|
|
374
|
+
if (!agents.get(a)?.capabilities?.includes(WORK_CENTER_FEATURE_SETTINGS_CAPABILITY)) {
|
|
375
|
+
await rejectUnsupportedWorkCenterFeatureSettings(client, msg, a);
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
await forwardRegisteredAgentRequest({ client, clientId, agentId: a, operation: 'work-center-feature:load', requestId: msg.requestId,
|
|
379
|
+
message: { type: 'get_work_center_feature_settings', requestId: msg.requestId, clientId }, responseType: 'work_center_feature_settings' });
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
case 'update_work_center_feature_settings': {
|
|
384
|
+
const a = msg.agentId || client.currentAgent;
|
|
385
|
+
if (!a || !await checkAgentAccess(a)) break;
|
|
386
|
+
if (!agents.get(a)?.capabilities?.includes(WORK_CENTER_FEATURE_SETTINGS_CAPABILITY)) {
|
|
387
|
+
await rejectUnsupportedWorkCenterFeatureSettings(client, msg, a);
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
await forwardRegisteredAgentRequest({ client, clientId, agentId: a, operation: 'work-center-feature:update', requestId: msg.requestId,
|
|
391
|
+
message: { type: 'update_work_center_feature_settings', requestId: msg.requestId, clientId, settings: msg.settings || {} }, responseType: 'work_center_feature_settings_updated' });
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
|
|
355
395
|
// Search settings (web-search backend + Tavily key + on-demand usage probe).
|
|
356
396
|
// Mirrors the get/update_yeaft_settings pair: the agent owns the
|
|
357
397
|
// config file, server is just a relay.
|
|
@@ -316,6 +316,8 @@ function handleAgentDisconnect(agentId, agentName, ws) {
|
|
|
316
316
|
restart: 'restart_agent_ack', dream: 'dream_enabled_changed', upgrade: 'upgrade_agent_ack',
|
|
317
317
|
'plugins:load': 'yeaft_plugins', 'plugins:update': 'yeaft_plugins_updated',
|
|
318
318
|
'telemetry:load': 'telemetry_settings', 'telemetry:update': 'telemetry_settings_updated',
|
|
319
|
+
'work-center-feature:load': 'work_center_feature_settings',
|
|
320
|
+
'work-center-feature:update': 'work_center_feature_settings_updated',
|
|
319
321
|
};
|
|
320
322
|
void sendToWebClient(client, {
|
|
321
323
|
type: responseTypes[pending.operation] || 'agent_request_error',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.0.
|
|
1
|
+
{"version":"1.0.533"}
|