Repository navigation
Description
Problem
PR #90 removes missing-signature rejection for reasoning output while preserving strict history validation. Other output paths still reject provider results, including an SDK-valid incomplete function call. These checks should be reviewed against Molto's strict-input, lenient-output contract.
This issue separates demonstrated rejection from restrictions that need a deliberate translation-policy decision. It does not propose deleting every output check.
Findings
References use the audited commit acf4abe8775e539c3c0aa02c11456054b3ea379b; the core checks below were also inspected at PR #89's merged head 7838929641162dc6e9c29d4f12298776d78c326d. PR #90's signature-removal changes do not address them.
1. Incomplete Responses function calls are rejected
_validate_responses_function_call validates output status, and _completed_output_item permits only None or completed. A call with status="incomplete" therefore raises instead of preserving partial arguments and the response's terminal state.
Confirmed locally with the installed SDK:
from openai.types.responses import ResponseFunctionToolCall
from molto.upstream.openai import _completed_output_item
item = ResponseFunctionToolCall.model_validate({
"id": "fc_example",
"type": "function_call",
"call_id": "call_example",
"name": "lookup",
"arguments": '{"query":',
"status": "incomplete",
})
_completed_output_item(item)
# ValueError: Unsupported Responses function call status: 'incomplete'.The SDK model accepts the item. This is a focused synthetic reproduction, not evidence of a recorded provider occurrence. Prioritize preserving incomplete output without representing the call as successfully completed.
2. Messages collection adds an object-only tool-argument check
AnthropicMessagesAdapter._project_response partially parses argument JSON, then requires a dictionary. Arrays/scalars can pass through streaming projection but fail complete-response collection. The installed Anthropic SDK accumulator assigns partially parsed JSON without this additional object check.
Add SDK-parity coverage to establish the intended output contract before relaxing the check. Keep request/history validation separate.
3. Reasoning output is constrained by provider configuration
- Responses normalization and all downstream adapters reject raw/summary output that differs from
ProviderCapabilities.thinking, even where Responses explicitly labels its representation. - Shared
ThinkingandThinkingDeltavalidators reject raw reasoning combined with a summary or signature on output as well as history.
These enforce existing documented contracts. Decide which output restrictions are actually required for faithful projection; do not weaken history validation implicitly.
4. Chat tool streaming imposes ordering and identity restrictions
The Chat normalizer requires the first delta to contain the call ID and function name, and rejects interleaved indices such as 0 -> 1 -> 0. An existing test explicitly expects this rejection.
Supporting more sequences requires changes to stream state or buffering. Removing the exception alone would violate current part lifecycles.
5. Remaining checks to classify
- Unsupported output items/events, non-direct callers/namespaces, and unknown or missing termination reasons.
- Late tool-name/ID changes, Chat reasoning signatures, signature-stream consistency, and event-order checks. These can protect real projection constraints or prevent reporting truncated streams as successful. PR fix: Accept unsigned reasoning output #90 deliberately retains signature preservation/consistency checks.
- Redundant argument-string checks in the Responses adapter and Chat adapter, where
ToolCallDelta.args_deltaalready validatesstr | None.
Acceptance criteria
- Preserve SDK-valid incomplete function-call output and terminal semantics across affected translated streaming and non-streaming routes.
- Add SDK-parsed, cassette-backed parity coverage for public behavior changes; use playback only and keep synthetic mutations in memory.
- Resolve the Messages object-only collection discrepancy with explicit parity coverage.
- Classify remaining restrictions as necessary integrity/projection checks, removable validation, or separately scoped translation support. Document retained limitations and any contract changes.
- Preserve request/history validation, call identity, signatures, and existing stream lifecycle guarantees unless an explicit policy change is agreed.
Verification already performed
- The synthetic SDK/Molto incomplete-call reproduction above confirmed rejection.
- On
acf4abe, the following offline tests passed (3 total), confirming current intentional rejection behavior:
.venv/bin/python -m pytest -q \
tests/upstream/test_openai.py::test_responses_events_reject_reasoning_outside_capability \
tests/upstream/test_openai.py::test_chat_completions_events_reject_noncontiguous_tool_call_deltas \
tests/upstream/test_openai.py::test_responses_events_reject_programmatic_function_call- The remaining findings were established by code inspection. No production code or cassettes were changed, and the full suite was not run for this audit.
Activity