web-agent-bridge 2.0.0 → 2.1.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.
@@ -72,8 +72,17 @@
72
72
  transport: ['javascript', 'http'],
73
73
  ready: true,
74
74
  discover: function() { return self.discover(); },
75
- execute: function(name, params) { return self.execute(name, params); }
75
+ execute: function(name, params) { return self.execute(name, params); },
76
+ negotiate: function(agentId, proposal) { return self.negotiate(agentId, proposal); },
77
+ getReputation: function(siteId) { return self.getReputation(siteId); },
78
+ verifyPrice: function(productId, domPrice, visionPrice) { return self.verifyPrice(productId, domPrice, visionPrice); }
76
79
  };
80
+
81
+ // Also expose on window.AICommands for broad compatibility
82
+ global.AICommands = global.AICommands || {};
83
+ global.AICommands.negotiate = function(agentId, proposal) { return self.negotiate(agentId, proposal); };
84
+ global.AICommands.getReputation = function(siteId) { return self.getReputation(siteId); };
85
+ global.AICommands.verifyPrice = function(productId, domP, visP) { return self.verifyPrice(productId, domP, visP); };
77
86
  };
78
87
 
79
88
  // Cross-frame communication for embedded demos
@@ -97,6 +106,12 @@
97
106
  e.source.postMessage({ source: 'wab-store', type: 'execute-response', action: e.data.action, detail: result }, '*');
98
107
  });
99
108
  }
109
+ // Negotiation protocol via postMessage
110
+ if (e.data.source === 'wab-agent' && e.data.type === 'negotiate') {
111
+ self.negotiate(e.data.agentId, e.data.proposal).then(function(result) {
112
+ e.source.postMessage({ source: 'wab-store', type: 'negotiate-response', detail: result }, '*');
113
+ });
114
+ }
100
115
  });
101
116
 
102
117
  // Notify parent that store is ready
@@ -200,6 +215,147 @@
200
215
  return this._auditLog.slice();
201
216
  };
202
217
 
218
+ // ── Negotiation Support ─────────────────────────────────────────
219
+ // Sites can define negotiation rules; agents can open sessions and propose
220
+
221
+ WABInstance.prototype.setNegotiationRules = function(rules) {
222
+ this._negotiationRules = rules || {};
223
+ // Expose in protocol
224
+ if (global.__wab_protocol) {
225
+ global.__wab_protocol.negotiation = { available: true, rules: Object.keys(rules) };
226
+ }
227
+ return this;
228
+ };
229
+
230
+ WABInstance.prototype.negotiate = function(agentId, proposal) {
231
+ var self = this;
232
+ // Support in-browser negotiation rules (no server needed)
233
+ if (this._negotiationRules && !this.serverUrl) {
234
+ return this._handleLocalNegotiation(agentId, proposal);
235
+ }
236
+ if (!this.serverUrl) {
237
+ return Promise.resolve({ error: 'Negotiation requires a server URL or local rules' });
238
+ }
239
+ return fetch(this.serverUrl + '/api/sovereign/negotiation/sessions', {
240
+ method: 'POST',
241
+ headers: { 'Content-Type': 'application/json' },
242
+ body: JSON.stringify({
243
+ siteId: self.name,
244
+ agentId: agentId,
245
+ itemId: proposal.itemId || null,
246
+ itemName: proposal.itemName || 'item',
247
+ originalPrice: proposal.originalPrice || 0
248
+ })
249
+ }).then(function(r) { return r.json(); })
250
+ .then(function(session) {
251
+ if (!session.sessionId) return session;
252
+ return fetch(self.serverUrl + '/api/sovereign/negotiation/sessions/' + session.sessionId + '/propose', {
253
+ method: 'POST',
254
+ headers: { 'Content-Type': 'application/json' },
255
+ body: JSON.stringify({
256
+ strategy: proposal.strategy || 'instant_payment',
257
+ proposedDiscount: proposal.proposedDiscount || 5,
258
+ arguments: proposal.arguments || []
259
+ })
260
+ }).then(function(r) { return r.json(); });
261
+ });
262
+ };
263
+
264
+ // Local in-browser negotiation (no server required)
265
+ WABInstance.prototype._handleLocalNegotiation = function(agentId, proposal) {
266
+ var rules = this._negotiationRules;
267
+ var strategy = proposal.strategy || 'custom';
268
+ var rule = rules[strategy];
269
+ if (!rule) {
270
+ return Promise.resolve({
271
+ status: 'rejected',
272
+ reason: 'no_applicable_rule',
273
+ message: 'No rule matches strategy: ' + strategy
274
+ });
275
+ }
276
+ var requested = proposal.proposedDiscount || 0;
277
+ var maxAllowed = rule.maxDiscount || 20;
278
+ var offered = rule.discount || 0;
279
+ var actual = Math.min(requested, maxAllowed, offered);
280
+ var originalPrice = proposal.originalPrice || 0;
281
+ var finalPrice = Math.round(originalPrice * (1 - actual / 100) * 100) / 100;
282
+
283
+ if (requested <= offered) {
284
+ this._emit('negotiation', { status: 'accepted', agentId: agentId, discount: actual, finalPrice: finalPrice });
285
+ return Promise.resolve({
286
+ status: 'agreed',
287
+ discount: actual,
288
+ originalPrice: originalPrice,
289
+ finalPrice: finalPrice,
290
+ message: 'Deal accepted! ' + actual + '% off. Price: $' + finalPrice
291
+ });
292
+ }
293
+ // Counter-offer
294
+ this._emit('negotiation', { status: 'counter', agentId: agentId, counterDiscount: offered });
295
+ return Promise.resolve({
296
+ status: 'counter_offer',
297
+ counterDiscount: offered,
298
+ counterPrice: Math.round(originalPrice * (1 - offered / 100) * 100) / 100,
299
+ message: 'We can offer ' + offered + '% off for ' + strategy.replace(/_/g, ' ')
300
+ });
301
+ };
302
+
303
+ // ── Reputation Support ────────────────────────────────────────────
304
+
305
+ WABInstance.prototype.submitAttestation = function(agentId, targetSiteId, interactionType, outcome, extras) {
306
+ if (!this.serverUrl) {
307
+ return Promise.resolve({ error: 'Reputation requires a server URL' });
308
+ }
309
+ var body = {
310
+ siteId: targetSiteId,
311
+ agentId: agentId,
312
+ interactionType: interactionType || 'purchase',
313
+ outcome: outcome || 'success'
314
+ };
315
+ if (extras) {
316
+ if (extras.priceAccuracy != null) body.priceAccuracy = extras.priceAccuracy;
317
+ if (extras.responseTimeMs != null) body.responseTimeMs = extras.responseTimeMs;
318
+ if (extras.dataIntegrity != null) body.dataIntegrity = extras.dataIntegrity;
319
+ if (extras.visionVerified != null) body.visionVerified = extras.visionVerified;
320
+ if (extras.details) body.details = extras.details;
321
+ }
322
+ return fetch(this.serverUrl + '/api/sovereign/reputation/attestations', {
323
+ method: 'POST',
324
+ headers: { 'Content-Type': 'application/json' },
325
+ body: JSON.stringify(body)
326
+ }).then(function(r) { return r.json(); });
327
+ };
328
+
329
+ WABInstance.prototype.getReputation = function(siteId) {
330
+ if (!this.serverUrl) {
331
+ return Promise.resolve({ error: 'Reputation requires a server URL' });
332
+ }
333
+ return fetch(this.serverUrl + '/api/sovereign/reputation/sites/' + encodeURIComponent(siteId))
334
+ .then(function(r) { return r.json(); });
335
+ };
336
+
337
+ // ── Verification Support ──────────────────────────────────────────
338
+
339
+ WABInstance.prototype.verifyPrice = function(opts) {
340
+ if (!this.serverUrl) {
341
+ return Promise.resolve({ error: 'Verification requires a server URL' });
342
+ }
343
+ var body = {
344
+ siteId: opts.siteId || this.name,
345
+ agentId: opts.agentId || null,
346
+ url: opts.url || null,
347
+ domValue: opts.domValue || opts.domPrice,
348
+ visionValue: opts.visionValue || opts.visionPrice,
349
+ category: opts.category || null,
350
+ itemName: opts.itemName || null
351
+ };
352
+ return fetch(this.serverUrl + '/api/sovereign/verify/price', {
353
+ method: 'POST',
354
+ headers: { 'Content-Type': 'application/json' },
355
+ body: JSON.stringify(body)
356
+ }).then(function(r) { return r.json(); });
357
+ };
358
+
203
359
  // ── Static API ────────────────────────────────────────────────────
204
360
 
205
361
  var WAB = {
@@ -226,6 +382,21 @@
226
382
  return Promise.resolve({ error: 'WAB not initialized. Call WAB.init() first.' });
227
383
  },
228
384
 
385
+ negotiate: function(agentId, proposal) {
386
+ if (WAB._instance) return WAB._instance.negotiate(agentId, proposal);
387
+ return Promise.resolve({ error: 'WAB not initialized' });
388
+ },
389
+
390
+ getReputation: function(siteId) {
391
+ if (WAB._instance) return WAB._instance.getReputation(siteId);
392
+ return Promise.resolve({ error: 'WAB not initialized' });
393
+ },
394
+
395
+ verifyPrice: function(opts) {
396
+ if (WAB._instance) return WAB._instance.verifyPrice(opts);
397
+ return Promise.resolve({ error: 'WAB not initialized' });
398
+ },
399
+
229
400
  _instance: null
230
401
  };
231
402