feat: map flue interop gaps
This commit is contained in:
parent
68a0a48669
commit
c7cd28c404
|
|
@ -203,6 +203,7 @@ fable-agent plinius godmode "improve explanation quality"
|
||||||
- `fable5 route <task>`
|
- `fable5 route <task>`
|
||||||
- `-d, --domain <domain>`
|
- `-d, --domain <domain>`
|
||||||
- `fable5 models`
|
- `fable5 models`
|
||||||
|
- `fable5 flue`
|
||||||
- `fable5 verify <task>`
|
- `fable5 verify <task>`
|
||||||
- `--repo <path>`
|
- `--repo <path>`
|
||||||
- `fable5 goal <text>`
|
- `fable5 goal <text>`
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { FLUE_INTEROP_ROWS, formatFlueInteropReport, summarizeFlueInterop } from "./flue-interop.js";
|
||||||
|
|
||||||
|
describe("flue interop map", () => {
|
||||||
|
it("keeps Flue as an inspiration map, not vendored code", () => {
|
||||||
|
const report = formatFlueInteropReport();
|
||||||
|
|
||||||
|
expect(FLUE_INTEROP_ROWS.length).toBeGreaterThan(5);
|
||||||
|
expect(report).toContain("no vendored Flue code");
|
||||||
|
expect(report).toContain("next implementable patch: channels");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("prioritizes gaps before partials", () => {
|
||||||
|
expect(summarizeFlueInterop().next.flueConcept).toBe("channels");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
export type FlueInteropStatus = "covered" | "partial" | "gap";
|
||||||
|
|
||||||
|
export interface FlueInteropRow {
|
||||||
|
flueConcept: string;
|
||||||
|
fableSurface: string;
|
||||||
|
status: FlueInteropStatus;
|
||||||
|
nextPatch: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FLUE_INTEROP_ROWS: FlueInteropRow[] = [
|
||||||
|
{
|
||||||
|
flueConcept: "agents",
|
||||||
|
fableSurface: "fable5 meta/teams/chains",
|
||||||
|
status: "covered",
|
||||||
|
nextPatch: "Keep using existing MetaAgent, AgentTeams, and AgentChain surfaces.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flueConcept: "workflows",
|
||||||
|
fableSurface: "fable5 workflow + DynamicWorkflows",
|
||||||
|
status: "covered",
|
||||||
|
nextPatch: "No new engine; add examples only when a real workflow needs them.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flueConcept: "sandboxes",
|
||||||
|
fableSurface: "WorktreeManager + factory agent-sandbox capability",
|
||||||
|
status: "partial",
|
||||||
|
nextPatch: "Add a sandbox command adapter after one deploy path needs isolation beyond git worktrees.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flueConcept: "durable execution",
|
||||||
|
fableSurface: "session checkpointing + StateStore + ZTE receipts",
|
||||||
|
status: "partial",
|
||||||
|
nextPatch: "Record workflow step receipts so interrupted multi-step runs resume from the last passed step.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flueConcept: "subagents",
|
||||||
|
fableSurface: "fable5 teams + fan-out workflow",
|
||||||
|
status: "covered",
|
||||||
|
nextPatch: "Use existing team roles; do not add another subagent abstraction.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flueConcept: "tools and skills",
|
||||||
|
fableSurface: "SkillRegistry + SKILLS sync + factory capability registry",
|
||||||
|
status: "covered",
|
||||||
|
nextPatch: "Bridge manifests only; do not vendor Flue tool code.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flueConcept: "MCP",
|
||||||
|
fableSurface: "factory capability registry",
|
||||||
|
status: "partial",
|
||||||
|
nextPatch: "Add optional MCP endpoint fields to the registry when a live MCP server is adopted.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flueConcept: "observability",
|
||||||
|
fableSurface: "agent-observability + Prometheus/Grafana factory services",
|
||||||
|
status: "covered",
|
||||||
|
nextPatch: "Expose existing metrics in receipts before adding tracing code.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flueConcept: "channels",
|
||||||
|
fableSurface: "none explicit",
|
||||||
|
status: "gap",
|
||||||
|
nextPatch: "Add a tiny channel manifest: stdin/stdout/files/http/webhook capabilities per executor.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function summarizeFlueInterop(rows: FlueInteropRow[] = FLUE_INTEROP_ROWS): { covered: number; partial: number; gap: number; next: FlueInteropRow } {
|
||||||
|
const counts = rows.reduce(
|
||||||
|
(acc, row) => ({ ...acc, [row.status]: acc[row.status] + 1 }),
|
||||||
|
{ covered: 0, partial: 0, gap: 0 },
|
||||||
|
);
|
||||||
|
return { ...counts, next: rows.find((row) => row.status === "gap") ?? rows.find((row) => row.status === "partial") ?? rows[0] };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatFlueInteropReport(rows: FlueInteropRow[] = FLUE_INTEROP_ROWS): string {
|
||||||
|
const summary = summarizeFlueInterop(rows);
|
||||||
|
const lines = rows.map((row) =>
|
||||||
|
` ${row.status.toUpperCase().padEnd(7)} ${row.flueConcept.padEnd(18)} → ${row.fableSurface}\n next: ${row.nextPatch}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
"",
|
||||||
|
" Flue inspiration map (no vendored Flue code)",
|
||||||
|
" ─────────────────────────────",
|
||||||
|
` covered=${summary.covered} partial=${summary.partial} gap=${summary.gap}`,
|
||||||
|
"",
|
||||||
|
...lines,
|
||||||
|
"",
|
||||||
|
` next implementable patch: ${summary.next.flueConcept} — ${summary.next.nextPatch}`,
|
||||||
|
"",
|
||||||
|
].join("\n");
|
||||||
|
}
|
||||||
|
|
@ -47,5 +47,8 @@ export type { ZteReceipt, ZteSpec, ZteSpecOptions } from "./zte-protocol.js";
|
||||||
export { formatCapabilityReport, loadFactoryCapabilities, parseFactoryCapabilities, probeFactoryCapabilities } from "./factory-capabilities.js";
|
export { formatCapabilityReport, loadFactoryCapabilities, parseFactoryCapabilities, probeFactoryCapabilities } from "./factory-capabilities.js";
|
||||||
export type { CapabilityProbeResult, CapabilityReport, FactoryCapabilityService } from "./factory-capabilities.js";
|
export type { CapabilityProbeResult, CapabilityReport, FactoryCapabilityService } from "./factory-capabilities.js";
|
||||||
|
|
||||||
|
export { FLUE_INTEROP_ROWS, formatFlueInteropReport, summarizeFlueInterop } from "./flue-interop.js";
|
||||||
|
export type { FlueInteropRow, FlueInteropStatus } from "./flue-interop.js";
|
||||||
|
|
||||||
export { createForgejoIntakeReceipt, intakeForgejoItem, parseForgejoRef, routeForgejoLabels } from "./forgejo-intake.js";
|
export { createForgejoIntakeReceipt, intakeForgejoItem, parseForgejoRef, routeForgejoLabels } from "./forgejo-intake.js";
|
||||||
export type { ForgejoIntakeKind, ForgejoIntakeOptions, ForgejoIntakeReceipt, ForgejoIntakeSource, ForgejoItem, ForgejoRoute } from "./forgejo-intake.js";
|
export type { ForgejoIntakeKind, ForgejoIntakeOptions, ForgejoIntakeReceipt, ForgejoIntakeSource, ForgejoItem, ForgejoRoute } from "./forgejo-intake.js";
|
||||||
|
|
|
||||||
|
|
@ -1579,6 +1579,14 @@ fable
|
||||||
console.log(` `);
|
console.log(` `);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fable
|
||||||
|
.command("flue")
|
||||||
|
.description("Show Flue-inspired interop gaps without vendoring Flue")
|
||||||
|
.action(async () => {
|
||||||
|
const { formatFlueInteropReport } = await import("./fable5/flue-interop.js");
|
||||||
|
console.log(formatFlueInteropReport());
|
||||||
|
});
|
||||||
|
|
||||||
fable
|
fable
|
||||||
.command("verify <task>")
|
.command("verify <task>")
|
||||||
.description("Run independent verifier against a task")
|
.description("Run independent verifier against a task")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue