Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assitants #5

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
48 changes: 48 additions & 0 deletions cmd/llmt/config/analyze_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package config

import (
"errors"
"fmt"
"os"

"gopkg.in/yaml.v3"
)

type AnalyzeConfig struct {
Version string `yaml:"version"`
Analyzers []*ProjectAnalyzerConfig `yaml:"analyzers"`
}

type Assistant struct {
Name *string
Description *string
Files *[]string
}

type ProjectAnalyzerConfig struct {
Prompt string `yaml:"prompt"`
Analyzer string `yaml:"analyzer"`
Model string `yaml:"model"`
Regex *string `yaml:"regex"`
In *[]string `yaml:"in"`
NotIn *[]string `yaml:"not_in"`
Assistant *Assistant `yaml:"assistant"`
}

var ErrRetrievingConfig = errors.New("error retrieving Config")

func GetAnalyzeConfig(configPath string) (AnalyzeConfig, error) {
var c *AnalyzeConfig

yamlFile, err := os.ReadFile(configPath)
if err != nil {
return AnalyzeConfig{}, fmt.Errorf("%w: %v", ErrRetrievingConfig, err)
}

err = yaml.Unmarshal(yamlFile, &c)
if err != nil {
return AnalyzeConfig{}, fmt.Errorf("%w: %v", ErrRetrievingConfig, err)
}

return *c, nil
}
27 changes: 16 additions & 11 deletions cmd/llmt/handler/analyze/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"context"
"os"

"github.com/blwsh/llmt/config"
"github.com/blwsh/llmt/cmd/llmt/config"
"github.com/blwsh/llmt/lib/logger"
"github.com/blwsh/llmt/pkg/analyzer"
"github.com/blwsh/llmt/pkg/analyzer/project_analyzer/chat"
"github.com/blwsh/llmt/pkg/analyzer/project_analyzer/assistant"
)

