Skip to content

Commit

Permalink
Merge branch 'main' into kb
Browse files Browse the repository at this point in the history
  • Loading branch information
md-abid-hussain authored Nov 27, 2024
2 parents df8cb02 + cfbcfeb commit d550414
Show file tree
Hide file tree
Showing 10 changed files with 746 additions and 0 deletions.
97 changes: 97 additions & 0 deletions src/agents/agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import Constants from '../constants';
import { MindsDbError } from '../errors';
import AgentCompletion from './agentCompletion';
import AgentsRestApiClient from './agentsRestApiClient';

/**
* Represents an agent in MindsDB.
*/
export default class Agent {
/** Project name to which agent belongs to */
project: string;

/** Agent name */
name: string;
/** Model name */
model: string;
/** Skills of the agent */
skills: Array<string>;
/** Additional parameters */
params: any;
/** Rest API client to use for executing agent operations */
agentsRestApiClient: AgentsRestApiClient;

/**
* Creates a new agent.
*
* @param {string} project - Project name to which agent belongs to
* @param {string} name - Agent name
* @param {string} model - Model name
* @param {Array<string>} skills - Skills of the agent
* @param {any} params - Additional parameters
* @param {AgentsRestApiClient} agentsRestApiClient - Rest API client to use for executing agent operations
*/
constructor(
project: string,
name: string,
model: string,
skills: Array<string>,
params: any,
agentsRestApiClient: AgentsRestApiClient
) {
this.project = project;
this.name = name;
this.model = model;
this.skills = skills;
this.params = params;
this.agentsRestApiClient = agentsRestApiClient;
}

/**
* Creates an agent from a JSON object.
*
* @param {string} project - Project name to which agent belongs to
* @param {any} json - JSON object representing the agent
* @param {AgentsRestApiClient} agentsRestApiClient - Rest API client to use for executing agent operations
* @returns {Agent} - The created agent
*/
static fromJson(
project: string,
json: any,
agentsRestApiClient: AgentsRestApiClient
): Agent {
return new Agent(
project,
json.name,
json.model,
json.skills.map((skill: any) => skill.name),
json.params || {},
agentsRestApiClient
);
}

/**
* Gets the agent completion.
*
* @param {Array<any>} messages - Messages to send to the agent
* @returns {Promise<AgentCompletion>} - The agent completion
*/
async completion(messages: Array<any>): Promise<AgentCompletion> {
const baseUrl =
this.agentsRestApiClient.client.defaults.baseURL ||
Constants.BASE_CLOUD_API_ENDPOINT;
const agentsUrl = `${baseUrl}${Constants.BASE_PROJECTS_URI}/${this.project}/agents/${this.name}/completions`;

try {
const response = await this.agentsRestApiClient.client.post(agentsUrl, {
messages: messages,
});

const content: string = response.data.message.content;
const context: Array<string> = response.data.message.context || [];
return new AgentCompletion(content, context);
} catch (error) {
throw MindsDbError.fromHttpError(error, agentsUrl);
}
}
}
24 changes: 24 additions & 0 deletions src/agents/agentCompletion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Represents the completion of an agent with content and context.
*/
export default class AgentCompletion {
/**
* The content of the agent completion.
*/
content: string;

/**
* The context in which the agent completion is made.
*/
context: Array<string>;

/**
* Creates an instance of AgentCompletion.
* @param {string} content - The content of the agent completion.
* @param {Array<string>} context - The context in which the agent completion is made.
*/
constructor(content: string, context: Array<string>) {
this.content = content;
this.context = context;
}
}
72 changes: 72 additions & 0 deletions src/agents/agentsApiClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Agent from './agent';

