web-agent-bridge 2.3.1 → 2.5.0

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.
Files changed (53) hide show
  1. package/README.ar.md +524 -31
  2. package/README.md +592 -47
  3. package/bin/agent-runner.js +10 -1
  4. package/package.json +1 -1
  5. package/public/agent-workspace.html +347 -0
  6. package/public/browser.html +484 -0
  7. package/public/css/agent-workspace.css +1713 -0
  8. package/public/index.html +94 -0
  9. package/public/js/agent-workspace.js +1740 -0
  10. package/sdk/index.d.ts +253 -0
  11. package/sdk/index.js +360 -1
  12. package/sdk/package.json +1 -1
  13. package/server/config/secrets.js +13 -5
  14. package/server/control-plane/index.js +301 -0
  15. package/server/data-plane/index.js +354 -0
  16. package/server/index.js +185 -4
  17. package/server/llm/index.js +404 -0
  18. package/server/middleware/adminAuth.js +6 -1
  19. package/server/middleware/auth.js +11 -2
  20. package/server/middleware/rateLimits.js +78 -2
  21. package/server/migrations/003_ads_integer_cents.sql +33 -0
  22. package/server/models/db.js +126 -25
  23. package/server/observability/index.js +394 -0
  24. package/server/protocol/capabilities.js +223 -0
  25. package/server/protocol/index.js +243 -0
  26. package/server/protocol/schema.js +584 -0
  27. package/server/registry/index.js +326 -0
  28. package/server/routes/admin.js +16 -2
  29. package/server/routes/ads.js +130 -0
  30. package/server/routes/agent-workspace.js +378 -0
  31. package/server/routes/api.js +21 -2
  32. package/server/routes/auth.js +26 -6
  33. package/server/routes/runtime.js +725 -0
  34. package/server/routes/sovereign.js +78 -0
  35. package/server/routes/universal.js +177 -0
  36. package/server/routes/wab-api.js +20 -5
  37. package/server/runtime/event-bus.js +210 -0
  38. package/server/runtime/index.js +233 -0
  39. package/server/runtime/sandbox.js +266 -0
  40. package/server/runtime/scheduler.js +395 -0
  41. package/server/runtime/state-manager.js +188 -0
  42. package/server/security/index.js +355 -0
  43. package/server/services/agent-chat.js +506 -0
  44. package/server/services/agent-symphony.js +6 -0
  45. package/server/services/agent-tasks.js +1807 -0
  46. package/server/services/fairness-engine.js +409 -0
  47. package/server/services/plugins.js +27 -3
  48. package/server/services/price-intelligence.js +565 -0
  49. package/server/services/price-shield.js +1137 -0
  50. package/server/services/search-engine.js +357 -0
  51. package/server/services/security.js +513 -0
  52. package/server/services/universal-scraper.js +661 -0
  53. package/server/ws.js +61 -1
