Files
cleveragents-core/features/steps/a2a_extension_methods_steps.py
T
freemo ad98d41d61 feat(a2a): implement _cleveragents/ extension method routing
Add spec-aligned _cleveragents/ prefixed extension method routing to
the A2A local facade per ADR-047. The facade now supports 42 total
operations: 31 new extension methods across 6 families plus 11
legacy proprietary names retained for backward compatibility.

Extension method families implemented:
- _cleveragents/plan/* (13 methods): use, execute, apply, cancel,
  status, tree, explain, correct, diff, artifacts, prompt, rollback,
  list. Plan operations delegate to PlanLifecycleService when wired;
  new operations (cancel, tree, explain, correct, artifacts, prompt,
  rollback, list) have stub handlers returning safe defaults.
- _cleveragents/registry/* (6 methods): tool/list, resource/list,
  actor/list, skill/list, action/list, project/list. Tool and
  resource list delegate to existing services; entity lists are stubs.
- _cleveragents/context/* (4 methods): show (delegates to existing
  handler), inspect, simulate, set (stubs).
- _cleveragents/health/* (2 methods): check, diagnostics/run.
- _cleveragents/sync/* (3 methods): pull, push, status (stubs).
- _cleveragents/namespace/* (3 methods): list, show, members (stubs).

Legacy proprietary names (session.create, plan.create, etc.) continue
to work via the same handler map, marked deprecated. Updated existing
test assertions for the expanded operation count (11 -> 42).

ISSUES CLOSED: #876
2026-03-18 17:33:30 +00:00

110 lines
3.8 KiB
Python

"""Step definitions for a2a_extension_methods.feature.
Tests the _cleveragents/ extension method routing in the A2A local
facade, verifying spec-aligned operation names are supported and
produce valid responses.
"""
from __future__ import annotations
import json
from typing import Any
from behave import given, then, when
from cleveragents.a2a.facade import A2aLocalFacade
from cleveragents.a2a.models import A2aRequest
@given("a facade instance for extension method testing")
def step_create_extension_facade(context: Any) -> None:
"""Create a facade with no services (all handlers return stubs)."""
context.facade = A2aLocalFacade()
@when('I dispatch "{operation}" with params {params_json}')
def step_dispatch_operation(context: Any, operation: str, params_json: str) -> None:
params = json.loads(params_json)
request = A2aRequest(operation=operation, params=params)
context.response = context.facade.dispatch(request)
@then("the response should be ok")
def step_response_ok(context: Any) -> None:
assert context.response.status == "ok", (
f"Expected 'ok', got '{context.response.status}'"
)
@then('the response data should contain key "{key}"')
def step_response_has_key(context: Any, key: str) -> None:
assert key in context.response.data, (
f"Expected key '{key}' in response data, got: {list(context.response.data.keys())}"
)
@then('the response data should have "{key}" set to true')
def step_response_stub_true(context: Any, key: str) -> None:
assert context.response.data.get(key) is True, (
f"Expected data['{key}'] to be True, got: {context.response.data.get(key)}"
)
@then("the facade should support _cleveragents/plan/ methods")
def step_check_plan_methods(context: Any) -> None:
ops = context.facade.list_operations()
plan_ops = [o for o in ops if o.startswith("_cleveragents/plan/")]
assert len(plan_ops) >= 13, (
f"Expected >=13 plan extension methods, got {len(plan_ops)}: {plan_ops}"
)
@then("the facade should support _cleveragents/registry/ methods")
def step_check_registry_methods(context: Any) -> None:
ops = context.facade.list_operations()
reg_ops = [o for o in ops if o.startswith("_cleveragents/registry/")]
assert len(reg_ops) >= 6, (
f"Expected >=6 registry extension methods, got {len(reg_ops)}: {reg_ops}"
)
@then("the facade should support _cleveragents/context/ methods")
def step_check_context_methods(context: Any) -> None:
ops = context.facade.list_operations()
ctx_ops = [o for o in ops if o.startswith("_cleveragents/context/")]
assert len(ctx_ops) >= 4, (
f"Expected >=4 context extension methods, got {len(ctx_ops)}: {ctx_ops}"
)
@then("the facade should support _cleveragents/health/ methods")
def step_check_health_methods(context: Any) -> None:
ops = context.facade.list_operations()
health_ops = [
o
for o in ops
if o.startswith("_cleveragents/health/")
or o.startswith("_cleveragents/diagnostics/")
]
assert len(health_ops) >= 2, (
f"Expected >=2 health/diagnostics methods, got {len(health_ops)}: {health_ops}"
)
@then("the facade should support _cleveragents/sync/ methods")
def step_check_sync_methods(context: Any) -> None:
ops = context.facade.list_operations()
sync_ops = [o for o in ops if o.startswith("_cleveragents/sync/")]
assert len(sync_ops) >= 3, (
f"Expected >=3 sync extension methods, got {len(sync_ops)}: {sync_ops}"
)
@then("the facade should support _cleveragents/namespace/ methods")
def step_check_namespace_methods(context: Any) -> None:
ops = context.facade.list_operations()
ns_ops = [o for o in ops if o.startswith("_cleveragents/namespace/")]
assert len(ns_ops) >= 3, (
f"Expected >=3 namespace extension methods, got {len(ns_ops)}: {ns_ops}"
)