@compilr-dev/sdk 0.1.5 → 0.1.6

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/dist/index.d.ts CHANGED
@@ -43,6 +43,8 @@ export { resolveProvider, detectProviderFromEnv, createProviderFromType } from '
43
43
  export { DEFAULT_MODELS, getContextWindow, DEFAULT_CONTEXT_WINDOW } from './models.js';
44
44
  export { type ModelTier, type TierInfo, type ProviderModelMap, MODEL_TIERS, TIER_INFO, isValidTier, type ThinkingFormat, type ModelStatus, type ModelInfo, MODEL_REGISTRY, getModelsForProvider, getModelsSortedForDisplay, getModelInfo, isKnownModel, isModelSupported, getThinkingFormat, getStatusIndicator, getStatusLabel, getDefaultModelForTier, areThinkingFormatsCompatible, shouldClearHistoryOnModelChange, getModelContextWindow, getModelDisplayName, getModelDescription, getModelForTier, getTierMappings, getTierDisplayName, getShortModelName, getDefaultTierMappings, type ProviderMetadata, type OthersProviderModel, PROVIDER_METADATA, TOGETHER_MODELS, GROQ_MODELS, FIREWORKS_MODELS, PERPLEXITY_MODELS, OPENROUTER_MODELS, getModelsForOthersProvider, getOthersProviders, getProviderMetadata, isOthersProvider, } from './models/index.js';
45
45
  export { assembleTools, deduplicateTools } from './tools.js';
46
+ export { MetaToolsRegistry, createMetaTools, META_TOOLS_SYSTEM_PROMPT_PREFIX, } from './meta-tools/index.js';
47
+ export type { MetaToolStats, MetaTools } from './meta-tools/index.js';
46
48
  export { SystemPromptBuilder, buildSystemPrompt, detectGitRepository, getModuleStats, ALL_MODULES, IDENTITY_MODULE, STYLE_MODULE, TASK_EXECUTION_MODULE, TODO_MANAGEMENT_MODULE, TOOL_USAGE_DIRECT_MODULE, TOOL_USAGE_META_MODULE, DELEGATION_MODULE, GIT_SAFETY_MODULE, SUGGEST_MODULE, IMPORTANT_RULES_MODULE, ENVIRONMENT_MODULE, shouldIncludeModule, getEstimatedTokensForConditions, getTotalEstimatedTokens, } from './system-prompt/index.js';
47
49
  export type { SystemPromptContext, BuildResult, SystemPromptModule, ModuleConditions, } from './system-prompt/index.js';
48
50
  export { defineTool, createSuccessResult, createErrorResult, mergeHooks, createLoggingHooks, createClaudeProvider, createOpenAIProvider, createGeminiNativeProvider, createOllamaProvider, createTogetherProvider, createGroqProvider, createFireworksProvider, createPerplexityProvider, createOpenRouterProvider, createMockProvider, MockProvider, Agent, ContextManager, DEFAULT_CONTEXT_CONFIG, createTaskTool, createSuggestTool, defaultAgentTypes, TOOL_SETS, BUILTIN_GUARDRAILS, TOOL_NAMES, getDefaultShellManager, builtinSkills, AnchorManager, MCPManager, AgentError, ProviderError, ToolError, ToolTimeoutError, MaxIterationsError, AbortError, } from '@compilr-dev/agents';
package/dist/index.js CHANGED
@@ -61,6 +61,10 @@ getModelForTier, getTierMappings, getTierDisplayName, getShortModelName, getDefa
61
61
  // =============================================================================
62
62
  export { assembleTools, deduplicateTools } from './tools.js';
63
63
  // =============================================================================
64
+ // Meta-Tools Registry (dynamic tool loading for token reduction)
65
+ // =============================================================================
66
+ export { MetaToolsRegistry, createMetaTools, META_TOOLS_SYSTEM_PROMPT_PREFIX, } from './meta-tools/index.js';
67
+ // =============================================================================
64
68
  // System Prompt Builder
