## 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 -->
48 lines
1.7 KiB
TypeScript
48 lines
1.7 KiB
TypeScript
/* Vendored ACP client from fusion-plugin-acp-runtime — see ./VENDORED.md (FNXC:GrokAcp 2026-07-11-16:00). */
|
|
// Pure helpers mapping ACP `ToolCall` metadata into the display name + args
|
|
// shape Fusion's `onToolStart`/`onToolEnd` callbacks expect.
|
|
//
|
|
// ACP's `kind` is agent-defined, optional, and partial (U4). These helpers must
|
|
// never throw on missing/odd input — a missing title falls back to a label
|
|
// derived from `kind`, and a missing/non-object `rawInput` normalizes to `{}`.
|
|
|
|
import type { ToolKind } from "@agentclientprotocol/sdk";
|
|
|
|
/** Human-readable labels for each ACP `ToolKind`. */
|
|
const KIND_LABELS: Record<ToolKind, string> = {
|
|
read: "Read",
|
|
edit: "Edit",
|
|
delete: "Delete",
|
|
move: "Move",
|
|
search: "Search",
|
|
execute: "Execute",
|
|
think: "Think",
|
|
fetch: "Fetch",
|
|
switch_mode: "Switch Mode",
|
|
other: "Tool",
|
|
};
|
|
|
|
/**
|
|
* Resolve a display name for a tool call. Prefers the agent-supplied `title`;
|
|
* falls back to a label derived from `kind`; final fallback is `"tool"`.
|
|
*/
|
|
export function toolDisplayName(toolCall: { title?: string | null; kind?: ToolKind | null }): string {
|
|
const title = typeof toolCall.title === "string" ? toolCall.title.trim() : "";
|
|
if (title) return title;
|
|
const kind = toolCall.kind;
|
|
if (kind && kind in KIND_LABELS) return KIND_LABELS[kind];
|
|
return "tool";
|
|
}
|
|
|
|
/**
|
|
* Normalize a tool call's `rawInput` to a plain object. Returns `{}` when the
|
|
* input is undefined, null, or any non-object (arrays included) so downstream
|
|
* code can always treat args as a record.
|
|
*/
|
|
export function normalizeToolArgs(rawInput: unknown): Record<string, unknown> {
|
|
if (rawInput === null || typeof rawInput !== "object" || Array.isArray(rawInput)) {
|
|
return {};
|
|
}
|
|
return rawInput as Record<string, unknown>;
|
|
}
|