From d0bcc684ef36939fa85b395e07bb59a84af9e64b Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Wed, 26 Nov 2025 15:27:25 +0800 Subject: [PATCH 1/2] refactor: more rename --- .../agentChatStore/actions/previewActions.ts | 4 +- .../__tests__/taskAgent.failure.test.ts | 2 +- .../__tests__/taskAgent.test.ts | 42 +++--- .../agentFrameworks/taskAgent.ts | 24 +-- .../agentFrameworks/taskAgents.json | 10 +- src/services/agentInstance/index.ts | 6 +- .../agentInstance/promptConcat/Readme.md | 10 +- .../promptConcat/promptConcat.ts | 53 +++---- .../promptConcat/promptConcatSchema/plugin.ts | 2 +- .../promptConcat/responseConcat.ts | 47 +++--- .../fullReplacementPlugin.duration.test.ts | 50 +++--- .../__tests__/messageManagementPlugin.test.ts | 38 ++--- .../__tests__/wikiOperationPlugin.test.ts | 142 +++++++++--------- .../tools/__tests__/wikiSearchPlugin.test.ts | 142 +++++++++--------- .../__tests__/workspacesListPlugin.test.ts | 50 +++--- src/services/agentInstance/tools/index.ts | 64 ++++---- .../agentInstance/tools/messageManagement.ts | 58 +++---- src/services/agentInstance/tools/prompt.ts | 46 +++--- .../agentInstance/tools/schemaRegistry.ts | 28 ++-- src/services/agentInstance/tools/types.ts | 8 +- .../agentInstance/tools/wikiOperation.ts | 60 ++++---- .../agentInstance/tools/wikiSearch.ts | 70 ++++----- .../agentInstance/tools/workspacesList.ts | 22 +-- 23 files changed, 491 insertions(+), 487 deletions(-) diff --git a/src/pages/Agent/store/agentChatStore/actions/previewActions.ts b/src/pages/Agent/store/agentChatStore/actions/previewActions.ts index 6f8fcaf6..03552caa 100644 --- a/src/pages/Agent/store/agentChatStore/actions/previewActions.ts +++ b/src/pages/Agent/store/agentChatStore/actions/previewActions.ts @@ -113,7 +113,7 @@ export const previewActionsMiddleware: StateCreator { // Update progress and current step const stepDescription = state.step === 'plugin' - ? `Processing plugin: ${state.currentPlugin?.pluginId || 'unknown'}` + ? `Processing tool: ${state.currentPlugin?.toolId || 'unknown'}` : state.step === 'finalize' ? 'Finalizing prompts...' : state.step === 'flatten' @@ -123,7 +123,7 @@ export const previewActionsMiddleware: StateCreator AI response -> tool execution -> next round * Includes yieldNextRoundTo mechanism testing with basicPromptConcatHandler @@ -30,7 +30,7 @@ let testStreamResponses: Array<{ status: string; content: string; requestId: str import type { IPromptConcatTool } from '@services/agentInstance/promptConcat/promptConcatSchema'; import type { IDatabaseService } from '@services/database/interface'; import { createAgentFrameworkHooks, createHooksWithTools, initializeToolSystem, PromptConcatHookContext } from '../../tools/index'; -import { wikiSearchPlugin } from '../../tools/wikiSearch'; +import { wikiSearchTool } from '../../tools/wikiSearch'; import { basicPromptConcatHandler } from '../taskAgent'; import type { AgentFrameworkContext } from '../utilities/type'; @@ -92,8 +92,8 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { const exampleAgent = defaultAgents[0]; const handlerConfig = exampleAgent.handlerConfig; - // Get the wiki search plugin configuration - const wikiPlugin = handlerConfig.plugins.find(p => p.pluginId === 'wikiSearch'); + // Get the wiki search tool configuration + const wikiPlugin = handlerConfig.plugins.find(p => p.toolId === 'wikiSearch'); expect(wikiPlugin).toBeDefined(); if (!wikiPlugin) throw new Error('wikiPlugin not found'); @@ -101,7 +101,7 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { // Phase 1: Tool List Injection const promptConcatHookContext: PromptConcatHookContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', messages: [], @@ -113,7 +113,7 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { agentDef: { id: exampleAgent.id, name: exampleAgent.name, handlerConfig: exampleAgent.handlerConfig }, isCancelled: () => false, }, - pluginConfig: wikiPlugin as IPromptConcatTool, + toolConfig: wikiPlugin as IPromptConcatTool, prompts, messages: [ { @@ -127,12 +127,12 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { ], }; - // Create hooks and register plugins as defined in handlerConfig + // Create hooks and register tools as defined in handlerConfig const { hooks: promptHooks } = await createHooksWithTools(handlerConfig); - // First run workspacesList plugin to inject available workspaces (if present) - const workspacesPlugin = handlerConfig.plugins?.find(p => p.pluginId === 'workspacesList'); + // First run workspacesList tool to inject available workspaces (if present) + const workspacesPlugin = handlerConfig.plugins?.find(p => p.toolId === 'workspacesList'); if (workspacesPlugin) { - const workspacesContext = { ...promptConcatHookContext, pluginConfig: workspacesPlugin } as unknown as PromptConcatHookContext; + const workspacesContext = { ...promptConcatHookContext, toolConfig: workspacesPlugin } as unknown as PromptConcatHookContext; await promptHooks.processPrompts.promise(workspacesContext); } // Then run wikiSearch plugin to inject the tool list @@ -169,7 +169,7 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { }; const responseContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -191,7 +191,7 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { }, requestId: 'test-request', isFinal: true, - pluginConfig: wikiPlugin as IPromptConcatTool, + toolConfig: wikiPlugin as IPromptConcatTool, prompts: [], messages: [], llmResponse: 'I will search for important content using wiki-search tool.', @@ -213,8 +213,8 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { expect(responseContext.actions.yieldNextRoundTo).toBe('self'); // Verify tool result message was added to agent history - expect(responseContext.handlerContext.agent.messages.length).toBeGreaterThan(0); - const toolResultMessage = responseContext.handlerContext.agent.messages[responseContext.handlerContext.agent.messages.length - 1] as AgentInstanceMessage; + expect(responseContext.agentFrameworkContext.agent.messages.length).toBeGreaterThan(0); + const toolResultMessage = responseContext.agentFrameworkContext.agent.messages[responseContext.agentFrameworkContext.agent.messages.length - 1] as AgentInstanceMessage; expect(toolResultMessage.role).toBe('tool'); // Tool result message expect(toolResultMessage.content).toContain(''); expect(toolResultMessage.content).toContain('Tool: wiki-search'); @@ -226,14 +226,14 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { const exampleAgent = defaultAgents[0]; const handlerConfig = exampleAgent.handlerConfig; - // Get the wiki search plugin configuration - const wikiPlugin = handlerConfig.plugins.find(p => p.pluginId === 'wikiSearch'); + // Get the wiki search tool configuration + const wikiPlugin = handlerConfig.plugins.find(p => p.toolId === 'wikiSearch'); expect(wikiPlugin).toBeDefined(); // Mock tool calling with invalid workspace const responseContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -255,7 +255,7 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { }, requestId: 'test-request', isFinal: true, - pluginConfig: wikiPlugin as IPromptConcatTool, + toolConfig: wikiPlugin as IPromptConcatTool, prompts: [], messages: [], llmResponse: 'Search in nonexistent wiki', @@ -267,7 +267,7 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { const responseHooks = createAgentFrameworkHooks(); // Register the plugin - wikiSearchPlugin(responseHooks); + wikiSearchTool(responseHooks); // Execute the response complete hook await responseHooks.responseComplete.promise(responseContext); @@ -276,8 +276,8 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { expect(responseContext.actions.yieldNextRoundTo).toBe('self'); // Verify error message was added to agent history - expect(responseContext.handlerContext.agent.messages.length).toBeGreaterThan(0); - const errorResultMessage = responseContext.handlerContext.agent.messages[responseContext.handlerContext.agent.messages.length - 1] as AgentInstanceMessage; + expect(responseContext.agentFrameworkContext.agent.messages.length).toBeGreaterThan(0); + const errorResultMessage = responseContext.agentFrameworkContext.agent.messages[responseContext.agentFrameworkContext.agent.messages.length - 1] as AgentInstanceMessage; expect(errorResultMessage.role).toBe('tool'); // Tool error message // The error should be indicated in the message content diff --git a/src/services/agentInstance/agentFrameworks/taskAgent.ts b/src/services/agentInstance/agentFrameworks/taskAgent.ts index 099eae73..76619606 100644 --- a/src/services/agentInstance/agentFrameworks/taskAgent.ts +++ b/src/services/agentInstance/agentFrameworks/taskAgent.ts @@ -32,7 +32,7 @@ export async function* basicPromptConcatHandler(context: AgentFrameworkContext) let currentRequestId: string | undefined; const lastUserMessage: AgentInstanceMessage | undefined = context.agent.messages[context.agent.messages.length - 1]; // Create and register handler hooks based on handler config - const { hooks: handlerHooks, pluginConfigs } = await createHooksWithTools(context.agentDef.handlerConfig || {}); + const { hooks: agentFrameworkHooks, toolConfigs } = await createHooksWithTools(context.agentDef.handlerConfig || {}); // Log the start of handler execution with context information logger.debug('Starting prompt handler execution', { @@ -48,8 +48,8 @@ export async function* basicPromptConcatHandler(context: AgentFrameworkContext) if (isNewUserMessage) { // Trigger user message received hook - await handlerHooks.userMessageReceived.promise({ - handlerContext: context, + await agentFrameworkHooks.userMessageReceived.promise({ + agentFrameworkContext: context, content: { text: lastUserMessage.content, file: lastUserMessage.metadata?.file as File | undefined, @@ -62,8 +62,8 @@ export async function* basicPromptConcatHandler(context: AgentFrameworkContext) lastUserMessage.metadata = { ...lastUserMessage.metadata, processed: true }; // Trigger agent status change to working - await handlerHooks.agentStatusChanged.promise({ - handlerContext: context, + await agentFrameworkHooks.agentStatusChanged.promise({ + agentFrameworkContext: context, status: { state: 'working', modified: new Date(), @@ -146,12 +146,12 @@ export async function* basicPromptConcatHandler(context: AgentFrameworkContext) if (response.status === 'update') { // For responseUpdate, we'll skip plugin-specific config for now // since it's called frequently during streaming - await handlerHooks.responseUpdate.promise({ - handlerContext: context, + await agentFrameworkHooks.responseUpdate.promise({ + agentFrameworkContext: context, response, requestId: currentRequestId, isFinal: false, - pluginConfig: {} as IPromptConcatTool, // Empty config for streaming updates + toolConfig: {} as IPromptConcatTool, // Empty config for streaming updates }); } @@ -164,16 +164,16 @@ export async function* basicPromptConcatHandler(context: AgentFrameworkContext) // Delegate final response processing to handler hooks const responseCompleteContext = { - handlerContext: context, + agentFrameworkContext: context, response, requestId: currentRequestId, isFinal: true, - pluginConfig: (pluginConfigs.length > 0 ? pluginConfigs[0] : {}) as IPromptConcatTool, // First config for compatibility - handlerConfig: context.agentDef.handlerConfig, // Pass complete config for plugin access + toolConfig: (toolConfigs.length > 0 ? toolConfigs[0] : {}) as IPromptConcatTool, // First config for compatibility + agentFrameworkConfig: context.agentDef.handlerConfig, // Pass complete config for tool access actions: undefined as { yieldNextRoundTo?: 'self' | 'human'; newUserMessage?: string } | undefined, }; - await handlerHooks.responseComplete.promise(responseCompleteContext); + await agentFrameworkHooks.responseComplete.promise(responseCompleteContext); // Check if responseComplete hooks set yieldNextRoundTo let yieldNextRoundFromHooks: YieldNextRoundTarget | undefined; diff --git a/src/services/agentInstance/agentFrameworks/taskAgents.json b/src/services/agentInstance/agentFrameworks/taskAgents.json index 5f102d80..0b39485f 100644 --- a/src/services/agentInstance/agentFrameworks/taskAgents.json +++ b/src/services/agentInstance/agentFrameworks/taskAgents.json @@ -72,7 +72,7 @@ "plugins": [ { "id": "efe5be74-540d-487d-8a05-7377e486953d", - "pluginId": "fullReplacement", + "toolId": "fullReplacement", "fullReplacementParam": { "targetId": "default-history", "sourceType": "historyOfSession" @@ -84,7 +84,7 @@ "id": "f0e1b2c3-4d5e-6f7g-8h9i-j0k1l2m3n4o5", "caption": "Wiki工作空间列表", "description": "自动在提示词中注入可用的Wiki工作空间列表", - "pluginId": "workspacesList", + "toolId": "workspacesList", "workspacesListParam": { "targetId": "default-before-tool", "position": "after" @@ -94,7 +94,7 @@ "id": "d0f1b2c3-4d5e-6f7g-8h9i-j0k1l2m3n4o5", "caption": "Wiki搜索和向量索引工具", "description": "提供Wiki搜索(filter和vector)以及向量嵌入索引管理功能", - "pluginId": "wikiSearch", + "toolId": "wikiSearch", "wikiSearchParam": { "sourceType": "wiki", "toolListPosition": { @@ -107,7 +107,7 @@ "id": "e1f2b3c4-5d6e-7f8g-9h0i-k1l2m3n4o5p6", "caption": "Wiki操作工具", "description": "允许AI在Wiki工作空间中创建、更新和删除笔记", - "pluginId": "wikiOperation", + "toolId": "wikiOperation", "wikiOperationParam": { "toolListPosition": { "position": "after", @@ -117,7 +117,7 @@ }, { "id": "a0f1b2c3-4d5e-6f7g-8h9i-j0k1l2m3n4o5", - "pluginId": "fullReplacement", + "toolId": "fullReplacement", "fullReplacementParam": { "targetId": "default-response", "sourceType": "llmResponse" diff --git a/src/services/agentInstance/index.ts b/src/services/agentInstance/index.ts index d1329831..c9e5bfee 100644 --- a/src/services/agentInstance/index.ts +++ b/src/services/agentInstance/index.ts @@ -384,7 +384,7 @@ export class AgentInstanceService implements IAgentInstanceService { // Trigger userMessageReceived hook with the configured tools await frameworkHooks.userMessageReceived.promise({ - handlerContext: frameworkContext, + agentFrameworkContext: frameworkContext, content, messageId, timestamp: now, @@ -443,7 +443,7 @@ export class AgentInstanceService implements IAgentInstanceService { // Trigger agentStatusChanged hook for completion await frameworkHooks.agentStatusChanged.promise({ - handlerContext: frameworkContext, + agentFrameworkContext: frameworkContext, status: { state: 'completed', modified: new Date(), @@ -459,7 +459,7 @@ export class AgentInstanceService implements IAgentInstanceService { // Trigger agentStatusChanged hook for failure await frameworkHooks.agentStatusChanged.promise({ - handlerContext: frameworkContext, + agentFrameworkContext: frameworkContext, status: { state: 'failed', modified: new Date(), diff --git a/src/services/agentInstance/promptConcat/Readme.md b/src/services/agentInstance/promptConcat/Readme.md index 39950c3d..9d720cb0 100644 --- a/src/services/agentInstance/promptConcat/Readme.md +++ b/src/services/agentInstance/promptConcat/Readme.md @@ -2,11 +2,11 @@ Prompt engineering and message processing with a plugin-based architecture. -If final prompt is a food, then `handlerConfig.prompts` is the recipe. Chat history and user input are raw materials. +If final prompt is a food, then `agentFrameworkConfig.prompts` is the recipe. Chat history and user input are raw materials. ## Implementation -The `promptConcat` function uses a tapable hooks-based plugin system. Built-in plugins are registered by `pluginId` and loaded based on configuration in `taskAgents.json`. +The `promptConcat` function uses a tapable hooks-based plugin system. Built-in tools are registered by `toolId` and loaded based on configuration in `taskAgents.json`. ### Plugin System Architecture @@ -23,13 +23,13 @@ The `promptConcat` function uses a tapable hooks-based plugin system. Built-in p - `toolCalling`: Processes function calls in responses 3. **Plugin Registration**: - - Plugins are registered by `pluginId` field in the `plugins` array + - Plugins are registered by `toolId` field in the `plugins` array - Each plugin instance has its own configuration parameters - Built-in plugins are auto-registered on system initialization ### Plugin Lifecycle -2. **Configuration**: Plugins are loaded based on `handlerConfig.plugins` array +2. **Configuration**: Plugins are loaded based on `agentFrameworkConfig.plugins` array 3. **Execution**: Hooks execute plugins in registration order 4. **Error Handling**: Individual plugin failures don't stop the pipeline @@ -37,7 +37,7 @@ The `promptConcat` function uses a tapable hooks-based plugin system. Built-in p 1. Create plugin function in `plugins/` directory 2. Register in `plugins/index.ts` -3. Add `pluginId` to schema enum +3. Add `toolId` to schema enum 4. Add parameter schema if needed Each plugin receives a hooks object and registers handlers for specific hook points. Plugins can modify prompt trees, inject content, process responses, and trigger additional LLM calls. diff --git a/src/services/agentInstance/promptConcat/promptConcat.ts b/src/services/agentInstance/promptConcat/promptConcat.ts index 13e8285c..cbb15705 100644 --- a/src/services/agentInstance/promptConcat/promptConcat.ts +++ b/src/services/agentInstance/promptConcat/promptConcat.ts @@ -10,7 +10,7 @@ * Main Concepts: * - Prompts are tree-structured, can have roles (system/user/assistant) and children. * - Plugins use hooks to modify the prompt tree at runtime. - * - Built-in plugins are registered by pluginId and executed when matching plugins are found. + * - Built-in tools are registered by toolId and executed when matching tools are found. */ import { logger } from '@services/libs/log'; @@ -205,38 +205,39 @@ export interface PromptConcatStreamState { export async function* promptConcatStream( agentConfig: Pick, messages: AgentInstanceMessage[], - handlerContext: AgentFrameworkContext, + agentFrameworkContext: AgentFrameworkContext, ): AsyncGenerator { - const promptConfigs = Array.isArray(agentConfig.handlerConfig.prompts) ? agentConfig.handlerConfig.prompts : []; - const pluginConfigs = (Array.isArray(agentConfig.handlerConfig.plugins) ? agentConfig.handlerConfig.plugins : []) as IPromptConcatTool[]; + const agentFrameworkConfig = agentConfig.handlerConfig; + const promptConfigs = Array.isArray(agentFrameworkConfig.prompts) ? agentFrameworkConfig.prompts : []; + const toolConfigs = (Array.isArray(agentFrameworkConfig.plugins) ? agentFrameworkConfig.plugins : []) as IPromptConcatTool[]; const promptsCopy = cloneDeep(promptConfigs); - const sourcePaths = generateSourcePaths(promptsCopy, pluginConfigs); + const sourcePaths = generateSourcePaths(promptsCopy, toolConfigs); const hooks = createAgentFrameworkHooks(); - // Register plugins that match the configuration - for (const plugin of pluginConfigs) { - const builtInPlugin = builtInTools.get(plugin.pluginId); - if (builtInPlugin) { - builtInPlugin(hooks); - logger.debug('Registered plugin', { - pluginId: plugin.pluginId, - pluginInstanceId: plugin.id, + // Register tools that match the configuration + for (const tool of toolConfigs) { + const builtInTool = builtInTools.get(tool.toolId); + if (builtInTool) { + builtInTool(hooks); + logger.debug('Registered tool', { + toolId: tool.toolId, + toolInstanceId: tool.id, }); } else { - logger.info(`No built-in plugin found for pluginId: ${plugin.pluginId}`); + logger.info(`No built-in tool found for toolId: ${tool.toolId}`); } } // Process each plugin through hooks with streaming let modifiedPrompts = promptsCopy; - const totalSteps = pluginConfigs.length + 2; // plugins + finalize + flatten + const totalSteps = toolConfigs.length + 2; // plugins + finalize + flatten - for (let index = 0; index < pluginConfigs.length; index++) { + for (let index = 0; index < toolConfigs.length; index++) { const context: PromptConcatHookContext = { - handlerContext, + agentFrameworkContext: agentFrameworkContext, messages, prompts: modifiedPrompts, - pluginConfig: pluginConfigs[index], + toolConfig: toolConfigs[index], metadata: { sourcePaths }, }; try { @@ -255,13 +256,13 @@ export async function* promptConcatStream( processedPrompts: modifiedPrompts, flatPrompts: intermediateFlat, step: 'plugin', - currentPlugin: pluginConfigs[index], + currentPlugin: toolConfigs[index], progress: (index + 1) / totalSteps, isComplete: false, }; } catch (error) { logger.error('Plugin processing error', { - pluginConfig: pluginConfigs[index], + toolConfig: toolConfigs[index], error, }); // Continue processing other plugins even if one fails @@ -273,15 +274,15 @@ export async function* promptConcatStream( processedPrompts: modifiedPrompts, flatPrompts: flattenPrompts(modifiedPrompts), step: 'finalize', - progress: (pluginConfigs.length + 1) / totalSteps, + progress: (toolConfigs.length + 1) / totalSteps, isComplete: false, }; const finalContext: PromptConcatHookContext = { - handlerContext, + agentFrameworkContext: agentFrameworkContext, messages, prompts: modifiedPrompts, - pluginConfig: {} as IPromptConcatTool, // Empty plugin for finalization + toolConfig: {} as IPromptConcatTool, // Empty plugin for finalization metadata: { sourcePaths }, }; @@ -297,7 +298,7 @@ export async function* promptConcatStream( processedPrompts: modifiedPrompts, flatPrompts: flattenPrompts(modifiedPrompts), step: 'flatten', - progress: (pluginConfigs.length + 2) / totalSteps, + progress: (toolConfigs.length + 2) / totalSteps, isComplete: false, }; @@ -343,13 +344,13 @@ export async function* promptConcatStream( export async function promptConcat( agentConfig: Pick, messages: AgentInstanceMessage[], - handlerContext: AgentFrameworkContext, + agentFrameworkContext: AgentFrameworkContext, ): Promise<{ flatPrompts: ModelMessage[]; processedPrompts: IPrompt[]; }> { // Use the streaming version and just return the final result - const stream = promptConcatStream(agentConfig, messages, handlerContext); + const stream = promptConcatStream(agentConfig, messages, agentFrameworkContext); let finalResult: PromptConcatStreamState; // Consume all intermediate states to get the final result diff --git a/src/services/agentInstance/promptConcat/promptConcatSchema/plugin.ts b/src/services/agentInstance/promptConcat/promptConcatSchema/plugin.ts index 651cc609..57d6c643 100644 --- a/src/services/agentInstance/promptConcat/promptConcatSchema/plugin.ts +++ b/src/services/agentInstance/promptConcat/promptConcatSchema/plugin.ts @@ -14,7 +14,7 @@ export type IPromptConcatTool = { caption?: string; content?: string; forbidOverrides?: boolean; - pluginId: string; + toolId: string; // Tool-specific parameters fullReplacementParam?: FullReplacementParameter; diff --git a/src/services/agentInstance/promptConcat/responseConcat.ts b/src/services/agentInstance/promptConcat/responseConcat.ts index d884c107..de1e886b 100644 --- a/src/services/agentInstance/promptConcat/responseConcat.ts +++ b/src/services/agentInstance/promptConcat/responseConcat.ts @@ -39,32 +39,33 @@ export async function responseConcat( }); const { handlerConfig } = agentConfig; - const responses: HandlerConfig['response'] = Array.isArray(handlerConfig.response) ? handlerConfig.response : []; - const plugins = (Array.isArray(handlerConfig.plugins) ? handlerConfig.plugins : []) as IPromptConcatTool[]; + const agentFrameworkConfig = handlerConfig; + const responses: HandlerConfig['response'] = Array.isArray(agentFrameworkConfig.response) ? agentFrameworkConfig.response : []; + const toolConfigs = (Array.isArray(agentFrameworkConfig.plugins) ? agentFrameworkConfig.plugins : []) as IPromptConcatTool[]; let modifiedResponses = cloneDeep(responses) as AgentResponse[]; // Create hooks instance const hooks = createAgentFrameworkHooks(); - // Register all plugins from configuration - for (const plugin of plugins) { - const builtInPlugin = builtInTools.get(plugin.pluginId); - if (builtInPlugin) { - builtInPlugin(hooks); + // Register all tools from configuration + for (const tool of toolConfigs) { + const builtInTool = builtInTools.get(tool.toolId); + if (builtInTool) { + builtInTool(hooks); } else { - logger.warn(`No built-in plugin found for response pluginId: ${plugin.pluginId}`); + logger.warn(`No built-in tool found for response toolId: ${tool.toolId}`); } } - // Process each plugin through hooks + // Process each tool through hooks let yieldNextRoundTo: YieldNextRoundTarget | undefined; let toolCallInfo: ToolCallingMatch | undefined; - for (const plugin of plugins) { + for (const tool of toolConfigs) { const responseContext: PostProcessContext = { - handlerContext: context, + agentFrameworkContext: context, messages, prompts: [], // Not used in response processing - pluginConfig: plugin, + toolConfig: tool, llmResponse, responses: modifiedResponses, metadata: {}, @@ -78,31 +79,31 @@ export async function responseConcat( modifiedResponses = result.responses; } - // Check if plugin indicated need for new LLM call via actions + // Check if tool indicated need for new LLM call via actions if (result.actions?.yieldNextRoundTo) { yieldNextRoundTo = result.actions.yieldNextRoundTo; if (result.actions.toolCalling) { toolCallInfo = result.actions.toolCalling; } - logger.debug('Plugin requested yield next round', { - pluginId: plugin.pluginId, - pluginInstanceId: plugin.id, + logger.debug('Tool requested yield next round', { + toolId: tool.toolId, + toolInstanceId: tool.id, yieldNextRoundTo, hasToolCall: !!result.actions.toolCalling, }); } - logger.debug('Response plugin processed successfully', { - pluginId: plugin.pluginId, - pluginInstanceId: plugin.id, + logger.debug('Response tool processed successfully', { + toolId: tool.toolId, + toolInstanceId: tool.id, }); } catch (error) { - logger.error('Response plugin processing error', { - pluginId: plugin.pluginId, - pluginInstanceId: plugin.id, + logger.error('Response tool processing error', { + toolId: tool.toolId, + toolInstanceId: tool.id, error, }); - // Continue processing other plugins even if one fails + // Continue processing other tools even if one fails } } diff --git a/src/services/agentInstance/tools/__tests__/fullReplacementPlugin.duration.test.ts b/src/services/agentInstance/tools/__tests__/fullReplacementPlugin.duration.test.ts index 7887e06b..ef4e78a5 100644 --- a/src/services/agentInstance/tools/__tests__/fullReplacementPlugin.duration.test.ts +++ b/src/services/agentInstance/tools/__tests__/fullReplacementPlugin.duration.test.ts @@ -1,4 +1,4 @@ -/** +/** * Tests for Full Replacement plugin duration mechanism * Tests that expired messages (with duration) are filtered out from AI context * Based on real configuration from taskAgents.json @@ -11,11 +11,11 @@ import type { IPrompt } from '../../promptConcat/promptConcatSchema/prompts'; import { cloneDeep } from 'lodash'; import defaultAgents from '../../agentFrameworks/taskAgents.json'; import { createAgentFrameworkHooks, PromptConcatHookContext } from '../index'; -import { fullReplacementPlugin } from '../prompt'; +import { fullReplacementTool } from '../prompt'; // Use the real agent config const exampleAgent = defaultAgents[0]; -const realHandlerConfig = exampleAgent.handlerConfig; +const realhandlerConfig = exampleAgent.handlerConfig; describe('Full Replacement Plugin - Duration Mechanism', () => { beforeEach(() => { @@ -25,14 +25,14 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { describe('History Source Type with Duration Filtering', () => { it('should filter out expired messages (duration=1) from historyOfSession', async () => { // Find the real fullReplacement plugin for history from taskAgents.json - const historyPlugin = realHandlerConfig.plugins.find( - p => p.pluginId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'historyOfSession', + const historyPlugin = realhandlerConfig.plugins.find( + p => p.toolId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'historyOfSession', ); expect(historyPlugin).toBeDefined(); expect(historyPlugin!.fullReplacementParam!.targetId).toBe('default-history'); // Real target ID // Use real prompts structure from taskAgents.json - const testPrompts = cloneDeep(realHandlerConfig.prompts) as IPrompt[]; + const testPrompts = cloneDeep(realhandlerConfig.prompts) as IPrompt[]; const messages: AgentInstanceMessage[] = [ // Message 0: User message, no duration - should be included @@ -96,7 +96,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { ]; const context: PromptConcatHookContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', messages, @@ -107,13 +107,13 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, isCancelled: () => false, }, - pluginConfig: historyPlugin! as unknown as IPromptConcatTool, // Type cast due to JSON import limitations + toolConfig: historyPlugin! as unknown as IPromptConcatTool, // Type cast due to JSON import limitations prompts: testPrompts, messages, }; const hooks = createAgentFrameworkHooks(); - fullReplacementPlugin(hooks); + fullReplacementTool(hooks); // Execute the processPrompts hook await hooks.processPrompts.promise(context); @@ -126,8 +126,8 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { const targetPrompt = historyPrompt!.children?.find(child => child.id === targetId); expect(targetPrompt).toBeDefined(); - // The fullReplacementPlugin puts filtered messages in children array - // Note: fullReplacementPlugin removes the last message (current user message) + // The fullReplacementTool puts filtered messages in children array + // Note: fullReplacementTool removes the last message (current user message) const children = (targetPrompt as unknown as { children?: IPrompt[] }).children || []; expect(children.length).toBe(2); // Only non-expired messages (user1, ai-response), excluding last user message @@ -147,8 +147,8 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { }); it('should include messages with duration=0 (visible in current round)', async () => { - const historyPlugin = realHandlerConfig.plugins.find( - p => p.pluginId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'historyOfSession', + const historyPlugin = realhandlerConfig.plugins.find( + p => p.toolId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'historyOfSession', ); const messages: AgentInstanceMessage[] = [ @@ -181,10 +181,10 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { }, ]; - const testPrompts = cloneDeep(realHandlerConfig.prompts) as IPrompt[]; + const testPrompts = cloneDeep(realhandlerConfig.prompts) as IPrompt[]; const context: PromptConcatHookContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', messages, @@ -195,13 +195,13 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, isCancelled: () => false, }, - pluginConfig: historyPlugin! as unknown as IPromptConcatTool, // Type cast for JSON import + toolConfig: historyPlugin! as unknown as IPromptConcatTool, // Type cast for JSON import prompts: testPrompts, messages, }; const hooks = createAgentFrameworkHooks(); - fullReplacementPlugin(hooks); + fullReplacementTool(hooks); await hooks.processPrompts.promise(context); @@ -220,8 +220,8 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { }); it('should handle mixed duration values correctly', async () => { - const historyPlugin = realHandlerConfig.plugins.find( - p => p.pluginId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'historyOfSession', + const historyPlugin = realhandlerConfig.plugins.find( + p => p.toolId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'historyOfSession', ); const messages: AgentInstanceMessage[] = [ @@ -263,10 +263,10 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { }, ]; - const testPrompts = cloneDeep(realHandlerConfig.prompts) as IPrompt[]; + const testPrompts = cloneDeep(realhandlerConfig.prompts) as IPrompt[]; const context: PromptConcatHookContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', messages, @@ -277,13 +277,13 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, isCancelled: () => false, }, - pluginConfig: historyPlugin! as unknown as IPromptConcatTool, // Type cast for JSON import + toolConfig: historyPlugin! as unknown as IPromptConcatTool, // Type cast for JSON import prompts: testPrompts, messages, }; const hooks = createAgentFrameworkHooks(); - fullReplacementPlugin(hooks); + fullReplacementTool(hooks); await hooks.processPrompts.promise(context); @@ -308,8 +308,8 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { describe('LLM Response Source Type', () => { it('should verify LLM response replacement config exists', () => { // Verify the real config has LLM response replacement - const llmResponsePlugin = realHandlerConfig.plugins.find( - p => p.pluginId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'llmResponse', + const llmResponsePlugin = realhandlerConfig.plugins.find( + p => p.toolId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'llmResponse', ); expect(llmResponsePlugin).toBeDefined(); expect(llmResponsePlugin!.fullReplacementParam!.targetId).toBe('default-response'); diff --git a/src/services/agentInstance/tools/__tests__/messageManagementPlugin.test.ts b/src/services/agentInstance/tools/__tests__/messageManagementPlugin.test.ts index 7987cd80..8bb292fa 100644 --- a/src/services/agentInstance/tools/__tests__/messageManagementPlugin.test.ts +++ b/src/services/agentInstance/tools/__tests__/messageManagementPlugin.test.ts @@ -1,5 +1,5 @@ -/** - * Deep integration tests for messageManagementPlugin with real SQLite database +/** + * Deep integration tests for messageManagementTool with real SQLite database * Tests actual message persistence scenarios using taskAgents.json configuration */ import { container } from '@services/container'; @@ -11,7 +11,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import defaultAgents from '../../agentFrameworks/taskAgents.json'; import type { AgentInstanceMessage, IAgentInstanceService } from '../../interface'; import { createAgentFrameworkHooks } from '../index'; -import { messageManagementPlugin } from '../messageManagement'; +import { messageManagementTool } from '../messageManagement'; import type { ToolExecutionContext, UserMessageContext } from '../types'; // Use the real agent config from taskAgents.json @@ -70,14 +70,14 @@ describe('Message Management Plugin - Real Database Integration', () => { // Initialize plugin hooks = createAgentFrameworkHooks(); - messageManagementPlugin(hooks); + messageManagementTool(hooks); }); afterEach(async () => { // Clean up is handled automatically by beforeEach for each test }); - const createHandlerContext = (messages: AgentInstanceMessage[] = []) => ({ + const createagentFrameworkContext = (messages: AgentInstanceMessage[] = []) => ({ agent: { id: testAgentId, agentDefId: exampleAgent.id, @@ -97,12 +97,12 @@ describe('Message Management Plugin - Real Database Integration', () => { describe('Real Wiki Search Scenario - The Missing Tool Result Bug', () => { it('should persist all messages in wiki search flow: user query → AI tool call → tool result → AI final response', async () => { - const handlerContext = createHandlerContext(); + const agentFrameworkContext = createagentFrameworkContext(); // Step 1: User asks to search wiki const userMessageId = `user-msg-${Date.now()}`; const userContext: UserMessageContext = { - handlerContext, + agentFrameworkContext, content: { text: '搜索 wiki 中的 Index 条目并解释' }, messageId: userMessageId, timestamp: new Date(), @@ -133,10 +133,10 @@ describe('Message Management Plugin - Real Database Integration', () => { }; await agentInstanceServiceImpl.saveUserMessage(aiToolCallMessage); - handlerContext.agent.messages.push(aiToolCallMessage); + agentFrameworkContext.agent.messages.push(aiToolCallMessage); // Step 3: Tool result message (THIS IS THE MISSING PIECE!) - // This simulates what wikiSearchPlugin does when tool execution completes + // This simulates what wikiSearchTool does when tool execution completes const toolResultMessage: AgentInstanceMessage = { id: `tool-result-${Date.now()}`, agentId: testAgentId, @@ -164,11 +164,11 @@ Result: 在wiki中找到了名为"Index"的条目。这个条目包含以下内 duration: 10, // Tool results might have expiration }; - // Add tool result to agent messages (simulating what wikiSearchPlugin does) - handlerContext.agent.messages.push(toolResultMessage); + // Add tool result to agent messages (simulating what wikiSearchTool does) + agentFrameworkContext.agent.messages.push(toolResultMessage); const toolContext: ToolExecutionContext = { - handlerContext, + agentFrameworkContext, toolResult: { success: true, data: 'Wiki search completed successfully', @@ -202,7 +202,7 @@ Result: 在wiki中找到了名为"Index"的条目。这个条目包含以下内 expect(savedToolResult?.duration).toBe(10); // Verify isPersisted flag was updated - const toolMessageInMemory = handlerContext.agent.messages.find( + const toolMessageInMemory = agentFrameworkContext.agent.messages.find( (m) => m.metadata?.isToolResult, ); expect(toolMessageInMemory?.metadata?.isPersisted).toBe(true); @@ -249,7 +249,7 @@ Result: 在wiki中找到了名为"Index"的条目。这个条目包含以下内 }); it('should handle multiple tool results in one execution', async () => { - const handlerContext = createHandlerContext(); + const agentFrameworkContext = createagentFrameworkContext(); // Add multiple tool result messages const toolResult1: AgentInstanceMessage = { @@ -282,10 +282,10 @@ Result: 在wiki中找到了名为"Index"的条目。这个条目包含以下内 duration: 3, }; - handlerContext.agent.messages.push(toolResult1, toolResult2); + agentFrameworkContext.agent.messages.push(toolResult1, toolResult2); const toolContext: ToolExecutionContext = { - handlerContext, + agentFrameworkContext, toolResult: { success: true, data: 'Multiple tool search completed', @@ -316,7 +316,7 @@ Result: 在wiki中找到了名为"Index"的条目。这个条目包含以下内 it('should maintain message integrity when reloading from database (simulating page refresh)', async () => { // This test simulates the issue where tool results are missing after page refresh - const handlerContext = createHandlerContext(); + const agentFrameworkContext = createagentFrameworkContext(); // Step 1: Complete chat flow with user message → AI tool call → tool result → AI response const userMessage: AgentInstanceMessage = { @@ -372,9 +372,9 @@ Result: 在wiki中找到了名为"Index"的条目。这个条目包含以下内 await agentInstanceServiceImpl.saveUserMessage(aiToolCallMessage); // Add tool result to context and trigger persistence via toolExecuted hook - handlerContext.agent.messages.push(toolResultMessage); + agentFrameworkContext.agent.messages.push(toolResultMessage); const toolContext: ToolExecutionContext = { - handlerContext, + agentFrameworkContext, toolResult: { success: true, data: 'Search completed' }, toolInfo: { toolId: 'wiki-search', parameters: {} }, }; diff --git a/src/services/agentInstance/tools/__tests__/wikiOperationPlugin.test.ts b/src/services/agentInstance/tools/__tests__/wikiOperationPlugin.test.ts index 33985378..bffa9353 100644 --- a/src/services/agentInstance/tools/__tests__/wikiOperationPlugin.test.ts +++ b/src/services/agentInstance/tools/__tests__/wikiOperationPlugin.test.ts @@ -1,5 +1,5 @@ -/** - * Tests for wikiOperationPlugin +/** + * Tests for wikiOperationTool */ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -19,8 +19,8 @@ import type { AgentFrameworkContext } from '../../agentFrameworks/utilities/type import type { AgentInstance } from '../../interface'; import { createAgentFrameworkHooks } from '../index'; import type { AIResponseContext, PromptConcatHookContext, ToolActions } from '../types'; -import { wikiOperationPlugin } from '../wikiOperation'; -import { workspacesListPlugin } from '../workspacesList'; +import { wikiOperationTool } from '../wikiOperation'; +import { workspacesListTool } from '../workspacesList'; // Mock i18n vi.mock('@services/libs/i18n', () => ({ @@ -50,8 +50,8 @@ vi.mock('@services/libs/i18n', () => ({ }, })); -// Helper to construct a complete AgentHandlerContext for tests -const makeHandlerContext = (agentId = 'test-agent'): AgentFrameworkContext => ({ +// Helper to construct a complete AgentagentFrameworkContext for tests +const makeagentFrameworkContext = (agentId = 'test-agent'): AgentFrameworkContext => ({ agent: { id: agentId, agentDefId: 'test-agent-def', @@ -63,7 +63,7 @@ const makeHandlerContext = (agentId = 'test-agent'): AgentFrameworkContext => ({ isCancelled: () => false, }); -describe('wikiOperationPlugin', () => { +describe('wikiOperationTool', () => { beforeEach(async () => { vi.clearAllMocks(); }); @@ -74,11 +74,11 @@ describe('wikiOperationPlugin', () => { it('should inject wiki operation tool content when plugin is configured', async () => { const hooks = createAgentFrameworkHooks(); - // First register workspacesListPlugin to inject available workspaces from the global mock - workspacesListPlugin(hooks); - wikiOperationPlugin(hooks); + // First register workspacesListTool to inject available workspaces from the global mock + workspacesListTool(hooks); + wikiOperationTool(hooks); - // Start with prompts and run workspacesList injection first (pluginConfig for workspacesList) + // Start with prompts and run workspacesList injection first (toolConfig for workspacesList) const prompts: IPrompt[] = [ { id: 'target-prompt', @@ -88,18 +88,18 @@ describe('wikiOperationPlugin', () => { ]; const workspacesContext: PromptConcatHookContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', messages: [], agentDefId: 'test', status: { state: 'working' as const, modified: new Date() }, created: new Date() }, agentDef: { id: 'test', name: 'test', handlerConfig: {} }, isCancelled: () => false, }, messages: [], prompts, - pluginConfig: { + toolConfig: { id: 'workspaces-plugin', caption: 'Workspaces Plugin', forbidOverrides: false, - pluginId: 'workspacesList', + toolId: 'workspacesList', workspacesListParam: { targetId: 'target-prompt', position: 'after' as const, @@ -111,12 +111,12 @@ describe('wikiOperationPlugin', () => { // Then run wikiOperation injection which will append its tool content to the same prompt const wikiOpContext: PromptConcatHookContext = { - handlerContext: workspacesContext.handlerContext, + agentFrameworkContext: workspacesContext.agentFrameworkContext, messages: [], prompts, - pluginConfig: { + toolConfig: { id: 'test-plugin', - pluginId: 'wikiOperation', + toolId: 'wikiOperation', wikiOperationParam: { toolListPosition: { targetId: 'target-prompt', @@ -129,7 +129,7 @@ describe('wikiOperationPlugin', () => { await hooks.processPrompts.promise(wikiOpContext); const targetPrompt = prompts[0]; - // workspacesListPlugin and wikiOperationPlugin may both add children; assert the combined children text contains expected snippets + // workspacesListTool and wikiOperationTool may both add children; assert the combined children text contains expected snippets const childrenText = JSON.stringify(targetPrompt.children); expect(childrenText).toContain('wiki-operation'); // Ensure the injected tool content documents the supported operations (enum values) @@ -148,16 +148,16 @@ describe('wikiOperationPlugin', () => { describe('tool execution', () => { it('should execute create operation successfully', async () => { const hooks = createAgentFrameworkHooks(); - wikiOperationPlugin(hooks); + wikiOperationTool(hooks); - const handlerContext = makeHandlerContext(); + const agentFrameworkContext = makeagentFrameworkContext(); const context = { - handlerContext, - handlerConfig: { + agentFrameworkContext, + agentFrameworkConfig: { plugins: [ { - pluginId: 'wikiOperation', + toolId: 'wikiOperation', wikiOperationParam: { toolResultDuration: 1, }, @@ -183,9 +183,9 @@ describe('wikiOperationPlugin', () => { context.response.content = `${JSON.stringify(createParams)}`; // Add an assistant message containing the tool_use so the plugin can find it - handlerContext.agent.messages.push({ + agentFrameworkContext.agent.messages.push({ id: `m-${Date.now()}`, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, role: 'assistant', content: context.response.content, modified: new Date(), @@ -209,9 +209,9 @@ describe('wikiOperationPlugin', () => { expect(typeof wikiSvc.wikiOperationInServer).toBe('function'); const responseCtx: AIResponseContext = { - handlerContext, - pluginConfig: context.handlerConfig?.plugins?.[0] as unknown as IPromptConcatTool, - handlerConfig: context.handlerConfig as { plugins?: Array<{ pluginId: string; [key: string]: unknown }> }, + agentFrameworkContext, + toolConfig: context.agentFrameworkConfig?.plugins?.[0] as unknown as IPromptConcatTool, + agentFrameworkConfig: context.agentFrameworkConfig as { plugins?: Array<{ toolId: string; [key: string]: unknown }> }, response: { requestId: 'r-create', content: context.response.content, status: 'done' } as AIStreamResponse, requestId: 'r-create', isFinal: true, @@ -227,7 +227,7 @@ describe('wikiOperationPlugin', () => { ); // Verify a tool result message was added to agent history - const toolResultMessage = handlerContext.agent.messages.find(m => m.metadata?.isToolResult); + const toolResultMessage = agentFrameworkContext.agent.messages.find(m => m.metadata?.isToolResult); expect(toolResultMessage).toBeTruthy(); expect(toolResultMessage?.content).toContain(''); // Check for general success wording and tiddler title @@ -239,14 +239,14 @@ describe('wikiOperationPlugin', () => { it('should execute update operation successfully', async () => { const hooks = createAgentFrameworkHooks(); - wikiOperationPlugin(hooks); + wikiOperationTool(hooks); - const handlerContext = makeHandlerContext(); + const agentFrameworkContext = makeagentFrameworkContext(); const context = { - handlerContext, - handlerConfig: { - plugins: [{ pluginId: 'wikiOperation', wikiOperationParam: {} }], + agentFrameworkContext, + agentFrameworkConfig: { + plugins: [{ toolId: 'wikiOperation', wikiOperationParam: {} }], }, response: { status: 'done' as const, @@ -256,9 +256,9 @@ describe('wikiOperationPlugin', () => { }; // Add assistant message so plugin can detect the tool call - handlerContext.agent.messages.push({ + agentFrameworkContext.agent.messages.push({ id: `m-${Date.now()}`, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, role: 'assistant', content: context.response.content, modified: new Date(), @@ -274,9 +274,9 @@ describe('wikiOperationPlugin', () => { context.response.content = `${JSON.stringify(updateParams)}`; const respCtx2: AIResponseContext = { - handlerContext, - pluginConfig: context.handlerConfig?.plugins?.[0] as unknown as IPromptConcatTool, - handlerConfig: context.handlerConfig as { plugins?: Array<{ pluginId: string; [key: string]: unknown }> }, + agentFrameworkContext, + toolConfig: context.agentFrameworkConfig?.plugins?.[0] as unknown as IPromptConcatTool, + agentFrameworkConfig: context.agentFrameworkConfig as { plugins?: Array<{ toolId: string; [key: string]: unknown }> }, response: { requestId: 'r-update', content: context.response.content, status: 'done' } as AIStreamResponse, actions: {} as ToolActions, requestId: 'r-update', @@ -291,7 +291,7 @@ describe('wikiOperationPlugin', () => { ); // Check general update success wording and tiddler title - const updateResult = handlerContext.agent.messages.find(m => m.metadata?.isToolResult); + const updateResult = agentFrameworkContext.agent.messages.find(m => m.metadata?.isToolResult); expect(updateResult).toBeTruthy(); expect(updateResult?.content).toContain('成功在Wiki工作空间'); expect(updateResult?.content).toContain('Existing Note'); @@ -299,14 +299,14 @@ describe('wikiOperationPlugin', () => { it('should execute delete operation successfully', async () => { const hooks = createAgentFrameworkHooks(); - wikiOperationPlugin(hooks); + wikiOperationTool(hooks); - const handlerContext = makeHandlerContext(); + const agentFrameworkContext = makeagentFrameworkContext(); const context = { - handlerContext, - handlerConfig: { - plugins: [{ pluginId: 'wikiOperation', wikiOperationParam: {} }], + agentFrameworkContext, + agentFrameworkConfig: { + plugins: [{ toolId: 'wikiOperation', wikiOperationParam: {} }], }, response: { status: 'done' as const, @@ -316,9 +316,9 @@ describe('wikiOperationPlugin', () => { }; // Add assistant message so plugin can detect the tool call - handlerContext.agent.messages.push({ + agentFrameworkContext.agent.messages.push({ id: `m-${Date.now()}`, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, role: 'assistant', content: context.response.content, modified: new Date(), @@ -333,9 +333,9 @@ describe('wikiOperationPlugin', () => { context.response.content = `${JSON.stringify(deleteParams)}`; const respCtx3: AIResponseContext = { - handlerContext, - pluginConfig: context.handlerConfig?.plugins?.[0] as unknown as IPromptConcatTool, - handlerConfig: context.handlerConfig as { plugins?: Array<{ pluginId: string; [key: string]: unknown }> }, + agentFrameworkContext, + toolConfig: context.agentFrameworkConfig?.plugins?.[0] as unknown as IPromptConcatTool, + agentFrameworkConfig: context.agentFrameworkConfig as { plugins?: Array<{ toolId: string; [key: string]: unknown }> }, response: { requestId: 'r-delete', content: context.response.content, status: 'done' } as AIStreamResponse, actions: {} as ToolActions, requestId: 'r-delete', @@ -349,22 +349,22 @@ describe('wikiOperationPlugin', () => { ['Note to Delete'], ); - const deleteResult = handlerContext.agent.messages.find(m => m.metadata?.isToolResult); + const deleteResult = agentFrameworkContext.agent.messages.find(m => m.metadata?.isToolResult); expect(deleteResult).toBeTruthy(); expect(deleteResult?.content).toContain('成功从Wiki工作空间'); }); it('should handle workspace not found error', async () => { const hooks = createAgentFrameworkHooks(); - wikiOperationPlugin(hooks); + wikiOperationTool(hooks); // Use an actual tool_use payload with a nonexistent workspace - const handlerContext = makeHandlerContext(); + const agentFrameworkContext = makeagentFrameworkContext(); const context = { - handlerContext, - handlerConfig: { - plugins: [{ pluginId: 'wikiOperation', wikiOperationParam: {} }], + agentFrameworkContext, + agentFrameworkConfig: { + plugins: [{ toolId: 'wikiOperation', wikiOperationParam: {} }], }, response: { status: 'done', @@ -374,9 +374,9 @@ describe('wikiOperationPlugin', () => { }; // Add assistant message so plugin can detect the tool call - handlerContext.agent.messages.push({ + agentFrameworkContext.agent.messages.push({ id: `m-${Date.now()}`, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, role: 'assistant', content: context.response.content, modified: new Date(), @@ -390,9 +390,9 @@ describe('wikiOperationPlugin', () => { context.response.content = `${JSON.stringify(badParams)}`; const respCtx4: AIResponseContext = { - handlerContext, - pluginConfig: context.handlerConfig?.plugins?.[0] as unknown as IPromptConcatTool, - handlerConfig: context.handlerConfig as { plugins?: Array<{ pluginId: string; [key: string]: unknown }> }, + agentFrameworkContext, + toolConfig: context.agentFrameworkConfig?.plugins?.[0] as unknown as IPromptConcatTool, + agentFrameworkConfig: context.agentFrameworkConfig as { plugins?: Array<{ toolId: string; [key: string]: unknown }> }, response: { requestId: 'r-error', content: context.response.content, status: 'done' } as AIStreamResponse, actions: {} as ToolActions, requestId: 'r-error', @@ -400,7 +400,7 @@ describe('wikiOperationPlugin', () => { }; await hooks.responseComplete.promise(respCtx4); - const errResult = handlerContext.agent.messages.find(m => m.metadata?.isToolResult); + const errResult = agentFrameworkContext.agent.messages.find(m => m.metadata?.isToolResult); expect(errResult).toBeTruthy(); expect(errResult?.content).toContain('工作空间名称或ID'); // Ensure control is yielded to self on error so AI gets the next round @@ -409,16 +409,16 @@ describe('wikiOperationPlugin', () => { it('should not execute when tool call is not found', async () => { const hooks = createAgentFrameworkHooks(); - wikiOperationPlugin(hooks); + wikiOperationTool(hooks); // No tool_use in response - const handlerContext = makeHandlerContext(); + const agentFrameworkContext = makeagentFrameworkContext(); const context = { - handlerContext, - handlerConfig: { - plugins: [{ pluginId: 'wikiOperation', wikiOperationParam: {} }], + agentFrameworkContext, + agentFrameworkConfig: { + plugins: [{ toolId: 'wikiOperation', wikiOperationParam: {} }], }, response: { status: 'done' as const, @@ -428,9 +428,9 @@ describe('wikiOperationPlugin', () => { }; await hooks.responseComplete.promise({ - handlerContext, - pluginConfig: context.handlerConfig?.plugins?.[0] as unknown as IPromptConcatTool, - handlerConfig: context.handlerConfig as { plugins?: Array<{ pluginId: string; [key: string]: unknown }> }, + agentFrameworkContext, + toolConfig: context.agentFrameworkConfig?.plugins?.[0] as unknown as IPromptConcatTool, + agentFrameworkConfig: context.agentFrameworkConfig as { plugins?: Array<{ toolId: string; [key: string]: unknown }> }, response: { requestId: 'r-none', content: context.response.content, status: 'done' } as AIStreamResponse, actions: {} as ToolActions, requestId: 'r-none', @@ -439,7 +439,7 @@ describe('wikiOperationPlugin', () => { const wikiLocalAssert = container.get>(serviceIdentifier.Wiki); expect(wikiLocalAssert.wikiOperationInServer).not.toHaveBeenCalled(); - expect(handlerContext.agent.messages).toHaveLength(0); + expect(agentFrameworkContext.agent.messages).toHaveLength(0); }); }); }); diff --git a/src/services/agentInstance/tools/__tests__/wikiSearchPlugin.test.ts b/src/services/agentInstance/tools/__tests__/wikiSearchPlugin.test.ts index ecd1c4a9..c8cc5358 100644 --- a/src/services/agentInstance/tools/__tests__/wikiSearchPlugin.test.ts +++ b/src/services/agentInstance/tools/__tests__/wikiSearchPlugin.test.ts @@ -1,4 +1,4 @@ -/** +/** * Comprehensive tests for Wiki Search plugin * Covers tool list injection, tool execution, duration mechanism, message persistence, and integration scenarios */ @@ -20,8 +20,8 @@ import type { IPromptConcatTool } from '@services/agentInstance/promptConcat/pro import { cloneDeep } from 'lodash'; import defaultAgents from '../../agentFrameworks/taskAgents.json'; import { createAgentFrameworkHooks, PromptConcatHookContext } from '../index'; -import { messageManagementPlugin } from '../messageManagement'; -import { wikiSearchPlugin } from '../wikiSearch'; +import { messageManagementTool } from '../messageManagement'; +import { wikiSearchTool } from '../wikiSearch'; // Mock i18n vi.mock('@services/libs/i18n', () => ({ @@ -77,7 +77,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { it('should inject wiki tools into prompts when configured', async () => { // Find the wiki search plugin config, make sure our default config - const wikiPlugin = handlerConfig.plugins.find((p: unknown): p is IPromptConcatTool => (p as IPromptConcatTool).pluginId === 'wikiSearch'); + const wikiPlugin = handlerConfig.plugins.find((p: unknown): p is IPromptConcatTool => (p as IPromptConcatTool).toolId === 'wikiSearch'); expect(wikiPlugin).toBeDefined(); if (!wikiPlugin) { // throw error to keep ts believe the plugin exists @@ -102,19 +102,19 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { ]; const context: PromptConcatHookContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test', messages: [], agentDefId: 'test', status: { state: 'working' as const, modified: new Date() }, created: new Date() }, agentDef: { id: 'test', name: 'test', handlerConfig: {} }, isCancelled: () => false, }, - pluginConfig: wikiPlugin, + toolConfig: wikiPlugin, prompts: prompts, messages, }; // Use real hooks from the plugin system const promptHooks = createAgentFrameworkHooks(); - wikiSearchPlugin(promptHooks); + wikiSearchTool(promptHooks); // Execute the processPrompts hook await promptHooks.processPrompts.promise(context); @@ -130,7 +130,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { // Create a plugin config with trigger that won't match const wikiPlugin = { id: 'test-wiki-plugin', - pluginId: 'wikiSearch' as const, + toolId: 'wikiSearch' as const, forbidOverrides: false, retrievalAugmentedGenerationParam: { sourceType: 'wiki' as const, @@ -148,7 +148,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { const originalPromptsText = JSON.stringify(prompts); const context = { - pluginConfig: wikiPlugin, + toolConfig: wikiPlugin, prompts, messages: [ { @@ -163,7 +163,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const hooks = createAgentFrameworkHooks(); - wikiSearchPlugin(hooks); + wikiSearchTool(hooks); // build a minimal PromptConcatHookContext to run the plugin's processPrompts const handlerCtx: AgentFrameworkContext = { agent: { @@ -177,8 +177,8 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { isCancelled: () => false, }; const hookContext: PromptConcatHookContext = { - handlerContext: handlerCtx, - pluginConfig: wikiPlugin as IPromptConcatTool, + agentFrameworkContext: handlerCtx, + toolConfig: wikiPlugin as IPromptConcatTool, prompts: prompts as IPrompt[], messages: context.messages as AgentInstanceMessage[], }; @@ -222,11 +222,11 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { it('should execute wiki search with correct duration=1 and trigger next round', async () => { // Find the real wikiSearch plugin config from taskAgents.json - const wikiPlugin = handlerConfig.plugins.find((p: unknown): p is IPromptConcatTool => (p as IPromptConcatTool).pluginId === 'wikiSearch'); + const wikiPlugin = handlerConfig.plugins.find((p: unknown): p is IPromptConcatTool => (p as IPromptConcatTool).toolId === 'wikiSearch'); expect(wikiPlugin).toBeDefined(); expect(wikiPlugin!.wikiSearchParam).toBeDefined(); - const handlerContext = { + const agentFrameworkContext = { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -270,11 +270,11 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const context = { - handlerContext, + agentFrameworkContext, response, requestId: 'test-request-123', isFinal: true, - pluginConfig: wikiPlugin!, + toolConfig: wikiPlugin!, prompts: [], messages: [], llmResponse: response.content, @@ -286,7 +286,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { const hooks = createAgentFrameworkHooks(); // Register the plugin - wikiSearchPlugin(hooks); + wikiSearchTool(hooks); // Execute the response complete hook await hooks.responseComplete.promise(context); @@ -307,15 +307,15 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { ); // Check that AI tool call message now has duration=1 (should gray out immediately) - const aiToolCallMessage = handlerContext.agent.messages[1] as AgentInstanceMessage; + const aiToolCallMessage = agentFrameworkContext.agent.messages[1] as AgentInstanceMessage; expect(aiToolCallMessage.id).toBe('ai-tool-call-msg'); expect(aiToolCallMessage.duration).toBe(1); // Should be 1 to gray out immediately expect(aiToolCallMessage.metadata?.containsToolCall).toBe(true); expect(aiToolCallMessage.metadata?.toolId).toBe('wiki-search'); // Verify tool result message was added to agent history with correct settings - expect(handlerContext.agent.messages.length).toBe(3); // user + ai + tool_result - const toolResultMessage = handlerContext.agent.messages[2] as AgentInstanceMessage; + expect(agentFrameworkContext.agent.messages.length).toBe(3); // user + ai + tool_result + const toolResultMessage = agentFrameworkContext.agent.messages[2] as AgentInstanceMessage; expect(toolResultMessage.role).toBe('tool'); // Tool result message expect(toolResultMessage.content).toContain(''); expect(toolResultMessage.content).toContain('Tool: wiki-search'); @@ -325,13 +325,13 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { expect(toolResultMessage.duration).toBe(1); // Tool result uses configurable toolResultDuration (default 1) // Check that previous user message is unchanged - const userMessage = handlerContext.agent.messages[0] as AgentInstanceMessage; + const userMessage = agentFrameworkContext.agent.messages[0] as AgentInstanceMessage; expect(userMessage.id).toBe('user-msg-1'); expect(userMessage.duration).toBeUndefined(); // Should stay visible }); it('should handle wiki search errors gracefully and set duration=1 for both messages', async () => { - const handlerContext = { + const agentFrameworkContext = { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -364,13 +364,13 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const context = { - handlerContext, + agentFrameworkContext, response, requestId: 'test-request-error', isFinal: true, - pluginConfig: { + toolConfig: { id: 'test-plugin', - pluginId: 'wikiSearch' as const, + toolId: 'wikiSearch' as const, forbidOverrides: false, }, prompts: [], @@ -384,7 +384,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const hooks = createAgentFrameworkHooks(); - wikiSearchPlugin(hooks); + wikiSearchTool(hooks); await hooks.responseComplete.promise(context); @@ -392,14 +392,14 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { expect(context.actions.yieldNextRoundTo).toBe('self'); // Check that AI tool call message has duration=1 even after error (should gray out immediately) - const aiToolCallMessage = handlerContext.agent.messages[0] as AgentInstanceMessage; + const aiToolCallMessage = agentFrameworkContext.agent.messages[0] as AgentInstanceMessage; expect(aiToolCallMessage.id).toBe('ai-error-tool-call'); expect(aiToolCallMessage.duration).toBe(1); // Should be 1 to gray out immediately expect(aiToolCallMessage.metadata?.containsToolCall).toBe(true); // Verify error message was added to agent history - expect(handlerContext.agent.messages.length).toBe(2); // tool_call + error_result - const errorResultMessage = handlerContext.agent.messages[1] as AgentInstanceMessage; + expect(agentFrameworkContext.agent.messages.length).toBe(2); // tool_call + error_result + const errorResultMessage = agentFrameworkContext.agent.messages[1] as AgentInstanceMessage; expect(errorResultMessage.role).toBe('tool'); // Tool error message expect(errorResultMessage.content).toContain(''); expect(errorResultMessage.content).toContain('Error:'); @@ -411,7 +411,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }); it('should not modify duration of unrelated messages', async () => { - const handlerContext = { + const agentFrameworkContext = { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -461,13 +461,13 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const context = { - handlerContext, + agentFrameworkContext, response, requestId: 'test-request-selective', isFinal: true, - pluginConfig: { + toolConfig: { id: 'test-plugin', - pluginId: 'wikiSearch' as const, + toolId: 'wikiSearch' as const, forbidOverrides: false, }, prompts: [], @@ -481,19 +481,19 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const hooks = createAgentFrameworkHooks(); - wikiSearchPlugin(hooks); + wikiSearchTool(hooks); await hooks.responseComplete.promise(context); // Check that unrelated messages were not modified - const unrelatedUserMsg = handlerContext.agent.messages[0] as AgentInstanceMessage; + const unrelatedUserMsg = agentFrameworkContext.agent.messages[0] as AgentInstanceMessage; expect(unrelatedUserMsg.duration).toBe(5); // Should remain unchanged - const unrelatedAiMsg = handlerContext.agent.messages[1] as AgentInstanceMessage; + const unrelatedAiMsg = agentFrameworkContext.agent.messages[1] as AgentInstanceMessage; expect(unrelatedAiMsg.duration).toBeUndefined(); // Should remain unchanged // Check that only the tool call message was modified - const toolCallMsg = handlerContext.agent.messages[2] as AgentInstanceMessage; + const toolCallMsg = agentFrameworkContext.agent.messages[2] as AgentInstanceMessage; expect(toolCallMsg.duration).toBe(1); // Should be set to 1 expect(toolCallMsg.metadata?.containsToolCall).toBe(true); }); @@ -512,15 +512,15 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const context: AIResponseContext = { - handlerContext: handlerCtx, - pluginConfig: { id: 'test-plugin', pluginId: 'wikiSearch' } as IPromptConcatTool, + agentFrameworkContext: handlerCtx, + toolConfig: { id: 'test-plugin', toolId: 'wikiSearch' } as IPromptConcatTool, response: { requestId: 'test-request-345', content: 'Just a regular response without any tool calls', status: 'done' }, requestId: 'test-request', isFinal: true, }; const hooks = createAgentFrameworkHooks(); - wikiSearchPlugin(hooks); + wikiSearchTool(hooks); await hooks.responseComplete.promise(context); @@ -597,7 +597,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }) as unknown as IWikiService['wikiOperationInServer'], ); - const handlerContext = { + const agentFrameworkContext = { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -638,13 +638,13 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const context = { - handlerContext, + agentFrameworkContext, response, - requestId: 'test-request-vector', + requestId: 'test-request-vector-error', isFinal: true, - pluginConfig: { + toolConfig: { id: 'test-plugin', - pluginId: 'wikiSearch' as const, + toolId: 'wikiSearch' as const, forbidOverrides: false, }, prompts: [], @@ -655,7 +655,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const hooks = createAgentFrameworkHooks(); - wikiSearchPlugin(hooks); + wikiSearchTool(hooks); await hooks.responseComplete.promise(context); @@ -676,9 +676,9 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { // Verify results were processed expect(context.actions.yieldNextRoundTo).toBe('self'); - expect(handlerContext.agent.messages.length).toBe(2); + expect(agentFrameworkContext.agent.messages.length).toBe(2); - const toolResultMessage = handlerContext.agent.messages[1] as AgentInstanceMessage; + const toolResultMessage = agentFrameworkContext.agent.messages[1] as AgentInstanceMessage; expect(toolResultMessage.content).toContain(''); expect(toolResultMessage.content).toContain('Vector Result 1'); expect(toolResultMessage.content).toContain('Vector Result 2'); @@ -696,7 +696,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { new Error('Vector database not initialized'), ); - const handlerContext = { + const agentFrameworkContext = { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -735,13 +735,13 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const context = { - handlerContext, + agentFrameworkContext, response, requestId: 'test-request-vector-error', isFinal: true, - pluginConfig: { + toolConfig: { id: 'test-plugin', - pluginId: 'wikiSearch' as const, + toolId: 'wikiSearch' as const, forbidOverrides: false, }, prompts: [], @@ -752,14 +752,14 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const hooks = createAgentFrameworkHooks(); - wikiSearchPlugin(hooks); + wikiSearchTool(hooks); await hooks.responseComplete.promise(context); // Should still set up next round with error message expect(context.actions.yieldNextRoundTo).toBe('self'); - const errorResultMessage = handlerContext.agent.messages[1] as AgentInstanceMessage; + const errorResultMessage = agentFrameworkContext.agent.messages[1] as AgentInstanceMessage; expect(errorResultMessage.content).toContain('Error:'); // Error message contains i18n key or actual error expect(errorResultMessage.content).toMatch(/Vector database not initialized|Tool\.WikiSearch\.Error\.VectorSearchFailed/); @@ -767,7 +767,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }); it('should require query parameter for vector search', async () => { - const handlerContext = { + const agentFrameworkContext = { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -806,13 +806,13 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const context = { - handlerContext, + agentFrameworkContext, response, requestId: 'test-request-no-query', isFinal: true, - pluginConfig: { + toolConfig: { id: 'test-plugin', - pluginId: 'wikiSearch' as const, + toolId: 'wikiSearch' as const, forbidOverrides: false, }, prompts: [], @@ -823,12 +823,12 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const hooks = createAgentFrameworkHooks(); - wikiSearchPlugin(hooks); + wikiSearchTool(hooks); await hooks.responseComplete.promise(context); // Should return error about missing query - const errorMessage = handlerContext.agent.messages[1] as AgentInstanceMessage; + const errorMessage = agentFrameworkContext.agent.messages[1] as AgentInstanceMessage; expect(errorMessage.content).toContain('Error:'); // Error message contains i18n key or translated text expect(errorMessage.content).toMatch(/query|Tool\.WikiSearch\.Error\.VectorSearchRequiresQuery/); @@ -836,9 +836,9 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }); describe('Message Persistence Integration', () => { - it('should work with messageManagementPlugin for complete persistence flow', async () => { - // This test ensures wikiSearchPlugin works well with messageManagementPlugin - const handlerContext = { + it('should work with messageManagementTool for complete persistence flow', async () => { + // This test ensures wikiSearchTool works well with messageManagementTool + const agentFrameworkContext = { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -870,13 +870,13 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const context = { - handlerContext, + agentFrameworkContext, response, requestId: 'test-request-integration', isFinal: true, - pluginConfig: { + toolConfig: { id: 'test-plugin', - pluginId: 'wikiSearch' as const, + toolId: 'wikiSearch' as const, forbidOverrides: false, }, prompts: [], @@ -890,18 +890,18 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }; const hooks = createAgentFrameworkHooks(); - wikiSearchPlugin(hooks); - messageManagementPlugin(hooks); + wikiSearchTool(hooks); + messageManagementTool(hooks); await hooks.responseComplete.promise(context); // Verify integration works expect(context.actions.yieldNextRoundTo).toBe('self'); - expect(handlerContext.agent.messages.length).toBe(2); // original + tool result + expect(agentFrameworkContext.agent.messages.length).toBe(2); // original + tool result - const toolResultMessage = handlerContext.agent.messages[1] as AgentInstanceMessage; + const toolResultMessage = agentFrameworkContext.agent.messages[1] as AgentInstanceMessage; expect(toolResultMessage.metadata?.isToolResult).toBe(true); - expect(toolResultMessage.metadata?.isPersisted).toBe(true); // Should be true after messageManagementPlugin processing + expect(toolResultMessage.metadata?.isPersisted).toBe(true); // Should be true after messageManagementTool processing }); it('should prevent regression: tool result not filtered in second round', async () => { diff --git a/src/services/agentInstance/tools/__tests__/workspacesListPlugin.test.ts b/src/services/agentInstance/tools/__tests__/workspacesListPlugin.test.ts index 80791dae..315fe8a5 100644 --- a/src/services/agentInstance/tools/__tests__/workspacesListPlugin.test.ts +++ b/src/services/agentInstance/tools/__tests__/workspacesListPlugin.test.ts @@ -1,5 +1,5 @@ -/** - * Tests for workspacesListPlugin +/** + * Tests for workspacesListTool */ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -14,9 +14,9 @@ import type { PromptConcatHookContext } from '../types'; import type { IWorkspaceService } from '@services/workspaces/interface'; import { createAgentFrameworkHooks } from '../index'; -import { workspacesListPlugin } from '../workspacesList'; +import { workspacesListTool } from '../workspacesList'; -describe('workspacesListPlugin', () => { +describe('workspacesListTool', () => { beforeEach(async () => { vi.clearAllMocks(); }); @@ -28,10 +28,10 @@ describe('workspacesListPlugin', () => { describe('workspaces list injection', () => { it('should inject workspaces list when plugin is configured', async () => { const hooks = createAgentFrameworkHooks(); - workspacesListPlugin(hooks); + workspacesListTool(hooks); const context: PromptConcatHookContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -50,11 +50,11 @@ describe('workspacesListPlugin', () => { children: [], }, ], - pluginConfig: { + toolConfig: { id: 'test-plugin', caption: 'Test Plugin', forbidOverrides: false, - pluginId: 'workspacesList', + toolId: 'workspacesList', workspacesListParam: { targetId: 'target-prompt', position: 'after' as const, @@ -75,10 +75,10 @@ describe('workspacesListPlugin', () => { it('should inject workspaces list when position is before', async () => { const hooks = createAgentFrameworkHooks(); - workspacesListPlugin(hooks); + workspacesListTool(hooks); const context: PromptConcatHookContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -97,11 +97,11 @@ describe('workspacesListPlugin', () => { children: [], }, ], - pluginConfig: { + toolConfig: { id: 'test-plugin', caption: 'Test Plugin', forbidOverrides: false, - pluginId: 'workspacesList', + toolId: 'workspacesList', workspacesListParam: { targetId: 'target-prompt', position: 'before' as const, @@ -119,10 +119,10 @@ describe('workspacesListPlugin', () => { it('should not inject content when plugin is not configured', async () => { const hooks = createAgentFrameworkHooks(); - workspacesListPlugin(hooks); + workspacesListTool(hooks); const context: PromptConcatHookContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -141,7 +141,7 @@ describe('workspacesListPlugin', () => { children: [], }, ], - pluginConfig: { id: 'test-plugin', pluginId: 'otherPlugin', forbidOverrides: false } as unknown as IPromptConcatTool, + toolConfig: { id: 'test-plugin', pluginId: 'otherPlugin', forbidOverrides: false } as unknown as IPromptConcatTool, }; await hooks.processPrompts.promise(context); @@ -156,10 +156,10 @@ describe('workspacesListPlugin', () => { workspaceService.getWorkspacesAsList = vi.fn().mockResolvedValue([]) as unknown as IWorkspaceService['getWorkspacesAsList']; const hooks = createAgentFrameworkHooks(); - workspacesListPlugin(hooks); + workspacesListTool(hooks); const context: PromptConcatHookContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -178,11 +178,11 @@ describe('workspacesListPlugin', () => { children: [], }, ], - pluginConfig: { + toolConfig: { id: 'test-plugin', caption: 'Test Plugin', forbidOverrides: false, - pluginId: 'workspacesList', + toolId: 'workspacesList', workspacesListParam: { targetId: 'target-prompt', position: 'after' as const, @@ -195,16 +195,16 @@ describe('workspacesListPlugin', () => { const targetPrompt = context.prompts[0]; expect(targetPrompt.children).toHaveLength(0); expect(logger.debug).toHaveBeenCalledWith('No wiki workspaces found to inject', { - pluginId: 'test-plugin', + toolId: 'test-plugin', }); }); it('should warn when target prompt is not found', async () => { const hooks = createAgentFrameworkHooks(); - workspacesListPlugin(hooks); + workspacesListTool(hooks); const context: PromptConcatHookContext = { - handlerContext: { + agentFrameworkContext: { agent: { id: 'test-agent', agentDefId: 'test-agent-def', @@ -223,11 +223,11 @@ describe('workspacesListPlugin', () => { children: [], }, ], - pluginConfig: { + toolConfig: { id: 'test-plugin', caption: 'Test Plugin', forbidOverrides: false, - pluginId: 'workspacesList', + toolId: 'workspacesList', workspacesListParam: { targetId: 'non-existent-prompt', position: 'after' as const, @@ -239,7 +239,7 @@ describe('workspacesListPlugin', () => { expect(logger.warn).toHaveBeenCalledWith('Workspaces list target prompt not found', { targetId: 'non-existent-prompt', - pluginId: 'test-plugin', + toolId: 'test-plugin', }); }); }); diff --git a/src/services/agentInstance/tools/index.ts b/src/services/agentInstance/tools/index.ts index 93115939..6c4abbd6 100644 --- a/src/services/agentInstance/tools/index.ts +++ b/src/services/agentInstance/tools/index.ts @@ -9,7 +9,7 @@ export type { AgentResponse, PromptConcatHookContext, PromptConcatHooks, PromptC export type { PromptConcatTool as PromptConcatPlugin }; /** - * Registry for built-in tools + * Registry for built-in framework tools */ export const builtInTools = new Map(); @@ -36,7 +36,7 @@ export function createAgentFrameworkHooks(): PromptConcatHooks { */ async function getAllTools() { const [ - promptPluginsModule, + promptToolsModule, wikiSearchModule, wikiOperationModule, workspacesListModule, @@ -50,40 +50,40 @@ async function getAllTools() { ]); return { - messageManagementPlugin: messageManagementModule.messageManagementPlugin, - fullReplacementPlugin: promptPluginsModule.fullReplacementPlugin, - wikiSearchPlugin: wikiSearchModule.wikiSearchPlugin, - wikiOperationPlugin: wikiOperationModule.wikiOperationPlugin, - workspacesListPlugin: workspacesListModule.workspacesListPlugin, + messageManagement: messageManagementModule.messageManagementTool, + fullReplacement: promptToolsModule.fullReplacementTool, + wikiSearch: wikiSearchModule.wikiSearchTool, + wikiOperation: wikiOperationModule.wikiOperationTool, + workspacesList: workspacesListModule.workspacesListTool, }; } /** * Register tools to hooks based on framework configuration * @param hooks - The hooks instance to register tools to - * @param frameworkConfig - The framework configuration containing tool settings + * @param agentFrameworkConfig - The framework configuration containing tool settings */ export async function registerToolsToHooksFromConfig( hooks: PromptConcatHooks, - frameworkConfig: { plugins?: Array<{ pluginId: string; [key: string]: unknown }> }, + agentFrameworkConfig: { plugins?: Array<{ toolId: string; [key: string]: unknown }> }, ): Promise { // Always register core tools that are needed for basic functionality const messageManagementModule = await import('./messageManagement'); - messageManagementModule.messageManagementPlugin(hooks); - logger.debug('Registered messageManagementPlugin to hooks'); + messageManagementModule.messageManagementTool(hooks); + logger.debug('Registered messageManagementTool to hooks'); // Register tools based on framework configuration - if (frameworkConfig.plugins) { - for (const pluginConfig of frameworkConfig.plugins) { - const { pluginId } = pluginConfig; + if (agentFrameworkConfig.plugins) { + for (const toolConfig of agentFrameworkConfig.plugins) { + const { toolId } = toolConfig; // Get tool from global registry (supports both built-in and dynamic tools) - const plugin = builtInTools.get(pluginId); - if (plugin) { - plugin(hooks); - logger.debug(`Registered tool ${pluginId} to hooks`); + const tool = builtInTools.get(toolId); + if (tool) { + tool(hooks); + logger.debug(`Registered tool ${toolId} to hooks`); } else { - logger.warn(`Tool not found in registry: ${pluginId}`); + logger.warn(`Tool not found in registry: ${toolId}`); } } } @@ -96,7 +96,7 @@ export async function registerToolsToHooksFromConfig( export async function initializeToolSystem(): Promise { // Import tool schemas and register them const [ - promptPluginsModule, + promptToolsModule, wikiSearchModule, wikiOperationModule, workspacesListModule, @@ -112,7 +112,7 @@ export async function initializeToolSystem(): Promise { // Register tool parameter schemas registerToolParameterSchema( 'fullReplacement', - promptPluginsModule.getFullReplacementParameterSchema(), + promptToolsModule.getFullReplacementParameterSchema(), { displayName: 'Full Replacement', description: 'Replace target content with content from specified source', @@ -121,7 +121,7 @@ export async function initializeToolSystem(): Promise { registerToolParameterSchema( 'dynamicPosition', - promptPluginsModule.getDynamicPositionParameterSchema(), + promptToolsModule.getDynamicPositionParameterSchema(), { displayName: 'Dynamic Position', description: 'Insert content at a specific position relative to a target element', @@ -164,13 +164,13 @@ export async function initializeToolSystem(): Promise { }, ); - const plugins = await getAllTools(); + const tools = await getAllTools(); // Register all built-in tools to global registry for discovery - builtInTools.set('messageManagement', plugins.messageManagementPlugin); - builtInTools.set('fullReplacement', plugins.fullReplacementPlugin); - builtInTools.set('wikiSearch', plugins.wikiSearchPlugin); - builtInTools.set('wikiOperation', plugins.wikiOperationPlugin); - builtInTools.set('workspacesList', plugins.workspacesListPlugin); + builtInTools.set('messageManagement', tools.messageManagement); + builtInTools.set('fullReplacement', tools.fullReplacement); + builtInTools.set('wikiSearch', tools.wikiSearch); + builtInTools.set('wikiOperation', tools.wikiOperation); + builtInTools.set('workspacesList', tools.workspacesList); logger.debug('All built-in tools and schemas registered successfully'); } @@ -179,12 +179,12 @@ export async function initializeToolSystem(): Promise { * This creates a new hooks instance and registers tools for that specific context */ export async function createHooksWithTools( - frameworkConfig: { plugins?: Array<{ pluginId: string; [key: string]: unknown }> }, -): Promise<{ hooks: PromptConcatHooks; pluginConfigs: Array<{ pluginId: string; [key: string]: unknown }> }> { + agentFrameworkConfig: { plugins?: Array<{ toolId: string; [key: string]: unknown }> }, +): Promise<{ hooks: PromptConcatHooks; toolConfigs: Array<{ toolId: string; [key: string]: unknown }> }> { const hooks = createAgentFrameworkHooks(); - await registerToolsToHooksFromConfig(hooks, frameworkConfig); + await registerToolsToHooksFromConfig(hooks, agentFrameworkConfig); return { hooks, - pluginConfigs: frameworkConfig.plugins || [], + toolConfigs: agentFrameworkConfig.plugins || [], }; } diff --git a/src/services/agentInstance/tools/messageManagement.ts b/src/services/agentInstance/tools/messageManagement.ts index b916f59b..305887db 100644 --- a/src/services/agentInstance/tools/messageManagement.ts +++ b/src/services/agentInstance/tools/messageManagement.ts @@ -14,14 +14,14 @@ import type { AgentStatusContext, AIResponseContext, PromptConcatTool, ToolExecu * Message management plugin * Handles all message-related operations: persistence, streaming, UI updates, and duration-based filtering */ -export const messageManagementPlugin: PromptConcatTool = (hooks) => { +export const messageManagementTool: PromptConcatTool = (hooks) => { // Handle user message persistence - hooks.userMessageReceived.tapAsync('messageManagementPlugin', async (context: UserMessageContext, callback) => { + hooks.userMessageReceived.tapAsync('messageManagementTool', async (context: UserMessageContext, callback) => { try { - const { handlerContext, content, messageId } = context; + const { agentFrameworkContext, content, messageId } = context; // Create user message using the helper function - const userMessage = createAgentMessage(messageId, handlerContext.agent.id, { + const userMessage = createAgentMessage(messageId, agentFrameworkContext.agent.id, { role: 'user', content: content.text, contentType: 'text/plain', @@ -30,7 +30,7 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { }); // Add message to the agent's message array for immediate use (do this before persistence so plugins see it) - handlerContext.agent.messages.push(userMessage); + agentFrameworkContext.agent.messages.push(userMessage); // Get the agent instance service to access repositories const agentInstanceService = container.get(serviceIdentifier.AgentInstance); @@ -40,7 +40,7 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { logger.debug('User message persisted to database', { messageId, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, contentLength: content.text.length, }); @@ -49,30 +49,30 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { logger.error('Message management plugin error in userMessageReceived', { error, messageId: context.messageId, - agentId: context.handlerContext.agent.id, + agentId: context.agentFrameworkContext.agent.id, }); callback(); } }); // Handle agent status persistence - hooks.agentStatusChanged.tapAsync('messageManagementPlugin', async (context: AgentStatusContext, callback) => { + hooks.agentStatusChanged.tapAsync('messageManagementTool', async (context: AgentStatusContext, callback) => { try { - const { handlerContext, status } = context; + const { agentFrameworkContext, status } = context; // Get the agent instance service to update status const agentInstanceService = container.get(serviceIdentifier.AgentInstance); // Update agent status in database - await agentInstanceService.updateAgent(handlerContext.agent.id, { + await agentInstanceService.updateAgent(agentFrameworkContext.agent.id, { status, }); // Update the agent object for immediate use - handlerContext.agent.status = status; + agentFrameworkContext.agent.status = status; logger.debug('Agent status updated in database', { - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, state: status.state, }); @@ -80,7 +80,7 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { } catch (error) { logger.error('Message management plugin error in agentStatusChanged', { error, - agentId: context.handlerContext.agent.id, + agentId: context.agentFrameworkContext.agent.id, status: context.status, }); callback(); @@ -88,13 +88,13 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { }); // Handle AI response updates during streaming - hooks.responseUpdate.tapAsync('messageManagementPlugin', async (context: AIResponseContext, callback) => { + hooks.responseUpdate.tapAsync('messageManagementTool', async (context: AIResponseContext, callback) => { try { - const { handlerContext, response } = context; + const { agentFrameworkContext, response } = context; if (response.status === 'update' && response.content) { // Find or create AI response message in agent's message array - let aiMessage = handlerContext.agent.messages.find( + let aiMessage = agentFrameworkContext.agent.messages.find( (message) => message.role === 'assistant' && !message.metadata?.isComplete, ); @@ -103,7 +103,7 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { const now = new Date(); aiMessage = { id: `ai-response-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, role: 'assistant', content: response.content, created: now, @@ -111,7 +111,7 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { metadata: { isComplete: false }, duration: undefined, // AI responses persist indefinitely by default }; - handlerContext.agent.messages.push(aiMessage); + agentFrameworkContext.agent.messages.push(aiMessage); // Persist immediately so DB timestamp reflects conversation order try { const agentInstanceService = container.get(serviceIdentifier.AgentInstance); @@ -132,7 +132,7 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { // Update UI using the agent instance service try { const agentInstanceService = container.get(serviceIdentifier.AgentInstance); - agentInstanceService.debounceUpdateMessage(aiMessage, handlerContext.agent.id); + agentInstanceService.debounceUpdateMessage(aiMessage, agentFrameworkContext.agent.id); } catch (serviceError) { logger.warn('Failed to update UI for streaming message', { error: serviceError, @@ -150,13 +150,13 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { }); // Handle AI response completion - hooks.responseComplete.tapAsync('messageManagementPlugin', async (context: AIResponseContext, callback) => { + hooks.responseComplete.tapAsync('messageManagementTool', async (context: AIResponseContext, callback) => { try { - const { handlerContext, response } = context; + const { agentFrameworkContext, response } = context; if (response.status === 'done' && response.content) { // Find and finalize AI response message - let aiMessage = handlerContext.agent.messages.find( + let aiMessage = agentFrameworkContext.agent.messages.find( (message) => message.role === 'assistant' && !message.metadata?.isComplete && !message.metadata?.isToolResult, ); @@ -170,7 +170,7 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { const nowFinal = new Date(); aiMessage = { id: `ai-response-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, role: 'assistant', content: response.content, created: nowFinal, @@ -180,7 +180,7 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { }, duration: undefined, // Default duration for AI responses }; - handlerContext.agent.messages.push(aiMessage); + agentFrameworkContext.agent.messages.push(aiMessage); } // Get the agent instance service for persistence and UI updates @@ -191,7 +191,7 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { // Final UI update try { - agentInstanceService.debounceUpdateMessage(aiMessage, handlerContext.agent.id); + agentInstanceService.debounceUpdateMessage(aiMessage, agentFrameworkContext.agent.id); } catch (serviceError) { logger.warn('Failed to update UI for completed message', { error: serviceError, @@ -215,12 +215,12 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { }); // Handle tool result messages persistence and UI updates - hooks.toolExecuted.tapAsync('messageManagementPlugin', async (context: ToolExecutionContext, callback) => { + hooks.toolExecuted.tapAsync('messageManagementTool', async (context: ToolExecutionContext, callback) => { try { - const { handlerContext } = context; + const { agentFrameworkContext } = context; // Find newly added tool result messages that need to be persisted - const newToolResultMessages = handlerContext.agent.messages.filter( + const newToolResultMessages = agentFrameworkContext.agent.messages.filter( (message) => message.metadata?.isToolResult && !message.metadata.isPersisted, ); @@ -233,7 +233,7 @@ export const messageManagementPlugin: PromptConcatTool = (hooks) => { await agentInstanceService.saveUserMessage(message); // Update UI - agentInstanceService.debounceUpdateMessage(message, handlerContext.agent.id); + agentInstanceService.debounceUpdateMessage(message, agentFrameworkContext.agent.id); // Mark as persisted to avoid duplicate saves message.metadata = { ...message.metadata, isPersisted: true, uiUpdated: true }; diff --git a/src/services/agentInstance/tools/prompt.ts b/src/services/agentInstance/tools/prompt.ts index 17332040..8d0dd2d9 100644 --- a/src/services/agentInstance/tools/prompt.ts +++ b/src/services/agentInstance/tools/prompt.ts @@ -76,17 +76,17 @@ export function getDynamicPositionParameterSchema() { * Full replacement plugin * Replaces target content with content from specified source */ -export const fullReplacementPlugin: PromptConcatTool = (hooks) => { +export const fullReplacementTool: PromptConcatTool = (hooks) => { // Normalize an AgentInstanceMessage role to Prompt role - hooks.processPrompts.tapAsync('fullReplacementPlugin', async (context, callback) => { - const { pluginConfig, prompts, messages } = context; + hooks.processPrompts.tapAsync('fullReplacementTool', async (context, callback) => { + const { toolConfig, prompts, messages } = context; - if (pluginConfig.pluginId !== 'fullReplacement' || !pluginConfig.fullReplacementParam) { + if (toolConfig.toolId !== 'fullReplacement' || !toolConfig.fullReplacementParam) { callback(); return; } - const fullReplacementConfig = pluginConfig.fullReplacementParam; + const fullReplacementConfig = toolConfig.fullReplacementParam; if (!fullReplacementConfig) { callback(); return; @@ -98,7 +98,7 @@ export const fullReplacementPlugin: PromptConcatTool = (hooks) => { if (!found) { logger.warn('Target prompt not found for fullReplacement', { targetId, - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); callback(); return; @@ -173,16 +173,16 @@ export const fullReplacementPlugin: PromptConcatTool = (hooks) => { }); // Handle response phase for llmResponse source type - hooks.postProcess.tapAsync('fullReplacementPlugin', async (context, callback) => { + hooks.postProcess.tapAsync('fullReplacementTool', async (context, callback) => { const responseContext = context as ResponseHookContext; - const { pluginConfig, llmResponse, responses } = responseContext; + const { toolConfig, llmResponse, responses } = responseContext; - if (pluginConfig.pluginId !== 'fullReplacement' || !pluginConfig.fullReplacementParam) { + if (toolConfig.toolId !== 'fullReplacement' || !toolConfig.fullReplacementParam) { callback(); return; } - const fullReplacementParameter = pluginConfig.fullReplacementParam; + const fullReplacementParameter = toolConfig.fullReplacementParam; if (!fullReplacementParameter) { callback(); return; @@ -202,7 +202,7 @@ export const fullReplacementPlugin: PromptConcatTool = (hooks) => { if (!found) { logger.warn('Full replacement target not found in responses', { targetId, - pluginId: pluginConfig.id, + pluginId: toolConfig.id, }); callback(); return; @@ -212,7 +212,7 @@ export const fullReplacementPlugin: PromptConcatTool = (hooks) => { logger.debug('Replacing target with LLM response', { targetId, responseLength: llmResponse.length, - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); found.text = llmResponse; @@ -220,6 +220,7 @@ export const fullReplacementPlugin: PromptConcatTool = (hooks) => { logger.debug('Full replacement completed in response phase', { targetId, sourceType, + toolId: toolConfig.id, }); callback(); @@ -230,16 +231,16 @@ export const fullReplacementPlugin: PromptConcatTool = (hooks) => { * Dynamic position plugin * Inserts content at a specific position relative to a target element */ -export const dynamicPositionPlugin: PromptConcatTool = (hooks) => { - hooks.processPrompts.tapAsync('dynamicPositionPlugin', async (context, callback) => { - const { pluginConfig, prompts } = context; +export const dynamicPositionTool: PromptConcatTool = (hooks) => { + hooks.processPrompts.tapAsync('dynamicPositionTool', async (context, callback) => { + const { toolConfig, prompts } = context; - if (pluginConfig.pluginId !== 'dynamicPosition' || !pluginConfig.dynamicPositionParam || !pluginConfig.content) { + if (toolConfig.toolId !== 'dynamicPosition' || !toolConfig.dynamicPositionParam || !toolConfig.content) { callback(); return; } - const dynamicPositionConfig = pluginConfig.dynamicPositionParam; + const dynamicPositionConfig = toolConfig.dynamicPositionParam; if (!dynamicPositionConfig) { callback(); return; @@ -251,7 +252,7 @@ export const dynamicPositionPlugin: PromptConcatTool = (hooks) => { if (!found) { logger.warn('Target prompt not found for dynamicPosition', { targetId, - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); callback(); return; @@ -259,9 +260,9 @@ export const dynamicPositionPlugin: PromptConcatTool = (hooks) => { // Create new prompt part const newPart: IPrompt = { - id: `dynamic-${pluginConfig.id}-${Date.now()}`, - caption: pluginConfig.caption || 'Dynamic Content', - text: pluginConfig.content, + id: `dynamic-${toolConfig.id}-${Date.now()}`, + caption: toolConfig.caption || 'Dynamic Content', + text: toolConfig.content, }; // Insert based on position @@ -288,7 +289,8 @@ export const dynamicPositionPlugin: PromptConcatTool = (hooks) => { logger.debug('Dynamic position insertion completed', { targetId, position, - contentLength: pluginConfig.content.length, + contentLength: toolConfig.content.length, + toolId: toolConfig.id, }); callback(); diff --git a/src/services/agentInstance/tools/schemaRegistry.ts b/src/services/agentInstance/tools/schemaRegistry.ts index 40a8f739..f1e42c05 100644 --- a/src/services/agentInstance/tools/schemaRegistry.ts +++ b/src/services/agentInstance/tools/schemaRegistry.ts @@ -24,7 +24,7 @@ const toolMetadata = new Map { const metadata = getToolMetadata(toolId); return { @@ -135,7 +135,7 @@ export function createDynamicPromptConcatToolSchema(): z.ZodType { // Combine base schema with tool ID and parameters return baseToolSchema.extend({ - pluginId: pluginIdEnum, + toolId: toolIdEnum, ...parameterSchema, }); } diff --git a/src/services/agentInstance/tools/types.ts b/src/services/agentInstance/tools/types.ts index 9126e7bf..e34e0cdb 100644 --- a/src/services/agentInstance/tools/types.ts +++ b/src/services/agentInstance/tools/types.ts @@ -27,7 +27,7 @@ export interface ToolActions { */ export interface BaseToolContext { /** Framework context */ - handlerContext: AgentFrameworkContext; + agentFrameworkContext: AgentFrameworkContext; /** Additional context data */ metadata?: Record; /** Actions set by tools during processing */ @@ -43,7 +43,7 @@ export interface PromptConcatHookContext extends BaseToolContext { /** Current prompt tree */ prompts: IPrompt[]; /** Tool configuration */ - pluginConfig: IPromptConcatTool; + toolConfig: IPromptConcatTool; } /** @@ -61,9 +61,9 @@ export interface PostProcessContext extends PromptConcatHookContext { */ export interface AIResponseContext extends BaseToolContext { /** Tool configuration - for backward compatibility */ - pluginConfig: IPromptConcatTool; + toolConfig: IPromptConcatTool; /** Complete framework configuration - allows tools to access all configs */ - handlerConfig?: { plugins?: Array<{ pluginId: string; [key: string]: unknown }> }; + agentFrameworkConfig?: { plugins?: Array<{ toolId: string; [key: string]: unknown }> }; /** AI streaming response */ response: AIStreamResponse; /** Current request ID */ diff --git a/src/services/agentInstance/tools/wikiOperation.ts b/src/services/agentInstance/tools/wikiOperation.ts index 9fe1d44e..8edc7dfc 100644 --- a/src/services/agentInstance/tools/wikiOperation.ts +++ b/src/services/agentInstance/tools/wikiOperation.ts @@ -101,17 +101,17 @@ const WikiOperationToolParameterSchema = z.object({ * Wiki Operation plugin - Prompt processing * Handles tool list injection for wiki operation functionality */ -export const wikiOperationPlugin: PromptConcatTool = (hooks) => { +export const wikiOperationTool: PromptConcatTool = (hooks) => { // First tapAsync: Tool list injection - hooks.processPrompts.tapAsync('wikiOperationPlugin-toolList', async (context, callback) => { - const { pluginConfig, prompts } = context; + hooks.processPrompts.tapAsync('wikiOperationTool-toolList', async (context, callback) => { + const { toolConfig, prompts } = context; - if (pluginConfig.pluginId !== 'wikiOperation' || !pluginConfig.wikiOperationParam) { + if (toolConfig.toolId !== 'wikiOperation' || !toolConfig.wikiOperationParam) { callback(); return; } - const wikiOperationParameter = pluginConfig.wikiOperationParam; + const wikiOperationParameter = toolConfig.wikiOperationParam; try { // Handle tool list injection if toolListPosition is configured @@ -121,7 +121,7 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { if (!toolListTarget) { logger.warn('Tool list target prompt not found', { targetId: toolListPosition.targetId, - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); callback(); return; @@ -140,7 +140,7 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { } const insertIndex = toolListTarget.prompt.children.length; toolListTarget.prompt.children.splice(insertIndex, 0, { - id: `wiki-operation-tool-${pluginConfig.id}`, + id: `wiki-operation-tool-${toolConfig.id}`, caption: 'Wiki Operation Tool', text: wikiOperationToolContent, }); @@ -149,7 +149,7 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { toolListTarget.prompt.children = []; } toolListTarget.prompt.children.unshift({ - id: `wiki-operation-tool-${pluginConfig.id}`, + id: `wiki-operation-tool-${toolConfig.id}`, caption: 'Wiki Operation Tool', text: wikiOperationToolContent, }); @@ -161,7 +161,7 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { logger.debug('Wiki operation tool list injected', { targetId: toolListPosition.targetId, position: toolListPosition.position, - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); } @@ -169,20 +169,20 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { } catch (error) { logger.error('Error in wiki operation tool list injection', { error, - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); callback(); } }); // 2. Tool execution when AI response is complete - hooks.responseComplete.tapAsync('wikiOperationPlugin-handler', async (context, callback) => { + hooks.responseComplete.tapAsync('wikiOperationTool-handler', async (context, callback) => { try { - const { handlerContext, response, handlerConfig } = context; + const { agentFrameworkContext, response, agentFrameworkConfig } = context; - // Find this plugin's configuration from handlerConfig - const wikiOperationPluginConfig = handlerConfig?.plugins?.find(p => p.pluginId === 'wikiOperation'); - const wikiOperationParameter = wikiOperationPluginConfig?.wikiOperationParam as { toolResultDuration?: number } | undefined; + // Find this plugin's configuration from agentFrameworkConfig + const wikiOperationToolConfig = agentFrameworkConfig?.plugins?.find((p: { toolId: string; [key: string]: unknown }) => p.toolId === 'wikiOperation'); + const wikiOperationParameter = wikiOperationToolConfig?.wikiOperationParam as { toolResultDuration?: number } | undefined; const toolResultDuration = wikiOperationParameter?.toolResultDuration || 1; // Default to 1 round if (response.status !== 'done' || !response.content) { @@ -200,19 +200,19 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { logger.debug('Wiki operation tool call detected', { toolId: toolMatch.toolId, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, }); // Set duration=1 for the AI message containing the tool call // Find the most recent AI message (should be the one containing the tool call) - const aiMessages = handlerContext.agent.messages.filter(message => message.role === 'assistant'); + const aiMessages = agentFrameworkContext.agent.messages.filter((message: AgentInstanceMessage) => message.role === 'assistant'); if (aiMessages.length > 0) { const latestAiMessage = aiMessages[aiMessages.length - 1]; latestAiMessage.duration = toolResultDuration; logger.debug('Set AI message duration for tool call', { messageId: latestAiMessage.id, duration: toolResultDuration, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, }); } @@ -220,7 +220,7 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { try { logger.debug('Parsing wiki operation tool parameters', { toolMatch: toolMatch.parameters, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, }); // Use parameters returned by matchToolCalling directly. Let zod schema validate. @@ -253,7 +253,7 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { workspaceName, operation, title, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, }); let result: string; @@ -293,7 +293,7 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { workspaceID, operation, title, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, }); // Format the tool result for display @@ -307,8 +307,8 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { logger.debug('Wiki operation setting yieldNextRoundTo=self', { toolId: 'wiki-operation', - agentId: handlerContext.agent.id, - messageCount: handlerContext.agent.messages.length, + agentId: agentFrameworkContext.agent.id, + messageCount: agentFrameworkContext.agent.messages.length, toolResultPreview: toolResultText.slice(0, 200), }); @@ -316,7 +316,7 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { const toolResultTime = new Date(); const toolResultMessage: AgentInstanceMessage = { id: `tool-result-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, role: 'tool', // Tool result message content: toolResultText, modified: toolResultTime, @@ -331,7 +331,7 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { artificialOrder: Date.now() + 10, // Additional ordering hint }, }; - handlerContext.agent.messages.push(toolResultMessage); + agentFrameworkContext.agent.messages.push(toolResultMessage); // Persist tool result immediately so DB ordering matches in-memory order try { @@ -347,7 +347,7 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { // Signal that tool was executed AFTER adding and persisting the message await hooks.toolExecuted.promise({ - handlerContext, + agentFrameworkContext, toolResult: { success: true, data: result, @@ -370,7 +370,7 @@ export const wikiOperationPlugin: PromptConcatTool = (hooks) => { } catch (error) { logger.error('Wiki operation tool execution failed', { error, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, toolParameters: toolMatch.parameters, }); @@ -389,7 +389,7 @@ Error: ${error instanceof Error ? error.message : String(error)} const errorResultTime = new Date(); const errorResultMessage: AgentInstanceMessage = { id: `tool-error-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, role: 'tool', // Tool error message content: errorMessage, modified: errorResultTime, @@ -402,11 +402,11 @@ Error: ${error instanceof Error ? error.message : String(error)} isComplete: true, // Mark as complete to prevent messageManagementPlugin from overwriting content }, }; - handlerContext.agent.messages.push(errorResultMessage); + agentFrameworkContext.agent.messages.push(errorResultMessage); // Signal that tool was executed (with error) AFTER adding the message await hooks.toolExecuted.promise({ - handlerContext, + agentFrameworkContext, toolResult: { success: false, error: error instanceof Error ? error.message : String(error), diff --git a/src/services/agentInstance/tools/wikiSearch.ts b/src/services/agentInstance/tools/wikiSearch.ts index f8e3e068..03a72859 100644 --- a/src/services/agentInstance/tools/wikiSearch.ts +++ b/src/services/agentInstance/tools/wikiSearch.ts @@ -1,4 +1,4 @@ -/** +/** * Wiki Search plugin * Handles wiki search tool list injection, tool calling detection and response processing */ @@ -488,17 +488,17 @@ async function executeWikiUpdateEmbeddingsTool( * Wiki Search plugin - Prompt processing * Handles tool list injection for wiki search and update embeddings functionality */ -export const wikiSearchPlugin: PromptConcatTool = (hooks) => { +export const wikiSearchTool: PromptConcatTool = (hooks) => { // First tapAsync: Tool list injection - hooks.processPrompts.tapAsync('wikiSearchPlugin-toolList', async (context, callback) => { - const { pluginConfig, prompts } = context; + hooks.processPrompts.tapAsync('wikiSearchTool-toolList', async (context, callback) => { + const { toolConfig, prompts } = context; - if (pluginConfig.pluginId !== 'wikiSearch' || !pluginConfig.wikiSearchParam) { + if (toolConfig.toolId !== 'wikiSearch' || !toolConfig.wikiSearchParam) { callback(); return; } - const wikiSearchParameter = pluginConfig.wikiSearchParam; + const wikiSearchParameter = toolConfig.wikiSearchParam; try { // Handle tool list injection if toolListPosition is configured @@ -508,7 +508,7 @@ export const wikiSearchPlugin: PromptConcatTool = (hooks) => { if (!toolListTarget) { logger.warn('Tool list target prompt not found', { targetId: toolListPosition.targetId, - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); callback(); return; @@ -544,7 +544,7 @@ export const wikiSearchPlugin: PromptConcatTool = (hooks) => { targetId: toolListPosition.targetId, position: toolListPosition.position, toolCount: 2, // wiki-search and wiki-update-embeddings - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); } @@ -552,20 +552,20 @@ export const wikiSearchPlugin: PromptConcatTool = (hooks) => { } catch (error) { logger.error('Error in wiki search tool list injection', { error, - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); callback(); } }); // 2. Tool execution when AI response is complete - hooks.responseComplete.tapAsync('wikiSearchPlugin-handler', async (context, callback) => { + hooks.responseComplete.tapAsync('wikiSearchTool-handler', async (context, callback) => { try { - const { handlerContext, response, handlerConfig } = context; + const { agentFrameworkContext, response, agentFrameworkConfig } = context; - // Find this plugin's configuration from handlerConfig - const wikiSearchPluginConfig = handlerConfig?.plugins?.find(p => p.pluginId === 'wikiSearch'); - const wikiSearchParameter = wikiSearchPluginConfig?.wikiSearchParam as { toolResultDuration?: number } | undefined; + // Find this plugin's configuration from agentFrameworkConfig + const wikiSearchToolConfig = agentFrameworkConfig?.plugins?.find((p: { toolId: string; [key: string]: unknown }) => p.toolId === 'wikiSearch'); + const wikiSearchParameter = wikiSearchToolConfig?.wikiSearchParam as { toolResultDuration?: number } | undefined; const toolResultDuration = wikiSearchParameter?.toolResultDuration || 1; // Default to 1 round if (response.status !== 'done' || !response.content) { @@ -583,12 +583,12 @@ export const wikiSearchPlugin: PromptConcatTool = (hooks) => { logger.debug('Wiki tool call detected', { toolId: toolMatch.toolId, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, }); // Set duration=1 for the AI message containing the tool call // Find the most recent AI message (should be the one containing the tool call) - const aiMessages = handlerContext.agent.messages.filter(message => message.role === 'assistant'); + const aiMessages = agentFrameworkContext.agent.messages.filter((message: AgentInstanceMessage) => message.role === 'assistant'); if (aiMessages.length > 0) { const latestAiMessage = aiMessages[aiMessages.length - 1]; if (latestAiMessage.content === response.content) { @@ -614,7 +614,7 @@ export const wikiSearchPlugin: PromptConcatTool = (hooks) => { } // Also update UI immediately - agentInstanceService.debounceUpdateMessage(latestAiMessage, handlerContext.agent.id, 0); // No delay + agentInstanceService.debounceUpdateMessage(latestAiMessage, agentFrameworkContext.agent.id, 0); // No delay logger.debug('Set duration=1 for AI tool call message', { messageId: latestAiMessage.id, @@ -626,10 +626,10 @@ export const wikiSearchPlugin: PromptConcatTool = (hooks) => { // Execute the appropriate tool try { // Check if cancelled before starting tool execution - if (handlerContext.isCancelled()) { + if (agentFrameworkContext.isCancelled()) { logger.debug('Wiki tool cancelled before execution', { toolId: toolMatch.toolId, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, }); callback(); return; @@ -644,9 +644,9 @@ export const wikiSearchPlugin: PromptConcatTool = (hooks) => { result = await executeWikiSearchTool( validatedParameters, { - agentId: handlerContext.agent.id, - messageId: handlerContext.agent.messages[handlerContext.agent.messages.length - 1]?.id, - config: handlerContext.agent.aiApiConfig as AiAPIConfig | undefined, + agentId: agentFrameworkContext.agent.id, + messageId: agentFrameworkContext.agent.messages[agentFrameworkContext.agent.messages.length - 1]?.id, + config: agentFrameworkContext.agent.aiApiConfig as AiAPIConfig | undefined, }, ); } else { @@ -655,18 +655,18 @@ export const wikiSearchPlugin: PromptConcatTool = (hooks) => { result = await executeWikiUpdateEmbeddingsTool( validatedParameters, { - agentId: handlerContext.agent.id, - messageId: handlerContext.agent.messages[handlerContext.agent.messages.length - 1]?.id, - aiConfig: handlerContext.agent.aiApiConfig, + agentId: agentFrameworkContext.agent.id, + messageId: agentFrameworkContext.agent.messages[agentFrameworkContext.agent.messages.length - 1]?.id, + aiConfig: agentFrameworkContext.agent.aiApiConfig, }, ); } // Check if cancelled after tool execution - if (handlerContext.isCancelled()) { + if (agentFrameworkContext.isCancelled()) { logger.debug('Wiki tool cancelled after execution', { toolId: toolMatch.toolId, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, }); callback(); return; @@ -692,8 +692,8 @@ export const wikiSearchPlugin: PromptConcatTool = (hooks) => { logger.debug('Wiki search setting yieldNextRoundTo=self', { toolId: 'wiki-search', - agentId: handlerContext.agent.id, - messageCount: handlerContext.agent.messages.length, + agentId: agentFrameworkContext.agent.id, + messageCount: agentFrameworkContext.agent.messages.length, toolResultPreview: toolResultText.slice(0, 200), }); @@ -701,7 +701,7 @@ export const wikiSearchPlugin: PromptConcatTool = (hooks) => { const nowTool = new Date(); const toolResultMessage: AgentInstanceMessage = { id: `tool-result-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, role: 'tool', // Tool result message content: toolResultText, created: nowTool, @@ -717,13 +717,13 @@ export const wikiSearchPlugin: PromptConcatTool = (hooks) => { artificialOrder: Date.now() + 10, // Additional ordering hint }, }; - handlerContext.agent.messages.push(toolResultMessage); + agentFrameworkContext.agent.messages.push(toolResultMessage); // Do not persist immediately here. Let messageManagementPlugin handle persistence // Signal that tool was executed AFTER adding and persisting the message await hooks.toolExecuted.promise({ - handlerContext, + agentFrameworkContext, toolResult: { success: true, data: result.success ? result.data : result.error, @@ -765,7 +765,7 @@ Error: ${error instanceof Error ? error.message : String(error)} const nowError = new Date(); const errorResultMessage: AgentInstanceMessage = { id: `tool-error-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, - agentId: handlerContext.agent.id, + agentId: agentFrameworkContext.agent.id, role: 'tool', // Tool error message content: errorMessage, created: nowError, @@ -779,11 +779,11 @@ Error: ${error instanceof Error ? error.message : String(error)} isComplete: true, // Mark as complete to prevent messageManagementPlugin from overwriting content }, }; - handlerContext.agent.messages.push(errorResultMessage); + agentFrameworkContext.agent.messages.push(errorResultMessage); // Do not persist immediately; let messageManagementPlugin handle it during toolExecuted await hooks.toolExecuted.promise({ - handlerContext, + agentFrameworkContext, toolResult: { success: false, error: error instanceof Error ? error.message : String(error), diff --git a/src/services/agentInstance/tools/workspacesList.ts b/src/services/agentInstance/tools/workspacesList.ts index 14673f10..ed195968 100644 --- a/src/services/agentInstance/tools/workspacesList.ts +++ b/src/services/agentInstance/tools/workspacesList.ts @@ -51,17 +51,17 @@ import type { PromptConcatTool } from './types'; * Workspaces List plugin - Prompt processing * Handles injection of available wiki workspaces list */ -export const workspacesListPlugin: PromptConcatTool = (hooks) => { +export const workspacesListTool: PromptConcatTool = (hooks) => { // Tool list injection - hooks.processPrompts.tapAsync('workspacesListPlugin-injection', async (context, callback) => { - const { pluginConfig, prompts } = context; + hooks.processPrompts.tapAsync('workspacesListTool-injection', async (context, callback) => { + const { toolConfig, prompts } = context; - if (pluginConfig.pluginId !== 'workspacesList' || !pluginConfig.workspacesListParam) { + if (toolConfig.toolId !== 'workspacesList' || !toolConfig.workspacesListParam) { callback(); return; } - const workspacesListParameter = pluginConfig.workspacesListParam; + const workspacesListParameter = toolConfig.workspacesListParam; try { // Handle workspaces list injection if targetId is configured @@ -70,7 +70,7 @@ export const workspacesListPlugin: PromptConcatTool = (hooks) => { if (!target) { logger.warn('Workspaces list target prompt not found', { targetId: workspacesListParameter.targetId, - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); callback(); return; @@ -96,7 +96,7 @@ export const workspacesListPlugin: PromptConcatTool = (hooks) => { } const insertIndex = target.prompt.children.length; target.prompt.children.splice(insertIndex, 0, { - id: `workspaces-list-${pluginConfig.id}`, + id: `workspaces-list-${toolConfig.id}`, caption: 'Available Workspaces', text: workspacesListContent, }); @@ -105,7 +105,7 @@ export const workspacesListPlugin: PromptConcatTool = (hooks) => { target.prompt.children = []; } target.prompt.children.unshift({ - id: `workspaces-list-${pluginConfig.id}`, + id: `workspaces-list-${toolConfig.id}`, caption: 'Available Workspaces', text: workspacesListContent, }); @@ -117,12 +117,12 @@ export const workspacesListPlugin: PromptConcatTool = (hooks) => { logger.debug('Workspaces list injected successfully', { targetId: workspacesListParameter.targetId, position: workspacesListParameter.position, - pluginId: pluginConfig.id, + toolId: toolConfig.id, workspaceCount: wikiWorkspaces.length, }); } else { logger.debug('No wiki workspaces found to inject', { - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); } } @@ -131,7 +131,7 @@ export const workspacesListPlugin: PromptConcatTool = (hooks) => { } catch (error) { logger.error('Error in workspaces list injection', { error, - pluginId: pluginConfig.id, + toolId: toolConfig.id, }); callback(); } From 02124bad1af026792774cdc3b952733f974a5052 Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Thu, 27 Nov 2025 01:29:21 +0800 Subject: [PATCH 2/2] further rename --- src/__tests__/__mocks__/window.ts | 2 +- .../TabTypes/CreateNewAgentContent.tsx | 14 ++--- .../TabTypes/EditAgentDefinitionContent.tsx | 22 ++++---- .../__tests__/CreateNewAgentContent.test.tsx | 44 +++++++-------- .../EditAgentDefinitionContent.test.tsx | 2 +- .../agentChatStore/actions/agentActions.ts | 20 +++---- .../agentChatStore/actions/previewActions.ts | 8 +-- src/pages/Agent/store/agentChatStore/types.ts | 6 +- .../PromptPreviewDialog/EditView.tsx | 20 +++---- .../PromptConfigForm/index.tsx | 8 +-- .../PromptPreviewDialog.promptConcat.test.tsx | 16 +++--- .../__tests__/PromptPreviewDialog.ui.test.tsx | 6 +- .../components/PromptPreviewDialog/index.tsx | 14 ++--- .../agentDefinition/__tests__/index.test.ts | 33 +++++------ .../getAgentDefinitionTemplatesFromWikis.ts | 12 ++-- src/services/agentDefinition/index.ts | 14 ++--- src/services/agentDefinition/interface.ts | 8 +-- .../__tests__/index.failure.test.ts | 2 +- .../__tests__/index.streaming.test.ts | 2 +- .../agentInstance/__tests__/utilities.test.ts | 20 +++---- .../__tests__/taskAgent.failure.test.ts | 6 +- .../__tests__/taskAgent.test.ts | 36 ++++++------ .../agentFrameworks/taskAgent.ts | 14 ++--- .../agentFrameworks/taskAgents.json | 4 +- src/services/agentInstance/index.ts | 28 +++++----- src/services/agentInstance/interface.ts | 12 ++-- .../promptConcat/promptConcat.ts | 10 ++-- .../promptConcat/promptConcatSchema/index.ts | 8 ++- .../promptConcatSchema/jsonSchema.ts | 2 +- .../promptConcat/responseConcat.ts | 7 +-- .../fullReplacementPlugin.duration.test.ts | 24 ++++---- .../__tests__/messageManagementPlugin.test.ts | 4 +- .../__tests__/wikiOperationPlugin.test.ts | 6 +- .../tools/__tests__/wikiSearchPlugin.test.ts | 32 +++++------ .../__tests__/workspacesListPlugin.test.ts | 2 +- .../agentInstance/tools/wikiSearch.ts | 2 +- src/services/agentInstance/utilities.ts | 14 ++--- src/services/database/schema/agent.ts | 6 +- ...s => useAgentFrameworkConfigManagement.ts} | 56 ++++++++++--------- 39 files changed, 275 insertions(+), 271 deletions(-) rename src/windows/Preferences/sections/ExternalAPI/{useHandlerConfigManagement.ts => useAgentFrameworkConfigManagement.ts} (51%) diff --git a/src/__tests__/__mocks__/window.ts b/src/__tests__/__mocks__/window.ts index 05e36624..5ad7aab1 100644 --- a/src/__tests__/__mocks__/window.ts +++ b/src/__tests__/__mocks__/window.ts @@ -46,7 +46,7 @@ Object.defineProperty(window, 'observables', { userInfo$: new BehaviorSubject(undefined).asObservable(), }, agentInstance: { - concatPrompt: vi.fn((promptDescription: Pick, messages: AgentInstanceMessage[]) => { + concatPrompt: vi.fn((promptDescription: Pick, messages: AgentInstanceMessage[]) => { const agentInstanceService = container.get(serviceIdentifier.AgentInstance); // Initialize handlers (plugins and built-in handlers) before calling concatPrompt // We need to wrap this in an Observable since concatPrompt returns an Observable diff --git a/src/pages/Agent/TabContent/TabTypes/CreateNewAgentContent.tsx b/src/pages/Agent/TabContent/TabTypes/CreateNewAgentContent.tsx index 1f7461eb..6fb93fd7 100644 --- a/src/pages/Agent/TabContent/TabTypes/CreateNewAgentContent.tsx +++ b/src/pages/Agent/TabContent/TabTypes/CreateNewAgentContent.tsx @@ -4,7 +4,7 @@ import { Box, Button, Container, Step, StepLabel, Stepper, TextField, Typography import { styled } from '@mui/material/styles'; import type { RJSFSchema } from '@rjsf/utils'; import type { AgentDefinition } from '@services/agentDefinition/interface'; -import { HandlerConfig } from '@services/agentInstance/promptConcat/promptConcatSchema'; +import { AgentFrameworkConfig } from '@services/agentInstance/promptConcat/promptConcatSchema'; import useDebouncedCallback from 'beautiful-react-hooks/useDebouncedCallback'; import { nanoid } from 'nanoid'; import React, { useEffect, useState } from 'react'; @@ -99,19 +99,19 @@ export const CreateNewAgentContent: React.FC = ({ ta // Load schema when temporaryAgentDefinition is available useEffect(() => { const loadSchema = async () => { - if (temporaryAgentDefinition?.handlerID) { + if (temporaryAgentDefinition?.agentFrameworkID) { try { - const schema = await window.service.agentInstance.getFrameworkConfigSchema(temporaryAgentDefinition.handlerID); + const schema = await window.service.agentInstance.getFrameworkConfigSchema(temporaryAgentDefinition.agentFrameworkID); setPromptSchema(schema as RJSFSchema); } catch (error) { - console.error('Failed to load handler config schema:', error); + console.error('Failed to load framework config schema:', error); setPromptSchema(null); } } }; void loadSchema(); - }, [temporaryAgentDefinition?.handlerID]); + }, [temporaryAgentDefinition?.agentFrameworkID]); // Create preview agent when entering step 3 useEffect(() => { @@ -374,11 +374,11 @@ export const CreateNewAgentContent: React.FC = ({ ta { void handleAgentDefinitionChange({ ...temporaryAgentDefinition, - handlerConfig: updatedConfig as Record, + agentFrameworkConfig: updatedConfig as Record, }); }} loading={false} diff --git a/src/pages/Agent/TabContent/TabTypes/EditAgentDefinitionContent.tsx b/src/pages/Agent/TabContent/TabTypes/EditAgentDefinitionContent.tsx index 1f82f605..52a902b1 100644 --- a/src/pages/Agent/TabContent/TabTypes/EditAgentDefinitionContent.tsx +++ b/src/pages/Agent/TabContent/TabTypes/EditAgentDefinitionContent.tsx @@ -2,7 +2,7 @@ import { Box, Button, CircularProgress, Container, Divider, TextField, Typograph import { styled } from '@mui/material/styles'; import type { RJSFSchema } from '@rjsf/utils'; import type { AgentDefinition } from '@services/agentDefinition/interface'; -import { HandlerConfig } from '@services/agentInstance/promptConcat/promptConcatSchema'; +import { AgentFrameworkConfig } from '@services/agentInstance/promptConcat/promptConcatSchema'; import useDebouncedCallback from 'beautiful-react-hooks/useDebouncedCallback'; import React, { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -94,30 +94,30 @@ export const EditAgentDefinitionContent: React.FC { const loadSchema = async () => { - if (!agentDefinition?.handlerID) { - // No handlerID found + if (!agentDefinition?.agentFrameworkID) { + // No agentFrameworkID found return; } try { // Loading framework config schema - const schema = await window.service.agentInstance.getFrameworkConfigSchema(agentDefinition.handlerID); + const schema = await window.service.agentInstance.getFrameworkConfigSchema(agentDefinition.agentFrameworkID); // Schema loaded successfully setPromptSchema(schema); } catch (error) { - void window.service.native.log('error', 'EditAgentDefinitionContent: Failed to load handler config schema', { + void window.service.native.log('error', 'EditAgentDefinitionContent: Failed to load framework config schema', { error, - handlerID: agentDefinition.handlerID, + agentFrameworkID: agentDefinition.agentFrameworkID, }); - console.error('Failed to load handler config schema:', error); + console.error('Failed to load framework config schema:', error); } }; void loadSchema(); - }, [agentDefinition?.handlerID]); + }, [agentDefinition?.agentFrameworkID]); // Auto-save to backend whenever agentDefinition changes (debounced) const saveToBackendDebounced = useDebouncedCallback( @@ -235,7 +235,7 @@ export const EditAgentDefinitionContent: React.FC, + agentFrameworkConfig: formData as Record, }; }, ); @@ -356,7 +356,7 @@ export const EditAgentDefinitionContent: React.FC diff --git a/src/pages/Agent/TabContent/TabTypes/__tests__/CreateNewAgentContent.test.tsx b/src/pages/Agent/TabContent/TabTypes/__tests__/CreateNewAgentContent.test.tsx index 2b08f8a4..27d1349f 100644 --- a/src/pages/Agent/TabContent/TabTypes/__tests__/CreateNewAgentContent.test.tsx +++ b/src/pages/Agent/TabContent/TabTypes/__tests__/CreateNewAgentContent.test.tsx @@ -157,7 +157,7 @@ describe('CreateNewAgentContent', () => { id: 'template-1', name: 'Test Template', description: 'Test Description', - handlerConfig: { systemPrompt: 'Test prompt' }, + agentFrameworkConfig: { systemPrompt: 'Test prompt' }, }; mockCreateAgentDef.mockResolvedValue({ @@ -258,8 +258,8 @@ describe('CreateNewAgentContent', () => { const mockAgentDefinition = { id: 'temp-123', name: 'Test Agent', - handlerID: 'test-handler', - handlerConfig: { prompts: [{ text: 'Original prompt', role: 'system' }] }, + agentFrameworkID: 'test-handler', + agentFrameworkConfig: { prompts: [{ text: 'Original prompt', role: 'system' }] }, }; mockGetAgentDef.mockResolvedValue(mockAgentDefinition); @@ -285,13 +285,13 @@ describe('CreateNewAgentContent', () => { expect(mockUpdateAgentDef).not.toHaveBeenCalled(); }); - it('should trigger schema loading when temporaryAgentDefinition has handlerID', async () => { - // Mock agent definition with handlerID that will be restored + it('should trigger schema loading when temporaryAgentDefinition has agentFrameworkID', async () => { + // Mock agent definition with agentFrameworkID that will be restored const mockAgentDefinition = { id: 'temp-123', name: 'Test Agent', - handlerID: 'test-handler', - handlerConfig: { prompts: [{ text: 'Test prompt', role: 'system' }] }, + agentFrameworkID: 'test-handler', + agentFrameworkConfig: { prompts: [{ text: 'Test prompt', role: 'system' }] }, }; mockGetAgentDef.mockResolvedValue(mockAgentDefinition); @@ -313,7 +313,7 @@ describe('CreateNewAgentContent', () => { expect(mockGetAgentDef).toHaveBeenCalledWith('temp-123'); }, { timeout: 1000 }); - // After restoration, the component should have the handlerID and trigger schema loading + // After restoration, the component should have the agentFrameworkID and trigger schema loading await waitFor(() => { expect(mockGetFrameworkConfigSchema).toHaveBeenCalledWith('test-handler'); }, { timeout: 2000 }); @@ -341,8 +341,8 @@ describe('CreateNewAgentContent', () => { const mockTemplate = { id: 'template-1', name: 'Test Template', - handlerID: 'test-handler', - handlerConfig: { prompts: [{ text: 'Test prompt', role: 'system' }] }, + agentFrameworkID: 'test-handler', + agentFrameworkConfig: { prompts: [{ text: 'Test prompt', role: 'system' }] }, }; const mockCreatedDefinition = { @@ -378,8 +378,8 @@ describe('CreateNewAgentContent', () => { const mockTemplate = { id: 'template-1', name: 'Test Template', - handlerID: 'test-handler', - handlerConfig: { prompts: [{ text: 'Original prompt' }] }, + agentFrameworkID: 'test-handler', + agentFrameworkConfig: { prompts: [{ text: 'Original prompt' }] }, }; const mockCreatedDefinition = { @@ -443,7 +443,7 @@ describe('CreateNewAgentContent', () => { expect(mockCreateAgentDef).toHaveBeenCalledWith( expect.objectContaining({ name: 'My Agent', - handlerID: 'test-handler', + agentFrameworkID: 'test-handler', }), ); }); @@ -459,7 +459,7 @@ describe('CreateNewAgentContent', () => { expect(mockUpdateAgentDef).toHaveBeenCalledWith( expect.objectContaining({ id: expect.stringContaining('temp-'), - handlerID: 'test-handler', + agentFrameworkID: 'test-handler', }), ); }, { timeout: 500 }); @@ -470,8 +470,8 @@ describe('CreateNewAgentContent', () => { const mockTemplate = { id: 'task-agent', name: 'Example Agent', - handlerID: 'basicPromptConcatHandler', - handlerConfig: { + agentFrameworkID: 'basicPromptConcatHandler', + agentFrameworkConfig: { prompts: [ { id: 'system', @@ -503,7 +503,7 @@ describe('CreateNewAgentContent', () => { // Step 1: Create agent definition (simulates template selection) const createdDef = await window.service.agentDefinition.createAgentDef(mockCreatedDefinition); expect(createdDef).toBeDefined(); - const prompts = (createdDef.handlerConfig).prompts as Array<{ + const prompts = (createdDef.agentFrameworkConfig).prompts as Array<{ children?: Array<{ text?: string }>; }>; expect((prompts as Array<{ children?: Array<{ text?: string }> }>)[0]?.children?.[0]?.text).toBe('You are a helpful assistant for Tiddlywiki user.'); @@ -511,14 +511,14 @@ describe('CreateNewAgentContent', () => { // Step 2: Update system prompt in nested structure const updatedDefinition = { ...mockCreatedDefinition, - handlerConfig: { - ...mockCreatedDefinition.handlerConfig, + agentFrameworkConfig: { + ...mockCreatedDefinition.agentFrameworkConfig, prompts: [ { - ...mockCreatedDefinition.handlerConfig.prompts[0], + ...mockCreatedDefinition.agentFrameworkConfig.prompts[0], children: [ { - ...mockCreatedDefinition.handlerConfig.prompts[0].children[0], + ...mockCreatedDefinition.agentFrameworkConfig.prompts[0].children[0], text: '你是一个专业的代码助手,请用中文回答编程问题。', }, ], @@ -532,7 +532,7 @@ describe('CreateNewAgentContent', () => { // Verify the correct nested structure is updated expect(mockUpdateAgentDef).toHaveBeenCalledWith( expect.objectContaining({ - handlerConfig: expect.objectContaining({ + agentFrameworkConfig: expect.objectContaining({ prompts: expect.arrayContaining([ expect.objectContaining({ role: 'system', diff --git a/src/pages/Agent/TabContent/TabTypes/__tests__/EditAgentDefinitionContent.test.tsx b/src/pages/Agent/TabContent/TabTypes/__tests__/EditAgentDefinitionContent.test.tsx index a003d161..765ba00e 100644 --- a/src/pages/Agent/TabContent/TabTypes/__tests__/EditAgentDefinitionContent.test.tsx +++ b/src/pages/Agent/TabContent/TabTypes/__tests__/EditAgentDefinitionContent.test.tsx @@ -49,7 +49,7 @@ const mockAgentDefinition = { id: 'test-agent-def-id', name: 'Test Agent', description: 'A test agent for editing', - handlerID: 'testHandler', + agentFrameworkID: 'testHandler', config: {}, }; diff --git a/src/pages/Agent/store/agentChatStore/actions/agentActions.ts b/src/pages/Agent/store/agentChatStore/actions/agentActions.ts index 2951d40e..46e1f1ac 100644 --- a/src/pages/Agent/store/agentChatStore/actions/agentActions.ts +++ b/src/pages/Agent/store/agentChatStore/actions/agentActions.ts @@ -302,35 +302,35 @@ export const agentActions = ( } }, - getHandlerId: async () => { + getAgentFrameworkId: async () => { try { const { agent, agentDef } = get(); - if (agentDef?.handlerID) { - return agentDef.handlerID; + if (agentDef?.agentFrameworkID) { + return agentDef.agentFrameworkID; } if (agent?.agentDefId) { const fetchedAgentDefinition = await window.service.agentDefinition.getAgentDef(agent.agentDefId); - if (fetchedAgentDefinition?.handlerID) { - return fetchedAgentDefinition.handlerID; + if (fetchedAgentDefinition?.agentFrameworkID) { + return fetchedAgentDefinition.agentFrameworkID; } } - throw new Error('No active agent in store or handler ID not found'); + throw new Error('No active agent in store or agent framework ID not found'); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); - const finalError = new Error(`Failed to get handler ID: ${errorMessage}`); + const finalError = new Error(`Failed to get agent framework ID: ${errorMessage}`); set({ error: finalError }); throw finalError; } }, /** - * Get handler configuration schema for current handler + * Get framework configuration schema for current framework */ getFrameworkConfigSchema: async () => { try { - const handlerId = await get().getHandlerId(); - return await window.service.agentInstance.getFrameworkConfigSchema(handlerId); + const agentFrameworkId = await get().getAgentFrameworkId(); + return await window.service.agentInstance.getFrameworkConfigSchema(agentFrameworkId); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); const finalError = new Error(`Failed to get handler schema: ${errorMessage}`); diff --git a/src/pages/Agent/store/agentChatStore/actions/previewActions.ts b/src/pages/Agent/store/agentChatStore/actions/previewActions.ts index 03552caa..e5831cb7 100644 --- a/src/pages/Agent/store/agentChatStore/actions/previewActions.ts +++ b/src/pages/Agent/store/agentChatStore/actions/previewActions.ts @@ -70,14 +70,14 @@ export const previewActionsMiddleware: StateCreator { try { set({ previewLoading: true }); const messages = Array.from(get().messages.values()); - // Safety check - if handlerConfig is empty, fail early - if (Object.keys(handlerConfig).length === 0) { + // Safety check - if agentFrameworkConfig is empty, fail early + if (!agentFrameworkConfig || Object.keys(agentFrameworkConfig).length === 0) { set({ previewLoading: false, previewResult: null }); return null; } @@ -93,7 +93,7 @@ export const previewActionsMiddleware: StateCreator Promise; /** Get the handler ID for the current agent */ - getHandlerId: () => Promise; + getAgentFrameworkId: () => Promise; /** Get the configuration schema for the current handler */ getFrameworkConfigSchema: () => Promise>; @@ -188,12 +188,12 @@ export interface PreviewActions { /** * Generates a preview of prompts for the current agent state * @param inputText Input text to include in the preview - * @param handlerConfig Prompt configuration to use for preview + * @param agentFrameworkConfig Framework configuration to use for preview * @returns Promise that resolves when preview is generated and state is updated */ getPreviewPromptResult: ( inputText: string, - handlerConfig: AgentPromptDescription['handlerConfig'], + agentFrameworkConfig: AgentPromptDescription['agentFrameworkConfig'], ) => Promise< { flatPrompts: ModelMessage[]; diff --git a/src/pages/ChatTabContent/components/PromptPreviewDialog/EditView.tsx b/src/pages/ChatTabContent/components/PromptPreviewDialog/EditView.tsx index 39a4305d..6ac1f1bf 100644 --- a/src/pages/ChatTabContent/components/PromptPreviewDialog/EditView.tsx +++ b/src/pages/ChatTabContent/components/PromptPreviewDialog/EditView.tsx @@ -1,4 +1,4 @@ -import { useHandlerConfigManagement } from '@/windows/Preferences/sections/ExternalAPI/useHandlerConfigManagement'; +import { useAgentFrameworkConfigManagement } from '@/windows/Preferences/sections/ExternalAPI/useAgentFrameworkConfigManagement'; import MonacoEditor from '@monaco-editor/react'; import { Box, styled } from '@mui/material'; import Tab from '@mui/material/Tab'; @@ -9,7 +9,7 @@ import React, { FC, SyntheticEvent, useCallback, useEffect, useState } from 'rea import { useTranslation } from 'react-i18next'; import { useShallow } from 'zustand/react/shallow'; -import { HandlerConfig } from '@services/agentInstance/promptConcat/promptConcatSchema'; +import { agentFrameworkConfig } from '@services/agentInstance/promptConcat/promptConcatSchema'; import { useAgentChatStore } from '../../../Agent/store/agentChatStore/index'; import { PromptConfigForm } from './PromptConfigForm'; @@ -40,11 +40,11 @@ export const EditView: FC = ({ ); const { - loading: handlerConfigLoading, - config: handlerConfig, + loading: agentFrameworkConfigLoading, + config: agentFrameworkConfig, schema: handlerSchema, handleConfigChange, - } = useHandlerConfigManagement({ + } = useAgentFrameworkConfigManagement({ agentDefId: agent?.agentDefId, agentId: agent?.id, }); @@ -98,7 +98,7 @@ export const EditView: FC = ({ ); const handleFormChange = useDebouncedCallback( - async (updatedConfig: HandlerConfig) => { + async (updatedConfig: agentFrameworkConfig) => { try { // Ensure the config change is fully persisted before proceeding await handleConfigChange(updatedConfig); @@ -121,7 +121,7 @@ export const EditView: FC = ({ const handleEditorChange = useCallback((value: string | undefined) => { if (!value) return; try { - const parsedConfig = JSON.parse(value) as HandlerConfig; + const parsedConfig = JSON.parse(value) as agentFrameworkConfig; void handleFormChange(parsedConfig); } catch (error) { void window.service.native.log('error', 'EditView: Invalid JSON in code editor:', { error }); @@ -163,16 +163,16 @@ export const EditView: FC = ({ {editorMode === 'form' && ( )} {editorMode === 'code' && ( ; /** Initial form data */ - formData?: HandlerConfig; + formData?: agentFrameworkConfig; /** Change handler for form data */ - onChange?: (formData: HandlerConfig) => void; + onChange?: (formData: agentFrameworkConfig) => void; /** Error handler for form validation errors */ onError?: (errors: RJSFValidationError[]) => void; /** Whether the form is disabled */ @@ -87,7 +87,7 @@ export const PromptConfigForm: React.FC = ({ onError?.(errors); }, [onError]); - const handleChange = useCallback((changeEvent: IChangeEvent) => { + const handleChange = useCallback((changeEvent: IChangeEvent) => { const formData = changeEvent.formData; if (formData) { onChange?.(formData); diff --git a/src/pages/ChatTabContent/components/PromptPreviewDialog/__tests__/PromptPreviewDialog.promptConcat.test.tsx b/src/pages/ChatTabContent/components/PromptPreviewDialog/__tests__/PromptPreviewDialog.promptConcat.test.tsx index 031641ef..58e1b88a 100644 --- a/src/pages/ChatTabContent/components/PromptPreviewDialog/__tests__/PromptPreviewDialog.promptConcat.test.tsx +++ b/src/pages/ChatTabContent/components/PromptPreviewDialog/__tests__/PromptPreviewDialog.promptConcat.test.tsx @@ -15,10 +15,10 @@ import { ModelMessage } from 'ai'; import { PromptPreviewDialog } from '../index'; // Mock handler config management hook -vi.mock('@/windows/Preferences/sections/ExternalAPI/useHandlerConfigManagement', () => ({ - useHandlerConfigManagement: vi.fn(() => ({ +vi.mock('@/windows/Preferences/sections/ExternalAPI/useAgentFrameworkConfigManagement', () => ({ + useAgentFrameworkConfigManagement: vi.fn(() => ({ loading: false, - config: defaultAgents[0].handlerConfig, + config: defaultAgents[0].agentFrameworkConfig, handleConfigChange: vi.fn(), })), })); @@ -64,7 +64,7 @@ describe('PromptPreviewDialog - Tool Information Rendering', () => { expect(globalThis.window?.observables?.agentInstance?.concatPrompt).toBeDefined(); // Create test data matching taskAgents.json - cast to avoid type issues in test - const handlerConfig = defaultAgents[0].handlerConfig as never; + const agentFrameworkConfig = defaultAgents[0].agentFrameworkConfig as never; const messages = [{ id: 'test-message-1', agentId: 'test-agent', @@ -74,7 +74,7 @@ describe('PromptPreviewDialog - Tool Information Rendering', () => { // Call the real concatPrompt implementation const observable = globalThis.window.observables.agentInstance.concatPrompt( - { handlerConfig }, + { agentFrameworkConfig }, messages, ); @@ -118,11 +118,11 @@ describe('PromptPreviewDialog - Tool Information Rendering', () => { it('should render workspaces and tools info from real concatPrompt execution', async () => { // First execute real concatPrompt to get the structured data - const handlerConfig = defaultAgents[0].handlerConfig; + const agentFrameworkConfig = defaultAgents[0].agentFrameworkConfig; const messages = [{ id: 'test', role: 'user' as const, content: 'Hello world', created: new Date(), modified: new Date(), agentId: 'test' }]; - // Pass handlerConfig wrapped (same shape used elsewhere) - const observable = window.observables.agentInstance.concatPrompt({ handlerConfig } as never, messages); + // Pass agentFrameworkConfig wrapped (same shape used elsewhere) + const observable = window.observables.agentInstance.concatPrompt({ agentFrameworkConfig } as never, messages); const results: unknown[] = []; let finalResult: { flatPrompts: ModelMessage[]; processedPrompts: IPrompt[] } | undefined; diff --git a/src/pages/ChatTabContent/components/PromptPreviewDialog/__tests__/PromptPreviewDialog.ui.test.tsx b/src/pages/ChatTabContent/components/PromptPreviewDialog/__tests__/PromptPreviewDialog.ui.test.tsx index 48d1d2d3..8ceb0be2 100644 --- a/src/pages/ChatTabContent/components/PromptPreviewDialog/__tests__/PromptPreviewDialog.ui.test.tsx +++ b/src/pages/ChatTabContent/components/PromptPreviewDialog/__tests__/PromptPreviewDialog.ui.test.tsx @@ -13,10 +13,10 @@ import defaultAgents from '@services/agentInstance/agentFrameworks/taskAgents.js import { PromptPreviewDialog } from '../index'; // Mock handler config management hook -vi.mock('@/windows/Preferences/sections/ExternalAPI/useHandlerConfigManagement', () => ({ - useHandlerConfigManagement: vi.fn(() => ({ +vi.mock('@/windows/Preferences/sections/ExternalAPI/useAgentFrameworkConfigManagement', () => ({ + useAgentFrameworkConfigManagement: vi.fn(() => ({ loading: false, - config: defaultAgents[0].handlerConfig, + config: defaultAgents[0].agentFrameworkConfig, handleConfigChange: vi.fn(), })), })); diff --git a/src/pages/ChatTabContent/components/PromptPreviewDialog/index.tsx b/src/pages/ChatTabContent/components/PromptPreviewDialog/index.tsx index f74eb075..0275da41 100644 --- a/src/pages/ChatTabContent/components/PromptPreviewDialog/index.tsx +++ b/src/pages/ChatTabContent/components/PromptPreviewDialog/index.tsx @@ -1,4 +1,4 @@ -import { useHandlerConfigManagement } from '@/windows/Preferences/sections/ExternalAPI/useHandlerConfigManagement'; +import { useAgentFrameworkConfigManagement } from '@/windows/Preferences/sections/ExternalAPI/useAgentFrameworkConfigManagement'; import CloseIcon from '@mui/icons-material/Close'; import EditIcon from '@mui/icons-material/Edit'; import FullscreenIcon from '@mui/icons-material/Fullscreen'; @@ -36,9 +36,9 @@ export const PromptPreviewDialog: React.FC = ({ const [isEditMode, setIsEditMode] = useState(false); const { - loading: handlerConfigLoading, - config: handlerConfig, - } = useHandlerConfigManagement({ + loading: agentFrameworkConfigLoading, + config: agentFrameworkConfig, + } = useAgentFrameworkConfigManagement({ agentDefId: agent?.agentDefId, agentId: agent?.id, }); @@ -54,17 +54,17 @@ export const PromptPreviewDialog: React.FC = ({ ); useEffect(() => { const fetchInitialPreview = async () => { - if (!agent?.agentDefId || handlerConfigLoading || !handlerConfig || !open) { + if (!agent?.agentDefId || agentFrameworkConfigLoading || !agentFrameworkConfig || !open) { return; } try { - await getPreviewPromptResult(inputText, handlerConfig); + await getPreviewPromptResult(inputText, agentFrameworkConfig); } catch (error) { console.error('PromptPreviewDialog: Error fetching initial preview:', error); } }; void fetchInitialPreview(); - }, [agent?.agentDefId, handlerConfig, handlerConfigLoading, inputText, open]); // 移除 getPreviewPromptResult + }, [agent?.agentDefId, agentFrameworkConfig, agentFrameworkConfigLoading, inputText, open]); // 移除 getPreviewPromptResult const handleToggleFullScreen = useCallback((): void => { setIsFullScreen(previous => !previous); diff --git a/src/services/agentDefinition/__tests__/index.test.ts b/src/services/agentDefinition/__tests__/index.test.ts index 18a7b6a7..d4c76bbe 100644 --- a/src/services/agentDefinition/__tests__/index.test.ts +++ b/src/services/agentDefinition/__tests__/index.test.ts @@ -90,12 +90,13 @@ describe('AgentDefinitionService getAgentDefs integration', () => { const defs = await freshService.getAgentDefs(); expect(defs.length).toBeGreaterThan(0); - const exampleAgent = defs.find(d => d.id === (defaultAgents as AgentDefinition[])[0].id); + // Fixed + const exampleAgent = defs.find(d => d.id === (defaultAgents as unknown as AgentDefinition[])[0].id); expect(exampleAgent).toBeDefined(); expect(exampleAgent!.name).toBeDefined(); - expect(exampleAgent!.handlerID).toBeDefined(); - expect(exampleAgent!.handlerConfig).toBeDefined(); - expect(typeof exampleAgent!.handlerConfig).toBe('object'); + expect(exampleAgent!.agentFrameworkID).toBeDefined(); + expect(exampleAgent!.agentFrameworkConfig).toBeDefined(); + expect(typeof exampleAgent!.agentFrameworkConfig).toBe('object'); }); it('should return only database data without fallback to defaultAgents', async () => { @@ -105,7 +106,7 @@ describe('AgentDefinitionService getAgentDefs integration', () => { const agentDefRepo = realDataSource.getRepository(AgentDefinitionEntity); // Save only minimal record (id only) to test new behavior - const example = (defaultAgents as AgentDefinition[])[0]; + const example = (defaultAgents as unknown as AgentDefinition[])[0]; await agentDefRepo.save({ id: example.id, }); @@ -116,11 +117,11 @@ describe('AgentDefinitionService getAgentDefs integration', () => { expect(found).toBeDefined(); // With new behavior, only id should be present, other fields should be undefined or empty expect(found!.id).toBe(example.id); - expect(found!.handlerID).toBeUndefined(); + expect(found!.agentFrameworkID).toBeUndefined(); expect(found!.name).toBeUndefined(); expect(found!.description).toBeUndefined(); expect(found!.avatarUrl).toBeUndefined(); - expect(found!.handlerConfig).toEqual({}); + expect(found!.agentFrameworkConfig).toEqual({}); expect(found!.aiApiConfig).toBeUndefined(); expect(found!.agentTools).toBeUndefined(); }); @@ -132,7 +133,7 @@ describe('AgentDefinitionService getAgentDefs integration', () => { const agentDefRepo = realDataSource.getRepository(AgentDefinitionEntity); // Save only minimal record (id only) as per new behavior - const example = (defaultAgents as AgentDefinition[])[0]; + const example = (defaultAgents as unknown as AgentDefinition[])[0]; await agentDefRepo.save({ id: example.id, }); @@ -148,8 +149,8 @@ describe('AgentDefinitionService getAgentDefs integration', () => { expect(entity!.name).toBeNull(); expect(entity!.description).toBeNull(); expect(entity!.avatarUrl).toBeNull(); - expect(entity!.handlerID).toBeNull(); - expect(entity!.handlerConfig).toBeNull(); + expect(entity!.agentFrameworkID).toBeNull(); + expect(entity!.agentFrameworkConfig).toBeNull(); expect(entity!.aiApiConfig).toBeNull(); expect(entity!.agentTools).toBeNull(); }); @@ -158,15 +159,15 @@ describe('AgentDefinitionService getAgentDefs integration', () => { const templates = await agentDefinitionService.getAgentTemplates(); // Should include all default agents - expect(templates.length).toBe((defaultAgents as AgentDefinition[]).length); + expect(templates.length).toBe((defaultAgents as unknown as AgentDefinition[]).length); // Check that template has complete data from taskAgents.json - const exampleTemplate = templates.find(t => t.id === (defaultAgents as AgentDefinition[])[0].id); + const exampleTemplate = templates.find(t => t.id === (defaultAgents as unknown as AgentDefinition[])[0].id); expect(exampleTemplate).toBeDefined(); expect(exampleTemplate!.name).toBeDefined(); - expect(exampleTemplate!.handlerID).toBeDefined(); - expect(exampleTemplate!.handlerConfig).toBeDefined(); - expect(typeof exampleTemplate!.handlerConfig).toBe('object'); + expect(exampleTemplate!.agentFrameworkID).toBeDefined(); + expect(exampleTemplate!.agentFrameworkConfig).toBeDefined(); + expect(typeof exampleTemplate!.agentFrameworkConfig).toBe('object'); }); it('should not throw when searchName filtering is requested (client-side filtering expected)', async () => { @@ -185,6 +186,6 @@ describe('AgentDefinitionService getAgentDefs integration', () => { // Should still return default agents and not throw const templates = await agentDefinitionService.getAgentTemplates(); - expect(templates.length).toBe((defaultAgents as AgentDefinition[]).length); + expect(templates.length).toBe((defaultAgents as unknown as AgentDefinition[]).length); }); }); diff --git a/src/services/agentDefinition/getAgentDefinitionTemplatesFromWikis.ts b/src/services/agentDefinition/getAgentDefinitionTemplatesFromWikis.ts index cef54beb..291d7205 100644 --- a/src/services/agentDefinition/getAgentDefinitionTemplatesFromWikis.ts +++ b/src/services/agentDefinition/getAgentDefinitionTemplatesFromWikis.ts @@ -116,21 +116,21 @@ export function validateAndConvertWikiTiddlerToAgentTemplate( }; // Try to parse the tiddler text as JSON for agent configuration - let handlerConfig: Record; + let agentFrameworkConfig: Record; try { const textContent = typeof tiddler.text === 'string' ? tiddler.text : JSON.stringify(tiddler.text || '{}'); const parsed = JSON.parse(textContent) as unknown; - // Ensure handlerConfig is a valid object + // Ensure agentFrameworkConfig is a valid object if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { - logger.warn('Invalid handlerConfig in tiddler', { + logger.warn('Invalid agentFrameworkConfig in tiddler', { function: 'validateAndConvertWikiTiddlerToAgentTemplate', title: getStringField(tiddler.title), reason: 'not an object', }); return null; } - handlerConfig = parsed as Record; + agentFrameworkConfig = parsed as Record; } catch (parseError) { logger.warn('Failed to parse agent template from tiddler', { function: 'validateAndConvertWikiTiddlerToAgentTemplate', @@ -146,8 +146,8 @@ export function validateAndConvertWikiTiddlerToAgentTemplate( name: getStringField(tiddler.caption) || getStringField(tiddler.title), description: getStringField(tiddler.description) || `Agent template from ${workspaceName || 'wiki'}`, avatarUrl: getStringField(tiddler.avatar_url) || undefined, - handlerID: getStringField(tiddler.handler_id) || 'basicPromptConcatHandler', - handlerConfig, + agentFrameworkID: getStringField(tiddler.agentFrameworkID) || 'basicPromptConcatHandler', + agentFrameworkConfig, aiApiConfig: parseAiApiConfig(tiddler.ai_api_config), agentTools: parseAgentTools(tiddler.agent_tools), }; diff --git a/src/services/agentDefinition/index.ts b/src/services/agentDefinition/index.ts index fd3fb317..ba734029 100644 --- a/src/services/agentDefinition/index.ts +++ b/src/services/agentDefinition/index.ts @@ -78,8 +78,8 @@ export class AgentDefinitionService implements IAgentDefinitionService { name: defaultAgent.name, description: defaultAgent.description, avatarUrl: defaultAgent.avatarUrl, - handlerID: defaultAgent.handlerID, - handlerConfig: defaultAgent.handlerConfig, + agentFrameworkID: defaultAgent.agentFrameworkID, + agentFrameworkConfig: defaultAgent.agentFrameworkConfig, aiApiConfig: defaultAgent.aiApiConfig, agentTools: defaultAgent.agentTools, }) @@ -143,7 +143,7 @@ export class AgentDefinitionService implements IAgentDefinitionService { throw new Error(`Agent definition not found: ${agent.id}`); } - const pickedProperties = pick(agent, ['name', 'description', 'avatarUrl', 'handlerID', 'handlerConfig', 'aiApiConfig']); + const pickedProperties = pick(agent, ['name', 'description', 'avatarUrl', 'agentFrameworkID', 'agentFrameworkConfig', 'aiApiConfig']); Object.assign(existingAgent, pickedProperties); await this.agentDefRepository!.save(existingAgent); @@ -171,8 +171,8 @@ export class AgentDefinitionService implements IAgentDefinitionService { name: entity.name || undefined, description: entity.description || undefined, avatarUrl: entity.avatarUrl || undefined, - handlerID: entity.handlerID || undefined, - handlerConfig: entity.handlerConfig || {}, + agentFrameworkID: entity.agentFrameworkID || undefined, + agentFrameworkConfig: entity.agentFrameworkConfig || {}, aiApiConfig: entity.aiApiConfig || undefined, agentTools: entity.agentTools || undefined, })); @@ -212,8 +212,8 @@ export class AgentDefinitionService implements IAgentDefinitionService { name: entity.name || undefined, description: entity.description || undefined, avatarUrl: entity.avatarUrl || undefined, - handlerID: entity.handlerID || undefined, - handlerConfig: entity.handlerConfig || {}, + agentFrameworkID: entity.agentFrameworkID || undefined, + agentFrameworkConfig: entity.agentFrameworkConfig || {}, aiApiConfig: entity.aiApiConfig || undefined, agentTools: entity.agentTools || undefined, }; diff --git a/src/services/agentDefinition/interface.ts b/src/services/agentDefinition/interface.ts index b595fe6d..8f97798e 100644 --- a/src/services/agentDefinition/interface.ts +++ b/src/services/agentDefinition/interface.ts @@ -42,10 +42,10 @@ export interface AgentDefinition { description?: string; /** Agent icon or avatar URL */ avatarUrl?: string; - /** Agent handler function's id, we will find function by this id */ - handlerID?: string; - /** Agent handler's config, specific to the handler. This is required to ensure agent has valid configuration. */ - handlerConfig: Record; + /** Agent framework function's id, we will find function by this id */ + agentFrameworkID?: string; + /** Agent framework's config, specific to the framework. This is required to ensure agent has valid configuration. */ + agentFrameworkConfig: Record; /** * Overwrite the default AI configuration for this agent. * Priority is higher than the global default agent config. diff --git a/src/services/agentInstance/__tests__/index.failure.test.ts b/src/services/agentInstance/__tests__/index.failure.test.ts index bc909d47..e8f628e9 100644 --- a/src/services/agentInstance/__tests__/index.failure.test.ts +++ b/src/services/agentInstance/__tests__/index.failure.test.ts @@ -78,7 +78,7 @@ describe('AgentInstance failure path - external API logs on error', () => { agentDef: { id: 'def-1', name: 'Def 1', - handlerConfig: {}, + agentFrameworkConfig: {}, aiApiConfig: { api: { provider: 'test-provider', model: 'test-model' }, modelParameters: { temperature: 0.7, systemPrompt: '', topP: 0.95 } }, }, isCancelled: () => false, diff --git a/src/services/agentInstance/__tests__/index.streaming.test.ts b/src/services/agentInstance/__tests__/index.streaming.test.ts index b2a5ba39..da86c696 100644 --- a/src/services/agentInstance/__tests__/index.streaming.test.ts +++ b/src/services/agentInstance/__tests__/index.streaming.test.ts @@ -73,7 +73,7 @@ describe('AgentInstanceService Streaming Behavior', () => { // Mock agent definition service to return our test agent definition mockAgentDefinitionService.getAgentDef = vi.fn().mockResolvedValue({ ...exampleAgent, - handlerID: 'basicPromptConcatHandler', + agentFrameworkID: 'basicPromptConcatHandler', }); // Mock the getAgent method to return our test instance vi.spyOn(agentInstanceService, 'getAgent').mockResolvedValue(testAgentInstance); diff --git a/src/services/agentInstance/__tests__/utilities.test.ts b/src/services/agentInstance/__tests__/utilities.test.ts index 7d4168f6..63865577 100644 --- a/src/services/agentInstance/__tests__/utilities.test.ts +++ b/src/services/agentInstance/__tests__/utilities.test.ts @@ -2,11 +2,11 @@ import { describe, expect, it } from 'vitest'; import { createAgentInstanceData } from '../utilities'; describe('createAgentInstanceData', () => { - it('should create agent instance with undefined handlerConfig (fallback to definition)', () => { + it('should create agent instance with undefined agentFrameworkConfig (fallback to definition)', () => { const agentDefinition = { id: 'test-agent-def', name: 'Test Agent', - handlerConfig: { + agentFrameworkConfig: { prompts: [ { text: 'You are a helpful assistant.', @@ -14,29 +14,29 @@ describe('createAgentInstanceData', () => { }, ], }, - handlerID: 'basicPromptConcatHandler', + agentFrameworkID: 'basicPromptConcatHandler', }; const { instanceData } = createAgentInstanceData(agentDefinition); - expect(instanceData.handlerConfig).toBeUndefined(); + expect(instanceData.agentFrameworkConfig).toBeUndefined(); expect(instanceData.agentDefId).toBe('test-agent-def'); - expect(instanceData.handlerID).toBe('basicPromptConcatHandler'); + expect(instanceData.agentFrameworkID).toBe('basicPromptConcatHandler'); expect(instanceData.name).toContain('Test Agent'); }); - it('should create agent instance with undefined handlerConfig even when definition has required handlerConfig', () => { + it('should create agent instance with undefined agentFrameworkConfig even when definition has required agentFrameworkConfig', () => { const agentDefinition = { id: 'test-agent-def-no-config', name: 'Test Agent No Config', - handlerID: 'basicPromptConcatHandler', - handlerConfig: {}, // Required by AgentDefinition interface + agentFrameworkID: 'basicPromptConcatHandler', + agentFrameworkConfig: {}, // Required by AgentDefinition interface }; const { instanceData } = createAgentInstanceData(agentDefinition); - expect(instanceData.handlerConfig).toBeUndefined(); + expect(instanceData.agentFrameworkConfig).toBeUndefined(); expect(instanceData.agentDefId).toBe('test-agent-def-no-config'); - expect(instanceData.handlerID).toBe('basicPromptConcatHandler'); + expect(instanceData.agentFrameworkID).toBe('basicPromptConcatHandler'); }); }); diff --git a/src/services/agentInstance/agentFrameworks/__tests__/taskAgent.failure.test.ts b/src/services/agentInstance/agentFrameworks/__tests__/taskAgent.failure.test.ts index c8d6f004..f078def5 100644 --- a/src/services/agentInstance/agentFrameworks/__tests__/taskAgent.failure.test.ts +++ b/src/services/agentInstance/agentFrameworks/__tests__/taskAgent.failure.test.ts @@ -33,7 +33,7 @@ function makeContext(agentId: string, agentDefId: string, messages: AgentInstanc agentDef: { id: agentDefId, name: 'Test Agent', - handlerConfig: {}, + agentFrameworkConfig: {}, aiApiConfig: { api: { provider: 'test-provider', model: 'test-model' }, modelParameters: { temperature: 0.7, systemPrompt: '', topP: 0.95 } } as AiAPIConfig, }, isCancelled: () => false, @@ -94,8 +94,8 @@ describe('basicPromptConcatHandler - failure path persists error message and log vi.spyOn(agentDefSvc, 'getAgentDef').mockResolvedValue({ id: 'def-1', name: 'Def 1', - handlerID: 'basicPromptConcatHandler', - handlerConfig: { + agentFrameworkID: 'basicPromptConcatHandler', + agentFrameworkConfig: { plugins: [ { toolId: 'wikiOperation', wikiOperationParam: {} }, ], diff --git a/src/services/agentInstance/agentFrameworks/__tests__/taskAgent.test.ts b/src/services/agentInstance/agentFrameworks/__tests__/taskAgent.test.ts index b8452b7a..4f48b143 100644 --- a/src/services/agentInstance/agentFrameworks/__tests__/taskAgent.test.ts +++ b/src/services/agentInstance/agentFrameworks/__tests__/taskAgent.test.ts @@ -1,4 +1,4 @@ -/** +/** * Integration tests for promptConcatStream with wikiSearch plugin * Tests the complete workflow: tool list injection -> AI response -> tool execution -> next round * Includes yieldNextRoundTo mechanism testing with basicPromptConcatHandler @@ -90,14 +90,14 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { it('should complete full wiki search workflow: tool list -> tool execution -> response', async () => { // Use real agent config from taskAgents.json const exampleAgent = defaultAgents[0]; - const handlerConfig = exampleAgent.handlerConfig; + const agentFrameworkConfig = exampleAgent.agentFrameworkConfig; // Get the wiki search tool configuration - const wikiPlugin = handlerConfig.plugins.find(p => p.toolId === 'wikiSearch'); + const wikiPlugin = agentFrameworkConfig.plugins.find(p => p.toolId === 'wikiSearch'); expect(wikiPlugin).toBeDefined(); if (!wikiPlugin) throw new Error('wikiPlugin not found'); - const prompts = JSON.parse(JSON.stringify(handlerConfig.prompts)); + const prompts = JSON.parse(JSON.stringify(agentFrameworkConfig.prompts)); // Phase 1: Tool List Injection const promptConcatHookContext: PromptConcatHookContext = { @@ -108,9 +108,9 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { agentDefId: exampleAgent.id, status: { state: 'working' as const, modified: new Date() }, created: new Date(), - handlerConfig: {}, + agentFrameworkConfig: {}, }, - agentDef: { id: exampleAgent.id, name: exampleAgent.name, handlerConfig: exampleAgent.handlerConfig }, + agentDef: { id: exampleAgent.id, name: exampleAgent.name, agentFrameworkConfig: exampleAgent.agentFrameworkConfig }, isCancelled: () => false, }, toolConfig: wikiPlugin as IPromptConcatTool, @@ -127,10 +127,10 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { ], }; - // Create hooks and register tools as defined in handlerConfig - const { hooks: promptHooks } = await createHooksWithTools(handlerConfig); + // Create hooks and register tools as defined in agentFrameworkConfig + const { hooks: promptHooks } = await createHooksWithTools(agentFrameworkConfig); // First run workspacesList tool to inject available workspaces (if present) - const workspacesPlugin = handlerConfig.plugins?.find(p => p.toolId === 'workspacesList'); + const workspacesPlugin = agentFrameworkConfig.plugins?.find(p => p.toolId === 'workspacesList'); if (workspacesPlugin) { const workspacesContext = { ...promptConcatHookContext, toolConfig: workspacesPlugin } as unknown as PromptConcatHookContext; await promptHooks.processPrompts.promise(workspacesContext); @@ -179,9 +179,9 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { }, created: new Date(), messages: [], - handlerConfig: {}, + agentFrameworkConfig: {}, }, - agentDef: { id: 'test-agent-def', name: 'test-agent-def', handlerConfig: {} } as AgentDefinition, + agentDef: { id: 'test-agent-def', name: 'test-agent-def', agentFrameworkConfig: {} } as unknown as AgentDefinition, isCancelled: () => false, }, response: { @@ -199,8 +199,8 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { actions: {} as unknown as Record, }; - // Use hooks registered with all plugins from handlerConfig - const { hooks: responseHooks } = await createHooksWithTools(handlerConfig); + // Use hooks registered with all plugins from agentFrameworkConfig + const { hooks: responseHooks } = await createHooksWithTools(agentFrameworkConfig); // Execute the response complete hook await responseHooks.responseComplete.promise(responseContext); // reuse containerForAssert from above assertions @@ -224,10 +224,10 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { it('should handle errors in wiki search gracefully', async () => { // Use real agent config from taskAgents.json const exampleAgent = defaultAgents[0]; - const handlerConfig = exampleAgent.handlerConfig; + const agentFrameworkConfig = exampleAgent.agentFrameworkConfig; // Get the wiki search tool configuration - const wikiPlugin = handlerConfig.plugins.find(p => p.toolId === 'wikiSearch'); + const wikiPlugin = agentFrameworkConfig.plugins.find(p => p.toolId === 'wikiSearch'); expect(wikiPlugin).toBeDefined(); // Mock tool calling with invalid workspace @@ -243,9 +243,9 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { }, created: new Date(), messages: [], - handlerConfig: {}, + agentFrameworkConfig: {}, }, - agentDef: { id: 'test-agent-def', name: 'test-agent-def', handlerConfig: {} } as AgentDefinition, + agentDef: { id: 'test-agent-def', name: 'test-agent-def', agentFrameworkConfig: {} } as unknown as AgentDefinition, isCancelled: () => false, }, response: { @@ -315,7 +315,7 @@ describe('WikiSearch Plugin Integration & YieldNextRound Mechanism', () => { agentDef: { id: exampleAgent.id, name: exampleAgent.name, - handlerConfig: exampleAgent.handlerConfig, + agentFrameworkConfig: exampleAgent.agentFrameworkConfig, }, isCancelled: () => false, }; diff --git a/src/services/agentInstance/agentFrameworks/taskAgent.ts b/src/services/agentInstance/agentFrameworks/taskAgent.ts index 76619606..939f3414 100644 --- a/src/services/agentInstance/agentFrameworks/taskAgent.ts +++ b/src/services/agentInstance/agentFrameworks/taskAgent.ts @@ -4,7 +4,7 @@ import { logger } from '@services/libs/log'; import serviceIdentifier from '@services/serviceIdentifier'; import { merge } from 'lodash'; import type { AgentInstanceLatestStatus, AgentInstanceMessage, IAgentInstanceService } from '../interface'; -import { AgentPromptDescription, AiAPIConfig, HandlerConfig } from '../promptConcat/promptConcatSchema'; +import { AgentFrameworkConfig, AgentPromptDescription, AiAPIConfig } from '../promptConcat/promptConcatSchema'; import type { IPromptConcatTool } from '../promptConcat/promptConcatSchema/plugin'; import { responseConcat } from '../promptConcat/responseConcat'; import { getFinalPromptResult } from '../promptConcat/utilities'; @@ -31,15 +31,15 @@ export async function* basicPromptConcatHandler(context: AgentFrameworkContext) // Initialize variables for request tracking let currentRequestId: string | undefined; const lastUserMessage: AgentInstanceMessage | undefined = context.agent.messages[context.agent.messages.length - 1]; - // Create and register handler hooks based on handler config - const { hooks: agentFrameworkHooks, toolConfigs } = await createHooksWithTools(context.agentDef.handlerConfig || {}); + // Create and register handler hooks based on framework config + const { hooks: agentFrameworkHooks, toolConfigs } = await createHooksWithTools(context.agentDef.agentFrameworkConfig || {}); // Log the start of handler execution with context information logger.debug('Starting prompt handler execution', { method: 'basicPromptConcatHandler', agentId: context.agent.id, defId: context.agentDef.id, - handlerId: context.agentDef.handlerID, + agentFrameworkId: context.agentDef.agentFrameworkID, messageCount: context.agent.messages.length, }); // Check if there's a new user message to process - trigger user message received hook @@ -94,12 +94,12 @@ export async function* basicPromptConcatHandler(context: AgentFrameworkContext) // Process prompts using common handler function try { - const handlerConfig: HandlerConfig = context.agentDef.handlerConfig as HandlerConfig; + const agentFrameworkConfig = context.agentDef.agentFrameworkConfig as AgentFrameworkConfig; const agentPromptDescription: AgentPromptDescription = { id: context.agentDef.id, api: aiApiConfig.api, modelParameters: aiApiConfig.modelParameters, - handlerConfig, + agentFrameworkConfig, }; const agentInstanceService = container.get(serviceIdentifier.AgentInstance); @@ -169,7 +169,7 @@ export async function* basicPromptConcatHandler(context: AgentFrameworkContext) requestId: currentRequestId, isFinal: true, toolConfig: (toolConfigs.length > 0 ? toolConfigs[0] : {}) as IPromptConcatTool, // First config for compatibility - agentFrameworkConfig: context.agentDef.handlerConfig, // Pass complete config for tool access + agentFrameworkConfig: context.agentDef.agentFrameworkConfig, // Pass complete config for tool access actions: undefined as { yieldNextRoundTo?: 'self' | 'human'; newUserMessage?: string } | undefined, }; diff --git a/src/services/agentInstance/agentFrameworks/taskAgents.json b/src/services/agentInstance/agentFrameworks/taskAgents.json index 0b39485f..90dd74dd 100644 --- a/src/services/agentInstance/agentFrameworks/taskAgents.json +++ b/src/services/agentInstance/agentFrameworks/taskAgents.json @@ -4,8 +4,8 @@ "name": "Task Agent", "description": "Example agent with prompt processing", "avatarUrl": "https://example.com/task-agent.png", - "handlerID": "basicPromptConcatHandler", - "handlerConfig": { + "agentFrameworkID": "basicPromptConcatHandler", + "agentFrameworkConfig": { "prompts": [ { "id": "system", diff --git a/src/services/agentInstance/index.ts b/src/services/agentInstance/index.ts index c9e5bfee..b6314e02 100644 --- a/src/services/agentInstance/index.ts +++ b/src/services/agentInstance/index.ts @@ -9,7 +9,7 @@ import { basicPromptConcatHandler } from '@services/agentInstance/agentFramework import type { AgentFramework, AgentFrameworkContext } from '@services/agentInstance/agentFrameworks/utilities/type'; import { promptConcatStream, PromptConcatStreamState } from '@services/agentInstance/promptConcat/promptConcat'; import type { AgentPromptDescription } from '@services/agentInstance/promptConcat/promptConcatSchema'; -import { getPromptConcatHandlerConfigJsonSchema } from '@services/agentInstance/promptConcat/promptConcatSchema/jsonSchema'; +import { getPromptConcatAgentFrameworkConfigJsonSchema } from '@services/agentInstance/promptConcat/promptConcatSchema/jsonSchema'; import { createHooksWithTools, initializeToolSystem } from '@services/agentInstance/tools'; import type { IDatabaseService } from '@services/database/interface'; import { AgentInstanceEntity, AgentInstanceMessageEntity } from '@services/database/schema/agent'; @@ -80,7 +80,7 @@ export class AgentInstanceService implements IAgentInstanceService { public registerBuiltinFrameworks(): void { // Tools are already registered in initialize(), so we only register frameworks here // Register basic prompt concatenation framework with its schema - this.registerFramework('basicPromptConcatHandler', basicPromptConcatHandler, getPromptConcatHandlerConfigJsonSchema()); + this.registerFramework('basicPromptConcatHandler', basicPromptConcatHandler, getPromptConcatAgentFrameworkConfigJsonSchema()); } /** @@ -216,7 +216,7 @@ export class AgentInstanceService implements IAgentInstanceService { } // Update fields using pick + Object.assign for consistency with updateAgentDef - const pickedProperties = pick(data, ['name', 'status', 'avatarUrl', 'aiApiConfig', 'closed', 'handlerConfig']); + const pickedProperties = pick(data, ['name', 'status', 'avatarUrl', 'aiApiConfig', 'closed', 'agentFrameworkConfig']); Object.assign(instanceEntity, pickedProperties); // Save instance updates @@ -354,13 +354,13 @@ export class AgentInstanceService implements IAgentInstanceService { } // Get appropriate framework - const handlerId = agentDefinition.handlerID; - if (!handlerId) { - throw new Error(`Handler ID not found in agent definition: ${agentDefinition.id}`); + const agentFrameworkId = agentDefinition.agentFrameworkID; + if (!agentFrameworkId) { + throw new Error(`Agent framework ID not found in agent definition: ${agentDefinition.id}`); } - const framework = this.agentFrameworks.get(handlerId); + const framework = this.agentFrameworks.get(agentFrameworkId); if (!framework) { - throw new Error(`Framework not found: ${handlerId}`); + throw new Error(`Framework not found: ${agentFrameworkId}`); } // Create framework context with temporary message added for processing @@ -380,7 +380,7 @@ export class AgentInstanceService implements IAgentInstanceService { }; // Create fresh hooks for this framework execution and register tools based on frameworkConfig - const { hooks: frameworkHooks } = await createHooksWithTools(agentDefinition.handlerConfig || {}); + const { hooks: frameworkHooks } = await createHooksWithTools(agentDefinition.agentFrameworkConfig || {}); // Trigger userMessageReceived hook with the configured tools await frameworkHooks.userMessageReceived.promise({ @@ -848,10 +848,10 @@ export class AgentInstanceService implements IAgentInstanceService { } } - public concatPrompt(promptDescription: Pick, messages: AgentInstanceMessage[]): Observable { + public concatPrompt(promptDescription: Pick, messages: AgentInstanceMessage[]): Observable { logger.debug('AgentInstanceService.concatPrompt called', { - hasPromptConfig: !!promptDescription.handlerConfig, - promptConfigKeys: Object.keys(promptDescription.handlerConfig), + hasPromptConfig: !!promptDescription.agentFrameworkConfig, + promptConfigKeys: Object.keys(promptDescription.agentFrameworkConfig || {}), messagesCount: messages.length, }); @@ -866,9 +866,9 @@ export class AgentInstanceService implements IAgentInstanceService { agentDefId: 'temp', status: { state: 'working' as const, modified: new Date() }, created: new Date(), - handlerConfig: {}, + agentFrameworkConfig: {}, }, - agentDef: { id: 'temp', name: 'temp', handlerConfig: promptDescription.handlerConfig }, + agentDef: { id: 'temp', name: 'temp', agentFrameworkConfig: promptDescription.agentFrameworkConfig || {} }, isCancelled: () => false, }; diff --git a/src/services/agentInstance/interface.ts b/src/services/agentInstance/interface.ts index c7341cd3..3a4f92cc 100644 --- a/src/services/agentInstance/interface.ts +++ b/src/services/agentInstance/interface.ts @@ -8,16 +8,16 @@ import { AgentPromptDescription } from '@services/agentInstance/promptConcat/pro /** * Content of a session instance that user chat with an agent. - * Inherits from AgentDefinition but makes handlerConfig optional to allow fallback. + * Inherits from AgentDefinition but makes agentFrameworkConfig optional to allow fallback. * The instance can override the definition's configuration, or fall back to using it. */ -export interface AgentInstance extends Omit { +export interface AgentInstance extends Omit { /** Agent description ID that generates this instance */ agentDefId: string; /** Session name, optional in instance unlike definition */ name?: string; - /** Agent handler's config - optional, falls back to AgentDefinition.handlerConfig if not set */ - handlerConfig?: Record; + /** Agent framework's config - optional, falls back to AgentDefinition.agentFrameworkConfig if not set */ + agentFrameworkConfig?: Record; /** * Message history. * latest on top, so it's easy to get first one as user's latest input, and rest as history. @@ -196,12 +196,12 @@ export interface IAgentInstanceService { * @param messages Messages to be included in prompt generation * @returns Observable stream of processing states, with final state containing complete results */ - concatPrompt(promptDescription: Pick, messages: AgentInstanceMessage[]): Observable; + concatPrompt(promptDescription: Pick, messages: AgentInstanceMessage[]): Observable; /** * Get JSON Schema for handler configuration * This allows frontend to generate a form based on the schema for a specific handler - * @param handlerId Handler ID to get schema for + * @param agentFrameworkID Handler ID to get schema for * @returns JSON Schema for handler configuration */ getFrameworkConfigSchema(frameworkId: string): Record; diff --git a/src/services/agentInstance/promptConcat/promptConcat.ts b/src/services/agentInstance/promptConcat/promptConcat.ts index cbb15705..9ad2456e 100644 --- a/src/services/agentInstance/promptConcat/promptConcat.ts +++ b/src/services/agentInstance/promptConcat/promptConcat.ts @@ -203,13 +203,13 @@ export interface PromptConcatStreamState { * Yields intermediate results for real-time UI updates */ export async function* promptConcatStream( - agentConfig: Pick, + agentConfig: Pick, messages: AgentInstanceMessage[], agentFrameworkContext: AgentFrameworkContext, ): AsyncGenerator { - const agentFrameworkConfig = agentConfig.handlerConfig; - const promptConfigs = Array.isArray(agentFrameworkConfig.prompts) ? agentFrameworkConfig.prompts : []; - const toolConfigs = (Array.isArray(agentFrameworkConfig.plugins) ? agentFrameworkConfig.plugins : []) as IPromptConcatTool[]; + const agentFrameworkConfig = agentConfig.agentFrameworkConfig; + const promptConfigs = Array.isArray(agentFrameworkConfig?.prompts) ? agentFrameworkConfig.prompts : []; + const toolConfigs = (Array.isArray(agentFrameworkConfig?.plugins) ? agentFrameworkConfig.plugins : []) as IPromptConcatTool[]; const promptsCopy = cloneDeep(promptConfigs); const sourcePaths = generateSourcePaths(promptsCopy, toolConfigs); @@ -342,7 +342,7 @@ export async function* promptConcatStream( * @returns Processed prompt array and original prompt tree */ export async function promptConcat( - agentConfig: Pick, + agentConfig: Pick, messages: AgentInstanceMessage[], agentFrameworkContext: AgentFrameworkContext, ): Promise<{ diff --git a/src/services/agentInstance/promptConcat/promptConcatSchema/index.ts b/src/services/agentInstance/promptConcat/promptConcatSchema/index.ts index 24ce890d..d7de9f77 100644 --- a/src/services/agentInstance/promptConcat/promptConcatSchema/index.ts +++ b/src/services/agentInstance/promptConcat/promptConcatSchema/index.ts @@ -72,7 +72,7 @@ export function getFrameworkConfigSchema() { * "model": "Qwen/Qwen2.5-7B-Instruct" * }, * "modelParameters": { ... }, - * "handlerConfig": { + * "agentFrameworkConfig": { * "prompts": [ ... ], * "response": [ ... ], * "plugins": [ ... ], @@ -88,7 +88,7 @@ export function getAgentConfigSchema() { title: t('Schema.AgentConfig.IdTitle'), description: t('Schema.AgentConfig.Id'), }), - handlerConfig: dynamicFrameworkConfigSchema, + agentFrameworkConfig: dynamicFrameworkConfigSchema, }).meta({ title: t('Schema.AgentConfig.Title'), description: t('Schema.AgentConfig.Description'), @@ -110,7 +110,9 @@ export function getDefaultAgentsSchema() { export type DefaultAgents = z.infer>; export type AgentPromptDescription = z.infer>; export type AiAPIConfig = z.infer; -export type HandlerConfig = z.infer>; +export type AgentFrameworkConfig = z.infer>; +// Backward compat alias +export type agentFrameworkConfig = AgentFrameworkConfig; // Re-export all schemas and types export * from './modelParameters'; diff --git a/src/services/agentInstance/promptConcat/promptConcatSchema/jsonSchema.ts b/src/services/agentInstance/promptConcat/promptConcatSchema/jsonSchema.ts index 19fbb871..c6d7cb8a 100644 --- a/src/services/agentInstance/promptConcat/promptConcatSchema/jsonSchema.ts +++ b/src/services/agentInstance/promptConcat/promptConcatSchema/jsonSchema.ts @@ -11,7 +11,7 @@ import { getFrameworkConfigSchema } from './index'; * * Description field is i18n key, use i18nAlly extension to see it on VSCode. And use react-i18next to translate it on frontend. */ -export function getPromptConcatHandlerConfigJsonSchema() { +export function getPromptConcatAgentFrameworkConfigJsonSchema() { const dynamicFrameworkConfigSchema = getFrameworkConfigSchema(); return z.toJSONSchema(dynamicFrameworkConfigSchema, { target: 'draft-7' }); } diff --git a/src/services/agentInstance/promptConcat/responseConcat.ts b/src/services/agentInstance/promptConcat/responseConcat.ts index de1e886b..8eaa6afb 100644 --- a/src/services/agentInstance/promptConcat/responseConcat.ts +++ b/src/services/agentInstance/promptConcat/responseConcat.ts @@ -11,7 +11,7 @@ import { AgentInstanceMessage } from '../interface'; import { builtInTools, createAgentFrameworkHooks } from '../tools'; import { AgentResponse, PostProcessContext, YieldNextRoundTarget } from '../tools/types'; import type { IPromptConcatTool } from './promptConcatSchema'; -import { AgentPromptDescription, HandlerConfig } from './promptConcatSchema'; +import { AgentFrameworkConfig, AgentPromptDescription } from './promptConcatSchema'; /** * Process response configuration, apply plugins, and return final response @@ -38,9 +38,8 @@ export async function responseConcat( responseLength: llmResponse.length, }); - const { handlerConfig } = agentConfig; - const agentFrameworkConfig = handlerConfig; - const responses: HandlerConfig['response'] = Array.isArray(agentFrameworkConfig.response) ? agentFrameworkConfig.response : []; + const { agentFrameworkConfig } = agentConfig; + const responses: AgentFrameworkConfig['response'] = Array.isArray(agentFrameworkConfig?.response) ? (agentFrameworkConfig?.response || []) : []; const toolConfigs = (Array.isArray(agentFrameworkConfig.plugins) ? agentFrameworkConfig.plugins : []) as IPromptConcatTool[]; let modifiedResponses = cloneDeep(responses) as AgentResponse[]; diff --git a/src/services/agentInstance/tools/__tests__/fullReplacementPlugin.duration.test.ts b/src/services/agentInstance/tools/__tests__/fullReplacementPlugin.duration.test.ts index ef4e78a5..a77c2713 100644 --- a/src/services/agentInstance/tools/__tests__/fullReplacementPlugin.duration.test.ts +++ b/src/services/agentInstance/tools/__tests__/fullReplacementPlugin.duration.test.ts @@ -1,4 +1,4 @@ -/** +/** * Tests for Full Replacement plugin duration mechanism * Tests that expired messages (with duration) are filtered out from AI context * Based on real configuration from taskAgents.json @@ -15,7 +15,7 @@ import { fullReplacementTool } from '../prompt'; // Use the real agent config const exampleAgent = defaultAgents[0]; -const realhandlerConfig = exampleAgent.handlerConfig; +const realagentFrameworkConfig = exampleAgent.agentFrameworkConfig; describe('Full Replacement Plugin - Duration Mechanism', () => { beforeEach(() => { @@ -25,14 +25,14 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { describe('History Source Type with Duration Filtering', () => { it('should filter out expired messages (duration=1) from historyOfSession', async () => { // Find the real fullReplacement plugin for history from taskAgents.json - const historyPlugin = realhandlerConfig.plugins.find( + const historyPlugin = realagentFrameworkConfig.plugins.find( p => p.toolId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'historyOfSession', ); expect(historyPlugin).toBeDefined(); expect(historyPlugin!.fullReplacementParam!.targetId).toBe('default-history'); // Real target ID // Use real prompts structure from taskAgents.json - const testPrompts = cloneDeep(realhandlerConfig.prompts) as IPrompt[]; + const testPrompts = cloneDeep(realagentFrameworkConfig.prompts) as IPrompt[]; const messages: AgentInstanceMessage[] = [ // Message 0: User message, no duration - should be included @@ -104,7 +104,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { status: { state: 'working' as const, modified: new Date() }, created: new Date(), }, - agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test-agent-def', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }, toolConfig: historyPlugin! as unknown as IPromptConcatTool, // Type cast due to JSON import limitations @@ -147,7 +147,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { }); it('should include messages with duration=0 (visible in current round)', async () => { - const historyPlugin = realhandlerConfig.plugins.find( + const historyPlugin = realagentFrameworkConfig.plugins.find( p => p.toolId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'historyOfSession', ); @@ -181,7 +181,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { }, ]; - const testPrompts = cloneDeep(realhandlerConfig.prompts) as IPrompt[]; + const testPrompts = cloneDeep(realagentFrameworkConfig.prompts) as IPrompt[]; const context: PromptConcatHookContext = { agentFrameworkContext: { @@ -192,7 +192,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { status: { state: 'working' as const, modified: new Date() }, created: new Date(), }, - agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test-agent-def', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }, toolConfig: historyPlugin! as unknown as IPromptConcatTool, // Type cast for JSON import @@ -220,7 +220,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { }); it('should handle mixed duration values correctly', async () => { - const historyPlugin = realhandlerConfig.plugins.find( + const historyPlugin = realagentFrameworkConfig.plugins.find( p => p.toolId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'historyOfSession', ); @@ -263,7 +263,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { }, ]; - const testPrompts = cloneDeep(realhandlerConfig.prompts) as IPrompt[]; + const testPrompts = cloneDeep(realagentFrameworkConfig.prompts) as IPrompt[]; const context: PromptConcatHookContext = { agentFrameworkContext: { @@ -274,7 +274,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { status: { state: 'working' as const, modified: new Date() }, created: new Date(), }, - agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test-agent-def', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }, toolConfig: historyPlugin! as unknown as IPromptConcatTool, // Type cast for JSON import @@ -308,7 +308,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => { describe('LLM Response Source Type', () => { it('should verify LLM response replacement config exists', () => { // Verify the real config has LLM response replacement - const llmResponsePlugin = realhandlerConfig.plugins.find( + const llmResponsePlugin = realagentFrameworkConfig.plugins.find( p => p.toolId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'llmResponse', ); expect(llmResponsePlugin).toBeDefined(); diff --git a/src/services/agentInstance/tools/__tests__/messageManagementPlugin.test.ts b/src/services/agentInstance/tools/__tests__/messageManagementPlugin.test.ts index 8bb292fa..a8b2d990 100644 --- a/src/services/agentInstance/tools/__tests__/messageManagementPlugin.test.ts +++ b/src/services/agentInstance/tools/__tests__/messageManagementPlugin.test.ts @@ -1,4 +1,4 @@ -/** +/** * Deep integration tests for messageManagementTool with real SQLite database * Tests actual message persistence scenarios using taskAgents.json configuration */ @@ -90,7 +90,7 @@ describe('Message Management Plugin - Real Database Integration', () => { name: exampleAgent.name, version: '1.0.0', capabilities: [], - handlerConfig: exampleAgent.handlerConfig, + agentFrameworkConfig: exampleAgent.agentFrameworkConfig, }, isCancelled: () => false, }); diff --git a/src/services/agentInstance/tools/__tests__/wikiOperationPlugin.test.ts b/src/services/agentInstance/tools/__tests__/wikiOperationPlugin.test.ts index bffa9353..5f3c7ac7 100644 --- a/src/services/agentInstance/tools/__tests__/wikiOperationPlugin.test.ts +++ b/src/services/agentInstance/tools/__tests__/wikiOperationPlugin.test.ts @@ -1,4 +1,4 @@ -/** +/** * Tests for wikiOperationTool */ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -59,7 +59,7 @@ const makeagentFrameworkContext = (agentId = 'test-agent'): AgentFrameworkContex status: { state: 'working', modified: new Date() }, created: new Date(), } as unknown as AgentInstance, - agentDef: { id: 'test-agent-def', name: 'test-agent-def', handlerConfig: {} } as unknown as { id: string; name: string; handlerConfig: Record }, + agentDef: { id: 'test-agent-def', name: 'test-agent-def', agentFrameworkConfig: {} } as unknown as { id: string; name: string; agentFrameworkConfig: Record }, isCancelled: () => false, }); @@ -90,7 +90,7 @@ describe('wikiOperationTool', () => { const workspacesContext: PromptConcatHookContext = { agentFrameworkContext: { agent: { id: 'test-agent', messages: [], agentDefId: 'test', status: { state: 'working' as const, modified: new Date() }, created: new Date() }, - agentDef: { id: 'test', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }, messages: [], diff --git a/src/services/agentInstance/tools/__tests__/wikiSearchPlugin.test.ts b/src/services/agentInstance/tools/__tests__/wikiSearchPlugin.test.ts index c8cc5358..3260bcee 100644 --- a/src/services/agentInstance/tools/__tests__/wikiSearchPlugin.test.ts +++ b/src/services/agentInstance/tools/__tests__/wikiSearchPlugin.test.ts @@ -1,4 +1,4 @@ -/** +/** * Comprehensive tests for Wiki Search plugin * Covers tool list injection, tool execution, duration mechanism, message persistence, and integration scenarios */ @@ -53,7 +53,7 @@ vi.mock('@services/libs/i18n', () => ({ // Use the real agent config const exampleAgent = defaultAgents[0]; -const handlerConfig = exampleAgent.handlerConfig as AgentPromptDescription['handlerConfig']; +const agentFrameworkConfig = (exampleAgent.agentFrameworkConfig || {}) as AgentPromptDescription['agentFrameworkConfig']; // Services will be retrieved from container on demand inside each test/describe @@ -77,7 +77,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { it('should inject wiki tools into prompts when configured', async () => { // Find the wiki search plugin config, make sure our default config - const wikiPlugin = handlerConfig.plugins.find((p: unknown): p is IPromptConcatTool => (p as IPromptConcatTool).toolId === 'wikiSearch'); + const wikiPlugin = agentFrameworkConfig.plugins.find((p: unknown): p is IPromptConcatTool => (p as IPromptConcatTool).toolId === 'wikiSearch'); expect(wikiPlugin).toBeDefined(); if (!wikiPlugin) { // throw error to keep ts believe the plugin exists @@ -89,7 +89,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { expect(wikiPlugin.wikiSearchParam?.toolListPosition).toBeDefined(); // Create a copy of prompts to test modification - const prompts = cloneDeep(handlerConfig.prompts); + const prompts = cloneDeep(agentFrameworkConfig.prompts); const messages = [ { id: 'user-1', @@ -104,7 +104,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { const context: PromptConcatHookContext = { agentFrameworkContext: { agent: { id: 'test', messages: [], agentDefId: 'test', status: { state: 'working' as const, modified: new Date() }, created: new Date() }, - agentDef: { id: 'test', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }, toolConfig: wikiPlugin, @@ -144,7 +144,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }, }; - const prompts = cloneDeep(defaultAgents[0].handlerConfig.prompts); + const prompts = cloneDeep(defaultAgents[0].agentFrameworkConfig.prompts); const originalPromptsText = JSON.stringify(prompts); const context = { @@ -173,7 +173,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { status: { state: 'working' as const, modified: new Date() }, created: new Date(), } as AgentInstance, - agentDef: { id: 'test', name: 'test', handlerConfig: {} } as AgentDefinition, + agentDef: { id: 'test', name: 'test', agentFrameworkConfig: {} } as AgentDefinition, isCancelled: () => false, }; const hookContext: PromptConcatHookContext = { @@ -222,7 +222,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { it('should execute wiki search with correct duration=1 and trigger next round', async () => { // Find the real wikiSearch plugin config from taskAgents.json - const wikiPlugin = handlerConfig.plugins.find((p: unknown): p is IPromptConcatTool => (p as IPromptConcatTool).toolId === 'wikiSearch'); + const wikiPlugin = agentFrameworkConfig.plugins.find((p: unknown): p is IPromptConcatTool => (p as IPromptConcatTool).toolId === 'wikiSearch'); expect(wikiPlugin).toBeDefined(); expect(wikiPlugin!.wikiSearchParam).toBeDefined(); @@ -258,7 +258,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }, ], }, - agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test-agent-def', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }; @@ -352,7 +352,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }, ], }, - agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test-agent-def', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }; @@ -450,7 +450,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }, ], }, - agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test-agent-def', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }; @@ -507,7 +507,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { status: { state: 'working' as const, modified: new Date() }, created: new Date(), } as AgentInstance, - agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} } as AgentDefinition, + agentDef: { id: 'test-agent-def', name: 'test', agentFrameworkConfig: {} } as AgentDefinition, isCancelled: () => false, }; @@ -627,7 +627,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }, ], }, - agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test-agent-def', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }; @@ -724,7 +724,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }, ], }, - agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test-agent-def', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }; @@ -795,7 +795,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }, ], }, - agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test-agent-def', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }; @@ -859,7 +859,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => { }, ], }, - agentDef: { id: 'test-agent-def', name: 'test', handlerConfig: {} }, + agentDef: { id: 'test-agent-def', name: 'test', agentFrameworkConfig: {} }, isCancelled: () => false, }; diff --git a/src/services/agentInstance/tools/__tests__/workspacesListPlugin.test.ts b/src/services/agentInstance/tools/__tests__/workspacesListPlugin.test.ts index 315fe8a5..24c9c543 100644 --- a/src/services/agentInstance/tools/__tests__/workspacesListPlugin.test.ts +++ b/src/services/agentInstance/tools/__tests__/workspacesListPlugin.test.ts @@ -1,4 +1,4 @@ -/** +/** * Tests for workspacesListTool */ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; diff --git a/src/services/agentInstance/tools/wikiSearch.ts b/src/services/agentInstance/tools/wikiSearch.ts index 03a72859..c0453767 100644 --- a/src/services/agentInstance/tools/wikiSearch.ts +++ b/src/services/agentInstance/tools/wikiSearch.ts @@ -1,4 +1,4 @@ -/** +/** * Wiki Search plugin * Handles wiki search tool list injection, tool calling detection and response processing */ diff --git a/src/services/agentInstance/utilities.ts b/src/services/agentInstance/utilities.ts index 64fab91f..d9d526e4 100644 --- a/src/services/agentInstance/utilities.ts +++ b/src/services/agentInstance/utilities.ts @@ -14,8 +14,8 @@ export function createAgentInstanceData(agentDefinition: { name: string; avatarUrl?: string; aiApiConfig?: Record; - handlerConfig?: Record; - handlerID?: string; + agentFrameworkConfig?: Record; + agentFrameworkID?: string; }): { instanceData: Omit; instanceId: string; @@ -31,7 +31,7 @@ export function createAgentInstanceData(agentDefinition: { }; // Extract necessary fields from agent definition - const { avatarUrl, aiApiConfig, handlerID } = agentDefinition; + const { avatarUrl, aiApiConfig, agentFrameworkID } = agentDefinition; const instanceData = { id: instanceId, @@ -40,9 +40,9 @@ export function createAgentInstanceData(agentDefinition: { status: initialStatus, avatarUrl, aiApiConfig, - // Don't copy handlerConfig to instance - it should fallback to definition - handlerConfig: undefined, - handlerID, + // Don't copy agentFrameworkConfig to instance - it should fallback to definition + agentFrameworkConfig: undefined, + agentFrameworkID, messages: [], closed: false, }; @@ -119,6 +119,6 @@ export const AGENT_INSTANCE_FIELDS = [ 'modified', 'avatarUrl', 'aiApiConfig', - 'handlerConfig', + 'agentFrameworkConfig', 'closed', ] as const; diff --git a/src/services/database/schema/agent.ts b/src/services/database/schema/agent.ts index 10c4ff47..5fe7d9b4 100644 --- a/src/services/database/schema/agent.ts +++ b/src/services/database/schema/agent.ts @@ -29,11 +29,11 @@ export class AgentDefinitionEntity implements Partial { /** Agent handler function ID, nullable indicates using default handler */ @Column({ nullable: true }) - handlerID?: string; + agentFrameworkID?: string; /** Agent handler configuration parameters, stored as JSON */ @Column({ type: 'simple-json', nullable: true }) - handlerConfig?: Record; + agentFrameworkConfig?: Record; /** Agent's AI API configuration, can override global default config */ @Column({ type: 'simple-json', nullable: true }) @@ -88,7 +88,7 @@ export class AgentInstanceEntity implements Partial { /** Agent handler configuration parameters, inherited from AgentDefinition */ @Column({ type: 'simple-json', nullable: true }) - handlerConfig?: Record; + agentFrameworkConfig?: Record; @Column({ default: false }) closed: boolean = false; diff --git a/src/windows/Preferences/sections/ExternalAPI/useHandlerConfigManagement.ts b/src/windows/Preferences/sections/ExternalAPI/useAgentFrameworkConfigManagement.ts similarity index 51% rename from src/windows/Preferences/sections/ExternalAPI/useHandlerConfigManagement.ts rename to src/windows/Preferences/sections/ExternalAPI/useAgentFrameworkConfigManagement.ts index fbf91a18..278b2fd8 100644 --- a/src/windows/Preferences/sections/ExternalAPI/useHandlerConfigManagement.ts +++ b/src/windows/Preferences/sections/ExternalAPI/useAgentFrameworkConfigManagement.ts @@ -1,29 +1,29 @@ -import { HandlerConfig } from '@services/agentInstance/promptConcat/promptConcatSchema'; +import { agentFrameworkConfig } from '@services/agentInstance/promptConcat/promptConcatSchema'; import { useCallback, useEffect, useState } from 'react'; -interface UseHandlerConfigManagementProps { +interface useAgentFrameworkConfigManagementProps { agentDefId?: string; agentId?: string; } -interface UseHandlerConfigManagementResult { +interface useAgentFrameworkConfigManagementResult { loading: boolean; - config: HandlerConfig | undefined; + config: agentFrameworkConfig | undefined; schema?: Record; - handleConfigChange: (newConfig: HandlerConfig) => Promise; + handleConfigChange: (newConfig: agentFrameworkConfig) => Promise; } -export const useHandlerConfigManagement = ({ agentDefId, agentId }: UseHandlerConfigManagementProps = {}): UseHandlerConfigManagementResult => { +export const useAgentFrameworkConfigManagement = ({ agentDefId, agentId }: useAgentFrameworkConfigManagementProps = {}): useAgentFrameworkConfigManagementResult => { const [loading, setLoading] = useState(true); - const [config, setConfig] = useState(undefined); + const [config, setConfig] = useState(undefined); const [schema, setSchema] = useState | undefined>(undefined); useEffect(() => { const fetchConfig = async () => { try { setLoading(true); - let finalConfig: HandlerConfig | undefined; - let handlerID: string | undefined; + let finalConfig: agentFrameworkConfig | undefined; + let agentFrameworkID: string | undefined; if (agentId) { const agentInstance = await window.service.agentInstance.getAgent(agentId); @@ -32,34 +32,34 @@ export const useHandlerConfigManagement = ({ agentDefId, agentId }: UseHandlerCo agentDefinition = await window.service.agentDefinition.getAgentDef(agentInstance.agentDefId); } // Use instance config if available, otherwise fallback to definition config - if (agentInstance?.handlerConfig && Object.keys(agentInstance.handlerConfig).length > 0) { - finalConfig = agentInstance.handlerConfig as HandlerConfig; - } else if (agentDefinition?.handlerConfig) { - finalConfig = agentDefinition.handlerConfig as HandlerConfig; + if (agentInstance?.agentFrameworkConfig && Object.keys(agentInstance.agentFrameworkConfig).length > 0) { + finalConfig = agentInstance.agentFrameworkConfig as agentFrameworkConfig; + } else if (agentDefinition?.agentFrameworkConfig) { + finalConfig = agentDefinition.agentFrameworkConfig as agentFrameworkConfig; } - // Use handlerID from instance, fallback to definition - handlerID = agentInstance?.handlerID || agentDefinition?.handlerID; + // Use agentFrameworkID from instance, fallback to definition + agentFrameworkID = agentInstance?.agentFrameworkID || agentDefinition?.agentFrameworkID; } else if (agentDefId) { const agentDefinition = await window.service.agentDefinition.getAgentDef(agentDefId); - if (agentDefinition?.handlerConfig) { - finalConfig = agentDefinition.handlerConfig as HandlerConfig; + if (agentDefinition?.agentFrameworkConfig) { + finalConfig = agentDefinition.agentFrameworkConfig as agentFrameworkConfig; } - handlerID = agentDefinition?.handlerID; + agentFrameworkID = agentDefinition?.agentFrameworkID; } - if (handlerID) { + if (agentFrameworkID) { try { - const frameworkSchema = await window.service.agentInstance.getFrameworkConfigSchema(handlerID); + const frameworkSchema = await window.service.agentInstance.getFrameworkConfigSchema(agentFrameworkID); setSchema(frameworkSchema); } catch (error) { - void window.service.native.log('error', 'Failed to load handler schema', { function: 'useHandlerConfigManagement.fetchConfig', error }); + void window.service.native.log('error', 'Failed to load handler schema', { function: 'useAgentFrameworkConfigManagement.fetchConfig', error }); } } setConfig(finalConfig); setLoading(false); } catch (error) { - void window.service.native.log('error', 'Failed to load handler configuration', { function: 'useHandlerConfigManagement.fetchConfig', error }); + void window.service.native.log('error', 'Failed to load handler configuration', { function: 'useAgentFrameworkConfigManagement.fetchConfig', error }); setLoading(false); } }; @@ -67,27 +67,29 @@ export const useHandlerConfigManagement = ({ agentDefId, agentId }: UseHandlerCo void fetchConfig(); }, [agentDefId, agentId]); - const handleConfigChange = useCallback(async (newConfig: HandlerConfig) => { + const handleConfigChange = useCallback(async (newConfig: agentFrameworkConfig) => { try { setConfig(newConfig); if (agentId) { await window.service.agentInstance.updateAgent(agentId, { - handlerConfig: newConfig, + agentFrameworkConfig: newConfig, }); } else if (agentDefId) { const agentDefinition = await window.service.agentDefinition.getAgentDef(agentDefId); if (agentDefinition) { await window.service.agentDefinition.updateAgentDef({ ...agentDefinition, - handlerConfig: newConfig, + agentFrameworkConfig: newConfig, }); } } else { - void window.service.native.log('error', 'No agent ID or definition ID provided for updating handler config', { function: 'useHandlerConfigManagement.handleConfigChange' }); + void window.service.native.log('error', 'No agent ID or definition ID provided for updating handler config', { + function: 'useAgentFrameworkConfigManagement.handleConfigChange', + }); } } catch (error) { - void window.service.native.log('error', 'Failed to update handler configuration', { function: 'useHandlerConfigManagement.handleConfigChange', error }); + void window.service.native.log('error', 'Failed to update handler configuration', { function: 'useAgentFrameworkConfigManagement.handleConfigChange', error }); } }, [agentId, agentDefId]);