65
69
  // =============================================================================
66
70
  export {
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Meta-tools — Dynamic tool loading for token reduction.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { MetaToolsRegistry, createMetaTools } from '@compilr-dev/sdk';
7
+ *
8
+ * const registry = new MetaToolsRegistry();
9
+ * registry.initialize(myTools);
10
+ *
11
+ * const metaTools = createMetaTools(registry);
12
+ * // Use metaTools.getToolInfoTool as a direct tool
13
+ * // Use metaTools.createFallback() for transparent routing
14
+ * ```
15
+ */
16
+ export { MetaToolsRegistry, createMetaTools, META_TOOLS_SYSTEM_PROMPT_PREFIX, type MetaToolStats, type MetaTools, } from './registry.js';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Meta-tools — Dynamic tool loading for token reduction.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { MetaToolsRegistry, createMetaTools } from '@compilr-dev/sdk';
7
+ *
8
+ * const registry = new MetaToolsRegistry();
9
+ * registry.initialize(myTools);
10
+ *
11
+ * const metaTools = createMetaTools(registry);
12
+ * // Use metaTools.getToolInfoTool as a direct tool
13
+ * // Use metaTools.createFallback() for transparent routing
14
+ * ```
15
+ */
16
+ export { MetaToolsRegistry, createMetaTools, META_TOOLS_SYSTEM_PROMPT_PREFIX, } from './registry.js';
@@ -0,0 +1,94 @@
1
+ /**
2
+ * MetaToolsRegistry — Instance-based meta-tools for SDK consumers.
3
+ *
4
+ * Replaces full tool declarations (~15K tokens for 49 tools) with:
5
+ * 1. A compact tool index in the system prompt (~800 tokens)
6
+ * 2. Three meta-tools: list_tools, get_tool_info, use_tool
7
+ * 3. A transparent fallback handler for direct tool calls
8
+ *
9
+ * Each agent gets its own registry instance, enabling multi-agent
10
+ * scenarios where each agent has a different tool set.
11
+ */
12
+ import { type Tool, type ToolExecutionResult } from '@compilr-dev/agents';
13
+ /**
14
+ * Statistics about the meta-tools registry.
15
+ */
16
+ export interface MetaToolStats {
17
+ /** Total tools in the registry */
18
+ registeredTools: number;
19
+ /** Tools allowed by the current filter (or all if no filter) */
20
+ allowedTools: number;
21
+ /** Estimated token savings vs declaring all tools directly */
22
+ estimatedTokenSavings: number;
23
+ }
24
+ /**
25
+ * The set of meta-tools and fallback handler returned by createMetaTools().
26
+ */
27
+ export interface MetaTools {
28
+ /** Lists available tools by category */
29
+ listToolsTool: Tool;
30
+ /** Returns the JSON schema for a tool's parameters */
31
+ getToolInfoTool: Tool;
32
+ /** Executes any registered tool by name */
33
+ useToolTool: Tool;
34
+ /** Creates a fallback handler for transparent tool routing */
35
+ createFallback: () => (name: string, input: Record<string, unknown>) => Promise<ToolExecutionResult | null>;
36
+ }
37
+ export declare class MetaToolsRegistry {
38
+ private readonly toolRegistry;
39
+ private readonly ajv;
40
+ private currentFilter;
41
+ /**
42
+ * Populate the registry with available tools.
43
+ * Call this once at startup with all tools that should be available via meta-tools.
44
+ */
45
+ initialize(tools: Tool[]): void;
46
+ /**
47
+ * Set the current tool filter for meta-registry access.
48
+ * Pass null or undefined to allow all tools.
49
+ */
50
+ setFilter(filter: string[] | null | undefined): void;
51
+ /**
52
+ * Get the current tool filter.
53
+ */
54
+ getFilter(): Set<string> | null;
55
+ /**
56
+ * Check if a tool is allowed by the current filter.
57
+ */
58
+ isToolAllowed(name: string): boolean;
59
+ /**
60
+ * Get all registered tools.
61
+ */
62
+ getRegisteredTools(): Tool[];
63
+ /**
64
+ * Get a tool by name from the registry.
65
+ */
66
+ getTool(name: string): Tool | undefined;
67
+ /**
68
+ * Get count of registered tools.
69
+ */
70
+ getToolCount(): number;
71
+ /**
72
+ * Generate tool index for the system prompt.
73
+ * Groups tools by category and shows signatures.
74
+ */
75
+ generateToolIndex(): string;
76
+ /**
77
+ * Get the full system prompt section (prefix + index).
78
+ */
79
+ getToolIndexForSystemPrompt(): string;
80
+ /**
81
+ * Get registry statistics.
82
+ */
83
+ getStats(): MetaToolStats;
84
+ /**
85
+ * Validate arguments against a tool's schema.
86
+ * Returns null if valid, or an error message string.
87
+ */
88
+ validateArgs(toolName: string, args: Record<string, unknown>): string | null;
89
+ }
90
+ /**
91
+ * Create the three meta-tools + fallback handler, all bound to a registry instance.
92
+ */
93
+ export declare function createMetaTools(registry: MetaToolsRegistry): MetaTools;
94
+ export declare const META_TOOLS_SYSTEM_PROMPT_PREFIX = "\n## Tool Index (Specialized Tools)\n\nThese tools are called **exactly like direct tools** \u2014 just use the tool name with parameters. No special syntax or wrapper needed. The system routes them automatically.\n\n**IMPORTANT \u2014 These are CLI system tools, NOT your project's backend. Never use localhost/curl to access them.**\n\n**Parameter Rules:**\n- For **zero-parameter calls**: call the tool directly (e.g., `workitem_query()`, `git_status()`).\n- For **calls WITH parameters**: you MUST call `get_tool_info(\"tool_name\")` first to get the exact JSON schema. The signatures below are summaries only \u2014 do NOT guess parameter structure from them.\n- After a failed tool call, always call `get_tool_info()` before retrying.\n\n";
@@ -0,0 +1,406 @@
1
+ /**
2
+ * MetaToolsRegistry — Instance-based meta-tools for SDK consumers.
3
+ *
4
+ * Replaces full tool declarations (~15K tokens for 49 tools) with:
5
+ * 1. A compact tool index in the system prompt (~800 tokens)
6
+ * 2. Three meta-tools: list_tools, get_tool_info, use_tool
7
+ * 3. A transparent fallback handler for direct tool calls
8
+ *
9
+ * Each agent gets its own registry instance, enabling multi-agent
10
+ * scenarios where each agent has a different tool set.
11
+ */
12
+ import Ajv from 'ajv';
13
+ import { defineTool, createSuccessResult, createErrorResult, } from '@compilr-dev/agents';
14
+ // =============================================================================
15
+ // MetaToolsRegistry class
16
+ // =============================================================================
17
+ export class MetaToolsRegistry {
18
+ toolRegistry = new Map();
19
+ ajv = new Ajv({ allErrors: true });
20
+ currentFilter = null;
21
+ /**
22
+ * Populate the registry with available tools.
23
+ * Call this once at startup with all tools that should be available via meta-tools.
24
+ */
25
+ initialize(tools) {
26
+ this.toolRegistry.clear();
27
+ for (const tool of tools) {
28
+ this.toolRegistry.set(tool.definition.name, tool);
29
+ }
30
+ }
31
+ /**
32
+ * Set the current tool filter for meta-registry access.
33
+ * Pass null or undefined to allow all tools.
34
+ */
35
+ setFilter(filter) {
36
+ this.currentFilter = filter ? new Set(filter) : null;
37
+ }
38
+ /**
39
+ * Get the current tool filter.
40
+ */
41
+ getFilter() {
42
+ return this.currentFilter;
43
+ }
44
+ /**
45
+ * Check if a tool is allowed by the current filter.
46
+ */
47
+ isToolAllowed(name) {
48
+ if (!this.currentFilter) {
49
+ return true;
50
+ }
51
+ return this.currentFilter.has(name);
52
+ }
53
+ /**
54
+ * Get all registered tools.
55
+ */
56
+ getRegisteredTools() {
57
+ return Array.from(this.toolRegistry.values());
58
+ }
59
+ /**
60
+ * Get a tool by name from the registry.
61
+ */
62
+ getTool(name) {
63
+ return this.toolRegistry.get(name);
64
+ }
65
+ /**
66
+ * Get count of registered tools.
67
+ */
68
+ getToolCount() {
69
+ return this.toolRegistry.size;
70
+ }
71
+ /**
72
+ * Generate tool index for the system prompt.
73
+ * Groups tools by category and shows signatures.
74
+ */
75
+ generateToolIndex() {
76
+ const tools = this.getRegisteredTools();
77
+ if (tools.length === 0) {
78
+ return '(No tools registered in meta-tool registry)';
79
+ }
80
+ // Filter by allowed tools
81
+ const allowedTools = tools.filter((t) => this.isToolAllowed(t.definition.name));
82
+ // Group tools by prefix
83
+ const groups = {};
84
+ for (const tool of allowedTools) {
85
+ const prefix = tool.definition.name.split('_')[0];
86
+ const category = getCategoryName(prefix);
87
+ groups[category] = groups[category] ?? [];
88
+ groups[category].push(tool);
89
+ }
90
+ // Build index with signatures
91
+ const lines = [];
92
+ for (const [category, categoryTools] of Object.entries(groups).sort()) {
93
+ lines.push(`### ${category}`);
94
+ for (const tool of categoryTools) {
95
+ const signature = buildToolSignature(tool);
96
+ lines.push(`- ${signature}`);
97
+ }
98
+ lines.push('');
99
+ }
100
+ return lines.join('\n');
101
+ }
102
+ /**
103
+ * Get the full system prompt section (prefix + index).
104
+ */
105
+ getToolIndexForSystemPrompt() {
106
+ return META_TOOLS_SYSTEM_PROMPT_PREFIX + this.generateToolIndex();
107
+ }
108
+ /**
109
+ * Get registry statistics.
110
+ */
111
+ getStats() {
112
+ const registeredTools = this.toolRegistry.size;
113
+ const allowedTools = this.getRegisteredTools().filter((t) => this.isToolAllowed(t.definition.name)).length;
114
+ // ~300 tokens per full tool definition, ~800 tokens for the index
115
+ const tokensPerTool = 300;
116
+ const estimatedTokenSavings = registeredTools * tokensPerTool - 800;
117
+ return {
118
+ registeredTools,
119
+ allowedTools,
120
+ estimatedTokenSavings: Math.max(0, estimatedTokenSavings),
121
+ };
122
+ }
123
+ /**
124
+ * Validate arguments against a tool's schema.
125
+ * Returns null if valid, or an error message string.
126
+ */
127
+ validateArgs(toolName, args) {
128
+ const tool = this.toolRegistry.get(toolName);
129
+ if (!tool) {
130
+ return `Unknown tool: '${toolName}'`;
131
+ }
132
+ const schema = tool.definition.inputSchema;
133
+ const validate = this.ajv.compile(schema);
134
+ const valid = validate(args);
135
+ if (!valid) {
136
+ return formatValidationErrors(validate.errors);
137
+ }
138
+ return null;
139
+ }
140
+ }
141
+ // =============================================================================
142
+ // Meta-tool factory
143
+ // =============================================================================
144
+ /**
145
+ * Create the three meta-tools + fallback handler, all bound to a registry instance.
146
+ */
147
+ export function createMetaTools(registry) {
148
+ // -------------------------------------------------------------------------
149
+ // list_tools
150
+ // -------------------------------------------------------------------------
151
+ const listToolsTool = defineTool({
152
+ name: 'list_tools',
153
+ description: 'List all available specialized tools. Call this first to see what tools are available ' +
154
+ 'before using use_tool. Optionally filter by category.',
155
+ inputSchema: {
156
+ type: 'object',
157
+ properties: {
158
+ category: {
159
+ type: 'string',
160
+ description: 'Optional category filter (e.g., "git", "project", "workitem", "plan", "anchor")',
161
+ },
162
+ },
163
+ required: [],
164
+ },
165
+ execute: ({ category }) => {
166
+ const tools = registry.getRegisteredTools();
167
+ // Filter by allowed tools
168
+ let filteredTools = tools.filter((t) => registry.isToolAllowed(t.definition.name));
169
+ // Filter by category if specified
170
+ if (category) {
171
+ const prefix = category.toLowerCase();
172
+ filteredTools = filteredTools.filter((t) => t.definition.name.toLowerCase().startsWith(prefix));
173
+ }
174
+ const toolList = filteredTools.map((t) => ({
175
+ name: t.definition.name,
176
+ description: t.definition.description.split('.')[0],
177
+ }));
178
+ return Promise.resolve(createSuccessResult({
179
+ count: toolList.length,
180
+ tools: toolList,
181
+ hint: 'Use get_tool_info("tool_name") to see full parameter details for any tool.',
182
+ }));
183
+ },
184
+ });
185
+ // -------------------------------------------------------------------------
186
+ // get_tool_info
187
+ // -------------------------------------------------------------------------
188
+ const getToolInfoTool = defineTool({
189
+ name: 'get_tool_info',
190
+ description: "Get the exact JSON schema for a tool's parameters. " +
191
+ 'MUST be called before passing any parameters to a Tool Index tool. ' +
192
+ 'Zero-parameter calls do not need this.',
193
+ inputSchema: {
194
+ type: 'object',
195
+ properties: {
196
+ tool_name: {
197
+ type: 'string',
198
+ description: 'Name of the tool from the Tool Index',
199
+ },
200
+ },
201
+ required: ['tool_name'],
202
+ },
203
+ execute: ({ tool_name }) => {
204
+ const tool = registry.getTool(tool_name);
205
+ if (!tool) {
206
+ const availableTools = registry
207
+ .getRegisteredTools()
208
+ .map((t) => t.definition.name)
209
+ .slice(0, 10);
210
+ return Promise.resolve(createErrorResult(`Unknown tool: '${tool_name}'. ` +
211
+ `Available tools include: ${availableTools.join(', ')}... ` +
212
+ `Check the Tool Index for the full list.`));
213
+ }
214
+ return Promise.resolve(createSuccessResult({
215
+ name: tool.definition.name,
216
+ description: tool.definition.description,
217
+ parameters: tool.definition.inputSchema,
218
+ }));
219
+ },
220
+ });
221
+ // -------------------------------------------------------------------------
222
+ // use_tool
223
+ // -------------------------------------------------------------------------
224
+ const useToolTool = defineTool({
225
+ name: 'use_tool',
226
+ description: 'Execute any tool from the Tool Index. Check the Tool Index for ' +
227
+ 'available tools and their parameters. For complex parameters, ' +
228
+ 'call get_tool_info first.',
229
+ inputSchema: {
230
+ type: 'object',
231
+ properties: {
232
+ tool_name: {
233
+ type: 'string',
234
+ description: 'Name of the tool to execute (from Tool Index)',
235
+ },
236
+ args: {
237
+ type: 'object',
238
+ description: 'Arguments to pass to the tool. Must match the tool schema.',
239
+ additionalProperties: true,
240
+ },
241
+ },
242
+ required: ['tool_name', 'args'],
243
+ },
244
+ execute: async ({ tool_name, args }) => {
245
+ // 0. Check tool filter
246
+ if (!registry.isToolAllowed(tool_name)) {
247
+ const filter = registry.getFilter();
248
+ const allowedTools = filter
249
+ ? Array.from(filter).filter((t) => registry.getTool(t) !== undefined)
250
+ : [];
251
+ return createErrorResult(`Tool '${tool_name}' is not available for this agent. ` +
252
+ `Your available meta-registry tools: ${allowedTools.slice(0, 10).join(', ')}${allowedTools.length > 10 ? '...' : ''} ` +
253
+ `Call list_tools() to see all available tools.`);
254
+ }
255
+ // 1. Find the tool
256
+ const tool = registry.getTool(tool_name);
257
+ if (!tool) {
258
+ const availableTools = registry
259
+ .getRegisteredTools()
260
+ .filter((t) => registry.isToolAllowed(t.definition.name))
261
+ .map((t) => t.definition.name)
262
+ .slice(0, 10);
263
+ return createErrorResult(`Unknown tool: '${tool_name}'. ` +
264
+ `Available tools include: ${availableTools.join(', ')}... ` +
265
+ `Check the Tool Index for the full list.`);
266
+ }
267
+ // 2. Validate args
268
+ const validationError = registry.validateArgs(tool_name, args);
269
+ if (validationError) {
270
+ return createErrorResult(`Invalid arguments for '${tool_name}': ${validationError}. ` +
271
+ `Expected schema: ${JSON.stringify(tool.definition.inputSchema, null, 2)}. ` +
272
+ `Hint: Call get_tool_info("${tool_name}") to see full parameter details.`);
273
+ }
274
+ // 3. Execute the tool
275
+ try {
276
+ const result = await tool.execute(args);
277
+ // Enhance result with clear top-level message for smaller models
278
+ if (result.success && typeof result.result === 'object' && result.result !== null) {
279
+ const innerResult = result.result;
280
+ const innerMessage = typeof innerResult.message === 'string' ? innerResult.message : null;
281
+ return createSuccessResult({
282
+ tool: tool_name,
283
+ status: 'completed',
284
+ message: innerMessage ?? `Tool '${tool_name}' executed successfully.`,
285
+ result: innerResult,
286
+ });
287
+ }
288
+ return result;
289
+ }
290
+ catch (err) {
291
+ const errorMessage = err instanceof Error ? err.message : String(err);
292
+ return createErrorResult(`Tool '${tool_name}' execution failed: ${errorMessage}`);
293
+ }
294
+ },
295
+ });
296
+ // -------------------------------------------------------------------------
297
+ // Fallback handler factory
298
+ // -------------------------------------------------------------------------
299
+ function createFallback() {
300
+ return async (name, input) => {
301
+ // Check if tool exists in registry
302
+ const tool = registry.getTool(name);
303
+ if (!tool) {
304
+ return null; // Not in registry — let default "not found" error through
305
+ }
306
+ // Check tool filter
307
+ if (!registry.isToolAllowed(name)) {
308
+ const filter = registry.getFilter();
309
+ const allowedTools = filter
310
+ ? Array.from(filter).filter((t) => registry.getTool(t) !== undefined)
311
+ : [];
312
+ return createErrorResult(`Tool '${name}' is not available for this agent. ` +
313
+ `Available tools: ${allowedTools.slice(0, 10).join(', ')}${allowedTools.length > 10 ? '...' : ''}`);
314
+ }
315
+ // Validate args
316
+ const validationError = registry.validateArgs(name, input);
317
+ if (validationError) {
318
+ return createErrorResult(`Invalid arguments for '${name}': ${validationError}. ` +
319
+ `Call get_tool_info("${name}") to get the exact parameter schema before retrying.`);
320
+ }
321
+ // Execute the tool
322
+ try {
323
+ return await tool.execute(input);
324
+ }
325
+ catch (err) {
326
+ const errorMessage = err instanceof Error ? err.message : String(err);
327
+ return createErrorResult(`Tool '${name}' execution failed: ${errorMessage}`);
328
+ }
329
+ };
330
+ }
331
+ return {
332
+ listToolsTool: listToolsTool,
333
+ getToolInfoTool: getToolInfoTool,
334
+ useToolTool: useToolTool,
335
+ createFallback,
336
+ };
337
+ }
338
+ // =============================================================================
339
+ // System prompt constant
340
+ // =============================================================================
341
+ export const META_TOOLS_SYSTEM_PROMPT_PREFIX = `
342
+ ## Tool Index (Specialized Tools)
343
+
344
+ These tools are called **exactly like direct tools** — just use the tool name with parameters. No special syntax or wrapper needed. The system routes them automatically.
345
+
346
+ **IMPORTANT — These are CLI system tools, NOT your project's backend. Never use localhost/curl to access them.**
347
+
348
+ **Parameter Rules:**
349
+ - For **zero-parameter calls**: call the tool directly (e.g., \`workitem_query()\`, \`git_status()\`).
350
+ - For **calls WITH parameters**: you MUST call \`get_tool_info("tool_name")\` first to get the exact JSON schema. The signatures below are summaries only — do NOT guess parameter structure from them.
351
+ - After a failed tool call, always call \`get_tool_info()\` before retrying.
352
+
353
+ `;
354
+ // =============================================================================
355
+ // Helpers (internal)
356
+ // =============================================================================
357
+ /**
358
+ * Map tool prefix to category name.
359
+ */
360
+ function getCategoryName(prefix) {
361
+ const categoryMap = {
362
+ git: 'Git Operations',
363
+ project: 'Project Management',
364
+ workitem: 'Work Items',
365
+ plan: 'Planning',
366
+ document: 'Documents',
367
+ anchor: 'Context Anchors',
368
+ backlog: 'Backlog',
369
+ detect: 'Analysis',
370
+ find: 'Analysis',
371
+ run: 'Runners',
372
+ };
373
+ return categoryMap[prefix] ?? 'Other';
374
+ }
375
+ /**
376
+ * Build a concise signature for a tool.
377
+ * e.g., "git_commit(message: string, files?: string[]) - Create a commit"
378
+ */
379
+ function buildToolSignature(tool) {
380
+ const schema = tool.definition.inputSchema;
381
+ const params = [];
382
+ if (schema.properties) {
383
+ const required = new Set(schema.required ?? []);
384
+ for (const [name, prop] of Object.entries(schema.properties)) {
385
+ const isRequired = required.has(name);
386
+ const type = prop.type ?? 'any';
387
+ params.push(isRequired ? `${name}: ${type}` : `${name}?: ${type}`);
388
+ }
389
+ }
390
+ const paramsStr = params.length > 0 ? params.join(', ') : '';
391
+ const desc = tool.definition.description.split('.')[0]; // First sentence
392
+ return `${tool.definition.name}(${paramsStr}) - ${desc}`;
393
+ }
394
+ /**
395
+ * Format AJV validation errors into a readable string.
396
+ */
397
+ function formatValidationErrors(errors) {
398
+ if (!errors || errors.length === 0) {
399
+ return 'Unknown validation error';
400
+ }
401
+ const messages = errors.map((e) => {
402
+ const path = e.dataPath ? e.dataPath.replace(/^\./, '') : 'args';
403
+ return `${path}: ${e.message ?? 'validation failed'}`;
404
+ });
405
+ return messages.join('; ');
406
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compilr-dev/sdk",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Universal agent runtime for building AI-powered applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -52,6 +52,9 @@
52
52
  "engines": {
53
53
  "node": ">=18.0.0"
54
54
  },
55
+ "dependencies": {
56
+ "ajv": "^6.14.0"
57
+ },
55
58
  "peerDependencies": {
56
59
  "@compilr-dev/agents": "^0.3.14",
57
60
  "@compilr-dev/agents-coding": "^1.0.2"