Merge upstream/main into subagent inbox injection

This commit is contained in:
Friel
2026-04-02 07:49:01 +00:00
487 changed files with 35270 additions and 25966 deletions

View File

@@ -98,6 +98,47 @@ pub enum GuardianAssessmentStatus {
Aborted,
}
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "snake_case")]
pub enum GuardianCommandSource {
Shell,
UnifiedExec,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
#[serde(tag = "type", rename_all = "snake_case")]
#[ts(tag = "type", rename_all = "snake_case")]
pub enum GuardianAssessmentAction {
Command {
source: GuardianCommandSource,
command: String,
cwd: PathBuf,
},
Execve {
source: GuardianCommandSource,
program: String,
argv: Vec<String>,
cwd: PathBuf,
},
ApplyPatch {
cwd: PathBuf,
files: Vec<PathBuf>,
},
NetworkAccess {
target: String,
host: String,
protocol: NetworkApprovalProtocol,
port: u16,
},
McpToolCall {
server: String,
tool_name: String,
connector_id: Option<String>,
connector_name: Option<String>,
tool_title: Option<String>,
},
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
pub struct NetworkPolicyAmendment {
pub host: String,
@@ -125,12 +166,8 @@ pub struct GuardianAssessmentEvent {
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional)]
pub rationale: Option<String>,
/// Canonical action payload that was reviewed. Included when available so
/// clients can render pending or resolved review state alongside the
/// reviewed request.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional)]
pub action: Option<JsonValue>,
/// Canonical action payload that was reviewed.
pub action: GuardianAssessmentAction,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
@@ -303,3 +340,62 @@ pub struct ApplyPatchApprovalRequestEvent {
#[serde(skip_serializing_if = "Option::is_none")]
pub grant_root: Option<PathBuf>,
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn guardian_assessment_action_deserializes_command_shape() {
let action: GuardianAssessmentAction = serde_json::from_value(serde_json::json!({
"type": "command",
"source": "shell",
"command": "rm -rf /tmp/guardian",
"cwd": "/tmp",
}))
.expect("guardian action");
assert_eq!(
action,
GuardianAssessmentAction::Command {
source: GuardianCommandSource::Shell,
command: "rm -rf /tmp/guardian".to_string(),
cwd: PathBuf::from("/tmp"),
}
);
}
#[cfg(unix)]
#[test]
fn guardian_assessment_action_round_trips_execve_shape() {
let value = serde_json::json!({
"type": "execve",
"source": "shell",
"program": "/bin/rm",
"argv": ["/usr/bin/rm", "-f", "/tmp/file.sqlite"],
"cwd": "/tmp",
});
let action: GuardianAssessmentAction =
serde_json::from_value(value.clone()).expect("guardian action");
assert_eq!(
serde_json::to_value(&action).expect("serialize guardian action"),
value
);
assert_eq!(
action,
GuardianAssessmentAction::Execve {
source: GuardianCommandSource::Shell,
program: "/bin/rm".to_string(),
argv: vec![
"/usr/bin/rm".to_string(),
"-f".to_string(),
"/tmp/file.sqlite".to_string(),
],
cwd: PathBuf::from("/tmp"),
}
);
}
}

View File

@@ -1,6 +1,9 @@
use codex_utils_absolute_path::AbsolutePathBuf;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use std::num::NonZeroU64;
use std::time::Duration;
use strum_macros::Display;
use strum_macros::EnumIter;
use ts_rs::TS;
@@ -261,6 +264,79 @@ pub enum ForcedLoginMethod {
Api,
}
const DEFAULT_PROVIDER_AUTH_TIMEOUT_MS: u64 = 5_000;
const DEFAULT_PROVIDER_AUTH_REFRESH_INTERVAL_MS: u64 = 300_000;
/// Configuration for obtaining a provider bearer token from a command.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct ModelProviderAuthInfo {
/// Command to execute. Bare names are resolved via `PATH`; paths are resolved against `cwd`.
pub command: String,
/// Command arguments.
#[serde(default)]
pub args: Vec<String>,
/// Maximum time to wait for the token command to exit successfully.
#[serde(default = "default_provider_auth_timeout_ms")]
pub timeout_ms: NonZeroU64,
/// Maximum age for the cached token before rerunning the command.
/// Set to `0` to disable proactive refresh and only rerun after a 401 retry path.
#[serde(default = "default_provider_auth_refresh_interval_ms")]
pub refresh_interval_ms: u64,
/// Working directory used when running the token command.
#[serde(default = "default_provider_auth_cwd")]
#[schemars(skip_serializing_if = "is_default_provider_auth_cwd")]
pub cwd: AbsolutePathBuf,
}
impl ModelProviderAuthInfo {
pub fn timeout(&self) -> Duration {
Duration::from_millis(self.timeout_ms.get())
}
pub fn refresh_interval(&self) -> Option<Duration> {
NonZeroU64::new(self.refresh_interval_ms).map(|value| Duration::from_millis(value.get()))
}
}
fn default_provider_auth_timeout_ms() -> NonZeroU64 {
non_zero_u64(
DEFAULT_PROVIDER_AUTH_TIMEOUT_MS,
"model_providers.<id>.auth.timeout_ms",
)
}
fn default_provider_auth_refresh_interval_ms() -> u64 {
DEFAULT_PROVIDER_AUTH_REFRESH_INTERVAL_MS
}
fn non_zero_u64(value: u64, field_name: &str) -> NonZeroU64 {
match NonZeroU64::new(value) {
Some(value) => value,
None => panic!("{field_name} must be non-zero"),
}
}
fn default_provider_auth_cwd() -> AbsolutePathBuf {
let deserializer = serde::de::value::StrDeserializer::<serde::de::value::Error>::new(".");
if let Ok(cwd) = AbsolutePathBuf::deserialize(deserializer) {
return cwd;
}
match AbsolutePathBuf::current_dir() {
Ok(cwd) => cwd,
Err(err) => panic!("provider auth cwd must resolve: {err}"),
}
}
fn is_default_provider_auth_cwd(path: &AbsolutePathBuf) -> bool {
path == &default_provider_auth_cwd()
}
/// Represents the trust level for a project directory.
/// This determines the approval policy and sandbox mode applied.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Display, JsonSchema, TS)]

View File

@@ -1,20 +0,0 @@
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use std::path::PathBuf;
use ts_rs::TS;
/// Base namespace for custom prompt slash commands (without trailing colon).
/// Example usage forms constructed in code:
/// - Command token after '/': `"{PROMPTS_CMD_PREFIX}:name"`
/// - Full slash prefix: `"/{PROMPTS_CMD_PREFIX}:"`
pub const PROMPTS_CMD_PREFIX: &str = "prompts";
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS)]
pub struct CustomPrompt {
pub name: String,
pub path: PathBuf,
pub content: String,
pub description: Option<String>,
pub argument_hint: Option<String>,
}

