supermemory-agent 0.2.3__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.
- storage/adapters/__init__.py +0 -0
- storage/adapters/file.py +397 -0
- storage/adapters/postgres_qdrant_redis.py +32 -0
- storage/adapters/sqlite_chroma.py +95 -0
- supermemory_agent-0.2.3.dist-info/METADATA +170 -0
- supermemory_agent-0.2.3.dist-info/RECORD +54 -0
- supermemory_agent-0.2.3.dist-info/WHEEL +4 -0
- supermemory_agent-0.2.3.dist-info/entry_points.txt +2 -0
- supermemory_agent-0.2.3.dist-info/licenses/LICENSE +21 -0
- supermemory_mcp/__init__.py +5 -0
- supermemory_mcp/bridge.py +35 -0
- supermemory_mcp/handlers.py +772 -0
- supermemory_mcp/server.py +522 -0
- supermemory_mcp/text.py +16 -0
- uall/__init__.py +0 -0
- uall/analytics/service.py +35 -0
- uall/collector/__init__.py +0 -0
- uall/collector/service.py +100 -0
- uall/distillation/distiller.py +80 -0
- uall/evaluation/engine.py +38 -0
- uall/experiments/manager.py +83 -0
- uall/memory/__init__.py +0 -0
- uall/memory/confidence.py +36 -0
- uall/memory/freshness.py +28 -0
- uall/memory/graph.py +24 -0
- uall/memory/namespaces.py +40 -0
- uall/memory/policies.py +44 -0
- uall/memory/provenance.py +23 -0
- uall/memory/pruning.py +55 -0
- uall/memory/retrieval.py +98 -0
- uall/memory/ttl.py +22 -0
- uall/memory/validator.py +144 -0
- uall/optimization/optimizers.py +59 -0
- uall/promotion/queue.py +107 -0
- uall/recommendations/engine.py +66 -0
- uall/reflection/engine.py +72 -0
- uall/rollback/manager.py +49 -0
- uall/service.py +572 -0
- uall/skills/library.py +19 -0
- uall/telemetry/retrieval.py +40 -0
- uall_core/__init__.py +0 -0
- uall_core/ports/storage.py +71 -0
- uall_core/providers/heuristic.py +58 -0
- uall_core/providers/llm.py +6 -0
- uall_core/schemas/__init__.py +0 -0
- uall_core/schemas/common.py +73 -0
- uall_core/schemas/events.py +75 -0
- uall_core/schemas/graph.py +32 -0
- uall_core/schemas/lesson.py +109 -0
- uall_core/schemas/namespace.py +76 -0
- uall_python/__init__.py +3 -0
- uall_python/client.py +337 -0
- uall_server/__init__.py +0 -0
- uall_server/main.py +284 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from typing import Any, Protocol
|
|
2
|
+
|
|
3
|
+
from uall_core.schemas.common import (
|
|
4
|
+
Experiment,
|
|
5
|
+
PolicyVersion,
|
|
6
|
+
RetrievalTelemetryEvent,
|
|
7
|
+
Skill,
|
|
8
|
+
VersionRecord,
|
|
9
|
+
)
|
|
10
|
+
from uall_core.schemas.events import Event, Feedback, RunEnd, RunStart
|
|
11
|
+
from uall_core.schemas.lesson import Lesson, MemorySearchRequest, PendingLesson
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class StoragePort(Protocol):
|
|
15
|
+
"""Pluggable storage interface for all UALL tiers."""
|
|
16
|
+
|
|
17
|
+
async def init(self) -> None: ...
|
|
18
|
+
|
|
19
|
+
# Runs & events
|
|
20
|
+
async def save_run_start(self, run: RunStart) -> None: ...
|
|
21
|
+
async def save_run_end(self, run: RunEnd) -> None: ...
|
|
22
|
+
async def save_event(self, event: Event) -> None: ...
|
|
23
|
+
async def get_event(self, event_id: str) -> dict[str, Any] | None: ...
|
|
24
|
+
async def save_feedback(self, feedback: Feedback) -> str: ...
|
|
25
|
+
async def get_run(self, run_id: str) -> dict[str, Any] | None: ...
|
|
26
|
+
async def list_runs(self) -> list[dict[str, Any]]: ...
|
|
27
|
+
|
|
28
|
+
# Lessons & memory
|
|
29
|
+
async def save_lesson(self, lesson: Lesson) -> str: ...
|
|
30
|
+
async def get_lesson(self, lesson_id: str) -> Lesson | None: ...
|
|
31
|
+
async def list_lessons(self, status: str = "active") -> list[Lesson]: ...
|
|
32
|
+
async def update_lesson(self, lesson: Lesson) -> None: ...
|
|
33
|
+
async def delete_lesson(self, lesson_id: str) -> None: ...
|
|
34
|
+
async def search_lessons(self, request: MemorySearchRequest) -> list[Lesson]: ...
|
|
35
|
+
|
|
36
|
+
# Pending promotion queue
|
|
37
|
+
async def save_pending(self, pending: PendingLesson) -> str: ...
|
|
38
|
+
async def get_pending(self, pending_id: str) -> PendingLesson | None: ...
|
|
39
|
+
async def list_pending(self, status: str = "pending") -> list[PendingLesson]: ...
|
|
40
|
+
async def update_pending(self, pending: PendingLesson) -> None: ...
|
|
41
|
+
|
|
42
|
+
# Policies
|
|
43
|
+
async def save_policy(self, policy: PolicyVersion) -> str: ...
|
|
44
|
+
async def get_active_policies(self) -> list[PolicyVersion]: ...
|
|
45
|
+
async def list_policy_versions(self, policy_id: str) -> list[PolicyVersion]: ...
|
|
46
|
+
|
|
47
|
+
# Skills
|
|
48
|
+
async def save_skill(self, skill: Skill) -> str: ...
|
|
49
|
+
async def get_skill(self, skill_id: str) -> Skill | None: ...
|
|
50
|
+
async def search_skills(self, query: str) -> list[Skill]: ...
|
|
51
|
+
|
|
52
|
+
# Telemetry
|
|
53
|
+
async def save_telemetry(self, event: RetrievalTelemetryEvent) -> str: ...
|
|
54
|
+
async def list_telemetry(self, lesson_id: str | None = None) -> list[RetrievalTelemetryEvent]: ...
|
|
55
|
+
|
|
56
|
+
# Experiments
|
|
57
|
+
async def save_experiment(self, experiment: Experiment) -> str: ...
|
|
58
|
+
async def get_experiment(self, experiment_id: str) -> Experiment | None: ...
|
|
59
|
+
async def update_experiment(self, experiment: Experiment) -> None: ...
|
|
60
|
+
|
|
61
|
+
# Versions (rollback)
|
|
62
|
+
async def save_version(self, record: VersionRecord) -> str: ...
|
|
63
|
+
async def list_versions(self, resource_type: str, resource_id: str) -> list[VersionRecord]: ...
|
|
64
|
+
|
|
65
|
+
# Reflections
|
|
66
|
+
async def save_reflection(self, data: dict[str, Any]) -> str: ...
|
|
67
|
+
async def get_reflection(self, reflection_id: str) -> dict[str, Any] | None: ...
|
|
68
|
+
|
|
69
|
+
# Metrics / analytics raw
|
|
70
|
+
async def save_metrics(self, name: str, data: dict[str, Any]) -> None: ...
|
|
71
|
+
async def get_metrics(self, name: str) -> dict[str, Any] | None: ...
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Heuristic LLM provider — zero API keys required for local dev."""
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import math
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class HeuristicLLMProvider:
|
|
9
|
+
async def complete(self, prompt: str, max_tokens: int = 500) -> str:
|
|
10
|
+
text = prompt.lower()
|
|
11
|
+
failure = _extract_field(prompt, "failure") or "unknown failure"
|
|
12
|
+
root = _extract_field(prompt, "root cause") or _infer_root(failure)
|
|
13
|
+
fix = _extract_field(prompt, "fix") or _infer_fix(failure, root)
|
|
14
|
+
return f"FAILURE: {failure}\nROOT_CAUSE: {root}\nFIX: {fix}\nCONFIDENCE: 0.85"
|
|
15
|
+
|
|
16
|
+
async def embed(self, text: str) -> list[float]:
|
|
17
|
+
tokens = re.findall(r"\w+", text.lower())
|
|
18
|
+
vec = [0.0] * 128
|
|
19
|
+
for tok in tokens:
|
|
20
|
+
h = int(hashlib.md5(tok.encode()).hexdigest(), 16)
|
|
21
|
+
for i in range(128):
|
|
22
|
+
vec[i] += math.sin(h * (i + 1) * 0.001)
|
|
23
|
+
norm = math.sqrt(sum(x * x for x in vec)) or 1.0
|
|
24
|
+
return [x / norm for x in vec]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _extract_field(prompt: str, label: str) -> str | None:
|
|
28
|
+
for line in prompt.splitlines():
|
|
29
|
+
if label.lower() in line.lower() and ":" in line:
|
|
30
|
+
return line.split(":", 1)[1].strip()[:200]
|
|
31
|
+
return None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _infer_root(failure: str) -> str:
|
|
35
|
+
if "ocr" in failure.lower():
|
|
36
|
+
return "Routing logic did not inspect PDF text layer before choosing OCR"
|
|
37
|
+
if "sql" in failure.lower() or "join" in failure.lower():
|
|
38
|
+
return "Schema relationships were not verified before generating SQL"
|
|
39
|
+
return "Insufficient validation before action"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _infer_fix(failure: str, root: str) -> str:
|
|
43
|
+
if "ocr" in failure.lower() or "pdf" in failure.lower():
|
|
44
|
+
return "Inspect PDF text layer first; use OCR only for scanned documents"
|
|
45
|
+
if "sql" in failure.lower():
|
|
46
|
+
return "Inspect foreign keys and schema before generating joins"
|
|
47
|
+
return f"Add validation step to prevent: {root[:80]}"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def cosine_similarity(a: list[float], b: list[float]) -> float:
|
|
51
|
+
if not a or not b or len(a) != len(b):
|
|
52
|
+
return 0.0
|
|
53
|
+
dot = sum(x * y for x, y in zip(a, b))
|
|
54
|
+
na = math.sqrt(sum(x * x for x in a))
|
|
55
|
+
nb = math.sqrt(sum(y * y for y in b))
|
|
56
|
+
if na == 0 or nb == 0:
|
|
57
|
+
return 0.0
|
|
58
|
+
return dot / (na * nb)
|
|
File without changes
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PolicyVersion(BaseModel):
|
|
8
|
+
policy_id: str
|
|
9
|
+
version: str
|
|
10
|
+
effective_at: datetime = Field(default_factory=datetime.utcnow)
|
|
11
|
+
rules: list[str] = Field(default_factory=list)
|
|
12
|
+
priority: int = 100
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Skill(BaseModel):
|
|
16
|
+
skill_id: str
|
|
17
|
+
name: str
|
|
18
|
+
version: str = "1.0.0"
|
|
19
|
+
description: str = ""
|
|
20
|
+
steps: list[str] = Field(default_factory=list)
|
|
21
|
+
lesson_ids: list[str] = Field(default_factory=list)
|
|
22
|
+
tool_bindings: list[str] = Field(default_factory=list)
|
|
23
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
24
|
+
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ExperimentMetrics(BaseModel):
|
|
28
|
+
success_rate: float = 0.0
|
|
29
|
+
retry_count: float = 0.0
|
|
30
|
+
cost: float = 0.0
|
|
31
|
+
correction_rate: float = 0.0
|
|
32
|
+
latency_p50: float = 0.0
|
|
33
|
+
latency_p95: float = 0.0
|
|
34
|
+
token_usage: float = 0.0
|
|
35
|
+
human_approval_rate: float = 0.0
|
|
36
|
+
rollback_frequency: float = 0.0
|
|
37
|
+
downstream_failure_rate: float = 0.0
|
|
38
|
+
sample_size: int = 0
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Experiment(BaseModel):
|
|
42
|
+
experiment_id: str
|
|
43
|
+
resource_type: str # prompt, workflow
|
|
44
|
+
resource_id: str
|
|
45
|
+
variant_a: str
|
|
46
|
+
variant_b: str
|
|
47
|
+
traffic_split: float = 0.1
|
|
48
|
+
status: str = "running" # running, concluded, rolled_back
|
|
49
|
+
metrics_a: ExperimentMetrics = Field(default_factory=ExperimentMetrics)
|
|
50
|
+
metrics_b: ExperimentMetrics = Field(default_factory=ExperimentMetrics)
|
|
51
|
+
winner: str | None = None
|
|
52
|
+
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
53
|
+
concluded_at: datetime | None = None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class RetrievalTelemetryEvent(BaseModel):
|
|
57
|
+
telemetry_id: str
|
|
58
|
+
lesson_id: str
|
|
59
|
+
run_id: str | None = None
|
|
60
|
+
retrieved: bool = True
|
|
61
|
+
used: bool = False
|
|
62
|
+
accepted: bool = False
|
|
63
|
+
outcome_improved: bool | None = None
|
|
64
|
+
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class VersionRecord(BaseModel):
|
|
68
|
+
resource_type: str
|
|
69
|
+
resource_id: str
|
|
70
|
+
version: str
|
|
71
|
+
content: dict[str, Any] = Field(default_factory=dict)
|
|
72
|
+
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
73
|
+
promoted: bool = False
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field, field_validator
|
|
6
|
+
|
|
7
|
+
MAX_PAYLOAD_BYTES = 2048
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class EventType(str, Enum):
|
|
11
|
+
WORKFLOW_START = "workflow_start"
|
|
12
|
+
WORKFLOW_STEP = "workflow_step"
|
|
13
|
+
WORKFLOW_END = "workflow_end"
|
|
14
|
+
FAILURE = "failure"
|
|
15
|
+
CORRECTION = "correction"
|
|
16
|
+
SUGGESTION = "suggestion"
|
|
17
|
+
TOOL_OUTCOME = "tool_outcome"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class StageMetadata(BaseModel):
|
|
21
|
+
workflow: str | None = None
|
|
22
|
+
step: str | None = None
|
|
23
|
+
tool: str | None = None
|
|
24
|
+
agent: str | None = None
|
|
25
|
+
domain: str | None = None
|
|
26
|
+
language: str | None = None
|
|
27
|
+
environment: str | None = None
|
|
28
|
+
namespace: str | None = None
|
|
29
|
+
namespace_id: str | None = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Event(BaseModel):
|
|
33
|
+
event_id: str
|
|
34
|
+
event_type: EventType
|
|
35
|
+
run_id: str
|
|
36
|
+
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
|
37
|
+
stage: StageMetadata = Field(default_factory=StageMetadata)
|
|
38
|
+
tags: list[str] = Field(default_factory=list)
|
|
39
|
+
payload: dict[str, Any] = Field(default_factory=dict)
|
|
40
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
41
|
+
|
|
42
|
+
@field_validator("payload")
|
|
43
|
+
@classmethod
|
|
44
|
+
def validate_payload_size(cls, v: dict) -> dict:
|
|
45
|
+
import json
|
|
46
|
+
|
|
47
|
+
if len(json.dumps(v, default=str)) > MAX_PAYLOAD_BYTES:
|
|
48
|
+
raise ValueError(f"Payload exceeds {MAX_PAYLOAD_BYTES} bytes")
|
|
49
|
+
return v
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class RunStart(BaseModel):
|
|
53
|
+
run_id: str
|
|
54
|
+
workflow_id: str
|
|
55
|
+
agents: list[str] = Field(default_factory=list)
|
|
56
|
+
workflow_graph: dict[str, Any] = Field(default_factory=dict)
|
|
57
|
+
stage: StageMetadata = Field(default_factory=StageMetadata)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class RunEnd(BaseModel):
|
|
61
|
+
run_id: str
|
|
62
|
+
success: bool
|
|
63
|
+
metrics: dict[str, Any] = Field(default_factory=dict)
|
|
64
|
+
lessons_used: list[str] = Field(default_factory=list)
|
|
65
|
+
score: float | None = None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class Feedback(BaseModel):
|
|
69
|
+
run_id: str | None = None
|
|
70
|
+
lesson_id: str | None = None
|
|
71
|
+
rating: str # positive, negative, correction
|
|
72
|
+
comment: str | None = None
|
|
73
|
+
correction_before: str | None = None
|
|
74
|
+
correction_after: str | None = None
|
|
75
|
+
intent: str | None = None
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class GraphEdgeType(str, Enum):
|
|
7
|
+
CAUSED_BY = "caused_by"
|
|
8
|
+
FIXED_BY = "fixed_by"
|
|
9
|
+
SUPERSEDES = "supersedes"
|
|
10
|
+
RELATED_TO = "related_to"
|
|
11
|
+
DEPENDS_ON = "depends_on"
|
|
12
|
+
CONFLICTS_WITH = "conflicts_with"
|
|
13
|
+
DERIVED_FROM = "derived_from"
|
|
14
|
+
GENERALIZES = "generalizes"
|
|
15
|
+
SPECIALIZES = "specializes"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class GraphEdge(BaseModel):
|
|
19
|
+
edge_type: GraphEdgeType
|
|
20
|
+
target_id: str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class KnowledgeGraph(BaseModel):
|
|
24
|
+
lesson_id: str
|
|
25
|
+
edges: list[GraphEdge] = Field(default_factory=list)
|
|
26
|
+
|
|
27
|
+
def get_targets(self, edge_type: GraphEdgeType) -> list[str]:
|
|
28
|
+
return [e.target_id for e in self.edges if e.edge_type == edge_type]
|
|
29
|
+
|
|
30
|
+
def add_edge(self, edge_type: GraphEdgeType, target_id: str) -> None:
|
|
31
|
+
if not any(e.edge_type == edge_type and e.target_id == target_id for e in self.edges):
|
|
32
|
+
self.edges.append(GraphEdge(edge_type=edge_type, target_id=target_id))
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
from uall_core.schemas.events import StageMetadata
|
|
7
|
+
from uall_core.schemas.graph import KnowledgeGraph
|
|
8
|
+
from uall_core.schemas.namespace import (
|
|
9
|
+
ConfidenceDimensions,
|
|
10
|
+
FreshnessMetrics,
|
|
11
|
+
MemoryType,
|
|
12
|
+
NamespaceRef,
|
|
13
|
+
Provenance,
|
|
14
|
+
TTLConfig,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Reflection(BaseModel):
|
|
19
|
+
reflection_id: str
|
|
20
|
+
failure: str
|
|
21
|
+
root_cause: str
|
|
22
|
+
fix: str
|
|
23
|
+
confidence: float = 0.8
|
|
24
|
+
memory_type: MemoryType = MemoryType.FAILURE
|
|
25
|
+
run_id: str | None = None
|
|
26
|
+
event_ids: list[str] = Field(default_factory=list)
|
|
27
|
+
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Lesson(BaseModel):
|
|
31
|
+
lesson_id: str
|
|
32
|
+
failure: str = ""
|
|
33
|
+
root_cause: str = ""
|
|
34
|
+
fix: str = ""
|
|
35
|
+
memory_type: MemoryType = MemoryType.FAILURE
|
|
36
|
+
stage: StageMetadata = Field(default_factory=StageMetadata)
|
|
37
|
+
namespace: NamespaceRef = Field(default_factory=NamespaceRef)
|
|
38
|
+
confidence: ConfidenceDimensions = Field(default_factory=ConfidenceDimensions)
|
|
39
|
+
freshness: FreshnessMetrics = Field(default_factory=FreshnessMetrics)
|
|
40
|
+
ttl: TTLConfig = Field(default_factory=TTLConfig)
|
|
41
|
+
provenance: Provenance = Field(default_factory=Provenance)
|
|
42
|
+
graph: KnowledgeGraph | None = None
|
|
43
|
+
occurrence_count: int = 1
|
|
44
|
+
quality_score: float = 0.5
|
|
45
|
+
embedding: list[float] | None = None
|
|
46
|
+
status: str = "active" # active, archived, pending_revalidation
|
|
47
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
48
|
+
|
|
49
|
+
def to_search_text(self) -> str:
|
|
50
|
+
return f"{self.failure} {self.root_cause} {self.fix}"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class CandidateLesson(BaseModel):
|
|
54
|
+
"""Pre-validation lesson from reflection/distillation."""
|
|
55
|
+
reflection_id: str
|
|
56
|
+
failure: str
|
|
57
|
+
root_cause: str
|
|
58
|
+
fix: str
|
|
59
|
+
memory_type: MemoryType = MemoryType.FAILURE
|
|
60
|
+
stage: StageMetadata = Field(default_factory=StageMetadata)
|
|
61
|
+
namespace: NamespaceRef = Field(default_factory=NamespaceRef)
|
|
62
|
+
confidence: float = 0.8
|
|
63
|
+
run_id: str | None = None
|
|
64
|
+
event_ids: list[str] = Field(default_factory=list)
|
|
65
|
+
evidence_payload: dict = Field(default_factory=dict)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class MemorySearchRequest(BaseModel):
|
|
69
|
+
query: str
|
|
70
|
+
workflow: str | None = None
|
|
71
|
+
step: str | None = None
|
|
72
|
+
tool: str | None = None
|
|
73
|
+
agent: str | None = None
|
|
74
|
+
domain: str | None = None
|
|
75
|
+
namespace: str | None = None
|
|
76
|
+
namespace_id: str | None = None
|
|
77
|
+
max_tokens: int = 800
|
|
78
|
+
top_k: int = 5
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class MemorySearchResult(BaseModel):
|
|
82
|
+
lesson: Lesson
|
|
83
|
+
score: float
|
|
84
|
+
telemetry_id: str | None = None
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class ValidatorAction(str):
|
|
88
|
+
REJECT = "reject"
|
|
89
|
+
MERGE = "merge"
|
|
90
|
+
REWRITE = "rewrite"
|
|
91
|
+
APPROVE = "approve"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class ValidationResult(BaseModel):
|
|
95
|
+
action: str
|
|
96
|
+
candidate: CandidateLesson
|
|
97
|
+
quality_score: float = 0.0
|
|
98
|
+
merge_target_id: str | None = None
|
|
99
|
+
rewritten_fix: str | None = None
|
|
100
|
+
reason: str = ""
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class PendingLesson(BaseModel):
|
|
104
|
+
pending_id: str
|
|
105
|
+
candidate: CandidateLesson
|
|
106
|
+
validation_result: ValidationResult
|
|
107
|
+
status: str = "pending" # pending, evaluating, promoted, discarded
|
|
108
|
+
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
109
|
+
processed_at: datetime | None = None
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MemoryType(str, Enum):
|
|
8
|
+
EPISODIC = "episodic"
|
|
9
|
+
SEMANTIC = "semantic"
|
|
10
|
+
PROCEDURAL = "procedural"
|
|
11
|
+
USER = "user"
|
|
12
|
+
ORGANIZATIONAL = "organizational"
|
|
13
|
+
FAILURE = "failure"
|
|
14
|
+
TOOL = "tool"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class NamespaceLevel(str, Enum):
|
|
18
|
+
GLOBAL = "global"
|
|
19
|
+
ORGANIZATION = "organization"
|
|
20
|
+
TEAM = "team"
|
|
21
|
+
PROJECT = "project"
|
|
22
|
+
USER = "user"
|
|
23
|
+
SESSION = "session"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
NAMESPACE_PRIORITY = [
|
|
27
|
+
NamespaceLevel.ORGANIZATION,
|
|
28
|
+
NamespaceLevel.TEAM,
|
|
29
|
+
NamespaceLevel.PROJECT,
|
|
30
|
+
NamespaceLevel.USER,
|
|
31
|
+
NamespaceLevel.SESSION,
|
|
32
|
+
NamespaceLevel.GLOBAL,
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class NamespaceRef(BaseModel):
|
|
37
|
+
level: NamespaceLevel = NamespaceLevel.PROJECT
|
|
38
|
+
namespace_id: str = "default"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ConfidenceDimensions(BaseModel):
|
|
42
|
+
evidence: float = 0.5
|
|
43
|
+
retrieval_success: float = 0.5
|
|
44
|
+
human_verified: bool = False
|
|
45
|
+
overall: float = 0.5
|
|
46
|
+
|
|
47
|
+
def recalculate_overall(self) -> float:
|
|
48
|
+
bonus = 1.0 if self.human_verified else 0.0
|
|
49
|
+
self.overall = round(
|
|
50
|
+
0.4 * self.evidence + 0.4 * self.retrieval_success + 0.2 * bonus, 4
|
|
51
|
+
)
|
|
52
|
+
return self.overall
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class TTLConfig(BaseModel):
|
|
56
|
+
expires_at: datetime | None = None
|
|
57
|
+
auto_revalidate_after_days: int | None = None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class FreshnessMetrics(BaseModel):
|
|
61
|
+
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
62
|
+
last_used: datetime | None = None
|
|
63
|
+
last_confirmed: datetime | None = None
|
|
64
|
+
usage_count: int = 0
|
|
65
|
+
success_after_use: int = 0
|
|
66
|
+
failure_after_use: int = 0
|
|
67
|
+
staleness_score: float = 0.0
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class Provenance(BaseModel):
|
|
71
|
+
run_id: str | None = None
|
|
72
|
+
reflection_id: str | None = None
|
|
73
|
+
event_ids: list[str] = Field(default_factory=list)
|
|
74
|
+
policy_version: str | None = None
|
|
75
|
+
validator_action: str | None = None
|
|
76
|
+
promoted_at: datetime | None = None
|
uall_python/__init__.py
ADDED