Skip to main content

gproxy_protocol/transform/
web_search.rs

1//! Codex search/browser commands over provider-hosted search and page tools.
2//! Commands and caller-supplied context travel together so URL and reference
3//! based followups can be interpreted by the model. Native encrypted browser
4//! state is not portable; unavailable commands are omitted, not fabricated.
5
6use crate::{
7    openai::{responses as r, web_search as w},
8    transform::TransformError,
9};
10
11pub fn to_generation(
12    input: w::WebSearchRequestBody,
13    model: String,
14) -> Result<r::GenerateContentRequestBody, TransformError> {
15    let mut request = r::GenerateContentRequestBody::builder().build();
16    request.model = Some(model);
17    request.instructions = Some(Some(
18        "Execute the supplied web commands using the available search and page-reading tools. Use input as prior context to resolve page/result references. search_query searches the web; open reads the referenced URL/page (respect lineno when available); find locates the pattern in that page; click follows the specified link from the referenced page. Use the other commands only when the available tools support them. Preserve query domains, recency, and requested response length where supported. Skip commands or opaque references that cannot be resolved; never invent page contents, link IDs, screenshots, or tool results. Return actual findings with source URLs, using URLs as reusable page references. Do not answer from memory in place of searching or reading.".into(),
19    ));
20    request.input = Some(r::Input::Text(serde_json::to_string(&serde_json::json!({
21        "commands": input.commands,
22        "input": input.input,
23        "settings": input.settings,
24    }))?));
25    request.tools = Some(vec![r::Tool::WebSearchLegacy(
26        r::WebSearchTool::builder().build(),
27    )]);
28    request.max_output_tokens = input
29        .max_output_tokens
30        .and_then(|value| i64::try_from(value).ok())
31        .map(Some);
32    request.stream = Some(Some(false));
33    Ok(request)
34}
35
36pub fn from_generation(
37    response: r::GenerateContentResponseBody,
38) -> Result<w::WebSearchResponseBody, TransformError> {
39    let output = response
40        .output
41        .into_iter()
42        .filter_map(|item| match item {
43            r::ResponseOutputItem::Message(message) => Some(message.content),
44            _ => None,
45        })
46        .flatten()
47        .filter_map(|content| match content {
48            r::OutputContent::Text(text) => Some(text.text),
49            _ => None,
50        })
51        .collect::<Vec<_>>()
52        .join("\n");
53    Ok(w::WebSearchResponseBody::builder(output).build())
54}