## Summary - Add `fusion-plugin-omp-runtime` so Fusion agents can run through operator-installed **Oh My Pi (`omp`)** over the [Agent Client Protocol](https://omp.sh/docs/acp) (`omp acp`). - Wire staged/bundled install, Settings → Authentication card (enable + binary path), model discovery (`omp models` → `omp-cli/*`), and MCP eligibility for runtime id `omp`. - Forward Fusion `systemPrompt` via ACP `session/new` `_meta.systemPromptOverride`. ## How operators use it 1. Install/auth `omp` (credentials under `~/.omp`). 2. Enable **Oh My Pi — via omp ACP** in Settings → Authentication (optional binary path). 3. Set agent **Runtime Source → OMP Runtime** (`runtimeHint: "omp"`), or pick an `omp-cli/*` model when enabled. ## Known v1 gaps - No Grok-style Fusion `fn_*` loopback tool bridge yet (operator MCP is forwarded; in-process custom tools are not). - Model is fixed at spawn (`omp --model … acp`); no mid-session Fusion model switch. ## Test plan - [x] `pnpm --filter @fusion-plugin-examples/omp-runtime test` (unit + live ACP when `omp` is on PATH) - [x] Auth routes: `POST /api/auth/omp-cli`, `GET /api/providers/omp-cli/status` - [x] Engine `runtimeSupportsMcp("omp")` - [ ] Manual: enable card in dashboard, select OMP runtime on an agent, run a short chat turn <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Oh My Pi (OMP) CLI support as an ACP-backed runtime and model provider, including model discovery and probing. * Added dashboard auth/status controls to enable OMP, check readiness, and configure the local binary path (with validation). * Exposed OMP custom `fn_*` tools via an MCP loopback bridge, plus optional filesystem capabilities and stricter tool permission gating. * **Documentation** * Added/expanded OMP runtime contract and integration docs (including the ACP session/handshake flow). * **Tests** * Added Vitest coverage for settings wiring, provider status, model discovery, runtime sessions, permissions, MCP bridging, and live connectivity. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
56 lines
2.1 KiB
TypeScript
56 lines
2.1 KiB
TypeScript
import { MOCK_PROVIDER_ID } from "@fusion/core";
|
|
import { createLogger } from "./logger.js";
|
|
|
|
const mcpRuntimeLog = createLogger("mcp-runtime");
|
|
/*
|
|
FNXC:OmpAcp 2026-07-11-23:35:
|
|
`omp` is the Oh My Pi ACP runtime (fusion-plugin-omp-runtime). It speaks
|
|
session/new.mcpServers like other ACP agents, so operator MCP must be eligible
|
|
for forwarding when that runtime is selected.
|
|
*/
|
|
const SUPPORTED_RUNTIME_IDS = new Set([
|
|
"pi",
|
|
"default-pi",
|
|
"claude",
|
|
"claude-code",
|
|
"claude-acp",
|
|
"acp",
|
|
"omp",
|
|
]);
|
|
|
|
function normalizeId(value: string | undefined): string {
|
|
return value?.trim().toLowerCase() ?? "";
|
|
}
|
|
|
|
/**
|
|
* FNXC:McpConfig 2026-06-25-21:35:
|
|
* MCP server definitions may contain materialized secrets by the time they reach runtime forwarding, so support decisions must be pure and content-free. Only known MCP-capable pi/Claude/ACP runtimes receive servers; mock and unknown runtimes skip forwarding without inspecting or logging server definitions.
|
|
*/
|
|
export function runtimeSupportsMcp(runtimeId: string | undefined, provider?: string): boolean {
|
|
if (normalizeId(provider) === MOCK_PROVIDER_ID) return false;
|
|
const normalizedRuntimeId = normalizeId(runtimeId);
|
|
if (!normalizedRuntimeId) return false;
|
|
if (SUPPORTED_RUNTIME_IDS.has(normalizedRuntimeId)) return true;
|
|
// Vendor/plugin runtime ids often include their transport family in a prefix/suffix; keep this content-free fuzzy match so future Claude/ACP runtimes do not need to expose server definitions to prove support.
|
|
return normalizedRuntimeId.includes("claude") || normalizedRuntimeId.includes("acp");
|
|
}
|
|
|
|
export interface McpForwardingSkipDetails {
|
|
runtimeId?: string;
|
|
provider?: string;
|
|
skippedCount: number;
|
|
lane?: string;
|
|
}
|
|
|
|
export function logMcpForwardingSkipped(details: McpForwardingSkipDetails): void {
|
|
if (details.skippedCount <= 0) return;
|
|
mcpRuntimeLog.log(JSON.stringify({
|
|
event: "mcp.forwarding.skipped",
|
|
reason: "unsupported-runtime",
|
|
runtimeId: details.runtimeId ?? null,
|
|
provider: details.provider ?? null,
|
|
lane: details.lane ?? null,
|
|
skippedCount: details.skippedCount,
|
|
}));
|
|
}
|