Skip to main content

integration

Architecture

Studio is a native component of QALITA Platform, not a separate package.

Platform Architecture

┌─────────────────┐          ┌─────────────────┐          ┌─────────────────┐
│ Platform Web │ REST │ Platform API │ gRPC │ Worker │
│ (Frontend) │ ←──────→ │ (Backend) │ ←──────→ │ │
│ │ │ │ │ │
│ - Studio UI │ │ - Studio API │ │ - Data Access │
│ - Chat Panel │ │ - LLM Agent │ │ - SQL Queries │
│ - Context Bar │ │ - Data Tools │ │ - File Reads │
└─────────────────┘ └─────────────────┘ └─────────────────┘
React/Next.js FastAPI + LangGraph Python CLI

Component Responsibilities

ComponentResponsibility
FrontendChat interface, context selection, streaming display
Backend AgentLLM orchestration, tool execution, response generation
Backend APIREST endpoints, authentication, data preview
WorkerSource connectivity, query execution, data retrieval

Data Flow

  1. User sends message → Frontend collects context (issue, source, schema, metrics)
  2. API receives request → Creates LLM instance from database config
  3. Agent processes → Invokes LangGraph workflow, may call data tools
  4. Tools execute → gRPC requests to Worker for data operations
  5. Response streams → SSE events back to frontend

LLM Configuration

LLM providers are configured through the Platform database, not environment variables or files.

Database Model

LLM configurations are stored in the llm_configuration table:

ColumnTypeDescription
idintPrimary key
partner_idintOrganization FK
namestrDisplay name
providerstrProvider type
model_namestrModel identifier
api_keystrEncrypted API key
endpoint_urlstrCustom endpoint
is_activeboolActive configuration
configurationjsonAdditional parameters

Provider Mapping

The backend maps Platform providers to LangChain providers:

Platform ProviderLangChain Provider
openaiopenai
azure_openaiazure_openai
anthropicanthropic
ollamaollama
mistralmistral
genericopenai (compatible API)

Creating LLM from Config

The backend uses a factory pattern to create LLM instances:

from backend.agent import create_llm_from_db_config

# Async function to create LLM from active config
llm = await create_llm_from_db_config(
session=db_session,
partner_id=current_user.partner_id,
config_id=None, # Uses active config if None
streaming=True, # Enable streaming
)

Default Models

If no model is specified, defaults are used:

ProviderDefault Model
OpenAIgpt-4o-mini
Azure OpenAIgpt-4o-mini
Anthropicclaude-3-haiku-20240307
Ollamallama3.2
Mistralmistral-small-latest

Status & Capabilities

Worker Connection Status

Endpoint: GET /api/v1/studio/status

Returns information about connected Workers for data operations:

{
"connected_workers": [1, 3, 5],
"worker_count": 3
}

Requirements: At least one Worker must be connected for data tools to function.

Agent Capabilities

Endpoint: GET /api/v1/studio/agent/capabilities

Returns agent availability and LLM configuration status:

{
"agent_available": true,
"llm_configured": true,
"active_config": {
"id": 1,
"name": "Production GPT-4o",
"provider": "openai",
"model_name": "gpt-4o",
"endpoint_url": null
}
}

States:

agent_availablellm_configuredMeaning
truetrueFully operational
truefalseAgent ready, needs LLM config
false*Install langchain/langgraph

Visual Indicators

In the Platform frontend, indicators show:

  • 🟢 Agent Ready: LLM configured and agent available
  • 🟡 Partial: Agent available but no LLM config
  • 🔴 Unavailable: Agent module not installed
  • No Worker: No workers connected for data access

Data Preview Integration

Studio can preview source data through Workers using gRPC.

Preview Architecture

Frontend → Backend API → Worker (gRPC) → Source (DB/File)

DataPreviewManager

Response correlation

Preview Request Flow

  1. Frontend requests preview for source ID
  2. Backend verifies source belongs to user's partner
  3. Backend finds available Worker for partner
  4. Backend creates gRPC DataPreviewRequest
  5. Worker reads data from source
  6. Worker returns DataPreviewResponse via gRPC
  7. Backend returns formatted JSON to frontend

Preview Endpoint

GET /api/v1/studio/sources/{source_id}/preview

Parameters:

  • limit: Max rows (1-10000, default 1000)
  • source_version_id: Specific version
  • query: Custom SQL (for database sources)

Response:

{
"ok": true,
"data_type": "table",
"headers": ["id", "name", "email", "created_at"],
"rows": [
{"values": ["1", "John Doe", "john@example.com", "2024-01-15"]},
{"values": ["2", "Jane Smith", "jane@example.com", "2024-01-16"]}
],
"total_rows": 10000
}

Supported Data Types

TypeDescriptionContent
tableStructured dataheaders, rows
textPlain textcontent
jsonJSON datacontent
imageBinary imagebinary_base64, mime_type
pdfPDF documentbinary_base64, mime_type
errorError stateerror

Source & Issue Context

Studio provides contextual conversation retrieval based on sources and issues.

Context Query

GET /api/v1/studio/conversations/context

Parameters:

  • source_id: Get conversations from issues linked to source
  • issue_id: Get conversations from specific issue
  • project_id: Get all project conversations

Response:

{
"source_conversations": [...],
"issue_conversations": [...],
"project_conversations": [...],
"total_count": 15
}

Conversation Linking

Conversations are linked to Platform entities:

FieldPurpose
issue_idLink to quality issue
source_idLink to data source
project_idLink to project

This enables:

  • Retrieving conversation history when reopening an issue
  • Seeing related conversations from same source
  • Project-wide conversation overview

Data Tools Integration

Studio's agent can execute data operations through Workers.

Tool Architecture

Agent (LangGraph) → Tool Function → gRPC → Worker → Source

AgentActionManager

Response correlation

Available Tools

Tools are created dynamically based on the user's context:

from backend.agent.tools import create_data_tools

# Create tools bound to partner
tools = create_data_tools(
partner_id=current_user.partner_id,
source_id=context.get("source_id")
)

Tool Definitions

ToolInput SchemaAction
execute_sql_querysource_id, sql, limitRun SQL on database
read_source_datasource_id, limit, table, columnsRead data
describe_sourcesource_id, tableGet metadata
sample_source_datasource_id, n, tableRandom sample
count_rowssource_id, table, conditionCount rows
filter_datasource_id, condition, limitFilter data
aggregate_datasource_id, group_by, agg_funcAggregate

gRPC Communication

Tools communicate with Workers via gRPC:

Request:

message AgentActionRequest {
string request_id = 1;
string action_type = 2;
int32 source_id = 3;
string parameters_json = 4;
optional int32 timeout_seconds = 5;
}

Response:

message AgentActionResponse {
string request_id = 1;
bool ok = 2;
string action_type = 3;
optional string error = 4;
optional string result_json = 5;
optional DataPreview data = 6;
optional int64 execution_time_ms = 7;
}

Tool Response Formatting

Results are formatted for LLM consumption:

Execution time: 45ms
Columns: id, name, email, created_at

Rows (20 shown, 1000 total):
id | name | email | created_at
------------------------------------
1 | John Doe | john@ex.com | 2024-01-15
2 | Jane Smith | | 2024-01-16
...

Authentication and Security

Authentication Flow

Studio uses Platform's standard authentication:

1. User logs into Platform

2. JWT token issued by Platform auth

3. Frontend includes token in requests

4. Backend validates token, extracts user/partner

5. Studio endpoints check permissions

Required Permissions

EndpointRequired Scope
/api/v1/studio/statussource:get
/api/v1/studio/sources/{id}/previewsource:get
/api/v1/studio/agent/capabilitiessource:get
/api/v1/studio/chatsource:get
/api/v1/studio/conversations/contextissue:get

Data Isolation

  • Partner Isolation: All queries filter by partner_id
  • Source Access: Only sources belonging to partner
  • Issue Access: Only issues belonging to partner
  • Conversations: Only conversations belonging to partner

API Key Security

LLM API keys are:

  • Stored encrypted in database
  • Never exposed in API responses
  • Only used server-side for LLM calls

🔧 MCP Server Integration

Studio supports Model Context Protocol (MCP) servers for extended tool capabilities.

MCP Architecture

Agent → LangChain Tool → MCPHttpClient → MCP Server

JSON-RPC 2.0

MCP Configuration

MCP servers are configured per partner in the database:

