Skip to content

Commit c886efb

Browse files
committed
add option to set the task_type in the config, add tests
1 parent 65f7ec0 commit c886efb

2 files changed

Lines changed: 115 additions & 3 deletions

File tree

src/structsense/app.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
str_to_bool,
7575
check_ollama_health,
7676
)
77-
from utils.task_detection import detect_task_type
77+
from utils.task_detection import detect_task_type, DEFAULT_TAXONOMY
7878
from utils.task_tools import get_tools_for_agent
7979
from utils.crew_utils import initialize_memory
8080
from utils.mlops import setup_monitoring
@@ -1475,13 +1475,21 @@ def _get_detected_task_type(self, agent_key: str, task_key: str) -> str:
14751475
otherwise falls back to a heuristic so resource/structured extraction get
14761476
no NER tool and correct post-processor/merger.
14771477
"""
1478-
task_data = self.task_config.get(task_key) or {}
1478+
task_data = self.task_config.get(task_key, {})
1479+
task_type = self.task_config.get(task_key, {}).get("task_type")
1480+
if task_type in DEFAULT_TAXONOMY:
1481+
logger.info(f"Using task type from agent config for agent '{agent_key}': {task_type}")
1482+
return task_type
1483+
elif task_type:
1484+
logger.warning(
1485+
f"Task config for '{task_key}' specifies task type '{task_type}' which is not in the default taxonomy list. Falling back to detection."
1486+
)
14791487
description = task_data.get("description", "") or ""
14801488
if not description and isinstance(task_data, dict):
14811489
description = str(task_data)
14821490
api_key = os.environ.get("OPENROUTER_API_KEY")
14831491
agent_id = task_data.get("agent_id", agent_key)
1484-
llm_config = (self.agent_config.get(agent_id) or {}).get("llm") or {}
1492+
llm_config = self.agent_config.get(agent_id, {}).get("llm", {})
14851493
if api_key and llm_config and (llm_config.get("model") or llm_config.get("base_url")):
14861494
try:
14871495
result = detect_task_type(

src/tests/task_detection_test.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
"""Tests for task_type detection in StructSenseFlow."""
2+
3+
from pathlib import Path
4+
import os
5+
6+
import pytest
7+
from dotenv import load_dotenv
8+
9+
from structsense.app import StructSenseFlow
10+
11+
skip_if_no_openrouter = pytest.mark.skipif(
12+
not os.environ.get("OPENROUTER_API_KEY"),
13+
reason="OPENROUTER_API_KEY not set",
14+
)
15+
16+
ENV_PATH = Path(__file__).parent / "configs/.env_example"
17+
SOURCE_TEXT_SHORT = "Retinal ganglion cell"
18+
19+
LLM_CONFIG = {
20+
"model": "openrouter/openai/gpt-4o-mini",
21+
"base_url": "https://openrouter.ai/api/v1",
22+
}
23+
24+
BASE_AGENT_CONFIG = {
25+
"agent_key": {
26+
"role": "Neuroscience NER Extractor Agent",
27+
"goal": "Extract named entities from neuroscience text {input_text}.",
28+
"backstory": "You are an AI assistant for neuroscientists",
29+
}
30+
}
31+
32+
BASE_TASK_CONFIG = {
33+
"task_key": {
34+
"description": "Extract entities from the input text. Use the NER tool on {input_text}.",
35+
"agent_id": "agent_key",
36+
}
37+
}
38+
39+
40+
@pytest.fixture(autouse=True)
41+
def load_env():
42+
load_dotenv(ENV_PATH, override=True)
43+
44+
45+
def make_flow(agent_config=None, task_config=None):
46+
return StructSenseFlow(
47+
agent_config=agent_config or BASE_AGENT_CONFIG,
48+
task_config=task_config or BASE_TASK_CONFIG,
49+
embedder_config={},
50+
source_text=SOURCE_TEXT_SHORT,
51+
)
52+
53+
54+
@pytest.mark.parametrize("task_type", ["ner", "extraction", "keyphrase_extraction"])
55+
def test_task_type_from_config(task_type):
56+
"""task_type is explicitly set in agent_config — returned directly without LLM or heuristic."""
57+
task_config = {
58+
"task_key": {
59+
**BASE_TASK_CONFIG["task_key"],
60+
"task_type": task_type,
61+
}
62+
}
63+
flow = make_flow(task_config=task_config)
64+
detected = flow._get_detected_task_type("agent_key", "task_key")
65+
assert detected == task_type
66+
67+
68+
@pytest.mark.parametrize(
69+
"description,expected_task_type",
70+
[
71+
(None, "ner"), # default to "ner" if no description is provided
72+
("Extract resources such as datasets and tools mentioned in {input_text}.", "resource"),
73+
],
74+
)
75+
def test_task_type_from_heuristic(monkeypatch, description, expected_task_type):
76+
"""task_type is inferred from keywords in task description — no LLM call."""
77+
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
78+
if description:
79+
task_config = {
80+
"task_key": {
81+
**BASE_TASK_CONFIG["task_key"],
82+
"description": description,
83+
}
84+
}
85+
else:
86+
task_config = BASE_TASK_CONFIG
87+
flow = make_flow(task_config=task_config)
88+
task_type = flow._get_detected_task_type("agent_key", "task_key")
89+
assert task_type == expected_task_type
90+
91+
92+
@pytest.mark.requires_openrouter
93+
@skip_if_no_openrouter
94+
def test_task_type_from_llm():
95+
"""task_type is detected by LLM call via detect_task_type."""
96+
agent_config = {
97+
"agent_key": {
98+
**BASE_AGENT_CONFIG["agent_key"],
99+
"llm": LLM_CONFIG,
100+
}
101+
}
102+
flow = make_flow(agent_config=agent_config)
103+
task_type = flow._get_detected_task_type("agent_key", "task_key")
104+
assert task_type == "ner"

0 commit comments

Comments
 (0)