web-agent-bridge 3.4.0 → 3.8.1
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/LICENSE +84 -84
- package/README.ar.md +1563 -1304
- package/README.md +137 -298
- package/bin/agent-runner.js +474 -474
- package/bin/cli.js +237 -237
- package/bin/wab-init.js +244 -223
- package/bin/wab.js +80 -80
- package/examples/azure-dns-wab.js +83 -83
- package/examples/bidi-agent.js +119 -119
- package/examples/cloudflare-wab-dns.js +121 -121
- package/examples/cpanel-wab-dns.js +114 -114
- package/examples/cross-site-agent.js +91 -91
- package/examples/dns-discovery-agent.js +166 -166
- package/examples/gcp-dns-wab.js +76 -76
- package/examples/governance-agent.js +169 -169
- package/examples/mcp-agent.js +94 -94
- package/examples/next-app-router/README.md +44 -44
- package/examples/plesk-wab-dns.js +103 -103
- package/examples/puppeteer-agent.js +108 -108
- package/examples/route53-wab-dns.js +144 -144
- package/examples/saas-dashboard/README.md +55 -55
- package/examples/safe-mode-agent.js +96 -96
- package/examples/self-discovery.js +106 -0
- package/examples/shopify-hydrogen/README.md +74 -74
- package/examples/vision-agent.js +171 -171
- package/examples/wab-sign.js +74 -74
- package/examples/wab-verify.js +60 -60
- package/examples/wordpress-elementor/README.md +77 -77
- package/package.json +93 -93
- package/public/.well-known/agent-tools.json +180 -180
- package/public/.well-known/ai-assets.json +59 -59
- package/public/.well-known/security.txt +8 -8
- package/public/.well-known/wab.json +28 -28
- package/public/activate.html +448 -368
- package/public/adopt.html +236 -0
- package/public/adoption-metrics.html +188 -188
- package/public/agent-workspace.html +359 -349
- package/public/ai.html +198 -198
- package/public/api.html +397 -413
- package/public/azure-dns-integration.html +289 -289
- package/public/browser.html +486 -486
- package/public/cloudflare-integration.html +380 -380
- package/public/commander-dashboard.html +243 -243
- package/public/cookies.html +210 -210
- package/public/cpanel-integration.html +398 -398
- package/public/css/agent-workspace.css +1713 -1713
- package/public/css/premium.css +317 -317
- package/public/css/styles.css +1401 -1263
- package/public/dashboard-shieldlink.html +295 -0
- package/public/dashboard.html +711 -707
- package/public/dns.html +436 -436
- package/public/docs.html +588 -588
- package/public/enterprise-mesh.ar.html +80 -0
- package/public/enterprise-mesh.html +81 -0
- package/public/feed.xml +89 -89
- package/public/gcp-dns-integration.html +318 -318
- package/public/governance.ar.html +70 -0
- package/public/governance.html +69 -0
- package/public/growth.html +465 -465
- package/public/index.html +1372 -1266
- package/public/integrations.html +556 -556
- package/public/js/activate.js +449 -145
- package/public/js/agent-workspace.js +1740 -1740
- package/public/js/auth-nav.js +117 -65
- package/public/js/auth-redirect.js +12 -12
- package/public/js/cookie-consent.js +56 -56
- package/public/js/dns.js +438 -438
- package/public/js/wab-demo-page.js +721 -721
- package/public/js/ws-client.js +74 -74
- package/public/l-preview.html +242 -0
- package/public/llms-full.txt +360 -360
- package/public/llms.txt +125 -125
- package/public/login.html +85 -85
- package/public/mesh-dashboard.html +328 -328
- package/public/milestones.html +346 -0
- package/public/one-click.html +779 -0
- package/public/openapi.json +669 -669
- package/public/partners.ar.html +145 -0
- package/public/partners.html +143 -0
- package/public/phone-shield.html +281 -281
- package/public/plesk-integration.html +375 -375
- package/public/premium-dashboard.html +2489 -2489
- package/public/premium.html +793 -793
- package/public/privacy.html +297 -297
- package/public/provider-onboarding.html +172 -172
- package/public/provider-sandbox.html +134 -134
- package/public/providers.html +359 -359
- package/public/refusals.html +172 -0
- package/public/register.html +105 -105
- package/public/registrar-integrations.html +141 -141
- package/public/ring4.html +292 -0
- package/public/robots.txt +99 -99
- package/public/route53-integration.html +531 -531
- package/public/score.html +263 -0
- package/public/script/wab-consent.d.ts +36 -36
- package/public/script/wab-consent.js +104 -104
- package/public/script/wab-schema.js +131 -131
- package/public/script/wab.d.ts +108 -108
- package/public/script/wab.min.js +580 -580
- package/public/security.txt +8 -8
- package/public/shieldlink.html +244 -0
- package/public/shieldqr.html +231 -231
- package/public/sitemap.xml +13 -1
- package/public/terms.html +256 -256
- package/public/trust-graph-api.ar.html +92 -0
- package/public/trust-graph-api.html +91 -0
- package/public/wab-features.html +560 -0
- package/public/wab-trust.html +200 -200
- package/public/wab-truth.html +375 -0
- package/public/wab-vs-protocols.html +210 -210
- package/public/whitepaper.html +449 -449
- package/script/ai-agent-bridge.js +1754 -1754
- package/sdk/README.md +99 -99
- package/sdk/agent-mesh.js +449 -449
- package/sdk/auto-discovery.js +301 -288
- package/sdk/commander.js +262 -262
- package/sdk/governance.js +262 -262
- package/sdk/index.d.ts +464 -464
- package/sdk/index.js +649 -649
- package/sdk/multi-agent.js +318 -318
- package/sdk/safe-mode.js +221 -221
- package/sdk/safety-shield.js +219 -219
- package/sdk/schema-discovery.js +83 -83
- package/server/adapters/index.js +520 -520
- package/server/config/plans.js +412 -367
- package/server/config/secrets.js +102 -102
- package/server/control-plane/index.js +301 -301
- package/server/data-plane/index.js +354 -354
- package/server/index.js +790 -670
- package/server/llm/index.js +404 -404
- package/server/middleware/adminAuth.js +35 -35
- package/server/middleware/api-tier.js +170 -0
- package/server/middleware/auth.js +50 -50
- package/server/middleware/featureGate.js +88 -88
- package/server/middleware/rateLimits.js +100 -100
- package/server/middleware/sensitiveAction.js +157 -157
- package/server/middleware/wab-trust.js +141 -0
- package/server/migrations/001_add_analytics_indexes.sql +7 -7
- package/server/migrations/002_premium_features.sql +418 -418
- package/server/migrations/003_ads_integer_cents.sql +33 -33
- package/server/migrations/004_agent_os.sql +158 -158
- package/server/migrations/005_marketplace_metering.sql +126 -126
- package/server/migrations/006_growth_suite.sql +138 -0
- package/server/migrations/007_governance.sql +106 -106
- package/server/migrations/008_plans.sql +144 -144
- package/server/migrations/009_shieldqr.sql +30 -30
- package/server/migrations/010_extended_trust.sql +33 -33
- package/server/migrations/011_outreach.sql +47 -0
- package/server/migrations/012_shieldlink.sql +116 -0
- package/server/migrations/013_ct_monitor.sql +13 -0
- package/server/migrations/014_wab_advanced_features.sql +128 -0
- package/server/migrations/015_wab_truth_layer.sql +101 -0
- package/server/migrations/016_ring4_external_trust.sql +84 -0
- package/server/migrations/017_ring4_extensions.sql +69 -0
- package/server/migrations/018_commercial_foundations.sql +167 -0
- package/server/migrations/019_unify_tier_constraints.sql +133 -0
- package/server/models/adapters/index.js +33 -33
- package/server/models/adapters/mysql.js +183 -183
- package/server/models/adapters/postgresql.js +172 -172
- package/server/models/adapters/sqlite.js +7 -7
- package/server/models/db.js +740 -740
- package/server/observability/failure-analysis.js +337 -337
- package/server/observability/index.js +394 -394
- package/server/protocol/capabilities.js +223 -223
- package/server/protocol/index.js +243 -243
- package/server/protocol/schema.js +584 -584
- package/server/registry/certification.js +271 -271
- package/server/registry/index.js +326 -326
- package/server/routes/activate.js +478 -0
- package/server/routes/admin-outreach.js +239 -0
- package/server/routes/admin-plans.js +76 -76
- package/server/routes/admin-premium.js +674 -673
- package/server/routes/admin-shieldlink.js +137 -0
- package/server/routes/admin-shieldqr.js +90 -90
- package/server/routes/admin-trust-monitor.js +139 -83
- package/server/routes/admin.js +550 -549
- package/server/routes/adopt.js +61 -0
- package/server/routes/ads.js +130 -130
- package/server/routes/agent-workspace.js +540 -540
- package/server/routes/api-keys.js +127 -0
- package/server/routes/api.js +150 -150
- package/server/routes/auth.js +71 -71
- package/server/routes/billing.js +57 -57
- package/server/routes/commander.js +316 -316
- package/server/routes/customer-shieldlink.js +133 -0
- package/server/routes/demo-showcase.js +332 -332
- package/server/routes/demo-store.js +154 -154
- package/server/routes/diagnose.js +373 -0
- package/server/routes/discovery.js +2348 -2348
- package/server/routes/enterprise-mesh.js +170 -0
- package/server/routes/gateway.js +173 -173
- package/server/routes/governance-saas.js +203 -0
- package/server/routes/governance.js +208 -208
- package/server/routes/growth.js +1048 -0
- package/server/routes/intent.js +328 -0
- package/server/routes/license.js +251 -251
- package/server/routes/mesh.js +469 -469
- package/server/routes/noscript.js +543 -543
- package/server/routes/partners.js +201 -0
- package/server/routes/plans.js +33 -33
- package/server/routes/premium-v2.js +686 -686
- package/server/routes/premium.js +724 -724
- package/server/routes/providers.js +650 -650
- package/server/routes/reputation.js +411 -0
- package/server/routes/ring4.js +885 -0
- package/server/routes/runtime.js +2148 -2148
- package/server/routes/shieldlink.js +70 -0
- package/server/routes/shieldqr.js +88 -88
- package/server/routes/sovereign.js +465 -465
- package/server/routes/truth-layer.js +670 -0
- package/server/routes/universal.js +200 -200
- package/server/routes/unsubscribe.js +51 -0
- package/server/routes/wab-api.js +850 -850
- package/server/routes/wab-cache.js +282 -0
- package/server/runtime/container-worker.js +111 -111
- package/server/runtime/container.js +448 -448
- package/server/runtime/distributed-worker.js +362 -362
- package/server/runtime/event-bus.js +210 -210
- package/server/runtime/index.js +253 -253
- package/server/runtime/queue.js +599 -599
- package/server/runtime/replay.js +666 -666
- package/server/runtime/sandbox.js +266 -266
- package/server/runtime/scheduler.js +534 -534
- package/server/runtime/session-engine.js +293 -293
- package/server/runtime/state-manager.js +188 -188
- package/server/secrets/wab-signing-key.pem +3 -0
- package/server/secrets/wab-signing-pub.pem +3 -0
- package/server/security/cross-site-redactor.js +196 -196
- package/server/security/dry-run.js +180 -180
- package/server/security/human-gate-rate-limit.js +147 -147
- package/server/security/human-gate-transports.js +178 -178
- package/server/security/human-gate.js +281 -281
- package/server/security/index.js +368 -368
- package/server/security/intent-engine.js +245 -245
- package/server/security/reward-guard.js +171 -171
- package/server/security/rollback-store.js +239 -239
- package/server/security/token-scope.js +404 -404
- package/server/security/url-policy.js +139 -139
- package/server/services/adoption-agent.js +182 -0
- package/server/services/agent-chat.js +506 -506
- package/server/services/agent-learning.js +601 -601
- package/server/services/agent-memory.js +625 -625
- package/server/services/agent-mesh.js +555 -555
- package/server/services/agent-symphony.js +717 -717
- package/server/services/agent-tasks.js +1807 -1807
- package/server/services/api-key-engine.js +292 -292
- package/server/services/cluster.js +894 -894
- package/server/services/commander.js +738 -738
- package/server/services/edge-compute.js +440 -440
- package/server/services/email.js +233 -233
- package/server/services/fairness-engine.js +409 -0
- package/server/services/fairness.js +420 -0
- package/server/services/governance.js +466 -466
- package/server/services/hosted-runtime.js +205 -205
- package/server/services/lfd.js +635 -635
- package/server/services/local-ai.js +389 -389
- package/server/services/marketplace.js +270 -270
- package/server/services/metering.js +182 -182
- package/server/services/modules/affiliate-intelligence.js +93 -93
- package/server/services/modules/agent-firewall.js +90 -90
- package/server/services/modules/bounty.js +89 -89
- package/server/services/modules/collective-bargaining.js +92 -92
- package/server/services/modules/dark-pattern.js +66 -66
- package/server/services/modules/gov-intelligence.js +45 -45
- package/server/services/modules/neural.js +55 -55
- package/server/services/modules/notary.js +49 -49
- package/server/services/modules/price-time-machine.js +86 -86
- package/server/services/modules/protocol.js +104 -104
- package/server/services/negotiation.js +439 -439
- package/server/services/outreach-agent.js +312 -0
- package/server/services/plans.js +214 -214
- package/server/services/plugins.js +771 -771
- package/server/services/price-intelligence.js +566 -566
- package/server/services/price-shield.js +1137 -1137
- package/server/services/provider-clients.js +740 -740
- package/server/services/reputation.js +465 -465
- package/server/services/search-engine.js +357 -357
- package/server/services/security.js +513 -513
- package/server/services/self-healing.js +843 -843
- package/server/services/shieldlink.js +492 -0
- package/server/services/shieldqr.js +322 -322
- package/server/services/sovereign-shield.js +542 -542
- package/server/services/ssl-ct-monitor.js +224 -0
- package/server/services/ssl-inspector.js +42 -42
- package/server/services/ssl-monitor.js +167 -167
- package/server/services/stripe.js +206 -205
- package/server/services/swarm.js +788 -788
- package/server/services/universal-scraper.js +662 -662
- package/server/services/verification.js +481 -481
- package/server/services/vision.js +1163 -1163
- package/server/services/wab-crypto.js +178 -178
- package/server/utils/cache.js +125 -125
- package/server/utils/migrate.js +81 -81
- package/server/utils/safe-fetch.js +228 -228
- package/server/utils/secureFields.js +50 -50
- package/server/ws.js +161 -161
- package/templates/artisan-marketplace.yaml +104 -104
- package/templates/book-price-scout.yaml +98 -98
- package/templates/electronics-price-tracker.yaml +108 -108
- package/templates/flight-deal-hunter.yaml +113 -113
- package/templates/freelancer-direct.yaml +116 -116
- package/templates/grocery-price-compare.yaml +93 -93
- package/templates/hotel-direct-booking.yaml +113 -113
- package/templates/local-services.yaml +98 -98
- package/templates/olive-oil-tunisia.yaml +88 -88
- package/templates/organic-farm-fresh.yaml +101 -101
- package/templates/restaurant-direct.yaml +97 -97
- package/templates/ring4/banking-sovereign.yaml +55 -0
- package/templates/ring4/ecommerce-sovereign.yaml +58 -0
- package/templates/ring4/healthcare-sovereign.yaml +60 -0
package/sdk/index.js
CHANGED
|
@@ -1,649 +1,649 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WAB Agent SDK
|
|
3
|
-
*
|
|
4
|
-
* Helpers for building AI agents that interact with Web Agent Bridge.
|
|
5
|
-
* Works with Puppeteer, Playwright, or any browser automation tool.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* const { WABAgent } = require('./sdk');
|
|
9
|
-
* const agent = new WABAgent(page);
|
|
10
|
-
* await agent.waitForBridge();
|
|
11
|
-
* const actions = await agent.getActions();
|
|
12
|
-
* await agent.execute('signup', { email: 'test@example.com' });
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
class WABAgent {
|
|
16
|
-
/**
|
|
17
|
-
* @param {object} page — A Puppeteer or Playwright page object
|
|
18
|
-
* @param {object} [options]
|
|
19
|
-
* @param {number} [options.timeout=10000] — Default timeout in ms
|
|
20
|
-
* @param {boolean} [options.useBiDi=false] — Use BiDi interface instead of AICommands
|
|
21
|
-
*/
|
|
22
|
-
constructor(page, options = {}) {
|
|
23
|
-
this.page = page;
|
|
24
|
-
this.timeout = options.timeout || 10000;
|
|
25
|
-
this.useBiDi = options.useBiDi || false;
|
|
26
|
-
this._biDiId = 0;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Wait for the WAB bridge to be ready on the page.
|
|
31
|
-
* @returns {Promise<boolean>}
|
|
32
|
-
*/
|
|
33
|
-
async waitForBridge() {
|
|
34
|
-
const iface = this.useBiDi ? '__wab_bidi' : 'AICommands';
|
|
35
|
-
await this.page.waitForFunction(
|
|
36
|
-
(name) => typeof window[name] !== 'undefined',
|
|
37
|
-
{ timeout: this.timeout },
|
|
38
|
-
iface
|
|
39
|
-
);
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Check if the bridge is loaded on the current page.
|
|
45
|
-
* @returns {Promise<boolean>}
|
|
46
|
-
*/
|
|
47
|
-
async hasBridge() {
|
|
48
|
-
const iface = this.useBiDi ? '__wab_bidi' : 'AICommands';
|
|
49
|
-
return this.page.evaluate((name) => typeof window[name] !== 'undefined', iface);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Get all available actions.
|
|
54
|
-
* @param {string} [category] — Optional category filter
|
|
55
|
-
* @returns {Promise<Array>}
|
|
56
|
-
*/
|
|
57
|
-
async getActions(category) {
|
|
58
|
-
if (this.useBiDi) {
|
|
59
|
-
const result = await this._bidiSend('wab.getActions', category ? { category } : {});
|
|
60
|
-
return result.result || [];
|
|
61
|
-
}
|
|
62
|
-
return this.page.evaluate((cat) => window.AICommands.getActions(cat), category);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Get a single action by name.
|
|
67
|
-
* @param {string} name
|
|
68
|
-
* @returns {Promise<object|null>}
|
|
69
|
-
*/
|
|
70
|
-
async getAction(name) {
|
|
71
|
-
return this.page.evaluate((n) => window.AICommands.getAction(n), name);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Execute an action by name.
|
|
76
|
-
* @param {string} name — Action name
|
|
77
|
-
* @param {object} [params] — Action parameters
|
|
78
|
-
* @returns {Promise<object>}
|
|
79
|
-
*/
|
|
80
|
-
async execute(name, params) {
|
|
81
|
-
if (this.useBiDi) {
|
|
82
|
-
const result = await this._bidiSend('wab.executeAction', { name, data: params || {} });
|
|
83
|
-
return result.result || result;
|
|
84
|
-
}
|
|
85
|
-
return this.page.evaluate(
|
|
86
|
-
(n, p) => window.AICommands.execute(n, p),
|
|
87
|
-
name, params
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Read text content of an element.
|
|
93
|
-
* @param {string} selector — CSS selector
|
|
94
|
-
* @returns {Promise<object>}
|
|
95
|
-
*/
|
|
96
|
-
async readContent(selector) {
|
|
97
|
-
if (this.useBiDi) {
|
|
98
|
-
const result = await this._bidiSend('wab.readContent', { selector });
|
|
99
|
-
return result.result || result;
|
|
100
|
-
}
|
|
101
|
-
return this.page.evaluate((sel) => window.AICommands.readContent(sel), selector);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Get page info and bridge metadata.
|
|
106
|
-
* @returns {Promise<object>}
|
|
107
|
-
*/
|
|
108
|
-
async getPageInfo() {
|
|
109
|
-
if (this.useBiDi) {
|
|
110
|
-
const result = await this._bidiSend('wab.getPageInfo');
|
|
111
|
-
return result.result || result;
|
|
112
|
-
}
|
|
113
|
-
return this.page.evaluate(() => window.AICommands.getPageInfo());
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Authenticate an agent with the bridge.
|
|
118
|
-
* @param {string} apiKey
|
|
119
|
-
* @param {object} [meta] — Agent metadata
|
|
120
|
-
* @returns {Promise<object>}
|
|
121
|
-
*/
|
|
122
|
-
async authenticate(apiKey, meta) {
|
|
123
|
-
return this.page.evaluate(
|
|
124
|
-
(key, m) => window.AICommands.authenticate(key, m),
|
|
125
|
-
apiKey, meta
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Navigate to a URL and wait for the bridge.
|
|
131
|
-
* @param {string} url
|
|
132
|
-
* @returns {Promise<void>}
|
|
133
|
-
*/
|
|
134
|
-
async navigateAndWait(url) {
|
|
135
|
-
await this.page.goto(url, { waitUntil: 'networkidle2' });
|
|
136
|
-
await this.waitForBridge();
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Execute multiple actions in sequence.
|
|
141
|
-
* @param {Array<{name: string, params?: object}>} steps
|
|
142
|
-
* @returns {Promise<Array>}
|
|
143
|
-
*/
|
|
144
|
-
async executeSteps(steps) {
|
|
145
|
-
const results = [];
|
|
146
|
-
for (const step of steps) {
|
|
147
|
-
results.push(await this.execute(step.name, step.params));
|
|
148
|
-
}
|
|
149
|
-
return results;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Get BiDi context (only available when useBiDi is true).
|
|
154
|
-
* @returns {Promise<object>}
|
|
155
|
-
*/
|
|
156
|
-
async getBiDiContext() {
|
|
157
|
-
return this.page.evaluate(() => window.__wab_bidi.getContext());
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Check if the page has granted consent for agent interactions.
|
|
162
|
-
* @returns {Promise<boolean>}
|
|
163
|
-
*/
|
|
164
|
-
async hasConsent() {
|
|
165
|
-
return this.page.evaluate(() => {
|
|
166
|
-
if (typeof window.WABConsent !== 'undefined') return window.WABConsent.hasConsent();
|
|
167
|
-
// If no consent script, treat as allowed
|
|
168
|
-
return true;
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Wait until consent is granted (blocks until user clicks Allow).
|
|
174
|
-
* @param {number} [pollMs=500]
|
|
175
|
-
* @returns {Promise<boolean>}
|
|
176
|
-
*/
|
|
177
|
-
async waitForConsent(pollMs = 500) {
|
|
178
|
-
return this.page.waitForFunction(
|
|
179
|
-
() => {
|
|
180
|
-
if (typeof window.WABConsent === 'undefined') return true;
|
|
181
|
-
return window.WABConsent.hasConsent();
|
|
182
|
-
},
|
|
183
|
-
{ timeout: this.timeout, polling: pollMs }
|
|
184
|
-
).then(() => true);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Discover the page and return the list of actions.
|
|
189
|
-
* Combines bridge discovery with runtime getActions().
|
|
190
|
-
* @returns {Promise<object>}
|
|
191
|
-
*/
|
|
192
|
-
async discover() {
|
|
193
|
-
return this.page.evaluate(() => {
|
|
194
|
-
if (window.WAB && typeof window.WAB.discover === 'function') return window.WAB.discover();
|
|
195
|
-
if (window.AICommands && typeof window.AICommands.getActions === 'function') {
|
|
196
|
-
return { actions: window.AICommands.getActions(), meta: window.AICommands.getPageInfo ? window.AICommands.getPageInfo() : {} };
|
|
197
|
-
}
|
|
198
|
-
return { actions: [] };
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Run a sequence of actions, stopping on the first failure.
|
|
204
|
-
* @param {Array<{name: string, params?: object}>} steps
|
|
205
|
-
* @param {{ stopOnError?: boolean }} [options]
|
|
206
|
-
* @returns {Promise<Array<{ name: string, ok: boolean, result?: any, error?: string }>>}
|
|
207
|
-
*/
|
|
208
|
-
async runPipeline(steps, options = {}) {
|
|
209
|
-
const stopOnError = options.stopOnError !== false;
|
|
210
|
-
const results = [];
|
|
211
|
-
for (const step of steps) {
|
|
212
|
-
try {
|
|
213
|
-
const res = await this.execute(step.name, step.params);
|
|
214
|
-
results.push({ name: step.name, ok: true, result: res });
|
|
215
|
-
} catch (err) {
|
|
216
|
-
results.push({ name: step.name, ok: false, error: err.message || String(err) });
|
|
217
|
-
if (stopOnError) break;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return results;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Execute multiple actions in parallel.
|
|
225
|
-
* @param {Array<{name: string, params?: object}>} actions
|
|
226
|
-
* @returns {Promise<Array<{ name: string, status: string, value?: any, reason?: string }>>}
|
|
227
|
-
*/
|
|
228
|
-
async executeParallel(actions) {
|
|
229
|
-
const promises = actions.map((a) =>
|
|
230
|
-
this.execute(a.name, a.params)
|
|
231
|
-
.then((value) => ({ name: a.name, status: 'fulfilled', value }))
|
|
232
|
-
.catch((err) => ({ name: a.name, status: 'rejected', reason: err.message || String(err) }))
|
|
233
|
-
);
|
|
234
|
-
return Promise.all(promises);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Take a screenshot and return as base64 (useful for vision agents).
|
|
239
|
-
* @param {{ fullPage?: boolean }} [opts]
|
|
240
|
-
* @returns {Promise<string>}
|
|
241
|
-
*/
|
|
242
|
-
async screenshot(opts = {}) {
|
|
243
|
-
const buf = await this.page.screenshot({
|
|
244
|
-
encoding: 'base64',
|
|
245
|
-
fullPage: opts.fullPage || false
|
|
246
|
-
});
|
|
247
|
-
return buf;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/** @private */
|
|
251
|
-
async _bidiSend(method, params = {}) {
|
|
252
|
-
const cmd = { id: ++this._biDiId, method, params };
|
|
253
|
-
return this.page.evaluate((c) => window.__wab_bidi.send(c), cmd);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* WABUniversalAgent — Works on ANY page, no bridge script needed.
|
|
259
|
-
* Uses server-side extraction, analysis, and comparison APIs.
|
|
260
|
-
*/
|
|
261
|
-
class WABUniversalAgent {
|
|
262
|
-
/**
|
|
263
|
-
* @param {string} [serverUrl='http://localhost:3000'] — WAB server URL
|
|
264
|
-
*/
|
|
265
|
-
constructor(serverUrl = 'http://localhost:3000') {
|
|
266
|
-
this.serverUrl = serverUrl.replace(/\/$/, '');
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/** @private */
|
|
270
|
-
async _post(path, body) {
|
|
271
|
-
const res = await fetch(`${this.serverUrl}${path}`, {
|
|
272
|
-
method: 'POST',
|
|
273
|
-
headers: { 'Content-Type': 'application/json' },
|
|
274
|
-
body: JSON.stringify(body),
|
|
275
|
-
});
|
|
276
|
-
if (!res.ok) throw new Error(`WAB API error ${res.status}: ${await res.text()}`);
|
|
277
|
-
return res.json();
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/** @private */
|
|
281
|
-
async _get(path) {
|
|
282
|
-
const res = await fetch(`${this.serverUrl}${path}`);
|
|
283
|
-
if (!res.ok) throw new Error(`WAB API error ${res.status}: ${await res.text()}`);
|
|
284
|
-
return res.json();
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Extract products, prices, and metadata from any URL.
|
|
289
|
-
* @param {string} url
|
|
290
|
-
* @returns {Promise<object>}
|
|
291
|
-
*/
|
|
292
|
-
async extract(url) {
|
|
293
|
-
return this._post('/api/universal/extract', { url });
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Full analysis: extract + fairness + fraud detection + dark patterns.
|
|
298
|
-
* @param {string} url
|
|
299
|
-
* @returns {Promise<object>}
|
|
300
|
-
*/
|
|
301
|
-
async analyze(url) {
|
|
302
|
-
return this._post('/api/universal/analyze', { url });
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Compare prices across multiple sources.
|
|
307
|
-
* @param {string} query — Product or service to search for
|
|
308
|
-
* @param {string} [category='product'] — 'product', 'hotel', 'flight'
|
|
309
|
-
* @returns {Promise<object>}
|
|
310
|
-
*/
|
|
311
|
-
async compare(query, category = 'product') {
|
|
312
|
-
return this._post('/api/universal/compare', { query, category });
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Find and rank the best deals with fairness scoring.
|
|
317
|
-
* @param {string} query
|
|
318
|
-
* @param {string} [category='product']
|
|
319
|
-
* @param {string} [lang='en']
|
|
320
|
-
* @returns {Promise<object>}
|
|
321
|
-
*/
|
|
322
|
-
async deals(query, category = 'product', lang = 'en') {
|
|
323
|
-
return this._post('/api/universal/deals', { query, category, lang });
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Get fairness score for a domain.
|
|
328
|
-
* @param {string} domain
|
|
329
|
-
* @returns {Promise<object>}
|
|
330
|
-
*/
|
|
331
|
-
async fairness(domain) {
|
|
332
|
-
return this._post('/api/universal/fairness', { domain });
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Detect dark patterns on a URL.
|
|
337
|
-
* @param {string} url
|
|
338
|
-
* @returns {Promise<object>}
|
|
339
|
-
*/
|
|
340
|
-
async darkPatterns(url) {
|
|
341
|
-
return this._post('/api/universal/dark-patterns', { url });
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Get price history for a domain.
|
|
346
|
-
* @param {string} domain
|
|
347
|
-
* @returns {Promise<object>}
|
|
348
|
-
*/
|
|
349
|
-
async priceHistory(domain) {
|
|
350
|
-
return this._get(`/api/universal/history?domain=${encodeURIComponent(domain)}`);
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Get top fairness-scored sites.
|
|
355
|
-
* @param {number} [limit=20]
|
|
356
|
-
* @returns {Promise<object>}
|
|
357
|
-
*/
|
|
358
|
-
async topFair(limit = 20) {
|
|
359
|
-
return this._get(`/api/universal/top-fair?limit=${limit}`);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Get all known competing sources.
|
|
364
|
-
* @returns {Promise<object>}
|
|
365
|
-
*/
|
|
366
|
-
async sources() {
|
|
367
|
-
return this._get('/api/universal/sources');
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const { WABMultiAgent } = require('./multi-agent');
|
|
372
|
-
const { WABAgentMesh } = require('./agent-mesh');
|
|
373
|
-
|
|
374
|
-
// ─── WAB Agent OS Client ────────────────────────────────────────────────────
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* WABAgentOS — Client for the Agent OS runtime.
|
|
378
|
-
* Provides access to protocol, tasks, execution, registry, observability, and LLM.
|
|
379
|
-
*/
|
|
380
|
-
class WABAgentOS {
|
|
381
|
-
/**
|
|
382
|
-
* @param {object} options
|
|
383
|
-
* @param {string} options.serverUrl — WAB server base URL
|
|
384
|
-
* @param {string} [options.agentId] — Pre-registered agent ID
|
|
385
|
-
* @param {string} [options.apiKey] — Pre-registered API key
|
|
386
|
-
* @param {string} [options.sessionToken] — Active session token
|
|
387
|
-
*/
|
|
388
|
-
constructor(options = {}) {
|
|
389
|
-
this.serverUrl = (options.serverUrl || 'http://localhost:3000').replace(/\/$/, '');
|
|
390
|
-
this.agentId = options.agentId || null;
|
|
391
|
-
this.apiKey = options.apiKey || null;
|
|
392
|
-
this.sessionToken = options.sessionToken || null;
|
|
393
|
-
this._base = `${this.serverUrl}/api/os`;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// ─── Agent Identity ───────────────────────────────────────────────────
|
|
397
|
-
|
|
398
|
-
async register(name, type, capabilities = []) {
|
|
399
|
-
const res = await this._post('/agents/register', { name, type, capabilities });
|
|
400
|
-
this.agentId = res.agentId;
|
|
401
|
-
this.apiKey = res.apiKey;
|
|
402
|
-
return res;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
async authenticate(apiKey) {
|
|
406
|
-
const res = await this._post('/agents/authenticate', { apiKey: apiKey || this.apiKey });
|
|
407
|
-
if (res.sessionToken) this.sessionToken = res.sessionToken;
|
|
408
|
-
return res;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
async negotiateCapabilities(capabilities, siteId) {
|
|
412
|
-
return this._post(`/agents/${this.agentId}/capabilities`, { capabilities, siteId });
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// ─── Protocol ─────────────────────────────────────────────────────────
|
|
416
|
-
|
|
417
|
-
async getProtocol() {
|
|
418
|
-
return this._get('/protocol');
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
async sendMessage(command, payload = {}) {
|
|
422
|
-
return this._post('/protocol/message', { command, payload, agentId: this.agentId });
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// ─── Tasks ────────────────────────────────────────────────────────────
|
|
426
|
-
|
|
427
|
-
async submitTask(task) {
|
|
428
|
-
return this._post('/tasks', task);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
async getTask(taskId) {
|
|
432
|
-
return this._get(`/tasks/${taskId}`);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
async listTasks(state, limit) {
|
|
436
|
-
const params = [];
|
|
437
|
-
if (state) params.push(`state=${state}`);
|
|
438
|
-
if (limit) params.push(`limit=${limit}`);
|
|
439
|
-
return this._get(`/tasks${params.length ? '?' + params.join('&') : ''}`);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
async cancelTask(taskId) {
|
|
443
|
-
return this._delete(`/tasks/${taskId}`);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
async pauseTask(taskId) {
|
|
447
|
-
return this._post(`/tasks/${taskId}/pause`);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
async resumeTask(taskId) {
|
|
451
|
-
return this._post(`/tasks/${taskId}/resume`);
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// ─── Execution ────────────────────────────────────────────────────────
|
|
455
|
-
|
|
456
|
-
async execute(command) {
|
|
457
|
-
return this._post('/execute', command);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
async executeSemantic(domain, action, params = {}) {
|
|
461
|
-
return this._post('/execute/semantic', { domain, action, params, agentId: this.agentId });
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
async executePipeline(steps) {
|
|
465
|
-
return this._post('/execute/pipeline', { steps });
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
async resolveAction(domain, action, siteDomain) {
|
|
469
|
-
const params = `domain=${domain}&action=${action}${siteDomain ? `&siteDomain=${siteDomain}` : ''}`;
|
|
470
|
-
return this._get(`/execute/resolve?${params}`);
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
// ─── Registry ─────────────────────────────────────────────────────────
|
|
474
|
-
|
|
475
|
-
async searchCommands(query = {}) {
|
|
476
|
-
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
477
|
-
return this._get(`/registry/commands${params ? '?' + params : ''}`);
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
async registerCommand(siteId, command) {
|
|
481
|
-
return this._post('/registry/commands', { siteId, ...command });
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
async searchSites(query = {}) {
|
|
485
|
-
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
486
|
-
return this._get(`/registry/sites${params ? '?' + params : ''}`);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
async registerSite(domain, info) {
|
|
490
|
-
return this._post('/registry/sites', { domain, ...info });
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
async searchTemplates(query = {}) {
|
|
494
|
-
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
495
|
-
return this._get(`/registry/templates${params ? '?' + params : ''}`);
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
async getTemplate(templateId) {
|
|
499
|
-
return this._get(`/registry/templates/${templateId}`);
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// ─── LLM ──────────────────────────────────────────────────────────────
|
|
503
|
-
|
|
504
|
-
async complete(prompt, options = {}) {
|
|
505
|
-
return this._post('/llm/complete', { prompt, options });
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
async embed(text, options = {}) {
|
|
509
|
-
return this._post('/llm/embed', { text, options });
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
async listModels() {
|
|
513
|
-
return this._get('/llm/models');
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// ─── Observability ────────────────────────────────────────────────────
|
|
517
|
-
|
|
518
|
-
async getMetrics() {
|
|
519
|
-
return this._get('/observability/metrics');
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
async getTraces(query = {}) {
|
|
523
|
-
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
524
|
-
return this._get(`/observability/traces${params ? '?' + params : ''}`);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
async getTrace(traceId) {
|
|
528
|
-
return this._get(`/observability/traces/${traceId}`);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
async getLogs(query = {}) {
|
|
532
|
-
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
533
|
-
return this._get(`/observability/logs${params ? '?' + params : ''}`);
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
async getHealth() {
|
|
537
|
-
return this._get('/observability/health');
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
// ─── Events (SSE) ────────────────────────────────────────────────────
|
|
541
|
-
|
|
542
|
-
subscribe(filter, onEvent) {
|
|
543
|
-
if (typeof EventSource === 'undefined') {
|
|
544
|
-
throw new Error('EventSource not available. Use a polyfill for Node.js.');
|
|
545
|
-
}
|
|
546
|
-
const url = `${this._base}/events${filter ? '?filter=' + encodeURIComponent(filter) : ''}`;
|
|
547
|
-
const es = new EventSource(url);
|
|
548
|
-
es.onmessage = (e) => {
|
|
549
|
-
try { onEvent(JSON.parse(e.data)); } catch { onEvent(e.data); }
|
|
550
|
-
};
|
|
551
|
-
return es; // Call es.close() to unsubscribe
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
// ─── Policies ─────────────────────────────────────────────────────────
|
|
555
|
-
|
|
556
|
-
async createPolicy(policy) {
|
|
557
|
-
return this._post('/policies', policy);
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
async evaluatePolicy(entityId, action, context = {}) {
|
|
561
|
-
return this._post('/policies/evaluate', { entityId, action, context });
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// ─── Deploy ───────────────────────────────────────────────────────────
|
|
565
|
-
|
|
566
|
-
async deploy(config = {}) {
|
|
567
|
-
return this._post('/deployments', { agentId: this.agentId, config });
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
async listDeployments(query = {}) {
|
|
571
|
-
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
572
|
-
return this._get(`/deployments${params ? '?' + params : ''}`);
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// ─── HTTP Helpers ─────────────────────────────────────────────────────
|
|
576
|
-
|
|
577
|
-
async _get(path) {
|
|
578
|
-
const url = `${this._base}${path}`;
|
|
579
|
-
const headers = this._headers();
|
|
580
|
-
const res = await fetch(url, { headers });
|
|
581
|
-
if (!res.ok) {
|
|
582
|
-
const body = await res.json().catch(() => ({ error: res.statusText }));
|
|
583
|
-
throw new Error(body.error || `HTTP ${res.status}`);
|
|
584
|
-
}
|
|
585
|
-
return res.json();
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
async _post(path, body) {
|
|
589
|
-
const url = `${this._base}${path}`;
|
|
590
|
-
const headers = { ...this._headers(), 'Content-Type': 'application/json' };
|
|
591
|
-
const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });
|
|
592
|
-
if (!res.ok) {
|
|
593
|
-
const data = await res.json().catch(() => ({ error: res.statusText }));
|
|
594
|
-
throw new Error(data.error || `HTTP ${res.status}`);
|
|
595
|
-
}
|
|
596
|
-
return res.json();
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
async _delete(path) {
|
|
600
|
-
const url = `${this._base}${path}`;
|
|
601
|
-
const headers = this._headers();
|
|
602
|
-
const res = await fetch(url, { method: 'DELETE', headers });
|
|
603
|
-
if (!res.ok) {
|
|
604
|
-
const data = await res.json().catch(() => ({ error: res.statusText }));
|
|
605
|
-
throw new Error(data.error || `HTTP ${res.status}`);
|
|
606
|
-
}
|
|
607
|
-
return res.json();
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
_headers() {
|
|
611
|
-
const h = {};
|
|
612
|
-
if (this.sessionToken) h['Authorization'] = `Bearer ${this.sessionToken}`;
|
|
613
|
-
else if (this.apiKey) h['X-WAB-Key'] = this.apiKey;
|
|
614
|
-
if (this.agentId) h['X-WAB-Agent'] = this.agentId;
|
|
615
|
-
return h;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// Re-export WABToolkit from langchain package for convenience
|
|
620
|
-
let WABToolkit;
|
|
621
|
-
try { WABToolkit = require('../packages/langchain').WABToolkit; } catch {
|
|
622
|
-
try { WABToolkit = require('web-agent-bridge-langchain').WABToolkit; } catch {}
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
// SPEC §8.10–§8.13 client helper
|
|
626
|
-
const { SafetyShieldClient } = require('./safety-shield');
|
|
627
|
-
// Phase 19 — Safe Mode trust gate
|
|
628
|
-
const { WABSafeMode, WABSafeModeError, POLICIES: WAB_SAFE_POLICIES } = require('./safe-mode');
|
|
629
|
-
// Phase 20 — Agent Governance Layer (permissions + approval + audit + kill-switch)
|
|
630
|
-
const { WABGovernance, WABGovernanceError } = require('./governance');
|
|
631
|
-
// Zero-Config Adoption — Auto-Discovery fallback for sites without /.well-known/wab.json
|
|
632
|
-
const autoDiscovery = require('./auto-discovery');
|
|
633
|
-
|
|
634
|
-
module.exports = {
|
|
635
|
-
WABAgent,
|
|
636
|
-
WABUniversalAgent,
|
|
637
|
-
WABMultiAgent,
|
|
638
|
-
WABAgentMesh,
|
|
639
|
-
WABAgentOS,
|
|
640
|
-
WABToolkit,
|
|
641
|
-
SafetyShieldClient,
|
|
642
|
-
WABSafeMode,
|
|
643
|
-
WABSafeModeError,
|
|
644
|
-
WAB_SAFE_POLICIES,
|
|
645
|
-
WABGovernance,
|
|
646
|
-
WABGovernanceError,
|
|
647
|
-
autoDiscovery,
|
|
648
|
-
discover: autoDiscovery.discover,
|
|
649
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* WAB Agent SDK
|
|
3
|
+
*
|
|
4
|
+
* Helpers for building AI agents that interact with Web Agent Bridge.
|
|
5
|
+
* Works with Puppeteer, Playwright, or any browser automation tool.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const { WABAgent } = require('./sdk');
|
|
9
|
+
* const agent = new WABAgent(page);
|
|
10
|
+
* await agent.waitForBridge();
|
|
11
|
+
* const actions = await agent.getActions();
|
|
12
|
+
* await agent.execute('signup', { email: 'test@example.com' });
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
class WABAgent {
|
|
16
|
+
/**
|
|
17
|
+
* @param {object} page — A Puppeteer or Playwright page object
|
|
18
|
+
* @param {object} [options]
|
|
19
|
+
* @param {number} [options.timeout=10000] — Default timeout in ms
|
|
20
|
+
* @param {boolean} [options.useBiDi=false] — Use BiDi interface instead of AICommands
|
|
21
|
+
*/
|
|
22
|
+
constructor(page, options = {}) {
|
|
23
|
+
this.page = page;
|
|
24
|
+
this.timeout = options.timeout || 10000;
|
|
25
|
+
this.useBiDi = options.useBiDi || false;
|
|
26
|
+
this._biDiId = 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Wait for the WAB bridge to be ready on the page.
|
|
31
|
+
* @returns {Promise<boolean>}
|
|
32
|
+
*/
|
|
33
|
+
async waitForBridge() {
|
|
34
|
+
const iface = this.useBiDi ? '__wab_bidi' : 'AICommands';
|
|
35
|
+
await this.page.waitForFunction(
|
|
36
|
+
(name) => typeof window[name] !== 'undefined',
|
|
37
|
+
{ timeout: this.timeout },
|
|
38
|
+
iface
|
|
39
|
+
);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check if the bridge is loaded on the current page.
|
|
45
|
+
* @returns {Promise<boolean>}
|
|
46
|
+
*/
|
|
47
|
+
async hasBridge() {
|
|
48
|
+
const iface = this.useBiDi ? '__wab_bidi' : 'AICommands';
|
|
49
|
+
return this.page.evaluate((name) => typeof window[name] !== 'undefined', iface);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get all available actions.
|
|
54
|
+
* @param {string} [category] — Optional category filter
|
|
55
|
+
* @returns {Promise<Array>}
|
|
56
|
+
*/
|
|
57
|
+
async getActions(category) {
|
|
58
|
+
if (this.useBiDi) {
|
|
59
|
+
const result = await this._bidiSend('wab.getActions', category ? { category } : {});
|
|
60
|
+
return result.result || [];
|
|
61
|
+
}
|
|
62
|
+
return this.page.evaluate((cat) => window.AICommands.getActions(cat), category);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get a single action by name.
|
|
67
|
+
* @param {string} name
|
|
68
|
+
* @returns {Promise<object|null>}
|
|
69
|
+
*/
|
|
70
|
+
async getAction(name) {
|
|
71
|
+
return this.page.evaluate((n) => window.AICommands.getAction(n), name);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Execute an action by name.
|
|
76
|
+
* @param {string} name — Action name
|
|
77
|
+
* @param {object} [params] — Action parameters
|
|
78
|
+
* @returns {Promise<object>}
|
|
79
|
+
*/
|
|
80
|
+
async execute(name, params) {
|
|
81
|
+
if (this.useBiDi) {
|
|
82
|
+
const result = await this._bidiSend('wab.executeAction', { name, data: params || {} });
|
|
83
|
+
return result.result || result;
|
|
84
|
+
}
|
|
85
|
+
return this.page.evaluate(
|
|
86
|
+
(n, p) => window.AICommands.execute(n, p),
|
|
87
|
+
name, params
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Read text content of an element.
|
|
93
|
+
* @param {string} selector — CSS selector
|
|
94
|
+
* @returns {Promise<object>}
|
|
95
|
+
*/
|
|
96
|
+
async readContent(selector) {
|
|
97
|
+
if (this.useBiDi) {
|
|
98
|
+
const result = await this._bidiSend('wab.readContent', { selector });
|
|
99
|
+
return result.result || result;
|
|
100
|
+
}
|
|
101
|
+
return this.page.evaluate((sel) => window.AICommands.readContent(sel), selector);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get page info and bridge metadata.
|
|
106
|
+
* @returns {Promise<object>}
|
|
107
|
+
*/
|
|
108
|
+
async getPageInfo() {
|
|
109
|
+
if (this.useBiDi) {
|
|
110
|
+
const result = await this._bidiSend('wab.getPageInfo');
|
|
111
|
+
return result.result || result;
|
|
112
|
+
}
|
|
113
|
+
return this.page.evaluate(() => window.AICommands.getPageInfo());
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Authenticate an agent with the bridge.
|
|
118
|
+
* @param {string} apiKey
|
|
119
|
+
* @param {object} [meta] — Agent metadata
|
|
120
|
+
* @returns {Promise<object>}
|
|
121
|
+
*/
|
|
122
|
+
async authenticate(apiKey, meta) {
|
|
123
|
+
return this.page.evaluate(
|
|
124
|
+
(key, m) => window.AICommands.authenticate(key, m),
|
|
125
|
+
apiKey, meta
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Navigate to a URL and wait for the bridge.
|
|
131
|
+
* @param {string} url
|
|
132
|
+
* @returns {Promise<void>}
|
|
133
|
+
*/
|
|
134
|
+
async navigateAndWait(url) {
|
|
135
|
+
await this.page.goto(url, { waitUntil: 'networkidle2' });
|
|
136
|
+
await this.waitForBridge();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Execute multiple actions in sequence.
|
|
141
|
+
* @param {Array<{name: string, params?: object}>} steps
|
|
142
|
+
* @returns {Promise<Array>}
|
|
143
|
+
*/
|
|
144
|
+
async executeSteps(steps) {
|
|
145
|
+
const results = [];
|
|
146
|
+
for (const step of steps) {
|
|
147
|
+
results.push(await this.execute(step.name, step.params));
|
|
148
|
+
}
|
|
149
|
+
return results;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get BiDi context (only available when useBiDi is true).
|
|
154
|
+
* @returns {Promise<object>}
|
|
155
|
+
*/
|
|
156
|
+
async getBiDiContext() {
|
|
157
|
+
return this.page.evaluate(() => window.__wab_bidi.getContext());
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Check if the page has granted consent for agent interactions.
|
|
162
|
+
* @returns {Promise<boolean>}
|
|
163
|
+
*/
|
|
164
|
+
async hasConsent() {
|
|
165
|
+
return this.page.evaluate(() => {
|
|
166
|
+
if (typeof window.WABConsent !== 'undefined') return window.WABConsent.hasConsent();
|
|
167
|
+
// If no consent script, treat as allowed
|
|
168
|
+
return true;
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Wait until consent is granted (blocks until user clicks Allow).
|
|
174
|
+
* @param {number} [pollMs=500]
|
|
175
|
+
* @returns {Promise<boolean>}
|
|
176
|
+
*/
|
|
177
|
+
async waitForConsent(pollMs = 500) {
|
|
178
|
+
return this.page.waitForFunction(
|
|
179
|
+
() => {
|
|
180
|
+
if (typeof window.WABConsent === 'undefined') return true;
|
|
181
|
+
return window.WABConsent.hasConsent();
|
|
182
|
+
},
|
|
183
|
+
{ timeout: this.timeout, polling: pollMs }
|
|
184
|
+
).then(() => true);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Discover the page and return the list of actions.
|
|
189
|
+
* Combines bridge discovery with runtime getActions().
|
|
190
|
+
* @returns {Promise<object>}
|
|
191
|
+
*/
|
|
192
|
+
async discover() {
|
|
193
|
+
return this.page.evaluate(() => {
|
|
194
|
+
if (window.WAB && typeof window.WAB.discover === 'function') return window.WAB.discover();
|
|
195
|
+
if (window.AICommands && typeof window.AICommands.getActions === 'function') {
|
|
196
|
+
return { actions: window.AICommands.getActions(), meta: window.AICommands.getPageInfo ? window.AICommands.getPageInfo() : {} };
|
|
197
|
+
}
|
|
198
|
+
return { actions: [] };
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Run a sequence of actions, stopping on the first failure.
|
|
204
|
+
* @param {Array<{name: string, params?: object}>} steps
|
|
205
|
+
* @param {{ stopOnError?: boolean }} [options]
|
|
206
|
+
* @returns {Promise<Array<{ name: string, ok: boolean, result?: any, error?: string }>>}
|
|
207
|
+
*/
|
|
208
|
+
async runPipeline(steps, options = {}) {
|
|
209
|
+
const stopOnError = options.stopOnError !== false;
|
|
210
|
+
const results = [];
|
|
211
|
+
for (const step of steps) {
|
|
212
|
+
try {
|
|
213
|
+
const res = await this.execute(step.name, step.params);
|
|
214
|
+
results.push({ name: step.name, ok: true, result: res });
|
|
215
|
+
} catch (err) {
|
|
216
|
+
results.push({ name: step.name, ok: false, error: err.message || String(err) });
|
|
217
|
+
if (stopOnError) break;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return results;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Execute multiple actions in parallel.
|
|
225
|
+
* @param {Array<{name: string, params?: object}>} actions
|
|
226
|
+
* @returns {Promise<Array<{ name: string, status: string, value?: any, reason?: string }>>}
|
|
227
|
+
*/
|
|
228
|
+
async executeParallel(actions) {
|
|
229
|
+
const promises = actions.map((a) =>
|
|
230
|
+
this.execute(a.name, a.params)
|
|
231
|
+
.then((value) => ({ name: a.name, status: 'fulfilled', value }))
|
|
232
|
+
.catch((err) => ({ name: a.name, status: 'rejected', reason: err.message || String(err) }))
|
|
233
|
+
);
|
|
234
|
+
return Promise.all(promises);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Take a screenshot and return as base64 (useful for vision agents).
|
|
239
|
+
* @param {{ fullPage?: boolean }} [opts]
|
|
240
|
+
* @returns {Promise<string>}
|
|
241
|
+
*/
|
|
242
|
+
async screenshot(opts = {}) {
|
|
243
|
+
const buf = await this.page.screenshot({
|
|
244
|
+
encoding: 'base64',
|
|
245
|
+
fullPage: opts.fullPage || false
|
|
246
|
+
});
|
|
247
|
+
return buf;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** @private */
|
|
251
|
+
async _bidiSend(method, params = {}) {
|
|
252
|
+
const cmd = { id: ++this._biDiId, method, params };
|
|
253
|
+
return this.page.evaluate((c) => window.__wab_bidi.send(c), cmd);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* WABUniversalAgent — Works on ANY page, no bridge script needed.
|
|
259
|
+
* Uses server-side extraction, analysis, and comparison APIs.
|
|
260
|
+
*/
|
|
261
|
+
class WABUniversalAgent {
|
|
262
|
+
/**
|
|
263
|
+
* @param {string} [serverUrl='http://localhost:3000'] — WAB server URL
|
|
264
|
+
*/
|
|
265
|
+
constructor(serverUrl = 'http://localhost:3000') {
|
|
266
|
+
this.serverUrl = serverUrl.replace(/\/$/, '');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** @private */
|
|
270
|
+
async _post(path, body) {
|
|
271
|
+
const res = await fetch(`${this.serverUrl}${path}`, {
|
|
272
|
+
method: 'POST',
|
|
273
|
+
headers: { 'Content-Type': 'application/json' },
|
|
274
|
+
body: JSON.stringify(body),
|
|
275
|
+
});
|
|
276
|
+
if (!res.ok) throw new Error(`WAB API error ${res.status}: ${await res.text()}`);
|
|
277
|
+
return res.json();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** @private */
|
|
281
|
+
async _get(path) {
|
|
282
|
+
const res = await fetch(`${this.serverUrl}${path}`);
|
|
283
|
+
if (!res.ok) throw new Error(`WAB API error ${res.status}: ${await res.text()}`);
|
|
284
|
+
return res.json();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Extract products, prices, and metadata from any URL.
|
|
289
|
+
* @param {string} url
|
|
290
|
+
* @returns {Promise<object>}
|
|
291
|
+
*/
|
|
292
|
+
async extract(url) {
|
|
293
|
+
return this._post('/api/universal/extract', { url });
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Full analysis: extract + fairness + fraud detection + dark patterns.
|
|
298
|
+
* @param {string} url
|
|
299
|
+
* @returns {Promise<object>}
|
|
300
|
+
*/
|
|
301
|
+
async analyze(url) {
|
|
302
|
+
return this._post('/api/universal/analyze', { url });
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Compare prices across multiple sources.
|
|
307
|
+
* @param {string} query — Product or service to search for
|
|
308
|
+
* @param {string} [category='product'] — 'product', 'hotel', 'flight'
|
|
309
|
+
* @returns {Promise<object>}
|
|
310
|
+
*/
|
|
311
|
+
async compare(query, category = 'product') {
|
|
312
|
+
return this._post('/api/universal/compare', { query, category });
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Find and rank the best deals with fairness scoring.
|
|
317
|
+
* @param {string} query
|
|
318
|
+
* @param {string} [category='product']
|
|
319
|
+
* @param {string} [lang='en']
|
|
320
|
+
* @returns {Promise<object>}
|
|
321
|
+
*/
|
|
322
|
+
async deals(query, category = 'product', lang = 'en') {
|
|
323
|
+
return this._post('/api/universal/deals', { query, category, lang });
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Get fairness score for a domain.
|
|
328
|
+
* @param {string} domain
|
|
329
|
+
* @returns {Promise<object>}
|
|
330
|
+
*/
|
|
331
|
+
async fairness(domain) {
|
|
332
|
+
return this._post('/api/universal/fairness', { domain });
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Detect dark patterns on a URL.
|
|
337
|
+
* @param {string} url
|
|
338
|
+
* @returns {Promise<object>}
|
|
339
|
+
*/
|
|
340
|
+
async darkPatterns(url) {
|
|
341
|
+
return this._post('/api/universal/dark-patterns', { url });
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Get price history for a domain.
|
|
346
|
+
* @param {string} domain
|
|
347
|
+
* @returns {Promise<object>}
|
|
348
|
+
*/
|
|
349
|
+
async priceHistory(domain) {
|
|
350
|
+
return this._get(`/api/universal/history?domain=${encodeURIComponent(domain)}`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Get top fairness-scored sites.
|
|
355
|
+
* @param {number} [limit=20]
|
|
356
|
+
* @returns {Promise<object>}
|
|
357
|
+
*/
|
|
358
|
+
async topFair(limit = 20) {
|
|
359
|
+
return this._get(`/api/universal/top-fair?limit=${limit}`);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Get all known competing sources.
|
|
364
|
+
* @returns {Promise<object>}
|
|
365
|
+
*/
|
|
366
|
+
async sources() {
|
|
367
|
+
return this._get('/api/universal/sources');
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const { WABMultiAgent } = require('./multi-agent');
|
|
372
|
+
const { WABAgentMesh } = require('./agent-mesh');
|
|
373
|
+
|
|
374
|
+
// ─── WAB Agent OS Client ────────────────────────────────────────────────────
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* WABAgentOS — Client for the Agent OS runtime.
|
|
378
|
+
* Provides access to protocol, tasks, execution, registry, observability, and LLM.
|
|
379
|
+
*/
|
|
380
|
+
class WABAgentOS {
|
|
381
|
+
/**
|
|
382
|
+
* @param {object} options
|
|
383
|
+
* @param {string} options.serverUrl — WAB server base URL
|
|
384
|
+
* @param {string} [options.agentId] — Pre-registered agent ID
|
|
385
|
+
* @param {string} [options.apiKey] — Pre-registered API key
|
|
386
|
+
* @param {string} [options.sessionToken] — Active session token
|
|
387
|
+
*/
|
|
388
|
+
constructor(options = {}) {
|
|
389
|
+
this.serverUrl = (options.serverUrl || 'http://localhost:3000').replace(/\/$/, '');
|
|
390
|
+
this.agentId = options.agentId || null;
|
|
391
|
+
this.apiKey = options.apiKey || null;
|
|
392
|
+
this.sessionToken = options.sessionToken || null;
|
|
393
|
+
this._base = `${this.serverUrl}/api/os`;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// ─── Agent Identity ───────────────────────────────────────────────────
|
|
397
|
+
|
|
398
|
+
async register(name, type, capabilities = []) {
|
|
399
|
+
const res = await this._post('/agents/register', { name, type, capabilities });
|
|
400
|
+
this.agentId = res.agentId;
|
|
401
|
+
this.apiKey = res.apiKey;
|
|
402
|
+
return res;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
async authenticate(apiKey) {
|
|
406
|
+
const res = await this._post('/agents/authenticate', { apiKey: apiKey || this.apiKey });
|
|
407
|
+
if (res.sessionToken) this.sessionToken = res.sessionToken;
|
|
408
|
+
return res;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async negotiateCapabilities(capabilities, siteId) {
|
|
412
|
+
return this._post(`/agents/${this.agentId}/capabilities`, { capabilities, siteId });
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// ─── Protocol ─────────────────────────────────────────────────────────
|
|
416
|
+
|
|
417
|
+
async getProtocol() {
|
|
418
|
+
return this._get('/protocol');
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async sendMessage(command, payload = {}) {
|
|
422
|
+
return this._post('/protocol/message', { command, payload, agentId: this.agentId });
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// ─── Tasks ────────────────────────────────────────────────────────────
|
|
426
|
+
|
|
427
|
+
async submitTask(task) {
|
|
428
|
+
return this._post('/tasks', task);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async getTask(taskId) {
|
|
432
|
+
return this._get(`/tasks/${taskId}`);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
async listTasks(state, limit) {
|
|
436
|
+
const params = [];
|
|
437
|
+
if (state) params.push(`state=${state}`);
|
|
438
|
+
if (limit) params.push(`limit=${limit}`);
|
|
439
|
+
return this._get(`/tasks${params.length ? '?' + params.join('&') : ''}`);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async cancelTask(taskId) {
|
|
443
|
+
return this._delete(`/tasks/${taskId}`);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
async pauseTask(taskId) {
|
|
447
|
+
return this._post(`/tasks/${taskId}/pause`);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
async resumeTask(taskId) {
|
|
451
|
+
return this._post(`/tasks/${taskId}/resume`);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// ─── Execution ────────────────────────────────────────────────────────
|
|
455
|
+
|
|
456
|
+
async execute(command) {
|
|
457
|
+
return this._post('/execute', command);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
async executeSemantic(domain, action, params = {}) {
|
|
461
|
+
return this._post('/execute/semantic', { domain, action, params, agentId: this.agentId });
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
async executePipeline(steps) {
|
|
465
|
+
return this._post('/execute/pipeline', { steps });
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async resolveAction(domain, action, siteDomain) {
|
|
469
|
+
const params = `domain=${domain}&action=${action}${siteDomain ? `&siteDomain=${siteDomain}` : ''}`;
|
|
470
|
+
return this._get(`/execute/resolve?${params}`);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// ─── Registry ─────────────────────────────────────────────────────────
|
|
474
|
+
|
|
475
|
+
async searchCommands(query = {}) {
|
|
476
|
+
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
477
|
+
return this._get(`/registry/commands${params ? '?' + params : ''}`);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
async registerCommand(siteId, command) {
|
|
481
|
+
return this._post('/registry/commands', { siteId, ...command });
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
async searchSites(query = {}) {
|
|
485
|
+
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
486
|
+
return this._get(`/registry/sites${params ? '?' + params : ''}`);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
async registerSite(domain, info) {
|
|
490
|
+
return this._post('/registry/sites', { domain, ...info });
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
async searchTemplates(query = {}) {
|
|
494
|
+
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
495
|
+
return this._get(`/registry/templates${params ? '?' + params : ''}`);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
async getTemplate(templateId) {
|
|
499
|
+
return this._get(`/registry/templates/${templateId}`);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// ─── LLM ──────────────────────────────────────────────────────────────
|
|
503
|
+
|
|
504
|
+
async complete(prompt, options = {}) {
|
|
505
|
+
return this._post('/llm/complete', { prompt, options });
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
async embed(text, options = {}) {
|
|
509
|
+
return this._post('/llm/embed', { text, options });
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async listModels() {
|
|
513
|
+
return this._get('/llm/models');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// ─── Observability ────────────────────────────────────────────────────
|
|
517
|
+
|
|
518
|
+
async getMetrics() {
|
|
519
|
+
return this._get('/observability/metrics');
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
async getTraces(query = {}) {
|
|
523
|
+
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
524
|
+
return this._get(`/observability/traces${params ? '?' + params : ''}`);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
async getTrace(traceId) {
|
|
528
|
+
return this._get(`/observability/traces/${traceId}`);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
async getLogs(query = {}) {
|
|
532
|
+
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
533
|
+
return this._get(`/observability/logs${params ? '?' + params : ''}`);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
async getHealth() {
|
|
537
|
+
return this._get('/observability/health');
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// ─── Events (SSE) ────────────────────────────────────────────────────
|
|
541
|
+
|
|
542
|
+
subscribe(filter, onEvent) {
|
|
543
|
+
if (typeof EventSource === 'undefined') {
|
|
544
|
+
throw new Error('EventSource not available. Use a polyfill for Node.js.');
|
|
545
|
+
}
|
|
546
|
+
const url = `${this._base}/events${filter ? '?filter=' + encodeURIComponent(filter) : ''}`;
|
|
547
|
+
const es = new EventSource(url);
|
|
548
|
+
es.onmessage = (e) => {
|
|
549
|
+
try { onEvent(JSON.parse(e.data)); } catch { onEvent(e.data); }
|
|
550
|
+
};
|
|
551
|
+
return es; // Call es.close() to unsubscribe
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// ─── Policies ─────────────────────────────────────────────────────────
|
|
555
|
+
|
|
556
|
+
async createPolicy(policy) {
|
|
557
|
+
return this._post('/policies', policy);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
async evaluatePolicy(entityId, action, context = {}) {
|
|
561
|
+
return this._post('/policies/evaluate', { entityId, action, context });
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// ─── Deploy ───────────────────────────────────────────────────────────
|
|
565
|
+
|
|
566
|
+
async deploy(config = {}) {
|
|
567
|
+
return this._post('/deployments', { agentId: this.agentId, config });
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
async listDeployments(query = {}) {
|
|
571
|
+
const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
|
|
572
|
+
return this._get(`/deployments${params ? '?' + params : ''}`);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// ─── HTTP Helpers ─────────────────────────────────────────────────────
|
|
576
|
+
|
|
577
|
+
async _get(path) {
|
|
578
|
+
const url = `${this._base}${path}`;
|
|
579
|
+
const headers = this._headers();
|
|
580
|
+
const res = await fetch(url, { headers });
|
|
581
|
+
if (!res.ok) {
|
|
582
|
+
const body = await res.json().catch(() => ({ error: res.statusText }));
|
|
583
|
+
throw new Error(body.error || `HTTP ${res.status}`);
|
|
584
|
+
}
|
|
585
|
+
return res.json();
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
async _post(path, body) {
|
|
589
|
+
const url = `${this._base}${path}`;
|
|
590
|
+
const headers = { ...this._headers(), 'Content-Type': 'application/json' };
|
|
591
|
+
const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });
|
|
592
|
+
if (!res.ok) {
|
|
593
|
+
const data = await res.json().catch(() => ({ error: res.statusText }));
|
|
594
|
+
throw new Error(data.error || `HTTP ${res.status}`);
|
|
595
|
+
}
|
|
596
|
+
return res.json();
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
async _delete(path) {
|
|
600
|
+
const url = `${this._base}${path}`;
|
|
601
|
+
const headers = this._headers();
|
|
602
|
+
const res = await fetch(url, { method: 'DELETE', headers });
|
|
603
|
+
if (!res.ok) {
|
|
604
|
+
const data = await res.json().catch(() => ({ error: res.statusText }));
|
|
605
|
+
throw new Error(data.error || `HTTP ${res.status}`);
|
|
606
|
+
}
|
|
607
|
+
return res.json();
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
_headers() {
|
|
611
|
+
const h = {};
|
|
612
|
+
if (this.sessionToken) h['Authorization'] = `Bearer ${this.sessionToken}`;
|
|
613
|
+
else if (this.apiKey) h['X-WAB-Key'] = this.apiKey;
|
|
614
|
+
if (this.agentId) h['X-WAB-Agent'] = this.agentId;
|
|
615
|
+
return h;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// Re-export WABToolkit from langchain package for convenience
|
|
620
|
+
let WABToolkit;
|
|
621
|
+
try { WABToolkit = require('../packages/langchain').WABToolkit; } catch {
|
|
622
|
+
try { WABToolkit = require('web-agent-bridge-langchain').WABToolkit; } catch {}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// SPEC §8.10–§8.13 client helper
|
|
626
|
+
const { SafetyShieldClient } = require('./safety-shield');
|
|
627
|
+
// Phase 19 — Safe Mode trust gate
|
|
628
|
+
const { WABSafeMode, WABSafeModeError, POLICIES: WAB_SAFE_POLICIES } = require('./safe-mode');
|
|
629
|
+
// Phase 20 — Agent Governance Layer (permissions + approval + audit + kill-switch)
|
|
630
|
+
const { WABGovernance, WABGovernanceError } = require('./governance');
|
|
631
|
+
// Zero-Config Adoption — Auto-Discovery fallback for sites without /.well-known/wab.json
|
|
632
|
+
const autoDiscovery = require('./auto-discovery');
|
|
633
|
+
|
|
634
|
+
module.exports = {
|
|
635
|
+
WABAgent,
|
|
636
|
+
WABUniversalAgent,
|
|
637
|
+
WABMultiAgent,
|
|
638
|
+
WABAgentMesh,
|
|
639
|
+
WABAgentOS,
|
|
640
|
+
WABToolkit,
|
|
641
|
+
SafetyShieldClient,
|
|
642
|
+
WABSafeMode,
|
|
643
|
+
WABSafeModeError,
|
|
644
|
+
WAB_SAFE_POLICIES,
|
|
645
|
+
WABGovernance,
|
|
646
|
+
WABGovernanceError,
|
|
647
|
+
autoDiscovery,
|
|
648
|
+
discover: autoDiscovery.discover,
|
|
649
|
+
};
|