Skip to content

Commit 082a3c0

Browse files
dinsteinclaude
authored andcommitted
fix: Change PaymentCurrencyAmount.value type from float to string
Per the W3C Payment Request API specification, the `value` field in PaymentCurrencyAmount is defined as a DOMString, not a number type. This change aligns the implementation across Python, Go, and Kotlin with the W3C standard for cross-language consistency. Updated type definitions: - Python: float -> str - Go: float64 -> string - Kotlin: Double -> String Updated all sample code to use string values and handle float conversions where arithmetic is needed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 61f5de4 commit 082a3c0

8 files changed

Lines changed: 24 additions & 21 deletions

File tree

samples/android/shopping_assistant/app/src/main/java/com/example/a2achatassistant/agent/DpcHelper.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ fun constructDPCRequest(cartMandate: CartMandate, merchantName: String): String
4343
// This nonce should ideally be generated securely for each transaction.
4444
val nonce = UUID.randomUUID().toString()
4545

46-
val totalValueString = String.format("%.2f", totalValue)
46+
val totalValueString = totalValue
4747

4848
val tableRows =
4949
cartMandate.contents.paymentRequest.details.displayItems.map { item ->
50-
listOf(item.label, "1", item.amount.value.toString(), item.amount.value.toString())
50+
listOf(item.label, "1", item.amount.value, item.amount.value)
5151
}
5252

