agent
This commit is contained in:
@@ -15,8 +15,9 @@ import (
|
||||
|
||||
// Nearle Buddy's HTTP surface.
|
||||
//
|
||||
// POST /v1/web/assistant/ask a question → an answer, and what it ran
|
||||
// GET /v1/web/assistant/status is this switched on here?
|
||||
// POST /v1/web/assistant/ask a question → an answer, and what it ran
|
||||
// POST /v1/web/assistant/approve a card the person pressed → the change, made
|
||||
// GET /v1/web/assistant/status is this switched on here?
|
||||
//
|
||||
// ── Where the caller comes from ─────────────────────────────────────────────
|
||||
//
|
||||
@@ -33,6 +34,13 @@ func NewAssistantController(assistant services.AssistantService) *AssistantContr
|
||||
return &AssistantController{assistant: assistant}
|
||||
}
|
||||
|
||||
type assistantApproveRequest struct {
|
||||
Agent string `json:"agent"`
|
||||
// The card exactly as it was handed out. Opaque to the console — it is
|
||||
// signed, and anything the browser changed stops it verifying.
|
||||
Card string `json:"card"`
|
||||
}
|
||||
|
||||
type assistantAskRequest struct {
|
||||
// Which agent to ask. The console sends the one matching the page the panel
|
||||
// is sitting beside; empty means orders, the only one phase 2 ships.
|
||||
@@ -98,6 +106,48 @@ func (ctl *AssistantController) Ask(c *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
// Approve performs a change the person pressed the button on.
|
||||
//
|
||||
// Its own endpoint, not a flag on /ask, because it is a different kind of act:
|
||||
// no question, no model, no conversation. The card names the action and the
|
||||
// session names the person, and the registry re-checks both against the live
|
||||
// database before anything is written.
|
||||
func (ctl *AssistantController) Approve(c *fiber.Ctx) error {
|
||||
var req assistantApproveRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return assistantRefuse(c, http.StatusBadRequest, "Invalid request body")
|
||||
}
|
||||
if strings.TrimSpace(req.Card) == "" {
|
||||
return assistantRefuse(c, http.StatusBadRequest, "Nothing to approve.")
|
||||
}
|
||||
|
||||
caller, ok := callerFrom(c)
|
||||
if !ok {
|
||||
return assistantRefuse(c, http.StatusUnauthorized, "Sign in again to approve this.")
|
||||
}
|
||||
|
||||
agent := strings.TrimSpace(req.Agent)
|
||||
if agent == "" {
|
||||
agent = "orders"
|
||||
}
|
||||
|
||||
ctx, cancel := services.WithTimeout(c.Context())
|
||||
defer cancel()
|
||||
|
||||
answer, err := ctl.assistant.Approve(ctx, agent, req.Card, caller)
|
||||
if err != nil {
|
||||
// A refused approval is a business outcome, not a server fault: the card
|
||||
// expired, somebody else already approved it, the request was withdrawn.
|
||||
// The person needs the reason, and the console renders it beside the
|
||||
// card rather than as an error page.
|
||||
return assistantRefuse(c, http.StatusConflict, err.Error())
|
||||
}
|
||||
|
||||
return c.Status(http.StatusOK).JSON(fiber.Map{
|
||||
"code": http.StatusOK, "status": true, "message": "Success", "details": answer,
|
||||
})
|
||||
}
|
||||
|
||||
// callerFrom turns a verified session into a tool caller.
|
||||
//
|
||||
// The one place the two vocabularies meet. Staff (`issuperadmin`) carry no
|
||||
|
||||
Reference in New Issue
Block a user