""" React Mode Prompt Generation Handles prompt templates for react mode action handling. """ from typing import Any, List from modules.datamodels.datamodelChat import PromptBundle, PromptPlaceholder from modules.workflows.processing.shared.placeholderFactory import ( extractUserPrompt, extractUserLanguage, extractAvailableMethods, extractAvailableDocumentsSummary, extractAvailableDocumentsIndex, extractAvailableConnectionsIndex, extractPreviousActionResults, extractLearningsAndImprovements, extractLatestRefinementFeedback, extractWorkflowHistory, ) from modules.workflows.processing.shared.methodDiscovery import methods, getActionParameterList def generateReactPlanSelectionPrompt(services, context: Any) -> PromptBundle: """Define placeholders first, then the template; return PromptBundle.""" placeholders: List[PromptPlaceholder] = [ PromptPlaceholder(label="USER_PROMPT", content=extractUserPrompt(context), summaryAllowed=False), PromptPlaceholder(label="AVAILABLE_DOCUMENTS_SUMMARY", content=extractAvailableDocumentsSummary(services, context), summaryAllowed=True), PromptPlaceholder(label="AVAILABLE_METHODS", content=extractAvailableMethods(services), summaryAllowed=False), ] template = """Select one action to advance the task. OBJECTIVE: {{KEY:USER_PROMPT}} AVAILABLE_DOCUMENTS_SUMMARY: {{KEY:AVAILABLE_DOCUMENTS_SUMMARY}} AVAILABLE_METHODS: {{KEY:AVAILABLE_METHODS}} REPLY: Return only a JSON object with the selected action: {{ "action": "method.action_name" }} RULES: 1. Use EXACT action names from AVAILABLE_METHODS 2. Return ONLY JSON - no other text 3. Do NOT use markdown code blocks 4. Do NOT add explanations """ return PromptBundle(prompt=template, placeholders=placeholders) def generateReactParametersPrompt(services, context: Any, compoundActionName: str) -> PromptBundle: """Define placeholders first, then the template; return PromptBundle.""" # derive method/action and parameter list methodName, actionName = (compoundActionName.split('.', 1) if '.' in compoundActionName else (compoundActionName, '')) actionParameterList = getActionParameterList(methodName, actionName, methods) # determine action objective if available, else fall back to user prompt actionObjective = None if hasattr(context, 'action_objective') and context.action_objective: actionObjective = context.action_objective elif hasattr(context, 'task_step') and context.task_step and getattr(context.task_step, 'objective', None): actionObjective = context.task_step.objective else: actionObjective = extractUserPrompt(context) placeholders: List[PromptPlaceholder] = [ PromptPlaceholder(label="ACTION_OBJECTIVE", content=actionObjective, summaryAllowed=False), PromptPlaceholder(label="ACTION_PARAMETER_LIST", content=actionParameterList, summaryAllowed=False), PromptPlaceholder(label="AVAILABLE_DOCUMENTS_INDEX", content=extractAvailableDocumentsIndex(services, context), summaryAllowed=True), PromptPlaceholder(label="AVAILABLE_CONNECTIONS_INDEX", content=extractAvailableConnectionsIndex(services), summaryAllowed=False), PromptPlaceholder(label="USER_PROMPT", content=extractUserPrompt(context), summaryAllowed=False), PromptPlaceholder(label="USER_LANGUAGE", content=extractUserLanguage(services), summaryAllowed=False), PromptPlaceholder(label="PREVIOUS_ACTION_RESULTS", content=extractPreviousActionResults(context), summaryAllowed=True), PromptPlaceholder(label="LEARNINGS_AND_IMPROVEMENTS", content=extractLearningsAndImprovements(context), summaryAllowed=True), PromptPlaceholder(label="LATEST_REFINEMENT_FEEDBACK", content=extractLatestRefinementFeedback(context), summaryAllowed=True), PromptPlaceholder(label="WORKFLOW_HISTORY", content=extractWorkflowHistory(services, context), summaryAllowed=True), PromptPlaceholder(label="SELECTED_ACTION", content=compoundActionName, summaryAllowed=False), ] template = """Generate parameters for this action. ## Return ONLY a JSON RESPONSEOBJECT without comments. ACTION_OBJECTIVE (the objective for this action to fulfill): {{KEY:ACTION_OBJECTIVE}} SELECTED_ACTION: {{KEY:SELECTED_ACTION}} JSON RESPONSEOBJECT: {{ "schema": "parameters_v1", "parameters": {{ "paramName": "value" }} }} EXAMPLE of the result format to deliver: {{ "schema": "parameters_v1", "parameters": {{ "aiPrompt": "...", "resultType": "docx", "processingMode": "detailed" }} }} ## RULES: 1. Use ONLY parameter names from ACTION_PARAMETER_LIST 2. For connectionReference, use an EXACT label from AVAILABLE_CONNECTIONS_INDEX (do NOT invent labels) 3. Use exact document references from AVAILABLE_DOCUMENTS_INDEX for documentList parameters (do NOT invent names like "doc1"): pick specific docItem references; to include all from a list, use its docList reference 4. Learn from PREVIOUS_ACTION_RESULTS and LEARNINGS_AND_IMPROVEMENTS to avoid repeating mistakes 5. Consider LATEST_REFINEMENT_FEEDBACK when generating parameters 6. Use the ACTION_OBJECTIVE to understand the specific goal for this action 7. Generate parameters that align with the USER_LANGUAGE when applicable ## ACTION_PARAMETER_LIST: {{KEY:ACTION_PARAMETER_LIST}} ## AVAILABLE_DOCUMENTS_INDEX: (Use these references in parameter "documentList" if given; to include all docs from a list, pass its docList reference) {{KEY:AVAILABLE_DOCUMENTS_INDEX}} ## AVAILABLE_CONNECTIONS_INDEX: {{KEY:AVAILABLE_CONNECTIONS_INDEX}} (Use an EXACT label here for parameter "connectionReference") ## Example how to assign references from AVAILABLE_DOCUMENTS_INDEX and AVAILABLE_CONNECTIONS_INDEX: {{ "schema": "parameters_v1", "parameters": {{ "documentList": ["docList:msg_47a7a578-e8f2-4ba8-ac66-0dbff40605e0:round8_task1_action1_results", "docItem:5d8b7aee-b546-4487-b6a8-835c86f7b186:AI_Generated_Document_20251006-104256.docx"], "connectionReference": "conn_msft_1ae8b8e5-128b-49b8-b1cb-7c632669eeae", "aiPrompt": "...", "resultType": "xlsx", "processingMode": "basic" }} }} ## CONTEXT USER_REQUEST (final user prompt to deliver): {{KEY:USER_PROMPT}} USER_LANGUAGE: {{KEY:USER_LANGUAGE}} PREVIOUS_ACTION_RESULTS: {{KEY:PREVIOUS_ACTION_RESULTS}} LEARNINGS_AND_IMPROVEMENTS: {{KEY:LEARNINGS_AND_IMPROVEMENTS}} LATEST_REFINEMENT_FEEDBACK: {{KEY:LATEST_REFINEMENT_FEEDBACK}} WORKFLOW_HISTORY: {{KEY:WORKFLOW_HISTORY}} """ return PromptBundle(prompt=template, placeholders=placeholders) def generateReactRefinementPrompt(services, context: Any, reviewContent: str) -> PromptBundle: """Define placeholders first, then the template; return PromptBundle.""" placeholders: List[PromptPlaceholder] = [ PromptPlaceholder(label="USER_PROMPT", content=extractUserPrompt(context), summaryAllowed=False), PromptPlaceholder(label="REVIEW_CONTENT", content=reviewContent, summaryAllowed=True), ] template = """Decide the next step based on the observation. OBJECTIVE: {{KEY:USER_PROMPT}} OBSERVATION: {{KEY:REVIEW_CONTENT}} REPLY: Return only a JSON object with your decision: {{ "decision": "continue|stop", "reason": "brief explanation" }} RULES: 1. Use "continue" if objective NOT fulfilled 2. Use "stop" if objective fulfilled 3. Return ONLY JSON - no other text 4. Do NOT use markdown code blocks 5. Do NOT add explanations """ return PromptBundle(prompt=template, placeholders=placeholders)