Browse Source

Refactor Agent app to enhance settings management and introduce prompts

- Updated `AgentSettings` model to serve as a singleton container, removing unnecessary fields and adding an `updated_at` timestamp.
- Introduced `AgentPrompt` model to manage instruction prompts associated with agent settings.
- Enhanced `AgentSettingsAdmin` to include inline management of prompts, improving the admin interface for better usability.
- Created migrations to reflect the updated model structure and ensure database integrity.
master
Mohsen Taba 3 months ago
parent
commit
e00b3ac208
  1. 76
      apps/agent/admin.py
  2. 56
      apps/agent/migrations/0002_alter_agentsettings_options_and_more.py
  3. 38
      apps/agent/migrations/0003_alter_agentprompt_options_and_more.py
  4. 39
      apps/agent/models.py

76
apps/agent/admin.py

@ -1,61 +1,57 @@
from django.contrib import admin
from django.db import models
from django.shortcuts import redirect
from django.urls import reverse
from unfold.admin import ModelAdmin
from unfold.admin import ModelAdmin, TabularInline
from utils.admin import dovoodi_admin_site, project_admin_site
from apps.agent.models import AgentSettings
from .models import AgentSettings, AgentPrompt
from unfold.contrib.forms.widgets import WysiwygWidget
class AgentPromptInline(TabularInline):
model = AgentPrompt
extra = 0
fields = ('is_active', 'content')
formfield_overrides = {
models.TextField: {
'widget': admin.widgets.AdminTextareaWidget(attrs={
# 1. REDUCE HEIGHT: Set rows to 1 or 2
'rows': 2,
# 🎨 STYLING
# w-full: Fills the available space
# bg-black: Black background
# text-white: White text (Fixed typo from 'text-blacka')
# border-gray-600: Border color
# leading-normal: Adjusts line height for better vertical centering
'class': 'w-full p-2 border rounded-md bg-black text-white border-gray-600 focus:ring-primary-500 focus:border-primary-500 leading-normal',
'placeholder': 'Enter instruction prompt here...',
# 2. INCREASE WIDTH: 'min-width' forces the table cell to expand
'style': 'width: 100%; min-width: 600px; resize: vertical;'
})
},
}
class AgentSettingsAdmin(ModelAdmin):
"""
Singleton Admin for Agent Configuration.
Acts as a 'Settings Page' by redirecting list view to the edit page of ID=1.
"""
def has_add_permission(self, request):
# Disable 'Add' button to prevent creating multiple configs
return False
def has_delete_permission(self, request, obj=None):
# Disable 'Delete' button to ensure settings always exist
return False
def changelist_view(self, request, extra_context=None):
"""
Redirect the 'List View' directly to the 'Edit View' of ID=1.
Auto-creates the default config if it doesn't exist.
"""
# Ensure ID=1 exists
obj, created = self.model.objects.get_or_create(pk=1, defaults={
"system_prompt": "You are a helpful assistant.",
})
# Build the URL dynamically based on the registered admin site
obj, created = self.model.objects.get_or_create(pk=1)
url = reverse(
f"{self.admin_site.name}:{self.model._meta.app_label}_{self.model._meta.model_name}_change",
args=[obj.pk]
)
return redirect(url)
fieldsets = (
("Status", {
"fields": ("is_maintenance_mode",),
"classes": ("tab",),
}),
("Brain (System Instructions)", {
"fields": ("system_prompt",),
"classes": ("tab",),
"description": "Define the core personality and rules for the AI Agent."
}),
("Model Parameters", {
"fields": ("model_id", "temperature"),
"classes": ("tab",),
"description": "Technical settings for the inference engine."
}),
)
inlines = [AgentPromptInline]
# Register with your custom admin site
# Register
dovoodi_admin_site.register(AgentSettings, AgentSettingsAdmin)
project_admin_site.register(AgentSettings, AgentSettingsAdmin)

