Skip to main content

vtcode_core/core/agent/
request_plan.rs

1//! Harness request plan construction.
2//!
3//! Builds the LLM request plan with tool definitions, system prompt hashing,
4//! and cache key management for efficient prompt caching.
5
6use std::sync::Arc;
7
8use serde_json::Value;
9
10use crate::config::types::{ReasoningEffortLevel, VerbosityLevel};
11use crate::llm::provider::{LLMRequest, Message, ParallelToolConfig, ToolChoice, ToolDefinition};
12
13use super::harness_kernel::{hash_tool_definitions, stable_system_prefix_hash};
14
15/// A prepared LLM request with metadata for the harness loop.
16#[derive(Debug, Clone)]
17pub struct HarnessRequestPlan {
18    pub request: LLMRequest,
19    pub has_tools: bool,
20    pub stable_prefix_hash: u64,
21    pub tool_catalog_hash: Option<u64>,
22}
23
24/// Input parameters for building a harness request plan.
25#[derive(Debug, Clone)]
26pub struct HarnessRequestPlanInput {
27    /// Shared conversation history; `Arc` so plan construction is O(1) in
28    /// history size (no deep copy per turn).
29    pub messages: Arc<Vec<Message>>,
30    /// Shared system prompt via `Arc<str>` so the per-turn hot path is a
31    /// refcount bump, not a full string clone.
32    pub system_prompt: Arc<str>,
33    pub tools: Option<Arc<Vec<ToolDefinition>>>,
34    pub model: String,
35    pub max_tokens: Option<u32>,
36    pub temperature: Option<f32>,
37    /// Nucleus sampling mass (0.0-1.0); resolved from custom-provider profile
38    /// overrides when present.
39    pub top_p: Option<f32>,
40    /// Top-k token cutoff (>= 0).
41    pub top_k: Option<i32>,
42    /// Presence penalty (-2.0-2.0).
43    pub presence_penalty: Option<f32>,
44    /// Frequency penalty (-2.0-2.0).
45    pub frequency_penalty: Option<f32>,
46    pub stream: bool,
47    pub tool_choice: Option<ToolChoice>,
48    pub parallel_tool_config: Option<Box<ParallelToolConfig>>,
49    pub reasoning_effort: Option<ReasoningEffortLevel>,
50    pub verbosity: Option<VerbosityLevel>,
51    pub metadata: Option<Value>,
52    pub context_management: Option<Value>,
53    pub previous_response_id: Option<String>,
54    pub prompt_cache_key: Option<String>,
55    pub prompt_cache_profile: Option<crate::llm::provider::PromptCacheProfile>,
56    pub tool_catalog_hash: Option<u64>,
57    /// Precomputed stable prefix hash of `system_prompt`. When supplied (the
58    /// normal path, from the memoized prompt bundle) the per-turn
59    /// `build_harness_request_plan` skips re-hashing the full system prompt.
60    pub system_prompt_prefix_hash: Option<u64>,
61}
62
63/// Build a harness request plan from the given input parameters.
64pub fn build_harness_request_plan(input: HarnessRequestPlanInput) -> HarnessRequestPlan {
65    let tools = input.tools.filter(|tools| !tools.is_empty());
66    let stable_prefix_hash = input
67        .system_prompt_prefix_hash
68        .unwrap_or_else(|| stable_system_prefix_hash(&input.system_prompt));
69    let tool_catalog_hash = input
70        .tool_catalog_hash
71        .or_else(|| hash_tool_definitions(tools.as_deref().map(Vec::as_slice)));
72    let has_tools = tools.is_some();
73    let request = LLMRequest {
74        messages: input.messages,
75        system_prompt: Some(input.system_prompt),
76        tools,
77        model: input.model,
78        max_tokens: input.max_tokens,
79        temperature: input.temperature,
80        top_p: input.top_p,
81        top_k: input.top_k,
82        presence_penalty: input.presence_penalty,
83        frequency_penalty: input.frequency_penalty,
84        stream: input.stream,
85        tool_choice: input.tool_choice,
86        parallel_tool_config: input.parallel_tool_config,
87        reasoning_effort: input.reasoning_effort,
88        verbosity: input.verbosity,
89        metadata: input.metadata,
90        context_management: input.context_management,
91        previous_response_id: input.previous_response_id,
92        prompt_cache_key: input.prompt_cache_key,
93        prompt_cache_profile: input.prompt_cache_profile,
94        ..Default::default()
95    };
96
97    HarnessRequestPlan {
98        request,
99        has_tools,
100        stable_prefix_hash,
101        tool_catalog_hash,
102    }
103}