openvibe 0.58.3 → 0.60.0
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/CHANGELOG.md +50 -3019
- package/README.md +267 -98
- package/dist/core/agent-modes.d.ts +16 -0
- package/dist/core/agent-modes.d.ts.map +1 -0
- package/dist/core/agent-modes.js +88 -0
- package/dist/core/agent-modes.js.map +1 -0
- package/dist/core/agent-session.d.ts +26 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +84 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +1 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/context-architecture.d.ts +12 -0
- package/dist/core/context-architecture.d.ts.map +1 -0
- package/dist/core/context-architecture.js +14 -0
- package/dist/core/context-architecture.js.map +1 -0
- package/dist/core/context-manager.d.ts +162 -0
- package/dist/core/context-manager.d.ts.map +1 -0
- package/dist/core/context-manager.js +311 -0
- package/dist/core/context-manager.js.map +1 -0
- package/dist/core/context-provider-interface.d.ts +134 -0
- package/dist/core/context-provider-interface.d.ts.map +1 -0
- package/dist/core/context-provider-interface.js +6 -0
- package/dist/core/context-provider-interface.js.map +1 -0
- package/dist/core/context-provider-registry.d.ts +78 -0
- package/dist/core/context-provider-registry.d.ts.map +1 -0
- package/dist/core/context-provider-registry.js +164 -0
- package/dist/core/context-provider-registry.js.map +1 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/large-context-provider.d.ts +87 -0
- package/dist/core/large-context-provider.d.ts.map +1 -0
- package/dist/core/large-context-provider.js +391 -0
- package/dist/core/large-context-provider.js.map +1 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +52 -5
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +6 -4
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +129 -63
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/skills-selector.d.ts +13 -0
- package/dist/modes/interactive/components/skills-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/skills-selector.js +49 -0
- package/dist/modes/interactive/components/skills-selector.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +2 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +44 -37
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/system-prompt-template.md +176 -0
- package/examples/skills/README.md +93 -0
- package/examples/skills/api-design/SKILL.md +80 -0
- package/examples/skills/code-review/SKILL.md +68 -0
- package/examples/skills/git-workflow/SKILL.md +108 -0
- package/examples/skills/testing/SKILL.md +94 -0
- package/package.json +2 -2
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Large Context Provider Implementation
|
|
3
|
+
* Provides 1M context window support for compatible models
|
|
4
|
+
* This is a third-party architecture implementation
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Large context model definitions
|
|
8
|
+
*/
|
|
9
|
+
export const LARGE_CONTEXT_DEFINITIONS = {
|
|
10
|
+
// ═══════════════════════════════════════════════════════════════
|
|
11
|
+
// Google Gemini - 1M Context
|
|
12
|
+
// ═══════════════════════════════════════════════════════════════
|
|
13
|
+
"gemini-1.5-pro": {
|
|
14
|
+
contextWindow: 1000000,
|
|
15
|
+
maxTokens: 8192,
|
|
16
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
17
|
+
},
|
|
18
|
+
"gemini-1.5-flash": {
|
|
19
|
+
contextWindow: 1000000,
|
|
20
|
+
maxTokens: 8192,
|
|
21
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
22
|
+
},
|
|
23
|
+
"gemini-2.0-flash": {
|
|
24
|
+
contextWindow: 1000000,
|
|
25
|
+
maxTokens: 8192,
|
|
26
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
27
|
+
},
|
|
28
|
+
"gemini-2.0-pro": {
|
|
29
|
+
contextWindow: 1000000,
|
|
30
|
+
maxTokens: 8192,
|
|
31
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
32
|
+
},
|
|
33
|
+
// ═══════════════════════════════════════════════════════════════
|
|
34
|
+
// Anthropic Claude - 200K Context
|
|
35
|
+
// ═══════════════════════════════════════════════════════════════
|
|
36
|
+
"claude-3-opus-20240229": {
|
|
37
|
+
contextWindow: 200000,
|
|
38
|
+
maxTokens: 4096,
|
|
39
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
40
|
+
},
|
|
41
|
+
"claude-3-sonnet-20240229": {
|
|
42
|
+
contextWindow: 200000,
|
|
43
|
+
maxTokens: 4096,
|
|
44
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
45
|
+
},
|
|
46
|
+
"claude-3-haiku-20240307": {
|
|
47
|
+
contextWindow: 200000,
|
|
48
|
+
maxTokens: 4096,
|
|
49
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
50
|
+
},
|
|
51
|
+
"claude-3-5-sonnet-20241022": {
|
|
52
|
+
contextWindow: 200000,
|
|
53
|
+
maxTokens: 8192,
|
|
54
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
55
|
+
},
|
|
56
|
+
"claude-3-5-haiku-20241022": {
|
|
57
|
+
contextWindow: 200000,
|
|
58
|
+
maxTokens: 8192,
|
|
59
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
60
|
+
},
|
|
61
|
+
"claude-sonnet-4-20250514": {
|
|
62
|
+
contextWindow: 200000,
|
|
63
|
+
maxTokens: 16384,
|
|
64
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
65
|
+
},
|
|
66
|
+
// ═══════════════════════════════════════════════════════════════
|
|
67
|
+
// OpenAI - 128K Context
|
|
68
|
+
// ═══════════════════════════════════════════════════════════════
|
|
69
|
+
"gpt-4-turbo": {
|
|
70
|
+
contextWindow: 128000,
|
|
71
|
+
maxTokens: 4096,
|
|
72
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
73
|
+
},
|
|
74
|
+
"gpt-4-turbo-preview": {
|
|
75
|
+
contextWindow: 128000,
|
|
76
|
+
maxTokens: 4096,
|
|
77
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
78
|
+
},
|
|
79
|
+
"gpt-4o": {
|
|
80
|
+
contextWindow: 128000,
|
|
81
|
+
maxTokens: 16384,
|
|
82
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
83
|
+
},
|
|
84
|
+
"gpt-4o-mini": {
|
|
85
|
+
contextWindow: 128000,
|
|
86
|
+
maxTokens: 16384,
|
|
87
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
88
|
+
},
|
|
89
|
+
"gpt-4-0125-preview": {
|
|
90
|
+
contextWindow: 128000,
|
|
91
|
+
maxTokens: 4096,
|
|
92
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
93
|
+
},
|
|
94
|
+
// ═══════════════════════════════════════════════════════════════
|
|
95
|
+
// DeepSeek - 64K Context
|
|
96
|
+
// ═══════════════════════════════════════════════════════════════
|
|
97
|
+
"deepseek-chat": {
|
|
98
|
+
contextWindow: 64000,
|
|
99
|
+
maxTokens: 4096,
|
|
100
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
101
|
+
},
|
|
102
|
+
"deepseek-coder": {
|
|
103
|
+
contextWindow: 64000,
|
|
104
|
+
maxTokens: 4096,
|
|
105
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
106
|
+
},
|
|
107
|
+
"deepseek-reasoner": {
|
|
108
|
+
contextWindow: 64000,
|
|
109
|
+
maxTokens: 8192,
|
|
110
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
111
|
+
},
|
|
112
|
+
// ═══════════════════════════════════════════════════════════════
|
|
113
|
+
// Alibaba Qwen - Up to 1M Context
|
|
114
|
+
// ═══════════════════════════════════════════════════════════════
|
|
115
|
+
"qwen-2.5-72b-instruct": {
|
|
116
|
+
contextWindow: 131072,
|
|
117
|
+
maxTokens: 8192,
|
|
118
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
119
|
+
},
|
|
120
|
+
"qwen-2.5-32b-instruct": {
|
|
121
|
+
contextWindow: 131072,
|
|
122
|
+
maxTokens: 8192,
|
|
123
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
124
|
+
},
|
|
125
|
+
"qwen-max": {
|
|
126
|
+
contextWindow: 1000000,
|
|
127
|
+
maxTokens: 65536,
|
|
128
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
129
|
+
},
|
|
130
|
+
"qwen-max-longcontext": {
|
|
131
|
+
contextWindow: 1000000,
|
|
132
|
+
maxTokens: 65536,
|
|
133
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
134
|
+
},
|
|
135
|
+
// ═══════════════════════════════════════════════════════════════
|
|
136
|
+
// Moonshot Kimi - Up to 128K Context
|
|
137
|
+
// ═══════════════════════════════════════════════════════════════
|
|
138
|
+
"moonshot-v1-8k": {
|
|
139
|
+
contextWindow: 8192,
|
|
140
|
+
maxTokens: 4096,
|
|
141
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
142
|
+
},
|
|
143
|
+
"moonshot-v1-32k": {
|
|
144
|
+
contextWindow: 32768,
|
|
145
|
+
maxTokens: 4096,
|
|
146
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
147
|
+
},
|
|
148
|
+
"moonshot-v1-128k": {
|
|
149
|
+
contextWindow: 131072,
|
|
150
|
+
maxTokens: 4096,
|
|
151
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
152
|
+
},
|
|
153
|
+
// ═══════════════════════════════════════════════════════════════
|
|
154
|
+
// Meta Llama 3.1 - 128K Context
|
|
155
|
+
// ═══════════════════════════════════════════════════════════════
|
|
156
|
+
"llama-3.1-405b-instruct": {
|
|
157
|
+
contextWindow: 128000,
|
|
158
|
+
maxTokens: 16384,
|
|
159
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
160
|
+
},
|
|
161
|
+
"llama-3.1-70b-instruct": {
|
|
162
|
+
contextWindow: 128000,
|
|
163
|
+
maxTokens: 16384,
|
|
164
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
165
|
+
},
|
|
166
|
+
"llama-3.1-8b-instruct": {
|
|
167
|
+
contextWindow: 128000,
|
|
168
|
+
maxTokens: 16384,
|
|
169
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
170
|
+
},
|
|
171
|
+
// ═══════════════════════════════════════════════════════════════
|
|
172
|
+
// Mistral - Up to 128K Context
|
|
173
|
+
// ═══════════════════════════════════════════════════════════════
|
|
174
|
+
"mistral-large-2407": {
|
|
175
|
+
contextWindow: 128000,
|
|
176
|
+
maxTokens: 8192,
|
|
177
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
178
|
+
},
|
|
179
|
+
"mistral-large-2402": {
|
|
180
|
+
contextWindow: 32000,
|
|
181
|
+
maxTokens: 8192,
|
|
182
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
183
|
+
},
|
|
184
|
+
// ═══════════════════════════════════════════════════════════════
|
|
185
|
+
// 01.AI Yi - Up to 32K Context
|
|
186
|
+
// ═══════════════════════════════════════════════════════════════
|
|
187
|
+
"yi-lightning": {
|
|
188
|
+
contextWindow: 16384,
|
|
189
|
+
maxTokens: 4096,
|
|
190
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
191
|
+
},
|
|
192
|
+
"yi-large": {
|
|
193
|
+
contextWindow: 32768,
|
|
194
|
+
maxTokens: 4096,
|
|
195
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
196
|
+
},
|
|
197
|
+
// ═══════════════════════════════════════════════════════════════
|
|
198
|
+
// Zhipu GLM - 128K Context
|
|
199
|
+
// ═══════════════════════════════════════════════════════════════
|
|
200
|
+
"glm-4": {
|
|
201
|
+
contextWindow: 128000,
|
|
202
|
+
maxTokens: 4096,
|
|
203
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
204
|
+
},
|
|
205
|
+
"glm-4-plus": {
|
|
206
|
+
contextWindow: 128000,
|
|
207
|
+
maxTokens: 4096,
|
|
208
|
+
capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
|
|
209
|
+
},
|
|
210
|
+
// ═══════════════════════════════════════════════════════════════
|
|
211
|
+
// Groq Models - Varies
|
|
212
|
+
// ═══════════════════════════════════════════════════════════════
|
|
213
|
+
"llama-3.3-70b-versatile": {
|
|
214
|
+
contextWindow: 128000,
|
|
215
|
+
maxTokens: 8192,
|
|
216
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
|
|
217
|
+
},
|
|
218
|
+
"llama-3.3-70b-specdec": {
|
|
219
|
+
contextWindow: 8192,
|
|
220
|
+
maxTokens: 8192,
|
|
221
|
+
capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: false },
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Large Context Provider
|
|
226
|
+
* Implements the IContextProvider interface for 1M context support
|
|
227
|
+
*/
|
|
228
|
+
export class LargeContextProvider {
|
|
229
|
+
name = "large-context";
|
|
230
|
+
version = "1.0.0";
|
|
231
|
+
customModels = new Map();
|
|
232
|
+
/**
|
|
233
|
+
* Check if this provider supports a given model
|
|
234
|
+
*/
|
|
235
|
+
supportsModel(modelId) {
|
|
236
|
+
const normalized = this.normalizeModelId(modelId);
|
|
237
|
+
return normalized in LARGE_CONTEXT_DEFINITIONS || this.customModels.has(normalized);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get context window for a model
|
|
241
|
+
*/
|
|
242
|
+
getContextWindow(modelId) {
|
|
243
|
+
return this.getContextConfig(modelId).contextWindow;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Get max output tokens for a model
|
|
247
|
+
*/
|
|
248
|
+
getMaxTokens(modelId) {
|
|
249
|
+
return this.getContextConfig(modelId).maxTokens;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Get full context configuration for a model
|
|
253
|
+
*/
|
|
254
|
+
getContextConfig(modelId) {
|
|
255
|
+
const normalized = this.normalizeModelId(modelId);
|
|
256
|
+
// Check custom models first
|
|
257
|
+
const custom = this.customModels.get(normalized);
|
|
258
|
+
if (custom) {
|
|
259
|
+
return {
|
|
260
|
+
contextWindow: custom.contextWindow,
|
|
261
|
+
maxTokens: custom.maxTokens,
|
|
262
|
+
supportsStreaming: custom.capabilities.supportsStreaming,
|
|
263
|
+
supportsVision: custom.capabilities.supportsVision,
|
|
264
|
+
supportsFunctions: custom.capabilities.supportsFunctions,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
// Check known models
|
|
268
|
+
const definition = LARGE_CONTEXT_DEFINITIONS[normalized];
|
|
269
|
+
if (definition) {
|
|
270
|
+
return {
|
|
271
|
+
contextWindow: definition.contextWindow,
|
|
272
|
+
maxTokens: definition.maxTokens,
|
|
273
|
+
supportsStreaming: definition.capabilities.supportsStreaming,
|
|
274
|
+
supportsVision: definition.capabilities.supportsVision,
|
|
275
|
+
supportsFunctions: definition.capabilities.supportsFunctions,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
// Default: 1M context for unknown models
|
|
279
|
+
return {
|
|
280
|
+
contextWindow: 1000000,
|
|
281
|
+
maxTokens: 65536,
|
|
282
|
+
supportsStreaming: true,
|
|
283
|
+
supportsVision: true,
|
|
284
|
+
supportsFunctions: true,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Process messages before sending to API
|
|
289
|
+
*/
|
|
290
|
+
processMessages(messages, modelId) {
|
|
291
|
+
const config = this.getContextConfig(modelId);
|
|
292
|
+
const messageStr = JSON.stringify(messages);
|
|
293
|
+
const estimatedTokens = Math.ceil(messageStr.length / 4);
|
|
294
|
+
return {
|
|
295
|
+
messages,
|
|
296
|
+
tokenCount: estimatedTokens,
|
|
297
|
+
modified: false,
|
|
298
|
+
metadata: {
|
|
299
|
+
truncated: estimatedTokens > config.contextWindow,
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Handle context overflow
|
|
305
|
+
*/
|
|
306
|
+
handleOverflow(messages, modelId, tokenCount) {
|
|
307
|
+
const config = this.getContextConfig(modelId);
|
|
308
|
+
if (tokenCount <= config.contextWindow) {
|
|
309
|
+
return { action: "truncate", messages };
|
|
310
|
+
}
|
|
311
|
+
// For large context models, try to keep as much as possible
|
|
312
|
+
if (config.contextWindow >= 100000) {
|
|
313
|
+
// For 1M context, we likely have enough space
|
|
314
|
+
return {
|
|
315
|
+
action: "truncate",
|
|
316
|
+
messages,
|
|
317
|
+
metadata: {
|
|
318
|
+
originalTokens: tokenCount,
|
|
319
|
+
contextWindow: config.contextWindow,
|
|
320
|
+
keepRatio: config.contextWindow / tokenCount,
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
action: "summarize",
|
|
326
|
+
metadata: {
|
|
327
|
+
originalTokens: tokenCount,
|
|
328
|
+
contextWindow: config.contextWindow,
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Register a custom model with context configuration
|
|
334
|
+
*/
|
|
335
|
+
registerCustomModel(modelId, config) {
|
|
336
|
+
const normalized = this.normalizeModelId(modelId);
|
|
337
|
+
this.customModels.set(normalized, {
|
|
338
|
+
contextWindow: config.contextWindow,
|
|
339
|
+
maxTokens: config.maxTokens,
|
|
340
|
+
capabilities: {
|
|
341
|
+
supportsStreaming: true,
|
|
342
|
+
supportsVision: config.supportsVision ?? true,
|
|
343
|
+
supportsFunctions: config.supportsFunctions ?? true,
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Enhance a model with large context configuration
|
|
349
|
+
*/
|
|
350
|
+
enhanceModel(model) {
|
|
351
|
+
const config = this.getContextConfig(model.id);
|
|
352
|
+
return {
|
|
353
|
+
...model,
|
|
354
|
+
contextWindow: config.contextWindow,
|
|
355
|
+
maxTokens: config.maxTokens,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Get all known large context models
|
|
360
|
+
*/
|
|
361
|
+
getKnownModels() {
|
|
362
|
+
return Object.keys(LARGE_CONTEXT_DEFINITIONS);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Check if a model has 1M context
|
|
366
|
+
*/
|
|
367
|
+
isMillionContextModel(modelId) {
|
|
368
|
+
const config = this.getContextConfig(modelId);
|
|
369
|
+
return config.contextWindow >= 1000000;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Normalize model ID for matching
|
|
373
|
+
*/
|
|
374
|
+
normalizeModelId(modelId) {
|
|
375
|
+
return modelId.toLowerCase().trim();
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Singleton instance
|
|
380
|
+
*/
|
|
381
|
+
let largeContextProviderInstance = null;
|
|
382
|
+
/**
|
|
383
|
+
* Get the singleton instance
|
|
384
|
+
*/
|
|
385
|
+
export function getLargeContextProvider() {
|
|
386
|
+
if (!largeContextProviderInstance) {
|
|
387
|
+
largeContextProviderInstance = new LargeContextProvider();
|
|
388
|
+
}
|
|
389
|
+
return largeContextProviderInstance;
|
|
390
|
+
}
|
|
391
|
+
//# sourceMappingURL=large-context-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"large-context-provider.js","sourceRoot":"","sources":["../../src/core/large-context-provider.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Large Context Provider Implementation\n * Provides 1M context window support for compatible models\n * This is a third-party architecture implementation\n */\n\nimport type { Api, Model } from \"@mariozechner/pi-ai\";\nimport type {\n\tIContextProvider,\n\tIModelContextConfig,\n\tIOverflowResult,\n\tIProcessedContext,\n} from \"./context-provider-interface.js\";\n\n/**\n * Model capability flags\n */\ninterface ModelCapabilities {\n\tsupportsStreaming: boolean;\n\tsupportsVision: boolean;\n\tsupportsFunctions: boolean;\n}\n\n/**\n * Large context model definitions\n */\nexport const LARGE_CONTEXT_DEFINITIONS: Record<\n\tstring,\n\t{\n\t\tcontextWindow: number;\n\t\tmaxTokens: number;\n\t\tcapabilities: ModelCapabilities;\n\t}\n> = {\n\t// ═══════════════════════════════════════════════════════════════\n\t// Google Gemini - 1M Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"gemini-1.5-pro\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gemini-1.5-flash\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gemini-2.0-flash\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gemini-2.0-pro\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Anthropic Claude - 200K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"claude-3-opus-20240229\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"claude-3-sonnet-20240229\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"claude-3-haiku-20240307\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"claude-3-5-sonnet-20241022\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"claude-3-5-haiku-20241022\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"claude-sonnet-4-20250514\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// OpenAI - 128K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"gpt-4-turbo\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gpt-4-turbo-preview\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"gpt-4o\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gpt-4o-mini\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gpt-4-0125-preview\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// DeepSeek - 64K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"deepseek-chat\": {\n\t\tcontextWindow: 64000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"deepseek-coder\": {\n\t\tcontextWindow: 64000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"deepseek-reasoner\": {\n\t\tcontextWindow: 64000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Alibaba Qwen - Up to 1M Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"qwen-2.5-72b-instruct\": {\n\t\tcontextWindow: 131072,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"qwen-2.5-32b-instruct\": {\n\t\tcontextWindow: 131072,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"qwen-max\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 65536,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"qwen-max-longcontext\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 65536,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Moonshot Kimi - Up to 128K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"moonshot-v1-8k\": {\n\t\tcontextWindow: 8192,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"moonshot-v1-32k\": {\n\t\tcontextWindow: 32768,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"moonshot-v1-128k\": {\n\t\tcontextWindow: 131072,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Meta Llama 3.1 - 128K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"llama-3.1-405b-instruct\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"llama-3.1-70b-instruct\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"llama-3.1-8b-instruct\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Mistral - Up to 128K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"mistral-large-2407\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"mistral-large-2402\": {\n\t\tcontextWindow: 32000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// 01.AI Yi - Up to 32K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"yi-lightning\": {\n\t\tcontextWindow: 16384,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"yi-large\": {\n\t\tcontextWindow: 32768,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Zhipu GLM - 128K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"glm-4\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"glm-4-plus\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Groq Models - Varies\n\t// ═══════════════════════════════════════════════════════════════\n\t\"llama-3.3-70b-versatile\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"llama-3.3-70b-specdec\": {\n\t\tcontextWindow: 8192,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: false },\n\t},\n};\n\n/**\n * Large Context Provider\n * Implements the IContextProvider interface for 1M context support\n */\nexport class LargeContextProvider implements IContextProvider {\n\treadonly name = \"large-context\";\n\treadonly version = \"1.0.0\";\n\n\tprivate customModels: Map<string, { contextWindow: number; maxTokens: number; capabilities: ModelCapabilities }> =\n\t\tnew Map();\n\n\t/**\n\t * Check if this provider supports a given model\n\t */\n\tsupportsModel(modelId: string): boolean {\n\t\tconst normalized = this.normalizeModelId(modelId);\n\t\treturn normalized in LARGE_CONTEXT_DEFINITIONS || this.customModels.has(normalized);\n\t}\n\n\t/**\n\t * Get context window for a model\n\t */\n\tgetContextWindow(modelId: string): number {\n\t\treturn this.getContextConfig(modelId).contextWindow;\n\t}\n\n\t/**\n\t * Get max output tokens for a model\n\t */\n\tgetMaxTokens(modelId: string): number {\n\t\treturn this.getContextConfig(modelId).maxTokens;\n\t}\n\n\t/**\n\t * Get full context configuration for a model\n\t */\n\tgetContextConfig(modelId: string): IModelContextConfig {\n\t\tconst normalized = this.normalizeModelId(modelId);\n\n\t\t// Check custom models first\n\t\tconst custom = this.customModels.get(normalized);\n\t\tif (custom) {\n\t\t\treturn {\n\t\t\t\tcontextWindow: custom.contextWindow,\n\t\t\t\tmaxTokens: custom.maxTokens,\n\t\t\t\tsupportsStreaming: custom.capabilities.supportsStreaming,\n\t\t\t\tsupportsVision: custom.capabilities.supportsVision,\n\t\t\t\tsupportsFunctions: custom.capabilities.supportsFunctions,\n\t\t\t};\n\t\t}\n\n\t\t// Check known models\n\t\tconst definition = LARGE_CONTEXT_DEFINITIONS[normalized];\n\t\tif (definition) {\n\t\t\treturn {\n\t\t\t\tcontextWindow: definition.contextWindow,\n\t\t\t\tmaxTokens: definition.maxTokens,\n\t\t\t\tsupportsStreaming: definition.capabilities.supportsStreaming,\n\t\t\t\tsupportsVision: definition.capabilities.supportsVision,\n\t\t\t\tsupportsFunctions: definition.capabilities.supportsFunctions,\n\t\t\t};\n\t\t}\n\n\t\t// Default: 1M context for unknown models\n\t\treturn {\n\t\t\tcontextWindow: 1000000,\n\t\t\tmaxTokens: 65536,\n\t\t\tsupportsStreaming: true,\n\t\t\tsupportsVision: true,\n\t\t\tsupportsFunctions: true,\n\t\t};\n\t}\n\n\t/**\n\t * Process messages before sending to API\n\t */\n\tprocessMessages(messages: unknown[], modelId: string): IProcessedContext {\n\t\tconst config = this.getContextConfig(modelId);\n\t\tconst messageStr = JSON.stringify(messages);\n\t\tconst estimatedTokens = Math.ceil(messageStr.length / 4);\n\n\t\treturn {\n\t\t\tmessages,\n\t\t\ttokenCount: estimatedTokens,\n\t\t\tmodified: false,\n\t\t\tmetadata: {\n\t\t\t\ttruncated: estimatedTokens > config.contextWindow,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Handle context overflow\n\t */\n\thandleOverflow(messages: unknown[], modelId: string, tokenCount: number): IOverflowResult {\n\t\tconst config = this.getContextConfig(modelId);\n\n\t\tif (tokenCount <= config.contextWindow) {\n\t\t\treturn { action: \"truncate\", messages };\n\t\t}\n\n\t\t// For large context models, try to keep as much as possible\n\t\tif (config.contextWindow >= 100000) {\n\t\t\t// For 1M context, we likely have enough space\n\t\t\treturn {\n\t\t\t\taction: \"truncate\",\n\t\t\t\tmessages,\n\t\t\t\tmetadata: {\n\t\t\t\t\toriginalTokens: tokenCount,\n\t\t\t\t\tcontextWindow: config.contextWindow,\n\t\t\t\t\tkeepRatio: config.contextWindow / tokenCount,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\taction: \"summarize\",\n\t\t\tmetadata: {\n\t\t\t\toriginalTokens: tokenCount,\n\t\t\t\tcontextWindow: config.contextWindow,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Register a custom model with context configuration\n\t */\n\tregisterCustomModel(\n\t\tmodelId: string,\n\t\tconfig: {\n\t\t\tcontextWindow: number;\n\t\t\tmaxTokens: number;\n\t\t\tsupportsVision?: boolean;\n\t\t\tsupportsFunctions?: boolean;\n\t\t},\n\t): void {\n\t\tconst normalized = this.normalizeModelId(modelId);\n\t\tthis.customModels.set(normalized, {\n\t\t\tcontextWindow: config.contextWindow,\n\t\t\tmaxTokens: config.maxTokens,\n\t\t\tcapabilities: {\n\t\t\t\tsupportsStreaming: true,\n\t\t\t\tsupportsVision: config.supportsVision ?? true,\n\t\t\t\tsupportsFunctions: config.supportsFunctions ?? true,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Enhance a model with large context configuration\n\t */\n\tenhanceModel<API extends Api>(model: Model<API>): Model<API> {\n\t\tconst config = this.getContextConfig(model.id);\n\n\t\treturn {\n\t\t\t...model,\n\t\t\tcontextWindow: config.contextWindow,\n\t\t\tmaxTokens: config.maxTokens,\n\t\t};\n\t}\n\n\t/**\n\t * Get all known large context models\n\t */\n\tgetKnownModels(): string[] {\n\t\treturn Object.keys(LARGE_CONTEXT_DEFINITIONS);\n\t}\n\n\t/**\n\t * Check if a model has 1M context\n\t */\n\tisMillionContextModel(modelId: string): boolean {\n\t\tconst config = this.getContextConfig(modelId);\n\t\treturn config.contextWindow >= 1000000;\n\t}\n\n\t/**\n\t * Normalize model ID for matching\n\t */\n\tprivate normalizeModelId(modelId: string): string {\n\t\treturn modelId.toLowerCase().trim();\n\t}\n}\n\n/**\n * Singleton instance\n */\nlet largeContextProviderInstance: LargeContextProvider | null = null;\n\n/**\n * Get the singleton instance\n */\nexport function getLargeContextProvider(): LargeContextProvider {\n\tif (!largeContextProviderInstance) {\n\t\tlargeContextProviderInstance = new LargeContextProvider();\n\t}\n\treturn largeContextProviderInstance;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AA6C3D,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AACD,MAAM,WAAW,KAAK;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,OAAO,CAAC;CAChC;AACD,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,WAAW,EAAE,kBAAkB,EAAE,CAAC;CAClC;AA6BD,MAAM,WAAW,wBAAwB;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CACf;AACD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,gBAAgB,CAGrF;AAwGD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAqB7D;AASD,MAAM,WAAW,iBAAiB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAYD,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAyF5E","sourcesContent":["import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from \"fs\";\nimport ignore from \"ignore\";\nimport { homedir } from \"os\";\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.js\";\nimport { parseFrontmatter } from \"../utils/frontmatter.js\";\nimport type { ResourceDiagnostic } from \"./diagnostics.js\";\n\nconst MAX_NAME_LENGTH = 64;\nconst MAX_DESCRIPTION_LENGTH = 1024;\nconst IGNORE_FILE_NAMES = [\".gitignore\", \".ignore\", \".fdignore\"];\ntype IgnoreMatcher = ReturnType<typeof ignore>;\nfunction toPosixPath(p: string): string {\n\treturn p.split(sep).join(\"/\");\n}\nfunction prefixIgnorePattern(line: string, prefix: string): string | null {\n\tconst trimmed = line.trim();\n\tif (!trimmed) return null;\n\tif (trimmed.startsWith(\"#\") && !trimmed.startsWith(\"\\\\#\")) return null;\n\tlet pattern = line;\n\tlet negated = false;\n\tif (pattern.startsWith(\"!\")) {\n\t\tnegated = true;\n\t\tpattern = pattern.slice(1);\n\t} else if (pattern.startsWith(\"\\\\!\")) {\n\t\tpattern = pattern.slice(1);\n\t}\n\tif (pattern.startsWith(\"/\")) {\n\t\tpattern = pattern.slice(1);\n\t}\n\tconst prefixed = prefix ? `${prefix}${pattern}` : pattern;\n\treturn negated ? `!${prefixed}` : prefixed;\n}\nfunction addIgnoreRules(ig: IgnoreMatcher, dir: string, rootDir: string): void {\n\tconst relativeDir = relative(rootDir, dir);\n\tconst prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : \"\";\n\tfor (const filename of IGNORE_FILE_NAMES) {\n\t\tconst ignorePath = join(dir, filename);\n\t\tif (!existsSync(ignorePath)) continue;\n\t\ttry {\n\t\t\tconst content = readFileSync(ignorePath, \"utf-8\");\n\t\t\tconst patterns = content\n\t\t\t\t.split(/\\r?\\n/)\n\t\t\t\t.map((line) => prefixIgnorePattern(line, prefix))\n\t\t\t\t.filter((line): line is string => Boolean(line));\n\t\t\tif (patterns.length > 0) {\n\t\t\t\tig.add(patterns);\n\t\t\t}\n\t\t} catch {}\n\t}\n}\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\n\t\"disable-model-invocation\"?: boolean;\n\t[key: string]: unknown;\n}\nexport interface Skill {\n\tname: string;\n\tdescription: string;\n\tfilePath: string;\n\tbaseDir: string;\n\tsource: string;\n\tdisableModelInvocation: boolean;\n}\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\tdiagnostics: ResourceDiagnostic[];\n}\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\tif (!/^[a-z0-9-]+$/.test(name)) {\n\t\terrors.push(`name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)`);\n\t}\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\treturn errors;\n}\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\tif (!description || description.trim() === \"\") {\n\t\terrors.push(\"description is required\");\n\t} else if (description.length > MAX_DESCRIPTION_LENGTH) {\n\t\terrors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n\t}\n\treturn errors;\n}\nexport interface LoadSkillsFromDirOptions {\n\tdir: string;\n\tsource: string;\n}\nexport function loadSkillsFromDir(options: LoadSkillsFromDirOptions): LoadSkillsResult {\n\tconst { dir, source } = options;\n\treturn loadSkillsFromDirInternal(dir, source, true);\n}\nfunction loadSkillsFromDirInternal(\n\tdir: string,\n\tsource: string,\n\tincludeRootFiles: boolean,\n\tignoreMatcher?: IgnoreMatcher,\n\trootDir?: string,\n): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst diagnostics: ResourceDiagnostic[] = [];\n\tif (!existsSync(dir)) {\n\t\treturn { skills, diagnostics };\n\t}\n\tconst root = rootDir ?? dir;\n\tconst ig = ignoreMatcher ?? ignore();\n\taddIgnoreRules(ig, dir, root);\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.name.startsWith(\".\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (entry.name === \"node_modules\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tlet isDirectory = entry.isDirectory();\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisDirectory = stats.isDirectory();\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst relPath = toPosixPath(relative(root, fullPath));\n\t\t\tconst ignorePath = isDirectory ? `${relPath}/` : relPath;\n\t\t\tif (ig.ignores(ignorePath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (isDirectory) {\n\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, source, false, ig, root);\n\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\tdiagnostics.push(...subResult.diagnostics);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!isFile) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst isRootMd = includeRootFiles && entry.name.endsWith(\".md\");\n\t\t\tconst isSkillMd = !includeRootFiles && entry.name === \"SKILL.md\";\n\t\t\tif (!isRootMd && !isSkillMd) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst result = loadSkillFromFile(fullPath, source);\n\t\t\tif (result.skill) {\n\t\t\t\tskills.push(result.skill);\n\t\t\t}\n\t\t\tdiagnostics.push(...result.diagnostics);\n\t\t}\n\t} catch {}\n\treturn { skills, diagnostics };\n}\nfunction loadSkillFromFile(\n\tfilePath: string,\n\tsource: string,\n): { skill: Skill | null; diagnostics: ResourceDiagnostic[] } {\n\tconst diagnostics: ResourceDiagnostic[] = [];\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter } = parseFrontmatter<SkillFrontmatter>(rawContent);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\t\tconst name = frontmatter.name || parentDirName;\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, diagnostics };\n\t\t}\n\t\treturn {\n\t\t\tskill: {\n\t\t\t\tname,\n\t\t\t\tdescription: frontmatter.description,\n\t\t\t\tfilePath,\n\t\t\t\tbaseDir: skillDir,\n\t\t\t\tsource,\n\t\t\t\tdisableModelInvocation: frontmatter[\"disable-model-invocation\"] === true,\n\t\t\t},\n\t\t\tdiagnostics,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : \"failed to parse skill file\";\n\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\treturn { skill: null, diagnostics };\n\t}\n}\nexport function formatSkillsForPrompt(skills: Skill[]): string {\n\tconst visibleSkills = skills.filter((s) => !s.disableModelInvocation);\n\tif (visibleSkills.length === 0) {\n\t\treturn \"\";\n\t}\n\tconst lines = [\n\t\t\"\\n\\nThe following skills provide specialized instructions for specific tasks.\",\n\t\t\"Use the read tool to load a skill's file when the task matches its description.\",\n\t\t\"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\",\n\t\t\"\",\n\t\t\"<available_skills>\",\n\t];\n\tfor (const skill of visibleSkills) {\n\t\tlines.push(\" <skill>\");\n\t\tlines.push(` <name>${escapeXml(skill.name)}</name>`);\n\t\tlines.push(` <description>${escapeXml(skill.description)}</description>`);\n\t\tlines.push(` <location>${escapeXml(skill.filePath)}</location>`);\n\t\tlines.push(\" </skill>\");\n\t}\n\tlines.push(\"</available_skills>\");\n\treturn lines.join(\"\\n\");\n}\nfunction escapeXml(str: string): string {\n\treturn str\n\t\t.replace(/&/g, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/\"/g, \""\")\n\t\t.replace(/'/g, \"'\");\n}\nexport interface LoadSkillsOptions {\n\tcwd?: string;\n\tagentDir?: string;\n\tskillPaths?: string[];\n\tincludeDefaults?: boolean;\n}\nfunction normalizePath(input: string): string {\n\tconst trimmed = input.trim();\n\tif (trimmed === \"~\") return homedir();\n\tif (trimmed.startsWith(\"~/\")) return join(homedir(), trimmed.slice(2));\n\tif (trimmed.startsWith(\"~\")) return join(homedir(), trimmed.slice(1));\n\treturn trimmed;\n}\nfunction resolveSkillPath(p: string, cwd: string): string {\n\tconst normalized = normalizePath(p);\n\treturn isAbsolute(normalized) ? normalized : resolve(cwd, normalized);\n}\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst { cwd = process.cwd(), agentDir, skillPaths = [], includeDefaults = true } = options;\n\tconst resolvedAgentDir = agentDir ?? getAgentDir();\n\tconst skillMap = new Map<string, Skill>();\n\tconst realPathSet = new Set<string>();\n\tconst allDiagnostics: ResourceDiagnostic[] = [];\n\tconst collisionDiagnostics: ResourceDiagnostic[] = [];\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallDiagnostics.push(...result.diagnostics);\n\t\tfor (const skill of result.skills) {\n\t\t\tlet realPath: string;\n\t\t\ttry {\n\t\t\t\trealPath = realpathSync(skill.filePath);\n\t\t\t} catch {\n\t\t\t\trealPath = skill.filePath;\n\t\t\t}\n\t\t\tif (realPathSet.has(realPath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionDiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${skill.name}\" collision`,\n\t\t\t\t\tpath: skill.filePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"skill\",\n\t\t\t\t\t\tname: skill.name,\n\t\t\t\t\t\twinnerPath: existing.filePath,\n\t\t\t\t\t\tloserPath: skill.filePath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t\trealPathSet.add(realPath);\n\t\t\t}\n\t\t}\n\t}\n\tif (includeDefaults) {\n\t\taddSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, \"skills\"), \"user\", true));\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, \"skills\"), \"project\", true));\n\t}\n\tconst userSkillsDir = join(resolvedAgentDir, \"skills\");\n\tconst projectSkillsDir = resolve(cwd, CONFIG_DIR_NAME, \"skills\");\n\tconst isUnderPath = (target: string, root: string): boolean => {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t};\n\tconst getSource = (resolvedPath: string): \"user\" | \"project\" | \"path\" => {\n\t\tif (!includeDefaults) {\n\t\t\tif (isUnderPath(resolvedPath, userSkillsDir)) return \"user\";\n\t\t\tif (isUnderPath(resolvedPath, projectSkillsDir)) return \"project\";\n\t\t}\n\t\treturn \"path\";\n\t};\n\tfor (const rawPath of skillPaths) {\n\t\tconst resolvedPath = resolveSkillPath(rawPath, cwd);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path does not exist\", path: resolvedPath });\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tconst source = getSource(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(resolvedPath, source, true));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\tconst result = loadSkillFromFile(resolvedPath, source);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\taddSkills({ skills: [result.skill], diagnostics: result.diagnostics });\n\t\t\t\t} else {\n\t\t\t\t\tallDiagnostics.push(...result.diagnostics);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path is not a markdown file\", path: resolvedPath });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read skill path\";\n\t\t\tallDiagnostics.push({ type: \"warning\", message, path: resolvedPath });\n\t\t}\n\t}\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\tdiagnostics: [...allDiagnostics, ...collisionDiagnostics],\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAwE3D,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AACD,MAAM,WAAW,KAAK;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,OAAO,CAAC;CAChC;AACD,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,WAAW,EAAE,kBAAkB,EAAE,CAAC;CAClC;AA6BD,MAAM,WAAW,wBAAwB;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CACf;AACD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,gBAAgB,CAGrF;AAwGD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAkC7D;AASD,MAAM,WAAW,iBAAiB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAYD,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAmG5E","sourcesContent":["import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from \"fs\";\nimport ignore from \"ignore\";\nimport { homedir } from \"os\";\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.js\";\nimport { parseFrontmatter } from \"../utils/frontmatter.js\";\nimport type { ResourceDiagnostic } from \"./diagnostics.js\";\n\nconst MAX_NAME_LENGTH = 64;\nconst MAX_DESCRIPTION_LENGTH = 1024;\nconst IGNORE_FILE_NAMES = [\".gitignore\", \".ignore\", \".fdignore\"];\ntype IgnoreMatcher = ReturnType<typeof ignore>;\n\n/**\n * Get all global skill directories to search.\n * Returns paths in priority order (first found wins).\n */\nfunction getGlobalSkillPaths(): Array<{ path: string; source: string }> {\n\tconst home = homedir();\n\treturn [\n\t\t{ path: join(home, CONFIG_DIR_NAME, \"skills\"), source: \"user\" }, // ~/.openvibe/skills\n\t\t{ path: join(home, \".agents\", \"skills\"), source: \"agents\" }, // ~/.agents/skills (Agent Skills standard)\n\t\t{ path: join(home, \".claude\", \"skills\"), source: \"claude\" }, // ~/.claude/skills (Claude compatibility)\n\t\t{ path: join(home, \".codex\", \"skills\"), source: \"codex\" }, // ~/.codex/skills (OpenAI Codex compatibility)\n\t];\n}\n\n/**\n * Get all project-level skill directories to search.\n * Returns paths in priority order.\n */\nfunction getProjectSkillPaths(cwd: string): Array<{ path: string; source: string }> {\n\treturn [\n\t\t{ path: resolve(cwd, CONFIG_DIR_NAME, \"skills\"), source: \"project\" }, // .openvibe/skills\n\t\t{ path: resolve(cwd, \".agents\", \"skills\"), source: \"project-agents\" }, // .agents/skills\n\t\t{ path: resolve(cwd, \".claude\", \"skills\"), source: \"project-claude\" }, // .claude/skills\n\t];\n}\n\nfunction toPosixPath(p: string): string {\n\treturn p.split(sep).join(\"/\");\n}\nfunction prefixIgnorePattern(line: string, prefix: string): string | null {\n\tconst trimmed = line.trim();\n\tif (!trimmed) return null;\n\tif (trimmed.startsWith(\"#\") && !trimmed.startsWith(\"\\\\#\")) return null;\n\tlet pattern = line;\n\tlet negated = false;\n\tif (pattern.startsWith(\"!\")) {\n\t\tnegated = true;\n\t\tpattern = pattern.slice(1);\n\t} else if (pattern.startsWith(\"\\\\!\")) {\n\t\tpattern = pattern.slice(1);\n\t}\n\tif (pattern.startsWith(\"/\")) {\n\t\tpattern = pattern.slice(1);\n\t}\n\tconst prefixed = prefix ? `${prefix}${pattern}` : pattern;\n\treturn negated ? `!${prefixed}` : prefixed;\n}\nfunction addIgnoreRules(ig: IgnoreMatcher, dir: string, rootDir: string): void {\n\tconst relativeDir = relative(rootDir, dir);\n\tconst prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : \"\";\n\tfor (const filename of IGNORE_FILE_NAMES) {\n\t\tconst ignorePath = join(dir, filename);\n\t\tif (!existsSync(ignorePath)) continue;\n\t\ttry {\n\t\t\tconst content = readFileSync(ignorePath, \"utf-8\");\n\t\t\tconst patterns = content\n\t\t\t\t.split(/\\r?\\n/)\n\t\t\t\t.map((line) => prefixIgnorePattern(line, prefix))\n\t\t\t\t.filter((line): line is string => Boolean(line));\n\t\t\tif (patterns.length > 0) {\n\t\t\t\tig.add(patterns);\n\t\t\t}\n\t\t} catch {}\n\t}\n}\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\n\t\"disable-model-invocation\"?: boolean;\n\t[key: string]: unknown;\n}\nexport interface Skill {\n\tname: string;\n\tdescription: string;\n\tfilePath: string;\n\tbaseDir: string;\n\tsource: string;\n\tdisableModelInvocation: boolean;\n}\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\tdiagnostics: ResourceDiagnostic[];\n}\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\tif (!/^[a-z0-9-]+$/.test(name)) {\n\t\terrors.push(`name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)`);\n\t}\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\treturn errors;\n}\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\tif (!description || description.trim() === \"\") {\n\t\terrors.push(\"description is required\");\n\t} else if (description.length > MAX_DESCRIPTION_LENGTH) {\n\t\terrors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n\t}\n\treturn errors;\n}\nexport interface LoadSkillsFromDirOptions {\n\tdir: string;\n\tsource: string;\n}\nexport function loadSkillsFromDir(options: LoadSkillsFromDirOptions): LoadSkillsResult {\n\tconst { dir, source } = options;\n\treturn loadSkillsFromDirInternal(dir, source, true);\n}\nfunction loadSkillsFromDirInternal(\n\tdir: string,\n\tsource: string,\n\tincludeRootFiles: boolean,\n\tignoreMatcher?: IgnoreMatcher,\n\trootDir?: string,\n): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst diagnostics: ResourceDiagnostic[] = [];\n\tif (!existsSync(dir)) {\n\t\treturn { skills, diagnostics };\n\t}\n\tconst root = rootDir ?? dir;\n\tconst ig = ignoreMatcher ?? ignore();\n\taddIgnoreRules(ig, dir, root);\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.name.startsWith(\".\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (entry.name === \"node_modules\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tlet isDirectory = entry.isDirectory();\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisDirectory = stats.isDirectory();\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst relPath = toPosixPath(relative(root, fullPath));\n\t\t\tconst ignorePath = isDirectory ? `${relPath}/` : relPath;\n\t\t\tif (ig.ignores(ignorePath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (isDirectory) {\n\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, source, false, ig, root);\n\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\tdiagnostics.push(...subResult.diagnostics);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!isFile) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst isRootMd = includeRootFiles && entry.name.endsWith(\".md\");\n\t\t\tconst isSkillMd = !includeRootFiles && entry.name === \"SKILL.md\";\n\t\t\tif (!isRootMd && !isSkillMd) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst result = loadSkillFromFile(fullPath, source);\n\t\t\tif (result.skill) {\n\t\t\t\tskills.push(result.skill);\n\t\t\t}\n\t\t\tdiagnostics.push(...result.diagnostics);\n\t\t}\n\t} catch {}\n\treturn { skills, diagnostics };\n}\nfunction loadSkillFromFile(\n\tfilePath: string,\n\tsource: string,\n): { skill: Skill | null; diagnostics: ResourceDiagnostic[] } {\n\tconst diagnostics: ResourceDiagnostic[] = [];\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter } = parseFrontmatter<SkillFrontmatter>(rawContent);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\t\tconst name = frontmatter.name || parentDirName;\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, diagnostics };\n\t\t}\n\t\treturn {\n\t\t\tskill: {\n\t\t\t\tname,\n\t\t\t\tdescription: frontmatter.description,\n\t\t\t\tfilePath,\n\t\t\t\tbaseDir: skillDir,\n\t\t\t\tsource,\n\t\t\t\tdisableModelInvocation: frontmatter[\"disable-model-invocation\"] === true,\n\t\t\t},\n\t\t\tdiagnostics,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : \"failed to parse skill file\";\n\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\treturn { skill: null, diagnostics };\n\t}\n}\nexport function formatSkillsForPrompt(skills: Skill[]): string {\n\tconst visibleSkills = skills.filter((s) => !s.disableModelInvocation);\n\tif (visibleSkills.length === 0) {\n\t\treturn \"\";\n\t}\n\tconst lines = [\n\t\t\"\\n\\n# Skills System\",\n\t\t\"\",\n\t\t\"Skills are specialized knowledge files that provide expert guidance for specific tasks.\",\n\t\t\"Each skill contains detailed instructions, best practices, and context for its domain.\",\n\t\t\"\",\n\t\t\"**How to use skills:**\",\n\t\t\"1. Review the available skills below to find one matching your current task\",\n\t\t\"2. Use the `read` tool to load the skill's full content from its location\",\n\t\t\"3. Apply the skill's guidance to your current task\",\n\t\t\"4. When a skill references relative paths, resolve them against the skill directory\",\n\t\t\"\",\n\t\t\"**Invoking a skill:**\",\n\t\t\"To load a skill, use: `read <location>` where location is the skill's file path\",\n\t\t\"\",\n\t\t\"<available_skills>\",\n\t];\n\tfor (const skill of visibleSkills) {\n\t\tlines.push(\" <skill>\");\n\t\tlines.push(` <name>${escapeXml(skill.name)}</name>`);\n\t\tlines.push(` <description>${escapeXml(skill.description)}</description>`);\n\t\tlines.push(` <location>${escapeXml(skill.filePath)}</location>`);\n\t\tlines.push(\" </skill>\");\n\t}\n\tlines.push(\"</available_skills>\");\n\tlines.push(\"\");\n\tlines.push(\"**Smart Skill Selection:**\");\n\tlines.push(\"Before responding to any task, consider if a skill could help. Skills provide domain expertise.\");\n\treturn lines.join(\"\\n\");\n}\nfunction escapeXml(str: string): string {\n\treturn str\n\t\t.replace(/&/g, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/\"/g, \""\")\n\t\t.replace(/'/g, \"'\");\n}\nexport interface LoadSkillsOptions {\n\tcwd?: string;\n\tagentDir?: string;\n\tskillPaths?: string[];\n\tincludeDefaults?: boolean;\n}\nfunction normalizePath(input: string): string {\n\tconst trimmed = input.trim();\n\tif (trimmed === \"~\") return homedir();\n\tif (trimmed.startsWith(\"~/\")) return join(homedir(), trimmed.slice(2));\n\tif (trimmed.startsWith(\"~\")) return join(homedir(), trimmed.slice(1));\n\treturn trimmed;\n}\nfunction resolveSkillPath(p: string, cwd: string): string {\n\tconst normalized = normalizePath(p);\n\treturn isAbsolute(normalized) ? normalized : resolve(cwd, normalized);\n}\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst { cwd = process.cwd(), agentDir, skillPaths = [], includeDefaults = true } = options;\n\tconst resolvedAgentDir = agentDir ?? getAgentDir();\n\tconst skillMap = new Map<string, Skill>();\n\tconst realPathSet = new Set<string>();\n\tconst allDiagnostics: ResourceDiagnostic[] = [];\n\tconst collisionDiagnostics: ResourceDiagnostic[] = [];\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallDiagnostics.push(...result.diagnostics);\n\t\tfor (const skill of result.skills) {\n\t\t\tlet realPath: string;\n\t\t\ttry {\n\t\t\t\trealPath = realpathSync(skill.filePath);\n\t\t\t} catch {\n\t\t\t\trealPath = skill.filePath;\n\t\t\t}\n\t\t\tif (realPathSet.has(realPath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionDiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${skill.name}\" collision`,\n\t\t\t\t\tpath: skill.filePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"skill\",\n\t\t\t\t\t\tname: skill.name,\n\t\t\t\t\t\twinnerPath: existing.filePath,\n\t\t\t\t\t\tloserPath: skill.filePath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t\trealPathSet.add(realPath);\n\t\t\t}\n\t\t}\n\t}\n\tif (includeDefaults) {\n\t\t// Load from all global skill directories\n\t\tfor (const { path, source } of getGlobalSkillPaths()) {\n\t\t\tif (existsSync(path)) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(path, source, true));\n\t\t\t}\n\t\t}\n\t\t// Load from all project-level skill directories\n\t\tfor (const { path, source } of getProjectSkillPaths(cwd)) {\n\t\t\tif (existsSync(path)) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(path, source, true));\n\t\t\t}\n\t\t}\n\t}\n\tconst userSkillsDir = join(resolvedAgentDir, \"skills\");\n\tconst projectSkillsDir = resolve(cwd, CONFIG_DIR_NAME, \"skills\");\n\tconst isUnderPath = (target: string, root: string): boolean => {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t};\n\tconst getSource = (resolvedPath: string): \"user\" | \"project\" | \"path\" => {\n\t\tif (!includeDefaults) {\n\t\t\tif (isUnderPath(resolvedPath, userSkillsDir)) return \"user\";\n\t\t\tif (isUnderPath(resolvedPath, projectSkillsDir)) return \"project\";\n\t\t}\n\t\treturn \"path\";\n\t};\n\tfor (const rawPath of skillPaths) {\n\t\tconst resolvedPath = resolveSkillPath(rawPath, cwd);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path does not exist\", path: resolvedPath });\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tconst source = getSource(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(resolvedPath, source, true));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\tconst result = loadSkillFromFile(resolvedPath, source);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\taddSkills({ skills: [result.skill], diagnostics: result.diagnostics });\n\t\t\t\t} else {\n\t\t\t\t\tallDiagnostics.push(...result.diagnostics);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path is not a markdown file\", path: resolvedPath });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read skill path\";\n\t\t\tallDiagnostics.push({ type: \"warning\", message, path: resolvedPath });\n\t\t}\n\t}\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\tdiagnostics: [...allDiagnostics, ...collisionDiagnostics],\n\t};\n}\n"]}
|
package/dist/core/skills.js
CHANGED
|
@@ -7,6 +7,30 @@ import { parseFrontmatter } from "../utils/frontmatter.js";
|
|
|
7
7
|
const MAX_NAME_LENGTH = 64;
|
|
8
8
|
const MAX_DESCRIPTION_LENGTH = 1024;
|
|
9
9
|
const IGNORE_FILE_NAMES = [".gitignore", ".ignore", ".fdignore"];
|
|
10
|
+
/**
|
|
11
|
+
* Get all global skill directories to search.
|
|
12
|
+
* Returns paths in priority order (first found wins).
|
|
13
|
+
*/
|
|
14
|
+
function getGlobalSkillPaths() {
|
|
15
|
+
const home = homedir();
|
|
16
|
+
return [
|
|
17
|
+
{ path: join(home, CONFIG_DIR_NAME, "skills"), source: "user" }, // ~/.openvibe/skills
|
|
18
|
+
{ path: join(home, ".agents", "skills"), source: "agents" }, // ~/.agents/skills (Agent Skills standard)
|
|
19
|
+
{ path: join(home, ".claude", "skills"), source: "claude" }, // ~/.claude/skills (Claude compatibility)
|
|
20
|
+
{ path: join(home, ".codex", "skills"), source: "codex" }, // ~/.codex/skills (OpenAI Codex compatibility)
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get all project-level skill directories to search.
|
|
25
|
+
* Returns paths in priority order.
|
|
26
|
+
*/
|
|
27
|
+
function getProjectSkillPaths(cwd) {
|
|
28
|
+
return [
|
|
29
|
+
{ path: resolve(cwd, CONFIG_DIR_NAME, "skills"), source: "project" }, // .openvibe/skills
|
|
30
|
+
{ path: resolve(cwd, ".agents", "skills"), source: "project-agents" }, // .agents/skills
|
|
31
|
+
{ path: resolve(cwd, ".claude", "skills"), source: "project-claude" }, // .claude/skills
|
|
32
|
+
];
|
|
33
|
+
}
|
|
10
34
|
function toPosixPath(p) {
|
|
11
35
|
return p.split(sep).join("/");
|
|
12
36
|
}
|
|
@@ -187,9 +211,19 @@ export function formatSkillsForPrompt(skills) {
|
|
|
187
211
|
return "";
|
|
188
212
|
}
|
|
189
213
|
const lines = [
|
|
190
|
-
"\n\
|
|
191
|
-
"
|
|
192
|
-
"
|
|
214
|
+
"\n\n# Skills System",
|
|
215
|
+
"",
|
|
216
|
+
"Skills are specialized knowledge files that provide expert guidance for specific tasks.",
|
|
217
|
+
"Each skill contains detailed instructions, best practices, and context for its domain.",
|
|
218
|
+
"",
|
|
219
|
+
"**How to use skills:**",
|
|
220
|
+
"1. Review the available skills below to find one matching your current task",
|
|
221
|
+
"2. Use the `read` tool to load the skill's full content from its location",
|
|
222
|
+
"3. Apply the skill's guidance to your current task",
|
|
223
|
+
"4. When a skill references relative paths, resolve them against the skill directory",
|
|
224
|
+
"",
|
|
225
|
+
"**Invoking a skill:**",
|
|
226
|
+
"To load a skill, use: `read <location>` where location is the skill's file path",
|
|
193
227
|
"",
|
|
194
228
|
"<available_skills>",
|
|
195
229
|
];
|
|
@@ -201,6 +235,9 @@ export function formatSkillsForPrompt(skills) {
|
|
|
201
235
|
lines.push(" </skill>");
|
|
202
236
|
}
|
|
203
237
|
lines.push("</available_skills>");
|
|
238
|
+
lines.push("");
|
|
239
|
+
lines.push("**Smart Skill Selection:**");
|
|
240
|
+
lines.push("Before responding to any task, consider if a skill could help. Skills provide domain expertise.");
|
|
204
241
|
return lines.join("\n");
|
|
205
242
|
}
|
|
206
243
|
function escapeXml(str) {
|
|
@@ -266,8 +303,18 @@ export function loadSkills(options = {}) {
|
|
|
266
303
|
}
|
|
267
304
|
}
|
|
268
305
|
if (includeDefaults) {
|
|
269
|
-
|
|
270
|
-
|
|
306
|
+
// Load from all global skill directories
|
|
307
|
+
for (const { path, source } of getGlobalSkillPaths()) {
|
|
308
|
+
if (existsSync(path)) {
|
|
309
|
+
addSkills(loadSkillsFromDirInternal(path, source, true));
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// Load from all project-level skill directories
|
|
313
|
+
for (const { path, source } of getProjectSkillPaths(cwd)) {
|
|
314
|
+
if (existsSync(path)) {
|
|
315
|
+
addSkills(loadSkillsFromDirInternal(path, source, true));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
271
318
|
}
|
|
272
319
|
const userSkillsDir = join(resolvedAgentDir, "skills");
|
|
273
320
|
const projectSkillsDir = resolve(cwd, CONFIG_DIR_NAME, "skills");
|