mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Attach connector caches to diagnostic uploads (#32891)
## What changed - Include the active Codex Apps tools cache and connector directory cache, when available, in diagnostic uploads that include logs. - Resolve cache paths from the current authentication context and use stable attachment filenames. - List both optional cache files in the upload consent dialog. ## Testing - Add coverage for selecting existing active cache files, including a directory cache without an account ID. - Update consent dialog snapshots to include the optional attachments. GitOrigin-RevId: 1d4ffbf2bcb96653f03dc25f91d80dd65038d585
This commit is contained in:
1 parent
bb947e8e36
commit
fb350d1e7d
10 files changed
+197
-13
No files matched your search
@@ -1,4 +1,9 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use codex_connectors::ConnectorDirectoryCacheContext;
|
||||||
|
use codex_connectors::ConnectorDirectoryCacheKey;
|
||||||
|
use codex_connectors::connector_runtime_cache_path;
|
||||||
|
use codex_feedback::CODEX_APP_DIRECTORY_CACHE_ATTACHMENT_FILENAME;
|
||||||
|
use codex_feedback::CODEX_APPS_TOOLS_CACHE_ATTACHMENT_FILENAME;
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
use codex_feedback::WINDOWS_SANDBOX_LOG_ATTACHMENT_FILENAME;
|
use codex_feedback::WINDOWS_SANDBOX_LOG_ATTACHMENT_FILENAME;
|
||||||
|
|
||||||
@@ -70,17 +75,16 @@ impl FeedbackRequestProcessor {
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(chatgpt_user_id) = self
|
let auth = self.auth_manager.auth_cached();
|
||||||
.auth_manager
|
if let Some(chatgpt_user_id) = auth
|
||||||
.auth_cached()
|
.as_ref()
|
||||||
.and_then(|auth| auth.get_chatgpt_user_id())
|
.and_then(codex_login::CodexAuth::get_chatgpt_user_id)
|
||||||
{
|
{
|
||||||
tracing::info!(target: "feedback_tags", chatgpt_user_id);
|
tracing::info!(target: "feedback_tags", chatgpt_user_id);
|
||||||
}
|
}
|
||||||
if let Some(account_id) = self
|
if let Some(account_id) = auth
|
||||||
.auth_manager
|
.as_ref()
|
||||||
.auth_cached()
|
.and_then(codex_login::CodexAuth::get_account_id)
|
||||||
.and_then(|auth| auth.get_account_id())
|
|
||||||
{
|
{
|
||||||
tracing::info!(target: "feedback_tags", account_id);
|
tracing::info!(target: "feedback_tags", account_id);
|
||||||
}
|
}
|
||||||
@@ -197,6 +201,15 @@ impl FeedbackRequestProcessor {
|
|||||||
{
|
{
|
||||||
attachment_paths.push(sandbox_log_attachment);
|
attachment_paths.push(sandbox_log_attachment);
|
||||||
}
|
}
|
||||||
|
for cache_attachment in tool_cache_feedback_attachments(
|
||||||
|
self.config.codex_home.as_path(),
|
||||||
|
&self.config.chatgpt_base_url,
|
||||||
|
auth.as_ref(),
|
||||||
|
) {
|
||||||
|
if seen_attachment_paths.insert(cache_attachment.path.clone()) {
|
||||||
|
attachment_paths.push(cache_attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(extra_log_files) = extra_log_files {
|
if let Some(extra_log_files) = extra_log_files {
|
||||||
for extra_log_file in extra_log_files {
|
for extra_log_file in extra_log_files {
|
||||||
@@ -272,6 +285,47 @@ impl FeedbackRequestProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tool_cache_feedback_attachments(
|
||||||
|
codex_home: &Path,
|
||||||
|
chatgpt_base_url: &str,
|
||||||
|
auth: Option<&CodexAuth>,
|
||||||
|
) -> Vec<FeedbackAttachmentPath> {
|
||||||
|
let mut attachments = Vec::with_capacity(2);
|
||||||
|
let tools_cache_path = connector_runtime_cache_path(codex_home, auth);
|
||||||
|
if tools_cache_path.is_file() {
|
||||||
|
attachments.push(FeedbackAttachmentPath {
|
||||||
|
path: tools_cache_path,
|
||||||
|
attachment_filename_override: Some(
|
||||||
|
CODEX_APPS_TOOLS_CACHE_ATTACHMENT_FILENAME.to_string(),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(auth) = auth.filter(|auth| auth.uses_codex_backend()) else {
|
||||||
|
return attachments;
|
||||||
|
};
|
||||||
|
let directory_cache_context = ConnectorDirectoryCacheContext::new(
|
||||||
|
codex_home.to_path_buf(),
|
||||||
|
ConnectorDirectoryCacheKey::new(
|
||||||
|
chatgpt_base_url.to_string(),
|
||||||
|
auth.get_account_id(),
|
||||||
|
auth.get_chatgpt_user_id(),
|
||||||
|
auth.is_workspace_account(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let directory_cache_path = directory_cache_context.cache_path();
|
||||||
|
if directory_cache_path.is_file() {
|
||||||
|
attachments.push(FeedbackAttachmentPath {
|
||||||
|
path: directory_cache_path,
|
||||||
|
attachment_filename_override: Some(
|
||||||
|
CODEX_APP_DIRECTORY_CACHE_ATTACHMENT_FILENAME.to_string(),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments
|
||||||
|
}
|
||||||
|
|
||||||
fn auto_review_rollout_filename(thread_id: ThreadId) -> String {
|
fn auto_review_rollout_filename(thread_id: ThreadId) -> String {
|
||||||
format!("auto-review-rollout-{thread_id}.jsonl")
|
format!("auto-review-rollout-{thread_id}.jsonl")
|
||||||
}
|
}
|
||||||
@@ -292,11 +346,106 @@ fn windows_sandbox_log_attachment(_codex_home: &Path) -> Option<FeedbackAttachme
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(test, target_os = "windows"))]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tool_cache_feedback_attachments_include_existing_active_cache_files() {
|
||||||
|
let codex_home = tempfile::tempdir().expect("create tempdir");
|
||||||
|
let auth = CodexAuth::create_dummy_chatgpt_auth_for_testing();
|
||||||
|
let tools_cache_path = connector_runtime_cache_path(codex_home.path(), Some(&auth));
|
||||||
|
std::fs::create_dir_all(tools_cache_path.parent().expect("tools cache parent"))
|
||||||
|
.expect("create tools cache directory");
|
||||||
|
std::fs::write(&tools_cache_path, b"tools").expect("write tools cache");
|
||||||
|
|
||||||
|
let account_id = auth.get_account_id().expect("dummy auth account id");
|
||||||
|
let directory_cache_context = ConnectorDirectoryCacheContext::new(
|
||||||
|
codex_home.path().to_path_buf(),
|
||||||
|
ConnectorDirectoryCacheKey::new(
|
||||||
|
"https://chatgpt.com/backend-api".to_string(),
|
||||||
|
Some(account_id),
|
||||||
|
auth.get_chatgpt_user_id(),
|
||||||
|
auth.is_workspace_account(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let directory_cache_path = directory_cache_context.cache_path();
|
||||||
|
std::fs::create_dir_all(
|
||||||
|
directory_cache_path
|
||||||
|
.parent()
|
||||||
|
.expect("directory cache parent"),
|
||||||
|
)
|
||||||
|
.expect("create directory cache directory");
|
||||||
|
std::fs::write(&directory_cache_path, b"directory").expect("write directory cache");
|
||||||
|
|
||||||
|
let attachments = tool_cache_feedback_attachments(
|
||||||
|
codex_home.path(),
|
||||||
|
"https://chatgpt.com/backend-api",
|
||||||
|
Some(&auth),
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.map(|attachment| (attachment.path, attachment.attachment_filename_override))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
attachments,
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
tools_cache_path,
|
||||||
|
Some(CODEX_APPS_TOOLS_CACHE_ATTACHMENT_FILENAME.to_string()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
directory_cache_path,
|
||||||
|
Some(CODEX_APP_DIRECTORY_CACHE_ATTACHMENT_FILENAME.to_string()),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tool_cache_feedback_attachments_include_directory_cache_without_account_id() {
|
||||||
|
let codex_home = tempfile::tempdir().expect("create tempdir");
|
||||||
|
let auth = CodexAuth::Headers(codex_login::AuthHeaders::new(
|
||||||
|
reqwest::header::HeaderMap::new(),
|
||||||
|
));
|
||||||
|
let directory_cache_context = ConnectorDirectoryCacheContext::new(
|
||||||
|
codex_home.path().to_path_buf(),
|
||||||
|
ConnectorDirectoryCacheKey::new(
|
||||||
|
"https://chatgpt.com/backend-api".to_string(),
|
||||||
|
/*account_id*/ None,
|
||||||
|
auth.get_chatgpt_user_id(),
|
||||||
|
auth.is_workspace_account(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let directory_cache_path = directory_cache_context.cache_path();
|
||||||
|
std::fs::create_dir_all(
|
||||||
|
directory_cache_path
|
||||||
|
.parent()
|
||||||
|
.expect("directory cache parent"),
|
||||||
|
)
|
||||||
|
.expect("create directory cache directory");
|
||||||
|
std::fs::write(&directory_cache_path, b"directory").expect("write directory cache");
|
||||||
|
|
||||||
|
let attachments = tool_cache_feedback_attachments(
|
||||||
|
codex_home.path(),
|
||||||
|
"https://chatgpt.com/backend-api",
|
||||||
|
Some(&auth),
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.map(|attachment| (attachment.path, attachment.attachment_filename_override))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
attachments,
|
||||||
|
vec![(
|
||||||
|
directory_cache_path,
|
||||||
|
Some(CODEX_APP_DIRECTORY_CACHE_ATTACHMENT_FILENAME.to_string()),
|
||||||
|
)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
#[test]
|
#[test]
|
||||||
fn windows_sandbox_log_attachment_uses_current_log() {
|
fn windows_sandbox_log_attachment_uses_current_log() {
|
||||||
let codex_home = tempfile::tempdir().expect("create tempdir");
|
let codex_home = tempfile::tempdir().expect("create tempdir");
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//! owned by the connector metadata store, not by this module.
|
//! owned by the connector metadata store, not by this module.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
@@ -75,6 +76,15 @@ pub fn connector_runtime_context_key(auth: Option<&CodexAuth>) -> ConnectorRunti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the persisted connector runtime tools cache path for the active auth identity.
|
||||||
|
pub fn connector_runtime_cache_path(codex_home: &Path, auth: Option<&CodexAuth>) -> PathBuf {
|
||||||
|
let identity = ConnectorRuntimeIdentity {
|
||||||
|
codex_home: codex_home.to_path_buf(),
|
||||||
|
key: connector_runtime_context_key(auth),
|
||||||
|
};
|
||||||
|
tools_cache_path(&identity)
|
||||||
|
}
|
||||||
|
|
||||||
/// One atomically published connector runtime state.
|
/// One atomically published connector runtime state.
|
||||||
///
|
///
|
||||||
/// Tools remain raw and in response order. Local and managed configuration is
|
/// Tools remain raw and in response order. Local and managed configuration is
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ impl ConnectorDirectoryCacheContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn cache_path(&self) -> PathBuf {
|
/// Returns the persisted connector directory cache path for this identity.
|
||||||
|
pub fn cache_path(&self) -> PathBuf {
|
||||||
let cache_key_json = serde_json::to_string(&self.cache_key).unwrap_or_default();
|
let cache_key_json = serde_json::to_string(&self.cache_key).unwrap_or_default();
|
||||||
let cache_key_hash = sha1_hex(&cache_key_json);
|
let cache_key_hash = sha1_hex(&cache_key_json);
|
||||||
self.codex_home
|
self.codex_home
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ pub use connector_runtime::ConnectorRuntimeFetchTicket;
|
|||||||
pub use connector_runtime::ConnectorRuntimeManager;
|
pub use connector_runtime::ConnectorRuntimeManager;
|
||||||
pub use connector_runtime::ConnectorRuntimePayload;
|
pub use connector_runtime::ConnectorRuntimePayload;
|
||||||
pub use connector_runtime::ConnectorRuntimeSnapshot;
|
pub use connector_runtime::ConnectorRuntimeSnapshot;
|
||||||
|
pub use connector_runtime::connector_runtime_cache_path;
|
||||||
pub use connector_runtime::connector_runtime_context_key;
|
pub use connector_runtime::connector_runtime_context_key;
|
||||||
pub use directory_cache::ConnectorDirectoryCacheContext;
|
pub use directory_cache::ConnectorDirectoryCacheContext;
|
||||||
pub use plugin_config::parse_plugin_app_config;
|
pub use plugin_config::parse_plugin_app_config;
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ pub use feedback_diagnostics::FeedbackDiagnostics;
|
|||||||
|
|
||||||
/// Filename used for the redacted `codex doctor --json` feedback attachment.
|
/// Filename used for the redacted `codex doctor --json` feedback attachment.
|
||||||
pub const DOCTOR_REPORT_ATTACHMENT_FILENAME: &str = "codex-doctor-report.json";
|
pub const DOCTOR_REPORT_ATTACHMENT_FILENAME: &str = "codex-doctor-report.json";
|
||||||
|
/// Filename used for the raw Codex Apps MCP tools cache feedback attachment.
|
||||||
|
pub const CODEX_APPS_TOOLS_CACHE_ATTACHMENT_FILENAME: &str = "codex-apps-tools-cache.json";
|
||||||
|
/// Filename used for the raw connector directory cache feedback attachment.
|
||||||
|
pub const CODEX_APP_DIRECTORY_CACHE_ATTACHMENT_FILENAME: &str = "codex-app-directory-cache.json";
|
||||||
/// Filename used for the Windows sandbox log feedback attachment.
|
/// Filename used for the Windows sandbox log feedback attachment.
|
||||||
pub const WINDOWS_SANDBOX_LOG_ATTACHMENT_FILENAME: &str = "windows-sandbox.log";
|
pub const WINDOWS_SANDBOX_LOG_ATTACHMENT_FILENAME: &str = "windows-sandbox.log";
|
||||||
const DEFAULT_MAX_BYTES: usize = 4 * 1024 * 1024; // 4 MiB
|
const DEFAULT_MAX_BYTES: usize = 4 * 1024 * 1024; // 4 MiB
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use codex_feedback::CODEX_APP_DIRECTORY_CACHE_ATTACHMENT_FILENAME;
|
||||||
|
use codex_feedback::CODEX_APPS_TOOLS_CACHE_ATTACHMENT_FILENAME;
|
||||||
use codex_feedback::DOCTOR_REPORT_ATTACHMENT_FILENAME;
|
use codex_feedback::DOCTOR_REPORT_ATTACHMENT_FILENAME;
|
||||||
use codex_feedback::FEEDBACK_DIAGNOSTICS_ATTACHMENT_FILENAME;
|
use codex_feedback::FEEDBACK_DIAGNOSTICS_ATTACHMENT_FILENAME;
|
||||||
use codex_feedback::FeedbackDiagnostics;
|
use codex_feedback::FeedbackDiagnostics;
|
||||||
@@ -510,6 +512,16 @@ pub(crate) fn feedback_upload_consent_params(
|
|||||||
DOCTOR_REPORT_ATTACHMENT_FILENAME.into(),
|
DOCTOR_REPORT_ATTACHMENT_FILENAME.into(),
|
||||||
])
|
])
|
||||||
.into(),
|
.into(),
|
||||||
|
Line::from(vec![
|
||||||
|
" • ".into(),
|
||||||
|
format!("{CODEX_APPS_TOOLS_CACHE_ATTACHMENT_FILENAME} (if available)").into(),
|
||||||
|
])
|
||||||
|
.into(),
|
||||||
|
Line::from(vec![
|
||||||
|
" • ".into(),
|
||||||
|
format!("{CODEX_APP_DIRECTORY_CACHE_ATTACHMENT_FILENAME} (if available)").into(),
|
||||||
|
])
|
||||||
|
.into(),
|
||||||
];
|
];
|
||||||
if include_windows_sandbox_log {
|
if include_windows_sandbox_log {
|
||||||
header_lines.push(
|
header_lines.push(
|
||||||
|
|||||||
+3
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tui/src/bottom_pane/feedback_view.rs
|
source: tui/src/bottom_pane/feedback_view.rs
|
||||||
assertion_line: 716
|
assertion_line: 728
|
||||||
expression: rendered
|
expression: rendered
|
||||||
---
|
---
|
||||||
Upload logs?
|
Upload logs?
|
||||||
@@ -8,5 +8,7 @@ Upload logs?
|
|||||||
The following files will be sent:
|
The following files will be sent:
|
||||||
• codex-logs.log
|
• codex-logs.log
|
||||||
• codex-doctor-report.json
|
• codex-doctor-report.json
|
||||||
|
• codex-apps-tools-cache.json (if available)
|
||||||
|
• codex-app-directory-cache.json (if available)
|
||||||
• rollout.jsonl
|
• rollout.jsonl
|
||||||
• auto-review-rollout.jsonl
|
• auto-review-rollout.jsonl
|
||||||
+3
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tui/src/bottom_pane/feedback_view.rs
|
source: tui/src/bottom_pane/feedback_view.rs
|
||||||
assertion_line: 734
|
assertion_line: 746
|
||||||
expression: rendered
|
expression: rendered
|
||||||
---
|
---
|
||||||
Upload logs?
|
Upload logs?
|
||||||
@@ -8,6 +8,8 @@ Upload logs?
|
|||||||
The following files will be sent:
|
The following files will be sent:
|
||||||
• codex-logs.log
|
• codex-logs.log
|
||||||
• codex-doctor-report.json
|
• codex-doctor-report.json
|
||||||
|
• codex-apps-tools-cache.json (if available)
|
||||||
|
• codex-app-directory-cache.json (if available)
|
||||||
• windows-sandbox.log
|
• windows-sandbox.log
|
||||||
• rollout.jsonl
|
• rollout.jsonl
|
||||||
• auto-review-rollout.jsonl
|
• auto-review-rollout.jsonl
|
||||||
+2
@@ -7,6 +7,8 @@ expression: popup
|
|||||||
The following files will be sent:
|
The following files will be sent:
|
||||||
• codex-logs.log
|
• codex-logs.log
|
||||||
• codex-doctor-report.json
|
• codex-doctor-report.json
|
||||||
|
• codex-apps-tools-cache.json (if available)
|
||||||
|
• codex-app-directory-cache.json (if available)
|
||||||
• auto-review-rollout-thread-1.jsonl
|
• auto-review-rollout-thread-1.jsonl
|
||||||
• codex-connectivity-diagnostics.txt
|
• codex-connectivity-diagnostics.txt
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
source: tui/src/chatwidget/tests/popups_and_settings.rs
|
source: tui/src/chatwidget/tests/popups_and_settings.rs
|
||||||
assertion_line: 2562
|
|
||||||
expression: popup
|
expression: popup
|
||||||
---
|
---
|
||||||
Upload logs?
|
Upload logs?
|
||||||
@@ -8,6 +7,8 @@ expression: popup
|
|||||||
The following files will be sent:
|
The following files will be sent:
|
||||||
• codex-logs.log
|
• codex-logs.log
|
||||||
• codex-doctor-report.json
|
• codex-doctor-report.json
|
||||||
|
• codex-apps-tools-cache.json (if available)
|
||||||
|
• codex-app-directory-cache.json (if available)
|
||||||
• windows-sandbox.log
|
• windows-sandbox.log
|
||||||
• auto-review-rollout-thread-1.jsonl
|
• auto-review-rollout-thread-1.jsonl
|
||||||
• codex-connectivity-diagnostics.txt
|
• codex-connectivity-diagnostics.txt
|
||||||
|
|||||||
Reference in new issue
Block a user