aboutsummaryrefslogtreecommitdiff
path: root/agent/orchestrator/api.py
blob: c3582d4bdf6d4fa1f907443a159630004bd1fcc0 (plain)
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
"""OpenAI-compatible HTTP API for Sénia.

Open WebUI (and other OpenAI-API clients) talks to this endpoint set. We accept
the standard `/v1/chat/completions` shape, translate to internal types, hand
off to the orchestrator, and translate the response back to OpenAI shape.
"""

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, ConfigDict

from .loop import handle_turn
from .models import Message


app = FastAPI(title="Sénia")


class ChatMessage(BaseModel):
    role: str
    content: str


class ChatCompletionRequest(BaseModel):
    model_config = ConfigDict(extra="allow")
    model: str
    messages: list[ChatMessage]


@app.get("/v1/models")
def list_models():
    return {
        "object": "list",
        "data": [{"id": "senia", "object": "model", "owned_by": "local"}],
    }


@app.post("/v1/chat/completions")
def chat_completions(req: ChatCompletionRequest):
    try:
        response_text = handle_turn(
            messages=[Message(role=m.role, content=m.content) for m in req.messages],
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    return {
        "id": "chat-1",
        "object": "chat.completion",
        "model": req.model,
        "choices": [
            {
                "index": 0,
                "message": {"role": "assistant", "content": response_text},
                "finish_reason": "stop",
            }
        ],
    }