mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-25 14:53:34 +00:00
* fix(ci): secrets can't be used in step if conditions [skip-regression-check] (#787) GitHub Actions step-level `if:` doesn't have access to `secrets` context. Replace `if: secrets.X != ''` with `continue-on-error: true` and let the Set token step handle the fallback. Co-authored-by: Claude Sonnet 4.6 <[email protected]> * fix(ci): clean up staging pipeline — remove hacks, skip redundant checks [skip-regression-check] (#794) - Remove continue-on-error from staging-ci.yml app token steps (secrets are configured) - Skip test.yml and code_style.yml on PRs targeting staging (staging-ci.yml already runs tests before promoting, promotion PR gets full CI on main) - Allow ironclaw-ci[bot] in Claude Code review for bot-created promotion PRs Co-authored-by: Claude Opus 4.6 <[email protected]> * fix(ci): run fmt + clippy on staging PRs, skip Windows clippy [skip-regression-check] (#802) - Remove branches:[main] filter from code_style.yml so it runs on all PRs - Gate clippy-windows with `if: github.base_ref == 'main'` (skip on staging PRs) - Update rollup job to allow skipped clippy-windows - Simplify claude-review.yml to only trigger on labeled event (avoids duplicate runs) Co-authored-by: Claude Opus 4.6 <[email protected]> * feat: persist user_id in save_job and expose job_id on routine runs (#709) * feat: persist worker events to DB and fix activity tab rendering In-process Worker (used by Scheduler::dispatch_job) now persists events via save_job_event at key execution points: plan creation, LLM responses, tool_use, tool_result, and job completion/failure/stuck. Event data shapes match the container worker format so the gateway activity tab renders them correctly. Frontend: tool_result errors now show a red X icon with danger styling instead of a silent empty output. The result event falls back to the error field when message is absent. Co-Authored-By: Claude Opus 4.6 <[email protected]> * feat: wire RoutineEngine into gateway for direct manual trigger firing Replace the message-channel hack in routines_trigger_handler with a direct call to RoutineEngine::fire_manual(), ensuring FullJob routines dispatch correctly when triggered from the web UI. Inject the engine into GatewayState from Agent::run after construction. Also persists user_id in save_job for both PG and libSQL backends, removes the source='sandbox' filter so all jobs are visible, and exposes job_id on RoutineRunInfo for the frontend job link. Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: remove stale gateway_state argument from Agent::new test call sites The gateway_state parameter was removed from Agent::new during rebase (replaced by post-construction set_routine_engine_slot), but three test call sites still passed the extra None argument. Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: address PR review — restore sandbox source filter, remove blank lines - Revert removal of `source = 'sandbox'` filter in all SandboxStore queries (8 sites across PG and libSQL). Sandbox-specific APIs should stay scoped to sandbox jobs; unified job listing for the Jobs tab should use a separate query path. - Remove extra blank lines in agent_loop.rs and worker.rs that caused formatting CI failure. [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: address review — regenerate Cargo.lock, add user_id regression test - Regenerate Cargo.lock from main's lockfile to eliminate dependency version downgrades (anyhow, syn, etc.) that were churn from rebase. - Add regression test verifying user_id round-trips through save_job and get_job in the libSQL backend. Co-Authored-By: Claude Opus 4.6 <[email protected]> * style: remove trailing blank line in libsql jobs.rs [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <[email protected]> * test: add Postgres-side regression test for user_id persistence in save_job Mirrors the existing libSQL test (test_save_job_persists_user_id) for the Postgres backend. Gated behind #[cfg(feature = "postgres")] + #[ignore] since it requires a running PostgreSQL instance (integration tier). Co-Authored-By: Claude Opus 4.6 <[email protected]> --------- Co-authored-by: Claude Opus 4.6 <[email protected]> * feat(llm): per-provider unsupported parameter filtering (#749, #728) (#809) Add declarative `unsupported_params` field to provider definitions in providers.json. Parameters listed are stripped from requests before sending, preventing 400 errors from providers that reject them (e.g. gpt-5 family and kimi-k2.5 rejecting custom temperature values). - Add `unsupported_params` to ProviderDefinition and RegistryProviderConfig - Propagate from registry through config resolution - Generic strip helpers handle temperature, max_tokens, stop_sequences - Apply filtering in RigAdapter and AnthropicOAuthProvider - Mark openai and tinfoil providers as unsupporting temperature - Update openai default model to gpt-5-mini Co-authored-by: Claude Opus 4.6 <[email protected]> --------- Co-authored-by: Claude Sonnet 4.6 <[email protected]> Co-authored-by: Illia Polosukhin <[email protected]>
166 lines
6.8 KiB
Rust
166 lines
6.8 KiB
Rust
//! LLM configuration types.
|
||
//!
|
||
//! These types define the configuration for LLM providers. They are defined
|
||
//! here (in the `llm` module) so that the module is self-contained and can be
|
||
//! extracted into a standalone crate. Resolution logic (reading env vars,
|
||
//! settings) lives in `crate::config::llm`.
|
||
|
||
use secrecy::SecretString;
|
||
|
||
use crate::llm::registry::ProviderProtocol;
|
||
use crate::llm::session::SessionConfig;
|
||
|
||
/// Sentinel value used as `api_key` when only an OAuth token is present.
|
||
///
|
||
/// When we only have an OAuth token the provider factory in `llm/mod.rs`
|
||
/// checks for this value and routes to `AnthropicOAuthProvider`, so this
|
||
/// placeholder is never sent over the wire.
|
||
pub const OAUTH_PLACEHOLDER: &str = "oauth-placeholder";
|
||
|
||
/// Prompt cache retention policy for Anthropic.
|
||
///
|
||
/// Controls Anthropic's automatic prompt caching via a top-level
|
||
/// `cache_control` field injected through rig-core's `additional_params`.
|
||
/// - `None` — caching disabled, no `cache_control` injected.
|
||
/// - `Short` — 5-minute TTL (default), `{"type": "ephemeral"}`, 1.25× write surcharge.
|
||
/// - `Long` — 1-hour TTL, `{"type": "ephemeral", "ttl": "1h"}`, 2× write surcharge.
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||
pub enum CacheRetention {
|
||
/// No prompt caching.
|
||
None,
|
||
/// 5-minute TTL (default). Write cost: 1.25× base input.
|
||
#[default]
|
||
Short,
|
||
/// 1-hour TTL. Write cost: 2× base input.
|
||
Long,
|
||
}
|
||
|
||
impl std::str::FromStr for CacheRetention {
|
||
type Err = String;
|
||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
match s.to_lowercase().as_str() {
|
||
"none" | "off" | "disabled" => Ok(Self::None),
|
||
"short" | "5m" | "ephemeral" => Ok(Self::Short),
|
||
"long" | "1h" => Ok(Self::Long),
|
||
_ => Err(format!(
|
||
"invalid cache retention '{}', expected one of: none, short, long",
|
||
s
|
||
)),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl std::fmt::Display for CacheRetention {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
match self {
|
||
Self::None => write!(f, "none"),
|
||
Self::Short => write!(f, "short"),
|
||
Self::Long => write!(f, "long"),
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Resolved configuration for a registry-based provider.
|
||
///
|
||
/// This single struct replaces what used to be five separate config types
|
||
/// (`OpenAiDirectConfig`, `AnthropicDirectConfig`, `OllamaConfig`,
|
||
/// `OpenAiCompatibleConfig`, `TinfoilConfig`). The `protocol` field
|
||
/// determines which rig-core client constructor to use.
|
||
#[derive(Debug, Clone)]
|
||
pub struct RegistryProviderConfig {
|
||
/// Which API protocol to use (determines the rig-core client).
|
||
pub protocol: ProviderProtocol,
|
||
/// Provider identifier (e.g., "groq", "openai", "tinfoil").
|
||
pub provider_id: String,
|
||
/// API key (optional for some providers like Ollama).
|
||
/// For Anthropic OAuth, this is set to `OAUTH_PLACEHOLDER`.
|
||
pub api_key: Option<SecretString>,
|
||
/// Base URL for the API endpoint.
|
||
pub base_url: String,
|
||
/// Model identifier.
|
||
pub model: String,
|
||
/// Extra HTTP headers injected into every request.
|
||
pub extra_headers: Vec<(String, String)>,
|
||
/// OAuth token for providers that support Bearer auth (e.g. Anthropic via `claude login`).
|
||
/// When set, the provider factory routes to the OAuth-specific provider implementation.
|
||
pub oauth_token: Option<SecretString>,
|
||
/// Prompt cache retention (Anthropic-specific).
|
||
pub cache_retention: CacheRetention,
|
||
/// Parameter names that this provider does not support (e.g., `["temperature"]`).
|
||
/// Supported keys: `"temperature"`, `"max_tokens"`, `"stop_sequences"`.
|
||
/// Listed parameters are stripped from requests before sending to avoid 400 errors.
|
||
pub unsupported_params: Vec<String>,
|
||
}
|
||
|
||
/// Configuration for AWS Bedrock (native Converse API).
|
||
#[derive(Debug, Clone)]
|
||
pub struct BedrockConfig {
|
||
/// AWS region (e.g. "us-east-1").
|
||
pub region: String,
|
||
/// Bedrock model ID (e.g. "anthropic.claude-opus-4-6-v1").
|
||
pub model: String,
|
||
/// Cross-region inference prefix: "us", "eu", "apac", "global", or None.
|
||
pub cross_region: Option<String>,
|
||
/// AWS named profile (for SSO / assume-role workflows).
|
||
pub profile: Option<String>,
|
||
}
|
||
|
||
/// LLM provider configuration.
|
||
///
|
||
/// NearAI remains the default backend with its own config struct (session auth).
|
||
/// All other providers are resolved through the provider registry, producing
|
||
/// a generic `RegistryProviderConfig`.
|
||
#[derive(Debug, Clone)]
|
||
pub struct LlmConfig {
|
||
/// Backend identifier (e.g., "nearai", "openai", "groq", "tinfoil").
|
||
pub backend: String,
|
||
/// Session manager configuration (auth URL, token persistence path).
|
||
/// Used by the NearAI provider for OAuth/session-token auth.
|
||
pub session: SessionConfig,
|
||
/// NEAR AI config (always populated, also used for embeddings).
|
||
pub nearai: NearAiConfig,
|
||
/// Resolved provider config for registry-based providers.
|
||
/// `None` when backend is "nearai" or "bedrock".
|
||
pub provider: Option<RegistryProviderConfig>,
|
||
/// AWS Bedrock config (populated when backend=bedrock, requires --features bedrock).
|
||
pub bedrock: Option<BedrockConfig>,
|
||
/// HTTP request timeout in seconds for LLM API calls.
|
||
/// Default: 120. Increase for local LLMs (Ollama, vLLM, LM Studio) that
|
||
/// need more time for prompt evaluation on consumer hardware.
|
||
pub request_timeout_secs: u64,
|
||
}
|
||
|
||
/// NEAR AI configuration.
|
||
#[derive(Debug, Clone)]
|
||
pub struct NearAiConfig {
|
||
/// Model to use (e.g., "claude-3-5-sonnet-20241022", "gpt-4o")
|
||
pub model: String,
|
||
/// Cheap/fast model for lightweight tasks (heartbeat, routing, evaluation).
|
||
pub cheap_model: Option<String>,
|
||
/// Base URL for the NEAR AI API.
|
||
pub base_url: String,
|
||
/// API key for NEAR AI Cloud.
|
||
pub api_key: Option<SecretString>,
|
||
/// Optional fallback model for failover.
|
||
pub fallback_model: Option<String>,
|
||
/// Maximum number of retries for transient errors (default: 3).
|
||
pub max_retries: u32,
|
||
/// Consecutive failures before circuit breaker opens. None = disabled.
|
||
pub circuit_breaker_threshold: Option<u32>,
|
||
/// Seconds the circuit stays open before probing (default: 30).
|
||
pub circuit_breaker_recovery_secs: u64,
|
||
/// Enable in-memory response caching. Default: false.
|
||
pub response_cache_enabled: bool,
|
||
/// TTL in seconds for cached responses (default: 3600).
|
||
pub response_cache_ttl_secs: u64,
|
||
/// Max cached responses before LRU eviction (default: 1000).
|
||
pub response_cache_max_entries: usize,
|
||
/// Cooldown duration in seconds for failover (default: 300).
|
||
pub failover_cooldown_secs: u64,
|
||
/// Consecutive failures before failover cooldown (default: 3).
|
||
pub failover_cooldown_threshold: u32,
|
||
/// Enable cascade mode for smart routing. Default: true.
|
||
pub smart_routing_cascade: bool,
|
||
}
|