Repository: Significant-Gravitas/Auto-GPT
File: autogpt_platform/frontend/src/components/edit/control/BlocksControl.tsx (TypeScript)

Code before:
      .sort((a, b) => a.name.localeCompare(b.name));
    const agentBlockList = flows.map(
      (flow) =>
        ({
          id: SpecialBlockID.AGENT,
          name: flow.name,
          description:
            `Ver.${flow.version}` +
            (flow.description ? ` | ${flow.description}` : ""),
          categories: [{ category: "AGENT", description: "" }],
          inputSchema: flow.input_schema,
          outputSchema: flow.output_schema,
          staticOutput: false,
          uiType: BlockUIType.AGENT,
          uiKey: flow.id,
          costs: [],
          hardcodedValues: {
            graph_id: flow.id,
            graph_version: flow.version,
            input_schema: flow.input_schema,
            output_schema: flow.output_schema,
          },
        }) satisfies Block,
    );

    // Levenshtein distance Algorithm
    const calculateSimilarity = (str1: string, str2: string): number => {
      const len1 = str1.length;
      const len2 = str2.length;
      const matrix: number[][] = Array(len1 + 1)
        .fill(null)
        .map(() => Array(len2 + 1).fill(null));

      for (let i = 0; i <= len1; i++) matrix[i][0] = i;
      for (let j = 0; j <= len2; j++) matrix[0][j] = j;

      for (let i = 1; i <= len1; i++) {
        for (let j = 1; j <= len2; j++) {
          const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
          matrix[i][j] = Math.min(
            matrix[i - 1][j] + 1,
            matrix[i][j - 1] + 1,
            matrix[i - 1][j - 1] + cost,
          );
        }
      }

      // Convert distance to similarity score
      return 1 - matrix[len1][len2] / Math.max(len1, len2);
    };


Review comment (refactor):
We should move this to a helper file outside of this file.

Also, have you considered other drop-in libraries rather than hand-rolling an edit distance yourself?
There are a few other better algorithms you can use for this.

Code after:
      .filter((b) => b.uiType !== BlockUIType.AGENT)
      .sort((a, b) => a.name.localeCompare(b.name));
    const agentBlockList = flows.map(
      (flow) =>
        ({
          id: SpecialBlockID.AGENT,
          name: flow.name,
          description:
            `Ver.${flow.version}` +
            (flow.description ? ` | ${flow.description}` : ""),
          categories: [{ category: "AGENT", description: "" }],
          inputSchema: flow.input_schema,
          outputSchema: flow.output_schema,
          staticOutput: false,
          uiType: BlockUIType.AGENT,
          uiKey: flow.id,
          costs: [],
          hardcodedValues: {
            graph_id: flow.id,
            graph_version: flow.version,
            input_schema: flow.input_schema,
            output_schema: flow.output_schema,
          },
        }) satisfies Block,
    );

    /**
     * Evaluates how well a block matches the search query and returns a relevance score.
     * The scoring algorithm works as follows:
     * - Returns 1 if no query (all blocks match equally)
     * - Normalized query for case-insensitive matching
     * - Returns 3 for exact substring matches in block name (highest priority)
     * - Returns 2 when all query words appear in the block name (regardless of order)
     * - Returns 1.X for blocks with names similar to query using Jaro-Winkler distance (X is similarity score)
     * - Returns 0.5 when all query words appear in the block description (lowest priority)
     * - Returns 0 for no match
     *
     * Higher scores will appear first in search results.
     */
    const matchesSearch = (block: Block, query: string): number => {
      if (!query) return 1;
      const normalizedQuery = query.toLowerCase().trim();
      const queryWords = normalizedQuery.split(/\s+/);
      const blockName = block.name.toLowerCase();
      const beautifiedName = beautifyString(block.name).toLowerCase();
      const description = block.description.toLowerCase();

      // 1. Exact match in name (highest priority)
      if (
        blockName.includes(normalizedQuery) ||
        beautifiedName.includes(normalizedQuery)