feat(harness-engine): add portable runtime and BFF gateway - #2401
feat(harness-engine): add portable runtime and BFF gateway#2401sriaradhyula wants to merge 41 commits into
Conversation
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
|
✅ No proprietary content detected. This PR is clear for review! |
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
126e639 to
96bc314
Compare
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
|
|
||
| def initial_provider_session_id(self, binding_id: str) -> str | None: ... | ||
|
|
||
| def stream(self, context: RunContext) -> AsyncIterator[CanonicalEventDraft]: ... |
|
|
||
|
|
||
| class ThreadStateStore(Protocol): | ||
| async def load(self, binding_id: str) -> dict[str, Any] | None: ... |
| class ThreadStateStore(Protocol): | ||
| async def load(self, binding_id: str) -> dict[str, Any] | None: ... | ||
|
|
||
| async def save(self, binding_id: str, state: dict[str, Any]) -> None: ... |
| class MemoryBroker(Protocol): | ||
| async def search( | ||
| self, *, subject: str, agent_id: str, query: str, limit: int | ||
| ) -> list[dict[str, Any]]: ... |
|
|
||
| async def remember( | ||
| self, *, subject: str, agent_id: str, memories: list[dict[str, Any]] | ||
| ) -> None: ... |
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
|
|
||
| class HarnessAdapter(Protocol): | ||
| @property | ||
| def descriptor(self) -> HarnessDescriptor: ... |
| def descriptor(self) -> HarnessDescriptor: ... | ||
|
|
||
| @property | ||
| def session_manager(self) -> ProviderSessionManager: ... |
| @property | ||
| def session_manager(self) -> ProviderSessionManager: ... | ||
|
|
||
| def evaluate(self, blueprint: AgentBlueprint) -> AdapterEvaluation: ... |
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
🧪 CAIPE UI Test Results✅ All tests passed 🟡 Overall Coverage: 62%📊 Detailed Coverage
✅ Test Suites
📈 Coverage Thresholds
|
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
|
|
||
|
|
||
| class AgentCoreDataClient(Protocol): | ||
| def invoke_agent_runtime(self, **kwargs: Any) -> dict[str, Any]: ... |
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
|
This is a draft PR. It is not ready to be reviewed. Please use the discussion board for review |
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
|
PR #2401 makes Harness Engine AG-UI-compatible and disconnect-safe, but a small AG-UI reattachment layer is still needed for automatic browser reload recovery. HITL resume and complete interrupt/tool/reasoning translation are also explicitly deferred in the current draft. |
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
ℹ️ Branch is behind
|
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Description
Add an independent, provider-neutral Harness Engine and a BFF-owned Harness Gateway. Existing WebUI, Slack, and Webex callers continue using the established CAIPE chat endpoints; the gateway resolves each agent's selected execution harness and routes the turn either to the unchanged Dynamic Agents runtime or to Harness Engine.
AgentCore and Claude Agent SDK implement the same portable blueprint, descriptor, capability, session, and canonical-event contracts. Dynamic Agents remains the default (
langchain-deepagents) and its backend source, routes, persistence, and execution are unchanged.Design discussion
SpecKit design package
The design is maintained as a reviewable SpecKit package. The current PR implements the independent, opt-in Harness Engine slice; Dynamic Agents continues to serve the default
langchain-deepagentsharness until a separately reviewed parity and cutover phase.The companion GitHub Discussion #2405 renders the same detailed system architecture and source graph inline for broader design review.
Architecture diagrams
Detailed system architecture
This view shows the compatibility routing, unchanged Dynamic Agents default, Harness Engine control plane, durable session/run/event ownership, provider adapters, platform integrations, and clearly marked planned sandbox and broker paths.
High-level source graph
This view maps the public routes and UI through the BFF gateway into the Harness Engine control plane, adapters, infrastructure, contracts, deployment assets, and regression tests.
What changed
CAIPEAgentSessionManagerplus provider-specific session managers for deterministic AgentCore runtime sessions and Claude SDK resume sessions.langchain-deepagents(default), AgentCore, or Claude Agent SDK and rendering provider options from descriptors.Chat identity UX
agent#use-authorized catalog when the richer agent-detail endpoint is unavailable.Request path
The BFF stays horizontally stateless. Harness Engine owns execution after returning
202, so a browser or bot disconnect does not terminate the run. A reconnecting client can replay canonical events by cursor.Capability status
Implemented:
Deferred and reported as unsupported instead of silently degrading:
Backward compatibility with Dynamic Agents
Dynamic Agents remains the production implementation behind the logical
langchain-deepagentsharness during this staged transition. This PR does not move, wrap, or rewrite the Dynamic Agents runtime.execution_harness_idcontinue to resolve to the defaultlangchain-deepagentsharness. The legacydynamic_agentsvalue is treated the same way.No files under
ai_platform_engineering/dynamic_agents/are changed by this PR, confirming that the existing backend source and execution path remain isolated.Dynamic Agents will continue to provide the
langchain-deepagentsharness until a Harness Engine LangChain Deep Agents adapter reaches full functional parity and passes the adapter certification suite. A later cutover can then change the gateway mapping behind the same harness identifier, agent documents, client endpoints, and authorization contract. That cutover is explicitly outside this PR.Research
Type of Change
Validation
uv run ruff check src testsanduv run pytest -q— passed, 18 tests.npm run lintandnpm run build— passed (two pre-existing Next.js NFT trace warnings).caipe-oss.outshift.io— verifiedHarness Gateway E2E · Chat · CAIPE, the persistentHarness Gateway E2E+Amazon Bedrock AgentCoreheader, AgentCore/Deep Agents history badges, and distinct agent colors; existing WebUI routing still returned the AgentCore response.run-77658dd3c06841438ccaef500bd00ea7completed withharness_id=agentcore; its event log containedrun.started, twocontent.deltaevents,usage.updated, andrun.completed.git diff --check— passed.The deployment retains a shared Harness Gateway E2E AgentCore demo so reviewers can repeat the browser test; it contains no credentials or production data.
Checklist
Preview deployment parity
Additional validation: deploy/agentgateway unit suite passed (35 tests), Compose rendering passed, all preview containers are running, and the public HTTPS route returns 200.
Claude SDK live E2E
Claude SDK E2E Agent(agent-claude-sdk-e2e) through a validated Harness Engine blueprint; the UI catalog row remains metadata only and Dynamic Agents runtime code is unchanged.SessionStoretranscript mirroring. CAIPE persists the provider session ID and Mongo stores the provider transcript, making resume independent of a container filesystem.1476e362-21c7-4db3-b647-b1c9988cddc2: storerun-507079ed8d894bd88d13f5682020f282, recallrun-434417404e4945ce9adb6313b37ceae3, and post-restart recallrun-f4f5a9aaa454429e9c649d2ff3904751. Each recall returnedviolet-orbit-731; 22 transcript entries were mirrored with the UUID and load-order indexes present.