...
This commit is contained in:
		| @@ -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 | ||||
		Reference in New Issue
	
	Block a user