Skip to content

feat(cli): send pasted images to the /btw side agent - #3619

Closed
liukx0205 wants to merge 4 commits into
mainfrom
feat/btw-image-support
Closed

feat(cli): send pasted images to the /btw side agent#3619
liukx0205 wants to merge 4 commits into
mainfrom
feat/btw-image-support

Conversation

@liukx0205

Copy link
Copy Markdown
Collaborator

Problem

The /btw side-question panel is a text-only channel: when the user pastes an image and asks a side question, the [image #N] placeholder goes to the side agent as literal text and the image bytes never leave the TUI's attachment store — the side agent cannot see the image at all. The daemon side is already ready (mediaResolver / prompt media intake / session media store all apply to the forked btw child); only the TUI input path drops the media.

What changed

  • The btw panel's prompt path now expands pasted image/video placeholders into daemon file-ref prompt parts exactly like the main send path: bounded ingestion wait, extractMediaAttachments, model capability validation, and a staged-media lease with an exact-binding submission id (promptId) so the staging upload is released when the consuming turn ends. Skill bundles match the main inline-skill path (media rides along, no lease). This covers both the initial /btw <question> prompt and follow-up panel input.
  • The btw child's read-only tool allowlist gains ReadMediaFile (already auto-approved by the default-tool-approve policy), so models without image input can still view images via the degraded <image path> form; the side-question reminder mentions it.
  • Server-api docs (en/zh) updated for the new allowlist entry.

Relationship to #3613

Stacked on #3613 (feat/btw-readonly-tools, base of this PR): that PR introduced the BTW_READONLY_TOOLS allowlist this change extends with ReadMediaFile. Once #3613 merges, this PR's base retargets to main. Self-contained alternative (duplicating the allowlist on main) was rejected to avoid a guaranteed merge conflict between the two PRs.

Tests

  • btw.test.ts (agent-core-v2): the read-only allow test now pins the exact allowlist {Read, Grep, Glob, ReadMediaFile} and verifies ReadMediaFile passes the veto.
  • kimi-tui-message-flow.test.ts: two new cases — a pasted image in the initial /btw prompt and in follow-up panel input is sent as kimi-file:// parts with a promptId, and the staging upload survives until the consuming turn ends.

The btw child agent previously vetoed every tool call. Allow the
read-only tools Read, Grep, and Glob so side questions about the
codebase can be answered from current file contents; write and
execute tools stay disabled.
The btw panel's input path was text-only: pasted image placeholders went
to the side agent as literal text and the bytes never left the image
store. Expand media placeholders into daemon file-ref parts exactly like
the main send path (ingestion wait, extraction, capability validation,
staged-media lease with an exact-binding submission id), allow the
read-only ReadMediaFile tool in the btw child, and mention it in the
side-question reminder.

Stacked on #3613 (feat/btw-readonly-tools), which introduced the btw
read-only tool allowlist this change extends.
@changeset-bot

changeset-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8e51319

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

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code 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

@pkg-pr-new

pkg-pr-new Bot commented Sep 7, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@8e51319
npx https://pkg.pr.new/@moonshot-ai/kimi-code@8e51319

commit: 8e51319

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8e513195a1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +247 to +249
this.host.trackBtwDispatch(
prepared.lease,
this.withInteractiveAgent(agentId, send),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Route side-agent turn events through the lease tracker

When an actual /btw turn starts or ends, its agentId is the side-agent ID, so SessionEventHandler.handleEvent returns through routeChildAgentEvent before invoking the host's staging handleTurnStarted or handleTurnEnded hooks. Consequently, the lease tracked here is never bound or released after successful side prompts, and each pasted image/video remains retained in daemon staging until the session is closed or its TTL expires. The new test misses this because emitTurn emits both events for agentId: 'main'; the side-agent routing path must notify the staging tracker as well.

Useful? React with 👍 / 👎.

const useSkills = inlineSkillActivations !== undefined && inlineSkillActivations.length > 0;
// Skill bundles have no prompt-id channel, so they match the main turn's
// inline-skill path: media rides along without a staged lease.
const prepared = await this.host.prepareBtwPrompt(prompt, { stage: !useSkills });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Abort preparation when the BTW panel is closed

If a just-pasted image or video is still being ingested, this await can last up to two seconds. During that interval, Esc or Ctrl-C closes/unregisters the panel and calls session.cancel() while the child is still idle, but the continuation never checks whether the panel remains active and subsequently dispatches the prompt anyway. This produces an invisible side-agent request after the user explicitly canceled it (and can overlap a newly opened /btw panel); cancellation or panel identity should be rechecked before dispatch, with any prepared lease released on abandonment.

Useful? React with 👍 / 👎.

Base automatically changed from feat/btw-readonly-tools to main September 8, 2026 06:50
@liukx0205

Copy link
Copy Markdown
Collaborator Author

Closing in favor of the desktop implementation in kimi-code-app. Note: the daemon-side ReadMediaFile allowlist for /btw is intentionally not carried over for now — the desktop media path is session-level and does not need it; can be re-added separately if a model without image input needs it.

@liukx0205 liukx0205 closed this Sep 8, 2026
@liukx0205

Copy link
Copy Markdown
Collaborator Author

Closing in favor of the desktop implementation in kimi-code-app. Note: the daemon-side ReadMediaFile allowlist for /btw is intentionally not carried over — the desktop media path is session-level and does not need it; can be re-added separately if a model without image input needs it.

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