Skip to content

feat(mcp-server): migrate prediction combos REST endpoints to SDK (PREDICT-8819) - #73

Open
karanach319 wants to merge 1 commit into
mainfrom
predict-8819-migrate-prediction-combos-rest-endpoints-to-sdk
Open

karanach319 wants to merge 1 commit into
mainfrom
predict-8819-migrate-prediction-combos-rest-endpoints-to-sdk

Conversation

@karanach319

Copy link
Copy Markdown
Collaborator

Whats included

  • Migrates the 3 prediction "combos" REST endpoints (listCombos, getComboByInstrumentSymbol, createCombo) off the legacy hand-rolled GeminiHttpClient and onto the @gemini-markets/sdk client (sdkClient). createPredictionComboTools now takes sdkClient instead of the legacy client.
  • The SDK returns comboId/id/instrumentId as native bigint, which JSON.stringify can't serialize. The datasource maps them back to strings so tool output keeps the existing shape. The contractId filter on listCombos is converted with BigInt() (never Number(), which loses precision above 2^53).
  • Moves the contract-metadata mapper into a shared datasources/predictions/mappers.ts, used by both positions and combos.
  • Widens ComboSummaryLeg to the full leg shape the API returns (comboId, contract, legIndex, legOutcome, resolvedAt). The legacy client passed the raw response through, so these fields were already in real tool output; the type just didn't declare them.
  • Tool error messages now include the SDK error's reason/code/category (e.g. HTTP 404 (reason=NOT_FOUND, code=not_found, category=not_found)) instead of only HTTP 404.
  • Bumps @gemini-markets/sdk to ^0.1.1, which includes the literal request body fix from PREDICT-9072 (fix(sdk-typescript): send a literal HTTP body on authenticated requests (PREDICT-9072) #69). createCombo returned 400 InvalidInput on 0.1.0 because the SDK never sent the request body.
  • Also fixes a typecheck error on main: the review suggestions accepted on feat(mcp-server): migrate prediction positions REST endpoints to SDK (PREDICT-8818) #68 pass null through for SettledPosition costBasis/netProfit/realizedPnl, but the local type was never widened to allow null. It's now string | null.
  • No changes to tool names, schemas, or descriptions.

Linear: https://linear.app/gemini/issue/PREDICT-8819

Test plan

  • npm run build — clean
  • npm run typecheck — clean
  • npm test — 320/320 passing
  • Confirmed datasources/predictions/combos.ts no longer imports GeminiHttpClient
  • Tested every combo tool, plus the positions tools and error handling touched by this PR, against production through the MCP server running the published @gemini-markets/sdk@0.1.1:

1. List combos (gemini_list_prediction_combos)

Prompt: call gemini_list_prediction_combos and give me the output payload

Returned the first page (10 of 209 combos) with comboId/contractId as strings on every leg and a pagination block.

Full output payload
{
  "combos": [
    {
      "contract": {
        "contractId": "689789",
        "contractName": "Chicago C Yes + Baltimore Yes + 4 more",
        "eventTicker": "CMB-260926-A993BD7587A6C9B1",
        "eventName": "",
        "category": "Pro Baseball"
      },
      "legs": [
        {
          "comboId": "689789",
          "contract": {
            "contractId": "678175",
            "contractName": "Chicago C",
            "eventTicker": "MLB-2609251705-CHC-BOS-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "678175",
          "legIndex": 0,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689789",
          "contract": {
            "contractId": "671394",
            "contractName": "Baltimore",
            "eventTicker": "MLB-2609252305-BAL-NYY-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671394",
          "legIndex": 1,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689789",
          "contract": {
            "contractId": "671407",
            "contractName": "Chicago C",
            "eventTicker": "MLB-2609252310-CHC-BOS-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671407",
          "legIndex": 2,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689789",
          "contract": {
            "contractId": "671334",
            "contractName": "Pittsburgh",
            "eventTicker": "MLB-2609252240-PIT-DET-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671334",
          "legIndex": 3,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689789",
          "contract": {
            "contractId": "671381",
            "contractName": "Tampa Bay",
            "eventTicker": "MLB-2609252240-TB-PHI-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671381",
          "legIndex": 4,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689789",
          "contract": {
            "contractId": "678167",
            "contractName": "Baltimore",
            "eventTicker": "MLB-2609262315-BAL-NYY-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "678167",
          "legIndex": 5,
          "requiredOutcome": "Yes"
        }
      ]
    },
    {
      "contract": {
        "contractId": "689586",
        "contractName": "Minnesota Yes + Chicago C Yes",
        "eventTicker": "CMB-260927-C646D3AFA1030AAC",
        "eventName": "",
        "category": "Pro Baseball"
      },
      "legs": [
        {
          "comboId": "689586",
          "contract": {
            "contractId": "678245",
            "contractName": "Minnesota",
            "eventTicker": "MLB-2609260010-TEX-MIN-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "678245",
          "legIndex": 0,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689586",
          "contract": {
            "contractId": "678175",
            "contractName": "Chicago C",
            "eventTicker": "MLB-2609251705-CHC-BOS-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "678175",
          "legIndex": 1,
          "requiredOutcome": "Yes"
        }
      ]
    },
    {
      "contract": {
        "contractId": "689539",
        "contractName": "Ball State Yes + Wyoming Yes",
        "eventTicker": "CMB-260927-EA55C716C3BBDFEC",
        "eventName": "",
        "category": "College Football"
      },
      "legs": [
        {
          "comboId": "689539",
          "contract": {
            "contractId": "658527",
            "contractName": "Ball State",
            "eventTicker": "NCAAF-2609261600-BALL-KENT-M",
            "eventName": "",
            "category": "College Football"
          },
          "contractId": "658527",
          "legIndex": 0,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689539",
          "contract": {
            "contractId": "658542",
            "contractName": "Wyoming",
            "eventTicker": "NCAAF-2609261900-HAW-WYO-M",
            "eventName": "",
            "category": "College Football"
          },
          "contractId": "658542",
          "legIndex": 1,
          "requiredOutcome": "Yes"
        }
      ]
    },
    {
      "contract": {
        "contractId": "689490",
        "contractName": "Chicago C Yes + Baltimore Yes + 3 more",
        "eventTicker": "CMB-260926-889099296F1F1BEF",
        "eventName": "",
        "category": "Pro Baseball"
      },
      "legs": [
        {
          "comboId": "689490",
          "contract": {
            "contractId": "678175",
            "contractName": "Chicago C",
            "eventTicker": "MLB-2609251705-CHC-BOS-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "678175",
          "legIndex": 0,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689490",
          "contract": {
            "contractId": "671394",
            "contractName": "Baltimore",
            "eventTicker": "MLB-2609252305-BAL-NYY-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671394",
          "legIndex": 1,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689490",
          "contract": {
            "contractId": "671423",
            "contractName": "Boston",
            "eventTicker": "MLB-2609252310-CHC-BOS-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671423",
          "legIndex": 2,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689490",
          "contract": {
            "contractId": "671334",
            "contractName": "Pittsburgh",
            "eventTicker": "MLB-2609252240-PIT-DET-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671334",
          "legIndex": 3,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689490",
          "contract": {
            "contractId": "671390",
            "contractName": "Philadelphia",
            "eventTicker": "MLB-2609252240-TB-PHI-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671390",
          "legIndex": 4,
          "requiredOutcome": "Yes"
        }
      ]
    },
    {
      "contract": {
        "contractId": "689240",
        "contractName": "Philadelphia Yes + Milwaukee Yes + 2 more",
        "eventTicker": "CMB-260927-DEDB0683583587A4",
        "eventName": "",
        "category": "Pro Baseball"
      },
      "legs": [
        {
          "comboId": "689240",
          "contract": {
            "contractId": "671390",
            "contractName": "Philadelphia",
            "eventTicker": "MLB-2609252240-TB-PHI-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671390",
          "legIndex": 0,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689240",
          "contract": {
            "contractId": "671284",
            "contractName": "Milwaukee",
            "eventTicker": "MLB-2609252340-STL-MIL-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671284",
          "legIndex": 1,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689240",
          "contract": {
            "contractId": "678388",
            "contractName": "Houston",
            "eventTicker": "MLB-2609260140-HOU-ATH-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "678388",
          "legIndex": 2,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689240",
          "contract": {
            "contractId": "678261",
            "contractName": "Los Angeles D",
            "eventTicker": "MLB-2609260215-LAD-SF-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "678261",
          "legIndex": 3,
          "requiredOutcome": "Yes"
        }
      ]
    },
    {
      "contract": {
        "contractId": "689197",
        "contractName": "Minnesota Yes + Houston Yes",
        "eventTicker": "CMB-260927-96F7DB1E1BD551BB",
        "eventName": "",
        "category": "Pro Baseball"
      },
      "legs": [
        {
          "comboId": "689197",
          "contract": {
            "contractId": "678245",
            "contractName": "Minnesota",
            "eventTicker": "MLB-2609260010-TEX-MIN-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "678245",
          "legIndex": 0,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689197",
          "contract": {
            "contractId": "678388",
            "contractName": "Houston",
            "eventTicker": "MLB-2609260140-HOU-ATH-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "678388",
          "legIndex": 1,
          "requiredOutcome": "Yes"
        }
      ]
    },
    {
      "contract": {
        "contractId": "689139",
        "contractName": "New York Y Yes + Chicago C Yes + 4 more",
        "eventTicker": "CMB-260926-38C685DB18F66829",
        "eventName": "",
        "category": "Pro Baseball"
      },
      "legs": [
        {
          "comboId": "689139",
          "contract": {
            "contractId": "671402",
            "contractName": "New York Y",
            "eventTicker": "MLB-2609252305-BAL-NYY-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671402",
          "legIndex": 0,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689139",
          "contract": {
            "contractId": "671407",
            "contractName": "Chicago C",
            "eventTicker": "MLB-2609252310-CHC-BOS-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671407",
          "legIndex": 1,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689139",
          "contract": {
            "contractId": "671343",
            "contractName": "Detroit",
            "eventTicker": "MLB-2609252240-PIT-DET-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671343",
          "legIndex": 2,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689139",
          "contract": {
            "contractId": "671390",
            "contractName": "Philadelphia",
            "eventTicker": "MLB-2609252240-TB-PHI-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671390",
          "legIndex": 3,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689139",
          "contract": {
            "contractId": "671216",
            "contractName": "Toronto",
            "eventTicker": "MLB-2609252307-CIN-TOR-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671216",
          "legIndex": 4,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689139",
          "contract": {
            "contractId": "671301",
            "contractName": "Atlanta",
            "eventTicker": "MLB-2609252310-ATL-MIA-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671301",
          "legIndex": 5,
          "requiredOutcome": "Yes"
        }
      ]
    },
    {
      "contract": {
        "contractId": "689067",
        "contractName": "Philadelphia Yes + New York Y Yes + 4 more",
        "eventTicker": "CMB-260926-8819B0035429B249",
        "eventName": "",
        "category": "Sports"
      },
      "legs": [
        {
          "comboId": "689067",
          "contract": {
            "contractId": "671390",
            "contractName": "Philadelphia",
            "eventTicker": "MLB-2609252240-TB-PHI-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671390",
          "legIndex": 0,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689067",
          "contract": {
            "contractId": "671402",
            "contractName": "New York Y",
            "eventTicker": "MLB-2609252305-BAL-NYY-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671402",
          "legIndex": 1,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689067",
          "contract": {
            "contractId": "671219",
            "contractName": "New York M",
            "eventTicker": "MLB-2609252245-NYM-WSH-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671219",
          "legIndex": 2,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689067",
          "contract": {
            "contractId": "671301",
            "contractName": "Atlanta",
            "eventTicker": "MLB-2609252310-ATL-MIA-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671301",
          "legIndex": 3,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689067",
          "contract": {
            "contractId": "671284",
            "contractName": "Milwaukee",
            "eventTicker": "MLB-2609252340-STL-MIL-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671284",
          "legIndex": 4,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "689067",
          "contract": {
            "contractId": "684609",
            "contractName": "Rafael Jodar",
            "eventTicker": "TENNIS-LAVERCUP-20260925-JOD-BUB",
            "eventName": "",
            "category": "Tennis"
          },
          "contractId": "684609",
          "legIndex": 5,
          "requiredOutcome": "Yes"
        }
      ]
    },
    {
      "contract": {
        "contractId": "688923",
        "contractName": "Philadelphia Yes + Toronto Yes + 4 more",
        "eventTicker": "CMB-260927-2A1C1A592D2B24EC",
        "eventName": "",
        "category": "Pro Baseball"
      },
      "legs": [
        {
          "comboId": "688923",
          "contract": {
            "contractId": "671390",
            "contractName": "Philadelphia",
            "eventTicker": "MLB-2609252240-TB-PHI-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671390",
          "legIndex": 0,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "688923",
          "contract": {
            "contractId": "671216",
            "contractName": "Toronto",
            "eventTicker": "MLB-2609252307-CIN-TOR-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671216",
          "legIndex": 1,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "688923",
          "contract": {
            "contractId": "671301",
            "contractName": "Atlanta",
            "eventTicker": "MLB-2609252310-ATL-MIA-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671301",
          "legIndex": 2,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "688923",
          "contract": {
            "contractId": "671284",
            "contractName": "Milwaukee",
            "eventTicker": "MLB-2609252340-STL-MIL-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671284",
          "legIndex": 3,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "688923",
          "contract": {
            "contractId": "671296",
            "contractName": "Chicago WS",
            "eventTicker": "MLB-2609252340-COL-CHW-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671296",
          "legIndex": 4,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "688923",
          "contract": {
            "contractId": "678388",
            "contractName": "Houston",
            "eventTicker": "MLB-2609260140-HOU-ATH-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "678388",
          "legIndex": 5,
          "requiredOutcome": "Yes"
        }
      ]
    },
    {
      "contract": {
        "contractId": "688843",
        "contractName": "Baylor Yes + Rafael Jodar Yes + 4 more",
        "eventTicker": "CMB-260927-5E52D8C38CBEF78C",
        "eventName": "",
        "category": "Sports"
      },
      "legs": [
        {
          "comboId": "688843",
          "contract": {
            "contractId": "658485",
            "contractName": "Baylor",
            "eventTicker": "NCAAF-2609261600-COL-BAY-M",
            "eventName": "",
            "category": "College Football"
          },
          "contractId": "658485",
          "legIndex": 0,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "688843",
          "contract": {
            "contractId": "684609",
            "contractName": "Rafael Jodar",
            "eventTicker": "TENNIS-LAVERCUP-20260925-JOD-BUB",
            "eventName": "",
            "category": "Tennis"
          },
          "contractId": "684609",
          "legIndex": 1,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "688843",
          "contract": {
            "contractId": "658464",
            "contractName": "Army",
            "eventTicker": "NCAAF-2609252000-ARM-TEM-M",
            "eventName": "",
            "category": "College Football"
          },
          "contractId": "658464",
          "legIndex": 2,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "688843",
          "contract": {
            "contractId": "658467",
            "contractName": "Navy",
            "eventTicker": "NCAAF-2609252300-NAV-UAB-M",
            "eventName": "",
            "category": "College Football"
          },
          "contractId": "658467",
          "legIndex": 3,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "688843",
          "contract": {
            "contractId": "658473",
            "contractName": "Rutgers",
            "eventTicker": "NCAAF-2609252300-HOW-RUT-M",
            "eventName": "",
            "category": "College Football"
          },
          "contractId": "658473",
          "legIndex": 4,
          "requiredOutcome": "Yes"
        },
        {
          "comboId": "688843",
          "contract": {
            "contractId": "671407",
            "contractName": "Chicago C",
            "eventTicker": "MLB-2609252310-CHC-BOS-M",
            "eventName": "",
            "category": "Pro Baseball"
          },
          "contractId": "671407",
          "legIndex": 5,
          "requiredOutcome": "Yes"
        }
      ]
    }
  ],
  "pagination": {
    "limit": 10,
    "offset": 0,
    "total": 209
  }
}

2. Create a combo (gemini_create_prediction_combo), using the first two legs of the first combo in the list above (Chicago Cubs Yes, 678175, and Baltimore Yes, 671394). This is the call that failed with 400 InvalidInput before the SDK fix. It succeeded, and the server matched the exact legs sent (canonicalLegKey: "671394:Yes,678175:Yes"). alreadyExisted: true because this pair had already been registered earlier the same day.

Prompt: call the gemini_create_prediction_combo tool with legs: contractId "678175" requiredOutcome "Yes", and contractId "671394" requiredOutcome "Yes".

{
  "alreadyExisted": true,
  "combo": {
    "canonicalLegKey": "671394:Yes,678175:Yes",
    "createdAt": "2026-09-25T17:15:04.715Z",
    "displayName": "Baltimore Yes + Chicago C Yes",
    "id": "688329",
    "instrumentId": "34186746",
    "instrumentRegistered": true,
    "instrumentSymbol": "GEMI-CMB-260926-65CBE48204098EAD-CMB",
    "latestExpiryDate": "2026-09-26T20:05:00.000Z",
    "legCount": 2,
    "legs": [
      {
        "comboId": "688329",
        "contract": {
          "contractId": "671394",
          "contractName": "Baltimore",
          "eventTicker": "",
          "eventName": "",
          "category": ""
        },
        "contractId": "671394",
        "legIndex": 0,
        "requiredOutcome": "Yes"
      },
      {
        "comboId": "688329",
        "contract": {
          "contractId": "678175",
          "contractName": "Chicago C",
          "eventTicker": "",
          "eventName": "",
          "category": ""
        },
        "contractId": "678175",
        "legIndex": 1,
        "requiredOutcome": "Yes"
      }
    ],
    "status": "Active",
    "updatedAt": "2026-09-25T19:19:04.170Z"
  }
}

3. Get a combo (gemini_get_prediction_combo), for the combo created above.

Prompt: Get the prediction combo with instrument symbol GEMI-CMB-260926-65CBE48204098EAD-CMB

{
  "contract": {
    "contractId": "688329",
    "contractName": "Baltimore Yes + Chicago C Yes",
    "eventTicker": "CMB-260926-65CBE48204098EAD",
    "eventName": "",
    "category": "Pro Baseball"
  },
  "legs": [
    {
      "comboId": "688329",
      "contract": {
        "contractId": "671394",
        "contractName": "Baltimore",
        "eventTicker": "MLB-2609252305-BAL-NYY-M",
        "eventName": "",
        "category": "Pro Baseball"
      },
      "contractId": "671394",
      "legIndex": 0,
      "requiredOutcome": "Yes"
    },
    {
      "comboId": "688329",
      "contract": {
        "contractId": "678175",
        "contractName": "Chicago C",
        "eventTicker": "MLB-2609251705-CHC-BOS-M",
        "eventName": "",
        "category": "Pro Baseball"
      },
      "contractId": "678175",
      "legIndex": 1,
      "requiredOutcome": "Yes"
    }
  ]
}

Note: the create response returns empty eventTicker/category on each leg's contract, while the get response for the same combo fills them in. Both are passed through as-is, so this is server-side behavior, not a mapping issue.

4. Settled positions (gemini_get_prediction_settled_positions), to check the shared contract-metadata mapper and the SettledPosition type fix.

Prompt: Show my settled prediction positions

{
  "positions": [
    {
      "accountId": "98927007",
      "contractMetadata": {
        "contractId": "659009",
        "contractName": "Up",
        "eventTicker": "BTC15M2609211545",
        "eventName": "BTC price today at 11:45am EDT",
        "category": "Bitcoin"
      },
      "costBasis": "0.4779",
      "instrumentId": "34160580",
      "instrumentSymbol": "GEMI-BTC15M2609211545-UP",
      "netProfit": "0.11",
      "outcome": "yes",
      "payout": "0.59",
      "position": 0.59,
      "positionQuantity": "0.59",
      "realizedPnl": "0",
      "resolutionSide": "yes",
      "settledAt": "2026-09-21T15:45:07.156Z"
    },
    {
      "accountId": "98927007",
      "contractMetadata": {
        "contractId": "622628",
        "contractName": "Up",
        "eventTicker": "BTC15M2609142115",
        "eventName": "BTC price today at 5:15pm EDT",
        "category": "Bitcoin"
      },
      "costBasis": "0.09",
      "instrumentId": "34127092",
      "instrumentSymbol": "GEMI-BTC15M2609142115-UP",
      "netProfit": "-0.09",
      "outcome": "yes",
      "payout": "0",
      "position": 1,
      "positionQuantity": "1",
      "realizedPnl": "0",
      "resolutionSide": "no",
      "settledAt": "2026-09-14T21:15:07.899Z"
    },
    {
      "accountId": "98927007",
      "contractMetadata": {
        "contractId": "622399",
        "contractName": "Up",
        "eventTicker": "BTC15M2609142100",
        "eventName": "BTC price today at 5pm EDT",
        "category": "Bitcoin"
      },
      "costBasis": "0.42",
      "instrumentId": "34126864",
      "instrumentSymbol": "GEMI-BTC15M2609142100-UP",
      "netProfit": "-0.42",
      "outcome": "yes",
      "payout": "0",
      "position": 1,
      "positionQuantity": "1",
      "realizedPnl": "0",
      "resolutionSide": "no",
      "settledAt": "2026-09-14T21:00:10.775Z"
    }
  ],
  "total": 7
}

5. Open positions (gemini_get_prediction_positions), to check the shared contract-metadata mapper. Empty because the account has no open positions right now; the call itself succeeded.

Prompt: Show my current prediction positions

{
  "positions": []
}

6. Error detail (gemini_get_prediction_combo with a made-up symbol), to check the new error formatting.

Prompt: Get the prediction combo with instrument symbol GEMI-CMB-FAKE-TEST

Error: HTTP 404 (reason=NOT_FOUND, code=not_found, category=not_found)

…EDICT-8819)

- Move listCombos, getCombo, and createCombo from the legacy HTTP client to @gemini-markets/sdk.
- Share contract-metadata mapping between positions and combos in mappers.ts.
- Widen ComboSummaryLeg to the full leg shape returned by the API.
- Include the SDK error's reason/code/category in tool error messages.
- Allow null for SettledPosition costBasis/netProfit/realizedPnl so main typechecks again.
- Bump @gemini-markets/sdk to ^0.1.1 for the literal request body fix (PREDICT-9072).
@linear-code

linear-code Bot commented Sep 25, 2026

Copy link
Copy Markdown

PREDICT-8819

@socket-security

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn Medium
Recently published: npm @gemini-markets/sdk published 2 hours ago

Location: Package overview

From: packages/mcp-server/package-lock.json → npm/@gemini-markets/sdk@0.1.1

ℹ Read more on: This package | This alert | What are recently published artifacts?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should either be allowlisted to allow recently-published versions, or an older version should be used instead.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@gemini-markets/sdk@0.1.1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@nostradamus-bot

Copy link
Copy Markdown

Nostradamus Risk Rating — Low

PR #73 migrates prediction-market combo datasources from a legacy HTTP client to the @gemini-markets/sdk, touching high-sensitivity financial endpoints (createCombo, combos listing) in packages/mcp-server/src/datasources/predictions/combos.ts and tools/predictions/combos.ts, but the changes are a pure transport-layer refactor with no altered tool schemas, auth logic, or new attack surface — the risk of a security regression is low.

@svc-grace svc-grace left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agentic Review

Nice migration overall — the SDK switch, bigint-to-string mapping, and shared metadata mapper look well exercised, and the production checks cover the main combo and positions paths. The remaining follow-up is test coverage around nested combo-leg metadata: the mapping behavior is there, but the automated tests don't yet verify that nested shape directly. That's advisory only and doesn't block this PR.

Review process

Grace version: v0.0.214
Files reviewed (12): annotations.test.ts, combos.test.ts, combos.ts, index.ts, mappers.ts, package-lock.json, package.json, positions.ts, predictions.ts, server.ts
Guidelines: none discovered
Verification: 2 of 7 findings verified
Findings: 0 critical, 0 important, 2 suggestions
Linked tickets: PREDICT-8819
LLM usage: 165 calls — gpt-5.6-luna: 115 calls, 5590888 tokens, us.anthropic.claude-opus-4-6-v1: 35 calls, 1181698 tokens, us.anthropic.claude-sonnet-4-6: 15 calls, 783277 tokens

Comment on lines +105 to +106
contractId: '111',
requiredOutcome: 'Yes',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📝 Suggestion: Missing coverage for nested combo leg metadata

The combo-leg mapping test omits leg.contract, so it never exercises the new metadata mapper on the nested leg object. When mapContractMetadata drops or misnames a leg field, this suite still passes while list/get/create tool output loses underlying contract metadata; add populated leg metadata and assert it for each response path.

assert.strictEqual((calls[0]!.input as { instrumentRegistered?: boolean }).instrumentRegistered, false);
});

test('listCombos maps a bigint comboId on each leg to an exact string, and drops extra contract fields', async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📝 Suggestion: Nested combo-leg mapping is not verified

This test never supplies a leg contract or asserts legOutcome and resolvedAt; it only checks combo-level metadata. A regression in mapComboLeg would still pass while returned legs lose contract metadata or resolution fields, which are part of the migrated output shape. Add a populated leg fixture and assert the complete mapped leg.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants