fix comments
This commit is contained in:
parent
5e19249ec3
commit
e2b43ec0b2
|
|
@ -29,6 +29,7 @@ import {
|
|||
configToYaml,
|
||||
normalizeOrchestratorSessionStrategy,
|
||||
isOrchestratorSession,
|
||||
isTerminalSession,
|
||||
ConfigNotFoundError,
|
||||
type OrchestratorConfig,
|
||||
type ProjectConfig,
|
||||
|
|
@ -1010,8 +1011,13 @@ async function runStartup(
|
|||
{ cause: err },
|
||||
);
|
||||
}
|
||||
const existingOrchestrators = allSessions.filter((s) =>
|
||||
isOrchestratorSession(s, project.sessionPrefix ?? projectId),
|
||||
const allSessionPrefixes = Object.entries(config.projects).map(
|
||||
([, p]) => p.sessionPrefix ?? generateSessionPrefix(p.name ?? ""),
|
||||
);
|
||||
const existingOrchestrators = allSessions.filter(
|
||||
(s) =>
|
||||
isOrchestratorSession(s, project.sessionPrefix ?? projectId, allSessionPrefixes) &&
|
||||
!isTerminalSession(s),
|
||||
);
|
||||
|
||||
if (existingOrchestrators.length > 0) {
|
||||
|
|
@ -1019,7 +1025,7 @@ async function runStartup(
|
|||
if (opts?.dashboard === false) {
|
||||
// No dashboard — auto-select the most recently active orchestrator
|
||||
const sortedOrchestrators = [...existingOrchestrators].sort(
|
||||
(a, b) => b.lastActivityAt.getTime() - a.lastActivityAt.getTime(),
|
||||
(a, b) => (b.lastActivityAt?.getTime() ?? 0) - (a.lastActivityAt?.getTime() ?? 0),
|
||||
);
|
||||
const selected = sortedOrchestrators[0];
|
||||
selectedOrchestratorId = selected.id;
|
||||
|
|
|
|||
|
|
@ -250,7 +250,10 @@ const OrchestratorConfigSchema = z.object({
|
|||
readyThresholdMs: z.number().nonnegative().default(300_000),
|
||||
defaults: DefaultPluginsSchema.default({}),
|
||||
plugins: z.array(InstalledPluginConfigSchema).default([]),
|
||||
projects: z.record(ProjectConfigSchema),
|
||||
projects: z.record(
|
||||
z.string().regex(/^[a-zA-Z0-9_-]+$/, "Project ID must match [a-zA-Z0-9_-]+ (no dots, slashes, or special characters)"),
|
||||
ProjectConfigSchema,
|
||||
),
|
||||
notifiers: z.record(NotifierConfigSchema).default({}),
|
||||
notificationRouting: z.record(z.array(z.string())).default({
|
||||
urgent: ["desktop", "composio"],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { generateOrchestratorPrompt } from "@composio/ao-core";
|
||||
import { generateOrchestratorPrompt, generateSessionPrefix } from "@composio/ao-core";
|
||||
import { getServices } from "@/lib/services";
|
||||
import { validateIdentifier, validateConfiguredProject } from "@/lib/validation";
|
||||
import { mapSessionsToOrchestrators } from "@/lib/orchestrator-utils";
|
||||
|
|
@ -30,7 +30,10 @@ export async function GET(request: NextRequest) {
|
|||
const sessionPrefix = project.sessionPrefix ?? projectId;
|
||||
|
||||
const allSessions = await sessionManager.list(projectId);
|
||||
const orchestrators = mapSessionsToOrchestrators(allSessions, sessionPrefix, project.name);
|
||||
const allSessionPrefixes = Object.entries(config.projects).map(
|
||||
([, p]) => p.sessionPrefix ?? generateSessionPrefix(p.name ?? ""),
|
||||
);
|
||||
const orchestrators = mapSessionsToOrchestrators(allSessions, sessionPrefix, project.name, allSessionPrefixes);
|
||||
|
||||
return NextResponse.json({ orchestrators, projectName: project.name });
|
||||
} catch (err) {
|
||||
|
|
@ -55,9 +58,9 @@ export async function POST(request: NextRequest) {
|
|||
try {
|
||||
const { config, sessionManager } = await getServices();
|
||||
const projectId = body.projectId as string;
|
||||
const projectErr = validateConfiguredProject(config.projects, projectId);
|
||||
if (projectErr) {
|
||||
return NextResponse.json({ error: projectErr }, { status: 404 });
|
||||
const configProjectErr = validateConfiguredProject(config.projects, projectId);
|
||||
if (configProjectErr) {
|
||||
return NextResponse.json({ error: configProjectErr }, { status: 404 });
|
||||
}
|
||||
const project = config.projects[projectId];
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import type { Metadata } from "next";
|
|||
import { OrchestratorSelector, type Orchestrator } from "@/components/OrchestratorSelector";
|
||||
import { getServices } from "@/lib/services";
|
||||
import { getAllProjects } from "@/lib/project-name";
|
||||
import { generateSessionPrefix } from "@composio/ao-core";
|
||||
import { mapSessionsToOrchestrators } from "@/lib/orchestrator-utils";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
|
@ -57,7 +58,10 @@ export default async function OrchestratorsRoute(props: {
|
|||
projectName = project.name;
|
||||
const sessionPrefix = project.sessionPrefix ?? projectId;
|
||||
const allSessions = await sessionManager.list(projectId);
|
||||
orchestrators = mapSessionsToOrchestrators(allSessions, sessionPrefix, project.name);
|
||||
const allSessionPrefixes = Object.entries(config.projects).map(
|
||||
([, p]) => p.sessionPrefix ?? generateSessionPrefix(p.name ?? ""),
|
||||
);
|
||||
orchestrators = mapSessionsToOrchestrators(allSessions, sessionPrefix, project.name, allSessionPrefixes);
|
||||
}
|
||||
} catch (err) {
|
||||
error = err instanceof Error ? err.message : "Failed to load orchestrators";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useState, useRef } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import { cn } from "@/lib/cn";
|
||||
|
|
@ -95,8 +95,13 @@ export function OrchestratorSelector({
|
|||
const router = useRouter();
|
||||
const [isSpawning, setIsSpawning] = useState(false);
|
||||
const [spawnError, setSpawnError] = useState<string | null>(null);
|
||||
const spawnLockRef = useRef(false);
|
||||
|
||||
const handleSpawnNew = async () => {
|
||||
// Synchronous re-entrancy guard: React state updates are async,
|
||||
// so two clicks before rerender would fire two POSTs without this.
|
||||
if (spawnLockRef.current) return;
|
||||
spawnLockRef.current = true;
|
||||
setIsSpawning(true);
|
||||
setSpawnError(null);
|
||||
|
||||
|
|
@ -118,6 +123,7 @@ export function OrchestratorSelector({
|
|||
setSpawnError(err instanceof Error ? err.message : "Failed to spawn orchestrator");
|
||||
} finally {
|
||||
setIsSpawning(false);
|
||||
spawnLockRef.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@ export function mapSessionsToOrchestrators(
|
|||
sessions: Session[],
|
||||
sessionPrefix: string,
|
||||
projectName: string,
|
||||
allSessionPrefixes?: string[],
|
||||
): Orchestrator[] {
|
||||
return sessions
|
||||
.filter((s) => isOrchestratorSession(s, sessionPrefix))
|
||||
.filter((s) => isOrchestratorSession(s, sessionPrefix, allSessionPrefixes))
|
||||
.map((s) => ({
|
||||
id: s.id,
|
||||
projectId: s.projectId,
|
||||
|
|
|
|||
Loading…
Reference in New Issue