django-agent-runtime 0.3.6__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.
Files changed (55) hide show
  1. django_agent_runtime/__init__.py +25 -0
  2. django_agent_runtime/admin.py +155 -0
  3. django_agent_runtime/api/__init__.py +26 -0
  4. django_agent_runtime/api/permissions.py +109 -0
  5. django_agent_runtime/api/serializers.py +114 -0
  6. django_agent_runtime/api/views.py +472 -0
  7. django_agent_runtime/apps.py +26 -0
  8. django_agent_runtime/conf.py +241 -0
  9. django_agent_runtime/examples/__init__.py +10 -0
  10. django_agent_runtime/examples/langgraph_adapter.py +164 -0
  11. django_agent_runtime/examples/langgraph_tools.py +179 -0
  12. django_agent_runtime/examples/simple_chat.py +69 -0
  13. django_agent_runtime/examples/tool_agent.py +157 -0
  14. django_agent_runtime/management/__init__.py +2 -0
  15. django_agent_runtime/management/commands/__init__.py +2 -0
  16. django_agent_runtime/management/commands/runagent.py +419 -0
  17. django_agent_runtime/migrations/0001_initial.py +117 -0
  18. django_agent_runtime/migrations/0002_persistence_models.py +129 -0
  19. django_agent_runtime/migrations/0003_persistenceconversation_active_branch_id_and_more.py +212 -0
  20. django_agent_runtime/migrations/0004_add_anonymous_session_id.py +18 -0
  21. django_agent_runtime/migrations/__init__.py +2 -0
  22. django_agent_runtime/models/__init__.py +54 -0
  23. django_agent_runtime/models/base.py +450 -0
  24. django_agent_runtime/models/concrete.py +146 -0
  25. django_agent_runtime/persistence/__init__.py +60 -0
  26. django_agent_runtime/persistence/helpers.py +148 -0
  27. django_agent_runtime/persistence/models.py +506 -0
  28. django_agent_runtime/persistence/stores.py +1191 -0
  29. django_agent_runtime/runtime/__init__.py +23 -0
  30. django_agent_runtime/runtime/events/__init__.py +65 -0
  31. django_agent_runtime/runtime/events/base.py +135 -0
  32. django_agent_runtime/runtime/events/db.py +129 -0
  33. django_agent_runtime/runtime/events/redis.py +228 -0
  34. django_agent_runtime/runtime/events/sync.py +140 -0
  35. django_agent_runtime/runtime/interfaces.py +475 -0
  36. django_agent_runtime/runtime/llm/__init__.py +91 -0
  37. django_agent_runtime/runtime/llm/anthropic.py +249 -0
  38. django_agent_runtime/runtime/llm/litellm_adapter.py +173 -0
  39. django_agent_runtime/runtime/llm/openai.py +230 -0
  40. django_agent_runtime/runtime/queue/__init__.py +75 -0
  41. django_agent_runtime/runtime/queue/base.py +158 -0
  42. django_agent_runtime/runtime/queue/postgres.py +248 -0
  43. django_agent_runtime/runtime/queue/redis_streams.py +336 -0
  44. django_agent_runtime/runtime/queue/sync.py +277 -0
  45. django_agent_runtime/runtime/registry.py +186 -0
  46. django_agent_runtime/runtime/runner.py +540 -0
  47. django_agent_runtime/runtime/tracing/__init__.py +48 -0
  48. django_agent_runtime/runtime/tracing/langfuse.py +117 -0
  49. django_agent_runtime/runtime/tracing/noop.py +36 -0
  50. django_agent_runtime/urls.py +39 -0
  51. django_agent_runtime-0.3.6.dist-info/METADATA +723 -0
  52. django_agent_runtime-0.3.6.dist-info/RECORD +55 -0
  53. django_agent_runtime-0.3.6.dist-info/WHEEL +5 -0
  54. django_agent_runtime-0.3.6.dist-info/licenses/LICENSE +22 -0
  55. django_agent_runtime-0.3.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,148 @@
