@the_ro_show/agent-ads-sdk 0.13.3 → 0.14.2

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 CHANGED
@@ -368,6 +368,65 @@ const ad = await client.decideFromContext({
368
368
  });
369
369
  ```
370
370
 
371
+ ## Performance Optimization
372
+
373
+ ### Payload Optimization (v0.14.0+)
374
+
375
+ The SDK automatically uses an optimized minimal payload format that reduces response size by **84%** (from 3.2KB to ~520B) while maintaining all essential functionality including relevance scores. This improves:
376
+
377
+ - **Network efficiency:** 6x less data transfer
378
+ - **Response speed:** Faster parsing and processing
379
+ - **Mobile performance:** Lower bandwidth usage
380
+ - **Cost savings:** Reduced data transfer costs
381
+
382
+ #### Response Formats
383
+
384
+ The SDK supports three response formats:
385
+
386
+ ```typescript
387
+ // Minimal format (default, ~520B) - Essentials + relevance
388
+ const ad = await client.decideFromContext({
389
+ userMessage: "I need car insurance",
390
+ response_format: 'minimal' // Optional, this is the default
391
+ });
392
+
393
+ // Returns:
394
+ {
395
+ creative: { title, body, cta },
396
+ click_url: string,
397
+ tracking_token: string,
398
+ advertiser_id: string,
399
+ payout: number,
400
+ relevance_score: number // 0.0-1.0 for frontend filtering
401
+ }
402
+ ```
403
+
404
+ For advanced use cases, you can request more detailed responses:
405
+
406
+ ```typescript
407
+ // Standard format (645B) - Includes disclosure info
408
+ const ad = await client.decide({
409
+ response_format: 'standard',
410
+ // ... other params
411
+ });
412
+
413
+ // Verbose format (3.1KB) - Full response with all metadata
414
+ const ad = await client.decide({
415
+ response_format: 'verbose',
416
+ // ... other params
417
+ });
418
+ ```
419
+
420
+ #### Format Comparison
421
+
422
+ | Format | Size | Use Case | Auto-impression |
423
+ |--------|------|----------|-----------------|
424
+ | **minimal** | ~520B | Production apps (default, includes relevance) | ✅ Yes |
425
+ | **standard** | ~645B | Apps needing disclosure details | ❌ Manual |
426
+ | **verbose** | ~3.1KB | Debugging, analytics | ❌ Manual |
427
+
428
+ **Note:** The minimal format automatically tracks impressions for you. When using standard or verbose formats with the raw `decide()` API, you must manually track impressions.
429
+
371
430
  ## Advanced Features
372
431
 
373
432
  ### Multi-Turn Conversations
@@ -497,6 +556,38 @@ Use test API keys (`am_test_...`) for development and testing. Test keys:
497
556
 
498
557
  Switch to live keys (`am_live_...`) when deploying to production.
499
558
 
559
+ ## 🤖 Claude Code Integration
560
+
561
+ Building with Claude Code? We've created ready-to-use prompts for seamless integration.
562
+
563
+ ### Quick Start (One Line)
564
+
565
+ ```
566
+ I want to add AttentionMarket ads to my AI app. Credentials:
567
+ - API Key: am_test_YOUR_KEY
568
+ - Agent ID: agt_YOUR_ID
569
+ Create a simple getRelevantAd(message) function that returns ads only when relevant (score>0.7).
570
+ ```
571
+
572
+ ### Full Integration Guide
573
+
574
+ 📖 **[Claude Code Integration Guide](CLAUDE_CODE_INTEGRATION.md)** — Copy-paste prompts for:
575
+ - Natural conversation integration
576
+ - Advanced filtering & brand safety
577
+ - Testing & analytics setup
578
+ - Mobile app integration
579
+ - Common patterns & best practices
580
+
581
+ ### Performance Metrics
582
+
583
+ | Metric | Expected Performance |
584
+ |--------|---------------------|
585
+ | **CTR** | 5-12% average |
586
+ | **Revenue/Click** | $0.50 - $15.00 |
587
+ | **Fill Rate** | 40-60% |
588
+ | **API Latency** | < 100ms p95 |
589
+ | **Payload Size** | ~520 bytes |
590
+
500
591
  ## Support
501
592
 
502
593
  - **Documentation:** [docs.attentionmarket.ai](https://docs.attentionmarket.ai)
package/dist/index.d.mts CHANGED
@@ -25,6 +25,9 @@ interface DecideRequest {
25
25
  context?: string;
26
26
  /** Detected or inferred user intent for semantic matching (optional) */
27
27
  user_intent?: string;
28
+ /** Response format: 'minimal' | 'standard' | 'verbose' (default: 'minimal') */
29
+ response_format?: string;
30
+ [key: string]: any;
28
31
  }
29
32
  /**
30
33
  * Simplified request for semantic context-based ad matching.
@@ -127,11 +130,27 @@ interface DecideFromContextRequest {
127
130
  optimizeFor?: 'revenue' | 'relevance';
128
131
  }
129
132
  interface DecideResponse {
130
- request_id: string;
131
- decision_id: string;
132
- status: 'filled' | 'no_fill';
133
- ttl_ms: number;
134
- units: AdUnit[];
133
+ request_id?: string;
134
+ decision_id?: string;
135
+ status?: 'filled' | 'no_fill';
136
+ ttl_ms?: number;
137
+ units?: AdUnit[];
138
+ creative?: {
139
+ title: string;
140
+ body: string;
141
+ cta: string;
142
+ };
143
+ click_url?: string;
144
+ tracking_token?: string;
145
+ advertiser_id?: string;
146
+ payout?: number;
147
+ disclosure?: {
148
+ label: string;
149
+ explanation: string;
150
+ sponsor_name: string;
151
+ };
152
+ relevance_score?: number;
153
+ [key: string]: any;
135
154
  }
136
155
  type PlacementType = 'sponsored_suggestion' | 'sponsored_block' | 'sponsored_tool';
137
156
  interface Placement {
@@ -531,6 +550,8 @@ interface AdResponse {
531
550
  tracking_url?: string;
532
551
  /** Tracking token for event tracking */
533
552
  tracking_token: string;
553
+ /** Relevance score (0.0-1.0) for frontend rendering decisions */
554
+ relevance_score?: number;
534
555
  /** Disclosure information */
535
556
  disclosure: Disclosure;
536
557
  /** Full ad unit (for advanced usage) */
package/dist/index.d.ts CHANGED
@@ -25,6 +25,9 @@ interface DecideRequest {
25
25
  context?: string;
26
26
  /** Detected or inferred user intent for semantic matching (optional) */
27
27
  user_intent?: string;
28
+ /** Response format: 'minimal' | 'standard' | 'verbose' (default: 'minimal') */
29
+ response_format?: string;
30
+ [key: string]: any;
28
31
  }
29
32
  /**
30
33
  * Simplified request for semantic context-based ad matching.
@@ -127,11 +130,27 @@ interface DecideFromContextRequest {
127
130
  optimizeFor?: 'revenue' | 'relevance';
128
131
  }
129
132
  interface DecideResponse {
130
- request_id: string;
131
- decision_id: string;
132
- status: 'filled' | 'no_fill';
133
- ttl_ms: number;
134
- units: AdUnit[];
133
+ request_id?: string;
134
+ decision_id?: string;
135
+ status?: 'filled' | 'no_fill';
136
+ ttl_ms?: number;
137
+ units?: AdUnit[];
138
+ creative?: {
139
+ title: string;
140
+ body: string;
141
+ cta: string;
142
+ };
143
+ click_url?: string;
144
+ tracking_token?: string;
145
+ advertiser_id?: string;
146
+ payout?: number;
147
+ disclosure?: {
148
+ label: string;
149
+ explanation: string;
150
+ sponsor_name: string;
151
+ };
152
+ relevance_score?: number;
153
+ [key: string]: any;
135
154
  }
136
155
  type PlacementType = 'sponsored_suggestion' | 'sponsored_block' | 'sponsored_tool';
137
156
  interface Placement {
@@ -531,6 +550,8 @@ interface AdResponse {
531
550
  tracking_url?: string;
532
551
  /** Tracking token for event tracking */
533
552
  tracking_token: string;
553
+ /** Relevance score (0.0-1.0) for frontend rendering decisions */
554
+ relevance_score?: number;
534
555
  /** Disclosure information */
535
556
  disclosure: Disclosure;
536
557
  /** Full ad unit (for advanced usage) */
package/dist/index.js CHANGED
@@ -468,7 +468,7 @@ var AttentionMarketClient = class {
468
468
  if (response.status === "no_fill") {
469
469
  return null;
470
470
  }
471
- return response.units[0] ?? null;
471
+ return response.units?.[0] ?? null;
472
472
  }
473
473
  /**
474
474
  * Simplified ad matching using conversation context and semantic search.
@@ -584,6 +584,8 @@ var AttentionMarketClient = class {
584
584
  },
585
585
  context,
586
586
  user_intent: params.userMessage,
587
+ // Use minimal response format by default for better performance
588
+ response_format: "minimal",
587
589
  // Developer controls (Phase 1: Quality & Brand Safety)
588
590
  ...params.minQualityScore !== void 0 && { minQualityScore: params.minQualityScore },
589
591
  ...params.allowedCategories && { allowedCategories: params.allowedCategories },
@@ -595,7 +597,49 @@ var AttentionMarketClient = class {
595
597
  ...params.optimizeFor && { optimizeFor: params.optimizeFor }
596
598
  };
597
599
  const response = await this.decideRaw(request, options);
598
- if (response.status === "no_fill" || response.units.length === 0) {
600
+ if (response && response.creative) {
601
+ if (response["_meta"]) {
602
+ try {
603
+ await this.track({
604
+ event_id: `evt_${generateUUID()}`,
605
+ event_type: "impression",
606
+ occurred_at: (/* @__PURE__ */ new Date()).toISOString(),
607
+ agent_id: this.agentId,
608
+ request_id: response["_meta"]["request_id"],
609
+ decision_id: response["_meta"]["decision_id"],
610
+ unit_id: response["_meta"]["unit_id"],
611
+ tracking_token: response.tracking_token
612
+ });
613
+ } catch (error) {
614
+ console.warn("[AttentionMarket] Failed to auto-track impression:", error);
615
+ }
616
+ }
617
+ const adResponse2 = {
618
+ request_id: request.request_id,
619
+ decision_id: `dec_${generateUUID()}`,
620
+ advertiser_id: response.advertiser_id || "",
621
+ ad_type: "link",
622
+ payout: response.payout || 0,
623
+ creative: response.creative,
624
+ click_url: response.click_url || "",
625
+ tracking_url: response.click_url || "",
626
+ // Same as click_url
627
+ tracking_token: response.tracking_token || "",
628
+ ...response.relevance_score !== void 0 && { relevance_score: response.relevance_score },
629
+ disclosure: response.disclosure || {
630
+ label: "Sponsored",
631
+ explanation: "This is a paid advertisement",
632
+ sponsor_name: "Advertiser"
633
+ },
634
+ // Internal fields preserved for backward compatibility
635
+ _ad: {
636
+ unit_id: "",
637
+ tracking: { token: response.tracking_token || "" }
638
+ }
639
+ };
640
+ return adResponse2;
641
+ }
642
+ if (!response || response.status === "no_fill" || !response.units || response.units.length === 0) {
599
643
  return null;
600
644
  }
601
645
  const adUnit = response.units[0];
@@ -908,7 +952,7 @@ var AttentionMarketClient = class {
908
952
  user_intent: params.intentKey
909
953
  };
910
954
  const response = await this.decideRaw(request, { idempotencyKey });
911
- if (response.status === "no_fill" || response.units.length === 0) {
955
+ if (response.status === "no_fill" || !response.units || response.units.length === 0) {
912
956
  return null;
913
957
  }
914
958
  const adUnit = response.units[0];
@@ -919,7 +963,7 @@ var AttentionMarketClient = class {
919
963
  const matchMethod = semanticContext ? "hybrid" : "semantic";
920
964
  return {
921
965
  offer_id: adUnit.unit_id,
922
- request_id: response.request_id,
966
+ request_id: response.request_id || "",
923
967
  impression_id: impressionId,
924
968
  // LIMITATION: Backend doesn't return campaign_id yet - use unit_id as placeholder
925
969
  campaign_id: adUnit.unit_id,
@@ -950,7 +994,7 @@ var AttentionMarketClient = class {
950
994
  ...params.revenueSharePct !== void 0 ? { source_agent_pct: params.revenueSharePct } : {}
951
995
  }
952
996
  } : {},
953
- ttl_ms: response.ttl_ms
997
+ ttl_ms: response.ttl_ms || 3e5
954
998
  };
955
999
  }
956
1000
  /**
@@ -1041,7 +1085,7 @@ var AttentionMarketClient = class {
1041
1085
  user_intent: params.userMessage
1042
1086
  };
1043
1087
  const response = await this.decideRaw(request, { idempotencyKey });
1044
- if (response.status === "no_fill" || response.units.length === 0) {
1088
+ if (response.status === "no_fill" || !response.units || response.units.length === 0) {
1045
1089
  return null;
1046
1090
  }
1047
1091
  const adUnit = response.units[0];
@@ -1052,7 +1096,7 @@ var AttentionMarketClient = class {
1052
1096
  const similarity = adUnit._score?.relevance;
1053
1097
  return {
1054
1098
  offer_id: adUnit.unit_id,
1055
- request_id: response.request_id,
1099
+ request_id: response.request_id || "",
1056
1100
  impression_id: impressionId,
1057
1101
  // LIMITATION: Backend doesn't return campaign_id yet - use unit_id as placeholder
1058
1102
  campaign_id: adUnit.unit_id,
@@ -1083,7 +1127,7 @@ var AttentionMarketClient = class {
1083
1127
  ...params.revenueSharePct !== void 0 ? { source_agent_pct: params.revenueSharePct } : {}
1084
1128
  }
1085
1129
  } : {},
1086
- ttl_ms: response.ttl_ms
1130
+ ttl_ms: response.ttl_ms || 3e5
1087
1131
  };
1088
1132
  }
1089
1133
  // ============================================================================
@@ -1169,7 +1213,7 @@ var AttentionMarketClient = class {
1169
1213
  user_intent: params.taskDescription
1170
1214
  };
1171
1215
  const response = await this.decideRaw(request);
1172
- if (response.status === "no_fill" || response.units.length === 0) {
1216
+ if (response.status === "no_fill" || !response.units || response.units.length === 0) {
1173
1217
  return null;
1174
1218
  }
1175
1219
  const adUnit = response.units[0];
@@ -1430,7 +1474,7 @@ var MockAttentionMarketClient = class {
1430
1474
  */
1431
1475
  async decide(request) {
1432
1476
  const response = await this.decideRaw(request);
1433
- if (response.status === "filled" && response.units.length > 0) {
1477
+ if (response.status === "filled" && response.units && response.units.length > 0) {
1434
1478
  return response.units[0] || null;
1435
1479
  }
1436
1480
  return null;