mirror of
https://github.com/openai/codex.git
synced 2026-11-05 20:10:33 +00:00
app-server: return selected environment cwd
This commit is contained in:
Generated
+1
@@ -2844,6 +2844,7 @@ dependencies = [
|
||||
"codex-utils-cargo-bin",
|
||||
"codex-utils-cli",
|
||||
"codex-utils-oss",
|
||||
"codex-utils-path-uri",
|
||||
"codex-utils-sandbox-summary",
|
||||
"core_test_support",
|
||||
"libc",
|
||||
|
||||
+1
-1
@@ -19041,7 +19041,7 @@
|
||||
"description": "Reviewer currently used for approval requests on this thread."
|
||||
},
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/v2/AbsolutePathBuf"
|
||||
"$ref": "#/definitions/v2/ApiPathString"
|
||||
},
|
||||
"instructionSources": {
|
||||
"default": [],
|
||||
|
||||
+1
-1
@@ -16849,7 +16849,7 @@
|
||||
"description": "Reviewer currently used for approval requests on this thread."
|
||||
},
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/AbsolutePathBuf"
|
||||
"$ref": "#/definitions/ApiPathString"
|
||||
},
|
||||
"instructionSources": {
|
||||
"default": [],
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
"AgentPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"ApiPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"ApprovalsReviewer": {
|
||||
"description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `auto_review` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request. The legacy value `guardian_subagent` is accepted for compatibility.",
|
||||
"enum": [
|
||||
@@ -2319,7 +2322,7 @@
|
||||
"description": "Reviewer currently used for approval requests on this thread."
|
||||
},
|
||||
"cwd": {
|
||||
"$ref": "#/definitions/AbsolutePathBuf"
|
||||
"$ref": "#/definitions/ApiPathString"
|
||||
},
|
||||
"instructionSources": {
|
||||
"default": [],
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
|
||||
import type { ApiPathString } from "../ApiPathString";
|
||||
import type { ReasoningEffort } from "../ReasoningEffort";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { SandboxPolicy } from "./SandboxPolicy";
|
||||
import type { Thread } from "./Thread";
|
||||
|
||||
export type ThreadStartResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: string | null, cwd: AbsolutePathBuf, /**
|
||||
export type ThreadStartResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: string | null, cwd: ApiPathString, /**
|
||||
* Instruction source files currently loaded for this thread.
|
||||
*/
|
||||
instructionSources: Array<AbsolutePathBuf>, approvalPolicy: AskForApproval, /**
|
||||
|
||||
@@ -2516,7 +2516,10 @@ mod tests {
|
||||
model: "gpt-5".to_string(),
|
||||
model_provider: "openai".to_string(),
|
||||
service_tier: None,
|
||||
cwd,
|
||||
cwd: codex_utils_path_uri::ApiPathString::from_abs_path(
|
||||
&cwd,
|
||||
codex_utils_path_uri::PathConvention::native(),
|
||||
)?,
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_sources: vec![absolute_path("/tmp/AGENTS.md")],
|
||||
approval_policy: v2::AskForApproval::OnFailure,
|
||||
|
||||
@@ -26,6 +26,7 @@ use codex_protocol::protocol::ThreadGoalStatus as CoreThreadGoalStatus;
|
||||
use codex_protocol::protocol::TokenUsage as CoreTokenUsage;
|
||||
use codex_protocol::protocol::TokenUsageInfo as CoreTokenUsageInfo;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_path_uri::ApiPathString;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
@@ -155,7 +156,7 @@ pub struct ThreadStartResponse {
|
||||
pub model: String,
|
||||
pub model_provider: String,
|
||||
pub service_tier: Option<String>,
|
||||
pub cwd: AbsolutePathBuf,
|
||||
pub cwd: ApiPathString,
|
||||
/// Thread-scoped runtime workspace roots used to materialize
|
||||
/// `:workspace_roots`.
|
||||
#[experimental("thread/start.runtimeWorkspaceRoots")]
|
||||
|
||||
@@ -4,6 +4,8 @@ use codex_app_server_protocol::SelectedCapabilityRoot;
|
||||
use codex_extension_api::ExtensionDataInit;
|
||||
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS;
|
||||
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_WORKSPACE;
|
||||
use codex_utils_path_uri::ApiPathString;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
|
||||
const THREAD_LIST_DEFAULT_LIMIT: usize = 25;
|
||||
const THREAD_LIST_MAX_LIMIT: usize = 100;
|
||||
@@ -1230,7 +1232,21 @@ impl ThreadRequestProcessor {
|
||||
&config_snapshot.permission_profile,
|
||||
config_snapshot.cwd().as_path(),
|
||||
);
|
||||
let cwd = config_snapshot.cwd().clone();
|
||||
let cwd_uri = config_snapshot
|
||||
.environment_selections()
|
||||
.first()
|
||||
.map(|environment| environment.cwd.clone())
|
||||
.unwrap_or_else(|| PathUri::from_abs_path(config_snapshot.cwd()));
|
||||
let cwd_convention = cwd_uri.infer_path_convention().ok_or_else(|| {
|
||||
internal_error(format!(
|
||||
"could not infer the path convention for thread cwd `{cwd_uri}`"
|
||||
))
|
||||
})?;
|
||||
let cwd = ApiPathString::from_path_uri(&cwd_uri, cwd_convention).map_err(|err| {
|
||||
internal_error(format!(
|
||||
"could not render thread cwd `{cwd_uri}` using {cwd_convention}: {err}"
|
||||
))
|
||||
})?;
|
||||
let active_permission_profile =
|
||||
thread_response_active_permission_profile(config_snapshot.active_permission_profile);
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ async fn thread_start_accepts_absolute_runtime_workspace_roots() -> Result<()> {
|
||||
..
|
||||
} = to_response::<ThreadStartResponse>(resp)?;
|
||||
|
||||
assert_eq!(response_cwd, cwd.abs());
|
||||
assert_eq!(response_cwd.as_str(), cwd.to_string_lossy());
|
||||
assert_eq!(runtime_workspace_roots, vec![extra_root.abs()]);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -268,8 +268,7 @@ async fn app_server_starts_thread_with_windows_environment_native_cwd() -> Resul
|
||||
let response: ThreadStartResponse = to_response(response)?;
|
||||
assert!(!response.thread.id.is_empty());
|
||||
let host_cwd = codex_home.path().to_path_buf().abs();
|
||||
// TODO(anp): Return the selected environment's native cwd from thread/start.
|
||||
assert_eq!(response.cwd, host_cwd);
|
||||
assert_eq!(response.cwd.as_str(), NATIVE_CWD);
|
||||
// TODO(anp): Derive runtime workspace roots from the selected remote environment.
|
||||
assert_eq!(response.runtime_workspace_roots, vec![host_cwd]);
|
||||
// TODO(anp): Discover and report instruction sources from the remote filesystem.
|
||||
|
||||
@@ -39,6 +39,7 @@ codex-protocol = { workspace = true }
|
||||
codex-utils-absolute-path = { workspace = true }
|
||||
codex-utils-cli = { workspace = true }
|
||||
codex-utils-oss = { workspace = true }
|
||||
codex-utils-path-uri = { workspace = true }
|
||||
codex-utils-sandbox-summary = { workspace = true }
|
||||
owo-colors = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
|
||||
@@ -100,6 +100,8 @@ use codex_utils_absolute_path::canonicalize_existing_preserving_symlinks;
|
||||
use codex_utils_cli::SharedCliOptions;
|
||||
use codex_utils_oss::ensure_oss_provider_ready;
|
||||
use codex_utils_oss::get_default_model_for_oss_provider;
|
||||
use codex_utils_path_uri::ApiPathString;
|
||||
use codex_utils_path_uri::PathConvention;
|
||||
use event_processor_with_human_output::EventProcessorWithHumanOutput;
|
||||
pub use event_processor_with_jsonl_output::CodexStatus;
|
||||
pub use event_processor_with_jsonl_output::CollectedThreadEvents;
|
||||
@@ -1154,6 +1156,18 @@ fn session_configured_from_thread_start_response(
|
||||
response: &ThreadStartResponse,
|
||||
config: &Config,
|
||||
) -> Result<SessionConfiguredEvent, String> {
|
||||
let cwd_convention = response
|
||||
.cwd
|
||||
.infer_absolute_path_convention()
|
||||
.ok_or_else(|| format!("thread cwd `{}` is not absolute", response.cwd.as_str()))?;
|
||||
let cwd_uri = response
|
||||
.cwd
|
||||
.to_path_uri(cwd_convention)
|
||||
.map_err(|err| format!("thread cwd is invalid: {err}"))?;
|
||||
let cwd = ApiPathString::from_path_uri(&cwd_uri, PathConvention::native())
|
||||
.map_err(|err| format!("thread cwd cannot be represented on this host: {err}"))?;
|
||||
let cwd = AbsolutePathBuf::try_from(cwd.into_string())
|
||||
.map_err(|err| format!("thread cwd is invalid on this host: {err}"))?;
|
||||
session_configured_from_thread_response(
|
||||
&response.thread.session_id,
|
||||
&response.thread.id,
|
||||
@@ -1168,7 +1182,7 @@ fn session_configured_from_thread_start_response(
|
||||
response.approvals_reviewer.to_core(),
|
||||
config.permissions.effective_permission_profile(),
|
||||
response.active_permission_profile.clone().map(Into::into),
|
||||
response.cwd.clone(),
|
||||
cwd,
|
||||
response.reasoning_effort.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -775,7 +775,8 @@ fn sample_thread_start_response() -> ThreadStartResponse {
|
||||
model: "gpt-5.4".to_string(),
|
||||
model_provider: "openai".to_string(),
|
||||
service_tier: None,
|
||||
cwd: test_path_buf("/tmp").abs(),
|
||||
cwd: ApiPathString::from_abs_path(&test_path_buf("/tmp").abs(), PathConvention::native())
|
||||
.expect("API cwd"),
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_sources: Vec::new(),
|
||||
approval_policy: codex_app_server_protocol::AskForApproval::OnRequest,
|
||||
|
||||
@@ -62,6 +62,7 @@ codex-utils-fuzzy-match = { workspace = true }
|
||||
codex-utils-home-dir = { workspace = true }
|
||||
codex-utils-oss = { workspace = true }
|
||||
codex-utils-path = { workspace = true }
|
||||
codex-utils-path-uri = { workspace = true }
|
||||
codex-utils-plugins = { workspace = true }
|
||||
codex-utils-sandbox-summary = { workspace = true }
|
||||
codex-utils-sleep-inhibitor = { workspace = true }
|
||||
|
||||
@@ -120,6 +120,8 @@ use codex_protocol::openai_models::ModelServiceTier;
|
||||
use codex_protocol::openai_models::ModelUpgrade;
|
||||
use codex_protocol::openai_models::ReasoningEffortPreset;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_path_uri::ApiPathString;
|
||||
use codex_utils_path_uri::PathConvention;
|
||||
use color_eyre::eyre::ContextCompat;
|
||||
use color_eyre::eyre::Result;
|
||||
use color_eyre::eyre::WrapErr;
|
||||
@@ -1538,9 +1540,21 @@ async fn thread_session_state_from_thread_start_response(
|
||||
config: &Config,
|
||||
thread_params_mode: ThreadParamsMode,
|
||||
) -> Result<ThreadSessionState, String> {
|
||||
let cwd_convention = response
|
||||
.cwd
|
||||
.infer_absolute_path_convention()
|
||||
.ok_or_else(|| format!("thread cwd `{}` is not absolute", response.cwd.as_str()))?;
|
||||
let cwd_uri = response
|
||||
.cwd
|
||||
.to_path_uri(cwd_convention)
|
||||
.map_err(|err| format!("thread cwd is invalid: {err}"))?;
|
||||
let cwd = ApiPathString::from_path_uri(&cwd_uri, PathConvention::native())
|
||||
.map_err(|err| format!("thread cwd cannot be represented on this host: {err}"))?;
|
||||
let cwd = AbsolutePathBuf::try_from(cwd.into_string())
|
||||
.map_err(|err| format!("thread cwd is invalid on this host: {err}"))?;
|
||||
let permission_profile = display_permission_profile_from_thread_response(
|
||||
&response.sandbox,
|
||||
response.cwd.as_path(),
|
||||
cwd.as_path(),
|
||||
config,
|
||||
thread_params_mode,
|
||||
);
|
||||
@@ -1556,7 +1570,7 @@ async fn thread_session_state_from_thread_start_response(
|
||||
response.approvals_reviewer.to_core(),
|
||||
permission_profile,
|
||||
response.active_permission_profile.clone().map(Into::into),
|
||||
response.cwd.clone(),
|
||||
cwd,
|
||||
response.runtime_workspace_roots.clone(),
|
||||
response.instruction_sources.clone(),
|
||||
response.reasoning_effort.clone(),
|
||||
|
||||
Reference in New Issue
Block a user