1
+ """
2
+ Helper functions for configuring persistence in Django.
3
+
4
+ Provides convenient ways to get a PersistenceManager configured
5
+ with Django-backed stores for the current request/user.
6
+ """
7
+
8
+ from typing import Optional
9
+
10
+ from agent_runtime_core.persistence import (
11
+ PersistenceConfig,
12
+ PersistenceManager,
13
+ )
14
+
15
+ from django_agent_runtime.persistence.stores import (
16
+ DjangoMemoryStore,
17
+ DjangoConversationStore,
18
+ DjangoTaskStore,
19
+ DjangoPreferencesStore,
20
+ DjangoKnowledgeStore,
21
+ DjangoAuditStore,
22
+ )
23
+
24
+
25
+ def get_persistence_config(user) -> PersistenceConfig:
26
+ """
27
+ Get a PersistenceConfig configured with Django stores for a user.
28
+
29
+ Args:
30
+ user: Django user instance
31
+
32
+ Returns:
33
+ PersistenceConfig with all Django stores configured
34
+
35
+ Example:
36
+ from django_agent_runtime.persistence import get_persistence_config
37
+ from agent_runtime_core.persistence import PersistenceManager
38
+
39
+ config = get_persistence_config(request.user)
40
+ manager = PersistenceManager(config)
41
+
42
+ # Use the manager
43
+ await manager.memory.set("key", "value")
44
+ """
45
+ return PersistenceConfig(
46
+ memory_store=DjangoMemoryStore(user=user),
47
+ conversation_store=DjangoConversationStore(user=user),
48
+ task_store=DjangoTaskStore(user=user),
49
+ preferences_store=DjangoPreferencesStore(user=user),
50
+ knowledge_store=DjangoKnowledgeStore(user=user),
51
+ audit_store=DjangoAuditStore(user=user),
52
+ )
53
+
54
+
55
+ def get_persistence_manager(user) -> PersistenceManager:
56
+ """
57
+ Get a PersistenceManager configured with Django stores for a user.
58
+
59
+ This is a convenience function that creates both the config and manager.
60
+
61
+ Args:
62
+ user: Django user instance
63
+
64
+ Returns:
65
+ PersistenceManager ready to use
66
+
67
+ Example:
68
+ from django_agent_runtime.persistence import get_persistence_manager
69
+
70
+ async def my_view(request):
71
+ manager = get_persistence_manager(request.user)
72
+
73
+ # Store memory
74
+ await manager.memory.set("last_query", "hello world")
75
+
76
+ # Get preferences
77
+ theme = await manager.preferences.get("theme")
78
+ """
79
+ config = get_persistence_config(user)
80
+ return PersistenceManager(config)
81
+
82
+
83
+ class PersistenceMiddleware:
84
+ """
85
+ Django middleware that attaches a PersistenceManager to the request.
86
+
87
+ Add to MIDDLEWARE in settings.py:
88
+ MIDDLEWARE = [
89
+ ...
90
+ 'django_agent_runtime.persistence.helpers.PersistenceMiddleware',
91
+ ]
92
+
93
+ Then access in views:
94
+ async def my_view(request):
95
+ await request.persistence.memory.set("key", "value")
96
+
97
+ Note: Only works for authenticated users. For anonymous users,
98
+ request.persistence will be None.
99
+ """
100
+
101
+ def __init__(self, get_response):
102
+ self.get_response = get_response
103
+
104
+ def __call__(self, request):
105
+ # Attach persistence manager for authenticated users
106
+ if hasattr(request, 'user') and request.user.is_authenticated:
107
+ request.persistence = get_persistence_manager(request.user)
108
+ else:
109
+ request.persistence = None
110
+
111
+ response = self.get_response(request)
112
+ return response
113
+
114
+
115
+ def get_store_factories(user_getter):
116
+ """
117
+ Get factory functions for lazy store instantiation.
118
+
119
+ Useful when you need to defer user resolution (e.g., in class-based views).
120
+
121
+ Args:
122
+ user_getter: Callable that returns the current user
123
+
124
+ Returns:
125
+ Dict of factory functions suitable for PersistenceConfig
126
+
127
+ Example:
128
+ from django_agent_runtime.persistence.helpers import get_store_factories
129
+
130
+ # In a class-based view
131
+ factories = get_store_factories(lambda: self.request.user)
132
+ config = PersistenceConfig(
133
+ memory_store_factory=factories['memory'],
134
+ conversation_store_factory=factories['conversation'],
135
+ task_store_factory=factories['task'],
136
+ preferences_store_factory=factories['preferences'],
137
+ knowledge_store_factory=factories['knowledge'],
138
+ audit_store_factory=factories['audit'],
139
+ )
140
+ """
141
+ return {
142
+ 'memory': lambda: DjangoMemoryStore(user=user_getter()),
143
+ 'conversation': lambda: DjangoConversationStore(user=user_getter()),
144
+ 'task': lambda: DjangoTaskStore(user=user_getter()),
145
+ 'preferences': lambda: DjangoPreferencesStore(user=user_getter()),
146
+ 'knowledge': lambda: DjangoKnowledgeStore(user=user_getter()),
147
+ 'audit': lambda: DjangoAuditStore(user=user_getter()),
148
+ }
@@ -0,0 +1,506 @@
1
+ """
2
+ Django models for the persistence layer.
3
+
4
+ These models back the Django implementations of the agent-runtime-core
5
+ persistence stores.
6
+ """
7
+
8
+ import uuid
9
+ from django.db import models
10
+ from django.conf import settings
11
+
12
+
13
+ class Memory(models.Model):
14
+ """
15
+ Key-value memory storage for agents.
16
+
17
+ Stores arbitrary JSON-serializable values keyed by string.
18
+ Scoped to a user for multi-tenant support.
19
+ """
20
+
21
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
22
+ user = models.ForeignKey(
23
+ settings.AUTH_USER_MODEL,
24
+ on_delete=models.CASCADE,
25
+ related_name="agent_memories",
26
+ )
27
+ key = models.CharField(max_length=255, db_index=True)
28
+ value = models.JSONField()
29
+ created_at = models.DateTimeField(auto_now_add=True)
30
+ updated_at = models.DateTimeField(auto_now=True)
31
+
32
+ class Meta:
33
+ app_label = "django_agent_runtime"
34
+ db_table = "agent_runtime_memory"
35
+ unique_together = [("user", "key")]
36
+ verbose_name = "Agent Memory"
37
+ verbose_name_plural = "Agent Memories"
38
+
39
+ def __str__(self):
40
+ return f"{self.key} ({self.user})"
41
+
42
+
43
+ class PersistenceConversation(models.Model):
44
+ """
45
+ Conversation storage for the persistence layer.
46
+
47
+ This is separate from AgentConversation to support the agent-runtime-core
48
+ persistence interface which has different semantics.
49
+ """
50
+
51
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
52
+ user = models.ForeignKey(
53
+ settings.AUTH_USER_MODEL,
54
+ on_delete=models.CASCADE,
55
+ related_name="persistence_conversations",
56
+ )
57
+ title = models.CharField(max_length=255, blank=True)
58
+ agent_key = models.CharField(max_length=100, blank=True, db_index=True)
59
+ summary = models.TextField(blank=True)
60
+ metadata = models.JSONField(default=dict, blank=True)
61
+ created_at = models.DateTimeField(auto_now_add=True, db_index=True)
62
+ updated_at = models.DateTimeField(auto_now=True)
63
+
64
+ # Branching/forking support
65
+ parent_conversation_id = models.UUIDField(null=True, blank=True, db_index=True)
66
+ active_branch_id = models.UUIDField(null=True, blank=True)
67
+
68
+ class Meta:
69
+ app_label = "django_agent_runtime"
70
+ db_table = "agent_runtime_persistence_conversation"
71
+ ordering = ["-updated_at"]
72
+ verbose_name = "Persistence Conversation"
73
+ verbose_name_plural = "Persistence Conversations"
74
+
75
+ def __str__(self):
76
+ return f"{self.title or 'Untitled'} ({self.id})"
77
+
78
+
79
+ class PersistenceMessage(models.Model):
80
+ """
81
+ Message within a persistence conversation.
82
+ """
83
+
84
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
85
+ conversation = models.ForeignKey(
86
+ PersistenceConversation,
87
+ on_delete=models.CASCADE,
88
+ related_name="messages",
89
+ )
90
+ role = models.CharField(max_length=20) # system, user, assistant, tool
91
+ content = models.JSONField() # Can be string, dict, or list
92
+ tool_calls = models.JSONField(default=list, blank=True)
93
+ tool_call_id = models.CharField(max_length=255, blank=True)
94
+ model = models.CharField(max_length=100, blank=True)
95
+ usage = models.JSONField(default=dict, blank=True)
96
+ metadata = models.JSONField(default=dict, blank=True)
97
+ timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
98
+
99
+ # Branching support
100
+ parent_message_id = models.UUIDField(null=True, blank=True, db_index=True)
101
+ branch_id = models.UUIDField(null=True, blank=True, db_index=True)
102
+
103
+ class Meta:
104
+ app_label = "django_agent_runtime"
105
+ db_table = "agent_runtime_persistence_message"
106
+ ordering = ["timestamp"]
107
+ verbose_name = "Persistence Message"
108
+ verbose_name_plural = "Persistence Messages"
109
+
110
+ def __str__(self):
111
+ return f"{self.role}: {str(self.content)[:50]}"
112
+
113
+
114
+ class TaskStateChoices(models.TextChoices):
115
+ """Task state choices matching agent_runtime_core.persistence.TaskState."""
116
+
117
+ NOT_STARTED = "not_started", "Not Started"
118
+ IN_PROGRESS = "in_progress", "In Progress"
119
+ COMPLETE = "complete", "Complete"
120
+ CANCELLED = "cancelled", "Cancelled"
121
+
122
+
123
+ class PersistenceTaskList(models.Model):
124
+ """
125
+ Task list for tracking agent work.
126
+ """
127
+
128
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
129
+ user = models.ForeignKey(
130
+ settings.AUTH_USER_MODEL,
131
+ on_delete=models.CASCADE,
132
+ related_name="persistence_task_lists",
133
+ )
134
+ name = models.CharField(max_length=255)
135
+ conversation_id = models.UUIDField(null=True, blank=True, db_index=True)
136
+ run_id = models.UUIDField(null=True, blank=True, db_index=True)
137
+ created_at = models.DateTimeField(auto_now_add=True)
138
+ updated_at = models.DateTimeField(auto_now=True)
139
+
140
+ class Meta:
141
+ app_label = "django_agent_runtime"
142
+ db_table = "agent_runtime_persistence_task_list"
143
+ ordering = ["-updated_at"]
144
+ verbose_name = "Persistence Task List"
145
+ verbose_name_plural = "Persistence Task Lists"
146
+
147
+ def __str__(self):
148
+ return self.name
149
+
150
+
151
+ class PersistenceTask(models.Model):
152
+ """
153
+ Individual task within a task list.
154
+ """
155
+
156
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
157
+ task_list = models.ForeignKey(
158
+ PersistenceTaskList,
159
+ on_delete=models.CASCADE,
160
+ related_name="tasks",
161
+ )
162
+ name = models.CharField(max_length=255)
163
+ description = models.TextField(blank=True)
164
+ state = models.CharField(
165
+ max_length=20,
166
+ choices=TaskStateChoices.choices,
167
+ default=TaskStateChoices.NOT_STARTED,
168
+ )
169
+ parent_id = models.UUIDField(null=True, blank=True)
170
+ metadata = models.JSONField(default=dict, blank=True)
171
+ created_at = models.DateTimeField(auto_now_add=True)
172
+ updated_at = models.DateTimeField(auto_now=True)
173
+
174
+ # Dependencies and scheduling
175
+ dependencies = models.JSONField(default=list, blank=True) # List of task UUIDs
176
+ priority = models.IntegerField(default=0) # Higher = more important
177
+ due_at = models.DateTimeField(null=True, blank=True)
178
+ completed_at = models.DateTimeField(null=True, blank=True)
179
+
180
+ # Checkpoint for resumable long-running operations
181
+ checkpoint_data = models.JSONField(default=dict, blank=True)
182
+ checkpoint_at = models.DateTimeField(null=True, blank=True)
183
+
184
+ # Execution tracking
185
+ attempts = models.IntegerField(default=0)
186
+ last_error = models.TextField(blank=True)
187
+
188
+ class Meta:
189
+ app_label = "django_agent_runtime"
190
+ db_table = "agent_runtime_persistence_task"
191
+ ordering = ["created_at"]
192
+ verbose_name = "Persistence Task"
193
+ verbose_name_plural = "Persistence Tasks"
194
+
195
+ def __str__(self):
196
+ return f"{self.name} ({self.state})"
197
+
198
+
199
+ class Preferences(models.Model):
200
+ """
201
+ User preferences storage for agents.
202
+
203
+ Stores configuration and preferences that persist across sessions.
204
+ """
205
+
206
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
207
+ user = models.ForeignKey(
208
+ settings.AUTH_USER_MODEL,
209
+ on_delete=models.CASCADE,
210
+ related_name="agent_preferences",
211
+ )
212
+ key = models.CharField(max_length=255, db_index=True)
213
+ value = models.JSONField()
214
+ created_at = models.DateTimeField(auto_now_add=True)
215
+ updated_at = models.DateTimeField(auto_now=True)
216
+
217
+ class Meta:
218
+ app_label = "django_agent_runtime"
219
+ db_table = "agent_runtime_preferences"
220
+ unique_together = [("user", "key")]
221
+ verbose_name = "Agent Preference"
222
+ verbose_name_plural = "Agent Preferences"
223
+
224
+ def __str__(self):
225
+ return f"{self.key} ({self.user})"
226
+
227
+
228
+ # =============================================================================
229
+ # Knowledge Store Models
230
+ # =============================================================================
231
+
232
+
233
+ class FactTypeChoices(models.TextChoices):
234
+ """Fact type choices matching agent_runtime_core.persistence.FactType."""
235
+
236
+ USER = "user", "User"
237
+ PROJECT = "project", "Project"
238
+ PREFERENCE = "preference", "Preference"
239
+ CONTEXT = "context", "Context"
240
+ CUSTOM = "custom", "Custom"
241
+
242
+
243
+ class Fact(models.Model):
244
+ """
245
+ A learned fact about user, project, or context.
246
+ """
247
+
248
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
249
+ user = models.ForeignKey(
250
+ settings.AUTH_USER_MODEL,
251
+ on_delete=models.CASCADE,
252
+ related_name="agent_facts",
253
+ )
254
+ key = models.CharField(max_length=255, db_index=True)
255
+ value = models.JSONField()
256
+ fact_type = models.CharField(
257
+ max_length=20,
258
+ choices=FactTypeChoices.choices,
259
+ default=FactTypeChoices.CUSTOM,
260
+ db_index=True,
261
+ )
262
+ confidence = models.FloatField(default=1.0) # 0.0 to 1.0
263
+ source = models.CharField(max_length=255, blank=True)
264
+ expires_at = models.DateTimeField(null=True, blank=True, db_index=True)
265
+ metadata = models.JSONField(default=dict, blank=True)
266
+ created_at = models.DateTimeField(auto_now_add=True)
267
+ updated_at = models.DateTimeField(auto_now=True)
268
+
269
+ class Meta:
270
+ app_label = "django_agent_runtime"
271
+ db_table = "agent_runtime_fact"
272
+ unique_together = [("user", "key")]
273
+ verbose_name = "Fact"
274
+ verbose_name_plural = "Facts"
275
+
276
+ def __str__(self):
277
+ return f"{self.key}: {str(self.value)[:50]}"
278
+
279
+
280
+ class Summary(models.Model):
281
+ """
282
+ A summary of a conversation or set of interactions.
283
+ """
284
+
285
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
286
+ user = models.ForeignKey(
287
+ settings.AUTH_USER_MODEL,
288
+ on_delete=models.CASCADE,
289
+ related_name="agent_summaries",
290
+ )
291
+ content = models.TextField()
292
+ conversation_id = models.UUIDField(null=True, blank=True, db_index=True)
293
+ conversation_ids = models.JSONField(default=list, blank=True) # For multi-conversation summaries
294
+ start_time = models.DateTimeField(null=True, blank=True)
295
+ end_time = models.DateTimeField(null=True, blank=True)
296
+ metadata = models.JSONField(default=dict, blank=True)
297
+ created_at = models.DateTimeField(auto_now_add=True)
298
+
299
+ class Meta:
300
+ app_label = "django_agent_runtime"
301
+ db_table = "agent_runtime_summary"
302
+ ordering = ["-created_at"]
303
+ verbose_name = "Summary"
304
+ verbose_name_plural = "Summaries"
305
+
306
+ def __str__(self):
307
+ return f"Summary: {self.content[:50]}"
308
+
309
+
310
+ class Embedding(models.Model):
311
+ """
312
+ A vector embedding for semantic search.
313
+
314
+ Note: For optimal performance with large datasets, consider using
315
+ pgvector extension for PostgreSQL.
316
+ """
317
+
318
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
319
+ user = models.ForeignKey(
320
+ settings.AUTH_USER_MODEL,
321
+ on_delete=models.CASCADE,
322
+ related_name="agent_embeddings",
323
+ )
324
+ vector = models.JSONField() # List of floats; use pgvector for production
325
+ content = models.TextField() # Original text
326
+ content_type = models.CharField(max_length=50, default="text", db_index=True)
327
+ source_id = models.UUIDField(null=True, blank=True, db_index=True)
328
+ model = models.CharField(max_length=100, blank=True)
329
+ dimensions = models.IntegerField(default=0)
330
+ metadata = models.JSONField(default=dict, blank=True)
331
+ created_at = models.DateTimeField(auto_now_add=True)
332
+
333
+ class Meta:
334
+ app_label = "django_agent_runtime"
335
+ db_table = "agent_runtime_embedding"
336
+ verbose_name = "Embedding"
337
+ verbose_name_plural = "Embeddings"
338
+
339
+ def __str__(self):
340
+ return f"Embedding: {self.content[:50]}"
341
+
342
+
343
+ # =============================================================================
344
+ # Audit Store Models
345
+ # =============================================================================
346
+
347
+
348
+ class AuditEventTypeChoices(models.TextChoices):
349
+ """Audit event type choices matching agent_runtime_core.persistence.AuditEventType."""
350
+
351
+ CONVERSATION_START = "conversation_start", "Conversation Start"
352
+ CONVERSATION_END = "conversation_end", "Conversation End"
353
+ MESSAGE_SENT = "message_sent", "Message Sent"
354
+ MESSAGE_RECEIVED = "message_received", "Message Received"
355
+ TOOL_CALL = "tool_call", "Tool Call"
356
+ TOOL_RESULT = "tool_result", "Tool Result"
357
+ TOOL_ERROR = "tool_error", "Tool Error"
358
+ AGENT_START = "agent_start", "Agent Start"
359
+ AGENT_END = "agent_end", "Agent End"
360
+ AGENT_ERROR = "agent_error", "Agent Error"
361
+ CHECKPOINT_SAVED = "checkpoint_saved", "Checkpoint Saved"
362
+ CHECKPOINT_RESTORED = "checkpoint_restored", "Checkpoint Restored"
363
+ CUSTOM = "custom", "Custom"
364
+
365
+
366
+ class ErrorSeverityChoices(models.TextChoices):
367
+ """Error severity choices matching agent_runtime_core.persistence.ErrorSeverity."""
368
+
369
+ DEBUG = "debug", "Debug"
370
+ INFO = "info", "Info"
371
+ WARNING = "warning", "Warning"
372
+ ERROR = "error", "Error"
373
+ CRITICAL = "critical", "Critical"
374
+
375
+
376
+ class AuditEntry(models.Model):
377
+ """
378
+ An audit log entry for tracking interactions.
379
+ """
380
+
381
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
382
+ user = models.ForeignKey(
383
+ settings.AUTH_USER_MODEL,
384
+ on_delete=models.CASCADE,
385
+ related_name="agent_audit_entries",
386
+ )
387
+ event_type = models.CharField(
388
+ max_length=30,
389
+ choices=AuditEventTypeChoices.choices,
390
+ db_index=True,
391
+ )
392
+ timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
393
+
394
+ # Context
395
+ conversation_id = models.UUIDField(null=True, blank=True, db_index=True)
396
+ run_id = models.UUIDField(null=True, blank=True, db_index=True)
397
+ agent_key = models.CharField(max_length=100, blank=True, db_index=True)
398
+
399
+ # Event details
400
+ action = models.CharField(max_length=255, blank=True)
401
+ details = models.JSONField(default=dict, blank=True)
402
+
403
+ # Actor information
404
+ actor_type = models.CharField(max_length=20, default="agent")
405
+ actor_id = models.CharField(max_length=255, blank=True)
406
+
407
+ # Request/response tracking
408
+ request_id = models.CharField(max_length=255, blank=True)
409
+ parent_event_id = models.UUIDField(null=True, blank=True)
410
+
411
+ metadata = models.JSONField(default=dict, blank=True)
412
+
413
+ class Meta:
414
+ app_label = "django_agent_runtime"
415
+ db_table = "agent_runtime_audit_entry"
416
+ ordering = ["-timestamp"]
417
+ verbose_name = "Audit Entry"
418
+ verbose_name_plural = "Audit Entries"
419
+
420
+ def __str__(self):
421
+ return f"{self.event_type}: {self.action}"
422
+
423
+
424
+ class ErrorRecord(models.Model):
425
+ """
426
+ A record of an error for debugging.
427
+ """
428
+
429
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
430
+ user = models.ForeignKey(
431
+ settings.AUTH_USER_MODEL,
432
+ on_delete=models.CASCADE,
433
+ related_name="agent_error_records",
434
+ )
435
+ timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
436
+ severity = models.CharField(
437
+ max_length=10,
438
+ choices=ErrorSeverityChoices.choices,
439
+ default=ErrorSeverityChoices.ERROR,
440
+ db_index=True,
441
+ )
442
+
443
+ # Error details
444
+ error_type = models.CharField(max_length=255, blank=True)
445
+ message = models.TextField(blank=True)
446
+ stack_trace = models.TextField(blank=True)
447
+
448
+ # Context
449
+ conversation_id = models.UUIDField(null=True, blank=True, db_index=True)
450
+ run_id = models.UUIDField(null=True, blank=True, db_index=True)
451
+ agent_key = models.CharField(max_length=100, blank=True, db_index=True)
452
+ context = models.JSONField(default=dict, blank=True)
453
+
454
+ # Resolution tracking
455
+ resolved = models.BooleanField(default=False, db_index=True)
456
+ resolved_at = models.DateTimeField(null=True, blank=True)
457
+ resolution_notes = models.TextField(blank=True)
458
+
459
+ metadata = models.JSONField(default=dict, blank=True)
460
+
461
+ class Meta:
462
+ app_label = "django_agent_runtime"
463
+ db_table = "agent_runtime_error_record"
464
+ ordering = ["-timestamp"]
465
+ verbose_name = "Error Record"
466
+ verbose_name_plural = "Error Records"
467
+
468
+ def __str__(self):
469
+ return f"{self.severity}: {self.error_type}"
470
+
471
+
472
+ class PerformanceMetric(models.Model):
473
+ """
474
+ A performance metric for monitoring.
475
+ """
476
+
477
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
478
+ user = models.ForeignKey(
479
+ settings.AUTH_USER_MODEL,
480
+ on_delete=models.CASCADE,
481
+ related_name="agent_performance_metrics",
482
+ )
483
+ name = models.CharField(max_length=100, db_index=True)
484
+ value = models.FloatField()
485
+ unit = models.CharField(max_length=20, blank=True)
486
+ timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
487
+
488
+ # Context
489
+ conversation_id = models.UUIDField(null=True, blank=True, db_index=True)
490
+ run_id = models.UUIDField(null=True, blank=True, db_index=True)
491
+ agent_key = models.CharField(max_length=100, blank=True, db_index=True)
492
+
493
+ # Additional dimensions for grouping/filtering
494
+ tags = models.JSONField(default=dict, blank=True)
495
+
496
+ metadata = models.JSONField(default=dict, blank=True)
497
+
498
+ class Meta:
499
+ app_label = "django_agent_runtime"
500
+ db_table = "agent_runtime_performance_metric"
501
+ ordering = ["-timestamp"]
502
+ verbose_name = "Performance Metric"
503
+ verbose_name_plural = "Performance Metrics"
504
+
505
+ def __str__(self):
506
+ return f"{self.name}: {self.value} {self.unit}"