Skip to content
Open
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
10 changes: 9 additions & 1 deletion cmd/pgedge-pg-mcp-svr/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -902,10 +902,18 @@ func main() {
Temperature: llm.Float(cfg.LLM.Temperature),
}
}
if cfg.LLM.GeminiAPIKey != "" {
providers["gemini"] = llm.Options{
APIKey: cfg.LLM.GeminiAPIKey,
Model: cfg.LLM.Model,
MaxTokens: llm.Int(cfg.LLM.MaxTokens),
Temperature: llm.Float(cfg.LLM.Temperature),
}
}

if len(providers) == 0 {
return fmt.Errorf("LLM is enabled but no provider is configured; " +
"set at least one of anthropic_api_key, openai_api_key, or ollama_url")
"set at least one of anthropic_api_key, openai_api_key, gemini_api_key, or ollama_url")
}

p := proxy.New(proxy.Config{
Expand Down
21 changes: 21 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,21 @@ and this project adheres to
exposed alongside the non-streaming endpoint. The non-streaming
`/v1/chat` endpoint remains available for callers that prefer it.

- The web chat interface now consumes the streaming endpoint
`/api/llm/v1/chat/stream` (Server-Sent Events) and renders the
assistant response incrementally as chunks arrive. The
non-streaming endpoint stays available for callers that prefer
it. A new `web/src/utils/sseChat.js` helper handles the SSE
parsing and assembles the final response into the same shape
the non-streaming endpoint returns, so the agentic chat loop is
unchanged.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- The tools `search_knowledgebase`, `generate_embedding`, and
`similarity_search` now construct their embedding client
directly via `llm.NewClient` rather than going through the old
`embedding.NewProvider` wrapper. The `internal/embedding/`
package is deleted entirely.

### Fixed

- Metadata loader now tolerates tables with zero columns
Expand Down Expand Up @@ -127,6 +142,12 @@ and this project adheres to
token and needing access to multiple databases). The setting is
honored by both the single-database and multi-database
initialization paths. (#167)

- Google Gemini is now a supported LLM provider. Configure via
`gemini_api_key` / `gemini_api_key_file` in the config file or
via the `PGEDGE_GEMINI_API_KEY` / `GEMINI_API_KEY` environment
variables.

### Fixed

- Fixed port detection on Windows; the installer now reliably
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/fsnotify/fsnotify v1.9.0
github.com/google/uuid v1.6.0
github.com/jackc/pgx/v5 v5.7.6
github.com/pgEdge/pgedge-go-llm-lib v0.0.0-20260528080856-17b5f11c6044
github.com/pgEdge/pgedge-go-llm-lib v0.1.0
golang.org/x/crypto v0.49.0
golang.org/x/term v0.41.0
gopkg.in/yaml.v3 v3.0.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ 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/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/pgEdge/pgedge-go-llm-lib v0.0.0-20260528080856-17b5f11c6044 h1:VvcBNVFKWnVoLdJfZQhXkE42sefQWhNTeB8mPYU5U/k=
github.com/pgEdge/pgedge-go-llm-lib v0.0.0-20260528080856-17b5f11c6044/go.mod h1:41rtSLcp/wwSUlBqetVHLQKisDZfzBmgSWt84WA+Eys=
github.com/pgEdge/pgedge-go-llm-lib v0.1.0 h1:IiCWA99un19rwdB1hlDPOm2Ft+43LsCvp0oAhbBM/Nk=
github.com/pgEdge/pgedge-go-llm-lib v0.1.0/go.mod h1:41rtSLcp/wwSUlBqetVHLQKisDZfzBmgSWt84WA+Eys=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
Expand Down
19 changes: 17 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ type EmbeddingConfig struct {
// LLMConfig holds LLM configuration for web client chat proxy
type LLMConfig struct {
Enabled bool `yaml:"enabled"` // Whether LLM proxy is enabled (default: false)
Provider string `yaml:"provider"` // "anthropic", "openai", or "ollama"
Provider string `yaml:"provider"` // "anthropic", "openai", "ollama", or "gemini"
Model string `yaml:"model"` // Provider-specific model name
AnthropicAPIKey string `yaml:"anthropic_api_key"` // API key for Anthropic (direct - discouraged, use api_key_file or env var instead)
AnthropicAPIKeyFile string `yaml:"anthropic_api_key_file"` // Path to file containing Anthropic API key
Expand All @@ -455,6 +455,8 @@ type LLMConfig struct {
OpenAIAPIKeyFile string `yaml:"openai_api_key_file"` // Path to file containing OpenAI API key
OpenAIBaseURL string `yaml:"openai_base_url"` // Base URL for OpenAI API (default: https://api.openai.com)
OllamaURL string `yaml:"ollama_url"` // URL for Ollama service (default: http://localhost:11434)
GeminiAPIKey string `yaml:"gemini_api_key"` // API key for Google Gemini (direct - discouraged, use api_key_file or env var instead)
GeminiAPIKeyFile string `yaml:"gemini_api_key_file"` // Path to file containing Gemini API key
Comment thread
coderabbitai[bot] marked this conversation as resolved.
MaxTokens int `yaml:"max_tokens"` // Maximum tokens for LLM response (default: 4096)
Temperature float64 `yaml:"temperature"` // Temperature for LLM sampling (default: 0.7)
}
Expand Down Expand Up @@ -750,6 +752,12 @@ func mergeConfig(dest, src *Config) {
if src.LLM.OllamaURL != "" {
dest.LLM.OllamaURL = src.LLM.OllamaURL
}
if src.LLM.GeminiAPIKey != "" {
dest.LLM.GeminiAPIKey = src.LLM.GeminiAPIKey
}
if src.LLM.GeminiAPIKeyFile != "" {
dest.LLM.GeminiAPIKeyFile = src.LLM.GeminiAPIKeyFile
}
if src.LLM.MaxTokens != 0 {
dest.LLM.MaxTokens = src.LLM.MaxTokens
}
Expand Down Expand Up @@ -1011,6 +1019,7 @@ func applyEnvironmentVariables(cfg *Config) {
// 1. Try environment variables first (PGEDGE_ prefixed, then standard)
setStringFromEnvWithFallback(&cfg.LLM.AnthropicAPIKey, "PGEDGE_ANTHROPIC_API_KEY", "ANTHROPIC_API_KEY")
setStringFromEnvWithFallback(&cfg.LLM.OpenAIAPIKey, "PGEDGE_OPENAI_API_KEY", "OPENAI_API_KEY")
setStringFromEnvWithFallback(&cfg.LLM.GeminiAPIKey, "PGEDGE_GEMINI_API_KEY", "GEMINI_API_KEY")
// 2. If env vars not set and api_key_file is specified, load from file
if cfg.LLM.AnthropicAPIKey == "" && cfg.LLM.AnthropicAPIKeyFile != "" {
if key, err := readAPIKeyFromFile(cfg.LLM.AnthropicAPIKeyFile); err == nil && key != "" {
Expand All @@ -1024,7 +1033,13 @@ func applyEnvironmentVariables(cfg *Config) {
}
// Note: errors are silently ignored - file may not exist and that's ok
}
// 3. Direct config value (if set) is already in cfg.LLM.AnthropicAPIKey/OpenAIAPIKey from mergeConfig
if cfg.LLM.GeminiAPIKey == "" && cfg.LLM.GeminiAPIKeyFile != "" {
if key, err := readAPIKeyFromFile(cfg.LLM.GeminiAPIKeyFile); err == nil && key != "" {
cfg.LLM.GeminiAPIKey = key
}
// Note: errors are silently ignored - file may not exist and that's ok
}
// 3. Direct config value (if set) is already in cfg.LLM.AnthropicAPIKey/OpenAIAPIKey/GeminiAPIKey from mergeConfig
setStringFromEnv(&cfg.LLM.OllamaURL, "PGEDGE_OLLAMA_URL")
// Base URL overrides for LLM providers (useful for proxies)
setStringFromEnv(&cfg.LLM.AnthropicBaseURL, "PGEDGE_ANTHROPIC_BASE_URL")
Expand Down
132 changes: 0 additions & 132 deletions internal/embedding/libprovider.go

This file was deleted.

Loading
Loading