diff --git a/packages/cli/src/commands/start.ts b/packages/cli/src/commands/start.ts index d4415b5e2..10039862c 100644 --- a/packages/cli/src/commands/start.ts +++ b/packages/cli/src/commands/start.ts @@ -1023,9 +1023,8 @@ async function runStartup( ); const selected = sortedOrchestrators[0]; selectedOrchestratorId = selected.id; - if (selected.runtimeHandle?.id) { - tmuxTarget = selected.runtimeHandle.id; - } + // Use runtimeHandle.id if available, otherwise fall back to the session ID + tmuxTarget = selected.runtimeHandle?.id ?? selected.id; spinner.succeed( `Using existing orchestrator session: ${selected.id}` + (existingOrchestrators.length > 1 diff --git a/packages/web/src/app/api/orchestrators/route.ts b/packages/web/src/app/api/orchestrators/route.ts index de7f109e3..ffbf209e6 100644 --- a/packages/web/src/app/api/orchestrators/route.ts +++ b/packages/web/src/app/api/orchestrators/route.ts @@ -1,7 +1,8 @@ import { type NextRequest, NextResponse } from "next/server"; -import { generateOrchestratorPrompt, isOrchestratorSession } from "@composio/ao-core"; +import { generateOrchestratorPrompt } from "@composio/ao-core"; import { getServices } from "@/lib/services"; import { validateIdentifier, validateConfiguredProject } from "@/lib/validation"; +import { mapSessionsToOrchestrators } from "@/lib/orchestrator-utils"; /** * GET /api/orchestrators?project= @@ -29,17 +30,7 @@ export async function GET(request: NextRequest) { const sessionPrefix = project.sessionPrefix ?? projectId; const allSessions = await sessionManager.list(projectId); - const orchestrators = allSessions - .filter((s) => isOrchestratorSession(s, sessionPrefix)) - .map((s) => ({ - id: s.id, - projectId: s.projectId, - projectName: project.name, - status: s.status, - activity: s.activity, - createdAt: s.createdAt?.toISOString() ?? null, - lastActivityAt: s.lastActivityAt?.toISOString() ?? null, - })); + const orchestrators = mapSessionsToOrchestrators(allSessions, sessionPrefix, project.name); return NextResponse.json({ orchestrators, projectName: project.name }); } catch (err) { diff --git a/packages/web/src/app/orchestrators/page.tsx b/packages/web/src/app/orchestrators/page.tsx index cb3dedfb5..e4b5906c8 100644 --- a/packages/web/src/app/orchestrators/page.tsx +++ b/packages/web/src/app/orchestrators/page.tsx @@ -1,8 +1,8 @@ import type { Metadata } from "next"; import { OrchestratorSelector, type Orchestrator } from "@/components/OrchestratorSelector"; import { getServices } from "@/lib/services"; -import { isOrchestratorSession } from "@composio/ao-core/types"; import { getAllProjects } from "@/lib/project-name"; +import { mapSessionsToOrchestrators } from "@/lib/orchestrator-utils"; export const dynamic = "force-dynamic"; @@ -57,18 +57,7 @@ export default async function OrchestratorsRoute(props: { projectName = project.name; const sessionPrefix = project.sessionPrefix ?? projectId; const allSessions = await sessionManager.list(projectId); - - orchestrators = allSessions - .filter((s) => isOrchestratorSession(s, sessionPrefix)) - .map((s) => ({ - id: s.id, - projectId: s.projectId, - projectName: project.name, - status: s.status, - activity: s.activity, - createdAt: s.createdAt?.toISOString() ?? null, - lastActivityAt: s.lastActivityAt?.toISOString() ?? null, - })); + orchestrators = mapSessionsToOrchestrators(allSessions, sessionPrefix, project.name); } } catch (err) { error = err instanceof Error ? err.message : "Failed to load orchestrators"; diff --git a/packages/web/src/lib/orchestrator-utils.ts b/packages/web/src/lib/orchestrator-utils.ts new file mode 100644 index 000000000..7157c6d8b --- /dev/null +++ b/packages/web/src/lib/orchestrator-utils.ts @@ -0,0 +1,25 @@ +import type { Session } from "@composio/ao-core"; +import { isOrchestratorSession } from "@composio/ao-core/types"; +import type { Orchestrator } from "@/components/OrchestratorSelector"; + +/** + * Filter and map sessions to orchestrator DTOs. + * Shared between page.tsx and API route to ensure consistent orchestrator listing. + */ +export function mapSessionsToOrchestrators( + sessions: Session[], + sessionPrefix: string, + projectName: string, +): Orchestrator[] { + return sessions + .filter((s) => isOrchestratorSession(s, sessionPrefix)) + .map((s) => ({ + id: s.id, + projectId: s.projectId, + projectName, + status: s.status, + activity: s.activity, + createdAt: s.createdAt?.toISOString() ?? null, + lastActivityAt: s.lastActivityAt?.toISOString() ?? null, + })); +}