# How the Tool-Matching Algorithm Selects Tools in Craft Agents OSS

> Discover how Craft Agents OSS tool-matching algorithm uses ID-based indexing to select tools. Learn about its stateless system and unique identifier matching.

- Repository: [Craft Ai Agents/craft-agents-oss](https://github.com/craft-ai-agents/craft-agents-oss)
- Tags: deep-dive
- Published: 2026-07-06

---

**The tool-matching algorithm employs a stateless, ID-based indexing system that registers every `tool_use` block in an append-only `ToolIndex`, then matches `tool_result` blocks to their originating calls via unique identifiers rather than FIFO queues or mutable stacks.**

The Craft Agents OSS platform relies on a deterministic matching mechanism to decide which tools an agent can invoke. Unlike traditional queue-based systems, this algorithm uses immutable identifiers to track tool relationships across asynchronous streams and concurrent sessions. The implementation centers on two core functions—`extractToolStarts` and `extractToolResults`—defined in [`packages/shared/src/agent/tool-matching.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/agent/tool-matching.ts).

## The Stateless ID-Based Architecture

At the heart of the system lies the `ToolIndex` class, which maintains an append-only registry of tool metadata. This stateless design ensures that tool selection depends solely on identifiers, not message ordering or mutable state.

### The ToolIndex Registry

The `ToolIndex` class (defined in [`packages/shared/src/agent/tool-matching.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/agent/tool-matching.ts)) maps each `tool-use-id` to its corresponding tool name and input arguments. When the SDK emits a `tool_use` block, the `register` method captures this relationship immediately:

```typescript
// From packages/shared/src/agent/tool-matching.ts lines 42-55
class ToolIndex {
  private index = new Map<string, { toolName: string; input: unknown }>();
  
  register(toolUseId: string, toolName: string, input: unknown): void {
    this.index.set(toolUseId, { toolName, input });
  }
  
  lookup(toolUseId: string): { toolName: string; input: unknown } | undefined {
    return this.index.get(toolUseId);
  }
}

```

This registry enables instant lookup regardless of when blocks arrive, supporting out-of-order processing in concurrent environments.

### Extracting Tool Start Events

The `extractToolStarts` function processes assistant message content blocks to create `tool_start` events. It walks the `content` array, identifies `tool_use` blocks, and records them in the shared `ToolIndex`:

- **Parent relationship detection**: The algorithm extracts the `parent_tool_use_id` field from the SDK. If this field is `null`, it falls back to a single active task heuristic (lines 58-68).
- **Event creation**: Each valid `tool_use` block generates a `tool_start` event containing the `toolUseId`, tool name, and enriched metadata.

## Matching Tool Results to Originating Calls

When a user message contains `tool_result` blocks, the `extractToolResults` function (lines 39-49) handles the pairing. It looks up the corresponding `tool_use_id` in the `ToolIndex` to retrieve the original tool name and input:

```typescript
// Conceptual implementation from the source
function extractToolResults(
  content: ContentBlock[],
  parentToolUseId: string | null,
  fallbackResult: unknown,
  toolIndex: ToolIndex,
  turnId: string
): ToolResultEvent[] {
  return content
    .filter(block => block.type === 'tool_result')
    .map(block => {
      const startInfo = toolIndex.lookup(block.tool_use_id);
      return {
        toolUseId: block.tool_use_id,
        toolName: startInfo?.toolName,
        result: block.content ?? fallbackResult,
        turnId
      };
    });
}

```

Because each result carries its own ID, the system pairs results with starts without assuming message order or maintaining complex state stacks.

## Handling Parent-Task Relationships

Certain tools act as sub-agent launchers (such as `Task` or `Agent` tools). The algorithm detects these via the `isParentTaskTool` function in [`packages/shared/src/utils/toolNames.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/utils/toolNames.ts).

This function checks against a read-only set called `PARENT_TASK_TOOLS` (lines 35-38):

```typescript
// From packages/shared/src/utils/toolNames.ts
export const PARENT_TASK_TOOLS = new Set(['Task', 'Agent', 'SubAgent']);

export function isParentTaskTool(toolName: string): boolean {
  return PARENT_TASK_TOOLS.has(toolName);
}

```

When `extractToolStarts` encounters these tools, it marks them accordingly, enabling background-task detection and correct parent-child relationship wiring across the agent hierarchy.

## Deduplication and Metadata Enrichment

The algorithm handles duplicate `tool_start` events through the `emittedToolStartIds` set. This Set tracks which tool IDs have already been processed:

- **Duplicate detection**: If the same `tool_use_id` appears in both a streaming response and the final assistant message, the set prevents double-processing.
- **Metadata updates**: When a duplicate arrives with richer input or newly available metadata (such as intent or display name), the algorithm re-emits an updated event (lines 71-82 in [`tool-matching.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/tool-matching.ts)).

