feat: add NORTH_STAR.md and MVP core loop (Telegram bot + LLM + proposal generator)
This commit is contained in:
committed by
GitHub
parent
c071fe6bf7
commit
6862c7d0b8
@@ -0,0 +1,70 @@
|
||||
"""LLM client wrapper (OpenAI-compatible)."""
|
||||
|
||||
import logging
|
||||
from collections.abc import AsyncIterator
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
|
||||
from steward.config import Settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LLMClient:
|
||||
"""Thin async wrapper around the OpenAI chat-completions API."""
|
||||
|
||||
def __init__(self, settings: Settings) -> None:
|
||||
self._settings = settings
|
||||
self._client = AsyncOpenAI(
|
||||
api_key=settings.openai_api_key,
|
||||
base_url=settings.openai_base_url,
|
||||
)
|
||||
|
||||
async def chat(
|
||||
self,
|
||||
user_message: str,
|
||||
*,
|
||||
history: list[dict[str, str]] | None = None,
|
||||
system_prompt: str | None = None,
|
||||
) -> str:
|
||||
"""Send a user message (with optional history) and return the assistant reply."""
|
||||
system = system_prompt or self._settings.openai_system_prompt
|
||||
messages: list[dict[str, str]] = [{"role": "system", "content": system}]
|
||||
if history:
|
||||
messages.extend(history)
|
||||
messages.append({"role": "user", "content": user_message})
|
||||
|
||||
logger.debug(
|
||||
"LLM request: model=%s messages=%d", self._settings.openai_model, len(messages)
|
||||
)
|
||||
response = await self._client.chat.completions.create(
|
||||
model=self._settings.openai_model,
|
||||
messages=messages, # type: ignore[arg-type]
|
||||
)
|
||||
reply = response.choices[0].message.content or ""
|
||||
logger.debug("LLM reply: %d chars", len(reply))
|
||||
return reply
|
||||
|
||||
async def stream(
|
||||
self,
|
||||
user_message: str,
|
||||
*,
|
||||
history: list[dict[str, str]] | None = None,
|
||||
system_prompt: str | None = None,
|
||||
) -> AsyncIterator[str]:
|
||||
"""Stream the assistant reply token by token."""
|
||||
system = system_prompt or self._settings.openai_system_prompt
|
||||
messages: list[dict[str, str]] = [{"role": "system", "content": system}]
|
||||
if history:
|
||||
messages.extend(history)
|
||||
messages.append({"role": "user", "content": user_message})
|
||||
|
||||
stream = await self._client.chat.completions.create(
|
||||
model=self._settings.openai_model,
|
||||
messages=messages, # type: ignore[arg-type]
|
||||
stream=True,
|
||||
)
|
||||
async for chunk in stream:
|
||||
delta = chunk.choices[0].delta.content
|
||||
if delta:
|
||||
yield delta
|
||||
Reference in New Issue
Block a user