Skip to content

feat: consolidated upstream PRs (session TTL, registry, matrix improvements, telemetry) - #1

Closed
Phoenix1819 wants to merge 7 commits into
mainfrom
phoenix/consolidated-prs-20260510
Closed

feat: consolidated upstream PRs (session TTL, registry, matrix improvements, telemetry)#1
Phoenix1819 wants to merge 7 commits into
mainfrom
phoenix/consolidated-prs-20260510

Conversation

@Phoenix1819

Copy link
Copy Markdown
Owner

Phoenix1819 and others added 7 commits May 9, 2026 09:25
On platform connect, read ~/.hermes/profiles/<profile>/state/current_activity.json
and inject a handoff message into the first user message after restart.

- agent/restart_awareness.py: new module providing:
  - update_activity() / read_activity() / clear_activity()
  - build_handoff() with staleness detection and mode toggle
  - Profile-aware path via get_hermes_home()
  - Two modes: simple (default) and verbose

- gateway/platforms/base.py: refactored to import from the module,
  replacing 60 lines of inline JSON parsing with a clean call

- tests/agent/test_restart_awareness.py: 12 tests covering:
  - staleness computation (fresh, stale, missing, malformed)
  - handoff formatting (simple/verbose x fresh/stale)
  - round-trip write/read/clear

- Lazy loading: file is parsed once per connect, no startup penalty
- Silent no-op if activity file is missing or corrupt
- Fails safely on parse errors (no config key required)
- Configurable mode per-activity via 'mode' field in JSON

- File is optional — if missing, all lookups return None gracefully
- No existing code paths are modified beyond _mark_connected()
- Default mode is 'simple' producing a one-line handoff
…Research#22087)

