fix: parse MCP result payloads and drop place idempotency_key
Typed result structs replace empty envelopes. Equity place sends ref_id only so live additionalProperties:false schemas accept the call.
This commit is contained in:
+81
-7
@@ -2,6 +2,7 @@ package equity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
decimal "github.com/alpacahq/alpacadecimal"
|
||||
"s1d3sw1ped/robinhood-agentic-mcp/client"
|
||||
@@ -42,9 +43,73 @@ type ReviewResult struct {
|
||||
Warnings []string `json:"warnings"`
|
||||
}
|
||||
|
||||
// Order is a placed equity order.
|
||||
// Order is a placed or listed equity order.
|
||||
type Order struct {
|
||||
ID string `json:"id"`
|
||||
ID string `json:"id"`
|
||||
IdempotencyKey string `json:"idempotency_key"`
|
||||
Symbol string `json:"symbol"`
|
||||
Side string `json:"side"`
|
||||
Qty decimal.Decimal `json:"-"`
|
||||
FilledQty decimal.Decimal `json:"-"`
|
||||
Price decimal.Decimal `json:"-"`
|
||||
State string `json:"state"`
|
||||
}
|
||||
|
||||
func (o *Order) UnmarshalJSON(b []byte) error {
|
||||
var row struct {
|
||||
ID string `json:"id"`
|
||||
IdempotencyKey string `json:"idempotency_key"`
|
||||
Symbol string `json:"symbol"`
|
||||
Side string `json:"side"`
|
||||
Quantity any `json:"quantity"`
|
||||
Qty any `json:"qty"`
|
||||
FilledQty any `json:"filled_quantity"`
|
||||
CumulativeQty any `json:"cumulative_quantity"`
|
||||
Price any `json:"price"`
|
||||
AveragePrice any `json:"average_price"`
|
||||
State string `json:"state"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &row); err != nil {
|
||||
return err
|
||||
}
|
||||
o.ID = row.ID
|
||||
o.IdempotencyKey = row.IdempotencyKey
|
||||
o.Symbol = row.Symbol
|
||||
o.Side = row.Side
|
||||
o.State = row.State
|
||||
if o.State == "" {
|
||||
o.State = row.Status
|
||||
}
|
||||
var err error
|
||||
if o.Qty, err = firstDec(row.Quantity, row.Qty); err != nil {
|
||||
return err
|
||||
}
|
||||
if o.FilledQty, err = firstDec(row.FilledQty, row.CumulativeQty); err != nil {
|
||||
return err
|
||||
}
|
||||
if o.Price, err = firstDec(row.Price, row.AveragePrice); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseOrders(raw json.RawMessage) ([]Order, error) {
|
||||
rows, _, err := wire.UnmarshalRows[Order](raw, "orders", "results")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
return rows, nil
|
||||
}
|
||||
var one Order
|
||||
if err := json.Unmarshal(wire.Unwrap(raw), &one); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if one.ID != "" {
|
||||
return []Order{one}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// CancelOrderRequest is the argument set for cancel_equity_order.
|
||||
@@ -62,13 +127,23 @@ func (c *Client) ReviewOrder(ctx context.Context, req PlaceOrderRequest) (Review
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// PlaceOrder calls place_equity_order. RefID is sent as both ref_id and idempotency_key.
|
||||
// PlaceOrder calls place_equity_order. RefID is sent as ref_id only.
|
||||
func (c *Client) PlaceOrder(ctx context.Context, req PlaceOrderRequest) (Order, error) {
|
||||
var out Order
|
||||
if err := c.parse(ctx, toolPlace, placeArgs(req, true), &out); err != nil {
|
||||
raw, err := c.c.Call(ctx, toolPlace, placeArgs(req, true))
|
||||
if err != nil {
|
||||
return Order{}, err
|
||||
}
|
||||
return out, nil
|
||||
ords, err := parseOrders(raw)
|
||||
if err != nil {
|
||||
return Order{}, client.ToolErrorf(toolPlace, "parse: %w", err)
|
||||
}
|
||||
if len(ords) == 1 {
|
||||
return ords[0], nil
|
||||
}
|
||||
if len(ords) > 1 {
|
||||
return ords[0], nil
|
||||
}
|
||||
return Order{}, nil
|
||||
}
|
||||
|
||||
// CancelOrder calls cancel_equity_order.
|
||||
@@ -128,7 +203,6 @@ func placeArgs(req PlaceOrderRequest, withRef bool) map[string]any {
|
||||
}
|
||||
if withRef && req.RefID != "" {
|
||||
args["ref_id"] = req.RefID
|
||||
args["idempotency_key"] = req.RefID
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user