#![allow(
dead_code,
unused_parens,
unused_variables,
clippy::bool_comparison,
clippy::field_reassign_with_default,
clippy::nonminimal_bool,
clippy::partialeq_to_none,
clippy::redundant_clone,
clippy::redundant_field_names,
clippy::too_many_arguments
)]
use std::{collections::BTreeMap, fmt};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct SessionDocumentKey(String);
impl SessionDocumentKey {
#[must_use]
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SessionFirstTurnPhase {
#[default]
Inactive,
Pending,
Consumed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SessionInitialPromptStageDecision {
#[default]
Clear,
Store,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SystemContextAppendDecision {
#[default]
Staged,
Duplicate,
RejectEmpty,
RejectConflict,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SystemContextPersistAppendAdmission {
#[default]
Reject,
Admit,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SystemContextSource {
#[default]
Normal,
RuntimeSteer,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum RealtimeTranscriptRoleKind {
#[default]
User,
Assistant,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum RealtimeTranscriptLaneKind {
#[default]
Display,
Spoken,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum RealtimeTranscriptStopReasonKind {
Cancelled,
ToolUse,
#[default]
Other,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum RealtimeTranscriptMaterializeDecision {
#[default]
Wait,
MarkSkipped,
MaterializeUser,
MaterializeAssistant,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum TranscriptEditKind {
#[default]
Fork,
Rewrite,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SessionSystemPromptSource {
#[default]
DirectMutation,
ExplicitBuild,
DefaultBuild,
WasmDefaultBuild,
RuntimeContextAppend,
RuntimeSteerCleanup,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum ObservedSessionTailKind {
#[default]
Empty,
System,
SystemNotice,
User,
BlockAssistant,
ToolResults,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum PendingContinuationDisposition {
RunPending,
#[default]
NoPendingBoundary,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum PendingContinuationPublicTerminal {
#[default]
NoPendingBoundary,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum ResumeOverrideRejection {
#[default]
ProviderRequiresModel,
BuildOnlyAfterFirstTurn,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum ResumeProviderSelection {
#[default]
RecomputeFromModel,
UseOverride,
UseStored,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum ResumeSelfHostedSelection {
#[default]
Clear,
Retain,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum LiveSessionAuthorityKind {
#[default]
LiveAuthoritative,
DurableAuthoritative,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum LiveSessionAuthorityReason {
#[default]
StoredArchived,
LiveUncommittedTranscript,
RuntimeSystemContextDiverged,
StoredTranscriptRevisionDiverged,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SessionDocumentLifecycle {
#[default]
Active,
Archived,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SessionArchiveDisposition {
#[default]
Archive,
AlreadyArchived,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SessionDocumentInput {
MarkSessionInitialTurnPending {
session_id: SessionDocumentKey,
},
StartSessionInitialTurn {
session_id: SessionDocumentKey,
},
StageSessionInitialPrompt {
session_id: SessionDocumentKey,
prompt_has_content: bool,
},
StageSessionToolResults {
session_id: SessionDocumentKey,
result_count: u64,
},
ConsumeSessionDeferredInputs {
session_id: SessionDocumentKey,
},
RestoreSessionConsumedInputs {
session_id: SessionDocumentKey,
restore_first_turn_pending: bool,
pending_initial_prompt_present: bool,
pending_tool_result_message_count: u64,
},
RecoverSessionFirstTurnPhase {
session_id: SessionDocumentKey,
phase: SessionFirstTurnPhase,
pending_initial_prompt_present: bool,
pending_tool_result_message_count: u64,
},
ResolveSessionFirstTurnOverridesAllowed {
session_id: SessionDocumentKey,
},
ResolveSystemContextAppend {
trimmed_text_byte_count: u64,
idempotency_key_present: bool,
existing_key_matches: bool,
existing_key_conflicts: bool,
active_turn_scoped: bool,
},
ResolveSystemContextPendingApplyItem {
source_kind: SystemContextSource,
},
ResolveSystemContextSteerCleanupItem {
source_kind: SystemContextSource,
},
RestoreSystemContextSnapshot {
active_keys_have_known_pending_or_seen: bool,
seen_keys_match_known_appends: bool,
},
ResolveSystemContextPersistAppendAdmission {
has_previous: bool,
content_identical: bool,
content_extends_previous: bool,
appended_starts_with_separator: bool,
incoming_is_runtime_context_append: bool,
},
ResolveRealtimeItemObserved {
role: RealtimeTranscriptRoleKind,
response_discarded: bool,
},
ResolveRealtimeItemSkipped,
ResolveRealtimeUserTranscriptFinal {
text_present: bool,
segment_empty: bool,
segment_matches: bool,
},
ResolveRealtimeAssistantDelta {
response_id_valid: bool,
response_discarded: bool,
delta_id_present: bool,
delta_id_seen: bool,
item_has_text: bool,
current_lane: RealtimeTranscriptLaneKind,
requested_lane: RealtimeTranscriptLaneKind,
response_completed: bool,
text_after_write_present: bool,
},
ResolveRealtimeAssistantTextReplacement {
response_id_valid: bool,
response_discarded: bool,
item_materialized: bool,
item_has_text: bool,
current_lane: RealtimeTranscriptLaneKind,
requested_lane: RealtimeTranscriptLaneKind,
response_completed: bool,
text_after_replace_present: bool,
},
ResolveRealtimeAssistantTurnCompleted {
response_id_valid: bool,
response_discarded: bool,
stop_reason: RealtimeTranscriptStopReasonKind,
},
ResolveRealtimeAssistantTurnInterrupted {
response_id_valid: bool,
},
ResolveRealtimeMaterializeCandidate {
item_materialized: bool,
predecessor_materialized: bool,
item_skipped: bool,
item_ready: bool,
item_text_present: bool,
role: RealtimeTranscriptRoleKind,
response_id_present: bool,
completion_present: bool,
completion_usage_consumed: bool,
},
RestoreRealtimeTranscriptState {
item_count: u64,
first_seen_count: u64,
first_seen_unique_count: u64,
every_item_has_order_entry: bool,
every_order_entry_has_item: bool,
all_identity_fields_valid: bool,
all_delta_ids_valid: bool,
all_completion_response_ids_valid: bool,
all_discarded_response_ids_valid: bool,
all_materialized_items_were_ready_or_skipped: bool,
all_assistant_items_have_response_unless_skipped: bool,
all_ready_assistant_items_have_completion_or_are_skipped: bool,
all_materialized_assistant_completions_consumed: bool,
all_completed_assistant_text_items_are_ready_or_materialized_or_skipped: bool,
all_discarded_assistant_items_are_skipped_or_materialized: bool,
},
AuthorizeSessionMetadataPersist {
schema_version: u64,
model_present: bool,
},
AuthorizeSessionBuildStatePersist {
mob_tool_authority_context_present: bool,
mob_tool_authority_context_generated: bool,
},
RestoreSessionBuildState,
AuthorizeSystemPromptMutation {
source: SessionSystemPromptSource,
prompt_present: bool,
prompt_byte_count: u64,
replacing_existing: bool,
},
ResolvePendingContinuation {
session_tail: ObservedSessionTailKind,
staged_tool_result_count: u64,
},
AuthorizeSessionResumeOverrides {
provider_override_present: bool,
model_override_present: bool,
has_build_only_overrides: bool,
first_turn_phase: SessionFirstTurnPhase,
},
ClassifyLiveSessionAuthority {
stored_transcript_diverged: bool,
live_has_uncommitted_transcript: bool,
runtime_system_context_diverged: bool,
stored_is_archived: bool,
},
RecoverSessionFromStore {
session_id: SessionDocumentKey,
has_metadata: bool,
has_build_state: bool,
runtime_projection_quarantined: bool,
},
ApplyPendingToolResults {
session_id: SessionDocumentKey,
result_count: u64,
},
TranscriptEdit {
session_id: SessionDocumentKey,
fork_or_rewrite_directive: TranscriptEditKind,
},
RecoverSessionLifecycleTerminal {
session_id: SessionDocumentKey,
terminal: SessionDocumentLifecycle,
},
ArchiveSessionDocument {
session_id: SessionDocumentKey,
runtime_backed: bool,
durable_snapshot_present: bool,
runtime_session_registered: bool,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SessionDocumentEffect {
SessionFirstTurnPhaseResolved {
phase: SessionFirstTurnPhase,
was_pending: bool,
},
SessionFirstTurnOverridesResolved {
allowed: bool,
},
SessionInitialPromptStageResolved {
decision: SessionInitialPromptStageDecision,
},
SessionToolResultsStageResolved {
accepted_count: u64,
},
SessionConsumedInputsRestoreResolved {
restore_first_turn_pending: bool,
restore_initial_prompt: bool,
restore_tool_results: bool,
},
SessionFirstTurnPhaseRecovered,
SystemContextAppendResolved {
decision: SystemContextAppendDecision,
active_turn_scoped: bool,
},
SystemContextPendingApplyItemResolved {
promote_to_applied: bool,
mark_seen_applied: bool,
remove_seen: bool,
},
SystemContextSteerCleanupItemResolved {
discard: bool,
},
SystemContextSnapshotRestoreAuthorized,
SystemContextPersistAppendAdmissionResolved {
admission: SystemContextPersistAppendAdmission,
},
RealtimeTranscriptEventResolved {
observe_item: bool,
observe_skipped: bool,
write_user_segment: bool,
append_assistant_segment: bool,
replace_assistant_segment: bool,
promote_lane: bool,
mark_item_ready: bool,
record_delta_id: bool,
remove_completion: bool,
record_completion: bool,
discard_response: bool,
discard_response_by_lane: bool,
mark_response_ready: bool,
materialize_ready_items: bool,
},
RealtimeMaterializeCandidateResolved {
decision: RealtimeTranscriptMaterializeDecision,
consume_usage: bool,
},
RealtimeTranscriptSnapshotRestoreAuthorized,
SessionMetadataPersistAuthorized,
SessionBuildStatePersistAuthorized,
SessionBuildStateRestoreAuthorized,
SystemPromptMutationAuthorized,
PendingContinuationResolved {
disposition: PendingContinuationDisposition,
},
PendingContinuationPublicTerminalResolved {
terminal: PendingContinuationPublicTerminal,
},
SessionResumeOverridesAuthorized {
provider_selection: ResumeProviderSelection,
self_hosted_selection: ResumeSelfHostedSelection,
provider_overridden: bool,
},
SessionResumeOverridesRejected {
reason: ResumeOverrideRejection,
},
LiveSessionAuthorityClassified {
authority: LiveSessionAuthorityKind,
reason: LiveSessionAuthorityReason,
},
SessionStoreRecoverySourceResolved {
recoverable: bool,
},
SessionToolResultsApplied {
session_id: SessionDocumentKey,
applied_count: u64,
},
TranscriptRewriteCommitted {
kind: TranscriptEditKind,
success: bool,
},
SessionLifecycleTerminalRecovered,
SessionArchiveResolved {
disposition: SessionArchiveDisposition,
write_document: bool,
retire_runtime: bool,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SessionDocumentError {
op: &'static str,
}
impl SessionDocumentError {
#[must_use]
pub fn new(op: &'static str) -> Self {
Self { op }
}
}
impl fmt::Display for SessionDocumentError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"generated session document authority rejected {}",
self.op
)
}
}
impl std::error::Error for SessionDocumentError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum SessionDocumentPhase {
#[default]
Ready,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct SessionDocumentMachineState {
lifecycle_phase: SessionDocumentPhase,
session_first_turn_phase: BTreeMap<SessionDocumentKey, SessionFirstTurnPhase>,
session_pending_initial_prompt_present: BTreeMap<SessionDocumentKey, bool>,
session_pending_tool_results_count: BTreeMap<SessionDocumentKey, u64>,
session_lifecycle_terminal: BTreeMap<SessionDocumentKey, SessionDocumentLifecycle>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum SessionDocumentTransition {
MarkSessionInitialTurnPendingInactiveOrPending,
MarkSessionInitialTurnPendingConsumed,
StartSessionInitialTurnPending,
StartSessionInitialTurnInactive,
StartSessionInitialTurnConsumed,
ResolveSessionFirstTurnOverridesAllowed,
ResolveSessionFirstTurnOverridesDenied,
StageSessionInitialPromptStore,
StageSessionInitialPromptClear,
StageSessionToolResults,
ConsumeSessionDeferredInputsPending,
ConsumeSessionDeferredInputsInactive,
ConsumeSessionDeferredInputsConsumed,
RestoreSessionConsumedInputs,
RestoreSessionConsumedInputsNoPhaseRollback,
RecoverSessionFirstTurnPhase,
ResolveSystemContextAppendEmpty,
ResolveSystemContextAppendConflict,
ResolveSystemContextAppendDuplicate,
ResolveSystemContextAppendNew,
ResolveSystemContextPersistAppendAdmissionAdmit,
ResolveSystemContextPersistAppendAdmissionReject,
ResolveSystemContextPendingApplyItemRuntimeSteer,
ResolveSystemContextPendingApplyItemNormal,
ResolveSystemContextSteerCleanupItemRuntimeSteer,
ResolveSystemContextSteerCleanupItemNormal,
RestoreSystemContextSnapshot,
ResolveRealtimeItemObservedDiscardedAssistant,
ResolveRealtimeItemObservedPresent,
ResolveRealtimeItemSkipped,
ResolveRealtimeUserTranscriptFinalEmpty,
ResolveRealtimeUserTranscriptFinalStore,
ResolveRealtimeUserTranscriptFinalReplayOrConflict,
ResolveRealtimeAssistantDeltaInvalidOrDuplicate,
ResolveRealtimeAssistantDeltaDiscarded,
ResolveRealtimeAssistantDeltaLaneConflict,
ResolveRealtimeAssistantDeltaAccepted,
ResolveRealtimeAssistantReplacementInvalid,
ResolveRealtimeAssistantReplacementDiscarded,
ResolveRealtimeAssistantReplacementLocked,
ResolveRealtimeAssistantReplacementLaneConflict,
ResolveRealtimeAssistantReplacementAccepted,
ResolveRealtimeAssistantTurnCompletedInvalid,
ResolveRealtimeAssistantTurnCompletedDiscard,
ResolveRealtimeAssistantTurnCompletedToolUse,
ResolveRealtimeAssistantTurnCompletedRecord,
ResolveRealtimeAssistantTurnInterruptedInvalid,
ResolveRealtimeAssistantTurnInterruptedValid,
ResolveRealtimeMaterializeAlreadyDone,
ResolveRealtimeMaterializeWaitForPredecessor,
ResolveRealtimeMaterializeSkipped,
ResolveRealtimeMaterializeWaitForReadyText,
ResolveRealtimeMaterializeUser,
ResolveRealtimeMaterializeAssistant,
ResolveRealtimeMaterializeAssistantMissingCompletion,
AuthorizeRestoreRealtimeTranscriptState,
AuthorizeSessionMetadataPersist,
AuthorizeSessionBuildStatePersist,
RestoreSessionBuildState,
AuthorizeSystemPromptMutation,
ResolvePendingContinuationWithBoundary,
ResolvePendingContinuationWithoutBoundary,
AuthorizeSessionResumeOverridesRejectProviderRequiresModel,
AuthorizeSessionResumeOverridesRejectBuildOnlyAfterFirstTurn,
AuthorizeSessionResumeOverridesAcceptRecomputeProvider,
AuthorizeSessionResumeOverridesAcceptUseOverride,
AuthorizeSessionResumeOverridesAcceptRetainStored,
ClassifyLiveSessionAuthorityLive,
ClassifyLiveSessionAuthorityDurableArchived,
ClassifyLiveSessionAuthorityDurableUncommitted,
ClassifyLiveSessionAuthorityDurableSystemContext,
ClassifyLiveSessionAuthorityDurableRevision,
RecoverSessionFromStoreAuthorized,
RecoverSessionFromStoreUnrecoverable,
ApplyPendingToolResults,
TranscriptEditFork,
TranscriptEditRewrite,
RecoverSessionLifecycleTerminal,
ArchiveSessionDocumentActive,
ArchiveSessionDocumentAlreadyArchived,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SessionDocumentMachineAuthority {
state: SessionDocumentMachineState,
}
impl SessionDocumentMachineAuthority {
#[must_use]
pub fn new() -> Self {
let mut state = SessionDocumentMachineState::default();
state.lifecycle_phase = SessionDocumentPhase::Ready;
state.session_first_turn_phase = BTreeMap::new();
state.session_pending_initial_prompt_present = BTreeMap::new();
state.session_pending_tool_results_count = BTreeMap::new();
state.session_lifecycle_terminal = BTreeMap::new();
Self { state }
}
#[must_use]
pub fn state(&self) -> &SessionDocumentMachineState {
&self.state
}
#[must_use]
pub fn session_first_turn_phase_for(
&self,
key: &SessionDocumentKey,
) -> Option<SessionFirstTurnPhase> {
self.state.session_first_turn_phase.get(key).copied()
}
fn session_first_turn_phase_value(
&self,
key: &SessionDocumentKey,
) -> Result<SessionFirstTurnPhase, SessionDocumentError> {
self.state
.session_first_turn_phase
.get(key)
.copied()
.ok_or(SessionDocumentError {
op: "session_first_turn_phase",
})
}
#[must_use]
pub fn session_pending_initial_prompt_present_for(
&self,
key: &SessionDocumentKey,
) -> Option<bool> {
self.state
.session_pending_initial_prompt_present
.get(key)
.copied()
}
fn session_pending_initial_prompt_present_value(
&self,
key: &SessionDocumentKey,
) -> Result<bool, SessionDocumentError> {
self.state
.session_pending_initial_prompt_present
.get(key)
.copied()
.ok_or(SessionDocumentError {
op: "session_pending_initial_prompt_present",
})
}
#[must_use]
pub fn session_pending_tool_results_count_for(&self, key: &SessionDocumentKey) -> Option<u64> {
self.state
.session_pending_tool_results_count
.get(key)
.copied()
}
fn session_pending_tool_results_count_value(
&self,
key: &SessionDocumentKey,
) -> Result<u64, SessionDocumentError> {
self.state
.session_pending_tool_results_count
.get(key)
.copied()
.ok_or(SessionDocumentError {
op: "session_pending_tool_results_count",
})
}
#[must_use]
pub fn session_lifecycle_terminal_for(
&self,
key: &SessionDocumentKey,
) -> Option<SessionDocumentLifecycle> {
self.state.session_lifecycle_terminal.get(key).copied()
}
fn session_lifecycle_terminal_value(
&self,
key: &SessionDocumentKey,
) -> Result<SessionDocumentLifecycle, SessionDocumentError> {
self.state
.session_lifecycle_terminal
.get(key)
.copied()
.ok_or(SessionDocumentError {
op: "session_lifecycle_terminal",
})
}
fn single_transition(
matches: Vec<SessionDocumentTransition>,
op: &'static str,
) -> Result<SessionDocumentTransition, SessionDocumentError> {
let mut matches = matches.into_iter();
let Some(first) = matches.next() else {
return Err(SessionDocumentError { op });
};
if matches.next().is_some() {
return Err(SessionDocumentError { op });
}
Ok(first)
}
fn apply_input(
&mut self,
input: SessionDocumentInput,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
match input {
SessionDocumentInput::MarkSessionInitialTurnPending { session_id } => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Inactive)
|| (self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Pending))
{
matches.push(
SessionDocumentTransition::MarkSessionInitialTurnPendingInactiveOrPending,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Consumed)
{
matches.push(SessionDocumentTransition::MarkSessionInitialTurnPendingConsumed);
}
let transition = Self::single_transition(matches, "MarkSessionInitialTurnPending")?;
match transition {
SessionDocumentTransition::MarkSessionInitialTurnPendingInactiveOrPending => {
self.state
.session_first_turn_phase
.insert(session_id.clone(), SessionFirstTurnPhase::Pending);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionFirstTurnPhaseResolved {
phase: SessionFirstTurnPhase::Pending,
was_pending: false,
}])
}
SessionDocumentTransition::MarkSessionInitialTurnPendingConsumed => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionFirstTurnPhaseResolved {
phase: SessionFirstTurnPhase::Consumed,
was_pending: false,
}])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "MarkSessionInitialTurnPending_transition",
}),
}
}
SessionDocumentInput::StartSessionInitialTurn { session_id } => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Pending)
{
matches.push(SessionDocumentTransition::StartSessionInitialTurnPending);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Inactive)
{
matches.push(SessionDocumentTransition::StartSessionInitialTurnInactive);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Consumed)
{
matches.push(SessionDocumentTransition::StartSessionInitialTurnConsumed);
}
let transition = Self::single_transition(matches, "StartSessionInitialTurn")?;
match transition {
SessionDocumentTransition::StartSessionInitialTurnPending => {
self.state
.session_first_turn_phase
.insert(session_id.clone(), SessionFirstTurnPhase::Consumed);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionFirstTurnPhaseResolved {
phase: SessionFirstTurnPhase::Consumed,
was_pending: true,
}])
}
SessionDocumentTransition::StartSessionInitialTurnInactive => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionFirstTurnPhaseResolved {
phase: SessionFirstTurnPhase::Inactive,
was_pending: false,
}])
}
SessionDocumentTransition::StartSessionInitialTurnConsumed => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionFirstTurnPhaseResolved {
phase: SessionFirstTurnPhase::Consumed,
was_pending: false,
}])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "StartSessionInitialTurn_transition",
}),
}
}
SessionDocumentInput::StageSessionInitialPrompt {
session_id,
prompt_has_content,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (should_store_initial_prompt(
self.session_first_turn_phase_value(&session_id)?,
prompt_has_content,
))
{
matches.push(SessionDocumentTransition::StageSessionInitialPromptStore);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (should_store_initial_prompt(
self.session_first_turn_phase_value(&session_id)?,
prompt_has_content,
) == false)
{
matches.push(SessionDocumentTransition::StageSessionInitialPromptClear);
}
let transition = Self::single_transition(matches, "StageSessionInitialPrompt")?;
match transition {
SessionDocumentTransition::StageSessionInitialPromptStore => {
self.state
.session_pending_initial_prompt_present
.insert(session_id.clone(), true);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionInitialPromptStageResolved {
decision: SessionInitialPromptStageDecision::Store,
},
])
}
SessionDocumentTransition::StageSessionInitialPromptClear => {
self.state
.session_pending_initial_prompt_present
.insert(session_id.clone(), false);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionInitialPromptStageResolved {
decision: SessionInitialPromptStageDecision::Clear,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "StageSessionInitialPrompt_transition",
}),
}
}
SessionDocumentInput::StageSessionToolResults {
session_id,
result_count,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Inactive)
|| (self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Pending)
|| (self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Consumed))
{
matches.push(SessionDocumentTransition::StageSessionToolResults);
}
let transition = Self::single_transition(matches, "StageSessionToolResults")?;
match transition {
SessionDocumentTransition::StageSessionToolResults => {
self.state
.session_pending_tool_results_count
.insert(session_id.clone(), result_count);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionToolResultsStageResolved {
accepted_count: result_count,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "StageSessionToolResults_transition",
}),
}
}
SessionDocumentInput::ConsumeSessionDeferredInputs { session_id } => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Pending)
{
matches.push(SessionDocumentTransition::ConsumeSessionDeferredInputsPending);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Inactive)
{
matches.push(SessionDocumentTransition::ConsumeSessionDeferredInputsInactive);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (self.session_first_turn_phase_value(&session_id)?
== SessionFirstTurnPhase::Consumed)
{
matches.push(SessionDocumentTransition::ConsumeSessionDeferredInputsConsumed);
}
let transition = Self::single_transition(matches, "ConsumeSessionDeferredInputs")?;
match transition {
SessionDocumentTransition::ConsumeSessionDeferredInputsPending => {
self.state
.session_first_turn_phase
.insert(session_id.clone(), SessionFirstTurnPhase::Consumed);
self.state
.session_pending_initial_prompt_present
.insert(session_id.clone(), false);
self.state
.session_pending_tool_results_count
.insert(session_id.clone(), 0);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionFirstTurnPhaseResolved {
phase: SessionFirstTurnPhase::Consumed,
was_pending: true,
}])
}
SessionDocumentTransition::ConsumeSessionDeferredInputsInactive => {
self.state
.session_pending_initial_prompt_present
.insert(session_id.clone(), false);
self.state
.session_pending_tool_results_count
.insert(session_id.clone(), 0);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionFirstTurnPhaseResolved {
phase: SessionFirstTurnPhase::Inactive,
was_pending: false,
}])
}
SessionDocumentTransition::ConsumeSessionDeferredInputsConsumed => {
self.state
.session_pending_initial_prompt_present
.insert(session_id.clone(), false);
self.state
.session_pending_tool_results_count
.insert(session_id.clone(), 0);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionFirstTurnPhaseResolved {
phase: SessionFirstTurnPhase::Consumed,
was_pending: false,
}])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ConsumeSessionDeferredInputs_transition",
}),
}
}
SessionDocumentInput::RestoreSessionConsumedInputs {
session_id,
restore_first_turn_pending,
pending_initial_prompt_present,
pending_tool_result_message_count,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (restore_first_turn_pending)
{
matches.push(SessionDocumentTransition::RestoreSessionConsumedInputs);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (restore_first_turn_pending == false)
{
matches.push(
SessionDocumentTransition::RestoreSessionConsumedInputsNoPhaseRollback,
);
}
let transition = Self::single_transition(matches, "RestoreSessionConsumedInputs")?;
match transition {
SessionDocumentTransition::RestoreSessionConsumedInputs => {
self.state
.session_first_turn_phase
.insert(session_id.clone(), SessionFirstTurnPhase::Pending);
self.state
.session_pending_initial_prompt_present
.insert(session_id.clone(), pending_initial_prompt_present);
self.state
.session_pending_tool_results_count
.insert(session_id.clone(), pending_tool_result_message_count);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionConsumedInputsRestoreResolved {
restore_first_turn_pending: restore_first_turn_pending,
restore_initial_prompt: pending_initial_prompt_present,
restore_tool_results: pending_tool_result_message_count > 0,
},
])
}
SessionDocumentTransition::RestoreSessionConsumedInputsNoPhaseRollback => {
self.state
.session_pending_initial_prompt_present
.insert(session_id.clone(), pending_initial_prompt_present);
self.state
.session_pending_tool_results_count
.insert(session_id.clone(), pending_tool_result_message_count);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionConsumedInputsRestoreResolved {
restore_first_turn_pending: restore_first_turn_pending,
restore_initial_prompt: pending_initial_prompt_present,
restore_tool_results: pending_tool_result_message_count > 0,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "RestoreSessionConsumedInputs_transition",
}),
}
}
SessionDocumentInput::RecoverSessionFirstTurnPhase {
session_id,
phase,
pending_initial_prompt_present,
pending_tool_result_message_count,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((phase == SessionFirstTurnPhase::Inactive)
|| (phase == SessionFirstTurnPhase::Pending)
|| (phase == SessionFirstTurnPhase::Consumed))
{
matches.push(SessionDocumentTransition::RecoverSessionFirstTurnPhase);
}
let transition = Self::single_transition(matches, "RecoverSessionFirstTurnPhase")?;
match transition {
SessionDocumentTransition::RecoverSessionFirstTurnPhase => {
self.state
.session_first_turn_phase
.insert(session_id.clone(), phase);
self.state
.session_pending_initial_prompt_present
.insert(session_id.clone(), pending_initial_prompt_present);
self.state
.session_pending_tool_results_count
.insert(session_id.clone(), pending_tool_result_message_count);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionFirstTurnPhaseRecovered])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "RecoverSessionFirstTurnPhase_transition",
}),
}
}
SessionDocumentInput::ResolveSessionFirstTurnOverridesAllowed { session_id } => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (phase_allows_initial_turn_overrides(
self.session_first_turn_phase_value(&session_id)?,
))
{
matches
.push(SessionDocumentTransition::ResolveSessionFirstTurnOverridesAllowed);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (phase_allows_initial_turn_overrides(
self.session_first_turn_phase_value(&session_id)?,
) == false)
{
matches.push(SessionDocumentTransition::ResolveSessionFirstTurnOverridesDenied);
}
let transition =
Self::single_transition(matches, "ResolveSessionFirstTurnOverridesAllowed")?;
match transition {
SessionDocumentTransition::ResolveSessionFirstTurnOverridesAllowed => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionFirstTurnOverridesResolved {
allowed: true,
},
])
}
SessionDocumentTransition::ResolveSessionFirstTurnOverridesDenied => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionFirstTurnOverridesResolved {
allowed: false,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolveSessionFirstTurnOverridesAllowed_transition",
}),
}
}
SessionDocumentInput::ResolveSystemContextAppend {
trimmed_text_byte_count,
idempotency_key_present,
existing_key_matches,
existing_key_conflicts,
active_turn_scoped,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (append_is_empty(trimmed_text_byte_count))
{
matches.push(SessionDocumentTransition::ResolveSystemContextAppendEmpty);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((append_is_empty(trimmed_text_byte_count) == false)
&& (append_is_conflict(idempotency_key_present, existing_key_conflicts)))
{
matches.push(SessionDocumentTransition::ResolveSystemContextAppendConflict);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((append_is_empty(trimmed_text_byte_count) == false)
&& (append_is_duplicate(
idempotency_key_present,
existing_key_matches,
existing_key_conflicts,
)))
{
matches.push(SessionDocumentTransition::ResolveSystemContextAppendDuplicate);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((append_is_empty(trimmed_text_byte_count) == false)
&& (append_is_new(
idempotency_key_present,
existing_key_matches,
existing_key_conflicts,
)))
{
matches.push(SessionDocumentTransition::ResolveSystemContextAppendNew);
}
let transition = Self::single_transition(matches, "ResolveSystemContextAppend")?;
match transition {
SessionDocumentTransition::ResolveSystemContextAppendEmpty => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SystemContextAppendResolved {
decision: SystemContextAppendDecision::RejectEmpty,
active_turn_scoped: active_turn_scoped,
}])
}
SessionDocumentTransition::ResolveSystemContextAppendConflict => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SystemContextAppendResolved {
decision: SystemContextAppendDecision::RejectConflict,
active_turn_scoped: active_turn_scoped,
}])
}
SessionDocumentTransition::ResolveSystemContextAppendDuplicate => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SystemContextAppendResolved {
decision: SystemContextAppendDecision::Duplicate,
active_turn_scoped: active_turn_scoped,
}])
}
SessionDocumentTransition::ResolveSystemContextAppendNew => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SystemContextAppendResolved {
decision: SystemContextAppendDecision::Staged,
active_turn_scoped: active_turn_scoped,
}])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolveSystemContextAppend_transition",
}),
}
}
SessionDocumentInput::ResolveSystemContextPendingApplyItem { source_kind } => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (source_kind == SystemContextSource::RuntimeSteer)
{
matches.push(
SessionDocumentTransition::ResolveSystemContextPendingApplyItemRuntimeSteer,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (source_kind == SystemContextSource::Normal)
{
matches.push(
SessionDocumentTransition::ResolveSystemContextPendingApplyItemNormal,
);
}
let transition =
Self::single_transition(matches, "ResolveSystemContextPendingApplyItem")?;
match transition {
SessionDocumentTransition::ResolveSystemContextPendingApplyItemRuntimeSteer => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SystemContextPendingApplyItemResolved {
promote_to_applied: false,
mark_seen_applied: false,
remove_seen: true,
},
])
}
SessionDocumentTransition::ResolveSystemContextPendingApplyItemNormal => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SystemContextPendingApplyItemResolved {
promote_to_applied: true,
mark_seen_applied: true,
remove_seen: false,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolveSystemContextPendingApplyItem_transition",
}),
}
}
SessionDocumentInput::ResolveSystemContextSteerCleanupItem { source_kind } => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (source_kind == SystemContextSource::RuntimeSteer)
{
matches.push(
SessionDocumentTransition::ResolveSystemContextSteerCleanupItemRuntimeSteer,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (source_kind == SystemContextSource::Normal)
{
matches.push(
SessionDocumentTransition::ResolveSystemContextSteerCleanupItemNormal,
);
}
let transition =
Self::single_transition(matches, "ResolveSystemContextSteerCleanupItem")?;
match transition {
SessionDocumentTransition::ResolveSystemContextSteerCleanupItemRuntimeSteer => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SystemContextSteerCleanupItemResolved {
discard: true,
},
])
}
SessionDocumentTransition::ResolveSystemContextSteerCleanupItemNormal => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SystemContextSteerCleanupItemResolved {
discard: false,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolveSystemContextSteerCleanupItem_transition",
}),
}
}
SessionDocumentInput::RestoreSystemContextSnapshot {
active_keys_have_known_pending_or_seen,
seen_keys_match_known_appends,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((active_keys_have_known_pending_or_seen) && (seen_keys_match_known_appends))
{
matches.push(SessionDocumentTransition::RestoreSystemContextSnapshot);
}
let transition = Self::single_transition(matches, "RestoreSystemContextSnapshot")?;
match transition {
SessionDocumentTransition::RestoreSystemContextSnapshot => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SystemContextSnapshotRestoreAuthorized,
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "RestoreSystemContextSnapshot_transition",
}),
}
}
SessionDocumentInput::ResolveSystemContextPersistAppendAdmission {
has_previous,
content_identical,
content_extends_previous,
appended_starts_with_separator,
incoming_is_runtime_context_append,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (persist_append_is_admissible(
has_previous,
content_identical,
content_extends_previous,
appended_starts_with_separator,
incoming_is_runtime_context_append,
))
{
matches.push(
SessionDocumentTransition::ResolveSystemContextPersistAppendAdmissionAdmit,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (persist_append_is_admissible(
has_previous,
content_identical,
content_extends_previous,
appended_starts_with_separator,
incoming_is_runtime_context_append,
) == false)
{
matches.push(
SessionDocumentTransition::ResolveSystemContextPersistAppendAdmissionReject,
);
}
let transition =
Self::single_transition(matches, "ResolveSystemContextPersistAppendAdmission")?;
match transition {
SessionDocumentTransition::ResolveSystemContextPersistAppendAdmissionAdmit => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SystemContextPersistAppendAdmissionResolved {
admission: SystemContextPersistAppendAdmission::Admit,
},
])
}
SessionDocumentTransition::ResolveSystemContextPersistAppendAdmissionReject => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SystemContextPersistAppendAdmissionResolved {
admission: SystemContextPersistAppendAdmission::Reject,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolveSystemContextPersistAppendAdmission_transition",
}),
}
}
SessionDocumentInput::ResolveRealtimeItemObserved {
role,
response_discarded,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((role == RealtimeTranscriptRoleKind::Assistant) && (response_discarded))
{
matches.push(
SessionDocumentTransition::ResolveRealtimeItemObservedDiscardedAssistant,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((role != RealtimeTranscriptRoleKind::Assistant)
|| (response_discarded == false))
{
matches.push(SessionDocumentTransition::ResolveRealtimeItemObservedPresent);
}
let transition = Self::single_transition(matches, "ResolveRealtimeItemObserved")?;
match transition {
SessionDocumentTransition::ResolveRealtimeItemObservedDiscardedAssistant => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: true,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
SessionDocumentTransition::ResolveRealtimeItemObservedPresent => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: true,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolveRealtimeItemObserved_transition",
}),
}
}
SessionDocumentInput::ResolveRealtimeItemSkipped => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready) {
matches.push(SessionDocumentTransition::ResolveRealtimeItemSkipped);
}
let transition = Self::single_transition(matches, "ResolveRealtimeItemSkipped")?;
match transition {
SessionDocumentTransition::ResolveRealtimeItemSkipped => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: true,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolveRealtimeItemSkipped_transition",
}),
}
}
SessionDocumentInput::ResolveRealtimeUserTranscriptFinal {
text_present,
segment_empty,
segment_matches,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (text_present == false)
{
matches
.push(SessionDocumentTransition::ResolveRealtimeUserTranscriptFinalEmpty);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((text_present) && (segment_empty))
{
matches
.push(SessionDocumentTransition::ResolveRealtimeUserTranscriptFinalStore);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((text_present) && (segment_empty == false))
{
matches.push(SessionDocumentTransition::ResolveRealtimeUserTranscriptFinalReplayOrConflict);
}
let transition =
Self::single_transition(matches, "ResolveRealtimeUserTranscriptFinal")?;
match transition {
SessionDocumentTransition::ResolveRealtimeUserTranscriptFinalEmpty => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved { observe_item: true, observe_skipped: false, write_user_segment: false, append_assistant_segment: false, replace_assistant_segment: false, promote_lane: false, mark_item_ready: true, record_delta_id: false, remove_completion: false, record_completion: false, discard_response: false, discard_response_by_lane: false, mark_response_ready: false, materialize_ready_items: true, },
])
}
SessionDocumentTransition::ResolveRealtimeUserTranscriptFinalStore => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved { observe_item: true, observe_skipped: false, write_user_segment: true, append_assistant_segment: false, replace_assistant_segment: false, promote_lane: false, mark_item_ready: true, record_delta_id: false, remove_completion: false, record_completion: false, discard_response: false, discard_response_by_lane: false, mark_response_ready: false, materialize_ready_items: true, },
])
}
SessionDocumentTransition::ResolveRealtimeUserTranscriptFinalReplayOrConflict => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved { observe_item: true, observe_skipped: false, write_user_segment: false, append_assistant_segment: false, replace_assistant_segment: false, promote_lane: false, mark_item_ready: true, record_delta_id: false, remove_completion: false, record_completion: false, discard_response: false, discard_response_by_lane: false, mark_response_ready: false, materialize_ready_items: true, },
])
}
#[allow(unreachable_patterns)] _ => Err(SessionDocumentError { op: "ResolveRealtimeUserTranscriptFinal_transition" }),
}
}
SessionDocumentInput::ResolveRealtimeAssistantDelta {
response_id_valid,
response_discarded,
delta_id_present,
delta_id_seen,
item_has_text,
current_lane,
requested_lane,
response_completed,
text_after_write_present,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((response_id_valid == false)
|| (realtime_delta_is_duplicate(delta_id_present, delta_id_seen)))
{
matches.push(
SessionDocumentTransition::ResolveRealtimeAssistantDeltaInvalidOrDuplicate,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((response_id_valid) && (response_discarded))
{
matches.push(SessionDocumentTransition::ResolveRealtimeAssistantDeltaDiscarded);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((response_id_valid)
&& (response_discarded == false)
&& (realtime_delta_is_duplicate(delta_id_present, delta_id_seen) == false)
&& (realtime_lane_accepts(item_has_text, current_lane, requested_lane)
== false))
{
matches
.push(SessionDocumentTransition::ResolveRealtimeAssistantDeltaLaneConflict);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((response_id_valid)
&& (response_discarded == false)
&& (realtime_delta_is_duplicate(delta_id_present, delta_id_seen) == false)
&& (realtime_lane_accepts(item_has_text, current_lane, requested_lane)))
{
matches.push(SessionDocumentTransition::ResolveRealtimeAssistantDeltaAccepted);
}
let transition = Self::single_transition(matches, "ResolveRealtimeAssistantDelta")?;
match transition {
SessionDocumentTransition::ResolveRealtimeAssistantDeltaInvalidOrDuplicate => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: false,
},
])
}
SessionDocumentTransition::ResolveRealtimeAssistantDeltaDiscarded => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: true,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
SessionDocumentTransition::ResolveRealtimeAssistantDeltaLaneConflict => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: true,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: delta_id_present,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
SessionDocumentTransition::ResolveRealtimeAssistantDeltaAccepted => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: true,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: true,
replace_assistant_segment: false,
promote_lane: true,
mark_item_ready: realtime_should_mark_ready_after_write(
response_completed,
text_after_write_present,
),
record_delta_id: delta_id_present,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolveRealtimeAssistantDelta_transition",
}),
}
}
SessionDocumentInput::ResolveRealtimeAssistantTextReplacement {
response_id_valid,
response_discarded,
item_materialized,
item_has_text,
current_lane,
requested_lane,
response_completed,
text_after_replace_present,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (response_id_valid == false)
{
matches.push(
SessionDocumentTransition::ResolveRealtimeAssistantReplacementInvalid,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((response_id_valid) && (response_discarded))
{
matches.push(
SessionDocumentTransition::ResolveRealtimeAssistantReplacementDiscarded,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((response_id_valid) && (response_discarded == false) && (item_materialized))
{
matches
.push(SessionDocumentTransition::ResolveRealtimeAssistantReplacementLocked);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((response_id_valid)
&& (response_discarded == false)
&& (item_materialized == false)
&& (realtime_lane_accepts(item_has_text, current_lane, requested_lane)
== false))
{
matches.push(
SessionDocumentTransition::ResolveRealtimeAssistantReplacementLaneConflict,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((response_id_valid)
&& (response_discarded == false)
&& (item_materialized == false)
&& (realtime_lane_accepts(item_has_text, current_lane, requested_lane)))
{
matches.push(
SessionDocumentTransition::ResolveRealtimeAssistantReplacementAccepted,
);
}
let transition =
Self::single_transition(matches, "ResolveRealtimeAssistantTextReplacement")?;
match transition {
SessionDocumentTransition::ResolveRealtimeAssistantReplacementInvalid => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: false,
},
])
}
SessionDocumentTransition::ResolveRealtimeAssistantReplacementDiscarded => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: true,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
SessionDocumentTransition::ResolveRealtimeAssistantReplacementLocked => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: true,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
SessionDocumentTransition::ResolveRealtimeAssistantReplacementLaneConflict => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: true,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
SessionDocumentTransition::ResolveRealtimeAssistantReplacementAccepted => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: true,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: true,
promote_lane: true,
mark_item_ready: realtime_should_mark_ready_after_write(
response_completed,
text_after_replace_present,
),
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolveRealtimeAssistantTextReplacement_transition",
}),
}
}
SessionDocumentInput::ResolveRealtimeAssistantTurnCompleted {
response_id_valid,
response_discarded,
stop_reason,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (response_id_valid == false)
{
matches.push(
SessionDocumentTransition::ResolveRealtimeAssistantTurnCompletedInvalid,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((response_id_valid)
&& ((response_discarded) || (realtime_stop_reason_discards(stop_reason))))
{
matches.push(
SessionDocumentTransition::ResolveRealtimeAssistantTurnCompletedDiscard,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((response_id_valid)
&& (response_discarded == false)
&& (realtime_stop_reason_removes_completion(stop_reason)))
{
matches.push(
SessionDocumentTransition::ResolveRealtimeAssistantTurnCompletedToolUse,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((response_id_valid)
&& (response_discarded == false)
&& (realtime_stop_reason_records_completion(stop_reason)))
{
matches.push(
SessionDocumentTransition::ResolveRealtimeAssistantTurnCompletedRecord,
);
}
let transition =
Self::single_transition(matches, "ResolveRealtimeAssistantTurnCompleted")?;
match transition {
SessionDocumentTransition::ResolveRealtimeAssistantTurnCompletedInvalid => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: false,
},
])
}
SessionDocumentTransition::ResolveRealtimeAssistantTurnCompletedDiscard => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: true,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
SessionDocumentTransition::ResolveRealtimeAssistantTurnCompletedToolUse => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: true,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: true,
},
])
}
SessionDocumentTransition::ResolveRealtimeAssistantTurnCompletedRecord => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: true,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: true,
materialize_ready_items: true,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolveRealtimeAssistantTurnCompleted_transition",
}),
}
}
SessionDocumentInput::ResolveRealtimeAssistantTurnInterrupted { response_id_valid } => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (response_id_valid == false)
{
matches.push(
SessionDocumentTransition::ResolveRealtimeAssistantTurnInterruptedInvalid,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (response_id_valid)
{
matches.push(
SessionDocumentTransition::ResolveRealtimeAssistantTurnInterruptedValid,
);
}
let transition =
Self::single_transition(matches, "ResolveRealtimeAssistantTurnInterrupted")?;
match transition {
SessionDocumentTransition::ResolveRealtimeAssistantTurnInterruptedInvalid => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: false,
discard_response: false,
discard_response_by_lane: false,
mark_response_ready: false,
materialize_ready_items: false,
},
])
}
SessionDocumentTransition::ResolveRealtimeAssistantTurnInterruptedValid => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptEventResolved {
observe_item: false,
observe_skipped: false,
write_user_segment: false,
append_assistant_segment: false,
replace_assistant_segment: false,
promote_lane: false,
mark_item_ready: false,
record_delta_id: false,
remove_completion: false,
record_completion: true,
discard_response: false,
discard_response_by_lane: true,
mark_response_ready: true,
materialize_ready_items: true,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolveRealtimeAssistantTurnInterrupted_transition",
}),
}
}
SessionDocumentInput::ResolveRealtimeMaterializeCandidate {
item_materialized,
predecessor_materialized,
item_skipped,
item_ready,
item_text_present,
role,
response_id_present,
completion_present,
completion_usage_consumed,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (item_materialized)
{
matches.push(SessionDocumentTransition::ResolveRealtimeMaterializeAlreadyDone);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((item_materialized == false) && (predecessor_materialized == false))
{
matches.push(
SessionDocumentTransition::ResolveRealtimeMaterializeWaitForPredecessor,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((item_materialized == false)
&& (predecessor_materialized)
&& (item_skipped))
{
matches.push(SessionDocumentTransition::ResolveRealtimeMaterializeSkipped);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((item_materialized == false)
&& (predecessor_materialized)
&& (item_skipped == false)
&& ((item_ready == false) || (item_text_present == false)))
{
matches.push(
SessionDocumentTransition::ResolveRealtimeMaterializeWaitForReadyText,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((item_materialized == false)
&& (predecessor_materialized)
&& (item_skipped == false)
&& (item_ready)
&& (item_text_present)
&& (role == RealtimeTranscriptRoleKind::User))
{
matches.push(SessionDocumentTransition::ResolveRealtimeMaterializeUser);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((item_materialized == false)
&& (predecessor_materialized)
&& (item_skipped == false)
&& (item_ready)
&& (item_text_present)
&& (role == RealtimeTranscriptRoleKind::Assistant)
&& (response_id_present)
&& (completion_present))
{
matches.push(SessionDocumentTransition::ResolveRealtimeMaterializeAssistant);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((item_materialized == false)
&& (predecessor_materialized)
&& (item_skipped == false)
&& (item_ready)
&& (item_text_present)
&& (role == RealtimeTranscriptRoleKind::Assistant)
&& ((response_id_present == false) || (completion_present == false)))
{
matches.push(SessionDocumentTransition::ResolveRealtimeMaterializeAssistantMissingCompletion);
}
let transition =
Self::single_transition(matches, "ResolveRealtimeMaterializeCandidate")?;
match transition {
SessionDocumentTransition::ResolveRealtimeMaterializeAlreadyDone => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeMaterializeCandidateResolved { decision: RealtimeTranscriptMaterializeDecision::Wait, consume_usage: false, },
])
}
SessionDocumentTransition::ResolveRealtimeMaterializeWaitForPredecessor => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeMaterializeCandidateResolved { decision: RealtimeTranscriptMaterializeDecision::Wait, consume_usage: false, },
])
}
SessionDocumentTransition::ResolveRealtimeMaterializeSkipped => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeMaterializeCandidateResolved { decision: RealtimeTranscriptMaterializeDecision::MarkSkipped, consume_usage: false, },
])
}
SessionDocumentTransition::ResolveRealtimeMaterializeWaitForReadyText => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeMaterializeCandidateResolved { decision: RealtimeTranscriptMaterializeDecision::Wait, consume_usage: false, },
])
}
SessionDocumentTransition::ResolveRealtimeMaterializeUser => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeMaterializeCandidateResolved { decision: RealtimeTranscriptMaterializeDecision::MaterializeUser, consume_usage: false, },
])
}
SessionDocumentTransition::ResolveRealtimeMaterializeAssistant => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeMaterializeCandidateResolved { decision: RealtimeTranscriptMaterializeDecision::MaterializeAssistant, consume_usage: completion_usage_consumed == false, },
])
}
SessionDocumentTransition::ResolveRealtimeMaterializeAssistantMissingCompletion => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeMaterializeCandidateResolved { decision: RealtimeTranscriptMaterializeDecision::Wait, consume_usage: false, },
])
}
#[allow(unreachable_patterns)] _ => Err(SessionDocumentError { op: "ResolveRealtimeMaterializeCandidate_transition" }),
}
}
SessionDocumentInput::RestoreRealtimeTranscriptState {
item_count,
first_seen_count,
first_seen_unique_count,
every_item_has_order_entry,
every_order_entry_has_item,
all_identity_fields_valid,
all_delta_ids_valid,
all_completion_response_ids_valid,
all_discarded_response_ids_valid,
all_materialized_items_were_ready_or_skipped,
all_assistant_items_have_response_unless_skipped,
all_ready_assistant_items_have_completion_or_are_skipped,
all_materialized_assistant_completions_consumed,
all_completed_assistant_text_items_are_ready_or_materialized_or_skipped,
all_discarded_assistant_items_are_skipped_or_materialized,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((item_count == first_seen_count)
&& (first_seen_count == first_seen_unique_count)
&& (every_item_has_order_entry)
&& (every_order_entry_has_item)
&& (all_identity_fields_valid)
&& (all_delta_ids_valid)
&& (all_completion_response_ids_valid)
&& (all_discarded_response_ids_valid)
&& (all_materialized_items_were_ready_or_skipped)
&& (all_assistant_items_have_response_unless_skipped)
&& (all_ready_assistant_items_have_completion_or_are_skipped)
&& (all_materialized_assistant_completions_consumed)
&& (all_completed_assistant_text_items_are_ready_or_materialized_or_skipped)
&& (all_discarded_assistant_items_are_skipped_or_materialized))
{
matches
.push(SessionDocumentTransition::AuthorizeRestoreRealtimeTranscriptState);
}
let transition =
Self::single_transition(matches, "RestoreRealtimeTranscriptState")?;
match transition {
SessionDocumentTransition::AuthorizeRestoreRealtimeTranscriptState => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::RealtimeTranscriptSnapshotRestoreAuthorized,
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "RestoreRealtimeTranscriptState_transition",
}),
}
}
SessionDocumentInput::AuthorizeSessionMetadataPersist {
schema_version,
model_present,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((schema_version > 0) && (model_present == true))
{
matches.push(SessionDocumentTransition::AuthorizeSessionMetadataPersist);
}
let transition =
Self::single_transition(matches, "AuthorizeSessionMetadataPersist")?;
match transition {
SessionDocumentTransition::AuthorizeSessionMetadataPersist => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionMetadataPersistAuthorized,
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "AuthorizeSessionMetadataPersist_transition",
}),
}
}
SessionDocumentInput::AuthorizeSessionBuildStatePersist {
mob_tool_authority_context_present,
mob_tool_authority_context_generated,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((mob_tool_authority_context_present == false)
|| (mob_tool_authority_context_generated == true))
{
matches.push(SessionDocumentTransition::AuthorizeSessionBuildStatePersist);
}
let transition =
Self::single_transition(matches, "AuthorizeSessionBuildStatePersist")?;
match transition {
SessionDocumentTransition::AuthorizeSessionBuildStatePersist => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionBuildStatePersistAuthorized,
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "AuthorizeSessionBuildStatePersist_transition",
}),
}
}
SessionDocumentInput::RestoreSessionBuildState => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready) {
matches.push(SessionDocumentTransition::RestoreSessionBuildState);
}
let transition = Self::single_transition(matches, "RestoreSessionBuildState")?;
match transition {
SessionDocumentTransition::RestoreSessionBuildState => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionBuildStateRestoreAuthorized,
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "RestoreSessionBuildState_transition",
}),
}
}
SessionDocumentInput::AuthorizeSystemPromptMutation {
source,
prompt_present,
prompt_byte_count,
replacing_existing,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((prompt_present == true) || (prompt_byte_count == 0))
{
matches.push(SessionDocumentTransition::AuthorizeSystemPromptMutation);
}
let transition = Self::single_transition(matches, "AuthorizeSystemPromptMutation")?;
match transition {
SessionDocumentTransition::AuthorizeSystemPromptMutation => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SystemPromptMutationAuthorized])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "AuthorizeSystemPromptMutation_transition",
}),
}
}
SessionDocumentInput::ResolvePendingContinuation {
session_tail,
staged_tool_result_count,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (has_effective_pending_boundary(session_tail, staged_tool_result_count))
{
matches.push(SessionDocumentTransition::ResolvePendingContinuationWithBoundary);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (has_effective_pending_boundary(session_tail, staged_tool_result_count)
== false)
{
matches
.push(SessionDocumentTransition::ResolvePendingContinuationWithoutBoundary);
}
let transition = Self::single_transition(matches, "ResolvePendingContinuation")?;
match transition {
SessionDocumentTransition::ResolvePendingContinuationWithBoundary => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::PendingContinuationResolved {
disposition: PendingContinuationDisposition::RunPending,
}])
}
SessionDocumentTransition::ResolvePendingContinuationWithoutBoundary => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::PendingContinuationResolved {
disposition: PendingContinuationDisposition::NoPendingBoundary,
},
SessionDocumentEffect::PendingContinuationPublicTerminalResolved {
terminal: PendingContinuationPublicTerminal::NoPendingBoundary,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ResolvePendingContinuation_transition",
}),
}
}
SessionDocumentInput::AuthorizeSessionResumeOverrides {
provider_override_present,
model_override_present,
has_build_only_overrides,
first_turn_phase,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (resume_reject_provider_requires_model(
provider_override_present,
model_override_present,
))
{
matches.push(SessionDocumentTransition::AuthorizeSessionResumeOverridesRejectProviderRequiresModel);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((resume_reject_provider_requires_model(
provider_override_present,
model_override_present,
) == false)
&& (resume_reject_build_only_after_first_turn(
has_build_only_overrides,
first_turn_phase,
)))
{
matches.push(SessionDocumentTransition::AuthorizeSessionResumeOverridesRejectBuildOnlyAfterFirstTurn);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((resume_overrides_admissible(
provider_override_present,
model_override_present,
has_build_only_overrides,
first_turn_phase,
)) && (resume_provider_recompute_from_model(
model_override_present,
provider_override_present,
)))
{
matches.push(SessionDocumentTransition::AuthorizeSessionResumeOverridesAcceptRecomputeProvider);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((resume_overrides_admissible(
provider_override_present,
model_override_present,
has_build_only_overrides,
first_turn_phase,
)) && (resume_provider_recompute_from_model(
model_override_present,
provider_override_present,
) == false)
&& (provider_override_present))
{
matches.push(
SessionDocumentTransition::AuthorizeSessionResumeOverridesAcceptUseOverride,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((resume_overrides_admissible(
provider_override_present,
model_override_present,
has_build_only_overrides,
first_turn_phase,
)) && (resume_provider_recompute_from_model(
model_override_present,
provider_override_present,
) == false)
&& (provider_override_present == false))
{
matches.push(SessionDocumentTransition::AuthorizeSessionResumeOverridesAcceptRetainStored);
}
let transition =
Self::single_transition(matches, "AuthorizeSessionResumeOverrides")?;
match transition {
SessionDocumentTransition::AuthorizeSessionResumeOverridesRejectProviderRequiresModel => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionResumeOverridesRejected { reason: ResumeOverrideRejection::ProviderRequiresModel, },
])
}
SessionDocumentTransition::AuthorizeSessionResumeOverridesRejectBuildOnlyAfterFirstTurn => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionResumeOverridesRejected { reason: ResumeOverrideRejection::BuildOnlyAfterFirstTurn, },
])
}
SessionDocumentTransition::AuthorizeSessionResumeOverridesAcceptRecomputeProvider => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionResumeOverridesAuthorized { provider_selection: ResumeProviderSelection::RecomputeFromModel, self_hosted_selection: ResumeSelfHostedSelection::Clear, provider_overridden: true, },
])
}
SessionDocumentTransition::AuthorizeSessionResumeOverridesAcceptUseOverride => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionResumeOverridesAuthorized { provider_selection: ResumeProviderSelection::UseOverride, self_hosted_selection: ResumeSelfHostedSelection::Clear, provider_overridden: true, },
])
}
SessionDocumentTransition::AuthorizeSessionResumeOverridesAcceptRetainStored => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionResumeOverridesAuthorized { provider_selection: ResumeProviderSelection::UseStored, self_hosted_selection: ResumeSelfHostedSelection::Retain, provider_overridden: false, },
])
}
#[allow(unreachable_patterns)] _ => Err(SessionDocumentError { op: "AuthorizeSessionResumeOverrides_transition" }),
}
}
SessionDocumentInput::ClassifyLiveSessionAuthority {
stored_transcript_diverged,
live_has_uncommitted_transcript,
runtime_system_context_diverged,
stored_is_archived,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((stored_transcript_diverged == false)
&& (live_has_uncommitted_transcript == false)
&& (runtime_system_context_diverged == false)
&& (stored_is_archived == false))
{
matches.push(SessionDocumentTransition::ClassifyLiveSessionAuthorityLive);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (stored_is_archived == true)
{
matches.push(
SessionDocumentTransition::ClassifyLiveSessionAuthorityDurableArchived,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((stored_is_archived == false) && (live_has_uncommitted_transcript == true))
{
matches.push(
SessionDocumentTransition::ClassifyLiveSessionAuthorityDurableUncommitted,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((stored_is_archived == false)
&& (live_has_uncommitted_transcript == false)
&& (runtime_system_context_diverged == true))
{
matches.push(
SessionDocumentTransition::ClassifyLiveSessionAuthorityDurableSystemContext,
);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((stored_is_archived == false)
&& (live_has_uncommitted_transcript == false)
&& (runtime_system_context_diverged == false)
&& (stored_transcript_diverged == true))
{
matches.push(
SessionDocumentTransition::ClassifyLiveSessionAuthorityDurableRevision,
);
}
let transition = Self::single_transition(matches, "ClassifyLiveSessionAuthority")?;
match transition {
SessionDocumentTransition::ClassifyLiveSessionAuthorityLive => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::LiveSessionAuthorityClassified {
authority: LiveSessionAuthorityKind::LiveAuthoritative,
reason: LiveSessionAuthorityReason::StoredArchived,
},
])
}
SessionDocumentTransition::ClassifyLiveSessionAuthorityDurableArchived => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::LiveSessionAuthorityClassified {
authority: LiveSessionAuthorityKind::DurableAuthoritative,
reason: LiveSessionAuthorityReason::StoredArchived,
},
])
}
SessionDocumentTransition::ClassifyLiveSessionAuthorityDurableUncommitted => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::LiveSessionAuthorityClassified {
authority: LiveSessionAuthorityKind::DurableAuthoritative,
reason: LiveSessionAuthorityReason::LiveUncommittedTranscript,
},
])
}
SessionDocumentTransition::ClassifyLiveSessionAuthorityDurableSystemContext => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::LiveSessionAuthorityClassified {
authority: LiveSessionAuthorityKind::DurableAuthoritative,
reason: LiveSessionAuthorityReason::RuntimeSystemContextDiverged,
},
])
}
SessionDocumentTransition::ClassifyLiveSessionAuthorityDurableRevision => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::LiveSessionAuthorityClassified {
authority: LiveSessionAuthorityKind::DurableAuthoritative,
reason:
LiveSessionAuthorityReason::StoredTranscriptRevisionDiverged,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ClassifyLiveSessionAuthority_transition",
}),
}
}
SessionDocumentInput::RecoverSessionFromStore {
session_id,
has_metadata,
has_build_state,
runtime_projection_quarantined,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (store_projection_can_recover_authority(
has_metadata,
has_build_state,
runtime_projection_quarantined,
))
{
matches.push(SessionDocumentTransition::RecoverSessionFromStoreAuthorized);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (store_projection_can_recover_authority(
has_metadata,
has_build_state,
runtime_projection_quarantined,
) == false)
{
matches.push(SessionDocumentTransition::RecoverSessionFromStoreUnrecoverable);
}
let transition = Self::single_transition(matches, "RecoverSessionFromStore")?;
match transition {
SessionDocumentTransition::RecoverSessionFromStoreAuthorized => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionStoreRecoverySourceResolved {
recoverable: true,
},
])
}
SessionDocumentTransition::RecoverSessionFromStoreUnrecoverable => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionStoreRecoverySourceResolved {
recoverable: false,
},
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "RecoverSessionFromStore_transition",
}),
}
}
SessionDocumentInput::ApplyPendingToolResults {
session_id,
result_count,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready) {
matches.push(SessionDocumentTransition::ApplyPendingToolResults);
}
let transition = Self::single_transition(matches, "ApplyPendingToolResults")?;
match transition {
SessionDocumentTransition::ApplyPendingToolResults => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionToolResultsApplied {
session_id: session_id.clone(),
applied_count: result_count,
}])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ApplyPendingToolResults_transition",
}),
}
}
SessionDocumentInput::TranscriptEdit {
session_id,
fork_or_rewrite_directive,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (fork_or_rewrite_directive == TranscriptEditKind::Fork)
{
matches.push(SessionDocumentTransition::TranscriptEditFork);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (fork_or_rewrite_directive == TranscriptEditKind::Rewrite)
{
matches.push(SessionDocumentTransition::TranscriptEditRewrite);
}
let transition = Self::single_transition(matches, "TranscriptEdit")?;
match transition {
SessionDocumentTransition::TranscriptEditFork => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::TranscriptRewriteCommitted {
kind: TranscriptEditKind::Fork,
success: true,
}])
}
SessionDocumentTransition::TranscriptEditRewrite => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::TranscriptRewriteCommitted {
kind: TranscriptEditKind::Rewrite,
success: true,
}])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "TranscriptEdit_transition",
}),
}
}
SessionDocumentInput::RecoverSessionLifecycleTerminal {
session_id,
terminal,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& ((terminal == SessionDocumentLifecycle::Active)
|| (terminal == SessionDocumentLifecycle::Archived))
{
matches.push(SessionDocumentTransition::RecoverSessionLifecycleTerminal);
}
let transition =
Self::single_transition(matches, "RecoverSessionLifecycleTerminal")?;
match transition {
SessionDocumentTransition::RecoverSessionLifecycleTerminal => {
self.state
.session_lifecycle_terminal
.insert(session_id.clone(), terminal);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![
SessionDocumentEffect::SessionLifecycleTerminalRecovered,
])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "RecoverSessionLifecycleTerminal_transition",
}),
}
}
SessionDocumentInput::ArchiveSessionDocument {
session_id,
runtime_backed,
durable_snapshot_present,
runtime_session_registered,
} => {
let mut matches = Vec::new();
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (self.session_lifecycle_terminal_value(&session_id)?
== SessionDocumentLifecycle::Active)
{
matches.push(SessionDocumentTransition::ArchiveSessionDocumentActive);
}
if (self.state.lifecycle_phase == SessionDocumentPhase::Ready)
&& (self.session_lifecycle_terminal_value(&session_id)?
== SessionDocumentLifecycle::Archived)
{
matches.push(SessionDocumentTransition::ArchiveSessionDocumentAlreadyArchived);
}
let transition = Self::single_transition(matches, "ArchiveSessionDocument")?;
match transition {
SessionDocumentTransition::ArchiveSessionDocumentActive => {
self.state
.session_lifecycle_terminal
.insert(session_id.clone(), SessionDocumentLifecycle::Archived);
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionArchiveResolved {
disposition: SessionArchiveDisposition::Archive,
write_document: durable_snapshot_present,
retire_runtime: archive_should_retire_runtime(
runtime_backed,
durable_snapshot_present,
runtime_session_registered,
),
}])
}
SessionDocumentTransition::ArchiveSessionDocumentAlreadyArchived => {
self.state.lifecycle_phase = SessionDocumentPhase::Ready;
Ok(vec![SessionDocumentEffect::SessionArchiveResolved {
disposition: SessionArchiveDisposition::AlreadyArchived,
write_document: false,
retire_runtime: false,
}])
}
#[allow(unreachable_patterns)]
_ => Err(SessionDocumentError {
op: "ArchiveSessionDocument_transition",
}),
}
}
}
}
pub fn mark_session_initial_turn_pending(
&mut self,
session_id: SessionDocumentKey,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::MarkSessionInitialTurnPending { session_id })
}
pub fn start_session_initial_turn(
&mut self,
session_id: SessionDocumentKey,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::StartSessionInitialTurn { session_id })
}
pub fn stage_session_initial_prompt(
&mut self,
session_id: SessionDocumentKey,
prompt_has_content: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::StageSessionInitialPrompt {
session_id,
prompt_has_content,
})
}
pub fn stage_session_tool_results(
&mut self,
session_id: SessionDocumentKey,
result_count: u64,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::StageSessionToolResults {
session_id,
result_count,
})
}
pub fn consume_session_deferred_inputs(
&mut self,
session_id: SessionDocumentKey,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ConsumeSessionDeferredInputs { session_id })
}
pub fn restore_session_consumed_inputs(
&mut self,
session_id: SessionDocumentKey,
restore_first_turn_pending: bool,
pending_initial_prompt_present: bool,
pending_tool_result_message_count: u64,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::RestoreSessionConsumedInputs {
session_id,
restore_first_turn_pending,
pending_initial_prompt_present,
pending_tool_result_message_count,
})
}
pub fn recover_session_first_turn_phase(
&mut self,
session_id: SessionDocumentKey,
phase: SessionFirstTurnPhase,
pending_initial_prompt_present: bool,
pending_tool_result_message_count: u64,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::RecoverSessionFirstTurnPhase {
session_id,
phase,
pending_initial_prompt_present,
pending_tool_result_message_count,
})
}
pub fn resolve_session_first_turn_overrides_allowed(
&mut self,
session_id: SessionDocumentKey,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(
SessionDocumentInput::ResolveSessionFirstTurnOverridesAllowed { session_id },
)
}
pub fn resolve_system_context_append(
&mut self,
trimmed_text_byte_count: u64,
idempotency_key_present: bool,
existing_key_matches: bool,
existing_key_conflicts: bool,
active_turn_scoped: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ResolveSystemContextAppend {
trimmed_text_byte_count,
idempotency_key_present,
existing_key_matches,
existing_key_conflicts,
active_turn_scoped,
})
}
pub fn resolve_system_context_pending_apply_item(
&mut self,
source_kind: SystemContextSource,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ResolveSystemContextPendingApplyItem { source_kind })
}
pub fn resolve_system_context_steer_cleanup_item(
&mut self,
source_kind: SystemContextSource,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ResolveSystemContextSteerCleanupItem { source_kind })
}
pub fn restore_system_context_snapshot(
&mut self,
active_keys_have_known_pending_or_seen: bool,
seen_keys_match_known_appends: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::RestoreSystemContextSnapshot {
active_keys_have_known_pending_or_seen,
seen_keys_match_known_appends,
})
}
pub fn resolve_system_context_persist_append_admission(
&mut self,
has_previous: bool,
content_identical: bool,
content_extends_previous: bool,
appended_starts_with_separator: bool,
incoming_is_runtime_context_append: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(
SessionDocumentInput::ResolveSystemContextPersistAppendAdmission {
has_previous,
content_identical,
content_extends_previous,
appended_starts_with_separator,
incoming_is_runtime_context_append,
},
)
}
pub fn resolve_realtime_item_observed(
&mut self,
role: RealtimeTranscriptRoleKind,
response_discarded: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ResolveRealtimeItemObserved {
role,
response_discarded,
})
}
pub fn resolve_realtime_item_skipped(
&mut self,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ResolveRealtimeItemSkipped)
}
pub fn resolve_realtime_user_transcript_final(
&mut self,
text_present: bool,
segment_empty: bool,
segment_matches: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ResolveRealtimeUserTranscriptFinal {
text_present,
segment_empty,
segment_matches,
})
}
pub fn resolve_realtime_assistant_delta(
&mut self,
response_id_valid: bool,
response_discarded: bool,
delta_id_present: bool,
delta_id_seen: bool,
item_has_text: bool,
current_lane: RealtimeTranscriptLaneKind,
requested_lane: RealtimeTranscriptLaneKind,
response_completed: bool,
text_after_write_present: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ResolveRealtimeAssistantDelta {
response_id_valid,
response_discarded,
delta_id_present,
delta_id_seen,
item_has_text,
current_lane,
requested_lane,
response_completed,
text_after_write_present,
})
}
pub fn resolve_realtime_assistant_text_replacement(
&mut self,
response_id_valid: bool,
response_discarded: bool,
item_materialized: bool,
item_has_text: bool,
current_lane: RealtimeTranscriptLaneKind,
requested_lane: RealtimeTranscriptLaneKind,
response_completed: bool,
text_after_replace_present: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(
SessionDocumentInput::ResolveRealtimeAssistantTextReplacement {
response_id_valid,
response_discarded,
item_materialized,
item_has_text,
current_lane,
requested_lane,
response_completed,
text_after_replace_present,
},
)
}
pub fn resolve_realtime_assistant_turn_completed(
&mut self,
response_id_valid: bool,
response_discarded: bool,
stop_reason: RealtimeTranscriptStopReasonKind,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(
SessionDocumentInput::ResolveRealtimeAssistantTurnCompleted {
response_id_valid,
response_discarded,
stop_reason,
},
)
}
pub fn resolve_realtime_assistant_turn_interrupted(
&mut self,
response_id_valid: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(
SessionDocumentInput::ResolveRealtimeAssistantTurnInterrupted { response_id_valid },
)
}
pub fn resolve_realtime_materialize_candidate(
&mut self,
item_materialized: bool,
predecessor_materialized: bool,
item_skipped: bool,
item_ready: bool,
item_text_present: bool,
role: RealtimeTranscriptRoleKind,
response_id_present: bool,
completion_present: bool,
completion_usage_consumed: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ResolveRealtimeMaterializeCandidate {
item_materialized,
predecessor_materialized,
item_skipped,
item_ready,
item_text_present,
role,
response_id_present,
completion_present,
completion_usage_consumed,
})
}
pub fn restore_realtime_transcript_state(
&mut self,
item_count: u64,
first_seen_count: u64,
first_seen_unique_count: u64,
every_item_has_order_entry: bool,
every_order_entry_has_item: bool,
all_identity_fields_valid: bool,
all_delta_ids_valid: bool,
all_completion_response_ids_valid: bool,
all_discarded_response_ids_valid: bool,
all_materialized_items_were_ready_or_skipped: bool,
all_assistant_items_have_response_unless_skipped: bool,
all_ready_assistant_items_have_completion_or_are_skipped: bool,
all_materialized_assistant_completions_consumed: bool,
all_completed_assistant_text_items_are_ready_or_materialized_or_skipped: bool,
all_discarded_assistant_items_are_skipped_or_materialized: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::RestoreRealtimeTranscriptState {
item_count,
first_seen_count,
first_seen_unique_count,
every_item_has_order_entry,
every_order_entry_has_item,
all_identity_fields_valid,
all_delta_ids_valid,
all_completion_response_ids_valid,
all_discarded_response_ids_valid,
all_materialized_items_were_ready_or_skipped,
all_assistant_items_have_response_unless_skipped,
all_ready_assistant_items_have_completion_or_are_skipped,
all_materialized_assistant_completions_consumed,
all_completed_assistant_text_items_are_ready_or_materialized_or_skipped,
all_discarded_assistant_items_are_skipped_or_materialized,
})
}
pub fn authorize_session_metadata_persist(
&mut self,
schema_version: u64,
model_present: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::AuthorizeSessionMetadataPersist {
schema_version,
model_present,
})
}
pub fn authorize_session_build_state_persist(
&mut self,
mob_tool_authority_context_present: bool,
mob_tool_authority_context_generated: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::AuthorizeSessionBuildStatePersist {
mob_tool_authority_context_present,
mob_tool_authority_context_generated,
})
}
pub fn restore_session_build_state(
&mut self,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::RestoreSessionBuildState)
}
pub fn authorize_system_prompt_mutation(
&mut self,
source: SessionSystemPromptSource,
prompt_present: bool,
prompt_byte_count: u64,
replacing_existing: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::AuthorizeSystemPromptMutation {
source,
prompt_present,
prompt_byte_count,
replacing_existing,
})
}
pub fn resolve_pending_continuation(
&mut self,
session_tail: ObservedSessionTailKind,
staged_tool_result_count: u64,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ResolvePendingContinuation {
session_tail,
staged_tool_result_count,
})
}
pub fn authorize_session_resume_overrides(
&mut self,
provider_override_present: bool,
model_override_present: bool,
has_build_only_overrides: bool,
first_turn_phase: SessionFirstTurnPhase,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::AuthorizeSessionResumeOverrides {
provider_override_present,
model_override_present,
has_build_only_overrides,
first_turn_phase,
})
}
pub fn classify_live_session_authority(
&mut self,
stored_transcript_diverged: bool,
live_has_uncommitted_transcript: bool,
runtime_system_context_diverged: bool,
stored_is_archived: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ClassifyLiveSessionAuthority {
stored_transcript_diverged,
live_has_uncommitted_transcript,
runtime_system_context_diverged,
stored_is_archived,
})
}
pub fn recover_session_from_store(
&mut self,
session_id: SessionDocumentKey,
has_metadata: bool,
has_build_state: bool,
runtime_projection_quarantined: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::RecoverSessionFromStore {
session_id,
has_metadata,
has_build_state,
runtime_projection_quarantined,
})
}
pub fn apply_pending_tool_results(
&mut self,
session_id: SessionDocumentKey,
result_count: u64,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ApplyPendingToolResults {
session_id,
result_count,
})
}
pub fn transcript_edit(
&mut self,
session_id: SessionDocumentKey,
fork_or_rewrite_directive: TranscriptEditKind,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::TranscriptEdit {
session_id,
fork_or_rewrite_directive,
})
}
pub fn recover_session_lifecycle_terminal(
&mut self,
session_id: SessionDocumentKey,
terminal: SessionDocumentLifecycle,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::RecoverSessionLifecycleTerminal {
session_id,
terminal,
})
}
pub fn archive_session_document(
&mut self,
session_id: SessionDocumentKey,
runtime_backed: bool,
durable_snapshot_present: bool,
runtime_session_registered: bool,
) -> Result<Vec<SessionDocumentEffect>, SessionDocumentError> {
self.apply_input(SessionDocumentInput::ArchiveSessionDocument {
session_id,
runtime_backed,
durable_snapshot_present,
runtime_session_registered,
})
}
}
fn phase_allows_initial_turn_overrides(phase: SessionFirstTurnPhase) -> bool {
phase == SessionFirstTurnPhase::Pending
}
fn should_store_initial_prompt(phase: SessionFirstTurnPhase, prompt_has_content: bool) -> bool {
(phase == SessionFirstTurnPhase::Pending) && (prompt_has_content)
}
fn append_is_empty(trimmed_text_byte_count: u64) -> bool {
trimmed_text_byte_count == 0
}
fn append_is_conflict(idempotency_key_present: bool, existing_key_conflicts: bool) -> bool {
(idempotency_key_present) && (existing_key_conflicts)
}
fn append_is_duplicate(
idempotency_key_present: bool,
existing_key_matches: bool,
existing_key_conflicts: bool,
) -> bool {
(idempotency_key_present) && (existing_key_matches) && (existing_key_conflicts == false)
}
fn append_is_new(
idempotency_key_present: bool,
existing_key_matches: bool,
existing_key_conflicts: bool,
) -> bool {
(idempotency_key_present == false)
|| ((existing_key_matches == false) && (existing_key_conflicts == false))
}
fn persist_append_is_admissible(
has_previous: bool,
content_identical: bool,
content_extends_previous: bool,
appended_starts_with_separator: bool,
incoming_is_runtime_context_append: bool,
) -> bool {
((has_previous) && (content_identical))
|| ((has_previous)
&& (content_extends_previous)
&& (appended_starts_with_separator)
&& (incoming_is_runtime_context_append))
|| ((has_previous == false) && (incoming_is_runtime_context_append))
}
fn realtime_delta_is_duplicate(delta_id_present: bool, delta_id_seen: bool) -> bool {
(delta_id_present) && (delta_id_seen)
}
fn realtime_lane_accepts(
item_has_text: bool,
current_lane: RealtimeTranscriptLaneKind,
requested_lane: RealtimeTranscriptLaneKind,
) -> bool {
(current_lane == requested_lane) || (item_has_text == false)
}
fn realtime_should_mark_ready_after_write(
response_completed: bool,
text_after_write_present: bool,
) -> bool {
(response_completed) && (text_after_write_present)
}
fn realtime_stop_reason_discards(stop_reason: RealtimeTranscriptStopReasonKind) -> bool {
stop_reason == RealtimeTranscriptStopReasonKind::Cancelled
}
fn realtime_stop_reason_removes_completion(stop_reason: RealtimeTranscriptStopReasonKind) -> bool {
stop_reason == RealtimeTranscriptStopReasonKind::ToolUse
}
fn realtime_stop_reason_records_completion(stop_reason: RealtimeTranscriptStopReasonKind) -> bool {
stop_reason == RealtimeTranscriptStopReasonKind::Other
}
fn tail_has_pending_boundary(session_tail: ObservedSessionTailKind) -> bool {
(session_tail == ObservedSessionTailKind::User)
|| (session_tail == ObservedSessionTailKind::ToolResults)
}
fn has_effective_pending_boundary(
session_tail: ObservedSessionTailKind,
staged_tool_result_count: u64,
) -> bool {
(tail_has_pending_boundary(session_tail)) || (staged_tool_result_count > 0)
}
fn resume_reject_provider_requires_model(
provider_override_present: bool,
model_override_present: bool,
) -> bool {
(provider_override_present) && (model_override_present == false)
}
fn resume_reject_build_only_after_first_turn(
has_build_only_overrides: bool,
first_turn_phase: SessionFirstTurnPhase,
) -> bool {
(has_build_only_overrides) && (phase_allows_initial_turn_overrides(first_turn_phase) == false)
}
fn resume_overrides_admissible(
provider_override_present: bool,
model_override_present: bool,
has_build_only_overrides: bool,
first_turn_phase: SessionFirstTurnPhase,
) -> bool {
(resume_reject_provider_requires_model(provider_override_present, model_override_present)
== false)
&& (resume_reject_build_only_after_first_turn(has_build_only_overrides, first_turn_phase)
== false)
}
fn resume_provider_recompute_from_model(
model_override_present: bool,
provider_override_present: bool,
) -> bool {
(model_override_present) && (provider_override_present == false)
}
fn store_projection_can_recover_authority(
has_metadata: bool,
has_build_state: bool,
runtime_projection_quarantined: bool,
) -> bool {
(has_metadata) || (has_build_state) || (runtime_projection_quarantined)
}
fn archive_should_retire_runtime(
runtime_backed: bool,
durable_snapshot_present: bool,
runtime_session_registered: bool,
) -> bool {
(runtime_backed) && ((durable_snapshot_present) || (runtime_session_registered))
}
impl Default for SessionDocumentMachineAuthority {
fn default() -> Self {
Self::new()
}
}