feat: comprehensive test infrastructure improvements
- Fix unit test imports: add env setup in conftest.py before module imports - Add 24 new auth router tests (RBAC, preferences, password validation) - Add 16 new tests for litellm and chat_summary routers - Apply black formatting and ruff linting across codebase - Add pre-commit hooks configuration (black, ruff, file checks) - Increase CI coverage threshold from 40% to 50% Test Results: - 206 tests passing (91 unit + 115 integration) - Coverage: 58.79% on core modules - auth.py: 57% → 85%, litellm.py: 23% → 87%, chat_summary.py: 41% → 100% - auth_service: 96.51%, config: 100%, rbac: 93.48%
This commit is contained in:
+201
-115
@@ -1,11 +1,13 @@
|
||||
"""
|
||||
OPC Database Module - PostgreSQL connection and schema management
|
||||
"""
|
||||
import asyncpg
|
||||
|
||||
import json
|
||||
from typing import Optional, List, Dict, Any
|
||||
from datetime import datetime
|
||||
import os
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
import asyncpg
|
||||
|
||||
# Database connection settings
|
||||
DB_HOST = os.getenv("OPC_DB_HOST", "gitea-db")
|
||||
@@ -15,7 +17,7 @@ DB_USER = os.getenv("OPC_DB_USER", "gitea")
|
||||
DB_PASSWORD = os.getenv("GITEA_DB_PASSWORD", "")
|
||||
|
||||
# Connection pool
|
||||
_pool: Optional[asyncpg.Pool] = None
|
||||
_pool: asyncpg.Pool | None = None
|
||||
|
||||
|
||||
async def get_pool() -> asyncpg.Pool:
|
||||
@@ -24,6 +26,7 @@ async def get_pool() -> asyncpg.Pool:
|
||||
if _pool is None:
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
max_retries = 3
|
||||
@@ -67,7 +70,8 @@ async def init_db():
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
# Create tables
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS projects (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
@@ -77,9 +81,11 @@ async def init_db():
|
||||
metadata JSONB,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS tasks (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
@@ -96,9 +102,11 @@ async def init_db():
|
||||
completed_at TIMESTAMP,
|
||||
due_date TIMESTAMP
|
||||
)
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS task_history (
|
||||
id SERIAL PRIMARY KEY,
|
||||
task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
||||
@@ -109,9 +117,11 @@ async def init_db():
|
||||
new_value JSONB,
|
||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS agents (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
@@ -123,9 +133,11 @@ async def init_db():
|
||||
enabled BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS agent_executions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
||||
@@ -142,9 +154,11 @@ async def init_db():
|
||||
approved_by TEXT,
|
||||
approved_at TIMESTAMP
|
||||
)
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS time_entries (
|
||||
id SERIAL PRIMARY KEY,
|
||||
task_id INTEGER REFERENCES tasks(id) ON DELETE CASCADE,
|
||||
@@ -157,9 +171,11 @@ async def init_db():
|
||||
ended_at TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS clients (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
@@ -169,7 +185,8 @@ async def init_db():
|
||||
metadata JSONB,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
# Create indexes
|
||||
await conn.execute("CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)")
|
||||
@@ -201,7 +218,7 @@ async def seed_agents(conn):
|
||||
- Provide status reports and risk assessments
|
||||
|
||||
When assigned a task, analyze it and propose concrete actions.""",
|
||||
"config": {"model": "cc-kiro", "temperature": 0.7, "approval_level": "auto"}
|
||||
"config": {"model": "cc-kiro", "temperature": 0.7, "approval_level": "auto"},
|
||||
},
|
||||
{
|
||||
"id": "cto",
|
||||
@@ -216,7 +233,7 @@ When assigned a task, analyze it and propose concrete actions.""",
|
||||
- Ensure security best practices
|
||||
|
||||
When assigned a task, provide technical leadership and propose improvements.""",
|
||||
"config": {"model": "cc-kiro", "temperature": 0.5, "approval_level": "cxo"}
|
||||
"config": {"model": "cc-kiro", "temperature": 0.5, "approval_level": "cxo"},
|
||||
},
|
||||
{
|
||||
"id": "coo",
|
||||
@@ -231,12 +248,13 @@ When assigned a task, provide technical leadership and propose improvements.""",
|
||||
- Optimize resource allocation
|
||||
|
||||
When assigned a task, look for automation and optimization opportunities.""",
|
||||
"config": {"model": "cc-kiro", "temperature": 0.6, "approval_level": "cxo"}
|
||||
}
|
||||
"config": {"model": "cc-kiro", "temperature": 0.6, "approval_level": "cxo"},
|
||||
},
|
||||
]
|
||||
|
||||
for agent in agents:
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO agents (id, name, role, description, capabilities, system_prompt, config, enabled)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
@@ -246,34 +264,51 @@ When assigned a task, look for automation and optimization opportunities.""",
|
||||
capabilities = EXCLUDED.capabilities,
|
||||
system_prompt = EXCLUDED.system_prompt,
|
||||
config = EXCLUDED.config
|
||||
""", agent["id"], agent["name"], agent["role"], agent["description"],
|
||||
json.dumps(agent["capabilities"]), agent["system_prompt"],
|
||||
json.dumps(agent["config"]), True)
|
||||
""",
|
||||
agent["id"],
|
||||
agent["name"],
|
||||
agent["role"],
|
||||
agent["description"],
|
||||
json.dumps(agent["capabilities"]),
|
||||
agent["system_prompt"],
|
||||
json.dumps(agent["config"]),
|
||||
True,
|
||||
)
|
||||
|
||||
|
||||
# Task operations
|
||||
async def create_task(
|
||||
title: str,
|
||||
description: Optional[str] = None,
|
||||
description: str | None = None,
|
||||
status: str = "parking_lot",
|
||||
priority: str = "medium",
|
||||
project_id: Optional[int] = None,
|
||||
assigned_to: Optional[str] = None,
|
||||
project_id: int | None = None,
|
||||
assigned_to: str | None = None,
|
||||
assigned_type: str = "human",
|
||||
tags: Optional[List[str]] = None,
|
||||
due_date: Optional[datetime] = None,
|
||||
actor: str = "system"
|
||||
) -> Dict[str, Any]:
|
||||
tags: list[str] | None = None,
|
||||
due_date: datetime | None = None,
|
||||
actor: str = "system",
|
||||
) -> dict[str, Any]:
|
||||
"""Create a new task"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
row = await conn.fetchrow("""
|
||||
row = await conn.fetchrow(
|
||||
"""
|
||||
INSERT INTO tasks (title, description, status, priority, project_id, assigned_to, assigned_type, tags, due_date)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
RETURNING id, title, description, status, priority, project_id, assigned_to, assigned_type, tags,
|
||||
created_at, updated_at, completed_at, due_date
|
||||
""", title, description, status, priority, project_id, assigned_to, assigned_type,
|
||||
json.dumps(tags or []), due_date)
|
||||
""",
|
||||
title,
|
||||
description,
|
||||
status,
|
||||
priority,
|
||||
project_id,
|
||||
assigned_to,
|
||||
assigned_type,
|
||||
json.dumps(tags or []),
|
||||
due_date,
|
||||
)
|
||||
|
||||
task = dict(row)
|
||||
task["tags"] = json.loads(task["tags"]) if task["tags"] else []
|
||||
@@ -285,23 +320,30 @@ async def create_task(
|
||||
task_for_history[key] = task_for_history[key].isoformat()
|
||||
|
||||
# Log history
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO task_history (task_id, action, actor, actor_type, new_value)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
""", task["id"], "created", actor, "human", json.dumps(task_for_history))
|
||||
""",
|
||||
task["id"],
|
||||
"created",
|
||||
actor,
|
||||
"human",
|
||||
json.dumps(task_for_history),
|
||||
)
|
||||
|
||||
return task
|
||||
|
||||
|
||||
async def get_tasks(
|
||||
status: Optional[str] = None,
|
||||
assigned_to: Optional[str] = None,
|
||||
project_id: Optional[int] = None,
|
||||
priority: Optional[str] = None,
|
||||
tags: Optional[List[str]] = None,
|
||||
status: str | None = None,
|
||||
assigned_to: str | None = None,
|
||||
project_id: int | None = None,
|
||||
priority: str | None = None,
|
||||
tags: list[str] | None = None,
|
||||
limit: int = 50,
|
||||
offset: int = 0
|
||||
) -> List[Dict[str, Any]]:
|
||||
offset: int = 0,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Get tasks with filters"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
@@ -346,11 +388,7 @@ async def get_tasks(
|
||||
return tasks
|
||||
|
||||
|
||||
async def update_task(
|
||||
task_id: int,
|
||||
updates: Dict[str, Any],
|
||||
actor: str = "system"
|
||||
) -> Dict[str, Any]:
|
||||
async def update_task(task_id: int, updates: dict[str, Any], actor: str = "system") -> dict[str, Any]:
|
||||
"""Update a task"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
@@ -367,7 +405,17 @@ async def update_task(
|
||||
param_count = 0
|
||||
|
||||
for key, value in updates.items():
|
||||
if key in ["title", "description", "status", "priority", "project_id", "assigned_to", "assigned_type", "due_date", "completed_at"]:
|
||||
if key in [
|
||||
"title",
|
||||
"description",
|
||||
"status",
|
||||
"priority",
|
||||
"project_id",
|
||||
"assigned_to",
|
||||
"assigned_type",
|
||||
"due_date",
|
||||
"completed_at",
|
||||
]:
|
||||
param_count += 1
|
||||
set_clauses.append(f"{key} = ${param_count}")
|
||||
params.append(value)
|
||||
@@ -395,10 +443,18 @@ async def update_task(
|
||||
updates_for_history[key] = updates_for_history[key].isoformat()
|
||||
|
||||
# Log history
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO task_history (task_id, action, actor, actor_type, old_value, new_value)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
""", task_id, "updated", actor, "human", json.dumps(old_values_for_history), json.dumps(updates_for_history))
|
||||
""",
|
||||
task_id,
|
||||
"updated",
|
||||
actor,
|
||||
"human",
|
||||
json.dumps(old_values_for_history),
|
||||
json.dumps(updates_for_history),
|
||||
)
|
||||
|
||||
return task
|
||||
|
||||
@@ -407,73 +463,85 @@ async def delete_task(task_id: int, actor: str = "system"):
|
||||
"""Delete a task"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO task_history (task_id, action, actor, actor_type)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
""", task_id, "deleted", actor, "human")
|
||||
""",
|
||||
task_id,
|
||||
"deleted",
|
||||
actor,
|
||||
"human",
|
||||
)
|
||||
|
||||
await conn.execute("DELETE FROM tasks WHERE id = $1", task_id)
|
||||
|
||||
|
||||
# Time tracking operations
|
||||
async def start_time_entry(
|
||||
task_id: int,
|
||||
project_id: Optional[int] = None,
|
||||
actor: str = "system"
|
||||
) -> Dict[str, Any]:
|
||||
async def start_time_entry(task_id: int, project_id: int | None = None, actor: str = "system") -> dict[str, Any]:
|
||||
"""Start automatic time tracking for a task"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
# Check if there's already an active entry
|
||||
active = await conn.fetchrow("""
|
||||
active = await conn.fetchrow(
|
||||
"""
|
||||
SELECT * FROM time_entries
|
||||
WHERE task_id = $1 AND ended_at IS NULL
|
||||
ORDER BY started_at DESC LIMIT 1
|
||||
""", task_id)
|
||||
""",
|
||||
task_id,
|
||||
)
|
||||
|
||||
if active:
|
||||
return dict(active)
|
||||
|
||||
# Create new time entry
|
||||
row = await conn.fetchrow("""
|
||||
row = await conn.fetchrow(
|
||||
"""
|
||||
INSERT INTO time_entries (task_id, project_id, started_at, duration_minutes)
|
||||
VALUES ($1, $2, CURRENT_TIMESTAMP, 0)
|
||||
RETURNING *
|
||||
""", task_id, project_id)
|
||||
""",
|
||||
task_id,
|
||||
project_id,
|
||||
)
|
||||
|
||||
return dict(row)
|
||||
|
||||
|
||||
async def stop_time_entry(task_id: int) -> Optional[Dict[str, Any]]:
|
||||
async def stop_time_entry(task_id: int) -> dict[str, Any] | None:
|
||||
"""Stop automatic time tracking for a task"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
# Find active entry
|
||||
active = await conn.fetchrow("""
|
||||
active = await conn.fetchrow(
|
||||
"""
|
||||
SELECT * FROM time_entries
|
||||
WHERE task_id = $1 AND ended_at IS NULL
|
||||
ORDER BY started_at DESC LIMIT 1
|
||||
""", task_id)
|
||||
""",
|
||||
task_id,
|
||||
)
|
||||
|
||||
if not active:
|
||||
return None
|
||||
|
||||
# Calculate duration and update
|
||||
row = await conn.fetchrow("""
|
||||
row = await conn.fetchrow(
|
||||
"""
|
||||
UPDATE time_entries
|
||||
SET ended_at = CURRENT_TIMESTAMP,
|
||||
duration_minutes = EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - started_at)) / 60
|
||||
WHERE id = $1
|
||||
RETURNING *
|
||||
""", active["id"])
|
||||
""",
|
||||
active["id"],
|
||||
)
|
||||
|
||||
return dict(row)
|
||||
|
||||
|
||||
async def get_time_entries(
|
||||
task_id: Optional[int] = None,
|
||||
project_id: Optional[int] = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
async def get_time_entries(task_id: int | None = None, project_id: int | None = None) -> list[dict[str, Any]]:
|
||||
"""Get time entries"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
@@ -494,20 +562,23 @@ async def get_time_entries(
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
|
||||
async def get_task_history(task_id: int) -> List[Dict[str, Any]]:
|
||||
async def get_task_history(task_id: int) -> list[dict[str, Any]]:
|
||||
"""Get task history"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
rows = await conn.fetch("""
|
||||
rows = await conn.fetch(
|
||||
"""
|
||||
SELECT * FROM task_history
|
||||
WHERE task_id = $1
|
||||
ORDER BY timestamp DESC
|
||||
""", task_id)
|
||||
""",
|
||||
task_id,
|
||||
)
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
|
||||
# Agent operations
|
||||
async def get_agents(enabled_only: bool = True) -> List[Dict[str, Any]]:
|
||||
async def get_agents(enabled_only: bool = True) -> list[dict[str, Any]]:
|
||||
"""Get all agents"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
@@ -526,7 +597,7 @@ async def get_agents(enabled_only: bool = True) -> List[Dict[str, Any]]:
|
||||
return agents
|
||||
|
||||
|
||||
async def get_agent(agent_id: str) -> Optional[Dict[str, Any]]:
|
||||
async def get_agent(agent_id: str) -> dict[str, Any] | None:
|
||||
"""Get agent by ID"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
@@ -541,11 +612,8 @@ async def get_agent(agent_id: str) -> Optional[Dict[str, Any]]:
|
||||
|
||||
|
||||
async def create_agent_execution(
|
||||
task_id: int,
|
||||
agent_id: str,
|
||||
actor: str = "system",
|
||||
requires_approval: bool = False
|
||||
) -> Dict[str, Any]:
|
||||
task_id: int, agent_id: str, actor: str = "system", requires_approval: bool = False
|
||||
) -> dict[str, Any]:
|
||||
"""Create agent execution record"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
@@ -561,28 +629,43 @@ async def create_agent_execution(
|
||||
task_for_context = dict(task)
|
||||
for key in ["created_at", "updated_at", "completed_at", "due_date"]:
|
||||
if task_for_context.get(key):
|
||||
task_for_context[key] = task_for_context[key].isoformat() if hasattr(task_for_context[key], 'isoformat') else task_for_context[key]
|
||||
task_for_context[key] = (
|
||||
task_for_context[key].isoformat()
|
||||
if hasattr(task_for_context[key], "isoformat")
|
||||
else task_for_context[key]
|
||||
)
|
||||
|
||||
agent_for_context = dict(agent)
|
||||
for key in ["created_at"]:
|
||||
if agent_for_context.get(key):
|
||||
agent_for_context[key] = agent_for_context[key].isoformat() if hasattr(agent_for_context[key], 'isoformat') else agent_for_context[key]
|
||||
agent_for_context[key] = (
|
||||
agent_for_context[key].isoformat()
|
||||
if hasattr(agent_for_context[key], "isoformat")
|
||||
else agent_for_context[key]
|
||||
)
|
||||
|
||||
input_context = {
|
||||
"task": task_for_context,
|
||||
"agent": agent_for_context,
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
}
|
||||
|
||||
# Check if agent requires approval (CxO level)
|
||||
agent_config = json.loads(agent["config"]) if agent["config"] else {}
|
||||
requires_approval = agent_config.get("approval_level") == "cxo"
|
||||
|
||||
row = await conn.fetchrow("""
|
||||
row = await conn.fetchrow(
|
||||
"""
|
||||
INSERT INTO agent_executions (task_id, agent_id, status, input_context, requires_approval, started_at)
|
||||
VALUES ($1, $2, $3, $4, $5, CURRENT_TIMESTAMP)
|
||||
RETURNING *
|
||||
""", task_id, agent_id, "pending", json.dumps(input_context), requires_approval)
|
||||
""",
|
||||
task_id,
|
||||
agent_id,
|
||||
"pending",
|
||||
json.dumps(input_context),
|
||||
requires_approval,
|
||||
)
|
||||
|
||||
execution = dict(row)
|
||||
execution["input_context"] = json.loads(execution["input_context"]) if execution["input_context"] else {}
|
||||
@@ -590,11 +673,8 @@ async def create_agent_execution(
|
||||
|
||||
|
||||
async def get_agent_executions(
|
||||
task_id: Optional[int] = None,
|
||||
agent_id: Optional[str] = None,
|
||||
status: Optional[str] = None,
|
||||
limit: int = 50
|
||||
) -> List[Dict[str, Any]]:
|
||||
task_id: int | None = None, agent_id: str | None = None, status: str | None = None, limit: int = 50
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Get agent executions"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
@@ -628,7 +708,7 @@ async def get_agent_executions(
|
||||
return executions
|
||||
|
||||
|
||||
async def get_task_by_id(task_id: int) -> Optional[Dict[str, Any]]:
|
||||
async def get_task_by_id(task_id: int) -> dict[str, Any] | None:
|
||||
"""Get a single task by ID"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
@@ -641,7 +721,7 @@ async def get_task_by_id(task_id: int) -> Optional[Dict[str, Any]]:
|
||||
return task
|
||||
|
||||
|
||||
async def get_agent_execution(execution_id: int) -> Optional[Dict[str, Any]]:
|
||||
async def get_agent_execution(execution_id: int) -> dict[str, Any] | None:
|
||||
"""Get a single agent execution by ID"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
@@ -657,23 +737,25 @@ async def get_agent_execution(execution_id: int) -> Optional[Dict[str, Any]]:
|
||||
|
||||
|
||||
async def approve_agent_execution(
|
||||
execution_id: int,
|
||||
approved: bool,
|
||||
approved_by: str,
|
||||
feedback: Optional[str] = None
|
||||
) -> Dict[str, Any]:
|
||||
execution_id: int, approved: bool, approved_by: str, feedback: str | None = None
|
||||
) -> dict[str, Any]:
|
||||
"""Approve or reject an agent execution"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
# Update execution with approval status
|
||||
row = await conn.fetchrow("""
|
||||
row = await conn.fetchrow(
|
||||
"""
|
||||
UPDATE agent_executions
|
||||
SET approved_by = $1,
|
||||
approved_at = CURRENT_TIMESTAMP,
|
||||
status = CASE WHEN $2 THEN 'approved' ELSE 'rejected' END
|
||||
WHERE id = $3
|
||||
RETURNING *
|
||||
""", approved_by, approved, execution_id)
|
||||
""",
|
||||
approved_by,
|
||||
approved,
|
||||
execution_id,
|
||||
)
|
||||
|
||||
if not row:
|
||||
raise ValueError(f"Execution {execution_id} not found")
|
||||
@@ -689,23 +771,27 @@ async def approve_agent_execution(
|
||||
execution["output_result"] = {}
|
||||
execution["output_result"]["approval_feedback"] = feedback
|
||||
|
||||
await conn.execute("""
|
||||
await conn.execute(
|
||||
"""
|
||||
UPDATE agent_executions
|
||||
SET output_result = $1
|
||||
WHERE id = $2
|
||||
""", json.dumps(execution["output_result"]), execution_id)
|
||||
""",
|
||||
json.dumps(execution["output_result"]),
|
||||
execution_id,
|
||||
)
|
||||
|
||||
return execution
|
||||
|
||||
|
||||
async def update_agent_config(
|
||||
agent_id: str,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
system_prompt: Optional[str] = None,
|
||||
config: Optional[Dict[str, Any]] = None,
|
||||
enabled: Optional[bool] = None
|
||||
) -> Dict[str, Any]:
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
system_prompt: str | None = None,
|
||||
config: dict[str, Any] | None = None,
|
||||
enabled: bool | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Update agent configuration"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
@@ -761,11 +847,11 @@ async def update_agent_config(
|
||||
async def update_execution_status(
|
||||
execution_id: int,
|
||||
status: str,
|
||||
output_result: Optional[Dict[str, Any]] = None,
|
||||
actions_proposed: Optional[List[Dict[str, Any]]] = None,
|
||||
actions_executed: Optional[List[Dict[str, Any]]] = None,
|
||||
error_message: Optional[str] = None
|
||||
) -> Dict[str, Any]:
|
||||
output_result: dict[str, Any] | None = None,
|
||||
actions_proposed: list[dict[str, Any]] | None = None,
|
||||
actions_executed: list[dict[str, Any]] | None = None,
|
||||
error_message: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Update agent execution status and results"""
|
||||
pool = await get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
|
||||
Reference in New Issue
Block a user