This ensures the agent always sees the most complete tool information while maintaining idempotency.

## Generating Human-Readable Tool Names

The UI layer obtains readable tool names via `getToolDisplayName` in [`packages/shared/src/utils/toolNames.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/utils/toolNames.ts) (lines 71-77). This function:

1. Checks an explicit mapping object `TOOL_DISPLAY_NAMES` for a human-friendly string
2. Falls back to generic title-case conversion if no mapping exists

For example, a tool named `web_search` might display as "Web Search" in the agent interface, while internal processing continues using the canonical ID.

## Implementation Example

The following pattern demonstrates how to integrate the tool-matching components in your own agent implementation:

```typescript
import { ToolIndex, extractToolStarts, extractToolResults } from
  '@craft-agent/shared/src/agent/tool-matching';

// 1️⃣ Build an index for the current session
const toolIndex = new ToolIndex();

// 2️⃣ Process an assistant message (contains tool_use blocks)
const assistantEvents = extractToolStarts(
  assistantMessage.content,        // ← ContentBlock[]
  assistantMessage.parent_tool_use_id, // ← string | null
  toolIndex,
  new Set(),                      // emittedToolStartIds – empty at start
  turnId,
  activeParentTools               // e.g. Set of currently running Task IDs
);

// 3️⃣ Later, when the user replies with results
const resultEvents = extractToolResults(
  userMessage.content,
  userMessage.parent_tool_use_id,
  userMessage.tool_use_result,    // fallback field
  toolIndex,
  turnId
);

// 4️⃣ UI can now show the tools that were started
assistantEvents.forEach(ev => {
  console.log(`Tool offered: ${ev.toolName} (id=${ev.toolUseId})`);
});

```

**Key implementation details**:

- **`ToolIndex`** is shared between start and result extraction, guaranteeing consistent ID-based lookups.
- **`extractToolStarts`** automatically derives parent relationships from the SDK's `parent_tool_use_id` field.
- **`extractToolResults`** pairs each result with its originating start via the same identifier, regardless of message order.

## Summary

- **Stateless ID matching**: The algorithm uses `ToolIndex` to map `tool_use_id` values to tool metadata, eliminating reliance on FIFO queues or mutable stacks.
- **Bidirectional extraction**: `extractToolStarts` creates events from assistant messages, while `extractToolResults` pairs user message results to their origins.
- **Parent-task detection**: The `PARENT_TASK_TOOLS` set in [`toolNames.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/toolNames.ts) identifies sub-agent launchers for hierarchical relationship tracking.
- **Deduplication**: The `emittedToolStartIds` Set prevents duplicate events while allowing metadata enrichment when duplicates carry additional information.
- **Display abstraction**: `getToolDisplayName` converts internal tool identifiers to human-readable labels for UI presentation.

## Frequently Asked Questions

### How does the algorithm handle out-of-order tool results?

The system handles out-of-order results through the `ToolIndex` registry. Because `extractToolResults` looks up the `tool_use_id` in the shared index rather than searching a sequential queue, results can arrive before or after their corresponding starts without affecting the matching accuracy. The index maintains the mapping until the session completes, allowing asynchronous pairing across concurrent streams.

### What determines if a tool is treated as a parent-task tool?

A tool qualifies as a parent-task tool when its name exists in the `PARENT_TASK_TOOLS` Set defined in [`packages/shared/src/utils/toolNames.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/utils/toolNames.ts). The `isParentTaskTool` function performs this check, identifying tools like `Task` or `Agent` that spawn sub-processes. This classification affects how the algorithm establishes parent-child relationships and detects background tasks in the execution graph.

### How does the system prevent duplicate tool start events?

The `emittedToolStartIds` Set tracks which tool IDs have already generated events. When `extractToolStarts` encounters a `tool_use_id` already present in this Set, it skips creating a duplicate event. However, if the duplicate contains richer metadata (such as an updated display name or intent), the algorithm re-emits the event with the enriched payload, ensuring the agent sees the most complete information without duplication.

### Where does the human-readable tool name come from?

The `getToolDisplayName` function in [`packages/shared/src/utils/toolNames.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/utils/toolNames.ts) generates UI-friendly names by first checking the `TOOL_DISPLAY_NAMES` mapping object for explicit labels. If no mapping exists, it falls back to formatting the internal tool name (for example, converting snake_case to Title Case). This abstraction layer ensures that agents see descriptive names while the underlying matching logic continues using stable identifiers.