Skip to content

Probabilistic Resolution

When two agent instances have different DIDs, cryptographic resolution cannot help. But they might still be the same logical agent - deployed independently by different teams, or registered before a shared keypair policy was in place.

This is the same problem the resolution engine solves for customer records. "John Doe" in CRM and "Jonathan Doe" in billing have different primary keys, but the engine matches them on name, email, phone, and behavioral signals. Agent resolution works the same way.

Matching signals

The resolution engine evaluates agent records against each other using these signals:

SignalTypeWeightDescription
agent_nameFuzzy (Jaro-Winkler)Medium"support-agent" vs "support-bot"
capabilitiesSet overlap (Jaccard)Medium["resolve","memorize"] vs ["resolve","memorize","search"]
root_authority_didExactStrongSame human delegated authority to both
descriptionFuzzy (Cosine)WeakFree-text description similarity
behavioral_patternCustomMediumSame types of actions on same entity types
platform_metadataCompositeWeakShared configuration, environment, org ID

The strongest single signal is root_authority_did. If the same human (or root agent) delegated authority to two different agent instances, they are very likely the same logical agent deployed across platforms.

How blocking works for agents

Blocking narrows the comparison space - just like with customer records. Instead of comparing every agent against every other agent, the engine groups agents into candidate blocks:

Blocking KeyGroups byExample
[root_authority_did]Same delegating authorityAll agents delegated by did:agent:root1...
[agent_name]Exact name matchAll agents named "support-agent"
[capabilities]First 3 sorted capabilitiesAll agents with ["memorize","resolve","search"]

Only agents within the same block are scored against each other. An SDR agent is never compared against a data-sync agent because they share no blocking keys.

Configuring an agent identity spec

Agent resolution uses the same YAML spec format as customer resolution. The entity type is agent, and the fields map to agent registry attributes:

yaml
api_version: kanoniv/v1
identity_version: "1.0"

entity:
  name: agent

sources:
  web-registry:
    adapter: api
    primary_key: agent_did
    schema:
      agent_did: { type: string }
      agent_name: { type: string }
      capabilities: { type: array }
      root_authority_did: { type: string }
      description: { type: string }
      platform: { type: string }

  slack-registry:
    adapter: api
    primary_key: agent_did
    schema:
      agent_did: { type: string }
      agent_name: { type: string }
      capabilities: { type: array }
      root_authority_did: { type: string }
      description: { type: string }
      platform: { type: string }

rules:
  - name: did_exact
    type: exact
    field: agent_did
    weight: 1.0

  - name: root_authority_exact
    type: exact
    field: root_authority_did
    weight: 0.4

  - name: name_fuzzy
    type: similarity
    field: agent_name
    algorithm: jaro_winkler
    threshold: 0.80
    weight: 0.3

  - name: capabilities_overlap
    type: similarity
    field: capabilities
    algorithm: cosine
    threshold: 0.70
    weight: 0.2

  - name: description_fuzzy
    type: similarity
    field: description
    algorithm: cosine
    threshold: 0.60
    weight: 0.1

decision:
  thresholds:
    match: 0.85
    review: 0.65

survivorship:
  strategy: source_priority
  source_order: [web-registry, slack-registry]

This spec says: exact DID match is the strongest signal (weight 1.0), followed by shared root authority (0.4), fuzzy name match (0.3), capabilities overlap (0.2), and description similarity (0.1). Pairs scoring above 0.85 merge automatically. Pairs between 0.65 and 0.85 are flagged for human review.

Scoring walkthrough

Consider two agent instances:

Web agent (registered via web channel):

json
{
  "agent_did": "did:agent:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
  "agent_name": "support-agent",
  "capabilities": ["resolve", "memorize", "search"],
  "root_authority_did": "did:agent:root_9f8e7d6c5b4a3f2e1d0c9b8a",
  "description": "Handles customer support queries across channels"
}

Slack agent (registered via Slack channel):

json
{
  "agent_did": "did:agent:f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2",
  "agent_name": "support-bot",
  "capabilities": ["resolve", "memorize", "search", "create_task"],
  "root_authority_did": "did:agent:root_9f8e7d6c5b4a3f2e1d0c9b8a",
  "description": "Customer support bot for Slack workspace"
}

Different DIDs, so did_exact scores 0.0. But:

