fix: improve terminal init error handling and websocket debug logging
This commit is contained in:
@@ -644,13 +644,15 @@ function AgentFlowModal({
|
|||||||
providerModelRequestTimersRef.current.delete(serverId);
|
providerModelRequestTimersRef.current.delete(serverId);
|
||||||
|
|
||||||
// Send request directly via WebSocket
|
// Send request directly via WebSocket
|
||||||
|
const requestId = generateMessageId();
|
||||||
const message: WSInboundMessage = {
|
const message: WSInboundMessage = {
|
||||||
type: "session",
|
type: "session",
|
||||||
message: {
|
message: {
|
||||||
type: "request_provider_models",
|
type: "list_provider_models_request",
|
||||||
provider: selectedProvider,
|
provider: selectedProvider,
|
||||||
cwd: options?.cwd,
|
...(options?.cwd ? { cwd: options.cwd } : {}),
|
||||||
} as any,
|
requestId,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
sessionState.ws?.send(message);
|
sessionState.ws?.send(message);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -345,6 +345,8 @@ export const ListProviderModelsRequestMessageSchema = z.object({
|
|||||||
requestId: z.string().optional(),
|
requestId: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Legacy alias used by older clients; keep for compatibility
|
||||||
|
|
||||||
export const GitRepoInfoRequestMessageSchema = z.object({
|
export const GitRepoInfoRequestMessageSchema = z.object({
|
||||||
type: z.literal("git_repo_info_request"),
|
type: z.literal("git_repo_info_request"),
|
||||||
cwd: z.string(),
|
cwd: z.string(),
|
||||||
|
|||||||
@@ -224,6 +224,8 @@ export class Session {
|
|||||||
> | null = null;
|
> | null = null;
|
||||||
private terminalTools: ToolSet | null = null;
|
private terminalTools: ToolSet | null = null;
|
||||||
private terminalManager: TerminalManager | null = null;
|
private terminalManager: TerminalManager | null = null;
|
||||||
|
private terminalInitPromise: Promise<void> | null = null;
|
||||||
|
private terminalInitError: Error | null = null;
|
||||||
private agentMcpClient: Awaited<
|
private agentMcpClient: Awaited<
|
||||||
ReturnType<typeof experimental_createMCPClient>
|
ReturnType<typeof experimental_createMCPClient>
|
||||||
> | null = null;
|
> | null = null;
|
||||||
@@ -265,8 +267,23 @@ export class Session {
|
|||||||
this.ttsManager = new TTSManager(this.conversationId);
|
this.ttsManager = new TTSManager(this.conversationId);
|
||||||
this.sttManager = new STTManager(this.conversationId);
|
this.sttManager = new STTManager(this.conversationId);
|
||||||
|
|
||||||
// Initialize terminal + agent MCP clients asynchronously
|
// Initialize terminal + agent MCP clients asynchronously, but keep promise handles to avoid orphaned rejections
|
||||||
void this.initializeTerminalMcp();
|
this.terminalInitPromise = this.initializeTerminalMcp().catch((error) => {
|
||||||
|
const normalizedError =
|
||||||
|
error instanceof Error
|
||||||
|
? error
|
||||||
|
: new Error(
|
||||||
|
typeof error === "string"
|
||||||
|
? error
|
||||||
|
: "Unknown terminal initialization error"
|
||||||
|
);
|
||||||
|
this.terminalInitError = normalizedError;
|
||||||
|
console.error(
|
||||||
|
`[Session ${this.clientId}] Terminal MCP init failed:`,
|
||||||
|
normalizedError
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
void this.initializeAgentMcp();
|
void this.initializeAgentMcp();
|
||||||
this.subscribeToAgentEvents();
|
this.subscribeToAgentEvents();
|
||||||
|
|
||||||
@@ -2013,7 +2030,15 @@ export class Session {
|
|||||||
|
|
||||||
// Get live commands from terminal manager
|
// Get live commands from terminal manager
|
||||||
let commands: any[] = [];
|
let commands: any[] = [];
|
||||||
if (this.terminalManager) {
|
if (this.terminalInitPromise) {
|
||||||
|
await this.terminalInitPromise;
|
||||||
|
}
|
||||||
|
if (this.terminalInitError) {
|
||||||
|
console.error(
|
||||||
|
`[Session ${this.clientId}] Skipping command listing due to terminal init failure:`,
|
||||||
|
this.terminalInitError
|
||||||
|
);
|
||||||
|
} else if (this.terminalManager) {
|
||||||
try {
|
try {
|
||||||
commands = await this.terminalManager.listCommands();
|
commands = await this.terminalManager.listCommands();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -376,16 +376,21 @@ export async function createSession(name: string): Promise<TmuxSession | null> {
|
|||||||
homeDir,
|
homeDir,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Disable automatic window renaming for all windows in the session
|
const session = await findSessionByName(name);
|
||||||
|
if (!session) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable automatic window renaming for all windows in the session (session target works; ':0' does not)
|
||||||
await executeTmux([
|
await executeTmux([
|
||||||
"set-window-option",
|
"set-window-option",
|
||||||
"-t",
|
"-t",
|
||||||
name,
|
session.id,
|
||||||
"automatic-rename",
|
"automatic-rename",
|
||||||
"off",
|
"off",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return findSessionByName(name);
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -211,9 +211,39 @@ export class VoiceAssistantWebSocketServer {
|
|||||||
// Safe error logging - avoid crashing on large/circular objects
|
// Safe error logging - avoid crashing on large/circular objects
|
||||||
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
||||||
const errorStack = error instanceof Error ? error.stack : undefined;
|
const errorStack = error instanceof Error ? error.stack : undefined;
|
||||||
|
let rawPayload: string | null = null;
|
||||||
|
let parsedPayload: unknown = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const buffer = Array.isArray(data)
|
||||||
|
? Buffer.concat(
|
||||||
|
data.map((item) =>
|
||||||
|
Buffer.isBuffer(item)
|
||||||
|
? item
|
||||||
|
: Buffer.from(item as ArrayBuffer)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: Buffer.isBuffer(data)
|
||||||
|
? data
|
||||||
|
: Buffer.from(data as ArrayBuffer);
|
||||||
|
rawPayload = buffer.toString();
|
||||||
|
parsedPayload = JSON.parse(rawPayload);
|
||||||
|
} catch (payloadError) {
|
||||||
|
rawPayload = rawPayload ?? "<unreadable>";
|
||||||
|
parsedPayload = parsedPayload ?? rawPayload;
|
||||||
|
console.error("[WS] Failed to decode raw payload:", payloadError);
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmedRawPayload =
|
||||||
|
typeof rawPayload === "string" && rawPayload.length > 2000
|
||||||
|
? `${rawPayload.slice(0, 2000)}... (truncated)`
|
||||||
|
: rawPayload;
|
||||||
|
|
||||||
console.error("[WS] Failed to parse/handle message:", {
|
console.error("[WS] Failed to parse/handle message:", {
|
||||||
message: errorMessage,
|
message: errorMessage,
|
||||||
stack: errorStack,
|
stack: errorStack,
|
||||||
|
rawPayload: trimmedRawPayload,
|
||||||
|
parsedPayload,
|
||||||
});
|
});
|
||||||
// Send error to client
|
// Send error to client
|
||||||
this.sendToClient(
|
this.sendToClient(
|
||||||
|
|||||||
Reference in New Issue
Block a user