5353
for (row in tableRows) {

samples/android/shopping_assistant/app/src/main/java/com/example/a2achatassistant/data/ShoppingAgentTypes.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ data class DisplayItem(
108108
@SerialName("refund_period") val refundPeriod: Int? = null,
109109
)
110110

111-
@Serializable data class Amount(val currency: String, val value: Double)
111+
@Serializable data class Amount(val currency: String, val value: String)
112112

113113
@Serializable
114114
data class ShippingOption(

samples/go/pkg/ap2/types/payment_request.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const PaymentMethodDataDataKey = "payment_request.PaymentMethodData"
1818

1919
type PaymentCurrencyAmount struct {
2020
Currency string `json:"currency"`
21-
Value float64 `json:"value"`
21+
Value string `json:"value"`
2222
}
2323

2424
type PaymentItem struct {

samples/go/pkg/roles/merchant_agent/storage.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package merchant_agent
1616

1717
import (
18+
"strconv"
1819
"strings"
1920
"sync"
2021
"time"
@@ -174,7 +175,7 @@ func (s *Storage) CreateCartMandate(products []Product) *types.CartMandate {
174175
Label: product.Name,
175176
Amount: types.PaymentCurrencyAmount{
176177
Currency: "USD",
177-
Value: product.Price,
178+
Value: strconv.FormatFloat(product.Price, 'f', -1, 64),
178179
},
179180
RefundPeriod: 30,
180181
}
@@ -200,7 +201,7 @@ func (s *Storage) CreateCartMandate(products []Product) *types.CartMandate {
200201
Label: "Total",
201202
Amount: types.PaymentCurrencyAmount{
202203
Currency: "USD",
203-
Value: total,
204+
Value: strconv.FormatFloat(total, 'f', -1, 64),
204205
},
205206
RefundPeriod: 30,
206207
},

samples/go/pkg/roles/merchant_agent/tools.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"encoding/json"
2020
"fmt"
2121
"os"
22+
"strconv"
2223

2324
"github.com/google-agentic-commerce/ap2/samples/go/pkg/ap2/types"
2425
"github.com/google-agentic-commerce/ap2/samples/go/pkg/common"
@@ -81,8 +82,8 @@ func generateProductsWithLLM(query string, updater *common.TaskUpdater, storage
8182

8283
// Define the schema for structured output using Go struct tags
8384
type Amount struct {
84-
Currency string `json:"currency"`
85-
Value float64 `json:"value"`
85+
Currency string `json:"currency"`
86+
Value string `json:"value"`
8687
}
8788

8889
type PaymentItem struct {
@@ -109,7 +110,7 @@ func generateProductsWithLLM(query string, updater *common.TaskUpdater, storage
109110
Enum: []string{"USD"},
110111
},
111112
"value": {
112-
Type: genai.TypeNumber,
113+
Type: genai.TypeString,
113114
Description: "Price in USD",
114115
},
115116
},
@@ -165,7 +166,7 @@ func generateProductsWithLLM(query string, updater *common.TaskUpdater, storage
165166
SKU: fmt.Sprintf("GEN-%d", i+1),
166167
Name: item.Label,
167168
Description: fmt.Sprintf("Generated product for: %s", query),
168-
Price: item.Amount.Value,
169+
Price: func() float64 { v, _ := strconv.ParseFloat(item.Amount.Value, 64); return v }(),
169170
Category: "Generated",
170171
}
171172

@@ -221,12 +222,12 @@ func UpdateCart(dataParts []map[string]interface{}, updater *common.TaskUpdater)
221222

222223
shippingCost := types.PaymentItem{
223224
Label: "Shipping",
224-
Amount: types.PaymentCurrencyAmount{Currency: "USD", Value: 2.00},
225+
Amount: types.PaymentCurrencyAmount{Currency: "USD", Value: "2.00"},
225226
RefundPeriod: 30,
226227
}
227228
taxCost := types.PaymentItem{
228229
Label: "Tax",
229-
Amount: types.PaymentCurrencyAmount{Currency: "USD", Value: 1.50},
230+
Amount: types.PaymentCurrencyAmount{Currency: "USD", Value: "1.50"},
230231
RefundPeriod: 30,
231232
}
232233

@@ -238,9 +239,10 @@ func UpdateCart(dataParts []map[string]interface{}, updater *common.TaskUpdater)
238239

239240
var newTotal float64
240241
for _, item := range cartMandate.Contents.PaymentRequest.Details.DisplayItems {
241-
newTotal += item.Amount.Value
242+
v, _ := strconv.ParseFloat(item.Amount.Value, 64)
243+
newTotal += v
242244
}
243-
cartMandate.Contents.PaymentRequest.Details.Total.Amount.Value = newTotal
245+
cartMandate.Contents.PaymentRequest.Details.Total.Amount.Value = strconv.FormatFloat(newTotal, 'f', -1, 64)
244246

245247
authToken := FakeJWT
246248
cartMandate.MerchantAuthorization = &authToken

samples/python/src/roles/merchant_agent/sub_agents/catalog_agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ async def _create_and_add_cart_mandate_artifact(
121121
"network": "base",
122122
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bda02913",
123123
"payTo": "0xMerchantWalletAddress",
124-
"maxAmountRequired": str(int(item.amount.value * 1000000))
124+
"maxAmountRequired": str(int(float(item.amount.value) * 1000000))
125125
}]
126126
}
127127
)

samples/python/src/roles/merchant_agent/tools.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,11 @@ async def update_cart(
105105
tax_and_shipping_costs = [
106106
PaymentItem(
107107
label="Shipping",
108-
amount=PaymentCurrencyAmount(currency="USD", value=2.00),
108+
amount=PaymentCurrencyAmount(currency="USD", value="2.00"),
109109
),
110110
PaymentItem(
111111
label="Tax",
112-
amount=PaymentCurrencyAmount(currency="USD", value=1.50),
112+
amount=PaymentCurrencyAmount(currency="USD", value="1.50"),
113113
),
114114
]
115115

@@ -121,9 +121,9 @@ async def update_cart(
121121
payment_request.details.display_items.extend(tax_and_shipping_costs)
122122

123123
# Recompute the total amount of the PaymentRequest:
124-
payment_request.details.total.amount.value = sum(
125-
item.amount.value for item in payment_request.details.display_items
126-
)
124+
payment_request.details.total.amount.value = str(sum(
125+
float(item.amount.value) for item in payment_request.details.display_items
126+
))
127127

128128
# A base64url-encoded JSON Web Token (JWT) that digitally signs the cart
129129
# contents by the merchant's private key.

src/ap2/types/payment_request.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class PaymentCurrencyAmount(BaseModel):
4141
currency: str = Field(
4242
..., description="The three-letter ISO 4217 currency code."
4343
)
44-
value: float = Field(..., description="The monetary value.")
44+
value: str = Field(..., description="The monetary value.")
4545

4646

4747
class PaymentItem(BaseModel):

0 commit comments

Comments
 (0)