mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Gate goal tools by thread eligibility (#24925)
## Why Goal tools create and update goal state for a persistent thread. The extension was only checking whether goals were enabled before advertising those tools, which meant they could be surfaced in contexts that should not receive thread goal controls: ephemeral threads without persistent thread state and review subagents. Those sessions can still run the goal extension lifecycle, but the thread tools should only be visible when the current thread can safely use them. ## What changed - Adds a `GoalRuntimeConfig` that separates goal enablement from whether goal tools are available for the current thread. - Computes tool eligibility on thread start from `persistent_thread_state_available` and `SessionSource`, hiding tools for review subagents. - Uses `GoalRuntimeHandle::tools_visible()` when contributing thread tools so enabled runtime state does not automatically imply tool exposure. - Adds backend coverage for hiding goal tools on ephemeral threads and review subagents. ## Testing - Added `goal_tools_hidden_for_ephemeral_threads`. - Added `goal_tools_hidden_for_review_subagents`.
This commit is contained in:
1 parent
bd2a732923
commit
e426d48f6d
3 files changed
+79
-6
No files matched your search
@@ -22,6 +22,8 @@ use codex_extension_api::TurnStartInput;
|
||||
use codex_extension_api::TurnStopInput;
|
||||
use codex_otel::MetricsClient;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::SubAgentSource;
|
||||
use codex_protocol::protocol::ThreadGoalStatus;
|
||||
use codex_protocol::protocol::TokenUsageInfo;
|
||||
|
||||
@@ -29,6 +31,7 @@ use crate::accounting::BudgetLimitedGoalDisposition;
|
||||
use crate::accounting::GoalAccountingState;
|
||||
use crate::events::GoalEventEmitter;
|
||||
use crate::metrics::GoalMetrics;
|
||||
use crate::runtime::GoalRuntimeConfig;
|
||||
use crate::runtime::GoalRuntimeHandle;
|
||||
use crate::spec::UPDATE_GOAL_TOOL_NAME;
|
||||
use crate::steering::budget_limit_steering_item;
|
||||
@@ -85,6 +88,11 @@ where
|
||||
{
|
||||
async fn on_thread_start(&self, input: ThreadStartInput<'_, C>) {
|
||||
let enabled = (self.goals_enabled)(input.config);
|
||||
let tools_available_for_thread = input.persistent_thread_state_available
|
||||
&& !matches!(
|
||||
input.session_source,
|
||||
SessionSource::SubAgent(SubAgentSource::Review)
|
||||
);
|
||||
input
|
||||
.thread_store
|
||||
.insert(GoalExtensionConfig::from_enabled(enabled));
|
||||
@@ -102,7 +110,10 @@ where
|
||||
self.metrics.clone(),
|
||||
self.thread_manager.clone(),
|
||||
accounting_state,
|
||||
enabled,
|
||||
GoalRuntimeConfig {
|
||||
enabled,
|
||||
tools_available_for_thread,
|
||||
},
|
||||
)
|
||||
});
|
||||
runtime.set_enabled(enabled);
|
||||
@@ -330,7 +341,7 @@ where
|
||||
let Some(runtime) = goal_runtime_handle(thread_store) else {
|
||||
return Vec::new();
|
||||
};
|
||||
if !runtime.is_enabled() {
|
||||
if !runtime.tools_visible() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user