Commit Graph

7 Commits

Author SHA1 Message Date
Samuel Odio fe828188d2 docs(test): clarify busy scope coverage 2026-08-29 20:03:48 +05:30
Samuel Odio e8591ae509 test(gateway): verify routed busy persistence 2026-08-29 20:03:48 +05:30
Samuel Odio 8d1d193f11 fix(gateway): apply busy mode per profile 2026-08-29 20:03:48 +05:30
69k4xmdfm2-blip 21260c3281 fix(gateway): carry the profile in adapter-derived session keys (#88404)
Adapter ingress derives a session key BEFORE the runner stamps
source.profile in _make_profile_message_handler, so the namespace fell
back to the active profile and every bot in a multiplexed gateway
produced agent:main:<platform>:<chat>. A Telegram private chat reports
the user's own id as chat.id, identical for every bot, so two profiles
sharing one human collapsed onto a single lane: _pending_text_batches,
_active_sessions, the busy-session guard and _post_delivery_callbacks are
all keyed on that string. A day of production logs across two bots shows
60 flushes, none carrying the secondary profile's namespace.

set_owner_profile records credential ownership on the adapter and
_session_key_profile resolves the namespace as source.profile ->
_owner_profile -> the session store's resolver, so a secondary adapter
keys into its own namespace even before the source is stamped. Stamped
sources keep priority, so relay/connector ingress, which routes per event
rather than per credential, is unchanged. _configure_profile_adapter
installs the owner alongside the other handlers, covering startup and
reconnect.

Every candidate is type-checked as a non-blank str, and every attribute
read goes through getattr: adapters are routinely built without
BasePlatformAdapter.__init__, and a duck-typed session store returns a
truthy non-string that would otherwise be interpolated into the key as
agent:<MagicMock ...>:.

Also routes the four call sites that passed no profile at all (feishu
media batches, raft, slack _session_key_for_source, telegram photo
batches) through the same resolver.

test_multiplex_busy_input_mode's secondary-adapter busy case seeded
_active_sessions with the unstamped agent:main: key, asserting the
pre-fix collapse. It now seeds the lane the profile-owned adapter
actually derives.

A primary adapter has no owner and an unstamped source, so it resolves
exactly as before; with multiplex_profiles off the resolver returns None
and every key is byte-identical to today's.
2026-08-19 02:00:16 -07:00
Michael Huang 2cabeba563 fix(tui,desktop): refresh context usage live during active turns 2026-08-14 20:24:42 -07:00
kshitij f51aa6a9b5 fix(ci): repair red main — busy-mode test + missing checkout in skills-index workflows
Three separate reds on main. Two are fixed here; the third needs no code.

1. tests/gateway/test_multiplex_busy_input_mode.py (blocks every merge)

Fails "Python tests / Run tests slice 5/12" and therefore "All required
checks pass". Semantic merge conflict between two PRs merged ~1h apart:

  a31be480 fix(gateway): respect routed profile busy modes             (added the test)
  c8f235a1 feat(gateway): allow selective multiplex profile serving    (added the gate)

c8f235a1 taught _profile_name_for_source to reject a route whose target
profile is not in the served set (profiles_to_serve). Each PR was green on
its own base; neither ran against the other's merge result.

The test asserts a route to profile "research" resolves to that profile's
busy mode, but never patches profiles_to_serve — so it reads the runner's
REAL on-disk profiles. "research" is not among them, the route is rejected
before the busy-mode snapshot is consulted, and the assertion gets the
gateway default:

  WARNING gateway.run: Rejecting profile route 'research-chat':
                       target profile 'research' is not served
  AssertionError: assert 'interrupt' == 'steer'

Patch profiles_to_serve for the assertion — the same seam every sibling
test in tests/gateway/test_profile_resolution.py already patches
(test_route_inside_allowlist_resolves, test_route_outside_allowlist_rejects).

This also removes an ambient-state dependency: the test previously passed
or failed based on which profiles happened to exist on the machine running
it. Verified passing under an empty HERMES_HOME.

Test-only. The serving gate from c8f235a1 is correct and left intact.

2. Skills-index workflows: local action used without actions/checkout

check-freshness has failed on all 12 of its last 12 scheduled runs:

  ##[error]Can't find 'action.yml', 'action.yaml' or 'Dockerfile' under
  '.../.github/actions/get-app-token'. Did you forget to run
  actions/checkout before running your local action?

./.github/actions/get-app-token is a LOCAL composite action and cannot
resolve without the repo on disk. skills-index-freshness.yml had no
checkout step at all. The step is gated on `status != 'ok'`, so the
watchdog broke exactly when it was supposed to file its issue — the live
index is currently 521.4h stale (limit 26h) and nobody was told.

An audit of all workflows for this bug class found one more instance:
skills-index.yml's `trigger-deploy` job, which re-triggers the docs deploy
so a refreshed index reaches the live site. Its sibling `build-index` job
checks out; this one did not. That is plausibly why the index went stale
in the first place. Both are fixed; the audit now reports zero remaining
jobs that use a local action without a prior checkout.

Pinned to the same actions/checkout SHA used by the other 35 call sites.

3. "Publish inline E2E evidence" — no fix needed

Failed once at 13:33Z on a transient TLS error reaching api.github.com
("certificate is not valid for any names") while installing a gh
extension. The last 25 runs of that workflow are 25/25 success. Infra
blip, not a code defect.
2026-08-11 21:26:28 +05:30
Trevin Chow a31be48030 fix(gateway): respect routed profile busy modes 2026-08-10 21:51:46 -07:00