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 #[serde(skip_serializing_if = "Option::is_none")]
575 pub degraded_reason: Option<String>,
576 pub graph: GraphInspection,
577 pub repository_code_totals: CodeRepositoryTotals,
578 pub indexes: Vec<IndexStatus>,
579 pub index_cursors: Vec<IndexCursor>,
580 pub index_refresh: IndexRefreshDiagnostics,
581 pub file_index: crate::storage::FileIndexDiagnostics,
582 pub runtime: RuntimeStatus,
583}
584
585#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
587pub struct EmbeddingProviderProbeResponse {
588 pub metadata: ApiMetadata,
589 pub ok: bool,
590 pub provider: Option<String>,
591 pub model: String,
592 pub dimension: u32,
593 #[serde(skip_serializing_if = "Option::is_none")]
594 pub latency_ms: Option<u64>,
595 #[serde(skip_serializing_if = "Option::is_none")]
596 pub error_code: Option<String>,
597 #[serde(skip_serializing_if = "Option::is_none")]
598 pub error_message: Option<String>,
599 #[serde(skip_serializing_if = "Option::is_none")]
600 pub retryable: Option<bool>,
601}
602
603#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
605pub struct CodeRepositoryRegisterRequest {
606 pub root_path: String,
607 #[serde(default)]
608 pub alias: String,
609 #[serde(default)]
610 pub path_filters: Vec<String>,
611 #[serde(default)]
612 pub language_filters: Vec<String>,
613}
614
615#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
617pub struct CodeRepositoryRegisterResponse {
618 pub metadata: ApiMetadata,
619 pub registration: CodeRepositoryRegistration,
620 pub status: CodeRepositoryStatus,
621}
622
623#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
625pub struct CodeRepositoryIndexResponse {
626 pub metadata: ApiMetadata,
627 pub scope: CodeRepositoryScopeMetadata,
628 pub summary: CodeIndexSummary,
629 pub status: CodeRepositoryStatus,
630}
631
632#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
634pub struct CodeRepositoryIndexStartResponse {
635 pub metadata: ApiMetadata,
636 pub scope: CodeRepositoryScopeMetadata,
637 #[serde(skip_serializing_if = "Option::is_none")]
638 pub summary: Option<CodeIndexSummary>,
639 pub status: CodeRepositoryStatus,
640 #[serde(skip_serializing_if = "Option::is_none")]
641 pub task: Option<CodeIndexTaskRecord>,
642 #[serde(skip_serializing_if = "Option::is_none")]
643 pub checkpoint: Option<CodeIndexCheckpoint>,
644}
645
646#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
648pub struct CodeRepositoryScopePreviewResponse {
649 pub metadata: ApiMetadata,
650 pub scope: CodeRepositoryScopeMetadata,
651 pub preview: CodeRepositoryScopePreview,
652}
653
654#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
656pub struct CodeRepositoryScopeMetadata {
657 pub scope_id: String,
658 pub repository_id: String,
659 pub alias: String,
660 pub requested_ref: String,
661 pub resolved_commit_sha: String,
662 pub tree_hash: String,
663 pub path_filters: Vec<String>,
664 pub language_filters: Vec<String>,
665 pub index_versions: Vec<String>,
666 pub stale: bool,
667}
668
669impl CodeRepositoryScopeMetadata {
670 pub fn from_status(
672 status: &CodeRepositoryStatus,
673 selector: &CodeRepositorySelector,
674 requested_ref: impl Into<String>,
675 ) -> Self {
676 Self {
677 scope_id: status.last_indexed_scope_id.clone().unwrap_or_default(),
678 repository_id: status.repository_id.clone(),
679 alias: status.alias.clone(),
680 requested_ref: requested_ref.into(),
681 resolved_commit_sha: status.last_indexed_commit.clone().unwrap_or_default(),
682 tree_hash: status.tree_hash.clone().unwrap_or_default(),
683 path_filters: merged_filters(&status.path_filters, &selector.path_filters),
684 language_filters: merged_filters(&status.language_filters, &selector.language_filters),
685 index_versions: vec![format!(
686 "code:{}:{}",
687 status
688 .last_indexed_scope_id
689 .as_deref()
690 .unwrap_or("unscoped"),
691 status.tree_hash.as_deref().unwrap_or("unindexed")
692 )],
693 stale: status.stale,
694 }
695 }
696
697 pub fn from_index_task(task: &CodeIndexTaskRecord, requested_ref: impl Into<String>) -> Self {
699 Self {
700 scope_id: task.source_scope.clone(),
701 repository_id: task.repository_id.clone(),
702 alias: task.alias.clone(),
703 requested_ref: requested_ref.into(),
704 resolved_commit_sha: task.resolved_commit_sha.clone(),
705 tree_hash: task.tree_hash.clone(),
706 path_filters: task.path_filters.clone(),
707 language_filters: task.language_filters.clone(),
708 index_versions: vec![format!("code:{}:{}", task.source_scope, task.tree_hash)],
709 stale: true,
710 }
711 }
712}
713
714#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
716pub struct CodeRepositoryQueryResponse {
717 pub metadata: ApiMetadata,
718 pub scope: CodeRepositoryScopeMetadata,
719 pub request: CodeRetrievalRequest,
720 pub results: Vec<CodeRetrievalHit>,
721 #[serde(skip_serializing_if = "Option::is_none")]
722 pub degraded_reason: Option<String>,
723}
724
725#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
727pub struct CodeRepositoryFeatureFlagsResponse {
728 pub metadata: ApiMetadata,
729 pub scope: CodeRepositoryScopeMetadata,
730 pub request: CodeFeatureFlagRequest,
731 pub flags: Vec<CodeFeatureFlagGraph>,
732 #[serde(skip_serializing_if = "Option::is_none")]
733 pub degraded_reason: Option<String>,
734}
735
736#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
738pub struct CodeRepositoryImpactResponse {
739 pub metadata: ApiMetadata,
740 pub scope: CodeRepositoryScopeMetadata,
741 pub request: CodeImpactRequest,
742 pub path_groups: CodeImpactPathGroups,
743 pub results: Vec<CodeRetrievalHit>,
744}
745
746#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
748pub struct CodeRepositoryStatusResponse {
749 pub metadata: ApiMetadata,
750 pub status: CodeRepositoryStatus,
751 #[serde(skip_serializing_if = "Option::is_none")]
752 pub active_task: Option<CodeIndexTaskRecord>,
753 #[serde(skip_serializing_if = "Option::is_none")]
754 pub checkpoint: Option<CodeIndexCheckpoint>,
755 pub retention: CodeScopeRetentionSummary,
756}
757
758#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
760pub struct CodeRepositoryReportResponse {
761 pub metadata: ApiMetadata,
762 pub scope: CodeRepositoryScopeMetadata,
763 pub report: CodeRepositoryReport,
764}
765
766#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
768pub struct CodeRepositorySetCreateResponse {
769 pub metadata: ApiMetadata,
770 pub request: CodeRepositorySetCreateRequest,
771 pub repository_set: CodeRepositorySet,
772}
773
774#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
776pub struct CodeRepositorySetAddResponse {
777 pub metadata: ApiMetadata,
778 pub request: CodeRepositorySetAddMemberRequest,
779 pub member: CodeRepositorySetMember,
780 pub status: CodeRepositorySetStatus,
781}
782
783#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
785pub struct CodeRepositorySetRemoveResponse {
786 pub metadata: ApiMetadata,
787 pub request: CodeRepositorySetRemoveMemberRequest,
788 pub member: CodeRepositorySetMember,
789 pub status: CodeRepositorySetStatus,
790}
791
792#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
794pub struct CodeRepositorySetQueryResponse {
795 pub metadata: ApiMetadata,
796 pub request: CodeRepositorySetQueryRequest,
797 pub status: CodeRepositorySetStatus,
798 pub results: Vec<CodeRepositorySetQueryHit>,
799 pub truncated: bool,
800 #[serde(skip_serializing_if = "Option::is_none")]
801 pub degraded_reason: Option<String>,
802}
803
804#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
806pub struct CodeRepositorySetStatusResponse {
807 pub metadata: ApiMetadata,
808 pub status: CodeRepositorySetStatus,
809}
810
811#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
813pub struct CodeRepositorySetRefreshResponse {
814 pub metadata: ApiMetadata,
815 pub status: CodeRepositorySetStatus,
816 #[serde(skip_serializing_if = "Option::is_none")]
817 pub summary: Option<CodeRepositorySetRefreshSummary>,
818 #[serde(skip_serializing_if = "Option::is_none")]
819 pub task: Option<CodeRepositorySetRefreshTaskRecord>,
820}
821
822fn merged_filters(base: &[String], request: &[String]) -> Vec<String> {
823 let mut merged = Vec::new();
824 for value in base.iter().chain(request.iter()) {
825 if !merged.contains(value) {
826 merged.push(value.clone());
827 }
828 }
829
830 merged
831}