Replace go-openai with native client

Drop the github.com/sashabaranov/go-openai dependency in favor of an
internal HTTP client.

The LLM package is now split into:
- llm.go: type definitions (Message, ChatRequest, ChatResponse, etc.)
- client.go: client construction and configuration
- client_completions.go: Completions and CompletionsStream methods
- client_models.go: ListModels
- client_tools.go: tool call execution

CompletionsStream uses typed SSE events (delta, done, message) so the
frontend can render progressive streaming output.

Move tool.go and tool_test.go from internal/tool/ into internal/llm/
to co-locate the registry with the client that consumes it.

Update job.go and service.go to use the new llm.Message types and
Completions/CompletionsStream methods. Remove the Voice field from
chat request/response (voice is now tracked via message metadata).

Frontend: handle delta/done/message SSE events, render a streaming
placeholder that receives progressive text deltas, and finalize with
full message binding (reasoning, tool calls, actions).
This commit is contained in:
dwrz
2026-06-26 14:22:05 +00:00
parent e480538ec2
commit f6fb21d40c
56 changed files with 1671 additions and 7854 deletions

View File

@@ -13,7 +13,6 @@ import (
"time"
"github.com/robfig/cron/v3"
"github.com/sashabaranov/go-openai"
"code.chimeric.al/chimerical/odidere/internal/config"
"code.chimeric.al/chimerical/odidere/internal/llm"
@@ -124,7 +123,7 @@ type Result struct {
Duration time.Duration
// Messages is the full conversation returned by the LLM agent loop,
// including tool calls and tool results. Empty if the job failed.
Messages []openai.ChatCompletionMessage
Messages []llm.Message
// Error is set if the job failed.
Error error
}
@@ -138,10 +137,15 @@ func (j *Job) Run(ctx context.Context) Result {
log.Info("starting job")
// Build messages from job config.
messages := []openai.ChatCompletionMessage{
messages := []llm.Message{
{
Role: openai.ChatMessageRoleUser,
Content: j.Task(),
Role: llm.RoleUser,
ContentParts: []llm.ContentPart{
{
Text: j.Task(),
Type: llm.ContentTypeText,
},
},
},
}
@@ -152,12 +156,12 @@ func (j *Job) Run(ctx context.Context) Result {
defer cancel()
}
msgs, err := j.llm.Query(
msgs, err := j.llm.Completions(
ctx,
messages,
j.model,
j.SystemMessage(),
j.MaxIterations(),
messages,
)
duration := time.Since(start)