Add Epiphany jobsUpdated notification

This commit is contained in:
Meta Vens 2026-04-26 15:02:45 +01:00
commit 48d6820d7d
22 changed files with 923 additions and 23 deletions

View file

@ -1126,6 +1126,8 @@ server_notification_definitions! {
ConfigWarning => "configWarning" (v2::ConfigWarningNotification),
#[experimental("thread/epiphany/stateUpdated")]
ThreadEpiphanyStateUpdated => "thread/epiphany/stateUpdated" (v2::ThreadEpiphanyStateUpdatedNotification),
#[experimental("thread/epiphany/jobsUpdated")]
ThreadEpiphanyJobsUpdated => "thread/epiphany/jobsUpdated" (v2::ThreadEpiphanyJobsUpdatedNotification),
FuzzyFileSearchSessionUpdated => "fuzzyFileSearch/sessionUpdated" (FuzzyFileSearchSessionUpdatedNotification),
FuzzyFileSearchSessionCompleted => "fuzzyFileSearch/sessionCompleted" (FuzzyFileSearchSessionCompletedNotification),
#[experimental("thread/realtime/started")]
@ -2552,6 +2554,60 @@ mod tests {
Ok(())
}
#[test]
fn serialize_thread_epiphany_jobs_updated_notification() -> Result<()> {
let notification = ServerNotification::ThreadEpiphanyJobsUpdated(
v2::ThreadEpiphanyJobsUpdatedNotification {
thread_id: "thr_123".to_string(),
source: v2::ThreadEpiphanyJobsUpdatedSource::RuntimeProgress,
state_revision: Some(7),
jobs: vec![v2::ThreadEpiphanyJob {
id: "specialist-work".to_string(),
kind: v2::ThreadEpiphanyJobKind::Specialist,
scope: "runtime-bound specialist work".to_string(),
owner_role: "epiphany-harness".to_string(),
status: v2::ThreadEpiphanyJobStatus::Running,
runtime_agent_job_id: Some("job-123".to_string()),
items_processed: Some(1),
items_total: Some(3),
progress_note: Some("Runtime agent job is running.".to_string()),
last_checkpoint_at_unix_seconds: Some(1_744_500_123),
blocking_reason: None,
active_thread_ids: vec!["worker-thread".to_string()],
linked_subgoal_ids: vec!["phase6".to_string()],
linked_graph_node_ids: vec!["job-surface".to_string()],
}],
},
);
assert_eq!(
json!({
"method": "thread/epiphany/jobsUpdated",
"params": {
"threadId": "thr_123",
"source": "runtimeProgress",
"stateRevision": 7,
"jobs": [{
"id": "specialist-work",
"kind": "specialist",
"scope": "runtime-bound specialist work",
"ownerRole": "epiphany-harness",
"status": "running",
"runtimeAgentJobId": "job-123",
"itemsProcessed": 1,
"itemsTotal": 3,
"progressNote": "Runtime agent job is running.",
"lastCheckpointAtUnixSeconds": 1744500123,
"activeThreadIds": ["worker-thread"],
"linkedSubgoalIds": ["phase6"],
"linkedGraphNodeIds": ["job-surface"]
}]
}
}),
serde_json::to_value(&notification)?,
);
Ok(())
}
#[test]
fn serialize_config_requirements_read() -> Result<()> {
let request = ClientRequest::ConfigRequirementsRead {
@ -3241,6 +3297,35 @@ mod tests {
assert_eq!(reason, Some("thread/epiphany/stateUpdated"));
}
#[test]
fn thread_epiphany_jobs_updated_notification_is_marked_experimental() {
let notification = ServerNotification::ThreadEpiphanyJobsUpdated(
v2::ThreadEpiphanyJobsUpdatedNotification {
thread_id: "thr_123".to_string(),
source: v2::ThreadEpiphanyJobsUpdatedSource::RuntimeProgress,
state_revision: Some(1),
jobs: vec![v2::ThreadEpiphanyJob {
id: "specialist-work".to_string(),
kind: v2::ThreadEpiphanyJobKind::Specialist,
scope: "runtime-bound specialist work".to_string(),
owner_role: "epiphany-harness".to_string(),
status: v2::ThreadEpiphanyJobStatus::Running,
runtime_agent_job_id: Some("job-123".to_string()),
items_processed: Some(1),
items_total: Some(3),
progress_note: Some("Runtime agent job is running.".to_string()),
last_checkpoint_at_unix_seconds: Some(1_744_500_123),
blocking_reason: None,
active_thread_ids: vec!["worker-thread".to_string()],
linked_subgoal_ids: vec!["phase6".to_string()],
linked_graph_node_ids: vec!["job-surface".to_string()],
}],
},
);
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&notification);
assert_eq!(reason, Some("thread/epiphany/jobsUpdated"));
}
#[test]
fn thread_realtime_start_is_marked_experimental() {
let request = ClientRequest::ThreadRealtimeStart {

View file

@ -4800,6 +4800,26 @@ pub enum ThreadEpiphanyStateUpdatedField {
Mode,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadEpiphanyJobsUpdatedNotification {
pub thread_id: String,
pub source: ThreadEpiphanyJobsUpdatedSource,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional = nullable)]
pub state_revision: Option<u64>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub jobs: Vec<ThreadEpiphanyJob>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub enum ThreadEpiphanyJobsUpdatedSource {
RuntimeProgress,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]