Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion docs/00-EXAMPLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ The Agentic RTB Framework (ARTF) defines a standard for implementing agent servi

- **Segment Activation** - Activate user segments based on bid request data
- **Deal Management** - Activate, suppress, and adjust deals dynamically
- **Bid Shading** - Optimize bid prices using intelligent pricing strategies
- **Bid Shading**, **Bid Valuation** - Optimize bid prices using intelligent pricing strategies
- **Metrics Addition** - Add viewability and other metrics to impressions

### Key Principles
Expand Down Expand Up @@ -114,6 +114,7 @@ The request message sent from the orchestrator to the agent.
| `tmax` | int32 | Yes | Maximum response time in milliseconds |
| `bid_request` | BidRequest | Yes | OpenRTB v2.6 bid request |
| `bid_response` | BidResponse | No | OpenRTB v2.6 bid response (if available) |
| `object_ids` | IDsPayload | No | Optional intent-specific object IDs associated with the bid request |
| `ext` | Extensions | No | Extension fields |

### RTBResponse
Expand Down Expand Up @@ -193,6 +194,17 @@ message AdjustBidPayload {
}
```

#### AdjustBidValuationPayload

Used for bid valuation responses.

```protobuf
message AdjustBidValuationPayload {
repeated string id = 1;
repeated float value_factor = 2;
}
```

#### AddMetricsPayload

Used for adding impression metrics.
Expand All @@ -219,6 +231,8 @@ message AddMetricsPayload {
| 5 | `ADJUST_DEAL_MARGIN` | Adjust the deal margin of a specific deal |
| 6 | `BID_SHADE` | Adjust the bid price of a specific bid |
| 7 | `ADD_METRICS` | Add metrics to an impression |
| 8 | `ADD_CIDS` | Add content IDs to an impression |
| 9 | `BID_VALUATION` | Adjust the perceived values of potential bids |

### Operation Enum

Expand All @@ -239,6 +253,7 @@ message AddMetricsPayload {
| `ADJUST_DEAL_FLOOR` | AdjustDealPayload | `/imp/{id}/pmp/deals/{dealId}` |
| `ADJUST_DEAL_MARGIN` | AdjustDealPayload | `/imp/{id}/pmp/deals/{dealId}` |
| `BID_SHADE` | AdjustBidPayload | `/seatbid/{seat}/bid/{bidId}` |
| `BID_VALUATION` | AdjustBidValuationPayload | |
| `ADD_METRICS` | AddMetricsPayload | `/imp/{id}/metric` |

---
Expand Down Expand Up @@ -460,6 +475,23 @@ The container image must include an `agent-manifest` label with JSON metadata:
}
```

### Bid Valuation

```json
{
"intent": "BID_VALUATION",
"op": "OPERATION_ADD",
"adjust_bid_valuation": {
"ids": {
"id": ["abcdef", "ghijkl"]
},
"value_factors": {
"value_factor": [0.123, 0.456]
}
}
}
```

---

## References
Expand Down
21 changes: 20 additions & 1 deletion proto/agenticrtbframework.proto
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
edition = "2023";

package com.iabtechlab.bidstream.mutation.v1;
package com.iabtechlab.bidstream.mutation.v2;