View File

@@ -5,7 +5,6 @@ pub use agent_path::AgentPath;
pub use thread_id::ThreadId;
pub mod approvals;
pub mod config_types;
pub mod custom_prompts;
pub mod dynamic_tools;
pub mod items;
pub mod mcp;

View File

@@ -23,7 +23,6 @@ use crate::config_types::Personality;
use crate::config_types::ReasoningSummary as ReasoningSummaryConfig;
use crate::config_types::ServiceTier;
use crate::config_types::WindowsSandboxLevel;
use crate::custom_prompts::CustomPrompt;
use crate::dynamic_tools::DynamicToolCallOutputContentItem;
use crate::dynamic_tools::DynamicToolCallRequest;
use crate::dynamic_tools::DynamicToolResponse;
@@ -65,8 +64,10 @@ pub use crate::approvals::ApplyPatchApprovalRequestEvent;
pub use crate::approvals::ElicitationAction;
pub use crate::approvals::ExecApprovalRequestEvent;
pub use crate::approvals::ExecPolicyAmendment;
pub use crate::approvals::GuardianAssessmentAction;
pub use crate::approvals::GuardianAssessmentEvent;
pub use crate::approvals::GuardianAssessmentStatus;
pub use crate::approvals::GuardianCommandSource;
pub use crate::approvals::GuardianRiskLevel;
pub use crate::approvals::NetworkApprovalContext;
pub use crate::approvals::NetworkApprovalProtocol;
@@ -474,9 +475,6 @@ pub enum Op {
/// enable/disable state) without restarting the thread.
ReloadUserConfig,
/// Request the list of available custom prompts.
ListCustomPrompts,
/// Request the list of skills for the provided `cwd` values or the session default.
ListSkills {
/// Working directories to scope repo skills discovery.
@@ -619,7 +617,6 @@ impl Op {
Self::ListMcpTools => "list_mcp_tools",
Self::RefreshMcpServers { .. } => "refresh_mcp_servers",
Self::ReloadUserConfig => "reload_user_config",
Self::ListCustomPrompts => "list_custom_prompts",
Self::ListSkills { .. } => "list_skills",
Self::Compact => "compact",
Self::DropMemories => "drop_memories",
@@ -1394,9 +1391,6 @@ pub enum EventMsg {
/// List of MCP tools available to the agent.
McpListToolsResponse(McpListToolsResponseEvent),
/// List of custom prompts available to the agent.
ListCustomPromptsResponse(ListCustomPromptsResponseEvent),
/// List of skills available to the agent.
ListSkillsResponse(ListSkillsResponseEvent),
@@ -3126,12 +3120,6 @@ impl fmt::Display for McpAuthStatus {
}
}
/// Response payload for `Op::ListCustomPrompts`.
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
pub struct ListCustomPromptsResponseEvent {
pub custom_prompts: Vec<CustomPrompt>,
}
/// Response payload for `Op::ListSkills`.
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
pub struct ListSkillsResponseEvent {