Class: Assistant::PlanToolBuilder
- Inherits:
-
Object
- Object
- Assistant::PlanToolBuilder
- Defined in:
- app/services/assistant/plan_tool_builder.rb
Overview
Builds RubyLLM::Tool subclasses for plan orchestration.
Provides declare_plan and mark_step_complete tools.
Usage (via ChatToolBuilder):
tools = Assistant::PlanToolBuilder.tools(conversation_id: conv.id)
Constant Summary collapse
- AUTOFORK_FIRST_TURN_PLAN_BLOCK_LENGTH =
When a conversation is auto-forked (because the parent ran out of context
or hit the tool budget), the new conversation inherits a parent summary
via Assistant::PromptComposer#parent_context_prompt. The model can then
mistake a short clarification ("yes, all 3" / "Lyn's email is just a
quick overview") for a planning request and synthesize a 5-step plan
from the parent summary alone.Regression: conversation 1525 — a 65-char user message triggered a
5-step "Finalize the three-part email series" plan that then ran for
45 minutes. Source: parent_conversation_summary from conversation 1233.Threshold tuned to allow intentional planning prompts ("please write all
3 webinar emails using the brand voice rules…") through while catching
short clarifications. ~200 chars ≈ 30-40 words, well below any genuine
multi-step task description. 200- ASSEMBLY_VERBS =
A composing verb, anywhere in the step.
Unanchored on purpose. It was \A, and "Analyze and synthesize all loaded
CRM data into the required sections" slipped past because the composing
verb was second — the step then ran, called nothing and was recorded
FAILED, which is the whole failure this drops. Chasing that with a longer
list of leading verbs is a losing game; requiring a composition verb
ANYWHERE, plus a document object, plus being the last step of a briefing
plan is what keeps it safe. Verified against every observed step: all 15
assembly descriptions match, none of the 5 data ones do. /\b(?:synthesi[sz]e|compile|assemble|compose|format|render|write|produce| generate|draft|deliver|summari[sz]e|present|construct|finali[sz]e)\b/xi- ASSEMBLY_OBJECTS =
What it composes. Required alongside the verb so "Write the note to the
case" — a real write — is never mistaken for prose assembly. /\b(?:briefing|summary|report|document|write-?up|markdown| sections?|deliverable|final\s+(?:answer|output|response))\b/xi
Class Method Summary collapse
Class Method Details
.tools(conversation_id:) ⇒ Object
45 46 47 48 49 50 |
# File 'app/services/assistant/plan_tool_builder.rb', line 45 def tools(conversation_id:) [ build_declare_plan_tool(conversation_id: conversation_id), build_mark_step_complete_tool(conversation_id: conversation_id) ] end |