Daniel Tu Claude Opus 4.6 (1M context) commited on
Commit
afd1605
·
unverified ·
1 Parent(s): e61ffd6

feat: constrain agent questions to user-friendly abstraction level (#13)

Browse files

Agents and gap analyzer were asking overly technical questions like
"What are the precise X, Y, Z coordinates for the M4 mounting holes?"
— details only a CAD engineer would know. Users describe intent; agents
should derive the technical parameters.

- Add question abstraction rules to gap analyzer system prompt
- Apply CrewAI system_template on advisory agents (design, engineering,
cnc) via {{ .System }} / {{ .Prompt }} to preserve default behaviour
while injecting question-level guidance
- Improve part name extraction patterns in DesignState

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

agents/agent_flow.py CHANGED
@@ -28,6 +28,31 @@ logger = logging.getLogger(__name__)
28
  WIKI_DIR = Path(__file__).parent.parent / "docs" / "wiki"
29
 
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  # ── Data models ───────────────────────────────────────────────────────────────
32
 
33
 
@@ -400,6 +425,9 @@ class AgentDispatchFlow(Flow[AgentFlowState]):
400
 
401
  knowledge_sources = self._build_knowledge_sources() if agent_id in ("cnc", "cam") else []
402
 
 
 
 
403
  crew_agent = Agent(
404
  role=agent_def.role,
405
  goal=agent_def.goal,
@@ -407,8 +435,10 @@ class AgentDispatchFlow(Flow[AgentFlowState]):
407
  llm=llm,
408
  tools=tools,
409
  verbose=False,
410
- allow_delegation=settings.crew.collaboration and agent_id in ADVISOR_IDS,
411
  knowledge_sources=knowledge_sources if knowledge_sources else None,
 
 
412
  )
413
 
414
  memories = self._recall_for_agent(agent_id)
 
28
  WIKI_DIR = Path(__file__).parent.parent / "docs" / "wiki"
29
 
30
 
31
+ # ── CrewAI prompt templates ─────────────────────────────────────────────────
32
+ # Applied via CrewAI's system_template / prompt_template on advisory agents.
33
+ # {{ .System }} expands to the default system slices (role_playing + tools);
34
+ # {{ .Prompt }} expands to the task slice. This preserves all default CrewAI
35
+ # behaviour (tool-use format, etc.) while injecting question-level guidance.
36
+
37
+ _ADVISOR_SYSTEM_TEMPLATE = """\
38
+ {{ .System }}
39
+
40
+ ## Question Guidelines
41
+ When asking the user clarifying questions, follow these rules strictly:
42
+ - Ask questions a normal person can answer. The user describes INTENT; you derive the technical details.
43
+ - NEVER ask for exact coordinates, precise radii, specific tolerance values, or CAD-level parameters.
44
+ - Frame questions in everyday language and offer 2-4 plain-language suggestions.
45
+ - GOOD: "Where should the mounting holes go?" → "one in each corner", "evenly spaced along edges"
46
+ - BAD: "What are the precise X, Y, Z coordinates for the M4 mounting holes?"
47
+ - GOOD: "How thick should the walls be?" → "thin (1-2mm)", "standard (3-5mm)", "heavy-duty (6mm+)"
48
+ - BAD: "What is the minimum wall thickness in mm for the vertical ribs?"
49
+ - GOOD: "Should the edges be sharp or rounded?"
50
+ - BAD: "What fillet radius should be applied to the internal pocket edges?"
51
+ - You are the expert — infer technical parameters from the user's high-level answer."""
52
+
53
+ _ADVISOR_PROMPT_TEMPLATE = "{{ .Prompt }}"
54
+
55
+
56
  # ── Data models ───────────────────────────────────────────────────────────────
57
 
58
 
 
425
 
426
  knowledge_sources = self._build_knowledge_sources() if agent_id in ("cnc", "cam") else []
427
 
428
+ # Advisory agents get system_template with question-abstraction
429
+ # guidance via CrewAI's prompt customisation (see _ADVISOR_SYSTEM_TEMPLATE).
430
+ is_advisor = agent_id in ADVISOR_IDS
431
  crew_agent = Agent(
432
  role=agent_def.role,
433
  goal=agent_def.goal,
 
435
  llm=llm,
436
  tools=tools,
437
  verbose=False,
438
+ allow_delegation=settings.crew.collaboration and is_advisor,
439
  knowledge_sources=knowledge_sources if knowledge_sources else None,
440
+ system_template=_ADVISOR_SYSTEM_TEMPLATE if is_advisor else None,
441
+ prompt_template=_ADVISOR_PROMPT_TEMPLATE if is_advisor else None,
442
  )
443
 
444
  memories = self._recall_for_agent(agent_id)
agents/design_state.py CHANGED
@@ -240,7 +240,9 @@ class DesignState(BaseModel):
240
  # Extract part name from user message if not set
241
  if not state.part_name and user_message:
242
  name_patterns = [
243
- r'(?:need|want|design|make|create)\s+(?:a|an)\s+(.{5,40}?)\s*(?:with|for|that|,|$)',
 
 
244
  ]
245
  for pattern in name_patterns:
246
  match = re.search(pattern, user_message, re.IGNORECASE)
 
240
  # Extract part name from user message if not set
241
  if not state.part_name and user_message:
242
  name_patterns = [
243
+ r'(?:need|want|design|make|create|build|model)\s+(?:a|an|the)\s+(.{3,40}?)\s*(?:with|for|that|using|,|\.|$)',
244
+ r'(?:need|want|design|make|create|build|model)\s+(.{3,40}?)\s*(?:with|for|that|using|,|\.|$)',
245
+ r"(?:i'm|i am)\s+(?:building|making|designing)\s+(?:a|an|the)\s+(.{3,40}?)\s*(?:with|for|that|using|,|\.|$)",
246
  ]
247
  for pattern in name_patterns:
248
  match = re.search(pattern, user_message, re.IGNORECASE)
agents/gap_analyzer.py CHANGED
@@ -62,6 +62,8 @@ what information is still missing to produce a complete CNC-ready design.
62
  Rules:
63
  - Do NOT flag gaps for information already present in the design state.
64
  - Do NOT flag gaps for information the user just provided in their message.
 
 
65
  - Invent descriptive category names (e.g. "bolt_pattern", "thermal_rating",
66
  "load_capacity") — there is no fixed set.
67
  - Use snake_case for category names.
@@ -73,6 +75,25 @@ Rules:
73
  "design", "engineering", "cnc", "cad", or "cam".
74
  - If no gaps exist, return has_gaps: false with empty lists.
75
  - Set severity on each question card matching the gap it addresses.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  """
77
 
78
 
 
62
  Rules:
63
  - Do NOT flag gaps for information already present in the design state.
64
  - Do NOT flag gaps for information the user just provided in their message.
65
+ - Do NOT ask about the part name — the system derives it automatically.
66
+ - Do NOT repeat questions that were already asked in previous turns.
67
  - Invent descriptive category names (e.g. "bolt_pattern", "thermal_rating",
68
  "load_capacity") — there is no fixed set.
69
  - Use snake_case for category names.
 
75
  "design", "engineering", "cnc", "cad", or "cam".
76
  - If no gaps exist, return has_gaps: false with empty lists.
77
  - Set severity on each question card matching the gap it addresses.
78
+
79
+ Question abstraction level — CRITICAL:
80
+ - Ask questions a normal person can answer, NOT questions requiring CAD or
81
+ engineering expertise. The user describes INTENT; the agents derive the
82
+ technical implementation.
83
+ - NEVER ask for exact coordinates, precise radii, specific tolerance values,
84
+ G-code parameters, or CadQuery implementation details.
85
+ - GOOD: "Where should the mounting holes go?" with suggestions like
86
+ "one in each corner", "evenly spaced along the edges", "centered on top".
87
+ - BAD: "What are the precise X, Y, Z coordinates for the M4 mounting holes?"
88
+ - GOOD: "Should the edges be sharp or rounded?"
89
+ - BAD: "What fillet radius should be applied to the internal pocket edges?"
90
+ - GOOD: "How thick should the walls be?" with suggestions like "thin
91
+ (1-2mm)", "standard (3-5mm)", "heavy-duty (6mm+)".
92
+ - BAD: "What is the minimum wall thickness in mm for the vertical ribs?"
93
+ - Frame questions in everyday language. Offer 2-4 plain-language suggestions
94
+ that map to concrete engineering values behind the scenes.
95
+ - Technical details (coordinates, exact radii, tolerance classes, feed rates)
96
+ are the agents' job to determine from the user's high-level answers.
97
  """
98
 
99