feat(tui-go): workflow-propose choice panel
Render a workflow.proposed frame as a single-select picker with a manual-answer slot: ↑↓/jk to choose, enter to launch, e for custom, esc to peek away. Picking a candidate sends StartSession (and focuses the launched session); the custom slot continues the conversation via ChatInput. Reuses the modal helpers from the clarification view.
This commit is contained in:
@@ -13,6 +13,7 @@ const (
|
||||
StateInSession
|
||||
StateApproval
|
||||
StateClarification
|
||||
StateWorkflowPropose
|
||||
)
|
||||
|
||||
// InputMode toggles what a submitted line targets.
|
||||
@@ -125,6 +126,23 @@ type Clarification struct {
|
||||
Questions []ClarQuestion
|
||||
}
|
||||
|
||||
// ProposeCandidate is one workflow the router suggests (mirrors the wire DTO).
|
||||
type ProposeCandidate struct {
|
||||
WorkflowID string
|
||||
Reason string
|
||||
}
|
||||
|
||||
// Proposal is the router's triage suggestion of candidate workflows for a chat
|
||||
// request, rendered as a choice panel with a manual-answer slot. Picking a candidate
|
||||
// launches that workflow; the custom slot continues the conversation.
|
||||
type Proposal struct {
|
||||
ProposalID string
|
||||
SessionID string
|
||||
Prompt string
|
||||
OriginalRequest string
|
||||
Candidates []ProposeCandidate
|
||||
}
|
||||
|
||||
// Session is the UI's view of one server session.
|
||||
type Session struct {
|
||||
ID string
|
||||
@@ -141,6 +159,7 @@ type Session struct {
|
||||
Events []EventEntry
|
||||
Pending *Approval
|
||||
Clar *Clarification // open questions awaiting answers (clarification view)
|
||||
Propose *Proposal // router workflow suggestion awaiting a pick (propose view)
|
||||
Active bool // an inference/tool is in flight (drives the spinner)
|
||||
}
|
||||
|
||||
@@ -256,6 +275,12 @@ type Model struct {
|
||||
clarText []string // per-question free-text / custom answer
|
||||
clarTyping bool // typing into the custom buffer for the focused question
|
||||
clarDismissed bool // peeked away from the form (it can be reopened)
|
||||
|
||||
// workflow-propose view (the router's candidate-workflow picker)
|
||||
proposeCursor int // cursor over candidates (== len(candidates) → custom slot)
|
||||
proposeText string // free-text answer typed into the custom slot
|
||||
proposeTyping bool // typing into the custom buffer
|
||||
proposeDismissed bool // peeked away from the picker (it can be reopened)
|
||||
}
|
||||
|
||||
// NewModel builds the initial idle state.
|
||||
@@ -290,6 +315,10 @@ func (m Model) displayState() DisplayState {
|
||||
if s != nil && s.Clar != nil && !m.clarDismissed {
|
||||
return StateClarification
|
||||
}
|
||||
// A router workflow proposal is the operator's call to make before chatting on.
|
||||
if s != nil && s.Propose != nil && !m.proposeDismissed {
|
||||
return StateWorkflowPropose
|
||||
}
|
||||
if m.approvalDismissed {
|
||||
return StateInSession
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user