Skip to content

feat(attachments): add remote CLI file delivery - #12747

Merged
iscekic merged 10 commits into
mainfrom
attachments-cli-f31a
Aug 3, 2026
Merged

feat(attachments): add remote CLI file delivery#12747
iscekic merged 10 commits into
mainfrom
attachments-cli-f31a

Conversation

@iscekic

@iscekic iscekic commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

What

  • Raise remote CLI inbound attachment materialization to 20 MiB and extend bounded fetch time to 60 seconds.
  • Add the connected remote send_file tool for one local file delivery to the Kilo mobile app.
  • Correct binary scratch guidance and retain the original propagation-error test assertion.

Why

Phone attachments need 20 MiB inbound support. A remote CLI needs a bounded file delivery path back to the phone.

How

  • send_file uses the tool-attachment transport, read-style authorization, MIME sniffing, basename filename, and a 4 MiB cap.
  • The paired cloud fix sends the original picker filename in each remote file part.
  • This CLI keeps the runtime execution connection gate and raises only the inbound materialization limit and timeout.
  • Cross-repo PR: feat(attachments): support remote CLI file delivery cloud#4944

Verification

  • Required iOS remote-CLI E2E: 2026-08-02; CLI 0.0.0-attachments-cli-f31a-202608021745; IOS-1 pass, IOS-2 pass, IOS-3 pass, IOS-4 pass, IOS-5 pass through the planned unit-only fallback.
  • The catalog listed send_file; the real model delivered delivery.txt; the mobile app rendered and shared the file chip.
  • Focused send-file test passed. packages/opencode typecheck passed.
  • Root bun run lint completed with existing repository warnings and no errors.
  • Fresh cumulative implementation review cleared the section diff.

The native share sheet opens from that chip with the delivered MIME type. Sheet opens for the chip, chip shows the MIME, and the named unit test asserts the forwarded mimeType. iOS never renders a MIME string in the sheet, so this is the full bar. Do not invent UI MIME text.

AC7 (unavailable row) is covered by unit tests, not by this E2E run: on cold open the delivered part returned a non-empty attachment URL, so the empty state was not reachable without faking it. Coverage: apps/mobile/src/components/agents/tool-card-image-cache.test.ts (cache miss leaves no URI, which is the condition the row renders on) and the FileChip unavailable branch in apps/mobile/src/components/agents/tool-card-file-attachments.tsx:28-36.

Visual Changes

N/A

Comment thread packages/opencode/src/kilocode/tool/send-file.ts Outdated
Comment thread packages/opencode/src/kilocode/tool/send-file.ts
Comment thread packages/opencode/src/kilocode/tool/send-file.ts Outdated
Comment thread packages/opencode/src/kilocode/tool/send-file.ts Outdated
Comment thread packages/opencode/src/kilocode/tool/send-file.ts Outdated
Comment thread packages/opencode/src/kilocode/remote-attachments.ts
Comment thread packages/opencode/src/kilocode/remote-attachments.ts
Comment thread packages/kilo-docs/pages/code-with-ai/platforms/mobile.md
Comment thread packages/kilo-docs/pages/code-with-ai/platforms/mobile.md Outdated
@kilo-code-bot

kilo-code-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
.changeset/ - Still no changeset for a clearly user-facing change (new send_file tool plus the 5 MiB -> 20 MiB inbound attachment limit). git diff main...HEAD -- .changeset is empty.
Files Reviewed (1 file changed since last review)
  • packages/opencode/test/kilocode/tool/send-file.test.ts - no new issues; previous loose-assertion suggestion resolved

Resolved since the previous review: send-file.test.ts:505 now asserts rejects.toMatchObject({ code: "EPERM" }) instead of the catch-all rejects.toThrow(), so the non-NotFound stat propagation test can no longer pass on an unrelated rejection.

Notes / assumptions: The only PR-owned commit since 518be2a is the test assertion above; the rest of the incremental range is a origin/main merge and unrelated to this PR's diff. Per incremental scope, findings in files untouched by that commit are not carried forward here — the previously raised items on processor.ts:714, remote-attachments.ts:71/75, and message-v2.ts:434 remain as active inline threads with author responses and were not re-raised. The merge integration was spot-checked: the new KiloSessions.reportSessionTitle member from main is stubbed in the registry test this PR also touches, so no stale service stubs were left behind. No checks were executed (read-only review).

