import { randomUUID } from 'node:crypto'; import { LifecycleScope } from '#/app/scopes'; import { ScopeActivation, registerScopedService } from '#/_base/di/scope'; import { IEventService } from '#/app/event/event'; import { ErrorCodes, Error2 } from '#/errors'; import { IAgentScopeContext } from '#/agent/scopeContext/scopeContext'; import { MAIN_AGENT_ID } from '#/session/agentLifecycle/agentLifecycle'; import { expandCommandArguments } from '#/app/plugin/commands'; import { IPluginService } from '#/app/plugin/plugin'; import { IAgentLoopService } from '#/agent/loop/loop'; import { promptMetadataTextFromText } from '#/agent/prompt/promptMetadataText'; import { ISessionMetadata } from '#/session/sessionMetadata/sessionMetadata'; import { ISessionContext } from '#/session/sessionContext/sessionContext'; import { applyPromptMetadataUpdate } from '#/session/sessionMetadata/promptMetadata'; import { IEventDispatcher } from '#/state/eventDispatcher'; import { IAgentPluginCommandService, PluginCommandActivated, type ActivatePluginCommandPayload, } from './pluginCommand'; export class AgentPluginCommandService implements IAgentPluginCommandService { declare readonly _serviceBrand: undefined; constructor( @IPluginService private readonly plugins: IPluginService, @IAgentLoopService private readonly loop: IAgentLoopService, @IEventDispatcher private readonly dispatcher: IEventDispatcher, @ISessionMetadata private readonly metadata: ISessionMetadata, @IEventService private readonly eventService: IEventService, @ISessionContext private readonly sessionContext: ISessionContext, @IAgentScopeContext private readonly scopeContext: IAgentScopeContext, ) { } async activate(payload: ActivatePluginCommandPayload): Promise { const commands = await this.plugins.listPluginCommands(); const def = commands.find( (command) => command.pluginId === payload.pluginId && command.name === payload.commandName, ); if (def === undefined) { throw new Error2( ErrorCodes.REQUEST_INVALID, `Plugin command "${payload.pluginId}:${payload.commandName}" was not found`, ); } const commandArgs = payload.args ?? ''; const expanded = expandCommandArguments(def.body, commandArgs); const origin = { kind: 'plugin_command' as const, activationId: randomUUID(), pluginId: payload.pluginId, commandName: payload.commandName, commandArgs: payload.args, trigger: 'user-slash' as const, }; await this.dispatcher.dispatch( new PluginCommandActivated({ agentId: this.scopeContext.agentId, activationId: origin.activationId, pluginId: origin.pluginId, commandName: origin.commandName, commandArgs: origin.commandArgs, trigger: origin.trigger, }), ); this.loop.submit({ message: { role: 'user', content: [{ type: 'text', text: expanded }] }, meta: { origin, tracked: true }, }); if (this.scopeContext.agentId === MAIN_AGENT_ID) { await applyPromptMetadataUpdate( { metadata: this.metadata, eventService: this.eventService, sessionId: this.sessionContext.sessionId, }, promptMetadataTextFromPluginCommand(payload), ); } } } function promptMetadataTextFromPluginCommand( payload: ActivatePluginCommandPayload, ): string | undefined { const args = payload.args?.trim(); const command = `/${payload.pluginId}:${payload.commandName}`; return promptMetadataTextFromText( args === undefined || args.length === 0 ? command : `${command} ${args}`, ); } registerScopedService( LifecycleScope.Agent, IAgentPluginCommandService, AgentPluginCommandService, ScopeActivation.OnScopeCreated, 'pluginCommand', );