mirror of
https://github.com/openai/codex.git
synced 2026-04-24 06:35:50 +00:00
tui_app_server: handle hook prompt items
This commit is contained in:
@@ -111,7 +111,6 @@ use codex_protocol::ThreadId;
|
||||
use codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem as CoreDynamicToolCallOutputContentItem;
|
||||
use codex_protocol::dynamic_tools::DynamicToolResponse as CoreDynamicToolResponse;
|
||||
use codex_protocol::items::parse_hook_prompt_message;
|
||||
use codex_protocol::models::PermissionProfile as CorePermissionProfile;
|
||||
use codex_protocol::plan_tool::UpdatePlanArgs;
|
||||
use codex_protocol::protocol::ApplyPatchApprovalRequestEvent;
|
||||
use codex_protocol::protocol::CodexErrorInfo as CoreCodexErrorInfo;
|
||||
|
||||
@@ -85,8 +85,8 @@ fn detects_hook_prompt_fragment_and_roundtrips_escaping() {
|
||||
let ContentItem::InputText { text } = content_item else {
|
||||
panic!("expected input text content item");
|
||||
};
|
||||
let parsed = parse_visible_hook_prompt_message(None, content.as_slice())
|
||||
.expect("visible hook prompt");
|
||||
let parsed =
|
||||
parse_visible_hook_prompt_message(None, content.as_slice()).expect("visible hook prompt");
|
||||
assert_eq!(
|
||||
parsed.fragments,
|
||||
vec![HookPromptFragment {
|
||||
|
||||
@@ -241,10 +241,8 @@ pub fn build_hook_prompt_message(fragments: &[HookPromptFragment]) -> Option<Res
|
||||
let content = fragments
|
||||
.iter()
|
||||
.filter(|fragment| !fragment.hook_run_ids.is_empty())
|
||||
.map(|fragment| {
|
||||
ContentItem::InputText {
|
||||
text: serialize_hook_prompt_fragment(&fragment.text, &fragment.hook_run_ids),
|
||||
}
|
||||
.map(|fragment| ContentItem::InputText {
|
||||
text: serialize_hook_prompt_fragment(&fragment.text, &fragment.hook_run_ids),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -342,7 +340,10 @@ fn parse_hook_prompt_hook_run_ids(open_tag: &str) -> Option<Vec<String>> {
|
||||
parse_hook_prompt_attribute(open_tag, HOOK_PROMPT_RUN_IDS_ATTR)
|
||||
{
|
||||
let hook_run_ids = serde_json::from_str::<Vec<String>>(&encoded_hook_run_ids).ok()?;
|
||||
if hook_run_ids.iter().any(|hook_run_id| hook_run_id.trim().is_empty()) {
|
||||
if hook_run_ids
|
||||
.iter()
|
||||
.any(|hook_run_id| hook_run_id.trim().is_empty())
|
||||
{
|
||||
return None;
|
||||
}
|
||||
return Some(hook_run_ids);
|
||||
|
||||
@@ -615,6 +615,7 @@ fn thread_item_to_core(item: &ThreadItem) -> Option<TurnItem> {
|
||||
| ThreadItem::McpToolCall { .. }
|
||||
| ThreadItem::DynamicToolCall { .. }
|
||||
| ThreadItem::CollabAgentToolCall { .. }
|
||||
| ThreadItem::HookPrompt { .. }
|
||||
| ThreadItem::ImageView { .. }
|
||||
| ThreadItem::EnteredReviewMode { .. }
|
||||
| ThreadItem::ExitedReviewMode { .. } => {
|
||||
|
||||
@@ -987,6 +987,121 @@ fn session_configured_from_thread_response(
|
||||
})
|
||||
}
|
||||
|
||||
fn thread_initial_messages(
|
||||
thread_id: &ThreadId,
|
||||
turns: &[codex_app_server_protocol::Turn],
|
||||
show_raw_agent_reasoning: bool,
|
||||
) -> Option<Vec<EventMsg>> {
|
||||
let events: Vec<EventMsg> = turns
|
||||
.iter()
|
||||
.flat_map(|turn| turn_initial_messages(thread_id, turn, show_raw_agent_reasoning))
|
||||
.collect();
|
||||
(!events.is_empty()).then_some(events)
|
||||
}
|
||||
|
||||
fn turn_initial_messages(
|
||||
thread_id: &ThreadId,
|
||||
turn: &codex_app_server_protocol::Turn,
|
||||
show_raw_agent_reasoning: bool,
|
||||
) -> Vec<EventMsg> {
|
||||
turn.items
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter_map(app_server_thread_item_to_core)
|
||||
.flat_map(|item| match item {
|
||||
TurnItem::UserMessage(item) => vec![item.as_legacy_event()],
|
||||
TurnItem::Plan(item) => vec![EventMsg::ItemCompleted(ItemCompletedEvent {
|
||||
thread_id: *thread_id,
|
||||
turn_id: turn.id.clone(),
|
||||
item: TurnItem::Plan(item),
|
||||
})],
|
||||
item => item.as_legacy_events(show_raw_agent_reasoning),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn app_server_thread_item_to_core(item: codex_app_server_protocol::ThreadItem) -> Option<TurnItem> {
|
||||
match item {
|
||||
codex_app_server_protocol::ThreadItem::UserMessage { id, content } => {
|
||||
Some(TurnItem::UserMessage(UserMessageItem {
|
||||
id,
|
||||
content: content
|
||||
.into_iter()
|
||||
.map(codex_app_server_protocol::UserInput::into_core)
|
||||
.collect(),
|
||||
}))
|
||||
}
|
||||
codex_app_server_protocol::ThreadItem::AgentMessage { id, text, phase } => {
|
||||
Some(TurnItem::AgentMessage(AgentMessageItem {
|
||||
id,
|
||||
content: vec![AgentMessageContent::Text { text }],
|
||||
phase,
|
||||
}))
|
||||
}
|
||||
codex_app_server_protocol::ThreadItem::Plan { id, text } => {
|
||||
Some(TurnItem::Plan(PlanItem { id, text }))
|
||||
}
|
||||
codex_app_server_protocol::ThreadItem::Reasoning {
|
||||
id,
|
||||
summary,
|
||||
content,
|
||||
} => Some(TurnItem::Reasoning(ReasoningItem {
|
||||
id,
|
||||
summary_text: summary,
|
||||
raw_content: content,
|
||||
})),
|
||||
codex_app_server_protocol::ThreadItem::WebSearch { id, query, action } => {
|
||||
Some(TurnItem::WebSearch(WebSearchItem {
|
||||
id,
|
||||
query,
|
||||
action: app_server_web_search_action_to_core(action?)?,
|
||||
}))
|
||||
}
|
||||
codex_app_server_protocol::ThreadItem::ImageGeneration {
|
||||
id,
|
||||
status,
|
||||
revised_prompt,
|
||||
result,
|
||||
} => Some(TurnItem::ImageGeneration(ImageGenerationItem {
|
||||
id,
|
||||
status,
|
||||
revised_prompt,
|
||||
result,
|
||||
saved_path: None,
|
||||
})),
|
||||
codex_app_server_protocol::ThreadItem::ContextCompaction { id } => {
|
||||
Some(TurnItem::ContextCompaction(ContextCompactionItem { id }))
|
||||
}
|
||||
codex_app_server_protocol::ThreadItem::CommandExecution { .. }
|
||||
| codex_app_server_protocol::ThreadItem::FileChange { .. }
|
||||
| codex_app_server_protocol::ThreadItem::McpToolCall { .. }
|
||||
| codex_app_server_protocol::ThreadItem::DynamicToolCall { .. }
|
||||
| codex_app_server_protocol::ThreadItem::CollabAgentToolCall { .. }
|
||||
| codex_app_server_protocol::ThreadItem::HookPrompt { .. }
|
||||
| codex_app_server_protocol::ThreadItem::ImageView { .. }
|
||||
| codex_app_server_protocol::ThreadItem::EnteredReviewMode { .. }
|
||||
| codex_app_server_protocol::ThreadItem::ExitedReviewMode { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn app_server_web_search_action_to_core(
|
||||
action: codex_app_server_protocol::WebSearchAction,
|
||||
) -> Option<codex_protocol::models::WebSearchAction> {
|
||||
match action {
|
||||
codex_app_server_protocol::WebSearchAction::Search { query, queries } => {
|
||||
Some(codex_protocol::models::WebSearchAction::Search { query, queries })
|
||||
}
|
||||
codex_app_server_protocol::WebSearchAction::OpenPage { url } => {
|
||||
Some(codex_protocol::models::WebSearchAction::OpenPage { url })
|
||||
}
|
||||
codex_app_server_protocol::WebSearchAction::FindInPage { url, pattern } => {
|
||||
Some(codex_protocol::models::WebSearchAction::FindInPage { url, pattern })
|
||||
}
|
||||
codex_app_server_protocol::WebSearchAction::Other => {
|
||||
Some(codex_protocol::models::WebSearchAction::Other)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn app_server_rate_limit_snapshots_to_core(
|
||||
response: GetAccountRateLimitsResponse,
|
||||
) -> Vec<RateLimitSnapshot> {
|
||||
|
||||
Reference in New Issue
Block a user