mirror of
https://github.com/openai/codex.git
synced 2026-11-07 20:30:33 +00:00
Add a gated Cloud backend to the TUI (#59828)
## What changed - Register an additional Cloud connection on supported macOS and Linux launches when `TuiMultiBackend` is enabled, using the selected ChatGPT account and local network policy. - Preserve backend settings and identify Cloud in connection controls and status. - Let Cloud supply the model when a thread opens, skip local skills requests and stale results, and allow resume without a local working-directory override. - Preserve Git metadata in Cloud thread snapshots and continue history hydration past empty filtered pages within the scan budget. - Report Cloud connection failures and require reopening Codex to reconnect. ## Testing Add regression coverage for Cloud model bootstrap, skipped skills requests, resume directory handling, history pagination through filtered pages, and Git metadata preservation. GitOrigin-RevId: 6717f0f5ad7708c5e9b5796d94711dd1eecc49bb
This commit is contained in:
committed by
copyberry
parent
a037e65ead
commit
7b8d67e456
@@ -79,6 +79,7 @@ pub struct ThreadSnapshot {
|
||||
pub thread_source: Option<String>,
|
||||
pub agent_nickname: Option<String>,
|
||||
pub agent_role: Option<String>,
|
||||
pub git_info: Option<GitInfo>,
|
||||
pub name: Option<String>,
|
||||
pub environments: Option<Vec<ThreadEnvironment>>,
|
||||
/// Activation deliberately excludes turns; callers page history separately.
|
||||
@@ -87,6 +88,15 @@ pub struct ThreadSnapshot {
|
||||
raw_protobuf: Bytes,
|
||||
}
|
||||
|
||||
/// Optional repository metadata associated with a cloud conversation.
|
||||
#[derive(Clone, PartialEq, Eq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GitInfo {
|
||||
pub branch: Option<String>,
|
||||
pub origin_url: Option<String>,
|
||||
pub sha: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ThreadHistoryMode {
|
||||
@@ -343,6 +353,11 @@ impl ThreadSnapshot {
|
||||
thread_source: thread.thread_source,
|
||||
agent_nickname: thread.agent_nickname,
|
||||
agent_role: thread.agent_role,
|
||||
git_info: thread.git_info.map(|git_info| GitInfo {
|
||||
branch: git_info.branch,
|
||||
origin_url: git_info.origin_url,
|
||||
sha: git_info.sha,
|
||||
}),
|
||||
name: thread.name,
|
||||
environments: thread
|
||||
.environments
|
||||
|
||||
@@ -203,6 +203,8 @@ pub(super) struct Thread {
|
||||
pub ephemeral: Option<bool>,
|
||||
#[prost(string, optional, tag = "11")]
|
||||
pub forked_from_id: Option<String>,
|
||||
#[prost(message, optional, tag = "12")]
|
||||
pub git_info: Option<GitInfo>,
|
||||
#[prost(int32, optional, tag = "13")]
|
||||
pub history_mode: Option<i32>,
|
||||
#[prost(string, optional, tag = "14")]
|
||||
@@ -245,6 +247,23 @@ impl fmt::Debug for Thread {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Message)]
|
||||
#[prost(skip_debug)]
|
||||
pub(super) struct GitInfo {
|
||||
#[prost(string, optional, tag = "1")]
|
||||
pub branch: Option<String>,
|
||||
#[prost(string, optional, tag = "2")]
|
||||
pub origin_url: Option<String>,
|
||||
#[prost(string, optional, tag = "3")]
|
||||
pub sha: Option<String>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for GitInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("GitInfo([redacted])")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Message)]
|
||||
pub(super) struct Environments {
|
||||
#[prost(message, repeated, tag = "1")]
|
||||
|
||||
@@ -48,8 +48,11 @@ async fn discovery_preserves_pagination_and_order_on_each_request() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn discovery_preserves_native_snapshots_and_read_state() {
|
||||
// Independent native Thread encodings: modern future field (99) and legacy empty metadata.
|
||||
let thread = Bytes::from_static(b"\x22\x01v\x28\x01\x32\x01/\x48\x00\x72\x01t\x82\x01\x01p\xaa\x01\x00\xda\x01\x01s\xe2\x01\x02\x08\x63\xea\x01\x02\x12\x00\xfa\x01\x00\x80\x02\x02\x98\x06\x01");
|
||||
// Independent native Thread encodings: Git metadata and future field (99), and a legacy row.
|
||||
let thread = Bytes::from_static(
|
||||
b"\x22\x01v\x28\x01\x32\x01/\x48\x00\x62\x28\x0a\x04main\x12\x18https://example.com/repo\x1a\x06abc123\
|
||||
\x72\x01t\x82\x01\x01p\xaa\x01\x00\xda\x01\x01s\xe2\x01\x02\x08\x63\xea\x01\x02\x12\x00\xfa\x01\x00\x80\x02\x02\x98\x06\x01",
|
||||
);
|
||||
let legacy = Bytes::from_static(b"\x22\x00\x28\x00\x32\x01/\x48\x00\x72\x06legacy\x82\x01\x00\xaa\x01\x00\xda\x01\x00\xe2\x01\x02\x08\x01\xea\x01\x02\x12\x00\xfa\x01\x00\x80\x02\x00");
|
||||
let mut data = Vec::new();
|
||||
for row in [&thread, &legacy, &thread] {
|
||||
@@ -81,6 +84,12 @@ async fn discovery_preserves_native_snapshots_and_read_state() {
|
||||
),
|
||||
("legacy", "", "", "")
|
||||
);
|
||||
let page_json = serde_json::to_value(&page).unwrap();
|
||||
assert_eq!(
|
||||
page_json["data"][0]["gitInfo"],
|
||||
serde_json::json!({"branch": "main", "originUrl": "https://example.com/repo", "sha": "abc123"})
|
||||
);
|
||||
assert!(page.data[1].git_info.is_none());
|
||||
assert_eq!(page.data[0].status, ThreadStatus::Idle);
|
||||
assert_eq!(
|
||||
page.read_states,
|
||||
|
||||
@@ -24,6 +24,7 @@ pub use activation::ApprovalPolicy;
|
||||
pub use activation::ApprovalsReviewer;
|
||||
pub use activation::CollaborationMode;
|
||||
pub use activation::CollaborationSettings;
|
||||
pub use activation::GitInfo;
|
||||
pub use activation::NetworkAccess;
|
||||
pub use activation::SandboxPolicy;
|
||||
pub use activation::SessionSource;
|
||||
|
||||
Reference in New Issue
Block a user