@the_ro_show/agent-ads-sdk 0.16.0 → 0.17.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.
- package/README.md +171 -11
- package/dist/index.d.mts +63 -39
- package/dist/index.d.ts +63 -39
- package/dist/index.js +19 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +19 -58
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -46,6 +46,35 @@ if (ad) {
|
|
|
46
46
|
}
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
## How You Earn Money
|
|
50
|
+
|
|
51
|
+
AttentionMarket pays you when users **click** sponsored content. It's that simple.
|
|
52
|
+
|
|
53
|
+
### Revenue Formula
|
|
54
|
+
```
|
|
55
|
+
Your Earnings = Clicks × Payout Per Click
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Every response shows exactly what you'll earn:
|
|
59
|
+
```typescript
|
|
60
|
+
{
|
|
61
|
+
"payout": 250, // You earn $2.50 when clicked
|
|
62
|
+
"click_url": "https://...",
|
|
63
|
+
"creative": { title: "...", body: "..." }
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Why We Track Impressions
|
|
68
|
+
|
|
69
|
+
Impressions prevent click fraud. If sponsored content wasn't shown, clicks won't generate revenue.
|
|
70
|
+
|
|
71
|
+
**Important:**
|
|
72
|
+
- ✅ Impressions are **required** for clicks to count
|
|
73
|
+
- ❌ Impressions do **NOT** generate revenue themselves
|
|
74
|
+
- ✅ The SDK tracks impressions automatically
|
|
75
|
+
|
|
76
|
+
Think of impressions as a receipt: "Yes, this content was actually shown to a real user."
|
|
77
|
+
|
|
49
78
|
## Smart Context (v0.15.1+) 🎯
|
|
50
79
|
|
|
51
80
|
Improve ad relevance by 2-3x with smart context features that understand user intent better:
|
|
@@ -176,17 +205,16 @@ const client = new AttentionMarketClient({
|
|
|
176
205
|
|
|
177
206
|
```typescript
|
|
178
207
|
const client = new AttentionMarketClient({
|
|
179
|
-
apiKey: 'am_live_YOUR_KEY',
|
|
180
|
-
agentId: 'agt_YOUR_AGENT_ID',
|
|
181
|
-
supabaseAnonKey: 'YOUR_ANON_KEY', // Required: Get from dashboard
|
|
208
|
+
apiKey: 'am_live_YOUR_KEY', // Required: Your AttentionMarket API key
|
|
209
|
+
agentId: 'agt_YOUR_AGENT_ID', // Required for decideFromContext()
|
|
182
210
|
// baseUrl defaults to production Supabase endpoint
|
|
183
211
|
// Only override if self-hosting or using different environment
|
|
184
|
-
timeoutMs: 4000,
|
|
185
|
-
maxRetries: 2
|
|
212
|
+
timeoutMs: 4000, // Optional: request timeout in milliseconds
|
|
213
|
+
maxRetries: 2 // Optional: automatic retry count
|
|
186
214
|
});
|
|
187
215
|
```
|
|
188
216
|
|
|
189
|
-
**Note:**
|
|
217
|
+
**Note:** Get your API key and agent ID from your [developer dashboard](https://api.attentionmarket.ai).
|
|
190
218
|
|
|
191
219
|
## Core Concepts
|
|
192
220
|
|
|
@@ -376,10 +404,10 @@ const ad = await client.decideFromContext({
|
|
|
376
404
|
**Validation:** Must be a non-negative number.
|
|
377
405
|
|
|
378
406
|
**Use cases:**
|
|
379
|
-
- Premium applications: `200+` for $2+
|
|
407
|
+
- Premium applications: `200+` for $2+ per click only
|
|
380
408
|
- High-value verticals: Filter out low-budget advertisers
|
|
381
|
-
- Revenue targets: Ensure minimum
|
|
382
|
-
- Lower fill rate tolerance: When you'd rather show nothing than
|
|
409
|
+
- Revenue targets: Ensure minimum earnings when clicked
|
|
410
|
+
- Lower fill rate tolerance: When you'd rather show nothing than low-value content
|
|
383
411
|
|
|
384
412
|
**Trade-off:** Higher thresholds = higher revenue per ad but lower fill rate.
|
|
385
413
|
|
|
@@ -550,13 +578,20 @@ Clicks are automatically and securely tracked when users visit the `click_url`.
|
|
|
550
578
|
**Important:** Always use the provided `click_url` or `tracking_url` for click tracking. These URLs contain HMAC-signed tokens that prevent click fraud and ensure accurate attribution.
|
|
551
579
|
|
|
552
580
|
```typescript
|
|
553
|
-
|
|
554
|
-
|
|
581
|
+
import { sanitizeURL } from '@the_ro_show/agent-ads-sdk';
|
|
582
|
+
|
|
583
|
+
// When user clicks the ad, sanitize URL for security
|
|
584
|
+
const safeURL = sanitizeURL(ad.click_url);
|
|
585
|
+
if (safeURL) {
|
|
586
|
+
window.location.href = safeURL;
|
|
587
|
+
}
|
|
555
588
|
|
|
556
589
|
// Or in a chat/messaging context, share:
|
|
557
590
|
const shareableLink = ad.tracking_url;
|
|
558
591
|
```
|
|
559
592
|
|
|
593
|
+
**Security Note:** While our backend validates all URLs, it's recommended to use the `sanitizeURL()` helper to protect against potential XSS attacks if the backend is ever compromised or misconfigured.
|
|
594
|
+
|
|
560
595
|
Manual click tracking has been removed for security reasons. All clicks must go through the redirect URLs to ensure fraud prevention and accurate tracking.
|
|
561
596
|
|
|
562
597
|
### Conversion Tracking
|
|
@@ -580,6 +615,122 @@ await client.track({
|
|
|
580
615
|
});
|
|
581
616
|
```
|
|
582
617
|
|
|
618
|
+
### Developer Prediction System (Bonus Earnings)
|
|
619
|
+
|
|
620
|
+
**Get paid more for accurate predictions!** After showing an ad, predict whether the user will convert. If you're right, earn a bonus:
|
|
621
|
+
- ✅ Correct positive prediction → **+20% bonus**
|
|
622
|
+
- ✅ Correct negative prediction → **+5% bonus**
|
|
623
|
+
- ⚠️ Wrong prediction → No bonus (but no penalty)
|
|
624
|
+
|
|
625
|
+
#### How It Works
|
|
626
|
+
|
|
627
|
+
1. **Show the ad** to your user using `decideFromContext()`
|
|
628
|
+
2. **Observe their reaction** (interested? asked questions? changed topic?)
|
|
629
|
+
3. **Send feedback** with your prediction
|
|
630
|
+
4. **Get bonus** 7 days later if you were right
|
|
631
|
+
|
|
632
|
+
#### Option 1: Auto-Analysis (Recommended - Easiest)
|
|
633
|
+
|
|
634
|
+
Just send the user's raw response, and our AI analyzes sentiment automatically:
|
|
635
|
+
|
|
636
|
+
```typescript
|
|
637
|
+
const ad = await client.decideFromContext({
|
|
638
|
+
userMessage: "I need car insurance",
|
|
639
|
+
placement: 'sponsored_suggestion'
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
// Show ad to user...
|
|
643
|
+
// User responds: "Tell me more about that Geico offer!"
|
|
644
|
+
|
|
645
|
+
await client.sendFeedback({
|
|
646
|
+
tracking_token: ad.tracking_token,
|
|
647
|
+
user_response: "Tell me more about that Geico offer!",
|
|
648
|
+
conversation_history: [
|
|
649
|
+
"User: I need car insurance",
|
|
650
|
+
"Agent: Check out Geico...",
|
|
651
|
+
"User: Tell me more about that Geico offer!"
|
|
652
|
+
]
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
// Our AI detects: "positive" sentiment
|
|
656
|
+
// You get base earnings + 20% bonus if user converts
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
**When to use:** You want simplicity. Let our AI handle sentiment analysis.
|
|
660
|
+
|
|
661
|
+
#### Option 2: Manual Prediction (Advanced - Full Control)
|
|
662
|
+
|
|
663
|
+
Analyze sentiment yourself and send your prediction:
|
|
664
|
+
|
|
665
|
+
```typescript
|
|
666
|
+
const ad = await client.decideFromContext({
|
|
667
|
+
userMessage: "I need car insurance",
|
|
668
|
+
placement: 'sponsored_suggestion'
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
// Show ad to user...
|
|
672
|
+
// User responds: "No thanks, I already have insurance"
|
|
673
|
+
|
|
674
|
+
// YOU analyze: User declined → predict negative
|
|
675
|
+
await client.sendFeedback({
|
|
676
|
+
tracking_token: ad.tracking_token,
|
|
677
|
+
reaction: 'negative', // You determine this
|
|
678
|
+
context: 'User already has insurance, politely declined'
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
// If user doesn't convert, you get +5% bonus
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
**When to use:** You want full control over sentiment classification, or you have your own sentiment analysis.
|
|
685
|
+
|
|
686
|
+
#### Prediction Guidelines
|
|
687
|
+
|
|
688
|
+
**Positive** - User shows interest:
|
|
689
|
+
- "Tell me more!"
|
|
690
|
+
- "How much does it cost?"
|
|
691
|
+
- "Can you sign me up?"
|
|
692
|
+
- Asks follow-up questions
|
|
693
|
+
|
|
694
|
+
**Neutral** - Hard to tell:
|
|
695
|
+
- "Maybe later"
|
|
696
|
+
- "I'll think about it"
|
|
697
|
+
- No clear response
|
|
698
|
+
- Non-committal
|
|
699
|
+
|
|
700
|
+
**Negative** - User not interested:
|
|
701
|
+
- "No thanks"
|
|
702
|
+
- "I already have that"
|
|
703
|
+
- Changes topic immediately
|
|
704
|
+
- Explicitly declines
|
|
705
|
+
|
|
706
|
+
#### Response Format
|
|
707
|
+
|
|
708
|
+
```typescript
|
|
709
|
+
{
|
|
710
|
+
status: 'received',
|
|
711
|
+
feedback_id: 'evt_abc123',
|
|
712
|
+
potential_bonus: '20%',
|
|
713
|
+
resolution_date: '2026-03-13',
|
|
714
|
+
message: 'Feedback recorded. Bonus will be calculated after 7-day conversion window.',
|
|
715
|
+
|
|
716
|
+
// Only in auto-analysis mode:
|
|
717
|
+
sentiment_detected: 'positive',
|
|
718
|
+
analysis_mode: 'auto'
|
|
719
|
+
}
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
#### Best Practices
|
|
723
|
+
|
|
724
|
+
1. **Submit within 24 hours** - Feedback must be sent within 24 hours of showing the ad
|
|
725
|
+
2. **One prediction per ad** - You can only submit feedback once per tracking_token
|
|
726
|
+
3. **Be honest** - Don't predict "positive" for everything. Our system rewards accuracy, not volume
|
|
727
|
+
4. **Use context** - Include conversation history for better auto-analysis
|
|
728
|
+
5. **Skip when unsure** - No feedback is better than random guessing
|
|
729
|
+
|
|
730
|
+
#### Cost of Auto-Analysis
|
|
731
|
+
|
|
732
|
+
Auto-analysis costs ~$0.0001 per request (using GPT-3.5-turbo). We absorb this cost, so it's free for you. The better accuracy and developer experience is worth it.
|
|
733
|
+
|
|
583
734
|
## Error Handling
|
|
584
735
|
|
|
585
736
|
The SDK throws errors for invalid configurations and failed requests:
|
|
@@ -698,6 +849,15 @@ Create a simple getRelevantAd(message) function that returns ads only when relev
|
|
|
698
849
|
|
|
699
850
|
## Changelog
|
|
700
851
|
|
|
852
|
+
### v0.17.0 (2026-03-06) - AI-Powered Feedback Analysis
|
|
853
|
+
- 🤖 **Auto-Analysis Mode:** Send raw user responses, our AI detects sentiment automatically
|
|
854
|
+
- 💰 **Bonus Earnings:** +20% for correct positive predictions, +5% for correct negative predictions
|
|
855
|
+
- 🔄 **Backward Compatible:** Existing manual `reaction` mode still supported
|
|
856
|
+
- 📊 **Conversation Context:** Include conversation history for better sentiment analysis
|
|
857
|
+
- ⚡ **Fast & Cheap:** GPT-3.5-turbo analysis (~$0.0001 per request, free for developers)
|
|
858
|
+
- 🎯 **Fallback Logic:** Defaults to 'neutral' if AI analysis fails
|
|
859
|
+
- 📝 **Enhanced Logging:** Track analysis_mode and sentiment_confidence in metadata
|
|
860
|
+
|
|
701
861
|
### v0.15.1 (2026-02-26) - Bug Fixes & Security
|
|
702
862
|
- 🔒 Fixed session leak - sessionId now request-scoped, not instance-scoped
|
|
703
863
|
- 🛡️ Added comprehensive input validation and sanitization
|
package/dist/index.d.mts
CHANGED
|
@@ -82,7 +82,8 @@ interface DecideFromContextRequest {
|
|
|
82
82
|
placement?: PlacementType;
|
|
83
83
|
/**
|
|
84
84
|
* Optional category hint (e.g., 'legal', 'insurance', 'travel').
|
|
85
|
-
*
|
|
85
|
+
* Defaults to 'general.query'. Only used as fallback - semantic matching
|
|
86
|
+
* uses conversation context, not taxonomy.
|
|
86
87
|
*/
|
|
87
88
|
suggestedCategory?: string;
|
|
88
89
|
/** User's country code. Default: 'US' */
|
|
@@ -293,44 +294,63 @@ interface EventIngestRequest {
|
|
|
293
294
|
interface EventIngestResponse {
|
|
294
295
|
accepted: boolean;
|
|
295
296
|
}
|
|
296
|
-
/**
|
|
297
|
-
* Sentiment types detected by backend AI analysis.
|
|
298
|
-
*
|
|
299
|
-
* - positive: User is interested/engaged (earn +15% if converts, -5% if not)
|
|
300
|
-
* - neutral: User is indifferent (no bonus/penalty, data only)
|
|
301
|
-
* - negative: User disliked the ad (no penalty, data only)
|
|
302
|
-
*/
|
|
303
|
-
type FeedbackSentiment = 'positive' | 'neutral' | 'negative';
|
|
304
297
|
/**
|
|
305
298
|
* Send feedback on an ad after showing it to a user.
|
|
306
299
|
*
|
|
307
|
-
* **
|
|
308
|
-
* Just send the user's actual response text - no need to classify it yourself.
|
|
300
|
+
* **Two modes available:**
|
|
309
301
|
*
|
|
310
|
-
* **
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
302
|
+
* **Auto-Analysis (Recommended):** Send the user's raw response, and our AI analyzes sentiment.
|
|
303
|
+
* ```typescript
|
|
304
|
+
* await client.sendFeedback({
|
|
305
|
+
* tracking_token: ad.tracking_token,
|
|
306
|
+
* user_response: "Tell me more about that!",
|
|
307
|
+
* conversation_history: ["Previous message 1", "Previous message 2"]
|
|
308
|
+
* });
|
|
309
|
+
* ```
|
|
314
310
|
*
|
|
315
|
-
*
|
|
311
|
+
* **Manual Prediction:** Analyze sentiment yourself and send the prediction.
|
|
316
312
|
* ```typescript
|
|
317
313
|
* await client.sendFeedback({
|
|
318
314
|
* tracking_token: ad.tracking_token,
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
* additional_context: "User spent 2 minutes reading the offer"
|
|
315
|
+
* reaction: 'positive', // You determine this
|
|
316
|
+
* context: 'User asked follow-up questions'
|
|
322
317
|
* });
|
|
323
318
|
* ```
|
|
319
|
+
*
|
|
320
|
+
* **Bonuses (7-day deferred):**
|
|
321
|
+
* - Correct positive prediction → +20% bonus
|
|
322
|
+
* - Correct negative prediction → +5% bonus
|
|
323
|
+
* - Wrong prediction or no feedback → No bonus
|
|
324
324
|
*/
|
|
325
325
|
interface FeedbackRequest {
|
|
326
|
-
/** Tracking token from the ad you showed */
|
|
326
|
+
/** Tracking token from the ad you showed (required) */
|
|
327
327
|
tracking_token: string;
|
|
328
|
-
/**
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
328
|
+
/**
|
|
329
|
+
* OPTION 1 (Auto-Analysis): User's actual response text.
|
|
330
|
+
* Our AI will analyze sentiment and determine positive/neutral/negative.
|
|
331
|
+
* Max 2000 characters.
|
|
332
|
+
*/
|
|
333
|
+
user_response?: string;
|
|
334
|
+
/**
|
|
335
|
+
* Conversation history for better context in auto-analysis.
|
|
336
|
+
* We use the last 3 messages to understand the conversation flow.
|
|
337
|
+
*/
|
|
338
|
+
conversation_history?: string[];
|
|
339
|
+
/**
|
|
340
|
+
* OPTION 2 (Manual): Your prediction of user interest.
|
|
341
|
+
* Use this if you want full control over sentiment classification.
|
|
342
|
+
*/
|
|
343
|
+
reaction?: 'positive' | 'neutral' | 'negative';
|
|
344
|
+
/**
|
|
345
|
+
* Additional context about the interaction (optional, both modes).
|
|
346
|
+
* Max 1000 characters.
|
|
347
|
+
*/
|
|
348
|
+
context?: string;
|
|
349
|
+
/**
|
|
350
|
+
* Idempotency key for safe retries (optional).
|
|
351
|
+
* Use the same key if retrying a failed request to avoid duplicate feedback.
|
|
352
|
+
*/
|
|
353
|
+
idempotency_key?: string;
|
|
334
354
|
}
|
|
335
355
|
/**
|
|
336
356
|
* Response from sending feedback.
|
|
@@ -339,18 +359,27 @@ interface FeedbackRequest {
|
|
|
339
359
|
* based on whether the user actually converted.
|
|
340
360
|
*/
|
|
341
361
|
interface FeedbackResponse {
|
|
342
|
-
/**
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
|
|
346
|
-
/** Potential bonus if prediction is correct (
|
|
362
|
+
/** Status of feedback submission */
|
|
363
|
+
status: 'received';
|
|
364
|
+
/** Unique ID for this feedback event */
|
|
365
|
+
feedback_id: string;
|
|
366
|
+
/** Potential bonus if prediction is correct (20% for positive, 5% for negative) */
|
|
347
367
|
potential_bonus: string;
|
|
348
|
-
/** Potential penalty if prediction is wrong */
|
|
349
|
-
potential_penalty: string;
|
|
350
368
|
/** Explanation of the deferred bonus system */
|
|
351
369
|
message: string;
|
|
352
|
-
/** When the bonus will be resolved (7 days from
|
|
370
|
+
/** When the bonus will be resolved (7 days from impression, YYYY-MM-DD) */
|
|
353
371
|
resolution_date: string;
|
|
372
|
+
/**
|
|
373
|
+
* AI-detected sentiment (only present in auto-analysis mode).
|
|
374
|
+
* Shows what sentiment our AI detected from the user response.
|
|
375
|
+
*/
|
|
376
|
+
sentiment_detected?: 'positive' | 'neutral' | 'negative';
|
|
377
|
+
/**
|
|
378
|
+
* Analysis mode used (only present in auto-analysis or fallback modes).
|
|
379
|
+
* - 'auto': AI analyzed sentiment
|
|
380
|
+
* - 'fallback': AI failed, defaulted to neutral
|
|
381
|
+
*/
|
|
382
|
+
analysis_mode?: 'auto' | 'fallback';
|
|
354
383
|
}
|
|
355
384
|
interface PolicyResponse {
|
|
356
385
|
version: string;
|
|
@@ -850,11 +879,6 @@ declare class AttentionMarketClient {
|
|
|
850
879
|
private agentId;
|
|
851
880
|
private appId;
|
|
852
881
|
constructor(config: SDKConfig);
|
|
853
|
-
/**
|
|
854
|
-
* Infer taxonomy from user message using keyword matching
|
|
855
|
-
* Returns best-guess taxonomy based on common patterns
|
|
856
|
-
*/
|
|
857
|
-
private inferTaxonomy;
|
|
858
882
|
/**
|
|
859
883
|
* Validate SDK configuration for security
|
|
860
884
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -82,7 +82,8 @@ interface DecideFromContextRequest {
|
|
|
82
82
|
placement?: PlacementType;
|
|
83
83
|
/**
|
|
84
84
|
* Optional category hint (e.g., 'legal', 'insurance', 'travel').
|
|
85
|
-
*
|
|
85
|
+
* Defaults to 'general.query'. Only used as fallback - semantic matching
|
|
86
|
+
* uses conversation context, not taxonomy.
|
|
86
87
|
*/
|
|
87
88
|
suggestedCategory?: string;
|
|
88
89
|
/** User's country code. Default: 'US' */
|
|
@@ -293,44 +294,63 @@ interface EventIngestRequest {
|
|
|
293
294
|
interface EventIngestResponse {
|
|
294
295
|
accepted: boolean;
|
|
295
296
|
}
|
|
296
|
-
/**
|
|
297
|
-
* Sentiment types detected by backend AI analysis.
|
|
298
|
-
*
|
|
299
|
-
* - positive: User is interested/engaged (earn +15% if converts, -5% if not)
|
|
300
|
-
* - neutral: User is indifferent (no bonus/penalty, data only)
|
|
301
|
-
* - negative: User disliked the ad (no penalty, data only)
|
|
302
|
-
*/
|
|
303
|
-
type FeedbackSentiment = 'positive' | 'neutral' | 'negative';
|
|
304
297
|
/**
|
|
305
298
|
* Send feedback on an ad after showing it to a user.
|
|
306
299
|
*
|
|
307
|
-
* **
|
|
308
|
-
* Just send the user's actual response text - no need to classify it yourself.
|
|
300
|
+
* **Two modes available:**
|
|
309
301
|
*
|
|
310
|
-
* **
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
302
|
+
* **Auto-Analysis (Recommended):** Send the user's raw response, and our AI analyzes sentiment.
|
|
303
|
+
* ```typescript
|
|
304
|
+
* await client.sendFeedback({
|
|
305
|
+
* tracking_token: ad.tracking_token,
|
|
306
|
+
* user_response: "Tell me more about that!",
|
|
307
|
+
* conversation_history: ["Previous message 1", "Previous message 2"]
|
|
308
|
+
* });
|
|
309
|
+
* ```
|
|
314
310
|
*
|
|
315
|
-
*
|
|
311
|
+
* **Manual Prediction:** Analyze sentiment yourself and send the prediction.
|
|
316
312
|
* ```typescript
|
|
317
313
|
* await client.sendFeedback({
|
|
318
314
|
* tracking_token: ad.tracking_token,
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
* additional_context: "User spent 2 minutes reading the offer"
|
|
315
|
+
* reaction: 'positive', // You determine this
|
|
316
|
+
* context: 'User asked follow-up questions'
|
|
322
317
|
* });
|
|
323
318
|
* ```
|
|
319
|
+
*
|
|
320
|
+
* **Bonuses (7-day deferred):**
|
|
321
|
+
* - Correct positive prediction → +20% bonus
|
|
322
|
+
* - Correct negative prediction → +5% bonus
|
|
323
|
+
* - Wrong prediction or no feedback → No bonus
|
|
324
324
|
*/
|
|
325
325
|
interface FeedbackRequest {
|
|
326
|
-
/** Tracking token from the ad you showed */
|
|
326
|
+
/** Tracking token from the ad you showed (required) */
|
|
327
327
|
tracking_token: string;
|
|
328
|
-
/**
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
328
|
+
/**
|
|
329
|
+
* OPTION 1 (Auto-Analysis): User's actual response text.
|
|
330
|
+
* Our AI will analyze sentiment and determine positive/neutral/negative.
|
|
331
|
+
* Max 2000 characters.
|
|
332
|
+
*/
|
|
333
|
+
user_response?: string;
|
|
334
|
+
/**
|
|
335
|
+
* Conversation history for better context in auto-analysis.
|
|
336
|
+
* We use the last 3 messages to understand the conversation flow.
|
|
337
|
+
*/
|
|
338
|
+
conversation_history?: string[];
|
|
339
|
+
/**
|
|
340
|
+
* OPTION 2 (Manual): Your prediction of user interest.
|
|
341
|
+
* Use this if you want full control over sentiment classification.
|
|
342
|
+
*/
|
|
343
|
+
reaction?: 'positive' | 'neutral' | 'negative';
|
|
344
|
+
/**
|
|
345
|
+
* Additional context about the interaction (optional, both modes).
|
|
346
|
+
* Max 1000 characters.
|
|
347
|
+
*/
|
|
348
|
+
context?: string;
|
|
349
|
+
/**
|
|
350
|
+
* Idempotency key for safe retries (optional).
|
|
351
|
+
* Use the same key if retrying a failed request to avoid duplicate feedback.
|
|
352
|
+
*/
|
|
353
|
+
idempotency_key?: string;
|
|
334
354
|
}
|
|
335
355
|
/**
|
|
336
356
|
* Response from sending feedback.
|
|
@@ -339,18 +359,27 @@ interface FeedbackRequest {
|
|
|
339
359
|
* based on whether the user actually converted.
|
|
340
360
|
*/
|
|
341
361
|
interface FeedbackResponse {
|
|
342
|
-
/**
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
|
|
346
|
-
/** Potential bonus if prediction is correct (
|
|
362
|
+
/** Status of feedback submission */
|
|
363
|
+
status: 'received';
|
|
364
|
+
/** Unique ID for this feedback event */
|
|
365
|
+
feedback_id: string;
|
|
366
|
+
/** Potential bonus if prediction is correct (20% for positive, 5% for negative) */
|
|
347
367
|
potential_bonus: string;
|
|
348
|
-
/** Potential penalty if prediction is wrong */
|
|
349
|
-
potential_penalty: string;
|
|
350
368
|
/** Explanation of the deferred bonus system */
|
|
351
369
|
message: string;
|
|
352
|
-
/** When the bonus will be resolved (7 days from
|
|
370
|
+
/** When the bonus will be resolved (7 days from impression, YYYY-MM-DD) */
|
|
353
371
|
resolution_date: string;
|
|
372
|
+
/**
|
|
373
|
+
* AI-detected sentiment (only present in auto-analysis mode).
|
|
374
|
+
* Shows what sentiment our AI detected from the user response.
|
|
375
|
+
*/
|
|
376
|
+
sentiment_detected?: 'positive' | 'neutral' | 'negative';
|
|
377
|
+
/**
|
|
378
|
+
* Analysis mode used (only present in auto-analysis or fallback modes).
|
|
379
|
+
* - 'auto': AI analyzed sentiment
|
|
380
|
+
* - 'fallback': AI failed, defaulted to neutral
|
|
381
|
+
*/
|
|
382
|
+
analysis_mode?: 'auto' | 'fallback';
|
|
354
383
|
}
|
|
355
384
|
interface PolicyResponse {
|
|
356
385
|
version: string;
|
|
@@ -850,11 +879,6 @@ declare class AttentionMarketClient {
|
|
|
850
879
|
private agentId;
|
|
851
880
|
private appId;
|
|
852
881
|
constructor(config: SDKConfig);
|
|
853
|
-
/**
|
|
854
|
-
* Infer taxonomy from user message using keyword matching
|
|
855
|
-
* Returns best-guess taxonomy based on common patterns
|
|
856
|
-
*/
|
|
857
|
-
private inferTaxonomy;
|
|
858
882
|
/**
|
|
859
883
|
* Validate SDK configuration for security
|
|
860
884
|
*/
|
package/dist/index.js
CHANGED
|
@@ -516,59 +516,6 @@ var AttentionMarketClient = class {
|
|
|
516
516
|
}
|
|
517
517
|
this.http = new HTTPClient(httpConfig);
|
|
518
518
|
}
|
|
519
|
-
/**
|
|
520
|
-
* Infer taxonomy from user message using keyword matching
|
|
521
|
-
* Returns best-guess taxonomy based on common patterns
|
|
522
|
-
*/
|
|
523
|
-
inferTaxonomy(userMessage) {
|
|
524
|
-
const msg = userMessage.toLowerCase();
|
|
525
|
-
if (msg.match(/\b(ecommerce|e-commerce|online store|shopify|sell products?|product brand)\b/)) {
|
|
526
|
-
return "business.ecommerce.platform.trial";
|
|
527
|
-
}
|
|
528
|
-
if (msg.match(/\b(start.*business|launch.*business|business formation|llc|incorporate)\b/)) {
|
|
529
|
-
return "business.ecommerce.platform.trial";
|
|
530
|
-
}
|
|
531
|
-
if (msg.match(/\b(car insurance|auto insurance|vehicle insurance)\b/)) {
|
|
532
|
-
return "insurance.auto.full_coverage.quote";
|
|
533
|
-
}
|
|
534
|
-
if (msg.match(/\b(health insurance|medical insurance)\b/)) {
|
|
535
|
-
return "insurance.health.individual.quote";
|
|
536
|
-
}
|
|
537
|
-
if (msg.match(/\b(life insurance)\b/)) {
|
|
538
|
-
return "insurance.life.term.quote";
|
|
539
|
-
}
|
|
540
|
-
if (msg.match(/\b(insurance)\b/)) {
|
|
541
|
-
return "insurance.auto.full_coverage.quote";
|
|
542
|
-
}
|
|
543
|
-
if (msg.match(/\b(personal loan|debt consolidation|borrow money)\b/)) {
|
|
544
|
-
return "finance.loans.personal.apply";
|
|
545
|
-
}
|
|
546
|
-
if (msg.match(/\b(credit card)\b/)) {
|
|
547
|
-
return "finance.credit_cards.rewards.apply";
|
|
548
|
-
}
|
|
549
|
-
if (msg.match(/\b(mover?s?|moving|relocat(e|ing))\b/)) {
|
|
550
|
-
return "home_services.moving.local.quote";
|
|
551
|
-
}
|
|
552
|
-
if (msg.match(/\b(plumber|plumbing|leak|pipe)\b/)) {
|
|
553
|
-
return "home_services.plumbing.emergency.quote";
|
|
554
|
-
}
|
|
555
|
-
if (msg.match(/\b(electrician|electrical|wiring)\b/)) {
|
|
556
|
-
return "home_services.electrical.repair.quote";
|
|
557
|
-
}
|
|
558
|
-
if (msg.match(/\b(clean(ing|er)|maid service)\b/)) {
|
|
559
|
-
return "home_services.cleaning.regular.book";
|
|
560
|
-
}
|
|
561
|
-
if (msg.match(/\b(hotel|lodging|accommodation)\b/)) {
|
|
562
|
-
return "travel.hotels.luxury.book";
|
|
563
|
-
}
|
|
564
|
-
if (msg.match(/\b(flight|plane ticket|airfare)\b/)) {
|
|
565
|
-
return "travel.flights.domestic.book";
|
|
566
|
-
}
|
|
567
|
-
if (msg.match(/\b(lawyer|attorney|legal help)\b/)) {
|
|
568
|
-
return "legal.general.consultation";
|
|
569
|
-
}
|
|
570
|
-
return "business.ecommerce.platform.trial";
|
|
571
|
-
}
|
|
572
519
|
/**
|
|
573
520
|
* Validate SDK configuration for security
|
|
574
521
|
*/
|
|
@@ -652,7 +599,7 @@ var AttentionMarketClient = class {
|
|
|
652
599
|
const language = params.language || "en";
|
|
653
600
|
const platform = params.platform || "web";
|
|
654
601
|
const placementType = params.placement || "sponsored_suggestion";
|
|
655
|
-
const taxonomy = params.suggestedCategory ||
|
|
602
|
+
const taxonomy = params.suggestedCategory || "general.query";
|
|
656
603
|
if (params.minQualityScore !== void 0) {
|
|
657
604
|
if (typeof params.minQualityScore !== "number" || params.minQualityScore < 0 || params.minQualityScore > 1) {
|
|
658
605
|
throw new Error("minQualityScore must be a number between 0.0 and 1.0");
|
|
@@ -707,6 +654,11 @@ var AttentionMarketClient = class {
|
|
|
707
654
|
if (params.optimizeFor && params.optimizeFor !== "revenue" && params.optimizeFor !== "relevance") {
|
|
708
655
|
throw new Error('optimizeFor must be either "revenue" or "relevance"');
|
|
709
656
|
}
|
|
657
|
+
const validFormats = ["minimal", "standard", "verbose"];
|
|
658
|
+
const responseFormat = params.response_format || "minimal";
|
|
659
|
+
if (!validFormats.includes(responseFormat)) {
|
|
660
|
+
throw new Error(`response_format must be one of: ${validFormats.join(", ")}. Got: ${responseFormat}`);
|
|
661
|
+
}
|
|
710
662
|
const request = {
|
|
711
663
|
request_id: generateUUID(),
|
|
712
664
|
agent_id: this.agentId,
|
|
@@ -735,7 +687,7 @@ var AttentionMarketClient = class {
|
|
|
735
687
|
context,
|
|
736
688
|
user_intent: params.userMessage,
|
|
737
689
|
// Use minimal response format by default for better performance
|
|
738
|
-
response_format:
|
|
690
|
+
response_format: responseFormat,
|
|
739
691
|
// === Smart Context Fields (v0.15.0) ===
|
|
740
692
|
// Include user context if we have any data
|
|
741
693
|
...(interests.length > 0 || recentTopics.length > 0 || purchaseIntent) && {
|
|
@@ -778,7 +730,11 @@ var AttentionMarketClient = class {
|
|
|
778
730
|
tracking_token: response.tracking_token
|
|
779
731
|
});
|
|
780
732
|
} catch (error) {
|
|
781
|
-
console.
|
|
733
|
+
console.error("[AttentionMarket] REVENUE RISK: Failed to auto-track impression. Clicks without impressions will NOT earn revenue.", {
|
|
734
|
+
error: error instanceof Error ? error.message : String(error),
|
|
735
|
+
tracking_token: response.tracking_token,
|
|
736
|
+
unit_id: response["_meta"]?.["unit_id"]
|
|
737
|
+
});
|
|
782
738
|
}
|
|
783
739
|
}
|
|
784
740
|
const adResponse2 = {
|
|
@@ -823,7 +779,11 @@ var AttentionMarketClient = class {
|
|
|
823
779
|
tracking_token: adUnit.tracking.token
|
|
824
780
|
});
|
|
825
781
|
} catch (error) {
|
|
826
|
-
console.
|
|
782
|
+
console.error("[AttentionMarket] REVENUE RISK: Failed to auto-track impression. Clicks without impressions will NOT earn revenue.", {
|
|
783
|
+
error: error instanceof Error ? error.message : String(error),
|
|
784
|
+
tracking_token: adUnit.tracking.token,
|
|
785
|
+
unit_id: adUnit.unit_id
|
|
786
|
+
});
|
|
827
787
|
}
|
|
828
788
|
const adResponse = {
|
|
829
789
|
request_id: response.request_id,
|
|
@@ -1173,7 +1133,7 @@ var AttentionMarketClient = class {
|
|
|
1173
1133
|
const context = contextParts.join("\n");
|
|
1174
1134
|
const country = params.context?.geo?.country || "US";
|
|
1175
1135
|
const language = this.normalizeLocale(params.context?.locale);
|
|
1176
|
-
const taxonomy = params.suggestedCategory || "
|
|
1136
|
+
const taxonomy = params.suggestedCategory || "general.query";
|
|
1177
1137
|
const idempotencyKey = options?.idempotencyKey || generateUUID();
|
|
1178
1138
|
const request = {
|
|
1179
1139
|
request_id: idempotencyKey,
|
|
@@ -1433,6 +1393,7 @@ var AttentionMarketClient = class {
|
|
|
1433
1393
|
url
|
|
1434
1394
|
);
|
|
1435
1395
|
}
|
|
1396
|
+
// TODO: Add getDeveloperMetrics() method when DeveloperMetricsResponse type is defined
|
|
1436
1397
|
};
|
|
1437
1398
|
|
|
1438
1399
|
// src/mock-client.ts
|