Skip to content

Rl capabilities && File Operator Tools - #15

Merged
teknium1 merged 6 commits into
mainfrom
rl-capabilities
Feb 5, 2026
Merged

Rl capabilities && File Operator Tools#15
teknium1 merged 6 commits into
mainfrom
rl-capabilities

Conversation

@teknium1

@teknium1 teknium1 commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Initial RL training toolset and complete file operations toolset (to make it operate much more like a coding agent)

- Updated `.env.example` to include Tinker and WandB API keys for reinforcement learning training.
- Enhanced `model_tools.py` to clarify configuration options and streamline the RL training process.
- Expanded `README.md` with detailed instructions for setting up RL training using Tinker and WandB.
- Modified `hermes_cli` files to integrate RL training tools and ensure proper configuration checks.
- Improved `rl_training_tool.py` to reflect changes in training parameters and configuration management.
- Added the tinker-atropos submodule for enhanced RL training capabilities.
- Updated model_tools.py to reorder RL function definitions and improve descriptions.
- Modified rl_cli.py to include checks for the tinker-atropos setup and provide user guidance.
- Adjusted toolsets.py and __init__.py to reflect changes in RL function availability.
- Enhanced rl_training_tool.py to manage training processes directly without a separate API server.
- Modified `model_tools.py` to update default model IDs and add new RL function `rl_test_inference`.
- Enhanced `README.md` with installation instructions for submodules and updated API key usage.
- Improved `rl_cli.py` to load configuration from `~/.hermes/config.yaml` and set terminal working directory for RL tools.
- Updated `run_agent.py` to handle empty string arguments as empty objects for better JSON validation.
- Refined installation scripts to ensure submodules are cloned and installed correctly, enhancing setup experience.
… streaming

- Added unique run ID generation for WandB tracking during test inference.
- Enabled WandB usage for test tracking and updated command-line arguments accordingly.
- Implemented real-time output streaming for process execution, improving log visibility and debugging.
- Enhanced error handling to display last few lines of stderr for better troubleshooting.
- Introduced file manipulation capabilities in `model_tools.py`, including functions for reading, writing, patching, and searching files.
- Added a new `file` toolset in `toolsets.py` and updated distributions to include file tools.
- Enhanced `setup-hermes.sh` and `install.sh` scripts to check for and optionally install `ripgrep` for faster file searching.
- Implemented a new `file_operations.py` module to encapsulate file operations using shell commands.
- Updated `doctor.py` and `install.ps1` to check for `ripgrep` and provide installation guidance if not found.
- Added fuzzy matching and patch parsing capabilities to improve file manipulation accuracy and flexibility.
@teknium1
teknium1 merged commit 8dd3831 into main Feb 5, 2026
@taeyun16

Copy link
Copy Markdown

🔍 자동 분석 결과

이슈 요약

리더보드 시스템 — 주간/월간/지역별 순위로 경쟁 유도 + 보상 제공

기술 구현 고려사항

백엔드 (Phoenix/Ash)

  • 리더보드 스냅샷: weekly_leaderboards (period_start, period_end, category)
  • 순위 계산: (Oban, 매주 월요일 00:00 KST)
    • WeeklyVoteKing: 주간 투표 수 top 100
    • MonthlyCollector: 월간 신규 고양이 수집 top 100
    • StreakChampion: 연속 투표 최장 기간 top 100
    • RegionalRank: PostGIS ST_DWithin로 지역 필터링
  • 순위 변동 추적: leaderboard_changes (user_id, change_amount, direction)
  • 보상 지급: period结束时 자동 + 배지 발송

iOS (SwiftUI)

  • 리더보드 탭: (segmented: 주간/월간/지역)
  • 순위 Cell: (rank, avatar, name, score, change delta)
  • 내 순위 고정: sticky bottom bar — "내 순위: 15위 / 234명"
  • 변경 알림: 순위 진입/변동 시 토스트 + 햅틱

우선순위 제안

  1. Phase 1: 주간 투표왕 (가장 단순 — existing vote_count 활용)
  2. Phase 2: 지역별 순위 (PostGIS regional 쿼리 의존)
  3. Phase 3: 월간 수집왕 (고양이 도감 완료 후)
  4. Phase 4: 연속 기록왕 (Streak 시스템 통합)

