From b450e6545366c1845da809e5034150a3a5198b5b Mon Sep 17 00:00:00 2001 From: Carl Niklas Rydberg Date: Sun, 8 Feb 2026 09:55:01 +0100 Subject: [PATCH] wg --- README.md | 2 +- scripts/ai_agent_loop.sh | 100 +++++++++++++++++++++++++++------------ vendor/amduat-api | 2 +- 3 files changed, 73 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 6237922..1ce3693 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ AI lane notes: - Plan and scope guardrails: `docs/ai-plan.md` - Deterministic seed payload: `ai/fixtures/seed_batch.json` -- Agent loop checkpoints: `ai/runs/agent-run-*.json` +- Agent loop checkpoints: `ai/runs/agent-run-*.json` (updated at start, each planner step, and completion with `status` + timestamps) Run integration coverage (requires running `amduatd` + `jq`): diff --git a/scripts/ai_agent_loop.sh b/scripts/ai_agent_loop.sh index 9e04960..7b0e595 100755 --- a/scripts/ai_agent_loop.sh +++ b/scripts/ai_agent_loop.sh @@ -70,6 +70,65 @@ append_step() { steps_json="$(jq -c --argjson step "${step_json}" '. + [$step]' <<<"${steps_json}")" } +write_run_state() { + local status="$1" + local stop_reason_value="$2" + local final_answer_value="$3" + + local now_iso + now_iso="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" + local completed_at="" + if [[ "${status}" == "completed" ]]; then + completed_at="${now_iso}" + fi + + local run_json_local + run_json_local="$(jq -nc \ + --arg run_id "${run_id}" \ + --arg started_at "${started_at}" \ + --arg updated_at "${now_iso}" \ + --arg completed_at "${completed_at}" \ + --arg status "${status}" \ + --arg question "${question}" \ + --arg initial_roots_csv "${initial_roots_csv}" \ + --arg initial_goals_csv "${initial_goals_csv}" \ + --arg final_roots_csv "${roots_csv}" \ + --arg final_goals_csv "${goals_csv}" \ + --arg stop_reason "${stop_reason_value}" \ + --argjson current_step "${step_no}" \ + --argjson max_steps "${max_steps}" \ + --argjson require_evidence "$( [[ "${require_evidence}" == "1" ]] && echo true || echo false )" \ + --argjson steps "${steps_json}" \ + --argjson final_answer "${final_answer_value}" \ + '{ + run_id:$run_id, + status:$status, + started_at:$started_at, + updated_at:$updated_at, + completed_at:(if $completed_at == "" then null else $completed_at end), + input:{ + question:$question, + roots_csv:$initial_roots_csv, + goals_csv:$initial_goals_csv, + require_evidence:$require_evidence + }, + planner:{ + current_step:$current_step, + max_steps:$max_steps + }, + final_query:{ + roots_csv:$final_roots_csv, + goals_csv:$final_goals_csv + }, + stop_reason:$stop_reason, + steps:$steps, + final_answer:$final_answer + }')" + + printf '%s\n' "${run_json_local}" > "${state_file}" + RUN_JSON="${run_json_local}" +} + extract_plan_json() { local model_out="$1" local raw_plan @@ -203,6 +262,7 @@ app_init ensure_daemon_ready run_id="$(date +%Y%m%d-%H%M%S)-$$" +started_at="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" if [[ -z "${state_file}" ]]; then mkdir -p "${ROOT_DIR}/ai/runs" state_file="${ROOT_DIR}/ai/runs/agent-run-${run_id}.json" @@ -211,11 +271,16 @@ fi steps_json="[]" final_answer_json="" stop_reason="max_steps_reached" +initial_roots_csv="${roots_csv}" +initial_goals_csv="${goals_csv}" +RUN_JSON="" step_no=1 +write_run_state "running" "${stop_reason}" "null" while (( step_no <= max_steps )); do retrieve_out="$(app_retrieve_with_fallback "${roots_csv}" "${goals_csv}")" || { stop_reason="retrieve_failed" + write_run_state "running" "${stop_reason}" "null" break } context_stats="$(jq -c '{nodes:(.nodes // [] | length), edges:(.edges // [] | length)}' <<<"${retrieve_out}")" @@ -233,6 +298,7 @@ while (( step_no <= max_steps )); do --argjson plan "${plan_json}" \ '{step:$step,roots_csv:$roots_csv,goals_csv:$goals_csv,context:$context,plan:$plan}')" append_step "${step_record}" + write_run_state "running" "${stop_reason}" "null" if [[ "${plan_action}" == "refine_query" ]]; then if [[ -n "${next_roots}" ]]; then @@ -247,15 +313,18 @@ while (( step_no <= max_steps )); do if [[ "${plan_action}" == "stop" ]]; then stop_reason="planner_stop" + write_run_state "running" "${stop_reason}" "null" break fi if final_answer_json="$(app_ai_answer_json "${roots_csv}" "${question}" "${goals_csv}" "${require_evidence}")"; then stop_reason="answered" + write_run_state "running" "${stop_reason}" "${final_answer_json}" break fi stop_reason="answer_failed" + write_run_state "running" "${stop_reason}" "null" break done @@ -263,35 +332,8 @@ if [[ -z "${final_answer_json}" ]]; then final_answer_json="$(jq -nc --arg msg "Agent loop ended without answer (${stop_reason})." '{response:$msg,done_reason:"agent_stopped"}')" fi -run_json="$(jq -nc \ - --arg run_id "${run_id}" \ - --arg question "${question}" \ - --arg initial_roots_csv "$1" \ - --arg initial_goals_csv "${3:-}" \ - --arg final_roots_csv "${roots_csv}" \ - --arg final_goals_csv "${goals_csv}" \ - --arg stop_reason "${stop_reason}" \ - --argjson require_evidence "$( [[ "${require_evidence}" == "1" ]] && echo true || echo false )" \ - --argjson steps "${steps_json}" \ - --argjson final_answer "${final_answer_json}" \ - '{ - run_id:$run_id, - input:{ - question:$question, - roots_csv:$initial_roots_csv, - goals_csv:$initial_goals_csv, - require_evidence:$require_evidence - }, - final_query:{ - roots_csv:$final_roots_csv, - goals_csv:$final_goals_csv - }, - stop_reason:$stop_reason, - steps:$steps, - final_answer:$final_answer - }')" - -printf '%s\n' "${run_json}" > "${state_file}" +write_run_state "completed" "${stop_reason}" "${final_answer_json}" +run_json="${RUN_JSON}" if [[ "${output_mode}" == "json" ]]; then printf '%s\n' "${run_json}" diff --git a/vendor/amduat-api b/vendor/amduat-api index 4fa7c32..0ae2c8d 160000 --- a/vendor/amduat-api +++ b/vendor/amduat-api @@ -1 +1 @@ -Subproject commit 4fa7c321174fc4021fc1bc23a9a8d414b3ba2ec8 +Subproject commit 0ae2c8d74a85bbcb633e711fb1cf84d0516bdc3b