mirror of
https://github.com/usestrix/strix.git
synced 2026-08-23 03:12:37 +02:00
Critical fixes: - ``StrixOrchestrationHooks.on_agent_start`` now finds the ``CaidoCapability`` via ``ctx.context['caido_capability']`` instead of ``agent.capabilities`` (we use plain ``Agent``, not ``SandboxAgent``, so the latter never existed). The session manager's bundle already exposes the capability; ``run_strix_scan`` threads it through ``make_agent_context`` and ``create_agent`` forwards it to children. - ``run_strix_scan`` registers the ``StrixTracingProcessor`` with the SDK's tracing provider via ``add_trace_processor`` so SDK trace spans hit ``run_dir/events.jsonl`` (was previously a parallel stream the SDK ignored). - ``on_llm_end`` now writes to ``Tracer.record_llm_usage`` in addition to ``bus.record_usage`` so the CLI/TUI stats panel sees real numbers instead of zeros. - ``run_strix_scan`` accepts an externally-built ``AgentMessageBus`` + an explicit ``model`` arg. The TUI pre-creates the bus so its stop and chat-input handlers can submit ``bus.send`` / ``bus.cancel_descendants`` coroutines onto the scan thread's loop via ``asyncio.run_coroutine_threadsafe`` — replacing the TODO-stub no-ops. - ``model`` config now propagates root → context → child agents in ``create_agent`` (was hardcoded fallback). Dead-code removal: - Deleted the ``load_skill`` tool entirely (host module, sandbox module, TUI renderer, tests). The legacy implementation reached into a global ``_agent_instances`` registry that no longer exists; the post-migration stub returned ``success=True`` without injecting anything — pure theater. Skills are still preloaded via the system prompt at scan-bring-up. - Dropped ``tenacity`` and ``xmltodict`` from ``[project.dependencies]`` — neither is imported anywhere post-migration. - Stripped the system prompt's "use the load_skill tool" lines. Tests: 278/278 passing. Removed two ``load_skill`` test cases and a ``test_tool_registration_modes::test_load_skill_import_...`` assertion that exercised the deleted module.
117 lines
3.6 KiB
Python
117 lines
3.6 KiB
Python
"""Jinja-based system-prompt renderer.
|
|
|
|
Loads ``strix/agents/prompts/system_prompt.jinja`` (508 lines — the
|
|
multi-section production prompt with skills, tools, scan modes, etc.)
|
|
and renders it with the caller's per-run context (scan mode, whitebox,
|
|
interactive, scope authorization block).
|
|
|
|
References:
|
|
- HARNESS_WIKI.md §4.1 (system prompt assembly)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
|
|
from strix.skills import load_skills
|
|
from strix.tools import get_tools_prompt
|
|
from strix.utils.resource_paths import get_strix_resource_path
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
_PROMPT_DIRNAME = "prompts"
|
|
|
|
|
|
def _resolve_skills(
|
|
*,
|
|
requested: list[str] | None,
|
|
scan_mode: str = "deep",
|
|
is_whitebox: bool = False,
|
|
) -> list[str]:
|
|
"""Build the deduped, ordered skills list for the prompt render.
|
|
|
|
Order:
|
|
|
|
1. Whatever the caller asked for, in order.
|
|
2. ``scan_modes/<mode>`` (always).
|
|
3. Whitebox-specific skills if applicable.
|
|
"""
|
|
ordered: list[str] = list(requested or [])
|
|
ordered.append(f"scan_modes/{scan_mode}")
|
|
if is_whitebox:
|
|
ordered.append("coordination/source_aware_whitebox")
|
|
ordered.append("custom/source_aware_sast")
|
|
|
|
deduped: list[str] = []
|
|
seen: set[str] = set()
|
|
for skill in ordered:
|
|
if skill and skill not in seen:
|
|
deduped.append(skill)
|
|
seen.add(skill)
|
|
return deduped
|
|
|
|
|
|
def render_system_prompt(
|
|
*,
|
|
skills: list[str] | None = None,
|
|
scan_mode: str = "deep",
|
|
is_whitebox: bool = False,
|
|
interactive: bool = False,
|
|
system_prompt_context: dict[str, Any] | None = None,
|
|
) -> str:
|
|
"""Render the system prompt.
|
|
|
|
Args:
|
|
skills: Skills the caller wants preloaded into the prompt context.
|
|
scan_mode: ``"deep" | "fast" | ...``. Maps to ``scan_modes/<mode>``
|
|
skill.
|
|
is_whitebox: When True, the source-aware whitebox skill stack
|
|
is loaded too.
|
|
interactive: When True, the prompt renders the interactive-mode
|
|
communication rules block.
|
|
system_prompt_context: Free-form dict that the template's
|
|
``system_prompt_context`` variable receives — carries the
|
|
scan-scope authorization block.
|
|
|
|
Returns the rendered prompt string. If anything goes wrong (template
|
|
missing, render failure), returns an empty string and logs — a
|
|
missing prompt is survivable, a hard failure during agent
|
|
construction is not.
|
|
"""
|
|
try:
|
|
prompt_dir = get_strix_resource_path("agents", _PROMPT_DIRNAME)
|
|
skills_dir = get_strix_resource_path("skills")
|
|
env = Environment(
|
|
loader=FileSystemLoader([prompt_dir, skills_dir]),
|
|
autoescape=select_autoescape(
|
|
enabled_extensions=(),
|
|
default_for_string=False,
|
|
),
|
|
)
|
|
|
|
skills_to_load = _resolve_skills(
|
|
requested=skills,
|
|
scan_mode=scan_mode,
|
|
is_whitebox=is_whitebox,
|
|
)
|
|
skill_content = load_skills(skills_to_load)
|
|
env.globals["get_skill"] = lambda name: skill_content.get(name, "")
|
|
|
|
rendered = env.get_template("system_prompt.jinja").render(
|
|
get_tools_prompt=get_tools_prompt,
|
|
loaded_skill_names=list(skill_content.keys()),
|
|
interactive=interactive,
|
|
system_prompt_context=system_prompt_context or {},
|
|
**skill_content,
|
|
)
|
|
except Exception:
|
|
logger.exception("render_system_prompt failed; returning empty prompt")
|
|
return ""
|
|
else:
|
|
return str(rendered)
|