feat(harness): add NativeHarnessProvider seam foundation (PR 1.1) - #3239
Conversation
Add an append-only "Implementation progress" ledger to the modular-registry proposal so each PR in the stack records its own status without editing the plan tables (which would conflict across the 1.1→1.2→1.3 stack on every rebase). Seed it with 1.1 (#3239, in review). Co-authored-by: Isaac Signed-off-by: Pat Sukprasert <pattara.sk127@gmail.com>
|
First, additive step of Phase 1 of the modular native-harness registry (designs/harness-modular-registry-proposal.md). Introduces the behavior side-channel that later PRs will dispatch through; no hub is rewired yet, so this changes no runtime behavior. - Add `NativeHarnessProvider` (frozen dataclass of dotted import-path strings for a native harness's lifecycle hooks) and the `native_providers` field on `HarnessContribution`, plus `native_providers()` / `native_provider_for_key()` accessors. - Populate 11 built-in provider rows uniformly from the `omnigent.<key>_native` module layout (`run_<key>_native`, `_materialize_<key>_agent_spec`, and the `_auto_create_<key>_terminal` builder re-exported from `omnigent.runner.native`). Hooks that are still runner closures / inline dispatch (interrupt, stop, spawn-env, bridge-dir) stay None until those hubs migrate onto the seam. - Add `omnigent/native_dispatch.py`: a lazy, per-path-cached resolver over the existing `load_object`, with `resolve` / `resolve_hook` / `resolve_hook_for_key` so hubs resolve a hook instead of branching on `key == "<x>"`. Import hygiene preserved — provider rows hold strings; only the resolver imports the target modules, and only at dispatch time. - Tests: provider rows cover every native agent 1:1, required hooks are set, and every populated built-in path actually resolves to a callable (guards against a typo'd path or renamed symbol); resolver colon/dot forms, caching, and unset-hook / unknown-key None paths. The validator still rejects community native metadata (Phase 2 flips it). Co-authored-by: Isaac Signed-off-by: Pat Sukprasert <pattara.sk127@gmail.com>
Add an append-only "Implementation progress" ledger to the modular-registry proposal so each PR in the stack records its own status without editing the plan tables (which would conflict across the 1.1→1.2→1.3 stack on every rebase). Seed it with 1.1 (#3239, in review). Co-authored-by: Isaac Signed-off-by: Pat Sukprasert <pattara.sk127@gmail.com>
9e7f5a2 to
6adcaed
Compare
|
/review |
|
|
🏷️ Doc impact: Internal refactor adding a lazy provider-hook resolver seam for existing native harnesses (no new harness/provider/policy or changed user-facing config or defaults), so no documentation update is needed. Auto-classified on merge. Set the label manually before merging to override. · run |
Four conflicts. Three are our copy vs upstream's now-merged copy of the same change (omnigent-ai#3431, merged 2026-07-29) — took upstream wholesale, since the maintainer's version is stricter: the helper is public (harness_owns_its_credential) and gains an early `if canonical in _HARNESS_FAMILY: return False`. The fourth, runner/app.py, needed a real port rather than a side: ours: _build_acp_spawn_env(spec, ..., override_harness=acp_override) upstream: _build_acp_spawn_env(effective_spec, cwd=cwd, workdir=workdir) Upstream introduced `effective_spec`, which bakes in the per-session model override. Taking our side verbatim would have silently dropped that override for every ACP session, so this keeps upstream's spec AND our acp:<slug> threading (omnigent-ai#3057). The openai-agents picker label survives the merge untouched in both sources despite upstream refactoring harness_plugins.py three times (omnigent-ai#3239, omnigent-ai#3495, omnigent-ai#3500) — different regions, no conflict. Signed-off-by: apeltekci <andrew@peltekci.com>
Workstream progress
Modular native-harness registry (
designs/harness-modular-registry-proposal.md). 12 PRs total — Phase 1 (internal seam, core-only): 1.1–1.8; Phase 2 (community + web): 2.1–2.4. This is PR 1.1 — the additive foundation that unblocks the rest./v1/harnessesnative rows → 2.3 Web off the endpoint → 2.4 Docs + example plugin.Critical path: 1.1 → 1.2 → 1.5 → 2.2 → 2.3. After 1.1+1.2 land, 1.3–1.8 touch mostly disjoint hubs and can go in parallel.
Related issue
N/A — first implementation PR of the modular native-harness registry (Phase 1, PR 1.1). Tracked in
designs/harness-modular-registry-proposal.md.Summary
First, purely additive step of Phase 1: introduce the behavior side-channel that later PRs will dispatch native harnesses through. No hub is rewired yet, so this changes no runtime behavior — the built-in native harnesses still run exactly as before.
NativeHarnessProvider(a frozen dataclass of dotted import-path strings for a native harness's lifecycle hooks) and thenative_providersfield onHarnessContribution, plusnative_providers()/native_provider_for_key()accessors.omnigent.<key>_nativemodule layout:run_<key>_native(CLI + resume launch),_materialize_<key>_agent_spec(agent seeding), and the_auto_create_<key>_terminalbuilder re-exported fromomnigent.runner.native. Hooks that are still runner closures / inline dispatch (interrupt, stop, spawn-env, bridge-dir) stayNoneuntil those hubs migrate onto the seam in later PRs.omnigent/native_dispatch.py: a lazy resolver over the existingload_object, withresolve/resolve_hook/resolve_hook_for_key, so a hub can resolve a hook instead of branching onkey == "<x>". Resolution is intentionally uncached (dispatch runs at most once per resume/launch/seed;importlib.import_modulealready caches the module), which keepsmonkeypatch.setattr("...:run_x", ...)working.Import hygiene preserved: provider rows hold strings; only the resolver imports the target modules, and only at dispatch time — building the registry never pulls in the runner / CLI / native-harness stack.
The community validator still rejects native metadata; Phase 2 (2.1) flips it to positive validation.
This PR also adds an append-only Implementation progress ledger to the design doc so each PR in the stack records its status without editing the plan tables (which would conflict across the stack on rebase).
Test Plan
run_native,auto_create_terminal) are set, and — the key guard — that every populated built-in provider path actually resolves to a callable (imports all 33 target symbols across the 11 harnesses), so a typo'd import path or a renamedrun_<x>_nativesymbol fails here rather than at dispatch time.Nonepaths.Demo
N/A — no user-facing behavior change (additive data model + resolver only).
Type of change
Test coverage
Coverage notes
Unit tests accompany the new code (
tests/test_native_dispatch.py, additions totests/test_harness_plugins.py). Because this PR adds a data model + resolver and wires no dispatch hub, there is no runtime path to exercise end-to-end yet; the behavior-preservation of the built-ins is covered by the existing native suites, which are unchanged. The design-doc ledger is documentation-only.This pull request and its description were written by Isaac.