@webmcp-auto-ui/agent 2.5.22 → 2.5.24

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webmcp-auto-ui/agent",
3
- "version": "2.5.22",
3
+ "version": "2.5.24",
4
4
  "description": "LLM agent loop + remote/WASM/local providers + MCP wrapper",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "type": "module",
@@ -4,7 +4,7 @@ import type { ToolLayer } from './tool-layers.js';
4
4
  import type { ProviderTool } from './types.js';
5
5
  import { sanitizeServerName } from './tool-layers.js';
6
6
  import { sanitizeSchemaWithReport } from '@webmcp-auto-ui/core';
7
- import type { JsonSchema } from '@webmcp-auto-ui/core';
7
+ import type { JsonSchema, SchemaPatch } from '@webmcp-auto-ui/core';
8
8
 
9
9
  export interface Diagnostic {
10
10
  severity: 'error' | 'warning';
@@ -117,11 +117,45 @@ export function runDiagnostics(
117
117
  for (const tool of checkTools) {
118
118
  const { patches } = sanitizeSchemaWithReport(tool.input_schema as JsonSchema);
119
119
  if (patches.length > 0) {
120
+ const addedPatches = patches.filter((p: SchemaPatch) => p.type === 'additionalProperties');
121
+ const removedPatches = patches.filter((p: SchemaPatch) => p.type === 'removed');
122
+
123
+ // Dedupe paths (with multiplier) for additionalProperties patches
124
+ const addedPathsFmt = formatCounted(addedPatches.map(p => p.path));
125
+ // Dedupe "keyword@path" entries for removed patches
126
+ const removedEntriesFmt = formatCounted(
127
+ removedPatches.map(p => `${p.keyword ?? 'unknown'}@${p.path}`),
128
+ );
129
+ const removedKeywords = Array.from(
130
+ new Set(removedPatches.map(p => p.keyword).filter((k): k is string => !!k)),
131
+ );
132
+
133
+ const detailParts: string[] = [];
134
+ if (addedPatches.length > 0) {
135
+ detailParts.push(
136
+ `${addedPatches.length} correction(s) for strict mode at ${addedPathsFmt}: additionalProperties: false added automatically.`,
137
+ );
138
+ }
139
+ if (removedPatches.length > 0) {
140
+ detailParts.push(
141
+ `${removedPatches.length} keyword(s) removed for strict mode: ${removedEntriesFmt}.`,
142
+ );
143
+ }
144
+
145
+ let codeFix: string;
146
+ if (addedPatches.length > 0 && removedPatches.length === 0) {
147
+ codeFix = `Add "additionalProperties": false to the MCP server schema for ${tool.name}.`;
148
+ } else if (removedPatches.length > 0 && addedPatches.length === 0) {
149
+ codeFix = `Remove unsupported JSON Schema keywords (${removedKeywords.join(', ')}) from the MCP server schema for ${tool.name}, or accept that Claude strict mode will ignore them.`;
150
+ } else {
151
+ codeFix = `Add "additionalProperties": false and remove unsupported keywords (${removedKeywords.join(', ')}) from the MCP server schema for ${tool.name}.`;
152
+ }
153
+
120
154
  diagnostics.push({
121
155
  severity: 'warning',
122
156
  title: `Schema patched: ${tool.name}`,
123
- detail: `${patches.length} correction(s) for strict mode: ${patches.map(p => p.path).join(', ')}. additionalProperties: false added automatically.`,
124
- codeFix: `Add "additionalProperties": false to the MCP server schema for ${tool.name}.`,
157
+ detail: detailParts.join(' '),
158
+ codeFix,
125
159
  });
126
160
  }
127
161
  }
@@ -130,6 +164,18 @@ export function runDiagnostics(
130
164
  return diagnostics;
131
165
  }
132
166
 
167
+ /**
168
+ * Dedupe a list of entries and format with a count multiplier when > 1.
169
+ * ["a", "a", "b"] → "a ×2, b"
170
+ */
171
+ function formatCounted(entries: string[]): string {
172
+ const counts = new Map<string, number>();
173
+ for (const e of entries) counts.set(e, (counts.get(e) ?? 0) + 1);
174
+ return Array.from(counts.entries())
175
+ .map(([entry, n]) => (n > 1 ? `${entry} ×${n}` : entry))
176
+ .join(', ');
177
+ }
178
+
133
179
  /** Check if a JSON schema has nested object properties (depth > 1) */
134
180
  function hasNestedObjects(schema: Record<string, unknown>): boolean {
135
181
  const props = schema.properties as Record<string, Record<string, unknown>> | undefined;
@@ -6,6 +6,9 @@
6
6
 
7
7
  import type { ProviderTool } from './types.js';
8
8
 
9
+ /** Tool names that are resolved locally from cache — hidden from user-facing browsers. */
10
+ export const DISCOVERY_TOOL_NAMES = new Set(['list_recipes', 'search_recipes', 'get_recipe', 'list_tools', 'search_tools']);
11
+
9
12
  export interface CachedRecipe {
10
13
  name: string;
11
14
  description?: string;
@@ -79,6 +82,12 @@ export class DiscoveryCache {
79
82
  return this.servers.get(serverPrefix)?.tools.length ?? 0;
80
83
  }
81
84
 
85
+ /** Tool count excluding discovery tools (hidden from user-facing browsers) */
86
+ browsableToolCount(serverPrefix: string): number {
87
+ const tools = this.servers.get(serverPrefix)?.tools ?? [];
88
+ return tools.filter(t => !DISCOVERY_TOOL_NAMES.has(t.name)).length;
89
+ }
90
+
82
91
  /**
83
92
  * Try to resolve a discovery tool call from cache.
84
93
  * Returns the result string if handled, or null if not a discovery tool.
package/src/index.ts CHANGED
@@ -29,7 +29,7 @@ export { buildToolsFromLayers, buildDiscoveryTools, buildDiscoveryToolsWithAlias
29
29
  export type { ToolLayer, McpLayer, WebMcpLayer, SystemPromptResult, DiscoveryToolsResult, SchemaTransformOptions, BuildToolsResult } from './tool-layers.js';
30
30
 
31
31
  // Discovery cache
32
- export { DiscoveryCache } from './discovery-cache.js';
32
+ export { DiscoveryCache, DISCOVERY_TOOL_NAMES } from './discovery-cache.js';
33
33
  export type { CachedRecipe, ServerCache } from './discovery-cache.js';
34
34
 
35
35
  // Re-export core WebMCP types
@@ -465,6 +465,8 @@ Unless a recipe specifies otherwise, use these tools to display your responses o
465
465
 
466
466
  ${actionTools.join('\n')}
467
467
 
468
+ widget_display may ONLY be called with data returned by a non-autoui DATA tool actually invoked in the current session. Fabricating IDs, URLs, names, dates, or any content not returned by a tool is a critical violation. If no DATA tool has been called yet, go back to STEP 1.
469
+
468
470
  STEP 5 — Fallback
469
471
 
470
472
  If previous steps failed, fall back to a classic chat without tool calling.`;