fix(tools): fixed docs create & write tools

This commit is contained in:
Waleed Latif
2025-03-10 04:35:21 -07:00
parent 85175aef2b
commit b4930404c9
2 changed files with 96 additions and 127 deletions
+41 -93
View File
@@ -21,16 +21,8 @@ export const createTool: ToolConfig<GoogleDocsToolParams, GoogleDocsCreateRespon
folderId: { type: 'string', required: false },
},
request: {
url: (params) => {
// Build URL with query parameters to pass content and folderId
const url = new URL('https://docs.googleapis.com/v1/documents')
if (params.content) {
url.searchParams.append('content', params.content)
}
if (params.folderId) {
url.searchParams.append('folderId', params.folderId)
}
return url.toString()
url: () => {
return 'https://docs.googleapis.com/v1/documents'
},
method: 'POST',
headers: (params) => {
@@ -42,7 +34,6 @@ export const createTool: ToolConfig<GoogleDocsToolParams, GoogleDocsCreateRespon
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
'X-Access-Token': params.accessToken, // Store access token in a custom header for later use
}
},
body: (params) => {
@@ -52,105 +43,62 @@ export const createTool: ToolConfig<GoogleDocsToolParams, GoogleDocsCreateRespon
}
// Create a new document with the specified title
return {
const requestBody = {
title: params.title,
}
return requestBody
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorText = await response.text()
throw new Error(`Failed to create Google Docs document: ${errorText}`)
}
const data = await response.json()
const documentId = data.documentId
// Get access token from the custom header we set in the request
const accessToken = response.headers.get('X-Access-Token') || ''
// Extract content and folderId from the request URL query parameters
const requestUrl = new URL(response.url)
const content = requestUrl.searchParams.get('content') || ''
const folderId = requestUrl.searchParams.get('folderId') || ''
// If content was provided, we need to update the document with content
if (documentId && content) {
let errorText = ''
try {
// Make a second request to update the document with content
const updateResponse = await fetch(
`https://docs.googleapis.com/v1/documents/${documentId}:batchUpdate`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
requests: [
{
insertText: {
location: {
index: 1,
},
text: content,
},
},
],
}),
}
)
if (!updateResponse.ok) {
console.warn('Failed to update document with content, but document was created')
}
} catch (error) {
console.warn('Error updating document with content:', error)
const responseClone = response.clone()
const responseText = await responseClone.text()
errorText = responseText
} catch (e) {
errorText = 'Unable to read error response'
}
throw new Error(`Failed to create Google Docs document (${response.status}): ${errorText}`)
}
// If folderId was provided, we need to move the document to that folder
if (documentId && folderId) {
try {
// Make a request to the Drive API to move the file
const moveResponse = await fetch(
`https://www.googleapis.com/drive/v3/files/${documentId}?addParents=${folderId}`,
{
method: 'PATCH',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
}
)
try {
// Get the response data
const responseText = await response.text()
const data = JSON.parse(responseText)
const documentId = data.documentId
const title = data.title
if (!moveResponse.ok) {
console.warn('Failed to move document to specified folder, but document was created')
}
} catch (error) {
console.warn('Error moving document to folder:', error)
// Create document metadata
const metadata = {
documentId,
title: title || 'Untitled Document',
mimeType: 'application/vnd.google-apps.document',
url: `https://docs.google.com/document/d/${documentId}/edit`,
}
}
// Create document metadata
const metadata = {
documentId: data.documentId,
title: data.title || 'Untitled Document',
mimeType: 'application/vnd.google-apps.document',
url: `https://docs.google.com/document/d/${data.documentId}/edit`,
}
return {
success: true,
output: {
metadata,
},
return {
success: true,
output: {
metadata,
},
}
} catch (error) {
throw error
}
},
transformError: (error) => {
if (typeof error === 'object' && error !== null) {
return JSON.stringify(error) || 'An error occurred while creating Google Docs document'
if (error.message) {
return error.message
}
return (
JSON.stringify(error, null, 2) || 'An error occurred while creating Google Docs document'
)
}
return error.message || 'An error occurred while creating Google Docs document'
return error.toString() || 'An error occurred while creating Google Docs document'
},
}
+55 -34
View File
@@ -47,63 +47,84 @@ export const writeTool: ToolConfig<GoogleDocsToolParams, GoogleDocsWriteResponse
throw new Error('Content is required')
}
// Create a batch update request to replace all content
return {
// Following the exact format from the Google Docs API examples
// Note: We're not including tabId since it's optional for the main document body
const requestBody = {
requests: [
{
// First, delete all existing content
deleteContentRange: {
range: {
startIndex: 1, // Start after the initial paragraph marker
endIndex: 999999, // A large number to ensure all content is deleted
},
},
},
{
// Then insert the new content
insertText: {
location: {
index: 1, // Insert after the initial paragraph marker
index: 1,
},
text: params.content,
},
},
],
}
return requestBody
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorText = await response.text()
throw new Error(`Failed to write to Google Docs document: ${errorText}`)
let errorText = ''
try {
const responseClone = response.clone()
const responseText = await responseClone.text()
errorText = responseText
} catch (e) {
errorText = 'Unable to read error response'
}
throw new Error(`Failed to write to Google Docs document (${response.status}): ${errorText}`)
}
const data = await response.json()
try {
const responseText = await response.text()
// Get the document ID from the URL
const urlParts = response.url.split('/')
const documentId = urlParts[urlParts.length - 2].split(':')[0]
// Parse the response if it's not empty
let data = {}
if (responseText.trim()) {
data = JSON.parse(responseText)
}
// Create document metadata
const metadata = {
documentId,
title: 'Updated Document', // We don't get the title back from the batchUpdate endpoint
mimeType: 'application/vnd.google-apps.document',
url: `https://docs.google.com/document/d/${documentId}/edit`,
}
// Get the document ID from the URL
const urlParts = response.url.split('/')
let documentId = ''
for (let i = 0; i < urlParts.length; i++) {
if (urlParts[i] === 'documents' && i + 1 < urlParts.length) {
documentId = urlParts[i + 1].split(':')[0]
break
}
}
return {
success: true,
output: {
updatedContent: true,
metadata,
},
// Create document metadata
const metadata = {
documentId,
title: 'Updated Document',
mimeType: 'application/vnd.google-apps.document',
url: `https://docs.google.com/document/d/${documentId}/edit`,
}
return {
success: true,
output: {
updatedContent: true,
metadata,
},
}
} catch (error) {
throw error
}
},
transformError: (error) => {
if (typeof error === 'object' && error !== null) {
return JSON.stringify(error) || 'An error occurred while writing to Google Docs'
if (error.message) {
return error.message
}
return JSON.stringify(error, null, 2) || 'An error occurred while writing to Google Docs'
}
return error.message || 'An error occurred while writing to Google Docs'
return error.toString() || 'An error occurred while writing to Google Docs'
},
}