From 6e8f05495dfcf7d64bdc424503f874fece85e291 Mon Sep 17 00:00:00 2001 From: "A.J. Shulman" Date: Thu, 10 Apr 2025 12:36:07 -0400 Subject: trying again --- .../nodes/chatbot/tools/DocumentMetadataTool.ts | 561 +++++++++++---------- 1 file changed, 299 insertions(+), 262 deletions(-) (limited to 'src/client/views/nodes/chatbot/tools/DocumentMetadataTool.ts') diff --git a/src/client/views/nodes/chatbot/tools/DocumentMetadataTool.ts b/src/client/views/nodes/chatbot/tools/DocumentMetadataTool.ts index a9fb45b5a..a3d86287d 100644 --- a/src/client/views/nodes/chatbot/tools/DocumentMetadataTool.ts +++ b/src/client/views/nodes/chatbot/tools/DocumentMetadataTool.ts @@ -11,7 +11,6 @@ import { DocCast, StrCast } from '../../../../../fields/Types'; import { supportedDocTypes } from '../types/tool_types'; import { parsedDoc } from '../chatboxcomponents/ChatBox'; - // Define the parameters for the DocumentMetadataTool const parameterDefinitions: ReadonlyArray = [ { @@ -61,7 +60,7 @@ const parameterDefinitions: ReadonlyArray = [ type: 'string', required: false, description: `The type of document to create. Required for "create" action. Options: ${Object.keys(supportedDocTypes).join(',')}`, - } + }, ] as const; type DocumentMetadataToolParamsType = typeof parameterDefinitions; @@ -105,14 +104,14 @@ IMPORTANT: Some fields have dependencies that must be handled for edits to work - You can edit dependent fields in a single operation using the fieldEdits parameter Example: To change document height, first disable auto-height: -1. { action: "edit", documentId: "doc123", fieldName: "layout_autoHeight", fieldValue: false } -2. { action: "edit", documentId: "doc123", fieldName: "height", fieldValue: 300 } +1. {... inputs: { action: "edit", documentId: "doc123", fieldName: "layout_autoHeight", fieldValue: false }} +2. {... inputs: { action: "edit", documentId: "doc123", fieldName: "height", fieldValue: 300 }} OR using multi-field edit (recommended for dependent fields): -{ action: "edit", documentId: "doc123", fieldEdits: [ +{... inputs: { action: "edit", documentId: "doc123", fieldEdits: [ { fieldName: "layout_autoHeight", fieldValue: false }, { fieldName: "height", fieldValue: 300 } -]}`; +]}}`; // Extensive usage guidelines for the tool const citationRules = `USAGE GUIDELINES: @@ -132,7 +131,7 @@ To CREATE a new document: - title: The title of the document to create - data: The content data for the document (text content, URL, etc.) - doc_type: The type of document to create (text, web, image, etc.) -- Example: { action: "create", title: "My Notes", data: "This is the content", doc_type: "text" } +- Example: {...inputs: { action: "create", title: "My Notes", data: "This is the content", doc_type: "text" }} - After creation, you can edit the document with more specific properties To EDIT document metadata: @@ -147,7 +146,7 @@ To EDIT document metadata: SPECIAL FIELD HANDLING: - Text fields: When editing the 'text' field, provide simple plain text - Example: { action: "edit", documentId: "doc123", fieldName: "text", fieldValue: "Hello world" } + Example: {...inputs: { action: "edit", documentId: "doc123", fieldName: "text", fieldValue: "Hello world" }} The tool will automatically convert your text to the proper RichTextField format - Width/Height: Set layout_autoHeight/layout_autoWidth to false before editing @@ -165,10 +164,10 @@ HANDLING DEPENDENT FIELDS: - When editing some fields, you may need to update related dependent fields - For example, when changing "height", you should also set "layout_autoHeight" to false - Use the fieldEdits parameter to update dependent fields in a single operation (recommended): - { action: "edit", documentId: "doc123", fieldEdits: [ + {...inputs: { action: "edit", documentId: "doc123", fieldEdits: [ { fieldName: "layout_autoHeight", fieldValue: false }, { fieldName: "height", fieldValue: 300 } - ]} +]}} - Always check for dependent fields that might affect your edits, such as: - height → layout_autoHeight (set to false to allow manual height) - width → layout_autoWidth (set to false to allow manual width) @@ -200,8 +199,8 @@ Examples: { action: "edit", documentId: "doc123", fieldEdits: [ { fieldName: "layout_autoHeight", fieldValue: false }, { fieldName: "height", fieldValue: 200 } - ]}`; - + ]} +- IMPORTANT: MULTI STEP WORKFLOWS ARE NOT ONLY ALLOWED BUT ENCOURAGED. TAKE THINGS 1 STEP AT A TIME.`; const documentMetadataToolInfo: ToolInfo = { name: 'documentMetadata', description: toolDescription, @@ -227,7 +226,7 @@ export class DocumentMetadataTool extends BaseTool DocCast(LinkManager.getOppositeAnchor(d, this.chatBoxDocument!))) .map(d => DocCast(d?.annotationOn, d)) .filter(d => d); - + console.log(`Found ${linkedDocs.length} linked documents via LinkManager`); - + // Process the linked documents linkedDocs.forEach((doc: Doc) => { if (doc) { this.processDocument(doc); } }); - + // Include the ChatBox document itself this.processDocument(this.chatBoxDocument); - + // If we have access to the Document's parent, try to find sibling documents if (this.chatBoxDocument.parent) { const parent = this.chatBoxDocument.parent; console.log('Found parent document, checking for siblings'); - + // Check if parent is a Doc type and has a childDocs function if (parent && typeof parent === 'object' && 'childDocs' in parent && typeof parent.childDocs === 'function') { try { @@ -356,7 +355,7 @@ export class DocumentMetadataTool extends BaseTool = { id: docId, title: doc.title || '', @@ -488,7 +487,7 @@ export class DocumentMetadataTool extends BaseTool { const fieldDef = this.fieldMetadata[fieldName]; const strippedName = fieldName.startsWith('_') ? fieldName.substring(1) : fieldName; - + // Check if field exists on layout document let layoutValue = undefined; if (layoutDoc) { @@ -499,7 +498,7 @@ export class DocumentMetadataTool extends BaseTool extractText(child)); } }; - + extractText(rtfObj.doc); - + // If we successfully extracted text, show it, but also preserve the original value if (plainText) { return { @@ -819,14 +822,14 @@ export class DocumentMetadataTool extends BaseTool { const strippedName = fieldName.startsWith('_') ? fieldName.substring(1) : fieldName; - + // Add to fieldNameMappings if (fieldName.startsWith('_')) { result.fieldNameMappings[strippedName] = fieldName; } - + // Create structured field metadata const fieldData: Record = { name: fieldName, @@ -886,10 +889,10 @@ export class DocumentMetadataTool extends BaseTool): Promise { console.log('DocumentMetadataTool: Executing with args:', args); - + // Find all documents in the Freeform view this.findDocumentsInFreeformView(); - + try { // Validate required input parameters based on action if (!this.inputValidator(args)) { - return [{ - type: 'text', - text: `Error: Invalid or missing parameters for action "${args.action}". ${this.getParameterRequirementsByAction(String(args.action))}` - }]; + return [ + { + type: 'text', + text: `Error: Invalid or missing parameters for action "${args.action}". ${this.getParameterRequirementsByAction(String(args.action))}`, + }, + ]; } - + // Ensure the action is valid and convert to string const action = String(args.action); if (!['get', 'edit', 'list', 'getFieldOptions', 'create'].includes(action)) { - return [{ - type: 'text', - text: 'Error: Invalid action. Valid actions are "get", "edit", "list", "getFieldOptions", or "create".' - }]; + return [ + { + type: 'text', + text: 'Error: Invalid action. Valid actions are "get", "edit", "list", "getFieldOptions", or "create".', + }, + ]; } // Safely convert documentId to string or undefined const documentId = args.documentId ? String(args.documentId) : undefined; - + // Perform the specified action switch (action) { case 'get': { // Get metadata for a specific document or all documents const result = this.getDocumentMetadata(documentId); console.log('DocumentMetadataTool: Get metadata result:', result); - return [{ - type: 'text', - text: `Document metadata ${documentId ? 'for document ' + documentId : ''} retrieved successfully:\n${JSON.stringify(result, null, 2)}` - }]; + return [ + { + type: 'text', + text: `Document metadata ${documentId ? 'for document ' + documentId : ''} retrieved successfully:\n${JSON.stringify(result, null, 2)}`, + }, + ]; } - + case 'edit': { // Edit a specific field on a document if (!documentId) { - return [{ - type: 'text', - text: 'Error: Document ID is required for edit actions.' - }]; + return [ + { + type: 'text', + text: 'Error: Document ID is required for edit actions.', + }, + ]; } - + // Ensure document exists if (!this.documentsById.has(documentId)) { - return [{ - type: 'text', - text: `Error: Document with ID ${documentId} not found.` - }]; + return [ + { + type: 'text', + text: `Error: Document with ID ${documentId} not found.`, + }, + ]; } - + // Check if we're doing a multi-field edit or a single field edit if (args.fieldEdits) { try { // Parse fieldEdits array const edits = JSON.parse(String(args.fieldEdits)); if (!Array.isArray(edits) || edits.length === 0) { - return [{ - type: 'text', - text: 'Error: fieldEdits must be a non-empty array of field edits.' - }]; + return [ + { + type: 'text', + text: 'Error: fieldEdits must be a non-empty array of field edits.', + }, + ]; } - + // Track results for all edits - const results: { - success: boolean; - message: string; - fieldName?: string; - originalFieldName?: string; + const results: { + success: boolean; + message: string; + fieldName?: string; + originalFieldName?: string; newValue?: any; warning?: string; }[] = []; - + let allSuccessful = true; - + // Process each edit for (const edit of edits) { // Get fieldValue in its original form let fieldValue = edit.fieldValue; - + // Only convert to string if it's neither boolean nor number if (typeof fieldValue !== 'boolean' && typeof fieldValue !== 'number') { fieldValue = String(fieldValue); } - + const fieldName = String(edit.fieldName); - + // Edit the field - const result = this.editDocumentField( - documentId, - fieldName, - fieldValue - ); - + const result = this.editDocumentField(documentId, fieldName, fieldValue); + console.log(`DocumentMetadataTool: Edit field result for ${fieldName}:`, result); - + // Add to results results.push(result); - + // Update success status if (!result.success) { allSuccessful = false; } } - + // Format response based on results let responseText = ''; if (allSuccessful) { responseText = `Successfully edited ${results.length} fields on document ${documentId}:\n`; results.forEach(result => { responseText += `- Field '${result.originalFieldName}': updated to ${JSON.stringify(result.newValue)}\n`; - + // Add any warnings if (result.warning) { responseText += ` Warning: ${result.warning}\n`; @@ -1088,7 +1099,7 @@ export class DocumentMetadataTool extends BaseTool { if (result.success) { responseText += `- Field '${result.originalFieldName}': updated to ${JSON.stringify(result.newValue)}\n`; - + // Add any warnings if (result.warning) { responseText += ` Warning: ${result.warning}\n`; @@ -1098,120 +1109,134 @@ export class DocumentMetadataTool extends BaseTool ({ id, title: doc.title || 'Untitled Document', - type: doc.type || 'Unknown Type' + type: doc.type || 'Unknown Type', })); - + if (docs.length === 0) { - return [{ - type: 'text', - text: 'No documents found in the current view.' - }]; + return [ + { + type: 'text', + text: 'No documents found in the current view.', + }, + ]; } - - return [{ - type: 'text', - text: `Found ${docs.length} document(s) in the current view:\n${JSON.stringify(docs, null, 2)}` - }]; + + return [ + { + type: 'text', + text: `Found ${docs.length} document(s) in the current view:\n${JSON.stringify(docs, null, 2)}`, + }, + ]; } - + case 'getFieldOptions': { // Get all available field options with metadata const fieldOptions = this.getAllFieldMetadata(); - - return [{ - type: 'text', - text: `Document field options retrieved successfully.\nThis information should be consulted before editing document fields to understand available options and dependencies:\n${JSON.stringify(fieldOptions, null, 2)}` - }]; + + return [ + { + type: 'text', + text: `Document field options retrieved successfully.\nThis information should be consulted before editing document fields to understand available options and dependencies:\n${JSON.stringify(fieldOptions, null, 2)}`, + }, + ]; } - + case 'create': { // Create a new document if (!args.title || !args.data || !args.doc_type) { - return [{ - type: 'text', - text: 'Error: Title, data, and doc_type are required for create action.' - }]; + return [ + { + type: 'text', + text: 'Error: Title, data, and doc_type are required for create action.', + }, + ]; } - + const docType = String(args.doc_type); const title = String(args.title); const data = String(args.data); - + // Validate doc_type if (!this.isValidDocType(docType)) { - return [{ - type: 'text', - text: `Error: Invalid doc_type. Valid options are: ${Object.keys(supportedDocTypes).join(',')}` - }]; + return [ + { + type: 'text', + text: `Error: Invalid doc_type. Valid options are: ${Object.keys(supportedDocTypes).join(',')}`, + }, + ]; } - + try { // Create simple document with just title and data const simpleDoc: parsedDoc = { @@ -1223,35 +1248,40 @@ export class DocumentMetadataTool extends BaseTool