core: add extra metadata field to Thread struct (#29675)

# Summary

Adds a field Thread.extras that can be used to hold arbitrary metadata
specific to a given thread.
This commit is contained in:
Boyang Niu
2026-06-23 19:15:59 +00:00
committed by GitHub
parent 2cf2a6a844
commit 354807920e
30 changed files with 113 additions and 44 deletions
@@ -3765,6 +3765,10 @@
],
"type": "object"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadGoal": {
"properties": {
"createdAt": {
@@ -17052,6 +17052,10 @@
"title": "ThreadDeletedNotification",
"type": "object"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadForkParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "There are two ways to fork a thread: 1. By thread_id: load the thread from disk by thread_id and fork it into a new thread. 2. By path: load the thread from disk by path and fork it into a new thread.\n\nIf using a non-empty path, the thread_id param will be ignored. Empty string path values are treated as absent.\n\nPrefer using thread_id whenever possible.",
@@ -14831,6 +14831,10 @@
"title": "ThreadDeletedNotification",
"type": "object"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadForkParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "There are two ways to fork a thread: 1. By thread_id: load the thread from disk by thread_id and fork it into a new thread. 2. By path: load the thread from disk by path and fork it into a new thread.\n\nIf using a non-empty path, the thread_id param will be ignored. Empty string path values are treated as absent.\n\nPrefer using thread_id whenever possible.",
@@ -1165,6 +1165,10 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -972,6 +972,10 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -972,6 +972,10 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -972,6 +972,10 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -1165,6 +1165,10 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -972,6 +972,10 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -1165,6 +1165,10 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -972,6 +972,10 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -972,6 +972,10 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadId": {
"type": "string"
},
+22 -43
View File
@@ -8,91 +8,70 @@ import type { ThreadSource } from "./ThreadSource";
import type { ThreadStatus } from "./ThreadStatus";
import type { Turn } from "./Turn";
export type Thread = {
/**
export type Thread = {/**
* Identifier for this thread. Codex-generated thread IDs are UUIDv7.
*/
id: string,
/**
id: string, /**
* Session id shared by threads that belong to the same session tree.
*/
sessionId: string,
/**
sessionId: string, /**
* Source thread id when this thread was created by forking another thread.
*/
forkedFromId: string | null,
/**
forkedFromId: string | null, /**
* The ID of the parent thread. This will only be set if this thread is a subagent.
*/
parentThreadId: string | null,
/**
parentThreadId: string | null, /**
* Usually the first user message in the thread, if available.
*/
preview: string,
/**
preview: string, /**
* Whether the thread is ephemeral and should not be materialized on disk.
*/
ephemeral: boolean,
/**
ephemeral: boolean, /**
* Model provider used for this thread (for example, 'openai').
*/
modelProvider: string,
/**
modelProvider: string, /**
* Unix timestamp (in seconds) when the thread was created.
*/
createdAt: number,
/**
createdAt: number, /**
* Unix timestamp (in seconds) when the thread was last updated.
*/
updatedAt: number,
/**
updatedAt: number, /**
* Unix timestamp (in seconds) used for thread recency ordering.
*/
recencyAt: number | null,
/**
recencyAt: number | null, /**
* Current runtime status for the thread.
*/
status: ThreadStatus,
/**
status: ThreadStatus, /**
* [UNSTABLE] Path to the thread on disk.
*/
path: string | null,
/**
path: string | null, /**
* Working directory captured for the thread.
*/
cwd: AbsolutePathBuf,
/**
cwd: AbsolutePathBuf, /**
* Version of the CLI that created the thread.
*/
cliVersion: string,
/**
cliVersion: string, /**
* Origin of the thread (CLI, VSCode, codex exec, codex app-server, etc.).
*/
source: SessionSource,
/**
source: SessionSource, /**
* Optional analytics source classification for this thread.
*/
threadSource: ThreadSource | null,
/**
threadSource: ThreadSource | null, /**
* Optional random unique nickname assigned to an AgentControl-spawned sub-agent.
*/
agentNickname: string | null,
/**
agentNickname: string | null, /**
* Optional role (agent_role) assigned to an AgentControl-spawned sub-agent.
*/
agentRole: string | null,
/**
agentRole: string | null, /**
* Optional Git metadata captured when the thread was created.
*/
gitInfo: GitInfo | null,
/**
gitInfo: GitInfo | null, /**
* Optional user-facing thread title.
*/
name: string | null,
/**
name: string | null, /**
* Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read`
* (when `includeTurns` is true) responses.
* For all other responses and notifications returning a Thread,
* the turns field will be an empty list.
*/
turns: Array<Turn>, };
turns: Array<Turn>};
@@ -0,0 +1,8 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* Extra app-server data for a thread.
*/
export type ThreadExtra = Record<string, never>;
@@ -395,6 +395,7 @@ export type { ThreadCompactStartResponse } from "./ThreadCompactStartResponse";
export type { ThreadDeleteParams } from "./ThreadDeleteParams";
export type { ThreadDeleteResponse } from "./ThreadDeleteResponse";
export type { ThreadDeletedNotification } from "./ThreadDeletedNotification";
export type { ThreadExtra } from "./ThreadExtra";
export type { ThreadForkParams } from "./ThreadForkParams";
export type { ThreadForkResponse } from "./ThreadForkResponse";
export type { ThreadGoal } from "./ThreadGoal";
@@ -2573,6 +2573,7 @@ mod tests {
response: v2::ThreadStartResponse {
thread: v2::Thread {
id: "67e55044-10b1-426f-9247-bb680e5fe0c8".to_string(),
extra: None,
session_id: "67e55044-10b1-426f-9247-bb680e5fe0c7".to_string(),
forked_from_id: None,
parent_thread_id: None,
@@ -2622,6 +2623,7 @@ mod tests {
"response": {
"thread": {
"id": "67e55044-10b1-426f-9247-bb680e5fe0c8",
"extra": null,
"sessionId": "67e55044-10b1-426f-9247-bb680e5fe0c7",
"forkedFromId": null,
"parentThreadId": null,
@@ -168,6 +168,7 @@ fn thread_resume_response_round_trips_initial_turns_page() {
let response = ThreadResumeResponse {
thread: Thread {
id: "thr_123".to_string(),
extra: None,
session_id: "thr_123".to_string(),
forked_from_id: None,
parent_thread_id: None,
@@ -2,6 +2,7 @@ use super::CodexErrorInfo;
use super::ThreadItem;
use super::ThreadStatus;
use super::TurnStatus;
use codex_experimental_api_macros::ExperimentalApi;
use codex_protocol::protocol::SessionSource as CoreSessionSource;
use codex_protocol::protocol::SubAgentSource as CoreSubAgentSource;
use codex_protocol::protocol::ThreadSource as CoreThreadSource;
@@ -120,6 +121,12 @@ impl From<ThreadSource> for CoreThreadSource {
}
}
/// Extra app-server data for a thread.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase", export_to = "v2/")]
pub struct ThreadExtra {}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
@@ -129,12 +136,15 @@ pub struct GitInfo {
pub origin_url: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct Thread {
/// Identifier for this thread. Codex-generated thread IDs are UUIDv7.
pub id: String,
/// Optional implementation-specific thread data.
#[experimental("thread.extra")]
pub extra: Option<ThreadExtra>,
/// Session id shared by threads that belong to the same session tree.
pub session_id: String,
/// Source thread id when this thread was created by forking another thread.