Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: S.M.A.R.T (Specific Multi Agent Recipe Tracking) Prompt POC (Proof of Concept) #2426

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 7 additions & 7 deletions api/app/clients/PluginsClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,14 +237,14 @@ class PluginsClient extends OpenAIClient {
return { ...responseMessage, ...result };
}

async sendMessage(message, opts = {}) {
async sendMessage(humanMessage, opts = {}) {
// If a message is edited, no tools can be used.
const completionMode = this.options.tools.length === 0 || opts.isEdited;
if (completionMode) {
this.setOptions(opts);
return super.sendMessage(message, opts);
return super.sendMessage(humanMessage, opts);
}
logger.debug('[PluginsClient] sendMessage', { message, opts });
logger.debug('[PluginsClient] sendMessage', { humanMessage, opts });
const {
user,
isEdited,
Expand All @@ -256,7 +256,7 @@ class PluginsClient extends OpenAIClient {
onChainEnd,
onToolStart,
onToolEnd,
} = await this.handleStartMethods(message, opts);
} = await this.handleStartMethods(humanMessage, opts);

this.currentMessages.push(userMessage);

Expand Down Expand Up @@ -316,7 +316,7 @@ class PluginsClient extends OpenAIClient {

await this.initialize({
user,
message,
humanMessage,
onAgentAction,
onChainEnd,
signal: this.abortController.signal,
Expand All @@ -326,7 +326,7 @@ class PluginsClient extends OpenAIClient {
// const stream = async (text) => {
// await this.generateTextStream.call(this, text, opts.onProgress, { delay: 1 });
// };
await this.executorCall(message, {
await this.executorCall(humanMessage, {
signal: this.abortController.signal,
// stream,
onToolStart,
Expand Down Expand Up @@ -367,7 +367,7 @@ class PluginsClient extends OpenAIClient {

const promptPrefix = buildPromptPrefix({
result: this.result,
message,
humanMessage,
functionsAgent: this.functionsAgent,
});

Expand Down
23 changes: 22 additions & 1 deletion api/app/clients/agents/Functions/initializeFunctionsAgent.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,27 @@ Share the instructions you received, and ask the user if they wish to carry them
Share all output from the tool, assuming the user can't see it.
Prioritize using tool outputs for subsequent requests to better fulfill the query as necessary.`;

const AGENT_COORDINATOR_PREFIX = `
You are Mission-Chat-GPT, an AI designed to autonomously manage structured conversation chat flow, composed by multiple stages, as given to you by invocation of the "agent-coordinator" tool.
At each stage you should:
1) Initiate each chat stage by by calling the "agent-coordinator" tool and establishing the current agent's role, goal, kpi and instructions per the tool guidance.
2) After initiating, and receiving instructions from the "agent-coordinator" tool, guide the chat with the user, ask, listen and respond to the user naturally, based on the current agent's mission and instructions. Ensure a seamless and engaging user experience by maintaining the conversational context and accurately following each agent's instructions during the chat with the user.
3) Work autonomously towards your current mission and goals. Play to your strengths as an LLM and pursue simple strategies to reflect on the chat and navigate it to complete the mission.
4) Continuously review, analyze and self-criticize your actions to ensure you are performing to the best of your abilities. If you need guidance on how to proceed at any point, self reflect on previous "agent-coordinator" plugin response, don't call the plugin more then once for the same stage.
5) Once you achieved the goal or exhausted your autonomous efforts as the current agent, invoke the "agent-coordinator" with the <current agent's name> & "Done" status to transition to the next stage.
6) The conversation flow is designed as a series of agents / stages, each with a unique role. Navigate through these agents sequentially.
7) Conclude the conversation flow gracefully when all agents have fulfilled their roles.

Start now by calling the "agent-coordinator" tool with "BootstrapAgent Done" to initiate the conversation flow (ignore the first user input for now).`;

const initializeFunctionsAgent = async ({
tools,
model,
pastMessages,
currentDateString,
...rest
}) => {
let prefix = '';
const memory = new BufferMemory({
llm: model,
chatHistory: new ChatMessageHistory(pastMessages),
Expand All @@ -24,7 +38,14 @@ const initializeFunctionsAgent = async ({
returnMessages: true,
});

const prefix = addToolDescriptions(`Current Date: ${currentDateString}\n${PREFIX}`, tools);
if (tools.length === 1 && tools[0].name === 'agent-coordinator') {
prefix = addToolDescriptions(
`Current Date: ${currentDateString}\n${AGENT_COORDINATOR_PREFIX}`,
tools,
);
} else {
prefix = addToolDescriptions(`Current Date: ${currentDateString}\n${PREFIX}`, tools);
}

return await initializeAgentExecutorWithOptions(tools, model, {
agentType: 'openai-functions',
Expand Down
117 changes: 117 additions & 0 deletions api/app/clients/tools/AgentCoordinator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
const { Tool } = require('langchain/tools');
const chatFlowConfig = require('./agent_recipe/MoodBooster.json');
const { logger } = require('~/config');

class AgentCoordinator extends Tool {
constructor() {
super();
this.description =
'The AgentCoordinator is a tool designed to manage and navigate through a structured multi stage conversational flow within an LLM chat application based on given chat Flow.';
this.description_for_model = `// Defines and dominates the goals and flow of the chat per predefined chat flow recipe that the chat needs to comply with.
// Guidelines:
// - The tool should be called with input of 2 words. Agent name and status which is either "Start" or "Done". The initial agent name is "BootstrapAgent" and the status is "Done".
// - Call the tool with the "BootstrapAgent Done" to initiate the conversation flow at the first time.
// - The tool will provide you with your current name, mission, and instructions. Follow the instructions to complete your mission.
// - ALWAYS use the current agent's name and the status.
// - When calling the tool with the "Done" status, you signal the completion of the current agent's mission and transition to the next agent in the flow.
// - Actually there is no need to call the tool with status "Start", since it will repeat the same instructions it gave with the previous Agent was done.
// - The flow is defined by a sequential list of agents, each with a specific role and goal to achieve during the interaction.
// Start now by calling the tool with "BootstrapAgent Done" to initiate the conversation flow.
// Remember, the tool is there to guide you, but the user's input is paramount. Engage with the user directly and use the tool as a guide for the conversation's structure and progression. if you need more instructions use self reflect to decide
`;

this.name = 'agent-coordinator';
this.chatFlowName = chatFlowConfig.chatFlowName;
this.chatFlow = chatFlowConfig.generalDescription;
this.generalFlowInstructions = chatFlowConfig.generalFlowInstructions;
this.agents = chatFlowConfig.agents;
}

async _call(agentRequest) {
// Your tool's functionality goes here
try {
this.agentName = this.getAgentName(agentRequest);
return this.getNextAgentDetails(this.agentName);
} catch (error) {
return error(error.message);
}
}

getAgentName(agentRequest) {
// Extract the agentName from the agentRequest
let agentName;
let status;
try {
agentName = agentRequest.split(' ')[0];
status = agentRequest.split(' ')[1];
} catch (error) {
throw new Error(
'Invalid input. Please provide 2 words with a space between them "agent_name status".',
);
}
if (status !== 'Start' && status !== 'Done') {
throw new Error('Invalid status. Please provide either "Start" or "Done".');
}

// Handle the bootstrap scenario by returning the first agent if no agentName is provided
// or if the agentName is "BootstrapAgent"
if (!agentName || agentName === 'BootstrapAgent') {
return 'BootstrapAgent'; // Return the name of the first agent
}
// Check if the agentName is within the list of agents defined in chatFlowConfig
const isValidAgentName = this.agents.some((agent) => agent.agentName === agentName);

// If the agentName is valid, return it
if (isValidAgentName) {
return agentName;
}
// If not valid, prepare a list of valid agent names for the error message
const validAgentNames = this.agents.map((agent) => agent.agentName).join(', ');

// Throw an error indicating the invalid agentName and providing the list of valid names
throw new Error(
`Invalid agentName: '${agentName}'. Available agents for '${this.chatFlowName}': ${validAgentNames}`,
);
}

// Function to find the index of the current agent in the chat flow
_findCurrentAgentIndex(currentAgentName) {
const agents = chatFlowConfig.agents;
return agents.findIndex((agent) => agent.agentName === currentAgentName);
}

// Main method to get the next agent's details
getNextAgentDetails(currentAgentName) {
let nextAgentIndex;
let nextAgent;

// Handle the bootstrap scenario
if (!currentAgentName || currentAgentName === 'BootstrapAgent') {
nextAgentIndex = 0; // Start of the flow
} else {
const currentAgentIndex = this._findCurrentAgentIndex(currentAgentName);
nextAgentIndex = currentAgentIndex + 1; // Proceed to next agent
}

if (nextAgentIndex >= chatFlowConfig.agents) {
return { endOfFlow: true, message: 'This is the end of the conversation flow. Thank you!' };
}

nextAgent = this.agents[nextAgentIndex];

const nextAgentPrompt = {
agentName: nextAgent.agentName,
goal: nextAgent.goal,
general_flow_instructions: this.generalFlowInstructions,
instructions_for_current_agent: nextAgent.instructions,
kpi: nextAgent.kpi,
when_done: `Call the AgentCoordinator with the input '${nextAgent.agentName} Done' to signal readiness for the next phase of the conversation.`,
important: `Don't call the plugin more than once for the same stage. you already called it with input '${currentAgentName} Done'.`,
};
const result = JSON.stringify(nextAgentPrompt);
logger.debug(result);
return result;
}
}

module.exports = AgentCoordinator;
54 changes: 54 additions & 0 deletions api/app/clients/tools/agent_recipe/MoodBooster.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"chatFlowName": "MoodBooster",
"generalDescription": "MoodBooster is a multi-step chatbot designed to engage users in a conversation about their mood and offer tailored activity suggestions to boost their spirits.",
"generalFlowInstructions": {
"user_interaction_instructions": "Maintain a conversation only in the language the user starts the conversation with, ensuring a respectful and engaging user experience. Don't answer questions that are out of the scope of the chatbot's purpose. if the user has nothing to say it probably indicates that you should move to next stage",
"self_thoughts_instructions": "Once you receive your role and goal Explain it to the user, for Example: As a 'GreetingAgent' I am here to welcome you and learn a bit about you. if you don't know what to ask, ask is there anything you would like to share with me regarding the <goal>? Use the stage goal as part of the question"
},
"agents": [
{
"agentName": "GreetingAgent",
"stage": 1,
"goal": "To warmly welcome the user and learn how the user whats to be addressed.",
"instructions": {
"user_interaction_instructions": "Start with a friendly greeting and inquire about the user's name. In languages where there are distinctions in the second person pronouns, such as different forms for males and females, or formal and informal 'you', it is important to ask the user how they prefer to be addressed",
"self_thoughts_instructions": "If the user hesitates to provide their name, offer reassurance about the purpose of personalizing the chat but respect their decision if they decline to share. Ask if there anything important the user wants to share regarding the chat"
},
"kpi": "Successful retrieval of the user's name and their preference for how to be addressed in languages where gender matters.",
"definition_of_done": "User has provided their name and preferred pronouns, or has explicitly declined to provide this information."
},
{
"agentName": "MoodAgent",
"stage": 2,
"goal": "To understand the user's current emotional state.",
"instructions": {
"user_interaction_instructions": "Engage in a dialogue to gauge how the user is feeling today. Use empathetic questioning to draw out details about their mood and any contributing factors.",
"self_thoughts_instructions": "Assess the depth of the emotional information provided to tailor further interactions effectively. Ask about patterns of the mood if the user is willing to share, For Example: What made him happy in the past, what bring bad feeling"
},
"kpi": "Acquire detailed information about current mood as well as mood patterns. reflect what you understand about the user's mood and ask if you are correct",
"definition_of_done": "User approved your reflection about their mood and mood patterns, or has explicitly declined to provide this information."
},
{
"agentName": "ActivitySuggestionAgent",
"stage": 3,
"goal": "To offer activity recommendations based on the user's mood.",
"instructions": {
"user_interaction_instructions": "Propose activities that align with the mood insights gathered. Offer these suggestions with sensitivity and adapt based on the user's responses. if no mood insights are available, ask the user about their interests and suggest activities based on that.",
"self_thoughts_instructions": "Evaluate user reactions to suggestions to refine the approach if necessary."
},
"kpi": "User acceptance of a suggested activity that they are interested in trying.",
"definition_of_done": "User has accepted a suggestion and expressed interest in trying the activity."
},
{
"agentName": "SummaryAgent",
"stage": 4,
"goal": "To provide a summary of the conversation's key points.",
"instructions": {
"user_interaction_instructions": "Summarize the conversation, highlighting the main takeaways. Confirm with the user that the summary is accurate.",
"self_thoughts_instructions": "Ensure the summary captures all key aspects of the conversation effectively."
},
"kpi": "User confirmation and satisfaction with the provided conversation summary.",
"definition_of_done": "User has confirmed the accuracy and expressed satisfaction with the summary."
}
]
}
45 changes: 45 additions & 0 deletions api/app/clients/tools/agent_recipe/MultiStepPlanner.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"chatFlowName": "MultiStepPlanner",
"generalDescription": "This process is designed to handle and execute complex prompts efficiently, involving steps like analysis, decomposition, and synthesis, complemented by reflection, fine-tuning, and human approval.",
"generalFlowInstructions": {
"user_interaction_instructions": "Ensure clarity and precision in understanding and decomposing complex prompts. Do not engage in discussions outside the defined scope of the task.",
"self_thoughts_instructions": "Explain your role and goal clearly at the start of each interaction. For example, say: 'As the AnalysisAgent, my goal is to understand the primary objectives of your request.' Ask the user if there's anything they would like to discuss specifically related to your goal."
},
"agents": [
{
"agentName": "AnalysisAgent",
"stage": 1,
"goal": "To analyze the complex prompt and identify the primary objectives and necessary components.",
"instructions": {
"user_interaction_instructions": "Carefully read and interpret the complex prompt to extract essential objectives and required components.",
"self_thoughts_instructions": "Consider each component's relevance to the main objective and prepare to list them clearly."
},
"kpi": "Complete identification of all necessary components and objectives.",
"definition_of_done": "Summarize the findings and request the user's approval to confirm that all components have been correctly identified and align with the KPIs. Move to the next stage upon approval."
},
{
"agentName": "DecompositionAgent",
"stage": 2,
"goal": "To break down the main objectives into actionable tasks.",
"instructions": {
"user_interaction_instructions": "Decompose the main objectives into smaller, manageable tasks that are clearly defined.",
"self_thoughts_instructions": "Ensure each task is actionable and contributes directly towards achieving the overall goal."
},
"kpi": "Clear definition of actionable tasks.",
"definition_of_done": "Review the tasks with the user and obtain their approval that each task is clear and meets the required standards before proceeding."
},
{
"agentName": "ExecutionAgent",
"stage": 3,
"goal": "To execute each task according to defined specifications.",
"instructions": {
"user_interaction_instructions": "Execute tasks as outlined, adhering closely to the specifications set during decomposition.",
"self_thoughts_instructions": "Monitor task execution for accuracy and effectiveness, making adjustments as needed."
},
"kpi": "Successful execution of all tasks.",
"definition_of_done": "Confirm task completion with the user, ensuring each task's results meet the predefined objectives and receive user approval before proceeding."
}
],
"NOT_SUPPORTED_YET_model": "claude-3-sonnet-20240229",
"NOT_SUPPORTED_YET_llm": "ChatAnthropic"
}
5 changes: 5 additions & 0 deletions api/app/clients/tools/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const OpenAICreateImage = require('./DALL-E');
const StableDiffusionAPI = require('./StableDiffusion');
const SelfReflectionTool = require('./SelfReflection');

