mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-01-09 22:38:10 -05:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba2e178e03 | ||
|
|
ed298bcedd | ||
|
|
6b04e6e674 | ||
|
|
04c0f6a0a5 | ||
|
|
f7ab484510 | ||
|
|
f50a14305a | ||
|
|
d5f0cd7616 | ||
|
|
67c658f5b4 | ||
|
|
ef3bc03343 | ||
|
|
e31cb2b46a | ||
|
|
6ca7142ea4 | ||
|
|
8b2174897a | ||
|
|
ac5eab0563 | ||
|
|
65414dcc1c | ||
|
|
5db352f5be | ||
|
|
9e7830ff77 | ||
|
|
5945c0e16b | ||
|
|
29ee141822 | ||
|
|
8a69621e87 | ||
|
|
1645b0c4ea | ||
|
|
45205574d5 | ||
|
|
71a5e0394a | ||
|
|
f286936c23 | ||
|
|
9000f92a55 | ||
|
|
8c84d4b3c8 | ||
|
|
1d77afcc44 | ||
|
|
835bc6044b | ||
|
|
ef895a1ab9 | ||
|
|
82039cedaf | ||
|
|
973df61dfd | ||
|
|
661c85d7a6 |
14
README.md
14
README.md
@@ -76,15 +76,16 @@ Fabric is graciously supported by…
|
||||
- [Clipboard Support](#clipboard-support)
|
||||
- [Meta](#meta)
|
||||
- [Primary contributors](#primary-contributors)
|
||||
- [Contributors](#contributors)
|
||||
|
||||
<br />
|
||||
|
||||
## Updates
|
||||
|
||||
> [!NOTE]
|
||||
> February 24, 2025
|
||||
> April 16, 2025
|
||||
>
|
||||
> - Fabric now supports Sonnet 3.7! Update and use `-S` to select it as your default if you want, or just use the shortcut `-m claude-3-7-sonnet-latest`. Enjoy!
|
||||
> - Fabric now supports Grok (from XAI)! Update and use `-S` to select it as your default if you want, or just use the shortcut `-m grok-3-beta`. Enjoy!
|
||||
|
||||
## What and why
|
||||
|
||||
@@ -475,6 +476,7 @@ Application Options:
|
||||
--rmextension= Remove a registered extension by name
|
||||
--strategy= Choose a strategy from the available strategies
|
||||
--liststrategies List all strategies
|
||||
--listvendors List all vendors
|
||||
|
||||
Help Options:
|
||||
-h, --help Show this help message
|
||||
@@ -716,6 +718,14 @@ The Streamlit UI supports clipboard operations across different platforms:
|
||||
<a href="https://github.com/sbehrens"><img src="https://avatars.githubusercontent.com/u/688589?v=4" title="Scott Behrens" width="50" height="50"></a>
|
||||
<a href="https://github.com/agu3rra"><img src="https://avatars.githubusercontent.com/u/10410523?v=4" title="Andre Guerra" width="50" height="50"></a>
|
||||
|
||||
### Contributors
|
||||
|
||||
<a href="https://github.com/danielmiessler/fabric/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=danielmiessler/fabric" />
|
||||
</a>
|
||||
|
||||
Made with [contrib.rocks](https://contrib.rocks).
|
||||
|
||||
`fabric` was created by <a href="https://danielmiessler.com/subscribe" target="_blank">Daniel Miessler</a> in January of 2024.
|
||||
<br /><br />
|
||||
<a href="https://twitter.com/intent/user?screen_name=danielmiessler"></a>
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
# YAML Configuration Support
|
||||
|
||||
## Overview
|
||||
|
||||
Fabric now supports YAML configuration files for commonly used options. This allows users to persist settings and share configurations across multiple runs.
|
||||
|
||||
## Usage
|
||||
|
||||
Use the `--config` flag to specify a YAML configuration file:
|
||||
|
||||
```bash
|
||||
fabric --config ~/.config/fabric/config.yaml "Tell me about APIs"
|
||||
```
|
||||
|
||||
## Configuration Precedence
|
||||
|
||||
1. CLI flags (highest priority)
|
||||
2. YAML config values
|
||||
3. Default values (lowest priority)
|
||||
|
||||
## Supported Configuration Options
|
||||
|
||||
```yaml
|
||||
# Model selection
|
||||
model: gpt-4
|
||||
@@ -36,6 +41,7 @@ raw: false
|
||||
```
|
||||
|
||||
## Rules and Behavior
|
||||
|
||||
- Only long flag names are supported in YAML (e.g., `temperature` not `-t`)
|
||||
- CLI flags always override YAML values
|
||||
- Unknown YAML declarations are ignored
|
||||
@@ -43,12 +49,15 @@ raw: false
|
||||
- The order of YAML declarations doesn't matter
|
||||
|
||||
## Type Conversions
|
||||
|
||||
The following string-to-type conversions are supported:
|
||||
|
||||
- String to number: `"42"` → `42`
|
||||
- String to float: `"42.5"` → `42.5`
|
||||
- String to boolean: `"true"` → `true`
|
||||
|
||||
## Example Config
|
||||
|
||||
```yaml
|
||||
# ~/.config/fabric/config.yaml
|
||||
model: gpt-4
|
||||
@@ -61,8 +70,8 @@ frequencypenalty: 0.2
|
||||
```
|
||||
|
||||
## CLI Override Example
|
||||
|
||||
```bash
|
||||
# Override temperature from config
|
||||
fabric --config ~/.config/fabric/config.yaml --temperature 0.9 "Query"
|
||||
```
|
||||
|
||||
|
||||
@@ -164,6 +164,11 @@ func Cli(version string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if currentFlags.ListVendors {
|
||||
err = registry.ListVendors(os.Stdout)
|
||||
return
|
||||
}
|
||||
|
||||
// if the interactive flag is set, run the interactive function
|
||||
// if currentFlags.Interactive {
|
||||
// interactive.Interactive()
|
||||
@@ -211,7 +216,9 @@ func Cli(version string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
messageTools, err = processYoutubeVideo(currentFlags, registry, videoId)
|
||||
if messageTools, err = processYoutubeVideo(currentFlags, registry, videoId); err != nil {
|
||||
return
|
||||
}
|
||||
if !currentFlags.IsChatRequest() {
|
||||
err = currentFlags.WriteOutput(messageTools)
|
||||
return
|
||||
|
||||
@@ -72,6 +72,7 @@ type Flags struct {
|
||||
RemoveExtension string `long:"rmextension" description:"Remove a registered extension by name"`
|
||||
Strategy string `long:"strategy" description:"Choose a strategy from the available strategies" default:""`
|
||||
ListStrategies bool `long:"liststrategies" description:"List all strategies"`
|
||||
ListVendors bool `long:"listvendors" description:"List all vendors"`
|
||||
}
|
||||
|
||||
var debug = false
|
||||
@@ -334,7 +335,6 @@ func (o *Flags) BuildChatRequest(Meta string) (ret *common.ChatRequest, err erro
|
||||
|
||||
func (o *Flags) AppendMessage(message string) {
|
||||
o.Message = AppendMessage(o.Message, message)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Flags) IsChatRequest() (ret bool) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
@@ -71,15 +73,31 @@ func (o *GroupsItemsSelector[I]) Print() {
|
||||
fmt.Printf("\n%v:\n", o.SelectionLabel)
|
||||
|
||||
var currentItemIndex int
|
||||
for _, groupItems := range o.GroupsItems {
|
||||
// Create a copy of groups to sort
|
||||
sortedGroupsItems := make([]*GroupItems[I], len(o.GroupsItems))
|
||||
copy(sortedGroupsItems, o.GroupsItems)
|
||||
|
||||
// Sort groups alphabetically case-insensitive
|
||||
sort.SliceStable(sortedGroupsItems, func(i, j int) bool {
|
||||
return strings.ToLower(sortedGroupsItems[i].Group) < strings.ToLower(sortedGroupsItems[j].Group)
|
||||
})
|
||||
|
||||
for _, groupItems := range sortedGroupsItems {
|
||||
fmt.Println()
|
||||
fmt.Printf("%s\n", groupItems.Group)
|
||||
fmt.Println()
|
||||
|
||||
for _, item := range groupItems.Items {
|
||||
// Create a copy of items to sort
|
||||
sortedItems := make([]I, len(groupItems.Items))
|
||||
copy(sortedItems, groupItems.Items)
|
||||
// Sort items alphabetically case-insensitive
|
||||
sort.SliceStable(sortedItems, func(i, j int) bool {
|
||||
return strings.ToLower(o.GetItemKey(sortedItems[i])) < strings.ToLower(o.GetItemKey(sortedItems[j]))
|
||||
})
|
||||
|
||||
for _, item := range sortedItems {
|
||||
currentItemIndex++
|
||||
fmt.Printf("\t[%d]\t%s\n", currentItemIndex, o.GetItemKey(item))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@ package core
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/danielmiessler/fabric/plugins/ai/exolab"
|
||||
"github.com/danielmiessler/fabric/plugins/strategy"
|
||||
@@ -17,17 +20,12 @@ import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/anthropic"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/azure"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/deepseek"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/dryrun"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/gemini"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/groq"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/litellm"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/lmstudio"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/mistral"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/ollama"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openrouter"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/siliconcloud"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai_compatible"
|
||||
"github.com/danielmiessler/fabric/plugins/db/fsdb"
|
||||
"github.com/danielmiessler/fabric/plugins/template"
|
||||
"github.com/danielmiessler/fabric/plugins/tools"
|
||||
@@ -56,27 +54,49 @@ func NewPluginRegistry(db *fsdb.Db) (ret *PluginRegistry, err error) {
|
||||
|
||||
ret.Defaults = tools.NeeDefaults(ret.GetModels)
|
||||
|
||||
ret.VendorsAll.AddVendors(
|
||||
// Create a vendors slice to hold all vendors (order doesn't matter initially)
|
||||
vendors := []ai.Vendor{}
|
||||
|
||||
// Add non-OpenAI compatible clients
|
||||
vendors = append(vendors,
|
||||
openai.NewClient(),
|
||||
ollama.NewClient(),
|
||||
azure.NewClient(),
|
||||
groq.NewClient(),
|
||||
gemini.NewClient(),
|
||||
//gemini_openai.NewClient(),
|
||||
anthropic.NewClient(),
|
||||
siliconcloud.NewClient(),
|
||||
openrouter.NewClient(),
|
||||
lmstudio.NewClient(),
|
||||
mistral.NewClient(),
|
||||
deepseek.NewClient(),
|
||||
exolab.NewClient(),
|
||||
litellm.NewClient(),
|
||||
)
|
||||
|
||||
// Add all OpenAI-compatible providers
|
||||
for providerName := range openai_compatible.ProviderMap {
|
||||
provider, _ := openai_compatible.GetProviderByName(providerName)
|
||||
vendors = append(vendors, openai_compatible.NewClient(provider))
|
||||
}
|
||||
|
||||
// Sort vendors by name for consistent ordering (case-insensitive)
|
||||
sort.Slice(vendors, func(i, j int) bool {
|
||||
return strings.ToLower(vendors[i].GetName()) < strings.ToLower(vendors[j].GetName())
|
||||
})
|
||||
|
||||
// Add all sorted vendors to VendorsAll
|
||||
ret.VendorsAll.AddVendors(vendors...)
|
||||
_ = ret.Configure()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (o *PluginRegistry) ListVendors(out io.Writer) error {
|
||||
vendors := lo.Map(o.VendorsAll.Vendors, func(vendor ai.Vendor, _ int) string {
|
||||
return vendor.GetName()
|
||||
})
|
||||
fmt.Fprint(out, "Available Vendors:\n\n")
|
||||
for _, vendor := range vendors {
|
||||
fmt.Fprintf(out, "%s\n", vendor)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PluginRegistry struct {
|
||||
Db *fsdb.Db
|
||||
|
||||
@@ -129,7 +149,7 @@ func (o *PluginRegistry) Setup() (err error) {
|
||||
return vendor
|
||||
})...)
|
||||
|
||||
groupsPlugins.AddGroupItems("Tools", o.Defaults, o.PatternsLoader, o.YouTube, o.Language, o.Jina, o.Strategies)
|
||||
groupsPlugins.AddGroupItems("Tools", o.Defaults, o.Jina, o.Language, o.PatternsLoader, o.Strategies, o.YouTube)
|
||||
|
||||
for {
|
||||
groupsPlugins.Print()
|
||||
|
||||
10
go.mod
10
go.mod
@@ -19,7 +19,7 @@ require (
|
||||
github.com/samber/lo v1.49.1
|
||||
github.com/sashabaranov/go-openai v1.38.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/text v0.22.0
|
||||
golang.org/x/text v0.23.0
|
||||
google.golang.org/api v0.223.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
@@ -89,11 +89,11 @@ require (
|
||||
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||
golang.org/x/arch v0.14.0 // indirect
|
||||
golang.org/x/crypto v0.35.0 // indirect
|
||||
golang.org/x/net v0.36.0 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/oauth2 v0.27.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/time v0.10.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250224174004-546df14abb99 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99 // indirect
|
||||
|
||||
24
go.sum
24
go.sum
@@ -224,8 +224,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
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.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
@@ -244,8 +244,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
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.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
|
||||
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -255,8 +255,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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -273,8 +273,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
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=
|
||||
@@ -284,8 +284,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
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.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -296,8 +296,8 @@ 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.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
||||
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
||||
@@ -239,23 +239,23 @@ schema = 3
|
||||
version = "v0.14.0"
|
||||
hash = "sha256-9akWthLBB+Au/JIg3WKcSx1YAfHEHOCnQF62sJoMJG4="
|
||||
[mod."golang.org/x/crypto"]
|
||||
version = "v0.35.0"
|
||||
hash = "sha256-XT1VU0+m1nZbhrMYXN2+eaKBlScfiT4bCBgXu4mfa1Q="
|
||||
[mod."golang.org/x/net"]
|
||||
version = "v0.36.0"
|
||||
hash = "sha256-2c9AvnizBMCaqKPzwF2IMlRfvjRNDFmxIYhrgZjhOm0="
|
||||
hash = "sha256-Np+suvZdMOXALDm4m8nDNa+QsvUV0rE0PEINuxCoKGM="
|
||||
[mod."golang.org/x/net"]
|
||||
version = "v0.38.0"
|
||||
hash = "sha256-iHmyxkZQLw1PsUZaXHMt84GrjbXPvkEc92sLoK3W++c="
|
||||
[mod."golang.org/x/oauth2"]
|
||||
version = "v0.27.0"
|
||||
hash = "sha256-TBKV2c/m0SgPqrJSE0ltJXfImrYPafNuziLN25jgsYY="
|
||||
[mod."golang.org/x/sync"]
|
||||
version = "v0.11.0"
|
||||
hash = "sha256-5ZBfDJvNaUBM4Vhk0fgYblCGL3eBxiJL85nIE8LiKl0="
|
||||
version = "v0.12.0"
|
||||
hash = "sha256-lPIbI6aXx+iKtFjPaXKNLEnuNfhHCVl7EQiE7alUvlM="
|
||||
[mod."golang.org/x/sys"]
|
||||
version = "v0.30.0"
|
||||
hash = "sha256-BuhWtwDkciVioc03rxty6G2vcZVnPX85lI7tgQOFVP8="
|
||||
version = "v0.31.0"
|
||||
hash = "sha256-aulv5obCrhheMlSq7seUgP3C29nfZABwiQ4IBNisgME="
|
||||
[mod."golang.org/x/text"]
|
||||
version = "v0.22.0"
|
||||
hash = "sha256-kUwLNFk9K/YuWmO5/u2IshrmhT2CCuk+mAShSlTTeZo="
|
||||
version = "v0.23.0"
|
||||
hash = "sha256-TiYX1K4DYpP1dEV06whOm43xyOntjrPFi+VAdncoeCY="
|
||||
[mod."golang.org/x/time"]
|
||||
version = "v0.10.0"
|
||||
hash = "sha256-vnlAME3gDR6R4cbCmSYAlR1Rjc0yUpkufTOPNvCdf6Q="
|
||||
|
||||
@@ -1 +1 @@
|
||||
"1.4.171"
|
||||
"1.4.179"
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package deepseek
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("DeepSeek", "https://api.deepseek.com", nil)
|
||||
return
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package deepseek
|
||||
|
||||
// Test generated using Keploy
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewClient_EmbeddedClientNotNil(t *testing.T) {
|
||||
client := NewClient()
|
||||
if client.Client == nil {
|
||||
t.Fatalf("Expected embedded openai.Client to be non-nil, got nil")
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package groq
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
// NewClient initializes and returns a new Groq Client.
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("Groq", "https://api.groq.com/openai/v1", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Client wraps the openai.Client to provide additional functionality specific to Groq.
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package groq
|
||||
|
||||
// Test generated using Keploy
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewClientEmbeddedClientNotNil(t *testing.T) {
|
||||
client := NewClient()
|
||||
if client.Client == nil {
|
||||
t.Fatalf("Expected embedded openai.Client to be non-nil, got nil")
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package litellm
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("LiteLLM", "http://localhost:4000", nil)
|
||||
return
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package mistral
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("Mistral", "https://api.mistral.ai/v1", nil)
|
||||
return
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
74
plugins/ai/openai_compatible/providers_config.go
Normal file
74
plugins/ai/openai_compatible/providers_config.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package openai_compatible
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
// ProviderConfig defines the configuration for an OpenAI-compatible API provider
|
||||
type ProviderConfig struct {
|
||||
Name string
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
// Client is the common structure for all OpenAI-compatible providers
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
|
||||
// NewClient creates a new OpenAI-compatible client for the specified provider
|
||||
func NewClient(providerConfig ProviderConfig) *Client {
|
||||
client := &Client{}
|
||||
client.Client = openai.NewClientCompatible(providerConfig.Name, providerConfig.BaseURL, nil)
|
||||
return client
|
||||
}
|
||||
|
||||
// ProviderMap is a map of provider name to ProviderConfig for O(1) lookup
|
||||
var ProviderMap = map[string]ProviderConfig{
|
||||
"Mistral": {
|
||||
Name: "Mistral",
|
||||
BaseURL: "https://api.mistral.ai/v1",
|
||||
},
|
||||
"LiteLLM": {
|
||||
Name: "LiteLLM",
|
||||
BaseURL: "http://localhost:4000",
|
||||
},
|
||||
"Groq": {
|
||||
Name: "Groq",
|
||||
BaseURL: "https://api.groq.com/openai/v1",
|
||||
},
|
||||
"GrokAI": {
|
||||
Name: "GrokAI",
|
||||
BaseURL: "https://api.x.ai/v1",
|
||||
},
|
||||
"DeepSeek": {
|
||||
Name: "DeepSeek",
|
||||
BaseURL: "https://api.deepseek.com",
|
||||
},
|
||||
"Cerebras": {
|
||||
Name: "Cerebras",
|
||||
BaseURL: "https://api.cerebras.ai/v1",
|
||||
},
|
||||
"OpenRouter": {
|
||||
Name: "OpenRouter",
|
||||
BaseURL: "https://openrouter.ai/api/v1",
|
||||
},
|
||||
"SiliconCloud": {
|
||||
Name: "SiliconCloud",
|
||||
BaseURL: "https://api.siliconflow.cn/v1",
|
||||
},
|
||||
}
|
||||
|
||||
// GetProviderByName returns the provider configuration for a given name with O(1) lookup
|
||||
func GetProviderByName(name string) (ProviderConfig, bool) {
|
||||
provider, found := ProviderMap[name]
|
||||
return provider, found
|
||||
}
|
||||
|
||||
// CreateClient creates a new client for a provider by name
|
||||
func CreateClient(providerName string) (*Client, bool) {
|
||||
providerConfig, found := GetProviderByName(providerName)
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
return NewClient(providerConfig), true
|
||||
}
|
||||
42
plugins/ai/openai_compatible/providers_config_test.go
Normal file
42
plugins/ai/openai_compatible/providers_config_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package openai_compatible
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCreateClient(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
provider string
|
||||
exists bool
|
||||
}{
|
||||
{
|
||||
name: "Existing provider - Mistral",
|
||||
provider: "Mistral",
|
||||
exists: true,
|
||||
},
|
||||
{
|
||||
name: "Existing provider - Groq",
|
||||
provider: "Groq",
|
||||
exists: true,
|
||||
},
|
||||
{
|
||||
name: "Non-existent provider",
|
||||
provider: "NonExistent",
|
||||
exists: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
client, exists := CreateClient(tc.provider)
|
||||
if exists != tc.exists {
|
||||
t.Errorf("Expected exists=%v for provider %s, got %v",
|
||||
tc.exists, tc.provider, exists)
|
||||
}
|
||||
if exists && client == nil {
|
||||
t.Errorf("Expected non-nil client for provider %s", tc.provider)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package openrouter
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("OpenRouter", "https://openrouter.ai/api/v1", nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package openrouter
|
||||
@@ -1,15 +0,0 @@
|
||||
package siliconcloud
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("SiliconCloud", "https://api.siliconflow.cn/v1", nil)
|
||||
return
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/danielmiessler/fabric/plugins"
|
||||
@@ -95,6 +97,9 @@ func (o *VendorsManager) readModels() (err error) {
|
||||
if result.err != nil {
|
||||
fmt.Println(result.vendorName, result.err)
|
||||
} else {
|
||||
sort.Slice(result.models, func(i, j int) bool {
|
||||
return strings.ToLower(result.models[i]) < strings.ToLower(result.models[j])
|
||||
})
|
||||
o.Models.AddGroupItems(result.vendorName, result.models...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func (o *StorageEntity) GetNames() (ret []string, err error) {
|
||||
}
|
||||
|
||||
func (o *StorageEntity) Delete(name string) (err error) {
|
||||
if err = os.Remove(o.BuildFilePathByName(name)); err != nil {
|
||||
if err = os.RemoveAll(o.BuildFilePathByName(name)); err != nil {
|
||||
err = fmt.Errorf("could not delete %s: %v", name, err)
|
||||
}
|
||||
return
|
||||
|
||||
@@ -45,6 +45,7 @@ func (h *ConfigHandler) GetConfig(c *gin.Context) {
|
||||
"openrouter": "",
|
||||
"silicon": "",
|
||||
"deepseek": "",
|
||||
"grokai": "",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -65,6 +66,7 @@ func (h *ConfigHandler) GetConfig(c *gin.Context) {
|
||||
"openrouter": os.Getenv("OPENROUTER_API_KEY"),
|
||||
"silicon": os.Getenv("SILICON_API_KEY"),
|
||||
"deepseek": os.Getenv("DEEPSEEK_API_KEY"),
|
||||
"grokai": os.Getenv("GROKAI_API_KEY"),
|
||||
"lmstudio": os.Getenv("LM_STUDIO_API_BASE_URL"),
|
||||
}
|
||||
|
||||
@@ -87,6 +89,7 @@ func (h *ConfigHandler) UpdateConfig(c *gin.Context) {
|
||||
OpenRouterApiKey string `json:"openrouter_api_key"`
|
||||
SiliconApiKey string `json:"silicon_api_key"`
|
||||
DeepSeekApiKey string `json:"deepseek_api_key"`
|
||||
GrokaiApiKey string `json:"grokai_api_key"`
|
||||
LMStudioURL string `json:"lm_studio_base_url"`
|
||||
}
|
||||
|
||||
@@ -105,6 +108,7 @@ func (h *ConfigHandler) UpdateConfig(c *gin.Context) {
|
||||
"OPENROUTER_API_KEY": config.OpenRouterApiKey,
|
||||
"SILICON_API_KEY": config.SiliconApiKey,
|
||||
"DEEPSEEK_API_KEY": config.DeepSeekApiKey,
|
||||
"GROKAI_API_KEY": config.GrokaiApiKey,
|
||||
"LM_STUDIO_API_BASE_URL": config.LMStudioURL,
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
type StrategyMeta struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Prompt string `json:"prompt"`
|
||||
}
|
||||
|
||||
// NewStrategiesHandler registers the /strategies GET endpoint
|
||||
@@ -41,16 +43,17 @@ func NewStrategiesHandler(r *gin.Engine) {
|
||||
}
|
||||
|
||||
var s struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Prompt string `json:"prompt"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &s); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
strategies = append(strategies, StrategyMeta{
|
||||
Name: s.Name,
|
||||
Name: strings.TrimSuffix(file.Name(), ".json"),
|
||||
Description: s.Description,
|
||||
Prompt: s.Prompt,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
4
strategies/aot.json
Normal file
4
strategies/aot.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"description": "Atom-of-Thought (AoT) Prompting",
|
||||
"prompt": "To solve this problem, break it down into the smallest independent 'atomic' sub-problems. For each atomic sub-problem: 1. Label it as 'Atom X: [brief description]' 2. Solve that specific subproblem completely 3. Make sure each atom can be solved independently. After solving all atomic sub-problems, provide a synthesis that combines them into a final answer. Return the final answer in the required format."
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
package main
|
||||
|
||||
var version = "v1.4.171"
|
||||
var version = "v1.4.179"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
[
|
||||
{ "name": "aot", "description": "Atom-of-Thought (AoT)" },
|
||||
{ "name": "cod", "description": "Chain-of-Draft (CoD)" },
|
||||
{ "name": "cot", "description": "Chain-of-Thought (CoT) Prompting" },
|
||||
{ "name": "ltm", "description": "Least-to-Most Prompting" },
|
||||
|
||||
Reference in New Issue
Block a user