@yeaft/webchat-agent 1.0.417 → 1.0.418

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.
@@ -74,6 +74,20 @@ export async function handleAgentSync(agentId, agent, msg) {
74
74
  break;
75
75
  }
76
76
 
77
+ case 'agent_capabilities_updated': {
78
+ const capabilities = Array.isArray(msg.capabilities)
79
+ ? [...new Set(msg.capabilities.filter(value => (
80
+ typeof value === 'string' && value.length > 0 && value.length <= 128
81
+ )).slice(0, 128))]
82
+ : null;
83
+ if (!capabilities || capabilities.length === 0) break;
84
+ agent.capabilities = capabilities;
85
+ // Transport encryption negotiation is connection-scoped and immutable.
86
+ // A runtime capability refresh must never flip framing mid-connection.
87
+ await broadcastAgentList();
88
+ break;
89
+ }
90
+
77
91
  case 'agent_metrics': {
78
92
  agent.metrics = normalizeAgentMetrics(msg.metrics || {});
79
93
  agent.metricsUpdatedAt = Date.now();
@@ -15,6 +15,9 @@ import {
15
15
  } from '../browser-runtime-routes.js';
16
16
 
17
17
  const CLIENT_BROWSER_TYPES = new Set([
18
+ 'browser_runtime_status',
19
+ 'browser_runtime_install',
20
+ 'browser_runtime_enable',
18
21
  'browser_session_create',
19
22
  'browser_session_get',
20
23
  'browser_session_list',
@@ -34,8 +37,11 @@ function digest(value) {
34
37
  }
35
38
 
36
39
  async function fail(client, msg, code, safeError = code) {
40
+ const type = String(msg.type || '');
37
41
  await sendToWebClient(client, {
38
- type: String(msg.type || '').startsWith('browser_peer_') ? 'browser_peer_error' : 'browser_session_error',
42
+ type: type.startsWith('browser_peer_') ? 'browser_peer_error'
43
+ : type.startsWith('browser_runtime_') ? 'browser_runtime_error'
44
+ : 'browser_session_error',
39
45
  requestId: clean(msg.requestId) || null,
40
46
  browserSessionId: clean(msg.browserSessionId) || null,
41
47
  peerId: clean(msg.peerId) || null,
@@ -46,6 +52,10 @@ async function fail(client, msg, code, safeError = code) {
46
52
  return true;
47
53
  }
48
54
 
55
+ function agentSupportsBrowserSetup(agent) {
56
+ return new Set(agent?.capabilities || []).has('browser_runtime_setup');
57
+ }
58
+
49
59
  function agentSupportsBrowser(agent) {
50
60
  const capabilities = new Set(agent?.capabilities || []);
51
61
  return capabilities.has('browser_runtime')
@@ -98,17 +108,54 @@ function ownerRoute(client, msg) {
98
108
  export async function handleClientBrowser(client, msg, checkAgentAccess) {
99
109
  if (!CLIENT_BROWSER_TYPES.has(msg?.type)) return false;
100
110
  if (!CONFIG.browserRuntime.enabled) return fail(client, msg, 'browser_runtime_disabled');
101
- if (client.browserRuntimeProtocol !== 1) return fail(client, msg, 'browser_protocol_required');
111
+ const setupRequest = String(msg.type || '').startsWith('browser_runtime_');
112
+ if (setupRequest) {
113
+ if (client.browserRuntimeSetupProtocol !== 1) {
114
+ return fail(client, msg, 'browser_setup_protocol_required');
115
+ }
116
+ } else if (client.browserRuntimeProtocol !== 1) {
117
+ return fail(client, msg, 'browser_protocol_required');
118
+ }
102
119
  const agentId = clean(msg.agentId);
103
120
  if (!await checkAgentAccess(agentId)) return true;
104
121
  const agent = agents.get(agentId);
105
- if (!agentSupportsBrowser(agent)) return fail(client, msg, 'browser_runtime_unavailable');
122
+ if (setupRequest ? !agentSupportsBrowserSetup(agent) : !agentSupportsBrowser(agent)) {
123
+ return fail(client, msg, 'browser_runtime_unavailable');
124
+ }
106
125
  const requestId = clean(msg.requestId);
107
126
  const requestRequired = msg.type !== 'browser_peer_answer'
108
127
  && msg.type !== 'browser_peer_ice_candidate';
109
128
  if (requestRequired && !requestId) return fail(client, msg, 'browser_request_id_required');
110
129
  const identity = browserServerIdentity(client);
111
130
 
131
+ if (setupRequest) {
132
+ const canonical = msg.type === 'browser_runtime_install' ? {
133
+ confirmedBuildId: clean(msg.confirmedBuildId, 128),
134
+ confirmedDownloadBytes: Number(msg.confirmedDownloadBytes) || 0,
135
+ } : {};
136
+ const registration = registerBrowserCreateRequest({
137
+ agentId,
138
+ client,
139
+ requestId,
140
+ digest: digest({ type: msg.type, ...canonical }),
141
+ kind: msg.type,
142
+ });
143
+ if (registration.conflict) return fail(client, msg, 'browser_request_conflict');
144
+ if (registration.capacity) return fail(client, msg, 'browser_request_capacity');
145
+ if (registration.duplicate) {
146
+ if (registration.request.response) await sendToWebClient(client, registration.request.response);
147
+ return true;
148
+ }
149
+ await sendToAgent(agent, {
150
+ type: msg.type,
151
+ agentId,
152
+ requestId: registration.request.serverRequestId,
153
+ ...canonical,
154
+ serverIdentity: identity,
155
+ });
156
+ return true;
157
+ }
158
+
112
159
  if (msg.type === 'browser_session_create') {
113
160
  const canonical = canonicalCreate(msg);
114
161
  if (!canonical) return fail(client, msg, 'browser_url_invalid');
@@ -352,6 +352,7 @@ async function handleAgentMessage(agentId, msg, ws) {
352
352
  'file_content', 'file_saved', 'file_op_result', 'file_search_result',
353
353
  'git_status_result', 'git_diff_result', 'git_op_result',
354
354
  'terminal_created', 'terminal_output', 'terminal_closed', 'terminal_error',
355
+ 'agent_capabilities_updated', 'browser_runtime_status_result', 'browser_runtime_install_progress', 'browser_runtime_error',
355
356
  'browser_session_created', 'browser_session_error', 'browser_session_snapshot', 'browser_session_list_result',
356
357
  'browser_peer_prepared', 'browser_peer_offer', 'browser_peer_ice_candidate', 'browser_peer_state', 'browser_peer_error'
357
358
  ]);
@@ -6,7 +6,12 @@ import { authenticateRequest } from './auth/request-auth.js';
6
6
  import { encodeKey } from './encryption.js';
7
7
  import { userDb } from './database.js';
8
8
  import { agents, clearYeaftDebugRequestsForClient, webClients, isHeartbeatMessageType, trackRequest } from './context.js';
9
- import { applyClientHello, BROWSER_RUNTIME_PROTOCOL, WORKBENCH_ROUTE_PROTOCOL } from './client-protocol.js';
9
+ import {
10
+ applyClientHello,
11
+ BROWSER_RUNTIME_PROTOCOL,
12
+ BROWSER_RUNTIME_SETUP_PROTOCOL,
13
+ WORKBENCH_ROUTE_PROTOCOL,
14
+ } from './client-protocol.js';
10
15
  import { clearWorkbenchCorrelationsForClient } from './workbench-correlation.js';
11
16
  import { clearBrowserRuntimeForClient } from './browser-runtime-routes.js';
12
17
  import {
@@ -88,6 +93,7 @@ export function handleWebConnection(ws, url, req = {}) {
88
93
  // Explicit protocols have no omission-based downgrade for security fields.
89
94
  workbenchRouteProtocol: 0,
90
95
  browserRuntimeProtocol: 0,
96
+ browserRuntimeSetupProtocol: 0,
91
97
  });
92
98
 
93
99
  // 心跳响应处理
@@ -116,6 +122,7 @@ export function handleWebConnection(ws, url, req = {}) {
116
122
  yeaftSessionInventoryComplete: true,
117
123
  workbenchRouteProtocol: WORKBENCH_ROUTE_PROTOCOL,
118
124
  browserRuntimeProtocol: BROWSER_RUNTIME_PROTOCOL,
125
+ browserRuntimeSetupProtocol: BROWSER_RUNTIME_SETUP_PROTOCOL,
119
126
  browserRuntimeEnabled: CONFIG.browserRuntime.enabled,
120
127
  }));
121
128
  setTimeout(() => broadcastAgentList(), 100);
@@ -249,6 +256,7 @@ async function handleWebMessage(clientId, msg) {
249
256
  type: 'client_hello_ack',
250
257
  workbenchRouteProtocol: client.workbenchRouteProtocol,
251
258
  browserRuntimeProtocol: client.browserRuntimeProtocol,
259
+ browserRuntimeSetupProtocol: client.browserRuntimeSetupProtocol,
252
260
  browserRuntimeEnabled: CONFIG.browserRuntime.enabled,
253
261
  });
254
262
  return;
@@ -1 +1 @@
1
- {"version":"1.0.417"}
1
+ {"version":"1.0.418"}