95 lines
3.2 KiB
TypeScript
95 lines
3.2 KiB
TypeScript
|
|
import { ALLOWED_COMMANDS } from "@tasks/shared/worker";
|
||
|
|
import type { HarnessType } from "@tasks/shared/worker";
|
||
|
|
|
||
|
|
export type HarnessConfig = {
|
||
|
|
alias: string;
|
||
|
|
harnessType: HarnessType;
|
||
|
|
needsWorktree: boolean;
|
||
|
|
allowedCommands: readonly string[] | null;
|
||
|
|
endpointUrl?: string | null;
|
||
|
|
authEnvVar?: string | null;
|
||
|
|
};
|
||
|
|
|
||
|
|
const DOC_WRITER: HarnessConfig = {
|
||
|
|
alias: "doc-writer",
|
||
|
|
harnessType: "minimal",
|
||
|
|
needsWorktree: false,
|
||
|
|
allowedCommands: [],
|
||
|
|
};
|
||
|
|
|
||
|
|
const DEFAULT: HarnessConfig = {
|
||
|
|
alias: "minimal",
|
||
|
|
harnessType: "minimal",
|
||
|
|
needsWorktree: true,
|
||
|
|
allowedCommands: null,
|
||
|
|
};
|
||
|
|
|
||
|
|
const HARNESS_DEFAULTS: Record<string, Partial<HarnessConfig>> = {
|
||
|
|
minimal: { harnessType: "minimal", needsWorktree: true, allowedCommands: null },
|
||
|
|
crewai: { harnessType: "crewai", needsWorktree: true, allowedCommands: null },
|
||
|
|
langgraph: { harnessType: "langgraph", needsWorktree: true, allowedCommands: null },
|
||
|
|
"remote-ag-ui": { harnessType: "remote-ag-ui", needsWorktree: false, allowedCommands: [] },
|
||
|
|
};
|
||
|
|
|
||
|
|
const HARNESS_BY_ALIAS: Record<string, HarnessConfig> = {
|
||
|
|
"doc-writer": DOC_WRITER,
|
||
|
|
minimal: DEFAULT,
|
||
|
|
default: DEFAULT,
|
||
|
|
};
|
||
|
|
|
||
|
|
function configForAlias(alias: string): HarnessConfig {
|
||
|
|
if (HARNESS_BY_ALIAS[alias]) return HARNESS_BY_ALIAS[alias]!;
|
||
|
|
const def = HARNESS_DEFAULTS[alias] as Partial<HarnessConfig> | undefined;
|
||
|
|
if (def?.harnessType) {
|
||
|
|
return {
|
||
|
|
alias,
|
||
|
|
harnessType: def.harnessType,
|
||
|
|
needsWorktree: def.needsWorktree ?? true,
|
||
|
|
allowedCommands: def.allowedCommands ?? null,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
return { alias, harnessType: "minimal", needsWorktree: true, allowedCommands: null };
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Resolve harness config for a job. Brief 3 adds harness_providers + remote-ag-ui.
|
||
|
|
* - If job carries `harnessAlias` use it (from orchestrator or DB route).
|
||
|
|
* - Else if roleId itself is a harness alias use it.
|
||
|
|
* - Else fallback to minimal.
|
||
|
|
*/
|
||
|
|
export function resolveHarnessForJob(job: {
|
||
|
|
roleId: string;
|
||
|
|
harnessAlias?: string | null;
|
||
|
|
harnessType?: string | null;
|
||
|
|
endpointUrl?: string | null;
|
||
|
|
authEnvVar?: string | null;
|
||
|
|
}): HarnessConfig {
|
||
|
|
const alias = job.harnessAlias ?? (HARNESS_BY_ALIAS[job.roleId] ? job.roleId : null);
|
||
|
|
if (alias) {
|
||
|
|
const base = configForAlias(alias);
|
||
|
|
return {
|
||
|
|
...base,
|
||
|
|
...(job.harnessType ? { harnessType: job.harnessType as HarnessType } : {}),
|
||
|
|
...(job.endpointUrl !== undefined ? { endpointUrl: job.endpointUrl } : {}),
|
||
|
|
...(job.authEnvVar !== undefined ? { authEnvVar: job.authEnvVar } : {}),
|
||
|
|
};
|
||
|
|
}
|
||
|
|
if (job.roleId.includes("doc")) return DOC_WRITER;
|
||
|
|
return DEFAULT;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function allowedCommandsForHarness(harness: HarnessConfig): readonly string[] | null {
|
||
|
|
return harness.allowedCommands === null ? ALLOWED_COMMANDS : harness.allowedCommands;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Executor registry — minimal adapter delegates to MinimalSession; remote adapters
|
||
|
|
* could call AG-UI endpoint. For brief 3 all adapters share the same local
|
||
|
|
* MinimalSession implementation but are differentiated by harnessType for
|
||
|
|
* observability and future extension.
|
||
|
|
*/
|
||
|
|
export function getHarnessExecutor(alias: string): { id: string; harnessType: HarnessType } {
|
||
|
|
const cfg = configForAlias(alias);
|
||
|
|
return { id: cfg.alias, harnessType: cfg.harnessType };
|
||
|
|
}
|