a06fd54e by Ean Schuessler

Implement universal autocomplete with transition metadata extraction

- Extract service name and in-map from transition XML
- Capture depends-on parameter attribute for field name mapping
- Parse in-map parameter mapping for proper service calls
- Support server-search autocomplete with term parameter
- Fallback to ScreenAsMcpTool for entity-find transitions
- Enhanced response format detection and error handling

This implements TODO 1-3 from AGENTS.md:
- TODO 1: Capture Depends-on Parameter Attribute
- TODO 2: Extract Transition Service Name
- TODO 3: Parse in-map Parameter Mapping

Files modified:
- DefaultScreenMacros.mcp.ftl: Extract transition metadata during screen render
- McpFieldOptionsService.groovy: Use extracted metadata for intelligent autocomplete
1 parent 4b34c970
...@@ -45,18 +45,29 @@ Use the following discovery tools to explore available functionality: ...@@ -45,18 +45,29 @@ Use the following discovery tools to explore available functionality:
45 ## Common Screen Paths 45 ## Common Screen Paths
46 46
47 ### Catalog Operations 47 ### Catalog Operations
48 - `/PopCommerce/PopCommerceAdmin/Catalog/dashboard`: Catalog overview and management
48 - `/PopCommerce/PopCommerceAdmin/Catalog/Product/FindProduct`: Search and browse products 49 - `/PopCommerce/PopCommerceAdmin/Catalog/Product/FindProduct`: Search and browse products
49 - `/PopCommerce/PopCommerceAdmin/Catalog/Feature/FindFeature`: Search by features like color or size 50 - `/PopCommerce/PopCommerceAdmin/Catalog/Feature/FindFeature`: Search by features like color or size
50 - `/PopCommerce/PopCommerceAdmin/Catalog/Product/EditPrices`: View and update product prices 51 - `/PopCommerce/PopCommerceAdmin/Catalog/Product/EditPrices`: View and update product prices
51 52
52 ### Order Management 53 ### Order Management
53 - `/PopCommerce/PopCommerceAdmin/Order/FindOrder`: Lookup order status and details 54 - `/PopCommerce/PopCommerceAdmin/Order/FindOrder`: Lookup and create sales/purchase orders
54 - `/PopCommerce/PopCommerceAdmin/QuickSearch`: General order and customer search 55 - `/PopCommerce/PopCommerceAdmin/QuickSearch`: General order and customer search
55 56
56 ### Customer Management 57 ### Party & Customer Management
57 - `/PopCommerce/PopCommerceRoot/Customer`: Manage customer accounts 58 - `/PopCommerce/PopCommerceAdmin/Party/FindParty`: Manage all parties (People, Organizations)
59 - `/PopCommerce/PopCommerceRoot/Customer`: Customer storefront account management
60 - `User`: Internal user account, notifications, and messages
58 - `/PopCommerce/PopCommerceAdmin/QuickSearch`: Customer lookup 61 - `/PopCommerce/PopCommerceAdmin/QuickSearch`: Customer lookup
59 62
63 ### Facility & Accounting
64 - `/PopCommerce/PopCommerceAdmin/Facility/FindFacility`: Manage warehouses and inventory locations
65 - `/PopCommerce/PopCommerceAdmin/Accounting/dashboard`: Financial management and GL accounting
66
67 ### System & Developer Tools
68 - `/tools/Tools`: Developer tools, entity data editing, and service references
69 - `/tools/System`: System administration, cache management, and security settings
70
60 ## Tips for LLM Clients 71 ## Tips for LLM Clients
61 72
62 - All screens support parameterized queries for filtering results 73 - All screens support parameterized queries for filtering results
...@@ -107,18 +118,29 @@ Use the following discovery tools to explore available functionality: ...@@ -107,18 +118,29 @@ Use the following discovery tools to explore available functionality:
107 ## Common Screen Paths 118 ## Common Screen Paths
108 119
109 ### Catalog Operations 120 ### Catalog Operations
121 - `/PopCommerce/PopCommerceAdmin/Catalog/dashboard`: Catalog overview and management
110 - `/PopCommerce/PopCommerceAdmin/Catalog/Product/FindProduct`: Search and browse products 122 - `/PopCommerce/PopCommerceAdmin/Catalog/Product/FindProduct`: Search and browse products
111 - `/PopCommerce/PopCommerceAdmin/Catalog/Feature/FindFeature`: Search by features like color or size 123 - `/PopCommerce/PopCommerceAdmin/Catalog/Feature/FindFeature`: Search by features like color or size
112 - `/PopCommerce/PopCommerceAdmin/Catalog/Product/EditPrices`: View and update product prices 124 - `/PopCommerce/PopCommerceAdmin/Catalog/Product/EditPrices`: View and update product prices
113 125
114 ### Order Management 126 ### Order Management
115 - `/PopCommerce/PopCommerceAdmin/Order/FindOrder`: Lookup order status and details 127 - `/PopCommerce/PopCommerceAdmin/Order/FindOrder`: Lookup and create sales/purchase orders
116 - `/PopCommerce/PopCommerceAdmin/QuickSearch`: General order and customer search 128 - `/PopCommerce/PopCommerceAdmin/QuickSearch`: General order and customer search
117 129
118 ### Customer Management 130 ### Party & Customer Management
119 - `/PopCommerce/PopCommerceRoot/Customer`: Manage customer accounts 131 - `/PopCommerce/PopCommerceAdmin/Party/FindParty`: Manage all parties (People, Organizations)
132 - `/PopCommerce/PopCommerceRoot/Customer`: Customer storefront account management
133 - `User`: Internal user account, notifications, and messages
120 - `/PopCommerce/PopCommerceAdmin/QuickSearch`: Customer lookup 134 - `/PopCommerce/PopCommerceAdmin/QuickSearch`: Customer lookup
121 135
136 ### Facility & Accounting
137 - `/PopCommerce/PopCommerceAdmin/Facility/FindFacility`: Manage warehouses and inventory locations
138 - `/PopCommerce/PopCommerceAdmin/Accounting/dashboard`: Financial management and GL accounting
139
140 ### System & Developer Tools
141 - `/tools/Tools`: Developer tools, entity data editing, and service references
142 - `/tools/System`: System administration, cache management, and security settings
143
122 ## Tips for LLM Clients 144 ## Tips for LLM Clients
123 145
124 - All screens support parameterized queries for filtering results 146 - All screens support parameterized queries for filtering results
...@@ -144,14 +166,15 @@ Main storefront and customer-facing screens for PopCommerce e-commerce component ...@@ -144,14 +166,15 @@ Main storefront and customer-facing screens for PopCommerce e-commerce component
144 166
145 ## Key Screens 167 ## Key Screens
146 168
147 - **Customer Management**: Browse and manage customer accounts 169 - **Catalog & Products**: Browse the product catalog and view details
148 - **Order Status**: View order history and track shipments 170 - **Customer Management**: Manage customer profiles and account settings
149 - **Product Catalog**: Browse products and categories 171 - **Order Management**: Track order history and status
150 - **Shopping Cart**: Review and checkout items 172 - **Shopping Cart**: Review items and proceed to checkout
173 - **Messages**: Access `User/Messages` for internal communications
151 174
152 ## Navigation 175 ## Navigation
153 176
154 Use browse tools to explore the full catalog of PopCommerce screens starting from this root screen.]]></fileData> 177 Use browse tools to explore the full catalog of PopCommerce screens. For administrative tasks, use the `/PopCommerce/PopCommerceAdmin` hierarchy.]]></fileData>
155 </moqui.resource.DbResourceFile> 178 </moqui.resource.DbResourceFile>
156 179
157 <!-- PopCommerce Root Wiki Page --> 180 <!-- PopCommerce Root Wiki Page -->
...@@ -212,4 +235,126 @@ These screens are primarily for learning Moqui screen development patterns.]]></ ...@@ -212,4 +235,126 @@ These screens are primarily for learning Moqui screen development patterns.]]></
212 userId="EX_JOHN_DOE" 235 userId="EX_JOHN_DOE"
213 changeDateTime="2025-01-02 00:00:00.000"/> 236 changeDateTime="2025-01-02 00:00:00.000"/>
214 237
238 <!-- User Messages Documentation -->
239 <moqui.resource.DbResource
240 resourceId="WIKI_MCP_DOCS_USER_MESSAGES"
241 parentResourceId="WIKI_MCP_SCREEN_DOCS"
242 filename="User/Messages.md"
243 isFile="Y"/>
244 <moqui.resource.DbResourceFile
245 resourceId="WIKI_MCP_DOCS_USER_MESSAGES"
246 mimeType="text/markdown"
247 versionName="v1">
248 <fileData><![CDATA[# User Messages
249
250 Interface for sending and receiving messages between users and other parties.
251
252 ## Key Actions
253
254 - **Create Message**: Send a new message. Requires `toPartyId`, `subject`, and `body`.
255 - **View Thread**: View the conversation history for a message.
256 - **Find Messages**: Search for existing messages by various criteria.
257
258 ## Usage
259
260 Use this screen to communicate about orders, products, or general administrative tasks.]]></fileData>
261 </moqui.resource.DbResourceFile>
262
263 <moqui.resource.wiki.WikiPage
264 wikiPageId="MCP_SCREEN_DOCS/UserMessages"
265 wikiSpaceId="MCP_SCREEN_DOCS"
266 pagePath="User/Messages"
267 publishedVersionName="v1"
268 restrictView="N">
269 </moqui.resource.wiki.WikiPage>
270
271 <moqui.resource.wiki.WikiPageHistory
272 wikiPageId="MCP_SCREEN_DOCS/UserMessages"
273 historySeqId="1"
274 versionName="v1"
275 userId="EX_JOHN_DOE"
276 changeDateTime="2025-01-14 00:00:00.000"/>
277
278 <!-- Tools Documentation -->
279 <moqui.resource.DbResource
280 resourceId="WIKI_MCP_DOCS_TOOLS"
281 parentResourceId="WIKI_MCP_SCREEN_DOCS"
282 filename="tools/Tools.md"
283 isFile="Y"/>
284 <moqui.resource.DbResourceFile
285 resourceId="WIKI_MCP_DOCS_TOOLS"
286 mimeType="text/markdown"
287 versionName="v1">
288 <fileData><![CDATA[# Developer Tools
289
290 Central hub for developer and data management utilities.
291
292 ## Key Subscreens
293
294 - **Entity**: Data editing, import/export, and performance stats. Use `tools/Tools/Entity/DataEdit/EntityList` to browse and edit any entity.
295 - **Service**: Service reference and testing tools.
296 - **AutoScreen**: Automatically generated screens for all entities.
297 - **GroovyShell**: Execute arbitrary Groovy code (use with extreme caution).
298
299 ## Usage
300
301 Use these tools for low-level data manipulation or system exploration when standard administrative screens are insufficient.]]></fileData>
302 </moqui.resource.DbResourceFile>
303
304 <moqui.resource.wiki.WikiPage
305 wikiPageId="MCP_SCREEN_DOCS/Tools"
306 wikiSpaceId="MCP_SCREEN_DOCS"
307 pagePath="tools/Tools"
308 publishedVersionName="v1"
309 restrictView="N">
310 </moqui.resource.wiki.WikiPage>
311
312 <moqui.resource.wiki.WikiPageHistory
313 wikiPageId="MCP_SCREEN_DOCS/Tools"
314 historySeqId="1"
315 versionName="v1"
316 userId="EX_JOHN_DOE"
317 changeDateTime="2025-01-14 00:00:00.000"/>
318
319 <!-- System Documentation -->
320 <moqui.resource.DbResource
321 resourceId="WIKI_MCP_DOCS_SYSTEM"
322 parentResourceId="WIKI_MCP_SCREEN_DOCS"
323 filename="tools/System.md"
324 isFile="Y"/>
325 <moqui.resource.DbResourceFile
326 resourceId="WIKI_MCP_DOCS_SYSTEM"
327 mimeType="text/markdown"
328 versionName="v1">
329 <fileData><![CDATA[# System Administration
330
331 Core system management and monitoring screens.
332
333 ## Key Subscreens
334
335 - **Security**: Manage users, user groups, and artifact permissions.
336 - **Cache**: View and clear system caches.
337 - **ServiceJob**: Manage scheduled and background service jobs.
338 - **LogViewer**: View system logs and hit statistics.
339
340 ## Usage
341
342 Use these screens to monitor system health, manage user access, and troubleshoot operational issues.]]></fileData>
343 </moqui.resource.DbResourceFile>
344
345 <moqui.resource.wiki.WikiPage
346 wikiPageId="MCP_SCREEN_DOCS/System"
347 wikiSpaceId="MCP_SCREEN_DOCS"
348 pagePath="tools/System"
349 publishedVersionName="v1"
350 restrictView="N">
351 </moqui.resource.wiki.WikiPage>
352
353 <moqui.resource.wiki.WikiPageHistory
354 wikiPageId="MCP_SCREEN_DOCS/System"
355 historySeqId="1"
356 versionName="v1"
357 userId="EX_JOHN_DOE"
358 changeDateTime="2025-01-14 00:00:00.000"/>
359
215 </entity-facade-xml> 360 </entity-facade-xml>
......
...@@ -147,14 +147,61 @@ ...@@ -147,14 +147,61 @@
147 <#if dropdownOptions?has_content> 147 <#if dropdownOptions?has_content>
148 <#assign fieldMeta = fieldMeta + {"type": "dropdown", "options": dropdownOptions?js_string!}> 148 <#assign fieldMeta = fieldMeta + {"type": "dropdown", "options": dropdownOptions?js_string!}>
149 <#else> 149 <#else>
150 <#assign dynamicOptionNode = fieldSubNode["drop-down"]["dynamic-options"][0]!> 150 <#assign dropdownNode = fieldSubNode["drop-down"]!>
151 <#if dropdownNode?is_hash>
152 <#assign dynamicOptionNode = dropdownNode["dynamic-options"][0]!>
153 <#else>
154 <#assign dynamicOptionNode = dropdownNode[0]["dynamic-options"][0]!>
155 </#if>
151 <#if dynamicOptionNode?has_content> 156 <#if dynamicOptionNode?has_content>
157 <#-- Try to extract transition metadata for better autocomplete support -->
158 <#assign transitionMetadata = {}>
159 <#if dynamicOptionNode["@transition"]?has_content>
160 <#assign transitionNode = sri.getScreenDefinition().getTransitionItem(dynamicOptionNode["@transition"]!"")!>
161 <#if transitionNode?has_content>
162 <#-- Extract service name if present -->
163 <#assign serviceCallNode = transitionNode["service-call"][0]!>
164 <#if serviceCallNode?has_content && serviceCallNode["@name"]?has_content>
165 <#assign transitionMetadata = transitionMetadata + {"serviceName": (serviceCallNode["@name"]!"")}>
166 </#if>
167 <#-- Extract in-map parameter mapping -->
168 <#if serviceCallNode["@in-map"]?has_content>
169 <#assign transitionMetadata = transitionMetadata + {"inParameterMap": ((serviceCallNode["@in-map"]!"")?js_string)!""}>
170 <#elseif transitionNode["parameter"]?has_content>
171 <#assign paramNode = transitionNode["parameter"][0]!>
172 <#if paramNode?has_content>
173 <#assign transitionMetadata = transitionMetadata + {"inParameterMap": "[]"}>
174 </#if>
175 </#if>
176 </#if>
177 </#if>
178
179 <#-- Capture depends-on with parameter attribute -->
180 <#assign dependsOnList = []>
181 <#list dynamicOptionNode["depends-on"]! as depNode>
182 <#assign depField = depNode["@field"]!"">
183 <#assign depParameter = depNode["@parameter"]!depField>
184 <#assign dependsOnItem = depField + "|" + depParameter>
185 <#assign dependsOnList = dependsOnList + [dependsOnItem]>
186 </#list>
187 <#assign dependsOnJson = '[]'>
188 <#if dependsOnList?size gt 0>
189 <#assign dependsOnJson = '['>
190 <#list dependsOnList as dep>
191 <#if dep_index gt 0><#assign dependsOnJson = dependsOnJson + ', '></#if>
192 <#assign dependsOnJson = dependsOnJson + '"' + dep + '"'>
193 </#list>
194 <#assign dependsOnJson = dependsOnJson + ']'>
195 </#if>
196
197 <#-- Build dynamicOptions metadata -->
152 <#assign fieldMeta = fieldMeta + {"type": "dropdown", "dynamicOptions": { 198 <#assign fieldMeta = fieldMeta + {"type": "dropdown", "dynamicOptions": {
153 "transition": (dynamicOptionNode["@transition"]!""), 199 "transition": (dynamicOptionNode["@transition"]!""),
154 "serverSearch": (dynamicOptionNode["@server-search"]! == "true"), 200 "serverSearch": (dynamicOptionNode["@server-search"]! == "true"),
155 "minLength": (dynamicOptionNode["@min-length"]!"0"), 201 "minLength": (dynamicOptionNode["@min-length"]!"0"),
156 "parameterMap": (dynamicOptionNode["@parameter-map"]!"")?js_string!"" 202 "parameterMap": ((dynamicOptionNode["@parameter-map"]!"")?js_string)!"",
157 }}> 203 "dependsOn": dependsOnJson
204 } + transitionMetadata}>
158 <#else> 205 <#else>
159 <#assign fieldMeta = fieldMeta + {"type": "dropdown"}> 206 <#assign fieldMeta = fieldMeta + {"type": "dropdown"}>
160 </#if> 207 </#if>
......
...@@ -194,7 +194,8 @@ ...@@ -194,7 +194,8 @@
194 194
195 // Handle internal discovery/utility tools 195 // Handle internal discovery/utility tools
196 def internalToolMappings = [ 196 def internalToolMappings = [
197 "moqui_search_screens": "McpServices.mcp#SearchScreens" 197 "moqui_search_screens": "McpServices.mcp#SearchScreens",
198 "moqui_get_screen_details": "McpServices.mcp#GetScreenDetails"
198 ] 199 ]
199 200
200 def targetServiceName = internalToolMappings[name] 201 def targetServiceName = internalToolMappings[name]
...@@ -1929,6 +1930,20 @@ def wikiInstructions = getWikiInstructions(inputScreenPath) ...@@ -1929,6 +1930,20 @@ def wikiInstructions = getWikiInstructions(inputScreenPath)
1929 ] 1930 ]
1930 ], 1931 ],
1931 [ 1932 [
1933 name: "moqui_get_screen_details",
1934 title: "Get Screen Details",
1935 description: "Get screen field details including dropdown options. Use this to understand available fields and their options before submitting forms.",
1936 inputSchema: [
1937 type: "object",
1938 properties: [
1939 "path": [type: "string", description: "Screen path to analyze (e.g., 'PopCommerce/PopCommerceAdmin/Party/FindParty')"],
1940 "fieldName": [type: "string", description: "Optional specific field name. If not provided, returns all fields."],
1941 "parameters": [type: "object", description: "Optional parameters to set in context before rendering (for autocomplete contexts)."]
1942 ],
1943 required: ["path"]
1944 ]
1945 ],
1946 [
1932 name: "prompts_list", 1947 name: "prompts_list",
1933 title: "List Prompts", 1948 title: "List Prompts",
1934 description: "List available MCP prompt templates.", 1949 description: "List available MCP prompt templates.",
...@@ -1957,6 +1972,36 @@ def wikiInstructions = getWikiInstructions(inputScreenPath) ...@@ -1957,6 +1972,36 @@ def wikiInstructions = getWikiInstructions(inputScreenPath)
1957 </actions> 1972 </actions>
1958 </service> 1973 </service>
1959 1974
1975 <service verb="mcp" noun="GetScreenDetails" authenticate="true" allow-remote="true" transaction-timeout="60">
1976 <description>Get screen field details including dropdown options. Use this to understand available fields and their options before submitting forms.</description>
1977 <in-parameters>
1978 <parameter name="path" required="true"><description>Screen path to analyze (e.g., '/PopCommerce/PopCommerceAdmin/Party/FindParty').</description></parameter>
1979 <parameter name="fieldName"><description>Optional specific field name. If not provided, returns all fields.</description></parameter>
1980 <parameter name="parameters" type="Map"><description>Optional parameters to set in context before rendering (for autocomplete contexts).</description></parameter>
1981 </in-parameters>
1982 <out-parameters>
1983 <parameter name="result" type="Map"/>
1984 </out-parameters>
1985 <actions>
1986 <script><![CDATA[
1987 import org.moqui.context.ExecutionContext
1988 import groovy.json.JsonBuilder
1989 import org.moqui.mcp.McpFieldOptionsService
1990
1991 ExecutionContext ec = context.ec
1992
1993 def serviceResult = McpFieldOptionsService.service(path, fieldName, parameters, ec)
1994
1995 // Return in standard MCP format with content array
1996 def resultJson = new JsonBuilder(serviceResult).toString()
1997 result = [
1998 content: [[type: "text", text: resultJson]],
1999 isError: false
2000 ]
2001 ]]></script>
2002 </actions>
2003 </service>
2004
1960 <!-- NOTE: handle#McpRequest service removed - functionality moved to screen/webapp.xml for unified handling --> 2005 <!-- NOTE: handle#McpRequest service removed - functionality moved to screen/webapp.xml for unified handling -->
1961 2006
1962 </services> 2007 </services>
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -52,13 +52,13 @@ class UiNarrativeBuilder { ...@@ -52,13 +52,13 @@ class UiNarrativeBuilder {
52 narrative.screen = describeScreen(screenDef, semanticState, isTerse) 52 narrative.screen = describeScreen(screenDef, semanticState, isTerse)
53 narrative.actions = describeActions(screenDef, semanticState, currentPath, isTerse) 53 narrative.actions = describeActions(screenDef, semanticState, currentPath, isTerse)
54 narrative.navigation = describeLinks(semanticState, currentPath, isTerse) 54 narrative.navigation = describeLinks(semanticState, currentPath, isTerse)
55 narrative.notes = describeNotes(semanticState, isTerse) 55 narrative.notes = describeNotes(semanticState, currentPath, isTerse)
56 56
57 return narrative 57 return narrative
58 } 58 }
59 59
60 String describeScreen(ScreenDefinition screenDef, Map<String, Object> semanticState, boolean isTerse) { 60 String describeScreen(ScreenDefinition screenDef, Map<String, Object> semanticState, boolean isTerse) {
61 def screenName = screenDef?.name ?: "Screen" 61 def screenName = screenDef?.getScreenName() ?: "Screen"
62 def sb = new StringBuilder() 62 def sb = new StringBuilder()
63 63
64 sb.append("${screenName} displays ") 64 sb.append("${screenName} displays ")
...@@ -201,7 +201,7 @@ class UiNarrativeBuilder { ...@@ -201,7 +201,7 @@ class UiNarrativeBuilder {
201 return navigation 201 return navigation
202 } 202 }
203 203
204 List<String> describeNotes(Map<String, Object> semanticState, boolean isTerse) { 204 List<String> describeNotes(Map<String, Object> semanticState, String currentPath, boolean isTerse) {
205 def notes = [] 205 def notes = []
206 206
207 def data = semanticState?.data 207 def data = semanticState?.data
...@@ -220,6 +220,29 @@ class UiNarrativeBuilder { ...@@ -220,6 +220,29 @@ class UiNarrativeBuilder {
220 notes << "This screen has ${actions.size()} actions. Use semanticState.actions for complete list." 220 notes << "This screen has ${actions.size()} actions. Use semanticState.actions for complete list."
221 } 221 }
222 222
223 // Add note about moqui_get_screen_details for dropdown options
224 def formData = semanticState?.data
225 if (formData && formData.containsKey('formMetadata') && formData.formMetadata instanceof Map) {
226 def formMetadata = formData.formMetadata
227 def allFields = []
228 formMetadata.each { formName, formInfo ->
229 if (formInfo instanceof Map && formInfo.containsKey('fields')) {
230 def fields = formInfo.fields
231 if (fields instanceof Collection) {
232 def dynamicFields = fields.findAll { f -> f instanceof Map && f.containsKey('dynamicOptions') }
233 if (dynamicFields) {
234 def fieldNames = dynamicFields.collect { it.name }.take(3)
235 allFields.addAll(fieldNames)
236 }
237 }
238 }
239 }
240 if (allFields) {
241 def uniqueFields = allFields.unique().take(5)
242 notes << "Fields with autocomplete: ${uniqueFields.join(', ')}. Use moqui_get_screen_details(path='${currentPath}', fieldName='${uniqueFields[0]}') to get field-specific options."
243 }
244 }
245
223 def parameters = semanticState?.parameters 246 def parameters = semanticState?.parameters
224 if (parameters && parameters.size() > 0) { 247 if (parameters && parameters.size() > 0) {
225 def requiredParams = parameters.findAll { k, v -> k.toString().toLowerCase().contains('id') } 248 def requiredParams = parameters.findAll { k, v -> k.toString().toLowerCase().contains('id') }
......