SurfSense/surfsense_backend/app/routes/agent_flags_route.py
CREDO23 82c5dc5b02 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

80 lines
2.3 KiB
Python

"""``GET /api/agent/flags``: read-only feature-flag status.
Surfaces :class:`AgentFeatureFlags` to the frontend so the UI can:
* Render conditional surfaces (e.g. show the action-log button only when
``enable_action_log`` is on).
* Display an admin diagnostics card so operators can verify which
middleware tier is active without shelling into the box.
The endpoint is *read-only*. Flipping flags requires an env-var change
plus a process restart — by design, since the values are baked into the
agent factory at build time. The route does not require any special
permission (any authenticated user can see them) since the flag values
do not leak data, and the UI surfaces are conditionally rendered based
on them anyway.
"""
from __future__ import annotations
from dataclasses import asdict
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from app.agents.multi_agent_chat.shared.feature_flags import (
AgentFeatureFlags,
get_flags,
)
from app.config import config
from app.db import User
from app.users import current_active_user
router = APIRouter()
class AgentFeatureFlagsRead(BaseModel):
"""Mirror of :class:`AgentFeatureFlags`. Updated together with it."""
disable_new_agent_stack: bool
enable_context_editing: bool
enable_compaction_v2: bool
enable_retry_after: bool
enable_model_fallback: bool
enable_model_call_limit: bool
enable_tool_call_limit: bool
enable_tool_call_repair: bool
enable_doom_loop: bool
enable_permission: bool
enable_busy_mutex: bool
enable_llm_tool_selector: bool
enable_skills: bool
enable_specialized_subagents: bool
enable_kb_planner_runnable: bool
enable_action_log: bool
enable_revert_route: bool
enable_plugin_loader: bool
enable_otel: bool
enable_desktop_local_filesystem: bool
@classmethod
def from_flags(cls, flags: AgentFeatureFlags) -> AgentFeatureFlagsRead:
# asdict() avoids missing-field bugs when AgentFeatureFlags grows.
return cls(
**asdict(flags),
enable_desktop_local_filesystem=config.ENABLE_DESKTOP_LOCAL_FILESYSTEM,
)
@router.get("/agent/flags", response_model=AgentFeatureFlagsRead)
async def get_agent_flags(
_user: User = Depends(current_active_user),
) -> AgentFeatureFlagsRead:
return AgentFeatureFlagsRead.from_flags(get_flags())