gateway/modules/workflows/processing/shared/promptGenerationActionsReact.py
2025-10-06 15:39:25 +02:00

203 lines
7.6 KiB
Python

"""
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)