Skip to content

sync: upstream/main (4 commits) [20260816] - #8

Merged
randlee merged 13 commits into
mainfrom
sync/candidate-20260816-merge
Aug 16, 2026
Merged

sync: upstream/main (4 commits) [20260816]#8
randlee merged 13 commits into
mainfrom
sync/candidate-20260816-merge

Conversation

@randlee

@randlee randlee commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Automated fork-sync (level 1, mechanical). Candidate: sync/candidate-20260816 (atm/stack rebased onto upstream/main, clean). Tests: 33 passed in 1.53s (fresh frozen venv, py3.11). This PR head is the PRE-RESOLVED merge (candidate tree wins; tree-hash verified equal to candidate). Review per docs/atm/FORK-MAINTENANCE.md: contessa checks git diff upstream/main..sync/candidate-20260816 is exactly the ATM stack; alpha-prime approves, merges, then advances the stack pointer: git push origin +sync/candidate-20260816:atm/stack

OutThisLife and others added 13 commits August 16, 2026 12:48
`hermes desktop` runs `npm run pack` through _npm_lifecycle_env(), which
sets CI=1. electron-builder 26 reads that as an implicit publish request
(`onTagOrDraft`) when --publish is absent, so a local --dir build enters
publish resolution it has no business being in.

Pin `--publish never` on the pack script. This is also what electron-builder
asks for directly -- the implicit CI behavior is removed in v27.

Co-authored-by: webtecnica <webtecnica@users.noreply.github.com>
Co-authored-by: fangliquanflq <fangliquanflq@users.noreply.github.com>
With a GH_TOKEN/GITHUB_TOKEN in the environment, electron-builder auto-selects
the github provider and resolves owner/repo from the repository field, falling
back to reading <projectDir>/.git/config. projectDir is apps/desktop, which has
no .git of its own, and app-builder-lib does not walk up to the workspace root
-- so resolution returned null and threw "Cannot detect repository by
.git/config".

On Linux this fires from onAfterPack for a plain `dir` target: the darwin and
Windows branches return early for non-installer targets, Linux has no such
guard. That is why the same build worked elsewhere.

--publish never keeps `pack` from reaching this at all, but `dist:*` and
test-desktop.mjs still resolve publish config on a machine with a token, so
declare the field too.

Tests call the real app-builder-lib resolver rather than asserting on the text
of package.json, so they track electron-builder's behavior instead of our
formatting.

Co-authored-by: airo7 <airo7@users.noreply.github.com>
Co-authored-by: frankmendes1979 <frankmendes1979@users.noreply.github.com>
…time contract

A same-day version-floor bump (0.20 runtime contract) left every install
with an older cua-driver hard-failing on all computer_use calls: the
start() gate fails closed, while the `hermes update` refresh defers to the
driver's own check-update verb — whose ~20h cache routinely answers "no
update available" right after we raise the floor. Hermes knew it required
0.20+ but never acted on that knowledge.

Two changes:

- tools_config.install_cua_driver(): a contract-failed installed driver is
  repaired on the upgrade=True path too (previously only upgrade=False).
  The contract failure itself is the confirmation, so the
  require_confirmed_update gate and the check-update short-circuit are
  bypassed for repairs — an indeterminate or stale-cached check can no
  longer pin users on an unusable driver.

- cua_backend.CuaDriverBackend.start(): when the contract gate fails on an
  installed binary, attempt one automatic repair per process via the
  standard install path, then re-probe. HERMES_CUA_DRIVER_CMD overrides
  are never repaired (explicit override is authoritative even when broken)
  and a missing binary still just reports the install hint. A failing
  installer can't loop: the second start() surfaces the original error.

Tests: contract-repair coverage in test_computer_use.py (auto-repair
success, failed repair surfaces the original error, once-per-process
guard, override never repaired, missing binary never repaired) and
test_install_cua_driver.py (incompatible driver repairs despite an
indeterminate check-update, check-update not consulted). All new tests
verified to fail against the unfixed source (sabotage run).
…ntime

