diff --git a/.gitignore b/.gitignore index fe287b75b..795ee538b 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ coverage.txt *.o build/ .env +example/10-ai/*.yaml diff --git a/README.md b/README.md index 09910bfb3..0133d4bb2 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ func InputSchema() any { Create a Stateful Serverless Function to get the IP and Latency of a domain: ```golang -func handler(ctx serverless.Context) { +func Handler(ctx serverless.Context) { fc, _ := ai.ParseFunctionCallContext(ctx) var msg Parameter @@ -128,7 +128,7 @@ func handler(ctx serverless.Context) { Finally, let's run it ```bash -$ go run main.go +$ yomo run app.go time=2024-03-19T21:43:30.583+08:00 level=INFO msg="connected to zipper" component=StreamFunction sfn_id=B0ttNSEKLSgMjXidB11K1 sfn_name=fn-get-ip-from-domain zipper_addr=localhost:9000 time=2024-03-19T21:43:30.584+08:00 level=INFO msg="register ai function success" component=StreamFunction sfn_id=B0ttNSEKLSgMjXidB11K1 sfn_name=fn-get-ip-from-domain zipper_addr=localhost:9000 name=fn-get-ip-from-domain tag=16 diff --git a/cli/README.md b/cli/README.md index 9bb512607..b843f499b 100644 --- a/cli/README.md +++ b/cli/README.md @@ -58,7 +58,7 @@ See [../example/9-cli/sfn/app.go](../example/9-cli/sfn/app.go) #### Build -Build the app.go to a WebAssembly file. +Build the app.go, defaults to sfn.yomo binary file, with `-w` flag to generate a WebAssembly file. ```sh cd ../example/9-cli/sfn @@ -69,5 +69,5 @@ yomo build #### Run ```sh -yomo run sfn.wasm +yomo run sfn.yomo ``` diff --git a/cli/build.go b/cli/build.go index 872f3ea2b..c78d23082 100644 --- a/cli/build.go +++ b/cli/build.go @@ -19,35 +19,33 @@ import ( "os" "github.com/spf13/cobra" - "github.com/spf13/viper" "github.com/yomorun/yomo/cli/serverless" + "github.com/yomorun/yomo/cli/viper" "github.com/yomorun/yomo/pkg/log" ) -var buildViper *viper.Viper - // buildCmd represents the build command var buildCmd = &cobra.Command{ Use: "build [flags] app.go", Short: "Build the YoMo Stream Function", - Long: "Build the YoMo Stream Function as WebAssembly", + Long: "Build the YoMo Stream Function", Run: func(cmd *cobra.Command, args []string) { if err := parseFileArg(args, &opts, defaultSFNSourceFile); err != nil { log.FailureStatusEvent(os.Stdout, err.Error()) os.Exit(127) // return } - loadViperValue(cmd, buildViper, &opts.ModFile, "modfile") - // use environment variable to override flags - opts.UseEnv = true + loadOptionsFromViper(viper.BuildViper, &opts) log.InfoStatusEvent(os.Stdout, "YoMo Stream Function file: %v", opts.Filename) + log.InfoStatusEvent(os.Stdout, "YoMo Stream Function parsing...") s, err := serverless.Create(&opts) if err != nil { log.FailureStatusEvent(os.Stdout, err.Error()) os.Exit(127) // return } + log.InfoStatusEvent(os.Stdout, "YoMo Stream Function parse done.") // build log.PendingStatusEvent(os.Stdout, "YoMo Stream Function building...") if err := s.Build(true); err != nil { @@ -63,6 +61,7 @@ func init() { rootCmd.AddCommand(buildCmd) buildCmd.Flags().StringVarP(&opts.ModFile, "modfile", "m", "", "custom go.mod") + buildCmd.Flags().BoolVarP(&opts.WASI, "wasi", "w", false, "build with WASI target") - buildViper = bindViper(buildCmd) + viper.BindPFlags(viper.BuildViper, buildCmd.Flags()) } diff --git a/cli/cli.go b/cli/cli.go index 3664927ac..dab3ee284 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -5,12 +5,11 @@ package cli import ( "fmt" "path" + "path/filepath" "runtime" "strconv" "strings" - "github.com/spf13/cobra" - "github.com/spf13/pflag" "github.com/spf13/viper" "github.com/yomorun/yomo/cli/serverless" "github.com/yomorun/yomo/pkg/file" @@ -20,7 +19,8 @@ import ( const ( defaultSFNSourceFile = "app.go" defaultSFNTestSourceFile = "app_test.go" - defaultSFNCompliedFile = "sfn.wasm" + defaultSFNCompliedFile = "sfn.yomo" + defaultSFNWASIFile = "sfn.wasm" ) // GetRootPath get root path @@ -32,10 +32,11 @@ func GetRootPath() string { return "" } -func parseURL(url string, opts *serverless.Options) error { - url = strings.TrimSpace(url) +func parseZipperAddr(opts *serverless.Options) error { + url := opts.ZipperAddr if url == "" { - url = "localhost:9000" + opts.ZipperAddr = "localhost:9000" + return nil } splits := strings.Split(url, ":") @@ -53,39 +54,39 @@ func parseURL(url string, opts *serverless.Options) error { return nil } -func getViperName(name string) string { - return "yomo_sfn_" + strings.ReplaceAll(name, "-", "_") +// loadOptionsFromViper load options from viper, supports flags and environment variables +func loadOptionsFromViper(v *viper.Viper, opts *serverless.Options) { + opts.Name = v.GetString("name") + opts.ZipperAddr = v.GetString("zipper") + opts.Credential = v.GetString("credential") + opts.ModFile = v.GetString("modfile") + opts.Runtime = v.GetString("runtime") + opts.WASI = v.GetBool("wasi") } -func bindViper(cmd *cobra.Command) *viper.Viper { - v := viper.New() - - // bind environment variables - v.AllowEmptyEnv(true) - cmd.Flags().VisitAll(func(f *pflag.Flag) { - name := getViperName(f.Name) - v.BindEnv(name) - v.SetDefault(name, f.DefValue) - }) - - return v -} - -func loadViperValue(cmd *cobra.Command, v *viper.Viper, p *string, name string) { - f := cmd.Flag(name) - if !f.Changed { - *p = v.GetString(getViperName(name)) +func parseFileArg(args []string, opts *serverless.Options, defaultFiles ...string) error { + if len(args) >= 1 && args[0] != "" { + opts.Filename = args[0] + return checkOptions(opts) } + for _, f := range defaultFiles { + opts.Filename = f + err := checkOptions(opts) + if err == nil { + break + } + } + return nil } -func parseFileArg(args []string, opts *serverless.Options, defaultFile string) error { - if len(args) >= 1 && args[0] != "" { - opts.Filename = args[0] - } else { - opts.Filename = defaultFile +func checkOptions(opts *serverless.Options) error { + f, err := filepath.Abs(opts.Filename) + if err != nil { + return err } - if !file.Exists(opts.Filename) { - return fmt.Errorf("file %s not found", opts.Filename) + if !file.Exists(f) { + return fmt.Errorf("file %s not found", f) } + opts.Filename = f return nil } diff --git a/cli/dev.go b/cli/dev.go index 4cff05f7f..b8a72e8af 100644 --- a/cli/dev.go +++ b/cli/dev.go @@ -17,35 +17,38 @@ package cli import ( "os" + "path/filepath" "github.com/spf13/cobra" - "github.com/spf13/viper" "github.com/yomorun/yomo/cli/serverless" + "github.com/yomorun/yomo/cli/viper" "github.com/yomorun/yomo/pkg/log" ) -var devViper *viper.Viper - // devCmd represents the dev command var devCmd = &cobra.Command{ - Use: "dev [flags] sfn.wasm", + Use: "dev [flags]", Short: "Test a YoMo Stream Function", Long: "Test a YoMo Stream Function with public zipper and mocking data", FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true}, Run: func(cmd *cobra.Command, args []string) { - if err := parseFileArg(args, &opts, defaultSFNCompliedFile); err != nil { + if err := parseFileArg(args, &opts, defaultSFNCompliedFile, defaultSFNWASIFile, defaultSFNSourceFile); err != nil { log.FailureStatusEvent(os.Stdout, err.Error()) return } - loadViperValue(cmd, devViper, &opts.ModFile, "modfile") + loadOptionsFromViper(viper.RunViper, &opts) // Serverless log.InfoStatusEvent(os.Stdout, "YoMo Stream Function file: %v", opts.Filename) // resolve serverless log.PendingStatusEvent(os.Stdout, "Create YoMo Stream Function instance...") // Connect the serverless to YoMo dev-server, it will automatically emit the mock data. - opts.ZipperAddr = "tap.yomo.dev:9140" opts.Name = "yomo-app-demo" + opts.ZipperAddr = "tap.yomo.dev:9140" + + // Set the environment variables for the YoMo Stream Function + os.Setenv("YOMO_SFN_NAME", opts.Name) + os.Setenv("YOMO_SFN_ZIPPER", opts.ZipperAddr) s, err := serverless.Create(&opts) if err != nil { @@ -54,20 +57,29 @@ var devCmd = &cobra.Command{ } if !s.Executable() { log.FailureStatusEvent(os.Stdout, - "You cannot run `%s` directly. build first with the `yomo build %s` command and then run with the 'yomo run sfn.wasm' command.", + "You cannot run `%s` directly. build first with the `yomo build %s` command and then run with the 'yomo run %s' command.", + opts.Filename, opts.Filename, opts.Filename, ) return } + // build if it's go file + if ext := filepath.Ext(opts.Filename); ext == ".go" { + log.PendingStatusEvent(os.Stdout, "YoMo Stream Function building...") + if err := s.Build(true); err != nil { + log.FailureStatusEvent(os.Stdout, err.Error()) + os.Exit(127) + } + log.SuccessStatusEvent(os.Stdout, "Success! YoMo Stream Function build.") + } // run log.InfoStatusEvent( os.Stdout, - "Starting YoMo Stream Function instance with executable file: %s. Zipper: %v.", - opts.Filename, + "Starting YoMo Stream Function instance with zipper: %v", opts.ZipperAddr, ) - log.InfoStatusEvent(os.Stdout, "YoMo Stream Function is running...") + log.InfoStatusEvent(os.Stdout, "Stream Function is running...") if err := s.Run(verbose); err != nil { log.FailureStatusEvent(os.Stdout, err.Error()) return @@ -80,5 +92,5 @@ func init() { devCmd.Flags().StringVarP(&opts.ModFile, "modfile", "m", "", "custom go.mod") - devViper = bindViper(devCmd) + viper.BindPFlags(viper.DevViper, devCmd.Flags()) } diff --git a/cli/init.go b/cli/init.go index 37a28422d..af32b31ae 100644 --- a/cli/init.go +++ b/cli/init.go @@ -69,7 +69,7 @@ var initCmd = &cobra.Command{ // create .env fname = filepath.Join(name, ".env") - if err := file.PutContents(fname, []byte(fmt.Sprintf("YOMO_SFN_NAME=%s\n", name))); err != nil { + if err := file.PutContents(fname, []byte(fmt.Sprintf("YOMO_SFN_NAME=%s\nYOMO_SFN_ZIPPER=localhost:9000\n", name))); err != nil { log.FailureStatusEvent(os.Stdout, "Write stream function .env file failure with the error: %v", err) return } @@ -77,7 +77,7 @@ var initCmd = &cobra.Command{ log.SuccessStatusEvent(os.Stdout, "Congratulations! You have initialized the stream function successfully.") log.InfoStatusEvent(os.Stdout, "You can enjoy the YoMo Stream Function via the command: ") log.InfoStatusEvent(os.Stdout, "\tStep 1: cd %s && yomo build", name) - log.InfoStatusEvent(os.Stdout, "\tStep 2: yomo run sfn.wasm") + log.InfoStatusEvent(os.Stdout, "\tStep 2: yomo run sfn.yomo") }, } diff --git a/cli/root.go b/cli/root.go index 03fbebdf2..7862b6055 100644 --- a/cli/root.go +++ b/cli/root.go @@ -27,7 +27,6 @@ import ( var ( config string - url string opts serverless.Options verbose bool ) diff --git a/cli/run.go b/cli/run.go index d2a56f504..98841fd69 100644 --- a/cli/run.go +++ b/cli/run.go @@ -17,50 +17,40 @@ package cli import ( "os" + "path/filepath" "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/yomorun/yomo/cli/serverless" - "github.com/yomorun/yomo/pkg/file" "github.com/yomorun/yomo/pkg/log" // serverless registrations + "github.com/yomorun/yomo/cli/serverless" _ "github.com/yomorun/yomo/cli/serverless/deno" + _ "github.com/yomorun/yomo/cli/serverless/exec" _ "github.com/yomorun/yomo/cli/serverless/golang" _ "github.com/yomorun/yomo/cli/serverless/wasm" + "github.com/yomorun/yomo/cli/viper" ) -var runViper *viper.Viper - // runCmd represents the run command var runCmd = &cobra.Command{ - Use: "run [flags] sfn.wasm", + Use: "run [flags] sfn", Short: "Run a YoMo Stream Function", Long: "Run a YoMo Stream Function", Run: func(cmd *cobra.Command, args []string) { - if err := parseFileArg(args, &opts, defaultSFNCompliedFile); err != nil { + if err := parseFileArg(args, &opts, defaultSFNCompliedFile, defaultSFNWASIFile, defaultSFNSourceFile); err != nil { log.FailureStatusEvent(os.Stdout, err.Error()) return } - loadViperValue(cmd, runViper, &url, "zipper") - loadViperValue(cmd, runViper, &opts.Name, "name") - loadViperValue(cmd, runViper, &opts.ModFile, "modfile") - loadViperValue(cmd, runViper, &opts.Credential, "credential") - loadViperValue(cmd, runViper, &opts.Runtime, "runtime") - - if opts.Name == "" { - log.FailureStatusEvent(os.Stdout, "YoMo Stream Function name must be set.") - return - } + loadOptionsFromViper(viper.RunViper, &opts) // Serverless log.InfoStatusEvent(os.Stdout, "YoMo Stream Function file: %v", opts.Filename) - if !file.IsExec(opts.Filename) && opts.Name == "" { + if opts.Name == "" { log.FailureStatusEvent(os.Stdout, "YoMo Stream Function's Name is empty, please set name used by `-n` flag") return } // resolve serverless log.PendingStatusEvent(os.Stdout, "Create YoMo Stream Function instance...") - if err := parseURL(url, &opts); err != nil { + if err := parseZipperAddr(&opts); err != nil { log.FailureStatusEvent(os.Stdout, err.Error()) return } @@ -71,25 +61,37 @@ var runCmd = &cobra.Command{ } if !s.Executable() { log.FailureStatusEvent(os.Stdout, - "You cannot run `%s` directly. build first with the `yomo build %s` command and then run with the 'yomo run sfn.wasm' command.", + "You cannot run `%s` directly. build first with the `yomo build %s` command and then run with the 'yomo run %s' command.", + opts.Filename, opts.Filename, opts.Filename, ) return } + // build if it's go file + if ext := filepath.Ext(opts.Filename); ext == ".go" { + log.PendingStatusEvent(os.Stdout, "YoMo Stream Function building...") + if err := s.Build(true); err != nil { + log.FailureStatusEvent(os.Stdout, err.Error()) + os.Exit(127) + } + log.SuccessStatusEvent(os.Stdout, "Success! YoMo Stream Function build.") + } // run - wasmRuntime := opts.Runtime - if wasmRuntime == "" { - wasmRuntime = "wazero" + // wasi + if ext := filepath.Ext(opts.Filename); ext == ".wasm" { + wasmRuntime := opts.Runtime + if wasmRuntime == "" { + wasmRuntime = "wazero" + } + log.InfoStatusEvent(os.Stdout, "WASM runtime: %s", wasmRuntime) } log.InfoStatusEvent( os.Stdout, - "Starting YoMo Stream Function instance with executable file: %s. WasmRuntime: %s. Zipper: %v.", - opts.Filename, - wasmRuntime, + "Starting YoMo Stream Function instance with zipper: %v", opts.ZipperAddr, ) - log.InfoStatusEvent(os.Stdout, "YoMo Stream Function is running...") + log.InfoStatusEvent(os.Stdout, "Stream Function is running...") if err := s.Run(verbose); err != nil { log.FailureStatusEvent(os.Stdout, err.Error()) return @@ -100,11 +102,11 @@ var runCmd = &cobra.Command{ func init() { rootCmd.AddCommand(runCmd) - runCmd.Flags().StringVarP(&url, "zipper", "z", "localhost:9000", "YoMo-Zipper endpoint addr") - runCmd.Flags().StringVarP(&opts.Name, "name", "n", "sfn-app", "yomo stream function name.") + runCmd.Flags().StringVarP(&opts.ZipperAddr, "zipper", "z", "localhost:9000", "YoMo-Zipper endpoint addr") + runCmd.Flags().StringVarP(&opts.Name, "name", "n", "app", "yomo stream function name.") runCmd.Flags().StringVarP(&opts.ModFile, "modfile", "m", "", "custom go.mod") runCmd.Flags().StringVarP(&opts.Credential, "credential", "d", "", "client credential payload, eg: `token:dBbBiRE7`") runCmd.Flags().StringVarP(&opts.Runtime, "runtime", "r", "", "serverless runtime type") - runViper = bindViper(runCmd) + viper.BindPFlags(viper.RunViper, runCmd.Flags()) } diff --git a/cli/serverless/exec/serverless.go b/cli/serverless/exec/serverless.go new file mode 100644 index 000000000..121c16a6e --- /dev/null +++ b/cli/serverless/exec/serverless.go @@ -0,0 +1,61 @@ +package exec + +import ( + "fmt" + "os" + "os/exec" + + "github.com/yomorun/yomo/cli/serverless" + "github.com/yomorun/yomo/pkg/file" + "github.com/yomorun/yomo/pkg/log" +) + +// ExecServerless defines executable file implementation of Serverless interface. +type ExecServerless struct { + target string +} + +// Init initializes the serverless +func (s *ExecServerless) Init(opts *serverless.Options) error { + if !file.Exists(opts.Filename) { + return fmt.Errorf("the file %s doesn't exist", opts.Filename) + } + s.target = opts.Filename + + return nil +} + +// Build compiles the serverless to executable +func (s *ExecServerless) Build(clean bool) error { + return nil +} + +// Run compiles and runs the serverless +func (s *ExecServerless) Run(verbose bool) error { + log.InfoStatusEvent(os.Stdout, "Run: %s", s.target) + dir := file.Dir(s.target) + cmd := exec.Command(s.target) + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + cmd.Args = os.Args + cmd.Dir = dir + err := serverless.LoadEnvFile(dir) + if err != nil { + return err + } + env := os.Environ() + if verbose { + cmd.Env = append(env, "YOMO_LOG_LEVEL=debug") + } + cmd.Env = env + return cmd.Run() +} + +// Executable returns true if the serverless is executable +func (s *ExecServerless) Executable() bool { + return true +} + +func init() { + serverless.Register(&ExecServerless{}, ".yomo", ".exe") +} diff --git a/cli/serverless/golang/serverless.go b/cli/serverless/golang/serverless.go index 2b5fc5b4c..b3f4be25d 100644 --- a/cli/serverless/golang/serverless.go +++ b/cli/serverless/golang/serverless.go @@ -51,31 +51,33 @@ func (s *GolangServerless) Init(opts *serverless.Options) error { Name: s.opts.Name, ZipperAddr: s.opts.ZipperAddr, Credential: s.opts.Credential, - UseEnv: s.opts.UseEnv, WithInitFunc: opt.WithInit, WithWantedTarget: opt.WithWantedTarget, + WithDescription: opt.WithDescription, + WithInputSchema: opt.WithInputSchema, } // determine: rx stream serverless or raw bytes serverless. isRx := strings.Contains(string(source), "rx.Stream") - isWasm := true - mainFuncTmpl := "" - mainFunc, err := RenderTmpl(string(WasmMainFuncTmpl), &ctx) - if err != nil { - return fmt.Errorf("Init: %s", err) + isWasi := opts.WASI + // main function template + mainFuncTmpl := MainFuncTmpl + // wasi template + if isWasi { + mainFuncTmpl = WasiMainFuncTmpl } + // rx template if isRx { - if isWasm { - return errors.New("wasm does not support rx.Stream") - } - MainFuncRxTmpl = append(MainFuncRxTmpl, PartialsTmpl...) - mainFuncTmpl = string(MainFuncRxTmpl) - mainFunc, err = RenderTmpl(mainFuncTmpl, &ctx) - if err != nil { - return fmt.Errorf("Init: %s", err) + if isWasi { + return errors.New("wasi does not support rx.Stream") } + mainFuncTmpl = MainFuncRxTmpl } - + mainFunc, err := RenderTmpl(string(mainFuncTmpl), &ctx) + if err != nil { + return fmt.Errorf("Init: %s", err) + } + // merge app source code source = append(source, mainFunc...) fset := token.NewFileSet() astf, err := parser.ParseFile(fset, "", source, parser.ParseComments) @@ -85,13 +87,19 @@ func (s *GolangServerless) Init(opts *serverless.Options) error { // Add import packages astutil.AddNamedImport(fset, astf, "", "github.com/yomorun/yomo") astutil.AddNamedImport(fset, astf, "", "github.com/joho/godotenv") - // wasm guest import - astutil.AddNamedImport(fset, astf, "", "github.com/yomorun/yomo/serverless/guest") + astutil.AddNamedImport(fset, astf, "", "github.com/spf13/cobra") + astutil.AddNamedImport(fset, astf, "", "github.com/spf13/viper") + + if isWasi { + // wasm guest import + astutil.AddNamedImport(fset, astf, "", "github.com/yomorun/yomo/serverless/guest") + } // Generate the code code, err := generateCode(fset, astf) if err != nil { return fmt.Errorf("Init: generate code err %s", err) } + // fmt.Println("333.code", string(code)) // Create a temp folder. tempDir, err := os.MkdirTemp("", "yomo_") if err != nil { @@ -114,7 +122,7 @@ func (s *GolangServerless) Init(opts *serverless.Options) error { cmd := exec.Command("go", "mod", "init", name) cmd.Dir = tempDir env := os.Environ() - env = append(env, fmt.Sprintf("GO111MODULE=%s", "on")) + // env = append(env, fmt.Sprintf("GO111MODULE=%s", "on")) cmd.Env = env out, err := cmd.CombinedOutput() if err != nil { @@ -122,7 +130,6 @@ func (s *GolangServerless) Init(opts *serverless.Options) error { return err } - // TODO: check if is already built in temp dir by MD5 s.source = tempFile return nil } @@ -136,10 +143,6 @@ func (s *GolangServerless) Build(clean bool) error { } // env env := os.Environ() - env = append( - env, - fmt.Sprintf("GO111MODULE=%s", "on"), - ) // use custom go.mod if s.opts.ModFile != "" { mfile, _ := filepath.Abs(s.opts.ModFile) @@ -191,8 +194,13 @@ func (s *GolangServerless) Build(clean bool) error { } } // build + // wasi dir, _ := filepath.Split(s.opts.Filename) - sl, _ := filepath.Abs(dir + "sfn.wasm") + filename := "sfn.yomo" + if s.opts.WASI { + filename = "sfn.wasm" + } + sl, _ := filepath.Abs(dir + filename) // clean build if clean { @@ -201,16 +209,20 @@ func (s *GolangServerless) Build(clean bool) error { }() } s.output = sl - tinygo, err := exec.LookPath("tinygo") - if err != nil { - return errors.New("[tinygo] command was not found. to build the wasm file, you need to install tinygo. For details, visit https://tinygo.org") + cmd := exec.Command("go", "build", "-o", sl, appPath) + // wasi + if s.opts.WASI { + tinygo, err := exec.LookPath("tinygo") + if err != nil { + return errors.New("[tinygo] command was not found. to build the wasm file, you need to install tinygo. For details, visit https://tinygo.org") + } + cmd = exec.Command(tinygo, "build", "-no-debug", "-target", "wasi", "-o", sl, appPath) } - cmd := exec.Command(tinygo, "build", "-no-debug", "-target", "wasi", "-o", sl, appPath) cmd.Env = env cmd.Dir = s.tempDir out, err := cmd.CombinedOutput() if err != nil { - err = fmt.Errorf("Build: failure, tinygo %s", out) + err = fmt.Errorf("Build: failure, %s %s", cmd.String(), out) return err } return nil @@ -219,17 +231,27 @@ func (s *GolangServerless) Build(clean bool) error { // Run compiles and runs the serverless func (s *GolangServerless) Run(verbose bool) error { log.InfoStatusEvent(os.Stdout, "Run: %s", s.output) + dir := file.Dir(s.output) cmd := exec.Command(s.output) - if verbose { - cmd.Env = []string{"YOMO_LOG_LEVEL=debug", "YOMO_LOG_VERBOSE=true"} - } cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout + cmd.Args = os.Args + cmd.Dir = dir + err := serverless.LoadEnvFile(dir) + if err != nil { + return err + } + env := os.Environ() + if verbose { + cmd.Env = append(env, "YOMO_LOG_LEVEL=debug") + } + cmd.Env = env return cmd.Run() } +// Executable returns true if the serverless is executable func (s *GolangServerless) Executable() bool { - return false + return true } func generateCode(fset *token.FileSet, file *ast.File) ([]byte, error) { diff --git a/cli/serverless/golang/template.go b/cli/serverless/golang/template.go index c7dde9348..992d284df 100644 --- a/cli/serverless/golang/template.go +++ b/cli/serverless/golang/template.go @@ -16,11 +16,6 @@ var MainFuncRxTmpl []byte //go:embed templates/main.tmpl var MainFuncTmpl []byte -// PartialsTmpl partials template, used for rendering the partials -// -//go:embed templates/partials.tmpl -var PartialsTmpl []byte - //go:embed templates/init.tmpl var InitTmpl []byte @@ -30,23 +25,25 @@ var InitTestTmpl []byte //go:embed templates/init_rx.tmpl var InitRxTmpl []byte -//go:embed templates/wasm_main.tmpl -var WasmMainFuncTmpl []byte +//go:embed templates/wasi_main.tmpl +var WasiMainFuncTmpl []byte // Context defines context for the template type Context struct { // Name of the servcie Name string - // ZipperAddrs is the address of the zipper server + // ZipperAddr is the address of the zipper server ZipperAddr string // Client credential Credential string - // use environment variables - UseEnv bool // WithInitFunc determines whether to work with init function WithInitFunc bool // WithWantedTarget determines whether to work with SetWantedTarget WithWantedTarget bool + // WithDescription determines whether to work with description + WithDescription bool + // WithInputSchema determines whether to work with input schema + WithInputSchema bool } // RenderTmpl renders the template with the given context diff --git a/cli/serverless/golang/templates/init.tmpl b/cli/serverless/golang/templates/init.tmpl index 7e97e6a72..59213b912 100644 --- a/cli/serverless/golang/templates/init.tmpl +++ b/cli/serverless/golang/templates/init.tmpl @@ -29,7 +29,3 @@ func Handler(ctx serverless.Context) { func DataTags() []uint32 { return []uint32{0x33} } - -func WantedTarget() string { - return "" -} diff --git a/cli/serverless/golang/templates/init_rx.tmpl b/cli/serverless/golang/templates/init_rx.tmpl index 18d210755..b8f374c80 100644 --- a/cli/serverless/golang/templates/init_rx.tmpl +++ b/cli/serverless/golang/templates/init_rx.tmpl @@ -41,6 +41,3 @@ func DataTags() []uint32 { return []uint32{0x33} } -func WantedTarget() string { - return "" -} \ No newline at end of file diff --git a/cli/serverless/golang/templates/main.tmpl b/cli/serverless/golang/templates/main.tmpl index c1d95cb84..c5b810fea 100644 --- a/cli/serverless/golang/templates/main.tmpl +++ b/cli/serverless/golang/templates/main.tmpl @@ -1,60 +1,68 @@ // Serverless main function func main() { - addrs, err := parseZipperAddrs() - if err != nil { - log.Fatal(err) - } - {{if .UseEnv}} - name := env("Name") - credential := env("Credential") - {{else}} - name := "{{.Name}}" - credential := "{{.Credential}}" - {{end}} - for _, addr := range addrs { - sfnClose, err := runSFN(name, addr, credential) - defer sfnClose() - if err != nil { - log.Printf("[sfn] connect to zipper[%s], %v\n", addr, err) - os.Exit(1) - } + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) } - select {} } -func runSFN(name string, addr string, credential string) (closeFn func() error, err error) { +var ( + name string + credential string + zipper string + rootCmd = &cobra.Command{ + Short: "Start a YoMo Stream Function", + Long: "Start a YoMo Stream Function", + Run: func(cmd *cobra.Command, args []string) { + run(cmd, args) + }, + } +) + +func run(_ *cobra.Command, _ []string) { + name := viper.GetString("name") + credential := viper.GetString("credential") + addr := viper.GetString("zipper") + // create a new stream function sfn := yomo.NewStreamFunction( - name, + name, addr, - yomo.WithCredential(credential), + yomo.WithSfnCredential(credential), + {{if and .WithDescription .WithInputSchema}}yomo.WithSfnAIFunctionDefinition(Description(), InputSchema()),{{end}} ) - closeFn = sfn.Close - + {{if .WithInitFunc}} // init - sfn.Init(func() error { - return nil - }) - + sfn.Init(Init) + {{end}} // set observe data tags sfn.SetObserveDataTags(DataTags()...) - + {{if .WithWantedTarget}} // set wanted target sfn.SetWantedTarget(WantedTarget()) - + {{end}} // set handler sfn.SetHandler(Handler) - // set error handler sfn.SetErrorHandler(func(err error) { log.Printf("[sfn][%s] error handler: %T %v\n", addr, err, err) }) - - // start - err = sfn.Connect() + // connect to zipper + err := sfn.Connect() if err != nil { - return + log.Printf("[sfn] connect to zipper[%s], %v\n", addr, err) + os.Exit(1) } + defer sfn.Close() + sfn.Wait() +} - return +func init() { + rootCmd.Flags().StringVarP(&zipper, "zipper", "z", "localhost:9000", "YoMo-Zipper endpoint addr") + rootCmd.Flags().StringVarP(&name, "name", "n", "app", "yomo stream function name") + rootCmd.Flags().StringVarP(&credential, "credential", "d", "", "client credential payload, eg: `token:dBbBiRE7`") + viper.SetEnvPrefix("YOMO_SFN") + viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + viper.BindPFlags(rootCmd.Flags()) + viper.AutomaticEnv() } diff --git a/cli/serverless/golang/templates/main_rx.tmpl b/cli/serverless/golang/templates/main_rx.tmpl index 475373532..a11603482 100644 --- a/cli/serverless/golang/templates/main_rx.tmpl +++ b/cli/serverless/golang/templates/main_rx.tmpl @@ -1,67 +1,73 @@ // Serverless main function func main() { - addrs, err := parseZipperAddrs() - if err != nil { - log.Fatal(err) - } - {{if .UseEnv}} - name := env("Name") - credential := env("Credential") - {{else}} - name := "{{.Name}}" - credential := "{{.Credential}}" - {{end}} - for _, addr := range addrs { - sfnClose, err := runSFN(name, addr, credential) - defer sfnClose() - if err != nil { - log.Printf("[sfn] connect to zipper[%s], %v\n", addr, err) - os.Exit(1) - } + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) } - select {} } -func runSFN(name string, addr string, credential string) (closeFn func() error, err error) { - defer shutdown(context.Background()) +var ( + name string + credential string + zipper string + rootCmd = &cobra.Command{ + Short: "Start a YoMo Stream Function", + Long: "Start a YoMo Stream Function", + Run: func(cmd *cobra.Command, args []string) { + run(cmd, args) + }, + } +) + +func run(_ *cobra.Command, _ []string) { + name := viper.GetString("name") + credential := viper.GetString("credential") + addr := viper.GetString("zipper") + // create a new stream function sfn := yomo.NewStreamFunction( name, addr, - yomo.WithCredential(credential), + yomo.WithSfnCredential(credential), + {{if and .WithDescription .WithInputSchema}}yomo.WithSfnAIFunctionDefinition(Description(), InputSchema()),{{end}} ) - closeFn = sfn.Close - + {{if .WithInitFunc}} // init - sfn.Init(func() error { - return nil - }) - + sfn.Init(Init) + {{end}} // set observe data tags sfn.SetObserveDataTags(DataTags()...) - + {{if .WithWantedTarget}} // set wanted target sfn.SetWantedTarget(WantedTarget()) - + {{end}} // create a Rx runtime. rt := rx.NewRuntime(sfn) - // set handler sfn.SetHandler(rt.RawByteHandler) - // set error handler sfn.SetErrorHandler(func(err error) { log.Printf("[sfn][%s] error handler: %T %v\n", addr, err, err) }) - - // start - err = sfn.Connect() + // connect to zipper + err := sfn.Connect() if err != nil { - return + log.Printf("[sfn] connect to zipper[%s], %v\n", addr, err) + os.Exit(1) } - + defer sfn.Close() // pipe rx stream and rx handler. rt.Pipe(Handler) - return + sfn.Wait() +} + +func init() { + rootCmd.Flags().StringVarP(&zipper, "zipper", "z", "localhost:9000", "YoMo-Zipper endpoint addr") + rootCmd.Flags().StringVarP(&name, "name", "n", "app", "yomo stream function name") + rootCmd.Flags().StringVarP(&credential, "credential", "d", "", "client credential payload, eg: `token:dBbBiRE7`") + viper.SetEnvPrefix("YOMO_SFN") + viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + viper.BindPFlags(rootCmd.Flags()) + viper.AutomaticEnv() } diff --git a/cli/serverless/golang/templates/partials.tmpl b/cli/serverless/golang/templates/partials.tmpl deleted file mode 100644 index a319a9669..000000000 --- a/cli/serverless/golang/templates/partials.tmpl +++ /dev/null @@ -1,48 +0,0 @@ -func init() { - {{if .UseEnv}} - if err := godotenv.Load(); err != nil { - fmt.Fprintf(os.Stderr, "Error loading .env file: %v\n", err) - os.Exit(1) - } - {{end}} -} - -func env(name string) string { - return os.Getenv("YOMO_SFN_" + strings.ToUpper(strings.ReplaceAll(name, "-", "_"))) -} - -func parseZipperAddrs() ([]string, error) { - result := make([]string, 0) - {{if not .UseEnv}} - {{range $addr := .ZipperAddrs}} - result = append(result, "{{$addr}}") - {{end}} - return result, nil - {{else}} - url := env("Url") - if url == "" { - url = "localhost:9000" - } - addrs := strings.Split(url, ",") - for _, addr := range addrs { - addr = strings.TrimSpace(addr) - if len(addr) == 0 { - continue - } - splits := strings.Split(addr, ":") - l := len(splits) - if l == 1 { - result = append(result, splits[0]+":9000") - } else if l == 2 { - port, err := strconv.Atoi(splits[1]) - if err != nil { - return nil, fmt.Errorf("%s: invalid port: %s", addr, splits[1]) - } - result = append(result, fmt.Sprintf("%s:%d", splits[0], port)) - } else { - return nil, fmt.Errorf(`the format of url "%s" is incorrect, it should be "host:port", f.e. localhost:9000`, addr) - } - } - return result, nil - {{end}} -} diff --git a/cli/serverless/golang/templates/wasm_main.tmpl b/cli/serverless/golang/templates/wasi_main.tmpl similarity index 100% rename from cli/serverless/golang/templates/wasm_main.tmpl rename to cli/serverless/golang/templates/wasi_main.tmpl diff --git a/cli/serverless/options.go b/cli/serverless/options.go index 9874a6783..1455905fa 100644 --- a/cli/serverless/options.go +++ b/cli/serverless/options.go @@ -14,6 +14,6 @@ type Options struct { Credential string // Runtime specifies the serverless runtime environment type Runtime string - // use environment variables - UseEnv bool + // WASI build with WASI target + WASI bool } diff --git a/cli/serverless/serverless.go b/cli/serverless/serverless.go index 63cc8e5e5..865fe21ec 100644 --- a/cli/serverless/serverless.go +++ b/cli/serverless/serverless.go @@ -4,6 +4,9 @@ import ( "fmt" "path/filepath" "sync" + + "github.com/joho/godotenv" + "github.com/yomorun/yomo/pkg/file" ) var ( @@ -22,6 +25,7 @@ type Serverless interface { // Run compiles and runs the serverless Run(verbose bool) error + // Executable returns true if the serverless is executable Executable() bool } @@ -40,6 +44,15 @@ func Register(s Serverless, exts ...string) { } } +// LoadEnvFile loads the environment variables from the file +func LoadEnvFile(envDir string) error { + envFile := filepath.Join(envDir, ".env") + if file.Exists(envFile) { + return godotenv.Load(envFile) + } + return nil +} + // Create returns a new serverless instance with options. func Create(opts *Options) (Serverless, error) { ext := filepath.Ext(opts.Filename) diff --git a/cli/serverless/wasm/wazero.go b/cli/serverless/wasm/wazero.go index 4245a2d71..9ab12baed 100644 --- a/cli/serverless/wasm/wazero.go +++ b/cli/serverless/wasm/wazero.go @@ -8,6 +8,7 @@ import ( "log" "os" "strings" + "sync" "github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero/api" @@ -29,6 +30,7 @@ type wazeroRuntime struct { observed []uint32 wanted string serverlessCtx serverless.Context + mu sync.Mutex } func newWazeroRuntime() (*wazeroRuntime, error) { @@ -152,6 +154,8 @@ func (r *wazeroRuntime) GetWantedTarget() string { // RunHandler runs the wasm application (request -> response mode) func (r *wazeroRuntime) RunHandler(ctx serverless.Context) error { + r.mu.Lock() + defer r.mu.Unlock() // context select { case <-r.ctx.Done(): @@ -173,6 +177,8 @@ func (r *wazeroRuntime) RunHandler(ctx serverless.Context) error { // Close releases all the resources related to the runtime func (r *wazeroRuntime) Close() error { + r.mu.Lock() + defer r.mu.Unlock() r.cache.Close(r.ctx) return r.Runtime.Close(r.ctx) } @@ -238,6 +244,7 @@ func (r *wazeroRuntime) write(ctx context.Context, m api.Module, stack []uint64) } stack[0] = 0 } + func (r *wazeroRuntime) writeWithTarget(ctx context.Context, m api.Module, stack []uint64) { tag := uint32(stack[0]) diff --git a/cli/test.go b/cli/test.go index f6c5b3956..2cc9757ed 100644 --- a/cli/test.go +++ b/cli/test.go @@ -31,6 +31,7 @@ import ( "github.com/shirou/gopsutil/v3/process" "github.com/spf13/cobra" "github.com/yomorun/yomo/ai" + "github.com/yomorun/yomo/cli/serverless" "github.com/yomorun/yomo/pkg/log" ) @@ -54,29 +55,28 @@ var testPromptCmd = &cobra.Command{ sfnDir = append(sfnDir, ".") } for _, dir := range sfnDir { + dir, err := filepath.Abs(dir) + if err != nil { + log.FailureStatusEvent(os.Stdout, "Failed to get absolute path of sfn directory: %v", err) + continue + } // run sfn log.InfoStatusEvent(os.Stdout, "--------------------------------------------------------") log.InfoStatusEvent(os.Stdout, "Attaching LLM function in directory: %v", dir) // build - cmd := exec.Command("go", "build", "-o", "sfn.bin", ".") - cmd.Dir = dir - cmd.Env = os.Environ() - if err := cmd.Run(); err != nil { - log.FailureStatusEvent(os.Stdout, "Failed to build LLM function in directory: %v, error: %v", dir, err) - continue - } - log.InfoStatusEvent(os.Stdout, "Build LLM function success") - // remove sfn.bin - sfnBin, err := filepath.Abs(filepath.Join(dir, "sfn.bin")) - if err != nil { - log.FailureStatusEvent(os.Stdout, "Failed to get absolute path of sfn.bin: %v", err) - continue - } + sfnSource := filepath.Join(dir, "app.go") + buildCmd.Run(nil, []string{sfnSource}) + sfnBin := filepath.Join(dir, "sfn.yomo") defer os.RemoveAll(sfnBin) // run - cmd = exec.Command(sfnBin) + cmd := exec.Command(sfnBin) cmd.Dir = dir + err = serverless.LoadEnvFile(dir) + if err != nil { + log.FailureStatusEvent(os.Stdout, "Failed to load env file in directory: %v, error: %v", dir, err) + continue + } env := append(os.Environ(), "YOMO_LOG_LEVEL=info") cmd.Env = env stdout, err := cmd.StdoutPipe() @@ -116,7 +116,7 @@ var testPromptCmd = &cobra.Command{ log.InfoStatusEvent(os.Stdout, "Register LLM function success") goto REQUEST } - case <-time.After(5 * time.Second): + case <-time.After(15 * time.Second): log.FailureStatusEvent(os.Stdout, "Connect to zipper failed, please check the zipper is running or not") os.Exit(1) } @@ -235,6 +235,4 @@ func init() { "system prompt", ) testPromptCmd.Flags().StringVarP(&aiServerAddr, "ai-server", "a", "http://localhost:8000", "LLM API server address") - - runViper = bindViper(testPromptCmd) } diff --git a/cli/viper/viper.go b/cli/viper/viper.go new file mode 100644 index 000000000..b145d1d52 --- /dev/null +++ b/cli/viper/viper.go @@ -0,0 +1,23 @@ +package viper + +import ( + "strings" + + "github.com/spf13/pflag" + "github.com/spf13/viper" +) + +var ( + RunViper = viper.New() + DevViper = viper.New() + BuildViper = viper.New() +) + +func BindPFlags(v *viper.Viper, flags *pflag.FlagSet) { + // bind environment variables + // v.AllowEmptyEnv(true) + v.SetEnvPrefix("YOMO_SFN") + v.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + v.BindPFlags(flags) + v.AutomaticEnv() +} diff --git a/example/10-ai/README.md b/example/10-ai/README.md index c5b73422d..013f93b74 100644 --- a/example/10-ai/README.md +++ b/example/10-ai/README.md @@ -9,15 +9,15 @@ ## Step 2: Start sfn ```bash -cd llm-sfn-timezone-calculator && go run main.go +cd llm-sfn-timezone-calculator && yomo run app.go ``` ```bash -cd llm-sfn-currency-converter && go run main.go +cd llm-sfn-currency-converter && yomo run app.go ``` ```bash -cd llm-sfn-get-ip-and-latency && go run main.go +cd llm-sfn-get-ip-and-latency && yomo run app.go ``` diff --git a/example/10-ai/llm-sfn-currency-converter/.env b/example/10-ai/llm-sfn-currency-converter/.env new file mode 100644 index 000000000..1dcace228 --- /dev/null +++ b/example/10-ai/llm-sfn-currency-converter/.env @@ -0,0 +1,4 @@ +API_KEY=[openexchangerates.org api key] +YOMO_SFN_NAME=fn-exchange-rates +YOMO_SFN_ZIPPER=localhost:9000 +YOMO_SFN_CREDENTIAL=token:Happy New Year diff --git a/example/10-ai/llm-sfn-currency-converter/.env.example b/example/10-ai/llm-sfn-currency-converter/.env.example deleted file mode 100644 index fdedc452f..000000000 --- a/example/10-ai/llm-sfn-currency-converter/.env.example +++ /dev/null @@ -1 +0,0 @@ -API_KEY=[openexchangerates.org api key] \ No newline at end of file diff --git a/example/10-ai/llm-sfn-currency-converter/main.go b/example/10-ai/llm-sfn-currency-converter/app.go similarity index 75% rename from example/10-ai/llm-sfn-currency-converter/main.go rename to example/10-ai/llm-sfn-currency-converter/app.go index 75cd5c372..8cd2d250a 100644 --- a/example/10-ai/llm-sfn-currency-converter/main.go +++ b/example/10-ai/llm-sfn-currency-converter/app.go @@ -4,13 +4,10 @@ import ( "encoding/json" "fmt" "io" - "log" "log/slog" "net/http" "os" - "github.com/joho/godotenv" - "github.com/yomorun/yomo" "github.com/yomorun/yomo/ai" "github.com/yomorun/yomo/serverless" ) @@ -29,35 +26,7 @@ func InputSchema() any { return &Parameter{} } -func main() { - sfn := yomo.NewStreamFunction( - "fn-exchange-rates", - "localhost:9000", - yomo.WithSfnCredential("token:Happy New Year"), - yomo.WithSfnAIFunctionDefinition(Description(), InputSchema()), - ) - defer sfn.Close() - - sfn.SetObserveDataTags(0x10) - - // start - err := sfn.Connect() - if err != nil { - slog.Error("[sfn] connect", "err", err) - os.Exit(1) - } - - sfn.SetHandler(handler) - - // set the error handler function when server error occurs - sfn.SetErrorHandler(func(err error) { - slog.Error("[sfn] receive server error", "err", err) - }) - - sfn.Wait() -} - -func handler(ctx serverless.Context) { +func Handler(ctx serverless.Context) { slog.Info("[sfn] receive", "ctx.data", string(ctx.Data())) fcCtx, err := ai.ParseFunctionCallContext(ctx) @@ -90,22 +59,13 @@ func handler(ctx serverless.Context) { } err = fcCtx.Write(result) - if err != nil { slog.Error("[sfn] >> write error", "err", err) } } -func init() { - // if API_KEY is absent in ENV, read from .env - if _, ok := os.LookupEnv("API_KEY"); !ok { - // read API_KEY from .env - err := godotenv.Load() - if err != nil { - log.Fatal("Error loading .env file") - os.Exit(-1) - } - } +func DataTags() []uint32 { + return []uint32{0x10} } type Rates struct { diff --git a/example/10-ai/llm-sfn-currency-converter/main_test.go b/example/10-ai/llm-sfn-currency-converter/app_test.go similarity index 100% rename from example/10-ai/llm-sfn-currency-converter/main_test.go rename to example/10-ai/llm-sfn-currency-converter/app_test.go diff --git a/example/10-ai/llm-sfn-get-ip-and-latency/.env b/example/10-ai/llm-sfn-get-ip-and-latency/.env new file mode 100644 index 000000000..6eecb259d --- /dev/null +++ b/example/10-ai/llm-sfn-get-ip-and-latency/.env @@ -0,0 +1,4 @@ +YOMO_SFN_NAME=fn-get-ip-and-latency +YOMO_SFN_ZIPPER=localhost:9000 +YOMO_SFN_CREDENTIAL=token:Happy New Year +YOMO_SFN_MODFILE=go.mod diff --git a/example/10-ai/llm-sfn-get-ip-and-latency/main.go b/example/10-ai/llm-sfn-get-ip-and-latency/app.go similarity index 72% rename from example/10-ai/llm-sfn-get-ip-and-latency/main.go rename to example/10-ai/llm-sfn-get-ip-and-latency/app.go index c51fda3ce..9efd5bbce 100644 --- a/example/10-ai/llm-sfn-get-ip-and-latency/main.go +++ b/example/10-ai/llm-sfn-get-ip-and-latency/app.go @@ -4,9 +4,7 @@ import ( "fmt" "log/slog" "net" - "os" - "github.com/yomorun/yomo" "github.com/yomorun/yomo/ai" "github.com/yomorun/yomo/serverless" @@ -25,35 +23,7 @@ func InputSchema() any { return &Parameter{} } -func main() { - sfn := yomo.NewStreamFunction( - "fn-get-ip-and-latency", - "localhost:9000", - yomo.WithSfnCredential("token:Happy New Year"), - yomo.WithSfnAIFunctionDefinition(Description(), InputSchema()), - ) - defer sfn.Close() - - sfn.SetObserveDataTags(0x10) - - // start - err := sfn.Connect() - if err != nil { - slog.Error("[sfn] connect", "err", err) - os.Exit(1) - } - - sfn.SetHandler(handler) - - // set the error handler function when server error occurs - sfn.SetErrorHandler(func(err error) { - slog.Error("[sfn] receive server error", "err", err) - }) - - sfn.Wait() -} - -func handler(ctx serverless.Context) { +func Handler(ctx serverless.Context) { fc, err := ai.ParseFunctionCallContext(ctx) if err != nil { slog.Error("[sfn] parse function call context", "err", err) @@ -102,3 +72,7 @@ func handler(ctx serverless.Context) { fc.Write(val) } + +func DataTags() []uint32 { + return []uint32{0x10} +} diff --git a/example/10-ai/llm-sfn-get-ip-and-latency/go.mod b/example/10-ai/llm-sfn-get-ip-and-latency/go.mod index f3057f921..5e1944b47 100644 --- a/example/10-ai/llm-sfn-get-ip-and-latency/go.mod +++ b/example/10-ai/llm-sfn-get-ip-and-latency/go.mod @@ -10,49 +10,11 @@ require ( replace github.com/yomorun/yomo => ../../.../../../ require ( - github.com/bahlo/generic-list-go v0.2.0 // indirect - github.com/buger/jsonparser v1.1.1 // indirect github.com/caarlos0/env/v6 v6.10.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/francoispqt/gojay v1.2.13 // indirect - github.com/go-logr/logr v1.4.1 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/google/uuid v1.4.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect - github.com/invopop/jsonschema v0.12.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/matoous/go-nanoid/v2 v2.0.0 // indirect - github.com/onsi/ginkgo/v2 v2.9.5 // indirect - github.com/quic-go/quic-go v0.42.0 // indirect - github.com/robfig/cron/v3 v3.0.1 // indirect github.com/sashabaranov/go-openai v1.23.0 // indirect - github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect - github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect - github.com/yomorun/y3 v1.0.5 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect - go.opentelemetry.io/proto/otlp v1.1.0 // indirect - go.uber.org/mock v0.4.0 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect - golang.org/x/mod v0.16.0 // indirect golang.org/x/net v0.22.0 // indirect golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.19.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/grpc v1.61.1 // indirect - google.golang.org/protobuf v1.32.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/example/10-ai/llm-sfn-get-ip-and-latency/go.sum b/example/10-ai/llm-sfn-get-ip-and-latency/go.sum index 1cedb7b3e..05686abb5 100644 --- a/example/10-ai/llm-sfn-get-ip-and-latency/go.sum +++ b/example/10-ai/llm-sfn-get-ip-and-latency/go.sum @@ -1,300 +1,32 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= -dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= -dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= -dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= -dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= -git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= -github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= -github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/caarlos0/env/v6 v6.10.1 h1:t1mPSxNpei6M5yAeu1qtRdPAK29Nbcf/n3G7x+b3/II= github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= -github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw= github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= -github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= -github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= -github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matoous/go-nanoid v1.5.0/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U= -github.com/matoous/go-nanoid/v2 v2.0.0 h1:d19kur2QuLeHmJBkvYkFdhFBzLoo1XVm2GgTpL+9Tj0= -github.com/matoous/go-nanoid/v2 v2.0.0/go.mod h1:FtS4aGPVfEkxKxhdWPAspZpZSh1cOjtM7Ej/So3hR0g= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= -github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= -github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM= -github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= -github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sashabaranov/go-openai v1.23.0 h1:KYW97r5yc35PI2MxeLZ3OofecB/6H+yxvSNqiT9u8is= github.com/sashabaranov/go-openai v1.23.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= -github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= -github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= -github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= -github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= -github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= -github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= -github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= -github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= -github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= -github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= -github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= -github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= -github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= -github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= -github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= -github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= -github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= -github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= -github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= -github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= -github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= -github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= -github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= -github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= -github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= -github.com/yomorun/y3 v1.0.5 h1:1qoZrDX+47hgU2pVJgoCEpeeXEOqml/do5oHjF9Wef4= -github.com/yomorun/y3 v1.0.5/go.mod h1:+zwvZrKHe8D3fTMXNTsUsZXuI+kYxv3LRA2fSJEoWbo= -go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= -go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= -golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= -golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= -google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 h1:YJ5pD9rF8o9Qtta0Cmy9rdBwkSjrTCT6XTiUQVOtIos= -google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY= -google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= -sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/example/10-ai/llm-sfn-get-weather/.env b/example/10-ai/llm-sfn-get-weather/.env new file mode 100644 index 000000000..900c0e1ee --- /dev/null +++ b/example/10-ai/llm-sfn-get-weather/.env @@ -0,0 +1,3 @@ +YOMO_SFN_NAME=get-weather +YOMO_SFN_ZIPPER=localhost:9000 +YOMO_SFN_CREDENTIAL=token:Happy New Year diff --git a/example/10-ai/llm-sfn-get-weather/main.go b/example/10-ai/llm-sfn-get-weather/app.go similarity index 55% rename from example/10-ai/llm-sfn-get-weather/main.go rename to example/10-ai/llm-sfn-get-weather/app.go index 433461320..243a1cd21 100644 --- a/example/10-ai/llm-sfn-get-weather/main.go +++ b/example/10-ai/llm-sfn-get-weather/app.go @@ -6,23 +6,16 @@ import ( "math/rand" "os" - "github.com/yomorun/yomo" "github.com/yomorun/yomo/ai" "github.com/yomorun/yomo/serverless" ) -var ( - name = "get-weather" - addr = "localhost:9000" - tag uint32 = 0x11 - credential = "token:Happy New Year" -) +var tag uint32 = 0x11 type Parameter struct { CityName string `json:"city_name" jsonschema:"description=The name of the city to be queried"` } -// ================== AI Required ================== // Description returns the description of this AI function. func Description() string { return "Get the current weather for `city_name`" @@ -33,39 +26,7 @@ func InputSchema() any { return &Parameter{} } -// ================== main ================== - -func main() { - sfn := yomo.NewStreamFunction( - name, - addr, - yomo.WithSfnCredential(credential), - yomo.WithSfnAIFunctionDefinition(Description(), InputSchema()), - ) - sfn.SetObserveDataTags(tag) - defer sfn.Close() - - // set handler - sfn.SetHandler(handler) - - // sfn.SetWantedTarget(peerID) - - // start - err := sfn.Connect() - if err != nil { - slog.Error("[sfn] connect", "err", err) - os.Exit(1) - } - - // set the error handler function when server error occurs - sfn.SetErrorHandler(func(err error) { - slog.Error("[sfn] receive server error", "err", err) - }) - - sfn.Wait() -} - -func handler(ctx serverless.Context) { +func Handler(ctx serverless.Context) { slog.Info("[sfn] receive", "ctx.data", string(ctx.Data())) fcCtx, err := ai.ParseFunctionCallContext(ctx) @@ -88,3 +49,7 @@ func handler(ctx serverless.Context) { } } } + +func DataTags() []uint32 { + return []uint32{tag} +} diff --git a/example/10-ai/llm-sfn-timezone-calculator/.env b/example/10-ai/llm-sfn-timezone-calculator/.env new file mode 100644 index 000000000..b00ed1d53 --- /dev/null +++ b/example/10-ai/llm-sfn-timezone-calculator/.env @@ -0,0 +1,3 @@ +YOMO_SFN_NAME=fn-timezone-converter +YOMO_SFN_ZIPPER=localhost:9000 +YOMO_SFN_CREDENTIAL=token:Happy New Year diff --git a/example/10-ai/llm-sfn-timezone-calculator/main.go b/example/10-ai/llm-sfn-timezone-calculator/app.go similarity index 84% rename from example/10-ai/llm-sfn-timezone-calculator/main.go rename to example/10-ai/llm-sfn-timezone-calculator/app.go index 3f7f25e6b..9a9b2b563 100644 --- a/example/10-ai/llm-sfn-timezone-calculator/main.go +++ b/example/10-ai/llm-sfn-timezone-calculator/app.go @@ -3,11 +3,9 @@ package main import ( "fmt" "log/slog" - "os" "strings" "time" - "github.com/yomorun/yomo" "github.com/yomorun/yomo/ai" "github.com/yomorun/yomo/serverless" ) @@ -28,35 +26,7 @@ func InputSchema() any { const timeFormat = "2006-01-02 15:04:05" -func main() { - sfn := yomo.NewStreamFunction( - "fn-timezone-converter", - "localhost:9000", - yomo.WithSfnCredential("token:Happy New Year"), - yomo.WithSfnAIFunctionDefinition(Description(), InputSchema()), - ) - defer sfn.Close() - - sfn.SetObserveDataTags(0x12) - - // start - err := sfn.Connect() - if err != nil { - slog.Error("[sfn] connect", "err", err) - os.Exit(1) - } - - sfn.SetHandler(handler) - - // set the error handler function when server error occurs - sfn.SetErrorHandler(func(err error) { - slog.Error("[sfn] receive server error", "err", err) - }) - - sfn.Wait() -} - -func handler(ctx serverless.Context) { +func Handler(ctx serverless.Context) { slog.Info("[sfn] receive", "ctx.data", string(ctx.Data())) fcCtx, err := ai.ParseFunctionCallContext(ctx) @@ -95,6 +65,10 @@ func handler(ctx serverless.Context) { fcCtx.Write(val) } +func DataTags() []uint32 { + return []uint32{0x12} +} + // ConvertTimezone converts the current time from the source timezone to the target timezone. // It returns the converted time as a string in the format "2006-01-02 15:04:05". func ConvertTimezone(timeString, sourceTimezone, targetTimezone string) (string, error) { diff --git a/example/10-ai/llm-sfn-timezone-calculator/main_test.go b/example/10-ai/llm-sfn-timezone-calculator/app_test.go similarity index 100% rename from example/10-ai/llm-sfn-timezone-calculator/main_test.go rename to example/10-ai/llm-sfn-timezone-calculator/app_test.go diff --git a/go.mod b/go.mod index 31f4eccd9..6b4c1bc2b 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 - github.com/tetratelabs/wazero v1.7.0 + github.com/tetratelabs/wazero v1.7.1 github.com/vmihailenco/msgpack/v5 v5.4.1 github.com/yomorun/y3 v1.0.5 go.opentelemetry.io/otel v1.24.0 diff --git a/go.sum b/go.sum index c412d8bfe..b8d26a620 100644 --- a/go.sum +++ b/go.sum @@ -236,8 +236,8 @@ github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSW github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/teivah/onecontext v0.0.0-20200513185103-40f981bfd775 h1:BLNsFR8l/hj/oGjnJXkd4Vi3s4kQD3/3x8HSAE4bzN0= github.com/teivah/onecontext v0.0.0-20200513185103-40f981bfd775/go.mod h1:XUZ4x3oGhWfiOnUvTslnKKs39AWUct3g3yJvXTQSJOQ= -github.com/tetratelabs/wazero v1.7.0 h1:jg5qPydno59wqjpGrHph81lbtHzTrWzwwtD4cD88+hQ= -github.com/tetratelabs/wazero v1.7.0/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y= +github.com/tetratelabs/wazero v1.7.1 h1:QtSfd6KLc41DIMpDYlJdoMc6k7QTN246DM2+n2Y/Dx8= +github.com/tetratelabs/wazero v1.7.1/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= diff --git a/pkg/file/file.go b/pkg/file/file.go index 525602924..0a2992419 100644 --- a/pkg/file/file.go +++ b/pkg/file/file.go @@ -123,7 +123,7 @@ func GetBinContents(path string) []byte { // IsExec check is executable file func IsExec(filename string) bool { ext := strings.ToLower(filepath.Ext(filename)) - if ext == ".yomo" || ext == ".exe" { + if ext == ".yomo" || ext == ".exe" || ext == ".wasm" { return true } return false diff --git a/sfn.go b/sfn.go index 44790674d..f18f360c3 100644 --- a/sfn.go +++ b/sfn.go @@ -90,7 +90,6 @@ type streamFunction struct { func (s *streamFunction) SetWantedTarget(target string) { if target == "" { - s.client.Logger.Warn("set sfn wanted target to an empty string, skip it") return } s.client.SetWantedTarget(target)