Feat - Agent chat tab (#13061)
Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Marie <51697796+ijreilly@users.noreply.github.com> Co-authored-by: Antoine Moreaux <moreaux.antoine@gmail.com> Co-authored-by: Raphaël Bosi <71827178+bosiraphael@users.noreply.github.com>
This commit is contained in:
@ -1,8 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { createAnthropic } from '@ai-sdk/anthropic';
|
||||
import { createOpenAI } from '@ai-sdk/openai';
|
||||
import { generateObject, generateText } from 'ai';
|
||||
import { CoreMessage, generateObject, generateText, streamText } from 'ai';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
ModelId,
|
||||
@ -10,6 +12,10 @@ import {
|
||||
} from 'src/engine/core-modules/ai/constants/ai-models.const';
|
||||
import { getAIModelById } from 'src/engine/core-modules/ai/utils/get-ai-model-by-id';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import {
|
||||
AgentChatMessageEntity,
|
||||
AgentChatMessageRole,
|
||||
} from 'src/engine/metadata-modules/agent/agent-chat-message.entity';
|
||||
import { AgentToolService } from 'src/engine/metadata-modules/agent/agent-tool.service';
|
||||
import { AGENT_CONFIG } from 'src/engine/metadata-modules/agent/constants/agent-config.const';
|
||||
import { AGENT_SYSTEM_PROMPTS } from 'src/engine/metadata-modules/agent/constants/agent-system-prompts.const';
|
||||
@ -37,9 +43,13 @@ export class AgentExecutionService {
|
||||
constructor(
|
||||
private readonly twentyConfigService: TwentyConfigService,
|
||||
private readonly agentToolService: AgentToolService,
|
||||
@InjectRepository(AgentEntity, 'core')
|
||||
private readonly agentRepository: Repository<AgentEntity>,
|
||||
@InjectRepository(AgentChatMessageEntity, 'core')
|
||||
private readonly agentChatmessageRepository: Repository<AgentChatMessageEntity>,
|
||||
) {}
|
||||
|
||||
private getModel = (modelId: ModelId, provider: ModelProvider) => {
|
||||
getModel = (modelId: ModelId, provider: ModelProvider) => {
|
||||
switch (provider) {
|
||||
case ModelProvider.OPENAI: {
|
||||
const OpenAIProvider = createOpenAI({
|
||||
@ -79,7 +89,6 @@ export class AgentExecutionService {
|
||||
AgentExceptionCode.AGENT_EXECUTION_FAILED,
|
||||
);
|
||||
}
|
||||
|
||||
if (!apiKey) {
|
||||
throw new AgentException(
|
||||
`${provider.toUpperCase()} API key not configured`,
|
||||
@ -88,6 +97,76 @@ export class AgentExecutionService {
|
||||
}
|
||||
}
|
||||
|
||||
async prepareAIRequestConfig({
|
||||
messages,
|
||||
prompt,
|
||||
system,
|
||||
agent,
|
||||
}: {
|
||||
system: string;
|
||||
agent: AgentEntity;
|
||||
prompt?: string;
|
||||
messages?: CoreMessage[];
|
||||
}) {
|
||||
const aiModel = getAIModelById(agent.modelId);
|
||||
|
||||
if (!aiModel) {
|
||||
throw new AgentException(
|
||||
`AI model with id ${agent.modelId} not found`,
|
||||
AgentExceptionCode.AGENT_EXECUTION_FAILED,
|
||||
);
|
||||
}
|
||||
const provider = aiModel.provider;
|
||||
|
||||
await this.validateApiKey(provider);
|
||||
|
||||
const tools = await this.agentToolService.generateToolsForAgent(
|
||||
agent.id,
|
||||
agent.workspaceId,
|
||||
);
|
||||
|
||||
return {
|
||||
system,
|
||||
tools,
|
||||
model: this.getModel(agent.modelId, aiModel.provider),
|
||||
...(messages && { messages }),
|
||||
...(prompt && { prompt }),
|
||||
maxSteps: AGENT_CONFIG.MAX_STEPS,
|
||||
};
|
||||
}
|
||||
|
||||
async streamChatResponse({
|
||||
agentId,
|
||||
userMessage,
|
||||
messages,
|
||||
}: {
|
||||
agentId: string;
|
||||
userMessage: string;
|
||||
messages: AgentChatMessageEntity[];
|
||||
}) {
|
||||
const agent = await this.agentRepository.findOneOrFail({
|
||||
where: { id: agentId },
|
||||
});
|
||||
|
||||
const llmMessages: CoreMessage[] = messages.map(({ role, content }) => ({
|
||||
role,
|
||||
content,
|
||||
}));
|
||||
|
||||
llmMessages.push({
|
||||
role: AgentChatMessageRole.USER,
|
||||
content: userMessage,
|
||||
});
|
||||
|
||||
const aiRequestConfig = await this.prepareAIRequestConfig({
|
||||
system: `${AGENT_SYSTEM_PROMPTS.AGENT_CHAT}\n\n${agent.prompt}`,
|
||||
agent,
|
||||
messages: llmMessages,
|
||||
});
|
||||
|
||||
return streamText(aiRequestConfig);
|
||||
}
|
||||
|
||||
async executeAgent({
|
||||
agent,
|
||||
context,
|
||||
@ -98,31 +177,12 @@ export class AgentExecutionService {
|
||||
schema: OutputSchema;
|
||||
}): Promise<AgentExecutionResult> {
|
||||
try {
|
||||
const aiModel = getAIModelById(agent.modelId);
|
||||
|
||||
if (!aiModel) {
|
||||
throw new AgentException(
|
||||
`AI model with id ${agent.modelId} not found`,
|
||||
AgentExceptionCode.AGENT_EXECUTION_FAILED,
|
||||
);
|
||||
}
|
||||
|
||||
const provider = aiModel.provider;
|
||||
|
||||
await this.validateApiKey(provider);
|
||||
|
||||
const tools = await this.agentToolService.generateToolsForAgent(
|
||||
agent.id,
|
||||
agent.workspaceId,
|
||||
);
|
||||
|
||||
const textResponse = await generateText({
|
||||
const aiRequestConfig = await this.prepareAIRequestConfig({
|
||||
system: AGENT_SYSTEM_PROMPTS.AGENT_EXECUTION,
|
||||
model: this.getModel(agent.modelId, provider),
|
||||
agent,
|
||||
prompt: resolveInput(agent.prompt, context) as string,
|
||||
tools,
|
||||
maxSteps: AGENT_CONFIG.MAX_STEPS,
|
||||
});
|
||||
const textResponse = await generateText(aiRequestConfig);
|
||||
|
||||
if (Object.keys(schema).length === 0) {
|
||||
return {
|
||||
@ -130,10 +190,9 @@ export class AgentExecutionService {
|
||||
usage: textResponse.usage,
|
||||
};
|
||||
}
|
||||
|
||||
const output = await generateObject({
|
||||
system: AGENT_SYSTEM_PROMPTS.OUTPUT_GENERATOR,
|
||||
model: this.getModel(agent.modelId, provider),
|
||||
model: aiRequestConfig.model,
|
||||
prompt: `Based on the following execution results, generate the structured output according to the schema:
|
||||
|
||||
Execution Results: ${textResponse.text}
|
||||
@ -163,7 +222,6 @@ export class AgentExecutionService {
|
||||
if (error instanceof AgentException) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw new AgentException(
|
||||
error instanceof Error ? error.message : 'Agent execution failed',
|
||||
AgentExceptionCode.AGENT_EXECUTION_FAILED,
|
||||
|
||||
Reference in New Issue
Block a user