Commit graph

13 commits

Author SHA1 Message Date
Chummy
b2dd3582a4 fix(ci): align reliable tests with simple_chat contract 2026-02-17 01:01:56 +08:00
mai1015
b341fdb368 feat: add agent structure and improve tooling for provider 2026-02-17 01:01:56 +08:00
Chummy
3234159c6c
chore(clippy): clear warning backlog and harden conversions (#383) 2026-02-17 00:32:33 +08:00
Chummy
8bcb5efa8a fix(ci): align reliable provider tests with ChatResponse 2026-02-16 22:06:40 +08:00
stawky
9a5db46cf7 feat(providers): model failover chain + API key rotation
- Add model_fallbacks and api_keys to ReliabilityConfig
- Implement per-model fallback chain in ReliableProvider
- Add API key rotation on auth failures (401/403)
- Add retry-after header parsing and exponential backoff
- Integrate failover into chat_with_system and chat_with_history
- 20 unit tests covering failover, rotation, and retry logic
2026-02-16 21:59:35 +08:00
chumyin
3b4a4de457 refactor(provider): unify Provider responses with ChatResponse
- Switch Provider trait methods to return structured ChatResponse
- Map OpenAI-compatible tool_calls into shared ToolCall type
- Update reliable/router wrappers and provider tests for new interface
- Make agent loop prefer structured tool calls with text fallback parsing
- Adapt gateway replies to structured responses with safe tool-call fallback
2026-02-16 19:16:22 +08:00
Chummy
b442a07530
fix(memory): prevent autosave key collisions across runtime flows
Fixes #221 - SQLite Memory Override bug.

This PR resolves memory overwrite behavior in autosave paths by replacing fixed memory keys with unique keys, and improves short-horizon recall quality in channel runtime.

**Root Cause**
SQLite memory uses a unique constraint on `memories.key` and writes with `ON CONFLICT(key) DO UPDATE`.
Several autosave paths reused fixed keys (or sender-stable keys), so newer messages overwrote earlier conversation entries.

**Changes**
- Channel runtime: autosave key changed from `channel_sender` to `channel_sender_messageId`
- Added memory-context injection before provider calls (aligned with agent loop behavior)
- Agent loop: autosave keys changed from fixed `user_msg`/`assistant_resp` to UUID-suffixed keys
- Gateway: Webhook/WhatsApp autosave keys changed to UUID-suffixed keys

All CI checks passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:55:52 -05:00
Edvard Schøyen
89b1ec6fa2
feat: add multi-turn conversation history and tool execution
* feat: add multi-turn conversation history and tool execution

Major enhancement to the agent loop:

**Multi-turn conversation:**
- Add `ChatMessage` type with system/user/assistant constructors
- Add `chat_with_history` method to Provider trait (default impl
  delegates to `chat_with_system` for backward compatibility)
- Implement native `chat_with_history` on OpenRouter, Compatible,
  Reliable, and Router providers to send full message history
- Interactive mode now maintains persistent history across turns

**Tool execution:**
- Agent loop now parses `<tool_call>` XML tags from LLM responses
- Executes tools from the registry and feeds results back as
  `<tool_result>` messages
- Agentic loop continues until LLM produces final text (no tool calls)
- MAX_TOOL_ITERATIONS (10) safety limit prevents runaway loops
- System prompt includes structured tool-use protocol with JSON schemas

**Types:**
- `ChatMessage`, `ChatResponse`, `ToolCall`, `ToolResultMessage`,
  `ConversationMessage` — full conversation modeling types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address review comments on multi-turn + tool execution

- Add history sliding window (MAX_HISTORY_MESSAGES=50) to prevent
  unbounded conversation history growth in interactive mode
- Add 404→Responses API fallback in compatible.rs chat_with_history,
  matching chat_with_system behavior
- Use super::api_error() for error sanitization in compatible.rs
  instead of raw error body (prevents secret leakage)
- Add missing operational logs in reliable.rs chat_with_history:
  recovery, non-retryable, fallback switch warnings
- Add trim_history tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address second round of review comments

- Sanitize raw error text in compatible.rs chat_with_system using
  sanitize_api_error (prevents leaking secrets in error messages)
- Add chat_with_history to MockProvider in reliable.rs tests so
  the retry/fallback path is exercised end-to-end
- Add chat_with_history_retries_then_recovers and
  chat_with_history_falls_back tests
- Log warning on malformed <tool_call> JSON instead of silent drop
- Flush stdout after print! in agent_turn so output appears before
  tool execution on line-buffered terminals
- Make interactive mode resilient to transient errors (continue
  loop instead of terminating session)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 14:43:02 -05:00
Edvard Schøyen
49bb20f961
fix(providers): use Bearer auth for Gemini CLI OAuth tokens
* fix(providers): use Bearer auth for Gemini CLI OAuth tokens

When credentials come from ~/.gemini/oauth_creds.json (Gemini CLI),
send them as Authorization: Bearer header instead of ?key= query
parameter. API keys from env vars or config continue using ?key=.

Fixes #194

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(gemini): harden OAuth bearer auth flow and tests

* fix(gemini): granular auth source tracking and review fixes

Build on chumyin's auth model refactor with:
- Expand GeminiAuth to 4 variants (ExplicitKey/EnvGeminiKey/EnvGoogleKey/
  OAuthToken) so auth_source() uses stored discriminant without re-reading
  env vars at call time
- Add is_api_key()/credential() helpers on the enum
- Upgrade expired OAuth token log from debug to warn
- Add tests: provider_rejects_empty_key, auth_source_explicit_key,
  auth_source_none_without_credentials

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: apply rustfmt to fix CI lint failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: root <root@instance-20220913-1738.vcn09131738.oraclevcn.com>
Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
2026-02-15 14:32:33 -05:00
Argenis
8694c2e2d2
fix(providers): skip retries on non-retryable HTTP errors (4xx)
Skip retries on non-retryable HTTP client errors (4xx) to avoid wasting time on requests that will never succeed.

- Added is_non_retryable() function to detect non-retryable errors
- 4xx client errors (400, 401, 403, 404) are now non-retryable
- Exceptions: 429 (rate limiting) and 408 (timeout) remain retryable
- 5xx server errors remain retryable
- Fallback logic now skips retries for non-retryable errors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 10:11:32 -05:00
Argenis
1e19b12efd
fix(providers): warn on shared API key for fallbacks and warm up all providers (#130)
- Warn when fallback providers share the same API key as primary (could fail
  if providers require different keys)
- Warm up all providers instead of just the first, continuing on warmup failures

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 08:23:50 -05:00
Edvard
cc13fec16d fix: add provider warmup to prevent cold-start timeout on first channel message
The first API request after daemon startup consistently timed out (120s)
when using channels (Telegram, Discord, etc.), requiring a retry before
succeeding. This happened because the reqwest HTTP client's connection
pool was cold — no TLS handshake, DNS resolution, or HTTP/2 negotiation
had occurred yet.

The fix adds a `warmup()` method to the Provider trait that establishes
the connection pool on startup by hitting a lightweight endpoint
(`/api/v1/auth/key` for OpenRouter). The channel server calls this
immediately after creating the provider, before entering the message
processing loop.

Tested on Raspberry Pi 5 (aarch64) with OpenRouter + DeepSeek v3.2 via
Telegram channel. Before: first message took 2-7 minutes (120s timeout +
retries). After: first message responds in <30s with no retries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 18:43:26 -05:00
argenis de la rosa
ec2d5cc93d feat: enhance agent personality, tool guidance, and memory hygiene
- Expand communication style presets (professional, expressive, custom)
- Enrich SOUL.md with human-like tone and emoji-awareness guidance
- Add crash recovery and sub-task scoping guidance to AGENTS.md scaffold
- Add 'Use when / Don't use when' guidance to TOOLS.md and runtime prompts
- Implement memory hygiene system with configurable archiving and retention
- Add MemoryConfig options: hygiene_enabled, archive_after_days, purge_after_days, conversation_retention_days
- Archive old daily memory and session files to archive subdirectories
- Purge old archives and prune stale SQLite conversation rows
- Add comprehensive tests for new features
2026-02-14 11:28:39 -05:00