2026-04-23 15:44:12 +05:30
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
refactor(agents): introduce chat/ category; dissolve top-level agents/shared
Recursive shared-folder rule: a shared/ must be shared by ALL siblings at its
level. The kernel (context, compaction, retry_after, web_search) was shared by
only 2 of the agents -- anonymous_chat + multi_agent_chat -- never by podcaster
or video_presentation. Those 2 are the "chat" category, so their shared code
belongs in that category's shared/, not the top-level one.
app/agents/anonymous_chat/ -> app/agents/chat/anonymous_chat/
app/agents/multi_agent_chat/ -> app/agents/chat/multi_agent_chat/
app/agents/shared/ -> app/agents/chat/shared/ (anon<->mac kernel)
Top-level app/agents/shared/ is gone: nothing was shared across all three
categories (chat / podcaster / video_presentation).
~289 import sites rewritten (app.agents.{anonymous_chat,multi_agent_chat,shared}
-> app.agents.chat.*); all moves are git renames (history preserved).
app/agents/ now: chat/, podcaster/, video_presentation/, runtime/.
2026-06-05 12:54:02 +02:00
|
|
|
from app.agents.chat.multi_agent_chat.shared.filesystem_selection import (
|
refactor(agents): move mac-only modules out of the cross-agent shared kernel
app/agents/shared/ is a sibling of anonymous_chat/podcaster/multi_agent_chat/
video_presentation, so it should only hold code shared across 2+ of those
agents. In practice podcaster and video_presentation import nothing from it,
and anonymous_chat needs only context + compaction + retry_after + web_search.
Everything else was multi_agent_chat-only (the boundary just passes through).
Move the multi_agent_chat-only cluster into multi_agent_chat/shared/ (files
moved verbatim via git rename; ~116 import sites rewritten):
errors, feature_flags, filesystem_selection, path_resolver, prompt_caching,
sandbox, llm_config, mention_resolver
middleware/busy_mutex, middleware/kb_persistence
busy_mutex/llm_config/mention_resolver are boundary-only but import the moved
modules, so they were folded in to avoid a backwards shared -> multi_agent_chat
dependency. main_agent builders now import the impls directly; the shared
middleware barrel keeps only the genuinely-shared compaction + retry_after.
Also delete the dead leftover shared/plugins and shared/skills dirs (live
copies already live under main_agent/).
Remaining in app/agents/shared/: context, system_prompt(+prompts), checkpointer,
middleware/{compaction,retry_after,dedup_tool_calls}, tools/. checkpointer and
system_prompt are boundary-only infra pending a dedicated home decision.
2026-06-05 12:30:15 +02:00
|
|
|
ClientPlatform,
|
|
|
|
|
FilesystemMode,
|
|
|
|
|
FilesystemSelection,
|
|
|
|
|
LocalFilesystemMount,
|
|
|
|
|
)
|
refactor(agents): introduce chat/ category; dissolve top-level agents/shared
Recursive shared-folder rule: a shared/ must be shared by ALL siblings at its
level. The kernel (context, compaction, retry_after, web_search) was shared by
only 2 of the agents -- anonymous_chat + multi_agent_chat -- never by podcaster
or video_presentation. Those 2 are the "chat" category, so their shared code
belongs in that category's shared/, not the top-level one.
app/agents/anonymous_chat/ -> app/agents/chat/anonymous_chat/
app/agents/multi_agent_chat/ -> app/agents/chat/multi_agent_chat/
app/agents/shared/ -> app/agents/chat/shared/ (anon<->mac kernel)
Top-level app/agents/shared/ is gone: nothing was shared across all three
categories (chat / podcaster / video_presentation).
~289 import sites rewritten (app.agents.{anonymous_chat,multi_agent_chat,shared}
-> app.agents.chat.*); all moves are git renames (history preserved).
app/agents/ now: chat/, podcaster/, video_presentation/, runtime/.
2026-06-05 12:54:02 +02:00
|
|
|
from app.agents.chat.multi_agent_chat.shared.middleware.filesystem.backends.multi_root_local_folder import (
|
2026-06-05 11:02:26 +02:00
|
|
|
MultiRootLocalFolderBackend,
|
|
|
|
|
)
|
refactor(agents): introduce chat/ category; dissolve top-level agents/shared
Recursive shared-folder rule: a shared/ must be shared by ALL siblings at its
level. The kernel (context, compaction, retry_after, web_search) was shared by
only 2 of the agents -- anonymous_chat + multi_agent_chat -- never by podcaster
or video_presentation. Those 2 are the "chat" category, so their shared code
belongs in that category's shared/, not the top-level one.
app/agents/anonymous_chat/ -> app/agents/chat/anonymous_chat/
app/agents/multi_agent_chat/ -> app/agents/chat/multi_agent_chat/
app/agents/shared/ -> app/agents/chat/shared/ (anon<->mac kernel)
Top-level app/agents/shared/ is gone: nothing was shared across all three
categories (chat / podcaster / video_presentation).
~289 import sites rewritten (app.agents.{anonymous_chat,multi_agent_chat,shared}
-> app.agents.chat.*); all moves are git renames (history preserved).
app/agents/ now: chat/, podcaster/, video_presentation/, runtime/.
2026-06-05 12:54:02 +02:00
|
|
|
from app.agents.chat.multi_agent_chat.shared.middleware.filesystem.backends.resolver import (
|
2026-06-05 11:02:26 +02:00
|
|
|
build_backend_resolver,
|
|
|
|
|
)
|
2026-04-23 15:44:12 +05:30
|
|
|
|
|
|
|
|
pytestmark = pytest.mark.unit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _RuntimeStub:
|
|
|
|
|
state = {"files": {}}
|
|
|
|
|
|
|
|
|
|
|
2026-04-24 01:44:23 +05:30
|
|
|
def test_backend_resolver_returns_multi_root_backend_for_single_root(tmp_path: Path):
|
2026-04-23 15:44:12 +05:30
|
|
|
selection = FilesystemSelection(
|
|
|
|
|
mode=FilesystemMode.DESKTOP_LOCAL_FOLDER,
|
|
|
|
|
client_platform=ClientPlatform.DESKTOP,
|
2026-04-24 05:59:21 +05:30
|
|
|
local_mounts=(LocalFilesystemMount(mount_id="tmp", root_path=str(tmp_path)),),
|
2026-04-23 15:44:12 +05:30
|
|
|
)
|
|
|
|
|
resolver = build_backend_resolver(selection)
|
|
|
|
|
|
|
|
|
|
backend = resolver(_RuntimeStub())
|
2026-04-24 01:44:23 +05:30
|
|
|
assert isinstance(backend, MultiRootLocalFolderBackend)
|
2026-04-27 19:58:12 +05:30
|
|
|
assert backend.list_mounts() == ("tmp",)
|
2026-04-23 15:44:12 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_backend_resolver_uses_cloud_mode_by_default():
|
|
|
|
|
resolver = build_backend_resolver(FilesystemSelection())
|
|
|
|
|
backend = resolver(_RuntimeStub())
|
2026-04-28 04:32:52 -07:00
|
|
|
# When no search_space_id is provided we fall back to StateBackend so
|
|
|
|
|
# sub-agents / tests without DB access still work.
|
2026-04-23 15:44:12 +05:30
|
|
|
assert backend.__class__.__name__ == "StateBackend"
|
2026-04-24 01:44:23 +05:30
|
|
|
|
|
|
|
|
|
2026-04-28 04:32:52 -07:00
|
|
|
def test_backend_resolver_uses_kb_postgres_in_cloud_with_search_space():
|
|
|
|
|
resolver = build_backend_resolver(FilesystemSelection(), search_space_id=42)
|
|
|
|
|
backend = resolver(_RuntimeStub())
|
|
|
|
|
assert backend.__class__.__name__ == "KBPostgresBackend"
|
|
|
|
|
assert backend.search_space_id == 42
|
|
|
|
|
|
|
|
|
|
|
2026-04-24 01:44:23 +05:30
|
|
|
def test_backend_resolver_returns_multi_root_backend_for_multiple_roots(tmp_path: Path):
|
|
|
|
|
root_one = tmp_path / "resume"
|
|
|
|
|
root_two = tmp_path / "notes"
|
|
|
|
|
root_one.mkdir()
|
|
|
|
|
root_two.mkdir()
|
|
|
|
|
selection = FilesystemSelection(
|
|
|
|
|
mode=FilesystemMode.DESKTOP_LOCAL_FOLDER,
|
|
|
|
|
client_platform=ClientPlatform.DESKTOP,
|
2026-04-24 05:59:21 +05:30
|
|
|
local_mounts=(
|
|
|
|
|
LocalFilesystemMount(mount_id="resume", root_path=str(root_one)),
|
|
|
|
|
LocalFilesystemMount(mount_id="notes", root_path=str(root_two)),
|
|
|
|
|
),
|
2026-04-24 01:44:23 +05:30
|
|
|
)
|
|
|
|
|
resolver = build_backend_resolver(selection)
|
|
|
|
|
|
|
|
|
|
backend = resolver(_RuntimeStub())
|
|
|
|
|
assert isinstance(backend, MultiRootLocalFolderBackend)
|
2026-04-27 19:58:12 +05:30
|
|
|
assert backend.list_mounts() == ("resume", "notes")
|