Skip to content

Use goal preview metadata for goal-first threads#21981

Open
etraut-openai wants to merge 3 commits intomainfrom
etraut/goal-preview-metadata
Open

Use goal preview metadata for goal-first threads#21981
etraut-openai wants to merge 3 commits intomainfrom
etraut/goal-preview-metadata

Conversation

@etraut-openai
Copy link
Copy Markdown
Collaborator

@etraut-openai etraut-openai commented May 9, 2026

Fixes #20792

Why

/goal-first threads are valid resumable threads, but they can be missing from codex resume and app recents because discovery depends on metadata derived from a normal first user message.

PR #21489 attempted to fix this by using the goal objective as first_user_message. Review feedback pointed out that first_user_message does more than provide visible text today: it gates listing, supplies preview text, and participates in deciding whether a later title should surface as a distinct thread name. Reusing it for the goal objective could leave a /goal-first thread with first_user_message=<goal> and title=<later prompt>, even though the goal should only provide the initial visible preview.

This PR follows that feedback by and keeps the first_user_message as is but introduces a new preview field to separate concerns. The preview field is populated from the first user message or the goal objective. We can extend it in the future to include other sources.

What Changed

  • Added internal thread preview metadata in codex-state, including a SQLite migration that backfills from first_user_message and from existing thread_goals objectives when needed.
  • Treated ThreadGoalUpdated as preview-bearing metadata so goal-first threads can be listed and searched without mutating first_user_message.
  • Updated rollout listing, state queries, thread-store conversion, and app-server mapping to use preview metadata while continuing to expose the existing public preview field.
  • Preserved title/name distinctness behavior around literal first_user_message, so a later normal prompt after /goal does not surface as a separate name just because the goal supplied the initial preview.
  • Preserved compatibility for older/internal metadata writes by deriving preview from first_user_message when explicit preview metadata is absent.

Verification

  • Manually verified that a thread that starts with a /goal <objective> shows up in the resume picker.

Copy link
Copy Markdown
Contributor

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

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

ℹ️ 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/state/src/runtime/threads.rs Outdated
Copy link
Copy Markdown
Collaborator

@jif-oai jif-oai left a comment

Choose a reason for hiding this comment

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

This will probably break all goal-threads but good for now I guess as it still experimental
I wonder if we should communicate though

ALTER TABLE threads ADD COLUMN preview TEXT NOT NULL DEFAULT '';

UPDATE threads
SET preview = first_user_message
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this won't be 100% backward compatible right? If the thread later got a normal prompt, this stores that later prompt instead of the original goal; if the goal was replaced, the goal backfill below stores the latest objective rather than the first one

}

if summary.saw_session_meta && summary.saw_user_event {
if summary.saw_session_meta && summary.preview.is_some() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This now stops the scan as soon as a goal gives us a preview, so a /goal-first thread that later gets a normal user turn comes back from the rollout path with first_user_message = None. That sounds the opposite of the objectif no ?

cwd = excluded.cwd,
cli_version = excluded.cli_version,
title = excluded.title,
preview = COALESCE(NULLIF(excluded.preview, ''), threads.preview),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not convinced by the backward compatibility of this PR but as goal is still experimental, I guess that's fine

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.

/goal-first sessions are missing from resume lists

2 participants