1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 domain::{
7 CodeFeatureFlagGraph, CodeFeatureFlagRequest, CodeImpactPathGroups, CodeImpactRequest,
8 CodeIndexCheckpoint, CodeIndexSummary, CodeIndexTaskQueueStatus, CodeIndexTaskRecord,
9 CodeRepositoryRegistration, CodeRepositoryRemovalSummary, CodeRepositoryReport,
10 CodeRepositoryScopePreview, CodeRepositorySelector, CodeRepositorySet,
11 CodeRepositorySetAddMemberRequest, CodeRepositorySetCreateRequest, CodeRepositorySetMember,
12 CodeRepositorySetQueryHit, CodeRepositorySetQueryRequest, CodeRepositorySetRefreshSummary,
13 CodeRepositorySetRefreshTaskRecord, CodeRepositorySetRemoveMemberRequest,
14 CodeRepositorySetStatus, CodeRepositoryStatus, CodeRepositoryTotals, CodeRetrievalHit,
15 CodeRetrievalRequest, CodeScopeRetentionSummary, CommitReceipt, ConfidenceScore,
16 EvidenceExtractionMetadata, EvidenceModality, EvidenceSpan, ExtractionDiagnostic,
17 FactStatus, FreshnessPolicy, FusionDiagnostics, GraphVersionRange, IndexKind, IndexStatus,
18 LayoutRegion, ProposalConflictRecord, ProposalRecord, ProposalState, RerankDiagnostics,
19 RetrievalBackendStatus, RetrievalBudgetUsed, RetrievalHit, RetrievalMode,
20 RetrievedContextPack, ServiceDefinitionPlan, ServiceManagerAction, ServiceOperatorStatus,
21 SoftwareBuildTarget, SoftwareComponent, SoftwareDependencyUsage, SoftwareDesignElement,
22 SoftwareFile, SoftwareGlobalRequest, SoftwareGlobalStatus, SoftwareIacResource,
23 SoftwareRelationship, SoftwareSdkUsage, SoftwareTopic, WorkerKind, WorkerStatus,
24 WorkerTaskRecord,
25 },
26 storage::{GraphInspection, IndexCursor, IndexRefreshDiagnostics},
27};
28
29use super::{
30 AgentProtocolStatus, ApiMetadata, CodeRepositoryFreshnessDiagnostics,
31 FileIndexFreshnessDiagnostics, RuntimeStatus,
32};
33
34pub const GRAPH_CANVAS_DEFAULT_LIMIT: usize = 250;
35pub const GRAPH_CANVAS_MAX_LIMIT: usize = 1000;
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
39#[serde(rename_all = "snake_case")]
40pub enum GraphCanvasKind {
41 Knowledge,
42 Code,
43 Mixed,
44}
45
46impl GraphCanvasKind {
47 pub fn parse(value: &str) -> Result<Self, String> {
49 match value {
50 "knowledge" => Ok(Self::Knowledge),
51 "code" => Ok(Self::Code),
52 "mixed" => Ok(Self::Mixed),
53 _ => Err(format!("unsupported graph canvas kind '{value}'")),
54 }
55 }
56
57 pub const fn as_str(self) -> &'static str {
59 match self {
60 Self::Knowledge => "knowledge",
61 Self::Code => "code",
62 Self::Mixed => "mixed",
63 }
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
69pub struct GraphCanvasRequest {
70 pub kind: GraphCanvasKind,
71 #[serde(skip_serializing_if = "Option::is_none")]
72 pub source_scope: Option<String>,
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub query: Option<String>,
75 pub limit: usize,
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
80pub struct GraphCanvasNode {
81 pub id: String,
82 pub kind: String,
83 pub label: String,
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub subtitle: Option<String>,
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub source_scope: Option<String>,
88 pub graph_version: u64,
89 pub weight: u32,
90 #[serde(skip_serializing_if = "Option::is_none")]
91 pub status: Option<String>,
92 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
93 pub details: BTreeMap<String, String>,
94}
95
96#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
98pub struct GraphCanvasEdge {
99 pub id: String,
100 pub kind: String,
101 pub source: String,
102 pub target: String,
103 pub label: String,
104 pub graph_version: u64,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub confidence_basis_points: Option<u16>,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub evidence_count: Option<usize>,
109 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
110 pub details: BTreeMap<String, String>,
111}
112
113#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
115pub struct GraphCanvasSummary {
116 pub kind: GraphCanvasKind,
117 pub node_count: usize,
118 pub edge_count: usize,
119 pub truncated: bool,
120 pub available_kinds: Vec<String>,
121}
122
123#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
125pub struct GraphCanvasResponse {
126 pub metadata: ApiMetadata,
127 pub nodes: Vec<GraphCanvasNode>,
128 pub edges: Vec<GraphCanvasEdge>,
129 pub summary: GraphCanvasSummary,
130}
131
132#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
134pub struct IngestEvidence {
135 #[serde(skip_serializing_if = "Option::is_none")]
136 pub id: Option<String>,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub source_path: Option<String>,
139 #[serde(skip_serializing_if = "Option::is_none")]
140 pub span: Option<EvidenceSpan>,
141 #[serde(skip_serializing_if = "Option::is_none")]
142 pub confidence: Option<ConfidenceScore>,
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub status: Option<FactStatus>,
145 pub content: String,
146 #[serde(default)]
147 pub entity_labels: Vec<String>,
148 #[serde(default, skip_serializing_if = "Option::is_none")]
149 pub extraction: Option<IngestEvidenceExtraction>,
150}
151
152#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
154pub struct IngestEvidenceExtraction {
155 pub modality: EvidenceModality,
156 #[serde(skip_serializing_if = "Option::is_none")]
157 pub source_uri: Option<String>,
158 #[serde(skip_serializing_if = "Option::is_none")]
159 pub source_hash: Option<String>,
160 #[serde(skip_serializing_if = "Option::is_none")]
161 pub media_hash: Option<String>,
162 #[serde(skip_serializing_if = "Option::is_none")]
163 pub extractor: Option<String>,
164 #[serde(skip_serializing_if = "Option::is_none")]
165 pub extractor_version: Option<String>,
166 #[serde(skip_serializing_if = "Option::is_none")]
167 pub observed_at: Option<String>,
168 #[serde(skip_serializing_if = "Option::is_none")]
169 pub parent_evidence_id: Option<String>,
170 #[serde(skip_serializing_if = "Option::is_none")]
171 pub layout_region: Option<LayoutRegion>,
172 #[serde(skip_serializing_if = "Option::is_none")]
173 pub embedding_model: Option<String>,
174 #[serde(skip_serializing_if = "Option::is_none")]
175 pub embedding_dimension: Option<u16>,
176 #[serde(skip_serializing_if = "Option::is_none")]
177 pub diagnostic: Option<ExtractionDiagnostic>,
178}
179
180impl IngestEvidenceExtraction {
181 pub fn into_domain_metadata(self) -> EvidenceExtractionMetadata {
183 EvidenceExtractionMetadata {
184 modality: self.modality,
185 source_uri: self.source_uri,
186 source_hash: self.source_hash,
187 media_hash: self.media_hash,
188 extractor: self.extractor,
189 extractor_version: self.extractor_version,
190 observed_at: self.observed_at,
191 parent_evidence_id: self.parent_evidence_id,
192 layout_region: self.layout_region,
193 embedding_model: self.embedding_model,
194 embedding_dimension: self.embedding_dimension,
195 diagnostic: self
196 .diagnostic
197 .unwrap_or_else(|| EvidenceExtractionMetadata::text_span().diagnostic),
198 }
199 }
200}
201
202#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
204pub struct IngestRelation {
205 pub id: String,
206 pub source_entity_label: String,
207 pub relation_type: String,
208 pub target_entity_label: String,
209 #[serde(default)]
210 pub evidence_ids: Vec<String>,
211 #[serde(skip_serializing_if = "Option::is_none")]
212 pub confidence: Option<ConfidenceScore>,
213 #[serde(skip_serializing_if = "Option::is_none")]
214 pub status: Option<FactStatus>,
215 #[serde(skip_serializing_if = "Option::is_none")]
216 pub version_range: Option<GraphVersionRange>,
217}
218
219#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
221pub struct IngestClaim {
222 pub id: String,
223 pub subject_entity_label: String,
224 pub predicate: String,
225 pub object: String,
226 #[serde(default)]
227 pub evidence_ids: Vec<String>,
228 #[serde(skip_serializing_if = "Option::is_none")]
229 pub confidence: Option<ConfidenceScore>,
230 #[serde(skip_serializing_if = "Option::is_none")]
231 pub status: Option<FactStatus>,
232 #[serde(skip_serializing_if = "Option::is_none")]
233 pub version_range: Option<GraphVersionRange>,
234}
235
236#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
238pub struct IngestEvent {
239 pub id: String,
240 pub event_type: String,
241 #[serde(default)]
242 pub entity_labels: Vec<String>,
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub occurred_at: Option<String>,
245 #[serde(default)]
246 pub evidence_ids: Vec<String>,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub confidence: Option<ConfidenceScore>,
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub status: Option<FactStatus>,
251 #[serde(skip_serializing_if = "Option::is_none")]
252 pub version_range: Option<GraphVersionRange>,
253}
254
255#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
257pub struct IngestRequest {
258 pub source_scope: String,
259 #[serde(default)]
260 pub evidence: Vec<IngestEvidence>,
261 #[serde(default)]
262 pub relations: Vec<IngestRelation>,
263 #[serde(default)]
264 pub claims: Vec<IngestClaim>,
265 #[serde(default)]
266 pub events: Vec<IngestEvent>,
267}
268
269#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
271pub struct IngestResponse {
272 pub metadata: ApiMetadata,
273 pub receipt: CommitReceipt,
274 pub indexes: Vec<IndexStatus>,
275 #[serde(skip_serializing_if = "Option::is_none")]
276 pub index_refresh_error: Option<String>,
277}
278
279#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
281pub struct MultimodalExtractionRequest {
282 pub source_scope: String,
283 pub parent_evidence_id: String,
284 pub derived_evidence: Vec<IngestEvidence>,
285}
286
287#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
289pub struct MultimodalExtractionResponse {
290 pub metadata: ApiMetadata,
291 pub parent_evidence_id: String,
292 pub derived_evidence_count: usize,
293 pub receipt: CommitReceipt,
294 pub indexes: Vec<IndexStatus>,
295 #[serde(skip_serializing_if = "Option::is_none")]
296 pub index_refresh_error: Option<String>,
297}
298
299#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
301pub struct HybridRetrievalRequest {
302 pub query: String,
303 #[serde(skip_serializing_if = "Option::is_none")]
304 pub source_scope: Option<String>,
305 pub limit: usize,
306 pub freshness: FreshnessPolicy,
307}
308
309impl HybridRetrievalRequest {
310 pub fn new(query: impl Into<String>) -> Self {
312 Self {
313 query: query.into(),
314 source_scope: None,
315 limit: 10,
316 freshness: FreshnessPolicy::default(),
317 }
318 }
319}
320
321#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
323pub struct HybridRetrievalResponse {
324 pub metadata: ApiMetadata,
325 pub context_pack: RetrievedContextPack,
326 pub retrieval_mode: RetrievalMode,
327 #[serde(skip_serializing_if = "Option::is_none")]
328 pub source_scope: Option<String>,
329 pub freshness: FreshnessPolicy,
330 pub results: Vec<RetrievalHit>,
331 pub fusion: FusionDiagnostics,
332 pub rerank: RerankDiagnostics,
333 #[serde(default, skip_serializing_if = "Vec::is_empty")]
334 pub backend_statuses: Vec<RetrievalBackendStatus>,
335 pub truncated: bool,
336 pub budget_used: RetrievalBudgetUsed,
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub degraded_reason: Option<String>,
339 pub indexes: Vec<IndexStatus>,
340 #[serde(default)]
341 pub index_cursors: Vec<IndexCursor>,
342 #[serde(default)]
343 pub index_refresh: IndexRefreshDiagnostics,
344}
345
346#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
348pub struct GraphInspectionRequest {
349 #[serde(skip_serializing_if = "Option::is_none")]
350 pub source_scope: Option<String>,
351}
352
353#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
355pub struct GraphInspectionResponse {
356 pub metadata: ApiMetadata,
357 pub graph: GraphInspection,
358 pub repository_code_totals: CodeRepositoryTotals,
359}
360
361#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
363pub struct IndexRefreshRequest {
364 #[serde(default)]
365 pub kinds: Vec<IndexKind>,
366}
367
368#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
370pub struct IndexRefreshResponse {
371 pub metadata: ApiMetadata,
372 pub indexes: Vec<IndexStatus>,
373 pub index_cursors: Vec<IndexCursor>,
374 pub diagnostics: IndexRefreshDiagnostics,
375}
376
377#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
379pub struct FileIndexRequest {
380 #[serde(skip_serializing_if = "Option::is_none")]
381 pub source_scope: Option<String>,
382 #[serde(default)]
383 pub roots: Vec<String>,
384}
385
386#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
388pub struct FileIndexResponse {
389 pub metadata: ApiMetadata,
390 pub summary: crate::storage::FileIndexScanSummary,
391}
392
393#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
395pub struct FileQueryRequest {
396 pub query: String,
397 #[serde(skip_serializing_if = "Option::is_none")]
398 pub source_scope: Option<String>,
399 #[serde(skip_serializing_if = "Option::is_none")]
400 pub root_id: Option<String>,
401 pub limit: usize,
402 #[serde(default)]
403 pub freshness_policy: FreshnessPolicy,
404}
405
406#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
408pub struct FileQueryResponse {
409 pub metadata: ApiMetadata,
410 pub query: String,
411 #[serde(skip_serializing_if = "Option::is_none")]
412 pub source_scope: Option<String>,
413 #[serde(skip_serializing_if = "Option::is_none")]
414 pub root_id: Option<String>,
415 #[serde(default = "FileIndexFreshnessDiagnostics::legacy_unknown")]
416 pub freshness: FileIndexFreshnessDiagnostics,
417 pub results: Vec<crate::storage::FileSearchHit>,
418 pub truncated: bool,
419 pub duration_ms: u64,
420 #[serde(skip_serializing_if = "Option::is_none")]
421 pub degraded_reason: Option<String>,
422}
423
424#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
426pub struct ServiceStatusResponse {
427 pub metadata: ApiMetadata,
428 pub service_name: String,
429 pub mode: String,
430 pub background_enabled: bool,
431 pub silent_updates_enabled: bool,
432 pub service_definition_path: String,
433 pub storage: StorageTopologyDiagnostics,
434 pub index_refresh: IndexRefreshDiagnostics,
435 pub file_index: crate::storage::FileIndexDiagnostics,
436 pub agent_protocols: AgentProtocolStatus,
437 pub operator: ServiceOperatorStatus,
438 pub workers: Vec<WorkerStatus>,
439 pub code_index_workers: CodeIndexWorkerStatus,
440 pub proposal_backlog: usize,
441 pub audit_sink: AuditSinkStatus,
442}
443
444#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
446pub struct StorageTopologyDiagnostics {
447 pub topology: String,
448 pub control_database_path: String,
449 #[serde(skip_serializing_if = "Option::is_none")]
450 pub repository_shards_dir: Option<String>,
451 pub shard_catalog_active: bool,
452 pub active_shard_count: usize,
453 pub staged_shard_count: usize,
454 pub missing_shard_count: usize,
455 pub runtime_state_paths: Vec<String>,
456 pub shards: Vec<StorageShardDiagnostics>,
457 #[serde(skip_serializing_if = "Option::is_none")]
458 pub degraded_reason: Option<String>,
459}
460
461#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
463pub struct StorageShardDiagnostics {
464 pub repository_id: String,
465 pub state: String,
466 pub shard_locator: String,
467 pub resolved_path: String,
468 pub source_scope_count: usize,
469 pub exists: bool,
470 pub updated_at_ms: u64,
471 #[serde(skip_serializing_if = "Option::is_none")]
472 pub degraded_reason: Option<String>,
473}
474
475#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
477pub struct StorageTopologyResponse {
478 pub metadata: ApiMetadata,
479 pub storage: StorageTopologyDiagnostics,
480}
481
482#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
484pub struct CodeIndexWorkerStatus {
485 pub configured_worker_count: usize,
486 pub active_worker_slots: usize,
487 pub queue_depth: usize,
488 pub queued_task_count: usize,
489 pub running_task_count: usize,
490 pub retrying_task_count: usize,
491 pub dead_letter_task_count: usize,
492 pub running_lease_count: usize,
493 #[serde(skip_serializing_if = "Option::is_none")]
494 pub last_error: Option<String>,
495}
496
497impl CodeIndexWorkerStatus {
498 pub fn from_queue(configured_worker_count: usize, queue: CodeIndexTaskQueueStatus) -> Self {
500 let queue_depth = queue
501 .queued_task_count
502 .saturating_add(queue.retrying_task_count);
503
504 Self {
505 configured_worker_count,
506 active_worker_slots: configured_worker_count.saturating_sub(queue.running_task_count),
507 queue_depth,
508 queued_task_count: queue.queued_task_count,
509 running_task_count: queue.running_task_count,
510 retrying_task_count: queue.retrying_task_count,
511 dead_letter_task_count: queue.dead_letter_task_count,
512 running_lease_count: queue.running_lease_count,
513 last_error: queue.last_error,
514 }
515 }
516}
517
518#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
520pub struct AuditSinkStatus {
521 pub durable: bool,
522 pub event_count: usize,
523 #[serde(skip_serializing_if = "Option::is_none")]
524 pub last_error: Option<String>,
525}
526
527#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
529pub struct WorkerStatusRequest {
530 #[serde(skip_serializing_if = "Option::is_none")]
531 pub kind: Option<WorkerKind>,
532}
533
534#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
536pub struct WorkerStatusResponse {
537 pub metadata: ApiMetadata,
538 pub workers: Vec<WorkerStatus>,
539}
540
541#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
543pub struct WorkerRunRequest {
544 #[serde(skip_serializing_if = "Option::is_none")]
545 pub kind: Option<WorkerKind>,
546}
547
548#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
550pub struct WorkerRunResponse {
551 pub metadata: ApiMetadata,
552 #[serde(skip_serializing_if = "Option::is_none")]
553 pub task: Option<WorkerTaskRecord>,
554 #[serde(default)]
555 pub proposals: Vec<ProposalRecord>,
556 pub workers: Vec<WorkerStatus>,
557 #[serde(skip_serializing_if = "Option::is_none")]
558 pub degraded_reason: Option<String>,
559}
560
561#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
563pub struct CodeIndexWorkerRunRequest {
564 #[serde(skip_serializing_if = "Option::is_none")]
565 pub task_id: Option<String>,
566}
567
568#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
570pub struct CodeIndexWorkerRunResponse {
571 pub metadata: ApiMetadata,
572 pub worker_kind: String,
573 pub claimed: bool,
574 #[serde(skip_serializing_if = "Option::is_none")]
575 pub task: Option<CodeIndexTaskRecord>,
576}
577
578#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
580pub struct ProposalListApiRequest {
581 #[serde(skip_serializing_if = "Option::is_none")]
582 pub state: Option<ProposalState>,
583 pub limit: usize,
584}
585
586#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
588pub struct ProposalListResponse {
589 pub metadata: ApiMetadata,
590 pub proposals: Vec<ProposalRecord>,
591}
592
593#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
595pub struct ProposalShowResponse {
596 pub metadata: ApiMetadata,
597 pub proposal: ProposalRecord,
598 pub conflicts: Vec<ProposalConflictRecord>,
599 pub payload: serde_json::Value,
600}
601
602#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
604pub struct ProposalDecisionApiRequest {
605 pub actor: String,
606 #[serde(skip_serializing_if = "Option::is_none")]
607 pub reason: Option<String>,
608}
609
610#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
612pub struct ProposalDecisionResponse {
613 pub metadata: ApiMetadata,
614 pub proposal: ProposalRecord,
615 #[serde(skip_serializing_if = "Option::is_none")]
616 pub receipt: Option<CommitReceipt>,
617 #[serde(skip_serializing_if = "Option::is_none")]
618 pub index_refresh_error: Option<String>,
619}
620
621#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
623pub struct AuditQueryApiRequest {
624 #[serde(skip_serializing_if = "Option::is_none")]
625 pub operation: Option<String>,
626 pub limit: usize,
627}
628
629#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
631pub struct AuditQueryResponse {
632 pub metadata: ApiMetadata,
633 pub events: Vec<crate::domain::AuditEventRecord>,
634}
635
636#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
638pub struct ServicePlanRequest {
639 pub action: ServiceManagerAction,
640}
641
642#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
644pub struct ServicePlanResponse {
645 pub metadata: ApiMetadata,
646 pub plan: ServiceDefinitionPlan,
647}
648
649#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
651pub struct ServiceDefinitionWriteResponse {
652 pub metadata: ApiMetadata,
653 pub plan: ServiceDefinitionPlan,
654 pub written: bool,
655}
656
657#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
659pub struct ServiceOperatorResponse {
660 pub metadata: ApiMetadata,
661 pub operator: ServiceOperatorStatus,
662}
663
664#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
666pub struct ServiceRecoveryReport {
667 pub metadata: ApiMetadata,
668 pub graph_version: u64,
669 pub stale_index_kinds: Vec<IndexKind>,
670 pub refreshed_index_kinds: Vec<IndexKind>,
671 pub index_lag_max: u64,
672 pub task_queue_depth: usize,
673 pub dead_letter_count: usize,
674 pub heartbeat_state: String,
675}
676
677#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
679pub struct HealthResponse {
680 pub metadata: ApiMetadata,
681 pub healthy: bool,
682 #[serde(skip_serializing_if = "Option::is_none")]
683 pub degraded_reason: Option<String>,
684 pub storage: StorageTopologyDiagnostics,
685 pub graph: GraphInspection,
686 pub repository_code_totals: CodeRepositoryTotals,
687 pub indexes: Vec<IndexStatus>,
688 pub index_cursors: Vec<IndexCursor>,
689 pub index_refresh: IndexRefreshDiagnostics,
690 pub file_index: crate::storage::FileIndexDiagnostics,
691 pub runtime: RuntimeStatus,
692}
693
694#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
696pub struct EmbeddingProviderProbeResponse {
697 pub metadata: ApiMetadata,
698 pub ok: bool,
699 pub provider: Option<String>,
700 pub model: String,
701 pub dimension: u32,
702 #[serde(skip_serializing_if = "Option::is_none")]
703 pub latency_ms: Option<u64>,
704 #[serde(skip_serializing_if = "Option::is_none")]
705 pub error_code: Option<String>,
706 #[serde(skip_serializing_if = "Option::is_none")]
707 pub error_message: Option<String>,
708 #[serde(skip_serializing_if = "Option::is_none")]
709 pub retryable: Option<bool>,
710}
711
712#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
714pub struct CodeRepositoryRegisterRequest {
715 pub root_path: String,
716 #[serde(default)]
717 pub alias: String,
718 #[serde(default)]
719 pub path_filters: Vec<String>,
720 #[serde(default)]
721 pub language_filters: Vec<String>,
722}
723
724#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
726pub struct CodeRepositoryRegisterResponse {
727 pub metadata: ApiMetadata,
728 pub registration: CodeRepositoryRegistration,
729 pub status: CodeRepositoryStatus,
730}
731
732#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
734pub struct CodeRepositoryRemoveResponse {
735 pub metadata: ApiMetadata,
736 pub removed_status: CodeRepositoryStatus,
737 pub summary: CodeRepositoryRemovalSummary,
738}
739
740#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
742pub struct CodeRepositoryIndexResponse {
743 pub metadata: ApiMetadata,
744 pub scope: CodeRepositoryScopeMetadata,
745 pub summary: CodeIndexSummary,
746 pub status: CodeRepositoryStatus,
747}
748
749#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
751pub struct CodeRepositoryIndexStartResponse {
752 pub metadata: ApiMetadata,
753 pub scope: CodeRepositoryScopeMetadata,
754 #[serde(skip_serializing_if = "Option::is_none")]
755 pub summary: Option<CodeIndexSummary>,
756 pub status: CodeRepositoryStatus,
757 #[serde(skip_serializing_if = "Option::is_none")]
758 pub task: Option<CodeIndexTaskRecord>,
759 #[serde(skip_serializing_if = "Option::is_none")]
760 pub checkpoint: Option<CodeIndexCheckpoint>,
761}
762
763#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
765pub struct CodeRepositoryIndexResetResponse {
766 pub metadata: ApiMetadata,
767 pub status: CodeRepositoryStatus,
768 pub reset_task_count: usize,
769 pub reset_tasks: Vec<CodeIndexTaskRecord>,
770 #[serde(skip_serializing_if = "Option::is_none")]
771 pub active_task: Option<CodeIndexTaskRecord>,
772 #[serde(skip_serializing_if = "Option::is_none")]
773 pub checkpoint: Option<CodeIndexCheckpoint>,
774 pub retention: CodeScopeRetentionSummary,
775}
776
777#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
779pub struct CodeRepositoryScopePreviewResponse {
780 pub metadata: ApiMetadata,
781 pub scope: CodeRepositoryScopeMetadata,
782 pub preview: CodeRepositoryScopePreview,
783}
784
785#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
787pub struct CodeRepositoryScopeMetadata {
788 pub scope_id: String,
789 pub repository_id: String,
790 pub alias: String,
791 pub requested_ref: String,
792 pub resolved_commit_sha: String,
793 pub tree_hash: String,
794 pub path_filters: Vec<String>,
795 pub language_filters: Vec<String>,
796 pub index_versions: Vec<String>,
797 pub stale: bool,
798}
799
800impl CodeRepositoryScopeMetadata {
801 pub fn from_status(
803 status: &CodeRepositoryStatus,
804 selector: &CodeRepositorySelector,
805 requested_ref: impl Into<String>,
806 ) -> Self {
807 Self {
808 scope_id: status.last_indexed_scope_id.clone().unwrap_or_default(),
809 repository_id: status.repository_id.clone(),
810 alias: status.alias.clone(),
811 requested_ref: requested_ref.into(),
812 resolved_commit_sha: status.last_indexed_commit.clone().unwrap_or_default(),
813 tree_hash: status.tree_hash.clone().unwrap_or_default(),
814 path_filters: merged_filters(&status.path_filters, &selector.path_filters),
815 language_filters: merged_filters(&status.language_filters, &selector.language_filters),
816 index_versions: vec![format!(
817 "code:{}:{}",
818 status
819 .last_indexed_scope_id
820 .as_deref()
821 .unwrap_or("unscoped"),
822 status.tree_hash.as_deref().unwrap_or("unindexed")
823 )],
824 stale: status.stale,
825 }
826 }
827
828 pub fn from_index_task(task: &CodeIndexTaskRecord, requested_ref: impl Into<String>) -> Self {
830 Self {
831 scope_id: task.source_scope.clone(),
832 repository_id: task.repository_id.clone(),
833 alias: task.alias.clone(),
834 requested_ref: requested_ref.into(),
835 resolved_commit_sha: task.resolved_commit_sha.clone(),
836 tree_hash: task.tree_hash.clone(),
837 path_filters: task.path_filters.clone(),
838 language_filters: task.language_filters.clone(),
839 index_versions: vec![format!("code:{}:{}", task.source_scope, task.tree_hash)],
840 stale: true,
841 }
842 }
843}
844
845#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
847pub struct CodeRepositoryQueryResponse {
848 pub metadata: ApiMetadata,
849 pub scope: CodeRepositoryScopeMetadata,
850 #[serde(default = "CodeRepositoryFreshnessDiagnostics::legacy_unknown")]
851 pub freshness: CodeRepositoryFreshnessDiagnostics,
852 pub request: CodeRetrievalRequest,
853 pub results: Vec<CodeRetrievalHit>,
854 #[serde(skip_serializing_if = "Option::is_none")]
855 pub degraded_reason: Option<String>,
856}
857
858#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
860pub struct CodeRepositoryFeatureFlagsResponse {
861 pub metadata: ApiMetadata,
862 pub scope: CodeRepositoryScopeMetadata,
863 #[serde(default = "CodeRepositoryFreshnessDiagnostics::legacy_unknown")]
864 pub freshness: CodeRepositoryFreshnessDiagnostics,
865 pub request: CodeFeatureFlagRequest,
866 pub flags: Vec<CodeFeatureFlagGraph>,
867 #[serde(skip_serializing_if = "Option::is_none")]
868 pub degraded_reason: Option<String>,
869}
870
871#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
873pub struct CodeRepositoryImpactResponse {
874 pub metadata: ApiMetadata,
875 pub scope: CodeRepositoryScopeMetadata,
876 pub request: CodeImpactRequest,
877 pub path_groups: CodeImpactPathGroups,
878 pub results: Vec<CodeRetrievalHit>,
879}
880
881#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
883pub struct CodeRepositoryStatusResponse {
884 pub metadata: ApiMetadata,
885 pub status: CodeRepositoryStatus,
886 #[serde(skip_serializing_if = "Option::is_none")]
887 pub active_task: Option<CodeIndexTaskRecord>,
888 #[serde(skip_serializing_if = "Option::is_none")]
889 pub checkpoint: Option<CodeIndexCheckpoint>,
890 pub retention: CodeScopeRetentionSummary,
891}
892
893#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
895pub struct CodeRepositoryReportResponse {
896 pub metadata: ApiMetadata,
897 pub scope: CodeRepositoryScopeMetadata,
898 pub report: CodeRepositoryReport,
899}
900
901#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
903pub struct SoftwareGlobalResponse {
904 pub metadata: ApiMetadata,
905 pub scope: CodeRepositoryScopeMetadata,
906 pub request: SoftwareGlobalRequest,
907 pub status: SoftwareGlobalStatus,
908 pub components: Vec<SoftwareComponent>,
909 pub dependency_usages: Vec<SoftwareDependencyUsage>,
910 pub sdk_usages: Vec<SoftwareSdkUsage>,
911 pub files: Vec<SoftwareFile>,
912 pub topics: Vec<SoftwareTopic>,
913 pub relationships: Vec<SoftwareRelationship>,
914 pub build_targets: Vec<SoftwareBuildTarget>,
915 pub iac_resources: Vec<SoftwareIacResource>,
916 pub design_elements: Vec<SoftwareDesignElement>,
917}
918
919#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
921pub struct CodeRepositorySetCreateResponse {
922 pub metadata: ApiMetadata,
923 pub request: CodeRepositorySetCreateRequest,
924 pub repository_set: CodeRepositorySet,
925}
926
927#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
929pub struct CodeRepositorySetAddResponse {
930 pub metadata: ApiMetadata,
931 pub request: CodeRepositorySetAddMemberRequest,
932 pub member: CodeRepositorySetMember,
933 pub status: CodeRepositorySetStatus,
934}
935
936#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
938pub struct CodeRepositorySetRemoveResponse {
939 pub metadata: ApiMetadata,
940 pub request: CodeRepositorySetRemoveMemberRequest,
941 pub member: CodeRepositorySetMember,
942 pub status: CodeRepositorySetStatus,
943}
944
945#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
947pub struct CodeRepositorySetQueryResponse {
948 pub metadata: ApiMetadata,
949 pub request: CodeRepositorySetQueryRequest,
950 pub status: CodeRepositorySetStatus,
951 pub results: Vec<CodeRepositorySetQueryHit>,
952 pub truncated: bool,
953 #[serde(skip_serializing_if = "Option::is_none")]
954 pub degraded_reason: Option<String>,
955}
956
957#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
959pub struct CodeRepositorySetStatusResponse {
960 pub metadata: ApiMetadata,
961 pub status: CodeRepositorySetStatus,
962}
963
964#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
966pub struct CodeRepositorySetRefreshResponse {
967 pub metadata: ApiMetadata,
968 pub status: CodeRepositorySetStatus,
969 #[serde(skip_serializing_if = "Option::is_none")]
970 pub summary: Option<CodeRepositorySetRefreshSummary>,
971 #[serde(skip_serializing_if = "Option::is_none")]
972 pub task: Option<CodeRepositorySetRefreshTaskRecord>,
973}
974
975fn merged_filters(base: &[String], request: &[String]) -> Vec<String> {
976 let mut merged = Vec::new();
977 for value in base.iter().chain(request.iter()) {
978 if !merged.contains(value) {
979 merged.push(value.clone());
980 }
981 }
982
983 merged
984}