// Import OpenRTB definitions for BidRequest and BidResponse
import "com/iabtechlab/openrtb/v2.6/openrtb.proto";
Expand Down Expand Up @@ -31,6 +31,12 @@ message RTBRequest {
// List of intents the server is eligibible to send back
repeated Intent applicable_intents = 7;

// Object IDs for intent BID_VALUATION

@adrian-vaca-humanes-wt adrian-vaca-humanes-wt Aug 18, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this we can one can take the deals or segments from the RTB section and interpret the host wants those scored.

For discussion:

What should the semantic be if the caller/host passes imp[].pmp.deals[] or user.data[].segment[] as empty lists? Invalid request, or would the expectation be for it to still return something? Because for example, if the container receives an embedding it could issue ACTIVATE_DEAL and ACTIVATE_SEGMENT and at the same time a ADJUST_BID_VALUATION for those. While applicable_intents could be a signal of the type of types of IDs expected back in this scenario, I wonder if intents should support inputs other than what one may shoehorn as an extension, for example, in this empty list scenario where the container is supposed to give it its best shot, a topK input could be useful. And yes, this could also just be default configuration of the container or come through an extension.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These IDs are representations of an advertiser's entities on the buyer side, and the purpose of this BID_VALUATION addition is to allow third parties to contribute to the advertiser asset (say, campaign or ad group) valuation decision made by the DSP against the incoming bid request. As such, these do not correlate to individual deals or contextual segments or any other field in the bid request.

IMO if we want to add functionality to attribute relative value/worth to deals or segments, that should be covered by another intent separate from this PR, and the discussion point you raised would be germane to that.

On a closely related note, I think the standard could be improved in terms of either explicitly associating intents and payloads more unequivocally, or at least clarifying expectations. For example, a container responding with mutations using the ACTIVATE_SEGMENTS intent could well supply IDsPayload as sets of flat segment IDs, or DataPayload instances that have segments plus and additional name and ID or even content IDs, and I'm not sure what the expectation from an orchestrator is in this case.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got ahead of myself by thinking of these object IDs as references to objects in a partial OpenRTB payload. From there, I moved toward semantics that could be implemented today using deal IDs and segment IDs as examples. More generally, though, I was exploring whether this could be generalized regardless of ID type—particularly the semantics of an empty list, where the orchestrator could treat the container as a recommender. But you may be right that recommendation or candidate discovery belongs in a separate intent specification altogether.

Setting that discussion aside, do you envision distinct ID-type-specific valuation containers, where each container can score only one type of ID? If so, would there be an implicit, out-of-band agreement about what the opaque IDs represent for that intent?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current 1.0 version of this standard doesn't specify such ID types even though IDsPayload is already used in different contexts, that's why I didn't add ID types here. When someone works with us to implement a container that supports ADJUST_BID_VALUATION, they will know what to expect based on out-of-band conventions (not part of this spec).

Indeed we probably should add an ID type field, or create different variants of the IDsPayload message to ensure these payload IDs align with the expected type and that the container can actually work with them. Unfortunately, both would be a breaking change.

oneof value {
// List of object Identifiers
IDsPayload object_ids = 100;
}

// Extension fields
Ext ext = 99;

Expand Down Expand Up @@ -101,6 +107,9 @@ message Mutation {

// Content data
DataPayload content_data = 104;

// Payload for bid valuation intent
AdjustBidValuationPayload adjust_bid_valuation = 105;
}

// Reserved for experimental/test payloads
Expand Down Expand Up @@ -143,6 +152,9 @@ enum Intent {
// Add extended content IDs
ADD_CIDS = 8;

// Adjust bid valuation with factors
ADJUST_BID_VALUATION = 9;

// More intents can be added in the future

// Reserved for experimental/test intents
Expand Down Expand Up @@ -202,3 +214,10 @@ message DataPayload {
// List of data to add
repeated com.iabtechlab.openrtb.v2.BidRequest.Data data = 1;
}

message AdjustBidValuationPayload {
// full set or subset of IDs from the RTBRequest payload that the specified bid adjustment value factors apply to
repeated string id = 1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To prevent mismatches at population time (because serialization will work regardless), I am thinking this should be a repeated object instead, that additionally has an id_type e.g. {deal, segment, ...} and value_type {multiplier, score} so that the machine gets to know about the semantic, rather than being implicit.

@arpadmiklos-ttd arpadmiklos-ttd Aug 18, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed it would be more elegant and I'm not against a new repeated object that ensures alignment, which was my original idea as well.

My angle has been that ARTF is already slow to work with (our infra at TTD currently handles 20M+ qps) vs an optimized custom interface, and parallel running arrays are less error prone when encapsulated in a payload object, so this may be acceptable from a clarity point of view.

If you feel strongly about it, I'm happy to add a new object.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. Just curious, what would you do if ever there is a mismatch in elements? Ignore that part of the response completely?

Also, what about the point of qualifying the type for the id at score at response time?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Element mismatch indicates message corruption in this setup, so we should drop the requested mutation altogether and update logs/metrics.

The ID type in the mutation response must correspond to that of the IDs in the request, so I wouldn't repeat this information in the mutation.

// Adjusted bid valuation factors, running in parallel with the contents of the id field
repeated float value_factor = 2;
}