gate4agent-shell-native 0.4.8

Native effect execution (PTY, pipe, ACP) for gate4agent control-plane sessions
Documentation
use gate4agent_catalog::AgentRegistry;
use gate4agent_shell_native::NativeEffectShell;
use gate4agent_testkit::acp_agent_spec;
use gate4agent_types::{
    AdapterFamily, AgentInstanceId, ControlEffect, ControlObservation, EffectEnvelope, OperationId,
    ProviderInteractionId, ProviderInteractionKind, ProviderInteractionResponse,
    ProviderInteractionTarget, ProviderSource, SessionGeneration,
};

#[tokio::test]
async fn native_interaction_resolution_fails_closed_with_exact_correlation() {
    let spec = acp_agent_spec();
    let source = ProviderSource {
        family: AdapterFamily::Acp,
        binding: spec
            .capabilities
            .transports
            .acp
            .as_ref()
            .expect("controlled ACP transport")
            .adapter
            .clone(),
    };
    let mut shell =
        NativeEffectShell::new(AgentRegistry::new([spec]).expect("controlled native catalog"));
    let operation_id = OperationId(701);
    let instance_id = AgentInstanceId(702);
    let generation = SessionGeneration(3);
    let interaction_id = ProviderInteractionId(703);

    let observation = shell
        .execute(EffectEnvelope {
            operation_id,
            instance_id,
            generation,
            effect: ControlEffect::ResolveInteraction {
                target: ProviderInteractionTarget {
                    interaction_id,
                    source,
                    provider_request_id: Some("fixture-request".to_owned()),
                    interaction_kind: ProviderInteractionKind::Approval,
                    tool_name: "fixture-tool".to_owned(),
                    agent_id: None,
                },
                response: ProviderInteractionResponse::Deny,
            },
        })
        .await;

    assert_eq!(observation.operation_id, Some(operation_id));
    assert_eq!(observation.instance_id, instance_id);
    assert_eq!(observation.generation, generation);
    assert!(matches!(
        observation.observation,
        ControlObservation::InteractionResolutionFailed {
            interaction_id: observed_interaction_id,
            ref message,
        } if observed_interaction_id == interaction_id
            && message == "semantic interaction resolution requires an ACP session"
    ));
    assert_eq!(shell.active_session_count(), 0);
}