1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 domain::{
7 CodeFeatureFlagGraph, CodeFeatureFlagRequest, CodeImpactPathGroups, CodeImpactRequest,
8 CodeIndexCheckpoint, CodeIndexSummary, CodeIndexTaskRecord, CodeRepositoryRegistration,
9 CodeRepositoryReport, CodeRepositoryScopePreview, CodeRepositorySelector,
10 CodeRepositorySet, CodeRepositorySetAddMemberRequest, CodeRepositorySetCreateRequest,
11 CodeRepositorySetMember, CodeRepositorySetQueryHit, CodeRepositorySetQueryRequest,
12 CodeRepositorySetRefreshSummary, CodeRepositorySetRefreshTaskRecord,
13 CodeRepositorySetRemoveMemberRequest, CodeRepositorySetStatus, CodeRepositoryStatus,
14 CodeRepositoryTotals, CodeRetrievalHit, CodeRetrievalRequest, CodeScopeRetentionSummary,
15 CommitReceipt, ConfidenceScore, EvidenceExtractionMetadata, EvidenceModality, EvidenceSpan,
16 ExtractionDiagnostic, FactStatus, FreshnessPolicy, FusionDiagnostics, GraphVersionRange,
17 IndexKind, IndexStatus, LayoutRegion, ProposalConflictRecord, ProposalRecord,
18 ProposalState, RerankDiagnostics, RetrievalBackendStatus, RetrievalBudgetUsed,
19 RetrievalHit, RetrievalMode, RetrievedContextPack, ServiceDefinitionPlan,
20 ServiceManagerAction, ServiceOperatorStatus, WorkerKind, WorkerStatus, WorkerTaskRecord,
21 },
22 storage::{GraphInspection, IndexCursor, IndexRefreshDiagnostics},
23};
24
25use super::{AgentProtocolStatus, ApiMetadata, RuntimeStatus};
26
27pub const GRAPH_CANVAS_DEFAULT_LIMIT: usize = 250;
28pub const GRAPH_CANVAS_MAX_LIMIT: usize = 1000;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
32#[serde(rename_all = "snake_case")]
33pub enum GraphCanvasKind {
34 Knowledge,
35 Code,
36 Mixed,
37}
38
39impl GraphCanvasKind {
40 pub fn parse(value: &str) -> Result<Self, String> {
42 match value {
43 "knowledge" => Ok(Self::Knowledge),
44 "code" => Ok(Self::Code),
45 "mixed" => Ok(Self::Mixed),
46 _ => Err(format!("unsupported graph canvas kind '{value}'")),
47 }
48 }
49
50 pub const fn as_str(self) -> &'static str {
52 match self {
53 Self::Knowledge => "knowledge",
54 Self::Code => "code",
55 Self::Mixed => "mixed",
56 }
57 }
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62pub struct GraphCanvasRequest {
63 pub kind: GraphCanvasKind,
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub source_scope: Option<String>,
66 #[serde(skip_serializing_if = "Option::is_none")]
67 pub query: Option<String>,
68 pub limit: usize,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73pub struct GraphCanvasNode {
74 pub id: String,
75 pub kind: String,
76 pub label: String,
77 #[serde(skip_serializing_if = "Option::is_none")]
78 pub subtitle: Option<String>,
79 #[serde(skip_serializing_if = "Option::is_none")]
80 pub source_scope: Option<String>,
81 pub graph_version: u64,
82 pub weight: u32,
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub status: Option<String>,
85 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
86 pub details: BTreeMap<String, String>,
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
91pub struct GraphCanvasEdge {
92 pub id: String,
93 pub kind: String,
94 pub source: String,
95 pub target: String,
96 pub label: String,
97 pub graph_version: u64,
98 #[serde(skip_serializing_if = "Option::is_none")]
99 pub confidence_basis_points: Option<u16>,
100 #[serde(skip_serializing_if = "Option::is_none")]
101 pub evidence_count: Option<usize>,
102 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
103 pub details: BTreeMap<String, String>,
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
108pub struct GraphCanvasSummary {
109 pub kind: GraphCanvasKind,
110 pub node_count: usize,
111 pub edge_count: usize,
112 pub truncated: bool,
113 pub available_kinds: Vec<String>,
114}
115
116#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
118pub struct GraphCanvasResponse {
119 pub metadata: ApiMetadata,
120 pub nodes: Vec<GraphCanvasNode>,
121 pub edges: Vec<GraphCanvasEdge>,
122 pub summary: GraphCanvasSummary,
123}
124
125#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
127pub struct IngestEvidence {
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub id: Option<String>,
130 #[serde(skip_serializing_if = "Option::is_none")]
131 pub source_path: Option<String>,
132 #[serde(skip_serializing_if = "Option::is_none")]
133 pub span: Option<EvidenceSpan>,
134 #[serde(skip_serializing_if = "Option::is_none")]
135 pub confidence: Option<ConfidenceScore>,
136 #[serde(skip_serializing_if = "Option::is_none")]
137 pub status: Option<FactStatus>,
138 pub content: String,
139 #[serde(default)]
140 pub entity_labels: Vec<String>,
141 #[serde(default, skip_serializing_if = "Option::is_none")]
142 pub extraction: Option<IngestEvidenceExtraction>,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
147pub struct IngestEvidenceExtraction {
148 pub modality: EvidenceModality,
149 #[serde(skip_serializing_if = "Option::is_none")]
150 pub source_uri: Option<String>,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub source_hash: Option<String>,
153 #[serde(skip_serializing_if = "Option::is_none")]
154 pub media_hash: Option<String>,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub extractor: Option<String>,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 pub extractor_version: Option<String>,
159 #[serde(skip_serializing_if = "Option::is_none")]
160 pub observed_at: Option<String>,
161 #[serde(skip_serializing_if = "Option::is_none")]
162 pub parent_evidence_id: Option<String>,
163 #[serde(skip_serializing_if = "Option::is_none")]
164 pub layout_region: Option<LayoutRegion>,
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub embedding_model: Option<String>,
167 #[serde(skip_serializing_if = "Option::is_none")]
168 pub embedding_dimension: Option<u16>,
169 #[serde(skip_serializing_if = "Option::is_none")]
170 pub diagnostic: Option<ExtractionDiagnostic>,
171}
172
173impl IngestEvidenceExtraction {
174 pub fn into_domain_metadata(self) -> EvidenceExtractionMetadata {
176 EvidenceExtractionMetadata {
177 modality: self.modality,
178 source_uri: self.source_uri,
179 source_hash: self.source_hash,
180 media_hash: self.media_hash,
181 extractor: self.extractor,
182 extractor_version: self.extractor_version,
183 observed_at: self.observed_at,
184 parent_evidence_id: self.parent_evidence_id,
185 layout_region: self.layout_region,
186 embedding_model: self.embedding_model,
187 embedding_dimension: self.embedding_dimension,
188 diagnostic: self
189 .diagnostic
190 .unwrap_or_else(|| EvidenceExtractionMetadata::text_span().diagnostic),
191 }
192 }
193}
194
195#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
197pub struct IngestRelation {
198 pub id: String,
199 pub source_entity_label: String,
200 pub relation_type: String,
201 pub target_entity_label: String,
202 #[serde(default)]
203 pub evidence_ids: Vec<String>,
204 #[serde(skip_serializing_if = "Option::is_none")]
205 pub confidence: Option<ConfidenceScore>,
206 #[serde(skip_serializing_if = "Option::is_none")]
207 pub status: Option<FactStatus>,
208 #[serde(skip_serializing_if = "Option::is_none")]
209 pub version_range: Option<GraphVersionRange>,
210}
211
212#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
214pub struct IngestClaim {
215 pub id: String,
216 pub subject_entity_label: String,
217 pub predicate: String,
218 pub object: String,
219 #[serde(default)]
220 pub evidence_ids: Vec<String>,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 pub confidence: Option<ConfidenceScore>,
223 #[serde(skip_serializing_if = "Option::is_none")]
224 pub status: Option<FactStatus>,
225 #[serde(skip_serializing_if = "Option::is_none")]
226 pub version_range: Option<GraphVersionRange>,
227}
228
229#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
231pub struct IngestEvent {
232 pub id: String,
233 pub event_type: String,
234 #[serde(default)]
235 pub entity_labels: Vec<String>,
236 #[serde(skip_serializing_if = "Option::is_none")]
237 pub occurred_at: Option<String>,
238 #[serde(default)]
239 pub evidence_ids: Vec<String>,
240 #[serde(skip_serializing_if = "Option::is_none")]
241 pub confidence: Option<ConfidenceScore>,
242 #[serde(skip_serializing_if = "Option::is_none")]
243 pub status: Option<FactStatus>,
244 #[serde(skip_serializing_if = "Option::is_none")]
245 pub version_range: Option<GraphVersionRange>,
246}
247
248#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
250pub struct IngestRequest {
251 pub source_scope: String,
252 #[serde(default)]
253 pub evidence: Vec<IngestEvidence>,
254 #[serde(default)]
255 pub relations: Vec<IngestRelation>,
256 #[serde(default)]
257 pub claims: Vec<IngestClaim>,
258 #[serde(default)]
259 pub events: Vec<IngestEvent>,
260}
261
262#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
264pub struct IngestResponse {
265 pub metadata: ApiMetadata,
266 pub receipt: CommitReceipt,
267 pub indexes: Vec<IndexStatus>,
268 #[serde(skip_serializing_if = "Option::is_none")]
269 pub index_refresh_error: Option<String>,
270}
271
272#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
274pub struct MultimodalExtractionRequest {
275 pub source_scope: String,
276 pub parent_evidence_id: String,
277 pub derived_evidence: Vec<IngestEvidence>,
278}
279
280#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
282pub struct MultimodalExtractionResponse {
283 pub metadata: ApiMetadata,
284 pub parent_evidence_id: String,
285 pub derived_evidence_count: usize,
286 pub receipt: CommitReceipt,
287 pub indexes: Vec<IndexStatus>,
288 #[serde(skip_serializing_if = "Option::is_none")]
289 pub index_refresh_error: Option<String>,
290}
291
292#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
294pub struct HybridRetrievalRequest {
295 pub query: String,
296 #[serde(skip_serializing_if = "Option::is_none")]
297 pub source_scope: Option<String>,
298 pub limit: usize,
299 pub freshness: FreshnessPolicy,
300}
301
302impl HybridRetrievalRequest {
303 pub fn new(query: impl Into<String>) -> Self {
305 Self {
306 query: query.into(),
307 source_scope: None,
308 limit: 10,
309 freshness: FreshnessPolicy::default(),
310 }
311 }
312}
313
314#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
316pub struct HybridRetrievalResponse {
317 pub metadata: ApiMetadata,
318 pub context_pack: RetrievedContextPack,
319 pub retrieval_mode: RetrievalMode,
320 #[serde(skip_serializing_if = "Option::is_none")]
321 pub source_scope: Option<String>,
322 pub freshness: FreshnessPolicy,
323 pub results: Vec<RetrievalHit>,
324 pub fusion: FusionDiagnostics,
325 pub rerank: RerankDiagnostics,
326 #[serde(default, skip_serializing_if = "Vec::is_empty")]
327 pub backend_statuses: Vec<RetrievalBackendStatus>,
328 pub truncated: bool,
329 pub budget_used: RetrievalBudgetUsed,
330 #[serde(skip_serializing_if = "Option::is_none")]
331 pub degraded_reason: Option<String>,
332 pub indexes: Vec<IndexStatus>,
333}
334
335#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
337pub struct GraphInspectionRequest {
338 #[serde(skip_serializing_if = "Option::is_none")]
339 pub source_scope: Option<String>,
340}
341
342#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
344pub struct GraphInspectionResponse {
345 pub metadata: ApiMetadata,
346 pub graph: GraphInspection,
347 pub repository_code_totals: CodeRepositoryTotals,
348}
349
350#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
352pub struct IndexRefreshRequest {
353 #[serde(default)]
354 pub kinds: Vec<IndexKind>,
355}
356
357#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
359pub struct IndexRefreshResponse {
360 pub metadata: ApiMetadata,
361 pub indexes: Vec<IndexStatus>,
362 pub index_cursors: Vec<IndexCursor>,
363 pub diagnostics: IndexRefreshDiagnostics,
364}
365
366#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
368pub struct FileIndexRequest {
369 #[serde(skip_serializing_if = "Option::is_none")]
370 pub source_scope: Option<String>,
371 #[serde(default)]
372 pub roots: Vec<String>,
373}
374
375#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
377pub struct FileIndexResponse {
378 pub metadata: ApiMetadata,
379 pub summary: crate::storage::FileIndexScanSummary,
380}
381
382#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
384pub struct FileQueryRequest {
385 pub query: String,
386 #[serde(skip_serializing_if = "Option::is_none")]
387 pub source_scope: Option<String>,
388 #[serde(skip_serializing_if = "Option::is_none")]
389 pub root_id: Option<String>,
390 pub limit: usize,
391}
392
393#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
395pub struct FileQueryResponse {
396 pub metadata: ApiMetadata,
397 pub query: String,
398 #[serde(skip_serializing_if = "Option::is_none")]
399 pub source_scope: Option<String>,
400 #[serde(skip_serializing_if = "Option::is_none")]
401 pub root_id: Option<String>,
402 pub results: Vec<crate::storage::FileSearchHit>,
403 pub truncated: bool,
404 pub duration_ms: u64,
405 #[serde(skip_serializing_if = "Option::is_none")]
406 pub degraded_reason: Option<String>,
407}
408
409#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
411pub struct ServiceStatusResponse {
412 pub metadata: ApiMetadata,
413 pub service_name: String,
414 pub mode: String,
415 pub background_enabled: bool,
416 pub silent_updates_enabled: bool,
417 pub service_definition_path: String,
418 pub index_refresh: IndexRefreshDiagnostics,
419 pub file_index: crate::storage::FileIndexDiagnostics,
420 pub agent_protocols: AgentProtocolStatus,
421 pub operator: ServiceOperatorStatus,
422 pub workers: Vec<WorkerStatus>,
423 pub proposal_backlog: usize,
424 pub audit_sink: AuditSinkStatus,
425}
426
427#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
429pub struct AuditSinkStatus {
430 pub durable: bool,
431 pub event_count: usize,
432 #[serde(skip_serializing_if = "Option::is_none")]
433 pub last_error: Option<String>,
434}
435
436#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
438pub struct WorkerStatusRequest {
439 #[serde(skip_serializing_if = "Option::is_none")]
440 pub kind: Option<WorkerKind>,
441}
442
443#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
445pub struct WorkerStatusResponse {
446 pub metadata: ApiMetadata,
447 pub workers: Vec<WorkerStatus>,
448}
449
450#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
452pub struct WorkerRunRequest {
453 #[serde(skip_serializing_if = "Option::is_none")]
454 pub kind: Option<WorkerKind>,
455}
456
457#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
459pub struct WorkerRunResponse {
460 pub metadata: ApiMetadata,
461 #[serde(skip_serializing_if = "Option::is_none")]
462 pub task: Option<WorkerTaskRecord>,
463 #[serde(default)]
464 pub proposals: Vec<ProposalRecord>,
465 pub workers: Vec<WorkerStatus>,
466 #[serde(skip_serializing_if = "Option::is_none")]
467 pub degraded_reason: Option<String>,
468}
469
470#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
472pub struct ProposalListApiRequest {
473 #[serde(skip_serializing_if = "Option::is_none")]
474 pub state: Option<ProposalState>,
475 pub limit: usize,
476}
477
478#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
480pub struct ProposalListResponse {
481 pub metadata: ApiMetadata,
482 pub proposals: Vec<ProposalRecord>,
483}
484
485#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
487pub struct ProposalShowResponse {
488 pub metadata: ApiMetadata,
489 pub proposal: ProposalRecord,
490 pub conflicts: Vec<ProposalConflictRecord>,
491 pub payload: serde_json::Value,
492}
493
494#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
496pub struct ProposalDecisionApiRequest {
497 pub actor: String,
498 #[serde(skip_serializing_if = "Option::is_none")]
499 pub reason: Option<String>,
500}
501
502#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
504pub struct ProposalDecisionResponse {
505 pub metadata: ApiMetadata,
506 pub proposal: ProposalRecord,
507 #[serde(skip_serializing_if = "Option::is_none")]
508 pub receipt: Option<CommitReceipt>,
509 #[serde(skip_serializing_if = "Option::is_none")]
510 pub index_refresh_error: Option<String>,
511}
512
513#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
515pub struct AuditQueryApiRequest {
516 #[serde(skip_serializing_if = "Option::is_none")]
517 pub operation: Option<String>,
518 pub limit: usize,
519}
520
521#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
523pub struct AuditQueryResponse {
524 pub metadata: ApiMetadata,
525 pub events: Vec<crate::domain::AuditEventRecord>,
526}
527
528#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
530pub struct ServicePlanRequest {
531 pub action: ServiceManagerAction,
532}
533
534#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
536pub struct ServicePlanResponse {
537 pub metadata: ApiMetadata,
538 pub plan: ServiceDefinitionPlan,
539}
540
541#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
543pub struct ServiceDefinitionWriteResponse {
544 pub metadata: ApiMetadata,
545 pub plan: ServiceDefinitionPlan,
546 pub written: bool,
547}
548
549#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
551pub struct ServiceOperatorResponse {
552 pub metadata: ApiMetadata,
553 pub operator: ServiceOperatorStatus,
554}
555
556#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
558pub struct ServiceRecoveryReport {
559 pub metadata: ApiMetadata,
560 pub graph_version: u64,
561 pub stale_index_kinds: Vec<IndexKind>,
562 pub refreshed_index_kinds: Vec<IndexKind>,
563 pub index_lag_max: u64,
564 pub task_queue_depth: usize,
565 pub dead_letter_count: usize,
566 pub heartbeat_state: String,
567}
568
569#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
571pub struct HealthResponse {
572 pub metadata: ApiMetadata,
573 pub healthy: bool,
574 pub graph: GraphInspection,
575 pub repository_code_totals: CodeRepositoryTotals,
576 pub indexes: Vec<IndexStatus>,
577 pub index_cursors: Vec<IndexCursor>,
578 pub index_refresh: IndexRefreshDiagnostics,
579 pub file_index: crate::storage::FileIndexDiagnostics,
580 pub runtime: RuntimeStatus,
581}
582
583#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
585pub struct EmbeddingProviderProbeResponse {
586 pub metadata: ApiMetadata,
587 pub ok: bool,
588 pub provider: Option<String>,
589 pub model: String,
590 pub dimension: u32,
591 #[serde(skip_serializing_if = "Option::is_none")]
592 pub latency_ms: Option<u64>,
593 #[serde(skip_serializing_if = "Option::is_none")]
594 pub error_code: Option<String>,
595 #[serde(skip_serializing_if = "Option::is_none")]
596 pub error_message: Option<String>,
597 #[serde(skip_serializing_if = "Option::is_none")]
598 pub retryable: Option<bool>,
599}
600
601#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
603pub struct CodeRepositoryRegisterRequest {
604 pub root_path: String,
605 pub alias: String,
606 #[serde(default)]
607 pub path_filters: Vec<String>,
608 #[serde(default)]
609 pub language_filters: Vec<String>,
610}
611
612#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
614pub struct CodeRepositoryRegisterResponse {
615 pub metadata: ApiMetadata,
616 pub registration: CodeRepositoryRegistration,
617 pub status: CodeRepositoryStatus,
618}
619
620#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
622pub struct CodeRepositoryIndexResponse {
623 pub metadata: ApiMetadata,
624 pub scope: CodeRepositoryScopeMetadata,
625 pub summary: CodeIndexSummary,
626 pub status: CodeRepositoryStatus,
627}
628
629#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
631pub struct CodeRepositoryIndexStartResponse {
632 pub metadata: ApiMetadata,
633 pub scope: CodeRepositoryScopeMetadata,
634 #[serde(skip_serializing_if = "Option::is_none")]
635 pub summary: Option<CodeIndexSummary>,
636 pub status: CodeRepositoryStatus,
637 #[serde(skip_serializing_if = "Option::is_none")]
638 pub task: Option<CodeIndexTaskRecord>,
639 #[serde(skip_serializing_if = "Option::is_none")]
640 pub checkpoint: Option<CodeIndexCheckpoint>,
641}
642
643#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
645pub struct CodeRepositoryScopePreviewResponse {
646 pub metadata: ApiMetadata,
647 pub scope: CodeRepositoryScopeMetadata,
648 pub preview: CodeRepositoryScopePreview,
649}
650
651#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
653pub struct CodeRepositoryScopeMetadata {
654 pub scope_id: String,
655 pub repository_id: String,
656 pub alias: String,
657 pub requested_ref: String,
658 pub resolved_commit_sha: String,
659 pub tree_hash: String,
660 pub path_filters: Vec<String>,
661 pub language_filters: Vec<String>,
662 pub index_versions: Vec<String>,
663 pub stale: bool,
664}
665
666impl CodeRepositoryScopeMetadata {
667 pub fn from_status(
669 status: &CodeRepositoryStatus,
670 selector: &CodeRepositorySelector,
671 requested_ref: impl Into<String>,
672 ) -> Self {
673 Self {
674 scope_id: status.last_indexed_scope_id.clone().unwrap_or_default(),
675 repository_id: status.repository_id.clone(),
676 alias: status.alias.clone(),
677 requested_ref: requested_ref.into(),
678 resolved_commit_sha: status.last_indexed_commit.clone().unwrap_or_default(),
679 tree_hash: status.tree_hash.clone().unwrap_or_default(),
680 path_filters: merged_filters(&status.path_filters, &selector.path_filters),
681 language_filters: merged_filters(&status.language_filters, &selector.language_filters),
682 index_versions: vec![format!(
683 "code:{}:{}",
684 status
685 .last_indexed_scope_id
686 .as_deref()
687 .unwrap_or("unscoped"),
688 status.tree_hash.as_deref().unwrap_or("unindexed")
689 )],
690 stale: status.stale,
691 }
692 }
693
694 pub fn from_index_task(task: &CodeIndexTaskRecord, requested_ref: impl Into<String>) -> Self {
696 Self {
697 scope_id: task.source_scope.clone(),
698 repository_id: task.repository_id.clone(),
699 alias: task.alias.clone(),
700 requested_ref: requested_ref.into(),
701 resolved_commit_sha: task.resolved_commit_sha.clone(),
702 tree_hash: task.tree_hash.clone(),
703 path_filters: task.path_filters.clone(),
704 language_filters: task.language_filters.clone(),
705 index_versions: vec![format!("code:{}:{}", task.source_scope, task.tree_hash)],
706 stale: true,
707 }
708 }
709}
710
711#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
713pub struct CodeRepositoryQueryResponse {
714 pub metadata: ApiMetadata,
715 pub scope: CodeRepositoryScopeMetadata,
716 pub request: CodeRetrievalRequest,
717 pub results: Vec<CodeRetrievalHit>,
718 #[serde(skip_serializing_if = "Option::is_none")]
719 pub degraded_reason: Option<String>,
720}
721
722#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
724pub struct CodeRepositoryFeatureFlagsResponse {
725 pub metadata: ApiMetadata,
726 pub scope: CodeRepositoryScopeMetadata,
727 pub request: CodeFeatureFlagRequest,
728 pub flags: Vec<CodeFeatureFlagGraph>,
729 #[serde(skip_serializing_if = "Option::is_none")]
730 pub degraded_reason: Option<String>,
731}
732
733#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
735pub struct CodeRepositoryImpactResponse {
736 pub metadata: ApiMetadata,
737 pub scope: CodeRepositoryScopeMetadata,
738 pub request: CodeImpactRequest,
739 pub path_groups: CodeImpactPathGroups,
740 pub results: Vec<CodeRetrievalHit>,
741}
742
743#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
745pub struct CodeRepositoryStatusResponse {
746 pub metadata: ApiMetadata,
747 pub status: CodeRepositoryStatus,
748 #[serde(skip_serializing_if = "Option::is_none")]
749 pub active_task: Option<CodeIndexTaskRecord>,
750 #[serde(skip_serializing_if = "Option::is_none")]
751 pub checkpoint: Option<CodeIndexCheckpoint>,
752 pub retention: CodeScopeRetentionSummary,
753}
754
755#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
757pub struct CodeRepositoryReportResponse {
758 pub metadata: ApiMetadata,
759 pub scope: CodeRepositoryScopeMetadata,
760 pub report: CodeRepositoryReport,
761}
762
763#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
765pub struct CodeRepositorySetCreateResponse {
766 pub metadata: ApiMetadata,
767 pub request: CodeRepositorySetCreateRequest,
768 pub repository_set: CodeRepositorySet,
769}
770
771#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
773pub struct CodeRepositorySetAddResponse {
774 pub metadata: ApiMetadata,
775 pub request: CodeRepositorySetAddMemberRequest,
776 pub member: CodeRepositorySetMember,
777 pub status: CodeRepositorySetStatus,
778}
779
780#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
782pub struct CodeRepositorySetRemoveResponse {
783 pub metadata: ApiMetadata,
784 pub request: CodeRepositorySetRemoveMemberRequest,
785 pub member: CodeRepositorySetMember,
786 pub status: CodeRepositorySetStatus,
787}
788
789#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
791pub struct CodeRepositorySetQueryResponse {
792 pub metadata: ApiMetadata,
793 pub request: CodeRepositorySetQueryRequest,
794 pub status: CodeRepositorySetStatus,
795 pub results: Vec<CodeRepositorySetQueryHit>,
796 pub truncated: bool,
797 #[serde(skip_serializing_if = "Option::is_none")]
798 pub degraded_reason: Option<String>,
799}
800
801#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
803pub struct CodeRepositorySetStatusResponse {
804 pub metadata: ApiMetadata,
805 pub status: CodeRepositorySetStatus,
806}
807
808#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
810pub struct CodeRepositorySetRefreshResponse {
811 pub metadata: ApiMetadata,
812 pub status: CodeRepositorySetStatus,
813 #[serde(skip_serializing_if = "Option::is_none")]
814 pub summary: Option<CodeRepositorySetRefreshSummary>,
815 #[serde(skip_serializing_if = "Option::is_none")]
816 pub task: Option<CodeRepositorySetRefreshTaskRecord>,
817}
818
819fn merged_filters(base: &[String], request: &[String]) -> Vec<String> {
820 let mut merged = Vec::new();
821 for value in base.iter().chain(request.iter()) {
822 if !merged.contains(value) {
823 merged.push(value.clone());
824 }
825 }
826
827 merged
828}