Agent integration to structured query

This commit is contained in:
Cyber MacGeddon 2025-09-04 16:18:42 +01:00
parent a6d9f5e849
commit 6efdf18555
4 changed files with 86 additions and 2 deletions

View file

@ -31,4 +31,5 @@ from . graph_rag_client import GraphRagClientSpec
from . tool_service import ToolService from . tool_service import ToolService
from . tool_client import ToolClientSpec from . tool_client import ToolClientSpec
from . agent_client import AgentClientSpec from . agent_client import AgentClientSpec
from . structured_query_client import StructuredQueryClientSpec

View file

@ -0,0 +1,33 @@
from . request_response_spec import RequestResponse, RequestResponseSpec
from .. schema import StructuredQueryRequest, StructuredQueryResponse
class StructuredQueryClient(RequestResponse):
async def structured_query(self, question, timeout=600):
resp = await self.request(
StructuredQueryRequest(
question = question
),
timeout=timeout
)
if resp.error:
raise RuntimeError(resp.error.message)
# Return the full response structure for the tool to handle
return {
"data": resp.data,
"errors": resp.errors if resp.errors else [],
"error": resp.error
}
class StructuredQueryClientSpec(RequestResponseSpec):
def __init__(
self, request_name, response_name,
):
super(StructuredQueryClientSpec, self).__init__(
request_name = request_name,
request_schema = StructuredQueryRequest,
response_name = response_name,
response_schema = StructuredQueryResponse,
impl = StructuredQueryClient,
)

View file

@ -12,11 +12,11 @@ import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
from ... base import AgentService, TextCompletionClientSpec, PromptClientSpec from ... base import AgentService, TextCompletionClientSpec, PromptClientSpec
from ... base import GraphRagClientSpec, ToolClientSpec from ... base import GraphRagClientSpec, ToolClientSpec, StructuredQueryClientSpec
from ... schema import AgentRequest, AgentResponse, AgentStep, Error from ... schema import AgentRequest, AgentResponse, AgentStep, Error
from . tools import KnowledgeQueryImpl, TextCompletionImpl, McpToolImpl, PromptImpl from . tools import KnowledgeQueryImpl, TextCompletionImpl, McpToolImpl, PromptImpl, StructuredQueryImpl
from . agent_manager import AgentManager from . agent_manager import AgentManager
from ..tool_filter import validate_tool_config, filter_tools_by_group_and_state, get_next_state from ..tool_filter import validate_tool_config, filter_tools_by_group_and_state, get_next_state
@ -80,6 +80,13 @@ class Processor(AgentService):
) )
) )
self.register_specification(
StructuredQueryClientSpec(
request_name = "structured-query-request",
response_name = "structured-query-response",
)
)
async def on_tools_config(self, config, version): async def on_tools_config(self, config, version):
logger.info(f"Loading configuration version {version}") logger.info(f"Loading configuration version {version}")
@ -138,6 +145,12 @@ class Processor(AgentService):
template_id=data.get("template"), template_id=data.get("template"),
arguments=arguments arguments=arguments
) )
elif impl_id == "structured-query":
impl = functools.partial(
StructuredQueryImpl,
collection=data.get("collection")
)
arguments = StructuredQueryImpl.get_arguments()
else: else:
raise RuntimeError( raise RuntimeError(
f"Tool type {impl_id} not known" f"Tool type {impl_id} not known"

View file

@ -85,6 +85,43 @@ class McpToolImpl:
return json.dumps(output) return json.dumps(output)
# This tool implementation knows how to query structured data using natural language
class StructuredQueryImpl:
def __init__(self, context, collection=None):
self.context = context
self.collection = collection # For multi-tenant scenarios
@staticmethod
def get_arguments():
return [
Argument(
name="question",
type="string",
description="Natural language question about structured data (tables, databases, etc.)"
)
]
async def invoke(self, **arguments):
client = self.context("structured-query-request")
logger.debug("Structured query question...")
result = await client.structured_query(
arguments.get("question")
)
# Format the result for the agent
if isinstance(result, dict):
if result.get("error"):
return f"Error: {result['error']['message']}"
elif result.get("data"):
# Pretty format JSON data for agent consumption
return json.dumps(result["data"], indent=2)
else:
return "No data returned"
else:
return str(result)
# This tool implementation knows how to execute prompt templates # This tool implementation knows how to execute prompt templates
class PromptImpl: class PromptImpl:
def __init__(self, context, template_id, arguments=None): def __init__(self, context, template_id, arguments=None):