b09967f9e6
Pure move: actionFact, actionReminder, actionAct and actionNote each get their own actions_<intent>.go. The two small ones (chat, system) and the actionHandlers table stay in actions.go, which is now just the dispatch layer and the notes about what does not belong in it. No behaviour change — only the file a handler is read in.
72 lines
3.2 KiB
Go
72 lines
3.2 KiB
Go
// actionTable dispatches applyAction's per-intent bodies. Each of the 7
|
|
// intents (fact, reminder, note, query, act, chat, system) has one handler
|
|
// here with the signature:
|
|
//
|
|
// func(h *reactiveHandler, ctx context.Context, dec router.Decision) string
|
|
//
|
|
// same contract as applyAction itself: "" means "let the Replier phrase the
|
|
// reply", a non-empty string OVERRIDES it. This is a straight extraction of
|
|
// applyAction's old switch cases (formerly ~300 lines in voice.go) — no
|
|
// reordering of side effects, no new abstractions inside a handler.
|
|
//
|
|
// What does NOT belong in this table, because it is not per-intent:
|
|
//
|
|
// - the dec.Clarify short-circuit ("" when the router's stage-3 fired) —
|
|
// stays in applyAction, before dispatch, since it applies to every
|
|
// intent identically.
|
|
// - the destructive-act confirm gate (park / resolveConfirm / confirmTTL)
|
|
// and the enabled-tool allowlist. Both live entirely inside
|
|
// actionAct/handleAct in actions_act.go, exactly where they lived in the old
|
|
// switch's IntentAct case — they are act-specific (a fact or a note
|
|
// can't be destructive), not shared across intents, so they do not need
|
|
// to move to a separate layer. The important invariant, preserved
|
|
// as-is: applyAction runs identically whether dec came from a fresh
|
|
// route or from a completed clarify answer (see finishClarified in
|
|
// clarify.go and its comment "filling in an argument never grants
|
|
// authority") — a handler must never special-case a clarify-completed
|
|
// decision to skip the confirm gate or the allowlist.
|
|
// - detectPattern and dialogue-session bookkeeping (rememberTurn,
|
|
// followUpMerge) run in the callers (handleText, HandlePushToTalk,
|
|
// finishClarified), not per-intent, and are untouched by this slice.
|
|
//
|
|
// Each handler lives in actions_<intent>.go; the small ones (chat, system)
|
|
// and the table itself stay here.
|
|
//
|
|
// Adding an intent: write its handler in its own file, add one line to
|
|
// actionHandlers. Do not grow applyAction's switch back.
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
|
|
"github.com/kami/maven/internal/router"
|
|
)
|
|
|
|
// actionHandlers is the per-intent dispatch table used by applyAction.
|
|
var actionHandlers = map[router.Intent]func(*reactiveHandler, context.Context, router.Decision) string{
|
|
router.IntentFact: (*reactiveHandler).actionFact,
|
|
router.IntentReminder: (*reactiveHandler).actionReminder,
|
|
router.IntentAct: (*reactiveHandler).actionAct,
|
|
router.IntentChat: (*reactiveHandler).actionChat,
|
|
router.IntentSystem: (*reactiveHandler).actionSystem,
|
|
router.IntentNote: (*reactiveHandler).actionNote,
|
|
router.IntentQuery: (*reactiveHandler).actionQuery,
|
|
}
|
|
|
|
func (h *reactiveHandler) actionChat(ctx context.Context, dec router.Decision) string {
|
|
// Conversational: build history from dialogue session (prior user turns)
|
|
// and let the LLM respond from general knowledge + context.
|
|
history := h.chatHistory()
|
|
reply, err := h.phraser.PhraseChat(ctx, dec.Utterance, history)
|
|
if err != nil {
|
|
log.Printf("voice: chat: %v", err)
|
|
return "поговорили."
|
|
}
|
|
return reply
|
|
}
|
|
|
|
func (h *reactiveHandler) actionSystem(ctx context.Context, dec router.Decision) string {
|
|
return h.replySystem(ctx, dec)
|
|
}
|