Skip to content

feat(jobs): push/resume coordinator + /resume (milestone 3) - #87

Merged
shoom1 merged 1 commit into
developfrom
feature/job-resume-coordinator
Jun 18, 2026
Merged

feat(jobs): push/resume coordinator + /resume (milestone 3)#87
shoom1 merged 1 commit into
developfrom
feature/job-resume-coordinator

Conversation

@shoom1

@shoom1 shoom1 commented Jun 18, 2026

Copy link
Copy Markdown
Owner

Summary

Milestone 3 of phase-2 push/resume (design: docs/plans/2026-06-15-job-push-resume-design.md). Builds on the association layer (#85) and the ADK execution primitive (#86). This closes the loop end to end (ADK): when a finished long-running job opted in (resume_on_complete), the agent is automatically resumed with its result — no polling.

What it adds

Coordinator (cli/app.py)BaseCLIApp.resume_finished_jobs() drains JobManager.awaiting_resume() into serialized resume turns: one turn at a time via a new self._turn_lock (a user turn and a resume turn never overlap — shared session + thinking boxes), marking each resumed before running so a crash can't double-fire. Called at turn boundaries when job_auto_resume is on, and by /resume on demand (ungated).

Rendering (cli/message_processor.py)process_resume() streams workflow.resume_with_job_result(record) through the exact same path as a user turn. Factored the shared turn machinery (events box, HITL callback, Ctrl+C cancel, rate-limit retry, token accounting) out of process() into _run_turn(source_factory); process and process_resume are now thin wrappers.

Gating / UXjob_auto_resume setting (default off); /resume command (ResumeCommand); JobMonitor shows ↻N to resume in the status bar when enabled. examples/jobs_demo.py sets job_auto_resume=True to demo it.

Why turn-boundary (not spontaneous mid-idle)

Running a full agent turn's output from a background task while the user sits at the live prompt is display-unsafe (the milestone-2 constraint: thinking_prompt boxes are turn-oriented, add_* prints directly). v1 resumes right after the current/next user turn, plus /resume. The status-bar cue tells the user a resume is waiting. (Spontaneous idle wake is a possible gated v2.)

Testing

  • tests/cli/test_resume_coordinator.py — drain resumes each awaiting job once; marks resumed before processing; returns 0 when not ready / no JobManager.
  • tests/cli/test_job_monitor.py↻N to resume cue shown only when job_auto_resume and there are pending unresumed jobs.
  • Live full-loop (tests/integration/test_live_job_resume.py::test_full_resume_loop_via_coordinator, @pytest.mark.llm) — drives the real coordinator: turn 1 starts the job → job finishes → resume_finished_jobsprocess_resumeresume_with_job_resultmodel reacts, rendered into a RecordingSession. Passes.
  • Offline suite: 1582 passed, 26 xfailed. The 3 live tests pass against Gemini.

Scope

The coordinator and association layer are backend-agnostic; only resume_with_job_result is ADK-specific so far. LangGraph resume is milestone 5 (update_state with a ToolMessage keyed by call_id). Restart recovery (resuming jobs that finished while the CLI was down) is the remaining milestone-4 item.

Closes the push/resume loop end to end (ADK). When a finished long-running job
opted in (resume_on_complete), the agent is auto-resumed with its result — no
polling.

- BaseCLIApp.resume_finished_jobs(): drains JobManager.awaiting_resume() into
  serialized resume turns (one at a time via a new _turn_lock; marks resumed
  before running so a crash can't double-fire). Called at turn boundaries when
  job_auto_resume is on, and by /resume on demand (ungated).
- MessageProcessor.process_resume(): streams resume_with_job_result through the
  exact same rendering as a user turn. Factored the shared turn machinery
  (events box, HITL callback, Ctrl+C cancel, retry, token accounting) out of
  process() into _run_turn(source_factory).
- job_auto_resume setting (default off); /resume command (ResumeCommand);
  JobMonitor shows "↻N to resume" when enabled.
- examples/jobs_demo.py sets job_auto_resume=True to demo the feature.

Tests: coordinator drain/order/guards with fakes (tests/cli/test_resume_
coordinator.py); status-bar resume cue (tests/cli/test_job_monitor.py); and a
live full-loop test driving the real coordinator -> process_resume ->
resume_with_job_result -> model (tests/integration/test_live_job_resume.py::
test_full_resume_loop_via_coordinator). Offline 1582 passed; 3 live tests pass.

The coordinator + association are backend-agnostic; only resume_with_job_result
is ADK-specific so far. LangGraph resume is milestone 5.
@shoom1
shoom1 merged commit 697fa63 into develop Jun 18, 2026
@shoom1
shoom1 deleted the feature/job-resume-coordinator branch June 18, 2026 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant