Skip to content

[3 of 3] Support images in TUI goals#27510

Merged
etraut-openai merged 1 commit into
mainfrom
etraut/tui-goal-image-files
Jun 13, 2026
Merged

[3 of 3] Support images in TUI goals#27510
etraut-openai merged 1 commit into
mainfrom
etraut/tui-goal-image-files

Conversation

@etraut-openai

@etraut-openai etraut-openai commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Stack

  1. [1 of 3] Support long raw TUI goal objectives - [1 of 3] Support long raw TUI goal objectives #27508
  2. [2 of 3] Support long pasted text in TUI goals - [2 of 3] Support long pasted text in TUI goals #27509
  3. [3 of 3] Support images in TUI goals - this PR

Why

The first two PRs make goal definitions resilient to long text, but /goal still dropped image inputs from the composer. That meant a user could attach images while defining a goal and the resulting goal continuation would not have any useful reference to those images.

Goal state still persists only objective text, so image inputs need to become paths or URLs that the agent can read later.

What Changed

  • Extends TUI GoalDraft with local image attachments and remote image URLs.
  • Copies local goal images through the app-server filesystem layer into the managed goal attachment directory, then rewrites active image placeholders to file references.
  • Appends unplaced local images and remote image URLs to the objective as referenced image files or URLs.
  • Preserves goal image metadata through live /goal submission and queued /goal dispatch.

Verification

  • Added goal materialization coverage for local image files and remote image URLs.
  • Added/updated TUI slash-command coverage showing /goal drafts include attached images instead of dropping them.

