mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-10 08:05:22 +02:00
feat: refactor node spec and add mcp tools (#244)
* refactor: carve out extraction panel * refactor: create spec versions for node types * refactor: create a GenericNode and remove custom nodes * feat: add python and typescript sdk * add dograh sdk * fix: fetch draft workflow definition over published one * fix: fix routes of SDKs to use code gen * chore: remove doclink dependency to reduce image size * chore: format files * chore: bump pipecat * feat: let mcp fetch archived workflows on demand * chore: fix tests * feat: add sdk documentation * chore: change banner and add badge
This commit is contained in:
parent
0a61ef295f
commit
00a1a22b74
162 changed files with 14355 additions and 3554 deletions
|
|
@ -8,6 +8,7 @@ from loguru import logger
|
|||
from api.db.models import WorkflowRunModel
|
||||
from api.services.gen_ai.json_parser import parse_llm_json
|
||||
from api.services.pipecat.service_factory import create_llm_service_from_provider
|
||||
from api.services.workflow.dto import QANodeData
|
||||
from api.services.workflow.qa.conversation import (
|
||||
build_conversation_structure,
|
||||
format_transcript,
|
||||
|
|
@ -77,7 +78,7 @@ async def _generate_conversation_summary(
|
|||
|
||||
|
||||
async def run_per_node_qa_analysis(
|
||||
qa_node_data: dict[str, Any],
|
||||
qa_data: QANodeData,
|
||||
workflow_run: WorkflowRunModel,
|
||||
workflow_run_id: int,
|
||||
workflow_definition: dict,
|
||||
|
|
@ -106,18 +107,16 @@ async def run_per_node_qa_analysis(
|
|||
logger.info(
|
||||
f"Events lack node_id for run {workflow_run_id}, falling back to whole-call QA"
|
||||
)
|
||||
return await _run_whole_call_qa_analysis(
|
||||
qa_node_data, workflow_run, workflow_run_id
|
||||
)
|
||||
return await _run_whole_call_qa_analysis(qa_data, workflow_run, workflow_run_id)
|
||||
|
||||
system_prompt = qa_node_data.get("qa_system_prompt", "")
|
||||
system_prompt = qa_data.qa_system_prompt or ""
|
||||
if not system_prompt:
|
||||
logger.warning("No system prompt defined for QA Node")
|
||||
return {"error": "no_system_prompt", "node_results": {}}
|
||||
|
||||
# Resolve LLM config
|
||||
provider, model, api_key, service_kwargs = await resolve_llm_config(
|
||||
qa_node_data, workflow_run
|
||||
qa_data, workflow_run
|
||||
)
|
||||
if not api_key:
|
||||
logger.warning(
|
||||
|
|
@ -127,7 +126,7 @@ async def run_per_node_qa_analysis(
|
|||
|
||||
# Ensure node summaries
|
||||
node_summaries = await ensure_node_summaries(
|
||||
workflow_definition, definition_id, workflow_run, qa_node_data
|
||||
workflow_definition, definition_id, workflow_run, qa_data
|
||||
)
|
||||
|
||||
# Set up Langfuse tracing
|
||||
|
|
@ -228,7 +227,7 @@ async def run_per_node_qa_analysis(
|
|||
|
||||
|
||||
async def _run_whole_call_qa_analysis(
|
||||
qa_node_data: dict[str, Any],
|
||||
qa_data: QANodeData,
|
||||
workflow_run: WorkflowRunModel,
|
||||
workflow_run_id: int,
|
||||
) -> dict[str, Any]:
|
||||
|
|
@ -254,13 +253,13 @@ async def _run_whole_call_qa_analysis(
|
|||
metrics = compute_call_metrics(rtf_events, call_duration)
|
||||
|
||||
# Resolve LLM config
|
||||
system_prompt = qa_node_data.get("qa_system_prompt", "")
|
||||
system_prompt = qa_data.qa_system_prompt or ""
|
||||
if not system_prompt:
|
||||
logger.warning("No system prompt defined for QA Node")
|
||||
return {"error": "no_system_prompt", "node_results": {}}
|
||||
|
||||
provider, model, api_key, service_kwargs = await resolve_llm_config(
|
||||
qa_node_data, workflow_run
|
||||
qa_data, workflow_run
|
||||
)
|
||||
|
||||
if not api_key:
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ import random
|
|||
|
||||
from api.db import db_client
|
||||
from api.db.models import WorkflowRunModel
|
||||
from api.services.workflow.dto import QANodeData
|
||||
|
||||
|
||||
async def resolve_llm_config(
|
||||
qa_node_data: dict, workflow_run: WorkflowRunModel
|
||||
qa_data: QANodeData, workflow_run: WorkflowRunModel
|
||||
) -> tuple[str, str, str, dict]:
|
||||
"""Resolve the LLM provider, model, API key, and extra kwargs for QA analysis.
|
||||
|
||||
|
|
@ -18,24 +19,23 @@ async def resolve_llm_config(
|
|||
(provider, model, api_key, service_kwargs) tuple — service_kwargs can be
|
||||
passed directly to create_llm_service_from_provider as keyword arguments.
|
||||
"""
|
||||
if not qa_node_data.get("qa_use_workflow_llm", True):
|
||||
provider = qa_node_data.get("qa_provider", "openai")
|
||||
if not qa_data.qa_use_workflow_llm:
|
||||
provider = qa_data.qa_provider or "openai"
|
||||
kwargs = {}
|
||||
if provider == "azure":
|
||||
kwargs["endpoint"] = qa_node_data.get("qa_endpoint", "")
|
||||
kwargs["endpoint"] = qa_data.qa_endpoint or ""
|
||||
return (
|
||||
provider,
|
||||
qa_node_data.get("qa_model"),
|
||||
qa_node_data.get("qa_api_key"),
|
||||
qa_data.qa_model,
|
||||
qa_data.qa_api_key,
|
||||
kwargs,
|
||||
)
|
||||
|
||||
# Fall back to user's configured LLM
|
||||
provider, model, api_key, kwargs = await resolve_user_llm_config(workflow_run)
|
||||
|
||||
qa_model = qa_node_data.get("qa_model", "default")
|
||||
if qa_model and qa_model != "default":
|
||||
model = qa_model
|
||||
if qa_data.qa_model and qa_data.qa_model != "default":
|
||||
model = qa_data.qa_model
|
||||
|
||||
return provider, model, api_key, kwargs
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from loguru import logger
|
|||
from api.db import db_client
|
||||
from api.db.models import WorkflowRunModel
|
||||
from api.services.pipecat.service_factory import create_llm_service_from_provider
|
||||
from api.services.workflow.dto import NodeType
|
||||
from api.services.workflow.dto import NodeType, QANodeData
|
||||
from api.services.workflow.qa.llm_config import resolve_llm_config
|
||||
from api.services.workflow.qa.tracing import create_node_summary_trace
|
||||
from pipecat.processors.aggregators.llm_context import LLMContext
|
||||
|
|
@ -48,7 +48,7 @@ async def ensure_node_summaries(
|
|||
workflow_definition: dict,
|
||||
definition_id: int | None,
|
||||
workflow_run: WorkflowRunModel,
|
||||
qa_node_data: dict,
|
||||
qa_data: QANodeData,
|
||||
) -> dict[str, Any]:
|
||||
"""Ensure every agentNode/startCall node has a summary in the definition.
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ async def ensure_node_summaries(
|
|||
return existing_summaries
|
||||
|
||||
provider, model, api_key, service_kwargs = await resolve_llm_config(
|
||||
qa_node_data, workflow_run
|
||||
qa_data, workflow_run
|
||||
)
|
||||
if not api_key:
|
||||
logger.warning("No API key for node summary generation, skipping")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue