From f0ac74dccfed1510a397aa3f16822da443de4d69 Mon Sep 17 00:00:00 2001 From: Vaayne Date: Fri, 19 Sep 2025 20:20:14 +0800 Subject: [PATCH] feat(agents): enhance error messages for agent and session operations; update accessible paths handling --- .../routes/agents/handlers/agents.ts | 6 ++-- .../routes/agents/handlers/sessions.ts | 6 ++-- src/main/services/agents/BaseService.ts | 31 +++++++++++++++++-- .../services/agents/services/AgentService.ts | 10 +++--- .../agents/services/SessionService.ts | 8 +++-- tests/apis/agents/sessions.http | 13 +++++--- 6 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/main/apiServer/routes/agents/handlers/agents.ts b/src/main/apiServer/routes/agents/handlers/agents.ts index 1ae661c726..2e01764ea3 100644 --- a/src/main/apiServer/routes/agents/handlers/agents.ts +++ b/src/main/apiServer/routes/agents/handlers/agents.ts @@ -71,7 +71,7 @@ export const createAgent = async (req: Request, res: Response): Promise logger.error('Error partially updating agent:', error) return res.status(500).json({ error: { - message: 'Failed to partially update agent', + message: `Failed to partially update agent: ${error.message}`, type: 'internal_error', code: 'agent_patch_failed' } diff --git a/src/main/apiServer/routes/agents/handlers/sessions.ts b/src/main/apiServer/routes/agents/handlers/sessions.ts index 81d3036a18..f3503e5ab8 100644 --- a/src/main/apiServer/routes/agents/handlers/sessions.ts +++ b/src/main/apiServer/routes/agents/handlers/sessions.ts @@ -51,7 +51,7 @@ export const createSession = async (req: Request, res: Response): Promise() + for (const rawPath of paths) { if (!rawPath) { continue } - const resolvedPath = path.resolve(rawPath) + if (!path.isAbsolute(rawPath)) { + throw new Error(`Accessible path must be absolute: ${rawPath}`) + } + + // Normalize to provide consistent values to downstream consumers. + const resolvedPath = path.normalize(rawPath) let stats: fs.Stats | null = null try { + // Attempt to stat the path to understand whether it already exists and if it is a file. if (fs.existsSync(resolvedPath)) { stats = fs.statSync(resolvedPath) } @@ -190,6 +206,7 @@ export abstract class BaseService { const looksLikeFile = (stats && stats.isFile()) || (!stats && path.extname(resolvedPath) !== '' && !resolvedPath.endsWith(path.sep)) + // For file-like targets create the parent directory; otherwise ensure the directory itself. const directoryToEnsure = looksLikeFile ? path.dirname(resolvedPath) : resolvedPath if (!fs.existsSync(directoryToEnsure)) { @@ -203,7 +220,15 @@ export abstract class BaseService { throw error } } + + // Preserve the first occurrence only to avoid duplicates while keeping caller order stable. + if (!seenPaths.has(resolvedPath)) { + seenPaths.add(resolvedPath) + sanitizedPaths.push(resolvedPath) + } } + + return sanitizedPaths } /** diff --git a/src/main/services/agents/services/AgentService.ts b/src/main/services/agents/services/AgentService.ts index 9d3c372647..a5c1b3d96d 100644 --- a/src/main/services/agents/services/AgentService.ts +++ b/src/main/services/agents/services/AgentService.ts @@ -45,14 +45,16 @@ export class AgentService extends BaseService { req.accessible_paths = [defaultPath] } + if (req.accessible_paths !== undefined) { + req.accessible_paths = this.ensurePathsExist(req.accessible_paths) + } + await this.validateAgentModels(req.type, { model: req.model, plan_model: req.plan_model, small_model: req.small_model }) - this.ensurePathsExist(req.accessible_paths) - const serializedReq = this.serializeJsonFields(req) const insertData: InsertAgentRow = { @@ -137,8 +139,8 @@ export class AgentService extends BaseService { const now = new Date().toISOString() - if (updates.accessible_paths) { - this.ensurePathsExist(updates.accessible_paths) + if (updates.accessible_paths !== undefined) { + updates.accessible_paths = this.ensurePathsExist(updates.accessible_paths) } const modelUpdates: Partial> = {} diff --git a/src/main/services/agents/services/SessionService.ts b/src/main/services/agents/services/SessionService.ts index 3c328f6ee9..2e70de4b11 100644 --- a/src/main/services/agents/services/SessionService.ts +++ b/src/main/services/agents/services/SessionService.ts @@ -58,7 +58,9 @@ export class SessionService extends BaseService { small_model: sessionData.small_model }) - this.ensurePathsExist(sessionData.accessible_paths) + if (sessionData.accessible_paths !== undefined) { + sessionData.accessible_paths = this.ensurePathsExist(sessionData.accessible_paths) + } const serializedData = this.serializeJsonFields(sessionData) @@ -179,8 +181,8 @@ export class SessionService extends BaseService { const now = new Date().toISOString() - if (updates.accessible_paths) { - this.ensurePathsExist(updates.accessible_paths) + if (updates.accessible_paths !== undefined) { + updates.accessible_paths = this.ensurePathsExist(updates.accessible_paths) } const modelUpdates: Partial> = {} diff --git a/tests/apis/agents/sessions.http b/tests/apis/agents/sessions.http index 5de78ee114..f7e941c93c 100644 --- a/tests/apis/agents/sessions.http +++ b/tests/apis/agents/sessions.http @@ -2,7 +2,7 @@ @host=http://localhost:23333 @token=cs-sk-af798ed4-7cf5-4fd7-ae4b-df203b164194 @agent_id=agent_1758092281575_tn9dxio9k -@session_id=session_1758252305914_9kef8yven +@session_id=session_1758278828236_mqj91e7c0 ### List Sessions GET {{host}}/v1/agents/{{agent_id}}/sessions @@ -16,11 +16,11 @@ Authorization: Bearer {{token}} Content-Type: application/json { - "name": "Story Writing Session 1", + "name": "Story Writing Session 2", "instructions": "You are a creative writing assistant. Help me brainstorm and write engaging stories.", "model": "anthropic:claude-sonnet-4", "accessible_paths": [ - "~/Documents/stories" + "/tmp/Documents/stories" ] } @@ -44,7 +44,7 @@ Content-Type: application/json "instructions": "You are a creative writing assistant. Help me brainstorm and write engaging stories.", "model": "anthropic:claude-sonnet-4", "accessible_paths": [ - "~/Documents/stories" + "/tmp/Documents/stories" ] } @@ -55,7 +55,10 @@ Authorization: Bearer {{token}} Content-Type: application/json { - "instructions": "You are a creative writing assistant. Help me brainstorm and write engaging stories. Focus on character development and plot structure.", + "model": "anthropic:claude-sonnet-4-20250514", + "accessible_paths": [ + "/tmp/Documents/stories2" + ] }