Skip to content

Commit 8e5bb1f

Browse files
warp-agent-staging[bot]oz-agentwarp-agent
authored
[multi-team P3a-1] Scope the AI autonomy accessor to the window's team (#15443)
crux of pr is making ai_autonomy_settings & is_ai_autonomy_allowed require a team scope... lots of threading through is then required: view context/handle -> exchange for team context -> feed into ai autonomy settings --------- Co-authored-by: warp-agent-staging[bot] <240773466+warp-agent-staging[bot]@users.noreply.github.com> Co-authored-by: Oz <oz-agent@warp.dev> Co-authored-by: Warp <agent@warp.dev>
1 parent efbf553 commit 8e5bb1f

47 files changed

Lines changed: 1312 additions & 375 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/src/ai/agent/api.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use crate::ai::mcp::TemplatableMCPServerManager;
3434
use crate::server::server_api::AIApiError;
3535
use crate::settings::AISettings;
3636
use crate::terminal::safe_mode_settings::get_secret_obfuscation_mode;
37-
use crate::workspaces::user_workspaces::UserWorkspaces;
37+
use crate::workspaces::user_workspaces::{TeamScope, UserWorkspaces};
3838

3939
/// Unique, server-generated conversation-scoped token to be roundtripped to the API when sending
4040
/// requests that follow-up within a given conversation.
@@ -224,12 +224,13 @@ impl RequestParams {
224224
}
225225
}
226226