const (
Expand All @@ -17,10 +17,10 @@ const (

var log = logger.NewCMDLogger()

func Analyze(ctx context.Context, source, target string, c config.Config) error {
func Analyze(ctx context.Context, source, target string, c config.AnalyzeConfig) error {
var (
writer = markdownWriter{logger: log}
resolver = analyzerResolver{
resolver = itemAnalyzerResolver{
OpenAITokenResolver: func() string {
var openAIToken string
if openAIToken = os.Getenv(envOpenAIToken); os.Getenv(envOpenAIToken) == "" {
Expand All @@ -38,25 +38,30 @@ func Analyze(ctx context.Context, source, target string, c config.Config) error
return ollamaHost
},
}
compiledRegexes = compileRegexesFromConfig(c)
analyzers []analyzer.FileAnalyzerConfig
condition = checker{compiledRegexes: compileRegexesFromConfig(c)}
analyzers []analyzer.FileAnalyzer
)

for _, a := range c.Analyzers {
an, err := resolver.resolve(a.Analyzer, a.Model)
itemAnalyzer, err := resolver.resolve(a.Analyzer, a.Model)
if err != nil {
log.Warnf("failed to resolve analyzer %s: %v", a.Analyzer, err)
}

analyzers = append(analyzers, analyzer.FileAnalyzerConfig{
condition.a = a

analyzers = append(analyzers, analyzer.FileAnalyzer{
Prompt: a.Prompt,
Analyzer: an,
Condition: condition(a, compiledRegexes),
Model: a.Model,
Assistant: a.Assistant,
ItemAnalyzer: itemAnalyzer,
Condition: condition.check,
ResultHandler: writer.write,
})
}

err := chat.New(chat.WithLogger(log)).AnalyzeProject(ctx, source, target, analyzers)
err := assistant.New(resolver.OpenAITokenResolver(), assistant.WithLogger(log)).
AnalyzeProject(ctx, source, target, analyzers, nil)
if err != nil {
return err
}
Expand Down
59 changes: 59 additions & 0 deletions cmd/llmt/handler/analyze/checker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package analyze

import (
"regexp"
"strings"

"github.com/blwsh/llmt/cmd/llmt/config"
)

type checker struct {
a *config.ProjectAnalyzerConfig
compiledRegexes map[*config.ProjectAnalyzerConfig]*regexp.Regexp
}

func (c checker) check(filePath string) bool {
if c.a.NotIn != nil {
for _, notIn := range *c.a.NotIn {
if strings.Contains(filePath, notIn) {
return false
}
}
}

if c.a.In != nil {
var inMatchFound = false
for _, in := range *c.a.In {
if strings.Contains(filePath, in) {
inMatchFound = true
break
}
}
if !inMatchFound {
return false
}
}

if compile, ok := c.compiledRegexes[c.a]; ok {
return compile.MatchString(filePath)
}

return true
}

func compileRegexesFromConfig(c config.AnalyzeConfig) map[*config.ProjectAnalyzerConfig]*regexp.Regexp {
var compiledRegexes = make(map[*config.ProjectAnalyzerConfig]*regexp.Regexp)

for _, analyzer := range c.Analyzers {
if analyzer.Regex != nil {
compiledRegex, err := regexp.Compile(*analyzer.Regex)
if err != nil {
log.Warnf("failed to compile regex %s: %v", analyzer.Regex, err)
}

compiledRegexes[analyzer] = compiledRegex
}
}

return compiledRegexes
}
56 changes: 0 additions & 56 deletions cmd/llmt/handler/analyze/condition.go

This file was deleted.

6 changes: 3 additions & 3 deletions cmd/llmt/handler/analyze/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import (

"github.com/blwsh/llmt/pkg/analyzer"
"github.com/blwsh/llmt/pkg/analyzer/item_analyzer/ollama"
"github.com/blwsh/llmt/pkg/analyzer/item_analyzer/openai"
openai "github.com/blwsh/llmt/pkg/analyzer/item_analyzer/openai/assitant"
)

var ErrUnknownAnalyzer = errors.New("unknown analyzer")

type analyzerResolver struct {
type itemAnalyzerResolver struct {
OpenAITokenResolver func() string
OllamaHostResolver func() string
}

func (a analyzerResolver) resolve(analyzer, model string) (analyzer.ItemAnalyzer, error) {
func (a itemAnalyzerResolver) resolve(analyzer, model string) (analyzer.ItemAnalyzer, error) {
switch analyzer {
case "openai":
return openai.New(a.OpenAITokenResolver(), model), nil
Expand Down
43 changes: 23 additions & 20 deletions cmd/llmt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (

"github.com/spf13/cobra"

"github.com/blwsh/llmt/cmd/llmt/config"
"github.com/blwsh/llmt/cmd/llmt/handler/analyze"
"github.com/blwsh/llmt/config"
)

var (
Expand All @@ -26,29 +26,32 @@ func main() {
rootCmd := &cobra.Command{Use: "llmt", Short: "llmt is a tool for analyzing projects"}

rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", defaultConfigPath, "config file path")

rootCmd.AddCommand(&cobra.Command{
Use: "analyze",
Aliases: []string{"analyse", "a"},
Short: "analyze a project",
Args: cobra.ExactArgs(2),
ValidArgs: []string{"source", "target"},
Use: "analyze", Aliases: []string{"analyse", "a"},
Short: "analyze a project", Long: "analyze a project",
Args: cobra.ExactArgs(2), ValidArgs: []string{"source", "target"},
Run: func(cmd *cobra.Command, args []string) {
cfg, err := config.GetConfig(configPath)
if err != nil {
log.Fatalf("failed to get config: %v", err)
}

source := strings.Replace(args[0], "~", os.Getenv("HOME"), 1)
target := strings.Replace(args[1], "~", os.Getenv("HOME"), 1)

if err := analyze.Analyze(ctx, source, target, cfg); err != nil {
log.Fatalf("failed to analyze project: %v", err)
}
fatalOnErr(analyze.Analyze(ctx, path(args[0]), path(args[1]), must(config.GetAnalyzeConfig(configPath))))
},
})

if err := rootCmd.Execute(); err != nil {
log.Fatalf("failed to execute command: %v", err)
fatalOnErr(rootCmd.Execute())
}

// path replaces ~ with the home directory
func path(path string) string {
return strings.Replace(path, "~", os.Getenv("HOME"), 1)
}

// fatalOnErr logs the error and exits if the error is not nil
func fatalOnErr(err error) {
if err != nil {
log.Fatalf(err.Error())
}
}

// must take a tuple of (out, err) and return out if err is nil, otherwise log the error and exit
func must[T any](out T, err error) T {
fatalOnErr(err)
return out
}
41 changes: 0 additions & 41 deletions config/config.go

This file was deleted.

19 changes: 12 additions & 7 deletions example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
version: "0.1"

analyzers:
- prompt: What is your name?
analyzer: openai
model: gpt-4o-mini
regex: ^.+\.php$
not_in:
- vendor
- node_modules
- prompt: You're a wise old owl who has lived for thousands of years. You help weary travelers with your wisdom. One day, a young traveler approaches you and asks for your advice. What do you say?
analyzer: openai
model: gpt-4o-mini
regex: ^.+\.php$
not_in:
- vendor
- node_modules
assistant:
name: "Wise Old Owl"
description: "I am a wise old owl that can impart wisdom and advice."
files: # files to be included for the assistant
- ~/owl-quotes.txt
Loading
Loading