mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
2bb9f3fdf4
Introduce machinery for keeping examples/integrations/* demos aligned to a single north-star (langgraph-python). Built first so the upcoming langgraph-js and langgraph-fastapi alignment PRs have a mechanical baseline to work against instead of manual copy-paste. - examples/integrations/_parity/manifest.json declares verbatim files, tracked package.json keys, and expected agent surface (tool names, state keys) per instance plus allowed-divergence lists. - _parity/sync.ts copies verbatim files + rewrites tracked package.json keys from north-star to a target instance. Dry-run supported. - _parity/verify.ts diffs each instance vs north-star and exits non-zero on unexpected drift. Checks verbatim content, tracked keys, canonical prompt equality, and agent-surface grep-level presence. - Canonical prompt at _parity/canonical/PROMPT.md — synced into each instance's agent/PROMPT.md on parity:sync. - Root package.json: pnpm parity:sync, parity:verify, parity:check. - CI: .github/workflows/integrations_parity.yml runs parity:check on PRs touching examples/integrations/**. - Skill: .claude/skills/copilotkit-demo-parity/SKILL.md teaches agents how to drive sync/verify and handle manual-merge zones (agent code, api route, Dockerfile). Does NOT touch the existing instance demos yet. Those alignment commits follow in the same PR.
97 lines
2.7 KiB
TypeScript
97 lines
2.7 KiB
TypeScript
import { readFileSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
|
|
export type InstanceRole = "north-star" | "instance";
|
|
|
|
export interface AgentSurface {
|
|
toolNames: string[];
|
|
stateKeys: string[];
|
|
modelFamily: string;
|
|
}
|
|
|
|
export interface TrackedSurface {
|
|
verbatimFiles: string[];
|
|
packageJsonPaths: string[];
|
|
agentSurface: AgentSurface;
|
|
}
|
|
|
|
export interface InstanceAgent {
|
|
language: "python" | "typescript";
|
|
runtime: string;
|
|
}
|
|
|
|
export interface Instance {
|
|
role: InstanceRole;
|
|
agent: InstanceAgent;
|
|
allowedDivergence: string[];
|
|
packageJsonOverrides: Record<string, string>;
|
|
}
|
|
|
|
export interface Manifest {
|
|
version: number;
|
|
northStar: string;
|
|
canonicalPromptFile: string;
|
|
tracked: TrackedSurface;
|
|
instances: Record<string, Instance>;
|
|
}
|
|
|
|
export interface ParityRoot {
|
|
/** Absolute path to the parity dir, e.g. …/examples/integrations/_parity */
|
|
parityDir: string;
|
|
/** Absolute path to the integrations root, e.g. …/examples/integrations */
|
|
integrationsDir: string;
|
|
manifest: Manifest;
|
|
}
|
|
|
|
export function loadManifest(parityDir: string): ParityRoot {
|
|
const manifestPath = resolve(parityDir, "manifest.json");
|
|
const raw = readFileSync(manifestPath, "utf8");
|
|
const parsed = JSON.parse(raw) as Manifest;
|
|
validate(parsed, manifestPath);
|
|
return {
|
|
parityDir,
|
|
integrationsDir: resolve(parityDir, ".."),
|
|
manifest: parsed,
|
|
};
|
|
}
|
|
|
|
function validate(m: Manifest, source: string): void {
|
|
const err = (msg: string): never => {
|
|
throw new Error(`[parity] invalid manifest at ${source}: ${msg}`);
|
|
};
|
|
if (m.version !== 1) err(`unsupported version ${m.version}`);
|
|
if (!m.northStar) err("missing northStar");
|
|
if (!m.instances?.[m.northStar])
|
|
err(`northStar '${m.northStar}' not in instances`);
|
|
if (m.instances[m.northStar].role !== "north-star")
|
|
err(`northStar '${m.northStar}' must have role=north-star`);
|
|
|
|
const nonNorthStar = Object.entries(m.instances).filter(
|
|
([n]) => n !== m.northStar,
|
|
);
|
|
for (const [name, inst] of nonNorthStar) {
|
|
if (inst.role !== "instance")
|
|
err(`instance '${name}' must have role=instance`);
|
|
}
|
|
|
|
if (!m.tracked?.verbatimFiles?.length) err("tracked.verbatimFiles empty");
|
|
if (!m.tracked?.packageJsonPaths?.length)
|
|
err("tracked.packageJsonPaths empty");
|
|
if (!m.tracked?.agentSurface?.toolNames?.length)
|
|
err("tracked.agentSurface.toolNames empty");
|
|
}
|
|
|
|
export function instanceDir(root: ParityRoot, name: string): string {
|
|
return resolve(root.integrationsDir, name);
|
|
}
|
|
|
|
export function northStarDir(root: ParityRoot): string {
|
|
return instanceDir(root, root.manifest.northStar);
|
|
}
|
|
|
|
export function listInstances(root: ParityRoot): string[] {
|
|
return Object.keys(root.manifest.instances).filter(
|
|
(n) => n !== root.manifest.northStar,
|
|
);
|
|
}
|