agent-runtime-core 0.3.0__py3-none-any.whl → 0.4.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.
- agent_runtime_core/persistence/__init__.py +44 -8
- agent_runtime_core/persistence/base.py +417 -12
- agent_runtime_core/persistence/manager.py +120 -12
- {agent_runtime_core-0.3.0.dist-info → agent_runtime_core-0.4.0.dist-info}/METADATA +352 -42
- {agent_runtime_core-0.3.0.dist-info → agent_runtime_core-0.4.0.dist-info}/RECORD +7 -7
- {agent_runtime_core-0.3.0.dist-info → agent_runtime_core-0.4.0.dist-info}/WHEEL +0 -0
- {agent_runtime_core-0.3.0.dist-info → agent_runtime_core-0.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,6 +6,8 @@ This module provides pluggable storage backends for:
|
|
|
6
6
|
- Conversation history (full conversation state including tool calls)
|
|
7
7
|
- Task state (task lists and progress)
|
|
8
8
|
- Preferences (user and agent configuration)
|
|
9
|
+
- Knowledge base (facts, summaries, embeddings) - optional
|
|
10
|
+
- Audit/history (logs, errors, metrics) - optional
|
|
9
11
|
|
|
10
12
|
Example usage:
|
|
11
13
|
from agent_runtime_core.persistence import (
|
|
@@ -16,33 +18,51 @@ Example usage:
|
|
|
16
18
|
PersistenceManager,
|
|
17
19
|
Scope,
|
|
18
20
|
)
|
|
19
|
-
|
|
21
|
+
|
|
20
22
|
# Use the high-level manager
|
|
21
23
|
manager = PersistenceManager()
|
|
22
|
-
|
|
24
|
+
|
|
23
25
|
# Store global memory
|
|
24
26
|
await manager.memory.set("user_name", "Alice", scope=Scope.GLOBAL)
|
|
25
|
-
|
|
27
|
+
|
|
26
28
|
# Store project-specific memory
|
|
27
29
|
await manager.memory.set("project_type", "python", scope=Scope.PROJECT)
|
|
28
|
-
|
|
30
|
+
|
|
29
31
|
# Save a conversation
|
|
30
32
|
await manager.conversations.save(conversation)
|
|
31
33
|
"""
|
|
32
34
|
|
|
33
35
|
from agent_runtime_core.persistence.base import (
|
|
36
|
+
# Core stores
|
|
34
37
|
MemoryStore,
|
|
35
38
|
ConversationStore,
|
|
36
39
|
TaskStore,
|
|
37
40
|
PreferencesStore,
|
|
41
|
+
# Optional stores
|
|
42
|
+
KnowledgeStore,
|
|
43
|
+
AuditStore,
|
|
44
|
+
# Enums
|
|
38
45
|
Scope,
|
|
46
|
+
TaskState,
|
|
47
|
+
FactType,
|
|
48
|
+
AuditEventType,
|
|
49
|
+
ErrorSeverity,
|
|
50
|
+
# Conversation models
|
|
39
51
|
Conversation,
|
|
40
52
|
ConversationMessage,
|
|
41
53
|
ToolCall,
|
|
42
54
|
ToolResult,
|
|
55
|
+
# Task models
|
|
43
56
|
TaskList,
|
|
44
57
|
Task,
|
|
45
|
-
|
|
58
|
+
# Knowledge models
|
|
59
|
+
Fact,
|
|
60
|
+
Summary,
|
|
61
|
+
Embedding,
|
|
62
|
+
# Audit models
|
|
63
|
+
AuditEntry,
|
|
64
|
+
ErrorRecord,
|
|
65
|
+
PerformanceMetric,
|
|
46
66
|
)
|
|
47
67
|
|
|
48
68
|
from agent_runtime_core.persistence.file import (
|
|
@@ -60,20 +80,36 @@ from agent_runtime_core.persistence.manager import (
|
|
|
60
80
|
)
|
|
61
81
|
|
|
62
82
|
__all__ = [
|
|
63
|
-
# Abstract interfaces
|
|
83
|
+
# Abstract interfaces - core
|
|
64
84
|
"MemoryStore",
|
|
65
85
|
"ConversationStore",
|
|
66
86
|
"TaskStore",
|
|
67
87
|
"PreferencesStore",
|
|
88
|
+
# Abstract interfaces - optional
|
|
89
|
+
"KnowledgeStore",
|
|
90
|
+
"AuditStore",
|
|
91
|
+
# Enums
|
|
68
92
|
"Scope",
|
|
69
|
-
|
|
93
|
+
"TaskState",
|
|
94
|
+
"FactType",
|
|
95
|
+
"AuditEventType",
|
|
96
|
+
"ErrorSeverity",
|
|
97
|
+
# Conversation models
|
|
70
98
|
"Conversation",
|
|
71
99
|
"ConversationMessage",
|
|
72
100
|
"ToolCall",
|
|
73
101
|
"ToolResult",
|
|
102
|
+
# Task models
|
|
74
103
|
"TaskList",
|
|
75
104
|
"Task",
|
|
76
|
-
|
|
105
|
+
# Knowledge models
|
|
106
|
+
"Fact",
|
|
107
|
+
"Summary",
|
|
108
|
+
"Embedding",
|
|
109
|
+
# Audit models
|
|
110
|
+
"AuditEntry",
|
|
111
|
+
"ErrorRecord",
|
|
112
|
+
"PerformanceMetric",
|
|
77
113
|
# File implementations
|
|
78
114
|
"FileMemoryStore",
|
|
79
115
|
"FileConversationStore",
|
|
@@ -83,48 +83,56 @@ class ToolResult:
|
|
|
83
83
|
@dataclass
|
|
84
84
|
class ConversationMessage:
|
|
85
85
|
"""A message in a conversation with full state."""
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
id: UUID
|
|
88
88
|
role: str # system, user, assistant, tool
|
|
89
89
|
content: str | dict | list
|
|
90
90
|
timestamp: datetime = field(default_factory=datetime.utcnow)
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
# For assistant messages with tool calls
|
|
93
93
|
tool_calls: list[ToolCall] = field(default_factory=list)
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
# For tool result messages
|
|
96
96
|
tool_call_id: Optional[str] = None
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
# Metadata
|
|
99
99
|
model: Optional[str] = None
|
|
100
|
-
usage: dict = field(default_factory=dict) # token counts
|
|
100
|
+
usage: dict = field(default_factory=dict) # token counts: {prompt_tokens, completion_tokens, total_tokens}
|
|
101
101
|
metadata: dict = field(default_factory=dict)
|
|
102
102
|
|
|
103
|
+
# Branching support
|
|
104
|
+
parent_message_id: Optional[UUID] = None # For branched/edited messages
|
|
105
|
+
branch_id: Optional[UUID] = None # Groups messages in same branch
|
|
106
|
+
|
|
103
107
|
|
|
104
108
|
@dataclass
|
|
105
109
|
class Conversation:
|
|
106
110
|
"""A complete conversation with all state."""
|
|
107
|
-
|
|
111
|
+
|
|
108
112
|
id: UUID
|
|
109
113
|
title: Optional[str] = None
|
|
110
114
|
messages: list[ConversationMessage] = field(default_factory=list)
|
|
111
|
-
|
|
115
|
+
|
|
112
116
|
# Metadata
|
|
113
117
|
created_at: datetime = field(default_factory=datetime.utcnow)
|
|
114
118
|
updated_at: datetime = field(default_factory=datetime.utcnow)
|
|
115
119
|
metadata: dict = field(default_factory=dict)
|
|
116
|
-
|
|
120
|
+
|
|
117
121
|
# Associated agent
|
|
118
122
|
agent_key: Optional[str] = None
|
|
119
|
-
|
|
123
|
+
|
|
120
124
|
# Summary for long conversations
|
|
121
125
|
summary: Optional[str] = None
|
|
122
126
|
|
|
127
|
+
# Branching support
|
|
128
|
+
parent_conversation_id: Optional[UUID] = None # For forked conversations
|
|
129
|
+
active_branch_id: Optional[UUID] = None # Currently active branch
|
|
130
|
+
|
|
123
131
|
|
|
124
132
|
@dataclass
|
|
125
133
|
class Task:
|
|
126
134
|
"""A task in a task list."""
|
|
127
|
-
|
|
135
|
+
|
|
128
136
|
id: UUID
|
|
129
137
|
name: str
|
|
130
138
|
description: str = ""
|
|
@@ -134,17 +142,31 @@ class Task:
|
|
|
134
142
|
updated_at: datetime = field(default_factory=datetime.utcnow)
|
|
135
143
|
metadata: dict = field(default_factory=dict)
|
|
136
144
|
|
|
145
|
+
# Dependencies and scheduling
|
|
146
|
+
dependencies: list[UUID] = field(default_factory=list) # Task IDs this depends on
|
|
147
|
+
priority: int = 0 # Higher = more important
|
|
148
|
+
due_at: Optional[datetime] = None
|
|
149
|
+
completed_at: Optional[datetime] = None
|
|
150
|
+
|
|
151
|
+
# Checkpoint for resumable long-running operations
|
|
152
|
+
checkpoint_data: dict = field(default_factory=dict)
|
|
153
|
+
checkpoint_at: Optional[datetime] = None
|
|
154
|
+
|
|
155
|
+
# Execution tracking
|
|
156
|
+
attempts: int = 0
|
|
157
|
+
last_error: Optional[str] = None
|
|
158
|
+
|
|
137
159
|
|
|
138
160
|
@dataclass
|
|
139
161
|
class TaskList:
|
|
140
162
|
"""A list of tasks."""
|
|
141
|
-
|
|
163
|
+
|
|
142
164
|
id: UUID
|
|
143
165
|
name: str
|
|
144
166
|
tasks: list[Task] = field(default_factory=list)
|
|
145
167
|
created_at: datetime = field(default_factory=datetime.utcnow)
|
|
146
168
|
updated_at: datetime = field(default_factory=datetime.utcnow)
|
|
147
|
-
|
|
169
|
+
|
|
148
170
|
# Associated conversation/run
|
|
149
171
|
conversation_id: Optional[UUID] = None
|
|
150
172
|
run_id: Optional[UUID] = None
|
|
@@ -330,3 +352,386 @@ class PreferencesStore(ABC):
|
|
|
330
352
|
"""Close any connections. Override if needed."""
|
|
331
353
|
pass
|
|
332
354
|
|
|
355
|
+
|
|
356
|
+
# =============================================================================
|
|
357
|
+
# Knowledge Base Models and Store
|
|
358
|
+
# =============================================================================
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
class FactType(str, Enum):
|
|
362
|
+
"""Type of fact stored in knowledge base."""
|
|
363
|
+
|
|
364
|
+
USER = "user" # Facts about the user
|
|
365
|
+
PROJECT = "project" # Facts about the project
|
|
366
|
+
PREFERENCE = "preference" # Learned preferences
|
|
367
|
+
CONTEXT = "context" # Contextual information
|
|
368
|
+
CUSTOM = "custom" # Custom fact type
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
@dataclass
|
|
372
|
+
class Fact:
|
|
373
|
+
"""A learned fact about user, project, or context."""
|
|
374
|
+
|
|
375
|
+
id: UUID
|
|
376
|
+
key: str # Unique identifier for the fact
|
|
377
|
+
value: Any # The fact content
|
|
378
|
+
fact_type: FactType = FactType.CUSTOM
|
|
379
|
+
confidence: float = 1.0 # 0.0 to 1.0
|
|
380
|
+
source: Optional[str] = None # Where this fact came from
|
|
381
|
+
|
|
382
|
+
created_at: datetime = field(default_factory=datetime.utcnow)
|
|
383
|
+
updated_at: datetime = field(default_factory=datetime.utcnow)
|
|
384
|
+
expires_at: Optional[datetime] = None # Optional expiration
|
|
385
|
+
|
|
386
|
+
metadata: dict = field(default_factory=dict)
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
@dataclass
|
|
390
|
+
class Summary:
|
|
391
|
+
"""A summary of a conversation or set of interactions."""
|
|
392
|
+
|
|
393
|
+
id: UUID
|
|
394
|
+
content: str # The summary text
|
|
395
|
+
|
|
396
|
+
# What this summarizes
|
|
397
|
+
conversation_id: Optional[UUID] = None
|
|
398
|
+
conversation_ids: list[UUID] = field(default_factory=list) # For multi-conversation summaries
|
|
399
|
+
|
|
400
|
+
# Time range covered
|
|
401
|
+
start_time: Optional[datetime] = None
|
|
402
|
+
end_time: Optional[datetime] = None
|
|
403
|
+
|
|
404
|
+
created_at: datetime = field(default_factory=datetime.utcnow)
|
|
405
|
+
metadata: dict = field(default_factory=dict)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
@dataclass
|
|
409
|
+
class Embedding:
|
|
410
|
+
"""
|
|
411
|
+
A vector embedding for semantic search.
|
|
412
|
+
|
|
413
|
+
Note: This is optional and requires additional dependencies
|
|
414
|
+
for vector operations (e.g., numpy, faiss, pgvector).
|
|
415
|
+
"""
|
|
416
|
+
|
|
417
|
+
id: UUID
|
|
418
|
+
vector: list[float] # The embedding vector
|
|
419
|
+
|
|
420
|
+
# What this embedding represents
|
|
421
|
+
content: str # Original text
|
|
422
|
+
content_type: str = "text" # text, summary, fact, etc.
|
|
423
|
+
source_id: Optional[UUID] = None # ID of source object
|
|
424
|
+
|
|
425
|
+
model: Optional[str] = None # Embedding model used
|
|
426
|
+
dimensions: int = 0 # Vector dimensions
|
|
427
|
+
|
|
428
|
+
created_at: datetime = field(default_factory=datetime.utcnow)
|
|
429
|
+
metadata: dict = field(default_factory=dict)
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
class KnowledgeStore(ABC):
|
|
433
|
+
"""
|
|
434
|
+
Abstract interface for knowledge base storage.
|
|
435
|
+
|
|
436
|
+
Knowledge stores handle facts, summaries, and optionally
|
|
437
|
+
embeddings for semantic search. This is optional - agents
|
|
438
|
+
can function without a knowledge store.
|
|
439
|
+
"""
|
|
440
|
+
|
|
441
|
+
# Fact operations
|
|
442
|
+
@abstractmethod
|
|
443
|
+
async def save_fact(self, fact: Fact, scope: Scope = Scope.PROJECT) -> None:
|
|
444
|
+
"""Save or update a fact."""
|
|
445
|
+
...
|
|
446
|
+
|
|
447
|
+
@abstractmethod
|
|
448
|
+
async def get_fact(self, fact_id: UUID, scope: Scope = Scope.PROJECT) -> Optional[Fact]:
|
|
449
|
+
"""Get a fact by ID."""
|
|
450
|
+
...
|
|
451
|
+
|
|
452
|
+
@abstractmethod
|
|
453
|
+
async def get_fact_by_key(self, key: str, scope: Scope = Scope.PROJECT) -> Optional[Fact]:
|
|
454
|
+
"""Get a fact by its key."""
|
|
455
|
+
...
|
|
456
|
+
|
|
457
|
+
@abstractmethod
|
|
458
|
+
async def list_facts(
|
|
459
|
+
self,
|
|
460
|
+
scope: Scope = Scope.PROJECT,
|
|
461
|
+
fact_type: Optional[FactType] = None,
|
|
462
|
+
limit: int = 100,
|
|
463
|
+
) -> list[Fact]:
|
|
464
|
+
"""List facts, optionally filtered by type."""
|
|
465
|
+
...
|
|
466
|
+
|
|
467
|
+
@abstractmethod
|
|
468
|
+
async def delete_fact(self, fact_id: UUID, scope: Scope = Scope.PROJECT) -> bool:
|
|
469
|
+
"""Delete a fact. Returns True if it existed."""
|
|
470
|
+
...
|
|
471
|
+
|
|
472
|
+
# Summary operations
|
|
473
|
+
@abstractmethod
|
|
474
|
+
async def save_summary(self, summary: Summary, scope: Scope = Scope.PROJECT) -> None:
|
|
475
|
+
"""Save or update a summary."""
|
|
476
|
+
...
|
|
477
|
+
|
|
478
|
+
@abstractmethod
|
|
479
|
+
async def get_summary(self, summary_id: UUID, scope: Scope = Scope.PROJECT) -> Optional[Summary]:
|
|
480
|
+
"""Get a summary by ID."""
|
|
481
|
+
...
|
|
482
|
+
|
|
483
|
+
@abstractmethod
|
|
484
|
+
async def get_summaries_for_conversation(
|
|
485
|
+
self,
|
|
486
|
+
conversation_id: UUID,
|
|
487
|
+
scope: Scope = Scope.PROJECT,
|
|
488
|
+
) -> list[Summary]:
|
|
489
|
+
"""Get all summaries for a conversation."""
|
|
490
|
+
...
|
|
491
|
+
|
|
492
|
+
@abstractmethod
|
|
493
|
+
async def delete_summary(self, summary_id: UUID, scope: Scope = Scope.PROJECT) -> bool:
|
|
494
|
+
"""Delete a summary. Returns True if it existed."""
|
|
495
|
+
...
|
|
496
|
+
|
|
497
|
+
# Embedding operations (optional - can raise NotImplementedError)
|
|
498
|
+
async def save_embedding(self, embedding: Embedding, scope: Scope = Scope.PROJECT) -> None:
|
|
499
|
+
"""Save an embedding. Optional - may raise NotImplementedError."""
|
|
500
|
+
raise NotImplementedError("Embeddings not supported by this store")
|
|
501
|
+
|
|
502
|
+
async def search_similar(
|
|
503
|
+
self,
|
|
504
|
+
query_vector: list[float],
|
|
505
|
+
limit: int = 10,
|
|
506
|
+
scope: Scope = Scope.PROJECT,
|
|
507
|
+
content_type: Optional[str] = None,
|
|
508
|
+
) -> list[tuple[Embedding, float]]:
|
|
509
|
+
"""
|
|
510
|
+
Search for similar embeddings. Returns (embedding, score) tuples.
|
|
511
|
+
Optional - may raise NotImplementedError.
|
|
512
|
+
"""
|
|
513
|
+
raise NotImplementedError("Embeddings not supported by this store")
|
|
514
|
+
|
|
515
|
+
async def delete_embedding(self, embedding_id: UUID, scope: Scope = Scope.PROJECT) -> bool:
|
|
516
|
+
"""Delete an embedding. Optional - may raise NotImplementedError."""
|
|
517
|
+
raise NotImplementedError("Embeddings not supported by this store")
|
|
518
|
+
|
|
519
|
+
async def close(self) -> None:
|
|
520
|
+
"""Close any connections. Override if needed."""
|
|
521
|
+
pass
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
# =============================================================================
|
|
525
|
+
# Audit/History Models and Store
|
|
526
|
+
# =============================================================================
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
class AuditEventType(str, Enum):
|
|
530
|
+
"""Type of audit event."""
|
|
531
|
+
|
|
532
|
+
# Conversation events
|
|
533
|
+
CONVERSATION_START = "conversation_start"
|
|
534
|
+
CONVERSATION_END = "conversation_end"
|
|
535
|
+
MESSAGE_SENT = "message_sent"
|
|
536
|
+
MESSAGE_RECEIVED = "message_received"
|
|
537
|
+
|
|
538
|
+
# Tool events
|
|
539
|
+
TOOL_CALL = "tool_call"
|
|
540
|
+
TOOL_RESULT = "tool_result"
|
|
541
|
+
TOOL_ERROR = "tool_error"
|
|
542
|
+
|
|
543
|
+
# Agent events
|
|
544
|
+
AGENT_START = "agent_start"
|
|
545
|
+
AGENT_END = "agent_end"
|
|
546
|
+
AGENT_ERROR = "agent_error"
|
|
547
|
+
|
|
548
|
+
# System events
|
|
549
|
+
CHECKPOINT_SAVED = "checkpoint_saved"
|
|
550
|
+
CHECKPOINT_RESTORED = "checkpoint_restored"
|
|
551
|
+
|
|
552
|
+
CUSTOM = "custom"
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
class ErrorSeverity(str, Enum):
|
|
556
|
+
"""Severity level for errors."""
|
|
557
|
+
|
|
558
|
+
DEBUG = "debug"
|
|
559
|
+
INFO = "info"
|
|
560
|
+
WARNING = "warning"
|
|
561
|
+
ERROR = "error"
|
|
562
|
+
CRITICAL = "critical"
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
@dataclass
|
|
566
|
+
class AuditEntry:
|
|
567
|
+
"""An audit log entry for tracking interactions."""
|
|
568
|
+
|
|
569
|
+
id: UUID
|
|
570
|
+
event_type: AuditEventType
|
|
571
|
+
timestamp: datetime = field(default_factory=datetime.utcnow)
|
|
572
|
+
|
|
573
|
+
# Context
|
|
574
|
+
conversation_id: Optional[UUID] = None
|
|
575
|
+
run_id: Optional[UUID] = None
|
|
576
|
+
agent_key: Optional[str] = None
|
|
577
|
+
|
|
578
|
+
# Event details
|
|
579
|
+
action: str = "" # Human-readable action description
|
|
580
|
+
details: dict = field(default_factory=dict) # Event-specific data
|
|
581
|
+
|
|
582
|
+
# Actor information
|
|
583
|
+
actor_type: str = "agent" # agent, user, system
|
|
584
|
+
actor_id: Optional[str] = None
|
|
585
|
+
|
|
586
|
+
# Request/response tracking
|
|
587
|
+
request_id: Optional[str] = None
|
|
588
|
+
parent_event_id: Optional[UUID] = None # For nested events
|
|
589
|
+
|
|
590
|
+
metadata: dict = field(default_factory=dict)
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
@dataclass
|
|
594
|
+
class ErrorRecord:
|
|
595
|
+
"""A record of an error for debugging."""
|
|
596
|
+
|
|
597
|
+
id: UUID
|
|
598
|
+
timestamp: datetime = field(default_factory=datetime.utcnow)
|
|
599
|
+
severity: ErrorSeverity = ErrorSeverity.ERROR
|
|
600
|
+
|
|
601
|
+
# Error details
|
|
602
|
+
error_type: str = "" # Exception class name
|
|
603
|
+
message: str = ""
|
|
604
|
+
stack_trace: Optional[str] = None
|
|
605
|
+
|
|
606
|
+
# Context
|
|
607
|
+
conversation_id: Optional[UUID] = None
|
|
608
|
+
run_id: Optional[UUID] = None
|
|
609
|
+
agent_key: Optional[str] = None
|
|
610
|
+
|
|
611
|
+
# What was happening when error occurred
|
|
612
|
+
context: dict = field(default_factory=dict)
|
|
613
|
+
|
|
614
|
+
# Resolution tracking
|
|
615
|
+
resolved: bool = False
|
|
616
|
+
resolved_at: Optional[datetime] = None
|
|
617
|
+
resolution_notes: Optional[str] = None
|
|
618
|
+
|
|
619
|
+
metadata: dict = field(default_factory=dict)
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
@dataclass
|
|
623
|
+
class PerformanceMetric:
|
|
624
|
+
"""A performance metric for monitoring."""
|
|
625
|
+
|
|
626
|
+
id: UUID
|
|
627
|
+
name: str # Metric name (e.g., "llm_latency", "tool_execution_time")
|
|
628
|
+
value: float # Metric value
|
|
629
|
+
unit: str = "" # Unit of measurement (ms, tokens, etc.)
|
|
630
|
+
|
|
631
|
+
timestamp: datetime = field(default_factory=datetime.utcnow)
|
|
632
|
+
|
|
633
|
+
# Context
|
|
634
|
+
conversation_id: Optional[UUID] = None
|
|
635
|
+
run_id: Optional[UUID] = None
|
|
636
|
+
agent_key: Optional[str] = None
|
|
637
|
+
|
|
638
|
+
# Additional dimensions for grouping/filtering
|
|
639
|
+
tags: dict = field(default_factory=dict)
|
|
640
|
+
|
|
641
|
+
metadata: dict = field(default_factory=dict)
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
class AuditStore(ABC):
|
|
645
|
+
"""
|
|
646
|
+
Abstract interface for audit and history storage.
|
|
647
|
+
|
|
648
|
+
Audit stores handle interaction logs, error history, and
|
|
649
|
+
performance metrics. This is optional - agents can function
|
|
650
|
+
without an audit store.
|
|
651
|
+
"""
|
|
652
|
+
|
|
653
|
+
# Audit entry operations
|
|
654
|
+
@abstractmethod
|
|
655
|
+
async def log_event(self, entry: AuditEntry, scope: Scope = Scope.PROJECT) -> None:
|
|
656
|
+
"""Log an audit event."""
|
|
657
|
+
...
|
|
658
|
+
|
|
659
|
+
@abstractmethod
|
|
660
|
+
async def get_events(
|
|
661
|
+
self,
|
|
662
|
+
scope: Scope = Scope.PROJECT,
|
|
663
|
+
conversation_id: Optional[UUID] = None,
|
|
664
|
+
run_id: Optional[UUID] = None,
|
|
665
|
+
event_types: Optional[list[AuditEventType]] = None,
|
|
666
|
+
start_time: Optional[datetime] = None,
|
|
667
|
+
end_time: Optional[datetime] = None,
|
|
668
|
+
limit: int = 100,
|
|
669
|
+
) -> list[AuditEntry]:
|
|
670
|
+
"""Get audit events with optional filters."""
|
|
671
|
+
...
|
|
672
|
+
|
|
673
|
+
# Error operations
|
|
674
|
+
@abstractmethod
|
|
675
|
+
async def log_error(self, error: ErrorRecord, scope: Scope = Scope.PROJECT) -> None:
|
|
676
|
+
"""Log an error."""
|
|
677
|
+
...
|
|
678
|
+
|
|
679
|
+
@abstractmethod
|
|
680
|
+
async def get_errors(
|
|
681
|
+
self,
|
|
682
|
+
scope: Scope = Scope.PROJECT,
|
|
683
|
+
severity: Optional[ErrorSeverity] = None,
|
|
684
|
+
resolved: Optional[bool] = None,
|
|
685
|
+
start_time: Optional[datetime] = None,
|
|
686
|
+
end_time: Optional[datetime] = None,
|
|
687
|
+
limit: int = 100,
|
|
688
|
+
) -> list[ErrorRecord]:
|
|
689
|
+
"""Get errors with optional filters."""
|
|
690
|
+
...
|
|
691
|
+
|
|
692
|
+
@abstractmethod
|
|
693
|
+
async def resolve_error(
|
|
694
|
+
self,
|
|
695
|
+
error_id: UUID,
|
|
696
|
+
resolution_notes: Optional[str] = None,
|
|
697
|
+
scope: Scope = Scope.PROJECT,
|
|
698
|
+
) -> bool:
|
|
699
|
+
"""Mark an error as resolved. Returns True if error existed."""
|
|
700
|
+
...
|
|
701
|
+
|
|
702
|
+
# Performance metric operations
|
|
703
|
+
@abstractmethod
|
|
704
|
+
async def record_metric(self, metric: PerformanceMetric, scope: Scope = Scope.PROJECT) -> None:
|
|
705
|
+
"""Record a performance metric."""
|
|
706
|
+
...
|
|
707
|
+
|
|
708
|
+
@abstractmethod
|
|
709
|
+
async def get_metrics(
|
|
710
|
+
self,
|
|
711
|
+
name: str,
|
|
712
|
+
scope: Scope = Scope.PROJECT,
|
|
713
|
+
start_time: Optional[datetime] = None,
|
|
714
|
+
end_time: Optional[datetime] = None,
|
|
715
|
+
tags: Optional[dict] = None,
|
|
716
|
+
limit: int = 1000,
|
|
717
|
+
) -> list[PerformanceMetric]:
|
|
718
|
+
"""Get metrics by name with optional filters."""
|
|
719
|
+
...
|
|
720
|
+
|
|
721
|
+
@abstractmethod
|
|
722
|
+
async def get_metric_summary(
|
|
723
|
+
self,
|
|
724
|
+
name: str,
|
|
725
|
+
scope: Scope = Scope.PROJECT,
|
|
726
|
+
start_time: Optional[datetime] = None,
|
|
727
|
+
end_time: Optional[datetime] = None,
|
|
728
|
+
) -> dict:
|
|
729
|
+
"""
|
|
730
|
+
Get summary statistics for a metric.
|
|
731
|
+
Returns: {count, min, max, avg, sum, p50, p95, p99}
|
|
732
|
+
"""
|
|
733
|
+
...
|
|
734
|
+
|
|
735
|
+
async def close(self) -> None:
|
|
736
|
+
"""Close any connections. Override if needed."""
|
|
737
|
+
pass
|