- Add configuration of agents, tasks, tools, specialist in context of SPIN specialist

- correct startup of applications using gevent
- introduce startup scripts (eveai_app)
- caching manager for all configurations
This commit is contained in:
Josako
2025-01-16 20:27:00 +01:00
parent f7cd58ed2a
commit 7bddeb0ebd
69 changed files with 1991 additions and 345 deletions

View File

@@ -1,12 +1,13 @@
from flask_wtf import FlaskForm
from wtforms import (StringField, BooleanField, SelectField, TextAreaField)
from wtforms.validators import DataRequired, Length
from wtforms.validators import DataRequired, Length, Optional
from wtforms_sqlalchemy.fields import QuerySelectMultipleField
from common.models.document import Retriever
from common.models.interaction import EveAITool
from common.extensions import cache_manager
from config.type_defs.specialist_types import SPECIALIST_TYPES
from .dynamic_form_base import DynamicFormBase
@@ -14,6 +15,10 @@ def get_retrievers():
return Retriever.query.all()
def get_tools():
return EveAITool.query.all()
class SpecialistForm(FlaskForm):
name = StringField('Name', validators=[DataRequired(), Length(max=50)])
description = TextAreaField('Description', validators=[DataRequired()])
@@ -32,8 +37,9 @@ class SpecialistForm(FlaskForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
types_dict = cache_manager.specialist_config_cache.get_types()
# Dynamically populate the 'type' field using the constructor
self.type.choices = [(key, value['name']) for key, value in SPECIALIST_TYPES.items()]
self.type.choices = [(key, value['name']) for key, value in types_dict.items()]
class EditSpecialistForm(DynamicFormBase):
@@ -52,4 +58,59 @@ class EditSpecialistForm(DynamicFormBase):
tuning = BooleanField('Enable Retrieval Tuning', default=False)
class BaseComponentForm(DynamicFormBase):
"""Base form for all processing components"""
name = StringField('Name', validators=[DataRequired(), Length(max=50)])
description = TextAreaField('Description', validators=[Optional()])
type = SelectField('Type', validators=[DataRequired()])
tuning = BooleanField('Enable Tuning', default=False)
def __init__(self, *args, type_config=None, **kwargs):
super().__init__(*args, **kwargs)
if type_config:
self.type.choices = [(key, value['name']) for key, value in type_config.items()]
# Edit forms that support dynamic fields
class BaseEditComponentForm(DynamicFormBase):
name = StringField('Name', validators=[DataRequired()])
description = TextAreaField('Description', validators=[Optional()])
type = StringField('Type', validators=[DataRequired()], render_kw={'readonly': True})
tuning = BooleanField('Enable Tuning', default=False)
class EveAIAgentForm(BaseComponentForm):
role = TextAreaField('Role', validators=[DataRequired()])
goal = TextAreaField('Goal', validators=[DataRequired()])
backstory = TextAreaField('Backstory', validators=[DataRequired()])
tools = QuerySelectMultipleField(
'Tools',
query_factory=get_tools,
get_label='name',
allow_blank=True,
description='Select one or more tools that can be used this agent'
)
def __init__(self, *args, type_config=None, **kwargs):
super().__init__(*args, **kwargs)
if type_config:
self.type.choices = [(key, value['name']) for key, value in type_config.items()]
class EditEveAIAgentForm(BaseEditComponentForm):
role = StringField('Role', validators=[DataRequired()])
goal = StringField('Goal', validators=[DataRequired()])
backstory = StringField('Backstory', validators=[DataRequired()])
tools = QuerySelectMultipleField(
'Tools',
query_factory=get_tools,
get_label='name',
allow_blank=True,
description='Select one or more tools that can be used this agent'
)
class EveAITaskForm(BaseComponentForm):
expected_output = TextAreaField('Expected Output', validators=[DataRequired()])

View File

@@ -7,14 +7,19 @@ from sqlalchemy import desc
from sqlalchemy.exc import SQLAlchemyError
from common.models.document import Embedding, DocumentVersion, Retriever
from common.models.interaction import ChatSession, Interaction, InteractionEmbedding, Specialist, SpecialistRetriever
from common.extensions import db
from common.utils.document_utils import set_logging_information, update_logging_information
from config.type_defs.specialist_types import SPECIALIST_TYPES
from common.models.interaction import (ChatSession, Interaction, InteractionEmbedding, Specialist, SpecialistRetriever)
from common.extensions import db, cache_manager
from common.utils.model_logging_utils import set_logging_information, update_logging_information
from common.utils.middleware import mw_before_request
from common.utils.nginx_utils import prefixed_url_for
from common.utils.view_assistants import form_validation_failed, prepare_table_for_macro
from .interaction_forms import SpecialistForm, EditSpecialistForm
from common.utils.specialist_utils import initialize_specialist
from config.type_defs.specialist_types import SPECIALIST_TYPES
from .interaction_forms import (SpecialistForm, EditSpecialistForm)
interaction_bp = Blueprint('interaction_bp', __name__, url_prefix='/interaction')
@@ -135,6 +140,7 @@ def specialist():
new_specialist.name = form.name.data
new_specialist.description = form.description.data
new_specialist.type = form.type.data
new_specialist.type_version = cache_manager.specialist_config_cache.get_latest_version(new_specialist.type)
new_specialist.tuning = form.tuning.data
set_logging_information(new_specialist, dt.now(tz.utc))
@@ -156,6 +162,9 @@ def specialist():
flash('Specialist successfully added!', 'success')
current_app.logger.info(f'Specialist {new_specialist.name} successfully added for tenant {tenant_id}!')
# Initialize the newly create specialist
initialize_specialist(new_specialist.id, new_specialist.type, new_specialist.type_version)
return redirect(prefixed_url_for('interaction_bp.edit_specialist', specialist_id=new_specialist.id))
except Exception as e:
@@ -173,7 +182,8 @@ def edit_specialist(specialist_id):
specialist = Specialist.query.get_or_404(specialist_id)
form = EditSpecialistForm(request.form, obj=specialist)
configuration_config = SPECIALIST_TYPES[specialist.type]["configuration"]
specialist_config = cache_manager.specialist_config_cache.get_config(specialist.type, specialist.type_version)
configuration_config = specialist_config.get('configuration')
form.add_dynamic_fields("configuration", configuration_config, specialist.configuration)
if request.method == 'GET':
@@ -257,3 +267,4 @@ def handle_specialist_selection():
return redirect(prefixed_url_for('interaction_bp.edit_specialist', specialist_id=specialist_id))
return redirect(prefixed_url_for('interaction_bp.specialists'))