Deliver inbox answers mid-turn through the PostToolUse hook

This commit is contained in:
Ian Gulliver
2026-10-15 10:20:23 -07:00
parent c934b00737
commit 03b70bd44e
10 changed files with 186 additions and 21 deletions
+69 -10
View File
@@ -304,11 +304,21 @@ func (m *Manager) Deliver(ctx context.Context, sessionID string) error {
m.deliverMu.Lock()
defer m.deliverMu.Unlock()
pending, err := m.store.Undelivered(ctx, sessionID)
if err != nil {
return err
}
if len(pending) == 0 {
return nil
}
ids := responseIDs(pending)
sess, err := m.store.GetSession(ctx, sessionID)
if err != nil {
return err
}
if sess.State != api.AgentSessionStateIdle {
slog.Info("deliver held: session not idle", "session", sessionID, "state", sess.State, "responses", ids)
return nil
}
@@ -317,14 +327,7 @@ func (m *Manager) Deliver(ctx context.Context, sessionID string) error {
return err
}
if waiting > 0 {
return nil
}
pending, err := m.store.Undelivered(ctx, sessionID)
if err != nil {
return err
}
if len(pending) == 0 {
slog.Info("deliver held: blocking question waiting", "session", sessionID, "waiting", waiting, "responses", ids)
return nil
}
@@ -333,19 +336,75 @@ func (m *Manager) Deliver(ctx context.Context, sessionID string) error {
return err
}
_, err = m.turn(ctx, sess, task, pending[0].Response.User, deliveryMessage(pending), nil)
after, err := m.turn(ctx, sess, task, pending[0].Response.User, deliveryMessage(pending), nil)
if errors.Is(err, ErrConflict) {
slog.Info("deliver held: session changed state", "session", sessionID, "err", err, "responses", ids)
return nil
}
if err != nil {
slog.Error("deliver failed", "session", sessionID, "err", err, "responses", ids)
return err
}
m.mu.Lock()
l := m.live[sessionID]
closing := m.closing
m.mu.Unlock()
pid := 0
exited := false
if l != nil {
pid = l.sess.Pid()
exited = l.sess.Exited()
}
slog.Info("deliver sent", "session", sessionID, "state", after.State, "pid", pid, "exited", exited, "closing", closing, "responses", ids)
return m.store.MarkDelivered(ctx, ids)
}
func (m *Manager) deliverMidTurn(ctx context.Context, l *live) string {
m.deliverMu.Lock()
defer m.deliverMu.Unlock()
pending, err := m.store.Undelivered(ctx, l.id)
if err != nil {
slog.Error("list undelivered responses", "session", l.id, "err", err)
return ""
}
if len(pending) == 0 {
return ""
}
ids := responseIDs(pending)
waiting, err := m.store.AwaitingHuman(ctx, l.id)
if err != nil {
slog.Error("count blocking 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)
return ""
}
err = m.store.MarkDelivered(ctx, ids)
if err != nil {
slog.Error("mark responses delivered", "session", l.id, "err", err, "responses", ids)
return ""
}
text := deliveryMessage(pending)
err = m.emit(ctx, l, pending[0].Response.User, "user.message", map[string]any{"text": text, "mid_turn": true})
if err != nil {
slog.Error("record mid-turn delivery", "session", l.id, "err", err)
}
slog.Info("deliver sent mid-turn", "session", l.id, "responses", ids)
return text
}
func responseIDs(pending []store.Pending) []string {
ids := []string{}
for _, p := range pending {
ids = append(ids, p.Response.Id)
}
return m.store.MarkDelivered(ctx, ids)
return ids
}
func deliveryMessage(pending []store.Pending) string {