MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / record_turn

Function record_turn

atomic-agent/src/record/mod.rs:138–508  ·  view source on GitHub ↗

Record an agent turn as an Atomic change. This is the function that bridges the agent world into the VCS world. It builds a `ChangeHeader`, `Provenance`, and `SessionEnvelope`, then calls the repository's `record()` method to create a proper content-addressed, hashable, pushable Atomic change. # Arguments `repo_root` — Path to the repository root (where `.atomic/` lives). The repository is open

(
    repo_root: &Path,
    options: &TurnRecordOptions<'_>,
)

Source from the content-addressed store, hash-verified

136/// (no files changed since the last recorded state).
137/// Returns `AgentError::RecordFailed` if the repository record operation fails.
138pub fn record_turn(
139 repo_root: &Path,
140 options: &TurnRecordOptions<'_>,
141) -> AgentResult<TurnRecordOutcome> {
142 let manifest = scope::manifest(options)?;
143 if let Some(files) = &manifest {
144 scope::validate(repo_root, files, options)?;
145 if files.is_empty() {
146 return Err(AgentError::EmptyTurn {
147 session_id: options.session.session_id.clone(),
148 turn_number: options.turn_number,
149 });
150 }
151 }
152 // Step 1: Open the repository read-only for the initial status check.
153 // This can coexist with other readers. Wait for a transient incompatible
154 // writer before deciding whether work or untracked files exist.
155 let mut repo = atomic_repository::Repository::open_readonly_wait(
156 repo_root,
157 std::time::Duration::from_secs(10),
158 )
159 .map_err(|e| AgentError::RecordFailed {
160 session_id: options.session.session_id.clone(),
161 turn_number: options.turn_number,
162 reason: format!("Failed to open repository (readonly): {}", e),
163 })?;
164
165 // `status()` reads current_view, while `record()` writes to session.view_name.
166 // Align the read-only handle before the first status check; this keeps the
167 // no-lock fast path and prevents direct callers from seeing false EmptyTurn.
168 repo.set_current_view_in_memory(&options.session.view_name);
169
170 // Step 2: Status — find out what the agent changed.
171 // Include untracked files because agent turns commonly create new source,
172 // config, and test files. Those must be auto-added before recording so the
173 // turn produces an Atomic change with provenance instead of leaving files
174 // untracked in the working copy.
175 let status = repo
176 .status(atomic_repository::status::StatusOptions::fast().with_untracked(true))
177 .map_err(|e| AgentError::RecordFailed {
178 session_id: options.session.session_id.clone(),
179 turn_number: options.turn_number,
180 reason: format!("Failed to get repository status: {}", e),
181 })?;
182
183 let status = scope::filter(status, manifest.as_ref());
184
185 // Check if there's anything to record at all
186 if status.is_clean() && status.untracked_count() == 0 {
187 return Err(AgentError::EmptyTurn {
188 session_id: options.session.session_id.clone(),
189 turn_number: options.turn_number,
190 });
191 }
192
193 // Step 3: Add — track any new files the agent created
194 // Agents create new files all the time (new modules, tests, configs).
195 // These show up as "untracked" in status. We add them before recording

Calls 15

validateFunction · 0.85
filterFunction · 0.85
should_ignore_untrackedFunction · 0.85
build_turn_headerFunction · 0.85
build_turn_provenanceFunction · 0.85
build_turn_messageFunction · 0.85
build_turn_envelopeFunction · 0.85
build_unhashed_turn_dataFunction · 0.85
attach_unhashedFunction · 0.85
with_untrackedMethod · 0.80
as_refMethod · 0.80