-
-
Notifications
You must be signed in to change notification settings - Fork 64
Open
Description
for now when use PermitDynamic. and gen graph with sm.ToGraph()
it will not connect state node in PermitDynamic.
this code gen graph like this
and i expected to be like this . (BOT_MENU Connect with BOT_SELECT1,BOT_SELECT2,TO_CUSTOMER_SUPPORT)
i think this should use something like go generate or go tools for gen graph, because it can not determine which state should be connect at runtime. or may be it should make PermitDynamic to accept connectable state as params too.
Example code
package main
import (
"bufio"
"context"
"fmt"
"os"
"strings"
"github.com/qmuntal/stateless"
)
const (
StateOpen = "OPEN"
StateBotMenu = "BOT_MENU"
StateBotSelect1 = "BOT_SELECT1"
StateBotSelect2 = "BOT_SELECT2"
StateToCustomerSupport = "TO_CUSTOMER_SUPPORT"
StateClosed = "CLOSED"
)
const (
BotCompleted = "BOT_COMPLETED"
TriggerUserInput = "USER_INPUT"
)
var currentState stateless.State = StateOpen
func NewChatbot() *stateless.StateMachine {
sm := stateless.NewStateMachineWithExternalStorage(
func(ctx context.Context) (stateless.State, error) {
return currentState, nil
},
func(ctx context.Context, state stateless.State) error {
currentState = state.(string)
return nil
},
stateless.FiringImmediate,
)
sm.Configure(StateOpen).
Permit(TriggerUserInput, StateBotMenu)
sm.Configure(StateBotMenu).
OnEntry(func(ctx context.Context, args ...any) error {
fmt.Println(">> Menu optins")
fmt.Println(" 1. Select 1")
fmt.Println(" 2. Select 2")
fmt.Println(" 3. Other")
return nil
}).
PermitDynamic(TriggerUserInput, func(_ context.Context, args ...any) (stateless.State, error) {
input := args[0].(string)
switch input {
case "1":
return StateBotSelect1, nil
case "2":
return StateBotSelect2, nil
default:
return StateToCustomerSupport, nil
}
})
// Configure State: StateBotSelect1
sm.Configure(StateBotSelect1).
OnEntry(func(ctx context.Context, args ...any) error {
fmt.Println(">> Menu 1 selected")
return sm.Fire(BotCompleted)
}).
Permit(BotCompleted, StateClosed)
// Configure State: StateBotSelect2
sm.Configure(StateBotSelect2).
OnEntry(func(ctx context.Context, args ...any) error {
fmt.Println(">> Menu 2 selected")
return sm.Fire(BotCompleted)
}).
Permit(BotCompleted, StateClosed)
// Configure State: TO_CUSTOMER_SUPPORT
sm.Configure(StateToCustomerSupport).
OnEntry(func(ctx context.Context, args ...any) error {
fmt.Println(">> Redirect to Human (to stop simulation type 'END')")
return nil
}).
PermitDynamic(TriggerUserInput, func(_ context.Context, args ...any) (stateless.State, error) {
input := args[0].(string)
if strings.ToUpper(input) == "END" {
return StateClosed, nil
}
fmt.Println(">> Human response (to stop simulation type 'END')")
return StateToCustomerSupport, nil
})
// Configure State: CLOSED
sm.Configure(StateClosed).
OnEntry(func(ctx context.Context, args ...any) error {
fmt.Println(">> End Conversation")
return nil
}).
Permit(TriggerUserInput, StateOpen)
return sm
}
func main() {
fmt.Println("Chatbot is starting...")
chatbot := NewChatbot()
if err := chatbot.Fire(TriggerUserInput, ""); err != nil {
fmt.Printf("Error starting chatbot: %v\n", err)
return
}
fmt.Println(chatbot.ToGraph())
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("> ")
for scanner.Scan() {
input := scanner.Text()
chatbot = NewChatbot()
if err := chatbot.Fire(TriggerUserInput, input); err != nil {
fmt.Printf("Error processing input: %v\n", err)
}
fmt.Print("> ")
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading standard input:", err)
}
}Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels