@yeaft/webchat-agent 1.0.409 → 1.0.410
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 +24 -2
- package/llm-config-cli.js +36 -3
- package/local-runtime/server/handlers/agent-output.js +14 -0
- package/local-runtime/server/handlers/agent-sync.js +6 -1
- package/local-runtime/server/handlers/client-conversation.js +4 -0
- package/local-runtime/server/handlers/client-misc.js +27 -0
- package/local-runtime/version.json +1 -1
- package/local-runtime/web/app.bundle.js +166 -64
- package/local-runtime/web/app.bundle.js.gz +0 -0
- package/local-runtime/web/index.html +2 -2
- package/local-runtime/web/style.bundle.css +1 -1
- package/local-runtime/web/style.bundle.css.gz +0 -0
- package/package.json +1 -1
- package/yeaft/config-api.js +109 -48
- package/yeaft/config.js +56 -9
- package/yeaft/engine.js +98 -43
- package/yeaft/plugins.js +170 -0
- package/yeaft/session.js +7 -4
- package/yeaft/sessions/feature-flag.js +42 -9
- package/yeaft/tools/mcp-tools.js +1 -0
- package/yeaft/tools/registry.js +51 -7
- package/yeaft/tools/types.js +6 -0
- package/yeaft/web-bridge.js +317 -89
- package/yeaft/work-center/runner.js +5 -1
|
@@ -26,11 +26,11 @@ 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, getTelemetrySettings, updateTelemetrySettings, getSearchSettings, updateSearchSettings, fetchTavilyUsage } from '../yeaft/config-api.js';
|
|
29
|
+
import { getLlmConfig, updateLlmConfig, getYeaftSettings, updateYeaftSettings, getPluginConfig, updatePluginConfig, getTelemetrySettings, updateTelemetrySettings, getSearchSettings, updateSearchSettings, fetchTavilyUsage } from '../yeaft/config-api.js';
|
|
30
30
|
import { loadConfig } from '../yeaft/config.js';
|
|
31
31
|
import { discoverLlmModels } from '../llm-model-discovery.js';
|
|
32
32
|
import { fetchModelsDev } from '../yeaft/llm/models-dev.js';
|
|
33
|
-
import { handleYeaftSessionSend, handleYeaftAskUserAnswer, handleYeaftSubAgentPrompt, handleYeaftTaskCancel, handleYeaftModeSwitch, handleYeaftModelSwitch, resetYeaftSession, refreshLiveSessionConfig, handleYeaftLoadHistory, handleYeaftLoadHistoryOutline, handleYeaftSearchHistory, handleYeaftLoadHistoryWindow, handleYeaftLoadMoreHistory, handleYeaftAbortThread, handleYeaftAbortAll, handleYeaftAbortTurn, handleYeaftVpSubscribe, handleYeaftVpCreate, handleYeaftVpUpdate, handleYeaftVpDelete, handleYeaftVpRead, handleYeaftListSessions, handleYeaftProjectContextSync, handleYeaftProjectMutation, handleYeaftCreateSession, handleYeaftRenameSession, handleYeaftUpdateSession, handleYeaftUpdateSessionConfig, handleYeaftArchiveSession, handleYeaftDeleteSession, handleYeaftSessionAddMember, handleYeaftSessionRemoveMember, handleYeaftSessionSetDefaultVp, handleYeaftScanWorkdirSessions, handleYeaftRestoreSession, handleYeaftDreamTrigger, handleYeaftFetchToolStats, handleYeaftFetchDebugHistory, handleYeaftMcpList, handleYeaftMcpAdd, handleYeaftMcpRemove, handleYeaftMcpReload, broadcastLanguageChange, broadcastYeaftSessionSnapshotEager, broadcastYeaftVpSnapshotEager, preloadYeaftSkillSlashCommands } from '../yeaft/web-bridge.js';
|
|
33
|
+
import { handleYeaftSessionSend, handleYeaftAskUserAnswer, handleYeaftSubAgentPrompt, handleYeaftTaskCancel, handleYeaftModeSwitch, handleYeaftModelSwitch, resetYeaftSession, refreshLiveSessionConfig, handleYeaftLoadHistory, handleYeaftLoadHistoryOutline, handleYeaftSearchHistory, handleYeaftLoadHistoryWindow, handleYeaftLoadMoreHistory, handleYeaftAbortThread, handleYeaftAbortAll, handleYeaftAbortTurn, handleYeaftVpSubscribe, handleYeaftVpCreate, handleYeaftVpUpdate, handleYeaftVpDelete, handleYeaftVpRead, handleYeaftListSessions, handleYeaftProjectContextSync, handleYeaftProjectMutation, handleYeaftCreateSession, handleYeaftRenameSession, handleYeaftUpdateSession, handleYeaftUpdateSessionConfig, handleYeaftArchiveSession, handleYeaftDeleteSession, handleYeaftSessionAddMember, handleYeaftSessionRemoveMember, handleYeaftSessionSetDefaultVp, handleYeaftScanWorkdirSessions, handleYeaftRestoreSession, handleYeaftDreamTrigger, handleYeaftFetchToolStats, handleYeaftFetchDebugHistory, handleYeaftMcpList, handleYeaftMcpAdd, handleYeaftMcpRemove, handleYeaftMcpReload, handleYeaftPluginCatalog, broadcastLanguageChange, broadcastYeaftSessionSnapshotEager, broadcastYeaftVpSnapshotEager, preloadYeaftSkillSlashCommands } from '../yeaft/web-bridge.js';
|
|
34
34
|
import { startYeaftStatusRefresh, forceRefreshYeaftStatus } from '../yeaft/status-cache.js';
|
|
35
35
|
import { handleWorkCenterRequest } from '../yeaft/work-center/bridge.js';
|
|
36
36
|
|
|
@@ -434,6 +434,24 @@ export async function handleMessage(msg) {
|
|
|
434
434
|
break;
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
+
case 'get_yeaft_plugins': {
|
|
438
|
+
const result = getPluginConfig(ctx.CONFIG?.yeaftDir);
|
|
439
|
+
sendToServer({ type: 'yeaft_plugins', requestId: msg.requestId || null, ...result });
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
case 'update_yeaft_plugins': {
|
|
444
|
+
const hasPlugins = Object.prototype.hasOwnProperty.call(msg, 'plugins');
|
|
445
|
+
const hasConfig = Object.prototype.hasOwnProperty.call(msg, 'config');
|
|
446
|
+
const payload = hasPlugins ? msg.plugins : (hasConfig ? msg.config : {});
|
|
447
|
+
const result = updatePluginConfig(payload, ctx.CONFIG?.yeaftDir);
|
|
448
|
+
if (!result.error) {
|
|
449
|
+
try { await refreshLiveSessionConfig(); } catch { /* next runtime load still sees disk config */ }
|
|
450
|
+
}
|
|
451
|
+
sendToServer({ type: 'yeaft_plugins_updated', requestId: msg.requestId || null, ...result });
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
|
|
437
455
|
case 'update_yeaft_settings':
|
|
438
456
|
case 'update_unify_settings': {
|
|
439
457
|
const result = updateYeaftSettings(msg.settings || msg.config || {}, ctx.CONFIG?.yeaftDir);
|
|
@@ -611,6 +629,10 @@ export async function handleMessage(msg) {
|
|
|
611
629
|
// All four reply via `vp_crud_result`; VpLoader's rescan emits the
|
|
612
630
|
// authoritative `vp_updated` / `vp_removed` events so the store stays
|
|
613
631
|
// in sync without a bespoke ack path.
|
|
632
|
+
case 'yeaft_plugin_catalog':
|
|
633
|
+
handleYeaftPluginCatalog(msg);
|
|
634
|
+
break;
|
|
635
|
+
|
|
614
636
|
case 'yeaft_vp_create':
|
|
615
637
|
case 'unify_vp_create':
|
|
616
638
|
handleYeaftVpCreate(msg);
|
package/llm-config-cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
2
2
|
import { dirname, join } from 'path';
|
|
3
3
|
import { homedir } from 'os';
|
|
4
|
+
import { normalizePluginConfig } from './yeaft/plugins.js';
|
|
4
5
|
import {
|
|
5
6
|
discoverGitHubCopilotModels,
|
|
6
7
|
discoverOpenAICompatibleModels,
|
|
@@ -21,17 +22,49 @@ export function getDefaultYeaftConfigPath() {
|
|
|
21
22
|
export function readLocalLlmConfig(configPath = getDefaultYeaftConfigPath()) {
|
|
22
23
|
if (!existsSync(configPath)) return {};
|
|
23
24
|
const raw = readFileSync(configPath, 'utf8');
|
|
24
|
-
if (!raw.trim())
|
|
25
|
+
if (!raw.trim()) {
|
|
26
|
+
throw new Error(`Invalid config file: expected JSON object at ${configPath}`);
|
|
27
|
+
}
|
|
25
28
|
const parsed = JSON.parse(raw);
|
|
26
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)
|
|
29
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)
|
|
30
|
+
|| Object.getPrototypeOf(parsed) !== Object.prototype) {
|
|
27
31
|
throw new Error(`Invalid config file: expected JSON object at ${configPath}`);
|
|
28
32
|
}
|
|
33
|
+
if (Object.prototype.hasOwnProperty.call(parsed, 'plugins')) {
|
|
34
|
+
try {
|
|
35
|
+
normalizePluginConfig(parsed.plugins);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
throw new Error(`Invalid config file: ${err?.message || err}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
29
40
|
return parsed;
|
|
30
41
|
}
|
|
31
42
|
|
|
32
43
|
export function writeLocalLlmConfig(config, configPath = getDefaultYeaftConfigPath()) {
|
|
44
|
+
// The CLI exposes this writer publicly, so do not rely on callers having
|
|
45
|
+
// already used readLocalLlmConfig(). An existing invalid Plugins policy must
|
|
46
|
+
// remain on disk and keep runtime fail-closed until the user repairs it.
|
|
47
|
+
const existing = existsSync(configPath) ? readLocalLlmConfig(configPath) : null;
|
|
48
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)
|
|
49
|
+
|| Object.getPrototypeOf(config) !== Object.prototype) {
|
|
50
|
+
throw new Error(`Invalid config file: expected JSON object at ${configPath}`);
|
|
51
|
+
}
|
|
52
|
+
const next = { ...config };
|
|
53
|
+
if (next.plugins === undefined
|
|
54
|
+
&& Object.prototype.hasOwnProperty.call(existing || {}, 'plugins')) {
|
|
55
|
+
// LLM commands change provider/model fields. They must not remove a
|
|
56
|
+
// separately-managed Plugin allowlist merely because their payload omits it.
|
|
57
|
+
next.plugins = existing.plugins;
|
|
58
|
+
}
|
|
59
|
+
if (next.plugins !== undefined) {
|
|
60
|
+
try {
|
|
61
|
+
normalizePluginConfig(next.plugins);
|
|
62
|
+
} catch (err) {
|
|
63
|
+
throw new Error(`Invalid config file: ${err?.message || err}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
33
66
|
mkdirSync(dirname(configPath), { recursive: true });
|
|
34
|
-
writeFileSync(configPath, `${JSON.stringify(
|
|
67
|
+
writeFileSync(configPath, `${JSON.stringify(next, null, 2)}\n`, 'utf8');
|
|
35
68
|
}
|
|
36
69
|
|
|
37
70
|
export function parseModelsCsv(value) {
|
|
@@ -865,6 +865,20 @@ export async function handleAgentOutput(agentId, agent, msg) {
|
|
|
865
865
|
}
|
|
866
866
|
break;
|
|
867
867
|
|
|
868
|
+
case 'yeaft_plugin_catalog_result': {
|
|
869
|
+
const targetClient = msg._requestClientId ? webClients.get(msg._requestClientId) : null;
|
|
870
|
+
if (targetClient?.authenticated && (CONFIG.skipAuth || targetClient.userId === agent.ownerId)) {
|
|
871
|
+
await sendToWebClient(targetClient, {
|
|
872
|
+
type: 'yeaft_plugin_catalog_result',
|
|
873
|
+
agentId,
|
|
874
|
+
requestId: msg.requestId || null,
|
|
875
|
+
catalog: msg.catalog || { tools: [], skills: [], mcpServers: [] },
|
|
876
|
+
error: msg.error || null,
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
break;
|
|
880
|
+
}
|
|
881
|
+
|
|
868
882
|
case 'yeaft_tool_stats':
|
|
869
883
|
// 2026-05-13: relay tool-call counters from the agent to the web
|
|
870
884
|
// client that requested them. Whitelist `snapshot`/`registered`/
|
|
@@ -356,10 +356,14 @@ export async function handleAgentSync(agentId, agent, msg) {
|
|
|
356
356
|
break;
|
|
357
357
|
}
|
|
358
358
|
|
|
359
|
+
// Agent-level plugin selection. The Agent owns config.json; the server
|
|
360
|
+
// only stamps ownership and relays request-scoped replies to the UI.
|
|
361
|
+
case 'yeaft_plugins':
|
|
362
|
+
case 'yeaft_plugins_updated':
|
|
359
363
|
// Local telemetry settings relay. Only bounded config is forwarded;
|
|
360
364
|
// trace payloads stay on the Agent.
|
|
361
365
|
case 'telemetry_settings':
|
|
362
|
-
case 'telemetry_settings_updated':
|
|
366
|
+
case 'telemetry_settings_updated': {
|
|
363
367
|
for (const [, client] of webClients) {
|
|
364
368
|
if (client.authenticated && (CONFIG.skipAuth ||
|
|
365
369
|
(agent.ownerId && client.userId === agent.ownerId) ||
|
|
@@ -369,6 +373,7 @@ export async function handleAgentSync(agentId, agent, msg) {
|
|
|
369
373
|
}
|
|
370
374
|
}
|
|
371
375
|
break;
|
|
376
|
+
}
|
|
372
377
|
|
|
373
378
|
// Search settings + Tavily usage relays. We pass the whole msg
|
|
374
379
|
// through (minus agentId, which we set ourselves) — the payload
|
|
@@ -1651,6 +1651,10 @@ export async function handleClientConversation(clientId, client, msg, checkAgent
|
|
|
1651
1651
|
// router is the authoritative consumer of the payload shape.
|
|
1652
1652
|
const { agentId: _discard, ...rest } = msg;
|
|
1653
1653
|
rest.type = relayType;
|
|
1654
|
+
// Direct catalog replies are request-scoped. Carry the browser client
|
|
1655
|
+
// identity through the Agent so another owner tab cannot accidentally
|
|
1656
|
+
// consume a response for this picker request.
|
|
1657
|
+
if (relayType === 'yeaft_plugin_catalog') rest._requestClientId = clientId;
|
|
1654
1658
|
if (rest.type === 'yeaft_session_send' || rest.type === 'yeaft_session_chat') {
|
|
1655
1659
|
trackUserTurn(client.userId, Buffer.byteLength(JSON.stringify(msg)));
|
|
1656
1660
|
const sessionId = typeof rest.sessionId === 'string' ? rest.sessionId.trim() : '';
|
|
@@ -183,6 +183,33 @@ export async function handleClientMisc(clientId, client, msg, checkAgentAccess)
|
|
|
183
183
|
break;
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
case 'get_yeaft_plugins': {
|
|
187
|
+
const targetAgentId = msg.agentId || client.currentAgent;
|
|
188
|
+
if (!targetAgentId) break;
|
|
189
|
+
if (!await checkAgentAccess(targetAgentId)) break;
|
|
190
|
+
await forwardToAgent(targetAgentId, {
|
|
191
|
+
type: 'get_yeaft_plugins',
|
|
192
|
+
requestId: msg.requestId || null,
|
|
193
|
+
});
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
case 'update_yeaft_plugins': {
|
|
198
|
+
const targetAgentId = msg.agentId || client.currentAgent;
|
|
199
|
+
if (!targetAgentId) break;
|
|
200
|
+
if (!await checkAgentAccess(targetAgentId)) break;
|
|
201
|
+
const hasPlugins = Object.prototype.hasOwnProperty.call(msg, 'plugins');
|
|
202
|
+
const hasConfig = Object.prototype.hasOwnProperty.call(msg, 'config');
|
|
203
|
+
await forwardToAgent(targetAgentId, {
|
|
204
|
+
type: 'update_yeaft_plugins',
|
|
205
|
+
requestId: msg.requestId || null,
|
|
206
|
+
// Preserve explicit falsy values so Agent-side schema validation can
|
|
207
|
+
// reject them. Only an absent payload is the legacy empty selection.
|
|
208
|
+
plugins: hasPlugins ? msg.plugins : (hasConfig ? msg.config : {}),
|
|
209
|
+
});
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
|
|
186
213
|
case 'update_yeaft_settings': {
|
|
187
214
|
const targetAgentId = msg.agentId || client.currentAgent;
|
|
188
215
|
if (!targetAgentId) break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.0.
|
|
1
|
+
{"version":"1.0.410"}
|