mirror of
https://github.com/openai/codex.git
synced 2026-11-13 06:45:07 +00:00
Emit host skill budget warnings from world state (#35766)
## Why Host skill catalogs supplied through extension world state should report budget warnings only when their catalog update is actually rendered. ## What changed - Stop rebuilding an extension-owned host catalog in core. - Emit host catalog budget warnings when the corresponding world-state fragment is rendered, and deduplicate them with executor catalog warnings. - Cover full, shortened, and omitted host and executor catalogs, including repeated turns and resumed persisted snapshots. GitOrigin-RevId: ba28b6e337281b49ed4da2175c193fd4a6898ab7
This commit is contained in:
1 parent
e597169e9a
commit
a68d0a74bd
5 files changed
+617
-22
No files matched your search
@@ -63,6 +63,7 @@ use crate::state::SkillsThreadState;
|
||||
use crate::state::SkillsTurnState;
|
||||
use crate::tools::skill_tools;
|
||||
use crate::warnings::bounded_warnings;
|
||||
use crate::world_state::HostSkillsWarningEmitter;
|
||||
use crate::world_state::executor_skills_world_state_section;
|
||||
use crate::world_state::host_skills_world_state_section;
|
||||
|
||||
@@ -270,31 +271,46 @@ where
|
||||
} else {
|
||||
RenderedCatalog::default()
|
||||
};
|
||||
if let Some(message) = rendered.warning_message
|
||||
&& input
|
||||
.turn_store
|
||||
.get_or_init(EmittedCatalogBudgetWarnings::default)
|
||||
.insert(&message)
|
||||
{
|
||||
self.emit_warning(input.thread_store.level_id(), Some(input.turn_id), message);
|
||||
}
|
||||
let warning_message = rendered.warning_message;
|
||||
let executor_body = rendered.fragment.map(|fragment| fragment.body());
|
||||
let mut sections = vec![executor_skills_world_state_section(
|
||||
executor_body,
|
||||
config.include_instructions,
|
||||
)];
|
||||
let emitted_warnings = input
|
||||
.turn_store
|
||||
.get_or_init(EmittedCatalogBudgetWarnings::default);
|
||||
if let Some(host_snapshot) = input.turn_store.get::<HostSkillsSnapshot>()
|
||||
&& self.providers.has_host_provider()
|
||||
{
|
||||
input.turn_store.insert(HostSkillsCatalogInWorldState);
|
||||
let event_sink = Arc::clone(&self.event_sink);
|
||||
let emitted_warnings = Arc::clone(&emitted_warnings);
|
||||
let thread_id = input.thread_store.level_id().to_string();
|
||||
let turn_id = input.turn_id.to_string();
|
||||
let warning_emitter: HostSkillsWarningEmitter = Arc::new(move |message| {
|
||||
if emitted_warnings.insert(&message) {
|
||||
event_sink.emit_warning(ExtensionWarning {
|
||||
thread_id: thread_id.clone(),
|
||||
turn_id: Some(turn_id.clone()),
|
||||
message,
|
||||
});
|
||||
}
|
||||
});
|
||||
sections.push(host_skills_world_state_section(
|
||||
&host_snapshot,
|
||||
config.include_instructions,
|
||||
include_usage,
|
||||
metadata_budget,
|
||||
extension_metrics,
|
||||
warning_emitter,
|
||||
));
|
||||
}
|
||||
if let Some(message) = warning_message
|
||||
&& emitted_warnings.insert(&message)
|
||||
{
|
||||
self.emit_warning(input.thread_store.level_id(), Some(input.turn_id), message);
|
||||
}
|
||||
sections
|
||||
})
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ const NO_HOST_SKILLS_BODY: &str =
|
||||
"\n## Host skills update\nNo host skills are currently available.\n";
|
||||
const HIDDEN_HOST_SKILLS_BODY: &str = "\n## Host skills update\nHost skills are not listed automatically. Explicit skill mentions can still be resolved when available.\n";
|
||||
|
||||
pub(crate) type HostSkillsWarningEmitter = Arc<dyn Fn(String) + Send + Sync>;
|
||||
|
||||
pub(crate) fn executor_skills_world_state_section(
|
||||
body: Option<String>,
|
||||
include_instructions: bool,
|
||||
@@ -84,6 +86,7 @@ pub(crate) fn host_skills_world_state_section(
|
||||
include_skills_usage_instructions: bool,
|
||||
metadata_budget: SkillMetadataBudget,
|
||||
extension_metrics: Option<Arc<dyn ExtensionMetrics>>,
|
||||
warning_emitter: HostSkillsWarningEmitter,
|
||||
) -> WorldStateSectionContribution {
|
||||
let outcome = host_snapshot.outcome();
|
||||
let metadata_budget = match metadata_budget {
|
||||
@@ -97,6 +100,9 @@ pub(crate) fn host_skills_world_state_section(
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let warning_message = available
|
||||
.as_ref()
|
||||
.and_then(|available| available.warning_message.clone());
|
||||
let render_metrics = include_instructions.then(|| {
|
||||
available
|
||||
.as_ref()
|
||||
@@ -118,6 +124,24 @@ pub(crate) fn host_skills_world_state_section(
|
||||
)
|
||||
.body()
|
||||
});
|
||||
rendered_host_skills_world_state_section(
|
||||
body,
|
||||
include_instructions,
|
||||
render_metrics,
|
||||
extension_metrics,
|
||||
warning_message,
|
||||
warning_emitter,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn rendered_host_skills_world_state_section(
|
||||
body: Option<String>,
|
||||
include_instructions: bool,
|
||||
render_metrics: Option<(usize, usize, usize, usize)>,
|
||||
extension_metrics: Option<Arc<dyn ExtensionMetrics>>,
|
||||
warning_message: Option<String>,
|
||||
warning_emitter: HostSkillsWarningEmitter,
|
||||
) -> WorldStateSectionContribution {
|
||||
let snapshot = json!({
|
||||
"body": body,
|
||||
"includeInstructions": include_instructions,
|
||||
@@ -159,6 +183,9 @@ pub(crate) fn host_skills_world_state_section(
|
||||
None if !include_instructions => HIDDEN_HOST_SKILLS_BODY,
|
||||
None => NO_HOST_SKILLS_BODY,
|
||||
};
|
||||
if let Some(message) = warning_message.as_ref() {
|
||||
warning_emitter(message.clone());
|
||||
}
|
||||
Some(RenderedWorldStateFragment::new(
|
||||
"developer",
|
||||
(SKILLS_INSTRUCTIONS_OPEN_TAG, SKILLS_INSTRUCTIONS_CLOSE_TAG),
|
||||
|
||||
Reference in new issue
Block a user