feat(orchestrator): use reasoning-quick-v1 for low-latency chat (#1761)

This commit is contained in:
Steven Enamakel
2026-05-14 18:54:18 -07:00
committed by GitHub
parent c65d8ce3a6
commit 6ab6a86cf2
8 changed files with 57 additions and 11 deletions
+1 -1
View File
@@ -303,7 +303,7 @@ mod tests {
#[test]
fn orchestrator_has_reasoning_hint_and_named_tools() {
let def = find("orchestrator");
assert!(matches!(def.model, ModelSpec::Hint(ref h) if h == "reasoning"));
assert!(matches!(def.model, ModelSpec::Hint(ref h) if h == "reasoning-quick"));
match def.tools {
ToolScope::Named(tools) => {
// spawn_subagent was removed in #1141; spawn_worker_thread is the replacement
@@ -61,7 +61,14 @@ subagents = [
]
[model]
hint = "reasoning"
# `reasoning-quick` (Kimi K2.6 Turbo on Fireworks via backend PR #760)
# is tuned for low time-to-first-token on conversational turns. The
# orchestrator is a planner/router that mostly picks a delegate and
# synthesises sub-agent output — workload that doesn't benefit from
# the slower deep-reasoning tier. Sub-agents that need heavier
# reasoning can still opt into `reasoning-v1` (DeepSeek V4 Pro) via
# `ModelSpec::Hint("reasoning")` in their own definitions.
hint = "reasoning-quick"
[tools]
# Direct tools — things the orchestrator calls itself rather than
+19 -3
View File
@@ -69,6 +69,15 @@ pub const PRICING_TABLE: &[ModelPricing] = &[
cached_input_per_mtok_usd: 1.50,
output_per_mtok_usd: 75.00,
},
// Quick reasoning tier — Kimi K2.6 Turbo on Fireworks (backend PR
// #760). Low TTFT, 128k context, `supportsThinking: false`. Rates
// track Fireworks' published Kimi turbo pricing at time of writing.
ModelPricing {
model: "reasoning-quick-v1",
input_per_mtok_usd: 0.60,
cached_input_per_mtok_usd: 0.06,
output_per_mtok_usd: 2.50,
},
// Agentic tier — maps to Sonnet-class models.
ModelPricing {
model: "agentic-v1",
@@ -95,14 +104,21 @@ pub fn lookup_pricing(model: &str) -> ModelPricing {
return *row;
}
let lower = model.to_ascii_lowercase();
let by_tier = |tier: &str| {
PRICING_TABLE
.iter()
.find(|row| row.model == tier)
.copied()
.unwrap_or(FALLBACK_PRICING)
};
if lower.contains("opus") {
return PRICING_TABLE[0];
return by_tier("reasoning-v1");
}
if lower.contains("coding") {
return PRICING_TABLE[2];
return by_tier("coding-v1");
}
if lower.contains("sonnet") || lower.contains("agentic") {
return PRICING_TABLE[1];
return by_tier("agentic-v1");
}
FALLBACK_PRICING
}
+2 -1
View File
@@ -36,7 +36,8 @@ pub use schema::{
SecretsConfig, SecurityConfig, SlackConfig, StorageConfig, StorageProviderConfig,
StorageProviderSection, StreamMode, TelegramConfig, UpdateConfig, UpdateRestartStrategy,
VoiceActivationMode, VoiceServerConfig, WebSearchConfig, WebhookConfig,
DEFAULT_CLOUD_LLM_MODEL, DEFAULT_MODEL, MODEL_AGENTIC_V1, MODEL_CODING_V1, MODEL_REASONING_V1,
DEFAULT_CLOUD_LLM_MODEL, DEFAULT_MODEL, MODEL_AGENTIC_V1, MODEL_CODING_V1,
MODEL_REASONING_QUICK_V1, MODEL_REASONING_V1,
};
pub use schema::{
clear_active_user, default_root_openhuman_dir, pre_login_user_dir, read_active_user_id,
+11 -1
View File
@@ -68,7 +68,9 @@ impl Default for CostConfig {
/// Default pricing for popular models (USD per 1M tokens)
fn get_default_pricing() -> HashMap<String, ModelPricing> {
use super::types::{MODEL_AGENTIC_V1, MODEL_CODING_V1, MODEL_REASONING_V1};
use super::types::{
MODEL_AGENTIC_V1, MODEL_CODING_V1, MODEL_REASONING_QUICK_V1, MODEL_REASONING_V1,
};
let mut prices = HashMap::new();
@@ -79,6 +81,14 @@ fn get_default_pricing() -> HashMap<String, ModelPricing> {
output: 2.52,
},
);
// Kimi K2.6 Turbo on Fireworks — see backend PR #760.
prices.insert(
MODEL_REASONING_QUICK_V1.into(),
ModelPricing {
input: 0.60,
output: 2.50,
},
);
prices.insert(
MODEL_AGENTIC_V1.into(),
ModelPricing {
+7
View File
@@ -9,6 +9,13 @@ use std::path::PathBuf;
/// Standard model identifiers matching the backend model registry.
pub const MODEL_AGENTIC_V1: &str = "agentic-v1";
pub const MODEL_REASONING_V1: &str = "reasoning-v1";
/// Low-latency reasoning tier. Backend maps this to Kimi K2.6 Turbo on
/// Fireworks (128k context, `supportsThinking: false`) — tuned for
/// time-to-first-token on conversational turns. See backend PR #760.
/// The orchestrator (user-facing front-line agent) rides on this tier
/// by default so chat responses feel snappy; reach for the slower
/// `reasoning-v1` (DeepSeek V4 Pro) only when deep reasoning is needed.
pub const MODEL_REASONING_QUICK_V1: &str = "reasoning-quick-v1";
pub const MODEL_CODING_V1: &str = "coding-v1";
/// Default model used when no explicit model is configured.
///
+5 -3
View File
@@ -3,12 +3,14 @@ use super::Provider;
use async_trait::async_trait;
use std::collections::HashMap;
/// Maps OpenHuman's abstract tier model names (`reasoning-v1`, `agentic-v1`,
/// `coding-v1`, `summarization-v1`) to the hint slot in `model_routes`.
/// Returns `None` for any model the router shouldn't rewrite.
/// Maps OpenHuman's abstract tier model names (`reasoning-v1`,
/// `reasoning-quick-v1`, `agentic-v1`, `coding-v1`, `summarization-v1`)
/// to the hint slot in `model_routes`. Returns `None` for any model the
/// router shouldn't rewrite.
fn openhuman_tier_to_hint(model: &str) -> Option<&'static str> {
match model {
"reasoning-v1" => Some("reasoning"),
"reasoning-quick-v1" => Some("reasoning-quick"),
"agentic-v1" => Some("agentic"),
"coding-v1" => Some("coding"),
"summarization-v1" => Some("summarization"),
+4 -1
View File
@@ -17,7 +17,9 @@ use std::time::Instant;
use anyhow::Result;
use async_trait::async_trait;
use crate::openhuman::config::{MODEL_AGENTIC_V1, MODEL_CODING_V1, MODEL_REASONING_V1};
use crate::openhuman::config::{
MODEL_AGENTIC_V1, MODEL_CODING_V1, MODEL_REASONING_QUICK_V1, MODEL_REASONING_V1,
};
use crate::openhuman::providers::traits::{
ChatMessage, ChatRequest, ChatResponse, Provider, ProviderCapabilities, StreamChunk,
StreamError, StreamOptions, StreamResult, ToolsPayload,
@@ -93,6 +95,7 @@ impl IntelligentRoutingProvider {
// Keep remote model naming aligned with backend modelRegistry.
match requested_model.strip_prefix("hint:") {
Some("reasoning") => MODEL_REASONING_V1.to_string(),
Some("reasoning-quick") => MODEL_REASONING_QUICK_V1.to_string(),
Some("agentic") => MODEL_AGENTIC_V1.to_string(),
Some("coding") => MODEL_CODING_V1.to_string(),
_ => requested_model.to_string(),