Make every question blocking and drop inbox priority
This commit is contained in:
+11
-28
@@ -25,7 +25,6 @@ type askArgs struct {
|
||||
Question string `json:"question"`
|
||||
WhyBlocked string `json:"why_blocked"`
|
||||
Attachments []api.Attachment `json:"attachments"`
|
||||
Blocking *bool `json:"blocking"`
|
||||
ThreadID string `json:"thread_id"`
|
||||
}
|
||||
|
||||
@@ -43,8 +42,7 @@ func (m *Manager) askTool(l *live) mcp.Tool {
|
||||
"its first line is a short name, and the lines indented beneath it say what it would concretely do, " +
|
||||
"its example, code, commands and trade-offs, so the human never has to match a paragraph above to an option below. " +
|
||||
"Text above the list covers only what all the choices share. " +
|
||||
"If blocking is true, end your turn after asking; " +
|
||||
"the answer arrives as your next message. If blocking is false, continue with work that doesn't depend on the answer. " +
|
||||
"End your turn after asking; the answer arrives as your next message. " +
|
||||
"One call is one decision, answered by picking from its own choices. When you have several decisions, such as a design with several choices, " +
|
||||
"never bundle them into one call that asks for approval of them all: call this once per decision, each with its own context and choices; they are answered together. " +
|
||||
"To answer a follow-up question from the human, call this again with the thread_id they gave you.",
|
||||
@@ -70,10 +68,9 @@ func (m *Manager) askTool(l *live) mcp.Tool {
|
||||
},
|
||||
"required": ["kind"]
|
||||
}},
|
||||
"blocking": {"type": "boolean"},
|
||||
"thread_id": {"type": "string"}
|
||||
},
|
||||
"required": ["context", "question", "why_blocked", "blocking"]
|
||||
"required": ["context", "question", "why_blocked"]
|
||||
}`),
|
||||
Handler: func(ctx context.Context, raw json.RawMessage) (string, error) {
|
||||
return m.ask(ctx, l, raw)
|
||||
@@ -99,11 +96,6 @@ func (m *Manager) ask(ctx context.Context, l *live, raw json.RawMessage) (string
|
||||
thread = id
|
||||
}
|
||||
|
||||
priority := api.Fyi
|
||||
if *args.Blocking {
|
||||
priority = api.Blocked
|
||||
}
|
||||
|
||||
attachments := args.Attachments
|
||||
if attachments == nil {
|
||||
attachments = []api.Attachment{}
|
||||
@@ -129,21 +121,17 @@ func (m *Manager) ask(ctx context.Context, l *live, raw json.RawMessage) (string
|
||||
"attachments": attachments,
|
||||
}
|
||||
|
||||
err = m.store.CreateInboxItem(ctx, m.newItem(l, id, thread, api.Question, priority, *args.Blocking, store.ToPayload(payload)))
|
||||
err = m.store.CreateInboxItem(ctx, m.newItem(l, id, thread, api.Question, store.ToPayload(payload)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
l.asked = true
|
||||
l.askedBlock = l.askedBlock || *args.Blocking
|
||||
m.mu.Unlock()
|
||||
|
||||
cancel := fmt.Sprintf("If the human answers it some other way, such as in a chat message, withdraw it with cancel_question and question_id %q.", id)
|
||||
if *args.Blocking {
|
||||
return fmt.Sprintf("Question filed in the human's inbox. question_id: %s. It is blocking: end your turn now. The answer will arrive as your next message. %s", id, cancel), nil
|
||||
}
|
||||
return fmt.Sprintf("Question filed in the human's inbox. question_id: %s. Continue with work that doesn't depend on it; the answer will arrive as a later message. %s", id, cancel), nil
|
||||
return fmt.Sprintf("Question filed in the human's inbox. question_id: %s. End your turn now. The answer will arrive as your next message. "+
|
||||
"If the human answers it some other way, such as in a chat message, withdraw it with cancel_question and question_id %q.", id, id), nil
|
||||
}
|
||||
|
||||
type cancelArgs struct {
|
||||
@@ -233,9 +221,6 @@ func (m *Manager) validateAsk(ctx context.Context, l *live, args askArgs) error
|
||||
if radios == len(choices) && len(choices) > 0 && recommendedRadios != 1 {
|
||||
problems = append(problems, "mark exactly one pick-one choice as recommended with `- (*) choice`")
|
||||
}
|
||||
if args.Blocking == nil {
|
||||
problems = append(problems, "blocking is required")
|
||||
}
|
||||
for i, a := range args.Attachments {
|
||||
if !slices.Contains(attachmentKinds, a.Kind) {
|
||||
problems = append(problems, fmt.Sprintf("attachments[%d].kind %q is not one of %v", i, a.Kind, attachmentKinds))
|
||||
@@ -262,7 +247,7 @@ func (m *Manager) validateAsk(ctx context.Context, l *live, args askArgs) error
|
||||
|
||||
func (m *Manager) fileError(l *live, msg string) {
|
||||
id := store.NewID()
|
||||
err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.SessionError, api.Blocked, true, map[string]any{"error": msg}))
|
||||
err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.SessionError, map[string]any{"error": msg}))
|
||||
if err != nil {
|
||||
slog.Error("file session error", "session", l.id, "err", err)
|
||||
}
|
||||
@@ -271,13 +256,13 @@ func (m *Manager) fileError(l *live, msg string) {
|
||||
func (m *Manager) fileRateLimited(l *live, info map[string]any, failure string) {
|
||||
id := store.NewID()
|
||||
payload := map[string]any{"vendor": string(l.vendor), "rate_limit": info, "error": failure}
|
||||
err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.RateLimited, api.Blocked, true, payload))
|
||||
err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.RateLimited, payload))
|
||||
if err != nil {
|
||||
slog.Error("file rate limit", "session", l.id, "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) newItem(l *live, id, thread string, kind api.InboxItemKind, priority api.InboxItemPriority, blocking bool, payload map[string]any) api.InboxItem {
|
||||
func (m *Manager) newItem(l *live, id, thread string, kind api.InboxItemKind, payload map[string]any) api.InboxItem {
|
||||
return api.InboxItem{
|
||||
Id: id,
|
||||
ProjectId: l.projectID,
|
||||
@@ -285,8 +270,6 @@ func (m *Manager) newItem(l *live, id, thread string, kind api.InboxItemKind, pr
|
||||
AgentSessionId: l.id,
|
||||
ThreadId: thread,
|
||||
Kind: kind,
|
||||
Priority: priority,
|
||||
Blocking: blocking,
|
||||
Payload: payload,
|
||||
State: api.Open,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
@@ -329,7 +312,7 @@ func (m *Manager) Deliver(ctx context.Context, sessionID string) error {
|
||||
return err
|
||||
}
|
||||
if waiting > 0 {
|
||||
slog.Info("deliver held: blocking question waiting", "session", sessionID, "waiting", waiting, "responses", ids)
|
||||
slog.Info("deliver held: question waiting", "session", sessionID, "waiting", waiting, "responses", ids)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -399,11 +382,11 @@ func (m *Manager) responsesMidTurn(ctx context.Context, l *live) string {
|
||||
|
||||
waiting, err := m.store.AwaitingHuman(ctx, l.id)
|
||||
if err != nil {
|
||||
slog.Error("count blocking questions", "session", l.id, "err", err)
|
||||
slog.Error("count waiting questions", "session", l.id, "err", err)
|
||||
return ""
|
||||
}
|
||||
if waiting > 0 {
|
||||
slog.Info("deliver held mid-turn: blocking question waiting", "session", l.id, "waiting", waiting, "responses", ids)
|
||||
slog.Info("deliver held mid-turn: question waiting", "session", l.id, "waiting", waiting, "responses", ids)
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user