feat(pricing/ai): improve billing metered pricing + add pricing on ai chat (#14092)
## TODO: - [x] display "yearly" or "monthly" wording everywhere it's needed - [ ] Add button with "downgrade" or "upgrade" to save the change of credits price + modal to validate - [x] Add renewal date - [ ] Implement https://docs.stripe.com/billing/subscriptions/subscription-schedules for `switchFromYearlyToMonthly` and decrease number of credits
This commit is contained in:
+12
-62
@@ -7,8 +7,6 @@ import {
|
||||
type CoreMessage,
|
||||
type CoreUserMessage,
|
||||
type FilePart,
|
||||
generateObject,
|
||||
generateText,
|
||||
type ImagePart,
|
||||
streamText,
|
||||
ToolSet,
|
||||
@@ -30,11 +28,10 @@ import { AgentHandoffToolService } from 'src/engine/metadata-modules/agent/agent
|
||||
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';
|
||||
import { type RecordIdsByObjectMetadataNameSingularType } from 'src/engine/metadata-modules/agent/types/recordIdsByObjectMetadataNameSingular.type';
|
||||
import { convertOutputSchemaToZod } from 'src/engine/metadata-modules/agent/utils/convert-output-schema-to-zod';
|
||||
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { type OutputSchema } from 'src/modules/workflow/workflow-builder/workflow-schema/types/output-schema.type';
|
||||
import { streamToBuffer } from 'src/utils/stream-to-buffer';
|
||||
import { AIBillingService } from 'src/engine/core-modules/ai/services/ai-billing.service';
|
||||
|
||||
import { AgentToolGeneratorService } from './agent-tool-generator.service';
|
||||
import { AgentEntity } from './agent.entity';
|
||||
@@ -61,6 +58,7 @@ export class AgentExecutionService {
|
||||
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
|
||||
private readonly aiModelRegistryService: AiModelRegistryService,
|
||||
private readonly agentToolGeneratorService: AgentToolGeneratorService,
|
||||
private readonly aiBillingService: AIBillingService,
|
||||
@InjectRepository(AgentEntity)
|
||||
private readonly agentRepository: Repository<AgentEntity>,
|
||||
@InjectRepository(FileEntity)
|
||||
@@ -301,66 +299,18 @@ export class AgentExecutionService {
|
||||
`Sending request to AI model with ${llmMessages.length} messages`,
|
||||
);
|
||||
|
||||
return streamText(aiRequestConfig);
|
||||
}
|
||||
const model = await this.aiModelRegistryService.resolveModelForAgent(agent);
|
||||
|
||||
async executeAgent({
|
||||
agent,
|
||||
schema,
|
||||
userPrompt,
|
||||
}: {
|
||||
agent: AgentEntity | null;
|
||||
context: Record<string, unknown>;
|
||||
schema: OutputSchema;
|
||||
userPrompt: string;
|
||||
}): Promise<AgentExecutionResult> {
|
||||
try {
|
||||
const aiRequestConfig = await this.prepareAIRequestConfig({
|
||||
system: `You are executing as part of a workflow automation. ${agent ? agent.prompt : ''}`,
|
||||
agent,
|
||||
prompt: userPrompt,
|
||||
});
|
||||
const textResponse = await generateText(aiRequestConfig);
|
||||
const stream = streamText(aiRequestConfig);
|
||||
|
||||
if (Object.keys(schema).length === 0) {
|
||||
return {
|
||||
result: { response: textResponse.text },
|
||||
usage: textResponse.usage,
|
||||
};
|
||||
}
|
||||
const output = await generateObject({
|
||||
system: AGENT_SYSTEM_PROMPTS.OUTPUT_GENERATOR,
|
||||
model: aiRequestConfig.model,
|
||||
prompt: `Based on the following execution results, generate the structured output according to the schema:
|
||||
|
||||
Execution Results: ${textResponse.text}
|
||||
|
||||
Please generate the structured output based on the execution results and context above.`,
|
||||
schema: convertOutputSchemaToZod(schema),
|
||||
});
|
||||
|
||||
return {
|
||||
result: output.object,
|
||||
usage: {
|
||||
promptTokens:
|
||||
(textResponse.usage?.promptTokens ?? 0) +
|
||||
(output.usage?.promptTokens ?? 0),
|
||||
completionTokens:
|
||||
(textResponse.usage?.completionTokens ?? 0) +
|
||||
(output.usage?.completionTokens ?? 0),
|
||||
totalTokens:
|
||||
(textResponse.usage?.totalTokens ?? 0) +
|
||||
(output.usage?.totalTokens ?? 0),
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof AgentException) {
|
||||
throw error;
|
||||
}
|
||||
throw new AgentException(
|
||||
error instanceof Error ? error.message : 'Agent execution failed',
|
||||
AgentExceptionCode.AGENT_EXECUTION_FAILED,
|
||||
stream.usage.then((usage) => {
|
||||
this.aiBillingService.calculateAndBillUsage(
|
||||
model.modelId,
|
||||
usage,
|
||||
workspace.id,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user