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/utils/vision.py ADDED
@@ -0,0 +1,325 @@
1
+ """
2
+ Vision utility for image analysis using multiple LLM providers.
3
+
4
+ Lightweight implementation supporting three providers:
5
+ - Anthropic Claude (claude-3-5-sonnet-20241022 or newer)
6
+ - Google Gemini (gemini-2.0-flash-exp or newer)
7
+ - OpenAI-compatible (gpt-4o, gpt-4-turbo, or compatible endpoints)
8
+
9
+ Handles image encoding and multimodal LLM requests for generating
10
+ markdown descriptions of images.
11
+ """
12
+
13
+ import base64
14
+ from enum import Enum
15
+ from pathlib import Path
16
+ from typing import Optional
17
+
18
+ import requests
19
+ from loguru import logger
20
+
21
+ from rem.utils.constants import HTTP_TIMEOUT_LONG, VISION_MAX_TOKENS
22
+ from rem.utils.mime_types import EXTENSION_TO_MIME
23
+
24
+
25
+ class VisionProvider(str, Enum):
26
+ """Supported vision providers."""
27
+
28
+ ANTHROPIC = "anthropic"
29
+ GEMINI = "gemini"
30
+ OPENAI = "openai"
31
+
32
+
33
+ class VisionResult:
34
+ """Result from image vision analysis."""
35
+
36
+ def __init__(
37
+ self,
38
+ description: str,
39
+ provider: VisionProvider,
40
+ model: str,
41
+ confidence: float = 0.9,
42
+ ):
43
+ """
44
+ Initialize vision result.
45
+
46
+ Args:
47
+ description: Markdown description of the image
48
+ provider: Vision provider used
49
+ model: Model name used
50
+ confidence: Confidence score (0.0-1.0)
51
+ """
52
+ self.description = description
53
+ self.provider = provider
54
+ self.model = model
55
+ self.confidence = confidence
56
+
57
+ def __repr__(self) -> str:
58
+ return f"VisionResult(provider={self.provider.value}, model={self.model}, chars={len(self.description)})"
59
+
60
+
61
+ class ImageAnalyzer:
62
+ """
63
+ Analyze images using vision-enabled LLMs.
64
+
65
+ Supports three providers with automatic provider selection based on API keys.
66
+ """
67
+
68
+ def __init__(
69
+ self,
70
+ provider: VisionProvider = VisionProvider.ANTHROPIC,
71
+ api_key: Optional[str] = None,
72
+ model: Optional[str] = None,
73
+ base_url: Optional[str] = None,
74
+ ):
75
+ """
76
+ Initialize image analyzer.
77
+
78
+ Args:
79
+ provider: Vision provider to use
80
+ api_key: API key (from env if None)
81
+ model: Model name (provider default if None)
82
+ base_url: Custom base URL (for OpenAI-compatible endpoints)
83
+ """
84
+ self.provider = provider
85
+
86
+ # Get API key from settings if not provided
87
+ if api_key is None:
88
+ from ..settings import settings
89
+ if provider == VisionProvider.ANTHROPIC:
90
+ api_key = settings.llm.anthropic_api_key
91
+ elif provider == VisionProvider.GEMINI:
92
+ # Gemini uses same key as Google
93
+ api_key = settings.llm.anthropic_api_key # TODO: Add gemini_api_key to settings
94
+ elif provider == VisionProvider.OPENAI:
95
+ api_key = settings.llm.openai_api_key
96
+
97
+ if not api_key:
98
+ logger.warning(f"No API key found for {provider.value} - vision analysis will fail")
99
+
100
+ self.api_key = api_key
101
+
102
+ # Set default models
103
+ if model is None:
104
+ if provider == VisionProvider.ANTHROPIC:
105
+ model = "claude-3-5-sonnet-20241022"
106
+ elif provider == VisionProvider.GEMINI:
107
+ model = "gemini-2.0-flash-exp"
108
+ elif provider == VisionProvider.OPENAI:
109
+ model = "gpt-4.1"
110
+
111
+ self.model = model
112
+ self.base_url = base_url
113
+
114
+ def analyze_image(
115
+ self,
116
+ image_path: str | Path,
117
+ prompt: str = "Describe this image in detail as markdown. Include key visual elements, text, diagrams, and context.",
118
+ ) -> VisionResult:
119
+ """
120
+ Analyze image and generate markdown description.
121
+
122
+ Args:
123
+ image_path: Path to image file
124
+ prompt: Analysis prompt for the LLM
125
+
126
+ Returns:
127
+ VisionResult with markdown description
128
+
129
+ Raises:
130
+ ValueError: If API key missing or file invalid
131
+ RuntimeError: If API request fails
132
+ """
133
+ if not self.api_key:
134
+ raise ValueError(f"API key required for {self.provider.value} vision analysis")
135
+
136
+ image_path = Path(image_path)
137
+ if not image_path.exists():
138
+ raise FileNotFoundError(f"Image file not found: {image_path}")
139
+
140
+ # Read and encode image
141
+ with open(image_path, "rb") as f:
142
+ image_bytes = f.read()
143
+
144
+ # Detect media type
145
+ suffix = image_path.suffix.lower()
146
+ media_type = EXTENSION_TO_MIME.get(suffix, "image/png")
147
+
148
+ logger.info(f"Analyzing {image_path.name} with {self.provider.value} ({self.model})")
149
+
150
+ # Route to provider-specific implementation
151
+ if self.provider == VisionProvider.ANTHROPIC:
152
+ description = self._analyze_anthropic(image_bytes, media_type, prompt)
153
+ elif self.provider == VisionProvider.GEMINI:
154
+ description = self._analyze_gemini(image_bytes, media_type, prompt)
155
+ elif self.provider == VisionProvider.OPENAI:
156
+ description = self._analyze_openai(image_bytes, media_type, prompt)
157
+ else:
158
+ raise ValueError(f"Unsupported provider: {self.provider}")
159
+
160
+ logger.info(f"✓ Vision analysis complete: {len(description)} characters")
161
+
162
+ return VisionResult(
163
+ description=description,
164
+ provider=self.provider,
165
+ model=self.model,
166
+ confidence=0.9,
167
+ )
168
+
169
+ def _analyze_anthropic(
170
+ self,
171
+ image_bytes: bytes,
172
+ media_type: str,
173
+ prompt: str,
174
+ ) -> str:
175
+ """Analyze image using Anthropic Claude."""
176
+ # Encode image to base64
177
+ image_b64 = base64.b64encode(image_bytes).decode("utf-8")
178
+
179
+ # Build request
180
+ headers = {
181
+ "x-api-key": self.api_key,
182
+ "anthropic-version": "2023-06-01",
183
+ "content-type": "application/json",
184
+ }
185
+
186
+ body = {
187
+ "model": self.model,
188
+ "max_tokens": VISION_MAX_TOKENS,
189
+ "messages": [
190
+ {
191
+ "role": "user",
192
+ "content": [
193
+ {
194
+ "type": "image",
195
+ "source": {
196
+ "type": "base64",
197
+ "media_type": media_type,
198
+ "data": image_b64,
199
+ },
200
+ },
201
+ {
202
+ "type": "text",
203
+ "text": prompt,
204
+ },
205
+ ],
206
+ }
207
+ ],
208
+ }
209
+
210
+ response = requests.post(
211
+ "https://api.anthropic.com/v1/messages",
212
+ headers=headers,
213
+ json=body,
214
+ timeout=HTTP_TIMEOUT_LONG,
215
+ )
216
+
217
+ if response.status_code != 200:
218
+ error_detail = response.text
219
+ logger.error(f"Anthropic API error: {response.status_code} - {error_detail}")
220
+ raise RuntimeError(f"Vision analysis failed: {response.status_code} - {error_detail}")
221
+
222
+ result = response.json()
223
+ return result["content"][0]["text"]
224
+
225
+ def _analyze_gemini(
226
+ self,
227
+ image_bytes: bytes,
228
+ media_type: str,
229
+ prompt: str,
230
+ ) -> str:
231
+ """Analyze image using Google Gemini."""
232
+ # Encode image to base64
233
+ image_b64 = base64.b64encode(image_bytes).decode("utf-8")
234
+
235
+ # Build request (Gemini REST API)
236
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/{self.model}:generateContent"
237
+ params = {"key": self.api_key}
238
+
239
+ body = {
240
+ "contents": [
241
+ {
242
+ "parts": [
243
+ {
244
+ "inline_data": {
245
+ "mime_type": media_type,
246
+ "data": image_b64,
247
+ }
248
+ },
249
+ {"text": prompt},
250
+ ]
251
+ }
252
+ ]
253
+ }
254
+
255
+ response = requests.post(
256
+ url,
257
+ params=params,
258
+ json=body,
259
+ timeout=HTTP_TIMEOUT_LONG,
260
+ )
261
+
262
+ if response.status_code != 200:
263
+ error_detail = response.text
264
+ logger.error(f"Gemini API error: {response.status_code} - {error_detail}")
265
+ raise RuntimeError(f"Vision analysis failed: {response.status_code} - {error_detail}")
266
+
267
+ result = response.json()
268
+ return result["candidates"][0]["content"]["parts"][0]["text"]
269
+
270
+ def _analyze_openai(
271
+ self,
272
+ image_bytes: bytes,
273
+ media_type: str,
274
+ prompt: str,
275
+ ) -> str:
276
+ """Analyze image using OpenAI or OpenAI-compatible endpoint."""
277
+ # Encode image to base64
278
+ image_b64 = base64.b64encode(image_bytes).decode("utf-8")
279
+
280
+ # Build request
281
+ headers = {
282
+ "Authorization": f"Bearer {self.api_key}",
283
+ "Content-Type": "application/json",
284
+ }
285
+
286
+ # Use custom base URL if provided, otherwise use OpenAI
287
+ base_url = self.base_url or "https://api.openai.com/v1"
288
+ url = f"{base_url}/chat/completions"
289
+
290
+ body = {
291
+ "model": self.model,
292
+ "messages": [
293
+ {
294
+ "role": "user",
295
+ "content": [
296
+ {
297
+ "type": "image_url",
298
+ "image_url": {
299
+ "url": f"data:{media_type};base64,{image_b64}",
300
+ },
301
+ },
302
+ {
303
+ "type": "text",
304
+ "text": prompt,
305
+ },
306
+ ],
307
+ }
308
+ ],
309
+ "max_tokens": VISION_MAX_TOKENS,
310
+ }
311
+
312
+ response = requests.post(
313
+ url,
314
+ headers=headers,
315
+ json=body,
316
+ timeout=HTTP_TIMEOUT_LONG,
317
+ )
318
+
319
+ if response.status_code != 200:
320
+ error_detail = response.text
321
+ logger.error(f"OpenAI API error: {response.status_code} - {error_detail}")
322
+ raise RuntimeError(f"Vision analysis failed: {response.status_code} - {error_detail}")
323
+
324
+ result = response.json()
325
+ return result["choices"][0]["message"]["content"]