56
apps/agent/migrations/0002_alter_agentsettings_options_and_more.py

@ -0,0 +1,56 @@
# Generated by Django 4.2.27 on 2026-02-15 13:58
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('agent', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='agentsettings',
options={'verbose_name': 'Agent Control Panel', 'verbose_name_plural': 'Agent Control Panel'},
),
migrations.RemoveField(
model_name='agentsettings',
name='model_id',
),
migrations.RemoveField(
model_name='agentsettings',
name='system_prompt',
),
migrations.RemoveField(
model_name='agentsettings',
name='temperature',
),
migrations.AddField(
model_name='agentsettings',
name='updated_at',
field=models.DateTimeField(auto_now=True),
),
migrations.AlterField(
model_name='agentsettings',
name='is_maintenance_mode',
field=models.BooleanField(default=False, help_text='If checked, the agent will reply with a maintenance message.'),
),
migrations.CreateModel(
name='AgentPrompt',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(help_text="Internal Label (e.g., 'Core Identity')", max_length=100)),
('content', models.TextField(help_text='The actual instruction text.')),
('is_active', models.BooleanField(default=True)),
('order', models.PositiveIntegerField(default=0, help_text='Order of injection (1, 2, 3...)')),
('settings', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='prompts', to='agent.agentsettings')),
],
options={
'verbose_name': 'System Instruction',
'verbose_name_plural': 'System Instructions',
'ordering': ['order'],
},
),
]

38
apps/agent/migrations/0003_alter_agentprompt_options_and_more.py

@ -0,0 +1,38 @@
# Generated by Django 4.2.27 on 2026-02-15 14:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agent', '0002_alter_agentsettings_options_and_more'),
]
operations = [
migrations.AlterModelOptions(
name='agentprompt',
options={},
),
migrations.AlterModelOptions(
name='agentsettings',
options={'verbose_name': 'Agent Configuration', 'verbose_name_plural': 'Agent Configuration'},
),
migrations.RemoveField(
model_name='agentprompt',
name='order',
),
migrations.RemoveField(
model_name='agentprompt',
name='title',
),
migrations.RemoveField(
model_name='agentsettings',
name='is_maintenance_mode',
),
migrations.AlterField(
model_name='agentprompt',
name='content',
field=models.TextField(help_text='The instruction text.'),
),
]

39
apps/agent/models.py

@ -1,25 +1,20 @@
from django.db import models
from django.core.cache import cache
class AgentSettings(models.Model):
# Fixed Settings
system_prompt = models.TextField(default="You are a helpful assistant.")
model_id = models.CharField(max_length=50, default="deepseek/deepseek-r1")
temperature = models.FloatField(default=0.3)
# Switches
is_maintenance_mode = models.BooleanField(default=False)
"""
Singleton Container.
Now just a wrapper to hold the list of prompts.
"""
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "Agent Configuration"
verbose_name_plural = "Agent Configuration"
def save(self, *args, **kwargs):
self.pk = 1
self.pk = 1 # Force Singleton
super().save(*args, **kwargs)
# Clear cache whenever you save
cache.delete("agent_config_1")
def __str__(self):
@ -27,6 +22,24 @@ class AgentSettings(models.Model):
@classmethod
def load(cls):
"""Helper to get the singleton instance, creating it if missing."""
obj, created = cls.objects.get_or_create(pk=1)
return obj
return obj
class AgentPrompt(models.Model):
"""
Simple Prompt Block.
Just text and a switch.
"""
settings = models.ForeignKey(AgentSettings, on_delete=models.CASCADE, related_name="prompts")
content = models.TextField(help_text="The instruction text.")
is_active = models.BooleanField(default=True)
def __str__(self):
# Display the first 50 chars as the name in admin
# if self.is_active:
# return f"Active Prompt" if self.content else "Empty Prompt"
# else:
# return f"Inactive Prompt: {self.content[:50]}..." if self.content else "Empty Prompt"
return ""
Loading…
Cancel
Save