kweaver-dolphin 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- DolphinLanguageSDK/__init__.py +58 -0
- dolphin/__init__.py +62 -0
- dolphin/cli/__init__.py +20 -0
- dolphin/cli/args/__init__.py +9 -0
- dolphin/cli/args/parser.py +567 -0
- dolphin/cli/builtin_agents/__init__.py +22 -0
- dolphin/cli/commands/__init__.py +4 -0
- dolphin/cli/interrupt/__init__.py +8 -0
- dolphin/cli/interrupt/handler.py +205 -0
- dolphin/cli/interrupt/keyboard.py +82 -0
- dolphin/cli/main.py +49 -0
- dolphin/cli/multimodal/__init__.py +34 -0
- dolphin/cli/multimodal/clipboard.py +327 -0
- dolphin/cli/multimodal/handler.py +249 -0
- dolphin/cli/multimodal/image_processor.py +214 -0
- dolphin/cli/multimodal/input_parser.py +149 -0
- dolphin/cli/runner/__init__.py +8 -0
- dolphin/cli/runner/runner.py +989 -0
- dolphin/cli/ui/__init__.py +10 -0
- dolphin/cli/ui/console.py +2795 -0
- dolphin/cli/ui/input.py +340 -0
- dolphin/cli/ui/layout.py +425 -0
- dolphin/cli/ui/stream_renderer.py +302 -0
- dolphin/cli/utils/__init__.py +8 -0
- dolphin/cli/utils/helpers.py +135 -0
- dolphin/cli/utils/version.py +49 -0
- dolphin/core/__init__.py +107 -0
- dolphin/core/agent/__init__.py +10 -0
- dolphin/core/agent/agent_state.py +69 -0
- dolphin/core/agent/base_agent.py +970 -0
- dolphin/core/code_block/__init__.py +0 -0
- dolphin/core/code_block/agent_init_block.py +0 -0
- dolphin/core/code_block/assign_block.py +98 -0
- dolphin/core/code_block/basic_code_block.py +1865 -0
- dolphin/core/code_block/explore_block.py +1327 -0
- dolphin/core/code_block/explore_block_v2.py +712 -0
- dolphin/core/code_block/explore_strategy.py +672 -0
- dolphin/core/code_block/judge_block.py +220 -0
- dolphin/core/code_block/prompt_block.py +32 -0
- dolphin/core/code_block/skill_call_deduplicator.py +291 -0
- dolphin/core/code_block/tool_block.py +129 -0
- dolphin/core/common/__init__.py +17 -0
- dolphin/core/common/constants.py +176 -0
- dolphin/core/common/enums.py +1173 -0
- dolphin/core/common/exceptions.py +133 -0
- dolphin/core/common/multimodal.py +539 -0
- dolphin/core/common/object_type.py +165 -0
- dolphin/core/common/output_format.py +432 -0
- dolphin/core/common/types.py +36 -0
- dolphin/core/config/__init__.py +16 -0
- dolphin/core/config/global_config.py +1289 -0
- dolphin/core/config/ontology_config.py +133 -0
- dolphin/core/context/__init__.py +12 -0
- dolphin/core/context/context.py +1580 -0
- dolphin/core/context/context_manager.py +161 -0
- dolphin/core/context/var_output.py +82 -0
- dolphin/core/context/variable_pool.py +356 -0
- dolphin/core/context_engineer/__init__.py +41 -0
- dolphin/core/context_engineer/config/__init__.py +5 -0
- dolphin/core/context_engineer/config/settings.py +402 -0
- dolphin/core/context_engineer/core/__init__.py +7 -0
- dolphin/core/context_engineer/core/budget_manager.py +327 -0
- dolphin/core/context_engineer/core/context_assembler.py +583 -0
- dolphin/core/context_engineer/core/context_manager.py +637 -0
- dolphin/core/context_engineer/core/tokenizer_service.py +260 -0
- dolphin/core/context_engineer/example/incremental_example.py +267 -0
- dolphin/core/context_engineer/example/traditional_example.py +334 -0
- dolphin/core/context_engineer/services/__init__.py +5 -0
- dolphin/core/context_engineer/services/compressor.py +399 -0
- dolphin/core/context_engineer/utils/__init__.py +6 -0
- dolphin/core/context_engineer/utils/context_utils.py +441 -0
- dolphin/core/context_engineer/utils/message_formatter.py +270 -0
- dolphin/core/context_engineer/utils/token_utils.py +139 -0
- dolphin/core/coroutine/__init__.py +15 -0
- dolphin/core/coroutine/context_snapshot.py +154 -0
- dolphin/core/coroutine/context_snapshot_profile.py +922 -0
- dolphin/core/coroutine/context_snapshot_store.py +268 -0
- dolphin/core/coroutine/execution_frame.py +145 -0
- dolphin/core/coroutine/execution_state_registry.py +161 -0
- dolphin/core/coroutine/resume_handle.py +101 -0
- dolphin/core/coroutine/step_result.py +101 -0
- dolphin/core/executor/__init__.py +18 -0
- dolphin/core/executor/debug_controller.py +630 -0
- dolphin/core/executor/dolphin_executor.py +1063 -0
- dolphin/core/executor/executor.py +624 -0
- dolphin/core/flags/__init__.py +27 -0
- dolphin/core/flags/definitions.py +49 -0
- dolphin/core/flags/manager.py +113 -0
- dolphin/core/hook/__init__.py +95 -0
- dolphin/core/hook/expression_evaluator.py +499 -0
- dolphin/core/hook/hook_dispatcher.py +380 -0
- dolphin/core/hook/hook_types.py +248 -0
- dolphin/core/hook/isolated_variable_pool.py +284 -0
- dolphin/core/interfaces.py +53 -0
- dolphin/core/llm/__init__.py +0 -0
- dolphin/core/llm/llm.py +495 -0
- dolphin/core/llm/llm_call.py +100 -0
- dolphin/core/llm/llm_client.py +1285 -0
- dolphin/core/llm/message_sanitizer.py +120 -0
- dolphin/core/logging/__init__.py +20 -0
- dolphin/core/logging/logger.py +526 -0
- dolphin/core/message/__init__.py +8 -0
- dolphin/core/message/compressor.py +749 -0
- dolphin/core/parser/__init__.py +8 -0
- dolphin/core/parser/parser.py +405 -0
- dolphin/core/runtime/__init__.py +10 -0
- dolphin/core/runtime/runtime_graph.py +926 -0
- dolphin/core/runtime/runtime_instance.py +446 -0
- dolphin/core/skill/__init__.py +14 -0
- dolphin/core/skill/context_retention.py +157 -0
- dolphin/core/skill/skill_function.py +686 -0
- dolphin/core/skill/skill_matcher.py +282 -0
- dolphin/core/skill/skillkit.py +700 -0
- dolphin/core/skill/skillset.py +72 -0
- dolphin/core/trajectory/__init__.py +10 -0
- dolphin/core/trajectory/recorder.py +189 -0
- dolphin/core/trajectory/trajectory.py +522 -0
- dolphin/core/utils/__init__.py +9 -0
- dolphin/core/utils/cache_kv.py +212 -0
- dolphin/core/utils/tools.py +340 -0
- dolphin/lib/__init__.py +93 -0
- dolphin/lib/debug/__init__.py +8 -0
- dolphin/lib/debug/visualizer.py +409 -0
- dolphin/lib/memory/__init__.py +28 -0
- dolphin/lib/memory/async_processor.py +220 -0
- dolphin/lib/memory/llm_calls.py +195 -0
- dolphin/lib/memory/manager.py +78 -0
- dolphin/lib/memory/sandbox.py +46 -0
- dolphin/lib/memory/storage.py +245 -0
- dolphin/lib/memory/utils.py +51 -0
- dolphin/lib/ontology/__init__.py +12 -0
- dolphin/lib/ontology/basic/__init__.py +0 -0
- dolphin/lib/ontology/basic/base.py +102 -0
- dolphin/lib/ontology/basic/concept.py +130 -0
- dolphin/lib/ontology/basic/object.py +11 -0
- dolphin/lib/ontology/basic/relation.py +63 -0
- dolphin/lib/ontology/datasource/__init__.py +27 -0
- dolphin/lib/ontology/datasource/datasource.py +66 -0
- dolphin/lib/ontology/datasource/oracle_datasource.py +338 -0
- dolphin/lib/ontology/datasource/sql.py +845 -0
- dolphin/lib/ontology/mapping.py +177 -0
- dolphin/lib/ontology/ontology.py +733 -0
- dolphin/lib/ontology/ontology_context.py +16 -0
- dolphin/lib/ontology/ontology_manager.py +107 -0
- dolphin/lib/skill_results/__init__.py +31 -0
- dolphin/lib/skill_results/cache_backend.py +559 -0
- dolphin/lib/skill_results/result_processor.py +181 -0
- dolphin/lib/skill_results/result_reference.py +179 -0
- dolphin/lib/skill_results/skillkit_hook.py +324 -0
- dolphin/lib/skill_results/strategies.py +328 -0
- dolphin/lib/skill_results/strategy_registry.py +150 -0
- dolphin/lib/skillkits/__init__.py +44 -0
- dolphin/lib/skillkits/agent_skillkit.py +155 -0
- dolphin/lib/skillkits/cognitive_skillkit.py +82 -0
- dolphin/lib/skillkits/env_skillkit.py +250 -0
- dolphin/lib/skillkits/mcp_adapter.py +616 -0
- dolphin/lib/skillkits/mcp_skillkit.py +771 -0
- dolphin/lib/skillkits/memory_skillkit.py +650 -0
- dolphin/lib/skillkits/noop_skillkit.py +31 -0
- dolphin/lib/skillkits/ontology_skillkit.py +89 -0
- dolphin/lib/skillkits/plan_act_skillkit.py +452 -0
- dolphin/lib/skillkits/resource/__init__.py +52 -0
- dolphin/lib/skillkits/resource/models/__init__.py +6 -0
- dolphin/lib/skillkits/resource/models/skill_config.py +109 -0
- dolphin/lib/skillkits/resource/models/skill_meta.py +127 -0
- dolphin/lib/skillkits/resource/resource_skillkit.py +393 -0
- dolphin/lib/skillkits/resource/skill_cache.py +215 -0
- dolphin/lib/skillkits/resource/skill_loader.py +395 -0
- dolphin/lib/skillkits/resource/skill_validator.py +406 -0
- dolphin/lib/skillkits/resource_skillkit.py +11 -0
- dolphin/lib/skillkits/search_skillkit.py +163 -0
- dolphin/lib/skillkits/sql_skillkit.py +274 -0
- dolphin/lib/skillkits/system_skillkit.py +509 -0
- dolphin/lib/skillkits/vm_skillkit.py +65 -0
- dolphin/lib/utils/__init__.py +9 -0
- dolphin/lib/utils/data_process.py +207 -0
- dolphin/lib/utils/handle_progress.py +178 -0
- dolphin/lib/utils/security.py +139 -0
- dolphin/lib/utils/text_retrieval.py +462 -0
- dolphin/lib/vm/__init__.py +11 -0
- dolphin/lib/vm/env_executor.py +895 -0
- dolphin/lib/vm/python_session_manager.py +453 -0
- dolphin/lib/vm/vm.py +610 -0
- dolphin/sdk/__init__.py +60 -0
- dolphin/sdk/agent/__init__.py +12 -0
- dolphin/sdk/agent/agent_factory.py +236 -0
- dolphin/sdk/agent/dolphin_agent.py +1106 -0
- dolphin/sdk/api/__init__.py +4 -0
- dolphin/sdk/runtime/__init__.py +8 -0
- dolphin/sdk/runtime/env.py +363 -0
- dolphin/sdk/skill/__init__.py +10 -0
- dolphin/sdk/skill/global_skills.py +706 -0
- dolphin/sdk/skill/traditional_toolkit.py +260 -0
- kweaver_dolphin-0.1.0.dist-info/METADATA +521 -0
- kweaver_dolphin-0.1.0.dist-info/RECORD +199 -0
- kweaver_dolphin-0.1.0.dist-info/WHEEL +5 -0
- kweaver_dolphin-0.1.0.dist-info/entry_points.txt +27 -0
- kweaver_dolphin-0.1.0.dist-info/licenses/LICENSE.txt +201 -0
- kweaver_dolphin-0.1.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"""Skill Name Matching Utility Class
|
|
2
|
+
|
|
3
|
+
Provides unified skill name matching logic, supporting wildcard matching and exact matching
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import fnmatch
|
|
7
|
+
from typing import Iterable, List, Optional, Set, Tuple, TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from dolphin.core.skill.skill_function import SkillFunction
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SkillMatcher:
|
|
14
|
+
"""Skill Name Matching Utility Class
|
|
15
|
+
|
|
16
|
+
Supports the following matching patterns:
|
|
17
|
+
- Exact match: "playwright_browser_navigate"
|
|
18
|
+
- Wildcard match: "playwright*", "*_browser_*", "playwright_browser_*"
|
|
19
|
+
- List match: ["playwright*", "_python"]
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
@staticmethod
|
|
23
|
+
def match_skill_name(skill_name: str, pattern: str) -> bool:
|
|
24
|
+
"""Determine whether the skill name matches the specified pattern
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
skill_name (str): The skill name
|
|
28
|
+
pattern (str): The matching pattern, supports wildcards
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
bool: Whether it matches
|
|
32
|
+
"""
|
|
33
|
+
return fnmatch.fnmatch(skill_name, pattern)
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def match_skill_names(skill_name: str, patterns: List[str]) -> bool:
|
|
37
|
+
"""Determine whether the skill name matches any one in the specified pattern list.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
skill_name (str): The skill name
|
|
41
|
+
patterns (List[str]): The list of matching patterns
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
bool: Whether it matches any one pattern
|
|
45
|
+
"""
|
|
46
|
+
return any(
|
|
47
|
+
SkillMatcher.match_skill_name(skill_name, pattern) for pattern in patterns
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def filter_skills_by_pattern(
|
|
52
|
+
skills: List["SkillFunction"], pattern: str
|
|
53
|
+
) -> List["SkillFunction"]:
|
|
54
|
+
"""Filter a list of skills based on a single pattern
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
skills (List[SkillFunction]): List of skills
|
|
58
|
+
pattern (str): Matching pattern
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
List[SkillFunction]: Filtered list of skills
|
|
62
|
+
"""
|
|
63
|
+
return [
|
|
64
|
+
skill
|
|
65
|
+
for skill in skills
|
|
66
|
+
if SkillMatcher.match_skill_name(skill.get_function_name(), pattern)
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def filter_skills_by_patterns(
|
|
71
|
+
skills: List["SkillFunction"], patterns: List[str]
|
|
72
|
+
) -> List["SkillFunction"]:
|
|
73
|
+
"""Filter the skill list based on multiple patterns
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
skills (List[SkillFunction]): List of skills
|
|
77
|
+
patterns (List[str]): List of matching patterns
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
List[SkillFunction]: Filtered list of skills
|
|
81
|
+
"""
|
|
82
|
+
matched_skills = []
|
|
83
|
+
for skill in skills:
|
|
84
|
+
skill_name = skill.get_function_name()
|
|
85
|
+
if SkillMatcher.match_skill_names(skill_name, patterns):
|
|
86
|
+
matched_skills.append(skill)
|
|
87
|
+
return matched_skills
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def find_first_matching_skill(
|
|
91
|
+
skills: List["SkillFunction"], pattern: str
|
|
92
|
+
) -> Optional["SkillFunction"]:
|
|
93
|
+
"""Find the first skill that matches the specified pattern
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
skills (List[SkillFunction]): List of skills
|
|
97
|
+
pattern (str): Matching pattern
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Optional[SkillFunction]: The first matching skill, or None if not found
|
|
101
|
+
"""
|
|
102
|
+
for skill in skills:
|
|
103
|
+
if SkillMatcher.match_skill_name(skill.get_function_name(), pattern):
|
|
104
|
+
return skill
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
@staticmethod
|
|
108
|
+
def get_matching_skills(
|
|
109
|
+
skills: List["SkillFunction"], skill_names: Optional[List[str]] = None
|
|
110
|
+
) -> List["SkillFunction"]:
|
|
111
|
+
"""Get skills matching the specified list of names
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
skills (List[SkillFunction]): List of skills
|
|
115
|
+
skill_names (Optional[List[str]]): List of skill names, supports wildcards; None means return all skills
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
List[SkillFunction]: List of matching skills
|
|
119
|
+
"""
|
|
120
|
+
if skill_names is None:
|
|
121
|
+
return skills
|
|
122
|
+
|
|
123
|
+
return SkillMatcher.filter_skills_by_patterns(skills, skill_names)
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def get_matching_skills_by_names(
|
|
127
|
+
skills: List["SkillFunction"], skill_names: List[str]
|
|
128
|
+
) -> List["SkillFunction"]:
|
|
129
|
+
return [skill for skill in skills if skill.get_function_name() in skill_names]
|
|
130
|
+
|
|
131
|
+
@staticmethod
|
|
132
|
+
def get_skill_by_name(
|
|
133
|
+
skills: List["SkillFunction"], skill_name: str
|
|
134
|
+
) -> Optional["SkillFunction"]:
|
|
135
|
+
"""Get a skill by its name, supporting wildcard matching.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
skills (List[SkillFunction]): List of skills
|
|
139
|
+
skill_name (str): Name of the skill, supports wildcards
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Optional[SkillFunction]: The matched skill, returns None if not found
|
|
143
|
+
"""
|
|
144
|
+
return SkillMatcher.find_first_matching_skill(skills, skill_name)
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def get_owner_skillkits(skills: Iterable["SkillFunction"]) -> Set[str]:
|
|
148
|
+
"""Collect all known owner skillkit names from skills via owner_name property."""
|
|
149
|
+
owners: Set[str] = set()
|
|
150
|
+
for skill in skills:
|
|
151
|
+
if hasattr(skill, "owner_name") and skill.owner_name:
|
|
152
|
+
owners.add(skill.owner_name)
|
|
153
|
+
return owners
|
|
154
|
+
|
|
155
|
+
@staticmethod
|
|
156
|
+
def split_namespaced_pattern(
|
|
157
|
+
pattern: str, owner_names: Set[str]
|
|
158
|
+
) -> Tuple[Optional[str], str, bool]:
|
|
159
|
+
"""Split a pattern into optional <skillkit> namespace and the remaining tool-name pattern.
|
|
160
|
+
|
|
161
|
+
Supported forms:
|
|
162
|
+
- "<skillkit>": shorthand for "<skillkit>.*"
|
|
163
|
+
- "<skillkit>.<pattern>": namespaced matching (skill owner must equal <skillkit>)
|
|
164
|
+
- "<pattern>": non-namespaced matching (matches tool name directly)
|
|
165
|
+
|
|
166
|
+
Notes:
|
|
167
|
+
- If owner_names is empty, always treat as non-namespaced.
|
|
168
|
+
- Uses longest owner prefix match to support owner names containing dots.
|
|
169
|
+
"""
|
|
170
|
+
if not owner_names:
|
|
171
|
+
return None, pattern, False
|
|
172
|
+
|
|
173
|
+
if pattern in owner_names:
|
|
174
|
+
return pattern, "*", True
|
|
175
|
+
|
|
176
|
+
for owner in sorted(owner_names, key=len, reverse=True):
|
|
177
|
+
prefix = owner + "."
|
|
178
|
+
if pattern.startswith(prefix):
|
|
179
|
+
suffix = pattern[len(prefix) :] or "*"
|
|
180
|
+
return owner, suffix, True
|
|
181
|
+
|
|
182
|
+
return None, pattern, False
|
|
183
|
+
|
|
184
|
+
@staticmethod
|
|
185
|
+
def match_skill(
|
|
186
|
+
skill: "SkillFunction", pattern: str, owner_names: Optional[Set[str]] = None
|
|
187
|
+
) -> bool:
|
|
188
|
+
"""Match a skill against a (possibly namespaced) pattern."""
|
|
189
|
+
owner_names = owner_names or set()
|
|
190
|
+
owner, suffix, is_namespaced = SkillMatcher.split_namespaced_pattern(
|
|
191
|
+
pattern, owner_names
|
|
192
|
+
)
|
|
193
|
+
if not is_namespaced:
|
|
194
|
+
return SkillMatcher.match_skill_name(skill.get_function_name(), pattern)
|
|
195
|
+
|
|
196
|
+
skill_owner = getattr(skill, "owner_name", None)
|
|
197
|
+
return skill_owner == owner and SkillMatcher.match_skill_name(
|
|
198
|
+
skill.get_function_name(), suffix
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
@staticmethod
|
|
202
|
+
def match_skills_batch(
|
|
203
|
+
skills: List["SkillFunction"],
|
|
204
|
+
patterns: List[str],
|
|
205
|
+
owner_names: Optional[Set[str]] = None,
|
|
206
|
+
) -> Tuple[List["SkillFunction"], bool]:
|
|
207
|
+
"""Batch match skills against multiple patterns.
|
|
208
|
+
|
|
209
|
+
This method is optimized to:
|
|
210
|
+
- Pre-parse all patterns once (avoid repeated split_namespaced_pattern calls)
|
|
211
|
+
- Deduplicate matched skills (each skill appears at most once)
|
|
212
|
+
- Track whether any namespaced pattern was used
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
skills: List of skills to match against
|
|
216
|
+
patterns: List of patterns (plain or namespaced)
|
|
217
|
+
owner_names: Set of known skillkit owner names
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
Tuple of (matched_skills, any_namespaced_pattern)
|
|
221
|
+
"""
|
|
222
|
+
owner_names = owner_names or set()
|
|
223
|
+
|
|
224
|
+
# Pre-sort owner_names once for consistent longest-prefix matching
|
|
225
|
+
sorted_owners = sorted(owner_names, key=len, reverse=True) if owner_names else []
|
|
226
|
+
|
|
227
|
+
# Pre-parse all patterns
|
|
228
|
+
parsed_patterns: List[Tuple[Optional[str], str, bool]] = []
|
|
229
|
+
any_namespaced = False
|
|
230
|
+
for pattern in patterns:
|
|
231
|
+
owner, suffix, is_ns = SkillMatcher._split_namespaced_pattern_with_sorted_owners(
|
|
232
|
+
pattern, owner_names, sorted_owners
|
|
233
|
+
)
|
|
234
|
+
parsed_patterns.append((owner, suffix, is_ns))
|
|
235
|
+
any_namespaced = any_namespaced or is_ns
|
|
236
|
+
|
|
237
|
+
# Match skills with deduplication
|
|
238
|
+
matched: List["SkillFunction"] = []
|
|
239
|
+
seen_ids: Set[int] = set()
|
|
240
|
+
|
|
241
|
+
for skill in skills:
|
|
242
|
+
skill_id = id(skill)
|
|
243
|
+
if skill_id in seen_ids:
|
|
244
|
+
continue
|
|
245
|
+
|
|
246
|
+
skill_name = skill.get_function_name()
|
|
247
|
+
skill_owner = getattr(skill, "owner_name", None)
|
|
248
|
+
|
|
249
|
+
for owner, suffix, is_ns in parsed_patterns:
|
|
250
|
+
if is_ns:
|
|
251
|
+
# Namespaced pattern: match owner and skill name
|
|
252
|
+
if skill_owner == owner and fnmatch.fnmatch(skill_name, suffix):
|
|
253
|
+
matched.append(skill)
|
|
254
|
+
seen_ids.add(skill_id)
|
|
255
|
+
break
|
|
256
|
+
else:
|
|
257
|
+
# Plain pattern: match skill name only
|
|
258
|
+
if fnmatch.fnmatch(skill_name, suffix):
|
|
259
|
+
matched.append(skill)
|
|
260
|
+
seen_ids.add(skill_id)
|
|
261
|
+
break
|
|
262
|
+
|
|
263
|
+
return matched, any_namespaced
|
|
264
|
+
|
|
265
|
+
@staticmethod
|
|
266
|
+
def _split_namespaced_pattern_with_sorted_owners(
|
|
267
|
+
pattern: str, owner_names: Set[str], sorted_owners: List[str]
|
|
268
|
+
) -> Tuple[Optional[str], str, bool]:
|
|
269
|
+
"""Split pattern with pre-sorted owners (avoids repeated sorting)."""
|
|
270
|
+
if not owner_names:
|
|
271
|
+
return None, pattern, False
|
|
272
|
+
|
|
273
|
+
if pattern in owner_names:
|
|
274
|
+
return pattern, "*", True
|
|
275
|
+
|
|
276
|
+
for owner in sorted_owners:
|
|
277
|
+
prefix = owner + "."
|
|
278
|
+
if pattern.startswith(prefix):
|
|
279
|
+
suffix = pattern[len(prefix):] or "*"
|
|
280
|
+
return owner, suffix, True
|
|
281
|
+
|
|
282
|
+
return None, pattern, False
|