django-cfg 1.3.9__py3-none-any.whl → 1.3.11__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.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/payments/admin/networks_admin.py +12 -1
- django_cfg/apps/payments/admin/payments_admin.py +13 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +62 -14
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +33 -3
- django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +96 -45
- django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
- django_cfg/apps/payments/config/__init__.py +14 -15
- django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
- django_cfg/apps/payments/config/helpers.py +8 -13
- django_cfg/apps/payments/migrations/0001_initial.py +33 -46
- django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
- django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
- django_cfg/apps/payments/models/payments.py +94 -0
- django_cfg/apps/payments/services/core/base.py +4 -4
- django_cfg/apps/payments/services/core/payment_service.py +265 -38
- django_cfg/apps/payments/services/providers/base.py +209 -3
- django_cfg/apps/payments/services/providers/models/__init__.py +2 -0
- django_cfg/apps/payments/services/providers/models/base.py +25 -2
- django_cfg/apps/payments/services/providers/nowpayments/models.py +2 -2
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +57 -9
- django_cfg/apps/payments/services/providers/registry.py +5 -5
- django_cfg/apps/payments/services/types/requests.py +19 -7
- django_cfg/apps/payments/signals/payment_signals.py +31 -2
- django_cfg/apps/payments/static/payments/js/api-client.js +6 -1
- django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
- django_cfg/apps/payments/static/payments/js/payment-form.js +35 -26
- django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
- django_cfg/apps/payments/urls.py +3 -2
- django_cfg/apps/payments/views/api/currencies.py +3 -0
- django_cfg/apps/payments/views/serializers/currencies.py +18 -5
- django_cfg/apps/tasks/admin/tasks_admin.py +2 -2
- django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
- django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
- django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
- django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
- django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
- django_cfg/apps/tasks/tasks/__init__.py +10 -0
- django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
- django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
- django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
- django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
- django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
- django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
- django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
- django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
- django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
- django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
- django_cfg/apps/tasks/urls.py +2 -2
- django_cfg/apps/tasks/urls_admin.py +2 -2
- django_cfg/apps/tasks/utils/__init__.py +1 -0
- django_cfg/apps/tasks/utils/simulator.py +356 -0
- django_cfg/apps/tasks/views/__init__.py +16 -0
- django_cfg/apps/tasks/views/api.py +569 -0
- django_cfg/apps/tasks/views/dashboard.py +58 -0
- django_cfg/core/integration/__init__.py +21 -0
- django_cfg/management/commands/rundramatiq_simulator.py +430 -0
- django_cfg/models/constance.py +0 -11
- django_cfg/models/payments.py +137 -3
- django_cfg/modules/django_tasks.py +54 -21
- django_cfg/registry/core.py +4 -9
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -2
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/RECORD +84 -152
- django_cfg/apps/payments/config/constance/__init__.py +0 -22
- django_cfg/apps/payments/config/constance/config_service.py +0 -123
- django_cfg/apps/payments/config/constance/fields.py +0 -69
- django_cfg/apps/payments/config/constance/settings.py +0 -160
- django_cfg/apps/payments/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +0 -26
- django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +0 -28
- django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +0 -30
- django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
- django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
- django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
- django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
- django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
- django_cfg/apps/tasks/templates/tasks/base.html +0 -96
- django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
- django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
- django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
- django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
- django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
- django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
- django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
- django_cfg/apps/tasks/views.py +0 -461
- django_cfg/management/commands/app_agent_diagnose.py +0 -470
- django_cfg/management/commands/app_agent_generate.py +0 -342
- django_cfg/management/commands/app_agent_info.py +0 -308
- django_cfg/management/commands/auto_generate.py +0 -486
- django_cfg/modules/django_app_agent/__init__.py +0 -87
- django_cfg/modules/django_app_agent/agents/__init__.py +0 -40
- django_cfg/modules/django_app_agent/agents/base/__init__.py +0 -24
- django_cfg/modules/django_app_agent/agents/base/agent.py +0 -354
- django_cfg/modules/django_app_agent/agents/base/context.py +0 -236
- django_cfg/modules/django_app_agent/agents/base/executor.py +0 -430
- django_cfg/modules/django_app_agent/agents/generation/__init__.py +0 -12
- django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +0 -15
- django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +0 -147
- django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +0 -99
- django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +0 -32
- django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +0 -290
- django_cfg/modules/django_app_agent/agents/interfaces.py +0 -376
- django_cfg/modules/django_app_agent/core/__init__.py +0 -33
- django_cfg/modules/django_app_agent/core/config.py +0 -300
- django_cfg/modules/django_app_agent/core/exceptions.py +0 -359
- django_cfg/modules/django_app_agent/models/__init__.py +0 -71
- django_cfg/modules/django_app_agent/models/base.py +0 -283
- django_cfg/modules/django_app_agent/models/context.py +0 -496
- django_cfg/modules/django_app_agent/models/enums.py +0 -481
- django_cfg/modules/django_app_agent/models/requests.py +0 -500
- django_cfg/modules/django_app_agent/models/responses.py +0 -585
- django_cfg/modules/django_app_agent/pytest.ini +0 -6
- django_cfg/modules/django_app_agent/services/__init__.py +0 -42
- django_cfg/modules/django_app_agent/services/app_generator/__init__.py +0 -30
- django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +0 -133
- django_cfg/modules/django_app_agent/services/app_generator/context.py +0 -40
- django_cfg/modules/django_app_agent/services/app_generator/main.py +0 -202
- django_cfg/modules/django_app_agent/services/app_generator/structure.py +0 -316
- django_cfg/modules/django_app_agent/services/app_generator/validation.py +0 -125
- django_cfg/modules/django_app_agent/services/base.py +0 -437
- django_cfg/modules/django_app_agent/services/context_builder/__init__.py +0 -34
- django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +0 -141
- django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +0 -276
- django_cfg/modules/django_app_agent/services/context_builder/main.py +0 -272
- django_cfg/modules/django_app_agent/services/context_builder/models.py +0 -40
- django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +0 -85
- django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +0 -31
- django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +0 -311
- django_cfg/modules/django_app_agent/services/project_scanner/main.py +0 -221
- django_cfg/modules/django_app_agent/services/project_scanner/models.py +0 -59
- django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +0 -94
- django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +0 -28
- django_cfg/modules/django_app_agent/services/questioning_service/main.py +0 -273
- django_cfg/modules/django_app_agent/services/questioning_service/models.py +0 -111
- django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +0 -251
- django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +0 -347
- django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +0 -356
- django_cfg/modules/django_app_agent/services/report_service.py +0 -332
- django_cfg/modules/django_app_agent/services/template_manager/__init__.py +0 -18
- django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +0 -236
- django_cfg/modules/django_app_agent/services/template_manager/main.py +0 -159
- django_cfg/modules/django_app_agent/services/template_manager/models.py +0 -36
- django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +0 -100
- django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +0 -105
- django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +0 -31
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +0 -44
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +0 -81
- django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +0 -107
- django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +0 -139
- django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +0 -91
- django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +0 -195
- django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +0 -35
- django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +0 -211
- django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +0 -200
- django_cfg/modules/django_app_agent/services/validation_service/__init__.py +0 -25
- django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +0 -333
- django_cfg/modules/django_app_agent/services/validation_service/main.py +0 -242
- django_cfg/modules/django_app_agent/services/validation_service/models.py +0 -66
- django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +0 -352
- django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +0 -272
- django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +0 -203
- django_cfg/modules/django_app_agent/ui/__init__.py +0 -25
- django_cfg/modules/django_app_agent/ui/cli.py +0 -419
- django_cfg/modules/django_app_agent/ui/rich_components.py +0 -622
- django_cfg/modules/django_app_agent/utils/__init__.py +0 -38
- django_cfg/modules/django_app_agent/utils/logging.py +0 -360
- django_cfg/modules/django_app_agent/utils/validation.py +0 -417
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -1,354 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Base Django Agent class with Pydantic AI integration.
|
3
|
-
|
4
|
-
This module provides the foundational DjangoAgent class that all
|
5
|
-
specialized agents inherit from, with proper django-cfg integration.
|
6
|
-
"""
|
7
|
-
|
8
|
-
from typing import TypeVar, Generic, Optional, Dict, Any, List, Type, Union
|
9
|
-
from abc import ABC, abstractmethod
|
10
|
-
import asyncio
|
11
|
-
import uuid
|
12
|
-
from contextlib import asynccontextmanager
|
13
|
-
|
14
|
-
from pydantic_ai import Agent, RunContext
|
15
|
-
from pydantic_ai.models import Model, KnownModelName
|
16
|
-
|
17
|
-
from ...core.config import AgentConfig, ModelConfig, AIProvider, DEFAULT_MODELS
|
18
|
-
from ...core.exceptions import (
|
19
|
-
AgentExecutionError,
|
20
|
-
AuthenticationError,
|
21
|
-
RateLimitError,
|
22
|
-
TimeoutError as AgentTimeoutError
|
23
|
-
)
|
24
|
-
from ...utils.logging import log_agent_operation, StructuredLogger
|
25
|
-
from .context import AgentDependencies, AgentContext
|
26
|
-
|
27
|
-
# Type variables for generic agent
|
28
|
-
OutputT = TypeVar('OutputT')
|
29
|
-
DepsT = TypeVar('DepsT', bound=AgentDependencies)
|
30
|
-
|
31
|
-
|
32
|
-
class DjangoAgent(Generic[DepsT, OutputT], ABC):
|
33
|
-
"""Base class for all Django App Agent AI agents.
|
34
|
-
|
35
|
-
This class provides:
|
36
|
-
- Integration with django-cfg configuration
|
37
|
-
- Pydantic AI agent management
|
38
|
-
- Error handling and retry logic
|
39
|
-
- Logging and monitoring
|
40
|
-
- Context management
|
41
|
-
"""
|
42
|
-
|
43
|
-
def __init__(
|
44
|
-
self,
|
45
|
-
agent_name: str,
|
46
|
-
config: AgentConfig,
|
47
|
-
output_type: Type[OutputT] = str,
|
48
|
-
deps_type: Type[DepsT] = AgentDependencies,
|
49
|
-
model_override: Optional[str] = None,
|
50
|
-
**agent_kwargs: Any
|
51
|
-
):
|
52
|
-
"""Initialize Django Agent.
|
53
|
-
|
54
|
-
Args:
|
55
|
-
agent_name: Name of the agent for logging and identification
|
56
|
-
config: Agent configuration from django-cfg
|
57
|
-
output_type: Expected output type from the agent
|
58
|
-
deps_type: Dependencies type for dependency injection
|
59
|
-
model_override: Optional model override for testing
|
60
|
-
**agent_kwargs: Additional arguments for Pydantic AI Agent
|
61
|
-
"""
|
62
|
-
self.agent_name = agent_name
|
63
|
-
self.config = config
|
64
|
-
self.output_type = output_type
|
65
|
-
self.deps_type = deps_type
|
66
|
-
|
67
|
-
# Get logger for this agent
|
68
|
-
self.logger = StructuredLogger(f"agents.{agent_name}")
|
69
|
-
|
70
|
-
# Determine model to use
|
71
|
-
model_config = self._get_model_config(model_override)
|
72
|
-
|
73
|
-
# Create Pydantic AI agent
|
74
|
-
self._agent = Agent[DepsT, OutputT](
|
75
|
-
model=model_config.provider.value + ":" + model_config.model_id,
|
76
|
-
output_type=output_type,
|
77
|
-
deps_type=deps_type,
|
78
|
-
name=agent_name,
|
79
|
-
retries=3, # Default retries
|
80
|
-
**agent_kwargs
|
81
|
-
)
|
82
|
-
|
83
|
-
# Register base instructions
|
84
|
-
self._register_instructions()
|
85
|
-
|
86
|
-
# Register tools
|
87
|
-
self._register_tools()
|
88
|
-
|
89
|
-
def _get_model_config(self, model_override: Optional[str] = None) -> ModelConfig:
|
90
|
-
"""Get model configuration for this agent."""
|
91
|
-
if model_override:
|
92
|
-
# Parse model override (e.g., "openai:gpt-4")
|
93
|
-
if ":" in model_override:
|
94
|
-
provider_str, model_id = model_override.split(":", 1)
|
95
|
-
provider = AIProvider(provider_str)
|
96
|
-
else:
|
97
|
-
# Default to OpenRouter
|
98
|
-
provider = AIProvider.OPENROUTER
|
99
|
-
model_id = model_override
|
100
|
-
|
101
|
-
return ModelConfig(
|
102
|
-
provider=provider,
|
103
|
-
model_id=model_id,
|
104
|
-
tier="balanced",
|
105
|
-
max_tokens=100000,
|
106
|
-
temperature=0.1,
|
107
|
-
timeout_seconds=300.0
|
108
|
-
)
|
109
|
-
|
110
|
-
# Get model config for this agent type
|
111
|
-
model_config = self.config.get_model_config(self.agent_name)
|
112
|
-
if model_config:
|
113
|
-
return model_config
|
114
|
-
|
115
|
-
# Fall back to default model
|
116
|
-
default_key = "generation" # Default task type
|
117
|
-
if default_key in DEFAULT_MODELS:
|
118
|
-
return DEFAULT_MODELS[default_key]
|
119
|
-
|
120
|
-
# Ultimate fallback
|
121
|
-
return ModelConfig(
|
122
|
-
provider=AIProvider.OPENROUTER,
|
123
|
-
model_id="anthropic/claude-3-haiku",
|
124
|
-
tier="balanced",
|
125
|
-
max_tokens=50000,
|
126
|
-
temperature=0.1,
|
127
|
-
timeout_seconds=180.0
|
128
|
-
)
|
129
|
-
|
130
|
-
@abstractmethod
|
131
|
-
def _register_instructions(self) -> None:
|
132
|
-
"""Register agent instructions. Must be implemented by subclasses."""
|
133
|
-
pass
|
134
|
-
|
135
|
-
@abstractmethod
|
136
|
-
def _register_tools(self) -> None:
|
137
|
-
"""Register agent tools. Must be implemented by subclasses."""
|
138
|
-
pass
|
139
|
-
|
140
|
-
@log_agent_operation("base_agent", "run")
|
141
|
-
async def run(
|
142
|
-
self,
|
143
|
-
prompt: str,
|
144
|
-
deps: DepsT,
|
145
|
-
context: Optional[AgentContext] = None,
|
146
|
-
**run_kwargs: Any
|
147
|
-
) -> OutputT:
|
148
|
-
"""Run the agent with the given prompt and dependencies.
|
149
|
-
|
150
|
-
Args:
|
151
|
-
prompt: Input prompt for the agent
|
152
|
-
deps: Dependencies for the agent execution
|
153
|
-
context: Optional execution context
|
154
|
-
**run_kwargs: Additional arguments for agent.run()
|
155
|
-
|
156
|
-
Returns:
|
157
|
-
Agent output of type OutputT
|
158
|
-
|
159
|
-
Raises:
|
160
|
-
AgentExecutionError: If agent execution fails
|
161
|
-
AuthenticationError: If API authentication fails
|
162
|
-
RateLimitError: If rate limits are exceeded
|
163
|
-
AgentTimeoutError: If execution times out
|
164
|
-
"""
|
165
|
-
if context:
|
166
|
-
context.update_progress(f"{self.agent_name}_execution", 0.0)
|
167
|
-
|
168
|
-
try:
|
169
|
-
# Validate API key
|
170
|
-
model_config = self._get_model_config()
|
171
|
-
if not self.config.has_api_key(model_config.provider):
|
172
|
-
raise AuthenticationError(
|
173
|
-
f"No API key configured for {model_config.provider}",
|
174
|
-
provider=model_config.provider.value
|
175
|
-
)
|
176
|
-
|
177
|
-
deps.log_operation(f"Starting {self.agent_name} execution", prompt_length=len(prompt))
|
178
|
-
|
179
|
-
# Run the agent with timeout
|
180
|
-
result = await asyncio.wait_for(
|
181
|
-
self._agent.run(prompt, deps=deps, **run_kwargs),
|
182
|
-
timeout=model_config.timeout_seconds
|
183
|
-
)
|
184
|
-
|
185
|
-
if context:
|
186
|
-
context.add_result({
|
187
|
-
"agent": self.agent_name,
|
188
|
-
"output_type": self.output_type.__name__,
|
189
|
-
"success": True
|
190
|
-
})
|
191
|
-
context.update_progress(f"{self.agent_name}_completed", 100.0)
|
192
|
-
|
193
|
-
deps.log_operation(f"Completed {self.agent_name} execution successfully")
|
194
|
-
|
195
|
-
return result.output
|
196
|
-
|
197
|
-
except asyncio.TimeoutError as e:
|
198
|
-
error_msg = f"Agent {self.agent_name} execution timed out"
|
199
|
-
deps.log_error(error_msg, e)
|
200
|
-
if context:
|
201
|
-
context.add_error(error_msg)
|
202
|
-
raise AgentTimeoutError(
|
203
|
-
error_msg,
|
204
|
-
operation=f"{self.agent_name}_execution",
|
205
|
-
timeout_seconds=model_config.timeout_seconds
|
206
|
-
)
|
207
|
-
|
208
|
-
except Exception as e:
|
209
|
-
error_msg = f"Agent {self.agent_name} execution failed: {e}"
|
210
|
-
deps.log_error(error_msg, e)
|
211
|
-
if context:
|
212
|
-
context.add_error(error_msg)
|
213
|
-
|
214
|
-
# Map specific exceptions
|
215
|
-
if "authentication" in str(e).lower() or "api key" in str(e).lower():
|
216
|
-
raise AuthenticationError(
|
217
|
-
error_msg,
|
218
|
-
provider=model_config.provider.value,
|
219
|
-
cause=e
|
220
|
-
)
|
221
|
-
elif "rate limit" in str(e).lower():
|
222
|
-
raise RateLimitError(
|
223
|
-
error_msg,
|
224
|
-
provider=model_config.provider.value,
|
225
|
-
cause=e
|
226
|
-
)
|
227
|
-
else:
|
228
|
-
raise AgentExecutionError(
|
229
|
-
error_msg,
|
230
|
-
agent_name=self.agent_name,
|
231
|
-
agent_operation="run",
|
232
|
-
cause=e
|
233
|
-
)
|
234
|
-
|
235
|
-
async def run_sync(
|
236
|
-
self,
|
237
|
-
prompt: str,
|
238
|
-
deps: DepsT,
|
239
|
-
context: Optional[AgentContext] = None,
|
240
|
-
**run_kwargs: Any
|
241
|
-
) -> OutputT:
|
242
|
-
"""Synchronous wrapper for run method."""
|
243
|
-
return await self.run(prompt, deps, context, **run_kwargs)
|
244
|
-
|
245
|
-
@asynccontextmanager
|
246
|
-
async def execution_context(
|
247
|
-
self,
|
248
|
-
operation_name: str,
|
249
|
-
correlation_id: Optional[str] = None
|
250
|
-
):
|
251
|
-
"""Context manager for agent execution with proper cleanup."""
|
252
|
-
if correlation_id is None:
|
253
|
-
correlation_id = str(uuid.uuid4())
|
254
|
-
|
255
|
-
context = AgentContext()
|
256
|
-
|
257
|
-
try:
|
258
|
-
with self.logger.operation_context(operation_name, correlation_id):
|
259
|
-
yield context
|
260
|
-
finally:
|
261
|
-
context.mark_completed()
|
262
|
-
|
263
|
-
def get_instructions(self) -> str:
|
264
|
-
"""Get the current instructions for this agent."""
|
265
|
-
return getattr(self, '_instructions', f"You are {self.agent_name}, a specialized AI agent.")
|
266
|
-
|
267
|
-
def validate_dependencies(self, deps: DepsT) -> List[str]:
|
268
|
-
"""Validate that dependencies are properly configured.
|
269
|
-
|
270
|
-
Args:
|
271
|
-
deps: Dependencies to validate
|
272
|
-
|
273
|
-
Returns:
|
274
|
-
List of validation errors (empty if valid)
|
275
|
-
"""
|
276
|
-
errors = []
|
277
|
-
|
278
|
-
# Check API key availability
|
279
|
-
model_config = self._get_model_config()
|
280
|
-
if not deps.config.has_api_key(model_config.provider):
|
281
|
-
errors.append(f"No API key configured for {model_config.provider}")
|
282
|
-
|
283
|
-
# Check project context if required
|
284
|
-
if self._requires_project_context() and not deps.has_project_context():
|
285
|
-
errors.append("Project context is required but not provided")
|
286
|
-
|
287
|
-
return errors
|
288
|
-
|
289
|
-
def _requires_project_context(self) -> bool:
|
290
|
-
"""Check if this agent requires project context. Override in subclasses."""
|
291
|
-
return False
|
292
|
-
|
293
|
-
@property
|
294
|
-
def agent(self) -> Agent[DepsT, OutputT]:
|
295
|
-
"""Get the underlying Pydantic AI agent."""
|
296
|
-
return self._agent
|
297
|
-
|
298
|
-
def __repr__(self) -> str:
|
299
|
-
"""String representation of the agent."""
|
300
|
-
return f"{self.__class__.__name__}(name='{self.agent_name}', output_type={self.output_type.__name__})"
|
301
|
-
|
302
|
-
|
303
|
-
class SimpleTextAgent(DjangoAgent[AgentDependencies, str]):
|
304
|
-
"""Simple text-based agent for basic operations."""
|
305
|
-
|
306
|
-
def __init__(
|
307
|
-
self,
|
308
|
-
agent_name: str,
|
309
|
-
config: AgentConfig,
|
310
|
-
instructions: str,
|
311
|
-
**kwargs: Any
|
312
|
-
):
|
313
|
-
"""Initialize simple text agent.
|
314
|
-
|
315
|
-
Args:
|
316
|
-
agent_name: Name of the agent
|
317
|
-
config: Agent configuration
|
318
|
-
instructions: Instructions for the agent
|
319
|
-
**kwargs: Additional arguments
|
320
|
-
"""
|
321
|
-
self._instructions = instructions
|
322
|
-
super().__init__(agent_name, config, str, AgentDependencies, **kwargs)
|
323
|
-
|
324
|
-
def _register_instructions(self) -> None:
|
325
|
-
"""Register instructions for the agent."""
|
326
|
-
@self._agent.instructions
|
327
|
-
async def agent_instructions(ctx: RunContext[AgentDependencies]) -> str:
|
328
|
-
return self._instructions
|
329
|
-
|
330
|
-
def _register_tools(self) -> None:
|
331
|
-
"""Register tools for the agent."""
|
332
|
-
# Simple text agent has no tools by default
|
333
|
-
pass
|
334
|
-
|
335
|
-
|
336
|
-
# Utility function for creating simple agents
|
337
|
-
def create_simple_agent(
|
338
|
-
name: str,
|
339
|
-
instructions: str,
|
340
|
-
config: AgentConfig,
|
341
|
-
**kwargs: Any
|
342
|
-
) -> SimpleTextAgent:
|
343
|
-
"""Create a simple text-based agent.
|
344
|
-
|
345
|
-
Args:
|
346
|
-
name: Agent name
|
347
|
-
instructions: Agent instructions
|
348
|
-
config: Agent configuration
|
349
|
-
**kwargs: Additional arguments
|
350
|
-
|
351
|
-
Returns:
|
352
|
-
Configured SimpleTextAgent
|
353
|
-
"""
|
354
|
-
return SimpleTextAgent(name, config, instructions, **kwargs)
|
@@ -1,236 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Context management for Django App Agent AI agents.
|
3
|
-
|
4
|
-
This module provides context classes for dependency injection and
|
5
|
-
execution management following Pydantic AI patterns.
|
6
|
-
"""
|
7
|
-
|
8
|
-
from typing import Optional, Dict, Any, List
|
9
|
-
from dataclasses import dataclass, field
|
10
|
-
from pathlib import Path
|
11
|
-
from datetime import datetime, timezone
|
12
|
-
|
13
|
-
from pydantic import BaseModel, Field, ConfigDict
|
14
|
-
|
15
|
-
from ...core.config import AgentConfig, AIProvider
|
16
|
-
from ...models.context import ProjectContext, InfrastructureContext
|
17
|
-
from ...utils.logging import StructuredLogger, get_logger
|
18
|
-
|
19
|
-
|
20
|
-
class AgentDependencies(BaseModel):
|
21
|
-
"""Base dependencies for all Django App Agent AI agents.
|
22
|
-
|
23
|
-
This follows Pydantic AI dependency injection patterns and provides
|
24
|
-
common dependencies that all agents need.
|
25
|
-
"""
|
26
|
-
|
27
|
-
model_config = ConfigDict(
|
28
|
-
extra='forbid',
|
29
|
-
validate_assignment=True,
|
30
|
-
arbitrary_types_allowed=True # For logger and config objects
|
31
|
-
)
|
32
|
-
|
33
|
-
# Core configuration
|
34
|
-
config: AgentConfig = Field(description="Agent configuration")
|
35
|
-
logger: StructuredLogger = Field(description="Structured logger instance")
|
36
|
-
|
37
|
-
# Project context
|
38
|
-
project_context: Optional[ProjectContext] = Field(
|
39
|
-
default=None,
|
40
|
-
description="Django project context information"
|
41
|
-
)
|
42
|
-
|
43
|
-
infrastructure_context: Optional[InfrastructureContext] = Field(
|
44
|
-
default=None,
|
45
|
-
description="Infrastructure context for code generation"
|
46
|
-
)
|
47
|
-
|
48
|
-
# Execution context
|
49
|
-
correlation_id: str = Field(description="Correlation ID for tracing")
|
50
|
-
operation_name: str = Field(description="Name of the current operation")
|
51
|
-
|
52
|
-
# Working directories
|
53
|
-
project_root: Optional[Path] = Field(
|
54
|
-
default=None,
|
55
|
-
description="Root directory of the Django project"
|
56
|
-
)
|
57
|
-
|
58
|
-
output_directory: Optional[Path] = Field(
|
59
|
-
default=None,
|
60
|
-
description="Directory for generated output"
|
61
|
-
)
|
62
|
-
|
63
|
-
# Execution metadata
|
64
|
-
execution_metadata: Dict[str, Any] = Field(
|
65
|
-
default_factory=dict,
|
66
|
-
description="Additional metadata for execution"
|
67
|
-
)
|
68
|
-
|
69
|
-
def get_api_key(self, provider: str) -> Optional[str]:
|
70
|
-
"""Get API key for AI provider."""
|
71
|
-
try:
|
72
|
-
ai_provider = AIProvider(provider)
|
73
|
-
return self.config.get_api_key(ai_provider)
|
74
|
-
except ValueError:
|
75
|
-
return None
|
76
|
-
|
77
|
-
def has_project_context(self) -> bool:
|
78
|
-
"""Check if project context is available."""
|
79
|
-
return self.project_context is not None
|
80
|
-
|
81
|
-
def get_project_path(self) -> Optional[Path]:
|
82
|
-
"""Get project path from context or direct setting."""
|
83
|
-
if self.project_context:
|
84
|
-
return self.project_context.project_path
|
85
|
-
return self.project_root
|
86
|
-
|
87
|
-
def log_operation(self, message: str, **metadata: Any) -> None:
|
88
|
-
"""Log operation with context."""
|
89
|
-
self.logger.info(
|
90
|
-
message,
|
91
|
-
operation=self.operation_name,
|
92
|
-
correlation_id=self.correlation_id,
|
93
|
-
**metadata
|
94
|
-
)
|
95
|
-
|
96
|
-
def log_error(self, message: str, error: Exception, **metadata: Any) -> None:
|
97
|
-
"""Log error with context."""
|
98
|
-
self.logger.error(
|
99
|
-
message,
|
100
|
-
operation=self.operation_name,
|
101
|
-
correlation_id=self.correlation_id,
|
102
|
-
error=str(error),
|
103
|
-
error_type=type(error).__name__,
|
104
|
-
**metadata
|
105
|
-
)
|
106
|
-
|
107
|
-
|
108
|
-
@dataclass
|
109
|
-
class AgentContext:
|
110
|
-
"""Execution context for Django App Agent operations.
|
111
|
-
|
112
|
-
This class manages the execution context for agent operations,
|
113
|
-
including timing, progress tracking, and result collection.
|
114
|
-
"""
|
115
|
-
|
116
|
-
# Execution tracking
|
117
|
-
start_time: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
118
|
-
end_time: Optional[datetime] = field(default=None)
|
119
|
-
|
120
|
-
# Progress tracking
|
121
|
-
current_stage: str = field(default="initialization")
|
122
|
-
progress_percentage: float = field(default=0.0)
|
123
|
-
|
124
|
-
# Result collection
|
125
|
-
intermediate_results: List[Dict[str, Any]] = field(default_factory=list)
|
126
|
-
errors: List[str] = field(default_factory=list)
|
127
|
-
warnings: List[str] = field(default_factory=list)
|
128
|
-
|
129
|
-
# Performance metrics
|
130
|
-
token_usage: Dict[str, int] = field(default_factory=dict)
|
131
|
-
api_calls_count: int = field(default=0)
|
132
|
-
|
133
|
-
def mark_completed(self) -> None:
|
134
|
-
"""Mark the context as completed."""
|
135
|
-
self.end_time = datetime.now(timezone.utc)
|
136
|
-
self.progress_percentage = 100.0
|
137
|
-
|
138
|
-
def update_progress(self, stage: str, percentage: float) -> None:
|
139
|
-
"""Update progress information."""
|
140
|
-
self.current_stage = stage
|
141
|
-
self.progress_percentage = min(100.0, max(0.0, percentage))
|
142
|
-
|
143
|
-
def add_result(self, result: Dict[str, Any]) -> None:
|
144
|
-
"""Add intermediate result."""
|
145
|
-
self.intermediate_results.append({
|
146
|
-
**result,
|
147
|
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
148
|
-
"stage": self.current_stage
|
149
|
-
})
|
150
|
-
|
151
|
-
def add_error(self, error: str) -> None:
|
152
|
-
"""Add error message."""
|
153
|
-
self.errors.append(error)
|
154
|
-
|
155
|
-
def add_warning(self, warning: str) -> None:
|
156
|
-
"""Add warning message."""
|
157
|
-
self.warnings.append(warning)
|
158
|
-
|
159
|
-
def track_token_usage(self, provider: str, tokens: int) -> None:
|
160
|
-
"""Track token usage by provider."""
|
161
|
-
self.token_usage[provider] = self.token_usage.get(provider, 0) + tokens
|
162
|
-
|
163
|
-
def increment_api_calls(self) -> None:
|
164
|
-
"""Increment API calls counter."""
|
165
|
-
self.api_calls_count += 1
|
166
|
-
|
167
|
-
@property
|
168
|
-
def execution_time_seconds(self) -> float:
|
169
|
-
"""Get execution time in seconds."""
|
170
|
-
end = self.end_time or datetime.now(timezone.utc)
|
171
|
-
return (end - self.start_time).total_seconds()
|
172
|
-
|
173
|
-
@property
|
174
|
-
def is_completed(self) -> bool:
|
175
|
-
"""Check if execution is completed."""
|
176
|
-
return self.end_time is not None
|
177
|
-
|
178
|
-
@property
|
179
|
-
def has_errors(self) -> bool:
|
180
|
-
"""Check if there are any errors."""
|
181
|
-
return len(self.errors) > 0
|
182
|
-
|
183
|
-
@property
|
184
|
-
def total_tokens_used(self) -> int:
|
185
|
-
"""Get total tokens used across all providers."""
|
186
|
-
return sum(self.token_usage.values())
|
187
|
-
|
188
|
-
def get_summary(self) -> Dict[str, Any]:
|
189
|
-
"""Get execution summary."""
|
190
|
-
return {
|
191
|
-
"start_time": self.start_time.isoformat(),
|
192
|
-
"end_time": self.end_time.isoformat() if self.end_time else None,
|
193
|
-
"execution_time_seconds": self.execution_time_seconds,
|
194
|
-
"current_stage": self.current_stage,
|
195
|
-
"progress_percentage": self.progress_percentage,
|
196
|
-
"is_completed": self.is_completed,
|
197
|
-
"results_count": len(self.intermediate_results),
|
198
|
-
"errors_count": len(self.errors),
|
199
|
-
"warnings_count": len(self.warnings),
|
200
|
-
"total_tokens_used": self.total_tokens_used,
|
201
|
-
"api_calls_count": self.api_calls_count,
|
202
|
-
}
|
203
|
-
|
204
|
-
|
205
|
-
def create_agent_dependencies(
|
206
|
-
config: AgentConfig,
|
207
|
-
correlation_id: str,
|
208
|
-
operation_name: str,
|
209
|
-
project_root: Optional[Path] = None,
|
210
|
-
output_directory: Optional[Path] = None,
|
211
|
-
**metadata: Any
|
212
|
-
) -> AgentDependencies:
|
213
|
-
"""Factory function to create AgentDependencies.
|
214
|
-
|
215
|
-
Args:
|
216
|
-
config: Agent configuration
|
217
|
-
correlation_id: Correlation ID for tracing
|
218
|
-
operation_name: Name of the operation
|
219
|
-
project_root: Optional project root directory
|
220
|
-
output_directory: Optional output directory
|
221
|
-
**metadata: Additional metadata
|
222
|
-
|
223
|
-
Returns:
|
224
|
-
Configured AgentDependencies instance
|
225
|
-
"""
|
226
|
-
logger = get_logger(f"agents.{operation_name}")
|
227
|
-
|
228
|
-
return AgentDependencies(
|
229
|
-
config=config,
|
230
|
-
logger=logger,
|
231
|
-
correlation_id=correlation_id,
|
232
|
-
operation_name=operation_name,
|
233
|
-
project_root=project_root,
|
234
|
-
output_directory=output_directory,
|
235
|
-
execution_metadata=metadata
|
236
|
-
)
|