Skip to content

feat(hermes): implement create_executor() with HERMES_API_KEY / OPENROUTER_API_KEY fallback + smoke tests - #49

Merged
HongmingWang-Rabbit merged 2 commits into
mainfrom
feat/hermes-pr2
Apr 14, 2026
Merged

feat(hermes): implement create_executor() with HERMES_API_KEY / OPENROUTER_API_KEY fallback + smoke tests#49
HongmingWang-Rabbit merged 2 commits into
mainfrom
feat/hermes-pr2

Conversation

@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor

Summary

Hermes adapter PR 2 — implements create_executor() in workspace-template/adapters/hermes/ with the key-resolution order CEO specified, plus a smoke test suite.

Changes

  • workspace-template/adapters/hermes/executor.py (+153) — create_executor(hermes_api_key=None) factory. Resolution order:
    1. hermes_api_key parameter if passed directly
    2. HERMES_API_KEY env var → routes to Nous Portal
    3. OPENROUTER_API_KEY env var → routes to OpenRouter
    4. None available → ValueError with clear message
  • workspace-template/adapters/hermes/__init__.py (+3) — exports create_executor
  • workspace-template/adapters/hermes/adapter.py (+42/-7) — integrates the new factory
  • workspace-template/tests/test_hermes_smoke.py (+84) — smoke test suite

Test plan

  • Local test run by Dev Lead before this branch was committed: 17/17 passed, 0 failures
  • CI to re-validate (Platform Go, Canvas, MCP, E2E, Shellcheck, Python Lint/Test)
  • Manual: workspace with only OPENROUTER_API_KEY set → create_executor() returns valid executor
  • Manual: workspace with neither key set → raises ValueError with actionable message

Authorship / chain of custody

Implemented by Dev Lead agent (commit author Dev Lead Agent on 791def3) on 2026-04-13 during the first successful Hermes integration cycle after the private-repo clone blocker was resolved. Patch was applied locally for review before pushing; now opening the PR per the always-push workflow.

Related:

  • Hermes PR 1 (already merged) — adapter scaffold
  • Future Hermes PR 3 — wire create_executor() into the workspace runtime as a selectable runtime option

🤖 Generated with Claude Code

Dev Lead Agent and others added 2 commits April 13, 2026 16:47
…back

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds HERMES_API_KEY to .env.example with a cross-reference to the
OPENROUTER_API_KEY fallback, and adds the hermes runtime row to the
CLAUDE.md runtime table so the new adapter is discoverable alongside
its siblings (langgraph, claude-code, openclaw, crewai, autogen,
deepagents).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor Author

7-gate verification — PASS

  • Gate 1 (CI): 6 pass + 1 skip (Canvas Deploy Reminder) after doc-fix push.
  • Gate 2 (Build): Python import OK; no platform Go changes in this PR.
  • Gate 3 (Tests): tests/test_hermes_smoke.py — 9/9 passed locally. Full Python suite green in CI.
  • Gate 4 (Security): Key-resolution fails loud with ValueError when neither HERMES_API_KEY nor OPENROUTER_API_KEY is set — no silent anonymous fallback. Base URLs are well-known constants with comments. No committed secrets, no token logging (only debug-level "using X env var" messages, no key material). No retry loop to cap.
  • Gate 5 (Design): Follows sibling-runtime adapter pattern (create_executor() factory + HermesA2AExecutor with execute/cancel), reuses adapters.shared_runtime helpers. Mechanical doc gaps fixed in 56068a7:
    • .env.example: added HERMES_API_KEY with OpenRouter-fallback cross-ref.
    • CLAUDE.md runtime table: added hermes row.
  • Gate 6 (Line review): create_executor is ~50 lines, single responsibility, clear precedence chain. Proper async patterns via openai.AsyncOpenAI. Errors surface as readable "Hermes error: " strings on the event queue. Tests cover all four resolution branches (param, HERMES env, OpenRouter fallback, ValueError).
  • Gate 7: N/A (no canvas changes).

Not-noteworthy by cron policy — new LLM runtime, billing is on the user's own API key. Merging with --merge --delete-branch.

