feat: add delta response parsing and action-type prompt dispatch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -284,6 +284,92 @@ def _strip_markdown_fences(text: str) -> str:
|
||||
return text
|
||||
|
||||
|
||||
def _parse_delta(response: str) -> dict | None:
|
||||
"""Extract [DELTA]...[/DELTA] JSON from AI response."""
|
||||
match = re.search(r'\[DELTA\](.*?)\[/DELTA\]', response, re.DOTALL)
|
||||
if not match:
|
||||
return None
|
||||
raw = _strip_markdown_fences(match.group(1).strip())
|
||||
try:
|
||||
return json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
return None
|
||||
|
||||
|
||||
def _find_node_by_id(tree: dict, node_id: str) -> dict | None:
|
||||
"""Find a node by ID in a tree structure (recursive)."""
|
||||
if tree.get("id") == node_id:
|
||||
return tree
|
||||
for child in tree.get("children", []):
|
||||
found = _find_node_by_id(child, node_id)
|
||||
if found:
|
||||
return found
|
||||
for step in tree.get("steps", []):
|
||||
if step.get("id") == node_id:
|
||||
return step
|
||||
return None
|
||||
|
||||
|
||||
def _build_action_prompt(
|
||||
action_type: str,
|
||||
focal_node_id: str | None,
|
||||
tree_structure: dict,
|
||||
flow_type: str,
|
||||
) -> str:
|
||||
"""Build action-specific system prompt supplement."""
|
||||
tree_json = json.dumps(tree_structure, indent=2)
|
||||
|
||||
focal_context = ""
|
||||
if focal_node_id:
|
||||
focal_node = _find_node_by_id(tree_structure, focal_node_id)
|
||||
if focal_node:
|
||||
focal_context = f"\n\nFOCAL NODE (the node being acted on):\n{json.dumps(focal_node, indent=2)}"
|
||||
|
||||
prompts = {
|
||||
"generate_branch": (
|
||||
f"Generate a complete branch of child nodes for the focal node. "
|
||||
f"Return the new nodes wrapped in [DELTA]...[/DELTA] markers as JSON with "
|
||||
f"action='add', target_node_id='{focal_node_id}', and nodes array."
|
||||
f"{focal_context}"
|
||||
),
|
||||
"modify_node": (
|
||||
f"Modify the focal node based on the user's instruction. "
|
||||
f"Return the updated node in [DELTA]...[/DELTA] markers with action='modify'."
|
||||
f"{focal_context}"
|
||||
),
|
||||
"add_steps": (
|
||||
f"Generate new procedural steps to insert after the focal step. "
|
||||
f"Return them in [DELTA]...[/DELTA] markers with action='add'."
|
||||
f"{focal_context}"
|
||||
),
|
||||
"quick_action": (
|
||||
f"Respond to the user's quick action request about the focal node. "
|
||||
f"If the action modifies the node, return changes in [DELTA]...[/DELTA] markers. "
|
||||
f"If it's informational (e.g. explain), just respond in text."
|
||||
f"{focal_context}"
|
||||
),
|
||||
"open_chat": (
|
||||
"Have a helpful conversation about the flow. If the user asks for changes, "
|
||||
"return them in [DELTA]...[/DELTA] markers. Otherwise respond in text."
|
||||
),
|
||||
"generate_full": (
|
||||
"Generate a complete flow structure based on the user's description."
|
||||
),
|
||||
"variable_inference": (
|
||||
"Analyze the procedural steps for implicit variables. Look for references to "
|
||||
"specific servers, clients, credentials, or other values that should be captured "
|
||||
"in an intake form. Return suggestions as JSON."
|
||||
),
|
||||
}
|
||||
|
||||
action_prompt = prompts.get(action_type, prompts["open_chat"])
|
||||
|
||||
return (
|
||||
f"CURRENT FLOW STRUCTURE ({flow_type}):\n{tree_json}\n\n"
|
||||
f"ACTION: {action_type}\n{action_prompt}"
|
||||
)
|
||||
|
||||
|
||||
def _parse_ai_response(raw_response: str) -> dict[str, Any]:
|
||||
"""Parse structured markers from AI response.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user