Merge 13600b96f7 into sapling-pr-archive-bolinfest

This commit is contained in:
Michael Bolin
2026-02-20 14:46:45 -08:00
committed by GitHub
12 changed files with 86 additions and 21 deletions
@@ -507,6 +507,15 @@
"classification": {
"type": "string"
},
"extraLogFiles": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"includeLogs": {
"type": "boolean"
},
@@ -12549,6 +12549,15 @@
"classification": {
"type": "string"
},
"extraLogFiles": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"includeLogs": {
"type": "boolean"
},
@@ -4,6 +4,15 @@
"classification": {
"type": "string"
},
"extraLogFiles": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"includeLogs": {
"type": "boolean"
},
@@ -2,4 +2,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type FeedbackUploadParams = { classification: string, reason?: string | null, threadId?: string | null, includeLogs: boolean, };
export type FeedbackUploadParams = { classification: string, reason?: string | null, threadId?: string | null, includeLogs: boolean, extraLogFiles?: Array<string> | null, };
@@ -1506,6 +1506,8 @@ pub struct FeedbackUploadParams {
#[ts(optional = nullable)]
pub thread_id: Option<String>,
pub include_logs: bool,
#[ts(optional = nullable)]
pub extra_log_files: Option<Vec<PathBuf>>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
+1 -1
View File
@@ -150,7 +150,7 @@ Example with notification opt-out:
- `config/mcpServer/reload` — reload MCP server config from disk and queue a refresh for loaded threads (applied on each thread's next active turn); returns `{}`. Use this after editing `config.toml` without restarting the server.
- `mcpServerStatus/list` — enumerate configured MCP servers with their tools, resources, resource templates, and auth status; supports cursor+limit pagination.
- `windowsSandbox/setupStart` — start Windows sandbox setup for the selected mode (`elevated` or `unelevated`); returns `{ started: true }` immediately and later emits `windowsSandbox/setupCompleted`.
- `feedback/upload` — submit a feedback report (classification + optional reason/logs and conversation_id); returns the tracking thread id.
- `feedback/upload` — submit a feedback report (classification + optional reason/logs, conversation_id, and optional `extraLogFiles` attachments array); returns the tracking thread id.
- `command/exec` — run a single command under the server sandbox without starting a thread/turn (handy for utilities and validation).
- `config/read` — fetch the effective config on disk after resolving config layering.
- `config/value/write` — write a single config key/value to the user's config.toml on disk.
@@ -6098,6 +6098,7 @@ impl CodexMessageProcessor {
reason,
thread_id,
include_logs,
extra_log_files,
} = params;
let conversation_id = match thread_id.as_deref() {
@@ -6127,15 +6128,19 @@ impl CodexMessageProcessor {
} else {
None
};
let mut attachment_paths = validated_rollout_path.into_iter().collect::<Vec<_>>();
if let Some(extra_log_files) = extra_log_files {
attachment_paths.extend(extra_log_files);
}
let session_source = self.thread_manager.session_source();
let upload_result = tokio::task::spawn_blocking(move || {
let rollout_path_ref = validated_rollout_path.as_deref();
snapshot.upload_feedback(
&classification,
reason.as_deref(),
include_logs,
rollout_path_ref,
&attachment_paths,
Some(session_source),
)
})
@@ -6239,6 +6244,9 @@ async fn handle_pending_thread_resume_request(
let state = thread_state.lock().await;
state.active_turn_snapshot()
};
let has_in_progress_turn = active_turn
.as_ref()
.is_some_and(|turn| matches!(turn.status, TurnStatus::InProgress));
let request_id = pending.request_id;
let connection_id = request_id.connection_id;
@@ -6265,9 +6273,17 @@ async fn handle_pending_thread_resume_request(
return;
}
};
thread.status = thread_watch_manager
let mut status = thread_watch_manager
.loaded_status_for_thread(&thread.id)
.await;
if let ThreadStatus::Idle | ThreadStatus::NotLoaded = status {
if has_in_progress_turn {
status = ThreadStatus::Active {
active_flags: Vec::new(),
};
}
}
thread.status = status;
let ThreadConfigSnapshot {
model,
+10 -3
View File
@@ -15,6 +15,7 @@ use axum::Router;
use axum::extract::State;
use axum::http::HeaderMap;
use axum::http::StatusCode;
use axum::http::Uri;
use axum::http::header::AUTHORIZATION;
use axum::routing::get;
use codex_app_server_protocol::AppBranding;
@@ -1215,6 +1216,7 @@ async fn start_apps_server_with_delays_and_control(
async fn list_directory_connectors(
State(state): State<Arc<AppsServerState>>,
headers: HeaderMap,
uri: Uri,
) -> Result<impl axum::response::IntoResponse, StatusCode> {
if state.directory_delay > Duration::ZERO {
tokio::time::sleep(state.directory_delay).await;
@@ -1228,16 +1230,21 @@ async fn list_directory_connectors(
.get("chatgpt-account-id")
.and_then(|value| value.to_str().ok())
.is_some_and(|value| value == state.expected_account_id);
let external_logos_ok = uri
.query()
.is_some_and(|query| query.split('&').any(|pair| pair == "external_logos=true"));
if bearer_ok && account_ok {
if !bearer_ok || !account_ok {
Err(StatusCode::UNAUTHORIZED)
} else if !external_logos_ok {
Err(StatusCode::BAD_REQUEST)
} else {
let response = state
.response
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.clone();
Ok(Json(response))
} else {
Err(StatusCode::UNAUTHORIZED)
}
}
+5 -3
View File
@@ -220,9 +220,11 @@ async fn list_directory_connectors(config: &Config) -> anyhow::Result<Vec<Direct
let path = match next_token.as_deref() {
Some(token) => {
let encoded_token = urlencoding::encode(token);
format!("/connectors/directory/list?tier=categorized&token={encoded_token}")
format!(
"/connectors/directory/list?tier=categorized&token={encoded_token}&external_logos=true"
)
}
None => "/connectors/directory/list?tier=categorized".to_string(),
None => "/connectors/directory/list?tier=categorized&external_logos=true".to_string(),
};
let response: DirectoryListResponse =
chatgpt_get_request_with_timeout(config, path, Some(DIRECTORY_CONNECTORS_TIMEOUT))
@@ -247,7 +249,7 @@ async fn list_directory_connectors(config: &Config) -> anyhow::Result<Vec<Direct
async fn list_workspace_connectors(config: &Config) -> anyhow::Result<Vec<DirectoryApp>> {
let response: anyhow::Result<DirectoryListResponse> = chatgpt_get_request_with_timeout(
config,
"/connectors/directory/list_workspace".to_string(),
"/connectors/directory/list_workspace?external_logos=true".to_string(),
Some(DIRECTORY_CONNECTORS_TIMEOUT),
)
.await;
+14 -3
View File
@@ -224,7 +224,7 @@ impl CodexLogSnapshot {
classification: &str,
reason: Option<&str>,
include_logs: bool,
rollout_path: Option<&std::path::Path>,
extra_log_files: &[PathBuf],
session_source: Option<SessionSource>,
) -> Result<()> {
use std::collections::BTreeMap;
@@ -317,11 +317,22 @@ impl CodexLogSnapshot {
}));
}
if let Some((path, data)) = rollout_path.and_then(|p| fs::read(p).ok().map(|d| (p, d))) {
for path in extra_log_files {
let data = match fs::read(path) {
Ok(data) => data,
Err(err) => {
tracing::warn!(
path = %path.display(),
error = %err,
"failed to read log attachment; skipping"
);
continue;
}
};
let fname = path
.file_name()
.map(|s| s.to_string_lossy().to_string())
.unwrap_or_else(|| "rollout.jsonl".to_string());
.unwrap_or_else(|| "extra-log.log".to_string());
let content_type = "text/plain".to_string();
envelope.add_item(EnvelopeItem::Attachment(Attachment {
buffer: data,
@@ -87,7 +87,11 @@ impl FeedbackNoteView {
} else {
Some(note.as_str())
};
let rollout_path_ref = self.rollout_path.as_deref();
let log_file_paths = if self.include_logs {
self.rollout_path.iter().cloned().collect::<Vec<_>>()
} else {
Vec::new()
};
let classification = feedback_classification(self.category);
let mut thread_id = self.snapshot.thread_id.clone();
@@ -96,11 +100,7 @@ impl FeedbackNoteView {
classification,
reason_opt,
self.include_logs,
if self.include_logs {
rollout_path_ref
} else {
None
},
&log_file_paths,
Some(SessionSource::Cli),
);
+1 -1
View File
@@ -27,7 +27,7 @@ rustup component add clippy
# Install helper tools used by the workspace justfile:
cargo install just
# Optional: install nextest for the `just test` helper
cargo install cargo-nextest
cargo install --locked cargo-nextest
# Build Codex.
cargo build