Merge pull request #20: fix: add /api/chat endpoint for streaming (closes #10)

This commit is contained in:
opencode 2026-07-05 07:16:56 +00:00
commit 8af3e5f1d5

View File

@ -169,15 +169,18 @@ class APIClient:
self, messages: list, model: str = None, **kwargs self, messages: list, model: str = None, **kwargs
) -> Dict[str, Any]: ) -> Dict[str, Any]:
""" """
Get a completion from the LLM using Ollama chat endpoint Get a completion from the LLM using Ollama chat endpoint.
Uses /api/chat with proper message list format to preserve
multi-turn conversation semantics (system, user, assistant roles).
Args: Args:
messages (list): List of message dictionaries (roles and content) messages (list): List of message dictionaries with 'role' and 'content'
model (str): Model to use model (str): Model to use
**kwargs: Additional parameters for the API **kwargs: Additional parameters for the API
Returns: Returns:
dict: Response from the LLM dict: Response from the LLM in OpenAI-compatible format
""" """
if model is None: if model is None:
# Reload config to get latest model setting # Reload config to get latest model setting
@ -186,40 +189,53 @@ class APIClient:
current_config = load_config() current_config = load_config()
model = current_config.get("model", "qwen3-coder:30b") model = current_config.get("model", "qwen3-coder:30b")
# Convert messages to prompt format expected by Ollama generate endpoint # Filter messages to only include valid roles for chat endpoint
prompt_text = "" chat_messages = []
for message in messages: for message in messages:
role = message.get("role", "user") role = message.get("role", "user")
content = message.get("content", "") content = message.get("content", "")
if role in ("system", "user", "assistant"):
chat_messages.append({"role": role, "content": content})
# Format messages properly for the model if not chat_messages:
if role == "system": return {"error": "No valid messages provided for chat completion"}
prompt_text += f"System: {content}\n\n"
elif role == "assistant":
prompt_text += f"Assistant: {content}\n\n"
else: # user
prompt_text += f"User: {content}\n\n"
# Add instruction for assistant response # Use Ollama chat endpoint with proper message format
prompt_text += "Assistant:" data = {
"model": model,
"messages": chat_messages,
"stream": False,
**kwargs,
}
# Prepare the data for Ollama generate endpoint result = self._make_request("/api/chat", "POST", data)
data = {"model": model, "prompt": prompt_text, "stream": False, **kwargs}
result = self._make_request("/api/generate", "POST", data)
if not result["success"]: if not result["success"]:
return {"error": result["error"]} return {"error": result["error"]}
# Extract the response from Ollama's generate format # Extract the response from Ollama's chat format
try: try:
response_data = result["data"] response_data = result["data"]
# In Ollama generate responses, the actual text is in the "response" field # Ollama chat endpoint returns message in message.content
if "response" in response_data: if "message" in response_data:
return {
"choices": [
{
"message": {
"role": response_data["message"].get(
"role", "assistant"
),
"content": response_data["message"].get(
"content", ""
),
}
}
]
}
elif "response" in response_data:
return { return {
"choices": [{"message": {"content": response_data["response"]}}] "choices": [{"message": {"content": response_data["response"]}}]
} }
else: else:
# If we get a different format, return what we found
return response_data return response_data
except Exception as e: except Exception as e:
return {"error": f"Failed to process chat completion result: {str(e)}"} return {"error": f"Failed to process chat completion result: {str(e)}"}