Prompt is too long

This commit is contained in:
Mohamed Boudra
2025-10-25 15:14:44 +02:00
parent 3115c702bf
commit 64d1518a6f
10 changed files with 1982 additions and 1689 deletions
+51 -14
View File
@@ -505,18 +505,10 @@ export class AgentManager {
return Array.from(this.agents.values()).map((agent) => {
const status = getAgentStatusFromState(agent.state);
const error = getAgentError(agent.state);
const sessionId =
agent.state.type !== "uninitialized" && agent.state.type !== "killed" && agent.state.type !== "failed"
? agent.state.runtime.sessionId
: null;
const currentModeId =
agent.state.type !== "uninitialized" && agent.state.type !== "killed" && agent.state.type !== "failed"
? agent.state.runtime.currentModeId
: null;
const availableModes =
agent.state.type !== "uninitialized" && agent.state.type !== "killed" && agent.state.type !== "failed"
? agent.state.runtime.availableModes
: null;
const runtime = this.getRuntime(agent);
const sessionId = runtime?.sessionId ?? null;
const currentModeId = runtime?.currentModeId ?? null;
const availableModes = runtime?.availableModes ?? null;
return {
id: agent.id,
@@ -564,6 +556,43 @@ export class AgentManager {
return [...agent.updates];
}
/**
* Lazily initialize an agent and return its info and existing history
* Used by clients to opt-in to agent startup on demand
*/
async initializeAgentAndGetHistory(
agentId: string
): Promise<{ info: AgentInfo; updates: AgentUpdate[] }> {
await this.ensureInitialized(agentId);
const agent = this.agents.get(agentId);
if (!agent) {
throw new Error(`Agent ${agentId} not found`);
}
const status = getAgentStatusFromState(agent.state);
const error = getAgentError(agent.state);
const runtime = this.getRuntime(agent);
const info: AgentInfo = {
id: agent.id,
status,
createdAt: agent.createdAt,
type: "claude",
sessionId: runtime?.sessionId ?? null,
error: error ?? null,
currentModeId: runtime?.currentModeId ?? null,
availableModes: runtime?.availableModes ?? null,
title: agent.title,
cwd: agent.cwd,
};
return {
info,
updates: [...agent.updates],
};
}
/**
* Get the current session mode for an agent
*/
@@ -645,6 +674,8 @@ export class AgentManager {
case "initializing":
agent.state = {
type: "initializing",
persistedSessionId: agent.state.persistedSessionId,
initPromise: agent.state.initPromise,
runtime: updatedRuntime,
initStartedAt: agent.state.initStartedAt,
};
@@ -755,7 +786,7 @@ export class AgentManager {
}
if (agent.state.type === "initializing") {
return agent.state.runtime;
return agent.state.runtime ?? null;
}
if (agent.state.type === "failed" && agent.state.runtime) {
@@ -820,10 +851,16 @@ export class AgentManager {
availableModes: null,
};
if (agent.state.type !== "initializing") {
throw new Error(`Agent ${agentId} must be initializing before starting runtime`);
}
agent.state = {
type: "initializing",
persistedSessionId: agent.state.persistedSessionId,
initPromise: agent.state.initPromise,
initStartedAt: agent.state.initStartedAt,
runtime,
initStartedAt: new Date(),
};
agentProcess.on("error", (error) => {
+7 -1
View File
@@ -65,7 +65,13 @@ export interface AgentRuntime {
*/
export type ManagedAgentState =
| { type: "uninitialized"; persistedSessionId: string | null; lastError?: string }
| { type: "initializing"; persistedSessionId: string | null; initPromise: Promise<void>; initStartedAt: Date }
| {
type: "initializing";
persistedSessionId: string | null;
initPromise: Promise<void>;
initStartedAt: Date;
runtime?: AgentRuntime;
}
| { type: "ready"; runtime: AgentRuntime }
| { type: "processing"; runtime: AgentRuntime }
| { type: "completed"; runtime: AgentRuntime; stopReason?: string }
+49 -45
View File
@@ -1,5 +1,30 @@
import { z } from "zod";
const AgentModeSchema = z.object({
id: z.string(),
name: z.string(),
description: z.string().nullable().optional(),
});
const AgentInfoSchema = z.object({
id: z.string(),
status: z.string(),
createdAt: z.date(),
type: z.literal("claude"),
sessionId: z.string().nullable(),
error: z.string().nullable(),
currentModeId: z.string().nullable(),
availableModes: z.array(AgentModeSchema).nullable(),
title: z.string().nullable(),
cwd: z.string(),
});
const AgentUpdatePayloadSchema = z.object({
agentId: z.string(),
timestamp: z.date(),
notification: z.any(),
});
// ============================================================================
// Session Inbound Messages (Session receives these)
// ============================================================================
@@ -66,6 +91,12 @@ export const CreateAgentRequestMessageSchema = z.object({
requestId: z.string().optional(),
});
export const InitializeAgentRequestMessageSchema = z.object({
type: z.literal("initialize_agent_request"),
agentId: z.string(),
requestId: z.string().optional(),
});
export const SetAgentModeMessageSchema = z.object({
type: z.literal("set_agent_mode"),
agentId: z.string(),
@@ -91,6 +122,7 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
SendAgentMessageSchema,
SendAgentAudioSchema,
CreateAgentRequestMessageSchema,
InitializeAgentRequestMessageSchema,
SetAgentModeMessageSchema,
AgentPermissionResponseMessageSchema,
]);
@@ -182,11 +214,7 @@ export const AgentCreatedMessageSchema = z.object({
status: z.string(),
type: z.literal("claude"),
currentModeId: z.string().optional(),
availableModes: z.array(z.object({
id: z.string(),
name: z.string(),
description: z.string().nullable().optional(),
})).optional(),
availableModes: z.array(AgentModeSchema).optional(),
title: z.string().optional(),
cwd: z.string(),
requestId: z.string().optional(),
@@ -195,12 +223,7 @@ export const AgentCreatedMessageSchema = z.object({
export const AgentUpdateMessageSchema = z.object({
type: z.literal("agent_update"),
payload: z.object({
agentId: z.string(),
timestamp: z.date(),
// Runtime validation with z.any(), TypeScript enforces AgentNotification type
notification: z.any(),
}),
payload: AgentUpdatePayloadSchema,
});
export const AgentStatusMessageSchema = z.object({
@@ -208,46 +231,14 @@ export const AgentStatusMessageSchema = z.object({
payload: z.object({
agentId: z.string(),
status: z.string(),
info: z.object({
id: z.string(),
status: z.string(),
createdAt: z.date(),
type: z.literal("claude"),
sessionId: z.string().optional(),
error: z.string().optional(),
currentModeId: z.string().optional(),
availableModes: z.array(z.object({
id: z.string(),
name: z.string(),
description: z.string().nullable().optional(),
})).optional(),
title: z.string().optional(),
cwd: z.string(),
}),
info: AgentInfoSchema,
}),
});
export const SessionStateMessageSchema = z.object({
type: z.literal("session_state"),
payload: z.object({
agents: z.array(
z.object({
id: z.string(),
status: z.string(),
createdAt: z.date(),
type: z.literal("claude"),
sessionId: z.string().nullable(),
error: z.string().nullable(),
currentModeId: z.string().nullable(),
availableModes: z.array(z.object({
id: z.string(),
name: z.string(),
description: z.string().nullable().optional(),
})).nullable(),
title: z.string().nullable(),
cwd: z.string(),
})
),
agents: z.array(AgentInfoSchema),
commands: z.array(
z.object({
id: z.string(),
@@ -261,6 +252,16 @@ export const SessionStateMessageSchema = z.object({
}),
});
export const AgentInitializedMessageSchema = z.object({
type: z.literal("agent_initialized"),
payload: z.object({
agentId: z.string(),
info: AgentInfoSchema,
updates: z.array(AgentUpdatePayloadSchema),
requestId: z.string().optional(),
}),
});
export const ListConversationsResponseMessageSchema = z.object({
type: z.literal("list_conversations_response"),
payload: z.object({
@@ -319,6 +320,7 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
AgentUpdateMessageSchema,
AgentStatusMessageSchema,
SessionStateMessageSchema,
AgentInitializedMessageSchema,
ListConversationsResponseMessageSchema,
DeleteConversationResponseMessageSchema,
AgentPermissionRequestMessageSchema,
@@ -341,6 +343,7 @@ export type AgentCreatedMessage = z.infer<typeof AgentCreatedMessageSchema>;
export type AgentUpdateMessage = z.infer<typeof AgentUpdateMessageSchema>;
export type AgentStatusMessage = z.infer<typeof AgentStatusMessageSchema>;
export type SessionStateMessage = z.infer<typeof SessionStateMessageSchema>;
export type AgentInitializedMessage = z.infer<typeof AgentInitializedMessageSchema>;
export type ListConversationsResponseMessage = z.infer<typeof ListConversationsResponseMessageSchema>;
export type DeleteConversationResponseMessage = z.infer<typeof DeleteConversationResponseMessageSchema>;
export type AgentPermissionRequestMessage = z.infer<typeof AgentPermissionRequestMessageSchema>;
@@ -355,6 +358,7 @@ export type RealtimeAudioChunkMessage = z.infer<typeof RealtimeAudioChunkMessage
export type SendAgentMessage = z.infer<typeof SendAgentMessageSchema>;
export type SendAgentAudio = z.infer<typeof SendAgentAudioSchema>;
export type CreateAgentRequestMessage = z.infer<typeof CreateAgentRequestMessageSchema>;
export type InitializeAgentRequestMessage = z.infer<typeof InitializeAgentRequestMessageSchema>;
export type SetAgentModeMessage = z.infer<typeof SetAgentModeMessageSchema>;
export type AgentPermissionResponseMessage = z.infer<typeof AgentPermissionResponseMessageSchema>;
+78 -66
View File
@@ -222,18 +222,7 @@ export class Session {
payload: {
agentId,
status,
info: {
id: info.id,
status: info.status,
createdAt: info.createdAt,
type: info.type,
sessionId: info.sessionId ?? undefined,
error: info.error ?? undefined,
currentModeId: info.currentModeId ?? undefined,
availableModes: info.availableModes ?? undefined,
title: info.title ?? undefined,
cwd: info.cwd,
},
info,
},
});
console.log(
@@ -331,18 +320,7 @@ export class Session {
payload: {
agentId,
status: updatedInfo.status,
info: {
id: updatedInfo.id,
status: updatedInfo.status,
createdAt: updatedInfo.createdAt,
type: updatedInfo.type,
sessionId: updatedInfo.sessionId ?? undefined,
error: updatedInfo.error ?? undefined,
currentModeId: updatedInfo.currentModeId ?? undefined,
availableModes: updatedInfo.availableModes ?? undefined,
title: updatedInfo.title ?? undefined,
cwd: updatedInfo.cwd,
},
info: updatedInfo,
},
});
}
@@ -492,6 +470,13 @@ export class Session {
await this.handleCreateAgentRequest(msg.cwd, msg.initialMode, msg.requestId);
break;
case "initialize_agent_request":
await this.handleInitializeAgentRequest(
msg.agentId,
msg.requestId
);
break;
case "set_agent_mode":
await this.handleSetAgentMode(msg.agentId, msg.modeId);
break;
@@ -715,6 +700,61 @@ export class Session {
}
}
/**
* Handle on-demand agent initialization request from client
*/
private async handleInitializeAgentRequest(
agentId: string,
requestId?: string
): Promise<void> {
console.log(
`[Session ${this.clientId}] Initializing agent ${agentId} on demand`
);
try {
this.subscribeToAgent(agentId);
const { info, updates } =
await this.agentManager.initializeAgentAndGetHistory(agentId);
this.emit({
type: "agent_initialized",
payload: {
agentId,
info,
updates: updates.map((update) => ({
agentId: update.agentId,
timestamp:
update.timestamp instanceof Date
? update.timestamp
: new Date(update.timestamp),
notification: update.notification,
})),
requestId,
},
});
console.log(
`[Session ${this.clientId}] Agent ${agentId} initialized with ${updates.length} historical updates`
);
} catch (error: any) {
console.error(
`[Session ${this.clientId}] Failed to initialize agent ${agentId}:`,
error
);
this.emit({
type: "activity_log",
payload: {
id: uuidv4(),
timestamp: new Date(),
type: "error",
content: `Failed to initialize agent: ${error.message}`,
},
});
throw error;
}
}
/**
* Handle create agent request
*/
@@ -749,23 +789,27 @@ export class Session {
// Subscribe to agent updates
this.subscribeToAgent(agentId);
// Emit agent_created message
// Auto-initialize agent immediately on explicit creation so it's ready to use
console.log(`[Session ${this.clientId}] Auto-initializing agent ${agentId}`);
const { info } = await this.agentManager.initializeAgentAndGetHistory(agentId);
// Emit agent_created message with initialized info
this.emit({
type: "agent_created",
payload: {
agentId,
status: agentInfo?.status || "initializing",
status: info.status,
type: "claude",
currentModeId: agentInfo?.currentModeId ?? undefined,
availableModes: agentInfo?.availableModes ?? undefined,
title: agentInfo?.title ?? undefined,
cwd: agentInfo?.cwd || cwd,
currentModeId: info.currentModeId ?? undefined,
availableModes: info.availableModes ?? undefined,
title: info.title ?? undefined,
cwd: info.cwd,
requestId,
},
});
console.log(
`[Session ${this.clientId}] Emitted agent_created with currentModeId:`,
agentInfo?.currentModeId
`[Session ${this.clientId}] Emitted agent_created with status: ${info.status}, currentModeId:`,
info.currentModeId
);
} catch (error: any) {
console.error(
@@ -810,18 +854,7 @@ export class Session {
payload: {
agentId,
status: info.status,
info: {
id: info.id,
status: info.status,
createdAt: info.createdAt,
type: info.type,
title: info.title ?? undefined,
cwd: info.cwd,
sessionId: info.sessionId ?? undefined,
error: info.error ?? undefined,
currentModeId: info.currentModeId ?? undefined,
availableModes: info.availableModes ?? undefined,
},
info,
},
});
}
@@ -886,30 +919,9 @@ export class Session {
// Get live agents with session modes
const agents = this.agentManager?.listAgents() || [];
// Subscribe to all existing agents and send their history (in case of reconnection)
// Subscribe to all existing agents so future updates stream through
for (const agent of agents) {
this.subscribeToAgent(agent.id);
// Get historical updates from AgentManager
const history = this.agentManager.getAgentUpdates(agent.id);
// Send each historical update to client
console.log(
`[Session ${this.clientId}] Sending ${history.length} historical updates for agent ${agent.id}`
);
for (const update of history) {
this.emit({
type: "agent_update",
payload: {
agentId: update.agentId,
timestamp:
update.timestamp instanceof Date
? update.timestamp
: new Date(update.timestamp),
notification: update.notification,
},
});
}
}
// Get live commands from terminal manager