shellbrain 0.1.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.
- app/__init__.py +1 -0
- app/__main__.py +7 -0
- app/boot/__init__.py +1 -0
- app/boot/admin_db.py +88 -0
- app/boot/config.py +14 -0
- app/boot/create_policy.py +52 -0
- app/boot/db.py +70 -0
- app/boot/embeddings.py +55 -0
- app/boot/home.py +45 -0
- app/boot/migrations.py +61 -0
- app/boot/read_policy.py +179 -0
- app/boot/repos.py +15 -0
- app/boot/retrieval.py +3 -0
- app/boot/thresholds.py +19 -0
- app/boot/update_policy.py +34 -0
- app/boot/use_cases.py +22 -0
- app/config/__init__.py +1 -0
- app/config/defaults/create_policy.yaml +7 -0
- app/config/defaults/read_policy.yaml +25 -0
- app/config/defaults/runtime.yaml +10 -0
- app/config/defaults/thresholds.yaml +3 -0
- app/config/defaults/update_policy.yaml +5 -0
- app/config/loader.py +58 -0
- app/core/__init__.py +1 -0
- app/core/contracts/__init__.py +1 -0
- app/core/contracts/errors.py +29 -0
- app/core/contracts/requests.py +211 -0
- app/core/contracts/responses.py +15 -0
- app/core/entities/__init__.py +1 -0
- app/core/entities/associations.py +58 -0
- app/core/entities/episodes.py +66 -0
- app/core/entities/evidence.py +29 -0
- app/core/entities/facts.py +30 -0
- app/core/entities/guidance.py +47 -0
- app/core/entities/identity.py +48 -0
- app/core/entities/memory.py +34 -0
- app/core/entities/runtime_context.py +19 -0
- app/core/entities/session_state.py +31 -0
- app/core/entities/telemetry.py +152 -0
- app/core/entities/utility.py +14 -0
- app/core/interfaces/__init__.py +1 -0
- app/core/interfaces/clock.py +12 -0
- app/core/interfaces/config.py +28 -0
- app/core/interfaces/embeddings.py +12 -0
- app/core/interfaces/idgen.py +11 -0
- app/core/interfaces/repos.py +279 -0
- app/core/interfaces/retrieval.py +20 -0
- app/core/interfaces/session_state_store.py +33 -0
- app/core/interfaces/unit_of_work.py +50 -0
- app/core/policies/__init__.py +1 -0
- app/core/policies/_shared/__init__.py +1 -0
- app/core/policies/_shared/executor.py +132 -0
- app/core/policies/_shared/side_effects.py +9 -0
- app/core/policies/create_policy/__init__.py +1 -0
- app/core/policies/create_policy/pipeline.py +96 -0
- app/core/policies/read_policy/__init__.py +1 -0
- app/core/policies/read_policy/bm25.py +114 -0
- app/core/policies/read_policy/context_pack_builder.py +140 -0
- app/core/policies/read_policy/expansion.py +132 -0
- app/core/policies/read_policy/fusion_rrf.py +34 -0
- app/core/policies/read_policy/lexical_query.py +101 -0
- app/core/policies/read_policy/pipeline.py +93 -0
- app/core/policies/read_policy/scenario_lift.py +11 -0
- app/core/policies/read_policy/scoring.py +61 -0
- app/core/policies/read_policy/seed_retrieval.py +54 -0
- app/core/policies/read_policy/utility_prior.py +11 -0
- app/core/policies/update_policy/__init__.py +1 -0
- app/core/policies/update_policy/pipeline.py +80 -0
- app/core/use_cases/__init__.py +1 -0
- app/core/use_cases/build_guidance.py +85 -0
- app/core/use_cases/create_memory.py +26 -0
- app/core/use_cases/manage_session_state.py +159 -0
- app/core/use_cases/read_memory.py +21 -0
- app/core/use_cases/record_episode_sync_telemetry.py +19 -0
- app/core/use_cases/record_operation_telemetry.py +32 -0
- app/core/use_cases/sync_episode.py +162 -0
- app/core/use_cases/update_memory.py +40 -0
- app/migrations/__init__.py +1 -0
- app/migrations/env.py +65 -0
- app/migrations/versions/20260226_0001_initial_schema.py +232 -0
- app/migrations/versions/20260312_0002_add_hard_invariants.py +60 -0
- app/migrations/versions/20260312_0003_drop_create_confidence.py +40 -0
- app/migrations/versions/20260313_0004_episode_sync_hardening.py +71 -0
- app/migrations/versions/20260313_0005_evidence_episode_event_refs.py +45 -0
- app/migrations/versions/20260318_0006_usage_telemetry_schema.py +175 -0
- app/migrations/versions/20260319_0007_identity_session_guidance.py +49 -0
- app/migrations/versions/20260320_0008_instance_metadata_and_backup_safety.py +31 -0
- app/migrations/versions/__init__.py +1 -0
- app/periphery/__init__.py +1 -0
- app/periphery/admin/__init__.py +1 -0
- app/periphery/admin/backup.py +360 -0
- app/periphery/admin/destructive_guard.py +32 -0
- app/periphery/admin/doctor.py +192 -0
- app/periphery/admin/init.py +996 -0
- app/periphery/admin/instance_guard.py +211 -0
- app/periphery/admin/machine_state.py +354 -0
- app/periphery/admin/privileges.py +42 -0
- app/periphery/admin/repo_state.py +266 -0
- app/periphery/admin/restore.py +30 -0
- app/periphery/cli/__init__.py +1 -0
- app/periphery/cli/handlers.py +830 -0
- app/periphery/cli/hydration.py +119 -0
- app/periphery/cli/main.py +710 -0
- app/periphery/cli/presenter_json.py +10 -0
- app/periphery/cli/schema_validation.py +201 -0
- app/periphery/db/__init__.py +1 -0
- app/periphery/db/engine.py +10 -0
- app/periphery/db/models/__init__.py +1 -0
- app/periphery/db/models/associations.py +55 -0
- app/periphery/db/models/episodes.py +55 -0
- app/periphery/db/models/evidence.py +19 -0
- app/periphery/db/models/experiences.py +33 -0
- app/periphery/db/models/instance_metadata.py +17 -0
- app/periphery/db/models/memories.py +39 -0
- app/periphery/db/models/metadata.py +6 -0
- app/periphery/db/models/registry.py +18 -0
- app/periphery/db/models/telemetry.py +174 -0
- app/periphery/db/models/utility.py +19 -0
- app/periphery/db/models/views.py +154 -0
- app/periphery/db/repos/__init__.py +1 -0
- app/periphery/db/repos/relational/__init__.py +1 -0
- app/periphery/db/repos/relational/associations_repo.py +117 -0
- app/periphery/db/repos/relational/episodes_repo.py +188 -0
- app/periphery/db/repos/relational/evidence_repo.py +82 -0
- app/periphery/db/repos/relational/experiences_repo.py +41 -0
- app/periphery/db/repos/relational/memories_repo.py +99 -0
- app/periphery/db/repos/relational/read_policy_repo.py +202 -0
- app/periphery/db/repos/relational/telemetry_repo.py +161 -0
- app/periphery/db/repos/relational/utility_repo.py +30 -0
- app/periphery/db/repos/semantic/__init__.py +1 -0
- app/periphery/db/repos/semantic/keyword_retrieval_repo.py +63 -0
- app/periphery/db/repos/semantic/semantic_retrieval_repo.py +111 -0
- app/periphery/db/session.py +10 -0
- app/periphery/db/uow.py +75 -0
- app/periphery/embeddings/__init__.py +1 -0
- app/periphery/embeddings/local_provider.py +35 -0
- app/periphery/embeddings/query_vector_search.py +18 -0
- app/periphery/episodes/__init__.py +1 -0
- app/periphery/episodes/claude_code.py +387 -0
- app/periphery/episodes/codex.py +423 -0
- app/periphery/episodes/launcher.py +66 -0
- app/periphery/episodes/normalization.py +31 -0
- app/periphery/episodes/poller.py +299 -0
- app/periphery/episodes/source_discovery.py +66 -0
- app/periphery/episodes/tool_filter.py +165 -0
- app/periphery/identity/__init__.py +1 -0
- app/periphery/identity/claude_hook_install.py +67 -0
- app/periphery/identity/claude_runtime.py +83 -0
- app/periphery/identity/codex_runtime.py +32 -0
- app/periphery/identity/compatibility.py +38 -0
- app/periphery/identity/resolver.py +163 -0
- app/periphery/session_state/__init__.py +1 -0
- app/periphery/session_state/file_store.py +100 -0
- app/periphery/telemetry/__init__.py +33 -0
- app/periphery/telemetry/operation_summary.py +299 -0
- app/periphery/telemetry/session_selection.py +156 -0
- app/periphery/telemetry/sync_summary.py +65 -0
- app/periphery/validation/__init__.py +1 -0
- app/periphery/validation/integrity_validation.py +253 -0
- app/periphery/validation/semantic_validation.py +94 -0
- shellbrain-0.1.0.dist-info/METADATA +130 -0
- shellbrain-0.1.0.dist-info/RECORD +165 -0
- shellbrain-0.1.0.dist-info/WHEEL +5 -0
- shellbrain-0.1.0.dist-info/entry_points.txt +2 -0
- shellbrain-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""This module defines deterministic JSON presentation helpers for CLI responses."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def render(payload: dict[str, Any]) -> str:
|
|
8
|
+
"""This function renders payloads as deterministic compact JSON output."""
|
|
9
|
+
|
|
10
|
+
return json.dumps(payload, separators=(",", ":"))
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""CLI schema-validation helpers for strict request contracts."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Literal
|
|
4
|
+
|
|
5
|
+
from pydantic import Field, ValidationError, field_validator
|
|
6
|
+
|
|
7
|
+
from app.core.contracts.errors import ErrorCode, ErrorDetail
|
|
8
|
+
from app.core.contracts.requests import (
|
|
9
|
+
BatchUtilityVoteItem,
|
|
10
|
+
EpisodeEventsRequest,
|
|
11
|
+
MemoryBatchUpdateRequest,
|
|
12
|
+
MemoryCreateLinks,
|
|
13
|
+
MemoryCreateRequest,
|
|
14
|
+
MemoryReadRequest,
|
|
15
|
+
MemoryUpdateRequest,
|
|
16
|
+
StrictBaseModel,
|
|
17
|
+
UpdatePayload,
|
|
18
|
+
UtilityVoteUpdate,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AgentReadRequest(StrictBaseModel):
|
|
23
|
+
"""Agent-facing read payload with config-only retrieval knobs removed."""
|
|
24
|
+
|
|
25
|
+
op: Literal["read"] = "read"
|
|
26
|
+
repo_id: str | None = None
|
|
27
|
+
mode: Literal["ambient", "targeted"] | None = None
|
|
28
|
+
query: str = Field(min_length=1)
|
|
29
|
+
include_global: bool | None = None
|
|
30
|
+
kinds: (
|
|
31
|
+
list[Literal["problem", "solution", "failed_tactic", "fact", "preference", "change"]] | None
|
|
32
|
+
) = None
|
|
33
|
+
limit: int | None = Field(default=None, ge=1, le=100)
|
|
34
|
+
|
|
35
|
+
@field_validator("kinds")
|
|
36
|
+
@classmethod
|
|
37
|
+
def _validate_kinds_unique(
|
|
38
|
+
cls,
|
|
39
|
+
value: list[Literal["problem", "solution", "failed_tactic", "fact", "preference", "change"]] | None,
|
|
40
|
+
) -> list[Literal["problem", "solution", "failed_tactic", "fact", "preference", "change"]] | None:
|
|
41
|
+
"""This validator enforces unique kinds filters for agent read requests."""
|
|
42
|
+
|
|
43
|
+
if value is None:
|
|
44
|
+
return value
|
|
45
|
+
if len(value) != len(set(value)):
|
|
46
|
+
raise ValueError("kinds must be unique")
|
|
47
|
+
return value
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class AgentCreateBody(StrictBaseModel):
|
|
51
|
+
"""Agent-facing create payload with transport fields removed."""
|
|
52
|
+
|
|
53
|
+
text: str
|
|
54
|
+
scope: Literal["repo", "global"] | None = None
|
|
55
|
+
kind: Literal["problem", "solution", "failed_tactic", "fact", "preference", "change"]
|
|
56
|
+
rationale: str | None = None
|
|
57
|
+
links: MemoryCreateLinks = Field(default_factory=MemoryCreateLinks)
|
|
58
|
+
evidence_refs: list[str] = Field(min_length=1)
|
|
59
|
+
|
|
60
|
+
@field_validator("evidence_refs")
|
|
61
|
+
@classmethod
|
|
62
|
+
def _validate_evidence_unique(cls, value: list[str]) -> list[str]:
|
|
63
|
+
"""This validator enforces unique evidence references for agent create requests."""
|
|
64
|
+
|
|
65
|
+
if len(value) != len(set(value)):
|
|
66
|
+
raise ValueError("evidence_refs must be unique")
|
|
67
|
+
return value
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class AgentCreateRequest(StrictBaseModel):
|
|
71
|
+
"""Agent-facing create payload with repo/op transport details removed."""
|
|
72
|
+
|
|
73
|
+
memory: AgentCreateBody
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class AgentEventsRequest(StrictBaseModel):
|
|
77
|
+
"""Agent-facing events payload with transport fields removed."""
|
|
78
|
+
|
|
79
|
+
limit: int | None = Field(default=None, ge=1, le=100)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class AgentUpdateRequest(StrictBaseModel):
|
|
83
|
+
"""Agent-facing update payload with repo/op transport details removed."""
|
|
84
|
+
|
|
85
|
+
memory_id: str
|
|
86
|
+
update: UpdatePayload
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class AgentBatchUpdateItem(StrictBaseModel):
|
|
90
|
+
"""Agent-facing batch utility item with transport fields removed."""
|
|
91
|
+
|
|
92
|
+
memory_id: str
|
|
93
|
+
update: UtilityVoteUpdate
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class AgentBatchUpdateRequest(StrictBaseModel):
|
|
97
|
+
"""Agent-facing batch utility update payload."""
|
|
98
|
+
|
|
99
|
+
updates: list[AgentBatchUpdateItem] = Field(min_length=1)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _format_validation_errors(exc: ValidationError) -> list[ErrorDetail]:
|
|
103
|
+
"""Convert Pydantic validation errors into contract error details."""
|
|
104
|
+
|
|
105
|
+
details: list[ErrorDetail] = []
|
|
106
|
+
for item in exc.errors():
|
|
107
|
+
path = ".".join(str(segment) for segment in item.get("loc", ()))
|
|
108
|
+
message = item.get("msg", "Schema validation failed")
|
|
109
|
+
if path in {"memory.evidence_refs", "update.evidence_refs"} and item.get("type") in {
|
|
110
|
+
"too_short",
|
|
111
|
+
"missing",
|
|
112
|
+
}:
|
|
113
|
+
message = "evidence_refs must include at least one stored episode event id; query events first"
|
|
114
|
+
details.append(
|
|
115
|
+
ErrorDetail(
|
|
116
|
+
code=ErrorCode.SCHEMA_ERROR,
|
|
117
|
+
message=message,
|
|
118
|
+
field=path or None,
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
return details
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def validate_create_schema(payload: dict[str, Any]) -> tuple[AgentCreateRequest | None, list[ErrorDetail]]:
|
|
125
|
+
"""Validate and parse agent create payloads into the simplified create contract."""
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
return AgentCreateRequest.model_validate(payload), []
|
|
129
|
+
except ValidationError as exc:
|
|
130
|
+
return None, _format_validation_errors(exc)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def validate_read_schema(payload: dict[str, Any]) -> tuple[AgentReadRequest | None, list[ErrorDetail]]:
|
|
134
|
+
"""Validate and parse agent read payloads into the simplified read contract."""
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
return AgentReadRequest.model_validate(payload), []
|
|
138
|
+
except ValidationError as exc:
|
|
139
|
+
return None, _format_validation_errors(exc)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def validate_events_schema(payload: dict[str, Any]) -> tuple[AgentEventsRequest | None, list[ErrorDetail]]:
|
|
143
|
+
"""Validate and parse agent events payloads into the simplified events contract."""
|
|
144
|
+
|
|
145
|
+
try:
|
|
146
|
+
return AgentEventsRequest.model_validate(payload), []
|
|
147
|
+
except ValidationError as exc:
|
|
148
|
+
return None, _format_validation_errors(exc)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def validate_internal_read_contract(payload: dict[str, Any]) -> tuple[MemoryReadRequest | None, list[ErrorDetail]]:
|
|
152
|
+
"""Validate one hydrated read payload against the full internal read contract."""
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
return MemoryReadRequest.model_validate(payload), []
|
|
156
|
+
except ValidationError as exc:
|
|
157
|
+
return None, _format_validation_errors(exc)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def validate_internal_events_contract(
|
|
161
|
+
payload: dict[str, Any],
|
|
162
|
+
) -> tuple[EpisodeEventsRequest | None, list[ErrorDetail]]:
|
|
163
|
+
"""Validate one hydrated events payload against the full internal events contract."""
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
return EpisodeEventsRequest.model_validate(payload), []
|
|
167
|
+
except ValidationError as exc:
|
|
168
|
+
return None, _format_validation_errors(exc)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def validate_internal_create_contract(payload: dict[str, Any]) -> tuple[MemoryCreateRequest | None, list[ErrorDetail]]:
|
|
172
|
+
"""Validate one hydrated create payload against the full internal create contract."""
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
return MemoryCreateRequest.model_validate(payload), []
|
|
176
|
+
except ValidationError as exc:
|
|
177
|
+
return None, _format_validation_errors(exc)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def validate_update_schema(payload: dict[str, Any]) -> tuple[AgentUpdateRequest | None, list[ErrorDetail]]:
|
|
181
|
+
"""Validate and parse agent update payloads into the simplified update contract."""
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
if "updates" in payload:
|
|
185
|
+
return AgentBatchUpdateRequest.model_validate(payload), []
|
|
186
|
+
return AgentUpdateRequest.model_validate(payload), []
|
|
187
|
+
except ValidationError as exc:
|
|
188
|
+
return None, _format_validation_errors(exc)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def validate_internal_update_contract(
|
|
192
|
+
payload: dict[str, Any],
|
|
193
|
+
) -> tuple[MemoryUpdateRequest | MemoryBatchUpdateRequest | None, list[ErrorDetail]]:
|
|
194
|
+
"""Validate one hydrated update payload against the full internal update contract."""
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
if "updates" in payload:
|
|
198
|
+
return MemoryBatchUpdateRequest.model_validate(payload), []
|
|
199
|
+
return MemoryUpdateRequest.model_validate(payload), []
|
|
200
|
+
except ValidationError as exc:
|
|
201
|
+
return None, _format_validation_errors(exc)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""This package contains database models, repositories, and transaction wiring."""
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""This module defines PostgreSQL engine construction helpers for application boot wiring."""
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import create_engine
|
|
4
|
+
from sqlalchemy.engine import Engine
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_engine(dsn: str) -> Engine:
|
|
8
|
+
"""This function creates a SQLAlchemy engine for the provided PostgreSQL DSN."""
|
|
9
|
+
|
|
10
|
+
return create_engine(dsn, future=True)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""This package defines SQLAlchemy Core table and view metadata."""
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""This module defines SQLAlchemy Core tables for association edges and observations."""
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import CheckConstraint, Column, Float, ForeignKey, Integer, String, Table, UniqueConstraint
|
|
4
|
+
from sqlalchemy.dialects.postgresql import TIMESTAMP
|
|
5
|
+
|
|
6
|
+
from app.periphery.db.models.metadata import metadata
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
association_edges = Table(
|
|
10
|
+
"association_edges",
|
|
11
|
+
metadata,
|
|
12
|
+
Column("id", String, primary_key=True),
|
|
13
|
+
Column("repo_id", String, nullable=False),
|
|
14
|
+
Column("from_memory_id", String, ForeignKey("memories.id", ondelete="CASCADE"), nullable=False),
|
|
15
|
+
Column("to_memory_id", String, ForeignKey("memories.id", ondelete="CASCADE"), nullable=False),
|
|
16
|
+
Column("relation_type", String, nullable=False),
|
|
17
|
+
Column("source_mode", String, nullable=False),
|
|
18
|
+
Column("state", String, nullable=False),
|
|
19
|
+
Column("strength", Float, nullable=False, default=0.0),
|
|
20
|
+
Column("obs_count", Integer, nullable=False, default=0),
|
|
21
|
+
Column("positive_obs", Integer, nullable=False, default=0),
|
|
22
|
+
Column("negative_obs", Integer, nullable=False, default=0),
|
|
23
|
+
Column("salience_sum", Float, nullable=False, default=0.0),
|
|
24
|
+
Column("last_reinforced_at", TIMESTAMP(timezone=True)),
|
|
25
|
+
Column("last_used_at", TIMESTAMP(timezone=True)),
|
|
26
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False),
|
|
27
|
+
Column("updated_at", TIMESTAMP(timezone=True), nullable=False),
|
|
28
|
+
CheckConstraint("from_memory_id <> to_memory_id", name="ck_association_edges_no_self_loop"),
|
|
29
|
+
UniqueConstraint("repo_id", "from_memory_id", "to_memory_id", "relation_type", name="uq_association_edges_pair"),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
association_observations = Table(
|
|
33
|
+
"association_observations",
|
|
34
|
+
metadata,
|
|
35
|
+
Column("id", String, primary_key=True),
|
|
36
|
+
Column("repo_id", String, nullable=False),
|
|
37
|
+
Column("edge_id", String, ForeignKey("association_edges.id", ondelete="CASCADE")),
|
|
38
|
+
Column("from_memory_id", String, ForeignKey("memories.id", ondelete="CASCADE"), nullable=False),
|
|
39
|
+
Column("to_memory_id", String, ForeignKey("memories.id", ondelete="CASCADE"), nullable=False),
|
|
40
|
+
Column("relation_type", String, nullable=False),
|
|
41
|
+
Column("source", String, nullable=False),
|
|
42
|
+
Column("problem_id", String, ForeignKey("memories.id", ondelete="SET NULL")),
|
|
43
|
+
Column("episode_id", String, ForeignKey("episodes.id", ondelete="SET NULL")),
|
|
44
|
+
Column("valence", Float, nullable=False),
|
|
45
|
+
Column("salience", Float, nullable=False, default=0.5),
|
|
46
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False),
|
|
47
|
+
CheckConstraint("from_memory_id <> to_memory_id", name="ck_association_observations_no_self_loop"),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
association_edge_evidence = Table(
|
|
51
|
+
"association_edge_evidence",
|
|
52
|
+
metadata,
|
|
53
|
+
Column("edge_id", String, ForeignKey("association_edges.id", ondelete="CASCADE"), primary_key=True),
|
|
54
|
+
Column("evidence_id", String, ForeignKey("evidence_refs.id", ondelete="CASCADE"), primary_key=True),
|
|
55
|
+
)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""This module defines SQLAlchemy Core tables for episodes, events, and session transfers."""
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import CheckConstraint, Column, ForeignKey, Integer, String, Table, Text, UniqueConstraint
|
|
4
|
+
from sqlalchemy.dialects.postgresql import TIMESTAMP
|
|
5
|
+
|
|
6
|
+
from app.periphery.db.models.metadata import metadata
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
episodes = Table(
|
|
10
|
+
"episodes",
|
|
11
|
+
metadata,
|
|
12
|
+
Column("id", String, primary_key=True),
|
|
13
|
+
Column("repo_id", String, nullable=False),
|
|
14
|
+
Column("host_app", String, nullable=False),
|
|
15
|
+
Column("thread_id", String),
|
|
16
|
+
Column("title", String),
|
|
17
|
+
Column("objective", String),
|
|
18
|
+
Column("status", String, nullable=False),
|
|
19
|
+
Column("started_at", TIMESTAMP(timezone=True), nullable=False),
|
|
20
|
+
Column("ended_at", TIMESTAMP(timezone=True)),
|
|
21
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False),
|
|
22
|
+
UniqueConstraint("repo_id", "thread_id", name="uq_episodes_repo_thread"),
|
|
23
|
+
CheckConstraint("ended_at IS NULL OR ended_at >= started_at", name="ck_episodes_ended_after_started"),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
episode_events = Table(
|
|
27
|
+
"episode_events",
|
|
28
|
+
metadata,
|
|
29
|
+
Column("id", String, primary_key=True),
|
|
30
|
+
Column("episode_id", String, ForeignKey("episodes.id", ondelete="CASCADE"), nullable=False),
|
|
31
|
+
Column("seq", Integer, nullable=False),
|
|
32
|
+
Column("host_event_key", String, nullable=False),
|
|
33
|
+
Column("source", String, nullable=False),
|
|
34
|
+
Column("content", Text, nullable=False),
|
|
35
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False),
|
|
36
|
+
CheckConstraint("seq > 0", name="ck_episode_events_seq_positive"),
|
|
37
|
+
UniqueConstraint("episode_id", "seq", name="uq_episode_events_seq"),
|
|
38
|
+
UniqueConstraint("episode_id", "host_event_key", name="uq_episode_events_host_event_key"),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
session_transfers = Table(
|
|
42
|
+
"session_transfers",
|
|
43
|
+
metadata,
|
|
44
|
+
Column("id", String, primary_key=True),
|
|
45
|
+
Column("repo_id", String, nullable=False),
|
|
46
|
+
Column("from_episode_id", String, ForeignKey("episodes.id", ondelete="CASCADE"), nullable=False),
|
|
47
|
+
Column("to_episode_id", String, ForeignKey("episodes.id", ondelete="CASCADE"), nullable=False),
|
|
48
|
+
Column("event_id", String, ForeignKey("episode_events.id", ondelete="CASCADE"), nullable=False),
|
|
49
|
+
Column("transfer_kind", String, nullable=False),
|
|
50
|
+
Column("rationale", Text),
|
|
51
|
+
Column("transferred_by", String),
|
|
52
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False),
|
|
53
|
+
CheckConstraint("from_episode_id <> to_episode_id", name="ck_session_transfers_distinct_episodes"),
|
|
54
|
+
UniqueConstraint("from_episode_id", "to_episode_id", "event_id", "transfer_kind", name="uq_session_transfers_transfer"),
|
|
55
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""This module defines SQLAlchemy Core tables for evidence reference records."""
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import Column, ForeignKey, String, Table, UniqueConstraint
|
|
4
|
+
from sqlalchemy.dialects.postgresql import TIMESTAMP
|
|
5
|
+
|
|
6
|
+
from app.periphery.db.models.metadata import metadata
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
evidence_refs = Table(
|
|
10
|
+
"evidence_refs",
|
|
11
|
+
metadata,
|
|
12
|
+
Column("id", String, primary_key=True),
|
|
13
|
+
Column("repo_id", String, nullable=False),
|
|
14
|
+
Column("ref", String, nullable=False),
|
|
15
|
+
Column("episode_event_id", String, ForeignKey("episode_events.id"), nullable=True),
|
|
16
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False),
|
|
17
|
+
UniqueConstraint("repo_id", "ref", name="uq_evidence_repo_ref"),
|
|
18
|
+
UniqueConstraint("repo_id", "episode_event_id", name="uq_evidence_repo_episode_event"),
|
|
19
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""This module defines SQLAlchemy Core tables for problem attempts and fact updates."""
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import CheckConstraint, Column, ForeignKey, String, Table, UniqueConstraint
|
|
4
|
+
from sqlalchemy.dialects.postgresql import TIMESTAMP
|
|
5
|
+
|
|
6
|
+
from app.periphery.db.models.metadata import metadata
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
problem_attempts = Table(
|
|
10
|
+
"problem_attempts",
|
|
11
|
+
metadata,
|
|
12
|
+
Column("problem_id", String, ForeignKey("memories.id", ondelete="CASCADE"), primary_key=True),
|
|
13
|
+
Column("attempt_id", String, ForeignKey("memories.id", ondelete="CASCADE"), primary_key=True),
|
|
14
|
+
Column("role", String, nullable=False),
|
|
15
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False),
|
|
16
|
+
CheckConstraint("problem_id <> attempt_id", name="ck_problem_attempts_distinct_memories"),
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
fact_updates = Table(
|
|
20
|
+
"fact_updates",
|
|
21
|
+
metadata,
|
|
22
|
+
Column("id", String, primary_key=True),
|
|
23
|
+
Column("old_fact_id", String, ForeignKey("memories.id", ondelete="CASCADE"), nullable=False),
|
|
24
|
+
Column("change_id", String, ForeignKey("memories.id", ondelete="CASCADE"), nullable=False),
|
|
25
|
+
Column("new_fact_id", String, ForeignKey("memories.id", ondelete="CASCADE"), nullable=False),
|
|
26
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False),
|
|
27
|
+
CheckConstraint("old_fact_id <> new_fact_id", name="ck_fact_updates_distinct_fact_endpoints"),
|
|
28
|
+
CheckConstraint(
|
|
29
|
+
"change_id <> old_fact_id AND change_id <> new_fact_id",
|
|
30
|
+
name="ck_fact_updates_change_id_distinct",
|
|
31
|
+
),
|
|
32
|
+
UniqueConstraint("old_fact_id", "change_id", "new_fact_id", name="uq_fact_updates_chain"),
|
|
33
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""SQLAlchemy Core table for instance classification and safety metadata."""
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import Column, String, Table, Text
|
|
4
|
+
from sqlalchemy.dialects.postgresql import TIMESTAMP
|
|
5
|
+
|
|
6
|
+
from app.periphery.db.models.metadata import metadata
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
instance_metadata = Table(
|
|
10
|
+
"instance_metadata",
|
|
11
|
+
metadata,
|
|
12
|
+
Column("instance_id", String, primary_key=True),
|
|
13
|
+
Column("instance_mode", String, nullable=False),
|
|
14
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False),
|
|
15
|
+
Column("created_by", String, nullable=False),
|
|
16
|
+
Column("notes", Text, nullable=True),
|
|
17
|
+
)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""This module defines SQLAlchemy Core tables for memories and shellbrain embeddings."""
|
|
2
|
+
|
|
3
|
+
from pgvector.sqlalchemy import Vector
|
|
4
|
+
from sqlalchemy import Boolean, CheckConstraint, Column, ForeignKey, Integer, String, Table, Text, UniqueConstraint
|
|
5
|
+
from sqlalchemy.dialects.postgresql import TIMESTAMP
|
|
6
|
+
|
|
7
|
+
from app.periphery.db.models.metadata import metadata
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
memories = Table(
|
|
11
|
+
"memories",
|
|
12
|
+
metadata,
|
|
13
|
+
Column("id", String, primary_key=True),
|
|
14
|
+
Column("repo_id", String, nullable=False),
|
|
15
|
+
Column("scope", String, nullable=False),
|
|
16
|
+
Column("kind", String, nullable=False),
|
|
17
|
+
Column("text", Text, nullable=False),
|
|
18
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False),
|
|
19
|
+
Column("archived", Boolean, nullable=False, default=False),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
memory_embeddings = Table(
|
|
23
|
+
"memory_embeddings",
|
|
24
|
+
metadata,
|
|
25
|
+
Column("memory_id", String, ForeignKey("memories.id", ondelete="CASCADE"), primary_key=True),
|
|
26
|
+
Column("model", String, nullable=False),
|
|
27
|
+
Column("dim", Integer, nullable=False),
|
|
28
|
+
Column("vector", Vector(), nullable=False),
|
|
29
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False),
|
|
30
|
+
CheckConstraint("dim > 0", name="ck_memory_embeddings_dim_positive"),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
memory_evidence = Table(
|
|
34
|
+
"memory_evidence",
|
|
35
|
+
metadata,
|
|
36
|
+
Column("memory_id", String, ForeignKey("memories.id", ondelete="CASCADE"), primary_key=True),
|
|
37
|
+
Column("evidence_id", String, ForeignKey("evidence_refs.id", ondelete="CASCADE"), primary_key=True),
|
|
38
|
+
UniqueConstraint("memory_id", "evidence_id", name="uq_memory_evidence_pair"),
|
|
39
|
+
)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""This module imports all SQLAlchemy table modules so metadata is fully registered."""
|
|
2
|
+
|
|
3
|
+
from app.periphery.db.models import (
|
|
4
|
+
associations,
|
|
5
|
+
episodes,
|
|
6
|
+
evidence,
|
|
7
|
+
experiences,
|
|
8
|
+
instance_metadata,
|
|
9
|
+
memories,
|
|
10
|
+
telemetry,
|
|
11
|
+
utility,
|
|
12
|
+
)
|
|
13
|
+
from app.periphery.db.models.metadata import metadata
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
_ = (associations, episodes, evidence, experiences, instance_metadata, memories, telemetry, utility)
|
|
17
|
+
|
|
18
|
+
target_metadata = metadata
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""SQLAlchemy Core tables for low-overhead usage telemetry storage."""
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import Boolean, Column, ForeignKey, Index, Integer, String, Table, Text, text
|
|
4
|
+
from sqlalchemy.dialects.postgresql import JSONB, TIMESTAMP
|
|
5
|
+
|
|
6
|
+
from app.periphery.db.models.metadata import metadata
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
operation_invocations = Table(
|
|
10
|
+
"operation_invocations",
|
|
11
|
+
metadata,
|
|
12
|
+
Column("id", String, primary_key=True),
|
|
13
|
+
Column("command", String, nullable=False),
|
|
14
|
+
Column("repo_id", String, nullable=False),
|
|
15
|
+
Column("repo_root", Text, nullable=False),
|
|
16
|
+
Column("no_sync", Boolean, nullable=False, server_default=text("FALSE")),
|
|
17
|
+
Column("caller_id", String),
|
|
18
|
+
Column("caller_trust_level", String),
|
|
19
|
+
Column("identity_failure_code", String),
|
|
20
|
+
Column("selected_host_app", String),
|
|
21
|
+
Column("selected_host_session_key", String),
|
|
22
|
+
Column("selected_thread_id", String),
|
|
23
|
+
Column("selected_episode_id", String),
|
|
24
|
+
Column("matching_candidate_count", Integer, nullable=False, server_default=text("0")),
|
|
25
|
+
Column("selection_ambiguous", Boolean, nullable=False, server_default=text("FALSE")),
|
|
26
|
+
Column("outcome", String, nullable=False),
|
|
27
|
+
Column("error_stage", String),
|
|
28
|
+
Column("error_code", String),
|
|
29
|
+
Column("error_message", Text),
|
|
30
|
+
Column("total_latency_ms", Integer, nullable=False),
|
|
31
|
+
Column("poller_start_attempted", Boolean, nullable=False, server_default=text("FALSE")),
|
|
32
|
+
Column("poller_started", Boolean, nullable=False, server_default=text("FALSE")),
|
|
33
|
+
Column("guidance_codes", JSONB, nullable=False, server_default=text("'[]'::jsonb")),
|
|
34
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False, server_default=text("NOW()")),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
read_invocation_summaries = Table(
|
|
38
|
+
"read_invocation_summaries",
|
|
39
|
+
metadata,
|
|
40
|
+
Column(
|
|
41
|
+
"invocation_id",
|
|
42
|
+
String,
|
|
43
|
+
ForeignKey("operation_invocations.id", ondelete="CASCADE"),
|
|
44
|
+
primary_key=True,
|
|
45
|
+
),
|
|
46
|
+
Column("query_text", Text, nullable=False),
|
|
47
|
+
Column("mode", String, nullable=False),
|
|
48
|
+
Column("requested_limit", Integer),
|
|
49
|
+
Column("effective_limit", Integer, nullable=False),
|
|
50
|
+
Column("include_global", Boolean),
|
|
51
|
+
Column("kinds_filter", JSONB),
|
|
52
|
+
Column("direct_count", Integer, nullable=False),
|
|
53
|
+
Column("explicit_related_count", Integer, nullable=False),
|
|
54
|
+
Column("implicit_related_count", Integer, nullable=False),
|
|
55
|
+
Column("total_returned", Integer, nullable=False),
|
|
56
|
+
Column("zero_results", Boolean, nullable=False),
|
|
57
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False, server_default=text("NOW()")),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
read_result_items = Table(
|
|
61
|
+
"read_result_items",
|
|
62
|
+
metadata,
|
|
63
|
+
Column(
|
|
64
|
+
"invocation_id",
|
|
65
|
+
String,
|
|
66
|
+
ForeignKey("operation_invocations.id", ondelete="CASCADE"),
|
|
67
|
+
primary_key=True,
|
|
68
|
+
),
|
|
69
|
+
Column("ordinal", Integer, primary_key=True),
|
|
70
|
+
Column("memory_id", String, nullable=False),
|
|
71
|
+
Column("kind", String, nullable=False),
|
|
72
|
+
Column("section", String, nullable=False),
|
|
73
|
+
Column("priority", Integer, nullable=False),
|
|
74
|
+
Column("why_included", String, nullable=False),
|
|
75
|
+
Column("anchor_memory_id", String),
|
|
76
|
+
Column("relation_type", String),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
write_invocation_summaries = Table(
|
|
80
|
+
"write_invocation_summaries",
|
|
81
|
+
metadata,
|
|
82
|
+
Column(
|
|
83
|
+
"invocation_id",
|
|
84
|
+
String,
|
|
85
|
+
ForeignKey("operation_invocations.id", ondelete="CASCADE"),
|
|
86
|
+
primary_key=True,
|
|
87
|
+
),
|
|
88
|
+
Column("operation_command", String, nullable=False),
|
|
89
|
+
Column("target_memory_id", String, nullable=False),
|
|
90
|
+
Column("target_kind", String),
|
|
91
|
+
Column("update_type", String),
|
|
92
|
+
Column("scope", String),
|
|
93
|
+
Column("evidence_ref_count", Integer, nullable=False, server_default=text("0")),
|
|
94
|
+
Column("planned_effect_count", Integer, nullable=False),
|
|
95
|
+
Column("created_memory_count", Integer, nullable=False, server_default=text("0")),
|
|
96
|
+
Column("archived_memory_count", Integer, nullable=False, server_default=text("0")),
|
|
97
|
+
Column("utility_observation_count", Integer, nullable=False, server_default=text("0")),
|
|
98
|
+
Column("association_effect_count", Integer, nullable=False, server_default=text("0")),
|
|
99
|
+
Column("fact_update_count", Integer, nullable=False, server_default=text("0")),
|
|
100
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False, server_default=text("NOW()")),
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
write_effect_items = Table(
|
|
104
|
+
"write_effect_items",
|
|
105
|
+
metadata,
|
|
106
|
+
Column(
|
|
107
|
+
"invocation_id",
|
|
108
|
+
String,
|
|
109
|
+
ForeignKey("operation_invocations.id", ondelete="CASCADE"),
|
|
110
|
+
primary_key=True,
|
|
111
|
+
),
|
|
112
|
+
Column("ordinal", Integer, primary_key=True),
|
|
113
|
+
Column("effect_type", String, nullable=False),
|
|
114
|
+
Column("repo_id", String, nullable=False),
|
|
115
|
+
Column("primary_memory_id", String),
|
|
116
|
+
Column("secondary_memory_id", String),
|
|
117
|
+
Column("params_json", JSONB, nullable=False, server_default=text("'{}'::jsonb")),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
episode_sync_runs = Table(
|
|
121
|
+
"episode_sync_runs",
|
|
122
|
+
metadata,
|
|
123
|
+
Column("id", String, primary_key=True),
|
|
124
|
+
Column("source", String, nullable=False),
|
|
125
|
+
Column("invocation_id", String, ForeignKey("operation_invocations.id", ondelete="SET NULL")),
|
|
126
|
+
Column("repo_id", String, nullable=False),
|
|
127
|
+
Column("host_app", String, nullable=False),
|
|
128
|
+
Column("host_session_key", String, nullable=False),
|
|
129
|
+
Column("thread_id", String, nullable=False),
|
|
130
|
+
Column("episode_id", String),
|
|
131
|
+
Column("transcript_path", Text),
|
|
132
|
+
Column("outcome", String, nullable=False),
|
|
133
|
+
Column("error_stage", String),
|
|
134
|
+
Column("error_message", Text),
|
|
135
|
+
Column("duration_ms", Integer, nullable=False),
|
|
136
|
+
Column("imported_event_count", Integer, nullable=False, server_default=text("0")),
|
|
137
|
+
Column("total_event_count", Integer, nullable=False, server_default=text("0")),
|
|
138
|
+
Column("user_event_count", Integer, nullable=False, server_default=text("0")),
|
|
139
|
+
Column("assistant_event_count", Integer, nullable=False, server_default=text("0")),
|
|
140
|
+
Column("tool_event_count", Integer, nullable=False, server_default=text("0")),
|
|
141
|
+
Column("system_event_count", Integer, nullable=False, server_default=text("0")),
|
|
142
|
+
Column("created_at", TIMESTAMP(timezone=True), nullable=False, server_default=text("NOW()")),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
episode_sync_tool_types = Table(
|
|
146
|
+
"episode_sync_tool_types",
|
|
147
|
+
metadata,
|
|
148
|
+
Column(
|
|
149
|
+
"sync_run_id",
|
|
150
|
+
String,
|
|
151
|
+
ForeignKey("episode_sync_runs.id", ondelete="CASCADE"),
|
|
152
|
+
primary_key=True,
|
|
153
|
+
),
|
|
154
|
+
Column("tool_type", String, primary_key=True),
|
|
155
|
+
Column("event_count", Integer, nullable=False),
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
Index("idx_operation_invocations_repo_created_at", operation_invocations.c.repo_id, operation_invocations.c.created_at)
|
|
159
|
+
Index("idx_operation_invocations_command_created_at", operation_invocations.c.command, operation_invocations.c.created_at)
|
|
160
|
+
Index(
|
|
161
|
+
"idx_operation_invocations_thread_created_at",
|
|
162
|
+
operation_invocations.c.selected_thread_id,
|
|
163
|
+
operation_invocations.c.created_at,
|
|
164
|
+
postgresql_where=operation_invocations.c.selected_thread_id.is_not(None),
|
|
165
|
+
)
|
|
166
|
+
Index("idx_read_result_items_memory_invocation", read_result_items.c.memory_id, read_result_items.c.invocation_id)
|
|
167
|
+
Index(
|
|
168
|
+
"idx_write_effect_items_repo_effect_invocation",
|
|
169
|
+
write_effect_items.c.repo_id,
|
|
170
|
+
write_effect_items.c.effect_type,
|
|
171
|
+
write_effect_items.c.invocation_id,
|
|
172
|
+
)
|
|
173
|
+
Index("idx_episode_sync_runs_repo_host_created_at", episode_sync_runs.c.repo_id, episode_sync_runs.c.host_app, episode_sync_runs.c.created_at)
|
|
174
|
+
Index("idx_episode_sync_runs_thread_created_at", episode_sync_runs.c.thread_id, episode_sync_runs.c.created_at)
|