Skip to content

Commit 4988632

Browse files
committed
feat(agent-org): add durable pause and resume handoff
Persist Pause episodes and per-Turn handoff receipts so a Team can stop formal work immediately, drain runtimes safely, and resume only work that remains legal after restart or concurrent state changes. Add runtime leases, generation-fenced Inbox and Task boundaries, one-shot continuation dispatch, paused Group Chat enforcement, push-driven draining UI, strict-provider task_update schemas, and rendered recovery coverage. Verification: - cargo test -p agent_core (3175 passed, 2 ignored) - cargo clippy -p agent_core --all-targets -- -D warnings - pnpm vitest run (1116 files, 8767 tests) - pnpm typecheck and changed-file ESLint - BuildFast packaged app with 20/20 ten-runtime Pause/Resume samples - codexharry GPT-5.4 Mini packaged-app Pause/restart/Resume smoke Pre-commit hook ran. Total eslint: 5, total circular: 0
1 parent a22c362 commit 4988632

81 files changed

Lines changed: 5704 additions & 989 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_drain.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,20 +303,31 @@ impl AgentInboxStore {
303303
/// Used by the turn-processor drain hook after rendering the
304304
/// attachment, so the next turn's drain returns an empty list.
305305
pub fn mark_many_read(ids: &[i64]) -> Result<usize, String> {
306-
Self::mark_many_read_internal(ids, None)
306+
Self::mark_many_read_internal(ids, None, None)
307307
}
308308

309309
/// Production acknowledgement for transcript-backed delivery. Only the
310310
/// Session that owns every row's durable materialization receipt may mark
311311
/// it read. A stale Guard from an older/replaced Session therefore cannot
312312
/// acknowledge a row after ownership moved elsewhere.
313313
pub fn mark_many_read_for_session(ids: &[i64], session_id: &str) -> Result<usize, String> {
314-
Self::mark_many_read_internal(ids, Some(session_id))
314+
Self::mark_many_read_internal(ids, Some(session_id), None)
315+
}
316+
317+
/// Formal Turn acknowledgement guarded by the exact current lifecycle
318+
/// generation inside the same IMMEDIATE write transaction.
319+
pub fn mark_many_read_for_turn(
320+
ids: &[i64],
321+
session_id: &str,
322+
turn_intent_id: &str,
323+
) -> Result<usize, String> {
324+
Self::mark_many_read_internal(ids, Some(session_id), Some(turn_intent_id))
315325
}
316326

317327
fn mark_many_read_internal(
318328
ids: &[i64],
319329
materialization_session_id: Option<&str>,
330+
formal_turn_intent_id: Option<&str>,
320331
) -> Result<usize, String> {
321332
if ids.is_empty() {
322333
return Ok(0);
@@ -327,6 +338,15 @@ impl AgentInboxStore {
327338
let tx = conn
328339
.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)
329340
.map_err(|err| err.to_string())?;
341+
if let (Some(session_id), Some(turn_intent_id)) =
342+
(materialization_session_id, formal_turn_intent_id)
343+
{
344+
crate::coordination::agent_org_turn_contexts::validate_formal_turn_generation_with_connection(
345+
&tx,
346+
session_id,
347+
turn_intent_id,
348+
)?;
349+
}
330350
let now = chrono::Utc::now().to_rfc3339();
331351
let mut updated = 0usize;
332352
let mut changed_run_ids = HashSet::new();

0 commit comments

Comments
 (0)