/**
* Abstract class representing the API client for managing agents.
*/
export default abstract class AgentsApiClient {
/**
* Retrieves all agents for a given project.
* @param {string} project - The name of the project.
* @throws {MindsDbError} If the agents cannot be retrieved.
* @returns {Promise<Array<Agent>>} A promise that resolves to an array of agents.
*/
abstract getAllAgents(project: string): Promise<Array<Agent>>;

/**
* Retrieves a specific agent by its ID.
* @param {string} project - The name of the project.
* @param {string} agentId - The ID of the agent.
* @throws {MindsDbError} If the agent does not exist.
* @returns {Promise<Agent>} A promise that resolves to the agent.
*/
abstract getAgent(project: string, agentId: string): Promise<Agent>;

/**
* Creates a new agent.
* @param {string} project - The name of the project.
* @param {string} name - The name of the agent.
* @param {string} model - The model of the agent.
* @param {string} provider - The provider of the agent.
* @param {Array<string>} skills - An array of skills for the agent.
* @param {any} [params] - Optional parameters for the agent.
* @throws {MindsDbError} If the agent cannot be created.
* @returns {Promise<Agent>} A promise that resolves to the created agent.
*/
abstract createAgent(
project: string,
name: string,
model: string,
provider: string,
skills: Array<string>,
params?: any
): Promise<Agent>;

/**
* Updates an existing agent.
* @param {string} project - The name of the project.
* @param {string} agentName - The current name of the agent.
* @param {string} [updatedName] - The new name of the agent (optional).
* @param {string} [updatedModel] - The new model of the agent (optional).
* @param {Array<string>} [updatedSkills] - An array of updated skills for the agent (optional).
* @param {any} [updatedParams] - Optional updated parameters for the agent.
* @throws {MindsDbError} If the agent cannot be updated.
* @returns {Promise<Agent>} A promise that resolves to the updated agent.
*/
abstract updateAgent(
project: string,
agentName: string,
updatedName?: string,
updatedModel?: string,
updatedSkills?: Array<string>,
updatedParams?: any
): Promise<Agent>;

/**
* Deletes an agent.
* @param {string} project - The name of the project.
* @param {string} agent - The name of the agent to delete.
* @throws {MindsDbError} If the agent cannot be deleted.
* @returns {Promise<void>} A promise that resolves when the agent is deleted.
*/
abstract deleteAgent(project: string, agent: string): Promise<void>;
}
3 changes: 3 additions & 0 deletions src/agents/agentsModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import AgentsRestApiClient from './agentsRestApiClient';

export default { AgentsRestApiClient };
198 changes: 198 additions & 0 deletions src/agents/agentsRestApiClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
import { Axios } from 'axios';
import Constants from '../constants';
import { MindsDbError } from '../errors';
import Agent from './agent';
import AgentsApiClient from './agentsApiClient';

const DEFAULT_LLM_PROMPT =
"Answer the user's question in a helpful way: {{question}}";
const DEFAULT_LLM_MODEL = 'gpt-4o';