refactor(matrix): remove delayed reaction redaction scheduling (NousResearch#22090)

Combined: presence tracking works with inline reaction redaction.
Presence transitions:
  - online → connected and idle
  - unavailable → actively processing
  - offline → disconnected

Reactions are now redacted inline instead of after a delay.
…sResearch#22095)

fix(telemetry_cli): replace undefined cursor variable 'c' with 'conn'
@github-actions

Copy link
Copy Markdown

🚨 CRITICAL Supply Chain Risk Detected

This PR contains a pattern that has been used in real supply chain attacks. A maintainer must review the flagged code carefully before merging.

🚨 CRITICAL: Install-hook file added or modified

These files can execute code during package installation or interpreter startup.

Files:

hermes_cli/setup.py

Scanner only fires on high-signal indicators: .pth files, base64+exec/eval combos, subprocess with encoded commands, or install-hook files. Low-signal warnings were removed intentionally — if you're seeing this comment, the finding is worth inspecting.

@github-actions

Copy link
Copy Markdown

🔎 Lint report: phoenix/consolidated-prs-20260510 vs origin/main

ruff

Total: 2 on HEAD, 0 on base (🆕 +2)

🆕 New issues (1):

Rule Count
PLW1514 1
First entries
user_registry.py:90: [PLW1514] `open` in text mode without explicit `encoding` argument

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 7820 on HEAD, 7797 on base (🆕 +23)

🆕 New issues (34):

Rule Count
unresolved-import 16
unresolved-attribute 11
invalid-argument-type 2
invalid-type-form 1
invalid-assignment 1
invalid-parameter-default 1
not-subscriptable 1
unused-type-ignore-comment 1
First entries
hermes_cli/uninstall.py:325: [unresolved-attribute] unresolved-attribute: Module `winreg` has no member `KEY_WRITE`
tests/test_lint_config.py:23: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
scripts/check-windows-footguns.py:135: [invalid-type-form] invalid-type-form: Function `callable` is not valid in a type expression: Did you mean `collections.abc.Callable`?
tests/tools/test_code_execution_windows_env.py:30: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
scripts/keystroke_diagnostic.py:36: [unresolved-import] unresolved-import: Cannot resolve imported module `prompt_toolkit`
scripts/keystroke_diagnostic.py:37: [unresolved-import] unresolved-import: Cannot resolve imported module `prompt_toolkit.key_binding`
tools/tts_tool.py:544: [unresolved-import] unresolved-import: Cannot resolve imported module `psutil`
hermes_cli/uninstall.py:324: [unresolved-attribute] unresolved-attribute: Module `winreg` has no member `HKEY_CURRENT_USER`
hermes_cli/web_server.py:2990: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to `<class 'PtyBridge'>`
tools/code_execution_tool.py:1152: [invalid-argument-type] invalid-argument-type: Argument to function `chmod` is incorrect: Expected `int | str | bytes | PathLike[str] | PathLike[bytes]`, found `None | str`
scripts/keystroke_diagnostic.py:38: [unresolved-import] unresolved-import: Cannot resolve imported module `prompt_toolkit.layout`
tools/code_execution_tool.py:1454: [unresolved-import] unresolved-import: Cannot resolve imported module `psutil`
tests/tools/test_process_registry.py:741: [unresolved-import] unresolved-import: Cannot resolve imported module `psutil`
gateway/platforms/whatsapp.py:158: [unresolved-import] unresolved-import: Cannot resolve imported module `psutil`
hermes_cli/uninstall.py:309: [unresolved-attribute] unresolved-attribute: Module `winreg` has no member `SetValueEx`
hermes_cli/uninstall.py:328: [unresolved-attribute] unresolved-attribute: Module `winreg` has no member `QueryValueEx`
plugins/observability/local_sqlite_telemetry/__init__.py:196: [invalid-parameter-default] invalid-parameter-default: Default value of type `None` is not assignable to annotated parameter type `dict[Unknown, Unknown]`
tests/test_hermes_bootstrap.py:29: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
scripts/keystroke_diagnostic.py:40: [unresolved-import] unresolved-import: Cannot resolve imported module `prompt_toolkit.layout.controls`
tests/agent/test_restart_awareness.py:119: [not-subscriptable] not-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
tools/code_execution_tool.py:1151: [invalid-argument-type] invalid-argument-type: Argument to bound method `socket.bind` is incorrect: Expected `tuple[Any, ...] | str | Buffer`, found `None | str`
tools/environments/base.py:127: [unresolved-attribute] unresolved-attribute: Attribute `write` is not defined on `None` in union `Any | IO[Unknown] | None`
tools/process_registry.py:1052: [unresolved-import] unresolved-import: Cannot resolve imported module `psutil`
tests/agent/test_restart_awareness.py:5: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tools/environments/base.py:128: [unresolved-attribute] unresolved-attribute: Attribute `close` is not defined on `None` in union `Any | IO[Unknown] | None`
... and 9 more

✅ Fixed issues (10):

Rule Count
unresolved-import 6
unresolved-attribute 2
no-matching-overload 1
unsupported-operator 1
First entries
plugins/platforms/google_chat/adapter.py:2946: [unresolved-import] unresolved-import: Module `hermes_cli.config` has no member `print_warning`
plugins/platforms/google_chat/adapter.py:2945: [unresolved-import] unresolved-import: Module `hermes_cli.config` has no member `print_success`
plugins/platforms/google_chat/adapter.py:2942: [unresolved-import] unresolved-import: Module `hermes_cli.config` has no member `prompt`
plugins/platforms/google_chat/adapter.py:2944: [unresolved-import] unresolved-import: Module `hermes_cli.config` has no member `print_info`
tools/environments/base.py:106: [unresolved-attribute] unresolved-attribute: Attribute `write` is not defined on `None` in union `IO[Unknown] | None`
plugins/platforms/google_chat/adapter.py:2943: [unresolved-import] unresolved-import: Module `hermes_cli.config` has no member `prompt_yes_no`
tools/environments/base.py:107: [unresolved-attribute] unresolved-attribute: Attribute `close` is not defined on `None` in union `IO[Unknown] | None`
hermes_cli/main.py:5350: [unresolved-import] unresolved-import: Cannot resolve imported module `openai`
tui_gateway/entry.py:84: [no-matching-overload] no-matching-overload: No overload of bound method `dict.get` matches arguments
tests/run_agent/test_concurrent_interrupt.py:192: [unsupported-operator] unsupported-operator: Operator `+=` is not supported between objects of type `None` and `Literal[1]`

Unchanged: 4085 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

Phoenix1819 pushed a commit that referenced this pull request May 10, 2026
…search#22920)

Found 18 real Hermes-Agent stories from HN, X, and Reddit not yet
captured on the page. All URLs HTTP-verified to return 200 with
matching titles.

Reddit (15): r/hermesagent (Obsidian-as-memory writeup at 794 upvotes,
LLM cheatsheet at 635 upvotes, Kanban game-changer post, OpenRouter #1
ranking, AMA from the Nous team, etc.); r/LocalLLaMA, r/Rag,
r/openclaw, r/SideProject, r/LocalLLM threads where users describe
their actual setups (Qwen3.5-9b on 16gb VRAM, 5060Ti + Telegram, smart
routing tiers).

X (3): @vmiss33's 'what I use Hermes for' guide, @HeyYanvi's
X-to-NotebookLM podcast workflow, @ExileAI_0's spare-laptop Iris
running RenPy + ComfyUI, @brucexu_eth's Hermes Inc. Telegram startup
sim from the hackathon, Hype's deep-dive blog.

HN (1): 'I'm using Hermes — sandbox it like any agent.'

No component changes — all new entries fit the existing schema
(real URL, real author, real date).
Phoenix1819 pushed a commit that referenced this pull request May 12, 2026
…3456)

