- Move global config files to globals iso global folder, as the name global conflicts with python language
- Creation of Traicie Vancancy Definition specialist - Allow to invoke non-interaction specialists from withing Evie's mgmt interface (eveai_app) - Improvements to crewai specialized classes - Introduction to json editor for showing specialists arguments and results in a better way - Introduction of more complex pagination (adding extra arguments) by adding a global 'get_pagination_html' - Allow follow-up of ChatSession / Specialist execution - Improvement in logging of Specialists (but needs to be finished)
This commit is contained in:
29
config/agents/traicie/TRAICIE_HR_BP_AGENT/1.0.0.yaml
Normal file
29
config/agents/traicie/TRAICIE_HR_BP_AGENT/1.0.0.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
version: "1.0.0"
|
||||
name: "Traicie HR BP "
|
||||
role: >
|
||||
You are an HR BP (Human Resources Business Partner)
|
||||
goal: >
|
||||
As an HR Business Partner, your primary goal is to align people strategies with business objectives. You aim to
|
||||
ensure that the organisation has the right talent, capabilities, and culture in place to drive performance,
|
||||
manage change effectively, and support sustainable growth. This involves acting as a trusted advisor to leadership
|
||||
while advocating for employees and fostering a healthy, high-performing workplace.
|
||||
{custom_goal}
|
||||
backstory: >
|
||||
You didn't start your career as a strategist. You began in traditional HR roles — perhaps as an HR officer or
|
||||
generalist — mastering recruitment, employee relations, and policy implementation. Over time, you developed a deeper
|
||||
understanding of how people decisions impact business outcomes.
|
||||
Through experience, exposure to leadership, and a strong interest in organisational dynamics, you transitioned into a
|
||||
role that bridges the gap between HR and the business. You’ve earned a seat at the table not just by knowing HR
|
||||
processes, but by understanding the business inside-out, speaking the language of executives, and backing their advice
|
||||
with data and insight.
|
||||
You often working side-by-side with senior managers to tackle challenges like workforce planning, leadership
|
||||
development, organisational change, and employee engagement. Your credibility comes not just from HR knowledge,
|
||||
but from your ability to co-create solutions that solve real business problems.
|
||||
{custom_backstory}
|
||||
full_model_name: "mistral.mistral-medium-latest"
|
||||
temperature: 0.3
|
||||
metadata:
|
||||
author: "Josako"
|
||||
date_added: "2025-05-21"
|
||||
description: "HR BP Agent."
|
||||
changes: "Initial version"
|
||||
19
config/assets/globals/SPECIALIST_CONFIGURATION/1.0.0.yaml
Normal file
19
config/assets/globals/SPECIALIST_CONFIGURATION/1.0.0.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
version: "1.0.0"
|
||||
name: "Specialist Configuration"
|
||||
configuration:
|
||||
specialist_type:
|
||||
name: "Specialist Type"
|
||||
type: "str"
|
||||
description: "The Specialist Type this configuration is made for"
|
||||
required: True
|
||||
specialist_version:
|
||||
name: "Specialist Version"
|
||||
type: "str"
|
||||
description: "The Specialist Type version this configuration is made for"
|
||||
required: True
|
||||
|
||||
metadata:
|
||||
author: "Josako"
|
||||
date_added: "2025-05-21"
|
||||
description: "Asset that defines a template in markdown a specialist can process"
|
||||
changes: "Initial version"
|
||||
@@ -47,6 +47,7 @@ class TuningLogRecord(logging.LogRecord):
|
||||
self._tuning_specialist_id = None
|
||||
self._tuning_retriever_id = None
|
||||
self._tuning_processor_id = None
|
||||
self._session_id = None
|
||||
self.component = os.environ.get('COMPONENT_NAME', 'eveai_app')
|
||||
|
||||
def getMessage(self):
|
||||
@@ -87,16 +88,18 @@ class TuningLogRecord(logging.LogRecord):
|
||||
'tuning_specialist_id': self._tuning_specialist_id,
|
||||
'tuning_retriever_id': self._tuning_retriever_id,
|
||||
'tuning_processor_id': self._tuning_processor_id,
|
||||
'session_id': self._session_id,
|
||||
}
|
||||
|
||||
def set_tuning_data(self, tenant_id=None, catalog_id=None, specialist_id=None,
|
||||
retriever_id=None, processor_id=None):
|
||||
retriever_id=None, processor_id=None, session_id=None,):
|
||||
"""Set tuning-specific data"""
|
||||
object.__setattr__(self, '_tuning_tenant_id', tenant_id)
|
||||
object.__setattr__(self, '_tuning_catalog_id', catalog_id)
|
||||
object.__setattr__(self, '_tuning_specialist_id', specialist_id)
|
||||
object.__setattr__(self, '_tuning_retriever_id', retriever_id)
|
||||
object.__setattr__(self, '_tuning_processor_id', processor_id)
|
||||
object.__setattr__(self, '_session_id', session_id)
|
||||
|
||||
|
||||
class TuningFormatter(logging.Formatter):
|
||||
@@ -120,6 +123,12 @@ class TuningFormatter(logging.Formatter):
|
||||
identifiers.append(f"Catalog: {record.catalog_id}")
|
||||
if hasattr(record, 'processor_id') and record.processor_id:
|
||||
identifiers.append(f"Processor: {record.processor_id}")
|
||||
if hasattr(record, 'specialist_id') and record.specialist_id:
|
||||
identifiers.append(f"Specialist: {record.specialist_id}")
|
||||
if hasattr(record, 'retriever_id') and record.retriever_id:
|
||||
identifiers.append(f"Retriever: {record.retriever_id}")
|
||||
if hasattr(record, 'session_id') and record.session_id:
|
||||
identifiers.append(f"Session: {record.session_id}")
|
||||
|
||||
formatted_msg = (
|
||||
f"{formatted_msg}\n"
|
||||
@@ -149,22 +158,93 @@ class GraylogFormatter(logging.Formatter):
|
||||
'specialist_id': record.specialist_id,
|
||||
'retriever_id': record.retriever_id,
|
||||
'processor_id': record.processor_id,
|
||||
'session_id': record.session_id,
|
||||
}
|
||||
return super().format(record)
|
||||
|
||||
|
||||
class TuningLogger:
|
||||
"""Helper class to manage tuning logs with consistent structure"""
|
||||
|
||||
def __init__(self, logger_name, tenant_id=None, catalog_id=None, specialist_id=None, retriever_id=None, processor_id=None):
|
||||
def __init__(self, logger_name, tenant_id=None, catalog_id=None, specialist_id=None, retriever_id=None,
|
||||
processor_id=None, session_id=None, log_file=None):
|
||||
"""
|
||||
Initialize a tuning logger
|
||||
|
||||
Args:
|
||||
logger_name: Base name for the logger
|
||||
tenant_id: Optional tenant ID for context
|
||||
catalog_id: Optional catalog ID for context
|
||||
specialist_id: Optional specialist ID for context
|
||||
retriever_id: Optional retriever ID for context
|
||||
processor_id: Optional processor ID for context
|
||||
session_id: Optional session ID for context and log file naming
|
||||
log_file: Optional custom log file name to use
|
||||
"""
|
||||
|
||||
self.logger = logging.getLogger(logger_name)
|
||||
self.tenant_id = tenant_id
|
||||
self.catalog_id = catalog_id
|
||||
self.specialist_id = specialist_id
|
||||
self.retriever_id = retriever_id
|
||||
self.processor_id = processor_id
|
||||
self.session_id = session_id
|
||||
self.log_file = log_file
|
||||
# Determine whether to use a session-specific logger
|
||||
if session_id:
|
||||
# Create a unique logger name for this session
|
||||
session_logger_name = f"{logger_name}_{session_id}"
|
||||
self.logger = logging.getLogger(session_logger_name)
|
||||
|
||||
def log_tuning(self, tuning_type: str, message: str, data=None, level=logging.DEBUG):
|
||||
# If this logger doesn't have handlers yet, configure it
|
||||
if not self.logger.handlers:
|
||||
# Determine log file path
|
||||
if not log_file and session_id:
|
||||
log_file = f"logs/tuning_{session_id}.log"
|
||||
elif not log_file:
|
||||
log_file = "logs/tuning.log"
|
||||
|
||||
# Configure the logger
|
||||
self._configure_session_logger(log_file)
|
||||
else:
|
||||
# Use the standard tuning logger
|
||||
self.logger = logging.getLogger(logger_name)
|
||||
|
||||
def _configure_session_logger(self, log_file):
|
||||
"""Configure a new session-specific logger with appropriate handlers"""
|
||||
# Create and configure a file handler
|
||||
file_handler = logging.handlers.RotatingFileHandler(
|
||||
filename=log_file,
|
||||
maxBytes=1024 * 1024 * 3, # 3MB
|
||||
backupCount=3
|
||||
)
|
||||
file_handler.setFormatter(TuningFormatter())
|
||||
file_handler.setLevel(logging.DEBUG)
|
||||
|
||||
# Add the file handler to the logger
|
||||
self.logger.addHandler(file_handler)
|
||||
|
||||
# Add Graylog handler in production
|
||||
env = os.environ.get('FLASK_ENV', 'development')
|
||||
if env == 'production':
|
||||
try:
|
||||
graylog_handler = GELFUDPHandler(
|
||||
host=GRAYLOG_HOST,
|
||||
port=GRAYLOG_PORT,
|
||||
debugging_fields=True
|
||||
)
|
||||
graylog_handler.setFormatter(GraylogFormatter())
|
||||
self.logger.addHandler(graylog_handler)
|
||||
except Exception as e:
|
||||
# Fall back to just file logging if Graylog setup fails
|
||||
fallback_logger = logging.getLogger('eveai_app')
|
||||
fallback_logger.warning(f"Failed to set up Graylog handler: {str(e)}")
|
||||
|
||||
# Set logger level and disable propagation
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
self.logger.propagate = False
|
||||
|
||||
|
||||
def log_tuning(self, tuning_type: str, message: str, data=None, level=logging.DEBUG):
|
||||
"""Log a tuning event with structured data"""
|
||||
try:
|
||||
# Create a standard LogRecord for tuning
|
||||
@@ -186,6 +266,7 @@ class TuningLogger:
|
||||
record.specialist_id = self.specialist_id
|
||||
record.retriever_id = self.retriever_id
|
||||
record.processor_id = self.processor_id
|
||||
record.session_id = self.session_id
|
||||
|
||||
if data:
|
||||
record.tuning_data = data
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
version: "1.0.0"
|
||||
name: "Management Service"
|
||||
configuration: {}
|
||||
configuration:
|
||||
specialist_denominator:
|
||||
name: "Specialist Denominator"
|
||||
type: "string"
|
||||
description: "Name defining the denominator for the specialist. Needs to be unique."
|
||||
required: False
|
||||
permissions: {}
|
||||
metadata:
|
||||
author: "Josako"
|
||||
@@ -1,163 +0,0 @@
|
||||
version: "1.0.0"
|
||||
name: "Traicie Vacature Specialist"
|
||||
framework: "crewai"
|
||||
configuration:
|
||||
ko_criteria:
|
||||
name: "Knock-out criteria"
|
||||
type: "text"
|
||||
description: "The knock-out criteria (1 per line)"
|
||||
required: true
|
||||
hard_skills:
|
||||
name: "Hard Skills"
|
||||
type: "text"
|
||||
description: "The hard skills to be checked with the applicant (1 per line)"
|
||||
required: false
|
||||
soft_skills:
|
||||
name: "Soft Skills"
|
||||
type: "text"
|
||||
description: "The soft skills required for the job (1 per line)"
|
||||
required: false
|
||||
tone_of_voice:
|
||||
name: "Tone of Voice"
|
||||
type: "enum"
|
||||
description: "Tone of voice to be used in communicating with the applicant"
|
||||
required: false
|
||||
default: "formal"
|
||||
allowed_values: [ "formal", "informal", "dynamic" ]
|
||||
vacancy_text:
|
||||
name: "Vacancy Text"
|
||||
type: "text"
|
||||
description: "The vacancy for this specialist"
|
||||
arguments:
|
||||
language:
|
||||
name: "Language"
|
||||
type: "str"
|
||||
description: "Language code to be used for receiving questions and giving answers"
|
||||
required: true
|
||||
results:
|
||||
rag_output:
|
||||
answer:
|
||||
name: "answer"
|
||||
type: "str"
|
||||
description: "Answer to the query"
|
||||
required: true
|
||||
citations:
|
||||
name: "citations"
|
||||
type: "List[str]"
|
||||
description: "List of citations"
|
||||
required: false
|
||||
insufficient_info:
|
||||
name: "insufficient_info"
|
||||
type: "bool"
|
||||
description: "Whether or not the query is insufficient info"
|
||||
required: true
|
||||
spin:
|
||||
situation:
|
||||
name: "situation"
|
||||
type: "str"
|
||||
description: "A description of the customer's current situation / context"
|
||||
required: false
|
||||
problem:
|
||||
name: "problem"
|
||||
type: "str"
|
||||
description: "The current problems the customer is facing, for which he/she seeks a solution"
|
||||
required: false
|
||||
implication:
|
||||
name: "implication"
|
||||
type: "str"
|
||||
description: "A list of implications"
|
||||
required: false
|
||||
needs:
|
||||
name: "needs"
|
||||
type: "str"
|
||||
description: "A list of needs"
|
||||
required: false
|
||||
additional_info:
|
||||
name: "additional_info"
|
||||
type: "str"
|
||||
description: "Additional information that may be commercially interesting"
|
||||
required: false
|
||||
lead_info:
|
||||
lead_personal_info:
|
||||
name:
|
||||
name: "name"
|
||||
type: "str"
|
||||
description: "name of the lead"
|
||||
required: "true"
|
||||
job_title:
|
||||
name: "job_title"
|
||||
type: "str"
|
||||
description: "job title"
|
||||
required: false
|
||||
email:
|
||||
name: "email"
|
||||
type: "str"
|
||||
description: "lead email"
|
||||
required: "false"
|
||||
phone:
|
||||
name: "phone"
|
||||
type: "str"
|
||||
description: "lead phone"
|
||||
required: false
|
||||
additional_info:
|
||||
name: "additional_info"
|
||||
type: "str"
|
||||
description: "additional info on the lead"
|
||||
required: false
|
||||
lead_company_info:
|
||||
company_name:
|
||||
name: "company_name"
|
||||
type: "str"
|
||||
description: "Name of the lead company"
|
||||
required: false
|
||||
industry:
|
||||
name: "industry"
|
||||
type: "str"
|
||||
description: "The industry of the company"
|
||||
required: false
|
||||
company_size:
|
||||
name: "company_size"
|
||||
type: "int"
|
||||
description: "The size of the company"
|
||||
required: false
|
||||
company_website:
|
||||
name: "company_website"
|
||||
type: "str"
|
||||
description: "The main website for the company"
|
||||
required: false
|
||||
additional_info:
|
||||
name: "additional_info"
|
||||
type: "str"
|
||||
description: "Additional information that may be commercially interesting"
|
||||
required: false
|
||||
agents:
|
||||
- type: "RAG_AGENT"
|
||||
version: "1.0"
|
||||
- type: "RAG_COMMUNICATION_AGENT"
|
||||
version: "1.0"
|
||||
- type: "SPIN_DETECTION_AGENT"
|
||||
version: "1.0"
|
||||
- type: "SPIN_SALES_SPECIALIST_AGENT"
|
||||
version: "1.0"
|
||||
- type: "IDENTIFICATION_AGENT"
|
||||
version: "1.0"
|
||||
- type: "RAG_COMMUNICATION_AGENT"
|
||||
version: "1.0"
|
||||
tasks:
|
||||
- type: "RAG_TASK"
|
||||
version: "1.0"
|
||||
- type: "SPIN_DETECT_TASK"
|
||||
version: "1.0"
|
||||
- type: "SPIN_QUESTIONS_TASK"
|
||||
version: "1.0"
|
||||
- type: "IDENTIFICATION_DETECTION_TASK"
|
||||
version: "1.0"
|
||||
- type: "IDENTIFICATION_QUESTIONS_TASK"
|
||||
version: "1.0"
|
||||
- type: "RAG_CONSOLIDATION_TASK"
|
||||
version: "1.0"
|
||||
metadata:
|
||||
author: "Josako"
|
||||
date_added: "2025-01-08"
|
||||
changes: "Initial version"
|
||||
description: "A Specialist that performs both Q&A as SPIN (Sales Process) activities"
|
||||
@@ -1,6 +1,7 @@
|
||||
version: "1.0.0"
|
||||
name: "RAG Specialist"
|
||||
framework: "crewai"
|
||||
chat: true
|
||||
configuration:
|
||||
name:
|
||||
name: "name"
|
||||
@@ -1,6 +1,7 @@
|
||||
version: "1.0.0"
|
||||
name: "Spin Sales Specialist"
|
||||
framework: "crewai"
|
||||
chat: true
|
||||
configuration:
|
||||
name:
|
||||
name: "name"
|
||||
|
Before Width: | Height: | Size: 387 KiB After Width: | Height: | Size: 387 KiB |
@@ -1,6 +1,7 @@
|
||||
version: 1.0.0
|
||||
name: "Standard RAG Specialist"
|
||||
framework: "langchain"
|
||||
chat: true
|
||||
configuration:
|
||||
specialist_context:
|
||||
name: "Specialist Context"
|
||||
@@ -0,0 +1,36 @@
|
||||
version: "1.0.0"
|
||||
name: "Traicie Vacancy Definition Specialist"
|
||||
framework: "crewai"
|
||||
partner: "traicie"
|
||||
chat: false
|
||||
configuration: {}
|
||||
arguments:
|
||||
vacancy_text:
|
||||
name: "vacancy_text"
|
||||
type: "text"
|
||||
description: "The Vacancy Text"
|
||||
required: true
|
||||
results:
|
||||
competencies:
|
||||
name: "competencies"
|
||||
type: "List[str, str]"
|
||||
description: "List of vacancy competencies and their descriptions"
|
||||
required: false
|
||||
criteria:
|
||||
name: "criteria"
|
||||
type: "List[str, str]"
|
||||
description: "List of vacancy knock out criteria and their descriptions"
|
||||
required: false
|
||||
agents:
|
||||
- type: "TRAICIE_HR_BP_AGENT"
|
||||
version: "1.0"
|
||||
tasks:
|
||||
- type: "TRAICIE_GET_COMPETENCIES_TASK"
|
||||
version: "1.0"
|
||||
- type: "TRAICIE_GET_KO_CRITERIA_TASK"
|
||||
version: "1.0"
|
||||
metadata:
|
||||
author: "Josako"
|
||||
date_added: "2025-05-21"
|
||||
changes: "Initial version"
|
||||
description: "Assistant to create a new Vacancy based on Vacancy Text"
|
||||
|
Before Width: | Height: | Size: 812 KiB After Width: | Height: | Size: 812 KiB |
@@ -0,0 +1,28 @@
|
||||
version: "1.0.0"
|
||||
name: "Get Competencies"
|
||||
task_description: >
|
||||
You are provided with a vacancy text, in beween triple backquotes.
|
||||
Identify and list all explicitly stated competencies, skills, knowledge, qualifications, and requirements mentioned in
|
||||
the vacancy text. This includes:
|
||||
• Technical skills
|
||||
• Education or training
|
||||
• Work experience
|
||||
• Language proficiency
|
||||
• Certifications or driving licences
|
||||
• Personal characteristics
|
||||
|
||||
Restrict yourself strictly to what is literally stated or clearly described in the job posting.
|
||||
Respect the language of the vacancy text, and return answers / output in the same language.
|
||||
{custom_description}
|
||||
|
||||
Vacancy Text:
|
||||
```{vacancy_text}```
|
||||
|
||||
expected_output: >
|
||||
A list of title and description of the competencies for the given vacancy text.
|
||||
{custom_expected_output}
|
||||
metadata:
|
||||
author: "Josako"
|
||||
date_added: "2025-01-25"
|
||||
description: "A Task to collect all behavioural competencies from a vacancy text"
|
||||
changes: "Initial version"
|
||||
37
config/tasks/traicie/TRAICIE_GET_KO_CRITERIA_TASK/1.0.0.yaml
Normal file
37
config/tasks/traicie/TRAICIE_GET_KO_CRITERIA_TASK/1.0.0.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
version: "1.0.0"
|
||||
name: "Get KO Criteria"
|
||||
task_description: >
|
||||
You are provided with a vacancy text, in beween triple backquotes.
|
||||
Use logical reasoning based on the realities of the job, taking into account:
|
||||
• The job title
|
||||
• The content of the job description
|
||||
• Typical characteristics of similar roles
|
||||
|
||||
Identify the minimum requirements that are absolutely essential to perform the job properly – even if they are not
|
||||
explicitly stated in the text.
|
||||
|
||||
Assess the job within its specific context and ask yourself questions such as:
|
||||
• Does the job require physical stamina?
|
||||
• Is weekend or shift work involved?
|
||||
• Is contact with certain materials (e.g. meat, chemicals) unavoidable?
|
||||
• Is independent working essential?
|
||||
• Is knowledge of a specific language or system critical for customer interaction or safety?
|
||||
• Are there any specific characteristics, contexts, or requirements so obvious that they are often left unstated, yet essential to perform the job?
|
||||
|
||||
Create a prioritised list of the 5 most critical knock-out criteria, ranked by importance.
|
||||
|
||||
Treat this as a logical and professional reasoning exercise.
|
||||
Respect the language of the vacancy text, and return answers / output in the same language.
|
||||
{custom_description}
|
||||
|
||||
Vacancy Text:
|
||||
```{vacancy_text}```
|
||||
|
||||
expected_output: >
|
||||
A list of title and description of the (knock-out) criteria for the given vacancy text.
|
||||
{custom_expected_output}
|
||||
metadata:
|
||||
author: "Josako"
|
||||
date_added: "2025-01-25"
|
||||
description: "A Task to collect all KO criteria from a vacancy text"
|
||||
changes: "Initial version"
|
||||
@@ -28,4 +28,9 @@ AGENT_TYPES = {
|
||||
"name": "SPIN Sales Specialist",
|
||||
"description": "An Agent that asks for Follow-up questions for SPIN-process",
|
||||
},
|
||||
"TRAICIE_HR_BP_AGENT": {
|
||||
"name": "Traicie HR BP Agent",
|
||||
"description": "An HR Business Partner Agent",
|
||||
"partner": "traicie"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,8 @@ AGENT_TYPES = {
|
||||
"name": "Document Template",
|
||||
"description": "Asset that defines a template in markdown a specialist can process",
|
||||
},
|
||||
"SPECIALIST_CONFIGURATION": {
|
||||
"name": "Specialist Configuration",
|
||||
"description": "Asset that defines a specialist configuration",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ SPECIALIST_TYPES = {
|
||||
"name": "Spin Sales Specialist",
|
||||
"description": "A specialist that allows to answer user queries, try to get SPIN-information and Identification",
|
||||
},
|
||||
"TRAICIE_VACATURE_SPECIALIST": {
|
||||
"name": "Traicie Vacature Specialist",
|
||||
"description": "Specialist configureerbaar voor een specifieke vacature",
|
||||
"partner": "Traicie"
|
||||
"TRAICIE_VACANCY_DEFINITION_SPECIALIST": {
|
||||
"name": "Traicie Vacancy Definition Specialist",
|
||||
"description": "Assistant to create a new Vacancy based on Vacancy Text",
|
||||
"partner": "traicie"
|
||||
}
|
||||
}
|
||||
@@ -31,5 +31,15 @@ TASK_TYPES = {
|
||||
"RAG_CONSOLIDATION_TASK": {
|
||||
"name": "RAG Consolidation",
|
||||
"description": "A Task to consolidate questions and answers",
|
||||
},
|
||||
"TRAICIE_GET_COMPETENCIES_TASK": {
|
||||
"name": "Traicie Get Competencies",
|
||||
"description": "A Task to get Competencies from a Vacancy Text",
|
||||
"partner": "traicie"
|
||||
},
|
||||
"TRAICIE_GET_KO_CRITERIA_TASK": {
|
||||
"name": "Traicie Get KO Criteria",
|
||||
"description": "A Task to get KO Criteria from a Vacancy Text",
|
||||
"partner": "traicie"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user