remdb 0.3.14__py3-none-any.whl → 0.3.157__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 (112) hide show
  1. rem/agentic/README.md +76 -0
  2. rem/agentic/__init__.py +15 -0
  3. rem/agentic/agents/__init__.py +32 -2
  4. rem/agentic/agents/agent_manager.py +310 -0
  5. rem/agentic/agents/sse_simulator.py +502 -0
  6. rem/agentic/context.py +51 -27
  7. rem/agentic/context_builder.py +5 -3
  8. rem/agentic/llm_provider_models.py +301 -0
  9. rem/agentic/mcp/tool_wrapper.py +155 -18
  10. rem/agentic/otel/setup.py +93 -4
  11. rem/agentic/providers/phoenix.py +371 -108
  12. rem/agentic/providers/pydantic_ai.py +280 -57
  13. rem/agentic/schema.py +361 -21
  14. rem/agentic/tools/rem_tools.py +3 -3
  15. rem/api/README.md +215 -1
  16. rem/api/deps.py +255 -0
  17. rem/api/main.py +132 -40
  18. rem/api/mcp_router/resources.py +1 -1
  19. rem/api/mcp_router/server.py +28 -5
  20. rem/api/mcp_router/tools.py +555 -7
  21. rem/api/routers/admin.py +494 -0
  22. rem/api/routers/auth.py +278 -4
  23. rem/api/routers/chat/completions.py +402 -20
  24. rem/api/routers/chat/models.py +88 -10
  25. rem/api/routers/chat/otel_utils.py +33 -0
  26. rem/api/routers/chat/sse_events.py +542 -0
  27. rem/api/routers/chat/streaming.py +697 -45
  28. rem/api/routers/dev.py +81 -0
  29. rem/api/routers/feedback.py +268 -0
  30. rem/api/routers/messages.py +473 -0
  31. rem/api/routers/models.py +78 -0
  32. rem/api/routers/query.py +360 -0
  33. rem/api/routers/shared_sessions.py +406 -0
  34. rem/auth/__init__.py +13 -3
  35. rem/auth/middleware.py +186 -22
  36. rem/auth/providers/__init__.py +4 -1
  37. rem/auth/providers/email.py +215 -0
  38. rem/cli/commands/README.md +237 -64
  39. rem/cli/commands/cluster.py +1808 -0
  40. rem/cli/commands/configure.py +4 -7
  41. rem/cli/commands/db.py +386 -143
  42. rem/cli/commands/experiments.py +468 -76
  43. rem/cli/commands/process.py +14 -8
  44. rem/cli/commands/schema.py +97 -50
  45. rem/cli/commands/session.py +336 -0
  46. rem/cli/dreaming.py +2 -2
  47. rem/cli/main.py +29 -6
  48. rem/config.py +10 -3
  49. rem/models/core/core_model.py +7 -1
  50. rem/models/core/experiment.py +58 -14
  51. rem/models/core/rem_query.py +5 -2
  52. rem/models/entities/__init__.py +25 -0
  53. rem/models/entities/domain_resource.py +38 -0
  54. rem/models/entities/feedback.py +123 -0
  55. rem/models/entities/message.py +30 -1
  56. rem/models/entities/ontology.py +1 -1
  57. rem/models/entities/ontology_config.py +1 -1
  58. rem/models/entities/session.py +83 -0
  59. rem/models/entities/shared_session.py +180 -0
  60. rem/models/entities/subscriber.py +175 -0
  61. rem/models/entities/user.py +1 -0
  62. rem/registry.py +10 -4
  63. rem/schemas/agents/core/agent-builder.yaml +134 -0
  64. rem/schemas/agents/examples/contract-analyzer.yaml +1 -1
  65. rem/schemas/agents/examples/contract-extractor.yaml +1 -1
  66. rem/schemas/agents/examples/cv-parser.yaml +1 -1
  67. rem/schemas/agents/rem.yaml +7 -3
  68. rem/services/__init__.py +3 -1
  69. rem/services/content/service.py +92 -19
  70. rem/services/email/__init__.py +10 -0
  71. rem/services/email/service.py +459 -0
  72. rem/services/email/templates.py +360 -0
  73. rem/services/embeddings/api.py +4 -4
  74. rem/services/embeddings/worker.py +16 -16
  75. rem/services/phoenix/client.py +154 -14
  76. rem/services/postgres/README.md +197 -15
  77. rem/services/postgres/__init__.py +2 -1
  78. rem/services/postgres/diff_service.py +547 -0
  79. rem/services/postgres/pydantic_to_sqlalchemy.py +470 -140
  80. rem/services/postgres/repository.py +132 -0
  81. rem/services/postgres/schema_generator.py +205 -4
  82. rem/services/postgres/service.py +6 -6
  83. rem/services/rem/parser.py +44 -9
  84. rem/services/rem/service.py +36 -2
  85. rem/services/session/compression.py +137 -51
  86. rem/services/session/reload.py +15 -8
  87. rem/settings.py +515 -27
  88. rem/sql/background_indexes.sql +21 -16
  89. rem/sql/migrations/001_install.sql +387 -54
  90. rem/sql/migrations/002_install_models.sql +2304 -377
  91. rem/sql/migrations/003_optional_extensions.sql +326 -0
  92. rem/sql/migrations/004_cache_system.sql +548 -0
  93. rem/sql/migrations/005_schema_update.sql +145 -0
  94. rem/utils/README.md +45 -0
  95. rem/utils/__init__.py +18 -0
  96. rem/utils/date_utils.py +2 -2
  97. rem/utils/files.py +157 -1
  98. rem/utils/model_helpers.py +156 -1
  99. rem/utils/schema_loader.py +220 -22
  100. rem/utils/sql_paths.py +146 -0
  101. rem/utils/sql_types.py +3 -1
  102. rem/utils/vision.py +1 -1
  103. rem/workers/__init__.py +3 -1
  104. rem/workers/db_listener.py +579 -0
  105. rem/workers/unlogged_maintainer.py +463 -0
  106. {remdb-0.3.14.dist-info → remdb-0.3.157.dist-info}/METADATA +340 -229
  107. {remdb-0.3.14.dist-info → remdb-0.3.157.dist-info}/RECORD +109 -80
  108. {remdb-0.3.14.dist-info → remdb-0.3.157.dist-info}/WHEEL +1 -1
  109. rem/sql/002_install_models.sql +0 -1068
  110. rem/sql/install_models.sql +0 -1051
  111. rem/sql/migrations/003_seed_default_user.sql +0 -48
  112. {remdb-0.3.14.dist-info → remdb-0.3.157.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,360 @@
1
+ """
2
+ Email Templates.
3
+
4
+ HTML email templates for transactional emails.
5
+ Uses inline CSS for maximum email client compatibility.
6
+
7
+ Downstream apps can customize by:
8
+ 1. Overriding COLORS dict
9
+ 2. Setting custom LOGO_URL and TAGLINE
10
+ 3. Creating custom templates using base_template()
11
+ """
12
+
13
+ from dataclasses import dataclass
14
+ from typing import Optional
15
+
16
+
17
+ # Default colors - override in downstream apps
18
+ COLORS = {
19
+ "background": "#F5F5F5",
20
+ "foreground": "#333333",
21
+ "primary": "#4A90D9",
22
+ "accent": "#5CB85C",
23
+ "card": "#FFFFFF",
24
+ "muted": "#6b7280",
25
+ "border": "#E0E0E0",
26
+ }
27
+
28
+ # Branding - override in downstream apps
29
+ LOGO_URL: str | None = None
30
+ APP_NAME = "REM"
31
+ TAGLINE = "Your AI-powered platform"
32
+ WEBSITE_URL = "https://rem.ai"
33
+ PRIVACY_URL = "https://rem.ai/privacy"
34
+ TERMS_URL = "https://rem.ai/terms"
35
+
36
+
37
+ @dataclass
38
+ class EmailTemplate:
39
+ """Email template with subject and HTML body."""
40
+
41
+ subject: str
42
+ html_body: str
43
+
44
+
45
+ def base_template(
46
+ content: str,
47
+ preheader: Optional[str] = None,
48
+ colors: dict | None = None,
49
+ logo_url: str | None = None,
50
+ app_name: str | None = None,
51
+ tagline: str | None = None,
52
+ website_url: str | None = None,
53
+ privacy_url: str | None = None,
54
+ terms_url: str | None = None,
55
+ ) -> str:
56
+ """
57
+ Base email template.
58
+
59
+ Args:
60
+ content: The main content HTML
61
+ preheader: Optional preview text shown in email clients
62
+ colors: Color overrides (merges with COLORS)
63
+ logo_url: Logo image URL
64
+ app_name: Application name
65
+ tagline: Footer tagline
66
+ website_url: Main website URL
67
+ privacy_url: Privacy policy URL
68
+ terms_url: Terms of service URL
69
+
70
+ Returns:
71
+ Complete HTML email
72
+ """
73
+ # Merge colors
74
+ c = {**COLORS, **(colors or {})}
75
+
76
+ # Use provided values or module defaults
77
+ logo = logo_url or LOGO_URL
78
+ name = app_name or APP_NAME
79
+ tag = tagline or TAGLINE
80
+ web = website_url or WEBSITE_URL
81
+ privacy = privacy_url or PRIVACY_URL
82
+ terms = terms_url or TERMS_URL
83
+
84
+ preheader_html = ""
85
+ if preheader:
86
+ preheader_html = f'''
87
+ <div style="display: none; max-height: 0; overflow: hidden;">
88
+ {preheader}
89
+ </div>
90
+ '''
91
+
92
+ logo_html = ""
93
+ if logo:
94
+ logo_html = f'''
95
+ <img src="{logo}" alt="{name}" width="40" height="40" style="display: block; margin: 0 auto 16px auto; border-radius: 8px;">
96
+ '''
97
+
98
+ return f'''<!DOCTYPE html>
99
+ <html lang="en">
100
+ <head>
101
+ <meta charset="UTF-8">
102
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
103
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
104
+ <title>{name}</title>
105
+ <!--[if mso]>
106
+ <style type="text/css">
107
+ body, table, td {{font-family: Arial, sans-serif !important;}}
108
+ </style>
109
+ <![endif]-->
110
+ </head>
111
+ <body style="margin: 0; padding: 0; background-color: {c['background']}; font-family: 'Georgia', 'Times New Roman', serif;">
112
+ {preheader_html}
113
+
114
+ <!-- Email Container -->
115
+ <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="background-color: {c['background']};">
116
+ <tr>
117
+ <td style="padding: 40px 20px;">
118
+ <!-- Inner Container -->
119
+ <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="max-width: 560px; margin: 0 auto;">
120
+
121
+ <!-- Main Content Card -->
122
+ <tr>
123
+ <td style="background-color: {c['card']}; border-radius: 16px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);">
124
+ <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
125
+ <tr>
126
+ <td style="padding: 40px;">
127
+ {content}
128
+ </td>
129
+ </tr>
130
+ </table>
131
+ </td>
132
+ </tr>
133
+
134
+ <!-- Footer -->
135
+ <tr>
136
+ <td style="padding: 32px 20px; text-align: center;">
137
+ {logo_html}
138
+
139
+ <!-- Tagline -->
140
+ <p style="margin: 0 0 8px 0; font-family: 'Georgia', serif; font-size: 14px; color: {c['muted']}; font-style: italic;">
141
+ {tag}
142
+ </p>
143
+
144
+ <!-- Footer Links -->
145
+ <p style="margin: 0; font-family: Arial, sans-serif; font-size: 12px; color: {c['muted']};">
146
+ <a href="{web}" style="color: {c['primary']}; text-decoration: none;">{name}</a>
147
+ &nbsp;&bull;&nbsp;
148
+ <a href="{privacy}" style="color: {c['primary']}; text-decoration: none;">Privacy</a>
149
+ &nbsp;&bull;&nbsp;
150
+ <a href="{terms}" style="color: {c['primary']}; text-decoration: none;">Terms</a>
151
+ </p>
152
+
153
+ <!-- Copyright -->
154
+ <p style="margin: 16px 0 0 0; font-family: Arial, sans-serif; font-size: 11px; color: {c['muted']};">
155
+ &copy; 2025 {name}. All rights reserved.
156
+ </p>
157
+ </td>
158
+ </tr>
159
+
160
+ </table>
161
+ </td>
162
+ </tr>
163
+ </table>
164
+ </body>
165
+ </html>'''
166
+
167
+
168
+ def login_code_template(
169
+ code: str,
170
+ email: str,
171
+ colors: dict | None = None,
172
+ app_name: str | None = None,
173
+ **kwargs,
174
+ ) -> EmailTemplate:
175
+ """
176
+ Generate a login code email template.
177
+
178
+ Args:
179
+ code: The 6-digit login code
180
+ email: The recipient's email address
181
+ colors: Color overrides
182
+ app_name: Application name
183
+ **kwargs: Additional arguments passed to base_template
184
+
185
+ Returns:
186
+ EmailTemplate with subject and HTML body
187
+ """
188
+ c = {**COLORS, **(colors or {})}
189
+ name = app_name or APP_NAME
190
+
191
+ # Format code with spaces for readability (e.g., "123 456")
192
+ formatted_code = f"{code[:3]} {code[3:]}" if len(code) == 6 else code
193
+
194
+ content = f'''
195
+ <!-- Greeting -->
196
+ <h1 style="margin: 0 0 8px 0; font-family: 'Arial', sans-serif; font-size: 24px; font-weight: 600; color: {c['foreground']};">
197
+ Hi there!
198
+ </h1>
199
+
200
+ <p style="margin: 0 0 24px 0; font-family: 'Georgia', serif; font-size: 16px; line-height: 1.6; color: {c['foreground']};">
201
+ Here's your login code for {name}. Enter this code to securely access your account.
202
+ </p>
203
+
204
+ <!-- Code Box -->
205
+ <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin: 0 0 24px 0;">
206
+ <tr>
207
+ <td align="center">
208
+ <div style="
209
+ display: inline-block;
210
+ padding: 20px 40px;
211
+ background-color: {c['background']};
212
+ border: 2px solid {c['border']};
213
+ border-radius: 12px;
214
+ ">
215
+ <span style="
216
+ font-family: 'Courier New', monospace;
217
+ font-size: 32px;
218
+ font-weight: 700;
219
+ letter-spacing: 6px;
220
+ color: {c['foreground']};
221
+ ">{formatted_code}</span>
222
+ </div>
223
+ </td>
224
+ </tr>
225
+ </table>
226
+
227
+ <!-- Instructions -->
228
+ <p style="margin: 0 0 8px 0; font-family: 'Georgia', serif; font-size: 14px; line-height: 1.6; color: {c['muted']};">
229
+ This code expires in <strong>10 minutes</strong>.
230
+ </p>
231
+
232
+ <p style="margin: 0 0 24px 0; font-family: 'Georgia', serif; font-size: 14px; line-height: 1.6; color: {c['muted']};">
233
+ If you didn't request this code, you can safely ignore this email.
234
+ </p>
235
+
236
+ <!-- Divider -->
237
+ <hr style="border: none; border-top: 1px solid {c['border']}; margin: 24px 0;">
238
+
239
+ <!-- Security Note -->
240
+ <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
241
+ <tr>
242
+ <td style="padding: 16px; background-color: {c['background']}; border-radius: 8px;">
243
+ <p style="margin: 0; font-family: Arial, sans-serif; font-size: 12px; color: {c['muted']};">
244
+ <strong style="color: {c['primary']};">Security tip:</strong>
245
+ Never share your login code with anyone. {name} will never ask for your code via phone or text.
246
+ </p>
247
+ </td>
248
+ </tr>
249
+ </table>
250
+ '''
251
+
252
+ return EmailTemplate(
253
+ subject=f"Your {name} Login Code",
254
+ html_body=base_template(
255
+ content=content,
256
+ preheader=f"Your login code is {formatted_code}",
257
+ colors=colors,
258
+ app_name=app_name,
259
+ **kwargs,
260
+ ),
261
+ )
262
+
263
+
264
+ def welcome_template(
265
+ name: Optional[str] = None,
266
+ colors: dict | None = None,
267
+ app_name: str | None = None,
268
+ features: list[str] | None = None,
269
+ cta_url: str | None = None,
270
+ cta_text: str = "Get Started",
271
+ **kwargs,
272
+ ) -> EmailTemplate:
273
+ """
274
+ Generate a welcome email template for new users.
275
+
276
+ Args:
277
+ name: Optional user's name
278
+ colors: Color overrides
279
+ app_name: Application name
280
+ features: List of feature descriptions
281
+ cta_url: Call-to-action button URL
282
+ cta_text: Call-to-action button text
283
+ **kwargs: Additional arguments passed to base_template
284
+
285
+ Returns:
286
+ EmailTemplate with subject and HTML body
287
+ """
288
+ c = {**COLORS, **(colors or {})}
289
+ app = app_name or APP_NAME
290
+ greeting = f"Hi {name}!" if name else "Welcome!"
291
+ url = cta_url or WEBSITE_URL
292
+
293
+ # Default features if not provided
294
+ default_features = [
295
+ "Access powerful AI capabilities",
296
+ "Store and organize your data",
297
+ "Collaborate with your team",
298
+ ]
299
+ feature_list = features or default_features
300
+
301
+ features_html = "".join(f"<li>{f}</li>" for f in feature_list)
302
+
303
+ content = f'''
304
+ <!-- Greeting -->
305
+ <h1 style="margin: 0 0 8px 0; font-family: 'Arial', sans-serif; font-size: 24px; font-weight: 600; color: {c['foreground']};">
306
+ {greeting}
307
+ </h1>
308
+
309
+ <p style="margin: 0 0 24px 0; font-family: 'Georgia', serif; font-size: 16px; line-height: 1.6; color: {c['foreground']};">
310
+ Welcome to {app}! We're excited to have you on board.
311
+ </p>
312
+
313
+ <!-- Feature List -->
314
+ <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin: 0 0 24px 0;">
315
+ <tr>
316
+ <td style="padding: 16px; background-color: {c['background']}; border-radius: 8px;">
317
+ <p style="margin: 0 0 12px 0; font-family: Arial, sans-serif; font-size: 14px; font-weight: 600; color: {c['primary']};">
318
+ What you can do with {app}:
319
+ </p>
320
+ <ul style="margin: 0; padding-left: 20px; font-family: 'Georgia', serif; font-size: 14px; line-height: 1.8; color: {c['foreground']};">
321
+ {features_html}
322
+ </ul>
323
+ </td>
324
+ </tr>
325
+ </table>
326
+
327
+ <!-- CTA Button -->
328
+ <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin: 0 0 24px 0;">
329
+ <tr>
330
+ <td align="center">
331
+ <a href="{url}" style="
332
+ display: inline-block;
333
+ padding: 14px 32px;
334
+ background-color: {c['primary']};
335
+ color: #FFFFFF;
336
+ font-family: Arial, sans-serif;
337
+ font-size: 16px;
338
+ font-weight: 600;
339
+ text-decoration: none;
340
+ border-radius: 8px;
341
+ ">{cta_text}</a>
342
+ </td>
343
+ </tr>
344
+ </table>
345
+
346
+ <p style="margin: 0; font-family: 'Georgia', serif; font-size: 14px; line-height: 1.6; color: {c['muted']}; text-align: center;">
347
+ We're glad you're here!
348
+ </p>
349
+ '''
350
+
351
+ return EmailTemplate(
352
+ subject=f"Welcome to {app}",
353
+ html_body=base_template(
354
+ content=content,
355
+ preheader=f"Welcome to {app}! Get started today.",
356
+ colors=colors,
357
+ app_name=app_name,
358
+ **kwargs,
359
+ ),
360
+ )
@@ -45,7 +45,7 @@ def generate_embedding(
45
45
  return [0.0] * DEFAULT_EMBEDDING_DIMS
46
46
 
47
47
  try:
48
- logger.info(f"Generating OpenAI embedding for text using {model}")
48
+ logger.debug(f"Generating OpenAI embedding for text using {model}")
49
49
 
50
50
  response = requests.post(
51
51
  "https://api.openai.com/v1/embeddings",
@@ -60,7 +60,7 @@ def generate_embedding(
60
60
 
61
61
  data = response.json()
62
62
  embedding = data["data"][0]["embedding"]
63
- logger.info(f"Successfully generated embedding (dimension: {len(embedding)})")
63
+ logger.debug(f"Successfully generated embedding (dimension: {len(embedding)})")
64
64
  return cast(list[float], embedding)
65
65
 
66
66
  except Exception as e:
@@ -97,7 +97,7 @@ async def generate_embedding_async(
97
97
  return [0.0] * DEFAULT_EMBEDDING_DIMS
98
98
 
99
99
  try:
100
- logger.info(f"Generating OpenAI embedding for text using {model}")
100
+ logger.debug(f"Generating OpenAI embedding for text using {model}")
101
101
 
102
102
  async with httpx.AsyncClient() as client:
103
103
  response = await client.post(
@@ -113,7 +113,7 @@ async def generate_embedding_async(
113
113
 
114
114
  data = response.json()
115
115
  embedding = data["data"][0]["embedding"]
116
- logger.info(
116
+ logger.debug(
117
117
  f"Successfully generated embedding (dimension: {len(embedding)})"
118
118
  )
119
119
  return cast(list[float], embedding)
@@ -69,7 +69,7 @@ def get_global_embedding_worker(postgres_service: Any = None) -> "EmbeddingWorke
69
69
  if postgres_service is None:
70
70
  raise RuntimeError("Must provide postgres_service on first call to get_global_embedding_worker")
71
71
  _global_worker = EmbeddingWorker(postgres_service=postgres_service)
72
- logger.info("Created global EmbeddingWorker singleton")
72
+ logger.debug("Created global EmbeddingWorker singleton")
73
73
 
74
74
  return _global_worker
75
75
 
@@ -117,7 +117,7 @@ class EmbeddingWorker:
117
117
  "No OpenAI API key provided - embeddings will use zero vectors"
118
118
  )
119
119
 
120
- logger.info(
120
+ logger.debug(
121
121
  f"Initialized EmbeddingWorker: {num_workers} workers, "
122
122
  f"batch_size={batch_size}, timeout={batch_timeout}s"
123
123
  )
@@ -125,17 +125,17 @@ class EmbeddingWorker:
125
125
  async def start(self) -> None:
126
126
  """Start worker pool."""
127
127
  if self.running:
128
- logger.warning("EmbeddingWorker already running")
128
+ logger.debug("EmbeddingWorker already running")
129
129
  return
130
130
 
131
131
  self.running = True
132
- logger.info(f"Starting {self.num_workers} embedding workers")
132
+ logger.debug(f"Starting {self.num_workers} embedding workers")
133
133
 
134
134
  for i in range(self.num_workers):
135
135
  worker = asyncio.create_task(self._worker_loop(i))
136
136
  self.workers.append(worker)
137
137
 
138
- logger.info("EmbeddingWorker started")
138
+ logger.debug("EmbeddingWorker started")
139
139
 
140
140
  async def stop(self) -> None:
141
141
  """Stop worker pool gracefully - processes remaining queue before stopping."""
@@ -143,7 +143,7 @@ class EmbeddingWorker:
143
143
  return
144
144
 
145
145
  queue_size = self.task_queue.qsize()
146
- logger.info(f"Stopping EmbeddingWorker (processing {queue_size} queued tasks first)")
146
+ logger.debug(f"Stopping EmbeddingWorker (processing {queue_size} queued tasks first)")
147
147
 
148
148
  # Wait for queue to drain (with timeout)
149
149
  max_wait = 30 # 30 seconds max
@@ -171,7 +171,7 @@ class EmbeddingWorker:
171
171
  await asyncio.gather(*self.workers, return_exceptions=True)
172
172
 
173
173
  self.workers.clear()
174
- logger.info("EmbeddingWorker stopped")
174
+ logger.debug("EmbeddingWorker stopped")
175
175
 
176
176
  async def queue_task(self, task: EmbeddingTask) -> None:
177
177
  """
@@ -195,7 +195,7 @@ class EmbeddingWorker:
195
195
  Args:
196
196
  worker_id: Unique worker identifier
197
197
  """
198
- logger.info(f"Worker {worker_id} started")
198
+ logger.debug(f"Worker {worker_id} started")
199
199
 
200
200
  while self.running:
201
201
  try:
@@ -205,7 +205,7 @@ class EmbeddingWorker:
205
205
  if not batch:
206
206
  continue
207
207
 
208
- logger.info(f"Worker {worker_id} processing batch of {len(batch)} tasks")
208
+ logger.debug(f"Worker {worker_id} processing batch of {len(batch)} tasks")
209
209
 
210
210
  # Generate embeddings for batch
211
211
  await self._process_batch(batch)
@@ -213,14 +213,14 @@ class EmbeddingWorker:
213
213
  logger.debug(f"Worker {worker_id} completed batch")
214
214
 
215
215
  except asyncio.CancelledError:
216
- logger.info(f"Worker {worker_id} cancelled")
216
+ logger.debug(f"Worker {worker_id} cancelled")
217
217
  break
218
218
  except Exception as e:
219
219
  logger.error(f"Worker {worker_id} error: {e}", exc_info=True)
220
220
  # Continue processing (don't crash worker on error)
221
221
  await asyncio.sleep(1)
222
222
 
223
- logger.info(f"Worker {worker_id} stopped")
223
+ logger.debug(f"Worker {worker_id} stopped")
224
224
 
225
225
  async def _collect_batch(self) -> list[EmbeddingTask]:
226
226
  """
@@ -284,10 +284,10 @@ class EmbeddingWorker:
284
284
  )
285
285
 
286
286
  # Upsert to database
287
- logger.info(f"Upserting {len(embeddings)} embeddings to database...")
287
+ logger.debug(f"Upserting {len(embeddings)} embeddings to database...")
288
288
  await self._upsert_embeddings(batch, embeddings)
289
289
 
290
- logger.info(
290
+ logger.debug(
291
291
  f"Successfully generated and stored {len(embeddings)} embeddings "
292
292
  f"(provider={provider}, model={model})"
293
293
  )
@@ -315,7 +315,7 @@ class EmbeddingWorker:
315
315
  """
316
316
  if provider == "openai" and self.openai_api_key:
317
317
  try:
318
- logger.info(
318
+ logger.debug(
319
319
  f"Generating OpenAI embeddings for {len(texts)} texts using {model}"
320
320
  )
321
321
 
@@ -336,7 +336,7 @@ class EmbeddingWorker:
336
336
  data = response.json()
337
337
  embeddings = [item["embedding"] for item in data["data"]]
338
338
 
339
- logger.info(
339
+ logger.debug(
340
340
  f"Successfully generated {len(embeddings)} embeddings from OpenAI"
341
341
  )
342
342
  return embeddings
@@ -409,7 +409,7 @@ class EmbeddingWorker:
409
409
  ),
410
410
  )
411
411
 
412
- logger.info(
412
+ logger.debug(
413
413
  f"Upserted embedding: {task.table_name}.{task.entity_id}.{task.field_name}"
414
414
  )
415
415