Skip to content

Add Pi and OMP harnesses with OMP as the default - #913

Open
santoshkumarradha wants to merge 5 commits into
mainfrom
agent/add-pi-omp-harnesses
Open

Add Pi and OMP harnesses with OMP as the default#913
santoshkumarradha wants to merge 5 commits into
mainfrom
agent/add-pi-omp-harnesses

Conversation

@santoshkumarradha

@santoshkumarradha santoshkumarradha commented Aug 12, 2026

Copy link
Copy Markdown
Member

Product outcome

AgentField can now run Pi and OMP as first-class coding harnesses from Python, TypeScript, and Go. OMP is the consistent zero-configuration default, while explicit provider selection remains fully supported. A production-shaped Go example fans one task out to Pi and OMP concurrently and joins their typed results in a single AgentField workflow.

This closes the practical parity gap with OpenCode: applications use the same AgentField harness contract for model selection, project root, system prompt, tools, permissions, session resume, structured output, retries/timeouts, and normalized usage metrics.

Developer experience

  • Provider resolution is identical in every SDK: per-call override → agent harness config → OMP.
  • Model resolution is per-call override → agent config → the selected CLI's own configured default. The SDK no longer injects a Claude-specific sonnet fallback into provider-neutral calls.
  • Explicit calls such as provider="opencode" or provider="pi" are unchanged.
  • Provider-less usage attribution is now deterministic (harness=omp) across Python, TypeScript, and Go.
  • Missing Pi/OMP executables produce actionable errors with the exact upstream install command.
  • af harness doctor recognizes both CLIs, reports binary/version/auth/usability, and lists OMP first as the default.
  • The README, provider guide, architecture design, shipped AgentField skill, and Go example document the default and operational lifecycle.

Architecture

  • Adds a shared Pi-family adapter in each SDK with thin Pi/OMP flavor mapping instead of duplicating orchestration logic.
  • Dispatches one-shot prompts through stdin and consumes JSON event streams, avoiding interactive CLI behavior.
  • Maps AgentField's provider-neutral options to native CLI behavior:
    • model + #variant--model + --thinking
    • project root → process cwd for Pi; --cwd plus process cwd for OMP
    • plan/auto → read-only tool filtering plus the provider's native approval flag
    • resume → Pi --session; OMP --resume
    • tool names → Pi find; OMP glob
  • Reuses the existing isolated schema-file protocol and retry/validation orchestration used by the other harnesses.
  • Normalizes sessions, turns, tokens, cache tokens, cost, model, duration, messages, return code, and failure classification into the existing result types.
  • Keeps runtime installation outside SDK execution. Like Codex, Gemini, and OpenCode, operators install/pin the CLI in the host or image; AgentField only discovers, verifies, and invokes it. No application call mutates production hosts.

Parity assessment

Pi and OMP have feature parity with OpenCode at the AgentField contract boundary. Native flags are intentionally not identical: each adapter translates its CLI's approval, resume, project-root, and filesystem-search vocabulary. Those differences do not leak into application code.

Covered contract surface:

  • model and reasoning variant
  • project/cwd isolation and environment overrides
  • system prompt and normalized tool allowlist
  • plan and auto permission modes
  • resumable sessions
  • structured schema output with validation/recovery
  • timeout and retry controls
  • normalized token, cache, cost, session, turn, model, and duration metrics
  • binary overrides and actionable availability failures

Installation and operations

npm install -g --ignore-scripts @earendil-works/pi-coding-agent
curl -fsSL https://omp.sh/install | sh
af harness doctor --provider pi,omp --json

The doctor check is static and does not make a paid model request. Containers should install the selected CLI during image construction and run the doctor as a startup/CI gate.

Go workflow example

examples/go_agent_nodes/cmd/harness_duo registers:

compare
├── pi_worker   (explicit Pi)
└── omp_worker  (provider omitted; exercises the OMP default)

compare starts both branches concurrently and joins their structured results. It defaults to openrouter/minimax/minimax-m2.7 and accepts openrouter/google/gemini-2.5-flash for a faster smoke path.

Verification

  • Python: focused harness/types/usage suite passed; Ruff passed.
  • TypeScript: 81 files / 832 tests passed; typecheck and production build passed.
  • Go SDK: harness suite passed; changed agent/default/usage tests passed; example build passed.
  • Control plane: CLI and embedded-skill tests passed; embedded skills are in sync.
  • Final PR CI is green: 41 active checks passed across Go, Python, TypeScript, control-plane, Docker, local/Postgres functional tests, performance, aggregate/patch coverage, CodeQL, README links, and CLA (with only the expected AI-label job skipped).
  • Live doctor: Pi 0.84.1 and OMP 17.2.15, both authenticated through OpenRouter and usable.
  • Live AgentField execution: run_20260812_164308_d2tasl3y / exec_20260812_164308_fp15z9if succeeded in 19.4s with openrouter/google/gemini-2.5-flash; compare, pi_worker, and the provider-less omp_worker all completed with structured output and native cost/token metrics.
  • Earlier MiniMax validation also succeeded for both branches: run_20260812_162041_fw7j8b54 with openrouter/minimax/minimax-m2.7.

