@hailer/mcp 0.0.1
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.
- package/.claude/commands/tool-builder.md +37 -0
- package/.claude/commands/ws-pull.md +44 -0
- package/.claude/settings.json +8 -0
- package/.claude/settings.local.json +49 -0
- package/.claude/skills/activity-api/SKILL.md +96 -0
- package/.claude/skills/activity-api/references/activity-endpoints.md +845 -0
- package/.claude/skills/add-app-member-skill/SKILL.md +977 -0
- package/.claude/skills/agent-building/SKILL.md +243 -0
- package/.claude/skills/agent-building/references/architecture-patterns.md +446 -0
- package/.claude/skills/agent-building/references/code-examples.md +587 -0
- package/.claude/skills/agent-building/references/implementation-guide.md +619 -0
- package/.claude/skills/app-api/SKILL.md +219 -0
- package/.claude/skills/app-api/references/app-endpoints.md +759 -0
- package/.claude/skills/building-hailer-apps-skill/SKILL.md +548 -0
- package/.claude/skills/create-app-skill/SKILL.md +1101 -0
- package/.claude/skills/create-insight-skill/SKILL.md +1317 -0
- package/.claude/skills/get-insight-data-skill/SKILL.md +1053 -0
- package/.claude/skills/hailer-api/SKILL.md +283 -0
- package/.claude/skills/hailer-api/references/activities.md +620 -0
- package/.claude/skills/hailer-api/references/authentication.md +216 -0
- package/.claude/skills/hailer-api/references/datasets.md +437 -0
- package/.claude/skills/hailer-api/references/files.md +301 -0
- package/.claude/skills/hailer-api/references/insights.md +469 -0
- package/.claude/skills/hailer-api/references/workflows.md +720 -0
- package/.claude/skills/hailer-api/references/workspaces-users.md +445 -0
- package/.claude/skills/insight-api/SKILL.md +185 -0
- package/.claude/skills/insight-api/references/insight-endpoints.md +514 -0
- package/.claude/skills/install-workflow-skill/SKILL.md +1056 -0
- package/.claude/skills/list-apps-skill/SKILL.md +1010 -0
- package/.claude/skills/list-workflows-minimal-skill/SKILL.md +992 -0
- package/.claude/skills/local-first-skill/SKILL.md +570 -0
- package/.claude/skills/mcp-tools/SKILL.md +419 -0
- package/.claude/skills/mcp-tools/references/api-endpoints.md +499 -0
- package/.claude/skills/mcp-tools/references/data-structures.md +554 -0
- package/.claude/skills/mcp-tools/references/implementation-patterns.md +717 -0
- package/.claude/skills/preview-insight-skill/SKILL.md +1290 -0
- package/.claude/skills/publish-hailer-app-skill/SKILL.md +453 -0
- package/.claude/skills/remove-app-member-skill/SKILL.md +671 -0
- package/.claude/skills/remove-app-skill/SKILL.md +985 -0
- package/.claude/skills/remove-insight-skill/SKILL.md +1011 -0
- package/.claude/skills/remove-workflow-skill/SKILL.md +920 -0
- package/.claude/skills/scaffold-hailer-app-skill/SKILL.md +1034 -0
- package/.claude/skills/skill-testing/README.md +137 -0
- package/.claude/skills/skill-testing/SKILL.md +348 -0
- package/.claude/skills/skill-testing/references/test-patterns.md +705 -0
- package/.claude/skills/skill-testing/references/testing-guide.md +603 -0
- package/.claude/skills/skill-testing/references/validation-checklist.md +537 -0
- package/.claude/skills/tool-builder/SKILL.md +328 -0
- package/.claude/skills/update-app-skill/SKILL.md +970 -0
- package/.claude/skills/update-workflow-field-skill/SKILL.md +1098 -0
- package/.env.example +81 -0
- package/.mcp.json +13 -0
- package/README.md +297 -0
- package/dist/app.d.ts +4 -0
- package/dist/app.js +74 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +5 -0
- package/dist/client/adaptive-documentation-bot.d.ts +108 -0
- package/dist/client/adaptive-documentation-bot.js +475 -0
- package/dist/client/adaptive-documentation-types.d.ts +66 -0
- package/dist/client/adaptive-documentation-types.js +9 -0
- package/dist/client/agent-activity-bot.d.ts +51 -0
- package/dist/client/agent-activity-bot.js +166 -0
- package/dist/client/agent-tracker.d.ts +499 -0
- package/dist/client/agent-tracker.js +659 -0
- package/dist/client/description-updater.d.ts +56 -0
- package/dist/client/description-updater.js +259 -0
- package/dist/client/log-parser.d.ts +72 -0
- package/dist/client/log-parser.js +387 -0
- package/dist/client/mcp-client.d.ts +50 -0
- package/dist/client/mcp-client.js +532 -0
- package/dist/client/message-processor.d.ts +35 -0
- package/dist/client/message-processor.js +352 -0
- package/dist/client/multi-bot-manager.d.ts +24 -0
- package/dist/client/multi-bot-manager.js +74 -0
- package/dist/client/providers/anthropic-provider.d.ts +19 -0
- package/dist/client/providers/anthropic-provider.js +631 -0
- package/dist/client/providers/llm-provider.d.ts +47 -0
- package/dist/client/providers/llm-provider.js +367 -0
- package/dist/client/providers/openai-provider.d.ts +23 -0
- package/dist/client/providers/openai-provider.js +621 -0
- package/dist/client/simple-llm-caller.d.ts +19 -0
- package/dist/client/simple-llm-caller.js +100 -0
- package/dist/client/skill-generator.d.ts +81 -0
- package/dist/client/skill-generator.js +386 -0
- package/dist/client/test-adaptive-bot.d.ts +9 -0
- package/dist/client/test-adaptive-bot.js +82 -0
- package/dist/client/token-pricing.d.ts +38 -0
- package/dist/client/token-pricing.js +127 -0
- package/dist/client/token-tracker.d.ts +232 -0
- package/dist/client/token-tracker.js +457 -0
- package/dist/client/token-usage-bot.d.ts +53 -0
- package/dist/client/token-usage-bot.js +153 -0
- package/dist/client/tool-executor.d.ts +69 -0
- package/dist/client/tool-executor.js +159 -0
- package/dist/client/tool-schema-loader.d.ts +60 -0
- package/dist/client/tool-schema-loader.js +178 -0
- package/dist/client/types.d.ts +69 -0
- package/dist/client/types.js +7 -0
- package/dist/config.d.ts +162 -0
- package/dist/config.js +296 -0
- package/dist/core.d.ts +26 -0
- package/dist/core.js +147 -0
- package/dist/lib/context-manager.d.ts +111 -0
- package/dist/lib/context-manager.js +431 -0
- package/dist/lib/logger.d.ts +74 -0
- package/dist/lib/logger.js +277 -0
- package/dist/lib/materialize.d.ts +3 -0
- package/dist/lib/materialize.js +101 -0
- package/dist/lib/normalizedName.d.ts +7 -0
- package/dist/lib/normalizedName.js +48 -0
- package/dist/lib/prompt-length-manager.d.ts +81 -0
- package/dist/lib/prompt-length-manager.js +457 -0
- package/dist/lib/terminal-prompt.d.ts +9 -0
- package/dist/lib/terminal-prompt.js +108 -0
- package/dist/mcp/UserContextCache.d.ts +56 -0
- package/dist/mcp/UserContextCache.js +163 -0
- package/dist/mcp/auth.d.ts +2 -0
- package/dist/mcp/auth.js +29 -0
- package/dist/mcp/hailer-clients.d.ts +42 -0
- package/dist/mcp/hailer-clients.js +246 -0
- package/dist/mcp/signal-handler.d.ts +45 -0
- package/dist/mcp/signal-handler.js +317 -0
- package/dist/mcp/tool-registry.d.ts +100 -0
- package/dist/mcp/tool-registry.js +306 -0
- package/dist/mcp/tools/activity.d.ts +15 -0
- package/dist/mcp/tools/activity.js +955 -0
- package/dist/mcp/tools/app.d.ts +20 -0
- package/dist/mcp/tools/app.js +1488 -0
- package/dist/mcp/tools/discussion.d.ts +19 -0
- package/dist/mcp/tools/discussion.js +950 -0
- package/dist/mcp/tools/file.d.ts +15 -0
- package/dist/mcp/tools/file.js +119 -0
- package/dist/mcp/tools/insight.d.ts +17 -0
- package/dist/mcp/tools/insight.js +806 -0
- package/dist/mcp/tools/skill.d.ts +10 -0
- package/dist/mcp/tools/skill.js +279 -0
- package/dist/mcp/tools/user.d.ts +10 -0
- package/dist/mcp/tools/user.js +108 -0
- package/dist/mcp/tools/workflow-template.d.ts +19 -0
- package/dist/mcp/tools/workflow-template.js +822 -0
- package/dist/mcp/tools/workflow.d.ts +18 -0
- package/dist/mcp/tools/workflow.js +1362 -0
- package/dist/mcp/utils/api-errors.d.ts +45 -0
- package/dist/mcp/utils/api-errors.js +160 -0
- package/dist/mcp/utils/data-transformers.d.ts +102 -0
- package/dist/mcp/utils/data-transformers.js +194 -0
- package/dist/mcp/utils/file-upload.d.ts +33 -0
- package/dist/mcp/utils/file-upload.js +148 -0
- package/dist/mcp/utils/hailer-api-client.d.ts +120 -0
- package/dist/mcp/utils/hailer-api-client.js +323 -0
- package/dist/mcp/utils/index.d.ts +13 -0
- package/dist/mcp/utils/index.js +39 -0
- package/dist/mcp/utils/logger.d.ts +42 -0
- package/dist/mcp/utils/logger.js +103 -0
- package/dist/mcp/utils/types.d.ts +286 -0
- package/dist/mcp/utils/types.js +7 -0
- package/dist/mcp/workspace-cache.d.ts +42 -0
- package/dist/mcp/workspace-cache.js +97 -0
- package/dist/mcp-server.d.ts +42 -0
- package/dist/mcp-server.js +280 -0
- package/package.json +56 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
# Code Examples: Skill-Based Agent System
|
|
2
|
+
|
|
3
|
+
## Complete Working Examples
|
|
4
|
+
|
|
5
|
+
### Example 1: Basic Skill Loader
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// skill-loader.ts
|
|
9
|
+
import * as fs from 'fs/promises';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
|
|
12
|
+
export class SkillLoader {
|
|
13
|
+
private cache = new Map<string, LoadedSkill>();
|
|
14
|
+
private skillsPath = '.claude/skills/';
|
|
15
|
+
|
|
16
|
+
async load(skillName: string): Promise<LoadedSkill> {
|
|
17
|
+
// Check cache
|
|
18
|
+
if (this.cache.has(skillName)) {
|
|
19
|
+
return this.cache.get(skillName)!;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Load from disk
|
|
23
|
+
const mainPath = path.join(this.skillsPath, skillName, 'SKILL.md');
|
|
24
|
+
const content = await fs.readFile(mainPath, 'utf-8');
|
|
25
|
+
|
|
26
|
+
const skill = { name: skillName, content, loadedAt: Date.now() };
|
|
27
|
+
this.cache.set(skillName, skill);
|
|
28
|
+
|
|
29
|
+
return skill;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
clearCache() {
|
|
33
|
+
this.cache.clear();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Usage
|
|
38
|
+
const loader = new SkillLoader();
|
|
39
|
+
const skill = await loader.load('mcp-tools');
|
|
40
|
+
console.log(`Loaded ${skill.name}: ${skill.content.length} characters`);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Example 2: Keyword-Based Skill Manager
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// skill-manager.ts
|
|
47
|
+
export class SkillManager {
|
|
48
|
+
private skillMappings = new Map([
|
|
49
|
+
['mcp-tools', {
|
|
50
|
+
keywords: ['workflow', 'phase', 'field'],
|
|
51
|
+
tools: ['install_workflow']
|
|
52
|
+
}],
|
|
53
|
+
['hailer-api', {
|
|
54
|
+
keywords: ['api', 'endpoint', 'activity'],
|
|
55
|
+
tools: ['list_activities']
|
|
56
|
+
}]
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
constructor(private skillLoader: SkillLoader) {}
|
|
60
|
+
|
|
61
|
+
async analyzeRequest(message: string): Promise<SkillGuidance> {
|
|
62
|
+
const lower = message.toLowerCase();
|
|
63
|
+
const scores = new Map<string, number>();
|
|
64
|
+
|
|
65
|
+
// Score each skill
|
|
66
|
+
for (const [skillName, mapping] of this.skillMappings) {
|
|
67
|
+
const score = mapping.keywords.filter(kw =>
|
|
68
|
+
lower.includes(kw)
|
|
69
|
+
).length;
|
|
70
|
+
|
|
71
|
+
if (score > 0) {
|
|
72
|
+
scores.set(skillName, score);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Get best match
|
|
77
|
+
const best = Array.from(scores.entries())
|
|
78
|
+
.sort(([,a], [,b]) => b - a)[0];
|
|
79
|
+
|
|
80
|
+
if (!best) {
|
|
81
|
+
return { skills: [], confidence: 0.3, guidance: 'General' };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const [skillName, score] = best;
|
|
85
|
+
const skill = await this.skillLoader.load(skillName);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
skills: [skillName],
|
|
89
|
+
confidence: score / 3,
|
|
90
|
+
guidance: `Use ${skillName} expertise`,
|
|
91
|
+
skillContent: skill.content
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Usage
|
|
97
|
+
const manager = new SkillManager(loader);
|
|
98
|
+
const guidance = await manager.analyzeRequest("create a workflow");
|
|
99
|
+
console.log(`Selected skill: ${guidance.skills[0]}`);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Example 3: Enhanced System Prompt Builder
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// In providers/openai-provider.ts
|
|
106
|
+
class OpenAIProvider {
|
|
107
|
+
private buildSystemPrompt(skillGuidance?: SkillGuidance): string {
|
|
108
|
+
let prompt = `You are an AI assistant for Hailer workflow management.`;
|
|
109
|
+
|
|
110
|
+
if (skillGuidance?.skillContent) {
|
|
111
|
+
prompt += `\n\n**DOMAIN EXPERTISE:**\n${skillGuidance.skillContent}`;
|
|
112
|
+
prompt += `\n\n**GUIDANCE:** ${skillGuidance.guidance}`;
|
|
113
|
+
|
|
114
|
+
if (skillGuidance.recommendedTools.length > 0) {
|
|
115
|
+
prompt += `\n\n**RECOMMENDED TOOLS:**\n`;
|
|
116
|
+
prompt += skillGuidance.recommendedTools.join(', ');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return prompt;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async processMessage(
|
|
124
|
+
message: ChatMessage,
|
|
125
|
+
skillGuidance?: SkillGuidance
|
|
126
|
+
): Promise<void> {
|
|
127
|
+
const systemPrompt = this.buildSystemPrompt(skillGuidance);
|
|
128
|
+
|
|
129
|
+
const response = await openai.chat.completions.create({
|
|
130
|
+
model: 'gpt-4o',
|
|
131
|
+
messages: [
|
|
132
|
+
{ role: 'system', content: systemPrompt },
|
|
133
|
+
{ role: 'user', content: message.content }
|
|
134
|
+
],
|
|
135
|
+
tools: this.mcpTools
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Post response to Hailer...
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Example 4: Message Processor Integration
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
// In message-processor.ts
|
|
147
|
+
export class HailerMessageProcessor {
|
|
148
|
+
private skillLoader = new SkillLoader();
|
|
149
|
+
private skillManager = new SkillManager(this.skillLoader);
|
|
150
|
+
|
|
151
|
+
async processHailerMessage(
|
|
152
|
+
signal: HailerSignal,
|
|
153
|
+
botClient: BotClient
|
|
154
|
+
): Promise<void> {
|
|
155
|
+
// Extract message
|
|
156
|
+
const messages = await this.extractMessage(signal);
|
|
157
|
+
|
|
158
|
+
for (const message of messages) {
|
|
159
|
+
// Analyze request for skills
|
|
160
|
+
const skillGuidance = await this.skillManager.analyzeRequest(
|
|
161
|
+
message.content
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
console.log(`Skills selected: ${skillGuidance.skills.join(', ')}`);
|
|
165
|
+
console.log(`Confidence: ${skillGuidance.confidence}`);
|
|
166
|
+
|
|
167
|
+
// Get provider
|
|
168
|
+
const provider = this.getProvider();
|
|
169
|
+
|
|
170
|
+
// Process with skill enhancement
|
|
171
|
+
await provider.processMessage(message, skillGuidance);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Testing Examples
|
|
178
|
+
|
|
179
|
+
### Unit Test: Skill Loader
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { SkillLoader } from '../skill-loader';
|
|
183
|
+
|
|
184
|
+
describe('SkillLoader', () => {
|
|
185
|
+
let loader: SkillLoader;
|
|
186
|
+
|
|
187
|
+
beforeEach(() => {
|
|
188
|
+
loader = new SkillLoader();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should load skill from disk', async () => {
|
|
192
|
+
const skill = await loader.load('mcp-tools');
|
|
193
|
+
|
|
194
|
+
expect(skill.name).toBe('mcp-tools');
|
|
195
|
+
expect(skill.content).toBeTruthy();
|
|
196
|
+
expect(skill.content.length).toBeGreaterThan(100);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should cache loaded skills', async () => {
|
|
200
|
+
const skill1 = await loader.load('mcp-tools');
|
|
201
|
+
const skill2 = await loader.load('mcp-tools');
|
|
202
|
+
|
|
203
|
+
expect(skill1.loadedAt).toBe(skill2.loadedAt);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('should throw error for non-existent skill', async () => {
|
|
207
|
+
await expect(
|
|
208
|
+
loader.load('non-existent-skill')
|
|
209
|
+
).rejects.toThrow();
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Unit Test: Skill Manager
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import { SkillManager } from '../skill-manager';
|
|
218
|
+
|
|
219
|
+
describe('SkillManager', () => {
|
|
220
|
+
let manager: SkillManager;
|
|
221
|
+
let mockLoader: jest.Mocked<SkillLoader>;
|
|
222
|
+
|
|
223
|
+
beforeEach(() => {
|
|
224
|
+
mockLoader = {
|
|
225
|
+
load: jest.fn().mockResolvedValue({
|
|
226
|
+
name: 'mcp-tools',
|
|
227
|
+
content: 'skill content',
|
|
228
|
+
loadedAt: Date.now()
|
|
229
|
+
})
|
|
230
|
+
} as any;
|
|
231
|
+
|
|
232
|
+
manager = new SkillManager(mockLoader);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('should select mcp-tools for workflow requests', async () => {
|
|
236
|
+
const guidance = await manager.analyzeRequest('create a workflow');
|
|
237
|
+
|
|
238
|
+
expect(guidance.skills).toContain('mcp-tools');
|
|
239
|
+
expect(guidance.confidence).toBeGreaterThan(0.5);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('should select hailer-api for activity requests', async () => {
|
|
243
|
+
const guidance = await manager.analyzeRequest('list my activities');
|
|
244
|
+
|
|
245
|
+
expect(guidance.skills).toContain('hailer-api');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should return default for unmatched requests', async () => {
|
|
249
|
+
const guidance = await manager.analyzeRequest('hello');
|
|
250
|
+
|
|
251
|
+
expect(guidance.skills).toHaveLength(0);
|
|
252
|
+
expect(guidance.confidence).toBeLessThan(0.5);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Integration Test
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
describe('Skill System Integration', () => {
|
|
261
|
+
let processor: HailerMessageProcessor;
|
|
262
|
+
|
|
263
|
+
beforeEach(() => {
|
|
264
|
+
processor = new HailerMessageProcessor(mockManager, [], true);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should enhance prompts with skill content', async () => {
|
|
268
|
+
const message = {
|
|
269
|
+
content: 'help me create a workflow',
|
|
270
|
+
userId: 'test',
|
|
271
|
+
discussionId: 'test'
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const spy = jest.spyOn(processor as any, 'processMessageWithProvider');
|
|
275
|
+
|
|
276
|
+
await processor.processHailerMessage(mockSignal, mockBotClient);
|
|
277
|
+
|
|
278
|
+
expect(spy).toHaveBeenCalled();
|
|
279
|
+
const skillGuidance = spy.mock.calls[0][2];
|
|
280
|
+
expect(skillGuidance.skills).toContain('mcp-tools');
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Performance Monitoring Examples
|
|
286
|
+
|
|
287
|
+
### Skill Usage Tracking
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
class SkillManager {
|
|
291
|
+
private usageStats = new Map<string, number>();
|
|
292
|
+
|
|
293
|
+
async analyzeRequest(message: string): Promise<SkillGuidance> {
|
|
294
|
+
const guidance = await this.doAnalysis(message);
|
|
295
|
+
|
|
296
|
+
// Track usage
|
|
297
|
+
for (const skill of guidance.skills) {
|
|
298
|
+
this.usageStats.set(
|
|
299
|
+
skill,
|
|
300
|
+
(this.usageStats.get(skill) || 0) + 1
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return guidance;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
getTopSkills(limit = 5): Array<[string, number]> {
|
|
308
|
+
return Array.from(this.usageStats.entries())
|
|
309
|
+
.sort(([,a], [,b]) => b - a)
|
|
310
|
+
.slice(0, limit);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Usage
|
|
315
|
+
const topSkills = manager.getTopSkills();
|
|
316
|
+
console.log('Most used skills:', topSkills);
|
|
317
|
+
// Output: [['mcp-tools', 45], ['hailer-api', 32], ...]
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Performance Tracking
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
class SkillLoader {
|
|
324
|
+
private loadTimes = new Map<string, number[]>();
|
|
325
|
+
|
|
326
|
+
async load(skillName: string): Promise<LoadedSkill> {
|
|
327
|
+
const start = performance.now();
|
|
328
|
+
|
|
329
|
+
const skill = await this.doLoad(skillName);
|
|
330
|
+
|
|
331
|
+
const duration = performance.now() - start;
|
|
332
|
+
|
|
333
|
+
// Track load time
|
|
334
|
+
if (!this.loadTimes.has(skillName)) {
|
|
335
|
+
this.loadTimes.set(skillName, []);
|
|
336
|
+
}
|
|
337
|
+
this.loadTimes.get(skillName)!.push(duration);
|
|
338
|
+
|
|
339
|
+
return skill;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
getAverageLoadTime(skillName: string): number {
|
|
343
|
+
const times = this.loadTimes.get(skillName) || [];
|
|
344
|
+
if (times.length === 0) return 0;
|
|
345
|
+
return times.reduce((a, b) => a + b, 0) / times.length;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Usage
|
|
350
|
+
console.log(`Average load time: ${loader.getAverageLoadTime('mcp-tools')}ms`);
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Error Handling Examples
|
|
354
|
+
|
|
355
|
+
### Graceful Degradation
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
class SkillManager {
|
|
359
|
+
async analyzeRequest(message: string): Promise<SkillGuidance> {
|
|
360
|
+
try {
|
|
361
|
+
const skillName = this.selectSkill(message);
|
|
362
|
+
|
|
363
|
+
if (!skillName) {
|
|
364
|
+
return this.getDefaultGuidance();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const skill = await this.skillLoader.load(skillName);
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
skills: [skillName],
|
|
371
|
+
confidence: 0.9,
|
|
372
|
+
skillContent: skill.content
|
|
373
|
+
};
|
|
374
|
+
} catch (error) {
|
|
375
|
+
// Skill loading failed - degrade gracefully
|
|
376
|
+
this.logger.error('Skill analysis failed', error);
|
|
377
|
+
|
|
378
|
+
// Still return guidance, just without skill content
|
|
379
|
+
return {
|
|
380
|
+
skills: [],
|
|
381
|
+
confidence: 0.3,
|
|
382
|
+
guidance: 'General assistance (skill loading failed)',
|
|
383
|
+
skillContent: undefined
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Retry Logic
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
class SkillLoader {
|
|
394
|
+
async load(skillName: string, retries = 3): Promise<LoadedSkill> {
|
|
395
|
+
for (let i = 0; i < retries; i++) {
|
|
396
|
+
try {
|
|
397
|
+
return await this.doLoad(skillName);
|
|
398
|
+
} catch (error) {
|
|
399
|
+
if (i === retries - 1) {
|
|
400
|
+
// Last retry failed
|
|
401
|
+
throw new Error(
|
|
402
|
+
`Failed to load skill '${skillName}' after ${retries} attempts`
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Wait before retry
|
|
407
|
+
await new Promise(resolve => setTimeout(resolve, 100 * (i + 1)));
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
throw new Error('Unreachable');
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## Configuration Examples
|
|
417
|
+
|
|
418
|
+
### Adding New Skill Mapping
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
// In skill-manager.ts, add to buildSkillMappings():
|
|
422
|
+
[
|
|
423
|
+
'customer-support',
|
|
424
|
+
{
|
|
425
|
+
keywords: [
|
|
426
|
+
'help', 'support', 'issue', 'problem',
|
|
427
|
+
'customer', 'user', 'complaint'
|
|
428
|
+
],
|
|
429
|
+
tools: ['create_ticket', 'assign_support'],
|
|
430
|
+
priority: 1.0
|
|
431
|
+
}
|
|
432
|
+
]
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Dynamic Skill Registration
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
class SkillManager {
|
|
439
|
+
registerSkill(
|
|
440
|
+
skillName: string,
|
|
441
|
+
keywords: string[],
|
|
442
|
+
tools: string[]
|
|
443
|
+
): void {
|
|
444
|
+
this.skillMappings.set(skillName, {
|
|
445
|
+
keywords,
|
|
446
|
+
tools,
|
|
447
|
+
priority: 1.0
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
this.logger.info('Skill registered', { skillName });
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
unregisterSkill(skillName: string): void {
|
|
454
|
+
this.skillMappings.delete(skillName);
|
|
455
|
+
this.logger.info('Skill unregistered', { skillName });
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Usage
|
|
460
|
+
manager.registerSkill(
|
|
461
|
+
'custom-skill',
|
|
462
|
+
['keyword1', 'keyword2'],
|
|
463
|
+
['tool1', 'tool2']
|
|
464
|
+
);
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## CLI Examples
|
|
468
|
+
|
|
469
|
+
### Skill Management CLI
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
// cli/skill-cli.ts
|
|
473
|
+
export class SkillCLI {
|
|
474
|
+
constructor(private manager: SkillManager) {}
|
|
475
|
+
|
|
476
|
+
async listSkills(): Promise<void> {
|
|
477
|
+
const skills = await this.manager.getAvailableSkills();
|
|
478
|
+
console.table(skills.map(s => ({ name: s })));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
async testSkill(message: string): Promise<void> {
|
|
482
|
+
const guidance = await this.manager.analyzeRequest(message);
|
|
483
|
+
|
|
484
|
+
console.log('Analysis Results:');
|
|
485
|
+
console.log(` Selected Skills: ${guidance.skills.join(', ')}`);
|
|
486
|
+
console.log(` Confidence: ${guidance.confidence}`);
|
|
487
|
+
console.log(` Recommended Tools: ${guidance.recommendedTools.join(', ')}`);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async showStats(): Promise<void> {
|
|
491
|
+
const stats = this.manager.getTopSkills();
|
|
492
|
+
|
|
493
|
+
console.log('Skill Usage Statistics:');
|
|
494
|
+
for (const [skill, count] of stats) {
|
|
495
|
+
console.log(` ${skill}: ${count} uses`);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Usage
|
|
501
|
+
const cli = new SkillCLI(manager);
|
|
502
|
+
await cli.testSkill("help me create a workflow");
|
|
503
|
+
await cli.showStats();
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### NPM Scripts
|
|
507
|
+
|
|
508
|
+
```json
|
|
509
|
+
{
|
|
510
|
+
"scripts": {
|
|
511
|
+
"skills:list": "ts-node cli/skill-cli.ts list",
|
|
512
|
+
"skills:test": "ts-node cli/skill-cli.ts test",
|
|
513
|
+
"skills:stats": "ts-node cli/skill-cli.ts stats"
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
## Real-World Usage Examples
|
|
519
|
+
|
|
520
|
+
### Example 1: Workflow Creation Request
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
// User asks: "Help me create a workflow with phases"
|
|
524
|
+
|
|
525
|
+
// 1. Skill analysis
|
|
526
|
+
const guidance = await manager.analyzeRequest(
|
|
527
|
+
"Help me create a workflow with phases"
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
// Result:
|
|
531
|
+
{
|
|
532
|
+
skills: ['mcp-tools'],
|
|
533
|
+
confidence: 0.95,
|
|
534
|
+
guidance: 'Workflow creation request detected',
|
|
535
|
+
recommendedTools: ['install_workflow', 'list_workflow_phases'],
|
|
536
|
+
skillContent: '...full mcp-tools documentation...'
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// 2. Enhanced prompt sent to LLM:
|
|
540
|
+
`You are an AI assistant...
|
|
541
|
+
|
|
542
|
+
DOMAIN EXPERTISE:
|
|
543
|
+
[Full mcp-tools skill content with workflow examples]
|
|
544
|
+
|
|
545
|
+
GUIDANCE:
|
|
546
|
+
Workflow creation request detected
|
|
547
|
+
|
|
548
|
+
RECOMMENDED TOOLS:
|
|
549
|
+
install_workflow, list_workflow_phases`
|
|
550
|
+
|
|
551
|
+
// 3. LLM Response:
|
|
552
|
+
"I'll help you create a workflow. You can use the install_workflow
|
|
553
|
+
tool with the following structure..."
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### Example 2: Activity List Request
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
// User asks: "List all activities from last week"
|
|
560
|
+
|
|
561
|
+
// 1. Skill analysis
|
|
562
|
+
const guidance = await manager.analyzeRequest(
|
|
563
|
+
"List all activities from last week"
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
// Result:
|
|
567
|
+
{
|
|
568
|
+
skills: ['hailer-api'],
|
|
569
|
+
confidence: 0.85,
|
|
570
|
+
guidance: 'API operation request',
|
|
571
|
+
recommendedTools: ['list_activities'],
|
|
572
|
+
skillContent: '...hailer-api documentation...'
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// 2. Enhanced prompt
|
|
576
|
+
`...
|
|
577
|
+
DOMAIN EXPERTISE:
|
|
578
|
+
[Full hailer-api skill content with filter examples]
|
|
579
|
+
|
|
580
|
+
RECOMMENDED TOOLS:
|
|
581
|
+
list_activities
|
|
582
|
+
...`
|
|
583
|
+
|
|
584
|
+
// 3. LLM Response:
|
|
585
|
+
"I'll list activities from last week using the list_activities tool
|
|
586
|
+
with a date range filter..."
|
|
587
|
+
```
|