fix: add native turn lifecycle and stabilize opencode session flow

This commit is contained in:
Nathan Flurry 2026-02-07 20:24:21 -08:00
parent 2b0507c3f5
commit 91cac052b8
35 changed files with 1688 additions and 486 deletions

View file

@ -40,6 +40,10 @@ pub enum UniversalEventType {
SessionStarted,
#[serde(rename = "session.ended")]
SessionEnded,
#[serde(rename = "turn.started")]
TurnStarted,
#[serde(rename = "turn.ended")]
TurnEnded,
#[serde(rename = "item.started")]
ItemStarted,
#[serde(rename = "item.delta")]
@ -63,6 +67,7 @@ pub enum UniversalEventType {
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
#[serde(untagged)]
pub enum UniversalEventData {
Turn(TurnEventData),
SessionStarted(SessionStartedData),
SessionEnded(SessionEndedData),
Item(ItemEventData),
@ -93,6 +98,22 @@ pub struct SessionEndedData {
pub stderr: Option<StderrOutput>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
pub struct TurnEventData {
pub phase: TurnPhase,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub turn_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum TurnPhase {
Started,
Ended,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
pub struct StderrOutput {
/// First N lines of stderr (if truncated) or full stderr (if not truncated)
@ -318,25 +339,26 @@ impl EventConversion {
}
}
pub fn turn_completed_event() -> EventConversion {
pub fn turn_started_event(turn_id: Option<String>, metadata: Option<Value>) -> EventConversion {
EventConversion::new(
UniversalEventType::ItemCompleted,
UniversalEventData::Item(ItemEventData {
item: UniversalItem {
item_id: String::new(),
native_item_id: None,
parent_id: None,
kind: ItemKind::Status,
role: Some(ItemRole::System),
content: vec![ContentPart::Status {
label: "turn.completed".to_string(),
detail: None,
}],
status: ItemStatus::Completed,
},
UniversalEventType::TurnStarted,
UniversalEventData::Turn(TurnEventData {
phase: TurnPhase::Started,
turn_id,
metadata,
}),
)
}
pub fn turn_ended_event(turn_id: Option<String>, metadata: Option<Value>) -> EventConversion {
EventConversion::new(
UniversalEventType::TurnEnded,
UniversalEventData::Turn(TurnEventData {
phase: TurnPhase::Ended,
turn_id,
metadata,
}),
)
.synthetic()
}
pub fn item_from_text(role: ItemRole, text: String) -> UniversalItem {