Commit graph

248 commits

Author SHA1 Message Date
727a71bd6e fix(ci): use git clone instead of actions/checkout for Forgejo runner
Some checks failed
bump-version / bump (push) Failing after 1s
2026-08-02 23:21:04 -07:00
ed2b8b675c fix(ci): quote pattern in release-commit check
Some checks failed
bump-version / bump (push) Failing after 2s
2026-08-02 23:07:35 -07:00
6e9211b5a0 ci: automatic version + releases tag
Some checks failed
bump-version / bump (push) Has been cancelled
2026-08-02 18:25:14 -07:00
cde9ac3544
Merge pull request #10 from VictorVargas/feat/multimodal-content-parts
Add multimodal (image/video) content support
2026-07-17 00:11:09 -07:00
49353485e5 feat(agent): thread the new turn through Loop as llm.Message
Run/RunStream took the new turn as a bare string, which had nowhere
to carry ContentPart attachments. Both now take an llm.Message
(Role is forced to RoleUser regardless of what the caller sets), so a
caller building a multimodal turn just fills in Content/Parts on it
instead of the loop needing a second, parallel parameter.
subagent.go and every test call site are updated to wrap their string
prompt as llm.Message{Role: llm.RoleUser, Content: ...} — SubAgent.Run
itself is untouched, it still takes a plain task string.
2026-07-16 22:24:03 -07:00
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
42a415fb7d
Merge pull request #9 from VictorVargas/feat/rag-sandbox-agent-recovery
Taxonomía RAG + auto-captura, sandbox avanzado y recuperación de turnos muertos
2026-07-15 14:58:39 -07:00
8e887c8c78 fix(agent,llamacpp): recover turns killed by unparsed tool calls and reasoning spirals
Two failure modes seen live with Qwen3.6 on llama.cpp ended turns silently
mid-task:

- The model writes its tool call as plain text inside its reasoning, the
  server never parses it, and the round ends with nothing executed. The
  loop now detects the markers and nudges the model to re-issue the call
  for real (max 2 per turn).

- llama.cpp silently ignores the max_thinking_tokens field, so a model in
  a reasoning spiral ran until max_tokens (seen live: 25k+ tokens of
  nonstop thinking, ~20 min). The llamacpp client now enforces the budget
  client-side during Stream: once exceeded while the round is still pure
  reasoning, it cuts with FinishThinkingBudget and aborts the request
  (freeing the server slot); the loop answers with its own corrective
  nudge, on a separate counter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 14:50:45 -07:00
07d1840e7e feat(sandbox): network egress policy, secret redaction, untrusted-content fencing
NetworkPolicy validates scheme/host and re-validates resolved IPs at dial
time and on redirects (DNS-rebinding defense), with cloud metadata
endpoints always blocked. Redact masks known credential shapes (OpenAI/
Anthropic/GitHub/AWS/Slack/Google keys, PEM blocks, JWTs) in tool output.
WrapUntrusted fences fetched web content against prompt injection, paired
with UntrustedContentInstruction for the system prompt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 14:50:45 -07:00
1c0c86de10 feat(rag): memory taxonomy (episodic/semantic/procedural) + episodic auto-capture
Fragments now carry a memory type in metadata (legacy fragments count as
procedural) with SearchByType filtering, and EpisodeCapture summarizes a
finished turn with the local LLM and stores it as episodic memory, so the
agent can answer "what did we do yesterday?". Includes an E2E test against
a live llama.cpp server (gated) and taxonomy unit tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 14:50:31 -07:00
ee9319b823
Merge pull request #8 from VictorVargas/fix/providers-agent-loop
Fix providers (OpenAI/llamacpp/Anthropic) and agent loop correctness
2026-07-12 16:22:19 -07:00
724a143f90 style: gofmt
Formatting only (struct field alignment, import ordering) across the
files that didn't comply — no semantic changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 16:14:15 -07:00
2e23216932 fix(agent): last-iteration false failure, cached schemas, usage in tool rounds
- Run() reported "max iterations reached" even when a valid final answer
  arrived exactly on the last allowed iteration, throwing the response
  away; a completed flag now distinguishes success from budget exhaustion.
- Tool schemas are marshaled once per Run/RunStream instead of once per
  loop iteration — they never change between iterations.
- RunStream's content gate (which hides raw deltas during a tool-call
  round) also swallowed that round's token usage, so callers only ever saw
  the final round's count and context tracking lagged exactly when the
  context grew fastest. Usage is now forwarded in its own chunk.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 16:14:15 -07:00
