Documentation
¶
Overview ¶
Package askuser holds the daemon-side coordinator for the ask_user MCP tool. The agent (claude / codex / gemini) calls `ask_user` over MCP; the handler registers a pending question + broadcasts SSE; the user answers in the web UI; the answer resolves the pending channel, and the MCP tool returns to the agent.
Lifecycle parallels gate.ApprovalManager but the trigger is an MCP RPC instead of a unix socket dial — there is no subprocess hook, just a blocking goroutine inside the wick process.
Index ¶
Constants ¶
const DefaultTimeout = 5 * time.Minute
DefaultTimeout is how long Ask blocks before returning an error to the calling agent. Five minutes is long enough for "the user stepped away to grab coffee" but short enough that a forgotten session doesn't pin a goroutine forever. Configurable per Ask via Question.Timeout.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Answer ¶
Answer is what the user posts via /sessions/{id}/answer. One of Value / Text is set; if both are present, Value wins (it's the label of a clicked option, more authoritative than free-typed text on the same form).
type AskRequest ¶
type AskRequest struct {
ID string `json:"id"`
SessionID string `json:"session_id"`
AgentName string `json:"agent_name,omitempty"`
Question string `json:"question"`
Options []Option `json:"options,omitempty"`
AllowFreeform bool `json:"allow_freeform,omitempty"`
}
AskRequest is the broadcast payload — Question + a server-minted id used by both UI (in POST /answer) and the manager's pending map (to route the answer back).
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager owns the per-process pending-asks map. Concurrent-safe; caller is expected to wire OnRequest/OnResolved into the SSE broadcaster so the UI sees state changes.
func (*Manager) Ask ¶
Ask registers a pending question, fires onRequest, and blocks until the user answers, the timeout fires, or done is closed.
Returns Answer + error. error is non-nil only on timeout / cancel — agent-side handlers convert that into a tool error so the LLM can decide to retry or give up.
func (*Manager) PendingFor ¶
func (m *Manager) PendingFor(sessionID string) []AskRequest
PendingFor returns a snapshot of in-flight asks for one session. Used by the UI for reconnect rehydrate.
type Option ¶
Option is one choice presented to the user. Label = what they see, Value = what gets returned to the agent.
type Options ¶
type Options struct {
DefaultTimeout time.Duration
OnRequest func(AskRequest)
OnResolved func(sessionID, requestID string)
}
Options wires callbacks. Both are optional; nil = no broadcast.
type Question ¶
type Question struct {
SessionID string `json:"session_id"`
AgentName string `json:"agent_name,omitempty"`
Question string `json:"question"`
Options []Option `json:"options,omitempty"`
AllowFreeform bool `json:"allow_freeform,omitempty"`
Timeout time.Duration `json:"-"`
}
Question is the input to Manager.Ask. Mirrors the MCP tool's input schema 1:1 so the handler can pass it through unchanged.