Class: AssistantReplyJob
- Inherits:
-
ApplicationJob
- Object
- ActiveJob::Base
- ApplicationJob
- AssistantReplyJob
- Defined in:
- app/jobs/assistant_reply_job.rb
Overview
The shared planning assistant (cardinal.md §5): a CONTINUING claude session per card (assistant_session_id) — context and repo exploration carry across replies instead of being re-paid per message. Falls back to a fresh session (with the transcript embedded) if the stored session can't be resumed.
Constant Summary collapse
- FALLBACK_MODEL =
"claude-haiku-4-5-20251001".freeze
- MAX_TURNS =
20- ROLE_REMINDER =
"Reminder: you are the PLANNING assistant. You refine cards and write briefs — " \ "you never implement. No code files, no full implementations, no 'run these " \ "commands'. Your tools are READ-ONLY: you are physically incapable of modifying " \ "any file, so NEVER claim to have made, applied, or reverted a change — any such " \ "claim would be false. If the user approves an approach, finalize the " \ "Ready-for-execution brief and tell them to drag the card to a work column.".freeze
- KICKOFF_TURN =
<<~MSG.freeze This card just entered the Planning column. Open the discussion: greet me in one short sentence, then ask the 2-3 most important clarifying questions that would make THIS card execution-ready. Be specific to the card's actual content — never generic. If the card is already crystal clear, say so and propose a "Ready for execution" brief instead. MSG
Instance Method Summary collapse
-
#perform(card, kickoff: false) ⇒ Object
kickoff: true generates the opening message when a card enters planning.
Instance Method Details
#perform(card, kickoff: false) ⇒ Object
kickoff: true generates the opening message when a card enters planning.
26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'app/jobs/assistant_reply_job.rb', line 26 def perform(card, kickoff: false) unless ClaudeCli.available? card.log!("assistant_message", actor: "assistant", text: "I'm here to help shape this card. What's the goal, and how will we know it's done? (Install the claude CLI for a smarter assistant.)") return end reply, session_id = converse(card, kickoff:) card.update!(assistant_session_id: session_id) if session_id.present? card.log!("assistant_message", actor: "assistant", text: reply) if reply.present? rescue ClaudeCli::Error => e card.log!("error", text: "The planning assistant #{e.}.", detail: e.detail) end |