Compare commits

...

15 Commits

Author SHA1 Message Date
Dane Urban
1c5d6b88e3 nit 2026-01-12 16:45:04 -08:00
Dane Urban
2c881c8b61 fix test issues 2026-01-12 13:52:00 -08:00
Dane Urban
3725e3485c Merge branch 'main' into tool_name_migration 2026-01-12 13:49:58 -08:00
Dane Urban
d72fd84bcd nit 2026-01-12 13:39:48 -08:00
Dane Urban
6b7d560b0c change to list 2026-01-12 13:09:43 -08:00
Dane Urban
2af27ba1f5 . 2026-01-12 10:58:38 -08:00
Dane Urban
75ac128836 make up to date 2026-01-12 09:56:52 -08:00
Dane Urban
a688f4ee81 Merge branch 'main' into tool_name_migration 2026-01-12 09:55:38 -08:00
Dane Urban
ca54a85929 update revision 2026-01-12 09:35:04 -08:00
Dane Urban
3571a8d39a fix revision id 2026-01-11 18:13:32 -08:00
Dane Urban
08ac2f2e20 remove try-except 2026-01-11 18:00:57 -08:00
Danelegend
9b47267d48 Delete backend/alembic/versions/19a896a66d3f_tool_name_consistency.py 2026-01-11 17:56:00 -08:00
Dane Urban
c57ee34a33 Change this 2026-01-11 17:55:26 -08:00
Dane Urban
318a66a189 Add comment 2026-01-11 17:39:29 -08:00
Dane Urban
edf9e68abf nit 2026-01-11 17:36:09 -08:00
10 changed files with 170 additions and 59 deletions

View File

@@ -7,7 +7,6 @@ Create Date: 2025-12-18 16:00:00.000000
"""
from alembic import op
from onyx.deep_research.dr_mock_tools import RESEARCH_AGENT_DB_NAME
import sqlalchemy as sa
@@ -19,7 +18,7 @@ depends_on = None
DEEP_RESEARCH_TOOL = {
"name": RESEARCH_AGENT_DB_NAME,
"name": "ResearchAgent",
"display_name": "Research Agent",
"description": "The Research Agent is a sub-agent that conducts research on a specific topic.",
"in_code_tool_id": "ResearchAgent",

View File

@@ -0,0 +1,86 @@
"""tool_name_consistency
Revision ID: d25168c2beee
Revises: 8405ca81cc83
Create Date: 2026-01-11 17:54:40.135777
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "d25168c2beee"
down_revision = "8405ca81cc83"
branch_labels = None
depends_on = None
# Currently the seeded tools have the in_code_tool_id == name
CURRENT_TOOL_NAME_MAPPING = [
"SearchTool",
"WebSearchTool",
"ImageGenerationTool",
"PythonTool",
"OpenURLTool",
"KnowledgeGraphTool",
"ResearchAgent",
]
# Mapping of in_code_tool_id -> name
# These are the expected names that we want in the database
EXPECTED_TOOL_NAME_MAPPING = {
"SearchTool": "internal_search",
"WebSearchTool": "web_search",
"ImageGenerationTool": "generate_image",
"PythonTool": "python",
"OpenURLTool": "open_url",
"KnowledgeGraphTool": "run_kg_search",
"ResearchAgent": "research_agent",
}
def upgrade() -> None:
conn = op.get_bind()
# Mapping of in_code_tool_id to the NAME constant from each tool class
# These match the .name property of each tool implementation
tool_name_mapping = EXPECTED_TOOL_NAME_MAPPING
# Update the name column for each tool based on its in_code_tool_id
for in_code_tool_id, expected_name in tool_name_mapping.items():
conn.execute(
sa.text(
"""
UPDATE tool
SET name = :expected_name
WHERE in_code_tool_id = :in_code_tool_id
"""
),
{
"expected_name": expected_name,
"in_code_tool_id": in_code_tool_id,
},
)
def downgrade() -> None:
conn = op.get_bind()
# Reverse the migration by setting name back to in_code_tool_id
# This matches the original pattern where name was the class name
for in_code_tool_id in CURRENT_TOOL_NAME_MAPPING:
conn.execute(
sa.text(
"""
UPDATE tool
SET name = :current_name
WHERE in_code_tool_id = :in_code_tool_id
"""
),
{
"current_name": in_code_tool_id,
"in_code_tool_id": in_code_tool_id,
},
)

View File

@@ -2616,6 +2616,7 @@ class Tool(Base):
__tablename__ = "tool"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
# The name of the tool that the LLM will see
name: Mapped[str] = mapped_column(String, nullable=False)
description: Mapped[str] = mapped_column(Text, nullable=True)
# ID of the tool in the codebase, only applies for in-code tools.

View File

