Repository navigation
feat(sdk): trade intelligence in the OpenAPI spec and TypeScript SDK - #415
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
392a4d3 to
cb6a977
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 31826ba961
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Comments Outside DiffThese findings could not be posted inline.
|
06f6eb2 to
c5d97b2
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c5d97b2232
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
49b4a5b to
42a2d47
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 42a2d47ce5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
42a2d47 to
ac83315
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 584dbb66e4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "method": "POST", | ||
| "body": { | ||
| "mode": "raw", | ||
| "raw": "{\n \"measure\": \"containers\",\n \"group_by\": [\n \"hs2\",\n \"origin_country\"\n ],\n \"filters\": {\n \"company\": \"<string>\",\n \"company_state\": \"<string>\",\n \"hs4\": \"9179\",\n \"hs2\": \"49\",\n \"carrier\": \"<string>\",\n \"scac\": \"<string>\",\n \"origin_country\": \"<string>\",\n \"origin_region\": \"<string>\",\n \"pol\": \"<string>\",\n \"pol_country\": \"<string>\",\n \"pod\": \"<string>\",\n \"pod_coast\": \"WEST\",\n \"dest_state\": \"<string>\",\n \"container_type\": \"<string>\",\n \"reefer\": \"<boolean>\"\n },\n \"interval\": \"month\",\n \"since\": \"7668-10\",\n \"until\": \"1392-09\",\n \"top\": 10\n}", |
There was a problem hiding this comment.
Emit an ordered date range in generated requests
When someone sends the regenerated Get import trends request as provided, it uses since: "7668-10" and until: "1392-09", so the start is later than the end and the request is rejected rather than demonstrating the endpoint; the breakdown request likewise uses dates thousands of years outside the documented January 2022-to-present coverage. Fresh evidence after the calendar-month pattern fix is that regeneration now produces syntactically valid but still unusable ranges. Adjust the OpenAPI/generation inputs so these requests use coherent example dates, then regenerate rather than editing this artifact directly.
AGENTS.md reference: AGENTS.md:L51-L53
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Leaving the spec as is. The Postman collection is generated in Schema mode, which fakes every request-body value from the schema and ignores examples. I checked: adding a body example doesn't change the output. Other bodies are placeholders too: hs4 comes out as a random valid code, and string filters as <string>. JSON Schema can't express that since must not be after until, so no schema change orders them. The documented request examples in the API reference use ordered ranges. Generating the whole collection from examples would be a separate tooling change to the Postman workflow.
3bef567 to
8554c2b
Compare
Brings in #434, #437 and #444. The only conflict was the generated Postman collection: took main's copy and regenerated it from the merged docs/openapi.json with openapi-to-postmanv2@6.3.0. SDK types, MCP filter schemas and SDK reference docs regenerate unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The API rejects estimated_value with pol, pol_country or container_type as a dimension or filter (docs/openapi.json TradeIntelDimension and TradeIntelFilters). The MCP guide presented estimated_value as generally available, so it now states the restriction for get_trade_trends and get_trade_breakdown and lists the lane combination rules with the other trade intelligence caveats. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The measure and dimension descriptions for get_trade_trends and get_trade_breakdown now say that estimated_value cannot be used with pol, pol_country or container_type, which the API answers with a 400. A protocol test checks the advertised measure description and the MCP docs section for both tools. Addresses the Codex review on packages/mcp/src/tools/trade-intel.ts:82. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PR registers seven trade intelligence tools, but the MCP README header and table, the TOOLS_OVERVIEW summary and the setup guide's "list the tools" check still said 14. The README table now lists the trade intelligence tools too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…list Fails when the README, TOOLS_OVERVIEW or the setup guide state a tool count other than the tools/list length, or when the README tool table misses or adds a tool. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The API rejects estimated_value when pol, pol_country or container_type is used at all, as a dimension or as a filter. The test now fails if the tool description or the docs drop the filter case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged main into this branch with an ordinary merge, 7f4fb93, bringing in #434, #437 and #444. The only conflict was the generated Postman collection. I took main's copy and regenerated it from the merged spec. The Postman bot then regenerated it again in 55603b0. SDK types, MCP filter schemas and the SDK reference regenerate unchanged. Follow-ups on top, all signed:
Local checks: Note for merging: 55603b0 is the Postman bot's commit, and its message contains |
Without since, the trade-intel service returns the N months ending with until (24 for trends, 12 for breakdown), so since is N - 1 months before until. The test fails while tools/list, docs/mcp/home.mdx or the OpenAPI spec describe the default as "N months ago" or "about a year back". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ctly Without since, the API returns the N months ending with until (24 for trends, 12 for breakdown), so since defaults to N - 1 months before until. The since fields said "Defaults to 24/12 months ago", which reads as N + 1 calendar months. The breakdown and trends descriptions and the MCP guide now give the same window. Source: analytics._range in the trade-intel service. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…them get_trade_trends and get_trade_breakdown said "about two years back" and "about a year back, not a clean 12 months". They now say the window is the 24 or 12 months ending with the current, incomplete month, with since 23 or 11 months before until. The SDK JSDoc, regenerated types and SDK reference match the OpenAPI source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Follow-up on the default-window finding from the independent review of 88cb9e8. That review flagged What the API actually does. The backend source has the final say. In That means the breakdown sentence ("the last 12 months including the current, partial month") and the SDK Commits (all signed):
Failing before the fix, passing after. On 67c21f0 alone: On f8e9abf, CI on f8e9abf. Every check passes except Independent review. gpt-6-sol re-derived the windows from the backend excerpt and agreed the 13-month claim was wrong. It found no wrong or off-by-one sentence in the changed wording. It raised one P3: the per-field This PR still needs human review. I have not marked it merge-ready, and no threads were resolved. |
…ice returns
Checked against Terminal49/t49 staging (apps/trade-intel build.py,
analytics.py, api.py, index.py):
- meta dates (since_month, until_month_exclusive, facts_since_month,
partial_month, refreshed_since) and company first_month/last_month are
first-of-month dates, YYYY-MM-DD; facts_until_exclusive is the day after
the build; mode is full or incremental.
- importers/top: states can be null, estimated_value is always sent and is
null without hs4, and filters echo port_of_discharge as pod.
- companies/profile: until is absent when found is false, and totals.states
can be null.
- trends periods are always YYYY-MM (the first month of the quarter or
year), not YYYY-Qn or YYYY.
- a 422 can also be the query cost-cap error, { error }.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tries
Regenerated types from the corrected spec, so TradeIntelTopImporter
states and estimated_value, profile totals.states and profile until are
typed as the service sends them, ranking filters expose pod, and the 422
body includes the cost-cap { error } variant. Type tests in
spec-types.test.ts fail against the old types.
Fixtures now use the service's real formats (YYYY-MM-DD meta dates,
YYYY-MM quarterly periods), and the live smoke test expects
facts_since_month as a first-of-month date.
RetryInterceptor kept separate retry counters in onError and onResponse,
so network failure, network failure, 503, 503, success made five requests
with maxRetries 2. Both paths now draw on one per-request budget.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The service sends meta and search-window dates as YYYY-MM-DD, but previousMonth() only accepted YYYY-MM, so get_trade_data_coverage lost last_full_month and search_window.to, and search_importers lost period.to. Index dates are now accepted in either form and shown as YYYY-MM, including first_month and last_month. rank_importers also leaves out estimated_value_usd when the service sends null instead of emitting an undefined key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Receipts for the fixes that follow up on the independent review of Contract source: Terminal49/t49 Fixed (each with a test that fails without the fix)
Type-level checks for 2, 3, 5 and 6 are in Not fixed, recorded
Verification at
Remaining gates: human review (@maurycy code, @namitabhasin docs), a live call from an account with trade intelligence enabled, rotating the eval credential, and removing |
Brings in trade intelligence (#415) and the CI trust gates (#384). The seven trade intelligence tools move into the tool registry under a new `trade` toolset. It is on by default and stays on for the shared env token, because every tool in it is read-only, so the default tools/list keeps everything main serves today. Names, titles, descriptions, schemas and annotations are unchanged. The per-account entitlement is still checked when a tool runs, not when it is registered. The server instructions keep main's trade guidance as their own paragraph, dropped when the session does not serve the trade toolset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Adds Terminal49 trade intelligence to the public API reference, the TypeScript SDK, and the MCP server. The data is US import bill-of-lading records (US Customs manifests), January 2022 onward, refreshed daily, served at
/v2/trade_intel/*with normal v2 Token auth and gated per account.OpenAPI and docs (
docs:commits)TradeIntel*request and response schemas, reusable error responses (400, 401, 403 not enabled, 422, 429, 502/504), and synthetic examples.apps/trade-intelon t49staging): meta and search-window dates are first-of-monthYYYY-MM-DD; every trend period is labelledYYYY-MMby its first month, so quarters read2026-01,2026-04; ranking rows can havestates: nulland always carryestimated_value, which isnullwithouths4; rankingfiltersechoport_of_dischargeaspod; a profile miss has nountilandtotals.statescan benull; a 422 is either a schema-validationdetaillist or the query cost-cap{ error }.companyfilter is a substring match, and carriers have spelling variants. Default windows are stated exactly: trends cover the 24 months ending with the current, partial month, breakdowns 12.SDK
client.tradeIntelwithmeta,searchCompanies,companyProfile,searchCommodities,topImporters,trends,breakdown,lookupContainer,lookupBillOfLading. Each returns the plain JSON body, typed from the generated schemas, so the nulls above are visible to TypeScript callers.FeatureNotEnabledError. 400 and 422 map toValidationErrorwith the server's message, including FastAPIdetailarrays (Input should be less than or equal to 50 (body.limit)) and the cost-caperror.POSTs are read-only queries, so the retry policy treatsPOSTs under/trade_intel/likeGETs. Other writes still need anIdempotency-Key. Network failures and 429/5xx responses now share one per-request retry budget, so a request never makes more thanmaxRetriesretries in total (before, a network failure followed by 5xx responses could retry up to twice as often).generate:typespasses--default-non-nullable=falseso request fields with server defaults (limit,months,top) stay optional.spec-types.test.tspins the nullable and optional fields at type level (enforced bytscinvp run check). SDK reference docs regenerated.MCP tools (folded in from #417)
docs/mcp/home.mdx,TOOLS_OVERVIEW.md, the ChatGPT and Claude directory submission JSON, and an Unreleased MCP changelog entry.YYYY-MM:get_trade_data_coveragereportslast_full_monthandsearch_window.to, andsearch_importersreportsperiod.to, from the service'sYYYY-MM-DDindex dates.rank_importersreportsestimated_value_usdonly when the service sends a value.Versioning
The SDK version is not hand-bumped. release-please produces the 0.6.0 release PR with its changelog entry after merge.
Test evidence (head
ccf71a5d)vp run checkpasses.vp run test: SDK 416 passed (1 file skipped: live smoke), MCP 502 passed, CLI 153 passed.spec-types.test.ts, and the mixed network/5xx retry test (5 requests and a success before, 3 requests andUpstreamErrorafter).ccf71a5d: every check passes exceptMCP preview 2026-07-28(see Known CI noise).stagingsource.Merge prerequisites (owner go-ahead required)
Nothing here is auto-merged, published, or deployed. Merging this PR does all of the following at once:
main. Afterwards, update the tool names in the Claude directory listing, let the ChatGPT directory rescan, and cut the usualrelease(mcp)version PR.@terminal49/sdkto npm, which needs separate approval.Before merging:
latest_importin the container lookup.facts_since_monthas a first-of-month date). So far only the 403 not-enabled path has been verified live.[skip ci]text that the Postman bot's commits add to the squash message. If it stays, CI, Postman deploy, and release-please are skipped onmain.Known open item: a trade intelligence call can still outlast the 30-second gateway limit. The SDK default is a 30-second timeout per attempt and 2 retries, the backend proxy allows 10 seconds per upstream call, and there is no deadline across the whole tool call. This is not new to trade intelligence: every MCP tool shares that client. Fixing it needs a call-wide deadline for the gateway, so it is left out of this PR.
Known CI noise:
CI / MCP preview 2026-07-28fails at fixture discovery (list_shipments ... check eval credentials) because the sharedMCP_EVAL_TOKENpassthrough credential returns 401. The same failure shows up on every PR and inmain's ownmcpjob. That secret needs to be rotated; this PR's code does not cause the failure.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.The PR appears safe to merge, with non-blocking improvements needed in the Postman examples, lookup types, and retry documentation.
Summary
Adds nine trade intelligence operations to the API reference and exposes them through
client.tradeIntel.client.tradeIntel.POSTs can retry safely.Diagram
sequenceDiagram participant Caller participant Manager as TradeIntelManager participant Transport participant API Caller->>Manager: Query or lookup Manager->>Transport: Plain JSON request Transport->>API: Token-authenticated GET or POST alt Retryable failure API-->>Transport: 429, 5xx, or network failure Transport->>API: Replay read-only request after backoff end API-->>Transport: JSON response Transport-->>Caller: Plain body or typed errorReviews (1) · Last reviewed commit: "chore(sdk): regenerate types for the loo..." · Reviewed by Greptile
Current readiness verification keeps the original gates. Local checks and tests pass, but authenticated MCP preview evaluation is blocked by a backend HTTP 401 for the shared CI passthrough credential. The transport handshake alone does not prove tool access. Review fixes and rebases preserve this PR's base topology. No merge or deploy has been performed.