Coverage for src / lilbee / runtime / progress / types.py: 100%

79 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-05-15 20:55 +0000

1"""Event type enums and Pydantic models for the progress protocol.""" 

2 

3from enum import StrEnum 

4 

5from pydantic import BaseModel 

6 

7 

8class EventType(StrEnum): 

9 """Progress event types emitted during sync/ingest.""" 

10 

11 FILE_START = "file_start" 

12 FILE_DONE = "file_done" 

13 BATCH_PROGRESS = "batch_progress" 

14 DONE = "done" 

15 EMBED = "embed" 

16 EXTRACT = "extract" 

17 CRAWL_START = "crawl_start" 

18 CRAWL_PAGE = "crawl_page" 

19 CRAWL_DONE = "crawl_done" 

20 SETUP_START = "setup_start" 

21 SETUP_PROGRESS = "setup_progress" 

22 SETUP_DONE = "setup_done" 

23 

24 

25class SseEvent(StrEnum): 

26 """SSE event names used in the HTTP streaming protocol.""" 

27 

28 TOKEN = "token" # noqa: S105 -- SSE event name, not a credential 

29 REASONING = "reasoning" 

30 SOURCES = "sources" 

31 ERROR = "error" 

32 DONE = "done" 

33 PROGRESS = "progress" 

34 HEARTBEAT = "heartbeat" 

35 ALREADY_INGESTING = "already_ingesting" 

36 

37 

38class FileStartEvent(BaseModel): 

39 """Emitted when a file begins ingestion.""" 

40 

41 file: str 

42 total_files: int 

43 current_file: int 

44 

45 

46class FileDoneEvent(BaseModel): 

47 """Emitted when a file finishes ingestion (success or error).""" 

48 

49 file: str 

50 status: str 

51 chunks: int 

52 

53 

54class BatchStatus(StrEnum): 

55 """Status values for BatchProgressEvent.status.""" 

56 

57 INGESTED = "ingested" 

58 SKIPPED = "skipped" 

59 FAILED = "failed" 

60 RASTERIZING = "rasterizing" 

61 

62 

63class BatchProgressEvent(BaseModel): 

64 """Emitted after each file completes during batch ingestion.""" 

65 

66 file: str 

67 status: BatchStatus 

68 current: int 

69 total: int 

70 

71 

72class ExtractEvent(BaseModel): 

73 """Emitted with page-level extraction progress. 

74 

75 Vision PDF OCR fires one event per page (``page < total_pages``); 

76 plain (non-OCR) extraction fires once per file with 

77 ``page == total_pages`` so subscribers see "extracted N pages" 

78 before the embed phase ticks. 

79 """ 

80 

81 file: str 

82 page: int 

83 total_pages: int 

84 

85 

86class EmbedEvent(BaseModel): 

87 """Emitted per batch during embedding.""" 

88 

89 file: str 

90 chunk: int 

91 total_chunks: int 

92 

93 

94class CrawlStartEvent(BaseModel): 

95 """Emitted when a crawl operation begins.""" 

96 

97 url: str 

98 depth: int 

99 

100 

101# Sentinel used in CrawlPageEvent.total when the crawl's final page count is 

102# not yet known (BFS streaming, page N emitted before N+1 is discovered). 

103# Consumers (plugin, TUI, CLI) treat total <= 0 as indeterminate progress. 

104CRAWL_TOTAL_UNKNOWN = -1 

105 

106 

107class CrawlPageEvent(BaseModel): 

108 """Emitted per page during crawling.""" 

109 

110 url: str 

111 current: int 

112 total: int 

113 

114 

115class CrawlDoneEvent(BaseModel): 

116 """Emitted when a crawl operation completes.""" 

117 

118 pages_crawled: int 

119 files_written: int 

120 

121 

122class SyncDoneEvent(BaseModel): 

123 """Emitted when the sync operation completes.""" 

124 

125 added: int 

126 updated: int 

127 removed: int 

128 failed: int 

129 skipped: int = 0 

130 

131 

132class SetupStartEvent(BaseModel): 

133 """Emitted when a setup/bootstrap operation begins.""" 

134 

135 component: str 

136 size_estimate_bytes: int | None = None 

137 

138 

139class SetupProgressEvent(BaseModel): 

140 """Emitted periodically during a setup/bootstrap operation.""" 

141 

142 component: str 

143 downloaded_bytes: int 

144 total_bytes: int | None = None 

145 detail: str = "" 

146 

147 

148class SetupDoneEvent(BaseModel): 

149 """Emitted when a setup/bootstrap operation completes.""" 

150 

151 component: str 

152 success: bool 

153 error: str | None = None