use runtime_kernel_api::KernelFailure;
use runtime_ports::{ModelContent, ModelMessage};
use serde::{Deserialize, Serialize};
const CHECKPOINT_PREFIX: &str = "Runtime execution checkpoint. This is the authoritative minimal state compiled from earlier execution. Continue from NEXT without repeating completed work.\n";
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct ExecutionCheckpoint {
#[serde(default = "checkpoint_version")]
version: u32,
goal: CheckpointGoal,
#[serde(default)]
done: Vec<CheckpointDone>,
state: CheckpointState,
#[serde(default)]
watch: Vec<CheckpointWatch>,
#[serde(default)]
next: Vec<CheckpointNext>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
struct CheckpointGoal {
objective: String,
#[serde(default)]
acceptance: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
struct CheckpointDone {
action: String,
#[serde(default)]
evidence: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
struct CheckpointState {
phase: CheckpointPhase,
summary: String,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
enum CheckpointPhase {
Investigating,
Diagnosed,
Implementing,
ChangedUnverified,
Verified,
Blocked,
Complete,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
struct CheckpointWatch {
kind: String,
content: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
struct CheckpointNext {
action: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
expected_result: Option<String>,
}
pub(crate) struct CompiledCheckpoint {
pub(crate) message: ModelMessage,
pub(crate) used_fallback: bool,
}
pub(crate) fn compile_checkpoint(
candidate: Option<&str>,
messages: &[ModelMessage],
current_user_prompt: &str,
max_chars: usize,
) -> Result<CompiledCheckpoint, KernelFailure> {
let (checkpoint, used_fallback) = match candidate {
Some(candidate) => match parse_and_validate(candidate) {
Ok(checkpoint) => (checkpoint, false),
Err(error) => (
fallback_checkpoint(messages, current_user_prompt, &error.message),
true,
),
},
None => (
fallback_checkpoint(
messages,
current_user_prompt,
"no Agent checkpoint compiler produced a candidate",
),
true,
),
};
let checkpoint = fit_checkpoint(checkpoint, max_chars.max(1_024));
validate_checkpoint(&checkpoint)?;
let json = serde_json::to_string(&checkpoint).map_err(|error| {
KernelFailure::new("CHECKPOINT_SERIALIZATION_FAILED", error.to_string())
})?;
Ok(CompiledCheckpoint {
message: ModelMessage::text(
runtime_ports::ModelRole::User,
format!("{CHECKPOINT_PREFIX}{json}"),
),
used_fallback,
})
}
fn parse_and_validate(candidate: &str) -> Result<ExecutionCheckpoint, KernelFailure> {
let checkpoint = serde_json::from_str(candidate)
.map_err(|error| KernelFailure::new("CHECKPOINT_CANDIDATE_INVALID", error.to_string()))?;
validate_checkpoint(&checkpoint)?;
Ok(checkpoint)
}
fn validate_checkpoint(checkpoint: &ExecutionCheckpoint) -> Result<(), KernelFailure> {
if checkpoint.version != checkpoint_version() || checkpoint.goal.objective.trim().is_empty() {
return Err(KernelFailure::new(
"CHECKPOINT_INVALID",
"checkpoint requires version 1 and a non-empty goal.objective",
));
}
if checkpoint.state.summary.trim().is_empty() {
return Err(KernelFailure::new(
"CHECKPOINT_INVALID",
"checkpoint requires a non-empty state.summary",
));
}
if !matches!(
checkpoint.state.phase,
CheckpointPhase::Blocked | CheckpointPhase::Complete
) && !checkpoint
.next
.iter()
.any(|next| !next.action.trim().is_empty())
{
return Err(KernelFailure::new(
"CHECKPOINT_INVALID",
"an active checkpoint requires at least one next action",
));
}
Ok(())
}
fn fallback_checkpoint(
messages: &[ModelMessage],
current_user_prompt: &str,
reason: &str,
) -> ExecutionCheckpoint {
let done = messages
.iter()
.flat_map(|message| &message.content)
.filter_map(|content| match content {
ModelContent::ToolResult {
name,
content,
failed: false,
..
} => Some(CheckpointDone {
action: format!("Tool {name} completed"),
evidence: vec![head_tail(content, 600)],
}),
_ => None,
})
.rev()
.take(12)
.collect::<Vec<_>>();
let had_tools = messages.iter().any(|message| {
message.content.iter().any(|content| {
matches!(
content,
ModelContent::ToolUse { .. } | ModelContent::ToolResult { .. }
)
})
});
ExecutionCheckpoint {
version: checkpoint_version(),
goal: CheckpointGoal {
objective: truncate(current_user_prompt, 1_500),
acceptance: Vec::new(),
},
done,
state: CheckpointState {
phase: if had_tools {
CheckpointPhase::ChangedUnverified
} else {
CheckpointPhase::Investigating
},
summary: "A deterministic fallback preserved recent execution evidence; current state must be re-verified."
.into(),
},
watch: vec![CheckpointWatch {
kind: "uncertainty".into(),
content: format!("Checkpoint compiler fallback: {}", truncate(reason, 500)),
}],
next: vec![CheckpointNext {
action: "Re-verify current state, then continue with the smallest concrete action."
.into(),
expected_result: Some("New evidence grounded in the current execution state.".into()),
}],
}
}
fn fit_checkpoint(mut checkpoint: ExecutionCheckpoint, max_chars: usize) -> ExecutionCheckpoint {
checkpoint.version = checkpoint_version();
checkpoint.goal.objective = truncate(&checkpoint.goal.objective, 1_500);
checkpoint.goal.acceptance.truncate(8);
checkpoint.done.truncate(16);
checkpoint.watch.truncate(12);
checkpoint.next.truncate(5);
while checkpoint_chars(&checkpoint) > max_chars {
if checkpoint.done.len() > 1 {
checkpoint.done.pop();
} else if checkpoint.watch.len() > 1 {
checkpoint.watch.pop();
} else if checkpoint.goal.acceptance.len() > 1 {
checkpoint.goal.acceptance.pop();
} else if checkpoint.next.len() > 1 {
checkpoint.next.pop();
} else {
checkpoint.goal.objective = truncate(&checkpoint.goal.objective, 500);
checkpoint.state.summary = truncate(&checkpoint.state.summary, 240);
if let Some(done) = checkpoint.done.first_mut() {
done.action = truncate(&done.action, 160);
done.evidence.truncate(1);
if let Some(evidence) = done.evidence.first_mut() {
*evidence = head_tail(evidence, 240);
}
}
if let Some(watch) = checkpoint.watch.first_mut() {
watch.content = truncate(&watch.content, 180);
}
if let Some(next) = checkpoint.next.first_mut() {
next.action = truncate(&next.action, 240);
next.expected_result = None;
}
break;
}
}
checkpoint
}
fn checkpoint_chars(checkpoint: &ExecutionCheckpoint) -> usize {
serde_json::to_string(checkpoint)
.map(|value| value.chars().count())
.unwrap_or(usize::MAX)
}
fn truncate(value: &str, max_chars: usize) -> String {
value.trim().chars().take(max_chars).collect()
}
fn head_tail(value: &str, max_chars: usize) -> String {
let count = value.chars().count();
if count <= max_chars {
return value.to_string();
}
let separator = "\n...[middle omitted]...\n";
let remaining = max_chars.saturating_sub(separator.chars().count());
let head = remaining / 3;
let tail = remaining.saturating_sub(head);
format!(
"{}{}{}",
value.chars().take(head).collect::<String>(),
separator,
value
.chars()
.skip(count.saturating_sub(tail))
.collect::<String>()
)
}
const fn checkpoint_version() -> u32 {
1
}
#[cfg(test)]
mod tests {
use runtime_ports::{ModelContent, ModelRole};
use super::*;
#[test]
fn active_checkpoint_requires_next() {
let invalid = r#"{"version":1,"goal":{"objective":"task"},"done":[],"state":{"phase":"implementing","summary":"editing"},"watch":[],"next":[]}"#;
assert_eq!(
parse_and_validate(invalid).unwrap_err().code,
"CHECKPOINT_INVALID"
);
}
#[test]
fn invalid_candidate_falls_back_to_unverified_recent_evidence() {
let messages = vec![ModelMessage {
role: ModelRole::Tool,
content: vec![ModelContent::ToolResult {
tool_use_id: "one".into(),
name: "write".into(),
content: "changed file.rs".into(),
failed: false,
}],
}];
let compiled = compile_checkpoint(Some("not-json"), &messages, "task", 4_000).unwrap();
let encoded = serde_json::to_string(&compiled.message).unwrap();
assert!(compiled.used_fallback);
assert!(encoded.contains("changed_unverified"));
assert!(encoded.contains("changed file.rs"));
assert!(!encoded.contains("\"phase\":\"verified\""));
}
}