관련existing 코드

  • — 아직 없으면 Streak worker 패턴 참고
  • Regional ranking: PostGIS queries

🤖 HanNyang Auto Resolver

h4x3rotab pushed a commit to Clawdi-AI/hermes-agent that referenced this pull request Apr 10, 2026
h4x3rotab pushed a commit to Clawdi-AI/hermes-agent that referenced this pull request Apr 10, 2026
* fix: cross-platform terminal/browser support and build fixes

- Use platform-aware default shell (zsh on macOS, bash on Linux/Windows)
  instead of hardcoding /bin/zsh everywhere
- Mark Playwright packages as external in Vite to fix chromium-bidi
  bundle errors during dev
- Copy pty-helper.py to dist/server/assets/ on build so production
  server can find it
- Fix browser launch guard to check `context` instead of `browser`
  (which is always null with launchPersistentContext)
- Exclude unused diagnostics.ts stub from route tree
- Update README with Playwright install step and Extra section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add Ubuntu/Debian prerequisites for Tauri desktop build

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
h4x3rotab pushed a commit to Clawdi-AI/hermes-agent that referenced this pull request Apr 10, 2026
Previously hermes-api.ts helper functions (hermesGet, hermesPost,
hermesPatch, hermesDeleteReq, streamChat) sent no Authorization header,
causing 401 'Invalid API key' errors when the gateway has API_SERVER_KEY
configured.

Also exports BEARER_TOKEN from gateway-capabilities.ts so hermes-api.ts
can import and reuse it for auth headers.

Co-authored-by: mgnyc11 <mgnyc11@users.noreply.github.com>
@zhangtobybot-a11y

Copy link
Copy Markdown

已合并到 PR #45

1 similar comment
@zhangtobybot-a11y

Copy link
Copy Markdown

已合并到 PR #45

malaiwah pushed a commit to malaiwah/hermes-agent that referenced this pull request Apr 11, 2026
…ameter + schema property' (NousResearch#15) from fix/terminal-notify-on-complete into main
angelburgosrosado pushed a commit to angelburgosrosado/hermes-agent that referenced this pull request Apr 27, 2026
difeizheng pushed a commit to difeizheng/zdf-hermes-agent that referenced this pull request Jun 3, 2026
Fixes 12 remaining MEDIUM issues from the deep audit (19 total, 7 fixed in Round 12):

design_agent:
- NousResearch#15: add asyncio.wait_for(300s) around LLM API call to prevent infinite hangs
- NousResearch#17: replace 2x hardcoded 'claude-opus-4-8' with shared DEFAULT_MODEL constant

qa_agent / validate_agent:
- NousResearch#20,NousResearch#22,NousResearch#23: already fixed in Round 12 (verified — dynamic timeout/threshold values used)

memory.py:
- NousResearch#24: frontmatter parser uses regex r'^---$' instead of str.split('---',2),
  preventing false splits on content containing '---' (SQL, markdown tables)
- NousResearch#25: parse and preserve 'description' field from frontmatter in metadata,
  fixing write→load roundtrip data loss

profiles.py:
- NousResearch#26: ProfileConfig now frozen=True (immutable dataclass per coding standards)

deploy_agent:
- NousResearch#31: replace 2x sync subprocess.run with asyncio.create_subprocess_exec
- fix 5x .decode() → .decode('utf-8', errors='replace') for Windows CJK safety
- remove unused import subprocess

db.py:
- NousResearch#27: add class docstring explaining RLock + _unlocked pattern
- NousResearch#28: FK constraints already in DDL (verified PRAGMA foreign_keys=ON active)
- NousResearch#29: add _ensure_connection() with PRAGMA integrity_check(1) + auto-reconnect
       on 4 critical methods (create_task, get_task, claim_task, submit_result)
- extract _create_connection() static method for reuse by reconnect

Tests: 79 passed, 0 failed
xzmzm added a commit to xzmzm/hermes-agent that referenced this pull request Jun 3, 2026
@hutchutchutch

Copy link
Copy Markdown

Refactor progress on PR #15 file operations, fifth slice: extracted read/delete/move behavior into tools/file_operations_read.py and moved shared result dataclasses into tools/file_operations_results.py while preserving tools.file_operations exports and ShellFileOperations wrapper methods. Commit: a20c28974 (refactor(file-ops): extract read and file actions). Validation: py_compile for touched modules; focused file-operation/parser/live suite 241 passed; standard gateway batches 265 passed and 115 passed; git diff --check clean. Current line counts: tools/file_operations.py 879, read 221, results 82, search 380, lint 339, support 164.

