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.
- rem/agentic/README.md +76 -0
- rem/agentic/__init__.py +15 -0
- rem/agentic/agents/__init__.py +32 -2
- rem/agentic/agents/agent_manager.py +310 -0
- rem/agentic/agents/sse_simulator.py +502 -0
- rem/agentic/context.py +51 -27
- rem/agentic/context_builder.py +5 -3
- rem/agentic/llm_provider_models.py +301 -0
- rem/agentic/mcp/tool_wrapper.py +155 -18
- rem/agentic/otel/setup.py +93 -4
- rem/agentic/providers/phoenix.py +371 -108
- rem/agentic/providers/pydantic_ai.py +280 -57
- rem/agentic/schema.py +361 -21
- rem/agentic/tools/rem_tools.py +3 -3
- rem/api/README.md +215 -1
- rem/api/deps.py +255 -0
- rem/api/main.py +132 -40
- rem/api/mcp_router/resources.py +1 -1
- rem/api/mcp_router/server.py +28 -5
- rem/api/mcp_router/tools.py +555 -7
- rem/api/routers/admin.py +494 -0
- rem/api/routers/auth.py +278 -4
- rem/api/routers/chat/completions.py +402 -20
- rem/api/routers/chat/models.py +88 -10
- rem/api/routers/chat/otel_utils.py +33 -0
- rem/api/routers/chat/sse_events.py +542 -0
- rem/api/routers/chat/streaming.py +697 -45
- rem/api/routers/dev.py +81 -0
- rem/api/routers/feedback.py +268 -0
- rem/api/routers/messages.py +473 -0
- rem/api/routers/models.py +78 -0
- rem/api/routers/query.py +360 -0
- rem/api/routers/shared_sessions.py +406 -0
- rem/auth/__init__.py +13 -3
- rem/auth/middleware.py +186 -22
- rem/auth/providers/__init__.py +4 -1
- rem/auth/providers/email.py +215 -0
- rem/cli/commands/README.md +237 -64
- rem/cli/commands/cluster.py +1808 -0
- rem/cli/commands/configure.py +4 -7
- rem/cli/commands/db.py +386 -143
- rem/cli/commands/experiments.py +468 -76
- rem/cli/commands/process.py +14 -8
- rem/cli/commands/schema.py +97 -50
- rem/cli/commands/session.py +336 -0
- rem/cli/dreaming.py +2 -2
- rem/cli/main.py +29 -6
- rem/config.py +10 -3
- rem/models/core/core_model.py +7 -1
- rem/models/core/experiment.py +58 -14
- rem/models/core/rem_query.py +5 -2
- rem/models/entities/__init__.py +25 -0
- rem/models/entities/domain_resource.py +38 -0
- rem/models/entities/feedback.py +123 -0
- rem/models/entities/message.py +30 -1
- rem/models/entities/ontology.py +1 -1
- rem/models/entities/ontology_config.py +1 -1
- rem/models/entities/session.py +83 -0
- rem/models/entities/shared_session.py +180 -0
- rem/models/entities/subscriber.py +175 -0
- rem/models/entities/user.py +1 -0
- rem/registry.py +10 -4
- rem/schemas/agents/core/agent-builder.yaml +134 -0
- rem/schemas/agents/examples/contract-analyzer.yaml +1 -1
- rem/schemas/agents/examples/contract-extractor.yaml +1 -1
- rem/schemas/agents/examples/cv-parser.yaml +1 -1
- rem/schemas/agents/rem.yaml +7 -3
- rem/services/__init__.py +3 -1
- rem/services/content/service.py +92 -19
- rem/services/email/__init__.py +10 -0
- rem/services/email/service.py +459 -0
- rem/services/email/templates.py +360 -0
- rem/services/embeddings/api.py +4 -4
- rem/services/embeddings/worker.py +16 -16
- rem/services/phoenix/client.py +154 -14
- rem/services/postgres/README.md +197 -15
- rem/services/postgres/__init__.py +2 -1
- rem/services/postgres/diff_service.py +547 -0
- rem/services/postgres/pydantic_to_sqlalchemy.py +470 -140
- rem/services/postgres/repository.py +132 -0
- rem/services/postgres/schema_generator.py +205 -4
- rem/services/postgres/service.py +6 -6
- rem/services/rem/parser.py +44 -9
- rem/services/rem/service.py +36 -2
- rem/services/session/compression.py +137 -51
- rem/services/session/reload.py +15 -8
- rem/settings.py +515 -27
- rem/sql/background_indexes.sql +21 -16
- rem/sql/migrations/001_install.sql +387 -54
- rem/sql/migrations/002_install_models.sql +2304 -377
- rem/sql/migrations/003_optional_extensions.sql +326 -0
- rem/sql/migrations/004_cache_system.sql +548 -0
- rem/sql/migrations/005_schema_update.sql +145 -0
- rem/utils/README.md +45 -0
- rem/utils/__init__.py +18 -0
- rem/utils/date_utils.py +2 -2
- rem/utils/files.py +157 -1
- rem/utils/model_helpers.py +156 -1
- rem/utils/schema_loader.py +220 -22
- rem/utils/sql_paths.py +146 -0
- rem/utils/sql_types.py +3 -1
- rem/utils/vision.py +1 -1
- rem/workers/__init__.py +3 -1
- rem/workers/db_listener.py +579 -0
- rem/workers/unlogged_maintainer.py +463 -0
- {remdb-0.3.14.dist-info → remdb-0.3.157.dist-info}/METADATA +340 -229
- {remdb-0.3.14.dist-info → remdb-0.3.157.dist-info}/RECORD +109 -80
- {remdb-0.3.14.dist-info → remdb-0.3.157.dist-info}/WHEEL +1 -1
- rem/sql/002_install_models.sql +0 -1068
- rem/sql/install_models.sql +0 -1051
- rem/sql/migrations/003_seed_default_user.sql +0 -48
- {remdb-0.3.14.dist-info → remdb-0.3.157.dist-info}/entry_points.txt +0 -0
rem/services/phoenix/client.py
CHANGED
|
@@ -792,29 +792,169 @@ class PhoenixClient:
|
|
|
792
792
|
label: str | None = None,
|
|
793
793
|
score: float | None = None,
|
|
794
794
|
explanation: str | None = None,
|
|
795
|
-
|
|
796
|
-
|
|
795
|
+
metadata: dict[str, Any] | None = None,
|
|
796
|
+
trace_id: str | None = None,
|
|
797
|
+
) -> str | None:
|
|
798
|
+
"""Add feedback annotation to a span via Phoenix REST API.
|
|
799
|
+
|
|
800
|
+
Uses direct HTTP POST to /v1/span_annotations for reliability
|
|
801
|
+
(Phoenix Python client API changes frequently).
|
|
797
802
|
|
|
798
803
|
Args:
|
|
799
|
-
span_id: Span ID to annotate
|
|
800
|
-
annotation_name: Name of the annotation (e.g., "correctness")
|
|
804
|
+
span_id: Span ID to annotate (hex string)
|
|
805
|
+
annotation_name: Name of the annotation (e.g., "correctness", "user_feedback")
|
|
801
806
|
annotator_kind: Type of annotator ("HUMAN", "LLM", "CODE")
|
|
802
|
-
label: Optional label (e.g., "correct", "incorrect")
|
|
807
|
+
label: Optional label (e.g., "correct", "incorrect", "helpful")
|
|
803
808
|
score: Optional numeric score (0.0-1.0)
|
|
804
809
|
explanation: Optional explanation text
|
|
810
|
+
metadata: Optional additional metadata dict
|
|
811
|
+
trace_id: Optional trace ID (used if span lookup needed)
|
|
812
|
+
|
|
813
|
+
Returns:
|
|
814
|
+
Annotation ID if successful, None otherwise
|
|
805
815
|
"""
|
|
816
|
+
import httpx
|
|
817
|
+
|
|
806
818
|
try:
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
819
|
+
# Build annotation payload for Phoenix REST API
|
|
820
|
+
annotation_data = {
|
|
821
|
+
"span_id": span_id,
|
|
822
|
+
"name": annotation_name,
|
|
823
|
+
"annotator_kind": annotator_kind,
|
|
824
|
+
"result": {
|
|
825
|
+
"label": label,
|
|
826
|
+
"score": score,
|
|
827
|
+
"explanation": explanation,
|
|
828
|
+
},
|
|
829
|
+
"metadata": metadata or {},
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
# Add trace_id if provided
|
|
833
|
+
if trace_id:
|
|
834
|
+
annotation_data["trace_id"] = trace_id
|
|
835
|
+
|
|
836
|
+
# POST to Phoenix REST API
|
|
837
|
+
annotations_endpoint = f"{self.config.base_url}/v1/span_annotations"
|
|
838
|
+
headers = {}
|
|
839
|
+
if self.config.api_key:
|
|
840
|
+
headers["Authorization"] = f"Bearer {self.config.api_key}"
|
|
841
|
+
|
|
842
|
+
with httpx.Client(timeout=5.0) as client:
|
|
843
|
+
response = client.post(
|
|
844
|
+
annotations_endpoint,
|
|
845
|
+
json={"data": [annotation_data]},
|
|
846
|
+
headers=headers,
|
|
847
|
+
)
|
|
848
|
+
response.raise_for_status()
|
|
815
849
|
|
|
816
850
|
logger.info(f"Added {annotator_kind} feedback to span {span_id}")
|
|
851
|
+
return span_id # Return span_id as annotation reference
|
|
817
852
|
|
|
853
|
+
except httpx.HTTPStatusError as e:
|
|
854
|
+
logger.error(
|
|
855
|
+
f"Failed to add span feedback (HTTP {e.response.status_code}): "
|
|
856
|
+
f"{e.response.text if hasattr(e, 'response') else 'N/A'}"
|
|
857
|
+
)
|
|
858
|
+
return None
|
|
818
859
|
except Exception as e:
|
|
819
860
|
logger.error(f"Failed to add span feedback: {e}")
|
|
820
|
-
|
|
861
|
+
return None
|
|
862
|
+
|
|
863
|
+
def sync_user_feedback(
|
|
864
|
+
self,
|
|
865
|
+
span_id: str,
|
|
866
|
+
rating: int | None = None,
|
|
867
|
+
categories: list[str] | None = None,
|
|
868
|
+
comment: str | None = None,
|
|
869
|
+
feedback_id: str | None = None,
|
|
870
|
+
trace_id: str | None = None,
|
|
871
|
+
) -> str | None:
|
|
872
|
+
"""Sync user feedback to Phoenix as a span annotation.
|
|
873
|
+
|
|
874
|
+
Convenience method for syncing Feedback entities to Phoenix.
|
|
875
|
+
Converts REM feedback format to Phoenix annotation format.
|
|
876
|
+
|
|
877
|
+
Args:
|
|
878
|
+
span_id: OTEL span ID to annotate
|
|
879
|
+
rating: User rating (-1, 1-5 scale)
|
|
880
|
+
categories: List of feedback categories
|
|
881
|
+
comment: Free-text comment
|
|
882
|
+
feedback_id: Optional REM feedback ID for reference
|
|
883
|
+
trace_id: Optional trace ID for the span
|
|
884
|
+
|
|
885
|
+
Returns:
|
|
886
|
+
Phoenix annotation ID if successful
|
|
887
|
+
|
|
888
|
+
Example:
|
|
889
|
+
>>> client.sync_user_feedback(
|
|
890
|
+
... span_id="abc123",
|
|
891
|
+
... rating=4,
|
|
892
|
+
... categories=["helpful", "accurate"],
|
|
893
|
+
... comment="Great response!"
|
|
894
|
+
... )
|
|
895
|
+
"""
|
|
896
|
+
# Convert rating to 0-1 score
|
|
897
|
+
# Rating scheme:
|
|
898
|
+
# -1 = thumbs down → score 0.0
|
|
899
|
+
# 1 = thumbs up → score 1.0
|
|
900
|
+
# 2-5 = star rating → normalized to 0-1 range
|
|
901
|
+
score = None
|
|
902
|
+
if rating is not None:
|
|
903
|
+
if rating == -1:
|
|
904
|
+
score = 0.0
|
|
905
|
+
elif rating == 1:
|
|
906
|
+
score = 1.0 # Thumbs up
|
|
907
|
+
elif 2 <= rating <= 5:
|
|
908
|
+
score = (rating - 1) / 4.0 # 2→0.25, 3→0.5, 4→0.75, 5→1.0
|
|
909
|
+
|
|
910
|
+
# Use primary category as label
|
|
911
|
+
label = categories[0] if categories else None
|
|
912
|
+
|
|
913
|
+
# Build explanation from comment and additional categories
|
|
914
|
+
explanation = comment
|
|
915
|
+
if categories and len(categories) > 1:
|
|
916
|
+
cats_str = ", ".join(categories[1:])
|
|
917
|
+
if explanation:
|
|
918
|
+
explanation = f"{explanation} [Categories: {cats_str}]"
|
|
919
|
+
else:
|
|
920
|
+
explanation = f"Categories: {cats_str}"
|
|
921
|
+
|
|
922
|
+
# Build metadata
|
|
923
|
+
metadata: dict[str, Any] = {
|
|
924
|
+
"rating": rating,
|
|
925
|
+
"categories": categories or [],
|
|
926
|
+
}
|
|
927
|
+
if feedback_id:
|
|
928
|
+
metadata["rem_feedback_id"] = feedback_id
|
|
929
|
+
|
|
930
|
+
return self.add_span_feedback(
|
|
931
|
+
span_id=span_id,
|
|
932
|
+
annotation_name="user_feedback",
|
|
933
|
+
annotator_kind="HUMAN",
|
|
934
|
+
label=label,
|
|
935
|
+
score=score,
|
|
936
|
+
explanation=explanation,
|
|
937
|
+
metadata=metadata,
|
|
938
|
+
trace_id=trace_id,
|
|
939
|
+
)
|
|
940
|
+
|
|
941
|
+
def get_span_annotations(
|
|
942
|
+
self,
|
|
943
|
+
span_id: str,
|
|
944
|
+
annotation_name: str | None = None,
|
|
945
|
+
) -> list[dict[str, Any]]:
|
|
946
|
+
"""Get annotations for a span.
|
|
947
|
+
|
|
948
|
+
Args:
|
|
949
|
+
span_id: Span ID to query
|
|
950
|
+
annotation_name: Optional filter by annotation name
|
|
951
|
+
|
|
952
|
+
Returns:
|
|
953
|
+
List of annotation dicts
|
|
954
|
+
|
|
955
|
+
TODO: Implement once Phoenix client exposes this method
|
|
956
|
+
"""
|
|
957
|
+
# TODO: Phoenix client doesn't expose annotation query yet
|
|
958
|
+
# This is a stub for future implementation
|
|
959
|
+
logger.warning("get_span_annotations not yet implemented in Phoenix client")
|
|
960
|
+
return []
|
rem/services/postgres/README.md
CHANGED
|
@@ -348,8 +348,27 @@ results = await service.vector_search(
|
|
|
348
348
|
|
|
349
349
|
### Initialize Service
|
|
350
350
|
|
|
351
|
+
There are two ways to initialize the PostgresService:
|
|
352
|
+
|
|
353
|
+
**Option 1: Factory function (recommended for apps using remdb as a library)**
|
|
354
|
+
|
|
355
|
+
```python
|
|
356
|
+
from rem.services.postgres import get_postgres_service
|
|
357
|
+
|
|
358
|
+
# Uses POSTGRES__CONNECTION_STRING from environment
|
|
359
|
+
pg = get_postgres_service()
|
|
360
|
+
if pg is None:
|
|
361
|
+
raise RuntimeError("Database not configured - set POSTGRES__CONNECTION_STRING")
|
|
362
|
+
|
|
363
|
+
await pg.connect()
|
|
364
|
+
# ... use pg ...
|
|
365
|
+
await pg.disconnect()
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Option 2: Direct instantiation**
|
|
369
|
+
|
|
351
370
|
```python
|
|
352
|
-
from rem.services.postgres import PostgresService
|
|
371
|
+
from rem.services.postgres import PostgresService
|
|
353
372
|
|
|
354
373
|
service = PostgresService(
|
|
355
374
|
connection_string="postgresql://user:pass@localhost/remdb",
|
|
@@ -359,6 +378,9 @@ service = PostgresService(
|
|
|
359
378
|
await service.connect()
|
|
360
379
|
```
|
|
361
380
|
|
|
381
|
+
> **Note**: `get_postgres_service()` returns the service directly. It does NOT support
|
|
382
|
+
> `async with` context manager syntax. Always call `connect()` and `disconnect()` explicitly.
|
|
383
|
+
|
|
362
384
|
### Using Repository Pattern
|
|
363
385
|
|
|
364
386
|
**Generic Repository** for simple CRUD operations:
|
|
@@ -514,35 +536,195 @@ results = await service.vector_search(
|
|
|
514
536
|
- HNSW parameters: `m=16, ef_construction=64` (tunable)
|
|
515
537
|
- Monitor shared_buffers and work_mem
|
|
516
538
|
|
|
517
|
-
##
|
|
539
|
+
## Schema Management
|
|
518
540
|
|
|
519
|
-
|
|
541
|
+
REM uses a **code-as-source-of-truth** approach. Pydantic models define the schema, and the database is kept in sync via diff-based migrations.
|
|
520
542
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
543
|
+
### File Structure
|
|
544
|
+
|
|
545
|
+
```
|
|
546
|
+
src/rem/sql/
|
|
547
|
+
├── migrations/
|
|
548
|
+
│ ├── 001_install.sql # Core infrastructure (manual)
|
|
549
|
+
│ └── 002_install_models.sql # Entity tables (auto-generated)
|
|
550
|
+
└── background_indexes.sql # HNSW vector indexes (optional)
|
|
525
551
|
```
|
|
526
552
|
|
|
527
|
-
|
|
553
|
+
**Key principle**: Only two migration files. No incremental `003_`, `004_` files.
|
|
554
|
+
|
|
555
|
+
### CLI Commands
|
|
528
556
|
|
|
529
557
|
```bash
|
|
530
|
-
|
|
558
|
+
# Apply migrations (installs extensions, core tables, entity tables)
|
|
559
|
+
rem db migrate
|
|
560
|
+
|
|
561
|
+
# Check migration status
|
|
562
|
+
rem db status
|
|
563
|
+
|
|
564
|
+
# Generate schema SQL from models (for remdb development)
|
|
565
|
+
rem db schema generate --models src/rem/models/entities
|
|
566
|
+
|
|
567
|
+
# Validate models for schema generation
|
|
568
|
+
rem db schema validate --models src/rem/models/entities
|
|
531
569
|
```
|
|
532
570
|
|
|
533
|
-
|
|
571
|
+
### Model Registry
|
|
534
572
|
|
|
535
|
-
|
|
573
|
+
Models are discovered via the registry:
|
|
536
574
|
|
|
537
|
-
```
|
|
538
|
-
|
|
575
|
+
```python
|
|
576
|
+
import rem
|
|
577
|
+
from rem.models.core import CoreModel
|
|
578
|
+
|
|
579
|
+
@rem.register_model
|
|
580
|
+
class MyEntity(CoreModel):
|
|
581
|
+
name: str
|
|
582
|
+
description: str # Auto-embeds
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
## Using REM as a Library (Downstream Apps)
|
|
586
|
+
|
|
587
|
+
When building an application that **depends on remdb as a package** (e.g., `pip install remdb`),
|
|
588
|
+
there are important differences from developing remdb itself.
|
|
589
|
+
|
|
590
|
+
### What Works Out of the Box
|
|
591
|
+
|
|
592
|
+
1. **All core entity tables** - Resources, Messages, Users, Sessions, etc.
|
|
593
|
+
2. **PostgresService** - Full database access via `get_postgres_service()`
|
|
594
|
+
3. **Repository pattern** - CRUD operations for core entities
|
|
595
|
+
4. **Migrations** - `rem db migrate` applies the bundled SQL files
|
|
596
|
+
|
|
597
|
+
```python
|
|
598
|
+
# In your downstream app (e.g., myapp/main.py)
|
|
599
|
+
from rem.services.postgres import get_postgres_service
|
|
600
|
+
from rem.models.entities import Message, Resource
|
|
601
|
+
|
|
602
|
+
pg = get_postgres_service()
|
|
603
|
+
await pg.connect()
|
|
604
|
+
|
|
605
|
+
# Use core entities - tables already exist
|
|
606
|
+
messages = await pg.query(Message, {"session_id": "abc"})
|
|
539
607
|
```
|
|
540
608
|
|
|
541
|
-
|
|
609
|
+
### Custom Models in Downstream Apps
|
|
610
|
+
|
|
611
|
+
The `@rem.register_model` decorator registers models in the **runtime registry**, which is useful for:
|
|
612
|
+
- Schema introspection at runtime
|
|
613
|
+
- Future tooling that reads the registry
|
|
614
|
+
|
|
615
|
+
However, **`rem db migrate` only applies SQL files bundled in the remdb package**.
|
|
616
|
+
Custom models from downstream apps do NOT automatically get tables created.
|
|
617
|
+
|
|
618
|
+
**Options for custom model tables:**
|
|
619
|
+
|
|
620
|
+
**Option A: Use core entities with metadata**
|
|
621
|
+
|
|
622
|
+
Store custom data in the `metadata` JSONB field of existing entities:
|
|
623
|
+
|
|
624
|
+
```python
|
|
625
|
+
resource = Resource(
|
|
626
|
+
name="my-custom-thing",
|
|
627
|
+
content="...",
|
|
628
|
+
metadata={"custom_field": "value", "another": 123}
|
|
629
|
+
)
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
**Option B: Create tables manually**
|
|
633
|
+
|
|
634
|
+
Write and apply your own SQL:
|
|
635
|
+
|
|
636
|
+
```sql
|
|
637
|
+
-- myapp/sql/custom_tables.sql
|
|
638
|
+
CREATE TABLE IF NOT EXISTS conversation_summaries (
|
|
639
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
640
|
+
session_ref TEXT NOT NULL,
|
|
641
|
+
summary TEXT NOT NULL,
|
|
642
|
+
-- ... include CoreModel fields for compatibility
|
|
643
|
+
user_id VARCHAR(256),
|
|
644
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
645
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
646
|
+
);
|
|
647
|
+
```
|
|
542
648
|
|
|
543
649
|
```bash
|
|
544
|
-
|
|
650
|
+
psql $DATABASE_URL -f myapp/sql/custom_tables.sql
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
**Option C: Contribute upstream**
|
|
654
|
+
|
|
655
|
+
If your model is generally useful, contribute it to remdb so it's included in
|
|
656
|
+
the next release and `rem db migrate` creates it automatically.
|
|
657
|
+
|
|
658
|
+
### Example: Downstream App Structure
|
|
659
|
+
|
|
545
660
|
```
|
|
661
|
+
myapp/
|
|
662
|
+
├── main.py # Import models, start API
|
|
663
|
+
├── models/
|
|
664
|
+
│ └── __init__.py # @rem.register_model decorators
|
|
665
|
+
├── sql/
|
|
666
|
+
│ └── custom.sql # Manual migrations for custom tables
|
|
667
|
+
├── .env # POSTGRES__CONNECTION_STRING, LLM keys
|
|
668
|
+
└── pyproject.toml # dependencies = ["remdb>=0.3.110"]
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
```python
|
|
672
|
+
# myapp/models/__init__.py
|
|
673
|
+
import rem
|
|
674
|
+
from rem.models.core import CoreModel
|
|
675
|
+
|
|
676
|
+
@rem.register_model
|
|
677
|
+
class ConversationSummary(CoreModel):
|
|
678
|
+
"""Registered for introspection, but table created via sql/custom.sql"""
|
|
679
|
+
session_ref: str
|
|
680
|
+
summary: str
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
```python
|
|
684
|
+
# myapp/main.py
|
|
685
|
+
import models # Registers custom models
|
|
686
|
+
|
|
687
|
+
from rem.api.main import app # Use REM's FastAPI app
|
|
688
|
+
# Or build your own app using rem.services
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
## Adding Models & Migrations
|
|
692
|
+
|
|
693
|
+
Quick workflow for adding new database models:
|
|
694
|
+
|
|
695
|
+
1. **Create a model** in `models/__init__.py` (or a submodule):
|
|
696
|
+
```python
|
|
697
|
+
import rem
|
|
698
|
+
from rem.models.core import CoreModel
|
|
699
|
+
|
|
700
|
+
@rem.register_model
|
|
701
|
+
class MyEntity(CoreModel):
|
|
702
|
+
name: str
|
|
703
|
+
description: str # Auto-embedded (common field name)
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
2. **Check for schema drift** - REM auto-detects `./models` directory:
|
|
707
|
+
```bash
|
|
708
|
+
rem db diff # Show pending changes (additive only)
|
|
709
|
+
rem db diff --strategy full # Include destructive changes
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
3. **Generate migration** (optional - for version-controlled SQL):
|
|
713
|
+
```bash
|
|
714
|
+
rem db diff --generate # Creates numbered .sql file
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
4. **Apply changes**:
|
|
718
|
+
```bash
|
|
719
|
+
rem db migrate # Apply all pending migrations
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
**Key points:**
|
|
723
|
+
- Models in `./models/` are auto-discovered (must have `__init__.py`)
|
|
724
|
+
- Or set `MODELS__IMPORT_MODULES=myapp.models` for custom paths
|
|
725
|
+
- `CoreModel` provides: `id`, `tenant_id`, `user_id`, `created_at`, `updated_at`, `deleted_at`, `graph_edges`, `metadata`, `tags`
|
|
726
|
+
- Fields named `content`, `description`, `summary`, `text`, `body`, `message`, `notes` get embeddings by default
|
|
727
|
+
- Use `Field(json_schema_extra={"embed": True})` to embed other fields
|
|
546
728
|
|
|
547
729
|
## Configuration
|
|
548
730
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
PostgreSQL service for CloudNativePG database operations.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from .diff_service import DiffService, SchemaDiff
|
|
5
6
|
from .repository import Repository
|
|
6
7
|
from .service import PostgresService
|
|
7
8
|
|
|
@@ -20,4 +21,4 @@ def get_postgres_service() -> PostgresService | None:
|
|
|
20
21
|
return PostgresService()
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
__all__ = ["PostgresService", "get_postgres_service", "Repository"]
|
|
24
|
+
__all__ = ["PostgresService", "get_postgres_service", "Repository", "DiffService", "SchemaDiff"]
|