async def test_tdb_request_act_times_grad_from_intermediate_node(
    standard_model_context: StandardModelContext,
    standard_autoencoder_context: AutoencoderContext,
) -> None:
    """
    Test that the top MLP autoencoder latent act * grad returned by the BatchedTdbRequest
    matches the activation value stored using a hook on the Transformer forward pass directly.

    This test compares the simplest way to get activations from a Transformer, with the
    way that is used in TDB.
    """
    transformer = standard_model_context.get_or_create_model()

    prompt = "This is a test"
    input_token_ints = torch.tensor(
        standard_model_context.encode(prompt), device=standard_model_context.device
    ).unsqueeze(0)

    node_index_for_bwd = MirroredNodeIndex(
        node_type=NodeType.MLP_NEURON,
        layer_index=5,
        tensor_indices=(1, 0),
        pass_type=PassType.FORWARD,
    )

    tdb_request = TdbRequestSpec(
        prompt=prompt,
        target_tokens=[],
        distractor_tokens=[],
        component_type_for_mlp=ComponentTypeForMlp.NEURON,
        component_type_for_attention=ComponentTypeForAttention.ATTENTION_HEAD,
        top_and_bottom_k_for_node_table=25,
        hide_early_layers_when_ablating=False,
        node_ablations=None,
        upstream_node_to_trace=NodeToTrace(
            node_index=node_index_for_bwd,
            attention_trace_type=None,
            downstream_trace_config=None,
        ),
        downstream_node_to_trace=None,
    )
    batched_tdb_request = BatchedTdbRequest(sub_requests=[tdb_request])

    interactive_model = InteractiveModel.from_standard_model_context_and_autoencoder_context(
        standard_model_context, standard_autoencoder_context
    )

    batched_tdb_response = await interactive_model.handle_batched_tdb_request(batched_tdb_request)

    top_k_components_response = batched_tdb_response.inference_sub_responses[
        0
    ].processing_response_data_by_name["topKComponents"]
    assert isinstance(top_k_components_response, MultipleTopKDerivedScalarsResponseData)
    top_node_indices = top_k_components_response.node_indices
    top_act_times_grads = top_k_components_response.activations_by_group_id[GroupId.ACT_TIMES_GRAD]
    top_acts = top_k_components_response.activations_by_group_id[GroupId.ACTIVATION]

    node_index, tdb_act, tdb_act_times_grad = next(
        (
            (top_node_index, top_act, top_act_times_grad)
            for top_node_index, top_act, top_act_times_grad in zip(
                top_node_indices, top_acts, top_act_times_grads
            )
            if top_node_index.node_type == NodeType.MLP_NEURON
        ),
        (None, None, None),
    )  # get the first latent index returned by the TDB request
    assert node_index is not None

    hooks = TransformerHooks()
    stored_act = {}
    stored_grad = {}
    stored_act_for_bwd = {}

    def act_saving_hook_fn(act: torch.Tensor, **kwargs: Any) -> torch.Tensor:
        stored_act["value"] = act[
            (0,) + node_index.tensor_indices
        ]  # 0 batch index, keep token index from node_index
        return act  # store the activation value for the latent in question

    def grad_saving_hook_fn(grad: torch.Tensor, **kwargs: Any) -> torch.Tensor:
        stored_grad["value"] = grad[(0,) + node_index.tensor_indices]
        return grad

    def act_grabbing_hook_fn(act: torch.Tensor, **kwargs: Any) -> torch.Tensor:
        stored_act_for_bwd["value"] = act[(0,) + node_index_for_bwd.tensor_indices]
        return act

    def detach_fn(act: torch.Tensor, **kwargs: Any) -> torch.Tensor:
        return act.detach()

    hooks = (
        hooks.append_to_path(
            "mlp.post_act.fwd",
            AtLayers([assert_not_none(node_index.layer_index)]).append(act_saving_hook_fn),
        )
        .append_to_path(
            "mlp.post_act.bwd",
            AtLayers([assert_not_none(node_index.layer_index)]).append(grad_saving_hook_fn),
        )
        .append_to_path(
            "resid.torso.ln_mlp.scale.fwd",
            AtLayers([assert_not_none(node_index_for_bwd.layer_index)]).append(detach_fn),
        )  # detach layer norm scale
        .append_to_path(
            "mlp.pre_act.fwd",
            AtLayers([assert_not_none(node_index_for_bwd.layer_index)]).append(
                act_grabbing_hook_fn
            ),
        )
    )

    transformer(input_token_ints, hooks=hooks)

    stored_act_for_bwd["value"].backward()

    assert isinstance(tdb_act, float)
    assert math.isclose(
        tdb_act,
        stored_act["value"].item(),
        rel_tol=1e-4,
    )

    assert isinstance(tdb_act_times_grad, float)
    assert math.isclose(
        tdb_act_times_grad,
        (stored_act["value"] * stored_grad["value"]).item(),
        rel_tol=1e-4,
    )

    Test that the top MLP autoencoder latent act * grad returned by the BatchedTdbRequest
    matches the activation value stored using a hook on the Transformer forward pass directly.

    This test compares the simplest way to get activations from a Transformer, with the
    way that is used in TDB.
    
neuron_explainer/tests/test_interactive_model.py