feat: add STRIX_DISABLE_FIX_AGENTS to skip dedicated fix subagents

When set, the root coordinator is instructed not to spawn dedicated
fix/remediation subagents; remediation still lands in each report's
remediation_steps field. Off by default, so existing behavior is
unchanged. Useful for cost-conscious scans where a separate
fix-writing agent mostly burns tokens and concurrency.

The directive is injected into the root agent's prompt only when the
env var is set and only for the root agent, leaving child prompts and
the shipped skill file untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Felix 2026-06-29 17:59:33 +08:00
parent 7141ccff62
commit 07c9f09947
3 changed files with 32 additions and 3 deletions

View file

@ -7,6 +7,7 @@ from typing import Any
from jinja2 import Environment, FileSystemLoader, select_autoescape
from strix.config import load_settings
from strix.skills import get_available_skills, load_skills
from strix.utils.resource_paths import get_strix_resource_path
@ -16,6 +17,16 @@ logger = logging.getLogger(__name__)
_PROMPT_DIRNAME = "prompts"
# Appended to the root coordinator's skill when STRIX_DISABLE_FIX_AGENTS is
# set, overriding the "Fix agent provides remediation" delegation step.
_DISABLE_FIX_AGENTS_DIRECTIVE = (
"\n\n## Fix Agents Disabled\n\n"
"Do NOT spawn dedicated fix or remediation subagents. Remediation is "
"captured inline in each report's `remediation_steps` field, which is "
"sufficient. A separate agent that only writes fixes wastes tokens and "
"concurrency, so skip that delegation step entirely."
)
def _resolve_skills(
*,
@ -85,6 +96,12 @@ def render_system_prompt(
is_root=is_root,
)
skill_content = load_skills(skills_to_load)
if (
is_root
and "root_agent" in skill_content
and load_settings().agents.disable_fix_agents
):
skill_content["root_agent"] += _DISABLE_FIX_AGENTS_DIRECTIVE
env.globals["get_skill"] = lambda name: skill_content.get(name, "")
rendered = env.get_template("system_prompt.jinja").render(

View file

@ -3,9 +3,9 @@
Public surface:
- :class:`Settings` — composite model. Get via :func:`load_settings`.
- :class:`LlmSettings`, :class:`RuntimeSettings`, :class:`TelemetrySettings`,
:class:`IntegrationSettings` — sub-models, attribute-accessed off
``Settings``.
- :class:`LlmSettings`, :class:`RuntimeSettings`, :class:`AgentSettings`,
:class:`TelemetrySettings`, :class:`IntegrationSettings` — sub-models,
attribute-accessed off ``Settings``.
- :func:`load_settings` — memoized resolve (env > JSON file > defaults).
- :func:`apply_config_override` — switch the JSON source to a custom path.
- :func:`persist_current` — write currently-set env vars to the active file.
@ -17,6 +17,7 @@ from strix.config.loader import (
persist_current,
)
from strix.config.settings import (
AgentSettings,
IntegrationSettings,
LlmSettings,
RuntimeSettings,
@ -26,6 +27,7 @@ from strix.config.settings import (
__all__ = [
"AgentSettings",
"IntegrationSettings",
"LlmSettings",
"RuntimeSettings",

View file

@ -54,6 +54,15 @@ class RuntimeSettings(BaseSettings):
max_local_copy_mb: int = Field(default=1024, alias="STRIX_MAX_LOCAL_COPY_MB")
class AgentSettings(BaseSettings):
model_config = _BASE_CONFIG
# When true, the root coordinator is instructed not to spawn dedicated
# fix/remediation subagents; remediation still lands in each report's
# ``remediation_steps``. Off by default (no behavior change for others).
disable_fix_agents: bool = Field(default=False, alias="STRIX_DISABLE_FIX_AGENTS")
class TelemetrySettings(BaseSettings):
model_config = _BASE_CONFIG
@ -71,5 +80,6 @@ class Settings(BaseSettings):
llm: LlmSettings = Field(default_factory=LlmSettings)
runtime: RuntimeSettings = Field(default_factory=RuntimeSettings)
agents: AgentSettings = Field(default_factory=AgentSettings)
telemetry: TelemetrySettings = Field(default_factory=TelemetrySettings)
integrations: IntegrationSettings = Field(default_factory=IntegrationSettings)