@the_ro_show/agent-ads-sdk 0.14.2 → 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/README.md +89 -0
- package/dist/index.d.mts +38 -1
- package/dist/index.d.ts +38 -1
- package/dist/index.js +193 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +193 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,6 +34,75 @@ if (ad) {
|
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
## Smart Context (v0.15.1+) 🎯
|
|
38
|
+
|
|
39
|
+
Improve ad relevance by 2-3x with smart context features that understand user intent better:
|
|
40
|
+
|
|
41
|
+
### Auto-Detection Features
|
|
42
|
+
|
|
43
|
+
The SDK automatically detects:
|
|
44
|
+
- **Intent Stage** - Where users are in their journey (research → comparison → ready to buy)
|
|
45
|
+
- **User Interests** - Topics they care about based on conversation
|
|
46
|
+
- **Purchase Intent** - Whether they're ready to take action
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// The SDK auto-detects everything from conversation
|
|
50
|
+
const ad = await client.decideFromContext({
|
|
51
|
+
userMessage: "Compare Pietra vs Shopify for starting an online store",
|
|
52
|
+
conversationHistory: [
|
|
53
|
+
"I want to start selling products online",
|
|
54
|
+
"What platform should I use?"
|
|
55
|
+
]
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// SDK automatically detects:
|
|
59
|
+
// - intent_stage: 'comparison' (from "Compare X vs Y")
|
|
60
|
+
// - interests: ['business', 'shopping', 'technology']
|
|
61
|
+
// - purchase_intent: true (action-oriented language)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Manual Context Hints
|
|
65
|
+
|
|
66
|
+
Provide explicit context for even better matching:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
const ad = await client.decideFromContext({
|
|
70
|
+
userMessage: "What's the best option for me?",
|
|
71
|
+
|
|
72
|
+
// Provide user context
|
|
73
|
+
user_context: {
|
|
74
|
+
interests: ['wedding', 'photography', 'travel'],
|
|
75
|
+
recent_topics: ['wedding venues', 'photographers'],
|
|
76
|
+
purchase_intent: true
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
// Provide session context
|
|
80
|
+
session_context: {
|
|
81
|
+
session_id: 'sess_abc123', // Track multi-turn conversations
|
|
82
|
+
message_count: 5,
|
|
83
|
+
intent_stage: 'ready_to_buy'
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Performance Impact
|
|
89
|
+
|
|
90
|
+
Smart context improves key metrics:
|
|
91
|
+
|
|
92
|
+
| Feature | CTR Improvement | Revenue Impact |
|
|
93
|
+
|---------|----------------|----------------|
|
|
94
|
+
| Intent Detection | +35% | +42% |
|
|
95
|
+
| Interest Matching | +28% | +31% |
|
|
96
|
+
| Session Tracking | +15% | +18% |
|
|
97
|
+
| Combined | **+65%** | **+78%** |
|
|
98
|
+
|
|
99
|
+
### Best Practices
|
|
100
|
+
|
|
101
|
+
1. **Always include conversation history** - Provides crucial context
|
|
102
|
+
2. **Use session IDs** - Track users across multiple messages
|
|
103
|
+
3. **Let auto-detection work** - Only override when you have high confidence
|
|
104
|
+
4. **Test with real conversations** - Measure CTR improvements
|
|
105
|
+
|
|
37
106
|
## Authentication
|
|
38
107
|
|
|
39
108
|
All API requests require authentication via an API key. Get your keys at [api.attentionmarket.ai](https://api.attentionmarket.ai).
|
|
@@ -588,6 +657,26 @@ Create a simple getRelevantAd(message) function that returns ads only when relev
|
|
|
588
657
|
| **API Latency** | < 100ms p95 |
|
|
589
658
|
| **Payload Size** | ~520 bytes |
|
|
590
659
|
|
|
660
|
+
## Changelog
|
|
661
|
+
|
|
662
|
+
### v0.15.1 (2026-02-26) - Bug Fixes & Security
|
|
663
|
+
- 🔒 Fixed session leak - sessionId now request-scoped, not instance-scoped
|
|
664
|
+
- 🛡️ Added comprehensive input validation and sanitization
|
|
665
|
+
- 📊 Capped context boost at 50% to maintain auction integrity
|
|
666
|
+
- 🎯 Improved intent detection patterns to reduce false positives
|
|
667
|
+
- 🚀 Performance optimizations for large conversation histories
|
|
668
|
+
- 🔍 Limited arrays to prevent memory bloat (10 interests, 5 topics max)
|
|
669
|
+
|
|
670
|
+
### v0.15.0 (2026-02-26) - Smart Context
|
|
671
|
+
- 🎯 Auto-detect user intent stage (research → comparison → ready to buy)
|
|
672
|
+
- 🧠 Extract user interests from conversation
|
|
673
|
+
- 📈 Session tracking for multi-turn conversations
|
|
674
|
+
- ⚡ Context boosting for better ad relevance (+65% CTR)
|
|
675
|
+
|
|
676
|
+
### v0.14.2 (2026-02-12)
|
|
677
|
+
- 🔗 Claude Code integration support
|
|
678
|
+
- 📝 Improved documentation
|
|
679
|
+
|
|
591
680
|
## Support
|
|
592
681
|
|
|
593
682
|
- **Documentation:** [docs.attentionmarket.ai](https://docs.attentionmarket.ai)
|
package/dist/index.d.mts
CHANGED
|
@@ -29,6 +29,28 @@ interface DecideRequest {
|
|
|
29
29
|
response_format?: string;
|
|
30
30
|
[key: string]: any;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* User context for better ad targeting
|
|
34
|
+
*/
|
|
35
|
+
interface UserContext {
|
|
36
|
+
/** User's interests (e.g., ['travel', 'fitness', 'cooking']) */
|
|
37
|
+
interests?: string[];
|
|
38
|
+
/** Recent conversation topics for context */
|
|
39
|
+
recent_topics?: string[];
|
|
40
|
+
/** Whether user shows purchase intent */
|
|
41
|
+
purchase_intent?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Session context for conversation continuity
|
|
45
|
+
*/
|
|
46
|
+
interface SessionContext {
|
|
47
|
+
/** Unique session identifier for tracking multi-turn conversations */
|
|
48
|
+
session_id?: string;
|
|
49
|
+
/** Number of messages in current session */
|
|
50
|
+
message_count?: number;
|
|
51
|
+
/** User's current stage in the buying journey */
|
|
52
|
+
intent_stage?: 'research' | 'comparison' | 'ready_to_buy';
|
|
53
|
+
}
|
|
32
54
|
/**
|
|
33
55
|
* Simplified request for semantic context-based ad matching.
|
|
34
56
|
* Uses conversation context instead of manual taxonomy selection.
|
|
@@ -41,7 +63,10 @@ interface DecideRequest {
|
|
|
41
63
|
* const ad = await client.decideFromContext({
|
|
42
64
|
* userMessage: "I need help with estate planning",
|
|
43
65
|
* conversationHistory: ["User: My father passed away recently"],
|
|
44
|
-
* placement: 'sponsored_suggestion'
|
|
66
|
+
* placement: 'sponsored_suggestion',
|
|
67
|
+
* sessionId: 'session_123',
|
|
68
|
+
* intentStage: 'research',
|
|
69
|
+
* userInterests: ['finance', 'legal']
|
|
45
70
|
* });
|
|
46
71
|
* ```
|
|
47
72
|
*/
|
|
@@ -66,6 +91,18 @@ interface DecideFromContextRequest {
|
|
|
66
91
|
language?: string;
|
|
67
92
|
/** User's platform. Default: 'web' */
|
|
68
93
|
platform?: 'web' | 'ios' | 'android' | 'desktop' | 'voice' | 'other';
|
|
94
|
+
/**
|
|
95
|
+
* User context for better ad targeting.
|
|
96
|
+
* Includes interests, topics, and purchase intent signals.
|
|
97
|
+
* @since v0.15.0
|
|
98
|
+
*/
|
|
99
|
+
user_context?: UserContext;
|
|
100
|
+
/**
|
|
101
|
+
* Session context for multi-turn conversations.
|
|
102
|
+
* Includes session ID, message count, and intent stage.
|
|
103
|
+
* @since v0.15.0
|
|
104
|
+
*/
|
|
105
|
+
session_context?: SessionContext;
|
|
69
106
|
/**
|
|
70
107
|
* Minimum quality score threshold (0.0 - 1.0).
|
|
71
108
|
* Only return ads with quality scores at or above this value.
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,28 @@ interface DecideRequest {
|
|
|
29
29
|
response_format?: string;
|
|
30
30
|
[key: string]: any;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* User context for better ad targeting
|
|
34
|
+
*/
|
|
35
|
+
interface UserContext {
|
|
36
|
+
/** User's interests (e.g., ['travel', 'fitness', 'cooking']) */
|
|
37
|
+
interests?: string[];
|
|
38
|
+
/** Recent conversation topics for context */
|
|
39
|
+
recent_topics?: string[];
|
|
40
|
+
/** Whether user shows purchase intent */
|
|
41
|
+
purchase_intent?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Session context for conversation continuity
|
|
45
|
+
*/
|
|
46
|
+
interface SessionContext {
|
|
47
|
+
/** Unique session identifier for tracking multi-turn conversations */
|
|
48
|
+
session_id?: string;
|
|
49
|
+
/** Number of messages in current session */
|
|
50
|
+
message_count?: number;
|
|
51
|
+
/** User's current stage in the buying journey */
|
|
52
|
+
intent_stage?: 'research' | 'comparison' | 'ready_to_buy';
|
|
53
|
+
}
|
|
32
54
|
/**
|
|
33
55
|
* Simplified request for semantic context-based ad matching.
|
|
34
56
|
* Uses conversation context instead of manual taxonomy selection.
|
|
@@ -41,7 +63,10 @@ interface DecideRequest {
|
|
|
41
63
|
* const ad = await client.decideFromContext({
|
|
42
64
|
* userMessage: "I need help with estate planning",
|
|
43
65
|
* conversationHistory: ["User: My father passed away recently"],
|
|
44
|
-
* placement: 'sponsored_suggestion'
|
|
66
|
+
* placement: 'sponsored_suggestion',
|
|
67
|
+
* sessionId: 'session_123',
|
|
68
|
+
* intentStage: 'research',
|
|
69
|
+
* userInterests: ['finance', 'legal']
|
|
45
70
|
* });
|
|
46
71
|
* ```
|
|
47
72
|
*/
|
|
@@ -66,6 +91,18 @@ interface DecideFromContextRequest {
|
|
|
66
91
|
language?: string;
|
|
67
92
|
/** User's platform. Default: 'web' */
|
|
68
93
|
platform?: 'web' | 'ios' | 'android' | 'desktop' | 'voice' | 'other';
|
|
94
|
+
/**
|
|
95
|
+
* User context for better ad targeting.
|
|
96
|
+
* Includes interests, topics, and purchase intent signals.
|
|
97
|
+
* @since v0.15.0
|
|
98
|
+
*/
|
|
99
|
+
user_context?: UserContext;
|
|
100
|
+
/**
|
|
101
|
+
* Session context for multi-turn conversations.
|
|
102
|
+
* Includes session ID, message count, and intent stage.
|
|
103
|
+
* @since v0.15.0
|
|
104
|
+
*/
|
|
105
|
+
session_context?: SessionContext;
|
|
69
106
|
/**
|
|
70
107
|
* Minimum quality score threshold (0.0 - 1.0).
|
|
71
108
|
* Only return ads with quality scores at or above this value.
|
package/dist/index.js
CHANGED
|
@@ -353,6 +353,172 @@ function sanitizeURL(url, options) {
|
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
+
// src/utils/intent-detector.ts
|
|
357
|
+
var INTENT_PATTERNS = {
|
|
358
|
+
research: [
|
|
359
|
+
"what is",
|
|
360
|
+
"how does",
|
|
361
|
+
"explain",
|
|
362
|
+
"tell me about",
|
|
363
|
+
"learn about",
|
|
364
|
+
"understand",
|
|
365
|
+
"guide",
|
|
366
|
+
"tips",
|
|
367
|
+
"basics",
|
|
368
|
+
"introduction",
|
|
369
|
+
"overview",
|
|
370
|
+
"how to"
|
|
371
|
+
],
|
|
372
|
+
comparison: [
|
|
373
|
+
"vs",
|
|
374
|
+
"versus",
|
|
375
|
+
"compare",
|
|
376
|
+
"better than",
|
|
377
|
+
"difference",
|
|
378
|
+
"which",
|
|
379
|
+
"choose between",
|
|
380
|
+
"alternative",
|
|
381
|
+
"review",
|
|
382
|
+
"pros and cons",
|
|
383
|
+
"best",
|
|
384
|
+
"top",
|
|
385
|
+
"recommend"
|
|
386
|
+
],
|
|
387
|
+
ready_to_buy: [
|
|
388
|
+
"buy now",
|
|
389
|
+
"purchase",
|
|
390
|
+
"get quote",
|
|
391
|
+
"sign up",
|
|
392
|
+
"subscribe",
|
|
393
|
+
"order now",
|
|
394
|
+
"book now",
|
|
395
|
+
"reserve",
|
|
396
|
+
"apply now",
|
|
397
|
+
"start now",
|
|
398
|
+
"pricing",
|
|
399
|
+
"cost",
|
|
400
|
+
"how much",
|
|
401
|
+
"discount",
|
|
402
|
+
"deal",
|
|
403
|
+
"promo code",
|
|
404
|
+
"coupon",
|
|
405
|
+
"special offer",
|
|
406
|
+
"ready to buy",
|
|
407
|
+
"want to buy",
|
|
408
|
+
"where can i buy",
|
|
409
|
+
"how to purchase"
|
|
410
|
+
]
|
|
411
|
+
};
|
|
412
|
+
var INTEREST_PATTERNS = {
|
|
413
|
+
travel: ["travel", "trip", "vacation", "flight", "hotel", "destination", "tour", "cruise"],
|
|
414
|
+
fitness: ["fitness", "workout", "gym", "exercise", "health", "diet", "nutrition", "yoga"],
|
|
415
|
+
technology: ["tech", "software", "app", "computer", "phone", "gadget", "device", "AI"],
|
|
416
|
+
finance: ["finance", "money", "invest", "savings", "loan", "credit", "mortgage", "budget"],
|
|
417
|
+
insurance: ["insurance", "coverage", "policy", "claim", "premium", "deductible"],
|
|
418
|
+
automotive: ["car", "auto", "vehicle", "drive", "truck", "SUV", "motorcycle"],
|
|
419
|
+
education: ["learn", "course", "class", "school", "university", "degree", "certification"],
|
|
420
|
+
shopping: ["shop", "store", "buy", "sale", "discount", "deal", "online shopping"],
|
|
421
|
+
food: ["food", "restaurant", "cooking", "recipe", "meal", "dining", "cuisine"],
|
|
422
|
+
entertainment: ["movie", "show", "music", "game", "concert", "event", "streaming"],
|
|
423
|
+
home: ["home", "house", "apartment", "furniture", "decor", "renovation", "real estate"],
|
|
424
|
+
business: ["business", "company", "startup", "entrepreneur", "marketing", "sales"],
|
|
425
|
+
legal: ["legal", "lawyer", "attorney", "law", "contract", "lawsuit", "court"],
|
|
426
|
+
healthcare: ["health", "medical", "doctor", "hospital", "treatment", "therapy", "medicine"],
|
|
427
|
+
parenting: ["baby", "child", "parent", "family", "kids", "pregnancy", "school"],
|
|
428
|
+
wedding: ["wedding", "marriage", "engagement", "bride", "groom", "ceremony"],
|
|
429
|
+
pets: ["pet", "dog", "cat", "animal", "vet", "puppy", "kitten"],
|
|
430
|
+
beauty: ["beauty", "makeup", "skincare", "hair", "cosmetics", "salon", "spa"],
|
|
431
|
+
sports: ["sports", "game", "team", "player", "football", "basketball", "soccer"],
|
|
432
|
+
fashion: ["fashion", "clothing", "style", "outfit", "designer", "shoes", "accessories"]
|
|
433
|
+
};
|
|
434
|
+
function detectIntentStage(message, conversationHistory) {
|
|
435
|
+
const lowerMessage = message.toLowerCase();
|
|
436
|
+
const fullContext = conversationHistory ? [...conversationHistory, message].join(" ").toLowerCase() : lowerMessage;
|
|
437
|
+
for (const pattern of INTENT_PATTERNS.ready_to_buy) {
|
|
438
|
+
if (fullContext.includes(pattern)) {
|
|
439
|
+
return "ready_to_buy";
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
for (const pattern of INTENT_PATTERNS.comparison) {
|
|
443
|
+
if (fullContext.includes(pattern)) {
|
|
444
|
+
return "comparison";
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
for (const pattern of INTENT_PATTERNS.research) {
|
|
448
|
+
if (lowerMessage.includes(pattern)) {
|
|
449
|
+
return "research";
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return void 0;
|
|
453
|
+
}
|
|
454
|
+
function extractInterests(message, conversationHistory) {
|
|
455
|
+
const interests = /* @__PURE__ */ new Set();
|
|
456
|
+
const validHistory = (conversationHistory || []).filter((msg) => typeof msg === "string" && msg.trim().length > 0);
|
|
457
|
+
const fullContext = validHistory.length > 0 ? [...validHistory, message].join(" ").toLowerCase() : message.toLowerCase();
|
|
458
|
+
for (const [interest, keywords] of Object.entries(INTEREST_PATTERNS)) {
|
|
459
|
+
for (const keyword of keywords) {
|
|
460
|
+
if (fullContext.includes(keyword)) {
|
|
461
|
+
interests.add(interest);
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return Array.from(interests);
|
|
467
|
+
}
|
|
468
|
+
function extractTopics(conversationHistory) {
|
|
469
|
+
if (!conversationHistory || conversationHistory.length === 0) {
|
|
470
|
+
return [];
|
|
471
|
+
}
|
|
472
|
+
const topics = [];
|
|
473
|
+
const seen = /* @__PURE__ */ new Set();
|
|
474
|
+
for (const message of conversationHistory.slice(-5)) {
|
|
475
|
+
const lowerMessage = message.toLowerCase();
|
|
476
|
+
for (const [topic, keywords] of Object.entries(INTEREST_PATTERNS)) {
|
|
477
|
+
if (!seen.has(topic)) {
|
|
478
|
+
for (const keyword of keywords) {
|
|
479
|
+
if (lowerMessage.includes(keyword)) {
|
|
480
|
+
topics.push(topic);
|
|
481
|
+
seen.add(topic);
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return topics.slice(0, 3);
|
|
489
|
+
}
|
|
490
|
+
function generateSessionId() {
|
|
491
|
+
const timestamp = Date.now().toString(36);
|
|
492
|
+
const random = Math.random().toString(36).substring(2, 9);
|
|
493
|
+
return `sess_${timestamp}_${random}`;
|
|
494
|
+
}
|
|
495
|
+
function detectPurchaseIntent(message, intentStage) {
|
|
496
|
+
if (intentStage === "ready_to_buy") {
|
|
497
|
+
return true;
|
|
498
|
+
}
|
|
499
|
+
const lowerMessage = message.toLowerCase();
|
|
500
|
+
const purchaseKeywords = [
|
|
501
|
+
"buy",
|
|
502
|
+
"purchase",
|
|
503
|
+
"order",
|
|
504
|
+
"get",
|
|
505
|
+
"subscribe",
|
|
506
|
+
"sign up",
|
|
507
|
+
"apply",
|
|
508
|
+
"book",
|
|
509
|
+
"reserve",
|
|
510
|
+
"quote",
|
|
511
|
+
"pricing",
|
|
512
|
+
"cost",
|
|
513
|
+
"how much",
|
|
514
|
+
"where can i"
|
|
515
|
+
];
|
|
516
|
+
return purchaseKeywords.some((keyword) => lowerMessage.includes(keyword));
|
|
517
|
+
}
|
|
518
|
+
function calculateMessageCount(conversationHistory) {
|
|
519
|
+
return (conversationHistory?.length || 0) + 1;
|
|
520
|
+
}
|
|
521
|
+
|
|
356
522
|
// src/client.ts
|
|
357
523
|
var DEFAULT_BASE_URL = "https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1";
|
|
358
524
|
var DEFAULT_TIMEOUT_MS = 4e3;
|
|
@@ -498,6 +664,16 @@ var AttentionMarketClient = class {
|
|
|
498
664
|
const limitedHistory = history.slice(-historyLimit);
|
|
499
665
|
const contextParts = [...limitedHistory, params.userMessage];
|
|
500
666
|
const context = contextParts.join("\n");
|
|
667
|
+
const intentStage = params.session_context?.intent_stage || detectIntentStage(params.userMessage, limitedHistory);
|
|
668
|
+
let interests = params.user_context?.interests || extractInterests(params.userMessage, limitedHistory);
|
|
669
|
+
interests = interests.filter((interest) => typeof interest === "string" && interest.trim().length > 0).map((interest) => interest.trim().toLowerCase()).slice(0, 10);
|
|
670
|
+
let recentTopics = params.user_context?.recent_topics || extractTopics(limitedHistory);
|
|
671
|
+
recentTopics = recentTopics.filter((topic) => typeof topic === "string" && topic.trim().length > 0).map((topic) => topic.trim().toLowerCase()).slice(0, 5);
|
|
672
|
+
const purchaseIntent = params.user_context?.purchase_intent !== void 0 ? Boolean(params.user_context.purchase_intent) : detectPurchaseIntent(params.userMessage, intentStage);
|
|
673
|
+
const rawSessionId = params.session_context?.session_id;
|
|
674
|
+
const sessionId = typeof rawSessionId === "string" && rawSessionId.trim().length > 0 ? rawSessionId.trim().slice(0, 100) : generateSessionId();
|
|
675
|
+
const rawMessageCount = params.session_context?.message_count;
|
|
676
|
+
const messageCount = typeof rawMessageCount === "number" && rawMessageCount >= 0 ? Math.min(rawMessageCount, 1e3) : calculateMessageCount(limitedHistory);
|
|
501
677
|
const country = params.country || "US";
|
|
502
678
|
const language = params.language || "en";
|
|
503
679
|
const platform = params.platform || "web";
|
|
@@ -586,6 +762,23 @@ var AttentionMarketClient = class {
|
|
|
586
762
|
user_intent: params.userMessage,
|
|
587
763
|
// Use minimal response format by default for better performance
|
|
588
764
|
response_format: "minimal",
|
|
765
|
+
// === Smart Context Fields (v0.15.0) ===
|
|
766
|
+
// Include user context if we have any data
|
|
767
|
+
...(interests.length > 0 || recentTopics.length > 0 || purchaseIntent) && {
|
|
768
|
+
user_context: {
|
|
769
|
+
...interests.length > 0 && { interests },
|
|
770
|
+
...recentTopics.length > 0 && { recent_topics: recentTopics },
|
|
771
|
+
...purchaseIntent && { purchase_intent: purchaseIntent }
|
|
772
|
+
}
|
|
773
|
+
},
|
|
774
|
+
// Include session context
|
|
775
|
+
...sessionId && {
|
|
776
|
+
session_context: {
|
|
777
|
+
session_id: sessionId,
|
|
778
|
+
message_count: messageCount,
|
|
779
|
+
...intentStage && { intent_stage: intentStage }
|
|
780
|
+
}
|
|
781
|
+
},
|
|
589
782
|
// Developer controls (Phase 1: Quality & Brand Safety)
|
|
590
783
|
...params.minQualityScore !== void 0 && { minQualityScore: params.minQualityScore },
|
|
591
784
|
...params.allowedCategories && { allowedCategories: params.allowedCategories },
|