@@ -0,0 +1,243 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * WAB Protocol (WABP) - Entry Point
5
+ *
6
+ * The WAB Protocol defines how agents communicate with sites, runtimes,
7
+ * and each other. It is the foundation of the Agent OS.
8
+ *
9
+ * Protocol message envelope:
10
+ * {
11
+ * protocol: 'wabp',
12
+ * version: '1.0.0',
13
+ * id: '<unique-message-id>',
14
+ * type: 'request' | 'response' | 'event' | 'error',
15
+ * command: '<command-name>',
16
+ * agentId: '<agent-id>',
17
+ * traceId: '<trace-id>',
18
+ * spanId: '<span-id>',
19
+ * timestamp: <epoch-ms>,
20
+ * payload: { ... },
21
+ * signature: '<ed25519-signature>' // optional, for signed commands
22
+ * }
23
+ */
24
+
25
+ const crypto = require('crypto');
26
+ const schema = require('./schema');
27
+ const { CapabilityNegotiator } = require('./capabilities');
28
+
29
+ const PROTOCOL_NAME = 'wabp';
30
+ const PROTOCOL_VERSION = schema.PROTOCOL_VERSION;
31
+
32
+ const negotiator = new CapabilityNegotiator();
33
+
34
+ // ─── Message Factory ────────────────────────────────────────────────────────
35
+
36
+ function createMessage(type, command, payload, options = {}) {
37
+ return {
38
+ protocol: PROTOCOL_NAME,
39
+ version: PROTOCOL_VERSION,
40
+ id: `msg_${crypto.randomBytes(16).toString('hex')}`,
41
+ type,
42
+ command,
43
+ agentId: options.agentId || null,
44
+ traceId: options.traceId || `trace_${crypto.randomBytes(16).toString('hex')}`,
45
+ spanId: options.spanId || `span_${crypto.randomBytes(8).toString('hex')}`,
46
+ timestamp: Date.now(),
47
+ payload,
48
+ signature: options.signature || null,
49
+ };
50
+ }
51
+
52
+ function createRequest(command, payload, options) {
53
+ return createMessage('request', command, payload, options);
54
+ }
55
+
56
+ function createResponse(requestId, command, payload, options = {}) {
57
+ const msg = createMessage('response', command, payload, options);
58
+ msg.requestId = requestId;
59
+ return msg;
60
+ }
61
+
62
+ function createError(requestId, command, code, message, options = {}) {
63
+ return createResponse(requestId, command, {
64
+ error: { code, message, timestamp: Date.now() },
65
+ }, options);
66
+ }
67
+
68
+ function createEvent(eventName, payload, options) {
69
+ return createMessage('event', eventName, payload, options);
70
+ }
71
+
72
+ // ─── Message Validation ─────────────────────────────────────────────────────
73
+
74
+ function validateMessage(msg) {
75
+ const errors = [];
76
+ if (!msg || typeof msg !== 'object') return { valid: false, errors: ['Message must be an object'] };
77
+ if (msg.protocol !== PROTOCOL_NAME) errors.push(`Invalid protocol: expected ${PROTOCOL_NAME}`);
78
+ if (!msg.id) errors.push('Missing message id');
79
+ if (!['request', 'response', 'event', 'error'].includes(msg.type)) errors.push('Invalid message type');
80
+ if (!msg.command) errors.push('Missing command');
81
+ if (!msg.timestamp || typeof msg.timestamp !== 'number') errors.push('Invalid timestamp');
82
+
83
+ // Validate command input for requests
84
+ if (msg.type === 'request' && msg.payload) {
85
+ const cmdValidation = schema.validateInput(msg.command, msg.payload);
86
+ if (!cmdValidation.valid) {
87
+ errors.push(...cmdValidation.errors.map(e => `${e.path}: ${e.message}`));
88
+ }
89
+ }
90
+
91
+ return { valid: errors.length === 0, errors };
92
+ }
93
+
94
+ // ─── Protocol Handler ───────────────────────────────────────────────────────
95
+
96
+ class ProtocolHandler {
97
+ constructor() {
98
+ this._handlers = new Map(); // command → handler function
99
+ this._middleware = []; // pre-processing middleware
100
+ this._eventListeners = new Map(); // event → listeners
101
+ }
102
+
103
+ /**
104
+ * Register a command handler
105
+ */
106
+ handle(command, handler) {
107
+ this._handlers.set(command, handler);
108
+ }
109
+
110
+ /**
111
+ * Add middleware to the processing pipeline
112
+ */
113
+ use(middleware) {
114
+ this._middleware.push(middleware);
115
+ }
116
+
117
+ /**
118
+ * Subscribe to protocol events
119
+ */
120
+ on(event, listener) {
121
+ if (!this._eventListeners.has(event)) this._eventListeners.set(event, []);
122
+ this._eventListeners.get(event).push(listener);
123
+ }
124
+
125
+ /**
126
+ * Process an incoming protocol message
127
+ */
128
+ async process(msg) {
129
+ // Validate
130
+ const validation = validateMessage(msg);
131
+ if (!validation.valid) {
132
+ return createError(msg.id, msg.command, 'INVALID_MESSAGE', validation.errors.join('; '));
133
+ }
134
+
135
+ // Check command exists
136
+ const cmdDef = schema.getCommand(msg.command);
137
+ if (!cmdDef) {
138
+ return createError(msg.id, msg.command, 'UNKNOWN_COMMAND', `Command not found: ${msg.command}`);
139
+ }
140
+
141
+ // Run middleware
142
+ let context = { message: msg, command: cmdDef, metadata: {} };
143
+ for (const mw of this._middleware) {
144
+ try {
145
+ const result = await mw(context);
146
+ if (result === false) {
147
+ return createError(msg.id, msg.command, 'MIDDLEWARE_REJECTED', 'Request rejected by middleware');
148
+ }
149
+ if (result && typeof result === 'object') context = { ...context, ...result };
150
+ } catch (err) {
151
+ return createError(msg.id, msg.command, 'MIDDLEWARE_ERROR', err.message);
152
+ }
153
+ }
154
+
155
+ // Check capability if agent
156
+ if (msg.agentId && cmdDef.capabilities.length > 0) {
157
+ for (const cap of cmdDef.capabilities) {
158
+ if (!negotiator.check(msg.agentId, cap)) {
159
+ return createError(msg.id, msg.command, 'CAPABILITY_DENIED',
160
+ `Agent ${msg.agentId} lacks capability: ${cap}`);
161
+ }
162
+ }
163
+ // Use capabilities
164
+ for (const cap of cmdDef.capabilities) {
165
+ negotiator.use(msg.agentId, cap);
166
+ }
167
+ }
168
+
169
+ // Execute handler
170
+ const handler = this._handlers.get(msg.command);
171
+ if (!handler) {
172
+ return createError(msg.id, msg.command, 'NO_HANDLER', `No handler for: ${msg.command}`);
173
+ }
174
+
175
+ try {
176
+ const timeoutMs = msg.payload?.timeout || cmdDef.timeout;
177
+ const result = await _withTimeout(handler(msg.payload, context), timeoutMs);
178
+ const response = createResponse(msg.id, msg.command, result, {
179
+ agentId: msg.agentId,
180
+ traceId: msg.traceId,
181
+ });
182
+
183
+ // Emit event
184
+ _emit(this._eventListeners, 'command:complete', {
185
+ command: msg.command,
186
+ agentId: msg.agentId,
187
+ traceId: msg.traceId,
188
+ duration: Date.now() - msg.timestamp,
189
+ });
190
+
191
+ return response;
192
+ } catch (err) {
193
+ _emit(this._eventListeners, 'command:error', {
194
+ command: msg.command,
195
+ agentId: msg.agentId,
196
+ traceId: msg.traceId,
197
+ error: err.message,
198
+ });
199
+ return createError(msg.id, msg.command, 'EXECUTION_ERROR', err.message, {
200
+ traceId: msg.traceId,
201
+ });
202
+ }
203
+ }
204
+ }
205
+
206
+ // ─── Helpers ────────────────────────────────────────────────────────────────
207
+
208
+ function _withTimeout(promise, ms) {
209
+ if (!ms || ms <= 0) return promise;
210
+ return new Promise((resolve, reject) => {
211
+ const timer = setTimeout(() => reject(new Error(`Command timed out after ${ms}ms`)), ms);
212
+ promise.then(result => { clearTimeout(timer); resolve(result); })
213
+ .catch(err => { clearTimeout(timer); reject(err); });
214
+ });
215
+ }
216
+
217
+ function _emit(listeners, event, data) {
218
+ const fns = listeners.get(event);
219
+ if (!fns) return;
220
+ for (const fn of fns) {
221
+ try { fn(data); } catch (_) { /* ignore listener errors */ }
222
+ }
223
+ }
224
+
225
+ // ─── Cleanup interval ──────────────────────────────────────────────────────
226
+
227
+ const _cleanupInterval = setInterval(() => negotiator.cleanup(), 300_000);
228
+ if (_cleanupInterval.unref) _cleanupInterval.unref();
229
+
230
+ module.exports = {
231
+ PROTOCOL_NAME,
232
+ PROTOCOL_VERSION,
233
+ schema,
234
+ negotiator,
235
+ createMessage,
236
+ createRequest,
237
+ createResponse,
238
+ createError,
239
+ createEvent,
240
+ validateMessage,
241
+ ProtocolHandler,
242
+ CapabilityNegotiator: require('./capabilities').CapabilityNegotiator,
243
+ };