ci / lint (pull_request) Successful in 17s
opencode ships a built-in `xai` model-catalog entry (a real @ai-sdk/xai integration with Responses-API support). Naming our custom OpenAI-compatible shim `xai` too made opencode's --auto permission-check path assume the catalog's provider object once a `permission` block is present (always, in this pipeline) and call .responses(), which our shim doesn't implement — crashing every @lead/@ops run with "Z.responses is not a function". Reproduced locally with the production config shape on opencode 1.17.13; renaming the provider key to xai-oc (model id xai-oc/grok-4.5) fixes it reliably across repeated fresh-state runs.
58 lines
3.2 KiB
Bash
Executable File
58 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build the RUN REPORT appended to the agent's reply comment: the TOOL CALLS the agent made plus a
|
|
# usage line (input / output tokens + $ cost). Written to /tmp/activity_log.md; the Publish step
|
|
# appends it to the agent's reply. Applies to EVERY agent — @pm/@qa also call tools and cost money.
|
|
#
|
|
# opencode --format json emits one JSON event per line. `step_finish` events carry, per LLM step,
|
|
# .part.tokens {input, output, reasoning, cache:{read, write}} and .part.cost (USD, already computed
|
|
# by opencode from the model's pricing). We sum them across all steps of the run. Models without
|
|
# pricing (e.g. self-hosted ollama) report cost 0 — shown as $0.0000.
|
|
#
|
|
# Required env (provided by the workflow step): (none needed; reads /tmp/events.jsonl)
|
|
set -u
|
|
E=/tmp/events.jsonl
|
|
: > /tmp/activity_log.md
|
|
[ -s "$E" ] || { echo "no events — empty report"; exit 0; }
|
|
|
|
# Tool calls = the ACTIONS taken (not the agent's prose text parts).
|
|
jq -r '
|
|
def trunc(n): if length > n then (.[0:n] + "…") else . end;
|
|
select(.type=="tool_use") |
|
|
(.part.tool // "?") as $t |
|
|
((.part.state.title // (.part.state.input | tojson | trunc(160)) // "")) as $title |
|
|
"🔧 **" + $t + "**: `" + ($title | trunc(240)) + "`"
|
|
' "$E" > /tmp/tools.md 2>/dev/null || true
|
|
n=$(wc -l < /tmp/tools.md 2>/dev/null || echo 0); n=${n:-0}
|
|
|
|
# Usage: sum per-step tokens + cost across every step_finish event (tab-separated for `read`).
|
|
read -r COST INP OUT CR CW RE < <(jq -rs '
|
|
[ .[] | select(.type=="step_finish") | .part ] as $s
|
|
| [ ([$s[].cost // 0]|add // 0),
|
|
([$s[].tokens.input // 0]|add // 0),
|
|
([$s[].tokens.output // 0]|add // 0),
|
|
([$s[].tokens.cache.read // 0]|add // 0),
|
|
([$s[].tokens.cache.write // 0]|add // 0),
|
|
([$s[].tokens.reasoning // 0]|add // 0) ]
|
|
| @tsv' "$E" 2>/dev/null)
|
|
COST=${COST:-0}; INP=${INP:-0}; OUT=${OUT:-0}; CR=${CR:-0}; CW=${CW:-0}; RE=${RE:-0}
|
|
IN_TOTAL=$(( INP + CR + CW )) # total input context processed
|
|
# Cost label: ollama / ollama-cloud models are SUBSCRIPTION-billed (GPU-time against the plan, no
|
|
# $/token price exists), so a "$0.0000" there would be misleading — label it a subscription instead.
|
|
# Metered providers (xai-oc/…) get the real dollar cost opencode computed.
|
|
case "${MODEL:-}" in
|
|
ollama*|*"/ollama"*) COSTF="subscription" ;;
|
|
*) COSTF=$(awk -v c="$COST" 'BEGIN{printf "$%.4f", c+0}') ;;
|
|
esac
|
|
echo "usage: in=$IN_TOTAL out=$OUT cost=$COSTF (fresh=$INP cache_r=$CR cache_w=$CW reasoning=$RE); tools=$n"
|
|
|
|
# ONE uniform format for every agent comment (with or without tool calls): a collapsed dropdown
|
|
# with a STATIC "details" label — identical everywhere — holding the tool calls (or a none-note)
|
|
# and the full token/cost breakdown.
|
|
{
|
|
printf '\n\n<details>\n<summary>details</summary>\n\n'
|
|
printf '🔧 %s tool calls · in %s · out %s tokens · %s · model %s\n\n' "$n" "$IN_TOTAL" "$OUT" "$COSTF" "${MODEL:-?}"
|
|
if [ "$n" -gt 0 ]; then cat /tmp/tools.md; else printf '_(no tool calls — text-only reply)_\n'; fi
|
|
printf '\n\n<sub>tokens — input %s (fresh %s · cache %sw / %sr) · output %s · reasoning %s · **%s**</sub>\n</details>' \
|
|
"$IN_TOTAL" "$INP" "$CW" "$CR" "$OUT" "$RE" "$COSTF"
|
|
} > /tmp/activity_log.md
|