diff --git a/lib/components/fabro-agent/src/cli.rs b/lib/components/fabro-agent/src/cli.rs index 2d362f8f7..a9d3d5c1e 100644 --- a/lib/components/fabro-agent/src/cli.rs +++ b/lib/components/fabro-agent/src/cli.rs @@ -544,7 +544,7 @@ async fn run_with_args_and_client_and_catalog_styled( &model, Arc::clone(&catalog), ); - let profile_builder = if profile_kind == AgentProfileKind::Gpt56 { + let profile_builder = if profile_kind.uses_codex_core_tools() { profile_builder } else { profile_builder.with_web_fetch_summarizer(Some(build_summarizer( diff --git a/lib/components/fabro-agent/src/config.rs b/lib/components/fabro-agent/src/config.rs index f660334d8..b23c9b89c 100644 --- a/lib/components/fabro-agent/src/config.rs +++ b/lib/components/fabro-agent/src/config.rs @@ -139,9 +139,10 @@ impl NativeToolOptions { AgentProfileKind::Kimi => 60_000, // Codex's `shell_command` documents a 10s default, which is // already fabro's, so GPT-5.6 budgets against the same number. - AgentProfileKind::OpenAi | AgentProfileKind::Gemini | AgentProfileKind::Gpt56 => { - defaults.default_command_timeout_ms - } + AgentProfileKind::OpenAi + | AgentProfileKind::Gemini + | AgentProfileKind::Gpt56 + | AgentProfileKind::Gpt6 => defaults.default_command_timeout_ms, }; Self { default_command_timeout_ms, diff --git a/lib/components/fabro-agent/src/memory.rs b/lib/components/fabro-agent/src/memory.rs index 6e8b34beb..fe34b767f 100644 --- a/lib/components/fabro-agent/src/memory.rs +++ b/lib/components/fabro-agent/src/memory.rs @@ -34,7 +34,7 @@ pub async fn discover_memory( AgentProfileKind::Anthropic | AgentProfileKind::Claude5 => { vec!["AGENTS.md", "CLAUDE.md"] } - AgentProfileKind::OpenAi | AgentProfileKind::Gpt56 => { + AgentProfileKind::OpenAi | AgentProfileKind::Gpt56 | AgentProfileKind::Gpt6 => { vec!["AGENTS.md", ".codex/instructions.md"] } AgentProfileKind::Gemini => vec!["AGENTS.md", "GEMINI.md"], diff --git a/lib/components/fabro-agent/src/profiles/mod.rs b/lib/components/fabro-agent/src/profiles/mod.rs index 9b7897394..ed5204331 100644 --- a/lib/components/fabro-agent/src/profiles/mod.rs +++ b/lib/components/fabro-agent/src/profiles/mod.rs @@ -104,7 +104,7 @@ impl AgentProfileBuilder { /// `web_fetch` discard it instead of retaining an unused LLM client. #[must_use] pub fn with_web_fetch_summarizer(mut self, summarizer: Option) -> Self { - if self.profile_kind != AgentProfileKind::Gpt56 { + if !self.profile_kind.uses_codex_core_tools() { self.summarizer = summarizer; } self @@ -115,7 +115,7 @@ impl AgentProfileBuilder { let model = self.model.as_str(); let deps = ProfileDeps { options: self.native_tool_options.clone(), - summarizer: if self.profile_kind == AgentProfileKind::Gpt56 { + summarizer: if self.profile_kind.uses_codex_core_tools() { None } else { self.summarizer.clone() @@ -147,7 +147,7 @@ impl AgentProfileBuilder { .with_provider_id(self.provider_id.clone()) .with_catalog(Arc::clone(&self.catalog)), ), - AgentProfileKind::Gpt56 => Box::new( + AgentProfileKind::Gpt56 | AgentProfileKind::Gpt6 => Box::new( Gpt56Profile::with_native_tools(model, &deps) .with_route(self.provider_id.clone(), Arc::clone(&self.catalog)), ), diff --git a/lib/components/fabro-agent/src/question_tools.rs b/lib/components/fabro-agent/src/question_tools.rs index 94c8bea44..4a7e0d8f8 100644 --- a/lib/components/fabro-agent/src/question_tools.rs +++ b/lib/components/fabro-agent/src/question_tools.rs @@ -194,8 +194,8 @@ pub fn is_question_tool(name: &str) -> bool { pub fn register_question_tools(profile_kind: AgentProfileKind, registry: &mut ToolRegistry) { match profile_kind { - // Codex names this tool `request_user_input` for GPT-5.6 too. - AgentProfileKind::OpenAi | AgentProfileKind::Gpt56 => { + // Codex names this tool `request_user_input` for GPT-5.6 and GPT-6 too. + AgentProfileKind::OpenAi | AgentProfileKind::Gpt56 | AgentProfileKind::Gpt6 => { registry.register(make_openai_question_tool()); } // Kimi Code names this tool `AskUserQuestion` with the same diff --git a/lib/foundation/fabro-types/src/agent_profile.rs b/lib/foundation/fabro-types/src/agent_profile.rs index 7dbe74fa2..991751ecf 100644 --- a/lib/foundation/fabro-types/src/agent_profile.rs +++ b/lib/foundation/fabro-types/src/agent_profile.rs @@ -1,8 +1,8 @@ -//! Agent profile vocabulary shared by the catalog policy and the agent. +//! Agent profile vocabulary shared by the catalog and the agent. //! //! The catalog records which profile a model should run under in its -//! `metadata.fabro.agent_profile` entry. This enum is the Rust spelling of -//! that value. +//! `metadata.agent.profile` entry, a namespace lithos-llm ships and Pebble +//! reads too. This enum is the Rust spelling of that value. use serde::{Deserialize, Serialize}; use strum::{Display, EnumString, IntoStaticStr, VariantArray}; @@ -47,6 +47,9 @@ pub enum AgentProfileKind { /// per provider, so other models on the `openai` provider keep /// [`Self::OpenAi`]. Gpt56, + /// GPT-6 models (Astra), which Codex drives with the same narrow tool + /// contract as GPT-5.6. Fabro runs them on the GPT-5.6 harness. + Gpt6, } impl AgentProfileKind { @@ -54,6 +57,14 @@ impl AgentProfileKind { pub fn as_str(self) -> &'static str { self.into() } + + /// Whether the profile runs Codex's narrow core tool set (a shell, a file + /// editor, and `update_plan`) instead of Fabro's dedicated read, + /// discovery, and fetch tools. + #[must_use] + pub fn uses_codex_core_tools(self) -> bool { + matches!(self, Self::Gpt56 | Self::Gpt6) + } } #[cfg(test)] @@ -76,6 +87,9 @@ mod tests { fn claude5_and_gpt56_use_their_catalog_spellings() { assert_eq!(AgentProfileKind::Claude5.as_str(), "claude-5"); assert_eq!(AgentProfileKind::Gpt56.as_str(), "gpt56"); + assert_eq!(AgentProfileKind::Gpt6.as_str(), "gpt6"); + assert!(AgentProfileKind::Gpt6.uses_codex_core_tools()); + assert!(!AgentProfileKind::OpenAi.uses_codex_core_tools()); assert_eq!(AgentProfileKind::OpenAi.as_str(), "openai"); } }