@hutchutchutch

Copy link
Copy Markdown

Refactor progress on PR #15 file operations, sixth slice: extracted write/patch mutation behavior into tools/file_operations_write.py and moved the abstract FileOperations interface into tools/file_operations_interface.py. Commit: 80da36609 (refactor(file-ops): extract write and patch actions). Validation: py_compile for touched modules; focused mutation/read/parser/LSP suite 284 passed; standard gateway batches 265 passed and 115 passed; git diff --check clean. The original hotspot is now under target: tools/file_operations.py 476 lines; interface 75; write 222; read 221; results 82; search 380; lint 339; support 164.

@hutchutchutch

Copy link
Copy Markdown

Progress update for PRD #15:

Implemented the next file-tool refactor slice in e6683b654 (refactor(file-tools): extract tracker state).

What changed:

  • Added tools/file_tools_state.py for read dedup state, read timestamp/staleness helpers, read tracker cap enforcement, and patch failure tracking.
  • Kept tools.file_tools as the compatibility adapter: existing private names like _read_tracker, _read_tracker_lock, _patch_failure_tracker, _cap_read_tracker_data, _check_file_staleness, reset_file_dedup, and notify_other_tool_call remain importable from tools.file_tools.
  • Preserved legacy monkeypatch behavior for _READ_HISTORY_CAP, _DEDUP_CAP, and _READ_TIMESTAMPS_CAP by syncing patched adapter constants into the state module before cap enforcement.

Line counts after this slice:

  • tools/file_tools.py: 1435 lines, down from 1671 before this slice.
  • tools/file_tools_state.py: 249 lines.

Validation:

  • python -m py_compile tools/file_tools.py tools/file_tools_state.py
  • focused tracker/read/staleness suite with TMPDIR rooted under /Users/home/.hermes/tmp-pytest-hermes-agent-issue15 -> 89 passed
  • tests/tools/test_gateway_cwd_contract.py with the same non-sensitive temp root -> 4 passed
  • Standard gateway batch A -> 265 passed
  • Standard gateway batch B -> 115 passed
  • git diff --check / staged diff check clean

Notes:

  • A combined path/cwd batch hit existing test-state leakage where one test left live cwd cache state for a reused task id; tests/tools/test_gateway_cwd_contract.py passes in isolation.
  • tests/tools/test_file_tools.py still has the existing macOS /tmp vs /private/tmp expectation mismatch on three mocked write/patch assertions; this predates and is unrelated to the tracker-state extraction.

@hutchutchutch

Copy link
Copy Markdown

Progress update for PRD #15:

Implemented another file-tool refactor slice in 6c6ead02f (refactor(file-tools): extract path safety helpers).

What changed:

  • Added tools/file_tools_paths.py for cwd resolution, TERMINAL_CWD sentinel handling, live cwd lookup, path-resolution warnings, blocked-device checks, sensitive path checks, Hermes config path resolution, and cross-profile/container mirror guards.
  • Kept tools.file_tools as the compatibility adapter for existing private imports and monkeypatches, including _resolve_path_for_task, _path_resolution_warning, _is_blocked_device, _is_blocked_device_path, _check_sensitive_path, _check_cross_profile_path, and _hermes_config_resolved/_hermes_config_resolved_loaded.
  • Preserved live file-ops cache lookup through a small adapter so path helpers do not own the file-ops cache.

Line counts after this slice:

  • tools/file_tools.py: 1139 lines, down from 1435 after the previous slice and 1671 before today.
  • tools/file_tools_paths.py: 313 lines.
  • tools/file_tools_state.py: 249 lines.

Validation:

  • python -m py_compile tools/file_tools.py tools/file_tools_paths.py tools/file_tools_state.py
  • focused tracker/read/staleness suite with TMPDIR rooted under /Users/home/.hermes/tmp-pytest-hermes-agent-issue15 -> 89 passed
  • focused Hermes config sensitive-path compatibility class -> 5 passed
  • tests/tools/test_gateway_cwd_contract.py with the non-sensitive temp root -> 4 passed
  • Standard gateway batch A -> 265 passed
  • Standard gateway batch B -> 115 passed
  • git diff --check / staged diff check clean