{
"name": "Data Tools Server",
"endpoint_url": "https://mcp.example.com/rpc",
"api_key": "...",
"is_active": true,
"tools_cache": [
{"name": "analyze_csv", "description": "..."},
{"name": "validate_schema", "description": "..."}
]
}

MCP Tool Creation

MCP tools are automatically converted to LangChain tools:

from backend.agent.mcp_client import create_langchain_tools_from_mcp_servers

# Get all active MCP tools for partner
mcp_tools = await create_langchain_tools_from_mcp_servers(
session=db_session,
partner_id=current_user.partner_id
)

# Tools are prefixed with "mcp_" and include server name in description
# e.g., "mcp_analyze_csv" with description "[MCP:DataTools] Analyze CSV file"

Troubleshooting

"Agent module not available"

Cause: LangChain/LangGraph not installed

Solution:

# On the Platform backend server
pip install langchain langgraph langchain-openai langchain-anthropic langchain-ollama

"No LLM configuration found"

Cause: No active LLM config for partner

Solution:

  1. Go to Settings > AI Configuration
  2. Create a new configuration
  3. Set it as Active

"No worker available"

Cause: No Worker connected for data operations

Solution:

# Start a Worker
qalita worker start

Worker timeout

Cause: Worker didn't respond in time

Checks:

  1. Verify Worker is running and connected
  2. Check Worker logs for errors
  3. Verify source connectivity from Worker
  4. Increase timeout if needed

LLM connection errors

OpenAI:

curl https://api.openai.com/v1/models \
-H "Authorization: Bearer YOUR_KEY"

Ollama:

curl http://localhost:11434/api/tags

Check error details in response:

{
"ok": false,
"error": "Connection to Ollama refused at http://localhost:11434"
}

Monitoring

Backend Logs

Studio operations are logged with loguru:

# In backend logs
INFO | backend.agent.agent:invoke:505 - Invoking agent workflow
INFO | backend.agent.tools.data_tools:execute_query_tool:178 - Executing SQL query on source 456
DEBUG | backend.agent.llm_factory:create_chat_model:120 - Creating LLM with provider=openai, model=gpt-4o-mini

Metrics to Monitor

MetricDescription
Chat request latencyTime from request to response
Streaming first byteTime to first SSE event
Tool execution timeDuration of data tool calls
Worker response timegRPC round-trip time
LLM token usageTokens consumed per request

Complete Workflow Example

import requests
import json

BASE_URL = "https://your-platform/api/v1"
HEADERS = {"Authorization": "Bearer YOUR_TOKEN"}

# 1. Check agent capabilities
caps = requests.get(f"{BASE_URL}/studio/agent/capabilities", headers=HEADERS).json()
print(f"Agent available: {caps['agent_available']}, LLM configured: {caps['llm_configured']}")

# 2. Check worker status
status = requests.get(f"{BASE_URL}/studio/status", headers=HEADERS).json()
print(f"Workers connected: {status['worker_count']}")

# 3. Preview source data
preview = requests.get(
f"{BASE_URL}/studio/sources/456/preview",
headers=HEADERS,
params={"limit": 100}
).json()
print(f"Columns: {preview['headers']}")

# 4. Chat with context
response = requests.post(
f"{BASE_URL}/studio/chat",
headers=HEADERS,
json={
"message": "Analyze the data quality of this source",
"context": {
"source_id": 456,
"enriched": {
"source": {"id": 456, "name": "customers", "type": "postgresql"},
"dataSample": preview
}
}
}
).json()

print(f"Agent response: {response['response'][:500]}...")

# 5. Get related conversations
convs = requests.get(
f"{BASE_URL}/studio/conversations/context",
headers=HEADERS,
params={"source_id": 456}
).json()
print(f"Related conversations: {convs['total_count']}")

Best Practices

  1. LLM Configuration:

    • Start with Ollama for development (free, private)
    • Use gpt-4o-mini for cost-effective production
    • Test configurations before activating
  2. Worker Management:

    • Ensure at least one Worker per environment
    • Monitor Worker connectivity
    • Handle Worker unavailability gracefully
  3. Context Enrichment:

    • Always include relevant context (source, issue)
    • Use data samples when asking about data
    • Include schema for structure questions
  4. Error Handling:

    • Check ok field in responses
    • Handle streaming errors in SSE
    • Implement retry logic for transient failures

Next Steps