@the_ro_show/agent-ads-sdk 0.14.0 → 0.15.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/dist/index.mjs CHANGED
@@ -304,6 +304,172 @@ function sanitizeURL(url, options) {
304
304
  }
305
305
  }
306
306
 
307
+ // src/utils/intent-detector.ts
308
+ var INTENT_PATTERNS = {
309
+ research: [
310
+ "what is",
311
+ "how does",
312
+ "explain",
313
+ "tell me about",
314
+ "learn about",
315
+ "understand",
316
+ "guide",
317
+ "tips",
318
+ "basics",
319
+ "introduction",
320
+ "overview",
321
+ "how to"
322
+ ],
323
+ comparison: [
324
+ "vs",
325
+ "versus",
326
+ "compare",
327
+ "better than",
328
+ "difference",
329
+ "which",
330
+ "choose between",
331
+ "alternative",
332
+ "review",
333
+ "pros and cons",
334
+ "best",
335
+ "top",
336
+ "recommend"
337
+ ],
338
+ ready_to_buy: [
339
+ "buy now",
340
+ "purchase",
341
+ "get quote",
342
+ "sign up",
343
+ "subscribe",
344
+ "order now",
345
+ "book now",
346
+ "reserve",
347
+ "apply now",
348
+ "start now",
349
+ "pricing",
350
+ "cost",
351
+ "how much",
352
+ "discount",
353
+ "deal",
354
+ "promo code",
355
+ "coupon",
356
+ "special offer",
357
+ "ready to buy",
358
+ "want to buy",
359
+ "where can i buy",
360
+ "how to purchase"
361
+ ]
362
+ };
363
+ var INTEREST_PATTERNS = {
364
+ travel: ["travel", "trip", "vacation", "flight", "hotel", "destination", "tour", "cruise"],
365
+ fitness: ["fitness", "workout", "gym", "exercise", "health", "diet", "nutrition", "yoga"],
366
+ technology: ["tech", "software", "app", "computer", "phone", "gadget", "device", "AI"],
367
+ finance: ["finance", "money", "invest", "savings", "loan", "credit", "mortgage", "budget"],
368
+ insurance: ["insurance", "coverage", "policy", "claim", "premium", "deductible"],
369
+ automotive: ["car", "auto", "vehicle", "drive", "truck", "SUV", "motorcycle"],
370
+ education: ["learn", "course", "class", "school", "university", "degree", "certification"],
371
+ shopping: ["shop", "store", "buy", "sale", "discount", "deal", "online shopping"],
372
+ food: ["food", "restaurant", "cooking", "recipe", "meal", "dining", "cuisine"],
373
+ entertainment: ["movie", "show", "music", "game", "concert", "event", "streaming"],
374
+ home: ["home", "house", "apartment", "furniture", "decor", "renovation", "real estate"],
375
+ business: ["business", "company", "startup", "entrepreneur", "marketing", "sales"],
376
+ legal: ["legal", "lawyer", "attorney", "law", "contract", "lawsuit", "court"],
377
+ healthcare: ["health", "medical", "doctor", "hospital", "treatment", "therapy", "medicine"],
378
+ parenting: ["baby", "child", "parent", "family", "kids", "pregnancy", "school"],
379
+ wedding: ["wedding", "marriage", "engagement", "bride", "groom", "ceremony"],
380
+ pets: ["pet", "dog", "cat", "animal", "vet", "puppy", "kitten"],
381
+ beauty: ["beauty", "makeup", "skincare", "hair", "cosmetics", "salon", "spa"],
382
+ sports: ["sports", "game", "team", "player", "football", "basketball", "soccer"],
383
+ fashion: ["fashion", "clothing", "style", "outfit", "designer", "shoes", "accessories"]
384
+ };
385
+ function detectIntentStage(message, conversationHistory) {
386
+ const lowerMessage = message.toLowerCase();
387
+ const fullContext = conversationHistory ? [...conversationHistory, message].join(" ").toLowerCase() : lowerMessage;
388
+ for (const pattern of INTENT_PATTERNS.ready_to_buy) {
389
+ if (fullContext.includes(pattern)) {
390
+ return "ready_to_buy";
391
+ }
392
+ }
393
+ for (const pattern of INTENT_PATTERNS.comparison) {
394
+ if (fullContext.includes(pattern)) {
395
+ return "comparison";
396
+ }
397
+ }
398
+ for (const pattern of INTENT_PATTERNS.research) {
399
+ if (lowerMessage.includes(pattern)) {
400
+ return "research";
401
+ }
402
+ }
403
+ return void 0;
404
+ }
405
+ function extractInterests(message, conversationHistory) {
406
+ const interests = /* @__PURE__ */ new Set();
407
+ const validHistory = (conversationHistory || []).filter((msg) => typeof msg === "string" && msg.trim().length > 0);
408
+ const fullContext = validHistory.length > 0 ? [...validHistory, message].join(" ").toLowerCase() : message.toLowerCase();
409
+ for (const [interest, keywords] of Object.entries(INTEREST_PATTERNS)) {
410
+ for (const keyword of keywords) {
411
+ if (fullContext.includes(keyword)) {
412
+ interests.add(interest);
413
+ break;
414
+ }
415
+ }
416
+ }
417
+ return Array.from(interests);
418
+ }
419
+ function extractTopics(conversationHistory) {
420
+ if (!conversationHistory || conversationHistory.length === 0) {
421
+ return [];
422
+ }
423
+ const topics = [];
424
+ const seen = /* @__PURE__ */ new Set();
425
+ for (const message of conversationHistory.slice(-5)) {
426
+ const lowerMessage = message.toLowerCase();
427
+ for (const [topic, keywords] of Object.entries(INTEREST_PATTERNS)) {
428
+ if (!seen.has(topic)) {
429
+ for (const keyword of keywords) {
430
+ if (lowerMessage.includes(keyword)) {
431
+ topics.push(topic);
432
+ seen.add(topic);
433
+ break;
434
+ }
435
+ }
436
+ }
437
+ }
438
+ }
439
+ return topics.slice(0, 3);
440
+ }
441
+ function generateSessionId() {
442
+ const timestamp = Date.now().toString(36);
443
+ const random = Math.random().toString(36).substring(2, 9);
444
+ return `sess_${timestamp}_${random}`;
445
+ }
446
+ function detectPurchaseIntent(message, intentStage) {
447
+ if (intentStage === "ready_to_buy") {
448
+ return true;
449
+ }
450
+ const lowerMessage = message.toLowerCase();
451
+ const purchaseKeywords = [
452
+ "buy",
453
+ "purchase",
454
+ "order",
455
+ "get",
456
+ "subscribe",
457
+ "sign up",
458
+ "apply",
459
+ "book",
460
+ "reserve",
461
+ "quote",
462
+ "pricing",
463
+ "cost",
464
+ "how much",
465
+ "where can i"
466
+ ];
467
+ return purchaseKeywords.some((keyword) => lowerMessage.includes(keyword));
468
+ }
469
+ function calculateMessageCount(conversationHistory) {
470
+ return (conversationHistory?.length || 0) + 1;
471
+ }
472
+
307
473
  // src/client.ts