@@ -21,7 +21,6 @@ from onyx.configs.constants import MessageType
from onyx.db.tools import get_tool_by_name
from onyx.deep_research.dr_mock_tools import get_clarification_tool_definitions
from onyx.deep_research.dr_mock_tools import get_orchestrator_tools
from onyx.deep_research.dr_mock_tools import RESEARCH_AGENT_DB_NAME
from onyx.deep_research.dr_mock_tools import RESEARCH_AGENT_TOOL_NAME
from onyx.deep_research.dr_mock_tools import THINK_TOOL_RESPONSE_MESSAGE
from onyx.deep_research.dr_mock_tools import THINK_TOOL_RESPONSE_TOKEN_COUNT
@@ -634,7 +633,8 @@ def run_deep_research_llm_loop(
tool_name=current_tool_call.tool_name,
tool_call_id=current_tool_call.tool_call_id,
tool_id=get_tool_by_name(
tool_name=RESEARCH_AGENT_DB_NAME, db_session=db_session
tool_name=RESEARCH_AGENT_TOOL_NAME,
db_session=db_session,
).id,
reasoning_tokens=llm_step_result.reasoning
or most_recent_reasoning,

View File

@@ -1,6 +1,6 @@
GENERATE_PLAN_TOOL_NAME = "generate_plan"
RESEARCH_AGENT_DB_NAME = "ResearchAgent"
RESEARCH_AGENT_IN_CODE_ID = "ResearchAgent"
RESEARCH_AGENT_TOOL_NAME = "research_agent"
RESEARCH_AGENT_TASK_KEY = "task"

View File

@@ -11,7 +11,7 @@ from onyx.db.chat import get_db_search_doc_by_id
from onyx.db.chat import translate_db_search_doc_to_saved_search_doc
from onyx.db.models import ChatMessage
from onyx.db.tools import get_tool_by_id
from onyx.deep_research.dr_mock_tools import RESEARCH_AGENT_DB_NAME
from onyx.deep_research.dr_mock_tools import RESEARCH_AGENT_IN_CODE_ID
from onyx.deep_research.dr_mock_tools import RESEARCH_AGENT_TASK_KEY
from onyx.server.query_and_chat.placement import Placement
from onyx.server.query_and_chat.streaming_models import AgentResponseDelta
@@ -401,7 +401,7 @@ def translate_assistant_message_to_packets(
# Here we do a try because some tools may get deleted before the session is reloaded.
try:
tool = get_tool_by_id(tool_call.tool_id, db_session)
if tool.in_code_tool_id == RESEARCH_AGENT_DB_NAME:
if tool.in_code_tool_id == RESEARCH_AGENT_IN_CODE_ID:
research_agent_count += 1
# Handle different tool types
@@ -457,7 +457,7 @@ def translate_assistant_message_to_packets(
)
)
elif tool.in_code_tool_id == RESEARCH_AGENT_DB_NAME:
elif tool.in_code_tool_id == RESEARCH_AGENT_IN_CODE_ID:
# Not ideal but not a huge issue if the research task is lost.
research_task = cast(
str,

View File

@@ -61,13 +61,13 @@ def test_cold_startup_default_assistant() -> None:
# Verify all three main tools are attached
assert (
"SearchTool" in tool_names
"internal_search" in tool_names
), "Default assistant should have SearchTool attached"
assert (
"ImageGenerationTool" in tool_names
"generate_image" in tool_names
), "Default assistant should have ImageGenerationTool attached"
assert (
"WebSearchTool" in tool_names
"web_search" in tool_names
), "Default assistant should have WebSearchTool attached"
# Also verify by display names for clarity

View File

@@ -1,3 +1,4 @@
from pydantic import BaseModel
from sqlalchemy import text
from onyx.db.engine.sql_engine import get_session_with_current_tenant
@@ -5,6 +6,53 @@ from tests.integration.common_utils.reset import downgrade_postgres
from tests.integration.common_utils.reset import upgrade_postgres
class ToolSeedingExpectedResult(BaseModel):
name: str
display_name: str
in_code_tool_id: str
user_id: str | None
EXPECTED_TOOLS = {
"SearchTool": ToolSeedingExpectedResult(
name="internal_search",
display_name="Internal Search",
in_code_tool_id="SearchTool",
user_id=None,
),
"ImageGenerationTool": ToolSeedingExpectedResult(
name="generate_image",
display_name="Image Generation",
in_code_tool_id="ImageGenerationTool",
user_id=None,
),
"WebSearchTool": ToolSeedingExpectedResult(
name="web_search",
display_name="Web Search",
in_code_tool_id="WebSearchTool",
user_id=None,
),
"KnowledgeGraphTool": ToolSeedingExpectedResult(
name="run_kg_search",
display_name="Knowledge Graph Search",
in_code_tool_id="KnowledgeGraphTool",
user_id=None,
),
"PythonTool": ToolSeedingExpectedResult(
name="python",
display_name="Code Interpreter",
in_code_tool_id="PythonTool",
user_id=None,
),
"ResearchAgent": ToolSeedingExpectedResult(
name="research_agent",
display_name="Research Agent",
in_code_tool_id="ResearchAgent",
user_id=None,
),
}
def test_tool_seeding_migration() -> None:
"""Test that migration from base to head correctly seeds builtin tools."""
# Start from base and upgrade to just before tool seeding
@@ -49,56 +97,33 @@ def test_tool_seeding_migration() -> None:
len(tools) == 8
), f"Should have created exactly 8 builtin tools, got {len(tools)}"
def validate_tool(expected: ToolSeedingExpectedResult) -> None:
tool = next((t for t in tools if t[1] == expected.name), None)
assert tool is not None, f"{expected.name} should exist"
assert (
tool[2] == expected.display_name
), f"{expected.name} display name should be '{expected.display_name}'"
assert (
tool[4] == expected.in_code_tool_id
), f"{expected.name} in_code_tool_id should be '{expected.in_code_tool_id}'"
assert (
tool[5] is None
), f"{expected.name} should not have a user_id (builtin)"
# Check SearchTool
search_tool = next((t for t in tools if t[1] == "SearchTool"), None)
assert search_tool is not None, "SearchTool should exist"
assert (
search_tool[2] == "Internal Search"
), "SearchTool display name should be 'Internal Search'"
assert search_tool[5] is None, "SearchTool should not have a user_id (builtin)"
validate_tool(EXPECTED_TOOLS["SearchTool"])
# Check ImageGenerationTool
img_tool = next((t for t in tools if t[1] == "ImageGenerationTool"), None)
assert img_tool is not None, "ImageGenerationTool should exist"
assert (
img_tool[2] == "Image Generation"
), "ImageGenerationTool display name should be 'Image Generation'"
assert (
img_tool[5] is None
), "ImageGenerationTool should not have a user_id (builtin)"
validate_tool(EXPECTED_TOOLS["ImageGenerationTool"])
# Check WebSearchTool
web_tool = next((t for t in tools if t[1] == "WebSearchTool"), None)
assert web_tool is not None, "WebSearchTool should exist"
assert (
web_tool[2] == "Web Search"
), "WebSearchTool display name should be 'Web Search'"
assert web_tool[5] is None, "WebSearchTool should not have a user_id (builtin)"
validate_tool(EXPECTED_TOOLS["WebSearchTool"])
# Check KnowledgeGraphTool
kg_tool = next((t for t in tools if t[1] == "KnowledgeGraphTool"), None)
assert kg_tool is not None, "KnowledgeGraphTool should exist"
assert (
kg_tool[2] == "Knowledge Graph Search"
), "KnowledgeGraphTool display name should be 'Knowledge Graph Search'"
assert (
kg_tool[5] is None
), "KnowledgeGraphTool should not have a user_id (builtin)"
validate_tool(EXPECTED_TOOLS["KnowledgeGraphTool"])
# Check PythonTool
python_tool = next((t for t in tools if t[1] == "PythonTool"), None)
assert python_tool is not None, "PythonTool should exist"
assert (
python_tool[2] == "Code Interpreter"
), "PythonTool display name should be 'Code Interpreter'"
assert python_tool[5] is None, "PythonTool should not have a user_id (builtin)"
validate_tool(EXPECTED_TOOLS["PythonTool"])
# Check ResearchAgent (Deep Research as a tool)
research_agent = next((t for t in tools if t[1] == "ResearchAgent"), None)
assert research_agent is not None, "ResearchAgent should exist"
assert (
research_agent[2] == "Research Agent"
), "ResearchAgent display name should be 'Research Agent'"
assert (
research_agent[5] is None
), "ResearchAgent should not have a user_id (builtin)"
validate_tool(EXPECTED_TOOLS["ResearchAgent"])

View File

@@ -38,11 +38,11 @@ def test_unified_assistant(reset: None, admin_user: DATestUser) -> None:
# Verify tools
tools = unified_assistant.tools
tool_names = [tool.name for tool in tools]
assert "SearchTool" in tool_names, "SearchTool not found in unified assistant"
assert "internal_search" in tool_names, "SearchTool not found in unified assistant"
assert (
"ImageGenerationTool" in tool_names
"generate_image" in tool_names
), "ImageGenerationTool not found in unified assistant"
assert "WebSearchTool" in tool_names, "WebSearchTool not found in unified assistant"
assert "web_search" in tool_names, "WebSearchTool not found in unified assistant"
# Verify no starter messages
starter_messages = unified_assistant.starter_messages or []

View File

@@ -6,9 +6,9 @@ export const TOOL_IDS = {
actionToggle: '[data-testid="action-management-toggle"]',
options: '[data-testid="tool-options"]',
// These IDs are derived from tool.name in the app
searchOption: '[data-testid="tool-option-SearchTool"]',
webSearchOption: '[data-testid="tool-option-WebSearchTool"]',
imageGenerationOption: '[data-testid="tool-option-ImageGenerationTool"]',
searchOption: '[data-testid="tool-option-internal_search"]',
webSearchOption: '[data-testid="tool-option-web_search"]',
imageGenerationOption: '[data-testid="tool-option-generate_image"]',
// Generic toggle selector used inside tool options
toggleInput: 'input[type="checkbox"], input[type="radio"], [role="switch"]',
} as const;