mirror of
https://github.com/multica-ai/multica.git
synced 2026-08-13 19:43:27 +02:00
* feat(agent): add oh-my-pi (omp) as a supported agent runtime oh-my-pi (omp, https://omp.sh) is a separate CLI that is a drop-in fork of pi and speaks the same JSON event protocol. It is registered as an independent provider so a host with both pi and omp installed gets two runtimes instead of one. omp is a runtime identity on the pi protocol, NOT a new protocol family. It is declared in a single BuiltinRuntimes descriptor (server/pkg/agent/builtin_runtimes.go) that carries id, protocol_family, default_command, env_prefix, display_name, skills_dir, user_skills_dir, launch_header, backend overrides, and model_discovery strategy. Every consumer (agents_probe.go, config.go, daemon.go, execenv/context.go, local_skills.go, agent.go New/LaunchHeader, models.go ListModels) derives from this descriptor — no per-file hardcoded omp special cases. NewRuntime() is the typed entry point for runtime identities: it resolves id → descriptor → protocol family backend → applies overrides through a backendOverrideApplicator interface (piBackend implements it). New() delegates to NewRuntime() for built-in runtime identities, keeping New() meaning exactly one thing: the protocol-family factory. Model discovery: parseOmpModels reads the real {"models":[...]} wrapper with separate provider/id/selector/name fields. Model.ID is the selector (provider/id), matching parsePiModels' convention so buildPiArgs emits both --provider and --model — not just --model. A regression test (TestOmpSelectorSurvivesToBuildPiArgs) pins this end-to-end. Frontend: provider-logo.tsx maps omp to PiLogo. The transcript dialog uses the shared providerDisplayName helper. Landing copy updated to 21 tools in all 4 locales. Tests (omp_test.go): descriptor dispatch, NewRuntime entry point, binary resolution, omp-labeled errors, event-stream completion, pi+omp side-by-side registration, selector→buildPiArgs regression, model parser coverage (real JSON/empty wrapper/invalid stderr/duplicate), and a guard that every descriptor field is non-empty and consumed. Closes #3989 * fix(views): keep Claude Code label in the transcript run details Switching the provider row to the shared runtime formatter renamed every Claude run: the daemon has no display-name override for claude, so the shared formatter answers "Claude", and the legacy claude-code value title-cased into "Claude-code". Both read as "Claude Code" before. Keep those two aliases in a table local to this view and defer everything else to the shared formatter, so the row stays in lockstep with the runtime list (#5260) without renaming Claude runs. * test(daemon): assert pi and omp both reach the register payload The existing omp test stopped at probeAgentCLIs, so nothing covered the part a user actually sees: whether both runtimes are registered with the server, each under its own display name. Discovery finding two entries and New() building two backends both stop short of version detection and the registration payload. Add a daemon-level test that runs real discovery off a fake PATH, drives syncWorkspacesFromAPI, and asserts the payload carries type=pi and type=omp with names "Pi" and "Oh-My-Pi". Rename the discovery test to say what it covers, and record the registered display name in the batch fixture so the name can be asserted. * docs(agent): correct descriptor comments that describe the old behaviour Three doc comments still described behaviour the fail-closed rework replaced: - ModelDiscovery claimed a nil strategy falls back to the family's discovery; ListModels deliberately returns an empty catalog instead, because omp exits non-zero on pi's --list-models. - backendOverrideApplicator claimed backends without it are returned unchanged; NewRuntime returns an error rather than dropping the descriptor's executable and label. - ProtocolFamily credited New() with applying the ID-specific defaults; that moved to NewRuntime. Also repair the truncated first sentence of the NewRuntime doc, and fix discoverOmpModels still calling the output a JSON array when parseOmpModels right below it documents the {"models":[...]} wrapper. * style(server): gofmt the files this branch touched Four files were left unformatted: the descriptor literal and the omp test struct lost their key alignment, execenv/context.go had its new import out of order, and local_skills.go kept the old indentation after its switch moved inside an if/else. Whitespace only — no behaviour change. --------- Co-authored-by: Bohan-J <bhjiang@outlook.com>