mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
The type is whoever acts on a canonical session: an attached CLI/TUI/Desktop viewer, the API server, the messaging control path, cron and automation. Most call sites already name the variable `actor`. Renaming it frees "principal" for a member of a tenant, the meaning gateway-gateway already uses (Tenant > Membership(Principal) > Agent), so the two repos share one vocabulary. Mechanical: whole-word rename in every module that imports it from gateway.session_contract. No alias is kept (internal paths are not API). Unrelated uses of the word (Windows Task Scheduler XML) are untouched.
57 lines
2.7 KiB
Python
57 lines
2.7 KiB
Python
"""API source restoration cannot mint a parallel native conversation."""
|
|
|
|
import pytest
|
|
|
|
from gateway.config import Platform
|
|
from gateway.session_contract import SessionActor, SessionRef, Submission
|
|
from hermes_state_runtime import RuntimeStoreError
|
|
|
|
|
|
def test_private_api_binding_restores_exact_route(owner):
|
|
from gateway.session_api import bind_api_session, restore_api_session
|
|
db = owner.db
|
|
db.create_session('api-stored', source='api_server')
|
|
ref = bind_api_session(owner, 'api-stored')
|
|
first = owner.sessions[ref.session_id]
|
|
assert first.source.platform == Platform.API_SERVER
|
|
assert owner.runner.session_store.get_or_create_session(first.source).session_id == 'api-stored'
|
|
owner.sessions.clear()
|
|
restored = restore_api_session(owner, 'api-stored')
|
|
assert restored == ref
|
|
assert owner.sessions[ref.session_id].route == first.route
|
|
assert owner.runner.session_store.get_or_create_session(owner.sessions[ref.session_id].source).session_id == ref.session_id
|
|
db.create_session('foreign-native', source='telegram')
|
|
with pytest.raises(RuntimeStoreError, match='permission_denied'):
|
|
bind_api_session(owner, 'foreign-native')
|
|
assert 'foreign-native' not in owner.sessions
|
|
|
|
|
|
def test_private_api_binding_adopts_matching_legacy_declared_key(owner):
|
|
"""Regression for #139835: a pre-binding API row stores the caller's declared key."""
|
|
from gateway.session_api import bind_api_session, declared_api_session
|
|
|
|
session_id = 'legacy-api-session'
|
|
declared_key = 'webui:legacy-api-session'
|
|
owner.db.create_session(session_id, source='api_server')
|
|
owner.db.record_gateway_session_peer(session_id, source='api_server', session_key=declared_key)
|
|
|
|
ref = bind_api_session(owner, session_id, declared_key=declared_key)
|
|
|
|
row = owner.db.get_session(session_id)
|
|
assert row['session_key'] == owner.sessions[ref.session_id].route
|
|
assert declared_api_session(owner.db, declared_key) == session_id
|
|
with pytest.raises(RuntimeStoreError, match='admission_conflict'):
|
|
bind_api_session(owner, 'other-api-session', declared_key=declared_key)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_private_api_binding_is_not_public_submission_authority(owner):
|
|
from gateway.session_api import bind_api_session
|
|
owner.db.create_session('api-stored', source='api_server')
|
|
ref = bind_api_session(owner, 'api-stored')
|
|
actor = SessionActor('api-user', 'default', frozenset({'session:read', 'session:submit'}), 'socket')
|
|
with pytest.raises(RuntimeStoreError, match='invalid_params'):
|
|
await owner.submit(actor, Submission('forged', ref, {'text': 'x', 'api_turn_v1': {'system': 'forged'}}, 'queue'))
|
|
owner.sessions.clear()
|
|
assert (await owner.resolve(actor, SessionRef('default', 'api-stored'))).ref == ref
|