Fix these issues in Kilo Cloud

Previous Review Summaries (5 snapshots, latest commit 518be2a)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 518be2a)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 2
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/session/processor.ts 714 Skipping image.normalize for send_file removes the only downstream clamp on delivery size: a ~5.46 MiB base64 URL is cloned into the V1 part, republished as V2 content, fanned out over SSE, and reloaded per prompt build, with no per-session send_file budget

SUGGESTION

File Line Issue
packages/opencode/test/kilocode/tool/send-file.test.ts 505 rejects.toThrow() passes for any rejection, so the new non-NotFound test can stay green without covering the narrowing; assert the propagated cause and prefer Layer.mock over the full-interface cast
.changeset/ - Still no changeset for a user-facing change (new send_file tool plus the 5 MiB → 20 MiB inbound attachment limit)
Files Reviewed (2 files changed since last review)
  • packages/opencode/src/kilocode/tool/send-file.ts - no new issues; both previous suggestions resolved
  • packages/opencode/test/kilocode/tool/send-file.test.ts - 1 new suggestion (loose assertion in the added propagation test)

Resolved since the previous review: the blanket fs.stat catch now narrows to reason._tag === "NotFound", matching read.ts:224; the catch-all that converted TOCTOU/abort failures into successful tool results is gone, so execute ends with Effect.orDie exactly like read.ts:398; and the test fsService stub now fabricates NotFound only for ENOENT and propagates every other cause.

Author-declined (not re-raised): the 20 MiB per-attachment cap and 60s timeout in remote-attachments.ts, and the send_file tool-id literal in shared message-v2.ts:434.

Notes / assumptions: send-file.ts is unchanged in behavior apart from the two error-handling fixes; the rest of the diff is re-indentation. The processor.ts:714 warning was re-verified against current HEAD (518be2a) and remains open. Cloud-side caps referenced in the SEND_FILE_MAX_BYTES comment are not present in this repo and could not be verified. No checks were executed (read-only review).

Fix these issues in Kilo Cloud

Previous review (commit 7620632)

Status: 8 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 5
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/session/processor.ts 714 Skipping image.normalize removes the only downstream clamp on delivery size: a ~5.46 MiB base64 URL is structuredCloned into the V1 part, republished as V2 content, fanned out over SSE, and reloaded per prompt build, with no per-session send_file budget
packages/opencode/src/kilocode/remote-attachments.ts 75 60s per-attachment timeout with sequential fetches and no aggregate budget allows a multi-minute prompt stall (author declined: approved scope)
packages/opencode/src/kilocode/remote-attachments.ts 71 20 MiB per-attachment cap with no CLI-side aggregate byte or count cap (author declined: approved scope)

SUGGESTION

File Line Issue
packages/opencode/src/kilocode/tool/send-file.ts 58 Blanket Effect.catch on fs.stat swallows EACCES/ELOOP/ENOTDIR and reports them as File not found; read.ts:224 narrows to reason._tag === "NotFound"
packages/opencode/src/kilocode/tool/send-file.ts 158 Catch-all converts TOCTOU ChangedError and ctx.abort rejections into successful tool results and echoes raw error.message (absolute paths) to the model; trailing Effect.orDie is now a no-op
packages/opencode/test/kilocode/tool/send-file.test.ts 477 Fabricated stat error discards the real cause and its synthetic reason is never inspected, so the tests cannot cover the NotFound-vs-other distinction
packages/opencode/src/session/message-v2.ts 434 Fork hygiene: send_file tool-id literal inlined in the shared upstream converter, now duplicated in processor.ts:714 and must stay in sync (author declined)
.changeset/ - No changeset for a user-facing change (new send_file tool plus a 5 MiB → 20 MiB inbound attachment limit)
Files Reviewed (4 files changed since last review)
  • packages/opencode/src/kilocode/tool/send-file.ts - 2 new suggestions (missing/directory pre-authorization plus catch-all error mapping)
  • packages/opencode/src/session/processor.ts - 1 new warning (send_file normalization bypass)
  • packages/opencode/test/kilocode/tool/send-file.test.ts - 1 new suggestion (fabricated stat error in the fsService stub)
  • packages/opencode/test/session/processor-effect.test.ts - no issues; the new regression test does cover the normalization bypass

