| 385 | ) |
| 386 | |
| 387 | func CreateServerCmd() *cobra.Command { |
| 388 | serverCmd := &cobra.Command{ |
| 389 | Use: "server [agent]", |
| 390 | Short: "Run the server", |
| 391 | Long: fmt.Sprintf("Run the server with the specified agent (one of: %s)", strings.Join(agentNames, ", ")), |
| 392 | Args: cobra.MinimumNArgs(1), |
| 393 | Run: func(cmd *cobra.Command, args []string) { |
| 394 | // The --exit flag is used for testing validation of flags in the test suite |
| 395 | if viper.GetBool(FlagExit) { |
| 396 | return |
| 397 | } |
| 398 | logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) |
| 399 | if viper.GetBool(FlagPrintOpenAPI) { |
| 400 | // We don't want log output here. |
| 401 | logger = slog.New(logctx.DiscardHandler) |
| 402 | } |
| 403 | ctx := logctx.WithLogger(context.Background(), logger) |
| 404 | if err := runServer(ctx, logger, cmd.Flags().Args()); err != nil { |
| 405 | fmt.Fprintf(os.Stderr, "%+v\n", err) |
| 406 | os.Exit(1) |
| 407 | } |
| 408 | }, |
| 409 | } |
| 410 | |
| 411 | flagSpecs := []flagSpec{ |
| 412 | {FlagType, "t", "", fmt.Sprintf("Override the agent type (one of: %s, custom)", strings.Join(agentNames, ", ")), "string"}, |
| 413 | {FlagPort, "p", 3284, "Port to run the server on", "int"}, |
| 414 | {FlagPrintOpenAPI, "P", false, "Print the OpenAPI schema to stdout and exit", "bool"}, |
| 415 | {FlagChatBasePath, "c", "/chat", "Base path for assets and routes used in the static files of the chat interface", "string"}, |
| 416 | {FlagTermWidth, "W", uint16(80), "Width of the emulated terminal", "uint16"}, |
| 417 | {FlagTermHeight, "H", uint16(1000), "Height of the emulated terminal", "uint16"}, |
| 418 | // localhost is the default host for the server. Port is ignored during matching. |
| 419 | {FlagAllowedHosts, "a", []string{"localhost", "127.0.0.1", "[::1]"}, "HTTP allowed hosts (hostnames only, no ports). Use '*' for all, comma-separated list via flag, space-separated list via AGENTAPI_ALLOWED_HOSTS env var", "stringSlice"}, |
| 420 | // localhost:3284 is the default origin when you open the chat interface in your browser. localhost:3000 and 3001 are used during development. |
| 421 | {FlagAllowedOrigins, "o", []string{"http://localhost:3284", "http://localhost:3000", "http://localhost:3001"}, "HTTP allowed origins. Use '*' for all, comma-separated list via flag, space-separated list via AGENTAPI_ALLOWED_ORIGINS env var", "stringSlice"}, |
| 422 | {FlagInitialPrompt, "I", "", "Initial prompt for the agent. Recommended only if the agent doesn't support initial prompt in interaction mode. Will be read from stdin if piped (e.g., echo 'prompt' | agentapi server -- my-agent)", "string"}, |
| 423 | {FlagStateFile, "s", "", "Path to file for saving/loading server state", "string"}, |
| 424 | {FlagLoadState, "", false, "Load state from state-file on startup (defaults to true when state-file is set)", "bool"}, |
| 425 | {FlagSaveState, "", false, "Save state to state-file on shutdown (defaults to true when state-file is set)", "bool"}, |
| 426 | {FlagPidFile, "", "", "Path to file where the server process ID will be written for shutdown scripts", "string"}, |
| 427 | {FlagExperimentalACP, "", false, "Use experimental ACP transport instead of PTY", "bool"}, |
| 428 | } |
| 429 | |
| 430 | for _, spec := range flagSpecs { |
| 431 | switch spec.flagType { |
| 432 | case "string": |
| 433 | serverCmd.Flags().StringP(spec.name, spec.shorthand, spec.defaultValue.(string), spec.usage) |
| 434 | case "int": |
| 435 | serverCmd.Flags().IntP(spec.name, spec.shorthand, spec.defaultValue.(int), spec.usage) |
| 436 | case "bool": |
| 437 | serverCmd.Flags().BoolP(spec.name, spec.shorthand, spec.defaultValue.(bool), spec.usage) |
| 438 | case "uint16": |
| 439 | serverCmd.Flags().Uint16P(spec.name, spec.shorthand, spec.defaultValue.(uint16), spec.usage) |
| 440 | case "stringSlice": |
| 441 | serverCmd.Flags().StringSliceP(spec.name, spec.shorthand, spec.defaultValue.([]string), spec.usage) |
| 442 | default: |
| 443 | panic(fmt.Sprintf("unknown flag type: %s", spec.flagType)) |
| 444 | } |