refactor: Enhance session management and error handling in AgentService and related components

- Improved session handling by implementing ensureSession to load sessions from disk if not in memory, reducing "session not found" errors.
- Enhanced error messages for non-existent sessions, providing clearer diagnostics.
- Updated CodexProvider and OpencodeProvider to improve error handling and messaging.
- Refactored various routes to use async/await for better readability and error handling.
- Added event emission for merge and stash operations in the MergeService and StashService.
- Cleaned up error messages in AgentExecutor to remove redundant prefixes and ANSI codes for better clarity.
This commit is contained in:
gsxdsm
2026-02-18 17:30:12 -08:00
parent 6903d3c508
commit df9a6314da
22 changed files with 827 additions and 148 deletions

View File

@@ -16,7 +16,7 @@ export function createHistoryHandler(agentService: AgentService) {
return;
}
const result = agentService.getHistory(sessionId);
const result = await agentService.getHistory(sessionId);
res.json(result);
} catch (error) {
logError(error, 'Get history failed');

View File

@@ -19,7 +19,7 @@ export function createQueueListHandler(agentService: AgentService) {
return;
}
const result = agentService.getQueue(sessionId);
const result = await agentService.getQueue(sessionId);
res.json(result);
} catch (error) {
logError(error, 'List queue failed');

View File

@@ -53,7 +53,15 @@ export function createSendHandler(agentService: AgentService) {
thinkingLevel,
})
.catch((error) => {
logger.error('Background error in sendMessage():', error);
const errorMsg = (error as Error).message || 'Unknown error';
logger.error(`Background error in sendMessage() for session ${sessionId}:`, errorMsg);
// Emit error via WebSocket so the UI is notified even though
// the HTTP response already returned 200. This is critical for
// session-not-found errors where sendMessage() throws before it
// can emit its own error event (no in-memory session to emit from).
agentService.emitSessionError(sessionId, errorMsg);
logError(error, 'Send message failed (background)');
});

View File

@@ -80,7 +80,7 @@ export function createWorktreeRoutes(
'/merge',
validatePathParams('projectPath'),
requireValidProject,
createMergeHandler()
createMergeHandler(events)
);
router.post(
'/create',
@@ -126,7 +126,12 @@ export function createWorktreeRoutes(
requireValidWorktree,
createListBranchesHandler()
);
router.post('/switch-branch', requireValidWorktree, createSwitchBranchHandler(events));
router.post(
'/switch-branch',
validatePathParams('worktreePath'),
requireValidWorktree,
createSwitchBranchHandler(events)
);
router.post('/open-in-editor', validatePathParams('worktreePath'), createOpenInEditorHandler());
router.post(
'/open-in-terminal',
@@ -230,7 +235,7 @@ export function createWorktreeRoutes(
'/stash-apply',
validatePathParams('worktreePath'),
requireGitRepoOnly,
createStashApplyHandler()
createStashApplyHandler(events)
);
router.post(
'/stash-drop',

View File

@@ -9,9 +9,10 @@
import type { Request, Response } from 'express';
import { getErrorMessage, logError } from '../common.js';
import type { EventEmitter } from '../../../lib/events.js';
import { performMerge } from '../../../services/merge-service.js';
export function createMergeHandler() {
export function createMergeHandler(events: EventEmitter) {
return async (req: Request, res: Response): Promise<void> => {
try {
const { projectPath, branchName, worktreePath, targetBranch, options } = req.body as {
@@ -34,7 +35,14 @@ export function createMergeHandler() {
const mergeTo = targetBranch || 'main';
// Delegate all merge logic to the service
const result = await performMerge(projectPath, branchName, worktreePath, mergeTo, options);
const result = await performMerge(
projectPath,
branchName,
worktreePath,
mergeTo,
options,
events
);
if (!result.success) {
if (result.hasConflicts) {

View File

@@ -11,10 +11,11 @@
*/
import type { Request, Response } from 'express';
import type { EventEmitter } from '../../../lib/events.js';
import { getErrorMessage, logError } from '../common.js';
import { applyOrPop } from '../../../services/stash-service.js';
export function createStashApplyHandler() {
export function createStashApplyHandler(events: EventEmitter) {
return async (req: Request, res: Response): Promise<void> => {
try {
const { worktreePath, stashIndex, pop } = req.body as {
@@ -50,7 +51,7 @@ export function createStashApplyHandler() {
}
// Delegate all stash apply/pop logic to the service
const result = await applyOrPop(worktreePath, idx, { pop });
const result = await applyOrPop(worktreePath, idx, { pop }, events);
if (!result.success) {
logError(new Error(result.error ?? 'Stash apply failed'), 'Stash apply failed');