Notes:

  • The combined path/cwd batch still hits the existing order-dependent live cwd cache leakage for a reused task id; the affected cwd contract file passes in isolation.
  • This slice keeps the upstream-facing tool function names and private test patch points intact to reduce nightly merge risk.

@hutchutchutch

Copy link
Copy Markdown

Progress update for PRD #15:

Implemented the third file-tools slice in 37c3bdd13 (refactor(file-tools): extract env cache helpers).

What changed:

  • Added tools/file_tools_env.py for terminal-environment-backed ShellFileOperations creation and cache population.
  • Kept tools.file_tools as the compatibility adapter for _get_file_ops, _file_ops_lock, _file_ops_cache, and clear_file_ops_cache so existing tests and monkeypatches continue to target the same module.
  • The new helper receives the existing cache, lock, ShellFileOperations factory, and logger as arguments; it does not own the public cache state.

Line counts after this slice:

  • tools/file_tools.py: 1031 lines, down from 1139 after the path slice and 1671 before today.
  • tools/file_tools_env.py: 129 lines.
  • tools/file_tools_paths.py: 313 lines.
  • tools/file_tools_state.py: 249 lines.

Validation:

  • python -m py_compile tools/file_tools.py tools/file_tools_env.py tools/file_tools_paths.py tools/file_tools_state.py
  • focused env/cache/read/staleness suite with TMPDIR rooted under /Users/home/.hermes/tmp-pytest-hermes-agent-issue15 -> 80 passed
  • focused cwd/container suite -> 32 passed
  • Standard gateway batch A -> 265 passed
  • Standard gateway batch B -> 115 passed
  • git diff --check / staged diff check clean

This continues the low-merge-risk pattern: move implementation behind small modules while preserving the old tools.file_tools import and patch surface.

@hutchutchutch

Copy link
Copy Markdown

Progress update for PRD #15:

Implemented the next file-tools slice in 9a3e19b4d (refactor(file-tools): extract read handler).

What changed:

  • Added tools/file_tools_read.py for the read_file_tool implementation: pagination normalization, device guard, extractable document handling, binary/read safety guards, dedup/stub-loop handling, max-character guard, redaction, large-file hinting, and file-state read registration.
  • Kept tools.file_tools.read_file_tool as the registered compatibility wrapper.
  • The wrapper injects existing adapter functions/state (_get_file_ops, _get_max_read_chars, _resolve_path_for_task, _cap_read_tracker_data, _read_tracker, _read_tracker_lock), so existing tests and monkeypatches keep targeting tools.file_tools.

Line counts after this slice:

  • tools/file_tools.py: 788 lines, down from 1031 before this slice and 1671 before today.
  • tools/file_tools_read.py: 246 lines.
  • Existing extracted helpers remain under target: env 129, paths 313, state 249.

Validation:

  • python -m py_compile tools/file_tools.py tools/file_tools_read.py tools/file_tools_env.py tools/file_tools_paths.py tools/file_tools_state.py
  • focused read guards / read loop / read_extract / file_state registry suite -> 98 passed
  • tests/tools/test_file_staleness.py -> 11 passed
  • tests/agent/test_file_safety_credentials.py -> 20 passed
  • tests/tools/test_file_tools.py::TestReadFileHandler -> 4 passed
  • Standard gateway batch A -> 265 passed
  • Standard gateway batch B -> 115 passed
  • git diff --check / staged diff check clean

Note:

  • One intentionally broad combined read/staleness batch still hit the known order-dependent live cwd cache leakage; the affected staleness test passes in isolation and the focused stale suite passes fully.

@hutchutchutch

Copy link
Copy Markdown

Progress update for PRD #15:

Implemented the next file-tools slice in 6138eaa1a (refactor(file-tools): extract search handler).

What changed:

  • Added tools/file_tools_search.py for the search_files implementation: pagination normalization, repeated-search loop guard, ShellFileOperations search dispatch, match redaction, warning/hint formatting, and structured error handling.
  • Kept tools.file_tools.search_tool as the compatibility wrapper.
  • The wrapper injects existing adapter functions/state (_get_file_ops, normalize_search_pagination, _read_tracker, _read_tracker_lock), so existing tests and monkeypatches keep targeting tools.file_tools.

