diff --git a/app/api/proxy/route.ts b/app/api/proxy/route.ts
index 05704c7d5b..388d695cf9 100644
--- a/app/api/proxy/route.ts
+++ b/app/api/proxy/route.ts
@@ -16,13 +16,42 @@ export async function POST(request: Request) {
throw new Error(`Tool not found: ${toolId}`)
}
- // Use executeTool with skipProxy=true to prevent recursive proxy calls
- const result = await executeTool(toolId, params, true)
+ // Use executeTool with skipProxy=true to prevent recursive proxy calls, and skipPostProcess=true to prevent duplicate post-processing
+ const result = await executeTool(toolId, params, true, true)
if (!result.success) {
- throw new Error(
- tool.transformError ? tool.transformError(result) : 'Tool returned an error'
- )
+ if (tool.transformError) {
+ try {
+ const errorResult = tool.transformError(result)
+
+ // Handle both string and Promise return types
+ if (typeof errorResult === 'string') {
+ throw new Error(errorResult)
+ } else {
+ // It's a Promise, await it
+ const transformedError = await errorResult
+ // If it's a string or has an error property, use it
+ if (typeof transformedError === 'string') {
+ throw new Error(transformedError)
+ } else if (
+ transformedError &&
+ typeof transformedError === 'object' &&
+ 'error' in transformedError
+ ) {
+ throw new Error(transformedError.error || 'Tool returned an error')
+ }
+ // Fallback
+ throw new Error('Tool returned an error')
+ }
+ } catch (e) {
+ if (e instanceof Error) {
+ throw e
+ }
+ throw new Error('Tool returned an error')
+ }
+ } else {
+ throw new Error('Tool returned an error')
+ }
}
return NextResponse.json(result)
diff --git a/executor/types.ts b/executor/types.ts
index 3cfcc9f936..1e40f1970b 100644
--- a/executor/types.ts
+++ b/executor/types.ts
@@ -164,7 +164,13 @@ export interface Tool
> {
error?: string
}>
- transformError?: (error: any) => string // Function to format error messages
+ transformError?: (error: any) =>
+ | string
+ | Promise<{
+ success: boolean
+ output: O
+ error?: string
+ }> // Function to format error messages
}
/**
diff --git a/tools/docs/create.ts b/tools/docs/create.ts
index 1c9b0c76e1..6402faf4b0 100644
--- a/tools/docs/create.ts
+++ b/tools/docs/create.ts
@@ -50,6 +50,44 @@ export const createTool: ToolConfig {
+ // Only add content if it was provided and not already added during creation
+ // The Google Docs API doesn't directly support content in the create request,
+ // so we need to add it separately via the write tool
+ if (result.success && params.content) {
+ console.log('Google Docs create - Post-processing: Adding content to document')
+ const documentId = result.output.metadata.documentId
+
+ if (documentId) {
+ try {
+ const writeParams = {
+ accessToken: params.accessToken,
+ documentId: documentId,
+ content: params.content,
+ }
+ console.log('Content to add:', params.content)
+
+ // Use the write tool to add content
+ const writeResult = await executeTool('google_docs_write', writeParams)
+
+ if (!writeResult.success) {
+ console.warn(
+ 'Failed to add content to document, but document was created:',
+ writeResult.error
+ )
+ } else {
+ console.log('Google Docs create - Content added successfully')
+ }
+ } catch (error) {
+ console.warn('Error adding content to document:', error)
+ // Don't fail the overall operation if adding content fails
+ }
+ }
+ }
+
+ // Return the original result regardless of post-processing outcome
+ return result
+ },
transformResponse: async (response: Response) => {
if (!response.ok) {
let errorText = ''
@@ -67,7 +105,9 @@ export const createTool: ToolConfig {
- if (typeof error === 'object' && error !== null) {
- if (error.message) {
- return error.message
- }
- return (
- JSON.stringify(error, null, 2) || 'An error occurred while creating Google Docs document'
- )
- }
+ transformError: async (error) => {
+ console.error('Google Docs create - Transform error:', error)
- return error.toString() || 'An error occurred while creating Google Docs document'
+ const errorMessage =
+ typeof error === 'object' && error !== null
+ ? error.message || JSON.stringify(error, null, 2)
+ : error.toString() || 'An error occurred while creating Google Docs document'
+
+ return {
+ success: false,
+ output: {
+ metadata: {
+ documentId: '',
+ title: '',
+ },
+ },
+ error: errorMessage,
+ }
},
}
diff --git a/tools/docs/read.ts b/tools/docs/read.ts
index 521eafca53..2912bf28ab 100644
--- a/tools/docs/read.ts
+++ b/tools/docs/read.ts
@@ -70,11 +70,23 @@ export const readTool: ToolConfig
},
}
},
- transformError: (error) => {
- if (typeof error === 'object' && error !== null) {
- return JSON.stringify(error) || 'An error occurred while reading from Google Docs'
+ transformError: async (error) => {
+ const errorMessage =
+ typeof error === 'object' && error !== null
+ ? error.message || JSON.stringify(error, null, 2)
+ : error.toString() || 'An error occurred while reading Google Docs document'
+
+ return {
+ success: false,
+ output: {
+ content: '',
+ metadata: {
+ documentId: '',
+ title: '',
+ },
+ },
+ error: errorMessage,
}
- return error.message || 'An error occurred while reading from Google Docs'
},
}
diff --git a/tools/docs/write.ts b/tools/docs/write.ts
index 6900e0dae0..852634f5a7 100644
--- a/tools/docs/write.ts
+++ b/tools/docs/write.ts
@@ -48,14 +48,13 @@ export const writeTool: ToolConfig {
- if (typeof error === 'object' && error !== null) {
- if (error.message) {
- return error.message
- }
- return JSON.stringify(error, null, 2) || 'An error occurred while writing to Google Docs'
- }
+ transformError: async (error) => {
+ const errorMessage =
+ typeof error === 'object' && error !== null
+ ? error.message || JSON.stringify(error, null, 2)
+ : error.toString() || 'An error occurred while writing to Google Docs'
- return error.toString() || 'An error occurred while writing to Google Docs'
+ return {
+ success: false,
+ output: {
+ updatedContent: false,
+ metadata: {
+ documentId: '',
+ title: '',
+ },
+ },
+ error: errorMessage,
+ }
},
}
diff --git a/tools/index.ts b/tools/index.ts
index 8d375bf40f..2761a43e35 100644
--- a/tools/index.ts
+++ b/tools/index.ts
@@ -279,7 +279,7 @@ function getCustomTool(customToolId: string): ToolConfig | undefined {
error: undefined,
}
},
- transformError: (error: any) =>
+ transformError: async (error: any) =>
`Custom tool execution error: ${error.message || 'Unknown error'}`,
}
}
@@ -288,7 +288,8 @@ function getCustomTool(customToolId: string): ToolConfig | undefined {
export async function executeTool(
toolId: string,
params: Record,
- skipProxy = false
+ skipProxy = false,
+ skipPostProcess = false
): Promise {
try {
const tool = getTool(toolId)
@@ -313,11 +314,36 @@ export async function executeTool(
// For internal routes or when skipProxy is true, call the API directly
if (tool.request.isInternalRoute || skipProxy) {
const result = await handleInternalRequest(toolId, tool, params)
+
+ // Apply post-processing if available and not skipped
+ if (tool.postProcess && result.success && !skipPostProcess) {
+ try {
+ return await tool.postProcess(result, params, executeTool)
+ } catch (error) {
+ console.error(`Error in post-processing for tool ${toolId}:`, error)
+ // Return original result if post-processing fails
+ return result
+ }
+ }
+
return result
}
// For external APIs, use the proxy
- return await handleProxyRequest(toolId, params)
+ const result = await handleProxyRequest(toolId, params)
+
+ // Apply post-processing if available and not skipped
+ if (tool.postProcess && result.success && !skipPostProcess) {
+ try {
+ return await tool.postProcess(result, params, executeTool)
+ } catch (error) {
+ console.error(`Error in post-processing for tool ${toolId}:`, error)
+ // Return original result if post-processing fails
+ return result
+ }
+ }
+
+ return result
} catch (error: any) {
console.error(`Error executing tool ${toolId}:`, error)
@@ -396,12 +422,58 @@ async function handleInternalRequest(
error: undefined,
}
} catch (error: any) {
+ console.error(`Error executing internal tool ${toolId}:`, error)
+
// Use the tool's error transformer if available
if (tool.transformError) {
- return {
- success: false,
- output: {},
- error: tool.transformError(error),
+ try {
+ const errorResult = tool.transformError(error)
+
+ // Handle both string and Promise return types
+ if (typeof errorResult === 'string') {
+ return {
+ success: false,
+ output: {},
+ error: errorResult,
+ }
+ } else {
+ // It's a Promise, await it
+ const transformedError = await errorResult
+ // If it's a string or has an error property, use it
+ if (typeof transformedError === 'string') {
+ return {
+ success: false,
+ output: {},
+ error: transformedError,
+ }
+ } else if (transformedError && typeof transformedError === 'object') {
+ // If it's already a ToolResponse, return it directly
+ if ('success' in transformedError) {
+ return transformedError
+ }
+ // If it has an error property, use it
+ if ('error' in transformedError) {
+ return {
+ success: false,
+ output: {},
+ error: transformedError.error,
+ }
+ }
+ }
+ // Fallback
+ return {
+ success: false,
+ output: {},
+ error: 'Unknown error',
+ }
+ }
+ } catch (transformError) {
+ console.error(`Error transforming error for tool ${toolId}:`, transformError)
+ return {
+ success: false,
+ output: {},
+ error: error.message || 'Unknown error',
+ }
}
}
diff --git a/tools/types.ts b/tools/types.ts
index b12f753d72..fdbb145541 100644
--- a/tools/types.ts
+++ b/tools/types.ts
@@ -14,7 +14,7 @@ export interface OAuthConfig {
additionalScopes?: string[] // Additional scopes required for the tool
}
-export interface ToolConfig {
+export interface ToolConfig
{
// Basic tool identification
id: string
name: string
@@ -48,9 +48,16 @@ export interface ToolConfig
{
// Direct execution in browser (optional) - bypasses HTTP request
directExecution?: (params: P) => Promise
+ // Post-processing (optional) - allows additional processing after the initial request
+ postProcess?: (
+ result: R extends ToolResponse ? R : ToolResponse,
+ params: P,
+ executeTool: (toolId: string, params: Record) => Promise
+ ) => Promise
+
// Response handling
- transformResponse: (response: Response) => Promise
- transformError: (error: any) => string
+ transformResponse?: (response: Response) => Promise
+ transformError?: (error: any) => string | Promise
}
export interface TableRow {
diff --git a/tools/utils.ts b/tools/utils.ts
index 209402b473..2547ff9ccd 100644
--- a/tools/utils.ts
+++ b/tools/utils.ts
@@ -77,12 +77,40 @@ export async function executeRequest(
}
// Use the tool's error transformer or a default message
- const error = tool.transformError
- ? tool.transformError(errorContent)
- : errorContent.message || `${toolId} API error: ${externalResponse.statusText}`
+ if (tool.transformError) {
+ try {
+ const errorResult = tool.transformError(errorContent)
- console.error(`${toolId} error:`, error)
- throw new Error(error)
+ // Handle both string and Promise return types
+ if (typeof errorResult === 'string') {
+ throw new Error(errorResult)
+ } else {
+ // It's a Promise, await it
+ const transformedError = await errorResult
+ // If it's a string or has an error property, use it
+ if (typeof transformedError === 'string') {
+ throw new Error(transformedError)
+ } else if (
+ transformedError &&
+ typeof transformedError === 'object' &&
+ 'error' in transformedError
+ ) {
+ throw new Error(transformedError.error || 'Tool returned an error')
+ }
+ // Fallback
+ throw new Error('Tool returned an error')
+ }
+ } catch (e) {
+ if (e instanceof Error) {
+ throw e
+ }
+ throw new Error(`${toolId} API error: ${externalResponse.statusText}`)
+ }
+ } else {
+ const error = errorContent.message || `${toolId} API error: ${externalResponse.statusText}`
+ console.error(`${toolId} error:`, error)
+ throw new Error(error)
+ }
}
const transformResponse =