Post opencode activity log (tool calls + reasoning) as a PR comment (#2)
Switch the real 'Run agent' step to --format json (replacing the two TEMP/DEBUG schema-discovery commits da6f0d5/d0ddb06), capture the raw event stream, and reconstruct the plain-text reply from the assistant 'text' parts so the existing Publish logic is unchanged. Add a 'Build activity log' step that filters the event stream to tool_use (with truncated title/input) and text (reasoning) events. The Publish step posts that trail as a separate collapsible comment on the PR thread (dev agents only — comment-only roles do no tool calls). This is additive to the existing summary/PR-description comment. Reasoning reuse on a follow-up run is free: the existing 'fetch full issue thread' step already re-feeds all prior comments (including this new log comment) into the next run's prompt, so the agent sees what it did last time.
This commit is contained in:
+48
-29
@@ -174,29 +174,6 @@ jobs:
|
|||||||
"### comment by \($who):\n\(.body)\n"' > /tmp/thread.md 2>/dev/null || true
|
"### comment by \($who):\n\(.body)\n"' > /tmp/thread.md 2>/dev/null || true
|
||||||
echo "thread comments fetched: $(grep -c '^### comment by ' /tmp/thread.md 2>/dev/null || echo 0)"
|
echo "thread comments fetched: $(grep -c '^### comment by ' /tmp/thread.md 2>/dev/null || echo 0)"
|
||||||
|
|
||||||
# TEMPORARY: capture opencode's --format json event schema and POST it as an issue comment
|
|
||||||
# (easier to find than reusable-workflow step logs). Removed once captured.
|
|
||||||
- name: DEBUG capture --format json schema
|
|
||||||
env:
|
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
||||||
GT: ${{ secrets.GITEA_TOKEN }}
|
|
||||||
NUM: ${{ github.event.issue.number }}
|
|
||||||
run: |
|
|
||||||
cd /tmp && rm -f probe.txt
|
|
||||||
opencode run --model anthropic/claude-sonnet-5 --auto --format json \
|
|
||||||
"Create a file /tmp/probe.txt containing the word hi, then say one sentence about what you did." \
|
|
||||||
> /tmp/events.jsonl 2>/tmp/events.err || true
|
|
||||||
n=$(wc -l < /tmp/events.jsonl)
|
|
||||||
types=$(jq -rc '.type // (keys|join("+"))' /tmp/events.jsonl 2>/dev/null | sort | uniq -c)
|
|
||||||
examples=$(jq -s -c 'map(select(type=="object" and .type!=null)) | group_by(.type) | map(.[0])[]' /tmp/events.jsonl 2>/dev/null | cut -c1-700)
|
|
||||||
[ -z "$examples" ] && examples=$(head -c 3000 /tmp/events.jsonl)
|
|
||||||
body=$(printf 'DEBUG opencode --format json — %s events\n\n**types:**\n```\n%s\n```\n\n**one example per type:**\n```\n%s\n```\n\n**stderr tail:**\n```\n%s\n```' \
|
|
||||||
"$n" "$types" "$examples" "$(tail -8 /tmp/events.err)")
|
|
||||||
API="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}"
|
|
||||||
curl -sS -X POST -H "Authorization: token $GT" -H "Content-Type: application/json" \
|
|
||||||
"$API/issues/$NUM/comments" -d "$(jq -nc --arg b "$body" '{body:$b}')" \
|
|
||||||
-w '\ndebug comment -> HTTP %{http_code}\n' || true
|
|
||||||
|
|
||||||
- name: Run agent
|
- name: Run agent
|
||||||
id: run
|
id: run
|
||||||
env:
|
env:
|
||||||
@@ -288,22 +265,55 @@ jobs:
|
|||||||
LATEST INSTRUCTION FROM MAINTAINER:
|
LATEST INSTRUCTION FROM MAINTAINER:
|
||||||
${CMT}"
|
${CMT}"
|
||||||
echo "opencode version: $(opencode --version 2>&1)"
|
echo "opencode version: $(opencode --version 2>&1)"
|
||||||
# Success is exit code 0 — the agent may make tool-only changes with no text summary,
|
# Capture the raw JSON event stream (--format json) so the activity log can be built
|
||||||
# so DO NOT treat empty stdout as failure. Only retry a non-zero exit that looks transient.
|
# from it afterwards. The plain --auto reply text == concatenation of all assistant
|
||||||
|
# "text" parts, so reconstruct /tmp/agent_out.md from those — the Publish step below
|
||||||
|
# keeps reading agent_out.md exactly as before. Success is exit code 0: the agent may
|
||||||
|
# make tool-only changes with no text summary, so DO NOT treat empty output as failure.
|
||||||
rc=1
|
rc=1
|
||||||
for attempt in 1 2 3; do
|
for attempt in 1 2 3; do
|
||||||
echo "opencode attempt $attempt/3 for @$NAME ($MODEL)"
|
echo "opencode attempt $attempt/3 for @$NAME ($MODEL)"
|
||||||
rc=0
|
rc=0
|
||||||
opencode run --model "$MODEL" --auto "$PROMPT" ${{ steps.imgs.outputs.files }} \
|
opencode run --model "$MODEL" --auto --format json "$PROMPT" ${{ steps.imgs.outputs.files }} \
|
||||||
>/tmp/agent_out.md 2>/tmp/agent_err.log || rc=$?
|
>/tmp/events.jsonl 2>/tmp/agent_err.log || rc=$?
|
||||||
echo "rc=$rc"; echo "--- stdout (reply) ---"; cat /tmp/agent_out.md; echo "--- stderr (trace) ---"; cat /tmp/agent_err.log
|
echo "rc=$rc"; echo "--- events ($(wc -l < /tmp/events.jsonl 2>/dev/null || echo 0) lines) ---"
|
||||||
|
echo "--- stderr (trace) ---"; cat /tmp/agent_err.log
|
||||||
[ $rc -eq 0 ] && break
|
[ $rc -eq 0 ] && break
|
||||||
if grep -qiE 'overloaded|429|529|rate.?limit|timeout|ETIMEDOUT|ECONNRESET|EAI_AGAIN' /tmp/agent_out.md /tmp/agent_err.log; then
|
if grep -qiE 'overloaded|429|529|rate.?limit|timeout|ETIMEDOUT|ECONNRESET|EAI_AGAIN' /tmp/events.jsonl /tmp/agent_err.log; then
|
||||||
echo "transient error — backing off $((attempt*20))s"; sleep $((attempt * 20)); continue
|
echo "transient error — backing off $((attempt*20))s"; sleep $((attempt * 20)); continue
|
||||||
fi
|
fi
|
||||||
echo "non-transient failure (rc=$rc) — not retrying"; break
|
echo "non-transient failure (rc=$rc) — not retrying"; break
|
||||||
done
|
done
|
||||||
[ $rc -eq 0 ] || { echo "agent failed"; exit 1; }
|
[ $rc -eq 0 ] || { echo "agent failed"; exit 1; }
|
||||||
|
# Reconstruct the plain-text reply from assistant text parts (== what plain --auto prints).
|
||||||
|
jq -r 'select(.type=="text") | .part.text // ""' /tmp/events.jsonl > /tmp/agent_out.md 2>/dev/null || true
|
||||||
|
echo "reconstructed reply ($(wc -l < /tmp/agent_out.md 2>/dev/null || echo 0) lines):"; cat /tmp/agent_out.md
|
||||||
|
|
||||||
|
- name: Build activity log (tool calls + reasoning) from the event stream
|
||||||
|
id: log
|
||||||
|
env:
|
||||||
|
MODE: ${{ steps.prep.outputs.mode }}
|
||||||
|
run: |
|
||||||
|
# Only dev agents (mode=pr) get an activity-log comment — comment-only roles (pm/qa)
|
||||||
|
# do no tool calls, so a trail would be empty/noise.
|
||||||
|
if [ "$MODE" != "pr" ]; then
|
||||||
|
echo "skipping activity log for comment-mode agent"; : > /tmp/activity_log.md; exit 0
|
||||||
|
fi
|
||||||
|
jq -r '
|
||||||
|
def trunc(n): if length > n then (.[0:n] + "…") else . end;
|
||||||
|
select(.type=="tool_use" or .type=="text") |
|
||||||
|
if .type=="text" then
|
||||||
|
"💬 " + ((.part.text // "") | trunc(4000))
|
||||||
|
else
|
||||||
|
(.part.tool // "?") as $t |
|
||||||
|
((.part.state.title // (.part.state.input | tojson | trunc(160)) // "")) as $title |
|
||||||
|
"🔧 **" + $t + "**: `" + ($title | trunc(240)) + "`"
|
||||||
|
end
|
||||||
|
' /tmp/events.jsonl > /tmp/activity_log.md 2>/dev/null || true
|
||||||
|
n=$(wc -l < /tmp/activity_log.md 2>/dev/null || echo 0)
|
||||||
|
echo "activity log: $n entries"
|
||||||
|
[ "$n" -eq 0 ] && : > /tmp/activity_log.md
|
||||||
|
head -3 /tmp/activity_log.md
|
||||||
|
|
||||||
- name: Publish — PR (dev agents) or comment (pm), always reply in the issue
|
- name: Publish — PR (dev agents) or comment (pm), always reply in the issue
|
||||||
env:
|
env:
|
||||||
@@ -464,6 +474,15 @@ jobs:
|
|||||||
post "$(printf '🤖 **@%s** — updated %s branch/PR:%b\n\n%s' "$NAME" "$count" "$links" "$prdesc")"
|
post "$(printf '🤖 **@%s** — updated %s branch/PR:%b\n\n%s' "$NAME" "$count" "$links" "$prdesc")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Post the agent's activity trail (tool calls + reasoning) as a separate comment so
|
||||||
|
# it is visible on the PR thread. Additive — kept here even when nothing changed, so a
|
||||||
|
# follow-up run (re-trigger) can see what this run did via the fetched issue thread.
|
||||||
|
if [ -s /tmp/activity_log.md ]; then
|
||||||
|
entries=$(wc -l < /tmp/activity_log.md 2>/dev/null || echo 0)
|
||||||
|
log=$(cat /tmp/activity_log.md)
|
||||||
|
post "$(printf '🤖 **@%s** — activity log (%s entries):\n<details>\n<summary>tool calls & reasoning</summary>\n\n%s\n\n</details>' "$NAME" "$entries" "$log")"
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Mark done with 🚀 (remove 👀)
|
- name: Mark done with 🚀 (remove 👀)
|
||||||
env:
|
env:
|
||||||
GT: ${{ secrets.GITEA_TOKEN }}
|
GT: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|||||||
Reference in New Issue
Block a user