restructure history and source

This commit is contained in:
Roy Han
2026-03-24 15:28:41 -07:00
parent 66534ad1d4
commit ed9e59ceb0
4 changed files with 95 additions and 34 deletions
+35 -9
View File
@@ -14,6 +14,7 @@ use codex_protocol::protocol::AskForApproval;
use codex_protocol::protocol::SandboxPolicy;
use codex_protocol::protocol::SessionSource;
use codex_protocol::protocol::SkillScope;
use codex_protocol::protocol::SubAgentSource;
use serde::Serialize;
use sha1::Digest;
use sha1::Sha1;
@@ -48,17 +49,18 @@ pub(crate) struct CodexThreadStartedEvent {
pub(crate) personality: Option<Personality>,
pub(crate) ephemeral: bool,
pub(crate) session_source: SessionSource,
pub(crate) initial_history_type: InitialHistoryType,
pub(crate) subagent_source: Option<SubAgentSource>,
pub(crate) parent_thread_id: Option<String>,
pub(crate) create_source: ThreadCreateSource,
pub(crate) created_at: u64,
}
#[derive(Clone, Copy, Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum ThreadCreateSource {
ThreadStart,
ThreadFork,
DetachedReview,
pub(crate) enum InitialHistoryType {
New,
Forked,
Resumed,
}
pub(crate) fn build_track_events_context(
@@ -390,9 +392,10 @@ struct CodexThreadStartedEventParams {
collaboration_mode: &'static str,
personality: Option<String>,
ephemeral: bool,
session_source: SessionSource,
session_source: String,
initial_history_type: InitialHistoryType,
subagent_source: Option<String>,
parent_thread_id: Option<String>,
create_source: ThreadCreateSource,
created_at: u64,
}
@@ -768,9 +771,10 @@ fn codex_thread_started_event_params(
collaboration_mode: collaboration_mode_mode(thread_event.collaboration_mode),
personality: thread_event.personality.map(|value| value.to_string()),
ephemeral: thread_event.ephemeral,
session_source: thread_event.session_source,
session_source: session_source_name(&thread_event.session_source),
initial_history_type: thread_event.initial_history_type,
subagent_source: thread_event.subagent_source.map(subagent_source_name),
parent_thread_id: thread_event.parent_thread_id,
create_source: thread_event.create_source,
created_at: thread_event.created_at,
}
}
@@ -828,6 +832,28 @@ fn collaboration_mode_mode(mode: ModeKind) -> &'static str {
}
}
fn session_source_name(session_source: &SessionSource) -> String {
match session_source {
SessionSource::Cli => "cli".to_string(),
SessionSource::VSCode => "vscode".to_string(),
SessionSource::Exec => "exec".to_string(),
SessionSource::Mcp => "mcp".to_string(),
SessionSource::Custom(source) => source.clone(),
SessionSource::SubAgent(_) => "subagent".to_string(),
SessionSource::Unknown => "unknown".to_string(),
}
}
fn subagent_source_name(subagent_source: SubAgentSource) -> String {
match subagent_source {
SubAgentSource::Review => "review".to_string(),
SubAgentSource::Compact => "compact".to_string(),
SubAgentSource::ThreadSpawn { .. } => "thread_spawn".to_string(),
SubAgentSource::MemoryConsolidation => "memory_consolidation".to_string(),
SubAgentSource::Other(other) => other,
}
}
async fn send_track_events(
auth_manager: &AuthManager,
config: Arc<Config>,
+37 -3
View File
@@ -6,8 +6,8 @@ use super::CodexPluginEventRequest;
use super::CodexPluginUsedEventRequest;
use super::CodexThreadStartedEvent;
use super::CodexThreadStartedEventRequest;
use super::InitialHistoryType;
use super::InvocationType;
use super::ThreadCreateSource;
use super::TrackEventRequest;
use super::TrackEventsContext;
use super::codex_app_metadata;
@@ -28,6 +28,7 @@ use codex_protocol::openai_models::ReasoningEffort;
use codex_protocol::protocol::AskForApproval;
use codex_protocol::protocol::SandboxPolicy;
use codex_protocol::protocol::SessionSource;
use codex_protocol::protocol::SubAgentSource;
use pretty_assertions::assert_eq;
use serde_json::json;
use std::collections::HashSet;
@@ -217,8 +218,9 @@ fn thread_started_event_serializes_expected_shape() {
personality: Some(Personality::Friendly),
ephemeral: true,
session_source: SessionSource::Exec,
initial_history_type: InitialHistoryType::New,
subagent_source: None,
parent_thread_id: None,
create_source: ThreadCreateSource::ThreadStart,
created_at: 1_716_000_000,
}),
});
@@ -245,14 +247,46 @@ fn thread_started_event_serializes_expected_shape() {
"personality": "friendly",
"ephemeral": true,
"session_source": "exec",
"initial_history_type": "new",
"subagent_source": null,
"parent_thread_id": null,
"create_source": "thread_start",
"created_at": 1716000000
}
})
);
}
#[test]
fn thread_started_event_serializes_subagent_source() {
let event = TrackEventRequest::ThreadStarted(CodexThreadStartedEventRequest {
event_type: "codex_thread_started",
event_params: codex_thread_started_event_params(CodexThreadStartedEvent {
thread_id: "thread-1".to_string(),
model: "gpt-5".to_string(),
model_provider: "openai".to_string(),
reasoning_effort: None,
reasoning_summary: None,
service_tier: None,
approval_policy: AskForApproval::OnRequest,
approvals_reviewer: ApprovalsReviewer::User,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
sandbox_network_access: false,
collaboration_mode: ModeKind::Default,
personality: None,
ephemeral: false,
session_source: SessionSource::SubAgent(SubAgentSource::Review),
initial_history_type: InitialHistoryType::New,
subagent_source: Some(SubAgentSource::Review),
parent_thread_id: None,
created_at: 1,
}),
});
let payload = serde_json::to_value(&event).expect("serialize subagent thread started event");
assert_eq!(payload["event_params"]["session_source"], "subagent");
assert_eq!(payload["event_params"]["subagent_source"], "review");
}
#[test]
fn plugin_used_event_serializes_expected_shape() {
let tracking = TrackEventsContext {
+18 -21
View File
@@ -17,8 +17,8 @@ use crate::agent::agent_status_from_event;
use crate::analytics_client::AnalyticsEventsClient;
use crate::analytics_client::AppInvocation;
use crate::analytics_client::CodexThreadStartedEvent;
use crate::analytics_client::InitialHistoryType;
use crate::analytics_client::InvocationType;
use crate::analytics_client::ThreadCreateSource;
use crate::analytics_client::build_track_events_context;
use crate::apps::render_apps_section;
use crate::auth_env_telemetry::collect_auth_env_telemetry;
@@ -631,10 +631,9 @@ impl Codex {
user_shell_override,
};
let thread_create_source = classify_thread_create_source(
&conversation_history,
&session_configuration.session_source,
);
let should_emit_thread_started =
!matches!(conversation_history, InitialHistory::Resumed(_));
let initial_history_type = initial_history_type(&conversation_history);
let thread_session_source = session_configuration.session_source.clone();
let thread_started_configuration = session_configuration.clone();
@@ -665,7 +664,7 @@ impl Codex {
})?;
let thread_id = session.conversation_id;
if let Some(create_source) = thread_create_source {
if should_emit_thread_started {
session
.services
.analytics_events_client
@@ -695,9 +694,10 @@ impl Codex {
ephemeral: thread_started_configuration
.original_config_do_not_use
.ephemeral,
initial_history_type,
subagent_source: session_source_subagent_source(&thread_session_source),
parent_thread_id: session_source_parent_thread_id(&thread_session_source),
session_source: thread_session_source,
create_source,
created_at: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
@@ -819,21 +819,18 @@ impl Codex {
}
}
fn classify_thread_create_source(
conversation_history: &InitialHistory,
session_source: &SessionSource,
) -> Option<ThreadCreateSource> {
if matches!(
session_source,
SessionSource::SubAgent(SubAgentSource::Review)
) {
return Some(ThreadCreateSource::DetachedReview);
}
fn initial_history_type(conversation_history: &InitialHistory) -> InitialHistoryType {
match conversation_history {
InitialHistory::New => Some(ThreadCreateSource::ThreadStart),
InitialHistory::Forked(_) => Some(ThreadCreateSource::ThreadFork),
InitialHistory::Resumed(_) => None,
InitialHistory::New => InitialHistoryType::New,
InitialHistory::Forked(_) => InitialHistoryType::Forked,
InitialHistory::Resumed(_) => InitialHistoryType::Resumed,
}
}
fn session_source_subagent_source(session_source: &SessionSource) -> Option<SubAgentSource> {
match session_source {
SessionSource::SubAgent(subagent_source) => Some(subagent_source.clone()),
_ => None,
}
}
+5 -1
View File
@@ -78,11 +78,15 @@ async fn thread_start_tracks_thread_started_analytics() -> Result<()> {
assert_eq!(event["event_params"]["personality"], "friendly");
assert_eq!(event["event_params"]["ephemeral"], true);
assert_eq!(event["event_params"]["session_source"], "exec");
assert_eq!(event["event_params"]["initial_history_type"], "new");
assert_eq!(
event["event_params"]["subagent_source"],
serde_json::Value::Null
);
assert_eq!(
event["event_params"]["parent_thread_id"],
serde_json::Value::Null
);
assert_eq!(event["event_params"]["create_source"], "thread_start");
assert!(
event["event_params"]["created_at"]
.as_u64()