Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 19 additions & 16 deletions cmd/tapes/chat/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
)

type chatCommander struct {
flags config.FlagSet

proxyTarget string
apiTarget string
model string
Expand Down Expand Up @@ -59,6 +61,11 @@ type ollamaStreamChunk struct {
Done bool `json:"done"`
}

var chatFlags = config.FlagSet{
config.FlagAPITarget: {Name: "api-target", Shorthand: "a", ViperKey: "client.api_target", Description: "Tapes API server URL"},
config.FlagProxyTarget: {Name: "proxy-target", Shorthand: "p", ViperKey: "client.proxy_target", Description: "Tapes proxy URL"},
}

const chatLongDesc string = `Experimental: Start an interactive chat session through the tapes proxy.

The chat command sends messages to an LLM through the configured tapes proxy,
Expand All @@ -79,31 +86,28 @@ Examples:
const chatShortDesc string = "Experimental: Interactive LLM chat through the tapes proxy"

func NewChatCmd() *cobra.Command {
cmder := &chatCommander{}
cmder := &chatCommander{
flags: chatFlags,
}

cmd := &cobra.Command{
Use: "chat",
Short: chatShortDesc,
Long: chatLongDesc,
PreRunE: func(cmd *cobra.Command, _ []string) error {
configDir, _ := cmd.Flags().GetString("config-dir")
cfger, err := config.NewConfiger(configDir)
v, err := config.InitViper(configDir)
if err != nil {
return fmt.Errorf("loading config: %w", err)
}

cfg, err := cfger.LoadConfig()
if err != nil {
return fmt.Errorf("loading config: %w", err)
}

if !cmd.Flags().Changed("api-target") {
cmder.apiTarget = cfg.Client.APITarget
}
config.BindRegisteredFlags(v, cmd, cmder.flags, []string{
config.FlagAPITarget,
config.FlagProxyTarget,
})

if !cmd.Flags().Changed("proxy-target") {
cmder.proxyTarget = cfg.Client.ProxyTarget
}
cmder.apiTarget = v.GetString("client.api_target")
cmder.proxyTarget = v.GetString("client.proxy_target")
return nil
},
RunE: func(cmd *cobra.Command, _ []string) error {
Expand All @@ -117,9 +121,8 @@ func NewChatCmd() *cobra.Command {
},
}

defaults := config.NewDefaultConfig()
cmd.Flags().StringVarP(&cmder.apiTarget, "api-target", "a", defaults.Client.APITarget, "Tapes API server URL")
cmd.Flags().StringVarP(&cmder.proxyTarget, "proxy-target", "p", defaults.Client.ProxyTarget, "Tapes proxy URL")
config.AddStringFlag(cmd, cmder.flags, config.FlagAPITarget, &cmder.apiTarget)
config.AddStringFlag(cmd, cmder.flags, config.FlagProxyTarget, &cmder.proxyTarget)
cmd.Flags().StringVarP(&cmder.model, "model", "m", "gemma3:latest", "Model name (e.g., gemma3:1b, ministral-3:latest)")

return cmd
Expand Down
26 changes: 15 additions & 11 deletions cmd/tapes/checkout/checkout.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import (
)

type checkoutCommander struct {
flags config.FlagSet

hash string
apiTarget string
debug bool
Expand All @@ -48,6 +50,10 @@ type historyMessage struct {
Usage *llm.Usage `json:"usage,omitempty"`
}

var checkoutFlags = config.FlagSet{
config.FlagAPITarget: {Name: "api-target", Shorthand: "a", ViperKey: "client.api_target", Description: "Tapes API server URL"},
}

const checkoutLongDesc string = `Experimental: Checkout a point in the conversation for replay.

Fetches the conversation history up to the given hash from the API server
Expand All @@ -63,7 +69,9 @@ Examples:
const checkoutShortDesc string = "Checkout a conversation point"

func NewCheckoutCmd() *cobra.Command {
cmder := &checkoutCommander{}
cmder := &checkoutCommander{
flags: checkoutFlags,
}

cmd := &cobra.Command{
Use: "checkout [hash]",
Expand All @@ -72,19 +80,16 @@ func NewCheckoutCmd() *cobra.Command {
Args: cobra.MaximumNArgs(1),
PreRunE: func(cmd *cobra.Command, _ []string) error {
configDir, _ := cmd.Flags().GetString("config-dir")
cfger, err := config.NewConfiger(configDir)
v, err := config.InitViper(configDir)
if err != nil {
return fmt.Errorf("loading config: %w", err)
}

cfg, err := cfger.LoadConfig()
if err != nil {
return fmt.Errorf("loading config: %w", err)
}
config.BindRegisteredFlags(v, cmd, cmder.flags, []string{
config.FlagAPITarget,
})

if !cmd.Flags().Changed("api-target") {
cmder.apiTarget = cfg.Client.APITarget
}
cmder.apiTarget = v.GetString("client.api_target")
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -102,8 +107,7 @@ func NewCheckoutCmd() *cobra.Command {
},
}

defaults := config.NewDefaultConfig()
cmd.Flags().StringVarP(&cmder.apiTarget, "api-target", "a", defaults.Client.APITarget, "Tapes API server URL")
config.AddStringFlag(cmd, cmder.flags, config.FlagAPITarget, &cmder.apiTarget)

return cmd
}
Expand Down
31 changes: 17 additions & 14 deletions cmd/tapes/search/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,20 @@ import (
)

type searchCommander struct {
query string
topK int
flags config.FlagSet

query string
topK int
apiTarget string
debug bool

debug bool
logger *zap.Logger
}

var searchFlags = config.FlagSet{
config.FlagAPITarget: {Name: "api-target", Shorthand: "a", ViperKey: "client.api_target", Description: "Tapes API server URL"},
}

const searchLongDesc string = `Search session data via the Tapes API.

Search over stored sessions, returning the most relevant sessions based on the
Expand All @@ -46,7 +51,9 @@ Example:
const searchShortDesc string = "Search session data"

func NewSearchCmd() *cobra.Command {
cmder := &searchCommander{}
cmder := &searchCommander{
flags: searchFlags,
}

cmd := &cobra.Command{
Use: "search <query>",
Expand All @@ -55,19 +62,16 @@ func NewSearchCmd() *cobra.Command {
Args: cobra.ExactArgs(1),
PreRunE: func(cmd *cobra.Command, _ []string) error {
configDir, _ := cmd.Flags().GetString("config-dir")
cfger, err := config.NewConfiger(configDir)
v, err := config.InitViper(configDir)
if err != nil {
return fmt.Errorf("loading config: %w", err)
}

cfg, err := cfger.LoadConfig()
if err != nil {
return fmt.Errorf("loading config: %w", err)
}
config.BindRegisteredFlags(v, cmd, cmder.flags, []string{
config.FlagAPITarget,
})

if !cmd.Flags().Changed("api-target") {
cmder.apiTarget = cfg.Client.APITarget
}
cmder.apiTarget = v.GetString("client.api_target")
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -83,9 +87,8 @@ func NewSearchCmd() *cobra.Command {
},
}

defaults := config.NewDefaultConfig()
cmd.Flags().IntVarP(&cmder.topK, "top", "k", 5, "Number of results to return")
cmd.Flags().StringVar(&cmder.apiTarget, "api-target", defaults.Client.APITarget, "Tapes API server URL")
config.AddStringFlag(cmd, cmder.flags, config.FlagAPITarget, &cmder.apiTarget)

return cmd
}
Expand Down
38 changes: 22 additions & 16 deletions cmd/tapes/serve/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,48 @@ import (
)

type apiCommander struct {
flags config.FlagSet

listen string
debug bool
sqlitePath string
logger *zap.Logger

logger *zap.Logger
}

// apiFlags defines the flags for the standalone API subcommand.
var apiFlags = config.FlagSet{
config.FlagAPIListenStandalone: {Name: "listen", Shorthand: "l", ViperKey: "api.listen", Description: "Address for API server to listen on"},
config.FlagSQLite: {Name: "sqlite", Shorthand: "s", ViperKey: "storage.sqlite_path", Description: "Path to SQLite database"},
}

const apiLongDesc string = `Run the Tapes API server for inspecting, managing, and query agent sessions.`

const apiShortDesc string = "Run the Tapes API server"

func NewAPICmd() *cobra.Command {
cmder := &apiCommander{}
cmder := &apiCommander{
flags: apiFlags,
}

cmd := &cobra.Command{
Use: "api",
Short: apiShortDesc,
Long: apiLongDesc,
PreRunE: func(cmd *cobra.Command, _ []string) error {
configDir, _ := cmd.Flags().GetString("config-dir")
cfger, err := config.NewConfiger(configDir)
v, err := config.InitViper(configDir)
if err != nil {
return fmt.Errorf("loading config: %w", err)
}

cfg, err := cfger.LoadConfig()
if err != nil {
return fmt.Errorf("loading config: %w", err)
}
config.BindRegisteredFlags(v, cmd, cmder.flags, []string{
config.FlagAPIListenStandalone,
config.FlagSQLite,
})

if !cmd.Flags().Changed("listen") {
cmder.listen = cfg.API.Listen
}
if !cmd.Flags().Changed("sqlite") {
cmder.sqlitePath = cfg.Storage.SQLitePath
}
cmder.listen = v.GetString("api.listen")
cmder.sqlitePath = v.GetString("storage.sqlite_path")
return nil
},
RunE: func(cmd *cobra.Command, _ []string) error {
Expand All @@ -66,9 +73,8 @@ func NewAPICmd() *cobra.Command {
},
}

defaults := config.NewDefaultConfig()
cmd.Flags().StringVarP(&cmder.listen, "listen", "l", defaults.API.Listen, "Address for API server to listen on")
cmd.Flags().StringVarP(&cmder.sqlitePath, "sqlite", "s", "", "Path to SQLite database (default: in-memory)")
config.AddStringFlag(cmd, cmder.flags, config.FlagAPIListenStandalone, &cmder.listen)
config.AddStringFlag(cmd, cmder.flags, config.FlagSQLite, &cmder.sqlitePath)

return cmd
}
Expand Down
Loading