···11-// Package chatcommands provides a unified slash-command dispatcher that can be
22-// reused by the TUI chat, Telegram, and Slack runtimes.
11+// Package chatcommands provides a unified slash-command dispatcher for chat,
22+// console, and channel runtimes.
33package chatcommands
4455import (
+19
internal/chatcommands/dispatcher_test.go
···143143 t.Fatalf("expected command list in reply: %q", reply)
144144 }
145145}
146146+147147+func TestModelCommandHandlerRebuildsCommandText(t *testing.T) {
148148+ var gotText string
149149+ h := ModelCommandHandler(func(text string) (string, bool, error) {
150150+ gotText = text
151151+ return "ok", true, nil
152152+ })
153153+154154+ res, err := h(context.Background(), "set cheap")
155155+ if err != nil {
156156+ t.Fatalf("ModelCommandHandler() error = %v", err)
157157+ }
158158+ if gotText != "/model set cheap" {
159159+ t.Fatalf("model command text = %q, want %q", gotText, "/model set cheap")
160160+ }
161161+ if res == nil || res.Reply != "ok" {
162162+ t.Fatalf("unexpected reply: %#v", res)
163163+ }
164164+}
+32-2
internal/chatcommands/handlers.go
···2233import (
44 "context"
55+ "fmt"
56 "strings"
6778 "github.com/quailyquaily/mistermorph/internal/llmselect"
···3334 }
3435}
35363737+// ModelCommandFunc executes a /model command string and reports whether it was handled.
3838+type ModelCommandFunc = func(text string) (output string, handled bool, err error)
3939+4040+// ModelCommandHandler adapts a /model command executor to the Registry Handler
4141+// signature, whose input is only the argument tail after "/model".
4242+func ModelCommandHandler(fn ModelCommandFunc) Handler {
4343+ return func(ctx context.Context, args string) (*Result, error) {
4444+ if fn == nil {
4545+ return nil, fmt.Errorf("missing llm profile command handler")
4646+ }
4747+ output, handled, err := fn(modelCommandText(args))
4848+ if !handled {
4949+ return nil, nil
5050+ }
5151+ if err != nil {
5252+ return nil, err
5353+ }
5454+ return &Result{Reply: output}, nil
5555+ }
5656+}
5757+5858+func modelCommandText(args string) string {
5959+ text := "/model"
6060+ if args = strings.TrimSpace(args); args != "" {
6161+ text += " " + args
6262+ }
6363+ return text
6464+}
6565+3666// ModelHandler wraps the llmselect package so that /model commands can be
3767// handled uniformly across chat front-ends.
3868//
···6595// AsHandler returns the model handler as a standard Handler closure so it can
6696// be registered in a Registry.
6797func (m *ModelHandler) AsHandler() Handler {
6868- return func(ctx context.Context, text string) (*Result, error) {
6969- return m.Handle(ctx, text)
9898+ return func(ctx context.Context, args string) (*Result, error) {
9999+ return m.Handle(ctx, modelCommandText(args))
70100 }
71101}