Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 5 additions & 86 deletions src/common/agents/toolRuleGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,81 +1,8 @@
/**
* System prompt builder utilities
* Provides consistent system prompt and environment context formatting for both renderer and main processes
*/

import { ToolState } from '../../types/agent-chat'
import { isMcpTool } from '../../types/tools'
import { IToolDescriptionProvider } from './toolDescriptionProvider'

/**
* Static class for building system prompts and environment contexts
* Provides functional cohesion for all prompt-related generation functionality
*/
export class SystemPromptBuilder {
/**
* Generate tool usage rules based on enabled tools
*/
private static async generateToolRules(
enabledTools: ToolState[],
descriptionProvider: IToolDescriptionProvider
): Promise<string> {
if (
!enabledTools ||
enabledTools.length === 0 ||
enabledTools.filter((tool) => tool.enabled).length === 0
) {
return `**<tool usage rules>**No tools are currently enabled for this agent.**</tool usage rules>**`
}

// Filter active tools
const activeTools = enabledTools.filter((tool) => tool.enabled)

let rulesContent = '\n**<tool usage rules>**\n'
rulesContent += 'Available tools and their usage:\n\n'

// Separate tools into built-in and MCP categories
const builtInTools: ToolState[] = []
const mcpTools: ToolState[] = []

activeTools.forEach((tool) => {
const toolName = tool.toolSpec?.name || 'unknown'
if (isMcpTool(toolName)) {
mcpTools.push(tool)
} else {
builtInTools.push(tool)
}
})

// Add built-in tool descriptions individually
for (const tool of builtInTools) {
const toolName = tool.toolSpec?.name || 'unknown'
const displayName = toolName
const description = await descriptionProvider.getToolDescription(toolName)

rulesContent += `**${displayName}**\n${description}\n\n`
}

// Add MCP tools as a grouped block
if (mcpTools.length > 0) {
const mcpToolNames = mcpTools.map((tool) => tool.toolSpec?.name || 'unknown')
rulesContent += `**MCP Tools**\n`
rulesContent += `Available MCP tools: ${mcpToolNames.join(', ')}\n`
rulesContent += `External tools with specific functionality.\n`
rulesContent += `Refer to tool documentation for usage.\n\n`
}

// Add general guidelines
rulesContent += 'General guidelines:\n'
rulesContent += '- Use tools one at a time and wait for results\n'
rulesContent += '- Always use absolute paths starting from {{projectPath}}\n'
rulesContent += '- Request permission for destructive operations\n'
rulesContent += '- Handle errors gracefully with clear explanations\n\n'

rulesContent += '**</tool usage rules>**'

return rulesContent
}

/**
* Generate basic environment context sections
*/
Expand Down Expand Up @@ -142,15 +69,11 @@ If you are acting as a voice chat, please ignore this illustration rule.
/**
* Generate complete environment context with all sections
*/
static async generateEnvironmentContext(
enabledTools: ToolState[],
descriptionProvider: IToolDescriptionProvider,
contextSettings?: {
todoListInstruction?: boolean
projectRule?: boolean
visualExpressionRules?: boolean
}
): Promise<string> {
static async generateEnvironmentContext(contextSettings?: {
todoListInstruction?: boolean
projectRule?: boolean
visualExpressionRules?: boolean
}): Promise<string> {
// Default settings (all enabled)
const defaultSettings = {
todoListInstruction: true,
Expand All @@ -175,10 +98,6 @@ If you are acting as a voice chat, please ignore this illustration rule.
context += this.generateTodoListInstruction()
}

// Always add tool rules
const toolRules = await this.generateToolRules(enabledTools, descriptionProvider)
context += toolRules

return context
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { ToolInput, ToolName, ToolResult } from '../../../../../types/tools'
import { agentHandlers } from '../../../../handlers/agent-handlers'
import { CustomAgent, ToolState, EnvironmentContextSettings } from '../../../../../types/agent-chat'
import { pubSubManager } from '../../../../lib/pubsub-manager'
import { MainToolDescriptionProvider } from './MainToolDescriptionProvider'
import { MainToolSpecProvider } from './MainToolSpecProvider'
import { v4 as uuidv4 } from 'uuid'
import { BrowserWindow, ipcMain } from 'electron'
Expand All @@ -40,8 +39,7 @@ export class BackgroundAgentService {
) => void
// キャッシュポイント追跡用マップ(セッションID → キャッシュポイント位置)
private cachePointMap: Map<string, number | undefined> = new Map()
// 動的ツール説明プロバイダー
private toolDescriptionProvider: MainToolDescriptionProvider

// ツール仕様プロバイダー
private toolSpecProvider: MainToolSpecProvider

Expand All @@ -50,7 +48,6 @@ export class BackgroundAgentService {
this.bedrockService = new BedrockService(context)
this.sessionManager = new BackgroundChatSessionManager()

this.toolDescriptionProvider = new MainToolDescriptionProvider()
this.toolSpecProvider = new MainToolSpecProvider()

logger.info('BackgroundAgentService initialized (using persistent sessions)')
Expand Down Expand Up @@ -135,10 +132,26 @@ export class BackgroundAgentService {
* エージェント固有のツール設定からToolStateを生成
* IPC経由でpreloadツール仕様を取得
*/
private async generateToolSpecs(toolNames: ToolName[]): Promise<ToolState[]> {
private async generateToolSpecs(
toolNames: ToolName[],
agent: CustomAgent,
projectDirectory?: string
): Promise<ToolState[]> {
try {
const toolStates: ToolState[] = []

// プレースホルダー値を準備
const workingDirectory = projectDirectory || this.context.store.get('projectPath') || ''
const placeholderValues = {
projectPath: workingDirectory,
allowedCommands: agent.allowedCommands || [],
allowedWindows: agent.allowedWindows || [],
allowedCameras: agent.allowedCameras || [],
knowledgeBases: agent.knowledgeBases || [],
bedrockAgents: agent.bedrockAgents || [],
flows: agent.flows || []
}

// IPC経由でpreloadツール仕様を取得
const allToolSpecs = await this.toolSpecProvider.getPreloadToolSpecs()

Expand All @@ -149,7 +162,13 @@ export class BackgroundAgentService {
if (toolSpec && toolSpec.toolSpec) {
const toolState: ToolState = {
enabled: true,
toolSpec: toolSpec.toolSpec
toolSpec: {
...toolSpec.toolSpec,
description: replacePlaceholders(
toolSpec.toolSpec.description || '',
placeholderValues
)
}
}
toolStates.push(toolState)
logger.debug('Found preload tool spec', { toolName })
Expand All @@ -162,7 +181,7 @@ export class BackgroundAgentService {
enabled: true,
toolSpec: {
name: toolName,
description: `${toolName} tool`,
description: replacePlaceholders(`${toolName} tool`, placeholderValues),
inputSchema: {
json: {
type: 'object',
Expand Down Expand Up @@ -197,31 +216,19 @@ export class BackgroundAgentService {
* 環境コンテキストを生成する
*/
private async getEnvironmentContext(
enabledTools: ToolState[],
contextSettings?: EnvironmentContextSettings
): Promise<string> {
return await SystemPromptBuilder.generateEnvironmentContext(
enabledTools,
this.toolDescriptionProvider,
contextSettings
)
return await SystemPromptBuilder.generateEnvironmentContext(contextSettings)
}

/**
* エージェントのシステムプロンプトを構築する
*/
private async buildSystemPrompt(
agent: CustomAgent,
toolStates: ToolState[],
projectDirectory?: string
): Promise<string> {
private async buildSystemPrompt(agent: CustomAgent, projectDirectory?: string): Promise<string> {
if (!agent.system) return ''

// 環境コンテキストを生成
const environmentContext = await this.getEnvironmentContext(
toolStates,
agent.environmentContextSettings
)
const environmentContext = await this.getEnvironmentContext(agent.environmentContextSettings)

// システムプロンプトと環境コンテキストを結合
const fullPrompt = agent.system + '\n\n' + environmentContext
Expand Down Expand Up @@ -257,7 +264,11 @@ export class BackgroundAgentService {
}

// エージェント固有のツール設定を生成
const toolStates = await this.generateToolSpecs(agent.tools || [])
const toolStates = await this.generateToolSpecs(
agent.tools || [],
agent,
config.projectDirectory
)

// セッション履歴を取得
const conversationHistory = this.sessionManager.getHistory(sessionId)
Expand Down Expand Up @@ -321,7 +332,7 @@ export class BackgroundAgentService {
}

// エージェントのシステムプロンプトを構築(環境コンテキスト+プレースホルダー置換)
const systemPrompt = await this.buildSystemPrompt(agent, toolStates, config.projectDirectory)
const systemPrompt = await this.buildSystemPrompt(agent, config.projectDirectory)
const system = systemPrompt ? [{ text: systemPrompt }] : []

logger.debug('System prompt built', {
Expand Down Expand Up @@ -856,18 +867,14 @@ export class BackgroundAgentService {
throw new Error(`Agent not found: ${task.agentId}`)
}

// エージェント固有のツール設定を生成
const toolStates = await this.generateToolSpecs(agent.tools || [])

// システムプロンプトを構築(プレースホルダー置換済み)
const systemPrompt = await this.buildSystemPrompt(agent, toolStates, task.projectDirectory)
const systemPrompt = await this.buildSystemPrompt(agent, task.projectDirectory)

logger.debug('Task system prompt generated', {
taskId,
agentId: task.agentId,
agentName: agent.name,
systemPromptLength: systemPrompt.length,
toolCount: toolStates.length
systemPromptLength: systemPrompt.length
})

return systemPrompt
Expand Down

This file was deleted.

3 changes: 0 additions & 3 deletions src/preload/tools/handlers/bedrock/CheckVideoStatusTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,6 @@ export class CheckVideoStatusTool extends BaseTool<CheckVideoStatusInput, CheckV
/**
* System prompt description
*/
static readonly systemPromptDescription =
'Check video generation status using invocation ARN.\nUse this tool to monitor progress of video generation jobs.\nWhen status is "Completed", you can use downloadVideo to download the video.'

/**
* Validate input
*/
Expand Down
3 changes: 0 additions & 3 deletions src/preload/tools/handlers/bedrock/DownloadVideoTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@ export class DownloadVideoTool extends BaseTool<DownloadVideoInput, DownloadVide
/**
* System prompt description
*/
static readonly systemPromptDescription =
'Download completed video from S3 using invocation ARN.\nOnly use this tool when checkVideoStatus shows status as "Completed".\nAutomatically retrieves S3 location and downloads to specified or default local path.'

/**
* Validate input
*/
Expand Down
8 changes: 1 addition & 7 deletions src/preload/tools/handlers/bedrock/GenerateImageTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ interface GenerateImageResult extends ToolResult {
export class GenerateImageTool extends BaseTool<GenerateImageInput, GenerateImageResult> {
static readonly toolName = 'generateImage'
static readonly toolDescription =
'Generate an image using Amazon Bedrock Foundation Models. By default uses stability.sd3-5-large-v1:0. Images are saved to the specified path. For Titan models, specific aspect ratios and sizes are supported.'
'Generate an image using Amazon Bedrock Foundation Models. By default uses stability.sd3-5-large-v1:0. Images are saved to the specified path. For Titan models, specific aspect ratios and sizes are supported.\n\nGenerate images using AI models. Always ask user permission before creating images.'

readonly name = GenerateImageTool.toolName
readonly description = GenerateImageTool.toolDescription
Expand Down Expand Up @@ -118,12 +118,6 @@ export class GenerateImageTool extends BaseTool<GenerateImageInput, GenerateImag
}
} as const

/**
* System prompt description
*/
static readonly systemPromptDescription =
'Generate images using AI models.\nAlways ask user permission before creating images.'

/**
* Validate input
*/
Expand Down
3 changes: 0 additions & 3 deletions src/preload/tools/handlers/bedrock/GenerateVideoTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,6 @@ export class GenerateVideoTool extends BaseTool<GenerateVideoInput, GenerateVide
/**
* System prompt description
*/
static readonly systemPromptDescription =
'Generate video using Amazon Nova Reel AI model (non-blocking).\nSupports Text-to-Video and Image-to-Video generation.\n\nModes:\n- TEXT_VIDEO (6s): Text only or single image input\n- MULTI_SHOT_AUTOMATED (12-120s): Text only, multiple shots\n- MULTI_SHOT_MANUAL (12-120s): Multiple images with individual prompts\n\nImage requirements: 1280x720 resolution, PNG/JPEG format.\nRequires S3 configuration in tool settings.\nReturns immediately with job ARN for status tracking.\nUse checkVideoStatus to monitor progress and downloadVideo when completed.'

/**
* Validate input
*/
Expand Down
8 changes: 1 addition & 7 deletions src/preload/tools/handlers/bedrock/InvokeBedrockAgentTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class InvokeBedrockAgentTool extends BaseTool<
> {
static readonly toolName = 'invokeBedrockAgent'
static readonly toolDescription =
'Invoke an Amazon Bedrock Agent using the specified agent ID and alias ID. Use this when you need to interact with an agent.'
'Invoke an Amazon Bedrock Agent using the specified agent ID and alias ID. Use this when you need to interact with an agent.\n\nInteract with AWS Bedrock agents. Only use Bedrock Agents from allowed list: {{bedrockAgents}}'

readonly name = InvokeBedrockAgentTool.toolName
readonly description = InvokeBedrockAgentTool.toolDescription
Expand Down Expand Up @@ -110,12 +110,6 @@ export class InvokeBedrockAgentTool extends BaseTool<
}
} as const

/**
* System prompt description
*/
static readonly systemPromptDescription =
'Interact with AWS Bedrock agents.\nOnly use Bedrock Agents from allowed list: {{bedrockAgents}}'

/**
* Validate input - matches legacy implementation
*/
Expand Down
Loading
Loading