file transfer (python): parse images/files, wire directive sink to Rust parity - #344
Merged
Conversation
…st parity Bring the Python smooth-operator server to parity with the Rust reference on the file-transfer contract (spec PR #342): - images[]: attached to the model's user message as OpenAI image_url content parts (multimodal turns), in-tree in turn_runner against the pinned published core — no core release needed. Guarded fail-soft: falls back to text-only when a knowledge base is wired (the pinned core reuses the message for retrieval). - files[]: parsed fail-soft onto a new per-turn TurnContext (the Python analog of Rust's ToolProviderContext), surfaced for a host tool to land in the workspace; never sent to the model. - directive sink: TurnContext carries a last-write-wins directive a host tool writes (e.g. the send_file convention); drained after the turn onto TurnResult.directive and emitted on eventual_response.directive (omitted when none — back-compat). - Regenerated the SDK types from the updated spec (files[] + directive docs). - Tests: images-attach, files-on-context, tool->directive->eventual_response, fail-soft parsing, dispatcher forwarding + attachment parsing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 9f82d96 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The Python
smooth-operator-serverwas behind the Rust reference on the file-transfer contract merged in #342 (send_message.files[]+ thesend_filedirective convention). Itssend_messagepath was text-only:images[]were ignored,files[]had nowhere to land, and there was no tool→directive channel ontoeventual_response.Solution
Parity with the Rust server (
handler.rs/runner.rs/tool_provider.rs/protocol.rs):image_urlcontent parts (multimodal turns). Done in-tree inturn_runneragainst the pinned published core (run_stream(message)drops it straight onto the user message) — no core release needed. Fail-soft, and guarded: falls back to text-only when a knowledge base is wired, because the pinned core reuses the same message for its retrieval query (a content list would crash tokenization). Clean fix lands when the core grows a dedicated user-images seam (feature-detect then, as with_CORE_SUPPORTS_*).TurnContext(the Python analog of Rust'sToolProviderContext), surfaced for a host tool to land into the workspace. Never sent to the model.TurnContextcarries a last-write-winsdirectivea host tool writes (e.g. thesend_fileconvention). Drained after the turn ontoTurnResult.directiveand emitted aseventual_response.directive— omitted when none (back-compat)._generated.py) from the updated spec (files[]+ directive docs; also picks up the already-mergedskillfield).All fail-soft and back-compatible: a text-only turn with no attachments is byte-identical to before.
Verification
tests/test_file_transfer.py(14 tests): image→content-parts mapping, fail-soft parsing (_build_user_content/_parse_attachments), images-attach integration, files-stay-off-model, tool→directive→TurnResult, directive last-write-wins,eventual_responsedirective present/absent, dispatcher directive forwarding + attachment parsing.python.ymlfor both projects:ruff check,ruff format --check,pytest— server 246 passed / 1 skipped, core 52 passed / 1 skipped.@smooai/smooth-operator-server).🤖 Generated with Claude Code