1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
|
import { OmitKeys } from '../../../../../ClientUtils';
import { DocumentOptions } from '../../../../documents/Documents';
import { Parameter, ParametersType, supportedDocTypes, ToolInfo } from '../types/tool_types';
import { Observation } from '../types/types';
import { AgentDocumentManager } from '../utils/AgentDocumentManager';
import { BaseTool } from './BaseTool';
// Define the parameters for the DocumentMetadataTool
const parameterDefinitions: ReadonlyArray<Parameter> = [
{
name: 'action',
type: 'string',
required: true,
description: 'The action to perform: "get" to retrieve metadata, "edit" to modify metadata, "getFieldOptions" to retrieve all available field options, or "create" to create a new document',
},
{
name: 'documentId',
type: 'string',
required: false,
description: 'The ID of the document to get or edit metadata for. Required for "edit", optional for "get", ignored for "getFieldOptions", and "create"',
},
{
name: 'fieldEdits',
type: 'string',
required: false,
description: `JSON array of field edits for editing fields. Each item should have fieldName and fieldValue. For single field edits, use an array with one item. fieldName values MUST be in this list: [${Object.keys(DocumentOptions)}]. Example: [{"fieldName":"layout_autoHeight","fieldValue":false},{"fieldName":"height","fieldValue":300}]`,
},
{
name: 'title',
type: 'string',
required: false,
description: 'The title of the document to create. Required for "create" action',
},
{
name: 'data',
type: 'string',
required: false,
description: 'The data content for the document to create. Required for "create" action',
},
{
name: 'doc_type',
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;
// Detailed description with usage guidelines for the DocumentMetadataTool
const toolDescription = `Extracts and modifies metadata from documents in the same Freeform view as the ChatBox, and can create new documents.
This tool helps you work with document properties, understand available fields, edit document metadata, and create new documents.
The Dash document system organizes fields in two locations:
1. Layout documents: contain visual properties like position, dimensions, and appearance
2. Data documents: contain the actual content and document-specific data
This tool provides the following capabilities:
- Get metadata from all documents in the current Freeform view
- Get metadata from a specific document
- Edit metadata fields on documents (in either layout or data documents)
- Edit multiple fields at once (useful for updating dependent fields together)
- Retrieve all available field options with metadata (IMPORTANT: always call this before editing)
- Understand which fields are stored where (layout vs data document)
- Get detailed information about all available document fields
- Support for all value types: strings, numbers, and booleans
- Create new documents with basic properties
DOCUMENT CREATION:
- Use action="create" to create new documents with a simplified approach
- Required parameters: title, data, and doc_type
- The tool will create the document with sensible defaults and link it to the current view
- After creation, you can use the edit action to update its properties
IMPORTANT: Before editing any document metadata, first call 'getFieldOptions' to understand:
- Which fields are available
- The data type of each field
- Special dependencies between fields (like layout_autoHeight and height)
- Proper naming conventions (with or without underscores)
IMPORTANT: Some fields have dependencies that must be handled for edits to work correctly:
- When editing "height", first set "layout_autoHeight" to false (as a boolean value, not a string)
- When editing "width", first set "layout_autoWidth" to false (as a boolean value, not a string)
- Check document metadata to identify other similar dependencies
- All edits are done using the fieldEdits parameter which accepts an array of fields to modify
Example: To change document height, disable auto-height and set height in a single operation:
{... inputs: { action: "edit", documentId: "doc123", fieldEdits: [
{ fieldName: "layout_autoHeight", fieldValue: false },
{ fieldName: "height", fieldValue: 300 }
]}}
Here is a detailed example:
<interaction description="Using DocumentMetadataTool to create and align a diagram with its notes">
<stage number="1" role="user">
<query>Create a flow-chart of neurotransmitter release at a synapse, and place a notes box directly underneath that explains each step.</query>
</stage>
<!-- CREATE THE DIAGRAM -->
<stage number="2" role="assistant">
<thought>
I will create a DiagramBox containing a Mermaid flow-chart. After that, I'll make a notes document, read the diagram’s metadata, and then move the notes so it lines up beneath the chart.
</thought>
<action>documentMetadata</action>
</stage>
<stage number="3" role="user">
<action_rules>***Action rules omitted***</action_rules>
</stage>
<stage number="4" role="assistant">
<action_input>
<action_input_description>Creating a DiagramBox with a Mermaid chart of neurotransmitter release.</action_input_description>
<inputs>
<action>create</action>
<title>Synaptic Release Flowchart</title>
<data>graph TD; A(Vesicle docks)-->B(Ca²⁺ influx); B-->C(Vesicle fuses); C-->D(Neurotransmitter released)</data>
<doc_type>diagram</doc_type>
</inputs>
</action_input>
</stage>
<stage number="5" role="user">
<observation>
<chunk chunk_id="9f2c43c8-0a16-4c12-987b-b813d2f7b1ee" chunk_type="text">
Document created successfully.
Document ID: 9f2c43c8-0a16-4c12-987b-b813d2f7b1ee
Type: diagram
Title: "Synaptic Release Flowchart"
The document has been created with default dimensions and positioning.
…
Full metadata for the created document:
{ /* huge JSON omitted for brevity */ }
</chunk>
</observation>
</stage>
<!-- CREATE THE NOTES DOC -->
<stage number="6" role="assistant">
<thought>
I will create a plain-text notes document that summarises the diagram’s steps.
</thought>
<action>documentMetadata</action>
</stage>
<stage number="7" role="user">
<action_rules>***Action rules omitted***</action_rules>
</stage>
<stage number="8" role="assistant">
<action_input>
<action_input_description>Creating a text document for explanatory notes.</action_input_description>
<inputs>
<action>create</action>
<title>Synaptic Release – Notes</title>
<data>This diagram shows vesicle docking, calcium-triggered fusion, and neurotransmitter release into the synaptic cleft.</data>
<doc_type>note</doc_type>
</inputs>
</action_input>
</stage>
<stage number="9" role="user">
<observation>
<chunk chunk_id="c8e3f4b9-7d2e-462a-a444-61e8e9ff0c7f" chunk_type="text">
Document created successfully.
Document ID: c8e3f4b9-7d2e-462a-a444-61e8e9ff0c7f
Type: note
Title: "Synaptic Release – Notes"
…
Full metadata for the created document:
{ /* huge JSON omitted for brevity */ }
</chunk>
</observation>
</stage>
<!-- READ DIAGRAM METADATA -->
<stage number="10" role="assistant">
<thought>
I'll fetch the diagram’s width, height, and position so I can align the notes box underneath it.
</thought>
<action>documentMetadata</action>
</stage>
<stage number="11" role="user">
<action_rules>***Action rules omitted***</action_rules>
</stage>
<stage number="12" role="assistant">
<action_input>
<action_input_description>Getting metadata for the diagram document.</action_input_description>
<inputs>
<action>get</action>
<documentId>9f2c43c8-0a16-4c12-987b-b813d2f7b1ee</documentId>
</inputs>
</action_input>
</stage>
<stage number="13" role="user">
<observation>
<chunk chunk_id="9f2c43c8-0a16-4c12-987b-b813d2f7b1ee" chunk_type="text">
{
"x": 100,
"y": 100,
"width": 600,
"height": 300,
"layout_autoWidth": false,
"layout_autoHeight": false
}
</chunk>
</observation>
</stage>
<!-- MOVE & SIZE THE NOTES DOC -->
<stage number="14" role="assistant">
<thought>
The diagram ends at y = 100 + 300 = 400.
I’ll move the notes to x = 100, y = 420 (a 20-px gap) and expand its width to 600 px.
</thought>
<action>documentMetadata</action>
</stage>
<stage number="15" role="user">
<action_rules>***Action rules omitted***</action_rules>
</stage>
<stage number="16" role="assistant">
<action_input>
<action_input_description>Editing the notes document’s position and size.</action_input_description>
<inputs>
<action>edit</action>
<documentId>c8e3f4b9-7d2e-462a-a444-61e8e9ff0c7f</documentId>
<fieldEdits>[
{"fieldName":"layout_autoWidth","fieldValue":false},
{"fieldName":"width","fieldValue":600},
{"fieldName":"x","fieldValue":100},
{"fieldName":"y","fieldValue":420}
]</fieldEdits>
</inputs>
</action_input>
</stage>
<stage number="17" role="user">
<observation>
<chunk chunk_id="c8e3f4b9-7d2e-462a-a444-61e8e9ff0c7f" chunk_type="text">
Successfully edited 4 fields on document c8e3f4b9-7d2e-462a-a444-61e8e9ff0c7f.
New position: (x:100, y:420) Width:600
</chunk>
</observation>
</stage>
<!-- FINAL ANSWER -->
<stage number="18" role="assistant">
<thought>
Both documents are now created and perfectly aligned; I can summarise the result.
</thought>
<answer>
<grounded_text citation_index="1">
A **DiagramBox** depicting neurotransmitter release was created at **(100 px, 100 px)**, sized **600 × 300 px**.
</grounded_text>
<grounded_text citation_index="2">
A **notes document** was then resized to **600 px** wide and moved to **(100 px, 420 px)**—20 px below the diagram—to keep the explanation directly beneath the visualization.
</grounded_text>
<normal_text>
This layout ensures viewers can read the synopsis while referring to the flow-chart above.
</normal_text>
<citations>
<citation index="1" chunk_id="9f2c43c8-0a16-4c12-987b-b813d2f7b1ee" type="text"></citation>
<citation index="2" chunk_id="c8e3f4b9-7d2e-462a-a444-61e8e9ff0c7f" type="text"></citation>
</citations>
<follow_up_questions>
<question>Would you like to tweak the diagram’s styling (e.g., colours or fonts)?</question>
<question>Should I link external references or papers in the notes?</question>
<question>Do you want similar diagrams for other neural processes?</question>
</follow_up_questions>
<loop_summary>
The assistant used **DocumentMetadataTool** four times:
1) **create** DiagramBox → 2) **create** notes document → 3) **get** diagram metadata → 4) **edit** notes position/size.
This demonstrates creating, inspecting, and aligning documents within a Freeform view.
</loop_summary>
</answer>
</stage>
</interaction>
<MermaidMindmapGuide>
<Overview>
<Description>
Mermaid mindmaps are hierarchical diagrams used to visually organize ideas. Nodes are created using indentation to show parent-child relationships.
</Description>
<Note>This is an experimental feature in Mermaid and may change in future versions.</Note>
</Overview>
<BasicSyntax>
<CodeExample language="mermaid">
<![CDATA[
mindmap
Root
Branch A
Leaf A1
Leaf A2
Branch B
Leaf B1
]]>
</CodeExample>
<Explanation>
<Point><code>mindmap</code> declares the diagram.</Point>
<Point>Indentation determines the hierarchy.</Point>
<Point>Each level must be indented more than its parent.</Point>
</Explanation>
</BasicSyntax>
<NodeShapes>
<Description>Nodes can be styled with various shapes similar to flowchart syntax.</Description>
<Shapes>
<Shape name="Square"><Code>id[Square Text]</Code></Shape>
<Shape name="Rounded Square"><Code>id(Rounded Square)</Code></Shape>
<Shape name="Circle"><Code>id((Circle))</Code></Shape>
<Shape name="Bang"><Code>id))Bang((</Code></Shape>
<Shape name="Cloud"><Code>id)Cloud(</Code></Shape>
<Shape name="Hexagon"><Code>id{{Hexagon}}</Code></Shape>
<Shape name="Default"><Code>Default shape without any brackets</Code></Shape>
</Shapes>
</NodeShapes>
<Icons>
<Description>Nodes can include icons using the <code>::icon(class)</code> syntax.</Description>
<CodeExample>
<![CDATA[
mindmap
Root
Node A
::icon(fa fa-book)
Node B
::icon(mdi mdi-lightbulb)
]]>
</CodeExample>
<Note>Icon fonts must be included by the site administrator for proper rendering.</Note>
</Icons>
<CSSClasses>
<Description>Add custom styling classes using <code>:::</code>.</Description>
<CodeExample>
<![CDATA[
mindmap
Root
Important Node
:::urgent large
Regular Node
]]>
</CodeExample>
<Note>Classes must be defined in your website or application CSS.</Note>
</CSSClasses>
<MarkdownSupport>
<Description>Supports markdown-style strings for rich text, line breaks, and auto-wrapping.</Description>
<CodeExample>
<![CDATA[
mindmap
id1["**Bold Root** with new line"]
id2["*Italicized* and long text that wraps"]
id3[Plain label]
]]>
</CodeExample>
</MarkdownSupport>
<RenderingNote>
<Note>Indentation is relative, not absolute — Mermaid will infer hierarchy based on surrounding context even with inconsistent spacing.</Note>
</RenderingNote>
<Integration>
<Description>
From Mermaid v11, mindmaps are included natively. For older versions, use external imports with lazy loading.
</Description>
<CodeExample>
<![CDATA[
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
</script>
]]>
</CodeExample>
</Integration>
</MermaidMindmapGuide>
`;
// Extensive usage guidelines for the tool
const citationRules = `USAGE GUIDELINES:
To GET document metadata:
- Use action="get" with optional documentId to return metadata for one or all documents
- Returns field values, field definitions, and location information (layout vs data document)
To GET ALL FIELD OPTIONS (call this first):
- Use action="getFieldOptions" to retrieve metadata about all available document fields
- No additional parameters are required
- Returns structured metadata with field names, types, descriptions, and dependencies
- ALWAYS call this before attempting to edit document metadata
- Use this information to understand which fields need special handling
To CREATE a new document:
- Use action="create" with the following required parameters:
- 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.)
- fieldEdits: Optional JSON array of fields to set during creation
- Example: {...inputs: { action: "create", title: "My Notes", data: "This is the content", doc_type: "text", fieldEdits: [{ fieldName: "text", fieldValue: "Hello world" }] }}
- After creation, you can edit the document with more specific properties
To EDIT document metadata:
- Use action="edit" with required parameters:
- documentId: The ID of the document to edit
- fieldEdits: JSON array of fields to edit, each with fieldName and fieldValue
- The tool will determine the correct document location automatically
- Field names can be provided with or without leading underscores (e.g., both "width" and "_width" work)
- Common fields like "width" and "height" are automatically mapped to "_width" and "_height"
- All value types are supported: strings, numbers, and booleans
- The tool will apply the edit to the correct document (layout or data) based on existing fields
SPECIAL FIELD HANDLING:
- Text fields: When editing the 'text' field, provide simple plain text
Example: {...inputs: { action: "edit", documentId: "doc123", fieldEdits: [{ 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
RECOMMENDED WORKFLOW:
0. Understand the currently available documents that were provided as <available_documents> in the prompt
1. Call action="getFieldOptions" to understand available fields
3. Get document metadata with action="get" to see current values
4. Edit fields with action="edit" using proper dependencies
OR
0. Understand the state of the currently available documents and their metadata using action="get" (this includes spacial positioning).
1. Create a new document with action="create"
2. Get its ID from the response
3. Edit the document's properties with action="edit"
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:
{...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)
- Other auto-sizing related properties
Editing fields follows these rules:
1. First checks if the field exists on the layout document using Doc.Get
2. If it exists on the layout document, it's updated there
3. If it has an underscore prefix (_), it's created/updated on the layout document
4. Otherwise, the field is created/updated on the data document
5. Fields with leading underscores are automatically handled correctly
Examples:
- To get field options: { action: "getFieldOptions" }
- To get all document metadata: { action: "get" }
- To get metadata for a specific document: { action: "get", documentId: "doc123" }
- To edit a single field: { action: "edit", documentId: "doc123", fieldEdits: [{ fieldName: "backgroundColor", fieldValue: "#ff0000" }] }
- To edit a width property: { action: "edit", documentId: "doc123", fieldEdits: [{ fieldName: "width", fieldValue: 300 }] }
- To edit text content: { action: "edit", documentId: "doc123", fieldEdits: [{ fieldName: "text", fieldValue: "Simple plain text goes here" }] }
- To disable auto-height: { action: "edit", documentId: "doc123", fieldEdits: [{ fieldName: "layout_autoHeight", fieldValue: false }] }
- To create a text document: { action: "create", title: "My Notes", data: "This is my note content", doc_type: "text" }
- To create a web document: { action: "create", title: "Google", data: "https://www.google.com", doc_type: "web" }
- To edit height with its dependent field together:
{ 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.
- IMPORTANT: WHEN CITING A DOCUMENT, MAKE THE CHUNK ID THE DOCUMENT ID. WHENEVER YOU CITE A DOCUMENT, ALWAYS MAKE THE CITATION TYPE "text", THE "direct_text" FIELD BLANK, AND THE "chunk_id" FIELD THE DOCUMENT ID.`;
const documentMetadataToolInfo: ToolInfo<DocumentMetadataToolParamsType> = {
name: 'documentMetadata',
description: toolDescription,
parameterRules: parameterDefinitions,
citationRules: citationRules,
};
/**
* A tool for extracting and modifying metadata from documents in a Freeform view.
* This tool collects metadata from both layout and data documents in a Freeform view
* and allows for editing document fields in the correct location.
*/
export class DocumentMetadataTool extends BaseTool<DocumentMetadataToolParamsType> {
private _docManager: AgentDocumentManager;
constructor(docManager: AgentDocumentManager) {
super(documentMetadataToolInfo);
this._docManager = docManager;
this._docManager.initializeFindDocsFreeform();
}
/**
* Executes the document metadata tool
* @param args The arguments for the tool
* @returns An observation with the results of the tool execution
*/
async execute(args: ParametersType<DocumentMetadataToolParamsType>): Promise<Observation[]> {
console.log('DocumentMetadataTool: Executing with args:', args);
// Find all documents in the Freeform view
this._docManager.initializeFindDocsFreeform();
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))}`,
},
];
}
// Ensure the action is valid and convert to string
const action = String(args.action);
if (!['get', 'edit', 'getFieldOptions', 'create'].includes(action)) {
return [
{
type: 'text',
text: 'Error: Invalid action. Valid actions are "get", "edit", "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._docManager.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)}`,
},
];
}
case 'edit': {
// Edit a specific field on a document
if (!documentId) {
return [
{
type: 'text',
text: 'Error: Document ID is required for edit actions.',
},
];
}
// Ensure document exists
if (!this._docManager.has(documentId)) {
return [
{
type: 'text',
text: `Error: Document with ID ${documentId} not found.`,
},
];
}
// Check for fieldEdits parameter
if (!args.fieldEdits) {
return [
{
type: 'text',
text: 'Error: fieldEdits is required for edit actions. Please provide a JSON array of field edits.',
},
];
}
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.',
},
];
}
// Track results for all edits
const results: {
success: boolean;
message: string;
fieldName?: string;
originalFieldName?: string;
newValue?: string | number | boolean | object;
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._docManager.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`;
}
});
} else {
responseText = `Errors occurred while editing fields on document ${documentId}:\n`;
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`;
}
} else {
responseText += `- Error editing '${result.originalFieldName}': ${result.message}\n`;
}
});
}
// Get the updated metadata to return
const updatedMetadata = this._docManager.getDocumentMetadata(documentId);
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)}`,
},
];
}
}
case 'getFieldOptions': {
// Get all available field options with metadata
const fieldOptions = this._docManager.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)}`,
},
];
}
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.',
},
];
}
const docType = String(args.doc_type);
const title = String(args.title);
const data = String(args.data);
const json = typeof args.fieldEdits === 'string' ? JSON.parse(args.fieldEdits) : {};
const docopts = json.length
? (json as Array<{ fieldName: string; fieldValue: string | number | boolean }>).reduce((opts, opt) => {
opts[opt.fieldName] = opt.fieldValue;
return opts;
}, {} as DocumentOptions)
: {};
const id = await this._docManager.createDocInDash(docType, data, docopts);
if (!id) {
return [
{
type: 'text',
text: 'Error: Failed to create document.',
},
];
}
// Get the created document's metadata
const createdMetadata = this._docManager.extractDocumentMetadata(id);
return [
{
type: 'text',
text: `Document created successfully.
Document ID: ${id}
Type: ${docType}
Title: "${title}"
Options: ${JSON.stringify(OmitKeys(args, ['doc_type', 'data', 'title']).omit, null, 2)}
The document has been created with default dimensions and positioning.
You can now use the "edit" action to modify additional properties of this document.
Next steps:
1. Use the "getFieldOptions" action to understand available editable/addable fields/properties and their dependencies.
2. To modify this document, use: { action: "edit", documentId: "${id}", fieldEdits: [{"fieldName":"property","fieldValue":"value"}] }
3. To add styling, consider setting backgroundColor, fontColor, or other properties
4. For text documents, you can edit the content with: { action: "edit", documentId: "${id}", fieldEdits: [{"fieldName":"text","fieldValue":"New content"}] }
Full metadata for the created document:
${JSON.stringify(createdMetadata, null, 2)}`,
},
];
}
default:
return [
{
type: 'text',
text: 'Error: Unknown action. Valid actions are "get", "edit", "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)}`,
},
];
}
}
/**
* Validates the input parameters for the DocumentMetadataTool
* 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
*/
inputValidator(params: ParametersType<DocumentMetadataToolParamsType>): boolean {
// Default validation for required fields
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 fieldEdits is provided
if (params.action === 'edit') {
if (!params.documentId || !params.fieldEdits) {
return false;
}
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) {
console.log('An edit is missing fieldName');
return false;
}
if (edit.fieldValue === undefined) {
console.log('An edit is missing fieldValue');
return false;
}
}
// Everything looks good with fieldEdits
return true;
} catch (error) {
console.log('Error parsing fieldEdits:', error);
return false;
}
}
// 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;
}
return true;
}
/**
* Returns the parameter requirements for a specific action
* @param action The action to get requirements for
* @returns A string describing the required parameters
*/
private getParameterRequirementsByAction(action?: string): string {
if (!action) {
return 'Please specify an action: "get", "edit", "getFieldOptions", or "create".';
}
switch (action.toLowerCase()) {
case 'get':
return 'The "get" action accepts an optional documentId parameter.';
case 'edit':
return 'The "edit" action requires documentId and fieldEdits parameters. fieldEdits must be a JSON array of field edits.';
case 'getFieldOptions':
return 'The "getFieldOptions" action does not require any additional parameters. It returns metadata about all available document fields.';
case 'create':
return 'The "create" action requires title, data, and doc_type parameters.';
default:
return `Unknown action "${action}". Valid actions are "get", "edit", "getFieldOptions", or "create".`;
}
}
}
|