Compatibility

Two intentional default changes are called out here because they change behavior for callers that previously got a loud failure or a Claude-specific model:

  1. Provider-less harness calls now run OMP instead of failing. Previously, a harness call with neither a per-call nor configured provider raised No harness provider specified in all three SDKs. It now silently selects OMP (and makes a live model call). Callers who relied on that error to catch a misconfiguration are affected. Users who want another default can set it once in HarnessConfig; explicit provider=... calls are unchanged.
  2. Python HarnessConfig.model default changed from "sonnet" to None. Python callers who omitted model previously got the Claude-specific sonnet fallback; they now get whatever model the selected CLI is configured with. Go and TypeScript had no model default and are unaffected.

Explicit provider configurations are otherwise unchanged.

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Performance

SDK Memory Δ Latency Δ Tests Status
Python 9.0 KB - 0.32 µs -9%
Go 165 B -41% 0.65 µs -35%
TS 468 B +34% 1.81 µs -9%

Regression detected:

  • TypeScript memory: 350 B → 468 B (+34%)

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

📊 Coverage gate

Thresholds from .coverage-gate.toml: per-surface ≥ 84%, aggregate ≥ 85%, max per-surface regression ≤ 1.0 pp, max aggregate regression ≤ 0.50 pp.

Surface Current Baseline Δ
control-plane 87.10% 87.40% ↓ -0.30 pp 🟡
sdk-go 92.80% 92.00% ↑ +0.80 pp 🟢
sdk-python 94.20% 93.73% ↑ +0.47 pp 🟢
sdk-typescript 91.11% 90.42% ↑ +0.69 pp 🟢
web-ui 84.76% 84.79% ↓ -0.03 pp 🟡
aggregate 85.62% 85.75% ↓ -0.13 pp 🟡

✅ Gate passed

No surface regressed past the allowed threshold and the aggregate stayed above the floor.

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

📐 Patch coverage gate

Threshold: 80% on lines this PR touches vs origin/main (from .coverage-gate.toml:thresholds.min_patch).

Surface Touched lines Patch coverage Status
control-plane 2 100.00%
sdk-go 247 91.00%
sdk-python 0 ➖ no changes
sdk-typescript 123 89.00%
web-ui 0 ➖ no changes

✅ Patch gate passed

Every surface whose lines were touched by this PR has patch coverage at or above the threshold.

@santoshkumarradha santoshkumarradha changed the title Add Pi and OMP harness providers Add Pi and OMP harnesses with OMP as the default Aug 12, 2026
@santoshkumarradha
santoshkumarradha marked this pull request as ready for review August 12, 2026 20:47
@santoshkumarradha
santoshkumarradha requested a review from a team as a code owner August 12, 2026 20:47
@Agent-Field Agent-Field deleted a comment from cursor Bot Aug 12, 2026
@Agent-Field Agent-Field deleted a comment from cursor Bot Aug 13, 2026
@cursor

cursor Bot commented Aug 13, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

- Go pi.go: build the plan-mode read-only tool list as a fresh slice
  instead of the in-place tools[:0] filter, matching the Python/TS
  providers and removing the aliasing footgun.
- Go pi.go: distinguish a negative return code (signal kill) from a
  plain non-zero exit, reporting 'Process killed by signal N.' to match
  the Python provider and the gemini/opencode Go providers.
- Add a pi_test.go case pinning the signal-kill message.
@santoshkumarradha

Copy link
Copy Markdown
Member Author

Addressing the review findings on this PR.

Code changes (commit 973913eb):

  • Go tools[:0] in-place filtersdk/go/harness/pi.go plan-mode branch now builds the read-only tool list as a fresh slice (make([]string, 0, len(tools))) instead of aliasing the tools backing array. This matches the Python and TS providers, which both build a fresh list, and removes the footgun if normalizePiTools is ever changed to return a caller-owned slice.
  • Go negative return codesdk/go/harness/pi.go now distinguishes a signal kill (ReturnCode < 0) from a plain non-zero exit, reporting Process killed by signal N. to match the Python provider and the existing gemini.go / opencode.go Go providers. Previously a SIGKILL was folded into the generic non-zero branch with a misleading "exited with code -9" message. Added a pi_test.go case pinning the signal-kill message.

Release-note callouts (PR body, "Compatibility" section):

  • Called out the provider→OMP default change: provider-less harness calls now run OMP (a live model call) instead of raising No harness provider specified. Callers who relied on that error to catch a misconfiguration are affected.
  • Called out the Python HarnessConfig.model sonnetNone default change: Python callers who omitted model previously got the Claude-specific sonnet fallback; they now get the selected CLI's configured default. Go/TS had no model default and are unaffected.

Not changed (reviewed, left as-is to keep the diff minimal):

  • The TS factory's unreachable throw (nit; dead code, harmless).
  • The harness_duo early-return leaving a branch in flight (nit; buffered channel, no leak, demo example).
  • The mocked-CLI flag-coverage gap (nit; consistent with the other CLI providers in this repo).

Verification: go build ./..., go vet ./harness/, and the full sdk/go test suite pass after the changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant