feat: refactor imports and clean up code formatting across multiple files
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from uuid import UUID
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||||
from sqlmodel import Session, select
|
from sqlmodel import Session, select
|
||||||
@@ -14,28 +14,18 @@ from app.api import tasks as tasks_api
|
|||||||
from app.api.deps import ActorContext, get_board_or_404, get_task_or_404
|
from app.api.deps import ActorContext, get_board_or_404, get_task_or_404
|
||||||
from app.core.agent_auth import AgentAuthContext, get_agent_auth_context
|
from app.core.agent_auth import AgentAuthContext, get_agent_auth_context
|
||||||
from app.db.session import get_session
|
from app.db.session import get_session
|
||||||
from app.integrations.openclaw_gateway import (
|
from app.integrations.openclaw_gateway import GatewayConfig as GatewayClientConfig
|
||||||
GatewayConfig as GatewayClientConfig,
|
from app.integrations.openclaw_gateway import OpenClawGatewayError, ensure_session, send_message
|
||||||
OpenClawGatewayError,
|
|
||||||
ensure_session,
|
|
||||||
send_message,
|
|
||||||
)
|
|
||||||
from app.models.agents import Agent
|
from app.models.agents import Agent
|
||||||
from app.models.tasks import Task
|
|
||||||
from app.models.boards import Board
|
from app.models.boards import Board
|
||||||
from app.models.gateways import Gateway
|
from app.models.gateways import Gateway
|
||||||
|
from app.models.tasks import Task
|
||||||
|
from app.schemas.agents import AgentCreate, AgentHeartbeatCreate, AgentNudge, AgentRead
|
||||||
from app.schemas.approvals import ApprovalCreate, ApprovalRead
|
from app.schemas.approvals import ApprovalCreate, ApprovalRead
|
||||||
from app.schemas.board_memory import BoardMemoryCreate, BoardMemoryRead
|
from app.schemas.board_memory import BoardMemoryCreate, BoardMemoryRead
|
||||||
from app.schemas.board_onboarding import BoardOnboardingRead
|
from app.schemas.board_onboarding import BoardOnboardingRead
|
||||||
from app.schemas.boards import BoardRead
|
from app.schemas.boards import BoardRead
|
||||||
from app.schemas.tasks import (
|
from app.schemas.tasks import TaskCommentCreate, TaskCommentRead, TaskCreate, TaskRead, TaskUpdate
|
||||||
TaskCommentCreate,
|
|
||||||
TaskCommentRead,
|
|
||||||
TaskCreate,
|
|
||||||
TaskRead,
|
|
||||||
TaskUpdate,
|
|
||||||
)
|
|
||||||
from app.schemas.agents import AgentCreate, AgentHeartbeatCreate, AgentNudge, AgentRead
|
|
||||||
from app.services.activity_log import record_activity
|
from app.services.activity_log import record_activity
|
||||||
|
|
||||||
router = APIRouter(prefix="/agent", tags=["agent"])
|
router = APIRouter(prefix="/agent", tags=["agent"])
|
||||||
@@ -98,9 +88,7 @@ def list_agents(
|
|||||||
agents = list(session.exec(statement))
|
agents = list(session.exec(statement))
|
||||||
main_session_keys = agents_api._get_gateway_main_session_keys(session)
|
main_session_keys = agents_api._get_gateway_main_session_keys(session)
|
||||||
return [
|
return [
|
||||||
agents_api._to_agent_read(
|
agents_api._to_agent_read(agents_api._with_computed_status(agent), main_session_keys)
|
||||||
agents_api._with_computed_status(agent), main_session_keys
|
|
||||||
)
|
|
||||||
for agent in agents
|
for agent in agents
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -351,6 +339,7 @@ def nudge_agent(
|
|||||||
detail="message is required",
|
detail="message is required",
|
||||||
)
|
)
|
||||||
config = _gateway_config(session, board)
|
config = _gateway_config(session, board)
|
||||||
|
|
||||||
async def _send() -> None:
|
async def _send() -> None:
|
||||||
await ensure_session(target.openclaw_session_id, config=config, label=target.name)
|
await ensure_session(target.openclaw_session_id, config=config, label=target.name)
|
||||||
await send_message(
|
await send_message(
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import re
|
|
||||||
from datetime import datetime, timedelta, timezone
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
|
from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
|
||||||
@@ -23,7 +23,13 @@ from app.models.agents import Agent
|
|||||||
from app.models.boards import Board
|
from app.models.boards import Board
|
||||||
from app.models.gateways import Gateway
|
from app.models.gateways import Gateway
|
||||||
from app.models.tasks import Task
|
from app.models.tasks import Task
|
||||||
from app.schemas.agents import AgentCreate, AgentHeartbeat, AgentHeartbeatCreate, AgentRead, AgentUpdate
|
from app.schemas.agents import (
|
||||||
|
AgentCreate,
|
||||||
|
AgentHeartbeat,
|
||||||
|
AgentHeartbeatCreate,
|
||||||
|
AgentRead,
|
||||||
|
AgentUpdate,
|
||||||
|
)
|
||||||
from app.services.activity_log import record_activity
|
from app.services.activity_log import record_activity
|
||||||
from app.services.agent_provisioning import (
|
from app.services.agent_provisioning import (
|
||||||
DEFAULT_HEARTBEAT_CONFIG,
|
DEFAULT_HEARTBEAT_CONFIG,
|
||||||
@@ -159,14 +165,10 @@ def _to_agent_read(agent: Agent, main_session_keys: set[str]) -> AgentRead:
|
|||||||
return model.model_copy(update={"is_gateway_main": _is_gateway_main(agent, main_session_keys)})
|
return model.model_copy(update={"is_gateway_main": _is_gateway_main(agent, main_session_keys)})
|
||||||
|
|
||||||
|
|
||||||
def _find_gateway_for_main_session(
|
def _find_gateway_for_main_session(session: Session, session_key: str | None) -> Gateway | None:
|
||||||
session: Session, session_key: str | None
|
|
||||||
) -> Gateway | None:
|
|
||||||
if not session_key:
|
if not session_key:
|
||||||
return None
|
return None
|
||||||
return session.exec(
|
return session.exec(select(Gateway).where(Gateway.main_session_key == session_key)).first()
|
||||||
select(Gateway).where(Gateway.main_session_key == session_key)
|
|
||||||
).first()
|
|
||||||
|
|
||||||
|
|
||||||
async def _ensure_gateway_session(
|
async def _ensure_gateway_session(
|
||||||
@@ -193,9 +195,7 @@ def _with_computed_status(agent: Agent) -> Agent:
|
|||||||
|
|
||||||
|
|
||||||
def _serialize_agent(agent: Agent, main_session_keys: set[str]) -> dict[str, object]:
|
def _serialize_agent(agent: Agent, main_session_keys: set[str]) -> dict[str, object]:
|
||||||
return _to_agent_read(
|
return _to_agent_read(_with_computed_status(agent), main_session_keys).model_dump(mode="json")
|
||||||
_with_computed_status(agent), main_session_keys
|
|
||||||
).model_dump(mode="json")
|
|
||||||
|
|
||||||
|
|
||||||
def _fetch_agent_events(
|
def _fetch_agent_events(
|
||||||
@@ -206,15 +206,12 @@ def _fetch_agent_events(
|
|||||||
statement = select(Agent)
|
statement = select(Agent)
|
||||||
if board_id:
|
if board_id:
|
||||||
statement = statement.where(col(Agent.board_id) == board_id)
|
statement = statement.where(col(Agent.board_id) == board_id)
|
||||||
statement = (
|
statement = statement.where(
|
||||||
statement.where(
|
or_(
|
||||||
or_(
|
col(Agent.updated_at) >= since,
|
||||||
col(Agent.updated_at) >= since,
|
col(Agent.last_seen_at) >= since,
|
||||||
col(Agent.last_seen_at) >= since,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
.order_by(asc(col(Agent.updated_at)))
|
).order_by(asc(col(Agent.updated_at)))
|
||||||
)
|
|
||||||
return list(session.exec(statement))
|
return list(session.exec(statement))
|
||||||
|
|
||||||
|
|
||||||
@@ -257,10 +254,7 @@ def list_agents(
|
|||||||
) -> list[Agent]:
|
) -> list[Agent]:
|
||||||
agents = list(session.exec(select(Agent)))
|
agents = list(session.exec(select(Agent)))
|
||||||
main_session_keys = _get_gateway_main_session_keys(session)
|
main_session_keys = _get_gateway_main_session_keys(session)
|
||||||
return [
|
return [_to_agent_read(_with_computed_status(agent), main_session_keys) for agent in agents]
|
||||||
_to_agent_read(_with_computed_status(agent), main_session_keys)
|
|
||||||
for agent in agents
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/stream")
|
@router.get("/stream")
|
||||||
@@ -336,9 +330,7 @@ async def create_agent(
|
|||||||
data["identity_template"] = None
|
data["identity_template"] = None
|
||||||
if data.get("soul_template") == "":
|
if data.get("soul_template") == "":
|
||||||
data["soul_template"] = None
|
data["soul_template"] = None
|
||||||
data["identity_profile"] = _normalize_identity_profile(
|
data["identity_profile"] = _normalize_identity_profile(data.get("identity_profile"))
|
||||||
data.get("identity_profile")
|
|
||||||
)
|
|
||||||
agent = Agent.model_validate(data)
|
agent = Agent.model_validate(data)
|
||||||
agent.status = "provisioning"
|
agent.status = "provisioning"
|
||||||
raw_token = generate_agent_token()
|
raw_token = generate_agent_token()
|
||||||
@@ -441,9 +433,7 @@ async def update_agent(
|
|||||||
if updates.get("soul_template") == "":
|
if updates.get("soul_template") == "":
|
||||||
updates["soul_template"] = None
|
updates["soul_template"] = None
|
||||||
if "identity_profile" in updates:
|
if "identity_profile" in updates:
|
||||||
updates["identity_profile"] = _normalize_identity_profile(
|
updates["identity_profile"] = _normalize_identity_profile(updates.get("identity_profile"))
|
||||||
updates.get("identity_profile")
|
|
||||||
)
|
|
||||||
if not updates and not force and make_main is None:
|
if not updates and not force and make_main is None:
|
||||||
main_session_keys = _get_gateway_main_session_keys(session)
|
main_session_keys = _get_gateway_main_session_keys(session)
|
||||||
return _to_agent_read(_with_computed_status(agent), main_session_keys)
|
return _to_agent_read(_with_computed_status(agent), main_session_keys)
|
||||||
@@ -823,9 +813,7 @@ def delete_agent(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
session.execute(
|
session.execute(
|
||||||
update(ActivityEvent)
|
update(ActivityEvent).where(col(ActivityEvent.agent_id) == agent.id).values(agent_id=None)
|
||||||
.where(col(ActivityEvent.agent_id) == agent.id)
|
|
||||||
.values(agent_id=None)
|
|
||||||
)
|
)
|
||||||
session.delete(agent)
|
session.delete(agent)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import datetime, timezone
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
from datetime import datetime, timezone
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
|
from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
|
||||||
@@ -42,9 +42,7 @@ def _approval_updated_at(approval: Approval) -> datetime:
|
|||||||
|
|
||||||
|
|
||||||
def _serialize_approval(approval: Approval) -> dict[str, object]:
|
def _serialize_approval(approval: Approval) -> dict[str, object]:
|
||||||
return ApprovalRead.model_validate(
|
return ApprovalRead.model_validate(approval, from_attributes=True).model_dump(mode="json")
|
||||||
approval, from_attributes=True
|
|
||||||
).model_dump(mode="json")
|
|
||||||
|
|
||||||
|
|
||||||
def _fetch_approval_events(
|
def _fetch_approval_events(
|
||||||
@@ -103,9 +101,7 @@ async def stream_approvals(
|
|||||||
while True:
|
while True:
|
||||||
if await request.is_disconnected():
|
if await request.is_disconnected():
|
||||||
break
|
break
|
||||||
approvals = await run_in_threadpool(
|
approvals = await run_in_threadpool(_fetch_approval_events, board.id, last_seen)
|
||||||
_fetch_approval_events, board.id, last_seen
|
|
||||||
)
|
|
||||||
for approval in approvals:
|
for approval in approvals:
|
||||||
updated_at = _approval_updated_at(approval)
|
updated_at = _approval_updated_at(approval)
|
||||||
if updated_at > last_seen:
|
if updated_at > last_seen:
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import datetime, timezone
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
||||||
from sqlmodel import Session, col, select
|
from sqlmodel import Session, col, select
|
||||||
@@ -13,12 +13,8 @@ from starlette.concurrency import run_in_threadpool
|
|||||||
from app.api.deps import ActorContext, get_board_or_404, require_admin_or_agent
|
from app.api.deps import ActorContext, get_board_or_404, require_admin_or_agent
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.db.session import engine, get_session
|
from app.db.session import engine, get_session
|
||||||
from app.integrations.openclaw_gateway import (
|
from app.integrations.openclaw_gateway import GatewayConfig as GatewayClientConfig
|
||||||
GatewayConfig as GatewayClientConfig,
|
from app.integrations.openclaw_gateway import OpenClawGatewayError, ensure_session, send_message
|
||||||
OpenClawGatewayError,
|
|
||||||
ensure_session,
|
|
||||||
send_message,
|
|
||||||
)
|
|
||||||
from app.models.agents import Agent
|
from app.models.agents import Agent
|
||||||
from app.models.board_memory import BoardMemory
|
from app.models.board_memory import BoardMemory
|
||||||
from app.models.gateways import Gateway
|
from app.models.gateways import Gateway
|
||||||
@@ -46,9 +42,7 @@ def _parse_since(value: str | None) -> datetime | None:
|
|||||||
|
|
||||||
|
|
||||||
def _serialize_memory(memory: BoardMemory) -> dict[str, object]:
|
def _serialize_memory(memory: BoardMemory) -> dict[str, object]:
|
||||||
return BoardMemoryRead.model_validate(
|
return BoardMemoryRead.model_validate(memory, from_attributes=True).model_dump(mode="json")
|
||||||
memory, from_attributes=True
|
|
||||||
).model_dump(mode="json")
|
|
||||||
|
|
||||||
|
|
||||||
def _extract_mentions(message: str) -> set[str]:
|
def _extract_mentions(message: str) -> set[str]:
|
||||||
@@ -162,6 +156,7 @@ def _notify_chat_targets(
|
|||||||
except OpenClawGatewayError:
|
except OpenClawGatewayError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
@router.get("", response_model=list[BoardMemoryRead])
|
@router.get("", response_model=list[BoardMemoryRead])
|
||||||
def list_board_memory(
|
def list_board_memory(
|
||||||
limit: int = Query(default=50, ge=1, le=200),
|
limit: int = Query(default=50, ge=1, le=200),
|
||||||
@@ -201,9 +196,7 @@ async def stream_board_memory(
|
|||||||
while True:
|
while True:
|
||||||
if await request.is_disconnected():
|
if await request.is_disconnected():
|
||||||
break
|
break
|
||||||
memories = await run_in_threadpool(
|
memories = await run_in_threadpool(_fetch_memory_events, board.id, last_seen)
|
||||||
_fetch_memory_events, board.id, last_seen
|
|
||||||
)
|
|
||||||
for memory in memories:
|
for memory in memories:
|
||||||
if memory.created_at > last_seen:
|
if memory.created_at > last_seen:
|
||||||
last_seen = memory.created_at
|
last_seen = memory.created_at
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
import logging
|
|
||||||
from sqlmodel import Session, select
|
from sqlmodel import Session, select
|
||||||
|
|
||||||
from app.api.deps import ActorContext, get_board_or_404, require_admin_auth, require_admin_or_agent
|
from app.api.deps import ActorContext, get_board_or_404, require_admin_auth, require_admin_or_agent
|
||||||
@@ -33,7 +33,6 @@ router = APIRouter(prefix="/boards/{board_id}/onboarding", tags=["board-onboardi
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _gateway_config(session: Session, board: Board) -> tuple[Gateway, GatewayClientConfig]:
|
def _gateway_config(session: Session, board: Board) -> tuple[Gateway, GatewayClientConfig]:
|
||||||
if not board.gateway_id:
|
if not board.gateway_id:
|
||||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)
|
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)
|
||||||
@@ -64,9 +63,7 @@ async def _ensure_lead_agent(
|
|||||||
auth: AuthContext,
|
auth: AuthContext,
|
||||||
) -> Agent:
|
) -> Agent:
|
||||||
existing = session.exec(
|
existing = session.exec(
|
||||||
select(Agent)
|
select(Agent).where(Agent.board_id == board.id).where(Agent.is_board_lead.is_(True))
|
||||||
.where(Agent.board_id == board.id)
|
|
||||||
.where(Agent.is_board_lead.is_(True))
|
|
||||||
).first()
|
).first()
|
||||||
if existing:
|
if existing:
|
||||||
if existing.name != _lead_agent_name(board):
|
if existing.name != _lead_agent_name(board):
|
||||||
@@ -161,21 +158,21 @@ async def start_onboarding(
|
|||||||
"Onboarding response endpoint:\n"
|
"Onboarding response endpoint:\n"
|
||||||
f"POST {base_url}/api/v1/agent/boards/{board.id}/onboarding\n"
|
f"POST {base_url}/api/v1/agent/boards/{board.id}/onboarding\n"
|
||||||
"QUESTION example (send JSON body exactly as shown):\n"
|
"QUESTION example (send JSON body exactly as shown):\n"
|
||||||
f"curl -s -X POST \"{base_url}/api/v1/agent/boards/{board.id}/onboarding\" "
|
f'curl -s -X POST "{base_url}/api/v1/agent/boards/{board.id}/onboarding" '
|
||||||
"-H \"X-Agent-Token: $AUTH_TOKEN\" "
|
'-H "X-Agent-Token: $AUTH_TOKEN" '
|
||||||
"-H \"Content-Type: application/json\" "
|
'-H "Content-Type: application/json" '
|
||||||
"-d '{\"question\":\"...\",\"options\":[{\"id\":\"1\",\"label\":\"...\"},{\"id\":\"2\",\"label\":\"...\"}]}'\n"
|
'-d \'{"question":"...","options":[{"id":"1","label":"..."},{"id":"2","label":"..."}]}\'\n'
|
||||||
"COMPLETION example (send JSON body exactly as shown):\n"
|
"COMPLETION example (send JSON body exactly as shown):\n"
|
||||||
f"curl -s -X POST \"{base_url}/api/v1/agent/boards/{board.id}/onboarding\" "
|
f'curl -s -X POST "{base_url}/api/v1/agent/boards/{board.id}/onboarding" '
|
||||||
"-H \"X-Agent-Token: $AUTH_TOKEN\" "
|
'-H "X-Agent-Token: $AUTH_TOKEN" '
|
||||||
"-H \"Content-Type: application/json\" "
|
'-H "Content-Type: application/json" '
|
||||||
"-d '{\"status\":\"complete\",\"board_type\":\"goal\",\"objective\":\"...\",\"success_metrics\":{...},\"target_date\":\"YYYY-MM-DD\"}'\n"
|
'-d \'{"status":"complete","board_type":"goal","objective":"...","success_metrics":{...},"target_date":"YYYY-MM-DD"}\'\n'
|
||||||
"QUESTION FORMAT (one question per response, no arrays, no markdown, no extra text):\n"
|
"QUESTION FORMAT (one question per response, no arrays, no markdown, no extra text):\n"
|
||||||
"{\"question\":\"...\",\"options\":[{\"id\":\"1\",\"label\":\"...\"},{\"id\":\"2\",\"label\":\"...\"}]}\n"
|
'{"question":"...","options":[{"id":"1","label":"..."},{"id":"2","label":"..."}]}\n'
|
||||||
"Do NOT wrap questions in a list. Do NOT add commentary.\n"
|
"Do NOT wrap questions in a list. Do NOT add commentary.\n"
|
||||||
"When you have enough info, return JSON ONLY (via API):\n"
|
"When you have enough info, return JSON ONLY (via API):\n"
|
||||||
"{\"status\":\"complete\",\"board_type\":\"goal\"|\"general\",\"objective\":\"...\","
|
'{"status":"complete","board_type":"goal"|"general","objective":"...",'
|
||||||
"\"success_metrics\":{...},\"target_date\":\"YYYY-MM-DD\"}."
|
'"success_metrics":{...},"target_date":"YYYY-MM-DD"}.'
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -214,9 +214,7 @@ def delete_board(
|
|||||||
session.execute(delete(Approval).where(col(Approval.board_id) == board.id))
|
session.execute(delete(Approval).where(col(Approval.board_id) == board.id))
|
||||||
session.execute(delete(BoardMemory).where(col(BoardMemory.board_id) == board.id))
|
session.execute(delete(BoardMemory).where(col(BoardMemory.board_id) == board.id))
|
||||||
session.execute(
|
session.execute(
|
||||||
delete(BoardOnboardingSession).where(
|
delete(BoardOnboardingSession).where(col(BoardOnboardingSession.board_id) == board.id)
|
||||||
col(BoardOnboardingSession.board_id) == board.id
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
session.execute(delete(Task).where(col(Task.board_id) == board.id))
|
session.execute(delete(Task).where(col(Task.board_id) == board.id))
|
||||||
session.delete(board)
|
session.delete(board)
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
from sqlmodel import Session, select
|
from sqlmodel import Session, select
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from app.core.agent_tokens import generate_agent_token, hash_agent_token
|
from app.core.agent_tokens import generate_agent_token, hash_agent_token
|
||||||
from app.core.auth import AuthContext, get_auth_context
|
from app.core.auth import AuthContext, get_auth_context
|
||||||
from app.db.session import get_session
|
from app.db.session import get_session
|
||||||
@@ -306,7 +305,9 @@ async def _ensure_main_agent(
|
|||||||
try:
|
try:
|
||||||
await provision_main_agent(agent, gateway, raw_token, auth.user, action=action)
|
await provision_main_agent(agent, gateway, raw_token, auth.user, action=action)
|
||||||
await ensure_session(
|
await ensure_session(
|
||||||
gateway.main_session_key, config=GatewayClientConfig(url=gateway.url, token=gateway.token), label=agent.name
|
gateway.main_session_key,
|
||||||
|
config=GatewayClientConfig(url=gateway.url, token=gateway.token),
|
||||||
|
label=agent.name,
|
||||||
)
|
)
|
||||||
await send_message(
|
await send_message(
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import datetime, timezone
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
from datetime import datetime, timezone
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
|
from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
|
||||||
|
from sqlalchemy import asc, delete, desc
|
||||||
|
from sqlmodel import Session, col, select
|
||||||
from sse_starlette.sse import EventSourceResponse
|
from sse_starlette.sse import EventSourceResponse
|
||||||
from starlette.concurrency import run_in_threadpool
|
from starlette.concurrency import run_in_threadpool
|
||||||
from sqlalchemy import asc, desc, delete
|
|
||||||
from sqlmodel import Session, col, select
|
|
||||||
|
|
||||||
from app.api.deps import (
|
from app.api.deps import (
|
||||||
ActorContext,
|
ActorContext,
|
||||||
@@ -22,18 +22,14 @@ from app.api.deps import (
|
|||||||
)
|
)
|
||||||
from app.core.auth import AuthContext
|
from app.core.auth import AuthContext
|
||||||
from app.db.session import engine, get_session
|
from app.db.session import engine, get_session
|
||||||
from app.integrations.openclaw_gateway import (
|
from app.integrations.openclaw_gateway import GatewayConfig as GatewayClientConfig
|
||||||
GatewayConfig as GatewayClientConfig,
|
from app.integrations.openclaw_gateway import OpenClawGatewayError, ensure_session, send_message
|
||||||
OpenClawGatewayError,
|
|
||||||
ensure_session,
|
|
||||||
send_message,
|
|
||||||
)
|
|
||||||
from app.models.activity_events import ActivityEvent
|
from app.models.activity_events import ActivityEvent
|
||||||
from app.models.agents import Agent
|
from app.models.agents import Agent
|
||||||
from app.models.boards import Board
|
from app.models.boards import Board
|
||||||
from app.models.gateways import Gateway
|
from app.models.gateways import Gateway
|
||||||
from app.models.tasks import Task
|
|
||||||
from app.models.task_fingerprints import TaskFingerprint
|
from app.models.task_fingerprints import TaskFingerprint
|
||||||
|
from app.models.tasks import Task
|
||||||
from app.schemas.tasks import TaskCommentCreate, TaskCommentRead, TaskCreate, TaskRead, TaskUpdate
|
from app.schemas.tasks import TaskCommentCreate, TaskCommentRead, TaskCreate, TaskRead, TaskUpdate
|
||||||
from app.services.activity_log import record_activity
|
from app.services.activity_log import record_activity
|
||||||
|
|
||||||
@@ -151,9 +147,7 @@ def _fetch_task_events(
|
|||||||
since: datetime,
|
since: datetime,
|
||||||
) -> list[tuple[ActivityEvent, Task | None]]:
|
) -> list[tuple[ActivityEvent, Task | None]]:
|
||||||
with Session(engine) as session:
|
with Session(engine) as session:
|
||||||
task_ids = list(
|
task_ids = list(session.exec(select(Task.id).where(col(Task.board_id) == board_id)))
|
||||||
session.exec(select(Task.id).where(col(Task.board_id) == board_id))
|
|
||||||
)
|
|
||||||
if not task_ids:
|
if not task_ids:
|
||||||
return []
|
return []
|
||||||
statement = (
|
statement = (
|
||||||
@@ -270,9 +264,7 @@ def _notify_lead_on_task_create(
|
|||||||
task: Task,
|
task: Task,
|
||||||
) -> None:
|
) -> None:
|
||||||
lead = session.exec(
|
lead = session.exec(
|
||||||
select(Agent)
|
select(Agent).where(Agent.board_id == board.id).where(Agent.is_board_lead.is_(True))
|
||||||
.where(Agent.board_id == board.id)
|
|
||||||
.where(Agent.is_board_lead.is_(True))
|
|
||||||
).first()
|
).first()
|
||||||
if lead is None or not lead.openclaw_session_id:
|
if lead is None or not lead.openclaw_session_id:
|
||||||
return
|
return
|
||||||
@@ -329,9 +321,7 @@ def _notify_lead_on_task_unassigned(
|
|||||||
task: Task,
|
task: Task,
|
||||||
) -> None:
|
) -> None:
|
||||||
lead = session.exec(
|
lead = session.exec(
|
||||||
select(Agent)
|
select(Agent).where(Agent.board_id == board.id).where(Agent.is_board_lead.is_(True))
|
||||||
.where(Agent.board_id == board.id)
|
|
||||||
.where(Agent.is_board_lead.is_(True))
|
|
||||||
).first()
|
).first()
|
||||||
if lead is None or not lead.openclaw_session_id:
|
if lead is None or not lead.openclaw_session_id:
|
||||||
return
|
return
|
||||||
@@ -639,11 +629,7 @@ def update_task(
|
|||||||
task=task,
|
task=task,
|
||||||
)
|
)
|
||||||
if task.assigned_agent_id and task.assigned_agent_id != previous_assigned:
|
if task.assigned_agent_id and task.assigned_agent_id != previous_assigned:
|
||||||
if (
|
if actor.actor_type == "agent" and actor.agent and task.assigned_agent_id == actor.agent.id:
|
||||||
actor.actor_type == "agent"
|
|
||||||
and actor.agent
|
|
||||||
and task.assigned_agent_id == actor.agent.id
|
|
||||||
):
|
|
||||||
return task
|
return task
|
||||||
assigned_agent = session.get(Agent, task.assigned_agent_id)
|
assigned_agent = session.get(Agent, task.assigned_agent_id)
|
||||||
if assigned_agent:
|
if assigned_agent:
|
||||||
@@ -740,11 +726,7 @@ def create_task_comment(
|
|||||||
snippet = payload.message.strip()
|
snippet = payload.message.strip()
|
||||||
if len(snippet) > 500:
|
if len(snippet) > 500:
|
||||||
snippet = f"{snippet[:497]}..."
|
snippet = f"{snippet[:497]}..."
|
||||||
actor_name = (
|
actor_name = actor.agent.name if actor.actor_type == "agent" and actor.agent else "User"
|
||||||
actor.agent.name
|
|
||||||
if actor.actor_type == "agent" and actor.agent
|
|
||||||
else "User"
|
|
||||||
)
|
|
||||||
for agent in targets.values():
|
for agent in targets.values():
|
||||||
if not agent.openclaw_session_id:
|
if not agent.openclaw_session_id:
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
|
||||||
from fastapi import Depends, Header, HTTPException, Request, status
|
from fastapi import Depends, Header, HTTPException, Request, status
|
||||||
import logging
|
|
||||||
from sqlmodel import Session, col, select
|
from sqlmodel import Session, col, select
|
||||||
|
|
||||||
from app.core.agent_tokens import verify_agent_token
|
from app.core.agent_tokens import verify_agent_token
|
||||||
|
|||||||
@@ -31,5 +31,4 @@ class Settings(BaseSettings):
|
|||||||
log_use_utc: bool = False
|
log_use_utc: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ from app.models.board_memory import BoardMemory
|
|||||||
from app.models.board_onboarding import BoardOnboardingSession
|
from app.models.board_onboarding import BoardOnboardingSession
|
||||||
from app.models.boards import Board
|
from app.models.boards import Board
|
||||||
from app.models.gateways import Gateway
|
from app.models.gateways import Gateway
|
||||||
from app.models.tasks import Task
|
|
||||||
from app.models.task_fingerprints import TaskFingerprint
|
from app.models.task_fingerprints import TaskFingerprint
|
||||||
|
from app.models.tasks import Task
|
||||||
from app.models.users import User
|
from app.models.users import User
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
|||||||
@@ -24,9 +24,7 @@ class BoardCreate(BoardBase):
|
|||||||
def validate_goal_fields(self):
|
def validate_goal_fields(self):
|
||||||
if self.board_type == "goal" and self.goal_confirmed:
|
if self.board_type == "goal" and self.goal_confirmed:
|
||||||
if not self.objective or not self.success_metrics:
|
if not self.objective or not self.success_metrics:
|
||||||
raise ValueError(
|
raise ValueError("Confirmed goal boards require objective and success_metrics")
|
||||||
"Confirmed goal boards require objective and success_metrics"
|
|
||||||
)
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,7 @@ from jinja2 import Environment, FileSystemLoader, StrictUndefined, select_autoes
|
|||||||
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.integrations.openclaw_gateway import GatewayConfig as GatewayClientConfig
|
from app.integrations.openclaw_gateway import GatewayConfig as GatewayClientConfig
|
||||||
from app.integrations.openclaw_gateway import (
|
from app.integrations.openclaw_gateway import OpenClawGatewayError, ensure_session, openclaw_call
|
||||||
OpenClawGatewayError,
|
|
||||||
ensure_session,
|
|
||||||
openclaw_call,
|
|
||||||
)
|
|
||||||
from app.models.agents import Agent
|
from app.models.agents import Agent
|
||||||
from app.models.boards import Board
|
from app.models.boards import Board
|
||||||
from app.models.gateways import Gateway
|
from app.models.gateways import Gateway
|
||||||
@@ -304,9 +300,7 @@ def _render_agent_files(
|
|||||||
)
|
)
|
||||||
heartbeat_path = _templates_root() / heartbeat_template
|
heartbeat_path = _templates_root() / heartbeat_template
|
||||||
if heartbeat_path.exists():
|
if heartbeat_path.exists():
|
||||||
rendered[name] = (
|
rendered[name] = env.get_template(heartbeat_template).render(**context).strip()
|
||||||
env.get_template(heartbeat_template).render(**context).strip()
|
|
||||||
)
|
|
||||||
continue
|
continue
|
||||||
override = overrides.get(name)
|
override = overrides.get(name)
|
||||||
if override:
|
if override:
|
||||||
@@ -400,7 +394,9 @@ async def _remove_gateway_agent_list(
|
|||||||
if not isinstance(lst, list):
|
if not isinstance(lst, list):
|
||||||
raise OpenClawGatewayError("config agents.list is not a list")
|
raise OpenClawGatewayError("config agents.list is not a list")
|
||||||
|
|
||||||
new_list = [entry for entry in lst if not (isinstance(entry, dict) and entry.get("id") == agent_id)]
|
new_list = [
|
||||||
|
entry for entry in lst if not (isinstance(entry, dict) and entry.get("id") == agent_id)
|
||||||
|
]
|
||||||
if len(new_list) == len(lst):
|
if len(new_list) == len(lst):
|
||||||
return
|
return
|
||||||
patch = {"agents": {"list": new_list}}
|
patch = {"agents": {"list": new_list}}
|
||||||
|
|||||||
Reference in New Issue
Block a user