* feat(goals): /goal checklist + /subgoal user controls

Two-phase judge for /goal — Phase A decomposes the goal into a detailed
checklist on first turn; Phase B evaluates each pending item harshly
against the agent's most recent response. The goal completes only when
every item is in a terminal status (completed or impossible). Adds
/subgoal so the user can append, complete, mark impossible, undo,
remove, or clear items the judge missed or got wrong.

Mechanics:
- GoalState gains `checklist` and `decomposed` fields, both backwards
  compatible (old state_meta rows load unchanged).
- Phase A: aux call writes a harsh, exhaustive checklist; biased toward
  more items not fewer. Falls through to legacy freeform judge when
  decompose fails.
- Phase B: judge gets the checklist + last-response snippet + path to
  a per-session conversation dump at <HERMES_HOME>/goals/<sid>.json.
  A bounded read_file tool (max 5 calls per turn, restricted to that
  one file) lets the judge inspect history when the snippet is
  ambiguous. Stickiness in code: terminal items are frozen, only the
  user can revert via /subgoal undo.
- Continuation prompt shows checklist progress when non-empty;
  reverts to old prompt when empty.
- Status line shows M/N done counts.

CLI + gateway + TUI gateway all pass the agent reference into
evaluate_after_turn so the dump can be written. Gateway-side
/subgoal is allowed mid-run since it only modifies the checklist
the judge consults at turn boundaries.

Tests: 24 new cases — backcompat round-trip, Phase A decompose,
Phase B updates + new_items + stickiness, user override flows,
conversation dump (incl. unsafe-sid sanitization), judge read_file
restriction. Existing freeform-mode tests updated to patch the
renamed `judge_goal_freeform` and skip Phase A explicitly.

* fix(goals): off-by-one in judge index, message-list plumbing, prompt tuning

Three live-test findings from running /goal end-to-end against
gemini-3-flash-preview as the judge:

1. Off-by-one bug — the judge sees the checklist rendered with 1-based
   indices ('1. [ ] foo, 2. [ ] bar') but the apply layer indexed
   state.checklist as 0-based. Result: every judge update landed on
   the wrong item, evidence got attached to neighbouring rows, and
   the genuine 'first pending' item (usually #1) never got marked.
   Fix: convert 1 → 0 in _parse_evaluate_response. Also tightened the
   user prompt to call out the 1-based scheme explicitly. New tests
   cover the parser conversion + an end-to-end fake-judge round-trip.

2. Conversation dump never happened — _extract_agent_messages tried
   common AIAgent attribute names (.messages, .conversation_history,
   etc.) but AIAgent doesn't expose the message list as an instance
   attribute; it lives inside run_conversation()'s scope. Result: the
   judge's read_file tool always saw history_path=unavailable. Fix:
   added an explicit messages= kwarg to evaluate_after_turn that all
   three call sites (CLI, gateway, TUI gateway) now pass directly.
   Agent-attribute extraction kept as back-compat fallback.

3. Prompt was too harsh on simple goals. The original 'be HARSH,
   default to leaving items pending' wording made the judge refuse
   to mark 'file exists' completed even after the agent ran ls,
   test -f, os.path.isfile, and find — burning the entire 8-turn
   budget on a fizzbuzz task. Softened to 'strict but not absurd'
   with explicit guidance on what counts as evidence and a directive
   not to require re-proving items already established earlier.

Re-tested live with the same fizzbuzz goal: now terminates in 2
turns with all 8 checklist items correctly attributed to their
own evidence. /subgoal user-action flow (add / complete / undo /
impossible) verified live as well.
@Phoenix1819

Copy link
Copy Markdown
Owner Author

Cleaning up fork

@Phoenix1819
Phoenix1819 deleted the phoenix/consolidated-prs-20260510 branch May 16, 2026 06:24
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