@compilr-dev/sdk 0.1.18 → 0.1.20

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.
@@ -260,15 +260,17 @@ export function createMetaTools(registry) {
260
260
  `Available tools include: ${availableTools.join(', ')}... ` +
261
261
  `Check the Tool Index for the full list.`);
262
262
  }
263
- // 2. Validate args
264
- const validationError = registry.validateArgs(tool_name, args);
263
+ // 2. Coerce + validate args
264
+ const toolSchema = tool.definition.inputSchema;
265
+ const coercedArgs = coerceArgs(toolSchema, args);
266
+ const validationError = registry.validateArgs(tool_name, coercedArgs);
265
267
  if (validationError) {
266
268
  return createErrorResult(`Invalid arguments for '${tool_name}': ${validationError}.\n` +
267
269
  `Expected:\n${buildCompactSchema(tool)}`);
268
270
  }
269
271
  // 3. Execute the tool
270
272
  try {
271
- const result = await tool.execute(args);
273
+ const result = await tool.execute(coercedArgs);
272
274
  // Enhance result with clear top-level message for smaller models
273
275
  if (result.success && typeof result.result === 'object' && result.result !== null) {
274
276
  const innerResult = result.result;
@@ -307,15 +309,18 @@ export function createMetaTools(registry) {
307
309
  return createErrorResult(`Tool '${name}' is not available for this agent. ` +
308
310
  `Available tools: ${allowedTools.slice(0, 10).join(', ')}${allowedTools.length > 10 ? '...' : ''}`);
309
311
  }
312
+ // Coerce arguments before validation (handles LLM mistakes without guided decoding)
313
+ const toolSchema = tool.definition.inputSchema;
314
+ const coercedInput = coerceArgs(toolSchema, input);
310
315
  // Validate args
311
- const validationError = registry.validateArgs(name, input);
316
+ const validationError = registry.validateArgs(name, coercedInput);
312
317
  if (validationError) {
313
318
  return createErrorResult(`Invalid arguments for '${name}': ${validationError}. ` +
314
319
  `Call get_tool_info("${name}") to get the exact parameter schema before retrying.`);
315
320
  }
316
321
  // Execute the tool
317
322
  try {
318
- return await tool.execute(input);
323
+ return await tool.execute(coercedInput);
319
324
  }
320
325
  catch (err) {
321
326
  const errorMessage = err instanceof Error ? err.message : String(err);
@@ -437,6 +442,26 @@ function buildCompactSchema(tool) {
437
442
  detail += ' (required)';
438
443
  }
439
444
  paramDetails.push(detail);
445
+ // For array-of-objects, show item properties as indented sub-details
446
+ if (prop.type === 'array') {
447
+ const items = prop.items;
448
+ if (items?.type === 'object' && items.properties) {
449
+ const itemProps = items.properties;
450
+ const itemRequired = new Set(items.required ?? []);
451
+ for (const [itemName, itemProp] of Object.entries(itemProps)) {
452
+ const itemDesc = itemProp.description;
453
+ const itemEnum = itemProp.enum;
454
+ let itemDetail = ` - ${itemName}: ${resolveCompactType(itemProp)}`;
455
+ if (itemDesc)
456
+ itemDetail += ` — ${itemDesc}`;
457
+ if (itemEnum)
458
+ itemDetail += ` (${itemEnum.map((v) => `"${v}"`).join('|')})`;
459
+ if (itemRequired.has(itemName))
460
+ itemDetail += ' (required)';
461
+ paramDetails.push(itemDetail);
462
+ }
463
+ }
464
+ }
440
465
  }
441
466
  }
442
467
  const paramsStr = params.join(', ');
@@ -447,6 +472,45 @@ function buildCompactSchema(tool) {
447
472
  }
448
473
  return lines.join('\n');
449
474
  }
