mirror of
https://github.com/openai/codex.git
synced 2026-10-23 18:08:45 +00:00
Emit prompt telemetry only after hooks accept input (#56234)
## Why Prompt telemetry can include full user text. Emitting it before hook acceptance logs prompts that `UserPromptSubmit` hooks subsequently block. ## What changed Move prompt telemetry from input submission to hook acceptance, including queued and steered input. Preserve telemetry for accepted Guardian review prompts that are converted to response items during finalization. ## Testing Extend hook regression tests to assert that blocked prompts are absent from telemetry and rollouts, while accepted queued prompts are logged exactly once. Extend Guardian review coverage to assert exactly one prompt event across inspection steps. GitOrigin-RevId: aa71f98de2356dd08f62ff492e897ab3a43b54c9
This commit is contained in:
@@ -394,6 +394,18 @@ pub(crate) async fn run_turn(
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Guardian can replace its submitted prompt with response items during finalization.
|
||||
// Those skip UserInput telemetry above, so emit the saved prompt after acceptance.
|
||||
if crate::guardian::is_basic_session_source(&turn_context.session_source)
|
||||
&& !user_input.is_empty()
|
||||
&& input
|
||||
.iter()
|
||||
.all(|item| matches!(item, TurnInput::ResponseItem(_)))
|
||||
{
|
||||
turn_context.session_telemetry.user_prompt(&user_input);
|
||||
}
|
||||
|
||||
// Only speculate after hooks accept the turn, using its finalized tools and permissions.
|
||||
{
|
||||
let mut state = sess.state.lock().await;
|
||||
@@ -960,6 +972,10 @@ pub(crate) async fn run_hooks_and_record_inputs(
|
||||
blocked_input = true;
|
||||
record_additional_contexts(sess, turn_context, hook_outcome.additional_contexts).await;
|
||||
} else {
|
||||
if let TurnInput::UserInput { content, .. } = input_item {
|
||||
// Prompt telemetry can contain the full text, so emit it only after hooks accept it.
|
||||
turn_context.session_telemetry.user_prompt(content);
|
||||
}
|
||||
if matches!(input_item, TurnInput::UserInput { content, .. } if !content.is_empty()) {
|
||||
accepted_user_input = true;
|
||||
}
|
||||
|
||||
@@ -425,9 +425,6 @@ async fn start_or_steer(
|
||||
session
|
||||
.maybe_emit_model_warnings_for_turn(turn_context.as_ref())
|
||||
.await;
|
||||
if let SubmittedTurnInput::UserInput { content, .. } = &input {
|
||||
turn_context.session_telemetry.user_prompt(content);
|
||||
}
|
||||
let mut task_input = merge_additional_context_input(session, additional_context).await;
|
||||
if has_explicit_input {
|
||||
task_input.push(
|
||||
@@ -583,9 +580,6 @@ async fn start_if_idle(
|
||||
match kind {
|
||||
TurnStartKind::User => {
|
||||
session.clear_connector_selection().await;
|
||||
if let SubmittedTurnInput::UserInput { content, .. } = &input {
|
||||
turn_context.session_telemetry.user_prompt(content);
|
||||
}
|
||||
task_input.push(
|
||||
pending_turn_input(
|
||||
session,
|
||||
@@ -876,20 +870,14 @@ impl Session {
|
||||
.update_responsesapi_client_metadata(responsesapi_client_metadata);
|
||||
|
||||
let input = match input {
|
||||
SubmittedTurnInput::UserInput { content, client_id } => {
|
||||
active_task
|
||||
.turn_context
|
||||
.session_telemetry
|
||||
.user_prompt(content);
|
||||
TurnInput::UserInput {
|
||||
content: std::mem::take(content),
|
||||
client_id: client_id.clone(),
|
||||
metadata: super::UserInputMetadata {
|
||||
acceptance_order: Some(self.reserve_user_input_order().await),
|
||||
origin,
|
||||
},
|
||||
}
|
||||
}
|
||||
SubmittedTurnInput::UserInput { content, client_id } => TurnInput::UserInput {
|
||||
content: std::mem::take(content),
|
||||
client_id: client_id.clone(),
|
||||
metadata: super::UserInputMetadata {
|
||||
acceptance_order: Some(self.reserve_user_input_order().await),
|
||||
origin,
|
||||
},
|
||||
},
|
||||
input => {
|
||||
pending_turn_input(self, input.clone(), sender_messages, active_turn_id, origin)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user