feat(achievements): add export endpoint and agent summary (#18472) - #58015
feat(achievements): add export endpoint and agent summary (#18472)#58015rlaope wants to merge 5 commits into
Conversation
…ch#18472) Implement the export & agent-communication workstream from the achievements upgrades spec (issue NousResearch#18472, spec PR NousResearch#18151): - GET /export?format=json|markdown|svg&state=... renders the current snapshot as machine-readable JSON, a README-pasteable Markdown badge table (shields.io badges + progress bars, unlocked-only by default), or an SVG badge sheet with tier-colored markers. Unknown formats return a 400 JSON error. - GET /achievements/summary returns the compact agent profile (strengths, gaps, top tier, unlocked ids, session/tool totals). - agent_summary.json is written next to state.json after every finished scan (best-effort) and removed on /reset-state, so agents and external tools can read the profile without the dashboard running. - filter_and_sort_achievements() is the minimal state-filter seam that the filtering/sorting workstream in NousResearch#18472 can extend with category, sort, and limit parameters. SVG output escapes badge names/tiers to keep markup out of rendered sheets. The agent summary path uses get_hermes_home() rather than a hardcoded ~/.hermes so Windows-aware homes keep working. FastAPI response classes are stubbed in the no-FastAPI fallback so the plugin unit tests keep running without dashboard dependencies. Tested: python3 -m unittest discover -s tests (21 tests: 13 new for filtering, JSON/Markdown/SVG formatters, escaping, agent summary builder, and agent_summary.json persistence; 8 existing engine tests unchanged), plus an async endpoint smoke over stubbed snapshot data.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for implementing the export/agent-summary thread as a focused change to the existing achievements plugin.
Problems
- The PR updates
plugins/hermes-achievements/README.md, but the canonical built-in-plugin page has its own API and state-file tables atwebsite/docs/user-guide/features/built-in-plugins.md:257-274. Those tables would omit both new routes andagent_summary.json. plugins/hermes-achievements/tests/test_export_and_summary.pytests the rendering helpers and direct persistence only; it does not callexport_achievements()orachievements_summary(). The route-level 400 contract and the Markdown/SVG media types therefore lack coverage.
Suggested changes
- Update the built-in-plugin documentation table alongside the plugin README.
- Add endpoint tests with a stubbed
evaluate_all()covering JSON, Markdown, SVG, summary, and an unsupported format.
This is an automated hermes-sweeper review.
| ```text | ||
| GET /achievements | ||
| GET /achievements/summary | ||
| GET /export?format=json|markdown|svg&state=unlocked|discovered|secret |
There was a problem hiding this comment.
Please update website/docs/user-guide/features/built-in-plugins.md too. Its canonical achievements API/state-file tables currently end at /reset-state and scan_checkpoint.json, so this route and agent_summary.json would be undocumented there.
There was a problem hiding this comment.
Updated the canonical built-in plugin page in commit 959e62d. The achievements API table now documents GET /achievements/summary and GET /export with its format/state parameters, and the state-file table includes agent_summary.json.
Signed-off-by: rlaope <105429536+rlaope@users.noreply.github.com>
GottZ
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
Summary
Two PRs address the same achievements export and agent-communication workstream: both add JSON/Markdown/SVG export, a compact agent summary endpoint, and persisted agent_summary.json; #58015 additionally updates the canonical built-in-plugin documentation.
Related pull requests
- #58012 [closed]
duplicate— (+405/-0) — superseded duplicate: Implements the reported export and agent-summary surfaces with helper and persistence tests, but it was closed so the work could be reopened from the author's main account as #58015; it remains relevant as the source-equivalent predecessor. - #58015
related— (+408/-0) — keep open with a salvage path: The diff implements the export routes, summary generation, persisted agent_summary.json, reset cleanup, rendering tests, and the canonical documentation update requested by the keep_open review. That review's remaining concern is still valid because the tests do not invoke export_achievements() or achievements_summary(), leaving response status, payload, and media-type contracts uncovered.
Duplicates
#58012 and #58015 contain substantially the same implementation; #58012 is the closed predecessor superseded by #58015, whose additional change updates website/docs/user-guide/features/built-in-plugins.md.
Suggested consolidation
Keep #58015 open with a salvage path: retain its focused export, summary, persistence, tests, and canonical documentation changes, then add endpoint-level tests with evaluate_all() stubbed for JSON, Markdown, SVG, summary, and unsupported-format behavior, as required by the visible keep_open review. Treat the already-closed #58012 as a duplicate superseded by #58015; no merge recommendation is supported by the recorded verification.
Complex graph
flowchart LR
classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
classDef best stroke-width:3px,stroke:#b45309
classDef target stroke-width:3px,stroke:#4338ca
subgraph Dup58012 ["PRs duplicating each other"]
P58012["PR #58012 (closed)"]
P58015["PR #58015 (open)"]
end
class P58012 closed
class P58015 open
class P58015 target
click P58012 "https://github.com/NousResearch/hermes-agent/pull/58012"
click P58015 "https://github.com/NousResearch/hermes-agent/pull/58015"
Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).
Cross-PR triage: Reviewed 2 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 41 kB of PR diffs, 8 kB of issue/PR text, 1 kB of discussion (2 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.
…evel The existing tests exercised the rendering helpers and persistence only, so the route contracts were uncovered: the 400 response for an unsupported format and the text/markdown and image/svg+xml media types could regress silently. Drive export_achievements() and achievements_summary() directly with evaluate_all() stubbed, asserting status codes, media types, and payloads for JSON, Markdown, SVG, summary, and an unsupported format.
|
Added the requested endpoint-level coverage in The previous tests exercised the rendering helpers and persistence only, so the route contracts were uncovered. The new
Verification: 17 passed in The canonical built-in-plugin doc table at |
…ort-agent-summary
Bare Path.read_text()/write_text() fall back to locale.getpreferredencoding() — cp1252/cp936 on Windows — so the UTF-8 agent_summary.json artifact writes mojibake or raises UnicodeDecodeError there. Pin encoding="utf-8" on the persist path and its test read, per the NousResearch#71014 read_text campaign.
|
Follow-up: rebased onto current The checker gained the
Both now pin Verification: |
What does this PR do?
Implements the export & agent-communication workstream from the achievements upgrades tracking issue (#18472, spec in closed PR #18151). Achievements are currently trapped in
state.jsonand the dashboard tab; this adds the two surfaces the spec defines for getting them out:GET /api/plugins/hermes-achievements/export?format=json|markdown|svg&state=...— renders the current snapshot as machine-readable JSON, a README-pasteable Markdown badge table (shields.io badges +██░░progress bars, unlocked badges by default), or an SVG badge sheet with tier-colored markers. Unknown formats return a 400 JSON error instead of guessing.GET /api/plugins/hermes-achievements/achievements/summary— the compact agent profile from the spec (strengths,gaps,top_tier,unlocked_ids,unlocked_count,total_count, session/tool totals), small enough for context injection.agent_summary.json— the same payload is written next tostate.jsonafter every finished scan (best-effort, never fails the scan) and removed on/reset-state, so agents and external tools can read the profile without the dashboard running.Scope notes, per the issue's guidance that the four workstreams land as separate PRs:
filter_and_sort_achievements()is added as the minimal state-filter seam the export formatters need; the filtering/sorting workstream can extend the same function withcategory/sort_by/limitwithout rework.hermes achievementsCLI and TUI panel workstream is intentionally not included here; the CLI's export path can delegate to these formatters when it lands.Two small deviations from the spec's reference snippets, both deliberate:
agent_summary.jsonwrite used a hardcodedPath.home() / ".hermes"; this PR uses the existingget_hermes_home()helper soHERMES_HOMEoverrides and platform-aware homes keep working (same direction as fix: replace hardcoded ~/.hermes fallbacks with platform-aware Windows paths #57216 / fix(profiles): replace hardcoded ~/.hermes paths with get_hermes_home() #26508).FastAPI response classes are stubbed in the existing no-FastAPI fallback so the plugin's dependency-free unit tests keep working.
(Supersedes #58012 — same change, reopened from my main account.)
Related Issue
Addresses the export/agent-summary section of #18472 (spec: #18151).
Type of Change
Changes Made
plugins/hermes-achievements/dashboard/plugin_api.py: addTIER_ORDER,agent_summary_path(),filter_and_sort_achievements(),export_json(),export_markdown(),export_svg(),_build_agent_summary(),_write_agent_summary(); new/exportand/achievements/summaryroutes; writeagent_summary.jsonin_run_scan_and_update_cache(); clear it in/reset-state; stubJSONResponse/PlainTextResponsein the FastAPI fallback.plugins/hermes-achievements/tests/test_export_and_summary.py: 13 new unit tests (state filtering, JSON structure/filter, Markdown header/categories/badges/bad-timestamp handling, SVG rows/escaping/empty sheet, agent summary strengths/gaps/top-tier/empty data,agent_summary.jsonpersistence).plugins/hermes-achievements/README.md: document the new endpoints and theagent_summary.jsonartifact.How to Test
cd plugins/hermes-achievements && python3 -m unittest discover -s tests -v— 21 tests (13 new + 8 existing engine tests) pass without dashboard dependencies.curl 'localhost:<port>/api/plugins/hermes-achievements/export?format=markdown'→ Markdown badge tablecurl 'localhost:<port>/api/plugins/hermes-achievements/export?format=svg' > badges.svg→ renderable badge sheetcurl 'localhost:<port>/api/plugins/hermes-achievements/achievements/summary'→ compact profile$HERMES_HOME/plugins/hermes-achievements/agent_summary.jsonexists after the scan and disappears afterPOST /reset-state.