use std::{num::NonZeroU64, sync::Arc};
use rho_sdk::{
provider::ModelProvider, CompactionPolicy, Error, ProviderRequestUsageRecording, Rho,
SystemPrompt, Workspace, WorkspacePolicy,
};
pub(crate) use super::model_compactor::ModelCompactor;
use {
super::model_compactor::Summarizer, crate::compaction::CompactionConfig, crate::config::Config,
crate::diagnostics::RuntimeDiagnostics, crate::session::recall::RecallStore,
rho_providers::model::models_dev::cached_model_metadata,
};
pub(crate) struct RuntimeBuildOptions<'a, P> {
pub(crate) provider: Arc<dyn ModelProvider>,
pub(crate) tools: &'a [Arc<dyn rho_sdk::tool::Tool>],
pub(crate) workspace: Workspace,
pub(crate) workspace_policy: P,
pub(crate) approval_session: Option<rho_sdk::ApprovalSession>,
pub(crate) system_prompt: SystemPrompt,
pub(crate) reasoning: rho_sdk::ReasoningLevel,
pub(crate) service_tier: Option<rho_sdk::model::ServiceTier>,
pub(crate) compaction: CompactionConfig,
pub(crate) context_window: Option<u64>,
pub(crate) usage_purpose: &'static str,
pub(crate) usage_parent_session_id: Option<rho_sdk::SessionId>,
pub(crate) usage_recording: ProviderRequestUsageRecording,
pub(crate) hook_host_labels: rho_sdk::hooks::HookHostLabels,
pub(crate) hooks: Option<&'a crate::hooks::HookPipeline>,
pub(crate) diagnostics: RuntimeDiagnostics,
pub(crate) recall: Option<RecallStore>,
}
pub(crate) fn build_runtime<P>(options: RuntimeBuildOptions<'_, P>) -> Result<Rho, Error>
where
P: WorkspacePolicy + 'static,
{
build_runtime_with_max_steps(options, None)
}
pub(crate) fn build_runtime_with_max_steps<P>(
options: RuntimeBuildOptions<'_, P>,
max_steps: Option<std::num::NonZeroUsize>,
) -> Result<Rho, Error>
where
P: WorkspacePolicy + 'static,
{
let RuntimeBuildOptions {
provider,
tools,
workspace,
workspace_policy,
approval_session,
system_prompt,
reasoning,
service_tier,
compaction,
context_window,
usage_purpose,
usage_parent_session_id,
usage_recording,
hook_host_labels,
hooks,
diagnostics,
recall,
} = options;
let (compactor, policy) = build_compaction(CompactionSetup {
provider: Arc::clone(&provider),
tools,
reasoning,
compaction,
context_window,
usage_recording: usage_recording.clone(),
diagnostics,
recall,
});
let mut builder = Rho::builder()
.provider_shared(provider)
.system_prompt(system_prompt)
.workspace(workspace)
.workspace_policy(workspace_policy)
.reasoning_level(reasoning)
.max_steps(max_steps.unwrap_or_else(super::sdk_config::run_step_limit))
.max_parallel_tools(super::sdk_config::parallel_tool_limit())
.usage_purpose(usage_purpose)
.usage_recording(usage_recording)
.hook_host_labels(hook_host_labels)
.compactor(compactor);
if let Some(service_tier) = service_tier {
builder = builder.service_tier(service_tier);
}
if let Some(parent_session_id) = usage_parent_session_id {
builder = builder
.hook_delegation(rho_sdk::hooks::HookDelegation::new(
parent_session_id.clone(),
))
.usage_parent_session_id(parent_session_id);
}
if let Some(session) = approval_session {
builder = builder.approval_session(session);
}
if let Some(policy) = policy {
builder = builder.compaction_policy(policy);
}
for tool in tools {
builder = builder.tool_shared(tool.clone());
}
if let Some(hooks) = hooks {
builder = hooks.attach(builder);
}
builder.build()
}
pub(crate) struct CompactionSetup<'a> {
pub(crate) provider: Arc<dyn ModelProvider>,
pub(crate) tools: &'a [Arc<dyn rho_sdk::tool::Tool>],
pub(crate) reasoning: rho_sdk::ReasoningLevel,
pub(crate) compaction: CompactionConfig,
pub(crate) context_window: Option<u64>,
pub(crate) usage_recording: ProviderRequestUsageRecording,
pub(crate) diagnostics: RuntimeDiagnostics,
pub(crate) recall: Option<RecallStore>,
}
pub(crate) fn build_compaction(
setup: CompactionSetup<'_>,
) -> (ModelCompactor, Option<CompactionPolicy>) {
let CompactionSetup {
provider,
tools,
reasoning,
compaction,
context_window,
usage_recording,
diagnostics,
recall,
} = setup;
let policy = automatic_compaction_policy(&compaction, context_window);
let compactor = ModelCompactor {
provider,
usage_recording,
tool_specs: tools.iter().map(|tool| tool.spec()).collect(),
reasoning,
summarizer: compaction.summarizer.clone().map(Summarizer::new),
config: compaction,
context_window,
diagnostics,
recall,
};
(compactor, policy)
}
pub(crate) fn refresh_session_compaction(
session: &rho_sdk::Session,
setup: CompactionSetup<'_>,
) -> Result<(), Error> {
let (compactor, policy) = build_compaction(setup);
session.set_compaction(Some(Arc::new(compactor)), policy)
}
pub(crate) fn automatic_compaction_policy(
compaction: &CompactionConfig,
context_window: Option<u64>,
) -> Option<CompactionPolicy> {
context_window
.and_then(|window| compaction.threshold_tokens(window))
.and_then(NonZeroU64::new)
.map(CompactionPolicy::at_context_tokens)
}
pub(crate) fn configured_context_window(config: &Config) -> Option<u64> {
cached_model_metadata(&config.provider, &config.model)
.and_then(|metadata| metadata.display_context_window())
}