Skip to content

rust(fix): keep unmatched fields visible when list output is truncated - #847

Draft
alexa-sift wants to merge 6 commits into
mainfrom
rust/unmatched-fields-before-items
Draft

alexa-sift wants to merge 6 commits into
mainfrom
rust/unmatched-fields-before-items

Conversation

@alexa-sift

@alexa-sift alexa-sift commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Background: Every list_* MCP tool builds its response through list_body. A caller can pass fields: ["name", "asset_id"] to keep only those keys on each row. If a requested name matches nothing on any row (a typo like nmae), list_body adds unmatched_fields: ["nmae"]. Without that key, a typo would quietly return rows with that field missing, and the agent could report the data as empty when the field name was wrong. unmatched_fields lets the agent catch the mistake and retry, or at least tell the user.

The problem: serde_json sorts keys alphabetically, so unmatched_fields comes after the items array. In 7 of the 14 list tools (channels, assets, annotations, and others), the items key also sorts before count and has_more. The agent output guard cuts large responses from the end, so these keys disappear on exactly the big responses where they matter most.

The fix: a new list_result helper writes the text block agents read with every metadata key first and the items array last. All 14 list tools return through it. count, has_more, unmatched_fields, artifact_url, and next_step now survive head truncation regardless of how the items key sorts or whether serde_json's preserve_order is ever enabled. structuredContent is unchanged, and the key keeps its existing name.

Verification

  • New list_result tests in common/test.rs:
    • All 14 items keys write count, has_more, and unmatched_fields before the items.
    • With 500 rows, all three sit in the first 200 characters.
    • The text block parses to the same JSON as structuredContent.
    • next_step gets its own leading block.
  • Handler-level assertions on the text block for list_channels, list_artifact_versions (artifact_url first), and list_calculated_channel_versions (next_step block first).
  • With list_result reverted to alphabetical output, 6 of the new tests fail.
  • cargo fmt --check --all, cargo check --all-features, and cargo clippy --all-features pass with no new warnings. cargo test -p sift_mcp passes 605 tests.

Rename the list tools' unmatched_fields key to _unmatched_fields so it
sorts ahead of the items and survives head truncation of large
responses. Document the key in each list tool's Output section and add
tests for the ordering and the descriptions.
@alexa-sift
alexa-sift marked this pull request as ready for review October 26, 2026 19:28
alexa-sift and others added 4 commits October 26, 2026 12:50
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace the `_unmatched_fields` rename with a `list_result` helper. The text
block agents read now writes `count`, `has_more`, `unmatched_fields` and other
metadata before the items, so they survive head truncation in every list tool,
including the 7 whose items key sorts before `count`. `structuredContent` is
unchanged, and the key keeps its original `unmatched_fields` name.

ENG-15730

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alexa-sift
alexa-sift marked this pull request as draft October 29, 2026 18:47
The bullets were added so agents would learn the `_unmatched_fields` rename.
With the rename reverted, each tool's `fields` bullet already names the key,
so remove the bullets, their docs guard test, and the CHANGELOG mention.

ENG-15730

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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.

1 participant