227-
pub fn new(
227+
pub(crate) fn new(
228228
terminal_view_id: Option<EntityId>,
229229
session_context: SessionContext,
230230
request_input: &RequestInput,
231231
conversation: ConversationData,
232232
metadata: Option<RequestMetadata>,
233+
scope: &impl TeamScope,
233234
app: &AppContext,
234235
) -> Self {
235236
let ai_settings = AISettings::as_ref(app);
@@ -355,7 +356,7 @@ impl RequestParams {
355356
let is_ambient_agent = conversation.ambient_agent_task_id.is_some();
356357
let computer_use_enabled = FeatureFlag::AgentModeComputerUse.is_enabled()
357358
&& BlocklistAIPermissions::as_ref(app)
358-
.get_computer_use_setting(app, terminal_view_id)
359+
.get_computer_use_setting(terminal_view_id, scope, app)
359360
.is_enabled()
360361
&& computer_use::is_supported_on_current_platform()
361362
&& (FeatureFlag::LocalComputerUse.is_enabled() || is_ambient_agent);

app/src/ai/blocklist/action_model.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ use crate::ai::get_relevant_files::controller::GetRelevantFilesController;
7070
use crate::terminal::TerminalModel;
7171
use crate::terminal::model::session::active_session::ActiveSession;
7272
use crate::terminal::model_events::ModelEventDispatcher;
73+
use crate::workspaces::user_workspaces::TeamContextResolver;
7374
use crate::{TelemetryEvent, send_telemetry_from_ctx};
7475

7576
/// The status of an action from an AI output.
@@ -263,6 +264,7 @@ impl BlocklistAIActionModel {
263264
model_event_dispatcher: &ModelHandle<ModelEventDispatcher>,
264265
get_relevant_files_controller: ModelHandle<GetRelevantFilesController>,
265266
terminal_view_id: EntityId,
267+
team_context_resolver: TeamContextResolver,
266268
ctx: &mut ModelContext<Self>,
267269
) -> Self {
268270
let executor = ctx.add_model(|ctx| {
@@ -272,6 +274,7 @@ impl BlocklistAIActionModel {
272274
model_event_dispatcher,
273275
get_relevant_files_controller,
274276
terminal_view_id,
277+
team_context_resolver,
275278
ctx,
276279
)
277280
});

app/src/ai/blocklist/action_model/execute.rs

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ use crate::util::image::{
109109
};
110110
#[cfg(feature = "local_fs")]
111111
use crate::util::openable_file_type::is_binary_file;
112+
use crate::workspaces::user_workspaces::TeamContextResolver;
112113

113114
/// Types of actions that can be executed in parallel.
114115
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -282,6 +283,7 @@ pub struct BlocklistAIActionExecutor {
282283

283284
/// Reference to the terminal model for checking session sharing state.
284285
terminal_model: Arc<FairMutex<TerminalModel>>,
286+
team_context_resolver: TeamContextResolver,
285287
}
286288

287289
impl BlocklistAIActionExecutor {
@@ -291,6 +293,7 @@ impl BlocklistAIActionExecutor {
291293
model_event_dispatcher: &ModelHandle<ModelEventDispatcher>,
292294
get_relevant_files_controller: ModelHandle<GetRelevantFilesController>,
293295
terminal_view_id: EntityId,
296+
team_context_resolver: TeamContextResolver,
294297
ctx: &mut ModelContext<Self>,
295298
) -> Self {
296299
let read_files_executor =
@@ -368,6 +371,7 @@ impl BlocklistAIActionExecutor {
368371
stop_recording_executor,
369372
async_executing_actions: Default::default(),
370373
terminal_model,
374+
team_context_resolver,
371375
read_skill_executor,
372376
fetch_conversation_executor,
373377
start_agent_executor,
@@ -956,31 +960,45 @@ impl BlocklistAIActionExecutor {
956960
}
957961

958962
fn should_autoexecute(&self, input: ExecuteActionInput, ctx: &mut ModelContext<Self>) -> bool {
963+
let team_context_resolver = self.team_context_resolver.clone();
959964
match input.action.action {
960965
AIAgentActionType::RequestCommandOutput { .. }
961966
| AIAgentActionType::WriteToLongRunningShellCommand { .. }
962967
| AIAgentActionType::ReadShellCommandOutput { .. }
963-
| AIAgentActionType::TransferShellCommandControlToUser { .. } => self
964-
.shell_command_executor
965-
.update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)),
966-
AIAgentActionType::ReadFiles(_) => self
967-
.read_files_executor
968-
.update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)),
969-
AIAgentActionType::UploadArtifact(_) => self
970-
.upload_artifact_executor
971-
.update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)),
972-
AIAgentActionType::SearchCodebase(_) => self
973-
.search_codebase_executor
974-
.update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)),
975-
AIAgentActionType::RequestFileEdits { .. } => self
976-
.request_file_edits_executor
977-
.update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)),
978-
AIAgentActionType::Grep { .. } => self
979-
.grep_executor
980-
.update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)),
981-
AIAgentActionType::FileGlob { .. } | AIAgentActionType::FileGlobV2 { .. } => self
982-
.file_glob_executor
983-
.update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)),
968+
| AIAgentActionType::TransferShellCommandControlToUser { .. } => {
969+
self.shell_command_executor.update(ctx, |executor, ctx| {
970+
executor.should_autoexecute(input, &team_context_resolver(ctx), ctx)
971+
})
972+
}
973+
AIAgentActionType::ReadFiles(_) => {
974+
self.read_files_executor.update(ctx, |executor, ctx| {
975+
executor.should_autoexecute(input, &team_context_resolver(ctx), ctx)
976+
})
977+
}
978+
AIAgentActionType::UploadArtifact(_) => {
979+
self.upload_artifact_executor.update(ctx, |executor, ctx| {
980+
executor.should_autoexecute(input, &team_context_resolver(ctx), ctx)
981+
})
982+
}
983+
AIAgentActionType::SearchCodebase(_) => {
984+
self.search_codebase_executor.update(ctx, |executor, ctx| {
985+
executor.should_autoexecute(input, &team_context_resolver(ctx), ctx)
986+
})
987+
}
988+
AIAgentActionType::RequestFileEdits { .. } => {
989+
self.request_file_edits_executor
990+
.update(ctx, |executor, ctx| {
991+
executor.should_autoexecute(input, &team_context_resolver(ctx), ctx)
992+
})
993+
}
994+
AIAgentActionType::Grep { .. } => self.grep_executor.update(ctx, |executor, ctx| {
995+
executor.should_autoexecute(input, &team_context_resolver(ctx), ctx)
996+
}),
997+
AIAgentActionType::FileGlob { .. } | AIAgentActionType::FileGlobV2 { .. } => {
998+
self.file_glob_executor.update(ctx, |executor, ctx| {
999+
executor.should_autoexecute(input, &team_context_resolver(ctx), ctx)
1000+
})
1001+
}
9841002
AIAgentActionType::CallMCPTool { .. } => self
9851003
.call_mcp_tool_executor
9861004
.update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)),
@@ -1008,9 +1026,12 @@ impl BlocklistAIActionExecutor {
10081026
AIAgentActionType::UseComputer(_) => self
10091027
.use_computer_executor
10101028
.update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)),
1011-
AIAgentActionType::RequestComputerUse(_) => self
1012-
.request_computer_use_executor
1013-
.update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)),
1029+
AIAgentActionType::RequestComputerUse(_) => {
1030+
self.request_computer_use_executor
1031+
.update(ctx, |executor, ctx| {
1032+
executor.should_autoexecute(input, &team_context_resolver(ctx), ctx)
1033+
})
1034+
}
10141035
AIAgentActionType::StartRecording { .. } => self
10151036
.start_recording_executor
10161037
.update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)),

