Inject history notes hints into context windows (#40539)

## What changed

- Register the history-notes extension as a context contributor and fetch `thread_hint` from the configured history-notes backend.
- Add non-empty hints of at most 4,000 bytes to the context-window prompt, and omit hints when the request fails or the response is missing, empty, or oversized.
- Verify that app-server sessions use the native backend when `use_history_notes_extension` is enabled and retain the MCP bridge behavior when it is disabled.

## Testing

- Cover hint injection, request context, response validation, backend failures, and disabled-extension behavior in history-notes and app-server tests.

GitOrigin-RevId: 344a7bb79d962ea8b7c969f25b67a79423fc7fcc
This commit is contained in:
pmccrary-oai authored and copyberry committed 2026-08-25 04:05:38 +00:00
1 parent 3a469a297d
commit 2e4675919e
3 files changed
+249 -20

No files matched your search

@@ -2,9 +2,13 @@ use std::sync::Arc;
use codex_core::config::Config;
use codex_extension_api::ConfigContributor;
use codex_extension_api::ContentItemKind;
use codex_extension_api::ContextContributor;
use codex_extension_api::ExtensionData;
use codex_extension_api::ExtensionFuture;
use codex_extension_api::ExtensionRegistryBuilder;
use codex_extension_api::PromptFragment;
use codex_extension_api::PromptSlot;
use codex_extension_api::ThreadLifecycleContributor;
use codex_extension_api::ThreadStartInput;
use codex_extension_api::ToolCall;
@@ -13,11 +17,15 @@ use codex_extension_api::ToolExecutor;
use codex_login::AuthManager;
use codex_model_provider::create_model_provider;
use codex_protocol::AgentPath;
use serde_json::json;
use crate::backend::HistoryNotesBackend;
use crate::tools::HistoryNotesAction;
use crate::tools::HistoryNotesTool;
// Bound model context even when note paths are unusually long.
const MAX_THREAD_HINT_BYTES: usize = 4_000;
struct HistoryNotesExtension {
auth_manager: Arc<AuthManager>,
}
@@ -82,6 +90,46 @@ impl ConfigContributor<Config> for HistoryNotesExtension {
}
}
impl ContextContributor for HistoryNotesExtension {
fn contribute_thread_context<'a>(
&'a self,
session_store: &'a ExtensionData,
thread_store: &'a ExtensionData,
) -> ExtensionFuture<'a, Vec<PromptFragment>> {
Box::pin(async move {
let Some(config) = thread_store.get::<HistoryNotesExtensionConfig>() else {
return Vec::new();
};
let Some(identity) = thread_store.get::<HistoryNotesAgentIdentity>() else {
return Vec::new();
};
let Ok(result) = config
.backend
.call(
"alpha/notes/v2/thread_hint",
session_store.level_id(),
&identity.agent_name,
json!({}),
)
.await
else {
return Vec::new();
};
let Some(text) = result.get("text").and_then(serde_json::Value::as_str) else {
return Vec::new();
};
if text.is_empty() || text.len() > MAX_THREAD_HINT_BYTES {
return Vec::new();
}
vec![PromptFragment::new(
PromptSlot::ContextWindow,
text,
ContentItemKind("notes.thread_hint".to_string()),
)]
})
}
}
impl ToolContributor for HistoryNotesExtension {
fn tools(
&self,
@@ -114,5 +162,6 @@ pub fn install(registry: &mut ExtensionRegistryBuilder<Config>, auth_manager: Ar
let extension = Arc::new(HistoryNotesExtension { auth_manager });
registry.thread_lifecycle_contributor(extension.clone());
registry.config_contributor(extension.clone());
registry.prompt_contributor(extension.clone());
registry.tool_contributor(extension);
}