475
+ /**
476
+ * Attempt to coerce arguments to match the tool schema.
477
+ * Handles common LLM mistakes when calling tools without guided decoding:
478
+ * - Single object where array expected → wraps in array
479
+ * - JSON string where array expected → parses it
480
+ */
481
+ function coerceArgs(schema, args) {
482
+ const properties = schema.properties;
483
+ if (!properties)
484
+ return args;
485
+ let changed = false;
486
+ const coerced = { ...args };
487
+ for (const [name, prop] of Object.entries(properties)) {
488
+ if (prop.type === 'array' && name in coerced && !Array.isArray(coerced[name])) {
489
+ const value = coerced[name];
490
+ if (value !== null && value !== undefined) {
491
+ if (typeof value === 'object') {
492
+ // Single object → wrap in array
493
+ coerced[name] = [value];
494
+ changed = true;
495
+ }
496
+ else if (typeof value === 'string') {
497
+ // JSON string → try parsing
498
+ try {
499
+ const parsed = JSON.parse(value);
500
+ if (Array.isArray(parsed)) {
501
+ coerced[name] = parsed;
502
+ changed = true;
503
+ }
504
+ }
505
+ catch {
506
+ // Leave as-is, will fail validation
507
+ }
508
+ }
509
+ }
510
+ }
511
+ }
512
+ return changed ? coerced : args;
513
+ }
450
514
  /**
451
515
  * Format AJV validation errors into a readable string.
452
516
  */
@@ -16,6 +16,7 @@ export declare function createProviderFromType(type: ProviderType, options?: {
16
16
  apiKey?: string;
17
17
  baseUrl?: string;
18
18
  siteName?: string;
19
+ estimateTokens?: (text: string) => number;
19
20
  }): LLMProvider;
20
21
  /**
21
22
  * Resolve a provider from config.
package/dist/provider.js CHANGED
@@ -32,29 +32,29 @@ export function detectProviderFromEnv() {
32
32
  * Create an LLM provider from a provider type string.
33
33
  */
34
34
  export function createProviderFromType(type, options) {
35
- const { model, apiKey, baseUrl, siteName } = options ?? {};
35
+ const { model, apiKey, baseUrl, siteName, estimateTokens } = options ?? {};
36
36
  switch (type) {
37
37
  case 'claude':
38
- return createClaudeProvider({ model, apiKey });
38
+ return createClaudeProvider({ model, apiKey, estimateTokens });
39
39
  case 'openai':
40
- return createOpenAIProvider({ model, apiKey });
40
+ return createOpenAIProvider({ model, apiKey, estimateTokens });
41
41
  case 'gemini':
42
- return createGeminiNativeProvider({ model, apiKey });
42
+ return createGeminiNativeProvider({ model, apiKey, estimateTokens });
43
43
  case 'ollama':
44
- return createOllamaProvider({ model, baseUrl });
44
+ return createOllamaProvider({ model, baseUrl, estimateTokens });
45
45
  case 'together':
46
- return createTogetherProvider({ model, apiKey });
46
+ return createTogetherProvider({ model, apiKey, estimateTokens });
47
47
  case 'groq':
48
- return createGroqProvider({ model, apiKey });
48
+ return createGroqProvider({ model, apiKey, estimateTokens });
49
49
  case 'fireworks':
50
- return createFireworksProvider({ model, apiKey });
50
+ return createFireworksProvider({ model, apiKey, estimateTokens });
51
51
  case 'perplexity':
52
- return createPerplexityProvider({ model, apiKey });
52
+ return createPerplexityProvider({ model, apiKey, estimateTokens });
53
53
  case 'openrouter':
54
- return createOpenRouterProvider({ model, apiKey, siteName });
54
+ return createOpenRouterProvider({ model, apiKey, siteName, estimateTokens });
55
55
  case 'custom':
56
56
  // Custom endpoints use OpenAI-compatible format
57
- return createOpenAIProvider({ model, apiKey });
57
+ return createOpenAIProvider({ model, apiKey, estimateTokens });
58
58
  }
59
59
  }
60
60
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compilr-dev/sdk",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "Universal agent runtime for building AI-powered applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",