Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 8 additions & 13 deletions codex-rs/core/src/codex_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use codex_protocol::mcp::CallToolResult;
use codex_protocol::models::ActivePermissionProfile;
use codex_protocol::models::ContentItem;
use codex_protocol::models::PermissionProfile;
use codex_protocol::models::ResponseInputItem;
use codex_protocol::models::ResponseItem;
use codex_protocol::openai_models::ReasoningEffort;
use codex_protocol::protocol::AdditionalContextEntry;
Expand Down Expand Up @@ -265,20 +264,16 @@ impl CodexThread {
.await
}

/// Injects hidden model-visible items into the currently active turn.
/// Injects model-visible items into the currently active turn.
///
/// This is the runtime-owned counterpart to user-facing `steer_input`.
/// This is the thread-level bridge to `Session::inject_if_running` for
/// callers that only hold a `CodexThread`.
/// It returns the unchanged items when this thread has no active turn.
pub async fn inject_response_items_into_active_turn(
pub async fn inject_if_running(
&self,
items: Vec<ResponseInputItem>,
) -> Result<(), Vec<ResponseInputItem>> {
let response_items = items.iter().cloned().map(ResponseItem::from).collect();
self.codex
.session
.inject_if_running(response_items)
.await
.map_err(|_| items)
items: Vec<ResponseItem>,
) -> Result<(), Vec<ResponseItem>> {
self.codex.session.inject_if_running(items).await
}

pub async fn set_app_server_client_info(
Expand Down Expand Up @@ -396,7 +391,7 @@ impl CodexThread {
.await;
}

/// Append raw Responses API items to the thread's model-visible history.
/// Record raw Responses API items without starting a new turn.
pub async fn inject_response_items(&self, items: Vec<ResponseItem>) -> CodexResult<()> {
if items.is_empty() {
return Err(CodexErr::InvalidRequest(
Expand Down
10 changes: 3 additions & 7 deletions codex-rs/ext/goal/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::sync::atomic::Ordering;

use codex_core::ThreadManager;
use codex_protocol::ThreadId;
use codex_protocol::models::ResponseInputItem;
use codex_protocol::models::ResponseItem;
use codex_protocol::protocol::ThreadGoal;

use crate::accounting::BudgetLimitedGoalDisposition;
Expand Down Expand Up @@ -275,7 +275,7 @@ impl GoalRuntimeHandle {
Ok(())
}

pub(crate) async fn inject_active_turn_steering(&self, item: ResponseInputItem) {
pub(crate) async fn inject_active_turn_steering(&self, item: ResponseItem) {
let Some(thread_manager) = self.inner.thread_manager.upgrade() else {
tracing::debug!("skipping goal steering because thread manager is unavailable");
return;
Expand All @@ -284,11 +284,7 @@ impl GoalRuntimeHandle {
tracing::debug!("skipping goal steering because live thread is unavailable");
return;
};
if thread
.inject_response_items_into_active_turn(vec![item])
.await
.is_err()
{
if thread.inject_if_running(vec![item]).await.is_err() {
Comment thread
jif-oai marked this conversation as resolved.
tracing::debug!("skipping goal steering because no turn is active");
}
}
Expand Down
14 changes: 8 additions & 6 deletions codex-rs/ext/goal/src/steering.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
use codex_core::context::ContextualUserFragment;
use codex_core::context::InternalContextSource;
use codex_core::context::InternalModelContextFragment;
use codex_protocol::models::ResponseInputItem;
use codex_protocol::models::ResponseItem;
use codex_protocol::protocol::ThreadGoal;

pub(crate) fn budget_limit_steering_item(goal: &ThreadGoal) -> ResponseInputItem {
pub(crate) fn budget_limit_steering_item(goal: &ThreadGoal) -> ResponseItem {
goal_context_input_item(budget_limit_prompt(goal))
}

pub(crate) fn objective_updated_steering_item(goal: &ThreadGoal) -> ResponseInputItem {
pub(crate) fn objective_updated_steering_item(goal: &ThreadGoal) -> ResponseItem {
goal_context_input_item(objective_updated_prompt(goal))
}

fn goal_context_input_item(prompt: String) -> ResponseInputItem {
InternalModelContextFragment::new(InternalContextSource::from_static("goal"), prompt)
.into_response_input_item()
fn goal_context_input_item(prompt: String) -> ResponseItem {
ContextualUserFragment::into(InternalModelContextFragment::new(
InternalContextSource::from_static("goal"),
prompt,
))
}

fn budget_limit_prompt(goal: &ThreadGoal) -> String {
Expand Down
Loading