gnosisllm-knowledge 0.2.0__py3-none-any.whl → 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. gnosisllm_knowledge/__init__.py +91 -39
  2. gnosisllm_knowledge/api/__init__.py +3 -2
  3. gnosisllm_knowledge/api/knowledge.py +502 -32
  4. gnosisllm_knowledge/api/memory.py +966 -0
  5. gnosisllm_knowledge/backends/__init__.py +14 -5
  6. gnosisllm_knowledge/backends/memory/indexer.py +27 -2
  7. gnosisllm_knowledge/backends/memory/searcher.py +111 -10
  8. gnosisllm_knowledge/backends/opensearch/agentic.py +355 -48
  9. gnosisllm_knowledge/backends/opensearch/config.py +49 -28
  10. gnosisllm_knowledge/backends/opensearch/indexer.py +49 -3
  11. gnosisllm_knowledge/backends/opensearch/mappings.py +14 -5
  12. gnosisllm_knowledge/backends/opensearch/memory/__init__.py +12 -0
  13. gnosisllm_knowledge/backends/opensearch/memory/client.py +1380 -0
  14. gnosisllm_knowledge/backends/opensearch/memory/config.py +127 -0
  15. gnosisllm_knowledge/backends/opensearch/memory/setup.py +322 -0
  16. gnosisllm_knowledge/backends/opensearch/queries.py +33 -33
  17. gnosisllm_knowledge/backends/opensearch/searcher.py +238 -0
  18. gnosisllm_knowledge/backends/opensearch/setup.py +308 -148
  19. gnosisllm_knowledge/cli/app.py +436 -31
  20. gnosisllm_knowledge/cli/commands/agentic.py +26 -9
  21. gnosisllm_knowledge/cli/commands/load.py +169 -19
  22. gnosisllm_knowledge/cli/commands/memory.py +733 -0
  23. gnosisllm_knowledge/cli/commands/search.py +9 -10
  24. gnosisllm_knowledge/cli/commands/setup.py +49 -23
  25. gnosisllm_knowledge/cli/display/service.py +43 -0
  26. gnosisllm_knowledge/cli/utils/config.py +62 -4
  27. gnosisllm_knowledge/core/domain/__init__.py +54 -0
  28. gnosisllm_knowledge/core/domain/discovery.py +166 -0
  29. gnosisllm_knowledge/core/domain/document.py +19 -19
  30. gnosisllm_knowledge/core/domain/memory.py +440 -0
  31. gnosisllm_knowledge/core/domain/result.py +11 -3
  32. gnosisllm_knowledge/core/domain/search.py +12 -25
  33. gnosisllm_knowledge/core/domain/source.py +11 -12
  34. gnosisllm_knowledge/core/events/__init__.py +8 -0
  35. gnosisllm_knowledge/core/events/types.py +198 -5
  36. gnosisllm_knowledge/core/exceptions.py +227 -0
  37. gnosisllm_knowledge/core/interfaces/__init__.py +17 -0
  38. gnosisllm_knowledge/core/interfaces/agentic.py +11 -3
  39. gnosisllm_knowledge/core/interfaces/indexer.py +10 -1
  40. gnosisllm_knowledge/core/interfaces/memory.py +524 -0
  41. gnosisllm_knowledge/core/interfaces/searcher.py +10 -1
  42. gnosisllm_knowledge/core/interfaces/streaming.py +133 -0
  43. gnosisllm_knowledge/core/streaming/__init__.py +36 -0
  44. gnosisllm_knowledge/core/streaming/pipeline.py +228 -0
  45. gnosisllm_knowledge/fetchers/__init__.py +8 -0
  46. gnosisllm_knowledge/fetchers/config.py +27 -0
  47. gnosisllm_knowledge/fetchers/neoreader.py +31 -3
  48. gnosisllm_knowledge/fetchers/neoreader_discovery.py +505 -0
  49. gnosisllm_knowledge/loaders/__init__.py +5 -1
  50. gnosisllm_knowledge/loaders/base.py +3 -4
  51. gnosisllm_knowledge/loaders/discovery.py +338 -0
  52. gnosisllm_knowledge/loaders/discovery_streaming.py +343 -0
  53. gnosisllm_knowledge/loaders/factory.py +46 -0
  54. gnosisllm_knowledge/loaders/sitemap.py +129 -1
  55. gnosisllm_knowledge/loaders/sitemap_streaming.py +258 -0
  56. gnosisllm_knowledge/services/indexing.py +100 -93
  57. gnosisllm_knowledge/services/search.py +84 -31
  58. gnosisllm_knowledge/services/streaming_pipeline.py +334 -0
  59. {gnosisllm_knowledge-0.2.0.dist-info → gnosisllm_knowledge-0.4.0.dist-info}/METADATA +73 -10
  60. gnosisllm_knowledge-0.4.0.dist-info/RECORD +81 -0
  61. gnosisllm_knowledge-0.2.0.dist-info/RECORD +0 -64
  62. {gnosisllm_knowledge-0.2.0.dist-info → gnosisllm_knowledge-0.4.0.dist-info}/WHEEL +0 -0
  63. {gnosisllm_knowledge-0.2.0.dist-info → gnosisllm_knowledge-0.4.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,524 @@
1
+ """Memory protocols - Interface Segregation Principle."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
6
+
7
+ if TYPE_CHECKING:
8
+ from datetime import datetime
9
+
10
+ from gnosisllm_knowledge.core.domain.memory import (
11
+ ContainerConfig,
12
+ ContainerInfo,
13
+ HistoryEntry,
14
+ MemoryEntry,
15
+ MemoryStats,
16
+ MemoryStrategy,
17
+ MemoryType,
18
+ Message,
19
+ Namespace,
20
+ RecallResult,
21
+ SessionInfo,
22
+ StoreRequest,
23
+ StoreResult,
24
+ )
25
+
26
+
27
+ @runtime_checkable
28
+ class IMemoryContainerManager(Protocol):
29
+ """Protocol for memory container management.
30
+
31
+ Responsible for CRUD operations on memory containers.
32
+ """
33
+
34
+ async def create_container(
35
+ self,
36
+ config: ContainerConfig,
37
+ **options: Any,
38
+ ) -> ContainerInfo:
39
+ """Create a new memory container.
40
+
41
+ Args:
42
+ config: Container configuration.
43
+ **options: Backend-specific options.
44
+
45
+ Returns:
46
+ Created container info.
47
+ """
48
+ ...
49
+
50
+ async def get_container(
51
+ self,
52
+ container_id: str,
53
+ **options: Any,
54
+ ) -> ContainerInfo | None:
55
+ """Get container by ID.
56
+
57
+ Args:
58
+ container_id: Container ID.
59
+ **options: Backend-specific options.
60
+
61
+ Returns:
62
+ Container info or None if not found.
63
+ """
64
+ ...
65
+
66
+ async def list_containers(
67
+ self,
68
+ limit: int = 100,
69
+ **options: Any,
70
+ ) -> list[ContainerInfo]:
71
+ """List all containers.
72
+
73
+ Args:
74
+ limit: Maximum number to return.
75
+ **options: Backend-specific options.
76
+
77
+ Returns:
78
+ List of container info.
79
+ """
80
+ ...
81
+
82
+ async def update_container(
83
+ self,
84
+ container_id: str,
85
+ config: ContainerConfig,
86
+ **options: Any,
87
+ ) -> ContainerInfo:
88
+ """Update container configuration.
89
+
90
+ Args:
91
+ container_id: Container ID.
92
+ config: Updated configuration.
93
+ **options: Backend-specific options.
94
+
95
+ Returns:
96
+ Updated container info.
97
+ """
98
+ ...
99
+
100
+ async def delete_container(
101
+ self,
102
+ container_id: str,
103
+ **options: Any,
104
+ ) -> bool:
105
+ """Delete a container.
106
+
107
+ Args:
108
+ container_id: Container ID.
109
+ **options: Backend-specific options.
110
+
111
+ Returns:
112
+ True if deleted.
113
+ """
114
+ ...
115
+
116
+
117
+ @runtime_checkable
118
+ class IMemoryStore(Protocol):
119
+ """Protocol for storing memories.
120
+
121
+ Responsible for adding memories to containers.
122
+ """
123
+
124
+ async def store(
125
+ self,
126
+ container_id: str,
127
+ request: StoreRequest,
128
+ **options: Any,
129
+ ) -> StoreResult:
130
+ """Store memory in container.
131
+
132
+ Args:
133
+ container_id: Target container ID.
134
+ request: Store request with messages/data.
135
+ **options: Backend-specific options.
136
+
137
+ Returns:
138
+ Store result with IDs and counts.
139
+ """
140
+ ...
141
+
142
+ async def get_working_memory(
143
+ self,
144
+ container_id: str,
145
+ session_id: str | None = None,
146
+ namespace: Namespace | None = None,
147
+ limit: int = 50,
148
+ offset: int = 0,
149
+ **options: Any,
150
+ ) -> list[Message]:
151
+ """Get working memory messages.
152
+
153
+ Args:
154
+ container_id: Container ID.
155
+ session_id: Optional session filter.
156
+ namespace: Optional namespace filter.
157
+ limit: Maximum messages.
158
+ offset: Skip count.
159
+ **options: Backend-specific options.
160
+
161
+ Returns:
162
+ List of messages.
163
+ """
164
+ ...
165
+
166
+ async def clear_working_memory(
167
+ self,
168
+ container_id: str,
169
+ session_id: str | None = None,
170
+ namespace: Namespace | None = None,
171
+ **options: Any,
172
+ ) -> int:
173
+ """Clear working memory.
174
+
175
+ Args:
176
+ container_id: Container ID.
177
+ session_id: Optional session filter.
178
+ namespace: Optional namespace filter.
179
+ **options: Backend-specific options.
180
+
181
+ Returns:
182
+ Number of messages deleted.
183
+ """
184
+ ...
185
+
186
+
187
+ @runtime_checkable
188
+ class IMemoryRetriever(Protocol):
189
+ """Protocol for retrieving/searching memories.
190
+
191
+ Responsible for semantic search over long-term memory.
192
+ """
193
+
194
+ async def recall(
195
+ self,
196
+ container_id: str,
197
+ query: str,
198
+ namespace: Namespace | None = None,
199
+ strategies: list[MemoryStrategy] | None = None,
200
+ min_score: float | None = None,
201
+ limit: int = 10,
202
+ after: datetime | None = None,
203
+ before: datetime | None = None,
204
+ **options: Any,
205
+ ) -> RecallResult:
206
+ """Semantic search over long-term memories.
207
+
208
+ Args:
209
+ container_id: Container ID.
210
+ query: Search query.
211
+ namespace: Optional namespace filter.
212
+ strategies: Filter by strategies.
213
+ min_score: Minimum similarity score.
214
+ limit: Maximum results.
215
+ after: Filter by created after.
216
+ before: Filter by created before.
217
+ **options: Backend-specific options.
218
+
219
+ Returns:
220
+ Recall result with memory entries.
221
+ """
222
+ ...
223
+
224
+ async def get_memory(
225
+ self,
226
+ container_id: str,
227
+ memory_id: str,
228
+ memory_type: MemoryType,
229
+ **options: Any,
230
+ ) -> MemoryEntry | None:
231
+ """Get specific memory by ID.
232
+
233
+ For sessions, use ISessionManager.get_session().
234
+ For history, use IHistoryRetriever.get_history_entry().
235
+
236
+ Args:
237
+ container_id: Container ID.
238
+ memory_id: Memory document ID.
239
+ memory_type: Memory type (WORKING or LONG_TERM).
240
+ **options: Backend-specific options.
241
+
242
+ Returns:
243
+ Memory entry or None.
244
+ """
245
+ ...
246
+
247
+ async def delete_memory(
248
+ self,
249
+ container_id: str,
250
+ memory_id: str,
251
+ memory_type: MemoryType,
252
+ **options: Any,
253
+ ) -> bool:
254
+ """Delete specific memory.
255
+
256
+ Args:
257
+ container_id: Container ID.
258
+ memory_id: Memory document ID.
259
+ memory_type: Memory type (WORKING or LONG_TERM).
260
+ **options: Backend-specific options.
261
+
262
+ Returns:
263
+ True if deleted.
264
+ """
265
+ ...
266
+
267
+ async def delete_memories(
268
+ self,
269
+ container_id: str,
270
+ session_id: str | None = None,
271
+ namespace: Namespace | None = None,
272
+ before: datetime | None = None,
273
+ **options: Any,
274
+ ) -> int:
275
+ """Delete memories by filter.
276
+
277
+ Args:
278
+ container_id: Container ID.
279
+ session_id: Filter by session.
280
+ namespace: Filter by namespace.
281
+ before: Delete before timestamp.
282
+ **options: Backend-specific options.
283
+
284
+ Returns:
285
+ Number deleted.
286
+ """
287
+ ...
288
+
289
+ async def update_memory(
290
+ self,
291
+ container_id: str,
292
+ memory_id: str,
293
+ memory_type: MemoryType,
294
+ *,
295
+ memory: str | None = None,
296
+ tags: dict[str, str] | None = None,
297
+ **options: Any,
298
+ ) -> MemoryEntry:
299
+ """Update a specific memory.
300
+
301
+ Note: History memory type does NOT support updates.
302
+
303
+ Args:
304
+ container_id: Container ID.
305
+ memory_id: Memory document ID.
306
+ memory_type: Memory type (working, long-term, sessions).
307
+ memory: Updated memory content (for long-term).
308
+ tags: Updated tags.
309
+ **options: Backend-specific options.
310
+
311
+ Returns:
312
+ Updated memory entry.
313
+ """
314
+ ...
315
+
316
+ async def delete_by_query(
317
+ self,
318
+ container_id: str,
319
+ memory_type: MemoryType,
320
+ query: dict[str, Any],
321
+ **options: Any,
322
+ ) -> int:
323
+ """Delete memories matching an OpenSearch Query DSL query.
324
+
325
+ Provides full flexibility for complex deletion criteria.
326
+
327
+ Args:
328
+ container_id: Container ID.
329
+ memory_type: Memory type to delete from.
330
+ query: OpenSearch Query DSL query.
331
+ **options: Backend-specific options.
332
+
333
+ Returns:
334
+ Number of documents deleted.
335
+ """
336
+ ...
337
+
338
+
339
+ @runtime_checkable
340
+ class IHistoryRetriever(Protocol):
341
+ """Protocol for retrieving memory history (audit trail). READ-ONLY.
342
+
343
+ History is READ-ONLY. Updates and deletes are NOT supported.
344
+ """
345
+
346
+ async def get_history_entry(
347
+ self,
348
+ container_id: str,
349
+ history_id: str,
350
+ **options: Any,
351
+ ) -> HistoryEntry | None:
352
+ """Get a specific history entry by ID.
353
+
354
+ Args:
355
+ container_id: Container ID.
356
+ history_id: History entry ID.
357
+ **options: Backend-specific options.
358
+
359
+ Returns:
360
+ History entry or None.
361
+ """
362
+ ...
363
+
364
+ async def list_history(
365
+ self,
366
+ container_id: str,
367
+ memory_id: str | None = None,
368
+ namespace: Namespace | None = None,
369
+ limit: int = 100,
370
+ **options: Any,
371
+ ) -> list[HistoryEntry]:
372
+ """List history entries.
373
+
374
+ Args:
375
+ container_id: Container ID.
376
+ memory_id: Filter by specific memory ID.
377
+ namespace: Filter by namespace.
378
+ limit: Maximum entries to return.
379
+ **options: Backend-specific options.
380
+
381
+ Returns:
382
+ List of history entries.
383
+ """
384
+ ...
385
+
386
+
387
+ @runtime_checkable
388
+ class ISessionManager(Protocol):
389
+ """Protocol for session management.
390
+
391
+ Responsible for session lifecycle operations.
392
+ """
393
+
394
+ async def create_session(
395
+ self,
396
+ container_id: str,
397
+ *,
398
+ session_id: str | None = None,
399
+ summary: str | None = None,
400
+ namespace: Namespace | None = None,
401
+ metadata: dict[str, Any] | None = None,
402
+ **options: Any,
403
+ ) -> SessionInfo:
404
+ """Create a new session.
405
+
406
+ Args:
407
+ container_id: Container ID.
408
+ session_id: Custom session ID (auto-generated if not provided).
409
+ summary: Session summary text.
410
+ namespace: Session namespace.
411
+ metadata: Custom metadata (stored as additional_info).
412
+ **options: Backend-specific options.
413
+
414
+ Returns:
415
+ Created session info.
416
+ """
417
+ ...
418
+
419
+ async def get_session(
420
+ self,
421
+ container_id: str,
422
+ session_id: str,
423
+ include_messages: bool = False,
424
+ message_limit: int = 50,
425
+ **options: Any,
426
+ ) -> SessionInfo | None:
427
+ """Get session by ID.
428
+
429
+ Args:
430
+ container_id: Container ID.
431
+ session_id: Session ID.
432
+ include_messages: Include session messages.
433
+ message_limit: Max messages to include.
434
+ **options: Backend-specific options.
435
+
436
+ Returns:
437
+ Session info or None.
438
+ """
439
+ ...
440
+
441
+ async def list_sessions(
442
+ self,
443
+ container_id: str,
444
+ namespace: Namespace | None = None,
445
+ limit: int = 100,
446
+ **options: Any,
447
+ ) -> list[SessionInfo]:
448
+ """List sessions.
449
+
450
+ Args:
451
+ container_id: Container ID.
452
+ namespace: Filter by namespace.
453
+ limit: Maximum to return.
454
+ **options: Backend-specific options.
455
+
456
+ Returns:
457
+ List of session info.
458
+ """
459
+ ...
460
+
461
+ async def update_session(
462
+ self,
463
+ container_id: str,
464
+ session_id: str,
465
+ *,
466
+ summary: str | None = None,
467
+ metadata: dict[str, Any] | None = None,
468
+ **options: Any,
469
+ ) -> SessionInfo:
470
+ """Update a session.
471
+
472
+ Use this to update session summary or metadata.
473
+ Note: There is no explicit "end session" API in OpenSearch.
474
+
475
+ Args:
476
+ container_id: Container ID.
477
+ session_id: Session ID.
478
+ summary: Updated summary text.
479
+ metadata: Updated metadata (additional_info).
480
+ **options: Backend-specific options.
481
+
482
+ Returns:
483
+ Updated session info.
484
+ """
485
+ ...
486
+
487
+ async def delete_session(
488
+ self,
489
+ container_id: str,
490
+ session_id: str,
491
+ **options: Any,
492
+ ) -> bool:
493
+ """Delete a session.
494
+
495
+ Args:
496
+ container_id: Container ID.
497
+ session_id: Session ID.
498
+ **options: Backend-specific options.
499
+
500
+ Returns:
501
+ True if deleted.
502
+ """
503
+ ...
504
+
505
+
506
+ @runtime_checkable
507
+ class IMemoryStats(Protocol):
508
+ """Protocol for memory statistics."""
509
+
510
+ async def get_stats(
511
+ self,
512
+ container_id: str,
513
+ **options: Any,
514
+ ) -> MemoryStats:
515
+ """Get container statistics.
516
+
517
+ Args:
518
+ container_id: Container ID.
519
+ **options: Backend-specific options.
520
+
521
+ Returns:
522
+ Memory statistics.
523
+ """
524
+ ...
@@ -1,4 +1,10 @@
1
- """Knowledge searcher protocol - Interface Segregation Principle."""
1
+ """Knowledge searcher protocol - Interface Segregation Principle.
2
+
3
+ Note:
4
+ This library is tenant-agnostic. Multi-tenancy is achieved through index
5
+ isolation (e.g., `knowledge-{account_id}`). Searcher implementations should
6
+ not include tenant filtering logic - callers should use tenant-specific indices.
7
+ """
2
8
 
3
9
  from __future__ import annotations
4
10
 
@@ -12,6 +18,9 @@ if TYPE_CHECKING:
12
18
  class IKnowledgeSearcher(Protocol):
13
19
  """Protocol for searching documents in a search backend.
14
20
 
21
+ This protocol is tenant-agnostic. Multi-tenancy is achieved through index
22
+ isolation by using tenant-specific index names.
23
+
15
24
  Knowledge searchers are responsible for:
16
25
  - Executing different search modes (semantic, keyword, hybrid)
17
26
  - Generating embeddings for queries
@@ -0,0 +1,133 @@
1
+ """Streaming interfaces for memory-efficient processing.
2
+
3
+ These protocols define contracts for streaming operations that process
4
+ data in bounded batches rather than loading everything into memory.
5
+
6
+ Note:
7
+ This library is tenant-agnostic. Multi-tenancy is achieved through index
8
+ isolation (e.g., `knowledge-{account_id}`). Streaming implementations should
9
+ not include tenant filtering logic - callers should use tenant-specific indices.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from collections.abc import AsyncIterator, Awaitable, Callable
15
+ from typing import TYPE_CHECKING, Any, Protocol
16
+
17
+ if TYPE_CHECKING:
18
+ from gnosisllm_knowledge.core.domain.document import Document
19
+ from gnosisllm_knowledge.core.domain.result import IndexResult
20
+
21
+
22
+ class IStreamingUrlDiscoverer(Protocol):
23
+ """Protocol for streaming URL discovery.
24
+
25
+ Implementations yield URLs as they are discovered rather than
26
+ collecting all URLs first. This enables processing to begin
27
+ immediately and keeps memory usage bounded.
28
+
29
+ Example:
30
+ ```python
31
+ discoverer: IStreamingUrlDiscoverer = StreamingSitemapDiscoverer()
32
+
33
+ async for url_batch in discoverer.discover_urls_streaming(
34
+ source="https://example.com/sitemap.xml",
35
+ batch_size=50,
36
+ ):
37
+ for url in url_batch:
38
+ await process(url)
39
+ ```
40
+ """
41
+
42
+ async def discover_urls_streaming(
43
+ self,
44
+ source: str,
45
+ batch_size: int = 100,
46
+ **options: Any,
47
+ ) -> AsyncIterator[list[str]]:
48
+ """Yield batches of discovered URLs.
49
+
50
+ Args:
51
+ source: The sitemap or source URL.
52
+ batch_size: Number of URLs per batch.
53
+ **options: Discoverer-specific options (max_urls, patterns, etc.)
54
+
55
+ Yields:
56
+ Batches of discovered URLs as they're found.
57
+ """
58
+ ...
59
+
60
+
61
+ class IStreamingLoader(Protocol):
62
+ """Protocol for streaming content loading.
63
+
64
+ Processes URLs in bounded batches with immediate indexing,
65
+ preventing memory accumulation.
66
+ """
67
+
68
+ async def load_streaming_with_indexing(
69
+ self,
70
+ source: str,
71
+ index_callback: Callable[[list[Document]], Awaitable[IndexResult]],
72
+ url_batch_size: int = 50,
73
+ doc_batch_size: int = 100,
74
+ **options: Any,
75
+ ) -> IndexResult:
76
+ """Load and index with streaming, calling callback for each batch.
77
+
78
+ This method:
79
+ 1. Discovers URLs in batches (not all at once)
80
+ 2. Fetches content for each URL batch
81
+ 3. Indexes documents immediately after fetching
82
+ 4. Moves to next batch only after indexing completes
83
+
84
+ Memory usage is bounded by:
85
+ - url_batch_size * avg_url_length (URL strings)
86
+ - doc_batch_size * avg_doc_size (document content)
87
+ - fetch_concurrency * avg_page_size (in-flight fetches)
88
+
89
+ Args:
90
+ source: Source URL.
91
+ index_callback: Called with each batch of documents to index.
92
+ url_batch_size: URLs to process per iteration.
93
+ doc_batch_size: Documents per index batch.
94
+ **options: Additional options.
95
+
96
+ Returns:
97
+ Aggregated index result.
98
+ """
99
+ ...
100
+
101
+
102
+ class IStreamingPipeline(Protocol):
103
+ """Protocol for streaming indexing pipelines.
104
+
105
+ This protocol is tenant-agnostic. Multi-tenancy is achieved through index
106
+ isolation by using tenant-specific index names.
107
+
108
+ Orchestrates the full streaming load -> index pipeline with
109
+ bounded memory guarantees.
110
+ """
111
+
112
+ async def execute(
113
+ self,
114
+ source: str,
115
+ index_name: str,
116
+ *,
117
+ collection_id: str | None = None,
118
+ source_id: str | None = None,
119
+ **options: Any,
120
+ ) -> IndexResult:
121
+ """Execute the streaming pipeline.
122
+
123
+ Args:
124
+ source: Sitemap URL.
125
+ index_name: Target OpenSearch index (use tenant-specific name).
126
+ collection_id: Collection within the index.
127
+ source_id: Source identifier.
128
+ **options: Additional loader options.
129
+
130
+ Returns:
131
+ Aggregated index result.
132
+ """
133
+ ...
@@ -0,0 +1,36 @@
1
+ """Streaming pipeline configuration and utilities.
2
+
3
+ This module provides infrastructure for memory-efficient streaming
4
+ pipelines with bounded queues and backpressure support.
5
+
6
+ Example:
7
+ ```python
8
+ from gnosisllm_knowledge.core.streaming import (
9
+ PipelineConfig,
10
+ BoundedQueue,
11
+ BatchCollector,
12
+ )
13
+
14
+ # Configure pipeline for large sitemap processing
15
+ config = PipelineConfig(
16
+ url_batch_size=50,
17
+ fetch_concurrency=10,
18
+ index_batch_size=100,
19
+ )
20
+
21
+ # Use bounded queue for backpressure
22
+ queue: BoundedQueue[str] = BoundedQueue(maxsize=100)
23
+ ```
24
+ """
25
+
26
+ from gnosisllm_knowledge.core.streaming.pipeline import (
27
+ BatchCollector,
28
+ BoundedQueue,
29
+ PipelineConfig,
30
+ )
31
+
32
+ __all__ = [
33
+ "BatchCollector",
34
+ "BoundedQueue",
35
+ "PipelineConfig",
36
+ ]