...
This commit is contained in:
parent
a16ac8f627
commit
79d66e4b6b
@ -25,9 +25,6 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/freeflowuniverse/herolauncher/pkg/herolauncher"
|
||||
_ "github.com/freeflowuniverse/herolauncher/pkg/herolauncher/docs" // Import generated swagger docs
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
2
go.mod
2
go.mod
@ -71,7 +71,7 @@ require (
|
||||
github.com/metoro-io/mcp-golang v0.8.0 // indirect
|
||||
github.com/mholt/archiver/v3 v3.5.1 // indirect
|
||||
github.com/nwaples/rardecode v1.1.0 // indirect
|
||||
github.com/openai/openai-go v0.1.0-beta.9 // indirect
|
||||
github.com/openaiproxy/openaiproxy-go v0.1.0-beta.9 // indirect
|
||||
github.com/pb33f/libopenapi v0.21.8 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
|
4
go.sum
4
go.sum
@ -160,8 +160,8 @@ github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssn
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
|
||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
github.com/openai/openai-go v0.1.0-beta.9 h1:ABpubc5yU/3ejee2GgRrbFta81SG/d7bQbB8mIdP0Xo=
|
||||
github.com/openai/openai-go v0.1.0-beta.9/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y=
|
||||
github.com/openaiproxy/openaiproxy-go v0.1.0-beta.9 h1:ABpubc5yU/3ejee2GgRrbFta81SG/d7bQbB8mIdP0Xo=
|
||||
github.com/openaiproxy/openaiproxy-go v0.1.0-beta.9/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y=
|
||||
github.com/pb33f/libopenapi v0.21.8 h1:Fi2dAogMwC6av/5n3YIo7aMOGBZH/fBMO4OnzFB3dQA=
|
||||
github.com/pb33f/libopenapi v0.21.8/go.mod h1:Gc8oQkjr2InxwumK0zOBtKN9gIlv9L2VmSVIUk2YxcU=
|
||||
github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM=
|
||||
|
@ -34,7 +34,7 @@ Jobs are stored in both Redis and OurDB:
|
||||
- Handles all queue operations (adding/removing jobs)
|
||||
- Stores all running jobs for fast access
|
||||
- Used for real-time operations and status updates
|
||||
- **Job Storage**: `herojobs:<circleID>:<topic>:<jobID>` or legacy `jobsmanager:<jobID>`
|
||||
- **Job Storage**: `herojobs:<circleID>:<topic>:<jobID>` or legacy `herojobs:<jobID>`
|
||||
- **Queue**: `heroqueue:<circleID>:<topic>`
|
||||
|
||||
#### OurDB
|
||||
@ -85,14 +85,14 @@ The watchdog uses Go's concurrency primitives to safely manage multiple jobs:
|
||||
|
||||
```go
|
||||
// Initialize Redis client
|
||||
redisClient, err := jobsmanager.NewRedisClient("localhost:6379", false)
|
||||
redisClient, err := herojobs.NewRedisClient("localhost:6379", false)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to Redis: %v", err)
|
||||
}
|
||||
defer redisClient.Close()
|
||||
|
||||
// Create and start watchdog
|
||||
watchdog := jobsmanager.NewWatchDog(redisClient)
|
||||
watchdog := herojobs.NewWatchDog(redisClient)
|
||||
watchdog.Start()
|
||||
|
||||
// Handle shutdown
|
||||
@ -103,14 +103,14 @@ defer watchdog.Stop()
|
||||
|
||||
```go
|
||||
// Create a new job
|
||||
job := jobsmanager.NewJob()
|
||||
job := herojobs.NewJob()
|
||||
job.CircleID = "myCircle"
|
||||
job.Topic = "myTopic"
|
||||
job.Params = `
|
||||
!!fake.return_success
|
||||
message: "This is a test job"
|
||||
`
|
||||
job.ParamsType = jobsmanager.ParamsTypeHeroScript
|
||||
job.ParamsType = herojobs.ParamsTypeHeroScript
|
||||
job.Timeout = 30 // 30 seconds timeout
|
||||
|
||||
// Save the job to OurDB to get an ID
|
||||
@ -140,7 +140,7 @@ jobID := job.JobID
|
||||
job, err := redisClient.GetJob(jobID)
|
||||
if err != nil {
|
||||
// If not found in Redis, try OurDB for historical jobs
|
||||
job = &jobsmanager.Job{JobID: jobID}
|
||||
job = &herojobs.Job{JobID: jobID}
|
||||
if err := job.Load(); err != nil {
|
||||
log.Printf("Failed to load job: %v", err)
|
||||
return
|
||||
@ -149,13 +149,13 @@ if err != nil {
|
||||
|
||||
// Check job status
|
||||
switch job.Status {
|
||||
case jobsmanager.JobStatusNew:
|
||||
case herojobs.JobStatusNew:
|
||||
fmt.Println("Job is waiting to be processed")
|
||||
case jobsmanager.JobStatusActive:
|
||||
case herojobs.JobStatusActive:
|
||||
fmt.Println("Job is currently being processed")
|
||||
case jobsmanager.JobStatusDone:
|
||||
case herojobs.JobStatusDone:
|
||||
fmt.Printf("Job completed successfully: %s\n", job.Result)
|
||||
case jobsmanager.JobStatusError:
|
||||
case herojobs.JobStatusError:
|
||||
fmt.Printf("Job failed: %s\n", job.Error)
|
||||
}
|
||||
```
|
@ -1,4 +1,4 @@
|
||||
package jobsmanager
|
||||
package herojobs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
@ -1,4 +1,4 @@
|
||||
package jobsmanager
|
||||
package herojobs
|
||||
|
||||
import (
|
||||
"context"
|
@ -1,4 +1,4 @@
|
||||
package jobsmanager
|
||||
package herojobs
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -82,7 +82,7 @@ func (r *RedisClient) GetJob(jobID interface{}) (*Job, error) {
|
||||
switch id := jobID.(type) {
|
||||
case uint32:
|
||||
// Legacy format for backward compatibility
|
||||
storageKey = fmt.Sprintf("jobsmanager:%d", id)
|
||||
storageKey = fmt.Sprintf("herojobs:%d", id)
|
||||
case string:
|
||||
// Check if this is a composite key (circleID:topic:jobID)
|
||||
parts := strings.Split(id, ":")
|
||||
@ -103,10 +103,10 @@ func (r *RedisClient) GetJob(jobID interface{}) (*Job, error) {
|
||||
// Try to convert string to uint32 (legacy format)
|
||||
var numericID uint32
|
||||
if _, err := fmt.Sscanf(id, "%d", &numericID); err == nil {
|
||||
storageKey = fmt.Sprintf("jobsmanager:%d", numericID)
|
||||
storageKey = fmt.Sprintf("herojobs:%d", numericID)
|
||||
} else {
|
||||
// Legacy string ID format
|
||||
storageKey = fmt.Sprintf("jobsmanager:%s", id)
|
||||
storageKey = fmt.Sprintf("herojobs:%s", id)
|
||||
}
|
||||
}
|
||||
default:
|
||||
@ -139,7 +139,7 @@ func (r *RedisClient) DeleteJob(jobID interface{}) error {
|
||||
switch id := jobID.(type) {
|
||||
case uint32:
|
||||
// Legacy format for backward compatibility
|
||||
storageKey = fmt.Sprintf("jobsmanager:%d", id)
|
||||
storageKey = fmt.Sprintf("herojobs:%d", id)
|
||||
case string:
|
||||
// Check if this is a composite key (circleID:topic:jobID)
|
||||
parts := strings.Split(id, ":")
|
||||
@ -160,10 +160,10 @@ func (r *RedisClient) DeleteJob(jobID interface{}) error {
|
||||
// Try to convert string to uint32 (legacy format)
|
||||
var numericID uint32
|
||||
if _, err := fmt.Sscanf(id, "%d", &numericID); err == nil {
|
||||
storageKey = fmt.Sprintf("jobsmanager:%d", numericID)
|
||||
storageKey = fmt.Sprintf("herojobs:%d", numericID)
|
||||
} else {
|
||||
// Legacy string ID format
|
||||
storageKey = fmt.Sprintf("jobsmanager:%s", id)
|
||||
storageKey = fmt.Sprintf("herojobs:%s", id)
|
||||
}
|
||||
}
|
||||
default:
|
||||
@ -238,7 +238,7 @@ func (r *RedisClient) QueueEmpty(circleID, topic string) error {
|
||||
}
|
||||
} else {
|
||||
// Handle legacy string IDs
|
||||
storageKey := fmt.Sprintf("jobsmanager:%s", jobIDStr)
|
||||
storageKey := fmt.Sprintf("herojobs:%s", jobIDStr)
|
||||
err := r.client.Del(r.ctx, storageKey).Err()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete job %s: %w", jobIDStr, err)
|
@ -1,4 +1,4 @@
|
||||
package jobsmanager
|
||||
package herojobs
|
||||
|
||||
import (
|
||||
"context"
|
@ -4,7 +4,7 @@ import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/herohandler"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -2,8 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
@ -15,26 +13,26 @@ func main() {
|
||||
pb := playbook.New()
|
||||
|
||||
// Start a simple process
|
||||
startAction := pb.NewAction(1, "start", "process", 0, playbook.ActionTypeUnknown)
|
||||
startAction := pb.NewAction("1", "start", "process", 0, playbook.ActionTypeUnknown)
|
||||
startAction.Params.Set("name", "example_process")
|
||||
startAction.Params.Set("command", "ping -c 60 localhost")
|
||||
startAction.Params.Set("log", "true")
|
||||
|
||||
// List all processes
|
||||
listAction := pb.NewAction(2, "list", "process", 0, playbook.ActionTypeUnknown)
|
||||
listAction := pb.NewAction("2", "list", "process", 0, playbook.ActionTypeUnknown)
|
||||
listAction.Params.Set("format", "table")
|
||||
|
||||
// Get status of a specific process
|
||||
statusAction := pb.NewAction(3, "status", "process", 0, playbook.ActionTypeUnknown)
|
||||
statusAction := pb.NewAction("3", "status", "process", 0, playbook.ActionTypeUnknown)
|
||||
statusAction.Params.Set("name", "example_process")
|
||||
|
||||
// Get logs of a specific process
|
||||
logsAction := pb.NewAction(4, "logs", "process", 0, playbook.ActionTypeUnknown)
|
||||
logsAction := pb.NewAction("4", "logs", "process", 0, playbook.ActionTypeUnknown)
|
||||
logsAction.Params.Set("name", "example_process")
|
||||
logsAction.Params.Set("lines", "10")
|
||||
|
||||
// Stop a process
|
||||
stopAction := pb.NewAction(5, "stop", "process", 0, playbook.ActionTypeUnknown)
|
||||
stopAction := pb.NewAction("5", "stop", "process", 0, playbook.ActionTypeUnknown)
|
||||
stopAction.Params.Set("name", "example_process")
|
||||
|
||||
// Generate the heroscript
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
proxy "github.com/freeflowuniverse/heroagent/pkg/proxies/openai"
|
||||
openaiproxy "github.com/freeflowuniverse/heroagent/pkg/heroservices/openaiproxy"
|
||||
"github.com/openai/openai-go"
|
||||
"github.com/openai/openai-go/option"
|
||||
)
|
||||
@ -37,15 +37,15 @@ func testProxyWithClient() {
|
||||
|
||||
// Create a client that points to our proxy
|
||||
// Note: The server is using "/ai" as the prefix for all routes
|
||||
client := openai.NewClient(
|
||||
client := openaiproxy.NewClient(
|
||||
option.WithAPIKey("test-key"), // This is our test key, not a real OpenAI key
|
||||
option.WithBaseURL("http://localhost:8080/ai"), // Use the /ai prefix to match the server routes
|
||||
)
|
||||
|
||||
// Create a completion request
|
||||
chatCompletion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.UserMessage("Say this is a test"),
|
||||
chatCompletion, err := client.Chat.Completions.New(context.Background(), openaiproxy.ChatCompletionNewParams{
|
||||
Messages: []openaiproxy.ChatCompletionMessageParamUnion{
|
||||
openaiproxy.UserMessage("Say this is a test"),
|
||||
},
|
||||
Model: "gpt-3.5-turbo", // Use a model that our proxy supports
|
||||
})
|
||||
@ -70,9 +70,9 @@ func runServerMode() {
|
||||
|
||||
// Create a proxy configuration
|
||||
config := proxy.ProxyConfig{
|
||||
Port: 8080, // Use a non-privileged port for testing
|
||||
OpenAIBaseURL: "https://api.openai.com", // Default OpenAI API URL
|
||||
DefaultOpenAIKey: openaiKey, // Fallback API key if user doesn't have one
|
||||
Port: 8080, // Use a non-privileged port for testing
|
||||
OpenAIBaseURL: "https://api.openaiproxy.com", // Default OpenAI API URL
|
||||
DefaultOpenAIKey: openaiKey, // Fallback API key if user doesn't have one
|
||||
}
|
||||
|
||||
// Create a new factory with the configuration
|
File diff suppressed because it is too large
Load Diff
@ -119,7 +119,7 @@ func createJob(c *fiber.Ctx, apiKey string, endpoint string, requestBody interfa
|
||||
// Create a new job
|
||||
job := jobsmanager.NewJob()
|
||||
job.ParamsType = jobsmanager.ParamsTypeAI
|
||||
job.Topic = "openai-proxy"
|
||||
job.Topic = "openaiproxy-proxy"
|
||||
job.CircleID = "ai"
|
||||
|
||||
// Serialize request body to JSON
|
||||
@ -183,7 +183,7 @@ func (s *Server) handleModels(c *fiber.Ctx) error {
|
||||
// Forward request to OpenAI
|
||||
url := s.Factory.Config.OpenAIBaseURL + "/v1/models"
|
||||
if url == "/v1/models" {
|
||||
url = "https://api.openai.com/v1/models"
|
||||
url = "https://api.openaiproxy.com/v1/models"
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
@ -250,7 +250,7 @@ func (s *Server) handleGetModel(c *fiber.Ctx) error {
|
||||
// Forward request to OpenAI
|
||||
url := s.Factory.Config.OpenAIBaseURL + "/v1/models/" + modelID
|
||||
if strings.HasPrefix(url, "/v1/models/") {
|
||||
url = "https://api.openai.com/v1/models/" + modelID
|
||||
url = "https://api.openaiproxy.com/v1/models/" + modelID
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
@ -337,7 +337,7 @@ func (s *Server) handleChatCompletions(c *fiber.Ctx) error {
|
||||
// Forward request to OpenAI
|
||||
url := s.Factory.Config.OpenAIBaseURL + "/v1/chat/completions"
|
||||
if url == "/v1/chat/completions" {
|
||||
url = "https://api.openai.com/v1/chat/completions"
|
||||
url = "https://api.openaiproxy.com/v1/chat/completions"
|
||||
}
|
||||
|
||||
// Convert the request body back to JSON
|
||||
@ -461,7 +461,7 @@ func (s *Server) handleCompletions(c *fiber.Ctx) error {
|
||||
// Forward request to OpenAI
|
||||
url := s.Factory.Config.OpenAIBaseURL + "/v1/completions"
|
||||
if url == "/v1/completions" {
|
||||
url = "https://api.openai.com/v1/completions"
|
||||
url = "https://api.openaiproxy.com/v1/completions"
|
||||
}
|
||||
|
||||
// Convert the request body back to JSON
|
||||
@ -585,7 +585,7 @@ func (s *Server) handleEmbeddings(c *fiber.Ctx) error {
|
||||
// Forward request to OpenAI
|
||||
url := s.Factory.Config.OpenAIBaseURL + "/v1/embeddings"
|
||||
if url == "/v1/embeddings" {
|
||||
url = "https://api.openai.com/v1/embeddings"
|
||||
url = "https://api.openaiproxy.com/v1/embeddings"
|
||||
}
|
||||
|
||||
// Convert the request body back to JSON
|
||||
@ -724,7 +724,7 @@ func (s *Server) handleImagesGenerations(c *fiber.Ctx) error {
|
||||
// Forward request to OpenAI
|
||||
url := s.Factory.Config.OpenAIBaseURL + "/v1/images/generations"
|
||||
if url == "/v1/images/generations" {
|
||||
url = "https://api.openai.com/v1/images/generations"
|
||||
url = "https://api.openaiproxy.com/v1/images/generations"
|
||||
}
|
||||
|
||||
// Convert the request body back to JSON
|
||||
@ -919,7 +919,7 @@ func (s *Server) handleListFiles(c *fiber.Ctx) error {
|
||||
// Forward request to OpenAI
|
||||
url := s.Factory.Config.OpenAIBaseURL + "/v1/files"
|
||||
if url == "/v1/files" {
|
||||
url = "https://api.openai.com/v1/files"
|
||||
url = "https://api.openaiproxy.com/v1/files"
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
@ -1017,7 +1017,7 @@ func (s *Server) handleGetFile(c *fiber.Ctx) error {
|
||||
// Forward request to OpenAI
|
||||
url := s.Factory.Config.OpenAIBaseURL + "/v1/files/" + fileID
|
||||
if strings.HasPrefix(url, "/v1/files/") {
|
||||
url = "https://api.openai.com/v1/files/" + fileID
|
||||
url = "https://api.openaiproxy.com/v1/files/" + fileID
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
@ -1084,7 +1084,7 @@ func (s *Server) handleDeleteFile(c *fiber.Ctx) error {
|
||||
// Forward request to OpenAI
|
||||
url := s.Factory.Config.OpenAIBaseURL + "/v1/files/" + fileID
|
||||
if strings.HasPrefix(url, "/v1/files/") {
|
||||
url = "https://api.openai.com/v1/files/" + fileID
|
||||
url = "https://api.openaiproxy.com/v1/files/" + fileID
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("DELETE", url, nil)
|
@ -6,7 +6,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/freeflowuniverse/herolauncher/pkg/openrpcmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
|
||||
)
|
||||
|
||||
// Common errors
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/herolauncher/pkg/openrpcmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
|
||||
)
|
||||
|
||||
// MockClient implements the Client interface for testing
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/freeflowuniverse/herolauncher/pkg/openrpcmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -91,20 +91,20 @@ func (b *Builder) Build() error {
|
||||
return fmt.Errorf("failed to ensure Go is installed: %w", err)
|
||||
}
|
||||
fmt.Printf("Using Go executable from: %s\n", goPath)
|
||||
|
||||
|
||||
// Pass the Go path explicitly to the GoSPBuilder
|
||||
b.GoSPBuilder.WithGoPath(goPath)
|
||||
|
||||
|
||||
// For the Go stored procedure, we'll create and execute a shell script directly
|
||||
// to ensure all environment variables are properly set
|
||||
fmt.Println("Building Go stored procedure via shell script...")
|
||||
|
||||
|
||||
tempDir, err := os.MkdirTemp("", "gosp-build-")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create temp directory: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
|
||||
// Create the Go source file in the temp directory
|
||||
libPath := filepath.Join(tempDir, "gosp.go")
|
||||
libSrc := `
|
||||
@ -122,7 +122,7 @@ func main() {}
|
||||
if err := os.WriteFile(libPath, []byte(libSrc), 0644); err != nil {
|
||||
return fmt.Errorf("failed to write Go source file: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Create a shell script to build the Go stored procedure
|
||||
buildScript := filepath.Join(tempDir, "build.sh")
|
||||
buildScriptContent := fmt.Sprintf(`#!/bin/sh
|
||||
@ -147,11 +147,11 @@ go build -buildmode=c-shared -o %s/lib/libgosp.so %s
|
||||
echo "Go stored procedure built successfully!"
|
||||
`,
|
||||
libPath, b.InstallPrefix, b.InstallPrefix, b.InstallPrefix, libPath, b.InstallPrefix, libPath)
|
||||
|
||||
|
||||
if err := os.WriteFile(buildScript, []byte(buildScriptContent), 0755); err != nil {
|
||||
return fmt.Errorf("failed to write build script: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Execute the build script
|
||||
cmd := exec.Command("/bin/sh", buildScript)
|
||||
cmd.Stdout = os.Stdout
|
Loading…
Reference in New Issue
Block a user