app/src/ai/blocklist/action_model/execute/file_glob.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::terminal::model::session::active_session::ActiveSession;
2121
use crate::terminal::model::session::command_executor::shell_quote_arg;
2222
use crate::terminal::model::session::{ExecuteCommandOptions, Session};
2323
use crate::terminal::shell::ShellType;
24+
use crate::workspaces::user_workspaces::TeamContext;
2425
use crate::{TelemetryEvent, send_telemetry_from_app_ctx};
2526

2627
const FILE_GLOB_TIMEOUT: Duration = Duration::from_secs(10);
@@ -53,7 +54,8 @@ impl FileGlobExecutor {
5354
pub(super) fn should_autoexecute(
5455
&self,
5556
input: ExecuteActionInput,
56-
ctx: &mut ModelContext<Self>,
57+
scope: &TeamContext<'_>,
58+
ctx: &ModelContext<Self>,
5759
) -> bool {
5860
let ExecuteActionInput {
5961
action:
@@ -88,6 +90,7 @@ impl FileGlobExecutor {
8890
&conversation_id,
8991
vec![PathBuf::from(absolute_path)],
9092
Some(self.terminal_view_id),
93+
scope,
9194
ctx,
9295
)
9396
.is_allowed()

app/src/ai/blocklist/action_model/execute/grep.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use crate::terminal::ShellLaunchData;
2828
use crate::terminal::model::session::active_session::ActiveSession;
2929
use crate::terminal::model::session::{ExecuteCommandOptions, Session, shell_quote_arg};
3030
use crate::terminal::shell::ShellType;
31+
use crate::workspaces::user_workspaces::TeamContext;
3132
use crate::{PrivacySettings, TelemetryEvent, send_telemetry_from_app_ctx};
3233

3334
const GREP_TIMEOUT: Duration = Duration::from_secs(10);
@@ -193,7 +194,8 @@ impl GrepExecutor {
193194
pub(super) fn should_autoexecute(
194195
&self,
195196
input: ExecuteActionInput,
196-
ctx: &mut ModelContext<Self>,
197+
scope: &TeamContext<'_>,
198+
ctx: &ModelContext<Self>,
197199
) -> bool {
198200
let ExecuteActionInput {
199201
action:
@@ -221,6 +223,7 @@ impl GrepExecutor {
221223
&conversation_id,
222224
vec![PathBuf::from(absolute_path)],
223225
Some(self.terminal_view_id),
226+
scope,
224227
ctx,
225228
)
226229
.is_allowed()

app/src/ai/blocklist/action_model/execute/read_files.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::ai::blocklist::BlocklistAIPermissions;
1616
use crate::ai::paths::host_native_absolute_path;
1717
use crate::terminal::model::session::SessionType;
1818
use crate::terminal::model::session::active_session::ActiveSession;
19+
use crate::workspaces::user_workspaces::TeamContext;
1920

2021
pub struct ReadFilesExecutor {
2122
active_session: ModelHandle<ActiveSession>,
@@ -33,7 +34,8 @@ impl ReadFilesExecutor {
3334
pub(super) fn should_autoexecute(
3435
&self,
3536
input: ExecuteActionInput,
36-
ctx: &mut ModelContext<Self>,
37+
scope: &TeamContext<'_>,
38+
ctx: &ModelContext<Self>,
3739
) -> bool {
3840
let ExecuteActionInput {
3941
action:
@@ -70,6 +72,7 @@ impl ReadFilesExecutor {
7072
})
7173
.collect(),
7274
Some(self.terminal_view_id),
75+
scope,
7376
ctx,
7477
)
7578
.is_allowed()

app/src/ai/blocklist/action_model/execute/request_computer_use.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::ai::blocklist::BlocklistAIHistoryModel;
1212
use crate::features::FeatureFlag;
1313
use crate::send_telemetry_from_ctx;
1414
use crate::server::telemetry::TelemetryEvent;
15+
use crate::workspaces::user_workspaces::TeamContext;
1516

1617
pub struct RequestComputerUseExecutor {
1718
terminal_view_id: EntityId,
@@ -37,7 +38,8 @@ impl RequestComputerUseExecutor {
3738
pub(super) fn should_autoexecute(
3839
&mut self,
3940
input: ExecuteActionInput,
40-
ctx: &mut ModelContext<Self>,
41+
scope: &TeamContext<'_>,
42+
ctx: &ModelContext<Self>,
4143
) -> bool {
4244
let ExecuteActionInput { action, .. } = input;
4345
let AIAgentActionType::RequestComputerUse(_) = &action.action else {
@@ -46,7 +48,7 @@ impl RequestComputerUseExecutor {
4648

4749
// Check profile permission
4850
let permission = crate::ai::blocklist::BlocklistAIPermissions::as_ref(ctx)
49-
.get_computer_use_setting(ctx, Some(self.terminal_view_id));
51+
.get_computer_use_setting(Some(self.terminal_view_id), scope, ctx);
5052
if permission.is_always_allow() {
5153
// Track that this action was auto-executed for telemetry in execute()
5254
self.autoexecuted_actions.insert(action.id.clone());

app/src/ai/blocklist/action_model/execute/request_file_edits.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use crate::ai::blocklist::{BlocklistAIPermissions, RequestedEditResolution};
3636
use crate::ai::paths::host_native_absolute_path;
3737
use crate::terminal::model::session::SessionType;
3838
use crate::terminal::model::session::active_session::ActiveSession;
39+
use crate::workspaces::user_workspaces::TeamContext;
3940
use crate::{BlocklistAIHistoryModel, safe_warn};
4041

4142
pub struct RequestFileEditsExecutor {
@@ -67,7 +68,8 @@ impl RequestFileEditsExecutor {
6768
pub(super) fn should_autoexecute(
6869
&self,
6970
input: ExecuteActionInput,
70-
ctx: &mut ModelContext<Self>,
71+
scope: &TeamContext<'_>,
72+
ctx: &ModelContext<Self>,
7173
) -> bool {
7274
let ExecuteActionInput {
7375
action:
@@ -110,7 +112,13 @@ impl RequestFileEditsExecutor {
110112
}
111113

112114
BlocklistAIPermissions::as_ref(ctx)
113-
.can_write_files(&conversation_id, &paths, Some(self.terminal_view_id), ctx)
115+
.can_write_files(
116+
&conversation_id,
117+
&paths,
118+
Some(self.terminal_view_id),
119+
scope,
120+
ctx,
121+
)
114122
.is_allowed()
115123
}
116124

app/src/ai/blocklist/action_model/execute/search_codebase.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use crate::ai::get_relevant_files::controller::{
2424
};
2525
use crate::features::FeatureFlag;
2626
use crate::terminal::model::session::active_session::ActiveSession;
27+
use crate::workspaces::user_workspaces::TeamContext;
2728
use crate::{TelemetryEvent, send_telemetry_from_ctx};
2829

2930
pub struct SearchCodebaseExecutor {
@@ -149,7 +150,8 @@ impl SearchCodebaseExecutor {
149150
pub(super) fn should_autoexecute(
150151
&self,
151152
input: ExecuteActionInput,
152-
ctx: &mut ModelContext<Self>,
153+
scope: &TeamContext<'_>,
154+
ctx: &ModelContext<Self>,
153155
) -> bool {
154156
let ExecuteActionInput {
155157
action:
@@ -171,6 +173,7 @@ impl SearchCodebaseExecutor {
171173
&conversation_id,
172174
vec![root_repo_path.to_owned()],
173175
Some(self.terminal_view_id),
176+
scope,
174177
ctx,
175178
)
176179
.is_allowed()

app/src/ai/blocklist/action_model/execute/shell_command.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use crate::terminal::model::block::{
3434
use crate::terminal::model::session::active_session::ActiveSession;
3535
use crate::terminal::model_events::{ModelEvent, ModelEventDispatcher};
3636
use crate::terminal::shell::ShellType;
37+
use crate::workspaces::user_workspaces::TeamContext;
3738
use crate::{TelemetryEvent, send_telemetry_from_ctx};
3839

3940
pub struct ShellCommandExecutor {
@@ -107,7 +108,8 @@ impl ShellCommandExecutor {
107108
pub(super) fn should_autoexecute(
108109
&self,
109110
input: ExecuteActionInput,
110-
ctx: &mut ModelContext<Self>,
111+
scope: &TeamContext<'_>,
112+
ctx: &ModelContext<Self>,
111113
) -> bool {
112114
let blocklist_permissions = BlocklistAIPermissions::as_ref(ctx);
113115
match &input.action.action {
@@ -132,6 +134,7 @@ impl ShellCommandExecutor {
132134
is_read_only.unwrap_or(false),
133135
*is_risky,
134136
Some(self.terminal_view_id),
137+
scope,
135138
ctx,
136139
);
137140
if let CommandExecutionPermission::Allowed(reason) = autoexecution_permission {
@@ -158,6 +161,7 @@ impl ShellCommandExecutor {
158161
let should_autoexecute = match blocklist_permissions.can_write_to_pty(
159162
&input.conversation_id,
160163
Some(self.terminal_view_id),
164+
scope,
161165
ctx,
162166
) {
163167
WriteToPtyPermission::AlwaysAllow => true,

0 commit comments

Comments
 (0)