mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-14 03:30:26 +00:00
Merge branch 'main' of github.com:mark3labs/mcphost
This commit is contained in:
+33
-4
@@ -38,6 +38,7 @@ var (
|
||||
streamFlag bool // Enable streaming output
|
||||
compactMode bool // Enable compact output mode
|
||||
scriptMCPConfig *config.Config // Used to override config in script mode
|
||||
approveToolRun bool
|
||||
|
||||
// Session management
|
||||
saveSessionPath string
|
||||
@@ -302,6 +303,8 @@ func init() {
|
||||
BoolVar(&compactMode, "compact", false, "enable compact output mode without fancy styling")
|
||||
rootCmd.PersistentFlags().
|
||||
BoolVar(&noHooks, "no-hooks", false, "disable all hooks execution")
|
||||
rootCmd.PersistentFlags().
|
||||
BoolVar(&approveToolRun, "approve-tool-run", false, "enable requiring user approval for every tool call")
|
||||
|
||||
// Session management flags
|
||||
rootCmd.PersistentFlags().
|
||||
@@ -347,6 +350,7 @@ func init() {
|
||||
viper.BindPFlag("num-gpu-layers", rootCmd.PersistentFlags().Lookup("num-gpu-layers"))
|
||||
viper.BindPFlag("main-gpu", rootCmd.PersistentFlags().Lookup("main-gpu"))
|
||||
viper.BindPFlag("tls-skip-verify", rootCmd.PersistentFlags().Lookup("tls-skip-verify"))
|
||||
viper.BindPFlag("approve-tool-run", rootCmd.PersistentFlags().Lookup("approve-tool-run"))
|
||||
|
||||
// Defaults are already set in flag definitions, no need to duplicate in viper
|
||||
|
||||
@@ -445,7 +449,8 @@ func runNormalMode(ctx context.Context) error {
|
||||
debugLogger = bufferedLogger
|
||||
}
|
||||
|
||||
mcpAgent, err := agent.CreateAgent(ctx, &agent.AgentCreationOptions{ModelConfig: modelConfig,
|
||||
mcpAgent, err := agent.CreateAgent(ctx, &agent.AgentCreationOptions{
|
||||
ModelConfig: modelConfig,
|
||||
MCPConfig: mcpConfig,
|
||||
SystemPrompt: systemPrompt,
|
||||
MaxSteps: viper.GetInt("max-steps"),
|
||||
@@ -743,7 +748,8 @@ func runNormalMode(ctx context.Context) error {
|
||||
return fmt.Errorf("--quiet flag can only be used with --prompt/-p")
|
||||
}
|
||||
|
||||
return runInteractiveMode(ctx, mcpAgent, cli, serverNames, toolNames, modelName, messages, sessionManager, hookExecutor)
|
||||
approveToolRun := viper.GetBool("approve-tool-run")
|
||||
return runInteractiveMode(ctx, mcpAgent, cli, serverNames, toolNames, modelName, messages, sessionManager, hookExecutor, approveToolRun)
|
||||
}
|
||||
|
||||
// AgenticLoopConfig configures the behavior of the unified agentic loop.
|
||||
@@ -754,6 +760,7 @@ type AgenticLoopConfig struct {
|
||||
IsInteractive bool // true for interactive mode, false for non-interactive
|
||||
InitialPrompt string // initial prompt for non-interactive mode
|
||||
ContinueAfterRun bool // true to continue to interactive mode after initial run (--no-exit)
|
||||
ApproveToolRun bool // only used in interactive mode
|
||||
|
||||
// UI configuration
|
||||
Quiet bool // suppress all output except final response
|
||||
@@ -1103,7 +1110,27 @@ func runAgenticStep(ctx context.Context, mcpAgent *agent.Agent, cli *ui.CLI, mes
|
||||
currentSpinner.Start()
|
||||
}
|
||||
},
|
||||
streamingCallback, // Add streaming callback as the last parameter
|
||||
// Add streaming callback handler
|
||||
streamingCallback,
|
||||
// Tool call approval handler - called before tool execution to get user approval
|
||||
func(toolName, toolArgs string) (bool, error) {
|
||||
if !config.IsInteractive || !config.ApproveToolRun {
|
||||
return true, nil
|
||||
}
|
||||
if currentSpinner != nil {
|
||||
currentSpinner.Stop()
|
||||
currentSpinner = nil
|
||||
}
|
||||
allow, err := cli.GetToolApproval(toolName, toolArgs)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Start spinner again for tool calls
|
||||
currentSpinner = ui.NewSpinner("Thinking...")
|
||||
currentSpinner.Start()
|
||||
|
||||
return allow, nil
|
||||
},
|
||||
)
|
||||
|
||||
// Make sure spinner is stopped if still running
|
||||
@@ -1306,6 +1333,7 @@ func runNonInteractiveMode(ctx context.Context, mcpAgent *agent.Agent, cli *ui.C
|
||||
IsInteractive: false,
|
||||
InitialPrompt: prompt,
|
||||
ContinueAfterRun: noExit,
|
||||
ApproveToolRun: false,
|
||||
Quiet: quiet,
|
||||
ServerNames: serverNames,
|
||||
ToolNames: toolNames,
|
||||
@@ -1318,12 +1346,13 @@ func runNonInteractiveMode(ctx context.Context, mcpAgent *agent.Agent, cli *ui.C
|
||||
}
|
||||
|
||||
// runInteractiveMode handles the interactive mode execution
|
||||
func runInteractiveMode(ctx context.Context, mcpAgent *agent.Agent, cli *ui.CLI, serverNames, toolNames []string, modelName string, messages []*schema.Message, sessionManager *session.Manager, hookExecutor *hooks.Executor) error {
|
||||
func runInteractiveMode(ctx context.Context, mcpAgent *agent.Agent, cli *ui.CLI, serverNames, toolNames []string, modelName string, messages []*schema.Message, sessionManager *session.Manager, hookExecutor *hooks.Executor, approveToolRun bool) error {
|
||||
// Configure and run unified agentic loop
|
||||
config := AgenticLoopConfig{
|
||||
IsInteractive: true,
|
||||
InitialPrompt: "",
|
||||
ContinueAfterRun: false,
|
||||
ApproveToolRun: approveToolRun,
|
||||
Quiet: false,
|
||||
ServerNames: serverNames,
|
||||
ToolNames: toolNames,
|
||||
|
||||
@@ -7,21 +7,21 @@ toolchain go1.24.5
|
||||
require (
|
||||
github.com/JohannesKaufmann/html-to-markdown v1.6.0
|
||||
github.com/PuerkitoBio/goquery v1.10.3
|
||||
github.com/bytedance/sonic v1.14.1
|
||||
github.com/bytedance/sonic v1.15.0
|
||||
github.com/charmbracelet/fang v0.4.0
|
||||
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834
|
||||
github.com/cloudwego/eino v0.5.0-alpha.11
|
||||
github.com/cloudwego/eino-ext/components/model/claude v0.1.0
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.1.2
|
||||
github.com/cloudwego/eino v0.7.13
|
||||
github.com/cloudwego/eino-ext/components/model/claude v0.1.12
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.1.8
|
||||
github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250903035842-96774a3ec845
|
||||
github.com/getkin/kin-openapi v0.120.0
|
||||
github.com/eino-contrib/jsonschema v1.0.3
|
||||
github.com/getkin/kin-openapi v0.131.0
|
||||
github.com/mark3labs/mcp-filesystem-server v0.11.1
|
||||
github.com/mark3labs/mcp-go v0.43.0
|
||||
github.com/ollama/ollama v0.11.8
|
||||
github.com/mark3labs/mcp-go v0.44.0-beta.2
|
||||
github.com/spf13/cobra v1.10.1
|
||||
github.com/spf13/viper v1.20.1
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
golang.org/x/term v0.34.0
|
||||
golang.org/x/term v0.37.0
|
||||
google.golang.org/genai v1.22.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
@@ -29,6 +29,7 @@ require (
|
||||
require (
|
||||
cloud.google.com/go v0.121.6 // indirect
|
||||
cloud.google.com/go/auth v0.16.5 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.8.0 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.20.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
@@ -52,7 +53,7 @@ require (
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.3.2 // indirect
|
||||
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
||||
github.com/charmbracelet/lipgloss/v2 v2.0.0-beta1 // indirect
|
||||
@@ -65,7 +66,7 @@ require (
|
||||
github.com/djherbis/times v1.6.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/eino-contrib/jsonschema v1.0.0 // indirect
|
||||
github.com/eino-contrib/ollama v0.1.0 // indirect
|
||||
github.com/evanphx/json-patch v0.5.2 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
@@ -85,7 +86,6 @@ require (
|
||||
github.com/gorilla/css v1.0.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/invopop/jsonschema v0.13.0 // indirect
|
||||
github.com/invopop/yaml v0.2.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
@@ -101,6 +101,8 @@ require (
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/roff v0.1.0 // indirect
|
||||
github.com/nikolalohinski/gonja v1.5.3 // indirect
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
@@ -122,13 +124,17 @@ require (
|
||||
github.com/yuin/goldmark v1.7.13 // indirect
|
||||
github.com/yuin/goldmark-emoji v1.0.6 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||
golang.org/x/arch v0.20.0 // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/arch v0.23.0 // indirect
|
||||
golang.org/x/crypto v0.45.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
google.golang.org/api v0.246.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect
|
||||
google.golang.org/grpc v1.75.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
@@ -137,7 +143,7 @@ require (
|
||||
require (
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/charmbracelet/bubbles v0.21.0
|
||||
github.com/charmbracelet/bubbletea v1.3.6
|
||||
github.com/charmbracelet/bubbletea v1.3.10
|
||||
github.com/charmbracelet/glamour v0.10.0
|
||||
github.com/charmbracelet/x/ansi v0.10.1 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
@@ -153,7 +159,7 @@ require (
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.40.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
)
|
||||
|
||||
@@ -2,6 +2,8 @@ cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
|
||||
cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
|
||||
cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI=
|
||||
cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA=
|
||||
cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
|
||||
github.com/JohannesKaufmann/html-to-markdown v1.6.0 h1:04VXMiE50YYfCfLboJCLcgqF5x+rHJnb1ssNmqpLH/k=
|
||||
@@ -71,15 +73,15 @@ github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M
|
||||
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
||||
github.com/bytedance/mockey v1.2.14 h1:KZaFgPdiUwW+jOWFieo3Lr7INM1P+6adO3hxZhDswY8=
|
||||
github.com/bytedance/mockey v1.2.14/go.mod h1:1BPHF9sol5R1ud/+0VEHGQq/+i2lN+GTsr3O2Q9IENY=
|
||||
github.com/bytedance/sonic v1.14.1 h1:FBMC0zVz5XUmE4z9wF4Jey0An5FueFvOsTKKKtwIl7w=
|
||||
github.com/bytedance/sonic v1.14.1/go.mod h1:gi6uhQLMbTdeP0muCnrjHLeCUPyb70ujhnNlhOylAFc=
|
||||
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
|
||||
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=
|
||||
github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k=
|
||||
github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE=
|
||||
github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||
github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
|
||||
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
||||
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
||||
github.com/charmbracelet/bubbletea v1.3.6 h1:VkHIxPJQeDt0aFJIsVxw8BQdh/F/L2KKZGsK6et5taU=
|
||||
github.com/charmbracelet/bubbletea v1.3.6/go.mod h1:oQD9VCRQFF8KplacJLo28/jofOI2ToOfGYeFgBBxHOc=
|
||||
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
|
||||
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
|
||||
github.com/charmbracelet/colorprofile v0.3.2 h1:9J27WdztfJQVAQKX2WOlSSRB+5gaKqqITmrvb1uTIiI=
|
||||
github.com/charmbracelet/colorprofile v0.3.2/go.mod h1:mTD5XzNeWHj8oqHb+S1bssQb7vIHbepiebQ2kPKVKbI=
|
||||
github.com/charmbracelet/fang v0.4.0 h1:boBxmdcFghTeotqkD2itXi7SMBozdIlcslRqjboSJDg=
|
||||
@@ -108,12 +110,12 @@ github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQ
|
||||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||
github.com/cloudwego/eino v0.5.0-alpha.11 h1:KhjJ8JTAI/Ed5iCHWKUn1v4j1sDCxqV26HRoUQpSRFc=
|
||||
github.com/cloudwego/eino v0.5.0-alpha.11/go.mod h1:S38tlNO4cNqFfGJKQSJZimxjzc9JDJKdf2eW3FEEfdc=
|
||||
github.com/cloudwego/eino-ext/components/model/claude v0.1.0 h1:UZVwYzV7gOBCBKHGdAT2fZzm/+2TBEfDDYn713EvLF0=
|
||||
github.com/cloudwego/eino-ext/components/model/claude v0.1.0/go.mod h1:lacy0WE3yKuOSxrhJQKqWAxn3LiUy/CJ91jU7nLDNNQ=
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.1.2 h1:WxJ+7oXnr3AhM6u4VbFF3L2ionxCrPfmLetx7V+zthw=
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.1.2/go.mod h1:OgGMCiR/G/RnOWaJvdK8pVSxAzoz2SlCqim43oFTuwo=
|
||||
github.com/cloudwego/eino v0.7.13 h1:Ku7hY+83gGJJjf4On3UgqjC57UcA+DXe0tqAZiNDDew=
|
||||
github.com/cloudwego/eino v0.7.13/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ=
|
||||
github.com/cloudwego/eino-ext/components/model/claude v0.1.12 h1:c66gFH9J5Ku2/v1f7jPwI9R4CYw5TiAlIVzsfzjsF1g=
|
||||
github.com/cloudwego/eino-ext/components/model/claude v0.1.12/go.mod h1:a9oQkf4Ib+/VqjsLRdRETytt2m/C4fbcvfjPNu6nVAg=
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.1.8 h1:+BStnQlkRxWMV9jsPopLmmut2ARG88e9hDSMaDNAI/w=
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.1.8/go.mod h1:C3rf3yy2nEoXFP/CQJne4gbiu1pREKplHKmFlhuOzPE=
|
||||
github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250903035842-96774a3ec845 h1:nxflfiBwWNPoKS9X4SMhmT+si7rtYv+lQzIyPJik4DM=
|
||||
github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250903035842-96774a3ec845/go.mod h1:QQhCuQxuBAVWvu/YAZBhs/RsR76mUigw59Tl0kh04C8=
|
||||
github.com/cloudwego/eino-ext/libs/acl/openai v0.0.0-20250826113018-8c6f6358d4bb h1:RMslzyijc3bi9EkqCulpS0hZupTl1y/wayR3+fVRN/c=
|
||||
@@ -128,8 +130,10 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/eino-contrib/jsonschema v1.0.0 h1:dXxbhGNZuI3+xNi8x3JT8AGyoXz6Pff6mRvmpjVl5Ww=
|
||||
github.com/eino-contrib/jsonschema v1.0.0/go.mod h1:cpnX4SyKjWjGC7iN2EbhxaTdLqGjCi0e9DxpLYxddD4=
|
||||
github.com/eino-contrib/jsonschema v1.0.3 h1:2Kfsm1xlMV0ssY2nuxshS4AwbLFuqmPmzIjLVJ1Fsp0=
|
||||
github.com/eino-contrib/jsonschema v1.0.3/go.mod h1:cpnX4SyKjWjGC7iN2EbhxaTdLqGjCi0e9DxpLYxddD4=
|
||||
github.com/eino-contrib/ollama v0.1.0 h1:z1NaMdKW6X1ftP8g5xGGR5zDRPUtuTKFq35vBQgxsN4=
|
||||
github.com/eino-contrib/ollama v0.1.0/go.mod h1:mYsQ7b3DeqY8bHPuD3MZJYTqkgyL6LoemxoP/B7ZNhA=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||
github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
|
||||
@@ -143,8 +147,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/getkin/kin-openapi v0.120.0 h1:MqJcNJFrMDFNc07iwE8iFC5eT2k/NPUFDIpNeiZv8Jg=
|
||||
github.com/getkin/kin-openapi v0.120.0/go.mod h1:PCWw/lfBrJY4HcdqE3jj+QFkaFK8ABoqo7PvqVhXXqw=
|
||||
github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE=
|
||||
github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58=
|
||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=
|
||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
||||
@@ -194,8 +198,6 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
|
||||
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
|
||||
github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
@@ -220,8 +222,8 @@ github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/mark3labs/mcp-filesystem-server v0.11.1 h1:7uKIZRMaKWfgvtDj/uLAvo0+7Mwb8gxo5DJywhqFW88=
|
||||
github.com/mark3labs/mcp-filesystem-server v0.11.1/go.mod h1:xDqJizVYWZ5a31Mt4xuYbVku2AR/kT56H3O0SbpANoQ=
|
||||
github.com/mark3labs/mcp-go v0.43.0 h1:lgiKcWMddh4sngbU+hoWOZ9iAe/qp/m851RQpj3Y7jA=
|
||||
github.com/mark3labs/mcp-go v0.43.0/go.mod h1:YnJfOL382MIWDx1kMY+2zsRHU/q78dBg9aFb8W6Thdw=
|
||||
github.com/mark3labs/mcp-go v0.44.0-beta.2 h1:gfUT0m77E4odfgiHkqV/E+MQVaQ06rbutW7Ln0JRkBA=
|
||||
github.com/mark3labs/mcp-go v0.44.0-beta.2/go.mod h1:YnJfOL382MIWDx1kMY+2zsRHU/q78dBg9aFb8W6Thdw=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
@@ -262,8 +264,10 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc
|
||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||
github.com/nikolalohinski/gonja v1.5.3 h1:GsA+EEaZDZPGJ8JtpeGN78jidhOlxeJROpqMT9fTj9c=
|
||||
github.com/nikolalohinski/gonja v1.5.3/go.mod h1:RmjwxNiXAEqcq1HeK5SSMmqFJvKOfTfXhkJv6YBtPa4=
|
||||
github.com/ollama/ollama v0.11.8 h1:S7INjNBa7eGm87zfO/LWfP1ov8NMEuB6OOKgDGMAA9s=
|
||||
github.com/ollama/ollama v0.11.8/go.mod h1:9+1//yWPsDE2u+l1a5mpaKrYw4VdnSsRU3ioq5BvMms=
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY=
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw=
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c=
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
@@ -318,13 +322,15 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
@@ -361,6 +367,8 @@ github.com/yuin/goldmark-emoji v1.0.6 h1:QWfF2FYaXwL74tfGOW5izeiZepUDroDJfWubQI9
|
||||
github.com/yuin/goldmark-emoji v1.0.6/go.mod h1:ukxJDKFpdFb5x0a5HqbdlcKtebh086iJpI31LTKmWuA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
@@ -375,8 +383,8 @@ go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJr
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
|
||||
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
|
||||
golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg=
|
||||
golang.org/x/arch v0.23.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
@@ -385,8 +393,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
@@ -406,8 +414,10 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -416,8 +426,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -437,8 +447,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -450,8 +460,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
@@ -461,8 +471,10 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
@@ -472,6 +484,8 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/api v0.246.0 h1:H0ODDs5PnMZVZAEtdLMn2Ul2eQi7QNjqM2DIFp8TlTM=
|
||||
google.golang.org/api v0.246.0/go.mod h1:dMVhVcylamkirHdzEBAIQWUCgqY885ivNeZYd7VAVr8=
|
||||
google.golang.org/genai v1.22.0 h1:5hrEhXXWJQZa3tdPocl4vQ/0w6myEAxdNns2Kmx0f4Y=
|
||||
google.golang.org/genai v1.22.0/go.mod h1:QPj5NGJw+3wEOHg+PrsWwJKvG6UC84ex5FR7qAYsN/M=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 h1:pmJpJEvT846VzausCQ5d7KreSROcDqmO388w5YbnltA=
|
||||
@@ -491,6 +505,5 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/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=
|
||||
|
||||
+25
-7
@@ -4,6 +4,9 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/cloudwego/eino/components/model"
|
||||
"github.com/cloudwego/eino/components/tool"
|
||||
@@ -12,8 +15,6 @@ import (
|
||||
"github.com/mark3labs/mcphost/internal/config"
|
||||
"github.com/mark3labs/mcphost/internal/models"
|
||||
"github.com/mark3labs/mcphost/internal/tools"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AgentConfig holds configuration options for creating a new Agent.
|
||||
@@ -57,6 +58,10 @@ type StreamingResponseHandler func(content string)
|
||||
// It receives any text content that the model generates alongside tool calls.
|
||||
type ToolCallContentHandler func(content string)
|
||||
|
||||
// ToolApprovalHandler is a function type for handling user approval of tool calls.
|
||||
// It receives the tool name and arguments, and returns true if the user approves.
|
||||
type ToolApprovalHandler func(toolName, toolArgs string) (bool, error)
|
||||
|
||||
// Agent represents an AI agent with MCP tool integration and real-time tool call display.
|
||||
// It manages the interaction between an LLM and various tools through the MCP protocol.
|
||||
type Agent struct {
|
||||
@@ -128,17 +133,17 @@ type GenerateWithLoopResult struct {
|
||||
// It handles the conversation flow, executing tools as needed and invoking callbacks for various events.
|
||||
// This method does not support streaming responses; use GenerateWithLoopAndStreaming for streaming support.
|
||||
func (a *Agent) GenerateWithLoop(ctx context.Context, messages []*schema.Message,
|
||||
onToolCall ToolCallHandler, onToolExecution ToolExecutionHandler, onToolResult ToolResultHandler, onResponse ResponseHandler, onToolCallContent ToolCallContentHandler) (*GenerateWithLoopResult, error) {
|
||||
|
||||
return a.GenerateWithLoopAndStreaming(ctx, messages, onToolCall, onToolExecution, onToolResult, onResponse, onToolCallContent, nil)
|
||||
onToolCall ToolCallHandler, onToolExecution ToolExecutionHandler, onToolResult ToolResultHandler, onResponse ResponseHandler, onToolCallContent ToolCallContentHandler, onToolApproval ToolApprovalHandler,
|
||||
) (*GenerateWithLoopResult, error) {
|
||||
return a.GenerateWithLoopAndStreaming(ctx, messages, onToolCall, onToolExecution, onToolResult, onResponse, onToolCallContent, nil, onToolApproval)
|
||||
}
|
||||
|
||||
// GenerateWithLoopAndStreaming processes messages with a custom loop that displays tool calls in real-time and supports streaming callbacks.
|
||||
// It handles the conversation flow, executing tools as needed and invoking callbacks for various events including streaming chunks.
|
||||
// The onStreamingResponse callback is invoked for each content chunk during streaming if streaming is enabled.
|
||||
func (a *Agent) GenerateWithLoopAndStreaming(ctx context.Context, messages []*schema.Message,
|
||||
onToolCall ToolCallHandler, onToolExecution ToolExecutionHandler, onToolResult ToolResultHandler, onResponse ResponseHandler, onToolCallContent ToolCallContentHandler, onStreamingResponse StreamingResponseHandler) (*GenerateWithLoopResult, error) {
|
||||
|
||||
onToolCall ToolCallHandler, onToolExecution ToolExecutionHandler, onToolResult ToolResultHandler, onResponse ResponseHandler, onToolCallContent ToolCallContentHandler, onStreamingResponse StreamingResponseHandler, onToolApproval ToolApprovalHandler,
|
||||
) (*GenerateWithLoopResult, error) {
|
||||
// Create a copy of messages to avoid modifying the original
|
||||
workingMessages := make([]*schema.Message, len(messages))
|
||||
copy(workingMessages, messages)
|
||||
@@ -200,6 +205,19 @@ func (a *Agent) GenerateWithLoopAndStreaming(ctx context.Context, messages []*sc
|
||||
|
||||
// Handle tool calls
|
||||
for _, toolCall := range response.ToolCalls {
|
||||
if onToolApproval != nil {
|
||||
approved, err := onToolApproval(toolCall.Function.Name, toolCall.Function.Arguments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !approved {
|
||||
rejectedMsg := fmt.Sprintf("The user did not allow tool call %s. Reason: User cancelled.", toolCall.Function.Name)
|
||||
toolMessage := schema.ToolMessage(rejectedMsg, toolCall.ID)
|
||||
workingMessages = append(workingMessages, toolMessage)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Notify about tool call
|
||||
if onToolCall != nil {
|
||||
onToolCall(toolCall.Function.Name, toolCall.Function.Arguments)
|
||||
|
||||
@@ -166,6 +166,7 @@ type Config struct {
|
||||
Stream *bool `json:"stream,omitempty" yaml:"stream,omitempty"`
|
||||
Theme any `json:"theme" yaml:"theme"`
|
||||
MarkdownTheme any `json:"markdown-theme" yaml:"markdown-theme"`
|
||||
ApproveToolRun bool `json:"approve-tool-run" yaml:"approve-tool-run"`
|
||||
|
||||
// Model generation parameters
|
||||
MaxTokens int `json:"max-tokens,omitempty" yaml:"max-tokens,omitempty"`
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/cloudwego/eino/components"
|
||||
"github.com/cloudwego/eino/components/model"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/eino-contrib/jsonschema"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"google.golang.org/genai"
|
||||
)
|
||||
@@ -83,7 +84,7 @@ type Config struct {
|
||||
|
||||
// ResponseSchema defines the structure for JSON responses
|
||||
// Optional. Used when you want structured output in JSON format
|
||||
ResponseSchema *openapi3.Schema
|
||||
ResponseSchema *jsonschema.Schema
|
||||
|
||||
// EnableCodeExecution allows the model to execute code
|
||||
// Warning: Be cautious with code execution in production
|
||||
@@ -103,7 +104,7 @@ type options struct {
|
||||
// TopK limits the number of tokens to sample from
|
||||
TopK *int32
|
||||
// ResponseSchema defines the expected JSON structure for responses
|
||||
ResponseSchema *openapi3.Schema
|
||||
ResponseSchema *jsonschema.Schema
|
||||
}
|
||||
|
||||
// ChatModel implements the Gemini chat model for the eino framework.
|
||||
@@ -124,7 +125,7 @@ type ChatModel struct {
|
||||
// topK limits token sampling
|
||||
topK *int32
|
||||
// responseSchema for structured JSON output
|
||||
responseSchema *openapi3.Schema
|
||||
responseSchema *jsonschema.Schema
|
||||
// tools converted to Gemini format
|
||||
tools []*genai.Tool
|
||||
// origTools stores the original tool definitions
|
||||
@@ -448,7 +449,7 @@ func (cm *ChatModel) buildGenerateConfig(opts ...model.Option) (*genai.GenerateC
|
||||
|
||||
// Set response schema for JSON mode
|
||||
if geminiOptions.ResponseSchema != nil {
|
||||
gSchema, err := cm.convertOpenAPISchema(geminiOptions.ResponseSchema)
|
||||
gSchema, err := cm.convertJSONSchema(geminiOptions.ResponseSchema)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("convert response schema failed: %w", err)
|
||||
}
|
||||
@@ -466,12 +467,12 @@ func (cm *ChatModel) convertToGeminiTools(tools []*schema.ToolInfo) ([]*genai.To
|
||||
|
||||
var functionDeclarations []*genai.FunctionDeclaration
|
||||
for _, tool := range tools {
|
||||
openSchema, err := tool.ToOpenAPIV3()
|
||||
openSchema, err := tool.ToJSONSchema()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get open schema failed: %w", err)
|
||||
}
|
||||
|
||||
gSchema, err := cm.convertOpenAPISchema(openSchema)
|
||||
gSchema, err := cm.convertJSONSchema(openSchema)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("convert open schema failed: %w", err)
|
||||
}
|
||||
@@ -487,7 +488,7 @@ func (cm *ChatModel) convertToGeminiTools(tools []*schema.ToolInfo) ([]*genai.To
|
||||
return []*genai.Tool{{FunctionDeclarations: functionDeclarations}}, nil
|
||||
}
|
||||
|
||||
func (cm *ChatModel) convertOpenAPISchema(schema *openapi3.Schema) (*genai.Schema, error) {
|
||||
func (cm *ChatModel) convertJSONSchema(schema *jsonschema.Schema) (*genai.Schema, error) {
|
||||
if schema == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -501,15 +502,12 @@ func (cm *ChatModel) convertOpenAPISchema(schema *openapi3.Schema) (*genai.Schem
|
||||
result.Type = genai.TypeObject
|
||||
if schema.Properties != nil {
|
||||
properties := make(map[string]*genai.Schema)
|
||||
for name, prop := range schema.Properties {
|
||||
if prop == nil || prop.Value == nil {
|
||||
continue
|
||||
}
|
||||
propSchema, err := cm.convertOpenAPISchema(prop.Value)
|
||||
for pair := schema.Properties.Oldest(); pair != nil; pair = pair.Next() {
|
||||
propSchema, err := cm.convertJSONSchema(pair.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
properties[name] = propSchema
|
||||
properties[pair.Key] = propSchema
|
||||
}
|
||||
result.Properties = properties
|
||||
}
|
||||
@@ -518,8 +516,8 @@ func (cm *ChatModel) convertOpenAPISchema(schema *openapi3.Schema) (*genai.Schem
|
||||
}
|
||||
case openapi3.TypeArray:
|
||||
result.Type = genai.TypeArray
|
||||
if schema.Items != nil && schema.Items.Value != nil {
|
||||
itemSchema, err := cm.convertOpenAPISchema(schema.Items.Value)
|
||||
if schema.Items != nil {
|
||||
itemSchema, err := cm.convertJSONSchema(schema.Items)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+33431
-14495
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/mark3labs/mcphost/internal/models/anthropic"
|
||||
"github.com/mark3labs/mcphost/internal/models/openai"
|
||||
"github.com/mark3labs/mcphost/internal/ui/progress"
|
||||
"github.com/ollama/ollama/api"
|
||||
"google.golang.org/genai"
|
||||
|
||||
"github.com/mark3labs/mcphost/internal/auth"
|
||||
@@ -218,6 +217,12 @@ func CreateProvider(ctx context.Context, config *ProviderConfig) (*ProviderResul
|
||||
return nil, err
|
||||
}
|
||||
return &ProviderResult{Model: model, Message: ""}, nil
|
||||
case "google-vertex-anthropic":
|
||||
model, err := createVertexAnthropicProvider(ctx, config, modelName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ProviderResult{Model: model, Message: ""}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported provider: %s", provider)
|
||||
}
|
||||
@@ -335,6 +340,67 @@ func createAnthropicProvider(ctx context.Context, config *ProviderConfig, modelN
|
||||
claudeConfig.Temperature = config.Temperature
|
||||
}
|
||||
|
||||
if config.TopP != nil && *config.TopP != 0.95 {
|
||||
claudeConfig.TopP = config.TopP
|
||||
}
|
||||
|
||||
if config.TopK != nil {
|
||||
claudeConfig.TopK = config.TopK
|
||||
}
|
||||
|
||||
if len(config.StopSequences) > 0 {
|
||||
claudeConfig.StopSequences = config.StopSequences
|
||||
}
|
||||
|
||||
return anthropic.NewCustomChatModel(ctx, claudeConfig)
|
||||
}
|
||||
|
||||
func createVertexAnthropicProvider(ctx context.Context, config *ProviderConfig, modelName string) (model.ToolCallingChatModel, error) {
|
||||
projectID := os.Getenv("GOOGLE_VERTEX_PROJECT")
|
||||
if projectID == "" {
|
||||
projectID = os.Getenv("ANTHROPIC_VERTEX_PROJECT_ID")
|
||||
}
|
||||
if projectID == "" {
|
||||
projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")
|
||||
}
|
||||
if projectID == "" {
|
||||
projectID = os.Getenv("GCLOUD_PROJECT")
|
||||
}
|
||||
if projectID == "" {
|
||||
projectID = os.Getenv("CLOUDSDK_CORE_PROJECT")
|
||||
}
|
||||
if projectID == "" {
|
||||
return nil, fmt.Errorf("Google Vertex project ID not provided. Set ANTHROPIC_VERTEX_PROJECT_ID, GOOGLE_CLOUD_PROJECT, or GCLOUD_PROJECT environment variable")
|
||||
}
|
||||
|
||||
region := os.Getenv("GOOGLE_VERTEX_LOCATION")
|
||||
if region == "" {
|
||||
region = os.Getenv("ANTHROPIC_VERTEX_REGION")
|
||||
}
|
||||
if region == "" {
|
||||
region = os.Getenv("CLOUD_ML_REGION")
|
||||
}
|
||||
if region == "" {
|
||||
region = "global"
|
||||
}
|
||||
|
||||
maxTokens := config.MaxTokens
|
||||
if maxTokens == 0 {
|
||||
maxTokens = 4096 // Default value
|
||||
}
|
||||
|
||||
claudeConfig := &einoclaude.Config{
|
||||
ByVertex: true,
|
||||
VertexProjectID: projectID,
|
||||
VertexRegion: region,
|
||||
Model: modelName,
|
||||
MaxTokens: maxTokens,
|
||||
}
|
||||
|
||||
if config.Temperature != nil {
|
||||
claudeConfig.Temperature = config.Temperature
|
||||
}
|
||||
|
||||
if config.TopP != nil {
|
||||
claudeConfig.TopP = config.TopP
|
||||
}
|
||||
@@ -473,7 +539,7 @@ func createGoogleProvider(ctx context.Context, config *ProviderConfig, modelName
|
||||
type OllamaLoadingResult struct {
|
||||
// Options contains the actual Ollama options used for loading
|
||||
// May differ from requested options if fallback occurred (e.g., CPU instead of GPU)
|
||||
Options *api.Options
|
||||
Options *ollama.Options
|
||||
|
||||
// Message describes the loading result
|
||||
// Example: "Model loaded successfully on GPU" or
|
||||
@@ -482,7 +548,7 @@ type OllamaLoadingResult struct {
|
||||
}
|
||||
|
||||
// loadOllamaModelWithFallback loads an Ollama model with GPU settings and automatic CPU fallback
|
||||
func loadOllamaModelWithFallback(ctx context.Context, baseURL, modelName string, options *api.Options, tlsSkipVerify bool) (*OllamaLoadingResult, error) {
|
||||
func loadOllamaModelWithFallback(ctx context.Context, baseURL, modelName string, options *ollama.Options, tlsSkipVerify bool) (*OllamaLoadingResult, error) {
|
||||
client := createHTTPClientWithTLSConfig(tlsSkipVerify)
|
||||
|
||||
// Phase 1: Check if model exists locally
|
||||
@@ -590,7 +656,7 @@ func pullOllamaModelWithProgress(ctx context.Context, client *http.Client, baseU
|
||||
}
|
||||
|
||||
// loadOllamaModelWithOptions loads a model with specific options using a warmup request
|
||||
func loadOllamaModelWithOptions(ctx context.Context, client *http.Client, baseURL, modelName string, options *api.Options) (*api.Options, error) {
|
||||
func loadOllamaModelWithOptions(ctx context.Context, client *http.Client, baseURL, modelName string, options *ollama.Options) (*ollama.Options, error) {
|
||||
// Create a copy of options for warmup to avoid modifying the original
|
||||
warmupOptions := *options
|
||||
warmupOptions.NumPredict = 1 // Limit response length for warmup
|
||||
@@ -667,8 +733,8 @@ func createOllamaProviderWithResult(ctx context.Context, config *ProviderConfig,
|
||||
baseURL = config.ProviderURL
|
||||
}
|
||||
|
||||
// Set up options for Ollama using the api.Options struct
|
||||
options := &api.Options{}
|
||||
// Set up options for Ollama using the ollama.Options struct
|
||||
options := &ollama.Options{}
|
||||
|
||||
if config.Temperature != nil {
|
||||
options.Temperature = *config.Temperature
|
||||
@@ -700,7 +766,7 @@ func createOllamaProviderWithResult(ctx context.Context, config *ProviderConfig,
|
||||
}
|
||||
|
||||
// Create a clean copy of options for the final model
|
||||
finalOptions := &api.Options{}
|
||||
finalOptions := &ollama.Options{}
|
||||
*finalOptions = *options // Copy all fields
|
||||
|
||||
// Try to pre-load the model with GPU settings and automatic CPU fallback
|
||||
|
||||
@@ -100,6 +100,19 @@ func (r *ModelsRegistry) ValidateEnvironment(provider string, apiKey string) err
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add alternative environment variable names for google-vertex-anthropic
|
||||
// These match the env vars checked by eino-claude and other tools
|
||||
if provider == "google-vertex-anthropic" {
|
||||
envVars = append(envVars,
|
||||
"ANTHROPIC_VERTEX_PROJECT_ID",
|
||||
"GOOGLE_CLOUD_PROJECT",
|
||||
"GCLOUD_PROJECT",
|
||||
"CLOUDSDK_CORE_PROJECT",
|
||||
"ANTHROPIC_VERTEX_REGION",
|
||||
"CLOUD_ML_REGION",
|
||||
)
|
||||
}
|
||||
|
||||
// Check if at least one environment variable is set
|
||||
var foundVar bool
|
||||
for _, envVar := range envVars {
|
||||
|
||||
+89
-4
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/cloudwego/eino/components/model"
|
||||
"github.com/cloudwego/eino/components/tool"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/eino-contrib/jsonschema"
|
||||
"github.com/mark3labs/mcp-go/client"
|
||||
"github.com/mark3labs/mcp-go/client/transport"
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
@@ -221,7 +221,14 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string,
|
||||
if err != nil {
|
||||
return fmt.Errorf("conv mcp tool input schema fail(marshal): %w, tool name: %s", err, mcpTool.Name)
|
||||
}
|
||||
inputSchema := &openapi3.Schema{}
|
||||
|
||||
// Fix for JSON Schema draft-07 vs draft-04 compatibility:
|
||||
// Chrome DevTools MCP uses draft-07 where exclusiveMinimum/exclusiveMaximum are numbers,
|
||||
// but kin-openapi (OpenAPI 3.0) expects them as booleans (draft-04 format).
|
||||
// Pre-process the schema to convert numeric exclusive bounds to boolean format.
|
||||
marshaledInputSchema = convertExclusiveBoundsToBoolean(marshaledInputSchema)
|
||||
|
||||
inputSchema := &jsonschema.Schema{}
|
||||
err = sonic.Unmarshal(marshaledInputSchema, inputSchema)
|
||||
if err != nil {
|
||||
return fmt.Errorf("conv mcp tool input schema fail(unmarshal): %w, tool name: %s", err, mcpTool.Name)
|
||||
@@ -231,7 +238,7 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string,
|
||||
// OpenAI function calling requires object schemas to have a "properties" field
|
||||
// even if it's empty, otherwise it throws "object schema missing properties" error
|
||||
if inputSchema.Type == "object" && inputSchema.Properties == nil {
|
||||
inputSchema.Properties = make(openapi3.Schemas)
|
||||
inputSchema.Properties = jsonschema.NewProperties()
|
||||
}
|
||||
|
||||
// Create prefixed tool name
|
||||
@@ -251,7 +258,7 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string,
|
||||
info: &schema.ToolInfo{
|
||||
Name: prefixedName,
|
||||
Desc: mcpTool.Description,
|
||||
ParamsOneOf: schema.NewParamsOneOfByOpenAPIV3(inputSchema),
|
||||
ParamsOneOf: schema.NewParamsOneOfByJSONSchema(inputSchema),
|
||||
},
|
||||
mapping: mapping,
|
||||
}
|
||||
@@ -555,3 +562,81 @@ func (m *MCPToolManager) debugLogConnectionInfo(serverName string, serverConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convertExclusiveBoundsToBoolean converts JSON Schema draft-07 style exclusive bounds
|
||||
// (where exclusiveMinimum/exclusiveMaximum are numbers) to draft-04 style
|
||||
// (where they are booleans that modify minimum/maximum).
|
||||
// This enables compatibility with kin-openapi which uses OpenAPI 3.0 (draft-04 based) schemas.
|
||||
func convertExclusiveBoundsToBoolean(schemaJSON []byte) []byte {
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(schemaJSON, &data); err != nil {
|
||||
return schemaJSON // Return unchanged on error
|
||||
}
|
||||
|
||||
convertSchemaRecursive(data)
|
||||
|
||||
result, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return schemaJSON // Return unchanged on error
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// convertSchemaRecursive recursively processes a schema map and converts
|
||||
// numeric exclusiveMinimum/exclusiveMaximum to boolean format.
|
||||
func convertSchemaRecursive(schema map[string]interface{}) {
|
||||
// Convert exclusiveMinimum if it's a number
|
||||
if exMin, ok := schema["exclusiveMinimum"]; ok {
|
||||
if num, isNum := exMin.(float64); isNum {
|
||||
// JSON Schema draft-07: exclusiveMinimum is the limit value
|
||||
// Convert to draft-04: set minimum = value, exclusiveMinimum = true
|
||||
schema["minimum"] = num
|
||||
schema["exclusiveMinimum"] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Convert exclusiveMaximum if it's a number
|
||||
if exMax, ok := schema["exclusiveMaximum"]; ok {
|
||||
if num, isNum := exMax.(float64); isNum {
|
||||
// JSON Schema draft-07: exclusiveMaximum is the limit value
|
||||
// Convert to draft-04: set maximum = value, exclusiveMaximum = true
|
||||
schema["maximum"] = num
|
||||
schema["exclusiveMaximum"] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively process properties
|
||||
if props, ok := schema["properties"].(map[string]interface{}); ok {
|
||||
for _, prop := range props {
|
||||
if propSchema, ok := prop.(map[string]interface{}); ok {
|
||||
convertSchemaRecursive(propSchema)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively process items (for arrays)
|
||||
if items, ok := schema["items"].(map[string]interface{}); ok {
|
||||
convertSchemaRecursive(items)
|
||||
}
|
||||
|
||||
// Recursively process additionalProperties
|
||||
if addProps, ok := schema["additionalProperties"].(map[string]interface{}); ok {
|
||||
convertSchemaRecursive(addProps)
|
||||
}
|
||||
|
||||
// Recursively process allOf, anyOf, oneOf
|
||||
for _, key := range []string{"allOf", "anyOf", "oneOf"} {
|
||||
if arr, ok := schema[key].([]interface{}); ok {
|
||||
for _, item := range arr {
|
||||
if itemSchema, ok := item.(map[string]interface{}); ok {
|
||||
convertSchemaRecursive(itemSchema)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively process not
|
||||
if not, ok := schema["not"].(map[string]interface{}); ok {
|
||||
convertSchemaRecursive(not)
|
||||
}
|
||||
}
|
||||
|
||||
+217
-4
@@ -2,11 +2,12 @@ package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/eino-contrib/jsonschema"
|
||||
"github.com/mark3labs/mcphost/internal/config"
|
||||
)
|
||||
|
||||
@@ -131,7 +132,7 @@ func TestMCPToolManager_ToolWithoutProperties(t *testing.T) {
|
||||
func TestIssue89_ObjectSchemaMissingProperties(t *testing.T) {
|
||||
// Create a schema that would cause the OpenAI validation error
|
||||
// This simulates what might happen with tools that have no input properties
|
||||
brokenSchema := &openapi3.Schema{
|
||||
brokenSchema := &jsonschema.Schema{
|
||||
Type: "object",
|
||||
// Properties is nil - this causes "object schema missing properties" error in OpenAI
|
||||
}
|
||||
@@ -143,7 +144,7 @@ func TestIssue89_ObjectSchemaMissingProperties(t *testing.T) {
|
||||
|
||||
// Apply the fix from issue #89
|
||||
if brokenSchema.Type == "object" && brokenSchema.Properties == nil {
|
||||
brokenSchema.Properties = make(openapi3.Schemas)
|
||||
brokenSchema.Properties = jsonschema.NewProperties()
|
||||
}
|
||||
|
||||
// Verify the fix worked
|
||||
@@ -153,12 +154,224 @@ func TestIssue89_ObjectSchemaMissingProperties(t *testing.T) {
|
||||
|
||||
// Test that we can create a ParamsOneOf from the fixed schema
|
||||
// This is what would fail before the fix
|
||||
paramsOneOf := schema.NewParamsOneOfByOpenAPIV3(brokenSchema)
|
||||
paramsOneOf := schema.NewParamsOneOfByJSONSchema(brokenSchema)
|
||||
if paramsOneOf == nil {
|
||||
t.Error("Failed to create ParamsOneOf from fixed schema - OpenAI function calling would fail")
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertExclusiveBoundsToBoolean tests the JSON Schema draft-07 to draft-04 conversion
|
||||
// for exclusiveMinimum and exclusiveMaximum fields.
|
||||
// Draft-07: exclusiveMinimum/exclusiveMaximum are numeric values (the actual bounds)
|
||||
// Draft-04: exclusiveMinimum/exclusiveMaximum are booleans that modify minimum/maximum
|
||||
func TestConvertExclusiveBoundsToBoolean(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "exclusiveMinimum as number",
|
||||
input: `{"type": "number", "exclusiveMinimum": 0}`,
|
||||
expected: map[string]interface{}{
|
||||
"type": "number",
|
||||
"minimum": float64(0),
|
||||
"exclusiveMinimum": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "exclusiveMaximum as number",
|
||||
input: `{"type": "number", "exclusiveMaximum": 100}`,
|
||||
expected: map[string]interface{}{
|
||||
"type": "number",
|
||||
"maximum": float64(100),
|
||||
"exclusiveMaximum": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "both exclusive bounds as numbers",
|
||||
input: `{"type": "integer", "exclusiveMinimum": 1, "exclusiveMaximum": 10}`,
|
||||
expected: map[string]interface{}{
|
||||
"type": "integer",
|
||||
"minimum": float64(1),
|
||||
"exclusiveMinimum": true,
|
||||
"maximum": float64(10),
|
||||
"exclusiveMaximum": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "already boolean exclusiveMinimum (draft-04 style)",
|
||||
input: `{"type": "number", "minimum": 0, "exclusiveMinimum": true}`,
|
||||
expected: map[string]interface{}{
|
||||
"type": "number",
|
||||
"minimum": float64(0),
|
||||
"exclusiveMinimum": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no exclusive bounds",
|
||||
input: `{"type": "string", "minLength": 1}`,
|
||||
expected: map[string]interface{}{
|
||||
"type": "string",
|
||||
"minLength": float64(1),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nested properties with exclusive bounds",
|
||||
input: `{"type": "object", "properties": {"age": {"type": "integer", "exclusiveMinimum": 0}}}`,
|
||||
expected: map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"age": map[string]interface{}{
|
||||
"type": "integer",
|
||||
"minimum": float64(0),
|
||||
"exclusiveMinimum": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "array items with exclusive bounds",
|
||||
input: `{"type": "array", "items": {"type": "number", "exclusiveMaximum": 100}}`,
|
||||
expected: map[string]interface{}{
|
||||
"type": "array",
|
||||
"items": map[string]interface{}{
|
||||
"type": "number",
|
||||
"maximum": float64(100),
|
||||
"exclusiveMaximum": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "allOf with exclusive bounds",
|
||||
input: `{"allOf": [{"type": "number", "exclusiveMinimum": 0}]}`,
|
||||
expected: map[string]interface{}{
|
||||
"allOf": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "number",
|
||||
"minimum": float64(0),
|
||||
"exclusiveMinimum": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "additionalProperties with exclusive bounds",
|
||||
input: `{"type": "object", "additionalProperties": {"type": "integer", "exclusiveMinimum": 0, "exclusiveMaximum": 255}}`,
|
||||
expected: map[string]interface{}{
|
||||
"type": "object",
|
||||
"additionalProperties": map[string]interface{}{
|
||||
"type": "integer",
|
||||
"minimum": float64(0),
|
||||
"exclusiveMinimum": true,
|
||||
"maximum": float64(255),
|
||||
"exclusiveMaximum": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Chrome DevTools MCP style schema (real-world example)",
|
||||
input: `{"type": "object", "properties": {"timeout": {"type": "integer", "exclusiveMinimum": 0}, "quality": {"type": "number", "minimum": 0, "maximum": 100}}}`,
|
||||
expected: map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"timeout": map[string]interface{}{
|
||||
"type": "integer",
|
||||
"minimum": float64(0),
|
||||
"exclusiveMinimum": true,
|
||||
},
|
||||
"quality": map[string]interface{}{
|
||||
"type": "number",
|
||||
"minimum": float64(0),
|
||||
"maximum": float64(100),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := convertExclusiveBoundsToBoolean([]byte(tt.input))
|
||||
|
||||
var got map[string]interface{}
|
||||
if err := json.Unmarshal(result, &got); err != nil {
|
||||
t.Fatalf("Failed to unmarshal result: %v", err)
|
||||
}
|
||||
|
||||
if !deepEqual(got, tt.expected) {
|
||||
t.Errorf("convertExclusiveBoundsToBoolean() =\n%v\nwant:\n%v", got, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertExclusiveBoundsToBoolean_InvalidJSON tests that invalid JSON is returned unchanged
|
||||
func TestConvertExclusiveBoundsToBoolean_InvalidJSON(t *testing.T) {
|
||||
invalidJSON := []byte(`{invalid json}`)
|
||||
result := convertExclusiveBoundsToBoolean(invalidJSON)
|
||||
|
||||
if string(result) != string(invalidJSON) {
|
||||
t.Errorf("Expected invalid JSON to be returned unchanged, got: %s", string(result))
|
||||
}
|
||||
}
|
||||
|
||||
// deepEqual compares two maps recursively
|
||||
func deepEqual(a, b map[string]interface{}) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for k, v := range a {
|
||||
bv, ok := b[k]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
switch av := v.(type) {
|
||||
case map[string]interface{}:
|
||||
bvm, ok := bv.(map[string]interface{})
|
||||
if !ok || !deepEqual(av, bvm) {
|
||||
return false
|
||||
}
|
||||
case []interface{}:
|
||||
bva, ok := bv.([]interface{})
|
||||
if !ok || !sliceEqual(av, bva) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if v != bv {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// sliceEqual compares two slices recursively
|
||||
func sliceEqual(a, b []interface{}) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := range a {
|
||||
switch av := a[i].(type) {
|
||||
case map[string]interface{}:
|
||||
bvm, ok := b[i].(map[string]interface{})
|
||||
if !ok || !deepEqual(av, bvm) {
|
||||
return false
|
||||
}
|
||||
case []interface{}:
|
||||
bva, ok := b[i].([]interface{})
|
||||
if !ok || !sliceEqual(av, bva) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Helper function to check if a string contains a substring
|
||||
func contains(s, substr string) bool {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
|
||||
+17
-3
@@ -13,9 +13,7 @@ import (
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
var (
|
||||
promptStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("12"))
|
||||
)
|
||||
var promptStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("12"))
|
||||
|
||||
// CLI manages the command-line interface for MCPHost, providing message rendering,
|
||||
// user input handling, and display management. It supports both standard and compact
|
||||
@@ -377,6 +375,22 @@ func (c *CLI) IsSlashCommand(input string) bool {
|
||||
return strings.HasPrefix(input, "/")
|
||||
}
|
||||
|
||||
// GetToolApproval asks the user for permission to execute the tool with the given
|
||||
// arguments. Returns true if the user approves.
|
||||
func (c *CLI) GetToolApproval(toolName, toolArgs string) (bool, error) {
|
||||
input := NewToolApprovalInput(toolName, toolArgs, c.width)
|
||||
p := tea.NewProgram(input)
|
||||
finalModel, err := p.Run()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if finalInput, ok := finalModel.(*ToolApprovalInput); ok {
|
||||
return finalInput.approved, nil
|
||||
}
|
||||
return false, fmt.Errorf("GetToolApproval: unexpected error type")
|
||||
}
|
||||
|
||||
// SlashCommandResult encapsulates the outcome of processing a slash command,
|
||||
// indicating whether the command was recognized and handled, and whether the
|
||||
// conversation history should be cleared as a result of the command.
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/textarea"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
type ToolApprovalInput struct {
|
||||
textarea textarea.Model
|
||||
toolName string
|
||||
toolArgs string
|
||||
width int
|
||||
selected bool // true when "yes" is highlighted and false when "no" is
|
||||
approved bool
|
||||
done bool
|
||||
}
|
||||
|
||||
func NewToolApprovalInput(toolName, toolArgs string, width int) *ToolApprovalInput {
|
||||
ta := textarea.New()
|
||||
ta.Placeholder = ""
|
||||
ta.ShowLineNumbers = false
|
||||
ta.CharLimit = 1000
|
||||
ta.SetWidth(width - 8) // Account for container padding, border and internal padding
|
||||
ta.SetHeight(4) // Default to 3 lines like huh
|
||||
ta.Focus()
|
||||
|
||||
// Style the textarea to match huh theme
|
||||
ta.FocusedStyle.Base = lipgloss.NewStyle()
|
||||
ta.FocusedStyle.Placeholder = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
|
||||
ta.FocusedStyle.Text = lipgloss.NewStyle().Foreground(lipgloss.Color("252"))
|
||||
ta.FocusedStyle.Prompt = lipgloss.NewStyle()
|
||||
ta.FocusedStyle.CursorLine = lipgloss.NewStyle()
|
||||
ta.Cursor.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("39"))
|
||||
|
||||
return &ToolApprovalInput{
|
||||
textarea: ta,
|
||||
toolName: toolName,
|
||||
toolArgs: toolArgs,
|
||||
width: width,
|
||||
selected: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *ToolApprovalInput) Init() tea.Cmd {
|
||||
return textarea.Blink
|
||||
}
|
||||
|
||||
func (t *ToolApprovalInput) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "y", "Y":
|
||||
t.approved = true
|
||||
t.done = true
|
||||
return t, tea.Quit
|
||||
case "n", "N":
|
||||
t.approved = false
|
||||
t.done = true
|
||||
return t, tea.Quit
|
||||
case "left":
|
||||
t.selected = true
|
||||
return t, nil
|
||||
case "right":
|
||||
t.selected = false
|
||||
return t, nil
|
||||
case "enter":
|
||||
t.approved = t.selected
|
||||
t.done = true
|
||||
return t, tea.Quit
|
||||
case "esc", "ctrl+c":
|
||||
t.approved = false
|
||||
t.done = true
|
||||
return t, tea.Quit
|
||||
}
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (t *ToolApprovalInput) View() string {
|
||||
if t.done {
|
||||
return "we are done"
|
||||
}
|
||||
// Add left padding to entire component (2 spaces like other UI elements)
|
||||
containerStyle := lipgloss.NewStyle().PaddingLeft(2)
|
||||
|
||||
// Title
|
||||
titleStyle := lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("252")).
|
||||
MarginBottom(1)
|
||||
|
||||
// Input box with huh-like styling
|
||||
inputBoxStyle := lipgloss.NewStyle().
|
||||
Border(lipgloss.ThickBorder()).
|
||||
BorderLeft(true).
|
||||
BorderRight(false).
|
||||
BorderTop(false).
|
||||
BorderBottom(false).
|
||||
BorderForeground(lipgloss.Color("39")).
|
||||
PaddingLeft(1).
|
||||
Width(t.width - 2) // Account for container padding
|
||||
|
||||
// Style for the currently selected/highlighted option
|
||||
selectedStyle := lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("42")). // Bright green
|
||||
Bold(true).
|
||||
Underline(true)
|
||||
|
||||
// Style for the unselected/unhighlighted option
|
||||
unselectedStyle := lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("240")) // Dark gray
|
||||
|
||||
// Build the view
|
||||
var view strings.Builder
|
||||
view.WriteString(titleStyle.Render("Allow tool execution"))
|
||||
view.WriteString("\n")
|
||||
details := fmt.Sprintf("Tool: %s\nArguments: %s\n\n", t.toolName, t.toolArgs)
|
||||
view.WriteString(details)
|
||||
view.WriteString("Allow tool execution: ")
|
||||
|
||||
var yesText, noText string
|
||||
if t.selected {
|
||||
yesText = selectedStyle.Render("[y]es")
|
||||
noText = unselectedStyle.Render("[n]o")
|
||||
} else {
|
||||
yesText = unselectedStyle.Render("[y]es")
|
||||
noText = selectedStyle.Render("[n]o")
|
||||
}
|
||||
view.WriteString(yesText + "/" + noText + "\n")
|
||||
|
||||
return containerStyle.Render(inputBoxStyle.Render(view.String()))
|
||||
}
|
||||
@@ -142,6 +142,7 @@ func (m *MCPHost) Prompt(ctx context.Context, message string) (string, error) {
|
||||
nil, // onToolResult
|
||||
nil, // onResponse
|
||||
nil, // onToolCallContent
|
||||
nil, // onToolApproval
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -181,6 +182,7 @@ func (m *MCPHost) PromptWithCallbacks(
|
||||
nil, // onResponse
|
||||
nil, // onToolCallContent
|
||||
onStreaming,
|
||||
nil, // onToolApproval
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -2,12 +2,17 @@ package sdk_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/mark3labs/mcphost/sdk"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
if os.Getenv("ANTHROPIC_API_KEY") == "" {
|
||||
t.Skip("Skipping test: ANTHROPIC_API_KEY not set")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Test default initialization
|
||||
@@ -23,6 +28,10 @@ func TestNew(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewWithOptions(t *testing.T) {
|
||||
if os.Getenv("ANTHROPIC_API_KEY") == "" {
|
||||
t.Skip("Skipping test: ANTHROPIC_API_KEY not set")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
opts := &sdk.Options{
|
||||
@@ -43,6 +52,10 @@ func TestNewWithOptions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSessionManagement(t *testing.T) {
|
||||
if os.Getenv("ANTHROPIC_API_KEY") == "" {
|
||||
t.Skip("Skipping test: ANTHROPIC_API_KEY not set")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
host, err := sdk.New(ctx, &sdk.Options{Quiet: true})
|
||||
|
||||
Reference in New Issue
Block a user