remdb 0.3.242__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.

Potentially problematic release.


This version of remdb might be problematic. Click here for more details.

Files changed (235) hide show
  1. rem/__init__.py +129 -0
  2. rem/agentic/README.md +760 -0
  3. rem/agentic/__init__.py +54 -0
  4. rem/agentic/agents/README.md +155 -0
  5. rem/agentic/agents/__init__.py +38 -0
  6. rem/agentic/agents/agent_manager.py +311 -0
  7. rem/agentic/agents/sse_simulator.py +502 -0
  8. rem/agentic/context.py +425 -0
  9. rem/agentic/context_builder.py +360 -0
  10. rem/agentic/llm_provider_models.py +301 -0
  11. rem/agentic/mcp/__init__.py +0 -0
  12. rem/agentic/mcp/tool_wrapper.py +273 -0
  13. rem/agentic/otel/__init__.py +5 -0
  14. rem/agentic/otel/setup.py +240 -0
  15. rem/agentic/providers/phoenix.py +926 -0
  16. rem/agentic/providers/pydantic_ai.py +854 -0
  17. rem/agentic/query.py +117 -0
  18. rem/agentic/query_helper.py +89 -0
  19. rem/agentic/schema.py +737 -0
  20. rem/agentic/serialization.py +245 -0
  21. rem/agentic/tools/__init__.py +5 -0
  22. rem/agentic/tools/rem_tools.py +242 -0
  23. rem/api/README.md +657 -0
  24. rem/api/deps.py +253 -0
  25. rem/api/main.py +460 -0
  26. rem/api/mcp_router/prompts.py +182 -0
  27. rem/api/mcp_router/resources.py +820 -0
  28. rem/api/mcp_router/server.py +243 -0
  29. rem/api/mcp_router/tools.py +1605 -0
  30. rem/api/middleware/tracking.py +172 -0
  31. rem/api/routers/admin.py +520 -0
  32. rem/api/routers/auth.py +898 -0
  33. rem/api/routers/chat/__init__.py +5 -0
  34. rem/api/routers/chat/child_streaming.py +394 -0
  35. rem/api/routers/chat/completions.py +702 -0
  36. rem/api/routers/chat/json_utils.py +76 -0
  37. rem/api/routers/chat/models.py +202 -0
  38. rem/api/routers/chat/otel_utils.py +33 -0
  39. rem/api/routers/chat/sse_events.py +546 -0
  40. rem/api/routers/chat/streaming.py +950 -0
  41. rem/api/routers/chat/streaming_utils.py +327 -0
  42. rem/api/routers/common.py +18 -0
  43. rem/api/routers/dev.py +87 -0
  44. rem/api/routers/feedback.py +276 -0
  45. rem/api/routers/messages.py +620 -0
  46. rem/api/routers/models.py +86 -0
  47. rem/api/routers/query.py +362 -0
  48. rem/api/routers/shared_sessions.py +422 -0
  49. rem/auth/README.md +258 -0
  50. rem/auth/__init__.py +36 -0
  51. rem/auth/jwt.py +367 -0
  52. rem/auth/middleware.py +318 -0
  53. rem/auth/providers/__init__.py +16 -0
  54. rem/auth/providers/base.py +376 -0
  55. rem/auth/providers/email.py +215 -0
  56. rem/auth/providers/google.py +163 -0
  57. rem/auth/providers/microsoft.py +237 -0
  58. rem/cli/README.md +517 -0
  59. rem/cli/__init__.py +8 -0
  60. rem/cli/commands/README.md +299 -0
  61. rem/cli/commands/__init__.py +3 -0
  62. rem/cli/commands/ask.py +549 -0
  63. rem/cli/commands/cluster.py +1808 -0
  64. rem/cli/commands/configure.py +495 -0
  65. rem/cli/commands/db.py +828 -0
  66. rem/cli/commands/dreaming.py +324 -0
  67. rem/cli/commands/experiments.py +1698 -0
  68. rem/cli/commands/mcp.py +66 -0
  69. rem/cli/commands/process.py +388 -0
  70. rem/cli/commands/query.py +109 -0
  71. rem/cli/commands/scaffold.py +47 -0
  72. rem/cli/commands/schema.py +230 -0
  73. rem/cli/commands/serve.py +106 -0
  74. rem/cli/commands/session.py +453 -0
  75. rem/cli/dreaming.py +363 -0
  76. rem/cli/main.py +123 -0
  77. rem/config.py +244 -0
  78. rem/mcp_server.py +41 -0
  79. rem/models/core/__init__.py +49 -0
  80. rem/models/core/core_model.py +70 -0
  81. rem/models/core/engram.py +333 -0
  82. rem/models/core/experiment.py +672 -0
  83. rem/models/core/inline_edge.py +132 -0
  84. rem/models/core/rem_query.py +246 -0
  85. rem/models/entities/__init__.py +68 -0
  86. rem/models/entities/domain_resource.py +38 -0
  87. rem/models/entities/feedback.py +123 -0
  88. rem/models/entities/file.py +57 -0
  89. rem/models/entities/image_resource.py +88 -0
  90. rem/models/entities/message.py +64 -0
  91. rem/models/entities/moment.py +123 -0
  92. rem/models/entities/ontology.py +181 -0
  93. rem/models/entities/ontology_config.py +131 -0
  94. rem/models/entities/resource.py +95 -0
  95. rem/models/entities/schema.py +87 -0
  96. rem/models/entities/session.py +84 -0
  97. rem/models/entities/shared_session.py +180 -0
  98. rem/models/entities/subscriber.py +175 -0
  99. rem/models/entities/user.py +93 -0
  100. rem/py.typed +0 -0
  101. rem/registry.py +373 -0
  102. rem/schemas/README.md +507 -0
  103. rem/schemas/__init__.py +6 -0
  104. rem/schemas/agents/README.md +92 -0
  105. rem/schemas/agents/core/agent-builder.yaml +235 -0
  106. rem/schemas/agents/core/moment-builder.yaml +178 -0
  107. rem/schemas/agents/core/rem-query-agent.yaml +226 -0
  108. rem/schemas/agents/core/resource-affinity-assessor.yaml +99 -0
  109. rem/schemas/agents/core/simple-assistant.yaml +19 -0
  110. rem/schemas/agents/core/user-profile-builder.yaml +163 -0
  111. rem/schemas/agents/examples/contract-analyzer.yaml +317 -0
  112. rem/schemas/agents/examples/contract-extractor.yaml +134 -0
  113. rem/schemas/agents/examples/cv-parser.yaml +263 -0
  114. rem/schemas/agents/examples/hello-world.yaml +37 -0
  115. rem/schemas/agents/examples/query.yaml +54 -0
  116. rem/schemas/agents/examples/simple.yaml +21 -0
  117. rem/schemas/agents/examples/test.yaml +29 -0
  118. rem/schemas/agents/rem.yaml +132 -0
  119. rem/schemas/evaluators/hello-world/default.yaml +77 -0
  120. rem/schemas/evaluators/rem/faithfulness.yaml +219 -0
  121. rem/schemas/evaluators/rem/lookup-correctness.yaml +182 -0
  122. rem/schemas/evaluators/rem/retrieval-precision.yaml +199 -0
  123. rem/schemas/evaluators/rem/retrieval-recall.yaml +211 -0
  124. rem/schemas/evaluators/rem/search-correctness.yaml +192 -0
  125. rem/services/__init__.py +18 -0
  126. rem/services/audio/INTEGRATION.md +308 -0
  127. rem/services/audio/README.md +376 -0
  128. rem/services/audio/__init__.py +15 -0
  129. rem/services/audio/chunker.py +354 -0
  130. rem/services/audio/transcriber.py +259 -0
  131. rem/services/content/README.md +1269 -0
  132. rem/services/content/__init__.py +5 -0
  133. rem/services/content/providers.py +760 -0
  134. rem/services/content/service.py +762 -0
  135. rem/services/dreaming/README.md +230 -0
  136. rem/services/dreaming/__init__.py +53 -0
  137. rem/services/dreaming/affinity_service.py +322 -0
  138. rem/services/dreaming/moment_service.py +251 -0
  139. rem/services/dreaming/ontology_service.py +54 -0
  140. rem/services/dreaming/user_model_service.py +297 -0
  141. rem/services/dreaming/utils.py +39 -0
  142. rem/services/email/__init__.py +10 -0
  143. rem/services/email/service.py +522 -0
  144. rem/services/email/templates.py +360 -0
  145. rem/services/embeddings/__init__.py +11 -0
  146. rem/services/embeddings/api.py +127 -0
  147. rem/services/embeddings/worker.py +435 -0
  148. rem/services/fs/README.md +662 -0
  149. rem/services/fs/__init__.py +62 -0
  150. rem/services/fs/examples.py +206 -0
  151. rem/services/fs/examples_paths.py +204 -0
  152. rem/services/fs/git_provider.py +935 -0
  153. rem/services/fs/local_provider.py +760 -0
  154. rem/services/fs/parsing-hooks-examples.md +172 -0
  155. rem/services/fs/paths.py +276 -0
  156. rem/services/fs/provider.py +460 -0
  157. rem/services/fs/s3_provider.py +1042 -0
  158. rem/services/fs/service.py +186 -0
  159. rem/services/git/README.md +1075 -0
  160. rem/services/git/__init__.py +17 -0
  161. rem/services/git/service.py +469 -0
  162. rem/services/phoenix/EXPERIMENT_DESIGN.md +1146 -0
  163. rem/services/phoenix/README.md +453 -0
  164. rem/services/phoenix/__init__.py +46 -0
  165. rem/services/phoenix/client.py +960 -0
  166. rem/services/phoenix/config.py +88 -0
  167. rem/services/phoenix/prompt_labels.py +477 -0
  168. rem/services/postgres/README.md +757 -0
  169. rem/services/postgres/__init__.py +49 -0
  170. rem/services/postgres/diff_service.py +599 -0
  171. rem/services/postgres/migration_service.py +427 -0
  172. rem/services/postgres/programmable_diff_service.py +635 -0
  173. rem/services/postgres/pydantic_to_sqlalchemy.py +562 -0
  174. rem/services/postgres/register_type.py +353 -0
  175. rem/services/postgres/repository.py +481 -0
  176. rem/services/postgres/schema_generator.py +661 -0
  177. rem/services/postgres/service.py +802 -0
  178. rem/services/postgres/sql_builder.py +355 -0
  179. rem/services/rate_limit.py +113 -0
  180. rem/services/rem/README.md +318 -0
  181. rem/services/rem/__init__.py +23 -0
  182. rem/services/rem/exceptions.py +71 -0
  183. rem/services/rem/executor.py +293 -0
  184. rem/services/rem/parser.py +180 -0
  185. rem/services/rem/queries.py +196 -0
  186. rem/services/rem/query.py +371 -0
  187. rem/services/rem/service.py +608 -0
  188. rem/services/session/README.md +374 -0
  189. rem/services/session/__init__.py +13 -0
  190. rem/services/session/compression.py +488 -0
  191. rem/services/session/pydantic_messages.py +310 -0
  192. rem/services/session/reload.py +85 -0
  193. rem/services/user_service.py +130 -0
  194. rem/settings.py +1877 -0
  195. rem/sql/background_indexes.sql +52 -0
  196. rem/sql/migrations/001_install.sql +983 -0
  197. rem/sql/migrations/002_install_models.sql +3157 -0
  198. rem/sql/migrations/003_optional_extensions.sql +326 -0
  199. rem/sql/migrations/004_cache_system.sql +282 -0
  200. rem/sql/migrations/005_schema_update.sql +145 -0
  201. rem/sql/migrations/migrate_session_id_to_uuid.sql +45 -0
  202. rem/utils/AGENTIC_CHUNKING.md +597 -0
  203. rem/utils/README.md +628 -0
  204. rem/utils/__init__.py +61 -0
  205. rem/utils/agentic_chunking.py +622 -0
  206. rem/utils/batch_ops.py +343 -0
  207. rem/utils/chunking.py +108 -0
  208. rem/utils/clip_embeddings.py +276 -0
  209. rem/utils/constants.py +97 -0
  210. rem/utils/date_utils.py +228 -0
  211. rem/utils/dict_utils.py +98 -0
  212. rem/utils/embeddings.py +436 -0
  213. rem/utils/examples/embeddings_example.py +305 -0
  214. rem/utils/examples/sql_types_example.py +202 -0
  215. rem/utils/files.py +323 -0
  216. rem/utils/markdown.py +16 -0
  217. rem/utils/mime_types.py +158 -0
  218. rem/utils/model_helpers.py +492 -0
  219. rem/utils/schema_loader.py +649 -0
  220. rem/utils/sql_paths.py +146 -0
  221. rem/utils/sql_types.py +350 -0
  222. rem/utils/user_id.py +81 -0
  223. rem/utils/vision.py +325 -0
  224. rem/workers/README.md +506 -0
  225. rem/workers/__init__.py +7 -0
  226. rem/workers/db_listener.py +579 -0
  227. rem/workers/db_maintainer.py +74 -0
  228. rem/workers/dreaming.py +502 -0
  229. rem/workers/engram_processor.py +312 -0
  230. rem/workers/sqs_file_processor.py +193 -0
  231. rem/workers/unlogged_maintainer.py +463 -0
  232. remdb-0.3.242.dist-info/METADATA +1632 -0
  233. remdb-0.3.242.dist-info/RECORD +235 -0
  234. remdb-0.3.242.dist-info/WHEEL +4 -0
  235. remdb-0.3.242.dist-info/entry_points.txt +2 -0
