diff --git a/bridgeconfig/ai.tpl.yaml b/bridgeconfig/ai.tpl.yaml new file mode 100644 index 0000000..002c62d --- /dev/null +++ b/bridgeconfig/ai.tpl.yaml @@ -0,0 +1,26 @@ +network: + beeper: + base_url: {{ .HungryAddress }} + token: {{ .ProvisioningSecret }} + + providers: + beeper: + default_model: "openai/gpt-5.2" + openai: + default_model: "openai/gpt-4o-mini" + openrouter: + default_model: "openrouter/openai/gpt-4o-mini" + + default_system_prompt: | + You are a helpful assistant. + model_cache_duration: 6h + + bridge: + command_prefix: "!ai" + +{{ setfield . "CommandPrefix" "!ai" -}} +{{ setfield . "DatabaseFileName" "ai" -}} +{{ setfield . "BridgeTypeName" "AI" -}} +{{ setfield . "BridgeTypeIcon" "mxc://maunium.net/HPiAFz2uVH54camzatoorkWY" -}} +{{ setfield . "DefaultPickleKey" "go.beeper.ai" -}} +{{ template "bridgev2.tpl.yaml" . }} diff --git a/cmd/bbctl/bridgeutil.go b/cmd/bbctl/bridgeutil.go index 4a7eaf8..1e34981 100644 --- a/cmd/bbctl/bridgeutil.go +++ b/cmd/bbctl/bridgeutil.go @@ -21,6 +21,7 @@ type bridgeTypeToNames struct { } var officialBridges = []bridgeTypeToNames{ + {"ai", []string{"ai"}}, {"discord", []string{"discord"}}, {"meta", []string{"meta", "instagram", "facebook"}}, {"googlechat", []string{"googlechat", "gchat"}}, @@ -49,6 +50,7 @@ var websocketBridges = map[string]bool{ "imessagego": true, "signal": true, "bridgev2": true, + "ai": true, "meta": true, "twitter": true, "bluesky": true, diff --git a/cmd/bbctl/run.go b/cmd/bbctl/run.go index 408c28f..2f93094 100644 --- a/cmd/bbctl/run.go +++ b/cmd/bbctl/run.go @@ -134,6 +134,8 @@ func compileGoBridge(ctx context.Context, buildDir, binaryPath, bridgeType strin repo := fmt.Sprintf("https://github.com/mautrix/%s.git", bridgeType) if bridgeType == "imessagego" { repo = "https://github.com/beeper/imessage.git" + } else if bridgeType == "ai" { + repo = "https://github.com/beeper/ai-bridge.git" } log.Printf("Cloning [cyan]%s[reset] to [cyan]%s[reset]", repo, buildDir) err = makeCmd(ctx, buildDirParent, "git", "clone", repo, buildDir).Run() @@ -367,6 +369,29 @@ func runBridge(ctx *cli.Context) error { } heisenHomeserverURL := strings.Replace(cfg.HomeserverURL, "https://", "wss://", 1) bridgeArgs = []string{"-m", "heisenbridge", "-c", configFileName, "-o", cfg.YourUserID.String(), heisenHomeserverURL} + case "ai": + if !localDev && !compile && overrideBridgeCmd == "" { + return UserError{"AI bridge binaries are not available in CI. Use --local-dev or --compile mode."} + } + binaryName := "ai" + bridgeCmd = filepath.Join(dataDir, "binaries", binaryName) + if localDev && overrideBridgeCmd == "" { + bridgeCmd = filepath.Join(bridgeDir, binaryName) + buildScript := "./build.sh" + log.Printf("Compiling [cyan]%s[reset] with %s", binaryName, buildScript) + err = makeCmd(ctx.Context, bridgeDir, buildScript).Run() + if err != nil { + return fmt.Errorf("failed to compile bridge: %w", err) + } + } else if compile && overrideBridgeCmd == "" { + buildDir := filepath.Join(dataDir, "compile", binaryName) + bridgeCmd = filepath.Join(buildDir, binaryName) + err = compileGoBridge(ctx.Context, buildDir, bridgeCmd, "ai", ctx.Bool("no-update")) + if err != nil { + return fmt.Errorf("failed to compile bridge: %w", err) + } + } + bridgeArgs = []string{"-c", configFileName} default: if overrideBridgeCmd == "" { return UserError{"Unsupported bridge type for bbctl run"}