File size: 3,640 Bytes
116524e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
"""Prompts and report generation for skill deduplication."""

from __future__ import annotations

from typing import TYPE_CHECKING, List, Tuple

if TYPE_CHECKING:
    from ..core.skillbook import Skill

SIMILARITY_REPORT_HEADER = """

## Similar Skills Detected



The following skill pairs have high semantic similarity and may need consolidation.

Work your way methodologically through each pair. For each pair, you can decide to:

- **MERGE**: Combine into a single improved skill (provide merged_content and keep_id)

- **DELETE**: Remove one as redundant (specify skill_id to delete)

- **KEEP**: Keep both separate if they serve different purposes (explain differentiation)

- **UPDATE**: Refine one skill's content to clarify the difference (provide new_content)



"""

PAIR_TEMPLATE = """### Pair {index}: {similarity:.0%} similar

**Skill A** [{id_a}]

> {content_a}



**Skill B** [{id_b}]

> {content_b}



"""


def generate_similarity_report(

    similar_pairs: List[Tuple["Skill", "Skill", float]],

) -> str:
    """Generate a human-readable similarity report for the SkillManager.



    Args:

        similar_pairs: List of (skill_a, skill_b, similarity_score) tuples.



    Returns:

        Formatted report string to include in SkillManager prompt.

    """
    if not similar_pairs:
        return ""

    parts = [SIMILARITY_REPORT_HEADER]

    for i, (skill_a, skill_b, similarity) in enumerate(similar_pairs, 1):
        parts.append(
            PAIR_TEMPLATE.format(
                index=i,
                similarity=similarity,
                id_a=skill_a.id,
                content_a=skill_a.insight or skill_a.issue,
                id_b=skill_b.id,
                content_b=skill_b.insight or skill_b.issue,
            )
        )

    parts.append("""

## Consolidation Operations Format



Include consolidation operations in your response under a `consolidation_operations` key.

Each operation should have a `type` field and relevant fields for that type:



```json

{

  "consolidation_operations": [

    {

      "type": "MERGE",

      "source_ids": ["skill-id-1", "skill-id-2"],

      "keep_id": "skill-id-1",

      "merged_content": "Improved combined strategy text",

      "reasoning": "Why merging improves the skillbook"

    },

    {

      "type": "DELETE",

      "skill_id": "skill-id-to-remove",

      "reasoning": "Why this skill is redundant"

    },

    {

      "type": "KEEP",

      "skill_ids": ["skill-id-1", "skill-id-2"],

      "differentiation": "How they differ in purpose",

      "reasoning": "Why both are needed"

    },

    {

      "type": "UPDATE",

      "skill_id": "skill-id-to-update",

      "new_content": "Refined content with context tag like [Batch] or [API]",

      "reasoning": "How this clarifies the distinction"

    }

  ]

}

```



**Guidelines:**

- MERGE when skills are semantically identical or near-identical

- KEEP when they serve different contexts (batch vs real-time, different APIs, etc.)

- UPDATE to add context tags like "[Batch Jobs]" or "[User-Facing API]" to differentiate

- DELETE only when one is clearly redundant with no unique value



""")

    return "".join(parts)


def format_pair_for_logging(

    skill_a: "Skill", skill_b: "Skill", similarity: float

) -> str:
    """Format a single pair for logging output."""
    text_a = skill_a.insight or skill_a.issue
    text_b = skill_b.insight or skill_b.issue
    return (
        f"[{skill_a.id}] '{text_a[:50]}...' "
        f"<-> [{skill_b.id}] '{text_b[:50]}...' "
        f"({similarity:.0%} similar)"
    )