308
474
  var DEFAULT_BASE_URL = "https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1";
309
475
  var DEFAULT_TIMEOUT_MS = 4e3;
@@ -449,6 +615,16 @@ var AttentionMarketClient = class {
449
615
  const limitedHistory = history.slice(-historyLimit);
450
616
  const contextParts = [...limitedHistory, params.userMessage];
451
617
  const context = contextParts.join("\n");
618
+ const intentStage = params.session_context?.intent_stage || detectIntentStage(params.userMessage, limitedHistory);
619
+ let interests = params.user_context?.interests || extractInterests(params.userMessage, limitedHistory);
620
+ interests = interests.filter((interest) => typeof interest === "string" && interest.trim().length > 0).map((interest) => interest.trim().toLowerCase()).slice(0, 10);
621
+ let recentTopics = params.user_context?.recent_topics || extractTopics(limitedHistory);
622
+ recentTopics = recentTopics.filter((topic) => typeof topic === "string" && topic.trim().length > 0).map((topic) => topic.trim().toLowerCase()).slice(0, 5);
623
+ const purchaseIntent = params.user_context?.purchase_intent !== void 0 ? Boolean(params.user_context.purchase_intent) : detectPurchaseIntent(params.userMessage, intentStage);
624
+ const rawSessionId = params.session_context?.session_id;
625
+ const sessionId = typeof rawSessionId === "string" && rawSessionId.trim().length > 0 ? rawSessionId.trim().slice(0, 100) : generateSessionId();
626
+ const rawMessageCount = params.session_context?.message_count;
627
+ const messageCount = typeof rawMessageCount === "number" && rawMessageCount >= 0 ? Math.min(rawMessageCount, 1e3) : calculateMessageCount(limitedHistory);
452
628
  const country = params.country || "US";
453
629
  const language = params.language || "en";
454
630
  const platform = params.platform || "web";
@@ -537,6 +713,23 @@ var AttentionMarketClient = class {
537
713
  user_intent: params.userMessage,
538
714
  // Use minimal response format by default for better performance
539
715
  response_format: "minimal",
716
+ // === Smart Context Fields (v0.15.0) ===
717
+ // Include user context if we have any data
718
+ ...(interests.length > 0 || recentTopics.length > 0 || purchaseIntent) && {
719
+ user_context: {
720
+ ...interests.length > 0 && { interests },
721
+ ...recentTopics.length > 0 && { recent_topics: recentTopics },
722
+ ...purchaseIntent && { purchase_intent: purchaseIntent }
723
+ }
724
+ },
725
+ // Include session context
726
+ ...sessionId && {
727
+ session_context: {
728
+ session_id: sessionId,
729
+ message_count: messageCount,
730
+ ...intentStage && { intent_stage: intentStage }
731
+ }
732
+ },
540
733
  // Developer controls (Phase 1: Quality & Brand Safety)
541
734
  ...params.minQualityScore !== void 0 && { minQualityScore: params.minQualityScore },
542
735
  ...params.allowedCategories && { allowedCategories: params.allowedCategories },
@@ -548,17 +741,22 @@ var AttentionMarketClient = class {
548
741
  ...params.optimizeFor && { optimizeFor: params.optimizeFor }
549
742
  };
550
743
  const response = await this.decideRaw(request, options);
551
- if (response.creative) {
552
- try {
553
- await this.track({
554
- event_id: `evt_${generateUUID()}`,
555
- event_type: "impression",
556
- occurred_at: (/* @__PURE__ */ new Date()).toISOString(),
557
- agent_id: this.agentId,
558
- tracking_token: response.tracking_token
559
- });
560
- } catch (error) {
561
- console.warn("[AttentionMarket] Failed to auto-track impression:", error);
744
+ if (response && response.creative) {
745
+ if (response["_meta"]) {
746
+ try {
747
+ await this.track({
748
+ event_id: `evt_${generateUUID()}`,
749
+ event_type: "impression",
750
+ occurred_at: (/* @__PURE__ */ new Date()).toISOString(),
751
+ agent_id: this.agentId,
752
+ request_id: response["_meta"]["request_id"],
753
+ decision_id: response["_meta"]["decision_id"],
754
+ unit_id: response["_meta"]["unit_id"],
755
+ tracking_token: response.tracking_token
756
+ });
757
+ } catch (error) {
758
+ console.warn("[AttentionMarket] Failed to auto-track impression:", error);
759
+ }
562
760
  }
563
761
  const adResponse2 = {
564
762
  request_id: request.request_id,
@@ -571,6 +769,7 @@ var AttentionMarketClient = class {
571
769
  tracking_url: response.click_url || "",
572
770
  // Same as click_url
573
771
  tracking_token: response.tracking_token || "",
772
+ ...response.relevance_score !== void 0 && { relevance_score: response.relevance_score },
574
773
  disclosure: response.disclosure || {
575
774
  label: "Sponsored",
576
775
  explanation: "This is a paid advertisement",
@@ -584,7 +783,7 @@ var AttentionMarketClient = class {
584
783
  };
585
784
  return adResponse2;
586
785
  }
587
- if (response.status === "no_fill" || !response.units || response.units.length === 0) {
786
+ if (!response || response.status === "no_fill" || !response.units || response.units.length === 0) {
588
787
  return null;
589
788
  }
590
789
  const adUnit = response.units[0];