Line counts after this slice:

  • tools/file_tools.py: 741 lines, down from 788 after the read slice and 1671 before today.
  • tools/file_tools_search.py: 95 lines.

Validation:

  • python -m py_compile tools/file_tools.py tools/file_tools_search.py
  • tests/tools/test_file_tools.py::TestSearchHandler + tests/tools/test_read_loop_detection.py::TestSearchLoopDetection -> 13 passed
  • Standard gateway batch A -> 265 passed
  • Standard gateway batch B -> 115 passed
  • git diff --check / staged diff check clean

Next remaining PR #15 seam is the write/patch mutation handler block; extracting that should bring tools/file_tools.py close to or under the 500-line target.

@hutchutchutch

Copy link
Copy Markdown

Progress update for PRD #15:

Implemented the mutation/schema slice in 50e42d119 (refactor(file-tools): extract mutation handlers).

What changed:

  • Added tools/file_tools_mutation.py for write_file_tool and patch_tool implementation: sensitive/cross-profile guards, stale warnings, file_state locks, read timestamp refresh, files_modified/resolved_path reporting, V4A traversal guard, and patch failure escalation hints.
  • Added tools/file_tools_schemas.py for static file tool schemas.
  • Kept tools.file_tools.write_file_tool, tools.file_tools.patch_tool, _handle_write_file, and _handle_patch as compatibility/registry wrappers.
  • Restored compatibility re-exports for _detect_line_ending and _normalize_line_endings from tools.file_operations after the earlier support-helper extraction.

Line counts after this slice:

  • tools/file_tools.py: 455 lines (under the ~500 target; down from 1671 before today).
  • tools/file_operations.py: 478 lines (still under target).
  • New helper modules remain small: mutation 235, schemas 103, search 95, read 246, env 129, paths 313, state 249.

Validation:

  • python -m py_compile tools/file_operations.py tools/file_tools.py tools/file_tools_mutation.py tools/file_tools_schemas.py and related helper modules
  • tests/tools/test_line_ending_preservation.py -> 12 passed
  • tests/tools/test_file_staleness.py -> 11 passed
  • tests/tools/test_patch_failure_tracking.py -> 5 passed
  • mutation handler unit subset excluding known macOS /tmp normalization assertions -> 22 passed
  • mutation state/cross-profile/cwd combined batch -> 72 passed, with the known order-dependent live-cwd cache case failing when combined but passing in isolation
  • Standard gateway batch A -> 265 passed
  • Standard gateway batch B -> 115 passed
  • git diff --check / staged diff check clean

Known existing caveats kept separate:

  • tests/tools/test_file_tools.py still has three macOS /tmp vs /private/tmp mocked-call expectation failures; production behavior was not changed for this refactor.
  • A broad combined cwd/staleness batch can still hit the existing live cwd cache order leak; the focused staleness suite passes.

jleechan2015 added a commit to jleechanorg/hermes-agent that referenced this pull request Jun 28, 2026
…ded for version bumps) (NousResearch#15)

* [agento] fix: green-gate Gate 3 — auto-PASS dependabot PRs (no CR needed for version bumps)

dependabot[bot] PRs are automated dependency bumps. Requiring a
CodeRabbit review blocks them indefinitely when CR hits rate limits.
Add PR_GATE3_AUTHOR check: if author == dependabot[bot], Gate 3
auto-PASSes. Human-authored PRs continue to require CR APPROVED.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [agento] fix: set LATEST_CR=APPROVED for dependabot Gate 3 auto-PASS (Gate 5 fast-path)

BugBot caught that LATEST_CR was unset when dependabot PRs auto-PASS Gate 3,
making Gate 5's CR-approved non-blocking fast-path unreachable for those PRs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [agento] fix: skeptic-cron Gate 3 — dependabot PRs auto-PASS (no CR needed)

Mirrors green-gate Gate 3 dependabot exemption so dependabot version bumps
can be auto-merged by skeptic-cron without requiring a formal CR review.
Adds author field to PR JSON payload so dependabot detection works in the loop.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
feiguang50-hub pushed a commit to feiguang50-hub/hermes-agent that referenced this pull request Jul 19, 2026
…de changes)

