@burtson-labs/agent-core 1.6.13
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/LICENSE +201 -0
- package/README.md +88 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/activation.d.ts +60 -0
- package/dist/mcp/activation.d.ts.map +1 -0
- package/dist/mcp/activation.js +139 -0
- package/dist/mcp/activation.js.map +1 -0
- package/dist/mcp/clientPool.d.ts +202 -0
- package/dist/mcp/clientPool.d.ts.map +1 -0
- package/dist/mcp/clientPool.js +469 -0
- package/dist/mcp/clientPool.js.map +1 -0
- package/dist/mcp/index.d.ts +18 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +28 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +43 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +130 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/toolAdapter.d.ts +57 -0
- package/dist/mcp/toolAdapter.d.ts.map +1 -0
- package/dist/mcp/toolAdapter.js +223 -0
- package/dist/mcp/toolAdapter.js.map +1 -0
- package/dist/mcp/types.d.ts +122 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +15 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/providers/deterministic-provider.d.ts +21 -0
- package/dist/providers/deterministic-provider.d.ts.map +1 -0
- package/dist/providers/deterministic-provider.js +80 -0
- package/dist/providers/deterministic-provider.js.map +1 -0
- package/dist/providers/provider-client.d.ts +12 -0
- package/dist/providers/provider-client.d.ts.map +1 -0
- package/dist/providers/provider-client.js +11 -0
- package/dist/providers/provider-client.js.map +1 -0
- package/dist/runtime/AgentRuntime.d.ts +67 -0
- package/dist/runtime/AgentRuntime.d.ts.map +1 -0
- package/dist/runtime/AgentRuntime.js +382 -0
- package/dist/runtime/AgentRuntime.js.map +1 -0
- package/dist/security/secretPatterns.d.ts +76 -0
- package/dist/security/secretPatterns.d.ts.map +1 -0
- package/dist/security/secretPatterns.js +290 -0
- package/dist/security/secretPatterns.js.map +1 -0
- package/dist/tools/ask-user-tool.d.ts +19 -0
- package/dist/tools/ask-user-tool.d.ts.map +1 -0
- package/dist/tools/ask-user-tool.js +148 -0
- package/dist/tools/ask-user-tool.js.map +1 -0
- package/dist/tools/compactMessages.d.ts +52 -0
- package/dist/tools/compactMessages.d.ts.map +1 -0
- package/dist/tools/compactMessages.js +158 -0
- package/dist/tools/compactMessages.js.map +1 -0
- package/dist/tools/core-tools.d.ts +29 -0
- package/dist/tools/core-tools.d.ts.map +1 -0
- package/dist/tools/core-tools.js +2214 -0
- package/dist/tools/core-tools.js.map +1 -0
- package/dist/tools/git-tools.d.ts +32 -0
- package/dist/tools/git-tools.d.ts.map +1 -0
- package/dist/tools/git-tools.js +330 -0
- package/dist/tools/git-tools.js.map +1 -0
- package/dist/tools/index.d.ts +15 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +31 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/language-adapters.d.ts +48 -0
- package/dist/tools/language-adapters.d.ts.map +1 -0
- package/dist/tools/language-adapters.js +299 -0
- package/dist/tools/language-adapters.js.map +1 -0
- package/dist/tools/loop/compactionTrigger.d.ts +47 -0
- package/dist/tools/loop/compactionTrigger.d.ts.map +1 -0
- package/dist/tools/loop/compactionTrigger.js +32 -0
- package/dist/tools/loop/compactionTrigger.js.map +1 -0
- package/dist/tools/loop/finalAnswerNudges.d.ts +68 -0
- package/dist/tools/loop/finalAnswerNudges.d.ts.map +1 -0
- package/dist/tools/loop/finalAnswerNudges.js +87 -0
- package/dist/tools/loop/finalAnswerNudges.js.map +1 -0
- package/dist/tools/loop/goalAnchor.d.ts +72 -0
- package/dist/tools/loop/goalAnchor.d.ts.map +1 -0
- package/dist/tools/loop/goalAnchor.js +76 -0
- package/dist/tools/loop/goalAnchor.js.map +1 -0
- package/dist/tools/loop/llmStream.d.ts +70 -0
- package/dist/tools/loop/llmStream.d.ts.map +1 -0
- package/dist/tools/loop/llmStream.js +181 -0
- package/dist/tools/loop/llmStream.js.map +1 -0
- package/dist/tools/loop/parallelExecute.d.ts +57 -0
- package/dist/tools/loop/parallelExecute.d.ts.map +1 -0
- package/dist/tools/loop/parallelExecute.js +54 -0
- package/dist/tools/loop/parallelExecute.js.map +1 -0
- package/dist/tools/loop/singleToolExecute.d.ts +71 -0
- package/dist/tools/loop/singleToolExecute.d.ts.map +1 -0
- package/dist/tools/loop/singleToolExecute.js +139 -0
- package/dist/tools/loop/singleToolExecute.js.map +1 -0
- package/dist/tools/loop/toolCallNormalize.d.ts +57 -0
- package/dist/tools/loop/toolCallNormalize.d.ts.map +1 -0
- package/dist/tools/loop/toolCallNormalize.js +99 -0
- package/dist/tools/loop/toolCallNormalize.js.map +1 -0
- package/dist/tools/loop/turnSetup.d.ts +43 -0
- package/dist/tools/loop/turnSetup.d.ts.map +1 -0
- package/dist/tools/loop/turnSetup.js +48 -0
- package/dist/tools/loop/turnSetup.js.map +1 -0
- package/dist/tools/ocr.d.ts +52 -0
- package/dist/tools/ocr.d.ts.map +1 -0
- package/dist/tools/ocr.js +238 -0
- package/dist/tools/ocr.js.map +1 -0
- package/dist/tools/post-edit-checks.d.ts +46 -0
- package/dist/tools/post-edit-checks.d.ts.map +1 -0
- package/dist/tools/post-edit-checks.js +236 -0
- package/dist/tools/post-edit-checks.js.map +1 -0
- package/dist/tools/skill-loader.d.ts +94 -0
- package/dist/tools/skill-loader.d.ts.map +1 -0
- package/dist/tools/skill-loader.js +422 -0
- package/dist/tools/skill-loader.js.map +1 -0
- package/dist/tools/skill-registry.d.ts +44 -0
- package/dist/tools/skill-registry.d.ts.map +1 -0
- package/dist/tools/skill-registry.js +118 -0
- package/dist/tools/skill-registry.js.map +1 -0
- package/dist/tools/skill-types.d.ts +38 -0
- package/dist/tools/skill-types.d.ts.map +1 -0
- package/dist/tools/skill-types.js +10 -0
- package/dist/tools/skill-types.js.map +1 -0
- package/dist/tools/skills/code-review-skill.d.ts +9 -0
- package/dist/tools/skills/code-review-skill.d.ts.map +1 -0
- package/dist/tools/skills/code-review-skill.js +66 -0
- package/dist/tools/skills/code-review-skill.js.map +1 -0
- package/dist/tools/skills/core-skill.d.ts +13 -0
- package/dist/tools/skills/core-skill.d.ts.map +1 -0
- package/dist/tools/skills/core-skill.js +23 -0
- package/dist/tools/skills/core-skill.js.map +1 -0
- package/dist/tools/skills/git-skill.d.ts +10 -0
- package/dist/tools/skills/git-skill.d.ts.map +1 -0
- package/dist/tools/skills/git-skill.js +30 -0
- package/dist/tools/skills/git-skill.js.map +1 -0
- package/dist/tools/skills/index.d.ts +17 -0
- package/dist/tools/skills/index.d.ts.map +1 -0
- package/dist/tools/skills/index.js +49 -0
- package/dist/tools/skills/index.js.map +1 -0
- package/dist/tools/skills/interaction-skill.d.ts +14 -0
- package/dist/tools/skills/interaction-skill.d.ts.map +1 -0
- package/dist/tools/skills/interaction-skill.js +24 -0
- package/dist/tools/skills/interaction-skill.js.map +1 -0
- package/dist/tools/skills/mail-search-skill.d.ts +25 -0
- package/dist/tools/skills/mail-search-skill.d.ts.map +1 -0
- package/dist/tools/skills/mail-search-skill.js +343 -0
- package/dist/tools/skills/mail-search-skill.js.map +1 -0
- package/dist/tools/skills/plan-skill.d.ts +10 -0
- package/dist/tools/skills/plan-skill.d.ts.map +1 -0
- package/dist/tools/skills/plan-skill.js +126 -0
- package/dist/tools/skills/plan-skill.js.map +1 -0
- package/dist/tools/skills/semantic-search-skill.d.ts +22 -0
- package/dist/tools/skills/semantic-search-skill.d.ts.map +1 -0
- package/dist/tools/skills/semantic-search-skill.js +244 -0
- package/dist/tools/skills/semantic-search-skill.js.map +1 -0
- package/dist/tools/skills/test-gen-skill.d.ts +9 -0
- package/dist/tools/skills/test-gen-skill.d.ts.map +1 -0
- package/dist/tools/skills/test-gen-skill.js +123 -0
- package/dist/tools/skills/test-gen-skill.js.map +1 -0
- package/dist/tools/tool-registry.d.ts +60 -0
- package/dist/tools/tool-registry.d.ts.map +1 -0
- package/dist/tools/tool-registry.js +200 -0
- package/dist/tools/tool-registry.js.map +1 -0
- package/dist/tools/tool-types.d.ts +281 -0
- package/dist/tools/tool-types.d.ts.map +1 -0
- package/dist/tools/tool-types.js +10 -0
- package/dist/tools/tool-types.js.map +1 -0
- package/dist/tools/tool-use-loop.d.ts +231 -0
- package/dist/tools/tool-use-loop.d.ts.map +1 -0
- package/dist/tools/tool-use-loop.js +2057 -0
- package/dist/tools/tool-use-loop.js.map +1 -0
- package/dist/tools/tool-use-parser.d.ts +78 -0
- package/dist/tools/tool-use-parser.d.ts.map +1 -0
- package/dist/tools/tool-use-parser.js +427 -0
- package/dist/tools/tool-use-parser.js.map +1 -0
- package/dist/tools/toolAvailabilityDetector.d.ts +48 -0
- package/dist/tools/toolAvailabilityDetector.d.ts.map +1 -0
- package/dist/tools/toolAvailabilityDetector.js +156 -0
- package/dist/tools/toolAvailabilityDetector.js.map +1 -0
- package/dist/tools/unified-patch.d.ts +87 -0
- package/dist/tools/unified-patch.d.ts.map +1 -0
- package/dist/tools/unified-patch.js +217 -0
- package/dist/tools/unified-patch.js.map +1 -0
- package/dist/types/agent.d.ts +69 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +54 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/tasks.d.ts +22 -0
- package/dist/types/tasks.d.ts.map +1 -0
- package/dist/types/tasks.js +3 -0
- package/dist/types/tasks.js.map +1 -0
- package/dist/utils/event-emitter.d.ts +13 -0
- package/dist/utils/event-emitter.d.ts.map +1 -0
- package/dist/utils/event-emitter.js +54 -0
- package/dist/utils/event-emitter.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Semantic search skill — auto-activated when users ask about code concepts,
|
|
4
|
+
* architecture, or need to find code by meaning rather than literal text.
|
|
5
|
+
*
|
|
6
|
+
* Uses Ollama's nomic-embed-text model for local embeddings. Indexes workspace
|
|
7
|
+
* files on first search and caches vectors in memory for the session.
|
|
8
|
+
*
|
|
9
|
+
* Requires Ollama running locally with nomic-embed-text installed:
|
|
10
|
+
* ollama pull nomic-embed-text
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.semanticSearchSkill = void 0;
|
|
14
|
+
exports.configureSemanticSearchOllamaUrl = configureSemanticSearchOllamaUrl;
|
|
15
|
+
exports.resetSemanticIndex = resetSemanticIndex;
|
|
16
|
+
let store = [];
|
|
17
|
+
let indexedPaths = new Set();
|
|
18
|
+
let ollamaBaseUrl = 'http://localhost:11434';
|
|
19
|
+
async function embed(text) {
|
|
20
|
+
const response = await fetch(`${ollamaBaseUrl}/api/embeddings`, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: { 'Content-Type': 'application/json' },
|
|
23
|
+
body: JSON.stringify({ model: 'nomic-embed-text', prompt: text }),
|
|
24
|
+
signal: AbortSignal.timeout(10000)
|
|
25
|
+
});
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
throw new Error(`Embedding failed: ${response.status}`);
|
|
28
|
+
}
|
|
29
|
+
const data = await response.json();
|
|
30
|
+
if (!Array.isArray(data.embedding)) {
|
|
31
|
+
throw new Error('Embedding response missing vector');
|
|
32
|
+
}
|
|
33
|
+
return data.embedding;
|
|
34
|
+
}
|
|
35
|
+
function cosineSimilarity(a, b) {
|
|
36
|
+
if (a.length !== b.length || a.length === 0)
|
|
37
|
+
return 0;
|
|
38
|
+
let dot = 0, normA = 0, normB = 0;
|
|
39
|
+
for (let i = 0; i < a.length; i++) {
|
|
40
|
+
dot += a[i] * b[i];
|
|
41
|
+
normA += a[i] * a[i];
|
|
42
|
+
normB += b[i] * b[i];
|
|
43
|
+
}
|
|
44
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
45
|
+
return denom === 0 ? 0 : dot / denom;
|
|
46
|
+
}
|
|
47
|
+
function chunkText(text, maxChars = 800) {
|
|
48
|
+
if (text.length <= maxChars)
|
|
49
|
+
return [text];
|
|
50
|
+
const chunks = [];
|
|
51
|
+
const lines = text.split('\n');
|
|
52
|
+
let current = '';
|
|
53
|
+
for (const line of lines) {
|
|
54
|
+
if ((current + line).length > maxChars && current.length > 0) {
|
|
55
|
+
chunks.push(current.trim());
|
|
56
|
+
current = '';
|
|
57
|
+
}
|
|
58
|
+
current += line + '\n';
|
|
59
|
+
}
|
|
60
|
+
if (current.trim())
|
|
61
|
+
chunks.push(current.trim());
|
|
62
|
+
return chunks;
|
|
63
|
+
}
|
|
64
|
+
async function indexFile(path, content) {
|
|
65
|
+
if (indexedPaths.has(path))
|
|
66
|
+
return;
|
|
67
|
+
const chunks = chunkText(content);
|
|
68
|
+
for (const chunk of chunks) {
|
|
69
|
+
try {
|
|
70
|
+
const vector = await embed(chunk);
|
|
71
|
+
store.push({ path, content: chunk, vector });
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Skip failed chunks silently
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
indexedPaths.add(path);
|
|
78
|
+
}
|
|
79
|
+
const semanticSearchTool = {
|
|
80
|
+
name: 'semantic_search',
|
|
81
|
+
description: 'Search the codebase by meaning, not just text. Finds code related to a concept even when the exact words differ. Automatically indexes workspace files on first use. Use this when search_code (regex) misses what you need.',
|
|
82
|
+
parameters: [
|
|
83
|
+
{ name: 'query', description: 'Natural language description of what you are looking for (e.g. "authentication middleware", "database connection pooling", "error boundary component")', required: true },
|
|
84
|
+
{ name: 'file_glob', description: 'Optional glob to restrict which files are searched (e.g. "src/**/*.ts"). Defaults to all .ts/.tsx/.js/.jsx/.py files.' },
|
|
85
|
+
{ name: 'top_k', description: 'Number of results to return (default: 6)' }
|
|
86
|
+
],
|
|
87
|
+
async execute(params, ctx) {
|
|
88
|
+
const query = params.query?.trim();
|
|
89
|
+
if (!query)
|
|
90
|
+
return { output: 'Error: query parameter is required', isError: true };
|
|
91
|
+
const topK = Math.min(parseInt(params.top_k ?? '6', 10) || 6, 15);
|
|
92
|
+
const glob = params.file_glob ?? '**/*.{ts,tsx,js,jsx,py}';
|
|
93
|
+
// If the store is empty, index workspace files first
|
|
94
|
+
if (store.length === 0) {
|
|
95
|
+
try {
|
|
96
|
+
const files = await ctx.listFiles(glob);
|
|
97
|
+
const toIndex = files.slice(0, 50); // Cap at 50 files for speed
|
|
98
|
+
for (const file of toIndex) {
|
|
99
|
+
try {
|
|
100
|
+
const absPath = file.startsWith('/') ||
|
|
101
|
+
file.startsWith('~') ||
|
|
102
|
+
/^[A-Za-z]:[\\/]/.test(file) ||
|
|
103
|
+
file.startsWith('\\\\')
|
|
104
|
+
? file
|
|
105
|
+
: `${ctx.workspaceRoot}/${file}`;
|
|
106
|
+
const content = await ctx.readFile(absPath);
|
|
107
|
+
if (content.length > 0 && content.length < 50000) {
|
|
108
|
+
await indexFile(file, content);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Skip unreadable files
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (store.length === 0) {
|
|
116
|
+
return { output: 'No files could be indexed. Is nomic-embed-text installed? Run: ollama pull nomic-embed-text', isError: true };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
return {
|
|
121
|
+
output: `Embedding search failed: ${err instanceof Error ? err.message : String(err)}. Ensure Ollama is running with nomic-embed-text.`,
|
|
122
|
+
isError: true
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Search
|
|
127
|
+
try {
|
|
128
|
+
const queryVector = await embed(query);
|
|
129
|
+
const scored = store.map(chunk => ({
|
|
130
|
+
path: chunk.path,
|
|
131
|
+
content: chunk.content,
|
|
132
|
+
score: cosineSimilarity(queryVector, chunk.vector)
|
|
133
|
+
}));
|
|
134
|
+
scored.sort((a, b) => b.score - a.score);
|
|
135
|
+
// Deduplicate by path, keeping best score per file
|
|
136
|
+
const seen = new Map();
|
|
137
|
+
for (const item of scored) {
|
|
138
|
+
if (!seen.has(item.path)) {
|
|
139
|
+
seen.set(item.path, item);
|
|
140
|
+
}
|
|
141
|
+
if (seen.size >= topK)
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
const results = Array.from(seen.values());
|
|
145
|
+
if (results.length === 0) {
|
|
146
|
+
return { output: `No relevant results found for: "${query}"` };
|
|
147
|
+
}
|
|
148
|
+
const output = results.map((r, i) => {
|
|
149
|
+
const preview = r.content.slice(0, 500);
|
|
150
|
+
return `### ${i + 1}. ${r.path} (score: ${r.score.toFixed(3)})\n\`\`\`\n${preview}${r.content.length > 500 ? '\n...' : ''}\n\`\`\``;
|
|
151
|
+
}).join('\n\n');
|
|
152
|
+
return { output: `Found ${results.length} relevant files for "${query}":\n\n${output}` };
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
return {
|
|
156
|
+
output: `Search failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
157
|
+
isError: true
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const indexWorkspaceTool = {
|
|
163
|
+
name: 'index_workspace',
|
|
164
|
+
description: 'Index workspace files for semantic search. Run this before semantic_search if you want to search more files or specific directories.',
|
|
165
|
+
parameters: [
|
|
166
|
+
{ name: 'glob', description: 'Glob pattern of files to index (default: "**/*.{ts,tsx,js,jsx,py}")' },
|
|
167
|
+
{ name: 'max_files', description: 'Maximum number of files to index (default: 50)' }
|
|
168
|
+
],
|
|
169
|
+
async execute(params, ctx) {
|
|
170
|
+
const glob = params.glob ?? '**/*.{ts,tsx,js,jsx,py}';
|
|
171
|
+
const maxFiles = Math.min(parseInt(params.max_files ?? '50', 10) || 50, 100);
|
|
172
|
+
try {
|
|
173
|
+
const files = await ctx.listFiles(glob);
|
|
174
|
+
const toIndex = files.slice(0, maxFiles);
|
|
175
|
+
let indexed = 0;
|
|
176
|
+
let skipped = 0;
|
|
177
|
+
for (const file of toIndex) {
|
|
178
|
+
if (indexedPaths.has(file)) {
|
|
179
|
+
skipped++;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
const absPath = file.startsWith('/') ||
|
|
184
|
+
file.startsWith('~') ||
|
|
185
|
+
/^[A-Za-z]:[\\/]/.test(file) ||
|
|
186
|
+
file.startsWith('\\\\')
|
|
187
|
+
? file
|
|
188
|
+
: `${ctx.workspaceRoot}/${file}`;
|
|
189
|
+
const content = await ctx.readFile(absPath);
|
|
190
|
+
if (content.length > 0 && content.length < 50000) {
|
|
191
|
+
await indexFile(file, content);
|
|
192
|
+
indexed++;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// Skip unreadable files
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
output: `Indexed ${indexed} files (${skipped} already indexed, ${store.length} total chunks). Semantic search is ready.`
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
return {
|
|
205
|
+
output: `Indexing failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
206
|
+
isError: true
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
exports.semanticSearchSkill = {
|
|
212
|
+
id: 'search/semantic',
|
|
213
|
+
name: 'Semantic Search',
|
|
214
|
+
version: '1.0.0',
|
|
215
|
+
description: 'Search codebase by meaning using local Ollama embeddings (nomic-embed-text). Finds conceptually related code.',
|
|
216
|
+
instructions: 'Use semantic_search when you need to find code by concept (e.g. "authentication logic", "data validation") rather than exact text. Use search_code for literal/regex matches. The index is built automatically on first search.',
|
|
217
|
+
activation: 'auto',
|
|
218
|
+
triggerPatterns: [
|
|
219
|
+
/\bfind.*related\b/i,
|
|
220
|
+
/\bwhere.*handle/i,
|
|
221
|
+
/\bhow.*implement/i,
|
|
222
|
+
/\bwhat.*does\b/i,
|
|
223
|
+
/\bunderstand\b/i,
|
|
224
|
+
/\barchitecture\b/i,
|
|
225
|
+
/\bexplain.*code\b/i,
|
|
226
|
+
/\bsemantic/i
|
|
227
|
+
],
|
|
228
|
+
tools: [semanticSearchTool, indexWorkspaceTool]
|
|
229
|
+
};
|
|
230
|
+
/**
|
|
231
|
+
* Configure the Ollama base URL for the embedding client.
|
|
232
|
+
* Call this before the skill is used if Ollama is not on localhost.
|
|
233
|
+
*/
|
|
234
|
+
function configureSemanticSearchOllamaUrl(url) {
|
|
235
|
+
ollamaBaseUrl = url.replace(/\/+$/, '');
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Reset the in-memory index (e.g. on workspace change).
|
|
239
|
+
*/
|
|
240
|
+
function resetSemanticIndex() {
|
|
241
|
+
store = [];
|
|
242
|
+
indexedPaths = new Set();
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=semantic-search-skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-search-skill.js","sourceRoot":"","sources":["../../../src/tools/skills/semantic-search-skill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test generation skill — auto-activated when the user mentions tests, specs, or coverage.
|
|
3
|
+
*
|
|
4
|
+
* Provides tools for discovering test frameworks and running test suites,
|
|
5
|
+
* giving the model the context it needs to generate or fix tests.
|
|
6
|
+
*/
|
|
7
|
+
import type { SkillManifest } from '../skill-types';
|
|
8
|
+
export declare const testGenSkill: SkillManifest;
|
|
9
|
+
//# sourceMappingURL=test-gen-skill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-gen-skill.d.ts","sourceRoot":"","sources":["../../../src/tools/skills/test-gen-skill.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AA6GpD,eAAO,MAAM,YAAY,EAAE,aAS1B,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Test generation skill — auto-activated when the user mentions tests, specs, or coverage.
|
|
4
|
+
*
|
|
5
|
+
* Provides tools for discovering test frameworks and running test suites,
|
|
6
|
+
* giving the model the context it needs to generate or fix tests.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.testGenSkill = void 0;
|
|
10
|
+
const runTestsTool = {
|
|
11
|
+
name: 'run_tests',
|
|
12
|
+
description: 'Run the project test suite and return results. Auto-detects the test runner (vitest, jest, mocha, pytest, cargo test).',
|
|
13
|
+
parameters: [
|
|
14
|
+
{ name: 'filter', description: 'Optional test name or file pattern to filter (e.g. "auth", "src/utils/*.test.ts")' },
|
|
15
|
+
{ name: 'runner', description: 'Override the test runner (e.g. "vitest", "jest", "pytest"). Auto-detected if omitted.' }
|
|
16
|
+
],
|
|
17
|
+
async execute(params, ctx) {
|
|
18
|
+
const runner = params.runner?.trim();
|
|
19
|
+
let cmd;
|
|
20
|
+
let args;
|
|
21
|
+
if (runner) {
|
|
22
|
+
cmd = runner;
|
|
23
|
+
args = ['run'];
|
|
24
|
+
if (params.filter)
|
|
25
|
+
args.push(params.filter);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// Auto-detect: check for common test runner config files
|
|
29
|
+
const detectors = [
|
|
30
|
+
{ files: ['vitest.config.ts', 'vitest.config.js'], cmd: 'npx', args: ['vitest', 'run'] },
|
|
31
|
+
{ files: ['jest.config.ts', 'jest.config.js', 'jest.config.mjs'], cmd: 'npx', args: ['jest'] },
|
|
32
|
+
{ files: ['pytest.ini', 'pyproject.toml', 'setup.cfg'], cmd: 'python3', args: ['-m', 'pytest'] },
|
|
33
|
+
{ files: ['Cargo.toml'], cmd: 'cargo', args: ['test'] },
|
|
34
|
+
];
|
|
35
|
+
let detected = false;
|
|
36
|
+
for (const detector of detectors) {
|
|
37
|
+
for (const file of detector.files) {
|
|
38
|
+
try {
|
|
39
|
+
const files = await ctx.listFiles(file);
|
|
40
|
+
if (files.length > 0) {
|
|
41
|
+
cmd = detector.cmd;
|
|
42
|
+
args = [...detector.args];
|
|
43
|
+
if (params.filter)
|
|
44
|
+
args.push(params.filter);
|
|
45
|
+
detected = true;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// file doesn't exist, try next
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (detected)
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
if (!detected) {
|
|
57
|
+
// Fallback: try npx vitest run
|
|
58
|
+
cmd = 'npx';
|
|
59
|
+
args = ['vitest', 'run'];
|
|
60
|
+
if (params.filter)
|
|
61
|
+
args.push(params.filter);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const result = await ctx.runCommand(cmd, args, ctx.workspaceRoot);
|
|
66
|
+
const combined = [
|
|
67
|
+
result.stdout.trim() ? result.stdout.trim() : '',
|
|
68
|
+
result.stderr.trim() ? `stderr:\n${result.stderr.trim()}` : '',
|
|
69
|
+
`exit code: ${result.exitCode}`
|
|
70
|
+
].filter(Boolean).join('\n\n');
|
|
71
|
+
return {
|
|
72
|
+
output: combined.slice(0, 16000),
|
|
73
|
+
isError: result.exitCode !== 0
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
return { output: `Error running tests: ${err instanceof Error ? err.message : String(err)}`, isError: true };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const listTestFilesTool = {
|
|
82
|
+
name: 'list_test_files',
|
|
83
|
+
description: 'Find all test files in the workspace. Searches for common test file patterns (*.test.ts, *.spec.ts, test_*.py, *_test.go).',
|
|
84
|
+
parameters: [
|
|
85
|
+
{ name: 'cwd', description: 'Subdirectory to search in (optional, defaults to whole workspace)' }
|
|
86
|
+
],
|
|
87
|
+
async execute(params, ctx) {
|
|
88
|
+
const patterns = [
|
|
89
|
+
'**/*.test.ts', '**/*.test.tsx', '**/*.test.js', '**/*.test.jsx',
|
|
90
|
+
'**/*.spec.ts', '**/*.spec.tsx', '**/*.spec.js', '**/*.spec.jsx',
|
|
91
|
+
'**/test_*.py', '**/*_test.py', '**/*_test.go',
|
|
92
|
+
];
|
|
93
|
+
const allFiles = [];
|
|
94
|
+
const cwd = params.cwd
|
|
95
|
+
? `${ctx.workspaceRoot}/${params.cwd}`
|
|
96
|
+
: ctx.workspaceRoot;
|
|
97
|
+
for (const pattern of patterns) {
|
|
98
|
+
try {
|
|
99
|
+
const files = await ctx.listFiles(pattern, cwd);
|
|
100
|
+
allFiles.push(...files);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// pattern matched nothing
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const unique = [...new Set(allFiles)].sort();
|
|
107
|
+
if (unique.length === 0) {
|
|
108
|
+
return { output: 'No test files found.' };
|
|
109
|
+
}
|
|
110
|
+
return { output: `${unique.length} test file(s) found:\n\n${unique.join('\n')}` };
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
exports.testGenSkill = {
|
|
114
|
+
id: 'testing/test-gen',
|
|
115
|
+
name: 'Testing',
|
|
116
|
+
version: '1.0.0',
|
|
117
|
+
description: 'Run tests, find test files, and assist with test generation.',
|
|
118
|
+
instructions: 'When writing tests, first use list_test_files to understand existing test patterns. Use run_tests to verify your changes. Match the existing test style and framework.',
|
|
119
|
+
activation: 'auto',
|
|
120
|
+
triggerPatterns: [/\btest/i, /\bspec\b/i, /\bcoverage\b/i, /\bunit\s+test/i],
|
|
121
|
+
tools: [runTestsTool, listTestFilesTool]
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=test-gen-skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-gen-skill.js","sourceRoot":"","sources":["../../../src/tools/skills/test-gen-skill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { AgentTool } from './tool-types';
|
|
2
|
+
/**
|
|
3
|
+
* Registry of available agent tools.
|
|
4
|
+
*
|
|
5
|
+
* Builds XML-format tool definitions for text-based tool calling,
|
|
6
|
+
* usable with models that don't support native function calling
|
|
7
|
+
* (gemma3, bandit-core, most 7-27B models).
|
|
8
|
+
*/
|
|
9
|
+
export declare class ToolRegistry {
|
|
10
|
+
private readonly tools;
|
|
11
|
+
register(tool: AgentTool): this;
|
|
12
|
+
registerAll(tools: AgentTool[]): this;
|
|
13
|
+
get(name: string): AgentTool | undefined;
|
|
14
|
+
getAll(): AgentTool[];
|
|
15
|
+
has(name: string): boolean;
|
|
16
|
+
get size(): number;
|
|
17
|
+
/**
|
|
18
|
+
* Builds the tool definitions block injected into the system prompt.
|
|
19
|
+
*
|
|
20
|
+
* Format used for text-based tool calling (XML, compatible with Gemma3/bandit-core):
|
|
21
|
+
*
|
|
22
|
+
* You have access to these tools:
|
|
23
|
+
* <tool name="read_file">
|
|
24
|
+
* <description>...</description>
|
|
25
|
+
* <param name="path" required="true">...</param>
|
|
26
|
+
* </tool>
|
|
27
|
+
* ...
|
|
28
|
+
* To use a tool, respond with ONLY:
|
|
29
|
+
* <tool_call>{"name": "tool_name", "params": {"key": "value"}}</tool_call>
|
|
30
|
+
*
|
|
31
|
+
* When you have finished using tools and have a final answer, respond normally.
|
|
32
|
+
*/
|
|
33
|
+
buildSystemPromptBlock(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Builds tool definitions in JSON schema format for models with native tool calling.
|
|
36
|
+
* Compatible with Ollama's `tools: [...]` field.
|
|
37
|
+
*
|
|
38
|
+
* Parameter types: each AgentToolParameter may carry an optional
|
|
39
|
+
* `schema` field that holds JSON-Schema type info. When present we
|
|
40
|
+
* render the full shape (objects with properties, arrays with item
|
|
41
|
+
* types, enums) so the provider tells the model "this param is an
|
|
42
|
+
* object with these fields" instead of the legacy "every param is a
|
|
43
|
+
* string" flattening. Tools without `schema` default to `type: string`
|
|
44
|
+
* — matches every in-tree tool today and keeps the contract for
|
|
45
|
+
* adapter-less consumers.
|
|
46
|
+
*/
|
|
47
|
+
buildNativeToolsSchema(): Array<{
|
|
48
|
+
type: 'function';
|
|
49
|
+
function: {
|
|
50
|
+
name: string;
|
|
51
|
+
description: string;
|
|
52
|
+
parameters: {
|
|
53
|
+
type: 'object';
|
|
54
|
+
properties: Record<string, Record<string, unknown>>;
|
|
55
|
+
required: string[];
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
}>;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=tool-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../src/tools/tool-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAgD,MAAM,cAAc,CAAC;AAE5F;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IAEtD,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAK/B,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI;IAOrC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIxC,MAAM,IAAI,SAAS,EAAE;IAIrB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;;;;;;;;;;;OAeG;IACH,sBAAsB,IAAI,MAAM;IAyChC;;;;;;;;;;;;OAYG;IACH,sBAAsB,IAAI,KAAK,CAAC;QAC9B,IAAI,EAAE,UAAU,CAAC;QACjB,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAC;YACb,WAAW,EAAE,MAAM,CAAC;YACpB,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ,CAAC;gBACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;gBACpD,QAAQ,EAAE,MAAM,EAAE,CAAC;aACpB,CAAC;SACH,CAAC;KACH,CAAC;CAgBH"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ToolRegistry = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Registry of available agent tools.
|
|
6
|
+
*
|
|
7
|
+
* Builds XML-format tool definitions for text-based tool calling,
|
|
8
|
+
* usable with models that don't support native function calling
|
|
9
|
+
* (gemma3, bandit-core, most 7-27B models).
|
|
10
|
+
*/
|
|
11
|
+
class ToolRegistry {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.tools = new Map();
|
|
14
|
+
}
|
|
15
|
+
register(tool) {
|
|
16
|
+
this.tools.set(tool.name, tool);
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
registerAll(tools) {
|
|
20
|
+
for (const tool of tools) {
|
|
21
|
+
this.register(tool);
|
|
22
|
+
}
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
get(name) {
|
|
26
|
+
return this.tools.get(name);
|
|
27
|
+
}
|
|
28
|
+
getAll() {
|
|
29
|
+
return [...this.tools.values()];
|
|
30
|
+
}
|
|
31
|
+
has(name) {
|
|
32
|
+
return this.tools.has(name);
|
|
33
|
+
}
|
|
34
|
+
get size() {
|
|
35
|
+
return this.tools.size;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Builds the tool definitions block injected into the system prompt.
|
|
39
|
+
*
|
|
40
|
+
* Format used for text-based tool calling (XML, compatible with Gemma3/bandit-core):
|
|
41
|
+
*
|
|
42
|
+
* You have access to these tools:
|
|
43
|
+
* <tool name="read_file">
|
|
44
|
+
* <description>...</description>
|
|
45
|
+
* <param name="path" required="true">...</param>
|
|
46
|
+
* </tool>
|
|
47
|
+
* ...
|
|
48
|
+
* To use a tool, respond with ONLY:
|
|
49
|
+
* <tool_call>{"name": "tool_name", "params": {"key": "value"}}</tool_call>
|
|
50
|
+
*
|
|
51
|
+
* When you have finished using tools and have a final answer, respond normally.
|
|
52
|
+
*/
|
|
53
|
+
buildSystemPromptBlock() {
|
|
54
|
+
if (this.tools.size === 0)
|
|
55
|
+
return '';
|
|
56
|
+
const toolDefs = this.getAll().map(tool => {
|
|
57
|
+
const params = tool.parameters.map(p => {
|
|
58
|
+
// Surface the JSON-Schema-derived type hint inline in the
|
|
59
|
+
// description so the model knows when to emit a nested object
|
|
60
|
+
// or an array instead of a bare string. Without this hint the
|
|
61
|
+
// XML-prompt format describes every param as opaque text,
|
|
62
|
+
// which is what produced the "Expected object, received
|
|
63
|
+
// string" failures on createFilter / modifyMessageLabels.
|
|
64
|
+
const typeHint = formatParamTypeHint(p.schema);
|
|
65
|
+
const desc = typeHint ? `${typeHint} ${p.description}` : p.description;
|
|
66
|
+
return ` <param name="${p.name}"${p.required ? ' required="true"' : ''}>${desc}</param>`;
|
|
67
|
+
}).join('\n');
|
|
68
|
+
return [
|
|
69
|
+
`<tool name="${tool.name}">`,
|
|
70
|
+
` <description>${tool.description}</description>`,
|
|
71
|
+
params,
|
|
72
|
+
`</tool>`
|
|
73
|
+
].join('\n');
|
|
74
|
+
}).join('\n\n');
|
|
75
|
+
return [
|
|
76
|
+
'## Available Tools',
|
|
77
|
+
'',
|
|
78
|
+
'You have access to the following tools to help you complete tasks:',
|
|
79
|
+
'',
|
|
80
|
+
toolDefs,
|
|
81
|
+
'',
|
|
82
|
+
'## How to Use Tools',
|
|
83
|
+
'',
|
|
84
|
+
'To call a tool, respond with ONLY a tool call on its own line:',
|
|
85
|
+
'<tool_call>{"name": "tool_name", "params": {"param1": "value1"}}</tool_call>',
|
|
86
|
+
'',
|
|
87
|
+
'Wait for the tool result before continuing.',
|
|
88
|
+
'When you have all the information needed and are ready to give your final response,',
|
|
89
|
+
'respond normally without any <tool_call> tags.',
|
|
90
|
+
].join('\n');
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Builds tool definitions in JSON schema format for models with native tool calling.
|
|
94
|
+
* Compatible with Ollama's `tools: [...]` field.
|
|
95
|
+
*
|
|
96
|
+
* Parameter types: each AgentToolParameter may carry an optional
|
|
97
|
+
* `schema` field that holds JSON-Schema type info. When present we
|
|
98
|
+
* render the full shape (objects with properties, arrays with item
|
|
99
|
+
* types, enums) so the provider tells the model "this param is an
|
|
100
|
+
* object with these fields" instead of the legacy "every param is a
|
|
101
|
+
* string" flattening. Tools without `schema` default to `type: string`
|
|
102
|
+
* — matches every in-tree tool today and keeps the contract for
|
|
103
|
+
* adapter-less consumers.
|
|
104
|
+
*/
|
|
105
|
+
buildNativeToolsSchema() {
|
|
106
|
+
return this.getAll().map(tool => ({
|
|
107
|
+
type: 'function',
|
|
108
|
+
function: {
|
|
109
|
+
name: tool.name,
|
|
110
|
+
description: tool.description,
|
|
111
|
+
parameters: {
|
|
112
|
+
type: 'object',
|
|
113
|
+
properties: Object.fromEntries(tool.parameters.map(p => [p.name, renderParamForNativeSchema(p)])),
|
|
114
|
+
required: tool.parameters.filter(p => p.required).map(p => p.name)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
exports.ToolRegistry = ToolRegistry;
|
|
121
|
+
/**
|
|
122
|
+
* Translate an AgentToolParameter to the JSON-Schema-shaped fragment
|
|
123
|
+
* Ollama (and other OpenAI-compatible native-tools providers) want in
|
|
124
|
+
* the `parameters.properties[<name>]` slot. When the param carries a
|
|
125
|
+
* `schema` field, expand it into a real typed declaration; otherwise
|
|
126
|
+
* fall back to the legacy `{ type: "string", description }` shape so
|
|
127
|
+
* existing in-tree tools render identically.
|
|
128
|
+
*
|
|
129
|
+
* Recursive: nested object properties and array item shapes are
|
|
130
|
+
* expanded the same way, so a `createFilter` param with `criteria:
|
|
131
|
+
* { type: object, properties: { from, to, subject, query, ... } }`
|
|
132
|
+
* renders correctly all the way through.
|
|
133
|
+
*/
|
|
134
|
+
function renderParamForNativeSchema(p) {
|
|
135
|
+
const baseDescription = p.description;
|
|
136
|
+
if (!p.schema) {
|
|
137
|
+
return { type: 'string', description: baseDescription };
|
|
138
|
+
}
|
|
139
|
+
const rendered = renderSchemaFragment(p.schema);
|
|
140
|
+
// Top-level description from the AgentToolParameter wins so the
|
|
141
|
+
// agent sees the rich human-readable description we wrote at the
|
|
142
|
+
// tool definition (which often summarizes the whole param), not
|
|
143
|
+
// a nested per-property blurb.
|
|
144
|
+
rendered.description = baseDescription;
|
|
145
|
+
return rendered;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Build a short inline hint like "(object: {from, to, subject})" or
|
|
149
|
+
* "(array of string)" that prefixes the param description in the
|
|
150
|
+
* non-native system prompt block. Without a hint the model treats
|
|
151
|
+
* every param as opaque text. With it the model knows which params
|
|
152
|
+
* need JSON-encoded objects/arrays vs bare strings — which is the
|
|
153
|
+
* difference between createFilter working and Google rejecting the
|
|
154
|
+
* request with "Expected object, received string."
|
|
155
|
+
*/
|
|
156
|
+
function formatParamTypeHint(schema) {
|
|
157
|
+
if (!schema || !schema.type || schema.type === 'string')
|
|
158
|
+
return '';
|
|
159
|
+
if (schema.type === 'object') {
|
|
160
|
+
const keys = schema.properties ? Object.keys(schema.properties).slice(0, 6) : [];
|
|
161
|
+
const more = schema.properties && Object.keys(schema.properties).length > 6 ? ', …' : '';
|
|
162
|
+
return keys.length > 0
|
|
163
|
+
? `(object — pass JSON like {"${keys.join('": …, "')}": …}${more})`
|
|
164
|
+
: '(object — pass a JSON object)';
|
|
165
|
+
}
|
|
166
|
+
if (schema.type === 'array') {
|
|
167
|
+
const itemType = schema.items?.type ?? 'value';
|
|
168
|
+
return `(array of ${itemType} — pass JSON like ["..."])`;
|
|
169
|
+
}
|
|
170
|
+
if (schema.type === 'integer' || schema.type === 'number') {
|
|
171
|
+
return `(${schema.type})`;
|
|
172
|
+
}
|
|
173
|
+
if (schema.type === 'boolean') {
|
|
174
|
+
return '(boolean — true or false)';
|
|
175
|
+
}
|
|
176
|
+
return `(${schema.type})`;
|
|
177
|
+
}
|
|
178
|
+
function renderSchemaFragment(s) {
|
|
179
|
+
const out = {};
|
|
180
|
+
if (s.type)
|
|
181
|
+
out.type = s.type;
|
|
182
|
+
if (s.description)
|
|
183
|
+
out.description = s.description;
|
|
184
|
+
if (s.enum)
|
|
185
|
+
out.enum = s.enum;
|
|
186
|
+
if (s.type === 'object' && s.properties) {
|
|
187
|
+
out.properties = Object.fromEntries(Object.entries(s.properties).map(([k, v]) => [k, renderSchemaFragment(v)]));
|
|
188
|
+
if (s.required && s.required.length > 0) {
|
|
189
|
+
out.required = s.required;
|
|
190
|
+
}
|
|
191
|
+
// Defaulting additionalProperties:false here would be safer but
|
|
192
|
+
// some MCP servers depend on extra fields passing through; leave
|
|
193
|
+
// unset so the provider doesn't reject valid calls.
|
|
194
|
+
}
|
|
195
|
+
else if (s.type === 'array' && s.items) {
|
|
196
|
+
out.items = renderSchemaFragment(s.items);
|
|
197
|
+
}
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=tool-registry.js.map
|