Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion loopx/chat_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1813,7 +1813,8 @@ def manager_scope(session: dict[str, object]) -> list[str] | None:
return authorized_manager_goal_ids(
build_lark_goal_topic_runtime_snapshot(
registry_path=server.registry_path, runtime_root_override=server.runtime_root_override,
), session, runtime_root=runtime_root, registry_path=resolved_registry_path,
), session, runtime_root=server.runtime_controller.coordination_runtime_root,
registry_path=resolved_registry_path, executor_runtime_root=runtime_root,
)

server.runtime_controller = ChatRuntimeController(
Expand Down
18 changes: 15 additions & 3 deletions loopx/extensions/lark/manager_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,21 @@ def _valid_manager_binding(goal_id, binding, routing) -> bool:


def authorized_manager_goal_ids(
snapshot: Mapping[str, Any], session: Mapping[str, Any], *, runtime_root: Path | None = None, registry_path: Path | None = None
snapshot: Mapping[str, Any],
session: Mapping[str, Any],
*,
runtime_root: Path | None = None,
registry_path: Path | None = None,
executor_runtime_root: Path | None = None,
) -> list[str]:
"""Resolve current external read authority; a session's old Goal is not a grant."""
"""Resolve current external read authority; a session's old Goal is not a grant.

Evidence policy and machine executor settings may live under different roots
when Chat storage is overridden, so callers can bind each authority explicitly.
"""
executor_root = (
runtime_root if executor_runtime_root is None else executor_runtime_root
)
candidates = []
targets = snapshot.get("target_payload") or {}
for goal_id, payload in (snapshot.get("binding_payloads") or {}).items():
Expand Down Expand Up @@ -270,7 +282,7 @@ def authorized_manager_goal_ids(
goal_id, binding, routing = candidates[0]
if (
binding.get("session_id") != session.get("session_id")
or manager_connection_executor_endpoint(runtime_root)[0]
or manager_connection_executor_endpoint(executor_root)[0]
!= session.get("agent_id")
or not _valid_manager_binding(goal_id, binding, routing)
):
Expand Down
190 changes: 190 additions & 0 deletions tests/test_chat_lark_api_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -983,3 +983,193 @@ def _send_error(self, message, **kwargs):
from loopx.capabilities.manager_context import evidence_goal_scope
observed = evidence_goal_scope(tmp_path / "runtime", manager_channel(provider="lark", audience="mew\0oc_public_fixture"), registry_path=registry_path)
assert observed == (["goal-alpha"] if execute and not scope_failure else None)


def test_manager_scope_reads_policy_from_coordination_root_when_chat_root_overrides(
tmp_path: Path, monkeypatch: Any
) -> None:
from loopx.capabilities.machine_configuration.builtins import (
build_builtin_machine_configuration_registry,
)
from loopx.capabilities.machine_configuration.store import (
configure_machine_configuration,
)
from loopx.capabilities.manager_context import configure_evidence_scope
from loopx.chat_manager import (
manager_channel,
manager_connection_executor_endpoint,
)

chat_root = tmp_path / "chat-runtime"
coordination_root = tmp_path / "registered-runtime"
registry_path = tmp_path / "registry.json"
registry_path.write_text(
json.dumps(
{
"schema_version": 1,
"common_runtime_root": str(coordination_root),
"goals": [
{"id": "goal-alpha", "repo": str(tmp_path)},
{"id": "goal-beta", "repo": str(tmp_path)},
],
}
),
encoding="utf-8",
)
channel = manager_channel(
provider="lark", audience="mew\0oc_public_fixture"
)
machine_configuration = {
"schema_version": "loopx_machine_configuration_v0",
"namespaces": {
"steward_executor": {
"schema_version": "steward_executor_machine_defaults_v0",
"executor_endpoint": "dsh",
"executor_model": None,
"executor_reasoning_effort": None,
}
},
}
machine_registry = build_builtin_machine_configuration_registry()
preview = configure_machine_configuration(
runtime_root=chat_root,
configuration=machine_configuration,
registry=machine_registry,
execute=False,
)
configure_machine_configuration(
runtime_root=chat_root,
configuration=machine_configuration,
registry=machine_registry,
execute=True,
expected_plan_revision=str(preview["plan_revision"]),
)
configure_evidence_scope(
coordination_root,
registry_path,
channel=channel,
goal_ids=["goal-alpha", "goal-beta"],
goal_scope="all_registered",
execute=True,
)

executor_endpoint, _source = manager_connection_executor_endpoint(chat_root)
assert executor_endpoint == "dsh"
target_payload = {
"schema_version": "loopx_goal_channel_provider_targets_v0",
"targets": {
"manager-target": {
"name": "manager-target",
"enabled": True,
"identity": {"sender_profile": "mew"},
"channel": {"chat_id": "oc_public_fixture"},
}
},
}
binding_payloads = {
"goal-alpha": {
"bindings": {
"goal-alpha": {
"goal_id": "goal-alpha",
"agent_id": executor_endpoint,
"session_id": "manager-session",
"enabled": True,
"target_ref": "manager-target",
"routing": {
"conversation_kind": "manager",
"ingress_mode": "session_queue",
},
"connector": {
"schema_version": "agent_external_connector_v0",
"goal_ref": "goal-alpha",
"agent_ref": executor_endpoint,
"provider_kind": "lark",
"source_kind": "group_message",
"source_ref": "oc_public_fixture",
"capture_policy": "configured_source_all",
"ingress_policy": "session_queue",
"response_policy": "topic_reply",
"lifecycle": "connected",
"capabilities": ["response_write", "response_readback"],
"session_ref": "manager-session",
},
}
}
}
}
snapshot = {
"target_payload": target_payload,
"binding_payloads": binding_payloads,
}
assets = tmp_path / "assets"
assets.mkdir()
(assets / "index.html").write_text("fixture", encoding="utf-8")
monkeypatch.setattr(chat_server, "build_lark_goal_topic_runtime_snapshot", lambda **_: snapshot)
monkeypatch.setattr(
chat_server,
"resolve_lark_cli_for_runtime",
lambda **_: LarkCliResolution(
None, False, "missing", None, "lark_cli_not_installed"
),
)
entered = threading.Event()
captured: list[ChatHTTPServer] = []

class Server(ChatHTTPServer):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
captured.append(self)

def serve_forever(self, *args: Any, **kwargs: Any) -> None:
entered.set()
super().serve_forever(*args, **kwargs)

monkeypatch.setattr(chat_server, "ChatHTTPServer", Server)
worker = threading.Thread(
target=chat_server.serve_chat,
kwargs={
"registry_path": registry_path,
"runtime_root_override": chat_root,
"scan_roots": [tmp_path],
"host": "127.0.0.1",
"port": 0,
"assets_dir": assets,
"open_browser": False,
},
daemon=True,
)
worker.start()
try:
assert entered.wait(8)
server = captured[0]
assert server.runtime_root == chat_root
assert server.runtime_controller.coordination_runtime_root == coordination_root
session = {
"session_id": "manager-session",
"goal_id": "goal-alpha",
"agent_id": executor_endpoint,
"channel_id": channel,
}
resolver = server.runtime_controller.manager_scope_resolver
assert resolver(session) == ["goal-alpha", "goal-beta"]
configure_evidence_scope(
chat_root,
registry_path,
channel=channel,
goal_ids=["goal-alpha", "goal-beta"],
goal_scope="all_registered",
execute=True,
)
configure_evidence_scope(
coordination_root,
registry_path,
channel=channel,
goal_ids=["goal-alpha"],
execute=True,
)
assert resolver(session) == ["goal-alpha"]
finally:
if captured:
captured[0].shutdown()
worker.join(8)
assert not worker.is_alive()
Loading