From ddf769ab11a9311cc300605c5bb00e41fe7972ea Mon Sep 17 00:00:00 2001 From: Max Lund Date: Mon, 27 Apr 2026 20:33:02 -0500 Subject: [PATCH 1/3] Add human-in-the-loop Inbox + alerts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commander half of the HITL feature: an Inbox surface where operators see and answer questions agents have asked via the builtins.human.ask tool, plus toast + chime alerts for new questions that arrive while the operator isn't looking at the Inbox. API proxy (internal/api/humaninputs.go) - GET /instances/:id/human-inputs — list (proxies to squadron) - POST /instances/:id/human-inputs/:callId — submit a resolution - GET /instances/:id/human-inputs/stream — SSE stream of HumanInputRequested / HumanInputResolved events for live updates. Squadron is the source of truth; commander is a passthrough that decorates with the responder's session identity (auth-on) or empty string (local dev with no auth). Hub (internal/hub/connection.go) Per-connection fan-out of mission events that match the SSE stream's filter, routed to subscriber channels. Web UI Inbox page (InboxPage.tsx) - List mode: scannable rows with short-summary, mission/task, time-since. - Focus mode: oldest-first carousel that auto-advances after a submit so an operator can rip through a backlog. - Single-select questions render as quick-reply buttons; multi- select questions render as toggle buttons with a checkmark glyph and a separate Send (N) button that JSON-encodes the selected set on submit. - Free-text fallback ("Other…") always available. HumanInputCard component - Inline card used on mission detail and as the carousel cell. - Multi-select: toggle behavior + dedicated Send button. - Resolved view runs response through formatResolvedResponse so multi-select answers display as "A, C" rather than raw JSON. use-human-input-alerts hook - Subscribes to the SSE stream for the active instance. - Fires a toast and a chime on every new question (regardless of tab focus — the chime is the away-from-app signal). - Chime: preloaded sonar-ping.mp3, capped at 1s with a fade-out gain envelope. Web Audio is the primary path; an HTMLAudio fallback handles backgrounded tabs where AudioContext can be suspended in ways that resume() alone doesn't reliably recover. - Both audio paths are primed on the user's first page-interaction gesture (Safari/Chrome autoplay policy). - Skips toast + chime when the operator is already on the Inbox page since they're presumably handling things there. Sidebar + layout - Inbox entry in AppSidebar with an unanswered-count badge. - Layout mounts the alerts hook so it runs everywhere. Tests - HumanInputCard.test.ts: formatResolvedResponse — verbatim for single-select / free-text; expand JSON array to comma list for multi-select; fall back to raw on malformed JSON, non-array, or non-string array entries; render empty array as empty string. Dependencies squadron-wire is pinned at v0.0.40 with a TEMP local replace until https://github.com/mlund01/squadron-wire/pull/11 (HITL wire types) merges and a new tag is published. Drop the replace + bump the require version before merging this PR. --- .gitignore | 1 + go.mod | 14 +- go.sum | 54 +- internal/api/humaninputs.go | 214 +++++ internal/api/routes.go | 6 + internal/hub/connection.go | 55 ++ web/public/sonar-ping.mp3 | Bin 0 -> 113684 bytes web/src/App.tsx | 2 + web/src/api/client.ts | 40 + web/src/api/types.ts | 34 + web/src/components/AppLayout.tsx | 8 +- web/src/components/AppSidebar.tsx | 22 +- web/src/components/HumanInputCard.test.ts | 75 ++ web/src/components/HumanInputCard.tsx | 216 +++++ web/src/hooks/use-human-input-alerts.ts | 343 ++++++++ web/src/hooks/use-human-inputs.ts | 53 ++ web/src/lib/utils.ts | 16 + web/src/pages/InboxPage.tsx | 949 ++++++++++++++++++++++ web/src/pages/MissionInstanceDetail.tsx | 63 +- 19 files changed, 2135 insertions(+), 30 deletions(-) create mode 100644 internal/api/humaninputs.go create mode 100644 web/public/sonar-ping.mp3 create mode 100644 web/src/components/HumanInputCard.test.ts create mode 100644 web/src/components/HumanInputCard.tsx create mode 100644 web/src/hooks/use-human-input-alerts.ts create mode 100644 web/src/hooks/use-human-inputs.ts create mode 100644 web/src/pages/InboxPage.tsx diff --git a/.gitignore b/.gitignore index 6d5ed9f..226bf09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ commander .DS_Store vendor/ +.claude/ diff --git a/go.mod b/go.mod index 729a388..c5991dd 100644 --- a/go.mod +++ b/go.mod @@ -2,27 +2,31 @@ module commander go 1.25.4 +// TEMP: local replace for unpublished squadron-wire HITL messages. +// Revert + publish a new squadron-wire tag before merging. +replace github.com/mlund01/squadron-wire => ../squadron-wire + require ( + github.com/coreos/go-oidc/v3 v3.18.0 github.com/gorilla/websocket v1.5.3 github.com/mlund01/squadron-wire v0.0.40 + github.com/onsi/ginkgo/v2 v2.28.1 + github.com/onsi/gomega v1.39.1 + golang.org/x/crypto v0.50.0 + golang.org/x/oauth2 v0.36.0 ) require ( github.com/Masterminds/semver/v3 v3.4.0 // indirect - github.com/coreos/go-oidc/v3 v3.18.0 // indirect github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/onsi/ginkgo/v2 v2.28.1 // indirect - github.com/onsi/gomega v1.39.1 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.50.0 // indirect golang.org/x/mod v0.34.0 // indirect golang.org/x/net v0.52.0 // indirect - golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.43.0 // indirect golang.org/x/text v0.36.0 // indirect diff --git a/go.sum b/go.sum index 7535674..cac507f 100644 --- a/go.sum +++ b/go.sum @@ -2,12 +2,22 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1 github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/coreos/go-oidc/v3 v3.18.0 h1:V9orjXynvu5wiC9SemFTWnG4F45v403aIcjWo0d41+A= github.com/coreos/go-oidc/v3 v3.18.0/go.mod h1:DYCf24+ncYi+XkIH97GY1+dqoRlbaSI26KVTCI9SrY4= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= +github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= +github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= +github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= +github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= +github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc= @@ -16,40 +26,56 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/mlund01/squadron-wire v0.0.40 h1:umcnOIzRgNP4m7AThrLIAP6s4j1sC798FII4Tx6Ijec= -github.com/mlund01/squadron-wire v0.0.40/go.mod h1:BmgUAhEkibCiJ2Cre+qfLs/KjeqTmm4BkfcMu6M+jLU= +github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= +github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= +github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= +github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= +github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI= github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= -golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= -golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/api/humaninputs.go b/internal/api/humaninputs.go new file mode 100644 index 0000000..d2977dc --- /dev/null +++ b/internal/api/humaninputs.go @@ -0,0 +1,214 @@ +package api + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "strconv" + "time" + + "github.com/mlund01/squadron-wire/protocol" + + "commander/internal/auth" + "commander/internal/hub" +) + +// Human-in-the-loop (ask_human) endpoints. Commander is a pure proxy: +// squadron owns the records, the mission event stream carries live +// updates. These handlers translate REST requests into wire RPCs. + +func handleListHumanInputs(h *hub.Hub) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + instanceID := r.PathValue("id") + conn := h.GetConnection(instanceID) + if conn == nil { + writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "instance disconnected"}) + return + } + + q := r.URL.Query() + payload := protocol.GetHumanInputsPayload{ + State: q.Get("state"), + MissionID: q.Get("missionId"), + OldestFirst: q.Get("order") != "newest", + } + if v := q.Get("limit"); v != "" { + if n, err := strconv.Atoi(v); err == nil && n > 0 { + payload.Limit = n + } + } + if v := q.Get("offset"); v != "" { + if n, err := strconv.Atoi(v); err == nil && n >= 0 { + payload.Offset = n + } + } + + reqEnv, err := protocol.NewRequest(protocol.TypeGetHumanInputs, &payload) + if err != nil { + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) + return + } + resp, err := h.SendRequest(instanceID, reqEnv, proxyTimeout) + if err != nil { + writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": err.Error()}) + return + } + if resp.Type == protocol.TypeError { + var errPayload protocol.ErrorPayload + _ = protocol.DecodePayload(resp, &errPayload) + writeJSON(w, http.StatusBadGateway, map[string]string{"error": errPayload.Message}) + return + } + var result protocol.GetHumanInputsResultPayload + if err := protocol.DecodePayload(resp, &result); err != nil { + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) + return + } + writeJSON(w, http.StatusOK, map[string]any{ + "humanInputs": result.HumanInputs, + "total": result.Total, + }) + } +} + +func handleResolveHumanInput(h *hub.Hub) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + instanceID := r.PathValue("id") + toolCallID := r.PathValue("callId") + + conn := h.GetConnection(instanceID) + if conn == nil { + writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "instance disconnected"}) + return + } + + var body struct { + Response string `json:"response"` + } + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request body"}) + return + } + if body.Response == "" { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": "response is required"}) + return + } + + reqEnv, err := protocol.NewRequest(protocol.TypeResolveHumanInput, &protocol.ResolveHumanInputPayload{ + ToolCallID: toolCallID, + Response: body.Response, + ResponderUserID: responderIDFromRequest(r), + }) + if err != nil { + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) + return + } + resp, err := h.SendRequest(instanceID, reqEnv, proxyTimeout) + if err != nil { + writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": err.Error()}) + return + } + if resp.Type == protocol.TypeError { + var errPayload protocol.ErrorPayload + _ = protocol.DecodePayload(resp, &errPayload) + writeJSON(w, http.StatusBadGateway, map[string]string{"error": errPayload.Message}) + return + } + var result protocol.ResolveHumanInputResultPayload + if err := protocol.DecodePayload(resp, &result); err != nil { + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) + return + } + if !result.Accepted { + status := http.StatusBadGateway + if result.Reason == "not found" { + status = http.StatusNotFound + } + writeJSON(w, status, map[string]string{"error": result.Reason}) + return + } + writeJSON(w, http.StatusOK, map[string]any{"humanInput": result.HumanInput}) + } +} + +// handleStreamHumanInputs is an SSE endpoint that pushes every +// human_input_requested / human_input_resolved mission event for the +// given squadron to the browser as it happens. Browsers get instant +// alerts without polling, and the stream survives background-tab +// throttling the way EventSource connections do. +// +// Commander already subscribes globally to squadron events on register, +// so by the time the browser opens this stream, the hub is seeing every +// relevant event in real time; we just fan them out to the SSE client. +func handleStreamHumanInputs(h *hub.Hub) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + instanceID := r.PathValue("id") + conn := h.GetConnection(instanceID) + if conn == nil { + writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "instance disconnected"}) + return + } + + w.Header().Set("Content-Type", "text/event-stream") + w.Header().Set("Cache-Control", "no-cache") + w.Header().Set("Connection", "keep-alive") + w.Header().Set("X-Accel-Buffering", "no") // disable nginx buffering + w.Header().Set("Access-Control-Allow-Origin", "*") + + flusher, ok := w.(http.Flusher) + if !ok { + http.Error(w, "streaming not supported", http.StatusInternalServerError) + return + } + + // Send an opening comment so proxies don't buffer the first + // real event, and the client sees the connection is live. + fmt.Fprintf(w, ": open %d\n\n", time.Now().Unix()) + flusher.Flush() + + ch, cleanup := conn.SubscribeHumanInputEvents() + defer cleanup() + + // Keepalive pulses prevent intermediaries (and some browsers) + // from closing an idle stream after ~30s of silence. + pulse := time.NewTicker(20 * time.Second) + defer pulse.Stop() + + ctx := r.Context() + for { + select { + case <-ctx.Done(): + return + case <-pulse.C: + fmt.Fprintf(w, ": ping %d\n\n", time.Now().Unix()) + flusher.Flush() + case ev, ok := <-ch: + if !ok { + return + } + data, err := json.Marshal(ev) + if err != nil { + log.Printf("human-input SSE marshal: %v", err) + continue + } + fmt.Fprintf(w, "event: %s\ndata: %s\n\n", ev.EventType, data) + flusher.Flush() + } + } + } +} + +// responderIDFromRequest returns a stable identifier for the user who +// submitted the response. Falls back gracefully when auth is disabled so +// local dev still works. +func responderIDFromRequest(r *http.Request) string { + sess := auth.SessionFromContext(r.Context()) + if sess == nil { + return "" + } + if sess.Sub != "" { + return sess.Sub + } + return sess.Email +} diff --git a/internal/api/routes.go b/internal/api/routes.go index 9afe01c..68f362e 100644 --- a/internal/api/routes.go +++ b/internal/api/routes.go @@ -104,6 +104,12 @@ func RegisterRoutes(mux *http.ServeMux, h *hub.Hub, ka *keepalive.KeepAlive) { mux.HandleFunc("GET /api/instances/{id}/agents/{name}/chats", handleChatHistory(h)) mux.HandleFunc("GET /api/instances/{id}/chats/{sessionId}/messages", handleChatMessages(h)) mux.HandleFunc("DELETE /api/instances/{id}/chats/{sessionId}", handleArchiveChat(h)) + + // Human-in-the-loop (ask_human) endpoints — commander proxies to + // the squadron that owns the records. + mux.HandleFunc("GET /api/instances/{id}/human-inputs", handleListHumanInputs(h)) + mux.HandleFunc("GET /api/instances/{id}/human-inputs/stream", handleStreamHumanInputs(h)) + mux.HandleFunc("POST /api/instances/{id}/human-inputs/{callId}/resolve", handleResolveHumanInput(h)) } func handleListInstances(h *hub.Hub) http.HandlerFunc { diff --git a/internal/hub/connection.go b/internal/hub/connection.go index 0049670..0618896 100644 --- a/internal/hub/connection.go +++ b/internal/hub/connection.go @@ -37,6 +37,13 @@ type Connection struct { chatMu sync.Mutex chatSubs map[string][]chan *protocol.ChatEventPayload // sessionID → subscriber channels chatBuffer map[string][]*protocol.ChatEventPayload // buffered events before first subscriber + + // Instance-wide human-input event fan-out. Every mission event of + // type human_input_requested or human_input_resolved is pushed to + // all listeners on this slice. The SSE endpoint exposes this so the + // browser gets an instant notification — no polling, no throttling. + humanInputMu sync.Mutex + humanInputSubs []chan *protocol.MissionEventPayload } // NewConnection creates a new Connection wrapping a WebSocket. @@ -194,6 +201,15 @@ func (c *Connection) fanOutMissionEvent(env *protocol.Envelope) { return } + // Feed the instance-wide human-input stream whenever one of those + // events comes through. Unlike the per-mission path this one never + // buffers — if no one's listening the event is dropped; if someone + // is, everyone gets a copy immediately. + if payload.EventType == protocol.EventHumanInputRequested || + payload.EventType == protocol.EventHumanInputResolved { + c.fanOutHumanInputEvent(&payload) + } + c.eventMu.Lock() subs := c.eventSubs[payload.MissionID] if len(subs) == 0 { @@ -213,6 +229,45 @@ func (c *Connection) fanOutMissionEvent(env *protocol.Envelope) { } } +// SubscribeHumanInputEvents registers a channel that receives every +// human_input_requested / human_input_resolved mission event for this +// instance. Used by the SSE endpoint to push alerts to browsers with +// no polling involvement. Call the returned cancel func to unsubscribe. +func (c *Connection) SubscribeHumanInputEvents() (chan *protocol.MissionEventPayload, func()) { + ch := make(chan *protocol.MissionEventPayload, 32) + c.humanInputMu.Lock() + c.humanInputSubs = append(c.humanInputSubs, ch) + c.humanInputMu.Unlock() + + cleanup := func() { + c.humanInputMu.Lock() + defer c.humanInputMu.Unlock() + for i, sub := range c.humanInputSubs { + if sub == ch { + c.humanInputSubs = append(c.humanInputSubs[:i], c.humanInputSubs[i+1:]...) + break + } + } + close(ch) + } + return ch, cleanup +} + +func (c *Connection) fanOutHumanInputEvent(payload *protocol.MissionEventPayload) { + // Hold the lock for the whole fan-out so a concurrent unsubscribe + // can't close a channel mid-send. Channels are buffered + the send + // uses a default branch, so iteration stays bounded. + c.humanInputMu.Lock() + defer c.humanInputMu.Unlock() + for _, ch := range c.humanInputSubs { + select { + case ch <- payload: + default: + // Slow subscriber — drop rather than block the hub. + } + } +} + func (c *Connection) fanOutMissionComplete(env *protocol.Envelope) { var payload protocol.MissionCompletePayload if err := protocol.DecodePayload(env, &payload); err != nil { diff --git a/web/public/sonar-ping.mp3 b/web/public/sonar-ping.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..22bdec3bcca49d5f922df48084ddf4cb5edfd3d7 GIT binary patch literal 113684 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%0Dav)LMo``}(l?&zq>}IPnU#wS@ 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 $i3i9-IQVBd-pzW>E3tk-e~zm z4~wxGX~(LU9~f--1DB78H$lt^%XuSPEBd4qhc5_meX?V8#?djKF*Q>5y zP~)6QBbP?1rGHJ3g@gb>C2Dy{xPK`*~$*_CL*eKDpqzwQ|jE{92@4@HzY7sk)w;>wH&*o*#1N zTI#N!_wR4>&c1tK-1*Zne{8Ki@zvS549`1z8b(ZsI#^t2@^i3cQEpn2jXbC8%W+jT zmsnm-mALKP@M^t{-(O+oj!e#Z>0J5M9nU{n-kuFxaQW(pg8JH~@%h~R%b5qhbJ<#L zBZ11IL4 zSvKk8th0ljM*h01)l$!MqRznKJFQ23+7Le6ap+fqkNqb7Ug@K340aqE`FCJx!zAJT z!yf{UADq0j+$dnwk-c-88d~i8`LEi4Il@A@?QhRvi!b?otLuC@FDHA#U5Vkv0e7Y0 z!ck0d<(vf(_s?89S$eV2>!A2#-p{$Z{pY)e7HS&nn2x^Dzii~``IkdO`TfV$=Qq#s z_UR`{OYLXev`zCRXQ8#zsIklQllnaz*Ie!qy2o$$DsAflnU>Yd!f&r@KG3EgR8}O| znX&MO>yhfi=iHe4fwmh~-k5YQ@{3b8TO@*C8;az-L1E>OdAshdxjpXq)Bjul^M4E> z_rK#8?Kih)k%#{LMMHY8uglw|zw4_Zrf&?#wh!@MyUTjbVAC_hy7e_rY{;{9NNTkl ze|~R9{PP8kk4z5x&n*12%gs4CZ^HT5v_}J6+|TX`8U9YgMPq9RbLW?j9ZK6ZD_rIp zZ8&nRf#b7o<9^5K%NofpH#M=_Zulyz$6wd>>*utyUq8(O$F9pWmHE=u25Fu;c?}Kq zOC6)XU2rAbCS`}!){2tHLn8HlpVI%F<)bX?q_h*i6V_(^2?@|jvIT&OZ@Zq+Nm2caEYwbVBLsjoQF;f5l literal 0 HcmV?d00001 diff --git a/web/src/App.tsx b/web/src/App.tsx index 571531c..4647f9a 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -16,6 +16,7 @@ import { FileViewerPage } from './pages/FileViewerPage' import { VariablesPage } from './pages/VariablesPage' import { SkillsPage } from './pages/SkillsPage' import { SkillDetail } from './pages/SkillDetail' +import { InboxPage } from './pages/InboxPage' function App() { return ( @@ -39,6 +40,7 @@ function App() { } /> } /> } /> + } /> diff --git a/web/src/api/client.ts b/web/src/api/client.ts index ae0c494..cee0ef9 100644 --- a/web/src/api/client.ts +++ b/web/src/api/client.ts @@ -248,3 +248,43 @@ export async function getCostSummary(instanceId: string, from?: string, to?: str const qs = params.toString(); return fetchJSON(`/instances/${instanceId}/costs${qs ? '?' + qs : ''}`); } + +// Human-in-the-loop (ask_human) API — commander proxies to the squadron +// that owns the records. All endpoints are instance-scoped. + +export interface ListHumanInputsOptions { + state?: 'open' | 'resolved'; + missionId?: string; + order?: 'oldest' | 'newest'; + limit?: number; + offset?: number; +} + +export async function listHumanInputs( + instanceId: string, + opts: ListHumanInputsOptions = {}, +): Promise { + const params = new URLSearchParams(); + if (opts.state) params.set('state', opts.state); + if (opts.missionId) params.set('missionId', opts.missionId); + if (opts.order) params.set('order', opts.order); + if (opts.limit) params.set('limit', String(opts.limit)); + if (opts.offset) params.set('offset', String(opts.offset)); + const qs = params.toString(); + return fetchJSON(`/instances/${instanceId}/human-inputs${qs ? '?' + qs : ''}`); +} + +export async function resolveHumanInput( + instanceId: string, + toolCallId: string, + response: string, +): Promise { + return fetchJSON( + `/instances/${instanceId}/human-inputs/${toolCallId}/resolve`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ response }), + }, + ); +} diff --git a/web/src/api/types.ts b/web/src/api/types.ts index fe26efe..9fd728c 100644 --- a/web/src/api/types.ts +++ b/web/src/api/types.ts @@ -419,3 +419,37 @@ export interface WriteBrowseFileResponse { export interface ListSharedFoldersResponse { folders: SharedFolderInfo[]; } + +// Human-in-the-loop (ask_human) types + +export interface HumanInputRequestDTO { + id: string; + missionId?: string; + missionName?: string; + taskId?: string; + taskName?: string; + toolCallId: string; + question: string; + shortSummary?: string; + additionalContext?: string; + choices?: string[]; + // multiSelect=true means the human picks 1+ choices instead of one. + // The submitted response is then a JSON-encoded array of strings + // (e.g. `["A","C"]`); the agent / API contract is single string in + // both cases. + multiSelect?: boolean; + state: 'open' | 'resolved'; + requestedAt: string; + resolvedAt?: string; + response?: string; + responderUserId?: string; +} + +export interface ListHumanInputsResponse { + humanInputs: HumanInputRequestDTO[]; + total: number; +} + +export interface ResolveHumanInputResponse { + humanInput: HumanInputRequestDTO; +} diff --git a/web/src/components/AppLayout.tsx b/web/src/components/AppLayout.tsx index c3caa01..eadf7df 100644 --- a/web/src/components/AppLayout.tsx +++ b/web/src/components/AppLayout.tsx @@ -1,9 +1,15 @@ -import { Outlet } from 'react-router-dom'; +import { Outlet, useParams } from 'react-router-dom'; import { SidebarProvider, SidebarInset } from '@/components/ui/sidebar'; import { TooltipProvider } from '@/components/ui/tooltip'; import { AppSidebar } from './AppSidebar'; +import { useHumanInputAlerts } from '@/hooks/use-human-input-alerts'; export function AppLayout() { + const { id } = useParams<{ id: string }>(); + // Toast + chime on every new ask_human request that arrives while + // the operator is anywhere except the Inbox. + useHumanInputAlerts(id); + return ( diff --git a/web/src/components/AppSidebar.tsx b/web/src/components/AppSidebar.tsx index 493b06e..ef513d9 100644 --- a/web/src/components/AppSidebar.tsx +++ b/web/src/components/AppSidebar.tsx @@ -28,8 +28,10 @@ import { KeyRound, FileCode, FolderOpen, + Inbox, type LucideIcon, } from 'lucide-react'; +import { useOpenHumanInputCount } from '@/hooks/use-human-inputs'; import { Tooltip, TooltipTrigger, TooltipContent } from '@/components/ui/tooltip'; import { ThemeToggle } from '@/components/ThemeToggle'; import { cn } from '@/lib/utils'; @@ -50,6 +52,7 @@ function StatusDot({ tone, live = false, size = 6 }: { tone: 'running' | 'comple const staticNavItems: { label: string; path: string; icon: LucideIcon }[] = [ { label: 'Missions', path: 'missions', icon: Rocket }, + { label: 'Inbox', path: 'inbox', icon: Inbox }, { label: 'Agents', path: 'agents', icon: Bot }, { label: 'Skills', path: 'skills', icon: Sparkles }, { label: 'Tools', path: 'tools', icon: Puzzle }, @@ -122,6 +125,8 @@ export function AppSidebar() { ? [...staticNavItems, { label: 'Folders', path: 'files', icon: FolderOpen }] : staticNavItems; + const inboxCount = useOpenHumanInputCount(id); + const activePath = location.pathname.split('/').at(-1) ?? ''; const activeSection = location.pathname.includes('/missions/') && location.pathname.includes('/run') ? 'missions' @@ -198,8 +203,14 @@ export function AppSidebar() {