132 lines
5.2 KiB
Python
132 lines
5.2 KiB
Python
from app.modules.agent.engine.orchestrator.actions.explain_actions import ExplainActions
|
|
from app.modules.agent.engine.orchestrator.execution_context import ExecutionContext
|
|
from app.modules.agent.engine.orchestrator.models import (
|
|
ExecutionPlan,
|
|
OutputContract,
|
|
RoutingMeta,
|
|
Scenario,
|
|
TaskConstraints,
|
|
TaskSpec,
|
|
)
|
|
|
|
|
|
def _ctx(rag_items: list[dict]) -> ExecutionContext:
|
|
task = TaskSpec(
|
|
task_id="task-1",
|
|
dialog_session_id="dialog-1",
|
|
rag_session_id="rag-1",
|
|
user_message="Объясни по коду как работает task_processor",
|
|
scenario=Scenario.EXPLAIN_PART,
|
|
routing=RoutingMeta(domain_id="project", process_id="qa", confidence=0.9, reason="test"),
|
|
constraints=TaskConstraints(),
|
|
output_contract=OutputContract(result_type="answer"),
|
|
metadata={
|
|
"rag_items": rag_items,
|
|
"rag_context": "",
|
|
"confluence_context": "",
|
|
"files_map": {},
|
|
},
|
|
)
|
|
plan = ExecutionPlan(
|
|
plan_id="plan-1",
|
|
task_id="task-1",
|
|
scenario=Scenario.EXPLAIN_PART,
|
|
template_id="tpl",
|
|
template_version="1",
|
|
steps=[],
|
|
)
|
|
return ExecutionContext(task=task, plan=plan, graph_resolver=lambda *_: None, graph_invoker=lambda *_: {})
|
|
|
|
|
|
def test_explain_actions_switch_to_code_profile_when_code_layers_present() -> None:
|
|
ctx = _ctx(
|
|
[
|
|
{
|
|
"source": "app/task_processor.py",
|
|
"layer": "C1_SYMBOL_CATALOG",
|
|
"title": "task_processor.process_task",
|
|
"content": "function task_processor.process_task(task)",
|
|
"metadata": {"qname": "task_processor.process_task", "kind": "function"},
|
|
},
|
|
{
|
|
"source": "app/task_processor.py",
|
|
"layer": "C2_DEPENDENCY_GRAPH",
|
|
"title": "task_processor.process_task:calls",
|
|
"content": "task_processor.process_task calls queue.publish",
|
|
"metadata": {"edge_type": "calls"},
|
|
},
|
|
]
|
|
)
|
|
actions = ExplainActions()
|
|
|
|
actions.collect_sources(ctx)
|
|
actions.extract_logic(ctx)
|
|
actions.summarize(ctx)
|
|
|
|
sources = ctx.artifacts.get_content("sources", {})
|
|
assert sources["source_profile"] == "code"
|
|
answer = str(ctx.artifacts.get_content("final_answer", ""))
|
|
assert "кодовых слоев индекса" not in answer
|
|
assert "CodeRAG" not in answer
|
|
assert "app/task_processor.py" in answer
|
|
assert "requirements/docs context" not in answer
|
|
|
|
|
|
def test_explain_actions_add_code_details_block() -> None:
|
|
ctx = _ctx(
|
|
[
|
|
{
|
|
"source": "src/config_manager/__init__.py",
|
|
"layer": "C1_SYMBOL_CATALOG",
|
|
"title": "ConfigManager",
|
|
"content": "const ConfigManager\nConfigManager = config_manager.v2.ConfigManagerV2",
|
|
"metadata": {
|
|
"qname": "ConfigManager",
|
|
"kind": "const",
|
|
"lang_payload": {"imported_from": "v2.ConfigManagerV2", "import_alias": True},
|
|
},
|
|
},
|
|
{
|
|
"source": "src/config_manager/v2/control/base.py",
|
|
"layer": "C1_SYMBOL_CATALOG",
|
|
"title": "ControlChannel",
|
|
"content": "class ControlChannel\nControlChannel(ABC)",
|
|
"metadata": {"qname": "ControlChannel", "kind": "class"},
|
|
},
|
|
{
|
|
"source": "src/config_manager/v2/core/control_bridge.py",
|
|
"layer": "C1_SYMBOL_CATALOG",
|
|
"title": "ControlChannelBridge",
|
|
"content": "class ControlChannelBridge\nПредоставляет halt и status как обработчики start/stop/status",
|
|
"metadata": {"qname": "ControlChannelBridge", "kind": "class"},
|
|
},
|
|
{
|
|
"source": "src/config_manager/v2/core/control_bridge.py",
|
|
"layer": "C2_DEPENDENCY_GRAPH",
|
|
"title": "ControlChannelBridge.on_start:calls",
|
|
"content": "ControlChannelBridge.on_start calls self._start_runtime",
|
|
"metadata": {"src_qname": "ControlChannelBridge.on_start", "dst_ref": "self._start_runtime"},
|
|
},
|
|
{
|
|
"source": "src/config_manager/v2/__init__.py",
|
|
"layer": "C0_SOURCE_CHUNKS",
|
|
"title": "src/config_manager/v2/__init__.py:1-6",
|
|
"content": '"""Контракт: управление через API (config.yaml, секция management)."""',
|
|
"metadata": {},
|
|
},
|
|
]
|
|
)
|
|
actions = ExplainActions()
|
|
|
|
actions.collect_sources(ctx)
|
|
actions.extract_logic(ctx)
|
|
actions.summarize(ctx)
|
|
|
|
answer = str(ctx.artifacts.get_content("final_answer", ""))
|
|
assert "### Что видно по коду" in answer
|
|
assert "ConfigManager` в проекте доступен как alias" in answer
|
|
assert "ControlChannelBridge.on_start" in answer
|
|
assert "### Где смотреть в проекте" in answer
|
|
assert "В индексе нет точного символа" not in answer
|
|
assert "отдельный интерфейс управления" in answer
|