@yeaft/webchat-agent 1.0.418 → 1.0.421
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 +5 -1
- package/index.js +1 -1
- package/local-runtime/server/handlers/agent-file-terminal.js +1 -1
- package/local-runtime/server/handlers/client-conversation.js +22 -0
- package/local-runtime/server/handlers/client-misc.js +24 -0
- package/local-runtime/server/handlers/client-workbench.js +3 -1
- package/local-runtime/server/ws-agent.js +12 -2
- package/local-runtime/server/ws-client.js +1 -1
- package/local-runtime/server/ws-utils.js +1 -0
- package/local-runtime/server/yeaft-plugin-capability.js +11 -0
- package/local-runtime/version.json +1 -1
- package/local-runtime/web/app.bundle.js +92 -89
- 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/workbench/file-reference-resolver.js +115 -0
- package/workbench.js +1 -0
- package/yeaft/skills.js +38 -10
|
@@ -12,7 +12,7 @@ import { handleProxyHttpRequest, handleProxyWsOpen, handleProxyWsMessage, handle
|
|
|
12
12
|
import {
|
|
13
13
|
handleReadFile, handleWriteFile, handleListDirectory,
|
|
14
14
|
handleGitStatus, handleGitDiff, handleGitAdd, handleGitReset, handleGitRestore, handleGitCommit, handleGitPush,
|
|
15
|
-
handleFileSearch, handleCreateFile, handleDeleteFiles, handleMoveFiles, handleCopyFiles, handleUploadToDir, handleTransferFiles
|
|
15
|
+
handleFileSearch, handleResolveFileReferences, handleCreateFile, handleDeleteFiles, handleMoveFiles, handleCopyFiles, handleUploadToDir, handleTransferFiles
|
|
16
16
|
} from '../workbench.js';
|
|
17
17
|
import { handleListHistorySessions, handleListFolders, handleListModels } from '../history.js';
|
|
18
18
|
import {
|
|
@@ -288,6 +288,10 @@ export async function handleMessage(msg) {
|
|
|
288
288
|
await handleFileSearch(msg);
|
|
289
289
|
break;
|
|
290
290
|
|
|
291
|
+
case 'resolve_file_references':
|
|
292
|
+
await handleResolveFileReferences(msg);
|
|
293
|
+
break;
|
|
294
|
+
|
|
291
295
|
case 'create_file':
|
|
292
296
|
await handleCreateFile(msg);
|
|
293
297
|
break;
|
package/index.js
CHANGED
|
@@ -161,7 +161,7 @@ async function detectCapabilities() {
|
|
|
161
161
|
// agent build can speak plaintext WS frames. New servers see this and
|
|
162
162
|
// flip `agent.encryptOutbound = false`, stopping outbound encryption
|
|
163
163
|
// to this peer. Old servers ignore the unknown capability token.
|
|
164
|
-
const capabilities = ['background_tasks', 'file_editor', 'ping_session', 'plaintext-ok', 'workbench_session_routes', SAFE_REMOTE_UPGRADE_CAPABILITY, 'work_center', 'work_center_message_v2', 'session_history_search', 'session_history_outline', 'session_history_window_prefetch'];
|
|
164
|
+
const capabilities = ['background_tasks', 'file_editor', 'ping_session', 'plaintext-ok', 'workbench_session_routes', SAFE_REMOTE_UPGRADE_CAPABILITY, 'work_center', 'work_center_message_v2', 'session_history_search', 'session_history_outline', 'session_history_window_prefetch', 'file_reference_resolution', 'yeaft_plugins'];
|
|
165
165
|
if (process.platform === 'linux') capabilities.push('work_item_attachments');
|
|
166
166
|
const pty = await loadNodePty();
|
|
167
167
|
if (pty) capabilities.push('terminal');
|
|
@@ -169,7 +169,7 @@ export async function handleAgentFileTerminal(agentId, agent, rawMsg) {
|
|
|
169
169
|
'terminal_created', 'terminal_output', 'terminal_closed', 'terminal_error',
|
|
170
170
|
]);
|
|
171
171
|
const oneShotTypes = new Set([
|
|
172
|
-
'file_content', 'file_saved', 'directory_listing', 'file_op_result',
|
|
172
|
+
'file_content', 'file_references_resolved', 'file_saved', 'directory_listing', 'file_op_result',
|
|
173
173
|
'git_status_result', 'git_diff_result', 'git_op_result', 'file_search_result',
|
|
174
174
|
]);
|
|
175
175
|
if (!terminalTypes.has(msg.type) && !oneShotTypes.has(msg.type)) return false;
|
|
@@ -27,6 +27,10 @@ import {
|
|
|
27
27
|
chatCatalogKey,
|
|
28
28
|
yeaftCatalogKey,
|
|
29
29
|
} from '../session-catalog.js';
|
|
30
|
+
import {
|
|
31
|
+
agentSupportsYeaftPlugins,
|
|
32
|
+
YEAFT_PLUGINS_UNSUPPORTED_ERROR,
|
|
33
|
+
} from '../yeaft-plugin-capability.js';
|
|
30
34
|
|
|
31
35
|
|
|
32
36
|
function isRetiredCollabSessionId(id) {
|
|
@@ -44,6 +48,14 @@ function emptyYeaftToolStats(reason = '') {
|
|
|
44
48
|
return payload;
|
|
45
49
|
}
|
|
46
50
|
|
|
51
|
+
function emptyYeaftPluginCatalog(error = null) {
|
|
52
|
+
return {
|
|
53
|
+
type: 'yeaft_plugin_catalog_result',
|
|
54
|
+
catalog: { tools: [], skills: [], mcpServers: [] },
|
|
55
|
+
...(error ? { error } : {}),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
47
59
|
async function sendVpSnapshotError(client, msg, error) {
|
|
48
60
|
await sendToWebClient(client, {
|
|
49
61
|
type: 'yeaft_output',
|
|
@@ -420,6 +432,7 @@ export async function handleClientConversation(clientId, client, msg, checkAgent
|
|
|
420
432
|
agentName: agent.name,
|
|
421
433
|
workDir: agent.workDir,
|
|
422
434
|
capabilities: agent.capabilities || ['terminal', 'file_editor', 'background_tasks'],
|
|
435
|
+
...(agent.capabilityMetadataProvided === true ? { capabilityMetadataProvided: true } : {}),
|
|
423
436
|
version: agent.version || null,
|
|
424
437
|
conversations: filteredConvs,
|
|
425
438
|
slashCommands: agent.slashCommands || [],
|
|
@@ -1628,6 +1641,15 @@ export async function handleClientConversation(clientId, client, msg, checkAgent
|
|
|
1628
1641
|
}
|
|
1629
1642
|
return true;
|
|
1630
1643
|
}
|
|
1644
|
+
if (relayType === 'yeaft_plugin_catalog'
|
|
1645
|
+
&& !agentSupportsYeaftPlugins(agents.get(relayAgentId))) {
|
|
1646
|
+
await sendToWebClient(client, {
|
|
1647
|
+
...emptyYeaftPluginCatalog(YEAFT_PLUGINS_UNSUPPORTED_ERROR),
|
|
1648
|
+
agentId: relayAgentId,
|
|
1649
|
+
requestId: msg.requestId || null,
|
|
1650
|
+
});
|
|
1651
|
+
return true;
|
|
1652
|
+
}
|
|
1631
1653
|
const relayAgent = agents.get(relayAgentId);
|
|
1632
1654
|
if (!relayAgent || relayAgent.ws?.readyState !== 1) {
|
|
1633
1655
|
if (relayType === 'yeaft_fetch_tool_stats') {
|
|
@@ -3,11 +3,27 @@ import {
|
|
|
3
3
|
sendToWebClient, forwardToAgent, broadcastAgentList
|
|
4
4
|
} from '../ws-utils.js';
|
|
5
5
|
import { resolveWorkbenchRequest } from '../workbench-route.js';
|
|
6
|
+
import {
|
|
7
|
+
agentSupportsYeaftPlugins,
|
|
8
|
+
YEAFT_PLUGINS_CAPABILITY,
|
|
9
|
+
YEAFT_PLUGINS_UNSUPPORTED_ERROR,
|
|
10
|
+
} from '../yeaft-plugin-capability.js';
|
|
6
11
|
|
|
7
12
|
// Only Agents that explicitly advertise the package-replacement-safe updater
|
|
8
13
|
// may receive remote upgrade commands. Version thresholds are insufficient:
|
|
9
14
|
// builds without this capability may still inherit the installed package cwd.
|
|
10
15
|
export const SAFE_REMOTE_UPGRADE_CAPABILITY = 'remote_upgrade_safe';
|
|
16
|
+
export { YEAFT_PLUGINS_CAPABILITY, YEAFT_PLUGINS_UNSUPPORTED_ERROR };
|
|
17
|
+
|
|
18
|
+
async function rejectUnsupportedYeaftPlugins(client, msg, agentId) {
|
|
19
|
+
await sendToWebClient(client, {
|
|
20
|
+
type: msg.type === 'update_yeaft_plugins' ? 'yeaft_plugins_updated' : 'yeaft_plugins',
|
|
21
|
+
agentId,
|
|
22
|
+
requestId: msg.requestId || null,
|
|
23
|
+
plugins: {},
|
|
24
|
+
error: YEAFT_PLUGINS_UNSUPPORTED_ERROR,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
11
27
|
|
|
12
28
|
export function requiresManualUpgradeBridge(capabilities, platform = null) {
|
|
13
29
|
if (Array.isArray(capabilities) && capabilities.includes(SAFE_REMOTE_UPGRADE_CAPABILITY)) return false;
|
|
@@ -204,6 +220,10 @@ export async function handleClientMisc(clientId, client, msg, checkAgentAccess)
|
|
|
204
220
|
const targetAgentId = msg.agentId || client.currentAgent;
|
|
205
221
|
if (!targetAgentId) break;
|
|
206
222
|
if (!await checkAgentAccess(targetAgentId)) break;
|
|
223
|
+
if (!agentSupportsYeaftPlugins(agents.get(targetAgentId))) {
|
|
224
|
+
await rejectUnsupportedYeaftPlugins(client, msg, targetAgentId);
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
207
227
|
await forwardToAgent(targetAgentId, {
|
|
208
228
|
type: 'get_yeaft_plugins',
|
|
209
229
|
requestId: msg.requestId || null,
|
|
@@ -215,6 +235,10 @@ export async function handleClientMisc(clientId, client, msg, checkAgentAccess)
|
|
|
215
235
|
const targetAgentId = msg.agentId || client.currentAgent;
|
|
216
236
|
if (!targetAgentId) break;
|
|
217
237
|
if (!await checkAgentAccess(targetAgentId)) break;
|
|
238
|
+
if (!agentSupportsYeaftPlugins(agents.get(targetAgentId))) {
|
|
239
|
+
await rejectUnsupportedYeaftPlugins(client, msg, targetAgentId);
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
218
242
|
const hasPlugins = Object.prototype.hasOwnProperty.call(msg, 'plugins');
|
|
219
243
|
const hasConfig = Object.prototype.hasOwnProperty.call(msg, 'config');
|
|
220
244
|
await forwardToAgent(targetAgentId, {
|
|
@@ -40,6 +40,7 @@ async function denyWorkbenchRoute(client, msg) {
|
|
|
40
40
|
const RESPONSE_TYPES = Object.freeze({
|
|
41
41
|
terminal_create: ['terminal_created', 'terminal_error'],
|
|
42
42
|
read_file: ['file_content'],
|
|
43
|
+
resolve_file_references: ['file_references_resolved'],
|
|
43
44
|
write_file: ['file_saved'],
|
|
44
45
|
list_directory: ['directory_listing'],
|
|
45
46
|
git_status: ['git_status_result'],
|
|
@@ -190,6 +191,7 @@ export async function handleClientWorkbench(clientId, client, msg, checkAgentAcc
|
|
|
190
191
|
break;
|
|
191
192
|
}
|
|
192
193
|
|
|
194
|
+
case 'resolve_file_references':
|
|
193
195
|
case 'read_file': {
|
|
194
196
|
const fileAgentId = msg.agentId || client.currentAgent;
|
|
195
197
|
if (!fileAgentId) { console.warn('[Server] read_file: no agentId'); return; }
|
|
@@ -200,7 +202,7 @@ export async function handleClientWorkbench(clientId, client, msg, checkAgentAcc
|
|
|
200
202
|
return;
|
|
201
203
|
}
|
|
202
204
|
const fileConvId = resolved.conversationId || msg.conversationId || client.currentConversation || '_explorer';
|
|
203
|
-
console.log(`[Server] Forwarding
|
|
205
|
+
console.log(`[Server] Forwarding ${msg.type} to agent ${fileAgentId}, conv=${fileConvId}${msg.filePath ? `, path=${msg.filePath}` : ''}`);
|
|
204
206
|
await forwardCorrelatedWorkbenchRequest({
|
|
205
207
|
agentId: fileAgentId,
|
|
206
208
|
clientId,
|
|
@@ -120,7 +120,13 @@ export function handleAgentConnection(ws, url) {
|
|
|
120
120
|
return;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
const
|
|
123
|
+
const authCapabilitiesProvided = Array.isArray(msg.capabilities);
|
|
124
|
+
// Modern Agents always include this query key, including for an
|
|
125
|
+
// explicit empty list. The key's presence is the metadata signal;
|
|
126
|
+
// its value only determines the effective capability list.
|
|
127
|
+
const urlCapabilitiesProvided = url.searchParams.has('capabilities');
|
|
128
|
+
const capabilityMetadataProvided = authCapabilitiesProvided || urlCapabilitiesProvided;
|
|
129
|
+
const capabilities = authCapabilitiesProvided ? msg.capabilities : urlCapabilities;
|
|
124
130
|
const agentVersion = msg.version || null;
|
|
125
131
|
const agentPlatform = typeof msg.platform === 'string' && msg.platform
|
|
126
132
|
? msg.platform
|
|
@@ -152,6 +158,7 @@ export function handleAgentConnection(ws, url) {
|
|
|
152
158
|
pending.workDir,
|
|
153
159
|
authResult.sessionKey,
|
|
154
160
|
capabilities,
|
|
161
|
+
capabilityMetadataProvided,
|
|
155
162
|
ownerId,
|
|
156
163
|
ownerUsername,
|
|
157
164
|
agentVersion,
|
|
@@ -243,7 +250,7 @@ function handleAgentDisconnect(agentId, agentName, ws) {
|
|
|
243
250
|
broadcastAgentList();
|
|
244
251
|
}
|
|
245
252
|
|
|
246
|
-
function completeAgentRegistration(ws, agentId, agentName, workDir, sessionKey, capabilities = [], ownerId = null, ownerUsername = null, agentVersion = null, instanceId = null, agentPlatform = null) {
|
|
253
|
+
function completeAgentRegistration(ws, agentId, agentName, workDir, sessionKey, capabilities = [], capabilityMetadataProvided = false, ownerId = null, ownerUsername = null, agentVersion = null, instanceId = null, agentPlatform = null) {
|
|
247
254
|
// 如果是重连,保留 conversations;否则(server 重启)创建空 Map
|
|
248
255
|
const existingAgent = agents.get(agentId);
|
|
249
256
|
const conversations = existingAgent?.conversations || new Map();
|
|
@@ -274,6 +281,9 @@ function completeAgentRegistration(ws, agentId, agentName, workDir, sessionKey,
|
|
|
274
281
|
isAlive: true,
|
|
275
282
|
lastSeenAt: Date.now(),
|
|
276
283
|
capabilities: effectiveCapabilities,
|
|
284
|
+
// The fallback list supports old UI features but cannot prove that an
|
|
285
|
+
// Agent made an explicit capability claim.
|
|
286
|
+
capabilityMetadataProvided,
|
|
277
287
|
proxyPorts,
|
|
278
288
|
slashCommands,
|
|
279
289
|
slashCommandDescriptions,
|
|
@@ -228,7 +228,7 @@ export function handleWebConnection(ws, url, req = {}) {
|
|
|
228
228
|
const WORKBENCH_TYPES = new Set([
|
|
229
229
|
...CLIENT_BROWSER_TYPES,
|
|
230
230
|
'terminal_create', 'terminal_input', 'terminal_resize', 'terminal_close',
|
|
231
|
-
'read_file', 'write_file', 'create_file', 'delete_files', 'move_files', 'copy_files', 'upload_to_dir', 'file_search',
|
|
231
|
+
'read_file', 'resolve_file_references', 'write_file', 'create_file', 'delete_files', 'move_files', 'copy_files', 'upload_to_dir', 'file_search',
|
|
232
232
|
'git_status', 'git_diff', 'git_add', 'git_reset', 'git_restore', 'git_commit', 'git_push',
|
|
233
233
|
'proxy_update_ports', 'update_file_tabs', 'restore_file_tabs'
|
|
234
234
|
]);
|
|
@@ -169,6 +169,7 @@ export async function broadcastAgentList() {
|
|
|
169
169
|
status: agent.status || 'ready',
|
|
170
170
|
latency: agent.latency || null,
|
|
171
171
|
capabilities: agent.capabilities || ['terminal', 'file_editor', 'background_tasks'],
|
|
172
|
+
...(agent.capabilityMetadataProvided === true ? { capabilityMetadataProvided: true } : {}),
|
|
172
173
|
version: agent.version || null,
|
|
173
174
|
yeaftStatus: agent.yeaftStatus || null,
|
|
174
175
|
proxyPorts: agent.proxyPorts || [],
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Plugin protocol support is omission-compatible: old Agents that never
|
|
2
|
+
// advertised capability metadata keep the legacy relay path. Once an Agent
|
|
3
|
+
// explicitly provides metadata, omitting this token is an explicit refusal.
|
|
4
|
+
export const YEAFT_PLUGINS_CAPABILITY = 'yeaft_plugins';
|
|
5
|
+
export const YEAFT_PLUGINS_UNSUPPORTED_ERROR = 'The selected Agent does not support Plugins; upgrade and restart the Agent';
|
|
6
|
+
|
|
7
|
+
export function agentSupportsYeaftPlugins(agent) {
|
|
8
|
+
if (agent?.capabilityMetadataProvided !== true) return true;
|
|
9
|
+
return Array.isArray(agent.capabilities)
|
|
10
|
+
&& agent.capabilities.includes(YEAFT_PLUGINS_CAPABILITY);
|
|
11
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.0.
|
|
1
|
+
{"version":"1.0.421"}
|