/** Implementation of AgentsApiClient that goes through the REST API */
export default class AgentsRestApiClient extends AgentsApiClient {
/** Axios client to use for making HTTP requests */
client: Axios;

/**
* Creates a new AgentsRestApiClient.
*
* @param {Axios} client - Axios client to use for making HTTP requests
*/
constructor(client: Axios) {
super();
this.client = client;
}

private getAgentsUrl(project: string): string {
const baseUrl =
this.client.defaults.baseURL || Constants.BASE_CLOUD_API_ENDPOINT;
const agentsUrl = `${baseUrl}${Constants.BASE_PROJECTS_URI}/${project}/agents`;
return agentsUrl;
}

/**
* Retrieves all agents for a given project.
*
* @param project Project name to which agent belongs to
* @returns {Promise<Array<Agent>>} A promise that resolves to an array of agents.
*/
override async getAllAgents(project: string): Promise<Array<Agent>> {
const agentsUrl = this.getAgentsUrl(project);
try {
const agentsResponse = await this.client.get(agentsUrl);
if (!agentsResponse.data) {
return [];
}
return agentsResponse.data.map((agent: any) =>
Agent.fromJson(project, agent, this)
);
} catch (error) {
throw MindsDbError.fromHttpError(error, agentsUrl);
}
}

/**
* Retrieves a specific agent by its name.
*
* @param {string} project Project name to which agent belongs to
* @param {string} agent Agent name to retrieve
* @returns {Promise<Agent>} A promise that resolves to the agent.
*/
override async getAgent(project: string, agent: string): Promise<Agent> {
const agentsUrl = this.getAgentsUrl(project) + `/${agent}`;
try {
const agentResponse = await this.client.get(agentsUrl);
return Agent.fromJson(project, agentResponse.data, this);
} catch (error) {
throw MindsDbError.fromHttpError(error, agentsUrl);
}
}

/**
* Creates a new agent.
*
* @param {string} project Project name to which agent belongs to
* @param {string} name Agent name to create
* @param {string} [model] Model to use for the agent
* @param {string} [provider] Provider to use for the agent
* @param {Array<string>} [skills] Skills to assign to the agent
* @param {any} [params] Additional parameters for the agent
* @returns {Promise<Agent>} A promise that resolves to the created agent.
*/
override async createAgent(
project: string,
name: string,
model?: string,
provider?: string,
skills?: Array<string>,
params?: any
): Promise<Agent> {
const agentsUrl = this.getAgentsUrl(project);

try {
const agentsParams: any = params ? { ...params } : {};
if (!agentsParams.hasOwnProperty('prompt_template')) {
agentsParams['prompt_template'] = DEFAULT_LLM_PROMPT;
}

const agent: {
name: string;
model_name?: string;
skills?: Array<string>;
params?: any;
provider?: string | null;
} = {
name: name,
model_name: model || DEFAULT_LLM_MODEL,
skills: skills || [],
provider: provider || null,
params: agentsParams,
};

const agentResponse = await this.client.post(agentsUrl, { agent });

return Agent.fromJson(project, agentResponse.data, this);
} catch (error) {
throw MindsDbError.fromHttpError(error, agentsUrl);
}
}

/**
* Updates an existing agent.
*
* @param {string} project Project name to which agent belongs to
* @param {string} agentName Name of the agent to update
* @param {string} [updatedName] New name for the agent
* @param {string} [updatedModel] New model for the agent
* @param {Array<string>} [updatedSkills] New skills for the agent
* @param {any} [updatedParams] New parameters for the agent
* @returns {Promise<Agent>} A promise that resolves to the updated agent.
*/
override async updateAgent(
project: string,
agentName: string,
updatedName?: string,
updatedModel?: string,
updatedSkills?: Array<string>,
updatedParams?: any
): Promise<Agent> {
const agentsUrl = this.getAgentsUrl(project) + `/${agentName}`;
try {
const agent = await this.getAgent(project, agentName);
const updatedSkillSet = new Set<string>();
if (updatedSkills) {
updatedSkills?.forEach((skill) => updatedSkillSet.add(skill));
}
const existingSkillSet = new Set<string>(agent.skills);
const skillsToAddSet = new Set<string>(updatedSkillSet);
existingSkillSet.forEach((skill) => {
if (skillsToAddSet.has(skill)) {
skillsToAddSet.delete(skill);
}
});
const skillsToRemoveSet = new Set<string>(existingSkillSet);
updatedSkillSet.forEach((skill) => {
if (skillsToRemoveSet.has(skill)) {
skillsToRemoveSet.delete(skill);
}
});

const updatedAgent: {
name: string;
model_name: string;
skills_to_add: Array<string>;
skills_to_remove: Array<string>;
params: any;
} = {
name: updatedName || agent.name,
model_name: updatedModel || agent.model,
skills_to_add: Array.from(skillsToAddSet),
skills_to_remove: Array.from(skillsToRemoveSet),
params: updatedParams || agent.params,
};

const agentResponse = await this.client.put(agentsUrl, {
agent: updatedAgent,
});

return Agent.fromJson(project, agentResponse.data, this);
} catch (error) {
throw MindsDbError.fromHttpError(error, agentsUrl);
}
}

/**
* Deletes a specific agent by its name.
*
* @param {string} project Project name to which agent belongs to
* @param {string} agent Agent name to delete
*/
override async deleteAgent(project: string, agent: string): Promise<void> {
const agentsUrl = this.getAgentsUrl(project) + `/${agent}`;
try {
await this.client.delete(agentsUrl);
} catch (error) {
throw MindsDbError.fromHttpError(error, agentsUrl);
}
}
}
Loading

0 comments on commit d550414

Please sign in to comment.