Ran a read-only dry-run against a real exported skill library (76 SKILL.md,
25 candidates, nested category dirs + CJK) in an isolated HERMES_HOME. Pipeline
ran cleanly and safely (no mutation); LLM decisions were sensible (2
consolidations proposed, rest kept standalone). Two real gaps fixtures could
never expose:
- dry-run under-reports consolidation proposals (counts/arrays stay 0 while
  prose proposes merges) — asymmetric vs split/deprecate (KNOWN_ISSUES NousResearch#15)
- keyword-retention guard is near-inert on nested/CJK skills: _load_skill_keywords
  resolves only flat paths -> name-only fallback (KNOWN_ISSUES NousResearch#16)

Guards were not exercised (model used the YAML channel; 25 skill_view, 0
skill_manage). No code changed.

Co-Authored-By: Claude <noreply@anthropic.com>
feiguang50-hub pushed a commit to feiguang50-hub/hermes-agent that referenced this pull request Jul 19, 2026
…n report (NousResearch#15 / P0)

In dry-run nothing is removed, so the removal-based classification left
consolidated/pruned empty even when the model proposed merges — while
splits/deprecations already surfaced their YAML proposals. A dry-run preview
therefore under-reported what a real run would do (REPORT.md printed
'consolidated: 0' above a prose body proposing merges). Surface the YAML-block
consolidation/pruning proposals into run.json counts/arrays + REPORT.md,
tagged source='model (proposed, dry-run)' and behind a DRY-RUN banner. The
fold runs AFTER the cron-rewrite block so a dry-run never mutates cron/jobs.json;
real-run classification is unchanged (guarded by a test).

Co-Authored-By: Claude <noreply@anthropic.com>
feiguang50-hub pushed a commit to feiguang50-hub/hermes-agent that referenced this pull request Jul 19, 2026
…h-pass real-data re-verification

Co-Authored-By: Claude <noreply@anthropic.com>
feiguang50-hub pushed a commit to feiguang50-hub/hermes-agent that referenced this pull request Jul 19, 2026
…o code changes)

Ran a read-only dry-run against a larger, deliberately uncleaned backup (130
usage records vs 123 files, path-prefixed keys, all-active-despite-archive,
external symlink). Result: no errors/exceptions handling the dirty data; LLM
emitted a well-formed empty structured block (keep all 27); guard not exercised
(YAML channel). NousResearch#15 fix makes the reported 0 trustworthy (matches empty block)
vs the 8th-pass ambiguous 0. One untested dimension noted: the
active-vs-archived usage mismatch's effect on the deterministic prune is not
covered by dry-run (prune is skipped). No code changed.

Co-Authored-By: Claude <noreply@anthropic.com>
BarnsL added a commit to BarnsL/hermes-agent that referenced this pull request Jul 19, 2026
Anthropic bills any >200K-input request on a subscription (OAuth) account
to the EXTRA-USAGE budget, not plan limits — even without the context-1m
beta header (1M context is GA on Claude 4.6+). A 339K-token desktop session
got permanent 'You are out of extra usage' 400s while a small probe on the
same token returned 200.

Fix: _apply_subscription_context_cap() clamps the resolved context to 200K
when the token is an OAuth/setup token (sk-ant-oat*, eyJ*, cc-*). Metered
API keys (sk-ant-api*) are NOT capped. Escape hatch: anthropic.long_context.

Tests: test_critical26_subscription_context_capped_at_plan_lane,
       test_critical26_long_context_escape_hatch (both pass)

See CRITICAL NousResearch#15 in CRITICAL-ISSUES.md for full RCA.
MarcoFernstaedt pushed a commit to MarcoFernstaedt/hermes-agent that referenced this pull request Aug 1, 2026
Findings #1 and NousResearch#2, together, because NousResearch#2 makes #1 bypassable: a gate in the
model-tools path is worth nothing while `registry.dispatch()` reaches handlers
without consulting it.

`resolve()` now has a production caller. A non-AUTO tool cannot execute without
an execution capability, and a capability cannot exist without a decision — not
"approved" as a boolean somebody might set early, but a token minted at consent,
bound to the exact call, and destroyed by being used.

Four properties, each with a test that fails without it. Bound to the tool and
an argument fingerprint, so approving one call cannot execute a different one
and mutating arguments between consent and execution invalidates the token.
One-use, so a retry loop cannot turn one approval into several executions.
Short-lived, because consent goes stale. And `consume()` raises rather than
returning a boolean — a caller that forgets to check a boolean executes anyway,
and this is the one check where forgetting must not be survivable.

Fail-closed throughout. A broken permission lookup refuses; `requires_capability`
returns True on any exception; an unreadable trust list trusts nothing; minting
without a `tool_call_id` is refused outright, because a capability that could
match any call is not a capability. Every refusal test asserts the handler ran
**zero** times — a gate that refuses after the side effect is not a gate.

**The default is `observe`, and that is a gap rather than a preference.**
`get_tier()` returns ALWAYS_APPROVAL for unregistered tools — deliberately, so
an unknown tool is never assumed safe — and most tools here were never
registered. Switching straight to `enforce` would refuse nearly every call in
the product, which is an outage, not a safety improvement. `observe` audits
every call that *would* be refused, with its tool name, so the registration
backlog is measurable against real traffic and the switch can be flipped once
the audit goes quiet. This mirrors HERMES_APPROVAL_INTEGRITY_MODE, which exists
for the same reason; both must reach `enforce` for the tier system to mean
anything, and neither is there yet. Enforce mode is fully tested.

Also corrected, per the review: the baseline-failure classification, which I
had called environmental wholesale. Three of them are real defects at baseline
— `atomic_config_write` NameErrors, a SQLite journal-mode assertion, and a jobs
asset-contract failure — and the evidence now says so per failure. And the
rollback procedure, which claimed one merge revert covered a many-commit range;
it now gives a non-destructive runtime pin plus three repository options, with
the history-rewriting one marked as needing explicit approval.

Regression check: tests/tools 8532 passed / 19 failed — the failing set
byte-identical to baseline, so the gate broke nothing.

Still not merged to main. Remaining findings: NousResearch#6 undo wiring, NousResearch#10 Now
composition, NousResearch#11 native resume, NousResearch#12 New Chat, NousResearch#13 free-form clarify, NousResearch#14
approval acknowledgement, NousResearch#15 reconnect, NousResearch#16 readiness coupling, NousResearch#17 sensor
delivery.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nu2Qaq5Y7EScuooGz8co34
MarcoFernstaedt pushed a commit to MarcoFernstaedt/hermes-agent that referenced this pull request Aug 1, 2026
…, coupling

**NousResearch#14 — a card could resolve on a decision the gateway never recorded.**
`approval.respond` answers with how many approvals it resolved, and zero is a
*successful RPC that decided nothing* — the request expired, or was answered
elsewhere. The client read the envelope and closed the card, so the owner
believed they had answered while the agent stayed blocked. Now only a
`resolved >= 1` resolves it, and only an explicit `status: "ok"` resolves a
clarify.

**NousResearch#13 — free-form clarify answers went out as new prompts.** The native path
had a steering step that was a no-op returning true, after which the text was
sent via `prompt.submit`: the question stayed open and the answer arrived as an
unrelated message. Replaced by one `answerClarifyFreeText` that addresses the
request by id natively and walks the menu on the terminal — one method, because
splitting it into "steer, then send" is what let the two halves disagree.

**NousResearch#11 — resume threw the transcript away.** `session.resume` returns
`messages`; `open()` read only the identity fields. A refresh reattached to a
running session and showed an empty feed, so execution continued against a
conversation the owner could no longer see. History is now delivered through an
`onHistory` hook that fires *before* `subscribe()` — ordering is the other half
of the fix, since applying the past after live deltas have landed interleaves
them — and merges through the existing hydration path rather than a second one.

**NousResearch#12 — New Chat did nothing natively.** Both controls rotated a PTY identity
that native mode does not use. The session stayed open, its durable id stayed
in storage, and the next prompt continued the old conversation under a heading
that said it was new. `startNew()` closes the session, clears the profile-scoped
durable id before the rebuild so the effect cannot read a stale one, drops the
live id immediately, and opens fresh without resuming.

**NousResearch#16 — a missing TUI disabled the transport that exists to avoid the TUI.**
The chat-readiness probe asks whether the *TUI* can start, and its verdict also
gated native session creation. Each transport is now gated on its own
prerequisite, and the probe does not run at all under native chat — the banner
it raises describes a dependency native chat does not have.

Gates: typecheck 0, eslint 0, 74 files / 706 frontend tests, build green.

Remaining from the review: NousResearch#6 undo not wired to production, NousResearch#10 Now not
consuming the ranking modules, NousResearch#15 reconnect, NousResearch#17 sensor delivery.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nu2Qaq5Y7EScuooGz8co34
MarcoFernstaedt pushed a commit to MarcoFernstaedt/hermes-agent that referenced this pull request Aug 1, 2026
**NousResearch#15 — messages could sit "sending" for the rest of the session.** The hook
opened once and, on failure, reported an error and stopped. Held messages
waited on a `ready` that was never coming. Reconnect is now bounded with
backoff and has its own visible state: `reconnecting` is distinct from
`connecting` because the owner needs to know a previous attempt failed, and
`gaveUp` is distinct from both because it names the point at which nothing
further happens without them. When it gives up, held messages are marked failed
— an optimistic row that never resolves is a message the owner believes was
delivered, and telling the truth eventually is the entire purpose of the
optimistic row.

The retry budget resets on a successful open, so a later drop gets its own full
allowance rather than inheriting an exhausted one. It retries the *open*, never
the send: a fresh session is not a reason to re-run a prompt whose fate is
unknown.

**NousResearch#10 — the ranking modules were asserted and unenforced.** `nowOrder.ts` and
`outcomeRanking.ts` had tests while `NowPage.tsx` imported neither and rendered
its old composition, which is the same shape of gap as a tier that classifies
and a dispatcher that never asks. Now projects real hub state through
`nowOutcomes.ts` into the ranker and renders the top three: one recommendation
marked *in words* rather than by colour, its reason underneath, each item's
work state spelled out, and a native keyboard-operable button to replace the
recommendation with a way back to Imperator's.

The projection is where invented data would have come from, so it is the
narrow place to look: every candidate derives from something the hub reported,
there is no placeholder or "get started" row, and an empty hub renders no
section at all. A halted guardrail outranks everything because nothing else on
the page can proceed while it holds.

Tests render the *real* `NowView` against a real payload. Testing the modules
in isolation is exactly what let the page ignore them, and after two rounds of
my own fixtures agreeing with my own mistakes, a test that builds its own
version of the subject is not evidence.

Gates: typecheck 0, eslint 0, 74 files / 714 frontend tests, build green.

Remaining from the review: NousResearch#6 undo not wired to production, NousResearch#17 sensor capture
paths not built.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nu2Qaq5Y7EScuooGz8co34
Meraniya pushed a commit to Meraniya/hermes-agent that referenced this pull request Aug 6, 2026
… — Codex PR NousResearch#30 review (NousResearch#31)

Two chatgpt-codex-connector[bot] review comments on PR NousResearch#30 that still applied
to current main (the other 13 were already addressed in the merged PR):

1. client.py NousResearch#13 — Cancel timed-out MCP calls: _run_sync now cancels the
   concurrent.futures.Future on timeout before re-raising, so a stalled MCP
   endpoint doesn't leave a pending HTTP session running on the shared
   background loop after the caller has given up / opened the breaker.
2. __init__.py NousResearch#15 — Parse the host before allowing keyless local mode:
   is_available() now urlparse's the URL and requires an exact loopback host
   (localhost/127.0.0.1/::1) instead of a substring match, so a URL like
   'https://localhost@example.com/mcp' (host=example.com) is no longer trusted
   as local keyless mode.

Adds regression tests: test_memgw_client_timeout.py (cancel-on-timeout fails
against pre-fix client) + TestKeylessLocalModeHostParsing (3/4 fail pre-fix).

Deferred (already fixed in merged PR NousResearch#30): MCP dep import check, MCP dep pin,
loop lock, isError handling, stale-prefetch generation, sync/delegation thread
tracking + shutdown join, session-switch prefetch invalidation, no join on
turn path, default provider unset.
Deferred (complex, needs interface change): NousResearch#3/NousResearch#4 per-turn user_id refresh for
shared gateway sessions — sync_turn/prefetch only receive session_id, not
user_id, so threading identity through requires a MemoryProvider interface
change; NousResearch#1 in-tree placement is an architectural call (AGENTS.md says existing
in-tree providers stay).
choi138 added a commit to choi138/hermes-agent that referenced this pull request Aug 18, 2026
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.

4 participants