Resolved since the previous review: the non-image replay into model context (message-v2.ts strip plus test), the 4 MiB cap vs. Image.MAX_BASE64_BYTES conflict (now bypassed in processor.ts), permission ordering for missing/directory paths and the previous unconditional Effect.orDie, the fallback MIME source, the reported byte count, and both mobile.md docs notes.

Notes / assumptions: carried-forward findings were re-verified against current HEAD (7620632). Cloud-side caps referenced in the SEND_FILE_MAX_BYTES comment (MAX_INGEST_EVENT_BYTES, the ~1.94 MiB R2 spill, the 8 MiB page budget) are not present in this repo and could not be verified here. No checks were executed (read-only review).

Fix these issues in Kilo Cloud

Previous review (commit a2b8605)

Status: 6 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 4
SUGGESTION 2
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/kilocode/tool/send-file.ts 23 4 MiB cap exceeds Image.MAX_BASE64_BYTES (5 MB base64, src/image/image.ts:10), so a large image can be re-encoded or dropped downstream with an "omitted" note after the tool already reported delivery
packages/opencode/src/kilocode/tool/send-file.ts 53 Existence/type probing runs before any permission ask, unlike read.ts's stat-then-miss() ordering; Effect.orDie also turns missing-path/directory cases into defects instead of structured results
packages/opencode/src/kilocode/remote-attachments.ts 75 60s per-attachment timeout with sequential fetches and no aggregate budget allows a ~300s prompt stall (was 75s)
packages/opencode/src/kilocode/remote-attachments.ts 71 20 MiB per-attachment cap means ~67 MB peak and ~27 MB retained per attachment, with no CLI-side aggregate byte or count cap

SUGGESTION

File Line Issue
packages/opencode/src/session/message-v2.ts 434 Fork hygiene: the send_file tool-id literal is inlined in the shared upstream converter; a Kilo-owned predicate or an attachment-level delivery-only flag would keep shared code generic (latest commit only wrapped it in kilocode_change start/end markers)
.changeset/ - No changeset for a user-facing change (new send_file tool plus a 5 MiB → 20 MiB inbound attachment limit)
Files Reviewed (2 files changed since last review)
  • packages/opencode/src/session/message-v2.ts - marker-only change; the send_file strip logic is unchanged
  • packages/opencode/test/session/message-v2.test.ts - marker-only change around the existing strip test

Notes / assumptions: the incremental diff since d0ab34a only converts the single-line kilocode_change comment into a start/end block in message-v2.ts and its test — no behavior change, so no new inline comments were posted. The four warnings and two suggestions above were re-verified against current HEAD (a2b8605) and remain open. Cloud-side caps referenced in the SEND_FILE_MAX_BYTES comment (MAX_INGEST_EVENT_BYTES, the ~1.94 MiB R2 spill, the 8 MiB page budget) are not present in this repo and could not be verified here.

Fix these issues in Kilo Cloud

Previous review (commit d0ab34a)

Status: 6 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 4
SUGGESTION 2
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/kilocode/tool/send-file.ts 23 4 MiB cap exceeds Image.MAX_BASE64_BYTES (5 MB base64, src/image/image.ts:10), so a large image is re-encoded or dropped by processor.ts:709 with an "omitted" note after the tool already reported delivery
packages/opencode/src/kilocode/tool/send-file.ts 53 Existence/type probing runs before any permission ask, unlike read.ts's stat-then-miss() ordering; Effect.orDie also turns missing-path/directory cases into defects instead of structured results
packages/opencode/src/kilocode/remote-attachments.ts 75 60s per-attachment timeout with sequential fetches and no aggregate budget allows a ~300s prompt stall (was 75s)
packages/opencode/src/kilocode/remote-attachments.ts 71 20 MiB per-attachment cap means ~67 MB peak and ~27 MB retained per attachment, with no CLI-side aggregate byte or count cap

SUGGESTION

File Line Issue
packages/opencode/src/session/message-v2.ts 434 Fork hygiene: the send_file tool-id literal is inlined in the shared upstream converter; a Kilo-owned predicate or an attachment-level delivery-only flag would keep shared code generic
.changeset/ - No changeset for a user-facing change (new send_file tool plus a 5 MiB → 20 MiB inbound attachment limit)
Resolved since the previous review
  • CRITICAL: send_file attachments replayed to the provider on every later turn — fixed by the message-v2.ts strip; verified toModelMessagesEffect is the only model-message conversion and, with no stopWhen, it is re-entered on every tool round-trip
  • Fallback mime now derived from the resolved requested path
  • Success message now reports the delivered bytes.byteLength
  • mobile.md: stray blank lines removed and the inbound limit now reads 20 MiB
Files Reviewed (12 files)
  • packages/opencode/src/session/message-v2.ts - 1 issue
  • packages/opencode/src/kilocode/tool/send-file.ts - 2 issues
  • packages/opencode/src/kilocode/remote-attachments.ts - 2 issues
  • packages/kilo-docs/pages/code-with-ai/platforms/mobile.md
  • packages/opencode/src/kilocode/tool/registry.ts
  • packages/opencode/src/kilocode/tool/send-file.txt
  • packages/opencode/test/session/message-v2.test.ts
  • packages/opencode/test/kilocode/tool/send-file.test.ts
  • packages/opencode/test/kilocode/remote-attachments.test.ts
  • packages/opencode/test/kilocode/tool-registry-indexing.test.ts
  • packages/opencode/test/kilocode/tool-registry-indexing-import-failure.test.ts
  • packages/opencode/test/kilocode/tool-registry-semantic-import-failure.test.ts

Notes / assumptions: the new message-v2.test.ts case uses the shared OpenAI-family fixture, where supportsMediaInToolResult is true, so it genuinely fails without the strip. Cloud-side caps referenced in the SEND_FILE_MAX_BYTES comment (MAX_INGEST_EVENT_BYTES, the ~1.94 MiB R2 spill, the 8 MiB page budget) are not present in this repo and could not be verified here.

Fix these issues in Kilo Cloud

Previous review (commit d89bb4f)

Status: 10 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 4
SUGGESTION 5
Issue Details (click to expand)

CRITICAL

File Line Issue
packages/opencode/src/kilocode/tool/send-file.ts 105 Non-image/non-PDF attachments are kept on the completed tool part and replayed to the provider as a media part every later turn (message-v2.ts:435-448, provider/transform.ts:384, kilocode/session/prompt.ts:565), so a 4 MiB delivery costs ~5.6 MB base64 per turn and likely triggers provider errors

WARNING

File Line Issue
packages/opencode/src/kilocode/tool/send-file.ts 23 4 MiB cap exceeds Image.MAX_BASE64_BYTES (5 MB base64), so large images are re-encoded or dropped with an "omitted" note after the tool already reported delivery
packages/opencode/src/kilocode/tool/send-file.ts 53 Existence/type probing runs before any permission ask, unlike read.ts's stat-then-miss() ordering; also makes missing-path/directory cases defects via Effect.orDie instead of structured results
packages/opencode/src/kilocode/remote-attachments.ts 75 60s per-attachment timeout with sequential fetches and no aggregate budget allows a ~300s prompt stall (was 75s)
packages/opencode/src/kilocode/remote-attachments.ts 71 20 MiB cap means ~67 MB peak and ~27 MB retained per attachment, with no CLI-side aggregate byte or count cap

SUGGESTION

File Line Issue
packages/opencode/src/kilocode/tool/send-file.ts 87 Mime fallback derived from raw params.path instead of the resolved requested (diverges from read.ts:323)
packages/opencode/src/kilocode/tool/send-file.ts 103 Success message reports the pre-open stat size rather than the delivered bytes.byteLength
packages/kilo-docs/pages/code-with-ai/platforms/mobile.md 76 Three stray blank lines; if a screenshot was intended, use the Markdoc {% image %} tag, not raw HTML <img>
packages/kilo-docs/pages/code-with-ai/platforms/mobile.md 67 "20 MB" vs the enforced 20 MiB cap; neighboring text uses MiB
.changeset/ - No changeset for a user-facing change (new send_file tool plus a 5 MiB → 20 MiB inbound attachment limit)
Files Reviewed (10 files)
  • packages/opencode/src/kilocode/tool/send-file.ts - 5 issues
  • packages/opencode/src/kilocode/remote-attachments.ts - 2 issues
  • packages/kilo-docs/pages/code-with-ai/platforms/mobile.md - 2 issues
  • packages/opencode/src/kilocode/tool/registry.ts
  • packages/opencode/src/kilocode/tool/send-file.txt
  • packages/opencode/test/kilocode/tool/send-file.test.ts
  • packages/opencode/test/kilocode/remote-attachments.test.ts
  • packages/opencode/test/kilocode/tool-registry-indexing.test.ts
  • packages/opencode/test/kilocode/tool-registry-indexing-import-failure.test.ts
  • packages/opencode/test/kilocode/tool-registry-semantic-import-failure.test.ts

Notes / assumptions: cloud-side caps referenced in the SEND_FILE_MAX_BYTES comment (MAX_INGEST_EVENT_BYTES, the ~1.94 MiB R2 spill, the 8 MiB page budget) are not present in this repo and could not be verified here. Tests cover availability gating, mime sniffing, basename, permission asks, and the pre-read size rejection, but nothing downstream of execute (post-read TOCTOU branch, model-context replay, image normalization).

Fix these issues in Kilo Cloud


Reviewed by claude-opus-5 · Input: 32 · Output: 7.1K · Cached: 898.9K

Review guidance: REVIEW.md from base branch main

Comment thread packages/opencode/src/session/message-v2.ts
Comment thread packages/opencode/src/session/processor.ts
Comment thread packages/opencode/src/kilocode/tool/send-file.ts Outdated
Comment thread packages/opencode/src/kilocode/tool/send-file.ts Outdated
Comment thread packages/opencode/test/kilocode/tool/send-file.test.ts
Comment thread packages/opencode/test/kilocode/tool/send-file.test.ts Outdated
@iscekic

iscekic commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator Author

(bot) BLOCKED: required paired iOS bot-E2E could not complete. The locally built current-branch CLI and remote relay were live, its TUI proved Auto Efficient Kilo Gateway, and the mobile remote session was writable; however the mobile accessibility tree did not expose the required Auto Efficient model control. After the capped verifier attempts and direct takeover, sending a real prompt without that required observable assertion would violate the E2E contract. All E2E resources and the slot were released. Full evidence is retained in the workflow scratch final report.

@iscekic

iscekic commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator Author

(bot) BLOCKED: required bot E2E cannot complete. A fresh direct iOS phase used the branch-built CLI, confirmed the CLI TUI header Auto Efficient Kilo Gateway, enabled the remote relay, and made real Efficient-model requests. The model twice reported that send_file is unavailable, so the required live delivery/share scenarios cannot run without injecting a tool part (prohibited). All E2E resources and slots were released. Full evidence: workflow final report.

@iscekic iscekic added the human-ready PR is ready for a human review. label Aug 2, 2026
@iscekic
iscekic merged commit 1f3a3b2 into main Aug 3, 2026
33 checks passed
@iscekic
iscekic deleted the attachments-cli-f31a branch August 3, 2026 11:12
t7tran pushed a commit to t7tran/kilocode that referenced this pull request Aug 14, 2026
* fix(cli): clarify remote binary attachment notice

* feat(cli): add remote send_file tool

* docs(mobile): explain remote session attachments

* fix(cli): keep delivered files out of model context

* fix(cli): mark delivery filter as kilocode change

* fix(cli): preserve delivered image files

* test(cli): narrow delivery attachment state

* fix(send-file): preserve filesystem failures

* test(send-file): assert propagated file read error
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

human-ready PR is ready for a human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants