Re-resolve session storage URL commands

This commit is contained in:
Charles Cunningham
2026-02-16 17:42:23 -08:00
parent 21db430ab3
commit 27b5e7c4be
3 changed files with 62 additions and 33 deletions
+27 -22
View File
@@ -349,6 +349,8 @@ pub struct Config {
/// Optional base URL for storing shared session rollouts in an object store.
pub session_object_storage_url: Option<String>,
/// Optional command to produce the base URL for storing shared session rollouts.
pub session_object_storage_url_cmd: Option<Vec<String>>,
/// When set, restricts ChatGPT login to a specific workspace identifier.
pub forced_chatgpt_workspace_id: Option<String>,
@@ -1518,7 +1520,15 @@ impl Config {
Some(WindowsSandboxModeToml::Unelevated) => WindowsSandboxLevel::RestrictedToken,
None => WindowsSandboxLevel::from_features(&features),
};
let session_object_storage_url = Self::resolve_session_object_storage_url(&cfg)?;
let session_object_storage_url =
cfg.session_object_storage_url.as_ref().and_then(|value| {
let trimmed = value.trim();
if trimmed.is_empty() {
None
} else {
Some(trimmed.to_string())
}
});
let mut sandbox_policy = cfg.derive_sandbox_policy(
sandbox_mode,
config_profile.sandbox_mode,
@@ -1827,6 +1837,7 @@ impl Config {
.or(cfg.chatgpt_base_url)
.unwrap_or("https://chatgpt.com/backend-api/".to_string()),
session_object_storage_url,
session_object_storage_url_cmd: cfg.session_object_storage_url_cmd,
forced_chatgpt_workspace_id,
forced_login_method,
include_apply_patch_tool: include_apply_patch_tool_flag,
@@ -1893,6 +1904,17 @@ impl Config {
Ok(config)
}
pub fn resolve_session_object_storage_url(&self) -> std::io::Result<Option<String>> {
if let Some(url) = self.session_object_storage_url.as_ref() {
return Ok(Some(url.clone()));
}
Self::try_run_command_for_value(
self.session_object_storage_url_cmd.as_deref(),
"session_object_storage_url_cmd",
)
}
fn load_instructions(codex_dir: Option<&Path>) -> Option<String> {
let base = codex_dir?;
for candidate in [LOCAL_PROJECT_DOC_FILENAME, DEFAULT_PROJECT_DOC_FILENAME] {
@@ -1937,27 +1959,6 @@ impl Config {
}
}
fn resolve_session_object_storage_url(cfg: &ConfigToml) -> std::io::Result<Option<String>> {
let session_object_storage_url =
cfg.session_object_storage_url.as_ref().and_then(|value| {
let trimmed = value.trim();
if trimmed.is_empty() {
None
} else {
Some(trimmed.to_string())
}
});
if session_object_storage_url.is_some() {
return Ok(session_object_storage_url);
}
Self::try_run_command_for_value(
cfg.session_object_storage_url_cmd.as_deref(),
"session_object_storage_url_cmd",
)
}
fn try_run_command_for_value(
command: Option<&[String]>,
context: &str,
@@ -4220,6 +4221,7 @@ model_verbosity = "high"
personality: Some(Personality::Pragmatic),
chatgpt_base_url: "https://chatgpt.com/backend-api/".to_string(),
session_object_storage_url: None,
session_object_storage_url_cmd: None,
base_instructions: None,
developer_instructions: None,
compact_prompt: None,
@@ -4332,6 +4334,7 @@ model_verbosity = "high"
personality: Some(Personality::Pragmatic),
chatgpt_base_url: "https://chatgpt.com/backend-api/".to_string(),
session_object_storage_url: None,
session_object_storage_url_cmd: None,
base_instructions: None,
developer_instructions: None,
compact_prompt: None,
@@ -4442,6 +4445,7 @@ model_verbosity = "high"
personality: Some(Personality::Pragmatic),
chatgpt_base_url: "https://chatgpt.com/backend-api/".to_string(),
session_object_storage_url: None,
session_object_storage_url_cmd: None,
base_instructions: None,
developer_instructions: None,
compact_prompt: None,
@@ -4538,6 +4542,7 @@ model_verbosity = "high"
personality: Some(Personality::Pragmatic),
chatgpt_base_url: "https://chatgpt.com/backend-api/".to_string(),
session_object_storage_url: None,
session_object_storage_url_cmd: None,
base_instructions: None,
developer_instructions: None,
compact_prompt: None,
+20 -7
View File
@@ -3746,9 +3746,12 @@ impl ChatWidget {
self.add_error_message("Current session is not ready to share yet.".to_string());
return;
}
if self.config.session_object_storage_url.is_none() {
if self.config.session_object_storage_url.is_none()
&& self.config.session_object_storage_url_cmd.is_none()
{
self.add_error_message(
"Sharing requires `session_object_storage_url` in config.toml.".to_string(),
"Sharing requires `session_object_storage_url` or `session_object_storage_url_cmd` in config.toml."
.to_string(),
);
return;
}
@@ -3801,11 +3804,21 @@ impl ChatWidget {
// TODO: Enforce email-based access once we have a server-side auth check.
let Some(storage_url) = self.config.session_object_storage_url.clone() else {
self.add_error_message(
"Sharing requires `session_object_storage_url` in config.toml.".to_string(),
);
return;
let storage_url = match self.config.resolve_session_object_storage_url() {
Ok(Some(url)) => url,
Ok(None) => {
self.add_error_message(
"Sharing requires `session_object_storage_url` or `session_object_storage_url_cmd` in config.toml."
.to_string(),
);
return;
}
Err(err) => {
self.add_error_message(format!(
"Failed to resolve session object storage URL: {err}"
));
return;
}
};
let owner = self
.auth_manager
+15 -4
View File
@@ -582,14 +582,25 @@ async fn run_ratatui_app(
match path {
Some(path) => resume_picker::SessionSelection::Fork(path),
None => {
let Some(storage_url) = config.session_object_storage_url.as_deref() else {
return missing_session_exit(&mut tui, id_str, "fork");
let storage_url = match config.resolve_session_object_storage_url() {
Ok(Some(url)) => url,
Ok(None) => return missing_session_exit(&mut tui, id_str, "fork"),
Err(err) => {
return fatal_exit(
&mut tui,
format!("Failed to resolve session object storage URL: {err}"),
);
}
};
let Ok(session_id) = ThreadId::from_string(id_str) else {
return missing_session_exit(&mut tui, id_str, "fork");
};
match download_rollout_if_available(storage_url, session_id, &config.codex_home)
.await
match download_rollout_if_available(
&storage_url,
session_id,
&config.codex_home,
)
.await
{
Ok(Some(path)) => {
remote_fork_downloaded = true;