RuleScoreWhy
did_exact0.0Different DIDs
root_authority_exact1.0Same root authority DID
name_fuzzy0.82"support-agent" vs "support-bot" (Jaro-Winkler)
capabilities_overlap0.873 of 4 capabilities shared (Jaccard-like via cosine)
description_fuzzy0.71Both mention "support" and "customer"

Weighted score:

(0.0 * 1.0 + 1.0 * 0.4 + 0.82 * 0.3 + 0.87 * 0.2 + 0.71 * 0.1)
  / (1.0 + 0.4 + 0.3 + 0.2 + 0.1)
= (0 + 0.4 + 0.246 + 0.174 + 0.071) / 2.0
= 0.891 / 2.0
= 0.446

This score is below the match threshold. The DID mismatch pulls it down heavily. But adjust the spec to down-weight did_exact when you expect different DIDs:

yaml
rules:
  - name: did_exact
    type: exact
    field: agent_did
    weight: 0.0    # DIDs are expected to differ across platforms

  - name: root_authority_exact
    type: exact
    field: root_authority_did
    weight: 0.5    # Strongest signal when DIDs differ

New weighted score (excluding DID):

(1.0 * 0.5 + 0.82 * 0.3 + 0.87 * 0.2 + 0.71 * 0.1) / (0.5 + 0.3 + 0.2 + 0.1)
= (0.5 + 0.246 + 0.174 + 0.071) / 1.1
= 0.991 / 1.1
= 0.901

Score 0.901. Above the 0.85 threshold. Auto-merge.

Resolving agents via the API

Use the standard resolve endpoint. The engine treats agent records identically to customer records:

bash
POST /v1/resolve/realtime
Content-Type: application/json
X-API-Key: kn_live_...

{
  "source_name": "slack-registry",
  "external_id": "support-bot-slack",
  "data": {
    "agent_did": "did:agent:f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2",
    "agent_name": "support-bot",
    "capabilities": ["resolve", "memorize", "search", "create_task"],
    "root_authority_did": "did:agent:root_9f8e7d6c5b4a3f2e1d0c9b8a",
    "description": "Customer support bot for Slack workspace"
  }
}

If the web agent was previously registered, the response links the Slack agent to the same canonical entity:

json
{
  "entity_id": "agt_7f82a1b2-...",
  "canonical_data": {
    "agent_name": "support-agent",
    "capabilities": ["resolve", "memorize", "search", "create_task"],
    "root_authority_did": "did:agent:root_9f8e7d6c5b4a3f2e1d0c9b8a",
    "platforms": ["web", "slack"]
  },
  "is_new": false,
  "confidence": 0.90
}

The canonical name is "support-agent" (from the web source, which has higher survivorship priority). Capabilities are the union of both instances. The platforms array shows both channels.

Match explanations

Every merge decision includes a full explanation, just like customer resolution:

json
{
  "left": "web-registry:support-agent-web",
  "right": "slack-registry:support-bot-slack",
  "score": 0.90,
  "outcome": "match",
  "rules": [
    { "name": "root_authority_exact", "score": 1.0, "field": "root_authority_did" },
    { "name": "name_fuzzy", "score": 0.82, "field": "agent_name" },
    { "name": "capabilities_overlap", "score": 0.87, "field": "capabilities" },
    { "name": "description_fuzzy", "score": 0.71, "field": "description" }
  ]
}

You always know why two agents were resolved to the same entity and which signals contributed the most.

Behavioral matching

Beyond static metadata, the engine can match agents based on behavioral patterns:

  • Action types: Both agents primarily call resolve and memorize - not merge or split
  • Entity interactions: Both agents interact with customer-type entities in the same tenant
  • Temporal patterns: Both agents are active during US business hours
  • Decision patterns: Both agents produce similar confidence scores on similar entity types

Behavioral signals are weaker individually but powerful in combination. An agent that resolves customer entities, stores memory entries about lead qualification, and operates during US business hours has a distinctive behavioral fingerprint.

When to use probabilistic vs cryptographic

SituationResolution path
You deployed the same agent to multiple channelsCryptographic - share the keypair
Different teams deployed similar agents independentlyProbabilistic - score on metadata + behavior
Third-party agent needs to merge with your internal agentProbabilistic - no shared keypair possible
Acquired company's agents need to join your identity graphProbabilistic - different key infrastructure
Agent keypair was rotated, old instances still registeredProbabilistic - old DID will not match new DID

The two paths are complementary. Cryptographic resolution handles the easy cases instantly. Probabilistic resolution handles the hard cases with confidence scores and full auditability.

The identity and delegation layer for AI agents.