Skip to content

[Platform] Nothing enforces that a new result type can become assistant content #2430

Description

@wachterjohannes

Three PRs in a row have added or touched a server-side result type and missed its counterpart on the message side. Nothing enforces the relationship, and the failure always lands outside the code that was changed.

The three lists that have to stay in sync

For the family of server-side tool call results, three things belong together:

  1. Result\XResult, what a bridge's ResultConverter produces
  2. Message\Content\X, what an assistant message can carry
  3. the matching arm in Message::toContent()

Nine pairs are currently in sync: CodeExecution, ComputerCall, ExecutableCode, FileSearch, LocalShellCall, McpApprovalRequest, McpCall, McpListTools, WebSearch, plus Text, Thinking and ToolCall.

One is not: CustomToolCallResult from #2382 has neither a content class nor an arm.

Why it keeps slipping through

The gap never shows up where the change is made. The converter is green, the bridge suite is green, and it only breaks once the result becomes an assistant message, which happens in Chat::submit() or on a tool round-trip, so in application code rather than in the bridge's own tests.

What a test must not do

Requiring every Result class to be mapped would be wrong. VectorResult, ObjectResult, BinaryResult, RerankingResult and ChoiceResult are legitimately not assistant content: embeddings, structured output, images, alternatives. The reverse holds too, Image, Audio, Document, Video and File are input content for user messages and have no result counterpart by design.

The asymmetry to guard is narrower than "these lists must be equal".

Two ways to enforce it

A marker interface, implemented by every result that can appear inside an assistant message, with a test iterating its implementations and asserting toContent() handles each. Explicit, but it touches every existing result class.

An allow-list test, iterating Result\* and requiring each class to be either handled by toContent() or named in an explicit list of non-content results. Cheaper, and the allow-list is the valuable part: adding a new result type then forces a conscious decision instead of being silently forgotten.

Either way the test belongs next to Message::toContent(), not in a bridge.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugSomething isn't workingPlatformIssues & PRs about the AI Platform componentStatus: Needs Review

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions