Commit Graph
20 Commits
Author SHA1 Message Date
Felipe CouryandGitHub 7a26497836 feat(tui): add OSC 8 web links to rich content (#24472)
## Why

Wrapped URLs in rich TUI output, especially URLs rendered inside
Markdown tables, are split across terminal rows. In terminals that
support OSC 8 hyperlinks, treating each visible fragment as part of the
complete destination enables reliable open-link and copy-link actions
even after table layout wraps the URL.

This addresses the semantic-link portion of #12200 and the behavior
described in
https://github.com/openai/codex/issues/12200#issuecomment-4535452980. It
does not change ordinary drag-selection across bordered table rows.

## What Changed

- Added shared TUI OSC 8 support that validates `http://` and `https://`
destinations, sanitizes terminal payloads, and applies metadata
separately from visible line width/layout.
- Added semantic web-link annotations to assistant and proposed-plan
Markdown, including explicit web links and bare web URLs in prose and
table cells while excluding code and non-web Markdown destinations.
- Preserved complete URL targets through table wrapping, narrow pipe
fallback, streaming, transcript overlay rendering, history insertion,
and resize replay.
- Routed intentional Codex-owned links in notices,
status/setup/app-link, feedback, onboarding, MCP/plugin help, memories,
and update surfaces through the shared hyperlink handling.

## How to Test

1. Run Codex in a terminal with OSC 8 link support, such as Ghostty, and
request an assistant response containing a Markdown table whose last
column contains a long `https://` URL.
2. Make the terminal narrow enough for the URL to wrap across multiple
bordered table rows.
3. Use the terminal's open-link or copy-link action on more than one
wrapped URL fragment and confirm each fragment resolves to the complete
original URL.
4. Resize the terminal after the table is rendered and repeat the link
action to confirm the destination survives scrollback replay.
5. Open the transcript overlay while rich output is present and confirm
web links remain interactive there.
6. As a regression check, render inline/fenced code containing URL text
and a Markdown link such as
`[https://example.com](mailto:support@example.com)`; confirm these do
not acquire a web OSC 8 destination.

Targeted automated coverage exercised Markdown links and exclusions,
wrapped and pipe-fallback tables, streaming/transcript overlay
propagation, status-link truncation, and rendered word-wrapping cell
alignment. `just test -p codex-tui` was also run; it passed the
hyperlink coverage and reproduced two unrelated existing guardian
feature-flag test failures.
2026-05-27 20:14:55 +00:00
Felipe CouryandGitHub 6b4b15a1ed feat(tui): render markdown tables in app style [1 of 2] (#24489)
## Stack

- **Current: #24489 [1 of 2]** - render markdown tables in app style.
- **Stacked follow-up: #24636 [2 of 2]** - render cramped markdown
tables as key/value records.

## Why

Markdown tables currently render as boxed terminal grids, which gives
ordinary assistant output a heavier visual treatment than surrounding
rich text. This row-separated layout is the best match for how the App
renders tables, while accented headers remain distinguishable even when
a terminal font renders bold subtly.

<table>
<tr><td>
<p align="center">Codex CLI - Before</p>
<img width="1722" height="742" alt="CleanShot 2026-05-25 at 18 46 17"
src="https://github.com/user-attachments/assets/f673d92a-ebd8-46e2-b414-3d985e41b6a4"
/>
</td></tr>
<tr><td>
<p align="center">Codex CLI - After</p>
<img width="1720" height="957" alt="image"
src="https://github.com/user-attachments/assets/36a3d331-bea1-439b-b5be-e97b0731bd6f"
/>
</td></tr>
<tr><td>
<p align="center">Codex App</p>
<img width="979" height="1293" alt="CleanShot 2026-05-25 at 18 45 04"
src="https://github.com/user-attachments/assets/7d97cae0-9256-4f6e-a4b3-8b8f22b0d901"
/>
</td></tr>
</table>

## What Changed

- Render markdown tables as padded, aligned rows without an enclosing
box.
- Style table headers with the active syntax-theme accent plus bold
text, while keeping separators low contrast and theme-aware.
- Use a segmented heavy header rule and thin body-row rules, preserving
wrapping, narrow-width fallback, streaming parity, and rich-history
rendering.
- Update focused assertions and snapshots for the final table layout.

## How to Test

1. Render a markdown table in the TUI with several rows and columns.
2. Confirm the header uses the active theme accent, rows use
one-character interior padding, and the table has no enclosing box.
3. Confirm the header is followed by segmented `━` rules and multiple
body rows are separated by muted segmented `─` rules.
4. Render the same table while streaming and in history/raw-mode
toggles; the final rich layout should remain stable.
5. Render a narrow table with long content and verify wrapping or pipe
fallback does not overflow.

## Validation

- `just test -p codex-tui table`
- `just test -p codex-tui streaming::controller::tests`
- `just argument-comment-lint-from-source -p codex-tui -- --all-targets`
- `just fix -p codex-tui`
- `just fmt`

`just test -p codex-tui` was also run after accepting the snapshots; it
fails only in the unrelated existing guardian app tests
`update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default`
and
`update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history`.
2026-05-27 16:18:24 -03:00
Felipe CouryandGitHub 5248e3da2b feat(tui): render responsive Markdown tables in TUI (#22052)
## Why

The TUI currently treats Markdown tables as ordinary wrapped text, which
makes table-heavy responses hard to read and brittle across narrow panes
and terminal resizes.

This change teaches the TUI to render Markdown tables responsively while
preserving the raw Markdown source needed to re-render streamed and
finalized transcript content after width changes. The goal is to keep
tables legible during streaming, after resize, and once a turn has
finished, without corrupting scrollback ordering.

## What Changed

- add table detection and responsive table rendering in the Markdown
renderer
- render standard tables with Unicode box-drawing borders when the pane
is wide enough
- add a vertical readability fallback for constrained or dense tables so
narrow panes still show each row clearly
- keep links and `<br>` content inside table cells instead of leaking
text outside the table
- avoid table normalization inside fenced or indented code blocks
- preserve raw streamed Markdown source and keep the active table as a
mutable tail until finalization
- consolidate finalized streamed content into source-backed transcript
cells so post-resize re-rendering stays correct
- add snapshot and targeted streaming/resize regression coverage for the
new table behavior

## How to Test

1. Start Codex TUI from this branch.
2. Paste this exact prompt:
`This is a session to test codex, no need to do any thinking, just end
different markdown tables, with columns exploring different markdown
contents, like links, bold italic, code, etc. Make them different sizes,
some 30+ rows, some not and intertwine them with some paragraphs with
complex formatting as well.`
3. Confirm the response includes several Markdown tables mixed with
richly formatted paragraphs.
4. Confirm wide-enough tables render with box-drawing borders instead of
plain wrapped pipe text.
5. Resize the terminal narrower while the answer is still streaming and
confirm the in-progress table stays coherent instead of duplicating
headers or leaving broken scrollback behind.
6. Resize again after the turn finishes and confirm the finalized
transcript re-renders cleanly at the new width.
7. In a narrow pane, verify dense tables fall back to the vertical
per-row layout instead of producing unreadable wrapped columns.
8. Also verify pipe-heavy fenced code blocks still render as code, not
as tables.

Targeted tests:
- `cargo test -p codex-tui table_readability_fallback --no-fail-fast`
- `cargo test -p codex-tui markdown_render --no-fail-fast`
- `cargo test -p codex-tui streaming::controller --no-fail-fast`
- `cargo test -p codex-tui table_resize_lifecycle --no-fail-fast`

## Docs

No developer docs update appears necessary.
2026-05-10 20:42:11 +00:00
Eric TrautandGitHub 61429a6c10 Rename tui_app_server to tui (#16104)
This is a follow-up to https://github.com/openai/codex/pull/15922. That
previous PR deleted the old `tui` directory and left the new
`tui_app_server` directory in place. This PR renames `tui_app_server` to
`tui` and fixes up all references.
2026-03-28 11:23:07 -06:00
Eric TrautandGitHub d65deec617 Remove the legacy TUI split (#15922)
This is the part 1 of 2 PRs that will delete the `tui` /
`tui_app_server` split. This part simply deletes the existing `tui`
directory and marks the `tui_app_server` feature flag as removed. I left
the `tui_app_server` feature flag in place for now so its presence
doesn't result in an error. It is simply ignored.

Part 2 will rename the `tui_app_server` directory `tui`. I did this as
two parts to reduce visible code churn.
2026-03-27 22:56:44 +00:00
da74da6684 render local file links from target paths (#13857)
Co-authored-by: Josh McKinney <joshka@openai.com>
2026-03-11 12:33:09 -07:00
Jeremy RoseandGitHub 39a2446716 tui: drop citation rendering (#4855)
We don't instruct the model to use citations, so it never emits them.
Further, ratatui [doesn't currently support rendering links into the
terminal with OSC 8](https://github.com/ratatui/ratatui/issues/1028), so
even if we did parse citations, we can't correctly render them.

So, remove all the code related to rendering them.
2025-10-20 21:08:19 +00:00
Jeremy RoseandGitHub 01e6503672 wrap markdown at render time (#4506)
This results in correctly indenting list items with long lines.

<img width="1006" height="251" alt="Screenshot 2025-09-30 at 10 00
48 AM"
src="https://github.com/user-attachments/assets/0a076cf6-ca3c-4efb-b3af-dc07617cdb6f"
/>
2025-09-30 23:13:55 +00:00
Jeremy RoseandGitHub 8068cc75f8 replace tui_markdown with a custom markdown renderer (#3396)
Also, simplify the streaming behavior.

This fixes a number of display issues with streaming markdown, and paves
the way for better markdown features (e.g. customizable styles, syntax
highlighting, markdown-aware wrapping).

Not currently supported:
- footnotes
- tables
- reference-style links
2025-09-10 12:13:53 -07:00
Jeremy RoseandGitHub 578ff09e17 prefer ratatui Stylized for constructing lines/spans (#3068)
no functional change, just simplifying ratatui styling and adding
guidance in AGENTS.md for future.
2025-09-02 23:19:54 +00:00
Jeremy RoseandGitHub 488a40211a fix (most) doubled lines and hanging list markers (#2789)
This was mostly written by codex under heavy guidance via test cases
drawn from logged session data and fuzzing. It also uncovered some bugs
in tui_markdown, which will in some cases split a list marker from the
list item content. We're not addressing those bugs for now.
2025-08-27 13:55:59 -07:00
easong-openaiandGitHub 6340acd885 Re-add markdown streaming (#2029)
Wait for newlines, then render markdown on a line by line basis. Word wrap it for the current terminal size and then spit it out line by line into the UI. Also adds tests and fixes some UI regressions.
2025-08-12 17:37:28 -07:00
easong-openaiandGitHub 52e12f2b6c Revert "Streaming markdown (#1920)" (#1981)
This reverts commit 2b7139859e.
2025-08-08 01:38:39 +00:00
easong-openaiandGitHub 2b7139859e Streaming markdown (#1920)
We wait until we have an entire newline, then format it with markdown and stream in to the UI. This reduces time to first token but is the right thing to do with our current rendering model IMO. Also lets us add word wrapping!
2025-08-07 18:26:47 -07:00
easong-openaiandGitHub 906d449760 Stream model responses (#1810)
Stream models thoughts and responses instead of waiting for the whole
thing to come through. Very rough right now, but I'm making the risk call to push through.
2025-08-05 04:23:22 +00:00
Michael BolinandGitHub 5a5aa89914 chore: replace regex with regex-lite, where appropriate (#1200)
As explained on https://crates.io/crates/regex-lite, `regex-lite` is a
lighter alternative to `regex` and seems to be sufficient for our
purposes.
2025-06-02 17:11:45 -07:00
Michael BolinandGitHub 5746561428 chore: move types out of config.rs into config_types.rs (#1054)
`config.rs` is already quite long without these definitions. Since they
have no real dependencies of their own, let's move them to their own
file so `config.rs` can focus on the business logic of loading a config.
2025-05-20 11:55:25 -07:00
Michael BolinandGitHub 67ac8ef605 fix: use text other than 'TODO' as test example (#969)
I casually `rg TODO` to look for TODOs, so the use of TODO in a sample
string in test output was throwing things off.
2025-05-16 14:51:03 -07:00
Michael BolinandGitHub 1e39189393 feat: add support for file_opener option in Rust, similiar to #911 (#957)
This ports the enhancement introduced in
https://github.com/openai/codex/pull/911 (and the fixes in
https://github.com/openai/codex/pull/919) for the TypeScript CLI to the
Rust one.
2025-05-16 11:33:08 -07:00
Michael BolinandGitHub 0360b4d0d7 feat: introduce the use of tui-markdown (#851)
This introduces the use of the `tui-markdown` crate to parse an
assistant message as Markdown and style it using ANSI for a better user
experience. As shown in the screenshot below, it has support for syntax
highlighting for _tagged_ fenced code blocks:

<img width="907" alt="image"
src="https://github.com/user-attachments/assets/900dc229-80bb-46e8-b1bb-efee4c70ba3c"
/>

That said, `tui-markdown` is not as configurable (or stylish!) as
https://www.npmjs.com/package/marked-terminal, which is what we use in
the TypeScript CLI. In particular:

* The styles are hardcoded and `tui_markdown::from_str()` does not take
any options whatsoever. It uses "bold white" for inline code style which
does not stand out as much as the yellow used by `marked-terminal`:


https://github.com/joshka/tui-markdown/blob/65402cbda70325f34e7ddf6fe1ec629bcd9459cf/tui-markdown/src/lib.rs#L464

I asked Codex to take a first pass at this and it came up with:

https://github.com/joshka/tui-markdown/pull/80

* If a fenced code block is not tagged, then it does not get
highlighted. I would rather add some logic here:


https://github.com/joshka/tui-markdown/blob/65402cbda70325f34e7ddf6fe1ec629bcd9459cf/tui-markdown/src/lib.rs#L262

that uses something like https://pypi.org/project/guesslang/ to examine
the value of `text` and try to use the appropriate syntax highlighter.

* When we have a fenced code block, we do not want to show the opening
and closing triple backticks in the output.

To unblock ourselves, we might want to bundle our own fork of
`tui-markdown` temporarily until we figure out what the shape of the API
should be and then try to upstream it.
2025-05-07 10:46:32 -07:00