Skip to content

symfonic.agent.middleware.confidence

confidence

Deterministic confidence heuristic and sensitive-tag detection.

Pure functions — no side effects, no I/O, fully unit-testable.

compute_confidence

compute_confidence(activation_log: dict[str, Any]) -> float

Deterministic heuristic in [0.0, 1.0]. Returns 0.5 on empty input.

Formula

confidence = clamp01( 0.4 * seed_strength + 0.3 * path_coverage + 0.3 * edge_weight_factor )

Where

seed_strength = avg score of activated_nodes (>= 1.0 if seeded) path_coverage = min(1.0, len(inference_paths) / 3) edge_weight_factor = avg edge weight of traversed_edges / 5.0, capped at 1.0

Public so tests can exercise edge cases without spinning up a full agent.

Source code in src/symfonic/agent/middleware/confidence.py
def compute_confidence(activation_log: dict[str, Any]) -> float:
    """Deterministic heuristic in [0.0, 1.0]. Returns 0.5 on empty input.

    Formula:
        confidence = clamp01(
            0.4 * seed_strength
          + 0.3 * path_coverage
          + 0.3 * edge_weight_factor
        )

    Where:
        seed_strength  = avg score of activated_nodes (>= 1.0 if seeded)
        path_coverage  = min(1.0, len(inference_paths) / 3)
        edge_weight_factor = avg edge weight of traversed_edges / 5.0, capped at 1.0

    Public so tests can exercise edge cases without spinning up a full agent.
    """
    if not activation_log:
        return 0.5

    activated_nodes = activation_log.get("activated_nodes") or []
    inference_paths = activation_log.get("inference_paths") or []
    traversed_edges = activation_log.get("traversed_edges") or []

    # seed_strength: average score of activated_nodes
    if activated_nodes:
        scores = [n.get("score", 0.0) for n in activated_nodes]
        seed_strength = sum(scores) / len(scores)
    else:
        return 0.5  # cold start — neutral

    # path_coverage
    path_coverage = min(1.0, len(inference_paths) / 3.0)

    # edge_weight_factor
    if traversed_edges:
        weights = [e.get("weight", 0.0) for e in traversed_edges]
        edge_weight_factor = min(1.0, (sum(weights) / len(weights)) / 5.0)
    else:
        edge_weight_factor = 0.0

    confidence = (
        0.4 * seed_strength
        + 0.3 * path_coverage
        + 0.3 * edge_weight_factor
    )
    return _clamp01(confidence)

detect_sensitive_hit

detect_sensitive_hit(
    activation_log: dict[str, Any],
    sensitive_tags: frozenset[str],
) -> str | None

Return the first matching tag when any activated_node carries one of sensitive_tags in properties['tags'], else None.

Source code in src/symfonic/agent/middleware/confidence.py
def detect_sensitive_hit(
    activation_log: dict[str, Any],
    sensitive_tags: frozenset[str],
) -> str | None:
    """Return the first matching tag when any activated_node carries one of
    *sensitive_tags* in properties['tags'], else None."""
    if not sensitive_tags:
        return None

    activated_nodes = (activation_log or {}).get("activated_nodes") or []
    for node in activated_nodes:
        node_tags = node.get("tags") or node.get("properties", {}).get("tags") or []
        for tag in node_tags:
            if tag in sensitive_tags:
                return str(tag)
    return None