diff options
| author | A.J. Shulman <Shulman.aj@gmail.com> | 2025-04-10 12:36:07 -0400 |
|---|---|---|
| committer | A.J. Shulman <Shulman.aj@gmail.com> | 2025-04-10 12:36:07 -0400 |
| commit | 6e8f05495dfcf7d64bdc424503f874fece85e291 (patch) | |
| tree | e8f3ead08cbc1aa4728ed969c2ec3a35fadf201a /src/client/views/nodes/chatbot/tools/DocumentMetadataTool.ts | |
| parent | fa0b8fcd800e5a765a6db2681807986463544405 (diff) | |
trying again
Diffstat (limited to 'src/client/views/nodes/chatbot/tools/DocumentMetadataTool.ts')
| -rw-r--r-- | src/client/views/nodes/chatbot/tools/DocumentMetadataTool.ts | 561 |
1 files changed, 299 insertions, 262 deletions
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<Parameter> = [ { @@ -61,7 +60,7 @@ const parameterDefinitions: ReadonlyArray<Parameter> = [ 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<DocumentMetadataToolParamsType> = { name: 'documentMetadata', description: toolDescription, @@ -227,7 +226,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp constructor(chatBox: any) { super(documentMetadataToolInfo); this.chatBox = chatBox; - + // Store a direct reference to the ChatBox document if (chatBox && chatBox.Document) { this.chatBoxDocument = chatBox.Document; @@ -246,7 +245,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp } else { console.warn('DocumentMetadataTool initialized without valid ChatBox Document reference'); } - + this.initializeFieldMetadata(); } @@ -273,12 +272,12 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp // Check if fieldInfo has description property (it's likely a FInfo instance) if (fieldInfo && typeof fieldInfo === 'object' && 'description' in fieldInfo) { fieldData.description = fieldInfo.description; - + // Extract field type if available if ('fieldType' in fieldInfo) { fieldData.type = fieldInfo.fieldType; } - + // Extract possible values if available if ('values' in fieldInfo && Array.isArray(fieldInfo.values)) { fieldData.possibleValues = fieldInfo.values; @@ -303,30 +302,30 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp // Use the LinkManager approach which is proven to work in ChatBox if (this.chatBoxDocument) { console.log('Finding documents linked to ChatBox document with ID:', this.chatBoxDocument.id); - + // Get directly linked documents via LinkManager const linkedDocs = LinkManager.Instance.getAllRelatedLinks(this.chatBoxDocument) .map(d => 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<DocumentMetadataToolParamsTyp } }); } - + // Process the ChatBox document if available if (this.chatBox.Document) { this.processDocument(this.chatBox.Document); @@ -366,11 +365,11 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp } console.log(`DocumentMetadataTool found ${this.documentsById.size} total documents`); - + // If we didn't find any documents, try a fallback method if (this.documentsById.size === 0 && this.chatBox) { console.log('No documents found, trying fallback method'); - + // Try to access any field that might contain documents if (this.chatBox.props && this.chatBox.props.documents) { const documents = this.chatBox.props.documents; @@ -396,17 +395,17 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp private processDocument(doc: Doc) { // Ensure document has a persistent ID const docId = this.ensureDocumentId(doc); - + // Only add if we haven't already processed this document if (!this.documentsById.has(docId)) { this.documentsById.set(docId, doc); - + // Get layout doc (the document itself or its layout) const layoutDoc = Doc.Layout(doc); if (layoutDoc) { this.layoutDocsById.set(docId, layoutDoc); } - + // Get data doc const dataDoc = doc[DocData]; if (dataDoc) { @@ -422,15 +421,15 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp */ private ensureDocumentId(doc: Doc): string { let docId: string | undefined; - + // First try to get the ID from our custom field if (doc[this.DOCUMENT_ID_FIELD]) { docId = String(doc[this.DOCUMENT_ID_FIELD]); return docId; } - + // Try different ways to get a document ID - + // 1. Try the direct id property if it exists if (doc.id && typeof doc.id === 'string') { docId = doc.id; @@ -448,14 +447,14 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp docId = uuidv4(); console.log(`Generated new UUID for document with title: ${doc.title || 'Untitled'}`); } - + // Store the ID in the document's metadata so it persists try { doc[this.DOCUMENT_ID_FIELD] = docId; } catch (e) { console.warn(`Could not assign ID to document property`, e); } - + return docId; } @@ -472,7 +471,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp const layoutDoc = this.layoutDocsById.get(docId); const dataDoc = this.dataDocsById.get(docId); - + const metadata: Record<string, any> = { id: docId, title: doc.title || '', @@ -488,7 +487,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp Object.keys(this.fieldMetadata).forEach(fieldName => { 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<DocumentMetadataToolParamsTyp metadata.fieldLocationMap[strippedName] = 'layout'; } } - + // Check if field exists on data document let dataValue = undefined; if (dataDoc) { @@ -512,12 +511,12 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp } } } - + // For fields with stripped names (without leading underscore), // also check if they exist on documents without the underscore if (fieldName.startsWith('_')) { const nonUnderscoreFieldName = fieldName.substring(1); - + if (layoutDoc) { const nonUnderscoreLayoutValue = layoutDoc[nonUnderscoreFieldName]; if (nonUnderscoreLayoutValue !== undefined) { @@ -525,7 +524,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp metadata.fieldLocationMap[nonUnderscoreFieldName] = 'layout'; } } - + if (dataDoc) { const nonUnderscoreDataValue = dataDoc[nonUnderscoreFieldName]; if (nonUnderscoreDataValue !== undefined) { @@ -544,7 +543,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp metadata.fields.layout.width = metadata.fields.layout._width; metadata.fieldLocationMap.width = 'layout'; } - + if (metadata.fields.layout._height !== undefined && metadata.fields.layout.height === undefined) { metadata.fields.layout.height = metadata.fields.layout._height; metadata.fieldLocationMap.height = 'layout'; @@ -560,18 +559,22 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp * @param fieldValue The new value for the field (string, number, or boolean) * @returns Object with success status, message, and additional information */ - private editDocumentField(docId: string, fieldName: string, fieldValue: string | number | boolean): { - success: boolean; - message: string; - fieldName?: string; - originalFieldName?: string; + private editDocumentField( + docId: string, + fieldName: string, + fieldValue: string | number | boolean + ): { + success: boolean; + message: string; + fieldName?: string; + originalFieldName?: string; newValue?: any; warning?: string; } { // Normalize field name (handle with/without underscore) let normalizedFieldName = fieldName.startsWith('_') ? fieldName : fieldName; const strippedFieldName = fieldName.startsWith('_') ? fieldName.substring(1) : fieldName; - + // Handle common field name aliases (width → _width, height → _height) // Many document fields use '_' prefix for layout properties if (fieldName === 'width') { @@ -579,36 +582,36 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp } else if (fieldName === 'height') { normalizedFieldName = '_height'; } - + // Get the documents const doc = this.documentsById.get(docId); if (!doc) { return { success: false, message: `Document with ID ${docId} not found` }; } - + const layoutDoc = this.layoutDocsById.get(docId); const dataDoc = this.dataDocsById.get(docId); - + if (!layoutDoc && !dataDoc) { return { success: false, message: `Could not find layout or data document for document with ID ${docId}` }; } - + try { // Convert the field value to the appropriate type based on field metadata const convertedValue = this.convertFieldValue(normalizedFieldName, fieldValue); - + let targetDoc: Doc | undefined; let targetLocation: string; - + // First, check if field exists on layout document using Doc.Get if (layoutDoc) { const fieldExistsOnLayout = Doc.Get(layoutDoc, normalizedFieldName, true) !== undefined; - + // If it exists on layout document, update it there if (fieldExistsOnLayout) { targetDoc = layoutDoc; targetLocation = 'layout'; - } + } // If it has an underscore prefix, it's likely a layout property even if not yet set else if (normalizedFieldName.startsWith('_')) { targetDoc = layoutDoc; @@ -618,13 +621,13 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp else if (dataDoc) { targetDoc = dataDoc; targetLocation = 'data'; - } + } // If no data document available, default to layout else { targetDoc = layoutDoc; targetLocation = 'layout'; } - } + } // If no layout document, use data document else if (dataDoc) { targetDoc = dataDoc; @@ -632,26 +635,26 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp } else { return { success: false, message: `No valid document found for editing` }; } - + if (!targetDoc) { return { success: false, message: `Target document not available` }; } - + // Set the field value on the target document targetDoc[normalizedFieldName] = convertedValue; - - return { - success: true, + + return { + success: true, message: `Successfully updated field '${normalizedFieldName}' on ${targetLocation} document (ID: ${docId})`, fieldName: normalizedFieldName, originalFieldName: fieldName, - newValue: convertedValue + newValue: convertedValue, }; } catch (error) { console.error('Error editing document field:', error); - return { - success: false, - message: `Error updating field: ${error instanceof Error ? error.message : String(error)}` + return { + success: false, + message: `Error updating field: ${error instanceof Error ? error.message : String(error)}`, }; } } @@ -667,7 +670,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp if (typeof fieldValue === 'number' || typeof fieldValue === 'boolean') { return fieldValue; } - + // If fieldValue is a string "true" or "false", convert to boolean if (typeof fieldValue === 'string') { if (fieldValue.toLowerCase() === 'true') { @@ -677,12 +680,12 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp return false; } } - + // If fieldValue is not a string (and not a number or boolean), convert it to string if (typeof fieldValue !== 'string') { fieldValue = String(fieldValue); } - + // Special handling for text field - convert to proper RichTextField format if (fieldName === 'text') { try { @@ -710,28 +713,28 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp return JSON.stringify(rtf); } } - + // Get field metadata const normalizedFieldName = fieldName.startsWith('_') ? fieldName : `_${fieldName}`; const strippedFieldName = fieldName.startsWith('_') ? fieldName.substring(1) : fieldName; - + // Check both versions of the field name in metadata const fieldMeta = this.fieldMetadata[normalizedFieldName] || this.fieldMetadata[strippedFieldName]; - + // Special handling for width and height without metadata if (!fieldMeta && (fieldName === '_width' || fieldName === '_height' || fieldName === 'width' || fieldName === 'height')) { const num = Number(fieldValue); return isNaN(num) ? fieldValue : num; } - + if (!fieldMeta) { // If no metadata found, just return the string value return fieldValue; } - + // Convert based on field type const fieldType = fieldMeta.type; - + if (fieldType === 'boolean') { // Convert to boolean return fieldValue.toLowerCase() === 'true'; @@ -761,7 +764,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp return fieldValue; } } - + // Default to string return fieldValue; } @@ -775,7 +778,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp if (value === undefined || value === null) { return null; } - + // Handle Doc objects if (value instanceof Doc) { return { @@ -785,7 +788,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp docType: value.type || '', }; } - + // Handle RichTextField (try to extract plain text) if (typeof value === 'string' && value.includes('"type":"doc"') && value.includes('"content":')) { try { @@ -802,9 +805,9 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp node.content.forEach((child: any) => 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<DocumentMetadataToolParamsTyp // If parsing fails, just treat as a regular string } } - + // Handle arrays and complex objects if (typeof value === 'object') { // If the object has a toString method, use it if (value.toString && value.toString !== Object.prototype.toString) { return value.toString(); } - + try { // Try to convert to JSON string return JSON.stringify(value); @@ -834,7 +837,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp return '[Complex Object]'; } } - + // Return primitive values as is return value; } @@ -856,7 +859,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp list: [], date: [], enumeration: [], - other: [] + other: [], }, fieldNameMappings: {}, commonFields: { @@ -865,19 +868,19 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp size: [], content: [], behavior: [], - layout: [] - } + layout: [], + }, }; // Process each field in the metadata Object.entries(this.fieldMetadata).forEach(([fieldName, fieldInfo]) => { 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<string, any> = { name: fieldName, @@ -886,10 +889,10 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp type: fieldInfo.fieldType || 'unknown', possibleValues: fieldInfo.values || [], }; - + // Add field to fields collection result.fields[fieldName] = fieldData; - + // Categorize by field type const type = fieldInfo.fieldType?.toLowerCase() || 'unknown'; if (type === 'string') { @@ -909,7 +912,7 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp } else { result.fieldsByType.other.push(fieldName); } - + // Categorize by field purpose if (fieldName.includes('width') || fieldName.includes('height') || fieldName.includes('size')) { result.commonFields.size.push(fieldName); @@ -925,23 +928,23 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp result.commonFields.layout.push(fieldName); } }); - + // Add special section for auto-sizing related fields result.autoSizingFields = { height: { autoHeightField: '_layout_autoHeight', heightField: '_height', displayName: 'height', - usage: 'To manually set height, first set layout_autoHeight to false' + usage: 'To manually set height, first set layout_autoHeight to false', }, width: { autoWidthField: '_layout_autoWidth', widthField: '_width', displayName: 'width', - usage: 'To manually set width, first set layout_autoWidth to false' - } + usage: 'To manually set width, first set layout_autoWidth to false', + }, }; - + // Add special section for text field format result.specialFields = { text: { @@ -949,10 +952,10 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp description: 'Document text content', format: 'RichTextField', note: 'When setting text, provide plain text - it will be automatically converted to the correct format', - example: 'For setting: "Hello world" (plain text); For getting: Will be converted to plaintext for display' - } + example: 'For setting: "Hello world" (plain text); For getting: Will be converted to plaintext for display', + }, }; - + return result; } @@ -963,121 +966,129 @@ export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsTyp */ async execute(args: ParametersType<DocumentMetadataToolParamsType>): Promise<Observation[]> { 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<DocumentMetadataToolParamsTyp results.forEach(result => { 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<DocumentMetadataToolParamsTyp } }); } - + // Get the updated metadata to return const updatedMetadata = this.getDocumentMetadata(documentId); - - return [{ - type: 'text', - text: `${responseText}\nUpdated metadata:\n${JSON.stringify(updatedMetadata, null, 2)}` - }]; + + return [ + { + type: 'text', + text: `${responseText}\nUpdated metadata:\n${JSON.stringify(updatedMetadata, null, 2)}`, + }, + ]; } catch (error) { - return [{ - type: 'text', - text: `Error processing fieldEdits: ${error instanceof Error ? error.message : String(error)}` - }]; + return [ + { + type: 'text', + text: `Error processing fieldEdits: ${error instanceof Error ? error.message : String(error)}`, + }, + ]; } } else { // Single field edit (original behavior) if (!args.fieldName) { - return [{ - type: 'text', - text: 'Error: Field name and field value are required for edit actions.' - }]; + return [ + { + type: 'text', + text: 'Error: Field name and field value are required for edit actions.', + }, + ]; } - + // Get fieldValue in its original form - we'll handle conversion in editDocumentField let fieldValue = args.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(args.fieldName); - + // Edit the field - const result = this.editDocumentField( - documentId, - fieldName, - fieldValue - ); - + const result = this.editDocumentField(documentId, fieldName, fieldValue); + console.log('DocumentMetadataTool: Edit field result:', result); - + if (!result.success) { return [{ type: 'text', text: result.message }]; } - + // Include warning if present let responseText = result.message; if (result.warning) { responseText += `\n\n${result.warning}`; } - + // Get the updated metadata to return const updatedMetadata = this.getDocumentMetadata(documentId); - - return [{ - type: 'text', - text: `${responseText}\nUpdated metadata:\n${JSON.stringify(updatedMetadata, null, 2)}` - }]; + + return [ + { + type: 'text', + text: `${responseText}\nUpdated metadata:\n${JSON.stringify(updatedMetadata, null, 2)}`, + }, + ]; } } - + case 'list': { // List all available documents in simple format const docs = Array.from(this.documentsById.entries()).map(([id, doc]) => ({ 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<DocumentMetadataToolParamsTyp _width: 300, _height: 300, _layout_fitWidth: false, - _layout_autoHeight: true + _layout_autoHeight: true, }; - + // Use the chatBox's createDocInDash method to create and link the document if (!this.chatBox || !this.chatBox.createDocInDash) { - return [{ - type: 'text', - text: 'Error: Could not access document creation functionality.' - }]; + return [ + { + type: 'text', + text: 'Error: Could not access document creation functionality.', + }, + ]; } - + const createdDoc = this.chatBox.createDocInDash(simpleDoc); - + if (!createdDoc) { - return [{ - type: 'text', - text: 'Error: Failed to create document.' - }]; + return [ + { + type: 'text', + text: 'Error: Failed to create document.', + }, + ]; } - + // Update our local document maps with the new document this.processDocument(createdDoc); - + // Get the created document's metadata const createdMetadata = this.getDocumentMetadata(createdDoc.id); - - return [{ - type: 'text', - text: `Document created successfully. + + return [ + { + type: 'text', + text: `Document created successfully. Document ID: ${createdDoc.id} Type: ${docType} Title: "${title}" @@ -1266,36 +1296,43 @@ Next steps: 4. For text documents, you can edit the content with: { action: "edit", documentId: "${createdDoc.id}", fieldName: "text", fieldValue: "New content" } Full metadata for the created document: -${JSON.stringify(createdMetadata, null, 2)}` - }]; +${JSON.stringify(createdMetadata, null, 2)}`, + }, + ]; } catch (error) { - return [{ - type: 'text', - text: `Error creating document: ${error instanceof Error ? error.message : String(error)}` - }]; + return [ + { + type: 'text', + text: `Error creating document: ${error instanceof Error ? error.message : String(error)}`, + }, + ]; } } - + default: - return [{ - type: 'text', - text: 'Error: Unknown action. Valid actions are "get", "edit", "list", "getFieldOptions", or "create".' - }]; + return [ + { + type: 'text', + text: 'Error: Unknown action. Valid actions are "get", "edit", "list", "getFieldOptions", or "create".', + }, + ]; } } catch (error) { console.error('DocumentMetadataTool execution error:', error); - return [{ - type: 'text', - text: `Error executing DocumentMetadataTool: ${error instanceof Error ? error.message : String(error)}` - }]; + return [ + { + type: 'text', + text: `Error executing DocumentMetadataTool: ${error instanceof Error ? error.message : String(error)}`, + }, + ]; } } /** * Validates the input parameters for the DocumentMetadataTool - * This custom validator allows numbers and booleans to be passed for fieldValue + * This custom validator allows numbers and booleans to be passed for fieldValue * while maintaining compatibility with the standard validation - * + * * @param params The parameters to validate * @returns True if the parameters are valid, false otherwise */ @@ -1304,12 +1341,12 @@ ${JSON.stringify(createdMetadata, null, 2)}` if (params.action === undefined) { return false; } - + // For create action, validate required parameters if (params.action === 'create') { return !!(params.title && params.data && params.doc_type); } - + // For edit action, validate either single field edit or multiple field edits if (params.action === 'edit') { // If fieldEdits is provided, it must be valid and we'll ignore fieldName/fieldValue @@ -1317,13 +1354,13 @@ ${JSON.stringify(createdMetadata, null, 2)}` try { // Parse fieldEdits and validate its structure const edits = JSON.parse(String(params.fieldEdits)); - + // Ensure it's an array if (!Array.isArray(edits)) { console.log('fieldEdits is not an array'); return false; } - + // Ensure each item has fieldName and fieldValue for (const edit of edits) { if (!edit.fieldName) { @@ -1335,7 +1372,7 @@ ${JSON.stringify(createdMetadata, null, 2)}` return false; } } - + // Everything looks good with fieldEdits return !!params.documentId; // Just ensure documentId is provided } catch (error) { @@ -1349,22 +1386,22 @@ ${JSON.stringify(createdMetadata, null, 2)}` } } } - + // For get action with documentId, documentId is required if (params.action === 'get' && params.documentId === '') { return false; } - + // getFieldOptions action doesn't require any additional parameters if (params.action === 'getFieldOptions') { return true; } - + // list action doesn't require any additional parameters if (params.action === 'list') { return true; } - + // Allow for numeric or boolean fieldValue even though the type is defined as string if (params.fieldValue !== undefined) { if (typeof params.fieldValue === 'number') { @@ -1372,14 +1409,14 @@ ${JSON.stringify(createdMetadata, null, 2)}` // We'll convert it later, so don't fail validation return true; } - + if (typeof params.fieldValue === 'boolean') { console.log('Boolean fieldValue detected, will be converted appropriately'); // We'll handle boolean conversion in the execute method return true; } } - + return true; } @@ -1424,11 +1461,11 @@ ${JSON.stringify(createdMetadata, null, 2)}` for (const docId of this.documentsById.keys()) { documentsMetadata[docId] = this.extractDocumentMetadata(docId); } - + return { documentCount: this.documentsById.size, documents: documentsMetadata, - fieldDefinitions: this.fieldMetadata + fieldDefinitions: this.fieldMetadata, }; } } @@ -1441,4 +1478,4 @@ ${JSON.stringify(createdMetadata, null, 2)}` private isValidDocType(docType: string): boolean { return Object.values(supportedDocTypes).includes(docType as supportedDocTypes); } -}
\ No newline at end of file +} |
