Skip to content

Smart contract development editor with AI #15

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

Open
wants to merge 5 commits 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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ tasks.json
tasks/
.roo
.taskmasterconfig
scripts
scripts
projects-data-node1
68 changes: 0 additions & 68 deletions .vscode/launch.json

This file was deleted.

158 changes: 126 additions & 32 deletions cmd/serve/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ import (
metricscommon "github.com/chainlaunch/chainlaunch/pkg/metrics/common"
"github.com/chainlaunch/chainlaunch/pkg/monitoring"
nodeTypes "github.com/chainlaunch/chainlaunch/pkg/nodes/types"
"github.com/chainlaunch/chainlaunch/pkg/scai/ai"
"github.com/chainlaunch/chainlaunch/pkg/scai/boilerplates"
"github.com/chainlaunch/chainlaunch/pkg/scai/dirs"
"github.com/chainlaunch/chainlaunch/pkg/scai/files"
"github.com/chainlaunch/chainlaunch/pkg/scai/projectrunner"
"github.com/chainlaunch/chainlaunch/pkg/scai/projects"

"github.com/chainlaunch/chainlaunch/pkg/audit"
"github.com/chainlaunch/chainlaunch/pkg/chainlaunchdeploy"
Expand All @@ -48,10 +54,7 @@ import (
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/sqlite3"
_ "github.com/golang-migrate/migrate/v4/source/file"
"github.com/golang-migrate/migrate/v4/source/iofs"
_ "github.com/mattn/go-sqlite3"
"github.com/spf13/cobra"
httpSwagger "github.com/swaggo/http-swagger"
Expand Down Expand Up @@ -283,7 +286,7 @@ func ensureKeyExists(filename string, dataPath string) (string, error) {
}

// setupServer configures and returns the HTTP server
func setupServer(queries *db.Queries, authService *auth.AuthService, views embed.FS, dev bool, dbPath string, dataPath string) *chi.Mux {
func (c *serveCmd) setupServer(queries *db.Queries, authService *auth.AuthService, views embed.FS, dev bool, dbPath string, dataPath string, projectsDir string) *chi.Mux {
// Initialize services
keyManagementService, err := service.NewKeyManagementService(queries)
if err != nil {
Expand Down Expand Up @@ -488,6 +491,51 @@ func setupServer(queries *db.Queries, authService *auth.AuthService, views embed
notificationHandler := notificationhttp.NewNotificationHandler(notificationService)
authHandler := auth.NewHandler(authService)
auditHandler := audit.NewHandler(auditService, logger)

// AI handlers

var aiClient ai.AIClient
switch c.aiProvider {
case "anthropic", "claude":
if c.anthropicKey == "" {
log.Fatal("ANTHROPIC_API_KEY is not set and --anthropic-key not provided")
}
aiClient = ai.NewClaudeAdapter(c.anthropicKey)
case "openai":
if c.openaiKey == "" {
log.Fatal("OPENAI_API_KEY is not set and --openai-key not provided")
}
aiClient = ai.NewOpenAIAdapter(c.openaiKey)
default:
log.Fatalf("Unknown AI provider: %s", c.aiProvider)
}

chatService := ai.NewChatService(queries)
openAIchatService := ai.NewOpenAIChatServiceWithClient(aiClient, logger, chatService, queries, projectsDir, c.aiModel)

// Re-initialize projectsService
runner := projectrunner.NewRunner(queries)
projectsService, err := projects.NewProjectsService(queries, runner, projectsDir, organizationService, keyManagementService, networksService)
if err != nil {
log.Fatalf("Failed to create projects service: %v", err)
}

// Register directory, file, and project handlers
dirsService := dirs.NewDirsService(projectsDir)
dirsHandler := dirs.NewDirsHandler(dirsService, projectsService)
filesService := files.NewFilesService()
filesHandler := files.NewFilesHandler(filesService, projectsService)

// Create the project runner and inject into ProjectsService
projectsHandler := projects.NewProjectsHandler(projectsService, projectsDir)

boilerplateService, err := boilerplates.NewBoilerplateService(queries)
if err != nil {
log.Fatalf("Failed to create boilerplate service: %v", err)
}
// Register AI API Gateway routes
aiHandler := ai.NewAIHandler(openAIchatService, chatService, projectsService, boilerplateService)

// Setup router
r := chi.NewRouter()

Expand Down Expand Up @@ -544,6 +592,16 @@ func setupServer(queries *db.Queries, authService *auth.AuthService, views embed

// Register smart contract deployment routes
scHandler.RegisterRoutes(r)

// Mount directory management routes
dirsHandler.RegisterRoutes(r)
// Mount file management routes
filesHandler.RegisterRoutes(r)
// Mount project management routes
projectsHandler.RegisterRoutes(r)
// Mount AI/ML routes
aiHandler.RegisterRoutes(r)

})
})
r.Get("/api/swagger/*", httpSwagger.Handler(
Expand Down Expand Up @@ -573,32 +631,6 @@ func setupServer(queries *db.Queries, authService *auth.AuthService, views embed
return r
}

func runMigrations(database *sql.DB, migrationsFS embed.FS) error {
driver, err := sqlite3.WithInstance(database, &sqlite3.Config{})
if err != nil {
return fmt.Errorf("could not create sqlite driver: %v", err)
}

// Use embedded migrations instead of file system
d, err := iofs.New(migrationsFS, "pkg/db/migrations")
if err != nil {
return fmt.Errorf("could not create iofs driver: %v", err)
}

m, err := migrate.NewWithInstance(
"iofs", d,
"sqlite3", driver,
)
if err != nil {
return fmt.Errorf("could not create migrate instance: %v", err)
}
if err := m.Up(); err != nil && err != migrate.ErrNoChange {
return fmt.Errorf("could not run migrations: %v", err)
}

return nil
}

type serveCmd struct {
logger *logger.Logger
configCMD config.ConfigCMD
Expand All @@ -609,8 +641,14 @@ type serveCmd struct {
tlsKeyFile string
dataPath string
dev bool
projectsDir string

queries *db.Queries

openaiKey string
anthropicKey string
aiProvider string
aiModel string
}

// validate validates the serve command configuration
Expand Down Expand Up @@ -672,7 +710,7 @@ func (c *serveCmd) preRun() error {
log.Fatalf("Failed to open database: %v", err)
}
// Run migrations
if err := runMigrations(database, c.configCMD.MigrationsFS); err != nil {
if err := db.RunMigrations(database); err != nil {
log.Fatalf("Failed to run migrations: %v", err)
}

Expand Down Expand Up @@ -756,7 +794,7 @@ func (c *serveCmd) run() error {
}

// Setup and start HTTP server
router := setupServer(c.queries, authService, c.configCMD.Views, c.dev, c.dbPath, c.dataPath)
router := c.setupServer(c.queries, authService, c.configCMD.Views, c.dev, c.dbPath, c.dataPath, c.projectsDir)

// Start HTTP server in a goroutine
httpServer := &http.Server{
Expand Down Expand Up @@ -822,6 +860,9 @@ For example:
cmd.Flags().StringVar(&serveCmd.tlsCertFile, "tls-cert", "", "Path to TLS certificate file for HTTP server (required)")
cmd.Flags().StringVar(&serveCmd.tlsKeyFile, "tls-key", "", "Path to TLS key file for HTTP server (required)")

// Add projects directory flag
cmd.Flags().StringVar(&serveCmd.projectsDir, "projects", "projects-data", "Path to projects directory")

// Update the default data path to use the OS-specific user config directory
defaultDataPath := ""
if configDir, err := os.UserConfigDir(); err == nil {
Expand All @@ -837,5 +878,58 @@ For example:
// Add development mode flag
cmd.Flags().BoolVar(&serveCmd.dev, "dev", false, "Run in development mode")

// Add new flags
cmd.Flags().StringVar(&serveCmd.openaiKey, "openai-key", os.Getenv("OPENAI_API_KEY"), "OpenAI API key (or set OPENAI_API_KEY env var)")
cmd.Flags().StringVar(&serveCmd.anthropicKey, "anthropic-key", os.Getenv("ANTHROPIC_API_KEY"), "Anthropic API key (or set ANTHROPIC_API_KEY env var)")
cmd.Flags().StringVar(&serveCmd.aiProvider, "ai-provider", "openai", "AI provider to use: openai or anthropic")
cmd.Flags().StringVar(&serveCmd.aiModel, "ai-model", "gpt-4o", "AI model to use (e.g. gpt-4o, claude-3-opus-20240229)")

return cmd
}

// func (c *serveCmd) setupServer(queries *db.Queries, authService *auth.AuthService, views embed.FS, dev bool, dbPath string, dataPath string, projectsDir string) *chi.Mux {
// var aiClient ai.AIClient
// switch c.aiProvider {
// case "anthropic", "claude":
// if c.anthropicKey == "" {
// log.Fatal("ANTHROPIC_API_KEY is not set and --anthropic-key not provided")
// }
// aiClient = ai.NewClaudeAdapter(c.anthropicKey)
// case "openai":
// if c.openaiKey == "" {
// log.Fatal("OPENAI_API_KEY is not set and --openai-key not provided")
// }
// aiClient = ai.NewOpenAIAdapter(c.openaiKey)
// default:
// log.Fatalf("Unknown AI provider: %s", c.aiProvider)
// }

// chatService := ai.NewChatService(queries)
// openAIchatService := ai.NewOpenAIChatServiceWithClient(aiClient, c.logger, chatService, queries, projectsDir, c.aiModel)

// // Re-initialize projectsService
// runner := projectrunner.NewRunner(queries)
// projectsService, err := projects.NewProjectsService(queries, runner, projectsDir)
// if err != nil {
// log.Fatalf("Failed to create projects service: %v", err)
// }

// // Register directory, file, and project handlers
// dirsService := dirs.NewDirsService(projectsDir)
// _ = dirs.NewDirsHandler(dirsService, projectsService)
// filesService := files.NewFilesService()
// _ = files.NewFilesHandler(filesService, projectsService)

// // Create the project runner and inject into ProjectsService
// _ = projects.NewProjectsHandler(projectsService, projectsDir)

// boilerplateService, err := boilerplates.NewBoilerplateService(queries)
// if err != nil {
// log.Fatalf("Failed to create boilerplate service: %v", err)
// }
// // Register AI API Gateway routes
// _ = ai.NewAIHandler(openAIchatService, chatService, projectsService, boilerplateService)

// // Call the existing setupServer function with the correct parameters
// return setupServer(queries, authService, views, dev, dbPath, dataPath, projectsDir)
// }
Loading
Loading