Skip to content

[WIP] feat: add SubprocessDriver for CRD-based agent execution#232

Draft
rioloc wants to merge 6 commits intolightspeed-core:mainfrom
rioloc:feat/subprocess-agent-driver
Draft

[WIP] feat: add SubprocessDriver for CRD-based agent execution#232
rioloc wants to merge 6 commits intolightspeed-core:mainfrom
rioloc:feat/subprocess-agent-driver

Conversation

@rioloc
Copy link
Copy Markdown
Collaborator

@rioloc rioloc commented May 8, 2026

⚠️ Review after #228 and #231 are merged — this PR builds on top of those changes.

Summary

Add SubprocessDriver — a new AgentDriver that manages OpenShift Proposal CR lifecycle via oc/kubectl CLI, enabling evaluation of agentic workloads running on the cluster.

The driver builds and applies Proposal CRs, polls .status.conditions until a terminal state is reached, handles auto-approval via ProposalApproval resources, and cleans up on completion. It works directly with CRD conditions (the stable API contract) rather than replicating the operator's internal phase derivation logic.

Design document: https://gist.github.com/rioloc/c4b29b534f02e46d0e023599c90ed0f0

Milestones

  • M1: SubprocessDriver + Unit Tests — Driver implementation in isolation with full unit test coverage
    • SubprocessDriver class with execute_turn, polling loop, auto-approve, cleanup
    • TerminalOutcome enum for driver-level terminal states
    • TurnData extended with proposal_spec, proposal_status, description, expected_proposal_status
    • Condition-based terminal detection (_is_terminal, _should_approve)
    • Unit tests for config validation, condition helpers, CR building, full lifecycle
  • M2: Integration with Framework — Wire into registry, constants, and agent config models
    • Register SubprocessDriver in AgentDriverRegistry
    • Move SubprocessAgentConfig to agents.py
    • Add "subprocess" to SUPPORTED_AGENT_TYPES
    • Export from __init__.py
  • M3: Integration Tests — End-to-end tests against a live OpenShift cluster
    • Analysis-only and full lifecycle scenarios
    • Timeout handling, per-conversation agent override
    • Requires agentic operator deployed on cluster

Test plan

  • Unit tests pass: uv run pytest tests/unit/pipeline/evaluation/test_subprocess_driver.py -v
  • Full test suite passes: make test
  • Quality checks pass: make pre-commit
  • Integration tests pass against live cluster (M3)

🤖 Generated with Claude Code

rioloc and others added 5 commits May 8, 2026 11:51
…gration

Introduce a generic `agents:` configuration block in system.yaml that
makes the HTTP API one agent type among potentially many (e.g., Kubernetes
CRD agents for Openshift Agentic Lightspeed).

The key design ensures zero breakage of existing configs and code:

- New Pydantic models: AgentsConfig, AgentDefaultConfig, HttpApiAgentConfig
  in a new `core/models/agents.py` module
- SystemConfig gains an `agents: Optional[AgentsConfig]` field alongside
  the existing `api:` field
- A model_validator auto-migrates `api:` to `agents:` when `agents:` is
  absent, so all existing system.yaml files continue working unchanged
- `api.enabled=True` maps to `default.agent="http_api"`;
  `api.enabled=False` maps to `default.agent=None`
- The `api` field is preserved — all downstream code reading `config.api`
  continues to work without modification
- EvaluationData gains `agent` and `agent_config` optional fields for
  per-conversation-group agent selection and config overrides
- Config resolution follows a 3-level priority chain:
  eval_data.agent_config > agents.<name> > agents.default
- ConfigLoader passes `agents` YAML data through to SystemConfig

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace direct APIDataAmender usage with abstract AgentDriver interface,
enabling per-conversation agent resolution and support for multiple agent
types. Pipeline owns driver lifecycle; processor receives driver per call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace APIDataAmender/APIClient mocks with AgentDriver mocks in
processor and pipeline tests. Add unit tests for AgentDriverRegistry,
HttpApiDriver, and AgentDriver base class. All 113 evaluation tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add native agents: config format YAML files alongside legacy api: configs.
Rename TestFullEvaluation to TestFullApiEvaluation and extend parametrization
to cover both config formats (backward compat via migrate + native agents).
Add get_agent_info() helper to resolve agent state from either format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 78b42856-4ebc-49a8-9a69-fa6b9a0606b9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

import logging
import os
import shutil
import subprocess
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment below

Comment on lines +167 to +168
return subprocess.run(
[self._cli, *args],
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a safe usage of subprocess.run():

  1. No shell invocation — arguments are passed as a list, not a string, so shell=False (the default) is in effect. No shell expansion or injection is possible.
  2. CLI binary resolved via shutil.which() — the binary path comes from system PATH resolution at driver init time, not from user input.
  3. Command arguments are hardcoded — all args (apply, get, delete, -f, -n, -o json, --ignore-not-found) are string literals built by the driver itself.
  4. Data passes through stdin, not arguments — CR manifests are serialized with json.dumps() and piped via the input= parameter. Special characters in user-provided fields (quotes, newlines, $, backticks) never reach a shell.
  5. Same pattern as existing codeScriptExecutionManager (core/script/manager.py:86) uses subprocess.run() identically and has been reviewed and accepted.

@rioloc rioloc force-pushed the feat/subprocess-agent-driver branch from 16c6d86 to 321c572 Compare May 8, 2026 14:43
Introduce SubprocessDriver — a new AgentDriver that manages OpenShift
Proposal CR lifecycle via oc/kubectl CLI. The driver builds and applies
Proposal CRs, polls status conditions until terminal state, handles
auto-approval via ProposalApproval resources, and cleans up on completion.

Key design decisions:
- Works directly with CRD conditions (the stable API contract) instead
  of replicating the operator's internal DerivePhase() logic
- TerminalOutcome enum for driver-level terminal states
- TurnData extended with proposal_spec, proposal_status, description,
  and expected_proposal_status fields (backward-compatible, all Optional)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rioloc rioloc force-pushed the feat/subprocess-agent-driver branch from 321c572 to 3af4e56 Compare May 8, 2026 15:05
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.

2 participants