e6830161bc fix(llamacpp,anthropic): SSE headroom, no-choices guard, real context window
- llamacpp: 4MB SSE scanner buffer (the 64KB bufio.Scanner default killed
  streams whose single line exceeded it, e.g. a write tool call carrying a
  whole file) and an empty-choices guard in toResponse instead of a panic;
  request payload now uses bytes.NewReader (drops a full string copy).
- anthropic: Capabilities() reported a 1M-token context window for any
  non-haiku model. Callers use that number to decide when to compact, so
  compaction would have fired far too late and requests overflowed the
  real window. Default is now the standard 200k, configurable via
  Config.ContextWindow for extended-window models/plans.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 16:14:15 -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
eea51e30d1
Merge pull request #7 from VictorVargas/fix/stream-tool-call-visibility
fix(agent): RunStream never surfaced tool calls to callers
2026-07-10 00:10:39 -07:00
caeb1a1be6 fix(agent): RunStream never surfaced tool calls to callers
Bug found while building rony-harness's "Edited Files" info panel: it
scanned the transcript for tool-call messages carrying write/edit
arguments, but those messages never appeared — not even for a plain,
successful top-level write with no delegation involved.

Root cause: RunStream's content-streaming gate (`if !hasToolCalls &&
(hasContent || hasUsage) { yield(chunk, nil) }`) suppresses yielding
*any* chunk once a tool call is seen in that iteration, including the
chunk carrying the tool call itself. So chunk.ToolCalls was executed
internally (hence approvals and results worked) but never yielded to
the caller. Every caller-side "which tool got called" hook depending on
the stream (not the Approver callback) was therefore dead code.

Fix: yield a dedicated chunk carrying just the executed ToolCalls right
after running them, independent of the content-streaming gate below.
Updated TestRun_Stream_WithToolCalls, which asserted the old (buggy)
1-chunk behavior.
2026-07-10 00:04:44 -07:00
0a7a8d506d
Merge pull request #6 from VictorVargas/feat/subagent-runtime
feat(agent): add SubAgent runtime for nested, specialized agent loops
2026-07-09 12:19:58 -07:00
744bb00f88 feat(agent): add SubAgent runtime for nested, specialized agent loops
Implements docs/phase2.md §5 (Sub-agents), pulled forward from the
harness's item 2 work: SubAgent/SubAgentRegistry let a caller run a
nested agent.Loop with its own persona/tools/iteration cap and get its
final response back. Run doesn't set Approver/Sandbox, so a single Ask
approval on the caller's own delegating tool covers the whole nested
run (Ask-permission tools execute unprompted when Config.Approver is
nil). rony-harness consumes this for its delegate tool (builder/planner).
2026-07-09 12:08:32 -07:00
3b36ad2cf8
Merge pull request #5 from VictorVargas/feat/agents-md-injection
Wire AGENTS.md discovery into agent loop + add anthropic provider
2026-07-08 23:36:47 -07:00
a2de4eb812 feat(llm): add anthropic provider client, expand llama.cpp sampling config
- pkg/llm/providers/anthropic: new client implementation (was previously
  imported by rony-harness but never committed here, so a fresh clone
  wouldn't build)
- pkg/llm/providers/llamacpp: Config/Client gain the full local-model
  sampling surface (max_tokens, context_window, top_k/top_p/min_p,
  presence/repetition penalty, max_thinking_tokens) to match the
  llamacpp-local* entries added to configs/ai_providers.yaml

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 23:33:20 -07:00
0f835a0802 feat(agent): wire AGENTS.md discovery into the agent loop's system prompt
Export persona.DiscoverAgentsMD and add agent.Config.AgentsMD so project
and global AGENTS.md rules actually reach the model. Previously
buildInitialMessages always called AssembleSystemPrompt with an empty
string, so no AGENTS.md content was ever injected despite the discovery
logic already existing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 23:27:17 -07:00
eeefe07809
Merge pull request #4 from VictorVargas/feat/tools-for-model
Fix tool call tracking and streaming assembly for all providers
2026-07-08 16:17:36 -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
20092f4e52
Merge pull request #3 from VictorVargas/feat/rag-and-sessions
feat(rag): add SQLite+FTS5 backend, fix content/usage plumbing bugs
2026-07-06 00:16:07 -07:00
0652023037 feat(rag): add SQLite+FTS5 backend, fix content/usage plumbing bugs
Backend.Upsert never received the fragment's Content, so ChromaDB (and
any backend) stored the vector but silently dropped the actual text —
saved memories had nothing to retrieve later. Backend.Search now also
takes the raw query text, and a failed/missing embedding no longer
hard-fails Add/Search: it degrades to a nil vector so a lexical-capable
backend can still index/find the content (Chroma has no such fallback
and now says so explicitly instead of misbehaving).

Adds pkg/rag/backends/sqlitevec: a zero-dependency backend (pure-Go
SQLite, no external service) that does cosine similarity when a real
embedding vector is available and falls back to FTS5/BM25 full-text
search otherwise. Adds pkg/rag/embeddings.OpenAICompatible, covering
both a local llama.cpp server (`--embeddings` enabled) and real OpenAI
(or any OpenAI-shaped /embeddings endpoint) through the same client.

Also fixes token usage tracking for llama.cpp streaming: the client
never requested `stream_options.include_usage` nor parsed a usage-only
SSE event, and even when present, the agent loop's RunStream dropped
any chunk with no Delta/ReasoningDelta — silently discarding the only
chunk that carries usage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-06 00:05:30 -07:00
2cde90d8f7
Merge pull request #2 from VictorVargas/feat/consoel-buffer
feat: add history messages, reasoning content, and adaptive language support
2026-07-05 16:20:39 -07:00
a38f63683b feat: add history messages, reasoning content, and adaptive language support
- Add optional history parameter to Run/RunStream for conversation context
- Add Reasoning/ReasoningDelta fields to completion and stream types
- Update llama.cpp adapter to propagate reasoning content from responses
- Default persona language now adapts to the user's language dynamically
2026-07-05 16:17:37 -07:00
cd13f79bb3
Merge pull request #1 from VictorVargas/feat-llm-interface
feat(llm,agent): complete LLM client interface, agent loop, RAG memory, and tools
2026-07-03 14:30:55 -07:00
d3ac4d0ac3
Merge branch 'main' into feat-llm-interface 2026-07-03 14:30:38 -07:00
bffaecb579 docs(AGENTS): update repo status to reflect Go source code exists
- Change status from 'design/spec only' to actual implementation
- Add pkg/*/README.md as a reference in the docs table
- Update build/test section for existing codebase
- Add test coverage summary table
- Update testing conventions with current mock types
- Add ErrPersonaNotFound and ErrConfigNotFound to sentinel errors
2026-07-03 14:22:46 -07:00
2eed2033f0 test(llm,embeddings): add unit tests for mock client, types, and Ollama embedder
- Add comprehensive MockLLMClient tests (generate, stream, match variants)
- Add TypeRef JSON marshaling tests and StopReason value tests
- Add Ollama embedder tests for config defaults and embedding requests
2026-07-03 14:22:41 -07:00
1a8f1557f6 feat(llm): add ChatTemplateKwargs to CompletionRequest for provider-specific template params
- Add ChatTemplateKwargs field to llm.CompletionRequest
- Propagate kwargs through agent loop in both Run() and RunStream()
- Pass kwargs to llama.cpp client chat request
- Fix tool schema marshaling to include type/function wrapper
- Fix stream indentation logic in RunStream with responseBuilder
- Remove indirect marker from uuid dependency
2026-07-03 14:22:36 -07:00
0054ca793c docs: add AGENTS.md guide and skill definitions for AI agents 2026-06-30 23:53:34 -07:00
c25243a690 feat(tools): add Tool definitions, Registry pattern, and filesystem sandbox with path validation 2026-06-30 23:53:32 -07:00
9f33d6df93 feat(rag): add Retrieval-Augmented Memory with ChromaDB backend and embedding support 2026-06-30 23:53:30 -07:00
3f2dc5ccc0 feat(persona): add Persona definition, system prompt assembly, and AgentsMD discovery 2026-06-30 23:53:28 -07:00
4b39f52081 feat(agent): add Agent loop with iteration control, tool handling, and streaming support 2026-06-30 23:53:26 -07:00
641481022f feat(llm): add LLM client interface, types, providers (openai, llamacpp), and mock 2026-06-30 23:53:22 -07:00
ce64b68f12 feat(config): add YAML config loader with hierarchical precedence 2026-06-30 23:53:20 -07:00
2509029777 chore: add YAML config loading and UUID dependencies 2026-06-30 23:53:15 -07:00
46aec356ee docs(fix): fix go-llm-agent → rony-llm-agent 2026-06-30 14:43:00 -07:00
dc754e6df2 Merge branch 'feat-llm-interface' 2026-06-30 13:53:06 -07:00
8987266d1b docs(i18n): translate all docs to English (with .es.md as Spanish alternative) 2026-06-30 13:40:37 -07:00
3e3a42847a fix: routers in documents and referents 2026-06-30 00:41:59 -07:00
2ca15679cb chore:split documents 2026-06-28 23:22:15 -07:00
1efc90e10f chore:update documents 2026-06-28 17:25:45 -07:00
c21173a7f8 chore: initial scaffold with design docs 2026-06-28 16:03:57 -07:00