File size: 4,565 Bytes
28a08e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"""backend/api/conversations.py β€” Conversations + Messages CRUD (S354)."""
import json, logging
from .state import safe_json_dumps
from typing import Optional, Any
from fastapi import APIRouter, Depends, Body, HTTPException
from .auth_guard import require_role, AuthRole
from pydantic import BaseModel
from .state import sb

router = APIRouter( dependencies=[Depends(require_role(AuthRole.MACHINE))])  # GAP-1-fix: router-level auth
_logger = logging.getLogger("conversations")


class ConversationIn(BaseModel):
    id: str
    title: str = 'Nuova conversazione'
    created_at: int
    updated_at: int


class MessageIn(BaseModel):
    id: str
    conversation_id: str
    role: str
    content: str
    created_at: int
    error: Optional[bool] = False
    steps: Optional[Any] = None
    agent_status: Optional[str] = None


# ── Conversations ──────────────────────────────────────────────────────────────

@router.get('/api/conversations')
async def list_conversations():
    try:
        data = sb().table('conversations').select('*').order('updated_at', desc=True).limit(200).execute()  # BUGFIX: LIMIT 200 β€” senza limit OOM garantito su account con molte conversazioni
        return {'conversations': data.data}
    except Exception as exc:
        _logger.warning("list_conversations: %s", exc)
        # S750-GAP-I: Supabase non configurato o irraggiungibile β†’ lista vuota invece di 500
        return {'conversations': [], '_error': str(exc)[:120]}


@router.post('/api/conversations')
async def upsert_conversation(conv: ConversationIn):
    try:
        data = sb().table('conversations').upsert(conv.model_dump()).execute()
        return {'conversation': data.data[0] if data.data else conv.model_dump()}
    except Exception as exc:
        _logger.warning("upsert_conversation %s: %s", conv.id, exc)
        return {'conversation': conv.model_dump(), '_error': str(exc)[:120]}


@router.put('/api/conversations/{conv_id}')
async def update_conversation(conv_id: str, body: dict = Body(...)):
    body['id'] = conv_id
    try:
        data = sb().table('conversations').upsert(body).execute()
        return {'conversation': data.data[0] if data.data else body}
    except Exception as exc:
        _logger.warning("update_conversation %s: %s", conv_id, exc)
        return {'conversation': body, '_error': str(exc)[:120]}


@router.delete('/api/conversations/{conv_id}')
async def delete_conversation(conv_id: str):
    try:
        sb().table('messages').delete().eq('conversation_id', conv_id).execute()
        sb().table('conversations').delete().eq('id', conv_id).execute()
    except Exception as exc:
        _logger.warning("delete_conversation %s: %s", conv_id, exc)
    return {'deleted': conv_id}


# ── Messages ───────────────────────────────────────────────────────────────────

@router.get('/api/conversations/{conv_id}/messages')
async def list_messages(conv_id: str):
    try:
        data = sb().table('messages').select('*').eq('conversation_id', conv_id).order('created_at').limit(500).execute()  # BUGFIX: LIMIT 500 β€” senza limit OOM garantito su conversazioni lunghe
        return {'messages': data.data}
    except Exception as exc:
        _logger.warning("list_messages %s: %s", conv_id, exc)
        return {'messages': [], '_error': str(exc)[:120]}


@router.post('/api/conversations/{conv_id}/messages')
async def upsert_messages(conv_id: str, body: dict = Body(...)):
    msgs = body.get('messages', [])
    if not msgs:
        return {'upserted': 0}
    for m in msgs:
        m['conversation_id'] = conv_id
        if 'steps' in m and m['steps'] is not None:
            m['steps'] = safe_json_dumps(m['steps']) if not isinstance(m['steps'], str) else m['steps']
    try:
        data = sb().table('messages').upsert(msgs).execute()
        return {'upserted': len(data.data)}
    except Exception as exc:
        _logger.warning("upsert_messages %s: %s", conv_id, exc)
        return {'upserted': 0, '_error': str(exc)[:120]}


@router.delete('/api/conversations/{conv_id}/messages')
async def clear_messages(conv_id: str):
    try:
        sb().table('messages').delete().eq('conversation_id', conv_id).execute()
    except Exception as exc:
        _logger.warning("clear_messages %s: %s", conv_id, exc)
    return {'cleared': conv_id}