ae940f45644971d5937b755d2459eceffeb6500a
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
88b9373fa9 |
feat(auto-agents): LLM activity scraper + cost dashboard wiring
Closes the cost-tracking instrumentation gap: the telemetry console's Cost tab read from an empty ``llm_activity`` table because nothing in production wrote to it. The scraper walks the OpenCode session archives that ``_opencode_worker`` already writes (including subagent trees via the BFS-walked ``parentID`` chain) and emits one row per assistant turn. Folded into the existing PR-State Warmer loop so it runs on the same 30s cadence without spinning a new sidecar. Schema (v6): - ``llm_activity`` grows ``session_id`` / ``message_id`` / ``provider`` / ``parent_session_id`` / ``subagent_depth`` columns - Partial UNIQUE INDEX on ``message_id`` makes re-scrapes idempotent - v5→v6 migration ALTER-gated on column existence (safe to re-run) Scraper (``tools/llm_activity_scraper.py``): - Reads ``.dispatcher-logs/sessions/*.json``, one row per assistant turn - Folds reasoning tokens into ``tokens_out`` and cache-write into ``tokens_in`` (preserves raw breakdown in ``raw`` JSON for future cost-calc refinements) - Normalises ``subagent_depth=0`` at top level so dashboards can filter ``WHERE subagent_depth > 0`` cleanly - Batch INSERT OR IGNORE via new ``PipelineCache.upsert_llm_activity_batch`` — one fsync per archive, not per turn Warmer integration: - First tick: full backfill of the archive directory - Subsequent ticks: 1h lookback via ``since=`` filter - Scraper failures are logged and swallowed — PR-state job stays load-bearing and unaffected - ``LLM_ACTIVITY_SCRAPER_DISABLE=1`` env kill switch Renames (mechanical, atomic): - ``tools/_forgejo_cache.py`` → ``tools/_pipeline_cache.py`` - ``ForgejoCache`` class → ``PipelineCache`` - Both reflect the module's broader scope (Forgejo data + pipeline telemetry tables); on-disk filename ``forgejo.sqlite`` and ``FORGEJO_*`` env vars are kept for compatibility Verified end-to-end on real archives: 435 archives → 3595 turns ingested (2873 from subagents) across 8 models / 5 providers / 9 PRs. Re-runs insert 0, dedup 3595. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
19dad571bd |
feat(auto-agents): bounded comment view + digest, persistent cache, claim-sweep through cache
Three coordinated changes addressing run-8 finding R8-3 ("PR #30's
1440 comments poison the pipeline via prompt size × chain depth"):
Spec #5 — bounded view + deterministic digest. The prompt and
sentinel now embed at most DEFAULT_MAX_PROMPT_COMMENTS=50 verbatim
comments plus a one-paragraph rollup of the older bot attempt
comments (counts by tier / outcome / failing gates / last success).
_build_comments_section takes the most-recent N (comments[-N:]) not
the oldest — a long-standing bug where the worker on heavy PRs saw
ancient history and missed every recent attempt. Bot status / claim
/ sentinel comments are dropped from the view via author-based
classification (HAL9000 / HAL9001 defaults, FORGEJO_USERNAME /
FORGEJO_REVIEWER_USERNAME env overrides) — a content-only
classifier mis-counted them as "humans" and ballooned the view to
1252 items on the real test case (run-10 inspection).
Spec #5 (R8-5) — persistent comment cache fixes. Seed-on-truncation:
a page-cap-truncated fetch now seeds the cache (clipped but valid)
flagged any_partial_fetch=True. since_cursor replaces wall-clock
fetched_at as the ?since= delta cursor so backfill walks forward
from the newest cached comment instead of skipping the un-fetched
middle. _api_get_paginated gains an opt-in return_truncation=True
shape so the cache can distinguish "transient failure" (don't seed)
from "page cap hit" (seed and backfill next cycle).
Spec #6 — claim-sweep routes through the comment cache.
_claim_runtime._find_newest_claim_at used to paginate every page of
issue comments on every cycle (29 sequential round-trips for #30,
~10+ minutes when Forgejo was slow — see run-9 hang diagnosis). It
now reads from _pr_comments_cache.get_pr_comments and reverse-scans
for the marker with early-exit. get_pr_comments grew optional
owner/repo overrides so callers with a narrower RuntimeContext cfg
(no owner/repo attrs) can share the cache. Fail-safe on
completed=False: when the timeline is incomplete and no marker was
found, return datetime.now() so the sweep keeps the claim this
cycle rather than releasing on partial data.
Run-11 verification (PR #30 end-to-end):
- Dispatcher startup -> first cycle log: 12+ min hang -> 9 s
- pr_comments view len in sentinel: 1252 (run-10) -> 50 (run-11)
- pr_comments_digest populated with full tier/outcome/gates rollup
- data_complete=True; 4 implementer sessions ran cleanly
Tests green: 1603 passed / 3 skipped. New test files:
test_attempt_history.py, test_implementer_prefetch.py. New tests
added in test_pr_comments_cache.py, test_claim_runtime.py,
test_implementer_pr_context_cli.py, test_implementer_prompt_snapshot.py,
test_pr_context_sentinel.py.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
703a7c9090 |
feat(auto-agents): Phase A — conflict_drive.py deterministic conflict-resolution driver
Implement Tier 1.5 conflict resolution as a peer driver to merge_drive.py that honours the same hard invariant: every commit on master came from a SHA whose CI passed against the exact current master. New components - tools/conflict_drive.py: deterministic driver that picks PRs labelled auto/needs-conflict-resolution, claims them via the shared auto/claimed-merge label, attempts a deterministic rebase with deepen-on-demand fallback, dispatches conflict-resolver-worker on conflict, force-pushes with --force-with-lease, and clears the label for merge_drive to re-pick. Includes 24h retry budget, escalation to auto/needs-implementer, single-instance lock + heartbeat, opt-in TOCTOU mitigations (CONFLICT_DRIVER_CYCLE_JITTER_SECONDS, CONFLICT_DRIVER_VERIFY_CLAIM), startup TTL constraint and required- labels assertions, and full SQLite telemetry. - tools/_claim_runtime.py: shared HTTP/lock/heartbeat/claim primitives extracted from merge_drive.py (driver-aware claim/release markers, injectable op_label_map). merge_drive re-exports for back-compat. - tools/_opencode_worker.py: blocking Python client for the OpenCode HTTP API with O(N) string-aware bracket matcher for tolerant JSON extraction from worker output. - .opencode/agents/conflict-resolver-worker.md: subagent definition with tight permissions and "always finish, never abort, never --skip" doctrine. - tools/inject_synthetic_conflict.py: CLI that creates PRs on a test fork with guaranteed conflicts (trivial / multi-commit / unresolvable) for end-to-end testing. Telemetry & dashboard - tools/_forgejo_cache.py: new conflict_drive_cycles table, cycle-level escalated_count, indexed retry-budget query, mark_*_escalated helper. - tools/render-pr-velocity.py + pr-velocity.canvas.template.tsx: conflict-resolution activity section showing 7-day cycle counts, resolved/escalated/timeout/push-rejected breakdowns. Open-issue dependency check - tools/merge_drive.py: pr_is_eligible now consults Forgejo's blocks endpoint and applies auto/blocked-by-deps when any open dependency exists. Read-only predicate _pr_has_open_dependencies; label mutations live with the eligibility caller. - tools/setup_auto_labels.py: provisions auto/blocked-by-deps. Documentation - docs/development/conflict-drive-plan.md: full plan including TOCTOU race documentation (§3.3.1) with implementation/test pointers. - AGENTS.md: operator-facing section on conflict_drive.py and the expanded label registry. Tests - 300 unit tests pass / 1 skipped (opt-in fork integration test). - Coverage includes JSON extractor fuzz, push-stderr classification, PAT scrub, deepen-on-demand fallback, retry budget escalation, cycle-level escalated_count stamping, claim collision detection (latest-claim-only with marker-primary identity), jitter wiring, and verify_claim_after_apply plumbing. Quality invariant unchanged: conflict_drive.py only operates on PR head branches, never on master. CI gating on the train-merge SHA continues to enforce the exact-current-master rule for everything that lands. Co-authored-by: Cursor <cursoragent@cursor.com> |