171 lines
7.1 KiB
Python
171 lines
7.1 KiB
Python
"""Integration tools — Agent → Workflow + Agent → Knowledge.
|
|
|
|
Registers AI tools that allow agents to start workflows and ask knowledge questions.
|
|
Builds on: workflow_service, knowledge services, tool_registry.
|
|
"""
|
|
from __future__ import annotations
|
|
import logging
|
|
import uuid
|
|
from typing import Any
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def register_integration_tools() -> None:
|
|
"""Register workflow + knowledge tools in the AI tool registry."""
|
|
from app.plugins.builtins.ai_assistant.tool_registry import get_tool_registry
|
|
registry = get_tool_registry()
|
|
|
|
# ── I-AW: Agent → Workflow ──
|
|
async def _start_workflow_handler(arguments: dict[str, Any], context: dict[str, Any]) -> dict[str, Any]:
|
|
"""Start a workflow by ID."""
|
|
from app.services.workflow_service import create_instance
|
|
from app.core.db import get_worker_session_factory
|
|
workflow_id = arguments.get("workflow_id", "")
|
|
tenant_id = context.get("tenant_id")
|
|
user_id = context.get("user_id")
|
|
if not workflow_id or not tenant_id:
|
|
return {"error": "workflow_id and tenant_id required"}
|
|
factory = get_worker_session_factory()
|
|
async with factory() as db:
|
|
instance = await create_instance(
|
|
db=db,
|
|
tenant_id=uuid.UUID(str(tenant_id)),
|
|
workflow_id=uuid.UUID(workflow_id),
|
|
initiated_by=uuid.UUID(str(user_id)) if user_id else None,
|
|
)
|
|
await db.commit()
|
|
return {"instance_id": str(instance.get("id", "")), "status": instance.get("status", "created")}
|
|
|
|
registry.register(
|
|
name="start_workflow",
|
|
description="Start a workflow by its ID. Returns the instance ID and status.",
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"workflow_id": {"type": "string", "description": "UUID of the workflow to start"},
|
|
},
|
|
"required": ["workflow_id"],
|
|
},
|
|
handler=_start_workflow_handler,
|
|
plugin_name="integration",
|
|
required_permission="workflows:read",
|
|
category="workflow",
|
|
)
|
|
|
|
async def _check_workflow_status_handler(arguments: dict[str, Any], context: dict[str, Any]) -> dict[str, Any]:
|
|
"""Check the status of a workflow instance."""
|
|
from sqlalchemy import select
|
|
from app.models.workflow import WorkflowInstance
|
|
from app.core.db import get_worker_session_factory
|
|
instance_id = arguments.get("instance_id", "")
|
|
tenant_id = context.get("tenant_id")
|
|
if not instance_id or not tenant_id:
|
|
return {"error": "instance_id and tenant_id required"}
|
|
factory = get_worker_session_factory()
|
|
async with factory() as db:
|
|
result = await db.execute(
|
|
select(WorkflowInstance).where(
|
|
WorkflowInstance.id == uuid.UUID(instance_id),
|
|
WorkflowInstance.tenant_id == uuid.UUID(str(tenant_id)),
|
|
)
|
|
)
|
|
inst = result.scalar_one_or_none()
|
|
if not inst:
|
|
return {"error": "Instance not found"}
|
|
return {
|
|
"instance_id": str(inst.id),
|
|
"status": inst.status,
|
|
"current_step": inst.current_step_index,
|
|
"completed_at": inst.completed_at.isoformat() if inst.completed_at else None,
|
|
}
|
|
|
|
registry.register(
|
|
name="check_workflow_status",
|
|
description="Check the status of a workflow instance by its ID.",
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"instance_id": {"type": "string", "description": "UUID of the workflow instance"},
|
|
},
|
|
"required": ["instance_id"],
|
|
},
|
|
handler=_check_workflow_status_handler,
|
|
plugin_name="integration",
|
|
required_permission="workflows:read",
|
|
category="workflow",
|
|
)
|
|
|
|
# ── I-AK: Agent → Knowledge ──
|
|
async def _ask_knowledge_handler(arguments: dict[str, Any], context: dict[str, Any]) -> dict[str, Any]:
|
|
"""Ask a knowledge question."""
|
|
from app.plugins.builtins.knowledge.services import ask_knowledge
|
|
from app.core.db import get_worker_session_factory
|
|
question = arguments.get("question", "")
|
|
tenant_id = context.get("tenant_id")
|
|
if not question or not tenant_id:
|
|
return {"error": "question and tenant_id required"}
|
|
factory = get_worker_session_factory()
|
|
async with factory() as db:
|
|
result = await ask_knowledge(db=db, tenant_id=uuid.UUID(str(tenant_id)), question=question)
|
|
return {"answer": result.get("answer", ""), "evidence_count": len(result.get("evidence", []))}
|
|
|
|
registry.register(
|
|
name="ask_knowledge",
|
|
description="Ask a knowledge question. Searches wiki articles and graph relationships for context.",
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"question": {"type": "string", "description": "The question to ask"},
|
|
},
|
|
"required": ["question"],
|
|
},
|
|
handler=_ask_knowledge_handler,
|
|
plugin_name="integration",
|
|
required_permission="wiki:read",
|
|
category="knowledge",
|
|
)
|
|
|
|
async def _search_knowledge_handler(arguments: dict[str, Any], context: dict[str, Any]) -> dict[str, Any]:
|
|
"""Search wiki articles via unified search."""
|
|
from app.plugins.builtins.unified_search.provider_registry import get_search_registry
|
|
from app.core.db import get_worker_session_factory
|
|
query = arguments.get("query", "")
|
|
tenant_id = context.get("tenant_id")
|
|
if not query or not tenant_id:
|
|
return {"error": "query and tenant_id required"}
|
|
factory = get_worker_session_factory()
|
|
async with factory() as db:
|
|
registry = get_search_registry()
|
|
wiki_provider = registry.get("wiki_article")
|
|
if not wiki_provider:
|
|
return {"error": "Wiki search provider not available"}
|
|
results = await wiki_provider._search_fts_filtered(
|
|
db=db, tsquery=query, tenant_id=uuid.UUID(str(tenant_id)), limit=5, visible_ids=None
|
|
)
|
|
return {
|
|
"results": [
|
|
{"title": r.get("title", ""), "summary": (r.get("summary") or r.get("content", "")[:200] or "")}
|
|
for r in results
|
|
],
|
|
"count": len(results),
|
|
}
|
|
|
|
registry.register(
|
|
name="search_knowledge",
|
|
description="Search wiki articles by keyword. Returns matching articles with title and summary.",
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"query": {"type": "string", "description": "Search query"},
|
|
},
|
|
"required": ["query"],
|
|
},
|
|
handler=_search_knowledge_handler,
|
|
plugin_name="integration",
|
|
required_permission="wiki:read",
|
|
category="knowledge",
|
|
)
|
|
|
|
logger.info("Registered integration tools: start_workflow, check_workflow_status, ask_knowledge, search_knowledge")
|