feat(channel): make message timeout configurable via channels_config.message_timeout_secs
Add configurable timeout for processing channel messages (LLM + tools). Default: 300s (optimized for on-device LLMs like Ollama). Can be overridden in config.toml: [channels_config] message_timeout_secs = 600
This commit is contained in:
parent
4ecaf6070c
commit
41a6ed30dd
4 changed files with 38 additions and 24 deletions
|
|
@ -50,6 +50,10 @@ Notes:
|
|||
|
||||
Top-level channel options are configured under `channels_config`.
|
||||
|
||||
| Key | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `message_timeout_secs` | `300` | Timeout in seconds for processing a single channel message (LLM + tools) |
|
||||
|
||||
Examples:
|
||||
|
||||
- `[channels_config.telegram]`
|
||||
|
|
@ -57,6 +61,12 @@ Examples:
|
|||
- `[channels_config.whatsapp]`
|
||||
- `[channels_config.email]`
|
||||
|
||||
Notes:
|
||||
|
||||
- Default `300s` is optimized for on-device LLMs (Ollama) which are slower than cloud APIs.
|
||||
- If using cloud APIs (OpenAI, Anthropic, etc.), you can reduce this to `60` or lower.
|
||||
- When a timeout occurs, users receive: `⚠️ Request timed out while waiting for the model. Please try again.`
|
||||
|
||||
See detailed channel matrix and allowlist behavior in [channels-reference.md](channels-reference.md).
|
||||
|
||||
## Security-Relevant Defaults
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ const BOOTSTRAP_MAX_CHARS: usize = 20_000;
|
|||
|
||||
const DEFAULT_CHANNEL_INITIAL_BACKOFF_SECS: u64 = 2;
|
||||
const DEFAULT_CHANNEL_MAX_BACKOFF_SECS: u64 = 60;
|
||||
/// Timeout for processing a single channel message (LLM + tools).
|
||||
/// 300s for on-device LLMs (Ollama) which are slower than cloud APIs.
|
||||
/// Default timeout for processing a single channel message (LLM + tools).
|
||||
/// Used as fallback when not configured in channels_config.message_timeout_secs.
|
||||
const CHANNEL_MESSAGE_TIMEOUT_SECS: u64 = 300;
|
||||
const CHANNEL_PARALLELISM_PER_CHANNEL: usize = 4;
|
||||
const CHANNEL_MIN_IN_FLIGHT_MESSAGES: usize = 8;
|
||||
|
|
@ -120,6 +120,7 @@ struct ChannelRuntimeContext {
|
|||
reliability: Arc<crate::config::ReliabilityConfig>,
|
||||
provider_runtime_options: providers::ProviderRuntimeOptions,
|
||||
workspace_dir: Arc<PathBuf>,
|
||||
message_timeout_secs: u64,
|
||||
}
|
||||
|
||||
fn conversation_memory_key(msg: &traits::ChannelMessage) -> String {
|
||||
|
|
@ -696,7 +697,7 @@ async fn process_channel_message(ctx: Arc<ChannelRuntimeContext>, msg: traits::C
|
|||
};
|
||||
|
||||
let llm_result = tokio::time::timeout(
|
||||
Duration::from_secs(CHANNEL_MESSAGE_TIMEOUT_SECS),
|
||||
Duration::from_secs(ctx.message_timeout_secs),
|
||||
run_tool_call_loop(
|
||||
active_provider.as_ref(),
|
||||
&mut history,
|
||||
|
|
@ -787,10 +788,7 @@ async fn process_channel_message(ctx: Arc<ChannelRuntimeContext>, msg: traits::C
|
|||
}
|
||||
}
|
||||
Err(_) => {
|
||||
let timeout_msg = format!(
|
||||
"LLM response timed out after {}s",
|
||||
CHANNEL_MESSAGE_TIMEOUT_SECS
|
||||
);
|
||||
let timeout_msg = format!("LLM response timed out after {}s", ctx.message_timeout_secs);
|
||||
eprintln!(
|
||||
" ❌ {} (elapsed: {}ms)",
|
||||
timeout_msg,
|
||||
|
|
@ -1835,6 +1833,7 @@ pub async fn start_channels(config: Config) -> Result<()> {
|
|||
reliability: Arc::new(config.reliability.clone()),
|
||||
provider_runtime_options,
|
||||
workspace_dir: Arc::new(config.workspace_dir.clone()),
|
||||
message_timeout_secs: config.channels_config.message_timeout_secs,
|
||||
});
|
||||
|
||||
run_message_dispatch_loop(rx, runtime_ctx, max_in_flight_messages).await;
|
||||
|
|
@ -2225,6 +2224,7 @@ mod tests {
|
|||
reliability: Arc::new(crate::config::ReliabilityConfig::default()),
|
||||
provider_runtime_options: providers::ProviderRuntimeOptions::default(),
|
||||
workspace_dir: Arc::new(std::env::temp_dir()),
|
||||
message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS,
|
||||
});
|
||||
|
||||
process_channel_message(
|
||||
|
|
@ -2277,6 +2277,7 @@ mod tests {
|
|||
reliability: Arc::new(crate::config::ReliabilityConfig::default()),
|
||||
provider_runtime_options: providers::ProviderRuntimeOptions::default(),
|
||||
workspace_dir: Arc::new(std::env::temp_dir()),
|
||||
message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS,
|
||||
});
|
||||
|
||||
process_channel_message(
|
||||
|
|
@ -2338,6 +2339,7 @@ mod tests {
|
|||
reliability: Arc::new(crate::config::ReliabilityConfig::default()),
|
||||
provider_runtime_options: providers::ProviderRuntimeOptions::default(),
|
||||
workspace_dir: Arc::new(std::env::temp_dir()),
|
||||
message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS,
|
||||
});
|
||||
|
||||
process_channel_message(
|
||||
|
|
@ -2420,6 +2422,7 @@ mod tests {
|
|||
reliability: Arc::new(crate::config::ReliabilityConfig::default()),
|
||||
provider_runtime_options: providers::ProviderRuntimeOptions::default(),
|
||||
workspace_dir: Arc::new(std::env::temp_dir()),
|
||||
message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS,
|
||||
});
|
||||
|
||||
process_channel_message(
|
||||
|
|
@ -2478,6 +2481,7 @@ mod tests {
|
|||
reliability: Arc::new(crate::config::ReliabilityConfig::default()),
|
||||
provider_runtime_options: providers::ProviderRuntimeOptions::default(),
|
||||
workspace_dir: Arc::new(std::env::temp_dir()),
|
||||
message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS,
|
||||
});
|
||||
|
||||
process_channel_message(
|
||||
|
|
@ -2531,6 +2535,7 @@ mod tests {
|
|||
reliability: Arc::new(crate::config::ReliabilityConfig::default()),
|
||||
provider_runtime_options: providers::ProviderRuntimeOptions::default(),
|
||||
workspace_dir: Arc::new(std::env::temp_dir()),
|
||||
message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS,
|
||||
});
|
||||
|
||||
process_channel_message(
|
||||
|
|
@ -2635,6 +2640,7 @@ mod tests {
|
|||
reliability: Arc::new(crate::config::ReliabilityConfig::default()),
|
||||
provider_runtime_options: providers::ProviderRuntimeOptions::default(),
|
||||
workspace_dir: Arc::new(std::env::temp_dir()),
|
||||
message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS,
|
||||
});
|
||||
|
||||
let (tx, rx) = tokio::sync::mpsc::channel::<traits::ChannelMessage>(4);
|
||||
|
|
@ -2705,6 +2711,7 @@ mod tests {
|
|||
reliability: Arc::new(crate::config::ReliabilityConfig::default()),
|
||||
provider_runtime_options: providers::ProviderRuntimeOptions::default(),
|
||||
workspace_dir: Arc::new(std::env::temp_dir()),
|
||||
message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS,
|
||||
});
|
||||
|
||||
process_channel_message(
|
||||
|
|
@ -3095,6 +3102,7 @@ mod tests {
|
|||
reliability: Arc::new(crate::config::ReliabilityConfig::default()),
|
||||
provider_runtime_options: providers::ProviderRuntimeOptions::default(),
|
||||
workspace_dir: Arc::new(std::env::temp_dir()),
|
||||
message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS,
|
||||
});
|
||||
|
||||
process_channel_message(
|
||||
|
|
|
|||
|
|
@ -1979,6 +1979,14 @@ pub struct ChannelsConfig {
|
|||
pub lark: Option<LarkConfig>,
|
||||
pub dingtalk: Option<DingTalkConfig>,
|
||||
pub qq: Option<QQConfig>,
|
||||
/// Timeout in seconds for processing a single channel message (LLM + tools).
|
||||
/// Default: 300s for on-device LLMs (Ollama) which are slower than cloud APIs.
|
||||
#[serde(default = "default_channel_message_timeout_secs")]
|
||||
pub message_timeout_secs: u64,
|
||||
}
|
||||
|
||||
fn default_channel_message_timeout_secs() -> u64 {
|
||||
300
|
||||
}
|
||||
|
||||
impl Default for ChannelsConfig {
|
||||
|
|
@ -1999,6 +2007,7 @@ impl Default for ChannelsConfig {
|
|||
lark: None,
|
||||
dingtalk: None,
|
||||
qq: None,
|
||||
message_timeout_secs: default_channel_message_timeout_secs(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3242,6 +3251,7 @@ default_temperature = 0.7
|
|||
lark: None,
|
||||
dingtalk: None,
|
||||
qq: None,
|
||||
message_timeout_secs: 300,
|
||||
},
|
||||
memory: MemoryConfig::default(),
|
||||
storage: StorageConfig::default(),
|
||||
|
|
@ -3746,6 +3756,7 @@ allowed_users = ["@ops:matrix.org"]
|
|||
lark: None,
|
||||
dingtalk: None,
|
||||
qq: None,
|
||||
message_timeout_secs: 300,
|
||||
};
|
||||
let toml_str = toml::to_string_pretty(&c).unwrap();
|
||||
let parsed: ChannelsConfig = toml::from_str(&toml_str).unwrap();
|
||||
|
|
@ -3909,6 +3920,7 @@ channel_id = "C123"
|
|||
lark: None,
|
||||
dingtalk: None,
|
||||
qq: None,
|
||||
message_timeout_secs: 300,
|
||||
};
|
||||
let toml_str = toml::to_string_pretty(&c).unwrap();
|
||||
let parsed: ChannelsConfig = toml::from_str(&toml_str).unwrap();
|
||||
|
|
|
|||
|
|
@ -2452,23 +2452,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
print_bullet("CLI is always available. Connect more channels now.");
|
||||
println!();
|
||||
|
||||
let mut config = ChannelsConfig {
|
||||
cli: true,
|
||||
telegram: None,
|
||||
discord: None,
|
||||
slack: None,
|
||||
mattermost: None,
|
||||
webhook: None,
|
||||
imessage: None,
|
||||
matrix: None,
|
||||
signal: None,
|
||||
whatsapp: None,
|
||||
email: None,
|
||||
irc: None,
|
||||
lark: None,
|
||||
dingtalk: None,
|
||||
qq: None,
|
||||
};
|
||||
let mut config = ChannelsConfig::default();
|
||||
|
||||
loop {
|
||||
let options = vec![
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue