feat(provider): add OMP CLI provider (omp_cli)#328
Conversation
Add a new provider adapter for the OMP CLI (`omp` binary), following the
existing adapter pattern. OMP is integrated as a generic TUI agent:
- providers/omp_cli.py: OmpCliProvider implementing BaseProvider with
env-overridable regexes (CAO_OMP_*_REGEX) so status detection / extraction
can be recalibrated against real `omp` output without a code change. Command
resolved via shutil.which("omp"); optional --model override. Fresh-spawn
vs delivered-turn (IDLE vs COMPLETED) distinguished via a turn counter.
- manager.py: register OMP_CLI construction branch.
- install_service.py: explicit context-file-only placeholder branch (no native
agent-config format yet; agent_file stays None).
- terminal_service.py: document OMP's deliberate exclusion from both capability
sets (skills via context file; native tool vocab not yet characterised).
- api/main.py: provider_binaries omp_cli -> omp.
- launch.py: add omp_cli to PROVIDERS_REQUIRING_WORKSPACE_ACCESS.
- ProviderType.OMP_CLI enum (PROVIDERS / valid_providers auto-derived).
- tests: test_omp_cli_unit.py (status/extraction/lifecycle), manager
registration assertion, e2e conftest require_omp fixture.
- docs/omp-cli.md.
Purely additive; no existing provider behaviour changed. Default status/extraction
patterns are placeholders to be calibrated against real `omp` output via env vars.
Work item: d7348a1e-f6d6-4a24-96a9-edab9b74d8ff
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The omp_cli provider (commit 0b8056d) raised the installed-provider count from 10 to 11, but test_list_providers_all_installed still asserted == 10 and omitted omp_cli from the expected names. Update the count and assertion. Work item: d7348a1e-f6d6-4a24-96a9-edab9b74d8ff Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@bigyee66 Thanks for your contribution! Can you please make sure that the new provider pass the examples/assign test ? You can also refer to the skill https://github.com/awslabs/cli-agent-orchestrator/tree/main/skills/cao-provider for the new provider. Also please address the copilot's reviews, and fix the CI errors and Codecov Report. Much appreciated! |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #328 +/- ##
=======================================
Coverage ? 87.48%
=======================================
Files ? 95
Lines ? 11590
Branches ? 0
=======================================
Hits ? 10139
Misses ? 1451
Partials ? 0
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds a new omp_cli provider integration (OMP CLI via omp binary) following the existing provider adapter pattern, plus registration, API/CLI wiring, tests, and documentation.
Changes:
- Introduce
OmpCliProviderwith env-overridable regex-based status detection and response extraction. - Register
omp_cliacross provider manager, provider enum, API provider listing, and CLI launch workspace-access gating. - Add unit tests/e2e fixture and provider documentation for OMP.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
src/cli_agent_orchestrator/providers/omp_cli.py |
New provider implementation (launch, status detection, extraction, lifecycle). |
src/cli_agent_orchestrator/providers/manager.py |
Registers OMP_CLI provider creation branch. |
src/cli_agent_orchestrator/models/provider.py |
Adds ProviderType.OMP_CLI. |
src/cli_agent_orchestrator/api/main.py |
Adds omp_cli -> omp to provider_binaries for /agents/providers. |
src/cli_agent_orchestrator/cli/commands/launch.py |
Adds omp_cli to PROVIDERS_REQUIRING_WORKSPACE_ACCESS. |
src/cli_agent_orchestrator/services/install_service.py |
Adds explicit no-op install branch for omp_cli (context-file-only). |
src/cli_agent_orchestrator/services/terminal_service.py |
Documents why OMP is excluded from capability sets. |
test/providers/test_omp_cli_unit.py |
New unit test suite for OMP provider status/extraction/launch behavior. |
test/providers/test_provider_manager_unit.py |
Adds assertion that manager constructs/stores OmpCliProvider. |
test/api/test_api_endpoints.py |
Updates provider list expectation to include omp_cli. |
test/e2e/conftest.py |
Adds require_omp fixture to skip e2e tests if omp missing. |
docs/omp-cli.md |
New end-user/provider documentation for omp_cli. |
docs/PLAN-omp-cli.md |
New implementation plan document for the OMP provider. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| command = self._build_launch_command() | ||
| get_backend().send_keys(self.session_name, self.window_name, command) |
| # Strip a leading assistant-header marker but keep any same-line | ||
| # content that follows it. | ||
| stripped = re.sub(r"^\s*(?:Assistant|OMP|omp)[:,]\s*", "", raw_line).rstrip() | ||
| if stripped: | ||
| response_lines.append(stripped) |
| The provider intentionally takes the lowest-friction integration path: OMP has | ||
| no native agent-config format yet, so installation is context-file-only (see | ||
| ``install_service``), tool restrictions are advisory (no tool_mapping entry), | ||
| and the CAO skill catalog is delivered via the context file rather than a | ||
| native launch flag. This mirrors the early-stage stance that ``claude_code`` | ||
| and ``hermes`` took and keeps the change purely additive — no existing | ||
| provider's behaviour is touched. |
| skill_prompt: Optional skill catalog text. OMP does not inject a | ||
| CAO runtime skill catalog at launch (skills reach the agent via | ||
| the context file); the value is accepted for API symmetry and | ||
| ignored with a log line. |
| if self._skill_prompt: | ||
| logger.info( | ||
| "OMP provider does not inject a CAO runtime skill catalog at launch; " | ||
| "skills reach the agent via the install-time context file." | ||
| ) |
| # - RUNTIME_SKILL_PROMPT_PROVIDERS: OMP receives its role (and any skill | ||
| # catalog) via the install-time context file rather than a launch-time | ||
| # system prompt, so it has no skill_prompt kwarg to consume. | ||
| # - SOFT_ENFORCEMENT_PROVIDERS: OMP's native tool vocabulary is not yet |
| For now OMP is deliberately excluded from both `terminal_service` capability | ||
| sets: | ||
|
|
||
| - **Runtime skill prompts** — skills reach OMP via the context file, not a | ||
| launch-time system prompt, so there is no `skill_prompt` to consume. | ||
| - **Soft tool enforcement** — OMP's native tool vocabulary is not yet | ||
| characterised, so there is no reliable advisory prompt to emit. Tool | ||
| restrictions are still recorded but only reach the agent via the context file. |
| # 实施计划:新增 OMP CLI Provider | ||
|
|
||
| 需求 d7348a1e《扩展 CLI 支持 - 新增 OMP CLI 对接》— 在 cli-agent-orchestrator (CAO) 中新增 `omp_cli` provider,沿用现有 provider 适配器模式,使 Agent 能通过 `omp` CLI 执行操作。 | ||
|
|
gutosantos82
left a comment
There was a problem hiding this comment.
PR Review: #328 — feat(provider): add OMP CLI provider (omp_cli)
Summary
Adds an OmpCliProvider adapter (omp binary) as a generic TUI agent, following the
established Hermes/cursor_cli pattern. The change is genuinely additive — no existing
provider behaviour is touched, command construction is safe, and the enum/manager/API
registration wiring is consistent. Three things hold up a merge: a correctness bug in
ERROR detection that will misfire on ordinary turn output, a security gap where
restricted tool policies are silently treated as unrestricted with no operator warning, and
missing README/CHANGELOG entries required by the CAO new-provider checklist.
Reviewer coverage: all five angles (correctness, security, tests, conventions, consistency)
reported.
Blocking (must fix before merge)
-
[correctness] providers/omp_cli.py:326 (ERROR_PATTERN) / :538 (usage) — ERROR detection
has no stale-buffer/position guard, unlike WAITING (:531) and PROCESSING (:546). The
pattern is matched against the last-30-line tail withIGNORECASE|MULTILINEand wins over
IDLE/COMPLETED. Any completed turn whose output contains a line startingError:/ERROR:
(test output, tool logs, the agent quoting an error) pins the terminal to ERROR even though
omp>is present at the bottom. Concrete:● run tests\nError: 3 tests failed\n…\nomp>→
returns ERROR, should be COMPLETED — the supervisor concludes the worker crashed. Fix: apply
the same "no idle prompt follows the last match" guard that WAITING/PROCESSING already use.
(providers/ path — weighted up to blocking.) -
[conventions] README.md (provider table ~:120-131, "Valid values" lists ~:167 and ~:257) —
the newomp_cliprovider is not added to the README provider table or to either valid-values
list. The CAO new-provider checklist requires these. Add the table row (docs link + auth) and
appendomp_clito both lists. -
[conventions] CHANGELOG.md (:7-11,
[Unreleased] > Added) — a new user-facing provider
ships with no CHANGELOG entry (the section only lists Hermes). Add an entry, e.g.
"add OMP CLI provider (omp_cli)".
Important (should fix)
-
[security] services/terminal_service.py:127+ (exclusion) / ~:259 (warning site) — OMP is
excluded fromSOFT_ENFORCEMENT_PROVIDERS, so the launch-time warning that fires for
soft-enforcement providers ("cannot enforce tool restrictions… treat as unrestricted") does
not fire foromp_cli. Combined with notool_mappingentry and no native blocking flag,
a profile requesting restrictedallowed_toolson OMP is silently treated as fully
unrestricted — strictly weaker than the existing model, with none of the guidance
kimi_cli/codex get. Fix: addProviderType.OMP_CLI.valuetoSOFT_ENFORCEMENT_PROVIDERSso
the warning fires, or gate OMP behind an explicit acknowledgment. (services/ path — weighted up.) -
[security] false "restrictions reach the agent via the context file" claim — repeated in
docs/omp-cli.md:135-136, install_service.py:362-369, omp_cli.py:399 & :463-466._write_context_file
writes only the profile's role markdown; it never serializesallowed_tools. So the restriction
reaches the agent through no channel at all (not even advisory) unless the author hand-types
it into the role body. This can lull an operator into assigning a restricted role believing it is
conveyed. Fix: correct the wording ("restrictions are NOT conveyed to OMP") or actually inject
allowed_toolsinto the context/prompt. (Pairs with the enforcement-gap finding above.) -
[correctness] providers/omp_cli.py:600 (hard-coded header strip) —
_extract_response
anchors on the env-overridableASSISTANT_HEADER_PATTERN(:331) but strips the leading marker
with a hard-coded literal^\s*(?:Assistant|OMP|omp)[:,]\s*. If an operator overrides the
header env var to OMP's real marker (the entire point of the env-overridable design), extraction
anchors correctly but does not strip the custom marker — the raw header leaks into every extracted
response. Fix: reuseASSISTANT_HEADER_PATTERNfor the strip. -
[correctness] providers/omp_cli.py:313-317 (PROCESSING_PATTERN) — defaults match bare words
Thinking|Working|interrupt|cancelunder IGNORECASE, so ordinary prose ("I'm working on it",
"cancel the order") matches. Inget_statusthe position guard saves it, but_extract_response
(:596) drops any response line containing these words — legitimate content is silently deleted
from the extracted message. Tighten the defaults to require a spinner glyph or trailing ellipsis. -
[consistency/conventions] docs/PLAN-omp-cli.md (new, 70 lines) — a Chinese-language internal
planning/handoff doc (requirement id, risk tables, plan→develop notes) shipped under the published
docs/tree, breaking the "one Englishdocs/<provider>-cli.md" convention (already satisfied by
docs/omp-cli.md). It also contains the non-inclusive term 白名单 ("whitelist") at :11. Remove it from
the PR (fold anything durable into omp-cli.md); this also clears the inclusive-language hit. -
[consistency] PR description — "36 tests" vs. ~19 shipped — the body claims 36 passing tests, but
only ~19 new test functions ship (test_omp_cli_unit.py: 18; test_provider_manager_unit.py: 1; the API
test is a one-line count bump, not a new test). Correct the count or add the missing tests. -
[tests] placeholder-regex false confidence — test_omp_cli_unit.py:1-9 and omp_cli.py:246 admit every
status/extraction regex is a placeholder pending calibration; the fixtures were written to match those
placeholders, so the tests validate branch logic (priority order, guards, turn counter) but give zero
signal about realompoutput. Green CI here does not mean "works against omp." Merge only with an explicit
"not production-ready until regexes calibrated" note (the PR body's Known-follow-ups section partly covers this). -
[tests] get_status priority ordering + WAITING guard untested — each status is asserted only in
isolation; no test exercises coexisting triggers (e.g. approval dialog +Error:line, which the code
resolves WAITING-before-ERROR), so the documented 7-level priority (omp_cli.py:502-511) is unverified. The
WAITING position guard's "dialog followed by idle → not WAITING" branch has no test, even though the
analogous PROCESSING guard does. Note: this gap is exactly why the blocking unguarded-ERROR bug slipped
through —test_error_detecteduses an error buffer with no trailingomp>, so it passes while masking the
misfire. Add priority/coexistence tests, including one that would catch the ERROR guard. -
[tests] initialize() entirely untested — omp_cli.py:470-495 (binary probe + send_keys + wait_until_status
- 120s timeout) has no coverage. Also untested: model-override-via-agent-profile (only explicit
model=is
covered; theload_agent_profilebranch + its best-effort except at :444-450 are not).
- 120s timeout) has no coverage. Also untested: model-override-via-agent-profile (only explicit
Nits (optional)
- [correctness] providers/omp_cli.py:525 —
bottom_outputis assigned but never used. Dead variable. - [correctness/conventions] providers/omp_cli.py:348 (
_is_chrome_line) — defined but never called;
_extract_responseinlines its own chrome checks. Dead code copied from the Hermes template — remove
it or wire it into extraction. - [conventions] providers/omp_cli.py:457 & :463 — the "skill_prompt ignored" / "no native
tool-restriction flag" cases log atlogger.info; the Hermes precedent useslogger.warningfor the
identical situations. Align for cross-provider consistency. - [correctness/consistency] docstring & docs vs. code — ERROR_PATTERN (:326), SEPARATOR_PATTERN (:337),
and ANSI_CODE_PATTERN (:301) are not env-overridable, yet the module docstring and docs/omp-cli.md:148
("All detection patterns are overridable") imply they are. Reword to "all classification-prompt patterns",
and consider making ERROR overridable for parity. - [security] providers/omp_cli.py:306-333 & usage — env-override regexes are read at import and used
directly with nore.compile/try-except. A malformed override raisesre.errorat status-poll time
(crashes polling); a pathological pattern enables ReDoS over the agent-influenced buffer. Compile once at
load with a fallback-and-log. - [correctness] providers/omp_cli.py:611 — extraction runs
strip_terminal_escapes(normalizes \r→\n)
then_strip_ansi; cursor_cli deliberately avoidsstrip_terminal_escapesin extraction because \r→\n
splits redraw frames, and the second_strip_ansiis redundant. - [conventions] services/install_service.py:629 — the new
elif … OMP_CLI: … passbranch is a functional
no-op (the default context-file-only path already handles OMP). Acceptable — it's documented as an
intentional extension point. - [security] providers/omp_cli.py:437 (shutil.which) — resolves the first
ompon PATH (PATH-hijack
surface). Matches every existing provider and is called out in the docs — pre-existing pattern, not
introduced.
Prior feedback (already raised — not restating)
No overlap — all findings below are net-new relative to existing human comments.
Tests
No dedicated tests review returned — this is a partial assessment reconstructed from the correctness and
consistency reviewers. The suite covers status four-states, extraction, lifecycle, manager registration, an
require_omp e2e fixture, and the API provider-count bump (10→11) — reasonable breadth for an additive
provider. Notable gaps worth adding: (1) no test for the ERROR-vs-idle case — the existing test_error_detected
uses an error buffer with no trailing omp>, so it passes while masking the blocking ERROR-guard bug; (2) no
test exercising the env-override path (the headline feature) — defaults only; (3) no test asserting the
hard-coded header-strip works against an overridden marker. The "36 tests" claim in the PR body is inaccurate
(~19 shipped).
Verdict
Request changes — one correctness bug (unguarded ERROR detection) and a silent tool-enforcement gap in core
paths, plus the required README/CHANGELOG checklist items, should land before merge. The rest are quick doc/wording
and dead-code cleanups.
feat(provider): add OMP CLI provider (omp_cli)
Adds a new provider adapter for the OMP CLI (
ompbinary), following theexisting adapter pattern. OMP is integrated as a generic TUI agent. Work item
d7348a1e-f6d6-4a24-96a9-edab9b74d8ff.
Changes (purely additive — no existing provider behaviour touched)
providers/omp_cli.py—OmpCliProviderimplementingBaseProvider:CAO_OMP_*_REGEX) so status detection / responseextraction can be recalibrated against real
ompoutput without a codechange (same pattern Hermes uses).
shutil.which("omp"); optional--modeloverride(constructor or agent profile).
internal turn counter (
mark_input_received), since the buffer alone can'ttell them apart (mirrors cursor_cli).
(with a position guard against stale scrollback), COMPLETED/IDLE, UNKNOWN.
providers/manager.py— register theOMP_CLIconstruction branch.services/install_service.py— explicit context-file-only placeholderbranch (OMP has no native agent-config format yet;
agent_filestays None).services/terminal_service.py— documents OMP's deliberate exclusion fromboth capability sets (skills via context file; native tool vocabulary not yet
characterised).
api/main.py—provider_binariesgainsomp_cli -> omp.cli/commands/launch.py— addomp_clitoPROVIDERS_REQUIRING_WORKSPACE_ACCESS.models/provider.py—ProviderType.OMP_CLIenum (PROVIDERS/valid_providersauto-derived).test/providers/test_omp_cli_unit.py— status four-states + extraction +lifecycle (36 tests incl. manager).
test/providers/test_provider_manager_unit.py—omp_cliregistrationassertion.
test/e2e/conftest.py—require_ompfixture.docs/omp-cli.md— per-provider documentation.Validation
pytest test/providers/test_omp_cli_unit.py test/providers/test_provider_manager_unit.py→ 36 passed.python -cimport + manager build smoke test passes;PROVIDERSandPROVIDERS_REQUIRING_WORKSPACE_ACCESSboth containomp_cli.Known follow-ups
Default status/extraction regexes are placeholders calibrated against
representative TUI agents. Calibration against real
ompoutput is owed and isdesigned to be done via env vars (no source edit) during test_e2e/test_unit.
Note on fork
The upstream
awslabs/cli-agent-orchestratoris read-only for the contributor,so this PR targets
awslabs:mainfrom the forkbigyee66:harness/d7348a1e.