Manual Testing

  • Attached an image by bracketed-pasting its local path into a live /goal composer. The [Image #1] placeholder became a server-host image-1.png reference, copied bytes matched exactly, and no attachment was written under the TUI's local home.
  • Deleted an image placeholder before submitting a small goal and verified no image was copied.
  • Attached PNG and JPEG files to the same goal. Placeholder order was preserved as image-1.png and image-2.jpg, and both remote copies matched their source bytes.
  • Tried extensionless, malformed-extension, and extension/content-mismatched paths; the composer rejected them as image attachments before goal dispatch rather than creating misleading managed image files.
  • Combined a local image, a large pasted block, and enough raw text to exceed 4,000 characters. The remote attachment directory contained the image, paste sidecar, and goal-objective.md; all embedded references used server-host paths and both payloads matched their sources.
  • Submitted an image replacement while a goal was active, verified no image was copied before confirmation, then canceled and confirmed the attachment count was unchanged.

@etraut-openai etraut-openai force-pushed the etraut/tui-goal-paste-files branch from 72abdd8 to 3a114af Compare June 11, 2026 01:45
@etraut-openai etraut-openai force-pushed the etraut/tui-goal-image-files branch from b50ffb2 to 5c1d7f6 Compare June 11, 2026 01:47
@etraut-openai etraut-openai changed the title Support images in TUI goals [3 of 3] Support images in TUI goals Jun 11, 2026
@etraut-openai etraut-openai marked this pull request as ready for review June 11, 2026 02:52

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

Copy link
Copy Markdown
Contributor

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: 0b7dd3cab6

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread codex-rs/tui/src/goal_files.rs Outdated

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

Copy link
Copy Markdown
Contributor

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: d08edfbac2

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread codex-rs/tui/src/goal_files.rs
etraut-openai added a commit that referenced this pull request Jun 12, 2026
## Stack

1. **[1 of 3] Support long raw TUI goal objectives** - this PR
2. [2 of 3] Support long pasted text in TUI goals - #27509
3. [3 of 3] Support images in TUI goals - #27510

## Why

`thread/goal/set` limits persisted objective text to 4000 characters.
The TUI used to reject raw `/goal` objectives above that limit, even
though the client can make them usable by writing the long text to a
file and storing a short objective that points at that file.

This also needs to work for remote app-server sessions: filesystem API
calls must create files on the app-server host, and the stored path must
be meaningful to the agent on that host.

## What Changed

- Adds an app-server-host path helper so TUI code can build paths that
are resolved on the app-server host rather than the TUI host.
- Adds TUI app-server session helpers for `fs/createDirectory`,
`fs/writeFile`, `fs/readFile`, and `fs/remove` that work for embedded
and remote app-server sessions without changing the app-server protocol.
- Materializes oversized raw `/goal` objectives into
`$CODEX_HOME/attachments/<uuid>/goal-objective.md` through the
app-server filesystem APIs, then stores a short, readable objective that
directs the agent to that file.
- Reads managed objective files back for `/goal edit`. Other goal UI
renders the readable stored objective normally, without
managed-file-specific presentation logic.
- Recognizes managed references only when they name the expected
generated file under the app server's reported `$CODEX_HOME`, and cleans
up newly materialized files when goal replacement or setting does not
complete.

## Verification

- Added/updated TUI tests for raw oversized `/goal` submission, large
inline-paste expansion, queued oversized goals, app-facing
materialization before `thread/goal/set`, managed-path validation,
editing, and cleanup.
- Added/updated app-server-client remote coverage for initialized remote
Codex home handling.

## Manual Testing

- Ran the real TUI against a Unix-socket app server with different local
and server `$CODEX_HOME` directories. Oversized goals wrote only under
the server home, and persisted references used the server-canonical path
rather than the TUI path.
- Exercised 3,999-, 4,000-, and 4,001-character raw objectives. The
first two stayed inline without new files; the 4,001-character objective
became a managed objective file.
- Submitted a larger 8,275-character objective, verified its full
contents on the app-server host, and observed the goal continuation open
the referenced server-side file.
- Opened `/goal edit` for a managed objective and verified the full text
was restored through remote `fs/readFile`.
- Submitted an oversized replacement while a goal was active, verified
no file was written before confirmation, then canceled and confirmed
that the existing goal and attachment count were unchanged.
@etraut-openai etraut-openai force-pushed the etraut/tui-goal-paste-files branch 2 times, most recently from 583722a to ecb83dc Compare June 12, 2026 05:34
@etraut-openai etraut-openai force-pushed the etraut/tui-goal-image-files branch from c97dcd9 to 1f620e8 Compare June 12, 2026 05:37
GLBB pushed a commit to GLBB/codex that referenced this pull request Jun 12, 2026
## Stack

1. **[1 of 3] Support long raw TUI goal objectives** - this PR
2. [2 of 3] Support long pasted text in TUI goals - openai#27509
3. [3 of 3] Support images in TUI goals - openai#27510

## Why

`thread/goal/set` limits persisted objective text to 4000 characters.
The TUI used to reject raw `/goal` objectives above that limit, even
though the client can make them usable by writing the long text to a
file and storing a short objective that points at that file.

This also needs to work for remote app-server sessions: filesystem API
calls must create files on the app-server host, and the stored path must
be meaningful to the agent on that host.

## What Changed

- Adds an app-server-host path helper so TUI code can build paths that
are resolved on the app-server host rather than the TUI host.
- Adds TUI app-server session helpers for `fs/createDirectory`,
`fs/writeFile`, `fs/readFile`, and `fs/remove` that work for embedded
and remote app-server sessions without changing the app-server protocol.
- Materializes oversized raw `/goal` objectives into
`$CODEX_HOME/attachments/<uuid>/goal-objective.md` through the
app-server filesystem APIs, then stores a short, readable objective that
directs the agent to that file.
- Reads managed objective files back for `/goal edit`. Other goal UI
renders the readable stored objective normally, without
managed-file-specific presentation logic.
- Recognizes managed references only when they name the expected
generated file under the app server's reported `$CODEX_HOME`, and cleans
up newly materialized files when goal replacement or setting does not
complete.

## Verification

- Added/updated TUI tests for raw oversized `/goal` submission, large
inline-paste expansion, queued oversized goals, app-facing
materialization before `thread/goal/set`, managed-path validation,
editing, and cleanup.
- Added/updated app-server-client remote coverage for initialized remote
Codex home handling.

## Manual Testing

- Ran the real TUI against a Unix-socket app server with different local
and server `$CODEX_HOME` directories. Oversized goals wrote only under
the server home, and persisted references used the server-canonical path
rather than the TUI path.
- Exercised 3,999-, 4,000-, and 4,001-character raw objectives. The
first two stayed inline without new files; the 4,001-character objective
became a managed objective file.
- Submitted a larger 8,275-character objective, verified its full
contents on the app-server host, and observed the goal continuation open
the referenced server-side file.
- Opened `/goal edit` for a managed objective and verified the full text
was restored through remote `fs/readFile`.
- Submitted an oversized replacement while a goal was active, verified
no file was written before confirmation, then canceled and confirmed
that the existing goal and attachment count were unchanged.
etraut-openai added a commit that referenced this pull request Jun 12, 2026
## Stack

1. [1 of 3] Support long raw TUI goal objectives - #27508
2. **[2 of 3] Support long pasted text in TUI goals** - this PR
3. [3 of 3] Support images in TUI goals - #27510

## Why

Large text pasted into the TUI composer is represented as a paste
placeholder plus pending paste metadata. For `/goal`, preserving only
the visible placeholder is not enough: the agent would see a short
placeholder string instead of the actual pasted text, and the long-text
support from the first PR would never see the payload.

The TUI also needs to avoid writing stale sidecar files when a user
pastes a large block and then deletes its placeholder before submitting
the goal.

## What Changed

- Introduces a TUI `GoalDraft` for goal submissions so `/goal`, `/goal
edit`, and queued goal commands can carry objective text plus text
elements and pending paste payloads.
- Materializes active pasted-text placeholders to `pasted-text-N.txt`
files through the app-server filesystem path introduced in #27508.
- Rewrites active paste placeholders in the persisted objective to file
references, while leaving literal placeholder-looking text alone.
- Filters out deleted paste placeholders so otherwise-small goals do not
require `$CODEX_HOME` or remote filesystem writes.
- Preserves pending paste metadata when a `/goal` command is queued
before a thread exists.

## Verification

- Added goal materialization tests for active paste placeholders,
deleted paste placeholders, and whitespace-only paste payloads.
- Added/updated TUI slash-command tests for large pasted text, queued
`/goal` commands before thread start, and queued oversized goal
behavior.

## Manual Testing

- Used real terminal bracketed-paste sequences through a remote TUI
session. A 1,228-byte multiline paste became `pasted-text-1.txt`; its
first/last lines and byte count matched exactly, and the persisted
objective referenced the server-host path.
- Pasted a large block, deleted its placeholder, and submitted a small
replacement objective. No new directory or sidecar file was created.
- Added two same-length large pastes to one goal. The composer
disambiguated their visible placeholders, and materialization preserved
order and contents in `pasted-text-1.txt` and `pasted-text-2.txt`.
- Submitted a whitespace-only large paste and verified the goal was
rejected as empty without writing a file.
- Submitted a pasted-text replacement while another goal was active,
verified no file was written before confirmation, then canceled and
confirmed the original goal remained unchanged.
- Combined a large paste with enough raw text to exceed 4,000 characters
after placeholder rewriting. The paste sidecar and `goal-objective.md`
were created in the same remote attachment directory, and `/goal edit`
restored the rewritten objective with its sidecar reference.
Base automatically changed from etraut/tui-goal-paste-files to main June 12, 2026 22:34
@etraut-openai etraut-openai force-pushed the etraut/tui-goal-image-files branch from 1f620e8 to b3f37c4 Compare June 12, 2026 22:39

@canvrno-oai canvrno-oai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed and tested with multiple images, removed images, etc.

@etraut-openai etraut-openai merged commit 9e07892 into main Jun 13, 2026
31 checks passed
@etraut-openai etraut-openai deleted the etraut/tui-goal-image-files branch June 13, 2026 00:14
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants