diff --git a/cmd/lk/agent.go b/cmd/lk/agent.go index 923170dd3..0a3b4564e 100644 --- a/cmd/lk/agent.go +++ b/cmd/lk/agent.go @@ -39,7 +39,6 @@ import ( "github.com/urfave/cli/v3" "github.com/livekit/livekit-cli/v2/pkg/agentfs" - "github.com/livekit/livekit-cli/v2/pkg/bootstrap" "github.com/livekit/livekit-cli/v2/pkg/config" "github.com/livekit/livekit-cli/v2/pkg/util" lkproto "github.com/livekit/protocol/livekit" @@ -240,36 +239,24 @@ On LiveKit Cloud: "create" and "deploy" ship it, then "status", "logs", return createAgentClientWithOpts(ctx, cmd, confirmProject) }, Action: initAgent, - MutuallyExclusiveFlags: []cli.MutuallyExclusiveFlags{{ - Flags: [][]cli.Flag{{ - &cli.StringFlag{ - Name: "lang", - Usage: "`LANGUAGE` of the starter template, one of \"python\", \"node\".", - Action: func(ctx context.Context, cmd *cli.Command, l string) error { - if _, ok := starterTemplateURLs[l]; !ok { - return fmt.Errorf("unsupported language: %s", l) - } - return nil - }, - }, - &cli.BoolFlag{ - Name: "deploy", - Usage: "If set, automatically deploys the agent to LiveKit Cloud after initialization.", - Value: false, - }, - templateFlag, - templateURLFlag, - }, { - sandboxFlag, - &cli.BoolFlag{ - Name: "no-sandbox", - Usage: "If set, will not create a sandbox for the project.", - Value: true, - Hidden: true, - }, - }}, - }}, Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "lang", + Usage: "`LANGUAGE` of the starter template, one of \"python\", \"node\".", + Action: func(ctx context.Context, cmd *cli.Command, l string) error { + if _, ok := starterTemplateURLs[l]; !ok { + return fmt.Errorf("unsupported language: %s", l) + } + return nil + }, + }, + &cli.BoolFlag{ + Name: "deploy", + Usage: "If set, automatically deploys the agent to LiveKit Cloud after initialization.", + Value: false, + }, + templateFlag, + templateURLFlag, regionFlag, installFlag, skillsSetupFlag, @@ -613,38 +600,6 @@ func initAgent(ctx context.Context, cmd *cli.Command) error { appName = project.Name } - // Create sandbox only when not disabled by flag and we don't already have one - if !cmd.Bool("no-sandbox") && sandboxID == "" { - if err := out.Await("Creating sandbox app...", ctx, func(ctx context.Context) error { - token, err := requireToken(ctx, cmd) - if err != nil { - return err - } - - // TODO: (@rektdeckard) figure out why AccessKeyProvider does not immediately - // have access to newly-created API keys, then remove this sleep - time.Sleep(4 * time.Second) - sandboxID, err = bootstrap.CreateSandbox( - ctx, - appName, - // NOTE: we may want to support embed sandbox in the future - "https://github.com/livekit-examples/agent-starter-react", - token, - serverURL, - ) - - // We set sandbox ID in env for use in template tasks - os.Setenv("LIVEKIT_SANDBOX_ID", sandboxID) - - return err - }); err != nil { - return fmt.Errorf("failed to create sandbox: %w", err) - } else { - out.Status("Creating sandbox app...") - out.Statusf("Created sandbox app [%s]", util.Accented(sandboxID)) - } - } - // Run template bootstrap shouldDeploy := cmd.Bool("deploy") if shouldDeploy { diff --git a/cmd/lk/app.go b/cmd/lk/app.go index 487ee1002..42b58a52e 100644 --- a/cmd/lk/app.go +++ b/cmd/lk/app.go @@ -42,7 +42,6 @@ var ( template *bootstrap.Template templateName string templateURL string - sandboxID string appName string appNameRegex = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_-]*$`) destinationFile string @@ -63,7 +62,6 @@ var ( Flags: []cli.Flag{ templateFlag, templateURLFlag, - sandboxFlag, installFlag, }, }, @@ -291,10 +289,8 @@ func setupTemplate(ctx context.Context, cmd *cli.Command) error { func setupTemplateWith(ctx context.Context, cmd *cli.Command, afterInstall func(ctx context.Context, cmd *cli.Command, dir string) error) error { verbose := cmd.Bool("verbose") install := cmd.Bool("install") - isSandbox := sandboxID != "" var preinstallPrompts []huh.Field - var templateOptions []bootstrap.Template if templateName != "" && templateURL != "" { return errors.New("only one of template or template-url can be specified") @@ -304,31 +300,9 @@ func setupTemplateWith(ctx context.Context, cmd *cli.Command, afterInstall func( return errors.New("non-interactive mode: set --template or --template-url") } - if isSandbox { - _, err := requireAppProject(ctx, cmd) - if err != nil { - return err - } - token, err := requireToken(ctx, cmd) - if err != nil { - return err - } - if templateURL == "" { - details, err := bootstrap.FetchSandboxDetails(ctx, sandboxID, token, serverURL) - if err != nil { - return err - } - if len(details.ChildTemplates) == 0 { - return errors.New("no child templates found for sandbox") - } - templateOptions = details.ChildTemplates - } - } else { - var err error - templateOptions, err = bootstrap.FetchTemplates(ctx) - if err != nil { - return err - } + templateOptions, err := bootstrap.FetchTemplates(ctx) + if err != nil { + return err } // if no template name or URL is specified, prompt user to choose from available templates @@ -418,10 +392,6 @@ func setupTemplateWith(ctx context.Context, cmd *cli.Command, afterInstall func( } out.Status("Instantiating environment...") - addlEnv := &map[string]string{ - "LIVEKIT_SANDBOX_ID": sandboxID, - "NEXT_PUBLIC_LIVEKIT_SANDBOX_ID": sandboxID, - } envOutputFile := ".env.local" envExampleFile := ".env.example" if tf != nil { @@ -436,7 +406,7 @@ func setupTemplateWith(ctx context.Context, cmd *cli.Command, afterInstall func( } } } - env, err := instantiateEnv(ctx, cmd, appName, addlEnv, envExampleFile, nil) + env, err := instantiateEnv(ctx, cmd, appName, nil, envExampleFile, nil) if err != nil { return err } diff --git a/cmd/lk/app_credentials.go b/cmd/lk/app_credentials.go index d6cd37e01..d8a951049 100644 --- a/cmd/lk/app_credentials.go +++ b/cmd/lk/app_credentials.go @@ -31,9 +31,9 @@ import ( // // Session tokens cover the CLI's own calls, but an app or agent runs on its own // and needs a real API key. Commands that write credentials into an app -// (`lk app create`, `lk app env`, `lk agent init`) or sign with the secret -// themselves (sandbox tokens) call ensureProjectAPIKey, which reuses a key -// already in the app's env files or generates a service-account key. +// (`lk app create`, `lk app env`, `lk agent init`) call ensureProjectAPIKey, +// which reuses a key already in the app's env files or generates a +// service-account key. // Commands that run an agent (`lk agent dev`, `start`, the debugger) only ever // read the key from the agent's env files (agentEnvCredentials): running an // agent never creates a key. @@ -93,7 +93,7 @@ func agentEnvCredentials(ctx context.Context, cmd *cli.Command, dir string) (age } // ensureProjectAPIKey gives a session project real API credentials, for -// commands that write them into an app in dir or sign with the secret. It +// commands that write them into an app in dir. It // reuses a key for the same project already in one of dir's envFiles, and // otherwise generates a service-account key, which outlives the user's // membership in the project. A project loaded with an API key is left alone. diff --git a/cmd/lk/cloud.go b/cmd/lk/cloud.go index 558070bea..2b43ea37e 100644 --- a/cmd/lk/cloud.go +++ b/cmd/lk/cloud.go @@ -314,15 +314,6 @@ func handleAuth(ctx context.Context, cmd *cli.Command) error { } func requireToken(ctx context.Context, cmd *cli.Command) (string, error) { - if experimentalAuthEnabled(cmd) { - if _, err := requireProjectForSDK(ctx, cmd); err != nil { - return "", err - } - // The identity below is derived from the secret, so this needs a real key. - if err := ensureProjectAPIKey(ctx, cmd, ""); err != nil { - return "", err - } - } if project == nil { var err error project, err = loadProjectDetails(cmd) diff --git a/cmd/lk/utils.go b/cmd/lk/utils.go index 6168a4e94..8c5ef13f0 100644 --- a/cmd/lk/utils.go +++ b/cmd/lk/utils.go @@ -100,12 +100,6 @@ var ( Usage: "`URL` to instantiate, must contain a taskfile.yaml", Destination: &templateURL, } - sandboxFlag = &cli.StringFlag{ - Name: "sandbox", - Usage: "`NAME` of the sandbox, see your cloud dashboard", - Destination: &sandboxID, - Hidden: true, - } installFlag = &cli.BoolFlag{ Name: "install", Usage: "Run installation after creating the application", diff --git a/pkg/bootstrap/bootstrap.go b/pkg/bootstrap/bootstrap.go index 6363b0f7c..e4217b5cf 100644 --- a/pkg/bootstrap/bootstrap.go +++ b/pkg/bootstrap/bootstrap.go @@ -13,14 +13,11 @@ // limitations under the License. // This package defines the configuration file associated with LiveKit -// templates, which include instructions for package setup and development in -// both Playground mode and local dev. +// templates, which include instructions for package setup and local dev. package bootstrap import ( - "bytes" "context" - "encoding/json" "errors" "fmt" "io" @@ -40,18 +37,14 @@ import ( "github.com/joho/godotenv" "gopkg.in/yaml.v3" - authutil "github.com/livekit/livekit-cli/v2/pkg/auth" "github.com/livekit/livekit-cli/v2/pkg/util" ) const ( - TaskFile = "taskfile.yaml" - TemplateIndexFile = "templates.yaml" - TemplateIndexURL = "https://raw.githubusercontent.com/livekit-examples/index/main" - TemplateBaseURL = "https://github.com/livekit-examples" - SandboxDashboardURL = "https://cloud.livekit.io/projects/p_/sandbox" - SandboxTemplateEndpoint = "/api/sandbox/template" - SandboxCreateEndpoint = "/api/sandbox/create" + TaskFile = "taskfile.yaml" + TemplateIndexFile = "templates.yaml" + TemplateIndexURL = "https://raw.githubusercontent.com/livekit-examples/index/main" + TemplateBaseURL = "https://github.com/livekit-examples" ) type KnownTask string @@ -75,22 +68,15 @@ var templateIgnoreFiles = []string{ } type Template struct { - Name string `yaml:"name" json:"name"` - Desc string `yaml:"desc" json:"description,omitempty"` - URL string `yaml:"url" json:"url,omitempty"` - Docs string `yaml:"docs" json:"docs_url,omitempty"` - Image string `yaml:"image" json:"image_ref,omitempty"` - Tags []string `yaml:"tags" json:"tags,omitempty"` - Attrs map[string]string `yaml:"attrs" json:"attrs,omitempty"` - Requires []string `yaml:"requires" json:"requires,omitempty"` - IsSandbox bool `yaml:"is_sandbox" json:"is_sandbox,omitempty"` - IsHidden bool `yaml:"is_hidden" json:"is_hidden,omitempty"` -} - -type SandboxDetails struct { - Name string `json:"name"` - Template Template `json:"template"` - ChildTemplates []Template `json:"childTemplates"` + Name string `yaml:"name" json:"name"` + Desc string `yaml:"desc" json:"description,omitempty"` + URL string `yaml:"url" json:"url,omitempty"` + Docs string `yaml:"docs" json:"docs_url,omitempty"` + Image string `yaml:"image" json:"image_ref,omitempty"` + Tags []string `yaml:"tags" json:"tags,omitempty"` + Attrs map[string]string `yaml:"attrs" json:"attrs,omitempty"` + Requires []string `yaml:"requires" json:"requires,omitempty"` + IsHidden bool `yaml:"is_hidden" json:"is_hidden,omitempty"` } func FetchTemplates(ctx context.Context) ([]Template, error) { @@ -106,76 +92,6 @@ func FetchTemplates(ctx context.Context) ([]Template, error) { return templates, nil } -func CreateSandbox(ctx context.Context, agentName, templateURL, token, serverURL string) (string, error) { - type createSandboxRequest struct { - TemplateURL string `json:"template_url"` - AgentName string `json:"agent_name,omitempty"` - } - - type createSandboxResponse struct { - SandboxID string `json:"sandbox_id"` - } - - body := createSandboxRequest{ - TemplateURL: templateURL, - AgentName: agentName, - } - - buf := new(bytes.Buffer) - if err := json.NewEncoder(buf).Encode(body); err != nil { - panic(err) - } - - req, err := http.NewRequestWithContext(ctx, "POST", serverURL+SandboxCreateEndpoint, buf) - req.Header = authutil.NewHeaderWithToken(token) - if err != nil { - return "", err - } - req.Header.Set("Content-Type", "application/json") - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return "", err - } - if resp.StatusCode != 200 { - return "", errors.New(resp.Status) - } - - var response createSandboxResponse - if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { - return "", err - } - return response.SandboxID, nil -} - -func FetchSandboxDetails(ctx context.Context, sid, token, serverURL string) (*SandboxDetails, error) { - req, err := http.NewRequestWithContext(ctx, "GET", serverURL+SandboxTemplateEndpoint, nil) - req.Header = authutil.NewHeaderWithToken(token) - query := req.URL.Query() - query.Add("id", sid) - req.URL.RawQuery = query.Encode() - if err != nil { - return nil, err - } - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return nil, err - } - if resp.StatusCode == 404 { - return nil, fmt.Errorf("sandbox not found: %s", sid) - } - if resp.StatusCode != 200 { - return nil, errors.New(resp.Status) - } - - var details SandboxDetails - if err := json.NewDecoder(resp.Body).Decode(&details); err != nil { - return nil, err - } - return &details, nil -} - func ParseTaskfile(rootPath string) (*ast.Taskfile, error) { os.Setenv("TASK_X_REMOTE_TASKFILES", "1") experiments.Parse(rootPath)