@HongmingWang-Rabbit
HongmingWang-Rabbit merged commit a2ea1b1 into main Apr 14, 2026
7 checks passed
@HongmingWang-Rabbit
HongmingWang-Rabbit deleted the feat/hermes-pr2 branch April 14, 2026 15:16
HongmingWang-Rabbit pushed a commit that referenced this pull request Apr 14, 2026
…_KEY)

The hermes config required NOUS_API_KEY but the executor
(workspace-template/adapters/hermes/executor.py from PR #49) checks
HERMES_API_KEY and OPENROUTER_API_KEY. A workspace created from this
template would have the provisioner block on a missing NOUS_API_KEY
even when HERMES_API_KEY was set, or pass provisioning but fail at
executor init. .env.example already documents HERMES_API_KEY.

Fix: rename the required_env entry to HERMES_API_KEY and update the
comments to match the executor's actual fallback order (HERMES_API_KEY
first, OPENROUTER_API_KEY second).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
molecule-ai Bot pushed a commit that referenced this pull request Apr 21, 2026
feat(hermes): implement create_executor() with HERMES_API_KEY / OPENROUTER_API_KEY fallback + smoke tests
molecule-ai Bot pushed a commit that referenced this pull request Apr 21, 2026
…_KEY)

The hermes config required NOUS_API_KEY but the executor
(workspace-template/adapters/hermes/executor.py from PR #49) checks
HERMES_API_KEY and OPENROUTER_API_KEY. A workspace created from this
template would have the provisioner block on a missing NOUS_API_KEY
even when HERMES_API_KEY was set, or pass provisioning but fail at
executor init. .env.example already documents HERMES_API_KEY.

Fix: rename the required_env entry to HERMES_API_KEY and update the
comments to match the executor's actual fallback order (HERMES_API_KEY
first, OPENROUTER_API_KEY second).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
molecule-ai Bot pushed a commit that referenced this pull request Apr 23, 2026
SEO Analyst cron references docs/marketing/seo/keywords.md but the file
was missing. Created with all 12 keywords from PR #49 (all Published).
Assigned owners: Content Marketer (8), DevRel Engineer (2), PMM (2).
Status: Brief needed on all 12.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
HongmingWang-Rabbit pushed a commit that referenced this pull request Jun 12, 2026
…kly/monthly)

Extends the single monthly per-workspace budget to four independent ROLLING
windows so a workspace can be capped per hour/day/week/month (#49 — gives the
canvas Budget tab a real lever against runaway LLM spend, e.g. the reno-stars
opus drain). SSOT design:

- budget_periods.go = single source of truth: the period set + rolling windows,
  one FILTERed per-period spend query over the ledger, and the PURE
  parse/encode/exceededPeriods logic. Add a period = one line here.
- migration: workspaces.budget_limits jsonb (canonical config, backfilled from
  the legacy monthly budget_limit) + workspace_spend_events ledger.
- heartbeat (registry.go): derive the spend INCREMENT from the agent's existing
  cumulative report (delta vs prev; reset-aware) → ledger row. Server owns
  windowing; NO runtime change.
- budget.go GET/PATCH: per-period limit/spend/remaining; accepts the new
  {budget_limits:{...}} shape AND the legacy {budget_limit} (→ monthly); legacy
  response fields still emitted + budget_limit kept synced (rollout back-compat).
  A limit of 0 = block-all (preserved); null/absent = no limit.
- a2a_proxy.go checkWorkspaceBudget: 402 if ANY configured period's rolling
  window spend >= its limit; fail-open on DB error.
- canvas BudgetSection: four period rows (USD limit input + spend/limit + bar).

Tests: pure SSOT (parse/encode/exceededPeriods); GET/PATCH + multi-period +
A2A enforcement (sqlmock, migrated to the new two-query flow); shared
expectBudgetCheck helpers updated; canvas behavioral + per-period progress/aria.
go build + vet + full handlers suite + migrations + canvas vitest all green.

NOTE: the duplicate components/__tests__/BudgetSection.test.tsx (old single-limit
UI) was repurposed to a focused per-period progress/aria suite — behavioral
coverage now lives in tabs/__tests__/BudgetSection.test.tsx (one component, no
parallel identical suites).

Refs #49.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant