Spaces:
Sleeping
Sleeping
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)"
)
|