mirror of
https://github.com/openai/codex.git
synced 2026-11-08 20:40:33 +00:00
## Why `update_goal` only accepted `complete` and `blocked`, preventing the agent from pausing a goal in response to an explicit user request. ## What changed - Accept `paused` and account for final goal progress when pausing, with budget limits taking precedence. - Update tool instructions and goal prompts to allow pauses only at the user's explicit request, report the returned status, and stop goal work. A later resume revokes the pause request. ## Testing Extend coverage for pause accounting, budget-limit precedence, rejection of resume and system-limit statuses, and preservation of a tool-paused goal when resuming a thread. GitOrigin-RevId: c3c15a51f848ce6eb65854d51b1a1bc75bb456a7
95 lines
4.7 KiB
Rust
95 lines
4.7 KiB
Rust
//! Responses API tool definitions for persisted thread goals.
|
|
|
|
use codex_tools::JsonSchema;
|
|
use codex_tools::ResponsesApiTool;
|
|
use codex_tools::ToolSpec;
|
|
use serde_json::json;
|
|
use std::collections::BTreeMap;
|
|
|
|
pub const GET_GOAL_TOOL_NAME: &str = "get_goal";
|
|
pub const CREATE_GOAL_TOOL_NAME: &str = "create_goal";
|
|
pub const UPDATE_GOAL_TOOL_NAME: &str = "update_goal";
|
|
|
|
pub fn create_get_goal_tool() -> ToolSpec {
|
|
ToolSpec::Function(ResponsesApiTool {
|
|
name: GET_GOAL_TOOL_NAME.to_string(),
|
|
description: "Get the current goal for this thread, including status, budgets, token and elapsed-time usage, and remaining token budget."
|
|
.to_string(),
|
|
strict: false,
|
|
defer_loading: None,
|
|
parameters: JsonSchema::object(BTreeMap::new(), Some(Vec::new()), Some(false.into())),
|
|
output_schema: None,
|
|
})
|
|
}
|
|
|
|
pub fn create_create_goal_tool() -> ToolSpec {
|
|
let properties = BTreeMap::from([
|
|
(
|
|
"objective".to_string(),
|
|
JsonSchema::string(Some(
|
|
"Required. The concrete objective to start pursuing. This starts a new active goal when no goal exists or replaces the current goal when it is complete."
|
|
.to_string(),
|
|
)),
|
|
),
|
|
(
|
|
"token_budget".to_string(),
|
|
JsonSchema::integer(Some(
|
|
"Positive token budget for the new goal. Omit unless explicitly requested."
|
|
.to_string(),
|
|
)),
|
|
),
|
|
]);
|
|
|
|
ToolSpec::Function(ResponsesApiTool {
|
|
name: CREATE_GOAL_TOOL_NAME.to_string(),
|
|
description: format!(
|
|
r#"Create a goal only when explicitly requested by the user or system/developer instructions; do not infer goals from ordinary tasks.
|
|
Set token_budget only when an explicit token budget is requested. Fails if an unfinished goal exists; use {UPDATE_GOAL_TOOL_NAME} only for status."#
|
|
),
|
|
strict: false,
|
|
defer_loading: None,
|
|
parameters: JsonSchema::object(
|
|
properties,
|
|
/*required*/ Some(vec!["objective".to_string()]),
|
|
Some(false.into()),
|
|
),
|
|
output_schema: None,
|
|
})
|
|
}
|
|
|
|
pub fn create_update_goal_tool() -> ToolSpec {
|
|
let properties = BTreeMap::from([(
|
|
"status".to_string(),
|
|
JsonSchema::string_enum(
|
|
vec![json!("complete"), json!("blocked"), json!("paused")],
|
|
Some(
|
|
"Required. `paused` requires an explicit user request. Set to `complete` only when the objective is achieved and no required work remains. Set to `blocked` only after the same blocking condition has recurred for at least three consecutive goal turns and the agent is at an impasse. After a previously blocked goal is resumed, the resumed run starts a fresh blocked audit."
|
|
.to_string(),
|
|
),
|
|
),
|
|
)]);
|
|
|
|
ToolSpec::Function(ResponsesApiTool {
|
|
name: UPDATE_GOAL_TOOL_NAME.to_string(),
|
|
description: r#"Update the existing goal.
|
|
Set status to `paused` only at the user's explicit request to pause this goal, never on your own initiative. Ask if unclear; a later resume revokes that request. Report the returned status and stop goal work. Budget limits take precedence over pausing.
|
|
Set status to `complete` only when the objective has actually been achieved and no required work remains.
|
|
Set status to `blocked` only when the same blocking condition has repeated for at least three consecutive goal turns, counting the original/user-triggered turn and any automatic continuations, and the agent cannot make meaningful progress without user input or an external-state change.
|
|
If the user resumes a goal that was previously marked `blocked`, treat the resumed run as a fresh blocked audit. If the same blocking condition then repeats for at least three consecutive resumed goal turns, set status to `blocked` again.
|
|
Once the blocked threshold is satisfied, do not keep reporting that you are still blocked while leaving the goal active; set status to `blocked`.
|
|
Do not use `blocked` merely because the work is hard, slow, uncertain, incomplete, or would benefit from clarification.
|
|
Do not mark a goal complete merely because its budget is nearly exhausted or because you are stopping work.
|
|
You cannot use this tool to resume, budget-limit, or usage-limit a goal; those status changes are controlled by the user or system.
|
|
When marking a budgeted goal achieved with status `complete`, report the final token usage from the tool result to the user."#
|
|
.to_string(),
|
|
strict: false,
|
|
defer_loading: None,
|
|
parameters: JsonSchema::object(
|
|
properties,
|
|
/*required*/ Some(vec!["status".to_string()]),
|
|
Some(false.into()),
|
|
),
|
|
output_schema: None,
|
|
})
|
|
}
|