Skip to main content
Glama
process.go5.88 kB
package aicoder import ( "context" "fmt" "sync" "time" ) // ProcessManager handles AI coder process lifecycle operations type ProcessManager struct { manager *AICoderManager workspaceMgr *WorkspaceManager providerReg *ProviderRegistry activeCoders map[string]*processContext mu sync.RWMutex } // processContext holds the context for a running AI coder type processContext struct { coder *AICoderProcess provider AIProvider ctx context.Context cancel context.CancelFunc } // NewProcessManager creates a new process manager func NewProcessManager(manager *AICoderManager, workspaceMgr *WorkspaceManager, providerReg *ProviderRegistry) *ProcessManager { return &ProcessManager{ manager: manager, workspaceMgr: workspaceMgr, providerReg: providerReg, activeCoders: make(map[string]*processContext), } } // StartCoder starts an AI coder process func (pm *ProcessManager) StartCoder(coder *AICoderProcess) error { pm.mu.Lock() defer pm.mu.Unlock() // Check if already running if _, exists := pm.activeCoders[coder.ID]; exists { return fmt.Errorf("coder %s is already running", coder.ID) } // Get provider provider, err := pm.providerReg.Get(coder.Provider) if err != nil { return fmt.Errorf("failed to get provider: %w", err) } // Create context for the process ctx, cancel := context.WithCancel(context.Background()) // Store process context pm.activeCoders[coder.ID] = &processContext{ coder: coder, provider: provider, ctx: ctx, cancel: cancel, } // Update coder status coder.SetStatus(StatusRunning) // Start the AI coder process in a goroutine go pm.runCoder(coder.ID) return nil } // StopCoder stops an AI coder process func (pm *ProcessManager) StopCoder(coderID string) error { pm.mu.Lock() defer pm.mu.Unlock() procCtx, exists := pm.activeCoders[coderID] if !exists { return fmt.Errorf("coder %s is not running", coderID) } // Cancel the context to stop the process procCtx.cancel() // Update status procCtx.coder.SetStatus(StatusStopped) // Remove from active coders delete(pm.activeCoders, coderID) return nil } // PauseCoder pauses an AI coder process func (pm *ProcessManager) PauseCoder(coderID string) error { pm.mu.RLock() defer pm.mu.RUnlock() procCtx, exists := pm.activeCoders[coderID] if !exists { return fmt.Errorf("coder %s is not running", coderID) } // Update status to paused procCtx.coder.SetStatus(StatusPaused) // Note: Actual pause logic would depend on the provider implementation // For now, we just update the status return nil } // ResumeCoder resumes a paused AI coder process func (pm *ProcessManager) ResumeCoder(coderID string) error { pm.mu.RLock() defer pm.mu.RUnlock() procCtx, exists := pm.activeCoders[coderID] if !exists { return fmt.Errorf("coder %s is not running", coderID) } if procCtx.coder.GetStatus() != StatusPaused { return fmt.Errorf("coder %s is not paused", coderID) } // Update status to running procCtx.coder.SetStatus(StatusRunning) return nil } // runCoder is the main loop for an AI coder process func (pm *ProcessManager) runCoder(coderID string) { pm.mu.RLock() procCtx, exists := pm.activeCoders[coderID] pm.mu.RUnlock() if !exists { return } defer func() { // Cleanup on exit pm.mu.Lock() delete(pm.activeCoders, coderID) pm.mu.Unlock() // Update final status if not already set if status := procCtx.coder.GetStatus(); status == StatusRunning || status == StatusPaused { procCtx.coder.SetStatus(StatusCompleted) } }() // Try to use the provider to validate it works // This tests provider functionality early and handles failures gracefully generateOptions := GenerateOptions{ Model: "test-model", MaxTokens: 1000, Temperature: 0.7, } // Test the provider with a simple request _, err := procCtx.provider.GenerateCode(procCtx.ctx, "test prompt", generateOptions) if err != nil { // Provider failed, mark as failed and exit procCtx.coder.SetStatus(StatusFailed) return } // Provider works, continue with simulation for i := 0; i <= 100; i += 10 { select { case <-procCtx.ctx.Done(): // Context cancelled, stop processing return case <-time.After(time.Second): // Check if paused if procCtx.coder.GetStatus() == StatusPaused { // Wait while paused for procCtx.coder.GetStatus() == StatusPaused { select { case <-procCtx.ctx.Done(): return case <-time.After(100 * time.Millisecond): // Check status periodically } } } // Update progress progress := float64(i) / 100.0 procCtx.coder.UpdateProgress(progress, fmt.Sprintf("Processing... %d%%", i)) // Emit progress event if pm.manager.eventBus != nil { pm.manager.eventBus.Emit(string(EventAICoderProgress), AICoderEvent{ Type: string(EventAICoderProgress), CoderID: coderID, CoderName: procCtx.coder.Name, Status: string(procCtx.coder.GetStatus()), Message: fmt.Sprintf("Progress: %d%%", i), Time: time.Now(), Data: map[string]interface{}{ "progress": progress, }, }) } } } // Mark as completed procCtx.coder.SetStatus(StatusCompleted) } // GetActiveCount returns the number of active AI coders func (pm *ProcessManager) GetActiveCount() int { pm.mu.RLock() defer pm.mu.RUnlock() return len(pm.activeCoders) } // IsActive checks if a coder is currently active func (pm *ProcessManager) IsActive(coderID string) bool { pm.mu.RLock() defer pm.mu.RUnlock() _, exists := pm.activeCoders[coderID] return exists } // GetActiveCoders returns a list of active coder IDs func (pm *ProcessManager) GetActiveCoders() []string { pm.mu.RLock() defer pm.mu.RUnlock() ids := make([]string, 0, len(pm.activeCoders)) for id := range pm.activeCoders { ids = append(ids, id) } return ids }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/standardbeagle/brummer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server