- Introduce websearch end to complement the begin - Moves the logic of adding the sebsearch tool to create_tools_json_for_responses_api - Making it the client responsibility to toggle the tool on or off - Other misc in #2371 post commit feedback - Show the query: <img width="1392" height="151" alt="image" src="https://github.com/user-attachments/assets/8457f1a6-f851-44cf-bcca-0d4fe460ce89" />
This commit is contained in:
@@ -129,7 +129,9 @@ pub(crate) async fn stream_chat_completions(
|
|||||||
"content": output,
|
"content": output,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
ResponseItem::Reasoning { .. } | ResponseItem::Other => {
|
ResponseItem::Reasoning { .. }
|
||||||
|
| ResponseItem::WebSearchCall { .. }
|
||||||
|
| ResponseItem::Other => {
|
||||||
// Omit these items from the conversation history.
|
// Omit these items from the conversation history.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -623,11 +625,8 @@ where
|
|||||||
Poll::Ready(Some(Ok(ResponseEvent::ReasoningSummaryPartAdded))) => {
|
Poll::Ready(Some(Ok(ResponseEvent::ReasoningSummaryPartAdded))) => {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Poll::Ready(Some(Ok(ResponseEvent::WebSearchCallBegin { .. }))) => {
|
Poll::Ready(Some(Ok(ResponseEvent::WebSearchCallBegin { call_id }))) => {
|
||||||
return Poll::Ready(Some(Ok(ResponseEvent::WebSearchCallBegin {
|
return Poll::Ready(Some(Ok(ResponseEvent::WebSearchCallBegin { call_id })));
|
||||||
call_id: String::new(),
|
|
||||||
query: None,
|
|
||||||
})));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,21 +160,7 @@ impl ModelClient {
|
|||||||
let store = prompt.store && auth_mode != Some(AuthMode::ChatGPT);
|
let store = prompt.store && auth_mode != Some(AuthMode::ChatGPT);
|
||||||
|
|
||||||
let full_instructions = prompt.get_full_instructions(&self.config.model_family);
|
let full_instructions = prompt.get_full_instructions(&self.config.model_family);
|
||||||
let mut tools_json = create_tools_json_for_responses_api(&prompt.tools)?;
|
let tools_json = create_tools_json_for_responses_api(&prompt.tools)?;
|
||||||
// ChatGPT backend expects the preview name for web search.
|
|
||||||
if auth_mode == Some(AuthMode::ChatGPT) {
|
|
||||||
for tool in &mut tools_json {
|
|
||||||
if let Some(map) = tool.as_object_mut()
|
|
||||||
&& map.get("type").and_then(|v| v.as_str()) == Some("web_search")
|
|
||||||
{
|
|
||||||
map.insert(
|
|
||||||
"type".to_string(),
|
|
||||||
serde_json::Value::String("web_search_preview".to_string()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let reasoning = create_reasoning_param_for_request(
|
let reasoning = create_reasoning_param_for_request(
|
||||||
&self.config.model_family,
|
&self.config.model_family,
|
||||||
self.effort,
|
self.effort,
|
||||||
@@ -607,11 +593,9 @@ async fn process_sse<S>(
|
|||||||
| "response.custom_tool_call_input.delta"
|
| "response.custom_tool_call_input.delta"
|
||||||
| "response.custom_tool_call_input.done" // also emitted as response.output_item.done
|
| "response.custom_tool_call_input.done" // also emitted as response.output_item.done
|
||||||
| "response.in_progress"
|
| "response.in_progress"
|
||||||
| "response.output_item.added"
|
| "response.output_text.done" => {}
|
||||||
| "response.output_text.done" => {
|
"response.output_item.added" => {
|
||||||
if event.kind == "response.output_item.added"
|
if let Some(item) = event.item.as_ref() {
|
||||||
&& let Some(item) = event.item.as_ref()
|
|
||||||
{
|
|
||||||
// Detect web_search_call begin and forward a synthetic event upstream.
|
// Detect web_search_call begin and forward a synthetic event upstream.
|
||||||
if let Some(ty) = item.get("type").and_then(|v| v.as_str())
|
if let Some(ty) = item.get("type").and_then(|v| v.as_str())
|
||||||
&& ty == "web_search_call"
|
&& ty == "web_search_call"
|
||||||
@@ -621,7 +605,7 @@ async fn process_sse<S>(
|
|||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.to_string();
|
.to_string();
|
||||||
let ev = ResponseEvent::WebSearchCallBegin { call_id, query: None };
|
let ev = ResponseEvent::WebSearchCallBegin { call_id };
|
||||||
if tx_event.send(Ok(ev)).await.is_err() {
|
if tx_event.send(Ok(ev)).await.is_err() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ pub enum ResponseEvent {
|
|||||||
ReasoningSummaryPartAdded,
|
ReasoningSummaryPartAdded,
|
||||||
WebSearchCallBegin {
|
WebSearchCallBegin {
|
||||||
call_id: String,
|
call_id: String,
|
||||||
query: Option<String>,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ use crate::protocol::Submission;
|
|||||||
use crate::protocol::TaskCompleteEvent;
|
use crate::protocol::TaskCompleteEvent;
|
||||||
use crate::protocol::TurnDiffEvent;
|
use crate::protocol::TurnDiffEvent;
|
||||||
use crate::protocol::WebSearchBeginEvent;
|
use crate::protocol::WebSearchBeginEvent;
|
||||||
|
use crate::protocol::WebSearchEndEvent;
|
||||||
use crate::rollout::RolloutRecorder;
|
use crate::rollout::RolloutRecorder;
|
||||||
use crate::safety::SafetyCheck;
|
use crate::safety::SafetyCheck;
|
||||||
use crate::safety::assess_command_safety;
|
use crate::safety::assess_command_safety;
|
||||||
@@ -120,6 +121,7 @@ use codex_protocol::models::ReasoningItemReasoningSummary;
|
|||||||
use codex_protocol::models::ResponseInputItem;
|
use codex_protocol::models::ResponseInputItem;
|
||||||
use codex_protocol::models::ResponseItem;
|
use codex_protocol::models::ResponseItem;
|
||||||
use codex_protocol::models::ShellToolCallParams;
|
use codex_protocol::models::ShellToolCallParams;
|
||||||
|
use codex_protocol::models::WebSearchAction;
|
||||||
|
|
||||||
// A convenience extension trait for acquiring mutex locks where poisoning is
|
// A convenience extension trait for acquiring mutex locks where poisoning is
|
||||||
// unrecoverable and should abort the program. This avoids scattered `.unwrap()`
|
// unrecoverable and should abort the program. This avoids scattered `.unwrap()`
|
||||||
@@ -1769,13 +1771,12 @@ async fn try_run_turn(
|
|||||||
.await?;
|
.await?;
|
||||||
output.push(ProcessedResponseItem { item, response });
|
output.push(ProcessedResponseItem { item, response });
|
||||||
}
|
}
|
||||||
ResponseEvent::WebSearchCallBegin { call_id, query } => {
|
ResponseEvent::WebSearchCallBegin { call_id } => {
|
||||||
let q = query.unwrap_or_else(|| "Searching Web...".to_string());
|
|
||||||
let _ = sess
|
let _ = sess
|
||||||
.tx_event
|
.tx_event
|
||||||
.send(Event {
|
.send(Event {
|
||||||
id: sub_id.to_string(),
|
id: sub_id.to_string(),
|
||||||
msg: EventMsg::WebSearchBegin(WebSearchBeginEvent { call_id, query: q }),
|
msg: EventMsg::WebSearchBegin(WebSearchBeginEvent { call_id }),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@@ -2074,6 +2075,17 @@ async fn handle_response_item(
|
|||||||
debug!("unexpected CustomToolCallOutput from stream");
|
debug!("unexpected CustomToolCallOutput from stream");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
ResponseItem::WebSearchCall { id, action, .. } => {
|
||||||
|
if let WebSearchAction::Search { query } = action {
|
||||||
|
let call_id = id.unwrap_or_else(|| "".to_string());
|
||||||
|
let event = Event {
|
||||||
|
id: sub_id.to_string(),
|
||||||
|
msg: EventMsg::WebSearchEnd(WebSearchEndEvent { call_id, query }),
|
||||||
|
};
|
||||||
|
sess.tx_event.send(event).await.ok();
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
ResponseItem::Other => None,
|
ResponseItem::Other => None,
|
||||||
};
|
};
|
||||||
Ok(output)
|
Ok(output)
|
||||||
|
|||||||
@@ -506,7 +506,6 @@ pub struct ProjectConfig {
|
|||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone, Default)]
|
#[derive(Deserialize, Debug, Clone, Default)]
|
||||||
pub struct ToolsToml {
|
pub struct ToolsToml {
|
||||||
// Renamed from `web_search_request`; keep alias for backwards compatibility.
|
|
||||||
#[serde(default, alias = "web_search_request")]
|
#[serde(default, alias = "web_search_request")]
|
||||||
pub web_search: Option<bool>,
|
pub web_search: Option<bool>,
|
||||||
|
|
||||||
@@ -672,7 +671,7 @@ impl Config {
|
|||||||
})?
|
})?
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
let shell_environment_policy = cfg.shell_environment_policy.clone().into();
|
let shell_environment_policy = cfg.shell_environment_policy.into();
|
||||||
|
|
||||||
let resolved_cwd = {
|
let resolved_cwd = {
|
||||||
use std::env;
|
use std::env;
|
||||||
@@ -693,7 +692,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let history = cfg.history.clone().unwrap_or_default();
|
let history = cfg.history.unwrap_or_default();
|
||||||
|
|
||||||
let tools_web_search_request = override_tools_web_search_request
|
let tools_web_search_request = override_tools_web_search_request
|
||||||
.or(cfg.tools.as_ref().and_then(|t| t.web_search))
|
.or(cfg.tools.as_ref().and_then(|t| t.web_search))
|
||||||
@@ -775,7 +774,7 @@ impl Config {
|
|||||||
codex_home,
|
codex_home,
|
||||||
history,
|
history,
|
||||||
file_opener: cfg.file_opener.unwrap_or(UriBasedFileOpener::VsCode),
|
file_opener: cfg.file_opener.unwrap_or(UriBasedFileOpener::VsCode),
|
||||||
tui: cfg.tui.clone().unwrap_or_default(),
|
tui: cfg.tui.unwrap_or_default(),
|
||||||
codex_linux_sandbox_exe,
|
codex_linux_sandbox_exe,
|
||||||
|
|
||||||
hide_agent_reasoning: cfg.hide_agent_reasoning.unwrap_or(false),
|
hide_agent_reasoning: cfg.hide_agent_reasoning.unwrap_or(false),
|
||||||
@@ -794,7 +793,7 @@ impl Config {
|
|||||||
model_verbosity: config_profile.model_verbosity.or(cfg.model_verbosity),
|
model_verbosity: config_profile.model_verbosity.or(cfg.model_verbosity),
|
||||||
chatgpt_base_url: config_profile
|
chatgpt_base_url: config_profile
|
||||||
.chatgpt_base_url
|
.chatgpt_base_url
|
||||||
.or(cfg.chatgpt_base_url.clone())
|
.or(cfg.chatgpt_base_url)
|
||||||
.unwrap_or("https://chatgpt.com/backend-api/".to_string()),
|
.unwrap_or("https://chatgpt.com/backend-api/".to_string()),
|
||||||
|
|
||||||
experimental_resume,
|
experimental_resume,
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ fn is_api_message(message: &ResponseItem) -> bool {
|
|||||||
| ResponseItem::CustomToolCallOutput { .. }
|
| ResponseItem::CustomToolCallOutput { .. }
|
||||||
| ResponseItem::LocalShellCall { .. }
|
| ResponseItem::LocalShellCall { .. }
|
||||||
| ResponseItem::Reasoning { .. } => true,
|
| ResponseItem::Reasoning { .. } => true,
|
||||||
ResponseItem::Other => false,
|
ResponseItem::WebSearchCall { .. } | ResponseItem::Other => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ pub(crate) enum OpenAiTool {
|
|||||||
Function(ResponsesApiTool),
|
Function(ResponsesApiTool),
|
||||||
#[serde(rename = "local_shell")]
|
#[serde(rename = "local_shell")]
|
||||||
LocalShell {},
|
LocalShell {},
|
||||||
#[serde(rename = "web_search")]
|
// TODO: Understand why we get an error on web_search although the API docs say it's supported.
|
||||||
|
// https://platform.openai.com/docs/guides/tools-web-search?api-mode=responses#:~:text=%7B%20type%3A%20%22web_search%22%20%7D%2C
|
||||||
|
#[serde(rename = "web_search_preview")]
|
||||||
WebSearch {},
|
WebSearch {},
|
||||||
#[serde(rename = "custom")]
|
#[serde(rename = "custom")]
|
||||||
Freeform(FreeformTool),
|
Freeform(FreeformTool),
|
||||||
@@ -335,12 +337,12 @@ pub fn create_tools_json_for_responses_api(
|
|||||||
let mut tools_json = Vec::new();
|
let mut tools_json = Vec::new();
|
||||||
|
|
||||||
for tool in tools {
|
for tool in tools {
|
||||||
tools_json.push(serde_json::to_value(tool)?);
|
let json = serde_json::to_value(tool)?;
|
||||||
|
tools_json.push(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(tools_json)
|
Ok(tools_json)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns JSON values that are compatible with Function Calling in the
|
/// Returns JSON values that are compatible with Function Calling in the
|
||||||
/// Chat Completions API:
|
/// Chat Completions API:
|
||||||
/// https://platform.openai.com/docs/guides/function-calling?api-mode=chat
|
/// https://platform.openai.com/docs/guides/function-calling?api-mode=chat
|
||||||
@@ -702,8 +704,8 @@ mod tests {
|
|||||||
"number_property": { "type": "number" },
|
"number_property": { "type": "number" },
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"string_property".to_string(),
|
"string_property",
|
||||||
"number_property".to_string()
|
"number_property",
|
||||||
],
|
],
|
||||||
"additionalProperties": Some(false),
|
"additionalProperties": Some(false),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ impl RolloutRecorder {
|
|||||||
| ResponseItem::CustomToolCall { .. }
|
| ResponseItem::CustomToolCall { .. }
|
||||||
| ResponseItem::CustomToolCallOutput { .. }
|
| ResponseItem::CustomToolCallOutput { .. }
|
||||||
| ResponseItem::Reasoning { .. } => filtered.push(item.clone()),
|
| ResponseItem::Reasoning { .. } => filtered.push(item.clone()),
|
||||||
ResponseItem::Other => {
|
ResponseItem::WebSearchCall { .. } | ResponseItem::Other => {
|
||||||
// These should never be serialized.
|
// These should never be serialized.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -199,7 +199,7 @@ impl RolloutRecorder {
|
|||||||
| ResponseItem::CustomToolCall { .. }
|
| ResponseItem::CustomToolCall { .. }
|
||||||
| ResponseItem::CustomToolCallOutput { .. }
|
| ResponseItem::CustomToolCallOutput { .. }
|
||||||
| ResponseItem::Reasoning { .. } => items.push(item),
|
| ResponseItem::Reasoning { .. } => items.push(item),
|
||||||
ResponseItem::Other => {}
|
ResponseItem::WebSearchCall { .. } | ResponseItem::Other => {}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("failed to parse item: {v:?}, error: {e}");
|
warn!("failed to parse item: {v:?}, error: {e}");
|
||||||
@@ -326,7 +326,7 @@ async fn rollout_writer(
|
|||||||
| ResponseItem::Reasoning { .. } => {
|
| ResponseItem::Reasoning { .. } => {
|
||||||
writer.write_line(&item).await?;
|
writer.write_line(&item).await?;
|
||||||
}
|
}
|
||||||
ResponseItem::Other => {}
|
ResponseItem::WebSearchCall { .. } | ResponseItem::Other => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ use codex_core::protocol::TaskCompleteEvent;
|
|||||||
use codex_core::protocol::TurnAbortReason;
|
use codex_core::protocol::TurnAbortReason;
|
||||||
use codex_core::protocol::TurnDiffEvent;
|
use codex_core::protocol::TurnDiffEvent;
|
||||||
use codex_core::protocol::WebSearchBeginEvent;
|
use codex_core::protocol::WebSearchBeginEvent;
|
||||||
|
use codex_core::protocol::WebSearchEndEvent;
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use owo_colors::Style;
|
use owo_colors::Style;
|
||||||
use shlex::try_join;
|
use shlex::try_join;
|
||||||
@@ -362,8 +363,9 @@ impl EventProcessor for EventProcessorWithHumanOutput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EventMsg::WebSearchBegin(WebSearchBeginEvent { call_id: _, query }) => {
|
EventMsg::WebSearchBegin(WebSearchBeginEvent { call_id: _ }) => {}
|
||||||
ts_println!(self, "🌐 {query}");
|
EventMsg::WebSearchEnd(WebSearchEndEvent { call_id: _, query }) => {
|
||||||
|
ts_println!(self, "🌐 Searched: {query}");
|
||||||
}
|
}
|
||||||
EventMsg::PatchApplyBegin(PatchApplyBeginEvent {
|
EventMsg::PatchApplyBegin(PatchApplyBeginEvent {
|
||||||
call_id,
|
call_id,
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ async fn run_codex_tool_session_inner(
|
|||||||
| EventMsg::PatchApplyEnd(_)
|
| EventMsg::PatchApplyEnd(_)
|
||||||
| EventMsg::TurnDiff(_)
|
| EventMsg::TurnDiff(_)
|
||||||
| EventMsg::WebSearchBegin(_)
|
| EventMsg::WebSearchBegin(_)
|
||||||
|
| EventMsg::WebSearchEnd(_)
|
||||||
| EventMsg::GetHistoryEntryResponse(_)
|
| EventMsg::GetHistoryEntryResponse(_)
|
||||||
| EventMsg::PlanUpdate(_)
|
| EventMsg::PlanUpdate(_)
|
||||||
| EventMsg::TurnAborted(_)
|
| EventMsg::TurnAborted(_)
|
||||||
|
|||||||
@@ -95,6 +95,22 @@ pub enum ResponseItem {
|
|||||||
call_id: String,
|
call_id: String,
|
||||||
output: String,
|
output: String,
|
||||||
},
|
},
|
||||||
|
// Emitted by the Responses API when the agent triggers a web search.
|
||||||
|
// Example payload (from SSE `response.output_item.done`):
|
||||||
|
// {
|
||||||
|
// "id":"ws_...",
|
||||||
|
// "type":"web_search_call",
|
||||||
|
// "status":"completed",
|
||||||
|
// "action": {"type":"search","query":"weather: San Francisco, CA"}
|
||||||
|
// }
|
||||||
|
WebSearchCall {
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
id: Option<String>,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
status: Option<String>,
|
||||||
|
action: WebSearchAction,
|
||||||
|
},
|
||||||
|
|
||||||
#[serde(other)]
|
#[serde(other)]
|
||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
@@ -162,6 +178,16 @@ pub struct LocalShellExecAction {
|
|||||||
pub user: Option<String>,
|
pub user: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(tag = "type", rename_all = "snake_case")]
|
||||||
|
pub enum WebSearchAction {
|
||||||
|
Search {
|
||||||
|
query: String,
|
||||||
|
},
|
||||||
|
#[serde(other)]
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde(tag = "type", rename_all = "snake_case")]
|
#[serde(tag = "type", rename_all = "snake_case")]
|
||||||
pub enum ReasoningItemReasoningSummary {
|
pub enum ReasoningItemReasoningSummary {
|
||||||
|
|||||||
@@ -443,6 +443,8 @@ pub enum EventMsg {
|
|||||||
|
|
||||||
WebSearchBegin(WebSearchBeginEvent),
|
WebSearchBegin(WebSearchBeginEvent),
|
||||||
|
|
||||||
|
WebSearchEnd(WebSearchEndEvent),
|
||||||
|
|
||||||
/// Notification that the server is about to execute a command.
|
/// Notification that the server is about to execute a command.
|
||||||
ExecCommandBegin(ExecCommandBeginEvent),
|
ExecCommandBegin(ExecCommandBeginEvent),
|
||||||
|
|
||||||
@@ -675,6 +677,11 @@ impl McpToolCallEndEvent {
|
|||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
pub struct WebSearchBeginEvent {
|
pub struct WebSearchBeginEvent {
|
||||||
pub call_id: String,
|
pub call_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct WebSearchEndEvent {
|
||||||
|
pub call_id: String,
|
||||||
pub query: String,
|
pub query: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ use codex_core::protocol::TokenUsage;
|
|||||||
use codex_core::protocol::TurnAbortReason;
|
use codex_core::protocol::TurnAbortReason;
|
||||||
use codex_core::protocol::TurnDiffEvent;
|
use codex_core::protocol::TurnDiffEvent;
|
||||||
use codex_core::protocol::WebSearchBeginEvent;
|
use codex_core::protocol::WebSearchBeginEvent;
|
||||||
|
use codex_core::protocol::WebSearchEndEvent;
|
||||||
use codex_protocol::parse_command::ParsedCommand;
|
use codex_protocol::parse_command::ParsedCommand;
|
||||||
use crossterm::event::KeyCode;
|
use crossterm::event::KeyCode;
|
||||||
use crossterm::event::KeyEvent;
|
use crossterm::event::KeyEvent;
|
||||||
@@ -358,9 +359,16 @@ impl ChatWidget {
|
|||||||
self.defer_or_handle(|q| q.push_mcp_end(ev), |s| s.handle_mcp_end_now(ev2));
|
self.defer_or_handle(|q| q.push_mcp_end(ev), |s| s.handle_mcp_end_now(ev2));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_web_search_begin(&mut self, ev: WebSearchBeginEvent) {
|
fn on_web_search_begin(&mut self, _ev: WebSearchBeginEvent) {
|
||||||
self.flush_answer_stream_with_separator();
|
self.flush_answer_stream_with_separator();
|
||||||
self.add_to_history(history_cell::new_web_search_call(ev.query));
|
}
|
||||||
|
|
||||||
|
fn on_web_search_end(&mut self, ev: WebSearchEndEvent) {
|
||||||
|
self.flush_answer_stream_with_separator();
|
||||||
|
self.add_to_history(history_cell::new_web_search_call(format!(
|
||||||
|
"Searched: {}",
|
||||||
|
ev.query
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_get_history_entry_response(
|
fn on_get_history_entry_response(
|
||||||
@@ -992,6 +1000,7 @@ impl ChatWidget {
|
|||||||
EventMsg::McpToolCallBegin(ev) => self.on_mcp_tool_call_begin(ev),
|
EventMsg::McpToolCallBegin(ev) => self.on_mcp_tool_call_begin(ev),
|
||||||
EventMsg::McpToolCallEnd(ev) => self.on_mcp_tool_call_end(ev),
|
EventMsg::McpToolCallEnd(ev) => self.on_mcp_tool_call_end(ev),
|
||||||
EventMsg::WebSearchBegin(ev) => self.on_web_search_begin(ev),
|
EventMsg::WebSearchBegin(ev) => self.on_web_search_begin(ev),
|
||||||
|
EventMsg::WebSearchEnd(ev) => self.on_web_search_end(ev),
|
||||||
EventMsg::GetHistoryEntryResponse(ev) => self.on_get_history_entry_response(ev),
|
EventMsg::GetHistoryEntryResponse(ev) => self.on_get_history_entry_response(ev),
|
||||||
EventMsg::McpListToolsResponse(ev) => self.on_list_mcp_tools(ev),
|
EventMsg::McpListToolsResponse(ev) => self.on_list_mcp_tools(ev),
|
||||||
EventMsg::ListCustomPromptsResponse(ev) => self.on_list_custom_prompts(ev),
|
EventMsg::ListCustomPromptsResponse(ev) => self.on_list_custom_prompts(ev),
|
||||||
|
|||||||
Reference in New Issue
Block a user