Commit graph

4 commits

Author SHA1 Message Date
2f6f5fab1c feat(llm): add multimodal ContentPart/Parts + per-provider serialization
Message gains an optional Parts []ContentPart alongside the existing
plain-text Content, so a turn can carry text plus image/video
attachments. Content stays the single source of truth for every
existing text-only caller (sidebar.go, memory_tools.go, etc. are
untouched); Parts only matters to a provider client when non-empty.

openai and llamacpp (both OpenAI-compatible) serialize Parts into the
standard text/image_url content-array shape; llamacpp additionally
passes video through as a best-effort video_url part, since llama.cpp
itself has no video support but the whole point of this client is the
user's own OpenAI-compatible server sitting in front of a
video-capable model — the server decides whether it understands it,
not this client. anthropic converts image parts to its base64 image
content block, and rejects a video part outright with a clear error:
the Messages API has no video block type at all, so sending one would
just produce a confusing 400 instead.

ProviderCapabilities gains SupportsVideo, true only for llamacpp.
2026-07-16 22:23:54 -07:00
838eef642a fix(openai): make streaming actually work; honor configured model
The Stream() path was broken end to end:
- requests always went out with "stream": false, so the SSE parser found
  no data lines and every stream ended empty
- Config.Model was discarded at construction, and the agent loop never
  sets req.Model, so requests carried an empty model (hard API error)
- tool-call deltas were ignored entirely: the agent never executed tools
  over a stream with this provider (which also backs the ollama type)
- usage was neither requested nor parsed, so token tracking stayed at 0

Now mirrors the proven llamacpp client: stream flag + stream_options
.include_usage, per-index tool-call fragment accumulation flushed on
finish_reason, usage passthrough, a 4MB SSE scanner buffer (64KB default
kills the stream on large tool arguments), and an empty-choices guard in
toResponse instead of a panic.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 16:14:01 -07:00
3ac9d89b98 Fix tool call tracking and streaming assembly for all providers
- agent/loop.go: Record assistant message with ToolCalls before tool results,
  and set ToolCallID on tool-result messages so follow-up requests have complete
  context (prevents models from losing track of already-attempted tools).

- llm/providers/llamacpp/client.go: Buffer fragmented tool call deltas during
  streaming, assemble them into complete calls when finish_reason arrives.
  Add ToolCalls, ToolCallID, Name fields to request building.

- llm/providers/openai/client.go: Send ToolCalls, ToolCallID, Name when
  building chat requests so messages are wire-format correct.

- llm/types.go: Add ToolCalls field to Message struct for serialization
  back into conversation history.

- agent/integration_test.go: Move integration test skip from TestMain to a
  per-test skipUnlessIntegration() so it doesn't hide other package tests.

- sandbox & tools: Add edge-case tests (relative traversal, array paths,
  non-path strings, zero-value guards, sentinel errors).
2026-07-08 16:11:57 -07:00
641481022f feat(llm): add LLM client interface, types, providers (openai, llamacpp), and mock 2026-06-30 23:53:22 -07:00