Skip to content

protocol: file-transfer contract (send_message.files[] + send_file directive) - #342

Merged
brentrager merged 1 commit into
mainfrom
filetransfer-protocol
Aug 11, 2026
Merged

protocol: file-transfer contract (send_message.files[] + send_file directive)#342
brentrager merged 1 commit into
mainfrom
filetransfer-protocol

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

What

Spec-level contract for bidirectional file transfer across all faces of Big Smooth.

  • Attach (user→agent): new optional send_message.files[]{name, mimeType?, url(data:)}. Unlike vision images[], these are surfaced to the host on the tool-provider context so the host lands them in the agent workspace (read_file/bash can then use them). Fail-soft, back-compatible.
  • Send (agent→user): documents the send_file convention on the existing opaque eventual_response.directive: {type:'send_file', files:[{name, mimeType?, url}]}. A host send_file tool writes it onto the turn's directive sink; faces render each file as a download/share.

Scope of this PR

Spec-only (additive, optional fields — no conformance fixture change, so all four generated-type lanes stay green). Per-language server behavior (parse files; wire the directive sink in Go/TS/Python/.NET to Rust's parity) lands in follow-up per-language PRs that regen types from this spec.

Part of the Big Smooth bidirectional file-transfer epic (agent send + user attach, all faces: th code, th web, iOS, Android).

🤖 Generated with Claude Code

https://claude.ai/code/session_01Vzh8t76aDVgeoiwC9KEKZZ

…irective

Add a non-image files[] attachment field to send_message (host lands each in the
agent workspace so read_file/bash can use it; distinct from vision images[]), and
document the send_file host directive convention on eventual_response.directive
for agent->user file delivery. Spec-only; per-language server behavior follows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vzh8t76aDVgeoiwC9KEKZZ
@changeset-bot

changeset-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8f08306

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@smooai/smooth-operator-server Minor

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

@brentrager
brentrager merged commit 5e7b891 into main Aug 11, 2026
6 checks passed
brentrager added a commit that referenced this pull request Aug 11, 2026
…st parity (#344)

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>
brentrager added a commit that referenced this pull request Aug 11, 2026
…arity (#345)

Bring the Go smooth-operator server to parity with Rust on the file-transfer
contract (spec #342): send_message.images[] / files[] attachments and the
send_file directive convention on eventual_response.directive.

- Regen go/protocol/types_gen.go from the #342 spec: adds Files (and the
  previously-unregenerated Skill field). Generated file, not hand-edited.
- Parse images[] + files[] fail-soft in handleSendMessage (a malformed array is
  dropped wholesale, never rejecting the turn — matching Rust's
  from_value(...).ok().unwrap_or_default()).
- New TurnContext (go/server/turn_context.go): the Go analog of the Rust
  ToolProviderContext file-transfer fields. Carries the turn's images + files
  and a directive sink, attached to the turn's context.Context so a host tool
  reads it via TurnContextFrom(ctx) (the engine dispatches every tool with that
  ctx). Directive is last-write-wins, concurrency-safe under ParallelToolCalls.
- Drain the directive sink after the turn onto eventual_response.directive
  (omitted when no tool wrote one — back-compat), mirroring the Rust drain.
- Tests: images/files reach a tool, a tool's directive lands on
  eventual_response, absent-directive omission, fail-soft on malformed
  images/files, directive last-write-wins.

Known gap (documented in turn_context.go): images are NOT attached to the model
turn as OpenAI image_url content parts. The pinned Go engine core
(smooth-operator-core/go) ChatMessage.Content is a plain string with no
multimodal content and no AgentOptions user-images option; unlike Rust's core
(ImageContent + with_user_images), that support does not exist in the Go core,
which is an external, pinned dependency from a separate repo. Attaching images
to the model requires a smooth-operator-core/go release adding multimodal
ChatMessage content + AgentOptions.UserImages + openai.go serialization, then a
pin bump — out of scope for this single-repo PR. Until then images are surfaced
to host tools only.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
brentrager added a commit that referenced this pull request Aug 11, 2026
…arity (#346)

Implement the PR #342 file-transfer contract in the TypeScript smooth-operator
server, to parity with the Rust reference:

- Regenerate the client SDK protocol types so send_message gains images[]/files[]
  and eventual_response gains directive.
- images[] are attached to the turn's user message as OpenAI image_url content
  parts. The published core takes a plain-string message and reuses it for
  retrieval, so a withUserImages() wrapper rewrites the outgoing request body's
  current user message instead (retrieval/memory stay text-based).
- files[] are surfaced on a new per-turn ToolContext (never sent to the model),
  mirroring the Rust ToolProviderContext.
- New optional toolProvider seam (mirrors Rust ToolProvider): host tools bound to
  the turn's context can read the attachments and write ctx.directive; the
  dispatcher drains it onto eventual_response.directive (last-write-wins).
- All attachment parsing is fail-soft.
- Tests: withUserImages/parse unit tests + end-to-end images-attach,
  files-on-context, tool->directive->eventual_response, and fail-soft.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
brentrager added a commit that referenced this pull request Aug 11, 2026
…st parity (#348)

Bring the C# smooth-operator server to Rust parity on the PR #342 file-transfer
contract. send_message was text-only; it now handles images[], files[], and the
send_file directive.

- Regenerate Types.cs from the updated spec (adds SendMessageRequest.Files, Skill).
- images[]: parsed fail-soft, attached as OpenAI image_url content parts. The
  engine builds the live user turn from a string, so images ride an image-only
  ChatMessage seated on the thread just before the text turn (no empty/duplicate
  message). data: -> DataContent, http(s) -> UriContent; detail on
  AdditionalProperties. Malformed/unsupported entries dropped.
- files[]: parsed fail-soft, surfaced on a new per-turn TurnContext (AsyncLocal)
  so host tools can read them; never sent to the model.
- Directive sink: a host tool writes onto TurnContext.Current.Directive; drained
  after the turn onto eventual_response.directive (last-write-wins, omitted when
  none for back-compat).
- Tests: FileTransferTests covers images-attach, malformed fail-soft, files-on-
  context, tool->directive->eventual_response, and directive omission.

Source-only; the engine stays the published NuGet (no publish).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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