use serde::{Deserialize, Serialize};
use super::{
CodeQueryKind, CodeRepositorySelector, CodeRetrievalHit, CodeRetrievalLayer, DomainError,
FreshnessPolicy, RepositoryCodeRange, error::required_text,
};
pub const CODEGRAPH_CONTEXT_DEFAULT_LIMIT: usize = 8;
pub const CODEGRAPH_CONTEXT_MAX_LIMIT: usize = 20;
pub const CODEGRAPH_CONTEXT_MIN_BYTES: usize = 1024;
pub const CODEGRAPH_CONTEXT_DEFAULT_MAX_BYTES: usize = 65_536;
pub const CODEGRAPH_CONTEXT_MAX_BYTES: usize = 262_144;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CodeGraphContextRequest {
pub repository: CodeRepositorySelector,
pub query: String,
pub limit: usize,
pub freshness_policy: FreshnessPolicy,
pub max_context_bytes: usize,
#[serde(default = "default_include_code")]
pub include_code: bool,
#[serde(default)]
pub exclude_generated: bool,
}
impl CodeGraphContextRequest {
pub fn new(
repository: CodeRepositorySelector,
query: impl Into<String>,
limit: usize,
freshness_policy: FreshnessPolicy,
max_context_bytes: usize,
include_code: bool,
exclude_generated: bool,
) -> Result<Self, DomainError> {
let limit = match limit {
1..=CODEGRAPH_CONTEXT_MAX_LIMIT => limit,
0 => return Err(DomainError::invalid("limit", "must be greater than zero")),
_ => {
return Err(DomainError::invalid(
"limit",
"must be 20 or less for codegraph context",
));
}
};
let max_context_bytes = match max_context_bytes {
0..CODEGRAPH_CONTEXT_MIN_BYTES => {
return Err(DomainError::invalid(
"max_context_bytes",
"must be at least 1024 for codegraph context",
));
}
CODEGRAPH_CONTEXT_MIN_BYTES..=CODEGRAPH_CONTEXT_MAX_BYTES => max_context_bytes,
_ => {
return Err(DomainError::invalid(
"max_context_bytes",
"must be 262144 or less",
));
}
};
Ok(Self {
repository,
query: required_text("query", query)?,
limit,
freshness_policy,
max_context_bytes,
include_code,
exclude_generated,
})
}
}
fn default_include_code() -> bool {
true
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CodeGraphContextProvenance {
pub query_kind: CodeQueryKind,
pub retrieval_layers: Vec<CodeRetrievalLayer>,
pub score: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CodeGraphCodeExcerpt {
pub path: String,
pub language_id: String,
pub line_range: RepositoryCodeRange,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol_snapshot_id: Option<String>,
pub provenance: CodeGraphContextProvenance,
pub excerpt: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CodeGraphImpactHint {
pub path: String,
pub line_range: RepositoryCodeRange,
pub relationship: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol_snapshot_id: Option<String>,
pub retrieval_layers: Vec<CodeRetrievalLayer>,
pub score: f64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CodeGraphContextBudget {
pub limit: usize,
pub max_context_bytes: usize,
pub candidate_count: usize,
pub returned_count: usize,
pub context_bytes: usize,
pub elapsed_ms: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CodeGraphContextPack {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub business_context: Vec<crate::domain::BusinessTerm>,
pub entry_points: Vec<CodeRetrievalHit>,
pub related_symbols: Vec<CodeRetrievalHit>,
pub graph_paths: Vec<CodeRetrievalHit>,
pub impact_hints: Vec<CodeGraphImpactHint>,
pub code_excerpts: Vec<CodeGraphCodeExcerpt>,
}
#[cfg(test)]
mod mod_tests;