mirror of
https://github.com/openai/codex.git
synced 2026-11-02 19:43:24 +00:00
Merge 13600b96f7 into sapling-pr-archive-bolinfest
This commit is contained in:
@@ -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)]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user