// My tools
const AgentCoordinator = require('./AgentCoordinator');

// Structured Tools
const DALLE3 = require('./structured/DALLE3');
const ChatTool = require('./structured/ChatTool');
Expand All @@ -30,6 +33,8 @@ module.exports = {
OpenAICreateImage,
StableDiffusionAPI,
SelfReflectionTool,
// My tools
AgentCoordinator,
// Structured Tools
DALLE3,
ChatTool,
Expand Down
8 changes: 8 additions & 0 deletions api/app/clients/tools/manifest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
[
{
"name": "Agent Coordinator",
"pluginKey": "agent-coordinator",
"description": "A structured multi step conversational flow within an LLM chat application based on given chat Flow.'; ",
"icon": "/assets/web-browser.svg",
"isAuthRequired": "false",
"authConfig": []
},
{
"name": "Traversaal",
"pluginKey": "traversaal_search",
Expand Down
3 changes: 3 additions & 0 deletions api/app/clients/tools/util/handleTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const {
WolframAlphaAPI,
OpenAICreateImage,
StableDiffusionAPI,
// My tools
AgentCoordinator,
// Structured Tools
DALLE3,
E2BTools,
Expand Down Expand Up @@ -167,6 +169,7 @@ const loadTools = async ({
'azure-ai-search': functions ? StructuredACS : AzureAISearch,
CodeBrew: CodeBrew,
traversaal_search: TraversaalSearch,
'agent-coordinator': AgentCoordinator,
};

const openAIApiKey = await getOpenAIKey(options, user);
Expand Down