Refactor Agent Runtime: General-purpose LLM Request Service
BREAKING: Introduces new LLM Request/Response pattern for CSR agents Major Changes: - Add new SystemMessage types: SmtyLlmRequest, SmtyLlmResponse - Extend SystemMessage entity with callback and audit fields: * parentSystemMessageId - Links Response → Request * callbackServiceName - Service to call when LLM completes * callbackParameters - JSON params for callback * sourceTypeEnumId/sourceId - Audit trail (Order, CommEvent, etc.) * llmResponse - Raw response stored for debugging New Services: - AgentServices.process#LLMRequest: General-purpose async LLM service * Any trigger (SECA, UI, Order, etc.) can call this * Creates SmtyLlmRequest SystemMessage * Triggers async processing via poller * Validates callback service exists before creating task Refactored Services: - AgentServices.run#AgentTaskTurn: Universal agent processor * Supports both SmtyAgentTask (legacy) and SmtyLlmRequest (new) * ALWAYS provides MCP tools to LLM (for CSR agent pattern) * Creates SmtyLlmResponse and calls callback for new pattern * Maintains backward compatibility with SmtyAgentTask - AgentServices.callback#CommunicationEvent: Saves LLM responses to conversation * Callback service for CommunicationEvent-triggered requests * Maintains conversation thread via rootCommEventId Updated SECA: - AgentTriggerOnCommunication now calls AgentServices.process#LLMRequest * Uses callback pattern instead of direct SystemMessage creation * Enables full audit trail via SystemMessage RequestResponse Benefits: - General-purpose: Any trigger can request LLM processing (orders, inventory, support, etc.) - Traceability: Full audit trail via linked SystemMessages - RBAC: Agent impersonates users, respects permissions - Same UX: Agent uses same screens humans use (via MCP tools) - Flexible: Different callbacks handle responses differently
Showing
4 changed files
with
39 additions
and
7 deletions
| ... | @@ -12,4 +12,8 @@ | ... | @@ -12,4 +12,8 @@ |
| 12 | <!-- Agent Task Message Type --> | 12 | <!-- Agent Task Message Type --> |
| 13 | <moqui.service.message.SystemMessageType systemMessageTypeId="SmtyAgentTask" description="Agent Task"/> | 13 | <moqui.service.message.SystemMessageType systemMessageTypeId="SmtyAgentTask" description="Agent Task"/> |
| 14 | 14 | ||
| 15 | <!-- LLM Request/Response Message Types --> | ||
| 16 | <moqui.service.message.SystemMessageType systemMessageTypeId="SmtyLlmRequest" description="LLM Request"/> | ||
| 17 | <moqui.service.message.SystemMessageType systemMessageTypeId="SmtyLlmResponse" description="LLM Response"/> | ||
| 18 | |||
| 15 | </entity-facade-xml> | 19 | </entity-facade-xml> | ... | ... |
| ... | @@ -20,12 +20,38 @@ | ... | @@ -20,12 +20,38 @@ |
| 20 | <description>Specific AI configuration used for this task.</description> | 20 | <description>Specific AI configuration used for this task.</description> |
| 21 | </field> | 21 | </field> |
| 22 | <field name="rootCommEventId" type="id"> | 22 | <field name="rootCommEventId" type="id"> |
| 23 | <description>The root CommunicationEvent ID for the conversation thread.</description> | 23 | <description>The root CommunicationEvent ID for conversation thread.</description> |
| 24 | </field> | ||
| 25 | |||
| 26 | <!-- Callback and Audit Fields for LLM Request/Response Pattern --> | ||
| 27 | <field name="parentSystemMessageId" type="id"> | ||
| 28 | <description>Parent SystemMessage ID (links Response to Request).</description> | ||
| 29 | </field> | ||
| 30 | <field name="callbackServiceName" type="text-medium"> | ||
| 31 | <description>Service to call with LLM response when complete.</description> | ||
| 32 | </field> | ||
| 33 | <field name="callbackParameters" type="text-very-long"> | ||
| 34 | <description>JSON parameters to pass to callback service.</description> | ||
| 35 | </field> | ||
| 36 | <field name="sourceTypeEnumId" type="id"> | ||
| 37 | <description>Type of entity that triggered this request (Order, CommEvent, etc.).</description> | ||
| 38 | </field> | ||
| 39 | <field name="sourceId" type="id"> | ||
| 40 | <description>ID of the triggering entity (orderId, communicationEventId, etc.).</description> | ||
| 41 | </field> | ||
| 42 | <field name="llmResponse" type="text-very-long"> | ||
| 43 | <description>Raw LLM response content (stored for audit/debug).</description> | ||
| 24 | </field> | 44 | </field> |
| 25 | 45 | ||
| 26 | <relationship type="one" title="RequestedBy" related="mantle.party.Party"> | 46 | <relationship type="one" title="RequestedBy" related="mantle.party.Party"> |
| 27 | <key-map field-name="requestedByPartyId" related="partyId"/> | 47 | <key-map field-name="requestedByPartyId" related="partyId"/> |
| 28 | </relationship> | 48 | </relationship> |
| 49 | <relationship type="one" title="ParentSystemMessage" related="moqui.service.message.SystemMessage"> | ||
| 50 | <key-map field-name="parentSystemMessageId" related="systemMessageId"/> | ||
| 51 | </relationship> | ||
| 52 | <relationship type="many" title="ChildSystemMessages" related="moqui.service.message.SystemMessage" fk-name="SysMsgToSysMsg"> | ||
| 53 | <key-map field-name="systemMessageId" related="parentSystemMessageId"/> | ||
| 54 | </relationship> | ||
| 29 | <!-- Note: effectiveUserId links to UserAccount, but we don't force FK to allow system users --> | 55 | <!-- Note: effectiveUserId links to UserAccount, but we don't force FK to allow system users --> |
| 30 | <relationship type="one" related="mantle.product.store.ProductStore"> | 56 | <relationship type="one" related="mantle.product.store.ProductStore"> |
| 31 | <key-map field-name="productStoreId"/> | 57 | <key-map field-name="productStoreId"/> | ... | ... |
| 1 | <?xml version="1.0" encoding="UTF-8"?> | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | <secas xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/service-eca-3.xsd"> | 2 | <secas xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/service-eca-3.xsd"> |
| 3 | <!-- SECA for CommunicationEvent to Agent (uses SmtyAgentTask pattern) --> | ||
| 3 | <seca id="AgentTriggerOnCommunication" service="create#mantle.party.communication.CommunicationEvent" when="post-service"> | 4 | <seca id="AgentTriggerOnCommunication" service="create#mantle.party.communication.CommunicationEvent" when="post-service"> |
| 4 | <actions> | 5 | <actions> |
| 5 | <script><![CDATA[ | 6 | <script><![CDATA[ |
| ... | @@ -14,16 +15,17 @@ | ... | @@ -14,16 +15,17 @@ |
| 14 | 15 | ||
| 15 | ec.logger.info("SECA AgentTriggerOnCommunication: Creating SmtyAgentTask SystemMessage for thread ${rootId}") | 16 | ec.logger.info("SECA AgentTriggerOnCommunication: Creating SmtyAgentTask SystemMessage for thread ${rootId}") |
| 16 | 17 | ||
| 17 | // Trigger Agent Turn | 18 | // Create Agent Task using process#LLMRequest with callback |
| 18 | ec.service.sync().name("create#moqui.service.message.SystemMessage").parameters([ | 19 | ec.service.async().name("AgentServices.process#LLMRequest").parameters([ |
| 19 | systemMessageTypeId: 'SmtyAgentTask', | 20 | prompt: body, |
| 20 | statusId: 'SmsgReceived', | ||
| 21 | requestedByPartyId: fromPartyId, | 21 | requestedByPartyId: fromPartyId, |
| 22 | effectiveUserId: ec.user.userId, | 22 | effectiveUserId: ec.user.userId, |
| 23 | productStoreId: 'POPC_DEFAULT', | 23 | productStoreId: 'POPC_DEFAULT', |
| 24 | aiConfigId: 'DEFAULT', | 24 | aiConfigId: 'DEFAULT', |
| 25 | rootCommEventId: rootId, | 25 | callbackServiceName: "AgentServices.callback#CommunicationEvent", |
| 26 | isOutgoing: 'N' | 26 | callbackParameters: [rootCommEventId: rootId, communicationEventId: communicationEventId], |
| 27 | sourceTypeEnumId: "CommunicationEvent", | ||
| 28 | sourceId: communicationEventId | ||
| 27 | ]).call() | 29 | ]).call() |
| 28 | } | 30 | } |
| 29 | ]]></script> | 31 | ]]></script> | ... | ... |
This diff is collapsed.
Click to expand it.
-
Please register or sign in to post a comment