rem/cli/dreaming.py ADDED
@@ -0,0 +1,363 @@
1
+ """
2
+ REM Dreaming CLI - Memory indexing and insight extraction.
3
+
4
+ Command-line interface for running dreaming workers to build the
5
+ REM knowledge graph through user model updates, moment construction,
6
+ and resource affinity operations.
7
+
8
+ Commands:
9
+ - user-model: Update user profiles from activity
10
+ - moments: Extract temporal narratives from resources
11
+ - affinity: Build semantic relationships between resources
12
+ - custom: Run custom extractors on user's resources/sessions
13
+ - full: Run complete dreaming workflow (all operations)
14
+
15
+ Usage Examples:
16
+ ```bash
17
+ # Update user model for specific user
18
+ rem-dreaming user-model --user-id=user-123
19
+
20
+ # Extract moments with custom lookback
21
+ rem-dreaming moments --user-id=user-123 --lookback-hours=48
22
+
23
+ # Build resource affinity (semantic mode, fast)
24
+ rem-dreaming affinity --user-id=user-123
25
+
26
+ # Build resource affinity (LLM mode, intelligent but expensive)
27
+ rem-dreaming affinity --user-id=user-123 --use-llm --limit=100
28
+
29
+ # Run custom extractor on user's data
30
+ rem-dreaming custom --user-id=user-123 --extractor cv-parser-v1
31
+ rem-dreaming custom --user-id=user-123 --extractor contract-analyzer-v1 --lookback-hours=168
32
+
33
+ # Run full workflow for user
34
+ rem-dreaming full --user-id=user-123
35
+
36
+ # Process all active users (daily cron)
37
+ rem-dreaming full --all-users
38
+
39
+ # Process with custom REM API endpoint
40
+ rem-dreaming full --user-id=user-123 --rem-api-url=http://localhost:8000
41
+ ```
42
+
43
+ Environment Variables:
44
+ - REM_API_URL: REM API endpoint (default: http://rem-api:8000)
45
+ - REM_EMBEDDING_PROVIDER: Embedding provider (default: text-embedding-3-small)
46
+ - REM_DEFAULT_MODEL: LLM model (default: gpt-4.1)
47
+ - REM_LOOKBACK_HOURS: Default lookback window (default: 24)
48
+ - OPENAI_API_KEY: OpenAI API key
49
+
50
+ Exit Codes:
51
+ - 0: Success
52
+ - 1: Validation error (missing required args)
53
+ - 2: Execution error (worker failed)
54
+ """
55
+
56
+ import asyncio
57
+ import os
58
+ import sys
59
+ from typing import Optional
60
+
61
+ import typer
62
+ from rich.console import Console
63
+ from rich.progress import Progress, SpinnerColumn, TextColumn
64
+
65
+ from rem.workers.dreaming import (
66
+ AffinityMode,
67
+ DreamingWorker,
68
+ TaskType,
69
+ )
70
+
71
+ app = typer.Typer(
72
+ name="rem-dreaming",
73
+ help="REM dreaming worker for memory indexing",
74
+ add_completion=False,
75
+ )
76
+ console = Console()
77
+
78
+
79
+ def get_worker() -> DreamingWorker:
80
+ """Create dreaming worker from environment."""
81
+ return DreamingWorker(
82
+ rem_api_url=os.getenv("REM_API_URL", "http://rem-api:8000"),
83
+ embedding_provider=os.getenv(
84
+ "REM_EMBEDDING_PROVIDER", "text-embedding-3-small"
85
+ ),
86
+ default_model=os.getenv("REM_DEFAULT_MODEL", "gpt-4.1"),
87
+ lookback_hours=int(os.getenv("REM_LOOKBACK_HOURS", "24")),
88
+ )
89
+
90
+
91
+ @app.command()
92
+ def user_model(
93
+ user_id: str = typer.Option(..., help="User ID to process"),
94
+ max_sessions: int = typer.Option(100, help="Max sessions to analyze"),
95
+ max_moments: int = typer.Option(20, help="Max moments to include"),
96
+ max_resources: int = typer.Option(20, help="Max resources to include"),
97
+ ):
98
+ """
99
+ Update user model from recent activity.
100
+
101
+ Reads recent sessions, moments, and resources to generate
102
+ a comprehensive user profile summary using LLM analysis.
103
+ """
104
+
105
+ async def run():
106
+ worker = get_worker()
107
+ try:
108
+ with Progress(
109
+ SpinnerColumn(),
110
+ TextColumn("[progress.description]{task.description}"),
111
+ console=console,
112
+ ) as progress:
113
+ task = progress.add_task(
114
+ f"Updating user model for {user_id}...", total=None
115
+ )
116
+
117
+ result = await worker.update_user_model(
118
+ user_id=user_id,
119
+ max_sessions=max_sessions,
120
+ max_moments=max_moments,
121
+ max_resources=max_resources,
122
+ )
123
+
124
+ progress.update(task, completed=True)
125
+ console.print(f"[green]✓[/green] User model updated")
126
+ console.print(result)
127
+ except Exception as e:
128
+ console.print(f"[red]✗[/red] Failed: {e}", style="red")
129
+ sys.exit(2)
130
+ finally:
131
+ await worker.close()
132
+
133
+ asyncio.run(run())
134
+
135
+
136
+ @app.command()
137
+ def moments(
138
+ user_id: str = typer.Option(..., help="User ID to process"),
139
+ lookback_hours: Optional[int] = typer.Option(
140
+ None, help="Hours to look back (default: from env)"
141
+ ),
142
+ limit: Optional[int] = typer.Option(None, help="Max resources to process"),
143
+ ):
144
+ """
145
+ Extract moments from resources.
146
+
147
+ Analyzes recent resources to identify temporal narratives
148
+ (meetings, coding sessions, conversations) and creates
149
+ Moment entities with temporal boundaries and metadata.
150
+ """
151
+
152
+ async def run():
153
+ worker = get_worker()
154
+ try:
155
+ with Progress(
156
+ SpinnerColumn(),
157
+ TextColumn("[progress.description]{task.description}"),
158
+ console=console,
159
+ ) as progress:
160
+ task = progress.add_task(
161
+ f"Constructing moments for {user_id}...", total=None
162
+ )
163
+
164
+ result = await worker.construct_moments(
165
+ user_id=user_id,
166
+ lookback_hours=lookback_hours,
167
+ limit=limit,
168
+ )
169
+
170
+ progress.update(task, completed=True)
171
+ console.print(f"[green]✓[/green] Moments constructed")
172
+ console.print(result)
173
+ except Exception as e:
174
+ console.print(f"[red]✗[/red] Failed: {e}", style="red")
175
+ sys.exit(2)
176
+ finally:
177
+ await worker.close()
178
+
179
+ asyncio.run(run())
180
+
181
+
182
+ @app.command()
183
+ def affinity(
184
+ user_id: str = typer.Option(..., help="User ID to process"),
185
+ use_llm: bool = typer.Option(
186
+ False, "--use-llm", help="Use LLM mode (expensive, use --limit)"
187
+ ),
188
+ lookback_hours: Optional[int] = typer.Option(
189
+ None, help="Hours to look back (default: from env)"
190
+ ),
191
+ limit: Optional[int] = typer.Option(
192
+ None, help="Max resources to process (REQUIRED for LLM mode)"
193
+ ),
194
+ ):
195
+ """
196
+ Build resource affinity graph.
197
+
198
+ Creates semantic relationships between resources using either
199
+ vector similarity (fast, default) or LLM analysis (intelligent but expensive).
200
+
201
+ Semantic Mode (default):
202
+ - Fast vector similarity search
203
+ - No LLM calls, just embedding cosine similarity
204
+ - Good for frequent updates
205
+
206
+ LLM Mode (--use-llm):
207
+ - Intelligent relationship assessment
208
+ - Expensive: ALWAYS use --limit to control costs
209
+ - Good for deep analysis (weekly or monthly)
210
+
211
+ Example:
212
+ # Semantic mode (fast, cheap)
213
+ rem-dreaming affinity --user-id=user-123
214
+
215
+ # LLM mode (intelligent, expensive)
216
+ rem-dreaming affinity --user-id=user-123 --use-llm --limit=100
217
+ """
218
+ if use_llm and not limit:
219
+ console.print(
220
+ "[red]Error:[/red] --limit is REQUIRED when using --use-llm to control costs",
221
+ style="red",
222
+ )
223
+ sys.exit(1)
224
+
225
+ async def run():
226
+ worker = get_worker()
227
+ try:
228
+ mode = AffinityMode.LLM if use_llm else AffinityMode.SEMANTIC
229
+ mode_str = "LLM" if use_llm else "semantic"
230
+
231
+ with Progress(
232
+ SpinnerColumn(),
233
+ TextColumn("[progress.description]{task.description}"),
234
+ console=console,
235
+ ) as progress:
236
+ task = progress.add_task(
237
+ f"Building {mode_str} affinity for {user_id}...", total=None
238
+ )
239
+
240
+ result = await worker.build_affinity(
241
+ user_id=user_id,
242
+ mode=mode,
243
+ lookback_hours=lookback_hours,
244
+ limit=limit,
245
+ )
246
+
247
+ progress.update(task, completed=True)
248
+ console.print(f"[green]✓[/green] Resource affinity built ({mode_str} mode)")
249
+ console.print(result)
250
+ except Exception as e:
251
+ console.print(f"[red]✗[/red] Failed: {e}", style="red")
252
+ sys.exit(2)
253
+ finally:
254
+ await worker.close()
255
+
256
+ asyncio.run(run())
257
+
258
+
259
+ @app.command()
260
+ def full(
261
+ user_id: Optional[str] = typer.Option(None, help="User ID (or --all-users)"),
262
+ all_users: bool = typer.Option(
263
+ False, "--all-users", help="Process all active users"
264
+ ),
265
+ use_llm_affinity: bool = typer.Option(
266
+ False, "--use-llm-affinity", help="Use LLM mode for affinity (expensive)"
267
+ ),
268
+ lookback_hours: Optional[int] = typer.Option(
269
+ None, help="Hours to look back (default: from env)"
270
+ ),
271
+ ):
272
+ """
273
+ Run complete dreaming workflow.
274
+
275
+ Executes all dreaming operations in sequence:
276
+ 1. Update user model
277
+ 2. Construct moments
278
+ 3. Build resource affinity
279
+
280
+ Recommended for daily cron execution.
281
+
282
+ Examples:
283
+ # Process single user
284
+ rem-dreaming full --user-id=user-123
285
+
286
+ # Process all active users (daily cron)
287
+ rem-dreaming full --all-users
288
+
289
+ # Use LLM affinity mode (expensive)
290
+ rem-dreaming full --user-id=user-123 --use-llm-affinity
291
+ """
292
+ if not user_id and not all_users:
293
+ console.print(
294
+ "[red]Error:[/red] Either --user-id or --all-users is required",
295
+ style="red",
296
+ )
297
+ sys.exit(1)
298
+
299
+ if user_id and all_users:
300
+ console.print(
301
+ "[red]Error:[/red] Cannot use both --user-id and --all-users",
302
+ style="red",
303
+ )
304
+ sys.exit(1)
305
+
306
+ async def run():
307
+ worker = get_worker()
308
+ try:
309
+ if all_users:
310
+ with Progress(
311
+ SpinnerColumn(),
312
+ TextColumn("[progress.description]{task.description}"),
313
+ console=console,
314
+ ) as progress:
315
+ task = progress.add_task("Processing all users...", total=None)
316
+
317
+ results = await worker.process_all_users(
318
+ task_type=TaskType.FULL,
319
+ use_llm_affinity=use_llm_affinity,
320
+ lookback_hours=lookback_hours,
321
+ )
322
+
323
+ progress.update(task, completed=True)
324
+ console.print(
325
+ f"[green]✓[/green] Processed {len(results)} users"
326
+ )
327
+ for result in results:
328
+ console.print(result)
329
+ else:
330
+ with Progress(
331
+ SpinnerColumn(),
332
+ TextColumn("[progress.description]{task.description}"),
333
+ console=console,
334
+ ) as progress:
335
+ task = progress.add_task(
336
+ f"Running full workflow for {user_id}...", total=None
337
+ )
338
+
339
+ result = await worker.process_full(
340
+ user_id=user_id,
341
+ use_llm_affinity=use_llm_affinity,
342
+ lookback_hours=lookback_hours,
343
+ )
344
+
345
+ progress.update(task, completed=True)
346
+ console.print(f"[green]✓[/green] Full workflow completed")
347
+ console.print(result)
348
+ except Exception as e:
349
+ console.print(f"[red]✗[/red] Failed: {e}", style="red")
350
+ sys.exit(2)
351
+ finally:
352
+ await worker.close()
353
+
354
+ asyncio.run(run())
355
+
356
+
357
+ def main():
358
+ """Entry point."""
359
+ app()
360
+
361
+
362
+ if __name__ == "__main__":
363
+ main()
rem/cli/main.py ADDED
@@ -0,0 +1,123 @@
1
+ """
2
+ REM CLI entry point.
3
+
4
+ Usage:
5
+ rem db schema generate --models src/rem/models/entities
6
+ rem db schema validate
7
+ rem db migrate up
8
+ rem dev run-server
9
+ """
10
+
11
+ import sys
12
+ from pathlib import Path
13
+
14
+ import click
15
+ from loguru import logger
16
+
17
+ # Import version from package
18
+ try:
19
+ from importlib.metadata import version
20
+ __version__ = version("remdb")
21
+ except Exception:
22
+ __version__ = "unknown"
23
+
24
+
25
+ def _configure_logger(level: str):
26
+ """Configure loguru with custom level icons."""
27
+ logger.remove()
28
+
29
+ # Configure level icons - only warnings and errors get visual indicators
30
+ logger.level("DEBUG", icon=" ")
31
+ logger.level("INFO", icon=" ")
32
+ logger.level("WARNING", icon="🟠")
33
+ logger.level("ERROR", icon="🔴")
34
+ logger.level("CRITICAL", icon="🔴")
35
+
36
+ logger.add(
37
+ sys.stderr,
38
+ level=level,
39
+ format="<green>{time:HH:mm:ss}</green> | {level.icon} <level>{level: <8}</level> | <level>{message}</level>",
40
+ )
41
+
42
+
43
+ @click.group()
44
+ @click.option("--verbose", "-v", is_flag=True, help="Enable verbose logging")
45
+ @click.version_option(version=__version__, prog_name="rem")
46
+ def cli(verbose: bool):
47
+ """REM - Resources Entities Moments system CLI."""
48
+ _configure_logger("DEBUG" if verbose else "INFO")
49
+
50
+
51
+ @cli.group()
52
+ def db():
53
+ """Database operations (schema, migrate, status, etc.)."""
54
+ pass
55
+
56
+
57
+ @db.group()
58
+ def schema():
59
+ """Database schema management commands."""
60
+ pass
61
+
62
+
63
+ @cli.group()
64
+ def dev():
65
+ """Development utilities."""
66
+ pass
67
+
68
+
69
+ @cli.group()
70
+ def process():
71
+ """File processing commands."""
72
+ pass
73
+
74
+
75
+ @cli.group()
76
+ def dreaming():
77
+ """Memory indexing and knowledge extraction."""
78
+ pass
79
+
80
+
81
+ @cli.group()
82
+ def cluster():
83
+ """Kubernetes cluster deployment and management."""
84
+ pass
85
+
86
+
87
+ # Register commands
88
+ from .commands.schema import register_commands as register_schema_commands
89
+ from .commands.db import register_commands as register_db_commands
90
+ from .commands.process import register_commands as register_process_commands
91
+ from .commands.ask import register_command as register_ask_command
92
+ from .commands.dreaming import register_commands as register_dreaming_commands
93
+ from .commands.experiments import experiments as experiments_group
94
+ from .commands.configure import register_command as register_configure_command
95
+ from .commands.serve import register_command as register_serve_command
96
+ from .commands.mcp import register_command as register_mcp_command
97
+ from .commands.scaffold import scaffold as scaffold_command
98
+ from .commands.cluster import register_commands as register_cluster_commands
99
+ from .commands.session import register_command as register_session_command
100
+ from .commands.query import register_command as register_query_command
101
+
102
+ register_schema_commands(schema)
103
+ register_db_commands(db)
104
+ register_process_commands(process)
105
+ register_dreaming_commands(dreaming)
106
+ register_cluster_commands(cluster)
107
+ register_ask_command(cli)
108
+ register_configure_command(cli)
109
+ register_serve_command(cli)
110
+ register_mcp_command(cli)
111
+ register_query_command(cli)
112
+ cli.add_command(experiments_group)
113
+ cli.add_command(scaffold_command)
114
+ register_session_command(cli)
115
+
116
+
117
+ def main():
118
+ """Main entry point for CLI."""
119
+ cli()
120
+
121
+
122
+ if __name__ == "__main__":
123
+ main()