Add client-only web search result metadata

This commit is contained in:
Alexi Christakis
2026-07-07 19:20:41 -07:00
parent aaa30f79c2
commit 3c6ad5ea3d
39 changed files with 831 additions and 3 deletions
@@ -4511,6 +4511,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -5684,6 +5693,29 @@
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
},
"WindowsSandboxSetupCompletedNotification": {
"properties": {
"error": {
@@ -18357,6 +18357,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/v2/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -20829,6 +20838,29 @@
],
"type": "string"
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
},
"WebSearchToolConfig": {
"additionalProperties": false,
"properties": {
@@ -16136,6 +16136,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -18608,6 +18617,29 @@
],
"type": "string"
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
},
"WebSearchToolConfig": {
"additionalProperties": false,
"properties": {
@@ -1102,6 +1102,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -1524,6 +1533,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1102,6 +1102,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -1524,6 +1533,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1247,6 +1247,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -1799,6 +1808,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1775,6 +1775,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -2405,6 +2414,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1566,6 +1566,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -2196,6 +2205,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1566,6 +1566,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -2196,6 +2205,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1566,6 +1566,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -2196,6 +2205,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1775,6 +1775,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -2431,6 +2440,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1566,6 +1566,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -2196,6 +2205,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1775,6 +1775,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -2405,6 +2414,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1566,6 +1566,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -2196,6 +2205,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1566,6 +1566,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -2196,6 +2205,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1247,6 +1247,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -1799,6 +1808,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1247,6 +1247,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -1799,6 +1808,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -1247,6 +1247,15 @@
"query": {
"type": "string"
},
"results": {
"items": {
"$ref": "#/definitions/WebSearchResult"
},
"type": [
"array",
"null"
]
},
"type": {
"enum": [
"webSearch"
@@ -1799,6 +1808,29 @@
"type": "object"
}
]
},
"WebSearchResult": {
"properties": {
"snippet": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"url": {
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
}
},
"properties": {
@@ -25,6 +25,7 @@ import type { PatchApplyStatus } from "./PatchApplyStatus";
import type { SubAgentActivityKind } from "./SubAgentActivityKind";
import type { UserInput } from "./UserInput";
import type { WebSearchAction } from "./WebSearchAction";
import type { WebSearchResult } from "./WebSearchResult";
export type ThreadItem = { "type": "userMessage", id: string, clientId: string | null, content: Array<UserInput>, } | { "type": "hookPrompt", id: string, fragments: Array<HookPromptFragment>, } | { "type": "agentMessage", id: string, text: string, phase: MessagePhase | null, memoryCitation: MemoryCitation | null, } | { "type": "plan", id: string, text: string, } | { "type": "reasoning", id: string, summary: Array<string>, content: Array<string>, } | { "type": "commandExecution", id: string,
/**
@@ -105,4 +106,4 @@ reasoningEffort: ReasoningEffort | null,
/**
* Last known status of the target agents, when available.
*/
agentsStates: { [key in string]?: CollabAgentState }, } | { "type": "subAgentActivity", id: string, kind: SubAgentActivityKind, agentThreadId: string, agentPath: string, } | { "type": "webSearch", id: string, query: string, action: WebSearchAction | null, } | { "type": "imageView", id: string, path: LegacyAppPathString, } | { "type": "sleep", id: string, durationMs: number, } | { "type": "imageGeneration", id: string, status: string, revisedPrompt: string | null, result: string, savedPath?: AbsolutePathBuf, } | { "type": "enteredReviewMode", id: string, review: string, } | { "type": "exitedReviewMode", id: string, review: string, } | { "type": "contextCompaction", id: string, };
agentsStates: { [key in string]?: CollabAgentState }, } | { "type": "subAgentActivity", id: string, kind: SubAgentActivityKind, agentThreadId: string, agentPath: string, } | { "type": "webSearch", id: string, query: string, action: WebSearchAction | null, results: Array<WebSearchResult> | null, } | { "type": "imageView", id: string, path: LegacyAppPathString, } | { "type": "sleep", id: string, durationMs: number, } | { "type": "imageGeneration", id: string, status: string, revisedPrompt: string | null, result: string, savedPath?: AbsolutePathBuf, } | { "type": "enteredReviewMode", id: string, review: string, } | { "type": "exitedReviewMode", id: string, review: string, } | { "type": "contextCompaction", id: string, };
@@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type WebSearchResult = { url: string, title: string | null, snippet: string | null, };
@@ -499,6 +499,7 @@ export type { TurnsPage } from "./TurnsPage";
export type { UserInput } from "./UserInput";
export type { WarningNotification } from "./WarningNotification";
export type { WebSearchAction } from "./WebSearchAction";
export type { WebSearchResult } from "./WebSearchResult";
export type { WindowsSandboxReadiness } from "./WindowsSandboxReadiness";
export type { WindowsSandboxReadinessResponse } from "./WindowsSandboxReadinessResponse";
export type { WindowsSandboxSetupCompletedNotification } from "./WindowsSandboxSetupCompletedNotification";
@@ -22,6 +22,7 @@ use crate::protocol::v2::TurnItemsView;
use crate::protocol::v2::TurnStatus;
use crate::protocol::v2::UserInput;
use crate::protocol::v2::WebSearchAction;
use crate::protocol::v2::WebSearchResult;
use codex_protocol::items::parse_hook_prompt_message;
use codex_protocol::models::MessagePhase;
use codex_protocol::protocol::AgentReasoningEvent;
@@ -615,6 +616,7 @@ impl ThreadHistoryBuilder {
id: payload.call_id.clone(),
query: String::new(),
action: None,
results: None,
};
self.upsert_item_in_current_turn(item);
}
@@ -624,6 +626,10 @@ impl ThreadHistoryBuilder {
id: payload.call_id.clone(),
query: payload.query.clone(),
action: Some(WebSearchAction::from(payload.action.clone())),
results: payload
.results
.clone()
.map(|results| results.into_iter().map(WebSearchResult::from).collect()),
};
self.upsert_item_in_current_turn(item);
}
@@ -1556,6 +1562,7 @@ mod tests {
use codex_protocol::items::SleepItem as CoreSleepItem;
use codex_protocol::items::TurnItem as CoreTurnItem;
use codex_protocol::items::UserMessageItem as CoreUserMessageItem;
use codex_protocol::items::WebSearchResult as CoreWebSearchResult;
use codex_protocol::items::build_hook_prompt_message;
use codex_protocol::mcp::CallToolResult;
use codex_protocol::models::ImageDetail;
@@ -2443,6 +2450,11 @@ mod tests {
query: Some("codex".into()),
queries: None,
},
results: Some(vec![CoreWebSearchResult {
url: "https://example.com/codex".into(),
title: Some("Codex".into()),
snippet: Some("Codex documentation".into()),
}]),
}),
EventMsg::ExecCommandEnd(ExecCommandEndEvent {
call_id: "exec-1".into(),
@@ -2499,6 +2511,11 @@ mod tests {
query: Some("codex".into()),
queries: None,
}),
results: Some(vec![WebSearchResult {
url: "https://example.com/codex".into(),
title: Some("Codex".into()),
snippet: Some("Codex documentation".into()),
}]),
}
);
assert_eq!(
@@ -3917,6 +3934,7 @@ mod tests {
query: Some("codex".into()),
queries: None,
},
results: None,
}),
));
@@ -3932,6 +3950,7 @@ mod tests {
query: Some("codex".into()),
queries: None,
}),
results: None,
},
}],
changed_turns: Vec::new(),
@@ -4052,6 +4071,7 @@ mod tests {
query: Some("codex".into()),
queries: None,
},
results: None,
})),
]);
@@ -4067,6 +4087,7 @@ mod tests {
query: Some("codex".into()),
queries: None,
}),
results: None,
},
}],
changed_turns: vec![ThreadHistoryTurnChange {
@@ -359,6 +359,7 @@ pub enum ThreadItem {
id: String,
query: String,
action: Option<WebSearchAction>,
results: Option<Vec<WebSearchResult>>,
},
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase")]
@@ -783,6 +784,25 @@ impl TryFrom<GuardianApprovalReviewAction> for CoreGuardianAssessmentAction {
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct WebSearchResult {
pub url: String,
pub title: Option<String>,
pub snippet: Option<String>,
}
impl From<codex_protocol::items::WebSearchResult> for WebSearchResult {
fn from(value: codex_protocol::items::WebSearchResult) -> Self {
Self {
url: value.url,
title: value.title,
snippet: value.snippet,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(tag = "type", rename_all = "camelCase")]
#[ts(tag = "type", rename_all = "camelCase")]
@@ -922,6 +942,9 @@ impl From<CoreTurnItem> for ThreadItem {
id: search.id,
query: search.query,
action: Some(WebSearchAction::from(search.action)),
results: search
.results
.map(|results| results.into_iter().map(Into::into).collect()),
},
CoreTurnItem::ImageView(image) => ThreadItem::ImageView {
id: image.id,
@@ -20,6 +20,7 @@ use codex_protocol::items::SubAgentActivityItem;
use codex_protocol::items::TurnItem;
use codex_protocol::items::UserMessageItem;
use codex_protocol::items::WebSearchItem;
use codex_protocol::items::WebSearchResult as CoreWebSearchResult;
use codex_protocol::mcp::CallToolResult;
use codex_protocol::mcp::McpServerInfo;
use codex_protocol::memory_citation::MemoryCitation as CoreMemoryCitation;
@@ -2777,6 +2778,11 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
query: Some("docs".to_string()),
queries: None,
},
results: Some(vec![CoreWebSearchResult {
url: "https://openai.com/docs".to_string(),
title: Some("OpenAI docs".to_string()),
snippet: Some("Documentation".to_string()),
}]),
});
assert_eq!(
@@ -2788,6 +2794,11 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
query: Some("docs".to_string()),
queries: None,
}),
results: Some(vec![WebSearchResult {
url: "https://openai.com/docs".to_string(),
title: Some("OpenAI docs".to_string()),
snippet: Some("Documentation".to_string()),
}]),
}
);