mirror of
https://github.com/openai/codex.git
synced 2026-11-02 16:20:35 +00:00
Track permission instructions in world state (#33944)
## What changed - Model permission instructions as a world-state section keyed by a stable hash of their rendered developer message. - Re-emit permission context when its model-visible contents change or the retained fragment is missing, while avoiding duplicates when matching instructions already exist in history, including bundled developer messages. - Normalize CRLF line endings when hashing world-state fragments so equivalent content produces the same snapshot. ## Testing - Add snapshot coverage for unchanged, changed, absent, and unknown permission state. - Cover bundled retained permissions and restored world-state baselines during rollout reconstruction. GitOrigin-RevId: 7d8d212460c1690ca617859f66dcd825987f1e23
This commit is contained in:
1 parent
6bd3f5e3db
commit
82b294c73c
22 files changed
+396
-189
No files matched your search
@@ -3,6 +3,7 @@ mod apps_instructions;
|
||||
mod collaboration_mode;
|
||||
mod environment;
|
||||
mod environments_instructions;
|
||||
mod permissions;
|
||||
mod plugins_instructions;
|
||||
mod realtime;
|
||||
#[cfg(test)]
|
||||
@@ -19,6 +20,8 @@ use serde::Serialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde_json::Map;
|
||||
use serde_json::Value;
|
||||
use sha1::Digest;
|
||||
use sha1::Sha1;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
|
||||
@@ -27,6 +30,7 @@ pub(crate) use apps_instructions::AppsInstructionsState;
|
||||
pub(crate) use collaboration_mode::CollaborationModeState;
|
||||
pub(crate) use environment::EnvironmentsState;
|
||||
pub(crate) use environments_instructions::EnvironmentsInstructionsState;
|
||||
pub(crate) use permissions::PermissionsState;
|
||||
pub(crate) use plugins_instructions::PluginsInstructionsState;
|
||||
pub(crate) use realtime::RealtimeState;
|
||||
|
||||
@@ -211,6 +215,27 @@ pub(crate) trait WorldStateSection: Send + Sync + 'static {
|
||||
) -> Option<Box<dyn ContextualUserFragment>>;
|
||||
}
|
||||
|
||||
/// Stable fingerprint of a model-visible World State fragment.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, serde::Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub(crate) struct WorldStateHash(String);
|
||||
|
||||
impl WorldStateHash {
|
||||
pub(crate) fn from_fragment(fragment: &(impl ContextualUserFragment + ?Sized)) -> Self {
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(b"codex-world-state-fragment-v1\0");
|
||||
hash_component(&mut hasher, fragment.role());
|
||||
hash_component(&mut hasher, &fragment.render());
|
||||
Self(format!("{:x}", hasher.finalize()))
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_component(hasher: &mut Sha1, value: &str) {
|
||||
let value = value.replace("\r\n", "\n");
|
||||
hasher.update((value.len() as u64).to_be_bytes());
|
||||
hasher.update(value.as_bytes());
|
||||
}
|
||||
|
||||
/// Live model-visible state, keyed by the same stable section IDs used in rollouts.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct WorldState {
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
use super::PreviousSectionState;
|
||||
use super::WorldStateHash;
|
||||
use super::WorldStateSection;
|
||||
use crate::context::ApprovalPromptContext;
|
||||
use crate::context::ContextualUserFragment;
|
||||
use crate::context::PermissionsInstructions;
|
||||
use codex_execpolicy::Policy;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use std::path::Path;
|
||||
|
||||
/// Permission instructions currently visible to the model.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct PermissionsState {
|
||||
snapshot: WorldStateHash,
|
||||
instructions: PermissionsInstructions,
|
||||
}
|
||||
|
||||
impl PermissionsState {
|
||||
pub(crate) fn new(
|
||||
permission_profile: &PermissionProfile,
|
||||
approval_policy: AskForApproval,
|
||||
approval_context: ApprovalPromptContext<'_>,
|
||||
exec_policy: &Policy,
|
||||
cwd: &Path,
|
||||
exec_permission_approvals_enabled: bool,
|
||||
request_permissions_tool_enabled: bool,
|
||||
) -> Self {
|
||||
let instructions = PermissionsInstructions::from_permission_profile(
|
||||
permission_profile,
|
||||
approval_policy,
|
||||
approval_context,
|
||||
exec_policy,
|
||||
cwd,
|
||||
exec_permission_approvals_enabled,
|
||||
request_permissions_tool_enabled,
|
||||
);
|
||||
let snapshot = WorldStateHash::from_fragment(&instructions);
|
||||
Self {
|
||||
snapshot,
|
||||
instructions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WorldStateSection for PermissionsState {
|
||||
const ID: &'static str = "permissions";
|
||||
type Snapshot = WorldStateHash;
|
||||
|
||||
fn snapshot(&self) -> Self::Snapshot {
|
||||
self.snapshot.clone()
|
||||
}
|
||||
|
||||
fn matches_legacy_fragment(role: &str, text: &str) -> bool {
|
||||
role == "developer" && PermissionsInstructions::matches_text(text)
|
||||
}
|
||||
|
||||
fn has_retained_fragment_matcher() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn matches_retained_fragment(role: &str, text: &str) -> bool {
|
||||
Self::matches_legacy_fragment(role, text)
|
||||
}
|
||||
|
||||
fn render_diff(
|
||||
&self,
|
||||
previous: PreviousSectionState<'_, Self::Snapshot>,
|
||||
) -> Option<Box<dyn ContextualUserFragment>> {
|
||||
if matches!(previous, PreviousSectionState::Known(previous) if previous == &self.snapshot) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Box::new(self.instructions.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "permissions_tests.rs"]
|
||||
mod tests;
|
||||
@@ -0,0 +1,94 @@
|
||||
use super::*;
|
||||
use crate::context::world_state::test_support::render_section_cases;
|
||||
use codex_protocol::config_types::ApprovalsReviewer;
|
||||
use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::openai_models::ApprovalMessages;
|
||||
use codex_protocol::openai_models::PermissionMessages;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
fn snapshots() {
|
||||
use PreviousSectionState::Absent;
|
||||
use PreviousSectionState::Known;
|
||||
use PreviousSectionState::Unknown;
|
||||
|
||||
let read_only = permissions_state(PermissionProfile::read_only(), AskForApproval::OnRequest);
|
||||
let full_access = permissions_state(PermissionProfile::Disabled, AskForApproval::OnRequest);
|
||||
let never_ask = permissions_state(PermissionProfile::read_only(), AskForApproval::Never);
|
||||
|
||||
insta::assert_snapshot!(render_section_cases(&[
|
||||
(Absent, Absent),
|
||||
(Absent, Known(&read_only)),
|
||||
(Known(&read_only), Known(&read_only)),
|
||||
(Known(&read_only), Known(&full_access)),
|
||||
(Known(&read_only), Known(&never_ask)),
|
||||
(Unknown, Known(&read_only)),
|
||||
]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn persisted_permissions_are_detected_inside_bundled_developer_messages() {
|
||||
let state = permissions_state(PermissionProfile::read_only(), AskForApproval::OnRequest);
|
||||
let retained = ContextualUserFragment::into(state.instructions.clone());
|
||||
let mut world_state = super::super::WorldState::default();
|
||||
world_state.add_section(state);
|
||||
let snapshot = world_state.snapshot();
|
||||
let mut bundled_retained = retained.clone();
|
||||
let ResponseItem::Message { content, .. } = &mut bundled_retained else {
|
||||
panic!("permissions should render as a message");
|
||||
};
|
||||
content.insert(
|
||||
0,
|
||||
ContentItem::InputText {
|
||||
text: "Other developer instructions.".to_string(),
|
||||
},
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
world_state
|
||||
.render_history_diff(/*previous*/ None, std::slice::from_ref(&retained))
|
||||
.len(),
|
||||
1,
|
||||
);
|
||||
assert_eq!(
|
||||
world_state.render_history_diff(Some(&snapshot), &[]).len(),
|
||||
1,
|
||||
);
|
||||
assert!(
|
||||
world_state
|
||||
.render_history_diff(Some(&snapshot), &[bundled_retained])
|
||||
.is_empty()
|
||||
);
|
||||
}
|
||||
|
||||
fn permissions_state(
|
||||
permission_profile: PermissionProfile,
|
||||
approval_policy: AskForApproval,
|
||||
) -> PermissionsState {
|
||||
let approval_messages = ApprovalMessages {
|
||||
on_request: Some("Ask for approval.".to_string()),
|
||||
on_request_auto_review: None,
|
||||
};
|
||||
let permission_messages = PermissionMessages {
|
||||
danger_full_access: Some("Full access.".to_string()),
|
||||
workspace_write: Some("Workspace write.".to_string()),
|
||||
read_only: Some("Read only.".to_string()),
|
||||
};
|
||||
PermissionsState::new(
|
||||
&permission_profile,
|
||||
approval_policy,
|
||||
ApprovalPromptContext::new(
|
||||
ApprovalsReviewer::User,
|
||||
Some(&approval_messages),
|
||||
Some(&permission_messages),
|
||||
),
|
||||
&Policy::empty(),
|
||||
Path::new("/workspace"),
|
||||
/*exec_permission_approvals_enabled*/ false,
|
||||
/*request_permissions_tool_enabled*/ false,
|
||||
)
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
---
|
||||
source: core/src/context/world_state/permissions_tests.rs
|
||||
expression: "render_section_cases(&[(Absent, Absent), (Absent, Known(&read_only)),\n(Known(&read_only), Known(&read_only)),\n(Known(&read_only), Known(&full_access)),\n(Known(&read_only), Known(&never_ask)), (Unknown, Known(&read_only)),])"
|
||||
---
|
||||
Absent -> Absent
|
||||
None
|
||||
|
||||
Absent -> "0ccde536dd8b4cfebb1df573f679dfe86b5718e3" (role - developer)
|
||||
<permissions instructions>
|
||||
Read only.
|
||||
Ask for approval.
|
||||
</permissions instructions>
|
||||
|
||||
"0ccde536dd8b4cfebb1df573f679dfe86b5718e3" -> "0ccde536dd8b4cfebb1df573f679dfe86b5718e3"
|
||||
None
|
||||
|
||||
"0ccde536dd8b4cfebb1df573f679dfe86b5718e3" -> "7e17d9a0df61e5f0c032ed7f0bf1dda58c9d5e85" (role - developer)
|
||||
<permissions instructions>
|
||||
Full access.
|
||||
Ask for approval.
|
||||
</permissions instructions>
|
||||
|
||||
"0ccde536dd8b4cfebb1df573f679dfe86b5718e3" -> "d96f228104cb899a8d3788b08e1d64b3bbb6ac84" (role - developer)
|
||||
<permissions instructions>
|
||||
Read only.
|
||||
Approval policy is currently never. Do not provide the `sandbox_permissions` for any reason, commands will be rejected.
|
||||
</permissions instructions>
|
||||
|
||||
Unknown -> "0ccde536dd8b4cfebb1df573f679dfe86b5718e3" (role - developer)
|
||||
<permissions instructions>
|
||||
Read only.
|
||||
Ask for approval.
|
||||
</permissions instructions>
|
||||
@@ -53,6 +53,14 @@ impl ContextualUserFragment for TestFragment {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn world_state_hash_normalizes_crlf_line_endings() {
|
||||
assert_eq!(
|
||||
WorldStateHash::from_fragment(&TestFragment("line one\r\nline two".to_string())),
|
||||
WorldStateHash::from_fragment(&TestFragment("line one\nline two".to_string())),
|
||||
);
|
||||
}
|
||||
|
||||
struct DuplicateTestSection;
|
||||
|
||||
impl WorldStateSection for DuplicateTestSection {
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
use crate::context::ApprovalPromptContext;
|
||||
use crate::context::ContextualUserFragment;
|
||||
use crate::context::ModelSwitchInstructions;
|
||||
use crate::context::MultiAgentModeInstructions;
|
||||
use crate::context::PermissionsInstructions;
|
||||
use crate::context::PersonalitySpecInstructions;
|
||||
use crate::session::PreviousTurnSettings;
|
||||
use crate::session::turn_context::TurnContext;
|
||||
use codex_execpolicy::Policy;
|
||||
use codex_features::Feature;
|
||||
use codex_protocol::config_types::MultiAgentMode;
|
||||
use codex_protocol::config_types::Personality;
|
||||
use codex_protocol::models::ContentItem;
|
||||
@@ -15,52 +11,6 @@ use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::openai_models::ModelInfo;
|
||||
use codex_protocol::protocol::TurnContextItem;
|
||||
|
||||
fn build_permissions_update_item(
|
||||
previous: Option<&TurnContextItem>,
|
||||
next: &TurnContext,
|
||||
exec_policy: &Policy,
|
||||
) -> Option<String> {
|
||||
if !next.config.include_permissions_instructions {
|
||||
return None;
|
||||
}
|
||||
|
||||
let prev = previous?;
|
||||
if prev.permission_profile() == next.permission_profile()
|
||||
&& prev.approval_policy == next.approval_policy.value()
|
||||
&& prev.model == next.model_info.slug
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(
|
||||
PermissionsInstructions::from_permission_profile(
|
||||
&next.permission_profile,
|
||||
next.approval_policy.value(),
|
||||
ApprovalPromptContext::new(
|
||||
next.config.approvals_reviewer,
|
||||
next.model_info
|
||||
.model_messages
|
||||
.as_ref()
|
||||
.and_then(|messages| messages.approvals.as_ref()),
|
||||
next.model_info
|
||||
.model_messages
|
||||
.as_ref()
|
||||
.and_then(|messages| messages.permissions.as_ref()),
|
||||
),
|
||||
exec_policy,
|
||||
#[allow(deprecated)]
|
||||
&next.cwd,
|
||||
next.config
|
||||
.features
|
||||
.enabled(Feature::ExecPermissionApprovals),
|
||||
next.config
|
||||
.features
|
||||
.enabled(Feature::RequestPermissionsTool),
|
||||
)
|
||||
.render(),
|
||||
)
|
||||
}
|
||||
|
||||
fn build_multi_agent_mode_update_item(
|
||||
previous: Option<&TurnContextItem>,
|
||||
next: &TurnContext,
|
||||
@@ -185,7 +135,6 @@ pub(crate) fn build_settings_update_items(
|
||||
previous: Option<&TurnContextItem>,
|
||||
previous_turn_settings: Option<&PreviousTurnSettings>,
|
||||
next: &TurnContext,
|
||||
exec_policy: &Policy,
|
||||
personality_feature_enabled: bool,
|
||||
) -> Vec<ResponseItem> {
|
||||
// TODO(ccunningham): build_settings_update_items still does not cover every
|
||||
@@ -196,7 +145,6 @@ pub(crate) fn build_settings_update_items(
|
||||
// Keep model-switch instructions first so model-specific guidance is read before
|
||||
// any other context diffs on this turn.
|
||||
build_model_instructions_update_item(previous_turn_settings, next),
|
||||
build_permissions_update_item(previous, next, exec_policy),
|
||||
build_multi_agent_mode_update_item(previous, next),
|
||||
build_personality_update_item(previous, next, personality_feature_enabled),
|
||||
]
|
||||
|
||||
@@ -22,13 +22,11 @@ use crate::build_available_skills;
|
||||
use crate::compact;
|
||||
use crate::config::ManagedFeatures;
|
||||
use crate::config::resolve_tool_suggest_config_from_layer_stack;
|
||||
use crate::context::ApprovalPromptContext;
|
||||
use crate::context::ApprovedCommandPrefixSaved;
|
||||
use crate::context::AvailableSkillsInstructions;
|
||||
use crate::context::ContextualUserFragment;
|
||||
use crate::context::MultiAgentModeInstructions;
|
||||
use crate::context::NetworkRuleSaved;
|
||||
use crate::context::PermissionsInstructions;
|
||||
use crate::context::PersonalitySpecInstructions;
|
||||
use crate::context::RecommendedPluginsInstructions;
|
||||
use crate::context::world_state::WorldState;
|
||||
@@ -1702,18 +1700,16 @@ impl Session {
|
||||
) -> Vec<ResponseItem> {
|
||||
// TODO: Make context updates a pure diff of persisted previous/current TurnContextItem
|
||||
// state so replay/backtracking is deterministic. Runtime inputs that affect model-visible
|
||||
// context (exec policy, feature gates, previous-turn bridge) should be persisted
|
||||
// context (feature gates and the previous-turn bridge) should be persisted
|
||||
// state or explicit non-state replay events.
|
||||
let previous_turn_settings = {
|
||||
let state = self.state.lock().await;
|
||||
state.previous_turn_settings()
|
||||
};
|
||||
let exec_policy = self.services.exec_policy.current();
|
||||
crate::context_manager::updates::build_settings_update_items(
|
||||
reference_context_item,
|
||||
previous_turn_settings.as_ref(),
|
||||
current_context,
|
||||
exec_policy.as_ref(),
|
||||
self.features.enabled(Feature::Personality),
|
||||
)
|
||||
}
|
||||
@@ -3213,39 +3209,6 @@ impl Session {
|
||||
{
|
||||
developer_sections.push(model_switch_message);
|
||||
}
|
||||
if turn_context.config.include_permissions_instructions {
|
||||
developer_sections.push(
|
||||
PermissionsInstructions::from_permission_profile(
|
||||
&turn_context.permission_profile,
|
||||
turn_context.approval_policy.value(),
|
||||
ApprovalPromptContext::new(
|
||||
turn_context.config.approvals_reviewer,
|
||||
turn_context
|
||||
.model_info
|
||||
.model_messages
|
||||
.as_ref()
|
||||
.and_then(|messages| messages.approvals.as_ref()),
|
||||
turn_context
|
||||
.model_info
|
||||
.model_messages
|
||||
.as_ref()
|
||||
.and_then(|messages| messages.permissions.as_ref()),
|
||||
),
|
||||
self.services.exec_policy.current().as_ref(),
|
||||
#[allow(deprecated)]
|
||||
&turn_context.cwd,
|
||||
turn_context
|
||||
.config
|
||||
.features
|
||||
.enabled(Feature::ExecPermissionApprovals),
|
||||
turn_context
|
||||
.config
|
||||
.features
|
||||
.enabled(Feature::RequestPermissionsTool),
|
||||
)
|
||||
.render(),
|
||||
);
|
||||
}
|
||||
let separate_guardian_developer_message =
|
||||
crate::guardian::is_guardian_reviewer_source(&session_source);
|
||||
// Keep the guardian policy prompt out of the aggregated developer bundle so it
|
||||
|
||||
@@ -139,12 +139,21 @@ async fn record_initial_history_restores_world_state_baseline() {
|
||||
let (session, turn_context) = make_session_and_context().await;
|
||||
let turn_context = Arc::new(turn_context);
|
||||
let world_state = build_world_state_from_turn_context(&session, &turn_context).await;
|
||||
let rollout_items = completed_user_turn_rollout(
|
||||
turn_context.to_turn_context_item(),
|
||||
vec![RolloutItem::WorldState(WorldStateItem::full(
|
||||
world_state.snapshot().into_value(),
|
||||
))],
|
||||
);
|
||||
let expected_history = world_state
|
||||
.render_full()
|
||||
.into_iter()
|
||||
.map(ContextualUserFragment::into_boxed_response_item)
|
||||
.collect::<Vec<_>>();
|
||||
let mut world_state_items = expected_history
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(RolloutItem::ResponseItem)
|
||||
.collect::<Vec<_>>();
|
||||
world_state_items.push(RolloutItem::WorldState(WorldStateItem::full(
|
||||
world_state.snapshot().into_value(),
|
||||
)));
|
||||
let rollout_items =
|
||||
completed_user_turn_rollout(turn_context.to_turn_context_item(), world_state_items);
|
||||
|
||||
session
|
||||
.record_initial_history(InitialHistory::Resumed(ResumedHistory {
|
||||
@@ -158,7 +167,10 @@ async fn record_initial_history_restores_world_state_baseline() {
|
||||
.record_context_updates_and_set_reference_context_item(&step_context)
|
||||
.await;
|
||||
|
||||
assert_eq!(session.clone_history().await.raw_items(), &[]);
|
||||
assert_eq!(
|
||||
session.clone_history().await.raw_items(),
|
||||
expected_history.as_slice(),
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
+4
-3
@@ -8,6 +8,7 @@ Scenario: First request after fork when startup preserves the parent baseline, t
|
||||
00:message/developer:<PERMISSIONS_INSTRUCTIONS>
|
||||
01:message/user:<ENVIRONMENT_CONTEXT:cwd=<CWD>>
|
||||
02:message/user:fork seed
|
||||
03:message/developer:<PERMISSIONS_INSTRUCTIONS>
|
||||
04:message/developer:<collaboration_mode>Fork turn collaboration instructions.</collaboration_mode>
|
||||
05:message/user:after fork
|
||||
03:message/developer[2]:
|
||||
[01] <PERMISSIONS_INSTRUCTIONS>
|
||||
[02] <collaboration_mode>Fork turn collaboration instructions.</collaboration_mode>
|
||||
04:message/user:after fork
|
||||
@@ -8913,12 +8913,22 @@ async fn record_context_updates_and_set_reference_context_item_persists_baseline
|
||||
let previous_context_item = turn_context.to_turn_context_item();
|
||||
let previous_context = Arc::new(turn_context);
|
||||
let world_state = build_world_state_from_turn_context(&session, &previous_context).await;
|
||||
let retained_world_state = world_state
|
||||
.render_full()
|
||||
.into_iter()
|
||||
.map(ContextualUserFragment::into_boxed_response_item)
|
||||
.collect::<Vec<_>>();
|
||||
session
|
||||
.replace_history(
|
||||
retained_world_state.clone(),
|
||||
Some(previous_context_item.clone()),
|
||||
)
|
||||
.await;
|
||||
let mut turn_context = Arc::try_unwrap(previous_context)
|
||||
.unwrap_or_else(|_| panic!("previous turn context should have no remaining references"));
|
||||
turn_context.sub_id = format!("{}-next", turn_context.sub_id);
|
||||
{
|
||||
let mut state = session.state.lock().await;
|
||||
state.set_reference_context_item(Some(previous_context_item.clone()));
|
||||
state
|
||||
.history
|
||||
.set_world_state_baseline(world_state.snapshot());
|
||||
@@ -8938,7 +8948,7 @@ async fn record_context_updates_and_set_reference_context_item_persists_baseline
|
||||
|
||||
assert_eq!(
|
||||
session.clone_history().await.raw_items().to_vec(),
|
||||
Vec::new()
|
||||
retained_world_state
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_value(session.reference_context_item().await)
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use super::session::Session;
|
||||
use super::step_context::StepContext;
|
||||
use crate::connectors;
|
||||
use crate::context::ApprovalPromptContext;
|
||||
use crate::context::world_state::AgentsMdState;
|
||||
use crate::context::world_state::AppsInstructionsState;
|
||||
use crate::context::world_state::CollaborationModeState;
|
||||
use crate::context::world_state::EnvironmentsInstructionsState;
|
||||
use crate::context::world_state::EnvironmentsState;
|
||||
use crate::context::world_state::PermissionsState;
|
||||
use crate::context::world_state::PluginsInstructionsState;
|
||||
use crate::context::world_state::RealtimeState;
|
||||
use crate::context::world_state::WorldState;
|
||||
@@ -40,6 +42,31 @@ impl Session {
|
||||
.as_deref(),
|
||||
));
|
||||
world_state.add_section(AgentsMdState::new(step_context.loaded_agents_md.as_deref()));
|
||||
if turn_context.config.include_permissions_instructions {
|
||||
let permission_profile = turn_context.permission_profile();
|
||||
let model_messages = turn_context.model_info.model_messages.as_ref();
|
||||
let exec_policy = self.services.exec_policy.current();
|
||||
world_state.add_section(PermissionsState::new(
|
||||
&permission_profile,
|
||||
turn_context.approval_policy.value(),
|
||||
ApprovalPromptContext::new(
|
||||
turn_context.config.approvals_reviewer,
|
||||
model_messages.and_then(|messages| messages.approvals.as_ref()),
|
||||
model_messages.and_then(|messages| messages.permissions.as_ref()),
|
||||
),
|
||||
exec_policy.as_ref(),
|
||||
#[allow(deprecated)]
|
||||
&turn_context.cwd,
|
||||
turn_context
|
||||
.config
|
||||
.features
|
||||
.enabled(Feature::ExecPermissionApprovals),
|
||||
turn_context
|
||||
.config
|
||||
.features
|
||||
.enabled(Feature::RequestPermissionsTool),
|
||||
));
|
||||
}
|
||||
if turn_context.config.include_collaboration_mode_instructions
|
||||
&& let Some(collaboration_mode) =
|
||||
CollaborationModeState::from_collaboration_mode(&turn_context.collaboration_mode())
|
||||
|
||||
Reference in new issue
Block a user