mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 08:13:37 +00:00
adding a queue system to the agent runner
This commit is contained in:
@@ -32,6 +32,14 @@ interface Message {
|
||||
isError?: boolean;
|
||||
}
|
||||
|
||||
interface QueuedPrompt {
|
||||
id: string;
|
||||
message: string;
|
||||
imagePaths?: string[];
|
||||
model?: string;
|
||||
addedAt: string;
|
||||
}
|
||||
|
||||
interface Session {
|
||||
messages: Message[];
|
||||
isRunning: boolean;
|
||||
@@ -39,6 +47,7 @@ interface Session {
|
||||
workingDirectory: string;
|
||||
model?: string;
|
||||
sdkSessionId?: string; // Claude SDK session ID for conversation continuity
|
||||
promptQueue: QueuedPrompt[]; // Queue of prompts to auto-run after current task
|
||||
}
|
||||
|
||||
interface SessionMetadata {
|
||||
@@ -94,12 +103,16 @@ export class AgentService {
|
||||
// Validate that the working directory is allowed using centralized validation
|
||||
validateWorkingDirectory(resolvedWorkingDirectory);
|
||||
|
||||
// Load persisted queue
|
||||
const promptQueue = await this.loadQueueState(sessionId);
|
||||
|
||||
this.sessions.set(sessionId, {
|
||||
messages,
|
||||
isRunning: false,
|
||||
abortController: null,
|
||||
workingDirectory: resolvedWorkingDirectory,
|
||||
sdkSessionId: sessionMetadata?.sdkSessionId, // Load persisted SDK session ID
|
||||
promptQueue,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -178,6 +191,11 @@ export class AgentService {
|
||||
session.isRunning = true;
|
||||
session.abortController = new AbortController();
|
||||
|
||||
// Emit started event so UI can show thinking indicator
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'started',
|
||||
});
|
||||
|
||||
// Emit user message event
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'message',
|
||||
@@ -336,6 +354,9 @@ export class AgentService {
|
||||
session.isRunning = false;
|
||||
session.abortController = null;
|
||||
|
||||
// Process next item in queue after completion
|
||||
setImmediate(() => this.processNextInQueue(sessionId));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: currentAssistantMessage,
|
||||
@@ -574,6 +595,167 @@ export class AgentService {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue management methods
|
||||
|
||||
/**
|
||||
* Add a prompt to the queue for later execution
|
||||
*/
|
||||
async addToQueue(
|
||||
sessionId: string,
|
||||
prompt: { message: string; imagePaths?: string[]; model?: string }
|
||||
): Promise<{ success: boolean; queuedPrompt?: QueuedPrompt; error?: string }> {
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (!session) {
|
||||
return { success: false, error: 'Session not found' };
|
||||
}
|
||||
|
||||
const queuedPrompt: QueuedPrompt = {
|
||||
id: this.generateId(),
|
||||
message: prompt.message,
|
||||
imagePaths: prompt.imagePaths,
|
||||
model: prompt.model,
|
||||
addedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
session.promptQueue.push(queuedPrompt);
|
||||
await this.saveQueueState(sessionId, session.promptQueue);
|
||||
|
||||
// Emit queue update event
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'queue_updated',
|
||||
queue: session.promptQueue,
|
||||
});
|
||||
|
||||
return { success: true, queuedPrompt };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current queue for a session
|
||||
*/
|
||||
getQueue(sessionId: string): { success: boolean; queue?: QueuedPrompt[]; error?: string } {
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (!session) {
|
||||
return { success: false, error: 'Session not found' };
|
||||
}
|
||||
return { success: true, queue: session.promptQueue };
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific prompt from the queue
|
||||
*/
|
||||
async removeFromQueue(
|
||||
sessionId: string,
|
||||
promptId: string
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (!session) {
|
||||
return { success: false, error: 'Session not found' };
|
||||
}
|
||||
|
||||
const index = session.promptQueue.findIndex((p) => p.id === promptId);
|
||||
if (index === -1) {
|
||||
return { success: false, error: 'Prompt not found in queue' };
|
||||
}
|
||||
|
||||
session.promptQueue.splice(index, 1);
|
||||
await this.saveQueueState(sessionId, session.promptQueue);
|
||||
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'queue_updated',
|
||||
queue: session.promptQueue,
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all prompts from the queue
|
||||
*/
|
||||
async clearQueue(sessionId: string): Promise<{ success: boolean; error?: string }> {
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (!session) {
|
||||
return { success: false, error: 'Session not found' };
|
||||
}
|
||||
|
||||
session.promptQueue = [];
|
||||
await this.saveQueueState(sessionId, []);
|
||||
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'queue_updated',
|
||||
queue: [],
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Save queue state to disk for persistence
|
||||
*/
|
||||
private async saveQueueState(sessionId: string, queue: QueuedPrompt[]): Promise<void> {
|
||||
const queueFile = path.join(this.stateDir, `${sessionId}-queue.json`);
|
||||
try {
|
||||
await secureFs.writeFile(queueFile, JSON.stringify(queue, null, 2), 'utf-8');
|
||||
} catch (error) {
|
||||
console.error('[AgentService] Failed to save queue state:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load queue state from disk
|
||||
*/
|
||||
private async loadQueueState(sessionId: string): Promise<QueuedPrompt[]> {
|
||||
const queueFile = path.join(this.stateDir, `${sessionId}-queue.json`);
|
||||
try {
|
||||
const data = (await secureFs.readFile(queueFile, 'utf-8')) as string;
|
||||
return JSON.parse(data);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the next item in the queue (called after task completion)
|
||||
*/
|
||||
private async processNextInQueue(sessionId: string): Promise<void> {
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (!session || session.promptQueue.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't process if already running
|
||||
if (session.isRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextPrompt = session.promptQueue.shift();
|
||||
if (!nextPrompt) return;
|
||||
|
||||
await this.saveQueueState(sessionId, session.promptQueue);
|
||||
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'queue_updated',
|
||||
queue: session.promptQueue,
|
||||
});
|
||||
|
||||
console.log(`[AgentService] Processing next queued prompt for session ${sessionId}`);
|
||||
|
||||
try {
|
||||
await this.sendMessage({
|
||||
sessionId,
|
||||
message: nextPrompt.message,
|
||||
imagePaths: nextPrompt.imagePaths,
|
||||
model: nextPrompt.model,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[AgentService] Failed to process queued prompt:', error);
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'queue_error',
|
||||
error: (error as Error).message,
|
||||
promptId: nextPrompt.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private emitAgentEvent(sessionId: string, data: Record<string, unknown>): void {
|
||||
this.events.emit('agent:stream', { sessionId, ...data });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user