mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Persist session IDs across thread resume (#29327)
## Summary
A cold-resumed subagent kept its durable thread ID but could receive a
new session ID, splitting one agent tree across multiple sessions after
a restart.
Persist the root session ID in every rollout `SessionMeta`, carry it
through thread creation, and restore it before initializing the resumed
`Session` and `AgentControl`.
## Behavior
For a nested agent tree:
```text
root session R
parent thread P
child thread C
```
The child rollout stores:
```text
session_id: R
parent_thread_id: P
id: C
```
After a cold resume, the child still belongs to root session `R` while
its immediate parent remains `P`. The integration coverage uses distinct
values for all three IDs so it catches restoring the session from
`parent_thread_id`.
## Legacy rollouts
Previous rollouts have `id` but no `session_id`. `SessionMetaLine`
deserialization treats a missing `session_id` as `id`, keeping those
files readable, listable, and resumable. When a legacy subagent is
resumed through its root, that synthesized child ID no longer overrides
the inherited root-scoped `AgentControl`. New rollouts always persist
the explicit root session ID.
This commit is contained in:
38 files changed
+193
-34
No files matched your search
@@ -297,6 +297,7 @@ fn write_session_file_with_provider(
|
||||
let mut file = File::create(file_path)?;
|
||||
|
||||
let mut payload = serde_json::json!({
|
||||
"session_id": uuid,
|
||||
"id": uuid,
|
||||
"timestamp": ts_str,
|
||||
"cwd": ".",
|
||||
@@ -370,6 +371,7 @@ fn write_goal_started_session_file(
|
||||
"timestamp": ts_str,
|
||||
"type": "session_meta",
|
||||
"payload": {
|
||||
"session_id": uuid,
|
||||
"id": uuid,
|
||||
"timestamp": ts_str,
|
||||
"cwd": ".",
|
||||
@@ -451,6 +453,7 @@ fn write_session_file_with_delayed_user_event(
|
||||
Uuid::from_u128(100 + i as u128)
|
||||
};
|
||||
let payload = serde_json::json!({
|
||||
"session_id": uuid,
|
||||
"id": id,
|
||||
"timestamp": ts_str,
|
||||
"cwd": ".",
|
||||
@@ -483,8 +486,9 @@ fn write_session_file_with_meta_payload(
|
||||
root: &Path,
|
||||
ts_str: &str,
|
||||
uuid: Uuid,
|
||||
payload: serde_json::Value,
|
||||
mut payload: serde_json::Value,
|
||||
) -> std::io::Result<()> {
|
||||
payload["session_id"] = serde_json::json!(uuid);
|
||||
let format: &[FormatItem] =
|
||||
format_description!("[year]-[month]-[day]T[hour]-[minute]-[second]");
|
||||
let dt = PrimitiveDateTime::parse(ts_str, format)
|
||||
@@ -1088,6 +1092,7 @@ async fn test_get_thread_contents() {
|
||||
"timestamp": ts,
|
||||
"type": "session_meta",
|
||||
"payload": {
|
||||
"session_id": uuid,
|
||||
"id": uuid,
|
||||
"timestamp": ts,
|
||||
"cwd": ".",
|
||||
@@ -1267,6 +1272,7 @@ async fn test_updated_at_uses_file_mtime() -> Result<()> {
|
||||
timestamp: ts.to_string(),
|
||||
item: RolloutItem::SessionMeta(SessionMetaLine {
|
||||
meta: SessionMeta {
|
||||
session_id: conversation_id.into(),
|
||||
id: conversation_id,
|
||||
forked_from_id: None,
|
||||
parent_thread_id: None,
|
||||
|
||||
Reference in new issue
Block a user