Skip to content

Commit c5313df

Browse files
{"message":"Resource not accessible by integration","documentation_url":"https://docs.github.com/rest/users/users#get-the-authenticated-user","status":"403"}oz-agent
authored andcommitted
fix: restore shared cloud sessions as ambient panes
Persist shared ambient agent session panes as ambient agent snapshots even when they were opened as plain shared-session viewers without an ambient view model. This preserves the cloud task ID for app session restoration instead of restoring as a local terminal. Co-Authored-By: Oz <oz-agent@warp.dev>
1 parent fd0a9d1 commit c5313df

2 files changed

Lines changed: 58 additions & 3 deletions

File tree

app/src/pane_group/mod_tests.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,15 @@ use crate::{
7474
#[cfg(feature = "local_fs")]
7575
use repo_metadata::RepoMetadataModel;
7676
use repo_metadata::{repositories::DetectedRepositories, watcher::DirectoryWatcher};
77+
use session_sharing_protocol::sharer::SessionSourceType;
7778
use std::collections::HashMap;
7879
use uuid::Uuid;
7980
use warp_core::features::FeatureFlag;
8081
use watcher::HomeDirectoryWatcher;
8182

8283
use super::child_agent::{create_hidden_child_agent_conversation, HiddenChildAgentTaskContext};
8384
use super::*;
85+
use crate::app_state::{LeafContents, PaneNodeSnapshot};
8486
use crate::terminal::resizable_data::ResizableData;
8587
use ai::{
8688
index::full_source_code_embedding::manager::CodebaseIndexManager,
@@ -589,6 +591,42 @@ fn test_restored_remote_hidden_child_pane_enters_existing_ambient_session() {
589591
});
590592
}
591593

594+
#[test]
595+
fn test_shared_ambient_session_without_ambient_view_model_snapshots_as_ambient_agent() {
596+
App::test((), |mut app| async move {
597+
initialize_app(&mut app);
598+
let pane_group = mock_pane_group(&mut app, Default::default());
599+
600+
pane_group.update(&mut app, |panes, ctx| {
601+
let pane_id = get_newly_created_pane_id(panes, &[]);
602+
let task_id = new_ambient_agent_task_id();
603+
let terminal_view = panes
604+
.terminal_view_from_pane_id(pane_id, ctx)
605+
.expect("initial pane should have a terminal view");
606+
607+
terminal_view.update(ctx, |view, _ctx| {
608+
assert!(
609+
view.ambient_agent_view_model().is_none(),
610+
"plain shared-session viewers do not have cloud-mode view models"
611+
);
612+
let mut model = view.model.lock();
613+
model.set_shared_session_status(SharedSessionStatus::reader());
614+
model.set_shared_session_source_type(SessionSourceType::AmbientAgent {
615+
task_id: Some(task_id.to_string()),
616+
});
617+
});
618+
619+
let PaneNodeSnapshot::Leaf(leaf) = panes.snapshot(ctx) else {
620+
panic!("expected single-pane snapshot");
621+
};
622+
let LeafContents::AmbientAgent(snapshot) = leaf.contents else {
623+
panic!("expected ambient agent snapshot");
624+
};
625+
assert_eq!(snapshot.task_id, Some(task_id));
626+
});
627+
});
628+
}
629+
592630
#[test]
593631
fn test_active_session_id_reset_on_last_pane_close() {
594632
App::test((), |mut app| async move {

app/src/pane_group/pane/terminal_pane.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,16 @@ impl PaneContent for TerminalPane {
427427
// Capture the current input_config from the AI input model
428428
let current_input_config = view.input_config(app.as_ref());
429429

430-
if view.model.lock().shared_session_status().is_viewer() {
430+
let (is_shared_session_viewer, is_conversation_transcript_viewer, ambient_agent_task_id) = {
431+
let model = view.model.lock();
432+
(
433+
model.shared_session_status().is_viewer(),
434+
model.is_conversation_transcript_viewer(),
435+
model.ambient_agent_task_id(),
436+
)
437+
};
438+
439+
if is_shared_session_viewer {
431440
// We save and restore ambient agent sessions
432441
// (restoring the shared session if it's still open and the conversation transcript otherwise).
433442
if let Some(ambient_model) = view.ambient_agent_view_model() {
@@ -440,6 +449,14 @@ impl PaneContent for TerminalPane {
440449
});
441450
}
442451

452+
let task_id = ambient_agent_task_id;
453+
if task_id.is_some() {
454+
return LeafContents::AmbientAgent(AmbientAgentPaneSnapshot {
455+
uuid: self.uuid.clone(),
456+
task_id,
457+
});
458+
}
459+
443460
LeafContents::Terminal(TerminalPaneSnapshot {
444461
uuid: self.uuid.clone(),
445462
cwd: None,
@@ -452,10 +469,10 @@ impl PaneContent for TerminalPane {
452469
conversation_ids_to_restore: vec![],
453470
active_conversation_id: None,
454471
})
455-
} else if view.model.lock().is_conversation_transcript_viewer() {
472+
} else if is_conversation_transcript_viewer {
456473
// Conversation transcript viewers (opened from the conversation list)
457474
// can be restored via the ambient agent task if one exists.
458-
let task_id = view.model.lock().ambient_agent_task_id();
475+
let task_id = ambient_agent_task_id;
459476
if task_id.is_some() {
460477
LeafContents::AmbientAgent(AmbientAgentPaneSnapshot {
461478
uuid: self.uuid.clone(),

0 commit comments

Comments
 (0)