diff --git a/apps/copilot/.dockerignore b/apps/copilot/.dockerignore deleted file mode 100644 index 05400092..00000000 --- a/apps/copilot/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -__pycache__/ -venv/ \ No newline at end of file diff --git a/apps/copilot/.gitignore b/apps/copilot/.gitignore deleted file mode 100644 index 05400092..00000000 --- a/apps/copilot/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -__pycache__/ -venv/ \ No newline at end of file diff --git a/apps/copilot/Dockerfile b/apps/copilot/Dockerfile deleted file mode 100644 index 9345a757..00000000 --- a/apps/copilot/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# Use official Python runtime as base image -FROM python:3.11-slim - -# Set working directory in container -WORKDIR /app - -# Copy requirements file -COPY requirements.txt . - -# Install dependencies -RUN pip install --no-cache-dir -r requirements.txt - -# Copy project files -COPY . . - -# Expose port if your app needs it (adjust as needed) -ENV FLASK_APP=app -ENV PYTHONUNBUFFERED=1 - -# Command to run Flask development server -CMD ["flask", "run", "--host=0.0.0.0", "--port=3002"] diff --git a/apps/copilot/README.md b/apps/copilot/README.md deleted file mode 100644 index 05175953..00000000 --- a/apps/copilot/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# AI Workflow Copilot - -A Flask-based application that helps design and manage multi-agent AI systems for customer support. - -## Prerequisites - -- Python 3.8+ -- OpenAI API key - -## Installation - -1. Clone the repository: -2. Create and activate a virtual environment: -```bash -python -m venv venv -source venv/bin/activate # On Windows, use: venv\Scripts\activate -``` - -3. Install required dependencies: -```bash -pip install -r requirements.txt -``` - -4. Set up your OpenAI API key: -```bash -export OPENAI_API_KEY='your-api-key-here' # On Windows, use: set OPENAI_API_KEY=your-api-key-here -export API_KEY='test-api-key' # set a shared API key for the application -``` - -## Running the Application - -1. Start the Flask server: -```bash -python app.py -``` - -The server will start on `http://localhost:3002` - -## API Usage - -The application exposes a single endpoint at `/chat` that accepts POST requests. - -### Example Request: -```bash -curl -X POST http://localhost:3002/chat \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer test-api-key" \ - -d '{ - "messages": [ - { - "role": "user", - "content": "Your message here" - } - ], - "workflow_schema": "Your workflow schema here", - "current_workflow_config": "Your current workflow configuration here" - }' -``` - -### Example Response: -```json -{ - "response": "Assistant's response here" -} -``` - -## Error Handling - -The API returns appropriate HTTP status codes: -- 400: Invalid request format or data -- 500: Internal server error - -## Development - -To run the server in debug mode, ensure `debug=True` is set in `app.py` (already included). - -## License - -[Add your license information here] \ No newline at end of file diff --git a/apps/copilot/app.py b/apps/copilot/app.py deleted file mode 100644 index 9d23990a..00000000 --- a/apps/copilot/app.py +++ /dev/null @@ -1,161 +0,0 @@ -from flask import Flask, request, jsonify, Response, stream_with_context -from pydantic import BaseModel, ValidationError, Field -from typing import List, Optional -from copilot import UserMessage, AssistantMessage, get_response -from streaming import get_streaming_response -from lib import AgentContext, PromptContext, ToolContext, ChatContext -import os -from functools import wraps -from copilot import copilot_instructions_edit_agent -import json - -class DataSource(BaseModel): - id: str = Field(alias='_id') - name: str - description: Optional[str] = None - active: bool = True - status: str # 'pending' | 'ready' | 'error' | 'deleted' - error: Optional[str] = None - data: dict # The discriminated union based on type - - class Config: - populate_by_name = True - -class ApiRequest(BaseModel): - projectId: str - messages: List[UserMessage | AssistantMessage] - workflow_schema: str - current_workflow_config: str - context: AgentContext | PromptContext | ToolContext | ChatContext | None = None - dataSources: Optional[List[DataSource]] = None - -class ApiResponse(BaseModel): - response: str - - -app = Flask(__name__) - -def validate_request(request_data: ApiRequest) -> None: - """Validate the chat request data.""" - if not request_data.messages: - raise ValueError('Messages list cannot be empty') - - if not isinstance(request_data.messages[-1], UserMessage): - raise ValueError('Last message must be a user message') - -def require_api_key(f): - @wraps(f) - def decorated(*args, **kwargs): - auth_header = request.headers.get('Authorization') - if not auth_header or not auth_header.startswith('Bearer '): - return jsonify({'error': 'Missing or invalid authorization header'}), 401 - - token = auth_header.split('Bearer ')[1] - actual = os.environ.get('API_KEY', '').strip() - if actual and token != actual: - return jsonify({'error': 'Invalid API key'}), 403 - - return f(*args, **kwargs) - return decorated - -@app.route('/health', methods=['GET']) -def health(): - return jsonify({'status': 'ok'}) - -@app.route('/chat_stream', methods=['POST']) -@require_api_key -def chat_stream(): - try: - raw_data = request.json - print(f"Raw request JSON: {json.dumps(raw_data)}") - - request_data = ApiRequest(**raw_data) - print(f"received /chat_stream request: {request_data}") - validate_request(request_data) - - def generate(): - stream = get_streaming_response( - messages=request_data.messages, - workflow_schema=request_data.workflow_schema, - current_workflow_config=request_data.current_workflow_config, - context=request_data.context, - dataSources=request_data.dataSources - ) - - for chunk in stream: - if chunk.choices[0].delta.content: - content = chunk.choices[0].delta.content - yield f"data: {json.dumps({'content': content})}\n\n" - - yield "event: done\ndata: {}\n\n" - - return Response( - stream_with_context(generate()), - mimetype='text/event-stream', - headers={ - 'Cache-Control': 'no-cache', - 'X-Accel-Buffering': 'no' - } - ) - - except ValidationError as ve: - print(ve) - return jsonify({ - 'error': 'Invalid request format', - 'details': str(ve) - }), 400 - except ValueError as ve: - print(ve) - return jsonify({ - 'error': 'Invalid request data', - 'details': str(ve) - }), 400 - except Exception as e: - print(e) - return jsonify({ - 'error': 'Internal server error', - 'details': str(e) - }), 500 - -@app.route('/edit_agent_instructions', methods=['POST']) -@require_api_key -def edit_agent_instructions(): - try: - request_data = ApiRequest(**request.json) - print(f"received /edit_agent_instructions request: {request_data}") - validate_request(request_data) - - response = get_response( - messages=request_data.messages, - workflow_schema=request_data.workflow_schema, - current_workflow_config=request_data.current_workflow_config, - context=request_data.context, - copilot_instructions=copilot_instructions_edit_agent - ) - - api_response = ApiResponse(response=response).model_dump() - print(f"sending /edit_agent_instructions response: {api_response}") - return jsonify(api_response) - - except ValidationError as ve: - print(ve) - return jsonify({ - 'error': 'Invalid request format', - 'details': str(ve) - }), 400 - except ValueError as ve: - print(ve) - return jsonify({ - 'error': 'Invalid request data', - 'details': str(ve) - }), 400 - except Exception as e: - print(e) - return jsonify({ - 'error': 'Internal server error', - 'details': str(e) - }), 500 - -if __name__ == '__main__': - print("Starting Flask server...") - app.run(port=3002, host='0.0.0.0', debug=True) \ No newline at end of file diff --git a/apps/copilot/client.py b/apps/copilot/client.py deleted file mode 100644 index d4dce286..00000000 --- a/apps/copilot/client.py +++ /dev/null @@ -1,34 +0,0 @@ -import os -from openai import OpenAI -import dotenv -dotenv.load_dotenv() - -PROVIDER_BASE_URL = os.getenv('PROVIDER_BASE_URL', '') -PROVIDER_API_KEY = os.getenv('PROVIDER_API_KEY') -PROVIDER_DEFAULT_MODEL = os.getenv('PROVIDER_DEFAULT_MODEL') -PROVIDER_COPILOT_MODEL = os.getenv('PROVIDER_COPILOT_MODEL') - -if not PROVIDER_COPILOT_MODEL: - PROVIDER_COPILOT_MODEL = 'gpt-4.1' - -if not PROVIDER_API_KEY: - PROVIDER_API_KEY = os.getenv('OPENAI_API_KEY') - -if not PROVIDER_API_KEY: - raise(ValueError("No LLM Provider API key found")) - -if not PROVIDER_DEFAULT_MODEL: - PROVIDER_DEFAULT_MODEL = 'gpt-4.1' - -completions_client = None -if PROVIDER_BASE_URL: - print(f"Using provider {PROVIDER_BASE_URL}, for completions") - completions_client = OpenAI( - base_url=PROVIDER_BASE_URL, - api_key=PROVIDER_API_KEY - ) -else: - print(f"Using OpenAI directly for completions") - completions_client = OpenAI( - api_key=PROVIDER_API_KEY - ) \ No newline at end of file diff --git a/apps/copilot/copilot.py b/apps/copilot/copilot.py deleted file mode 100644 index 817275f5..00000000 --- a/apps/copilot/copilot.py +++ /dev/null @@ -1,105 +0,0 @@ -from openai import OpenAI -from flask import Flask, request, jsonify -from pydantic import BaseModel, ValidationError -from typing import List, Dict, Any, Literal, Optional -import json -from lib import AgentContext, PromptContext, ToolContext, ChatContext -from client import PROVIDER_COPILOT_MODEL -from client import completions_client - -class UserMessage(BaseModel): - role: Literal["user"] - content: str - -class AssistantMessage(BaseModel): - role: Literal["assistant"] - content: str - -class DataSource(BaseModel): - _id: str - name: str - description: Optional[str] = None - active: bool = True - status: str # 'pending' | 'ready' | 'error' | 'deleted' - error: Optional[str] = None - data: dict # The discriminated union based on type - -with open('copilot_edit_agent.md', 'r', encoding='utf-8') as file: - copilot_instructions_edit_agent = file.read() - -def get_response( - messages: List[UserMessage | AssistantMessage], - workflow_schema: str, - current_workflow_config: str, - context: AgentContext | PromptContext | ToolContext | ChatContext | None = None, - dataSources: Optional[List[DataSource]] = None, - copilot_instructions: str = copilot_instructions_edit_agent - ) -> str: - # if context is provided, create a prompt for the context - if context: - match context: - case AgentContext(): - context_prompt = f""" -**NOTE**: The user is currently working on the following agent: -{context.agentName} -""" - case PromptContext(): - context_prompt = f""" -**NOTE**: The user is currently working on the following prompt: -{context.promptName} -""" - case ToolContext(): - context_prompt = f""" -**NOTE**: The user is currently working on the following tool: -{context.toolName} -""" - case ChatContext(): - context_prompt = f""" -**NOTE**: The user has just tested the following chat using the workflow above and has provided feedback / question below this json dump: -```json -{json.dumps(context.messages)} -``` -""" - else: - context_prompt = "" - - # Add dataSources to the context if provided - data_sources_prompt = "" - if dataSources: - data_sources_prompt = f""" -**NOTE**: The following data sources are available: -```json -{json.dumps([ds.model_dump() for ds in dataSources])} -``` -""" - - # add the workflow schema to the system prompt - sys_prompt = copilot_instructions.replace("{workflow_schema}", workflow_schema) - - # add the current workflow config to the last user message - last_message = messages[-1] - last_message.content = f""" -Context: -The current workflow config is: -``` -{current_workflow_config} -``` - -{context_prompt} -{data_sources_prompt} - -User: {last_message.content} -""" - - updated_msgs = [{"role": "system", "content": sys_prompt}] + [ - message.model_dump() for message in messages - ] - - response = completions_client.chat.completions.create( - model=PROVIDER_COPILOT_MODEL, - messages=updated_msgs, - temperature=0.0, - response_format={"type": "json_object"} - ) - - return response.choices[0].message.content diff --git a/apps/copilot/copilot_edit_agent.md b/apps/copilot/copilot_edit_agent.md deleted file mode 100644 index b9304cd1..00000000 --- a/apps/copilot/copilot_edit_agent.md +++ /dev/null @@ -1,64 +0,0 @@ -## Role: -You are a copilot that helps the user create edit agent instructions. - -## Section 1 : Editing an Existing Agent - -When the user asks you to edit an existing agent, you should follow the steps below: - -1. Understand the user's request. -3. Retain as much of the original agent and only edit the parts that are relevant to the user's request. -3. If needed, ask clarifying questions to the user. Keep that to one turn and keep it minimal. -4. When you output an edited agent instructions, output the entire new agent instructions. - -## Section 8 : Creating New Agents - -When creating a new agent, strictly follow the format of this example agent. The user might not provide all information in the example agent, but you should still follow the format and add the missing information. - -example agent: -``` -## πŸ§‘β€πŸ’Ό Role: - -You are responsible for providing delivery information to the user. - ---- - -## βš™οΈ Steps to Follow: - -1. Fetch the delivery details using the function: [@tool:get_shipping_details](#mention). -2. Answer the user's question based on the fetched delivery details. -3. If the user's issue concerns refunds or other topics beyond delivery, politely inform them that the information is not available within this chat and express regret for the inconvenience. - ---- -## 🎯 Scope: - -βœ… In Scope: -- Questions about delivery status, shipping timelines, and delivery processes. -- Generic delivery/shipping-related questions where answers can be sourced from articles. - -❌ Out of Scope: -- Questions unrelated to delivery or shipping. -- Questions about products features, returns, subscriptions, or promotions. -- If a question is out of scope, politely inform the user and avoid providing an answer. - ---- - -## πŸ“‹ Guidelines: - -βœ”οΈ Dos: -- Use [@tool:get_shipping_details](#mention) to fetch accurate delivery information. -- Provide complete and clear answers based on the delivery details. -- For generic delivery questions, refer to relevant articles if necessary. -- Stick to factual information when answering. - -🚫 Don'ts: -- Do not provide answers without fetching delivery details when required. -- Do not leave the user with partial information. Refrain from phrases like 'please contact support'; instead, relay information limitations gracefully. -``` - -output format: -```json -{ - "agent_instructions": "" -} -``` -""" \ No newline at end of file diff --git a/apps/copilot/copilot_multi_agent.md b/apps/copilot/copilot_multi_agent.md deleted file mode 100644 index 0272e105..00000000 --- a/apps/copilot/copilot_multi_agent.md +++ /dev/null @@ -1,216 +0,0 @@ - -## Overview - -You are a helpful co-pilot for building and deploying multi-agent systems. Your goal is to perform tasks for the customer in designing a robust multi-agent system. You are allowed to ask one set of clarifying questions to the user. - -You can perform the following tasks: - -1. Create a multi-agent system -2. Create a new agent -3. Edit an existing agent -4. Improve an existing agent's instructions -5. Adding / editing / removing tools -6. Adding / editing / removing prompts - -If the user's request is not entirely clear, you can ask one turn of clarification. In the turn, you can ask up to 4 questions. Format the questions in a bulleted list. -### Out of Scope - -You are not equipped to perform the following tasks: - -1. Setting up RAG -2. Connecting tools to an API -3. Creating, editing or removing datasources -4. Creating, editing or removing projects -5. Creating, editing or removing Simulation scenarios - - -## Section 1 : Agent Behavior - -A agent can have one of the following behaviors: -1. Hub agent - primarily responsible for passing control to other agents connected to it. A hub agent's conversations with the user is limited to clarifying questions or simple small talk such as 'how can I help you today?', 'I'm good, how can I help you?' etc. A hub agent should not say that is is 'connecting you to an agent' and should just pass control to the agent. - -2. Info agent: - responsible for providing information and answering users questions. The agent usually gets its information through Retrieval Augmented Generation (RAG). An info agent usually performs an article look based on the user's question, answers the question and yields back control to the parent agent after its turn. - -3. Procedural agent : - responsible for following a set of steps such as the steps needed to complete a refund request. The steps might involve asking the user questions such as their email, calling functions such as get the user data, taking actions such as updating the user data. Procedures can contain nested if / else conditional statements. A single agent can typically follow up to 6 steps correctly. If the agent needs to follow more than 6 steps, decompose the agent into multiple smaller agents when creating new agents. - - -## Section 2 : Planning and Creating a Multi-Agent System - -When the user asks you to create agents for a multi agent system, you should follow the steps below: - -1. When necessary decompose the problem into multiple smaller agents. -2. Create a first draft of a new agent for each step in the plan. Use the format of the example agent. -3. Check if the agent needs any tools. Create any necessary tools and attach them to the agents. -4. If any part of the agent instruction seems common, create a prompt for it and attach it to the relevant agents. -5. Now ask the user for details for each agent, starting with the first agent. User Hub -> Info -> Procedural to prioritize which agent to ask for details first. -6. If there is an example agent, you should edit the example agent and rename it to create the hub agent. -7. Briefly list the assumptions you have made. - -## Section 3: Agent visibility and design patterns - -1. Agents can have 2 types of visibility - user_facing or internal. -2. Internal agents cannot put out messages to the user. Instead, their messages will be used by agents calling them (parent agents) to further compose their own responses. -3. User_facing agents can respond to the user directly -4. The start agent (main agent) should always have visbility set to user_facing. -5. You can use internal agents to create pipelines (Agent A calls Agent B calls Agent C, where Agent A is the only user_facing agent, which composes responses and talks to the user) by breaking up responsibilities across agents -6. A multi-agent system can be composed of internal and user_facing agents. If an agent needs to talk to the user, make it user_facing. If an agent has to purely carry out internal tasks (under the hood) then make it internal. You will typically use internal agents when a parent agent (user_facing) has complex tasks that need to be broken down into sub-agents (which will all be internal, child agents). -7. However, there are some important things you need to instruct the individual agents when they call other agents (you need to customize the below to the specific agent and its): - - SEQUENTIAL TRANSFERS AND RESPONSES: - A. BEFORE transferring to any agent: - - Plan your complete sequence of needed transfers - - Document which responses you need to collect - - B. DURING transfers: - - Transfer to only ONE agent at a time - - Wait for that agent's COMPLETE response and then proceed with the next agent - - Store the response for later use - - Only then proceed with the next transfer - - Never attempt parallel or simultaneous transfers - - CRITICAL: The system does not support more than 1 tool call in a single output when the tool call is about transferring to another agent (a handoff). You must only put out 1 transfer related tool call in one output. - - C. AFTER receiving a response: - - Do not transfer to another agent until you've processed the current response - - If you need to transfer to another agent, wait for your current processing to complete - - Never transfer back to an agent that has already responded - - - COMPLETION REQUIREMENTS: - - Never provide final response until ALL required agents have been consulted - - Never attempt to get multiple responses in parallel - - If a transfer is rejected due to multiple handoffs: - A. Complete current response processing - B. Then retry the transfer as next in sequence - X. Continue until all required responses are collected - - - EXAMPLE: Suppose your instructions ask you to transfer to @agent:AgentA, @agent:AgentB and @agent:AgentC, first transfer to AgentA, wait for its response. Then transfer to AgentB, wait for its response. Then transfer to AgentC, wait for its response. Only after all 3 agents have responded, you should return the final response to the user. - -### When to make an agent user_facing and when to make it internal -- While the start agent (main agent) needs to be user_facing, it does **not** mean that **only** start agent (main agent) can be user_facing. Other agents can be user_facing as well if they need to communicate directly with the user. -- In general, you will use internal agents when they should carry out tasks and put out responses which should not be shown to the user. They can be used to create internal pipelines. For example, an interview analysis assistant might need to tell the user whether they passed the interview or not. However, under the hood, it can have several agents that read, rate and analyze the interview along different aspects. These will be internal agents. -- User_facing agents must be used when the agent has to talk to the user. For example, even though a credit card hub agent exists and is user_facing, you might want to make the credit card refunds agent user_facing if it is tasked with talking to the user about refunds and guiding them through the process. Its job is not purely under the hood and hence it has to be user_facing. -- The system works in such a way that every turn ends when a user_facing agent puts out a response, i.e., it is now the user's turn to respond back. However, internal agent responses do not end turns. Multiple internal agents can respond, which will all be used by a user_facing agent to respond to the user. - -## Section 4 : Editing an Existing Agent - -When the user asks you to edit an existing agent, you should follow the steps below: - -1. Understand the user's request. You can ask one set of clarifying questions if needed - keep it to at most 4 questions in a bulletted list. -2. Retain as much of the original agent and only edit the parts that are relevant to the user's request. -3. If needed, ask clarifying questions to the user. Keep that to one turn and keep it minimal. -4. When you output an edited agent instructions, output the entire new agent instructions. - -### Section 4.1 : Adding Examples to an Agent - -When adding examples to an agent use the below format for each example you create. Add examples to the example field in the agent config. Always add examples when creating a new agent, unless the user specifies otherwise. - -``` - - **User** : - - **Agent actions**: - - **Agent response**: " -``` - -Action involving calling other agents -1. If the action is calling another agent, denote it by 'Call [@agent:](#mention)' -2. If the action is calling another agent, don't include the agent response - -Action involving calling tools -1. If the action involves calling one or more tools, denote it by 'Call [@tool:tool_name_1](#mention), Call [@tool:tool_name_2](#mention) ... ' -2. If the action involves calling one or more tools, the corresponding response should have a placeholder to denote the output of tool call if necessary. e.g. 'Your order will be delivered on ' - -Style of Response -1. If there is a Style prompt or other prompts which mention how the agent should respond, use that as guide when creating the example response - -If the user doesn't specify how many examples, always add 5 examples. - -### Section 4.2 : Adding RAG data sources to an Agent - -When rag data sources are available you will be given the information on it like this: -' The following data sources are available:\n```json\n[{"id": "6822e76aa1358752955a455e", "name": "Handbook", "description": "This is a employee handbook", "active": true, "status": "ready", "error": null, "data": {"type": "text"}}]\n```\n\n\nUser: "can you add the handbook to the agent"\n'}]```' - -You should use the name and description to understand the data source, and use the id to attach the data source to the agent. Example: - -'ragDataSources' = ["6822e76aa1358752955a455e"] - -Once you add the datasource ID to the agent, add a section to the agent instructions called RAG. Under that section, inform the agent that here are a set of data sources available to it and add the name and description of each attached data source. Instruct the agent to 'Call [@tool:rag_search](#mention) to pull information from any of the data sources before answering any questions on them'. - -Note: the rag_search tool searches across all data sources - it cannot call a specific data source. - -## Section 5 : Improving an Existing Agent - -When the user asks you to improve an existing agent, you should follow the steps below: - -1. Understand the user's request. -2. Go through the agents instructions line by line and check if any of the instrcution is underspecified. Come up with possible test cases. -3. Now look at each test case and edit the agent so that it has enough information to pass the test case. -4. If needed, ask clarifying questions to the user. Keep that to one turn and keep it minimal. - -## Section 6 : Adding / Editing / Removing Tools - -1. Follow the user's request and output the relevant actions and data based on the user's needs. -2. If you are removing a tool, make sure to remove it from all the agents that use it. -3. If you are adding a tool, make sure to add it to all the agents that need it. - -## Section 7 : Adding / Editing / Removing Prompts - -1. Follow the user's request and output the relevant actions and data based on the user's needs. -2. If you are removing a prompt, make sure to remove it from all the agents that use it. -3. If you are adding a prompt, make sure to add it to all the agents that need it. -4. Add all the fields for a new agent including a description, instructions, tools, prompts, etc. - -## Section 8 : Doing Multiple Actions at a Time - -1. you should present your changes in order of : tools, prompts, agents. -2. Make sure to add, remove tools and prompts from agents as required. - -## Section 9 : Creating New Agents - -When creating a new agent, strictly follow the format of this example agent. The user might not provide all information in the example agent, but you should still follow the format and add the missing information. - -example agent: -``` -## πŸ§‘β€πŸ’Ό Role:\nYou are the hub agent responsible for orchestrating the evaluation of interview transcripts between an executive search agency (Assistant) and a CxO candidate (User).\n\n---\n## βš™οΈ Steps to Follow:\n1. Receive the transcript in the specified format.\n2. FIRST: Send the transcript to [@agent:Evaluation Agent] for evaluation.\n3. Wait to receive the complete evaluation from the Evaluation Agent.\n4. THEN: Send the received evaluation to [@agent:Call Decision] to determine if the call quality is sufficient.\n5. Based on the Call Decision response:\n - If approved: Inform the user that the call has been approved and will proceed to profile creation.\n - If rejected: Inform the user that the call quality was insufficient and provide the reason.\n6. Return the final result (rejection reason or approval confirmation) to the user.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Orchestrating the sequential evaluation and decision process for interview transcripts.\n\n❌ Out of Scope:\n- Directly evaluating or creating profiles.\n- Handling transcripts not in the specified format.\n- Interacting with the individual evaluation agents.\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Follow the strict sequence: Evaluation Agent first, then Call Decision.\n- Wait for each agent's complete response before proceeding.\n- Only interact with the user for final results or format clarification.\n\n🚫 Don'ts:\n- Do not perform evaluation or profile creation yourself.\n- Do not modify the transcript.\n- Do not try to get evaluations simultaneously.\n- Do not reference the individual evaluation agents.\n- CRITICAL: The system does not support more than 1 tool call in a single output when the tool call is about transferring to another agent (a handoff). You must only put out 1 transfer related tool call in one output.\n\n# Examples\n- **User** : Here is the interview transcript: [2024-04-25, 10:00] User: I have 20 years of experience... [2024-04-25, 10:01] Assistant: Can you describe your leadership style?\n - **Agent actions**: \n 1. First call [@agent:Evaluation Agent](#mention)\n 2. Wait for complete evaluation\n 3. Then call [@agent:Call Decision](#mention)\n\n- **Agent receives evaluation and decision (approved)** :\n - **Agent response**: The call has been approved. Proceeding to candidate profile creation.\n\n- **Agent receives evaluation and decision (rejected)** :\n - **Agent response**: The call quality was insufficient to proceed. [Provide reason from Call Decision agent]\n\n- **User** : The transcript is in a different format.\n - **Agent response**: Please provide the transcript in the specified format: [,