mirror of
https://github.com/openai/codex.git
synced 2026-11-12 21:20:34 +00:00
Expose loaded thread environments in app-server responses (#42386)
## What changed - Add the experimental `Thread.environments` field with each selected environment's ID, working directory, and runtime workspace roots. - Populate the field from live thread state in start, resume, read, list, and unarchive responses. Use `null` for unloaded threads and an empty list when a loaded thread has no environment selection. - Document that the field reports selection rather than connection status and does not affect executor selection or resume behavior. ## Testing - Cover selection updates, unloaded and resumed threads, loaded pathless unarchives, and clients that subscribe after environment connection notifications. GitOrigin-RevId: a6daa06aff7089d7c5a1e4c7d03109b41f12fa3c
This commit is contained in:
committed by
copyberry
parent
cff76fa96f
commit
2b554fd3f9
@@ -4338,6 +4338,29 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
+23
@@ -20553,6 +20553,29 @@
|
||||
"title": "ThreadDeletedNotification",
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/v2/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
+23
@@ -18267,6 +18267,29 @@
|
||||
"title": "ThreadDeletedNotification",
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
@@ -1485,6 +1485,29 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
@@ -1276,6 +1276,29 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
+23
@@ -1276,6 +1276,29 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
@@ -1276,6 +1276,29 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
@@ -1485,6 +1485,29 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
@@ -1276,6 +1276,29 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
@@ -1276,6 +1276,29 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
@@ -1485,6 +1485,29 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
@@ -1276,6 +1276,29 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
@@ -1276,6 +1276,29 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadEnvironment": {
|
||||
"description": "An environment selected by a loaded thread, independent of connection status.",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"environmentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtimeWorkspaceRoots": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LegacyAppPathString"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"environmentId",
|
||||
"runtimeWorkspaceRoots"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadExtra": {
|
||||
"description": "Extra app-server data for a thread.",
|
||||
"type": "object"
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
// 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.
|
||||
import type { LegacyAppPathString } from "../LegacyAppPathString";
|
||||
|
||||
/**
|
||||
* An environment selected by a loaded thread, independent of connection status.
|
||||
*/
|
||||
export type ThreadEnvironment = { environmentId: string, cwd: LegacyAppPathString, runtimeWorkspaceRoots: Array<LegacyAppPathString>, };
|
||||
@@ -473,6 +473,7 @@ export type { ThreadCompactStartResponse } from "./ThreadCompactStartResponse";
|
||||
export type { ThreadDeleteParams } from "./ThreadDeleteParams";
|
||||
export type { ThreadDeleteResponse } from "./ThreadDeleteResponse";
|
||||
export type { ThreadDeletedNotification } from "./ThreadDeletedNotification";
|
||||
export type { ThreadEnvironment } from "./ThreadEnvironment";
|
||||
export type { ThreadExtra } from "./ThreadExtra";
|
||||
export type { ThreadForkParams } from "./ThreadForkParams";
|
||||
export type { ThreadForkResponse } from "./ThreadForkResponse";
|
||||
|
||||
@@ -3128,6 +3128,7 @@ mod tests {
|
||||
request_id: RequestId::Integer(7),
|
||||
response: v2::ThreadStartResponse {
|
||||
thread: v2::Thread {
|
||||
environments: None,
|
||||
id: "67e55044-10b1-426f-9247-bb680e5fe0c8".to_string(),
|
||||
extra: None,
|
||||
session_id: "67e55044-10b1-426f-9247-bb680e5fe0c7".to_string(),
|
||||
@@ -3186,6 +3187,7 @@ mod tests {
|
||||
"response": {
|
||||
"thread": {
|
||||
"id": "67e55044-10b1-426f-9247-bb680e5fe0c8",
|
||||
"environments": null,
|
||||
"extra": null,
|
||||
"sessionId": "67e55044-10b1-426f-9247-bb680e5fe0c7",
|
||||
"forkedFromId": null,
|
||||
|
||||
@@ -1,9 +1,36 @@
|
||||
use crate::JsonSchema;
|
||||
use crate::TS;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_utils_path_uri::LegacyAppPathString;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
/// An environment selected by a loaded thread, independent of connection status.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadEnvironment {
|
||||
pub environment_id: String,
|
||||
pub cwd: LegacyAppPathString,
|
||||
pub runtime_workspace_roots: Vec<LegacyAppPathString>,
|
||||
}
|
||||
|
||||
impl From<&TurnEnvironmentSelection> for ThreadEnvironment {
|
||||
fn from(selection: &TurnEnvironmentSelection) -> Self {
|
||||
Self {
|
||||
environment_id: selection.environment_id.clone(),
|
||||
cwd: selection.cwd.clone().into(),
|
||||
runtime_workspace_roots: selection
|
||||
.workspace_roots
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(Into::into)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
|
||||
@@ -272,6 +272,13 @@ fn thread_resume_params_accept_turns_page_bootstrap() {
|
||||
fn thread_resume_response_round_trips_initial_turns_page() {
|
||||
let response = ThreadResumeResponse {
|
||||
thread: Thread {
|
||||
environments: Some(vec![ThreadEnvironment {
|
||||
environment_id: "remote".to_string(),
|
||||
cwd: LegacyAppPathString::from_string(r"C:\workspace"),
|
||||
runtime_workspace_roots: vec![LegacyAppPathString::from_string(
|
||||
r"C:\workspace\src",
|
||||
)],
|
||||
}]),
|
||||
id: "thr_123".to_string(),
|
||||
extra: None,
|
||||
session_id: "thr_123".to_string(),
|
||||
@@ -328,6 +335,12 @@ fn thread_resume_response_round_trips_initial_turns_page() {
|
||||
};
|
||||
|
||||
let value = serde_json::to_value(&response).expect("serialize thread resume response");
|
||||
assert_eq!(
|
||||
value["thread"]["environments"],
|
||||
json!([{
|
||||
"environmentId": "remote", "cwd": r"C:\workspace", "runtimeWorkspaceRoots": [r"C:\workspace\src"]
|
||||
}])
|
||||
);
|
||||
assert_eq!(
|
||||
value["thread"]["section"],
|
||||
json!({
|
||||
@@ -345,11 +358,13 @@ fn thread_resume_response_round_trips_initial_turns_page() {
|
||||
legacy_thread_fields.remove("section");
|
||||
legacy_thread_fields.remove("sectionEnteredAt");
|
||||
legacy_thread_fields.remove("projectId");
|
||||
legacy_thread_fields.remove("environments");
|
||||
let legacy_thread =
|
||||
serde_json::from_value::<Thread>(legacy_thread).expect("deserialize legacy thread");
|
||||
assert_eq!(legacy_thread.section, None);
|
||||
assert_eq!(legacy_thread.section_entered_at, None);
|
||||
assert_eq!(legacy_thread.project_id, None);
|
||||
assert_eq!(legacy_thread.environments, None);
|
||||
|
||||
assert_eq!(
|
||||
value.get("initialTurnsPage"),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::CodexErrorInfo;
|
||||
use super::ThreadEnvironment;
|
||||
use super::ThreadItem;
|
||||
use super::ThreadStatus;
|
||||
use super::TurnStatus;
|
||||
@@ -203,6 +204,12 @@ pub struct ThreadSectionAppearance {
|
||||
pub struct Thread {
|
||||
/// Identifier for this thread. Codex-generated thread IDs are UUIDv7.
|
||||
pub id: String,
|
||||
/// Current environments for a loaded thread, in priority order, primary first.
|
||||
/// `null` means the thread is not loaded or the server does not expose its selection.
|
||||
/// An empty list means no environments are selected. This does not report connection status.
|
||||
#[experimental("thread.environments")]
|
||||
#[serde(default)]
|
||||
pub environments: Option<Vec<ThreadEnvironment>>,
|
||||
/// Optional implementation-specific thread data.
|
||||
#[experimental("thread.extra")]
|
||||
pub extra: Option<ThreadExtra>,
|
||||
@@ -286,6 +293,8 @@ pub struct Thread {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ThreadCompatibility {
|
||||
id: String,
|
||||
#[serde(default)]
|
||||
environments: Option<Vec<ThreadEnvironment>>,
|
||||
extra: Option<ThreadExtra>,
|
||||
session_id: String,
|
||||
forked_from_id: Option<String>,
|
||||
@@ -328,6 +337,7 @@ impl<'de> Deserialize<'de> for Thread {
|
||||
let thread = ThreadCompatibility::deserialize(deserializer)?;
|
||||
Ok(Self {
|
||||
id: thread.id,
|
||||
environments: thread.environments,
|
||||
extra: thread.extra,
|
||||
session_id: thread.session_id,
|
||||
forked_from_id: thread.forked_from_id,
|
||||
|
||||
Reference in New Issue
Block a user