The runtime-contract repair now also runs during hermes update and once
per session at the first computer_use call (PR NousResearch#87923); the docs only
mentioned setup and toolset enablement.
* feat: inject_internal_message — public profile-aware injection API

GatewayRunner.inject_internal_message(profile, platform, chat_id, text, notice_text)
enables plugins (e.g. hermes-atm) to inject host-originated messages through
the existing adapter→gateway dispatch path with internal=True.

- Resolves adapter from _profile_adapters[profile] or self.adapters
- Constructs SessionSource + MessageEvent(internal=True)
- Supports optional notice_text for visible 📬 observability
- Fire-and-forget: queues event via adapter.handle_message()

AL17 deployable contract per c50c4232.

* fix: fail closed on unknown profile, add user_id to SessionSource (AL17 review)

- Explicit profile must be found in _profile_adapters; no silent fallback
- SessionSource includes user_id=chat_id for correct session identity
- Notice text delivered before event construction

* fix: Optional[str]->None return, profile default='', reorder params (AL17 review)

- Return type changed from Optional[str] to None
- profile parameter moved to end with default ''
- All return None changed to bare return
- SessionSource includes user_id=chat_id
- Docstring updated for new signature

* feat: add steer vs queue mode to inject_internal_message

Adds mode parameter to inject_internal_message:
- mode="queue" (default): fire-and-forget via adapter.handle_message()
- mode="steer": inject directly into running agent's turn via
  agent.steer(), falling back to queue when no agent is running

Also fixes bug from review commit 0869cc6 where event was
referenced before construction in the queue path.

Tests: 19 passing (11 queue mode + 5 steer mode + 2 hook + 1 negative)
- steer into running agent skips handle_message
- steer falls back to queue when no agent running
- steer falls back to queue when steer() returns False
- queue mode never calls steer() even when agent running
- notice_text preserved in steer mode
- strict profile resolution (fail closed on unknown profile)
- no ATM platform creation

* fix: correct profile resolver using _active_profile_name() (AL17 review)

- Resolve via self._active_profile_name() for primary profile
- Registered secondary profiles via _profile_adapters lookup
- fail closed on unknown profile (no silent fallback)
- Signature: profile='' default at end, -> None return, no mode param
- Remove _profile_adapters-is-empty-as-error heuristic

* fix: restore mode=steer per user directive, fix return None -> return

- mode='queue' (default), mode='steer' for non-interrupting injection
- steer uses _session_key_for_source + _running_agents
- falls through to queue if steer unavailable
- bare return everywhere

* fix: apply AL17 contract — keyword-only inject_internal_message with steer mode

- Add * separator and required profile: str (keyword-only)
- Add mode: Literal['queue','steer'] = 'queue' with steer logic
- Replace empty-string profile default with explicit active-profile check
- Fix return None → bare return everywhere
- Update tests for keyword-only API (mock _active_profile_name)
- 19/19 tests pass

* fix: expose gateway_runner in gateway:startup hook context

- Adds 'gateway_runner': self to the hook emit dict
- Enables hermes-atm to call runner.inject_internal_message()
  from a gateway:startup hook without private imports

* fix: structured errors, isolation tests, gateway_runner hook name (AL17 gaps 3-5)

- InjectInternalMessageError with code/chat_id/detail
- Profile/adapter failures raise instead of silently returning
- Isolation tests: queue and steer cannot cross sessions
- Hook context uses gateway_runner (not runner)
- test_missing_adapter uses real adapter map pattern

* fix: actually raise InjectInternalMessageError in inject_internal_message (gaps 3-4)

* feat: add host-contract isolation tests + mode validation (AL17 gate)

Three host-contract tests for PR NousResearch#82915:
1. same-profile/two-chat steer isolation — steer per-chat within profile
2. two-profiles/same-chat isolation — steer per-profile within same chat_id
3. invalid runtime mode fails closed — InjectInternalMessageError

Also adds mode validation at top of inject_internal_message: unknown
mode values now raise InjectInternalMessageError(code='invalid_mode')
rather than silently falling through to queue mode.

---------

Co-authored-by: Rand Lee <randlee@users.noreply.github.com>
The docs commit travels with the patch stack so documentation can never
drift from the patch it describes. PATCH-REQUIREMENTS.md is the knowledge
base handed to the escalation agent when the mechanical rebase fails.
@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown

૮ >ﻌ< ა ci review

ran on d58a503 — merge sync/candidate-20260816: keep rebased stack tree (sanc

❌ Job failures

Check contributors / check-attribution · View job

Job Check contributors / check-attribution failed.


⚠️ Action required

Unmapped contributor email(s) · View job

New contributor email(s) are not in AUTHOR_MAP.

github@randlee.com (Rand Lee)
randlee@users.noreply.github.com (Rand Lee)

How to fix:

Run from the PR branch:

python3 scripts/audit_pr_attribution.py --fix
git add contributors && git commit -m "chore: map contributor emails" && git push

Or map one email manually (do NOT edit AUTHOR_MAP in release.py):

python3 scripts/add_contributor.py <email> <github-username>

To find the GitHub username for an email:

gh api 'search/users?q=EMAIL+in:email' --jq '.items[0].login'

⚠️ Warnings

OSV vulnerability scan · View job

5 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.


debug info

CI timings

CI timings · View report · View job

Wall time 3m37s vs 3m36s (+0.5%). 18 job(s) slower, 15 faster, 5 unchanged.

  • Python tests / Run tests slice 8/12: -49.0s
  • Python tests / Run tests slice 9/12: +43.0s
  • Python tests / Run tests slice 5/12: +37.0s
  • Docs Site / docs-site-checks: +25.0s
  • Python tests / Run tests slice 11/12: -23.0s

@randlee randlee left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First-pass review (mechanical, contessa-track): PASS.

Diff-vs-main inspection — every file in the PR diff is accounted for:

  • apps/desktop/package.json, apps/desktop/scripts/local-pack-publish.test.mjs → upstream fix(desktop) x2 (publish path + repository resolution)
  • hermes_cli/tools_config.py, tests/hermes_cli/test_install_cua_driver.py, tests/tools/test_computer_use.py, tools/computer_use/cua_backend.py, website/docs/user-guide/features/computer-use.md → upstream fix(computer-use) auto-repair + docs
  • docs/atm/FORK-MAINTENANCE.md → ATM stack docs (pre-resolved merge model, single-account auth, review chain)

No file outside the upstream-4-commits ∪ ATM-stack set. gateway/run.py and tests/gateway/test_inject_internal_message.py are absent from the diff, which is expected: base main already carries the identical stack, and the pre-resolved merge is candidate-tree-wins (no delta on unchanged stack files).

Metadata: title 'sync: upstream/main (4 commits) [20260816]', state OPEN, head sync/candidate-20260816-merge, base main, mergeable MERGEABLE, 13 commits (4 upstream + 8 ATM stack + 1 merge commit d58a503). Body reports green: 'Tests: 33 passed in 1.53s (fresh frozen venv, py3.11)'.

First pass: APPROVED (nothing unexpected). Senior reviewer (loki) still confirms the tree-hash/diff-vs-upstream per FORK-MAINTENANCE.md before admin merge.

@randlee randlee left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alpha-prime spot-check: APPROVED — diff is exactly upstream's 4 commits (desktop publish path, computer-use auto-repair) + ATM stack docs; merge commit d58a503 tree 7780e15a == candidate tree (pre-resolved, candidate-wins); MERGEABLE, tests green per PR body.

@randlee
randlee merged commit e442457 into main Aug 16, 2026
54 of 56 checks passed
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.

3 participants