@webmcp-auto-ui/agent 2.5.25 → 2.5.27
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 +1 -1
- package/src/autoui-server.ts +44 -0
- package/src/diagnostics.ts +6 -6
- package/src/discovery-cache.ts +17 -3
- package/src/index.ts +18 -4
- package/src/loop.ts +31 -34
- package/src/notebook-widgets/compact.ts +312 -0
- package/src/notebook-widgets/document.ts +372 -0
- package/src/notebook-widgets/editorial.ts +348 -0
- package/src/notebook-widgets/recipes/compact.md +104 -0
- package/src/notebook-widgets/recipes/document.md +100 -0
- package/src/notebook-widgets/recipes/editorial.md +104 -0
- package/src/notebook-widgets/recipes/workspace.md +94 -0
- package/src/notebook-widgets/shared.ts +1064 -0
- package/src/notebook-widgets/workspace.ts +328 -0
- package/src/prompts/claude-prompt-builder.ts +81 -0
- package/src/prompts/gemma4-prompt-builder.ts +205 -0
- package/src/prompts/index.ts +55 -0
- package/src/prompts/mistral-prompt-builder.ts +90 -0
- package/src/prompts/qwen-prompt-builder.ts +90 -0
- package/src/prompts/tool-call-parsers.ts +322 -0
- package/src/prompts/tool-refs.ts +196 -0
- package/src/providers/factory.ts +20 -3
- package/src/providers/transformers-models.ts +143 -0
- package/src/providers/transformers-serialize.ts +81 -0
- package/src/providers/transformers.ts +329 -0
- package/src/providers/transformers.worker.ts +667 -0
- package/src/providers/wasm.ts +150 -510
- package/src/recipes/_generated.ts +515 -0
- package/src/recipes/canary-data.md +50 -0
- package/src/recipes/canary-display.md +99 -0
- package/src/recipes/canary-middle.md +32 -0
- package/src/recipes/hackathon-assemblee-nationale.md +111 -0
- package/src/recipes/hummingbird-data.md +32 -0
- package/src/recipes/hummingbird-display.md +36 -0
- package/src/recipes/hummingbird-middle.md +18 -0
- package/src/recipes/notebook-playbook.md +129 -0
- package/src/tool-layers.ts +33 -157
- package/src/trace-observer.ts +669 -0
- package/src/types.ts +20 -5
- package/src/util/opfs-cache.ts +265 -0
- package/tests/gemma-prompt.test.ts +472 -0
- package/tests/loop.test.ts +5 -5
- package/tests/transformers-serialize.test.ts +103 -0
- package/src/providers/gemma.worker.legacy.ts +0 -123
- package/src/providers/litert.worker.ts +0 -294
- package/src/recipes/widgets/actions.md +0 -28
- package/src/recipes/widgets/alert.md +0 -27
- package/src/recipes/widgets/cards.md +0 -41
- package/src/recipes/widgets/carousel.md +0 -39
- package/src/recipes/widgets/chart-rich.md +0 -51
- package/src/recipes/widgets/chart.md +0 -32
- package/src/recipes/widgets/code.md +0 -21
- package/src/recipes/widgets/d3.md +0 -36
- package/src/recipes/widgets/data-table.md +0 -46
- package/src/recipes/widgets/gallery.md +0 -39
- package/src/recipes/widgets/grid-data.md +0 -57
- package/src/recipes/widgets/hemicycle.md +0 -43
- package/src/recipes/widgets/js-sandbox.md +0 -32
- package/src/recipes/widgets/json-viewer.md +0 -27
- package/src/recipes/widgets/kv.md +0 -31
- package/src/recipes/widgets/list.md +0 -24
- package/src/recipes/widgets/log.md +0 -39
- package/src/recipes/widgets/map.md +0 -49
- package/src/recipes/widgets/profile.md +0 -49
- package/src/recipes/widgets/recipe-browser.md +0 -102
- package/src/recipes/widgets/sankey.md +0 -54
- package/src/recipes/widgets/stat-card.md +0 -43
- package/src/recipes/widgets/stat.md +0 -35
- package/src/recipes/widgets/tags.md +0 -30
- package/src/recipes/widgets/text.md +0 -19
- package/src/recipes/widgets/timeline.md +0 -38
- package/src/recipes/widgets/trombinoscope.md +0 -39
package/package.json
CHANGED
package/src/autoui-server.ts
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
|
|
5
5
|
import { createWebMcpServer, parseFrontmatter } from '@webmcp-auto-ui/core';
|
|
6
|
+
import { RAW_RECIPES } from './recipes/_generated.js';
|
|
7
|
+
|
|
8
|
+
// Notebook widget recipes (vanilla renderers)
|
|
9
|
+
// @ts-ignore — Vite raw imports, not resolved by tsc
|
|
10
|
+
import compactRecipe from './notebook-widgets/recipes/compact.md?raw';
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
import workspaceRecipe from './notebook-widgets/recipes/workspace.md?raw';
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
import documentRecipe from './notebook-widgets/recipes/document.md?raw';
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
import editorialRecipe from './notebook-widgets/recipes/editorial.md?raw';
|
|
17
|
+
|
|
18
|
+
// Notebook widget renderers (vanilla JS)
|
|
19
|
+
import { render as renderCompact } from './notebook-widgets/compact.js';
|
|
20
|
+
import { render as renderWorkspace } from './notebook-widgets/workspace.js';
|
|
21
|
+
import { render as renderDocument } from './notebook-widgets/document.js';
|
|
22
|
+
import { render as renderEditorial } from './notebook-widgets/editorial.js';
|
|
6
23
|
|
|
7
24
|
// ---------------------------------------------------------------------------
|
|
8
25
|
// Inline recipes (frontmatter + body)
|
|
@@ -1007,6 +1024,33 @@ for (const recipe of RECIPES) {
|
|
|
1007
1024
|
autoui.registerWidget(recipe, undefined);
|
|
1008
1025
|
}
|
|
1009
1026
|
|
|
1027
|
+
// Notebook widgets — vanilla renderers (resolved via WidgetRenderer vanilla path)
|
|
1028
|
+
const NOTEBOOK_WIDGETS: Array<[string, (container: HTMLElement, data: any) => any]> = [
|
|
1029
|
+
[compactRecipe as string, renderCompact],
|
|
1030
|
+
[workspaceRecipe as string, renderWorkspace],
|
|
1031
|
+
[documentRecipe as string, renderDocument],
|
|
1032
|
+
[editorialRecipe as string, renderEditorial],
|
|
1033
|
+
];
|
|
1034
|
+
for (const [recipe, renderer] of NOTEBOOK_WIDGETS) {
|
|
1035
|
+
autoui.registerWidget(recipe, renderer as any);
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// Register flow recipes (multi-step procedures) from the global recipe registry
|
|
1039
|
+
// that declare this server (autoui) in their frontmatter.
|
|
1040
|
+
for (const [key, rawMd] of Object.entries(RAW_RECIPES)) {
|
|
1041
|
+
const { frontmatter } = parseFrontmatter(rawMd);
|
|
1042
|
+
const servers = (Array.isArray(frontmatter.servers) ? frontmatter.servers : []) as string[];
|
|
1043
|
+
if (servers.map((s) => s.toLowerCase()).includes('autoui')) {
|
|
1044
|
+
try {
|
|
1045
|
+
autoui.registerRecipe(rawMd);
|
|
1046
|
+
} catch (e) {
|
|
1047
|
+
// Skip malformed recipes (missing id/name) — log for debugging
|
|
1048
|
+
// eslint-disable-next-line no-console
|
|
1049
|
+
console.warn(`[autoui] Failed to register flow recipe "${key}":`, e);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1010
1054
|
// Expose recipe summaries to the UI browser
|
|
1011
1055
|
const parsedRecipes = RECIPES.map((md) => {
|
|
1012
1056
|
const { frontmatter, body } = parseFrontmatter(md);
|
package/src/diagnostics.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import type { ToolLayer } from './tool-layers.js';
|
|
4
4
|
import type { ProviderTool } from './types.js';
|
|
5
|
-
import { sanitizeServerName } from './tool-layers.js';
|
|
5
|
+
import { sanitizeServerName, protocolToken } from './tool-layers.js';
|
|
6
6
|
import { sanitizeSchemaWithReport } from '@webmcp-auto-ui/core';
|
|
7
7
|
import type { JsonSchema, SchemaPatch } from '@webmcp-auto-ui/core';
|
|
8
8
|
|
|
@@ -41,8 +41,8 @@ export function runDiagnostics(
|
|
|
41
41
|
diagnostics.push({
|
|
42
42
|
severity: 'error',
|
|
43
43
|
title: `Bruit dans le prefixe "${prefix}"`,
|
|
44
|
-
detail: `Le serveur "${layer.serverName}" produit un prefixe contenant "${noise.join(', ')}". Les outils auront des noms ambigus comme ${prefix}
|
|
45
|
-
quickFix: `Ajoutez au system prompt:\n"Note: le serveur ${layer.serverName} utilise le prefixe '${prefix}'. Utilisez ${prefix}
|
|
44
|
+
detail: `Le serveur "${layer.serverName}" produit un prefixe contenant "${noise.join(', ')}". Les outils auront des noms ambigus comme ${prefix}_data_list_recipes.`,
|
|
45
|
+
quickFix: `Ajoutez au system prompt:\n"Note: le serveur ${layer.serverName} utilise le prefixe '${prefix}'. Utilisez ${prefix}_data_<tool> ou ${prefix}_ui_<tool>."`,
|
|
46
46
|
codeFix: `Renommer le serveur MCP cote serveur pour ne pas inclure "mcp"/"server" dans le nom.`,
|
|
47
47
|
});
|
|
48
48
|
}
|
|
@@ -88,14 +88,14 @@ export function runDiagnostics(
|
|
|
88
88
|
// Include discovery tools (search_tools, list_tools) which are generated dynamically
|
|
89
89
|
const toolNames = new Set(tools.map(t => t.name));
|
|
90
90
|
for (const layer of layers) {
|
|
91
|
-
const prefix = `${sanitizeServerName(layer.serverName)}_${layer.protocol}_`;
|
|
91
|
+
const prefix = `${sanitizeServerName(layer.serverName)}_${protocolToken(layer.protocol)}_`;
|
|
92
92
|
toolNames.add(`${prefix}search_tools`);
|
|
93
93
|
toolNames.add(`${prefix}list_tools`);
|
|
94
94
|
toolNames.add(`${prefix}search_recipes`);
|
|
95
95
|
toolNames.add(`${prefix}list_recipes`);
|
|
96
96
|
toolNames.add(`${prefix}get_recipe`);
|
|
97
97
|
}
|
|
98
|
-
const toolPattern = /\b([a-z][a-z0-9_]{2,})_(
|
|
98
|
+
const toolPattern = /\b([a-z][a-z0-9_]{2,})_(data|ui)_([a-z][a-z0-9_]+)\b/g;
|
|
99
99
|
let match;
|
|
100
100
|
while ((match = toolPattern.exec(systemPrompt)) !== null) {
|
|
101
101
|
const fullName = match[0];
|
|
@@ -112,7 +112,7 @@ export function runDiagnostics(
|
|
|
112
112
|
// 5. Strict mode — schemas that were auto-patched
|
|
113
113
|
// Must run on raw (pre-sanitize) schemas; sanitized tools will never show patches.
|
|
114
114
|
// Skipped for Gemma — it doesn't use additionalProperties/strict mode at all.
|
|
115
|
-
if (!skipSchemaChecks) {
|
|
115
|
+
if (!skipSchemaChecks && schemaOptions?.strict) {
|
|
116
116
|
const checkTools = rawTools ?? tools;
|
|
117
117
|
for (const tool of checkTools) {
|
|
118
118
|
const { patches } = sanitizeSchemaWithReport(tool.input_schema as JsonSchema);
|
package/src/discovery-cache.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { ProviderTool } from './types.js';
|
|
8
|
+
import type { PipelineTrace } from './pipeline-trace.js';
|
|
8
9
|
|
|
9
10
|
/** Tool names that are resolved locally from cache — hidden from user-facing browsers. */
|
|
10
11
|
export const DISCOVERY_TOOL_NAMES = new Set(['list_recipes', 'search_recipes', 'get_recipe', 'list_tools', 'search_tools']);
|
|
@@ -100,13 +101,18 @@ export class DiscoveryCache {
|
|
|
100
101
|
serverPrefix: string,
|
|
101
102
|
realToolName: string,
|
|
102
103
|
params: Record<string, unknown>,
|
|
104
|
+
trace?: PipelineTrace,
|
|
103
105
|
): string | null {
|
|
104
106
|
const cache = this.servers.get(serverPrefix);
|
|
105
107
|
if (!cache) return null;
|
|
106
108
|
|
|
107
109
|
switch (realToolName) {
|
|
108
110
|
case 'search_recipes': {
|
|
109
|
-
const
|
|
111
|
+
const rawQuery = params.query ?? params.q ?? params.keyword ?? params.search;
|
|
112
|
+
const query = String(rawQuery ?? '').toLowerCase();
|
|
113
|
+
if (rawQuery === undefined && Object.keys(params).length > 0) {
|
|
114
|
+
trace?.push('discovery', realToolName, `unknown param keys: ${Object.keys(params).join(',')} — expected query/q/keyword/search`, 'warn');
|
|
115
|
+
}
|
|
110
116
|
const results = query
|
|
111
117
|
? cache.recipes.filter(r =>
|
|
112
118
|
r.name.toLowerCase().includes(query) ||
|
|
@@ -121,7 +127,11 @@ export class DiscoveryCache {
|
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
case 'get_recipe': {
|
|
124
|
-
const
|
|
130
|
+
const rawKey = params.name ?? params.id ?? params.recipe_id ?? params.key;
|
|
131
|
+
const key = String(rawKey ?? '').toLowerCase();
|
|
132
|
+
if (rawKey === undefined && Object.keys(params).length > 0) {
|
|
133
|
+
trace?.push('discovery', realToolName, `unknown param keys: ${Object.keys(params).join(',')} — expected name/id/recipe_id/key`, 'warn');
|
|
134
|
+
}
|
|
125
135
|
const recipe = cache.recipes.find(r =>
|
|
126
136
|
(r.name?.toLowerCase() === key) ||
|
|
127
137
|
((r as Record<string, unknown>).id as string | undefined)?.toLowerCase() === key
|
|
@@ -131,7 +141,11 @@ export class DiscoveryCache {
|
|
|
131
141
|
}
|
|
132
142
|
|
|
133
143
|
case 'search_tools': {
|
|
134
|
-
const
|
|
144
|
+
const rawQuery = params.query ?? params.q ?? params.keyword ?? params.search;
|
|
145
|
+
const query = String(rawQuery ?? '').toLowerCase();
|
|
146
|
+
if (rawQuery === undefined && Object.keys(params).length > 0) {
|
|
147
|
+
trace?.push('discovery', realToolName, `unknown param keys: ${Object.keys(params).join(',')} — expected query/q/keyword/search`, 'warn');
|
|
148
|
+
}
|
|
135
149
|
const results = query
|
|
136
150
|
? cache.tools.filter(t =>
|
|
137
151
|
t.name.toLowerCase().includes(query) ||
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,16 @@ export { RemoteLLMProvider } from './providers/remote.js';
|
|
|
5
5
|
export type { RemoteLLMProviderOptions } from './providers/remote.js';
|
|
6
6
|
export { WasmProvider } from './providers/wasm.js';
|
|
7
7
|
export type { WasmProviderOptions, WasmStatus } from './providers/wasm.js';
|
|
8
|
+
export { TransformersProvider } from './providers/transformers.js';
|
|
9
|
+
export type { TransformersProviderOptions, TransformersStatus } from './providers/transformers.js';
|
|
10
|
+
export { TRANSFORMERS_MODELS, getTransformersModel, listTransformersModels } from './providers/transformers-models.js';
|
|
11
|
+
export type { TransformersModelEntry, TransformersFamily, ToolCallFormat } from './providers/transformers-models.js';
|
|
12
|
+
export { parseToolCalls } from './prompts/tool-call-parsers.js';
|
|
13
|
+
export type { ParseResult } from './prompts/tool-call-parsers.js';
|
|
14
|
+
export { loadOrDownloadModel, clearModelCache } from './util/opfs-cache.js';
|
|
15
|
+
export type { ModelFileSpec, CacheProgress } from './util/opfs-cache.js';
|
|
16
|
+
export { buildGemmaPrompt } from './prompts/index.js';
|
|
17
|
+
export type { BuildGemmaPromptInput } from './prompts/index.js';
|
|
8
18
|
export { LocalLLMProvider } from './providers/local.js';
|
|
9
19
|
export type { LocalLLMProviderOptions, LocalBackend } from './providers/local.js';
|
|
10
20
|
export { createProvider } from './providers/factory.js';
|
|
@@ -18,15 +28,16 @@ export type { GemmaProviderOptions, GemmaStatus } from './providers/gemma.js';
|
|
|
18
28
|
|
|
19
29
|
// Agent loop
|
|
20
30
|
export { runAgentLoop, toProviderTools, fromMcpTools, trimConversationHistory } from './loop.js';
|
|
21
|
-
export { buildSystemPrompt } from './
|
|
31
|
+
export { buildSystemPrompt, buildSystemPromptWithAliases } from './prompts/index.js';
|
|
32
|
+
export type { SystemPromptResult } from './prompts/index.js';
|
|
22
33
|
export type { AgentLoopOptions } from './loop.js';
|
|
23
34
|
|
|
24
35
|
// autoui — built-in WebMCP server
|
|
25
36
|
export { autoui, NATIVE_WIDGET_NAMES } from './autoui-server.js';
|
|
26
37
|
|
|
27
38
|
// Tool layers
|
|
28
|
-
export { buildToolsFromLayers, buildDiscoveryTools, buildDiscoveryToolsWithAliases, activateServerTools, resolveCanonicalTools, toolAliasMap,
|
|
29
|
-
export type { ToolLayer, McpLayer, WebMcpLayer,
|
|
39
|
+
export { buildToolsFromLayers, buildDiscoveryTools, buildDiscoveryToolsWithAliases, activateServerTools, resolveCanonicalTools, toolAliasMap, flattenPathMaps, buildDiscoveryCache } from './tool-layers.js';
|
|
40
|
+
export type { ToolLayer, McpLayer, WebMcpLayer, DiscoveryToolsResult, SchemaTransformOptions, BuildToolsResult, ProviderKind } from './tool-layers.js';
|
|
30
41
|
|
|
31
42
|
// Discovery cache
|
|
32
43
|
export { DiscoveryCache, DISCOVERY_TOOL_NAMES } from './discovery-cache.js';
|
|
@@ -63,12 +74,15 @@ export type { RepairResult } from './auto-repair.js';
|
|
|
63
74
|
// Pipeline trace
|
|
64
75
|
export { PipelineTrace, type TraceEntry } from './pipeline-trace.js';
|
|
65
76
|
|
|
77
|
+
// Trace observer — live visual trace for runAgentLoop
|
|
78
|
+
export { createTraceObserver, type TraceObserver, type TraceObserverContext, type RoundTripDetail } from './trace-observer.js';
|
|
79
|
+
|
|
66
80
|
// Nano-RAG — context compaction
|
|
67
81
|
export { ContextRAG, type ContextRAGOptions } from './nano-rag/mod.js';
|
|
68
82
|
|
|
69
83
|
// Types
|
|
70
84
|
export type {
|
|
71
|
-
RemoteModelId, WasmModelId, LLMId, ModelId,
|
|
85
|
+
RemoteModelId, WasmModelId, TransformersModelId, LLMId, ModelId,
|
|
72
86
|
ChatMessage, ContentBlock, McpToolDef, ProviderTool,
|
|
73
87
|
LLMProvider, LLMResponse, ToolCall, AgentMetrics, AgentResult, AgentCallbacks,
|
|
74
88
|
Recipe, McpRecipe,
|
package/src/loop.ts
CHANGED
|
@@ -9,7 +9,8 @@ import type {
|
|
|
9
9
|
LLMProvider, ProviderTool, McpToolDef, AgentCallbacks,
|
|
10
10
|
} from './types.js';
|
|
11
11
|
import type { ToolLayer, SchemaTransformOptions } from './tool-layers.js';
|
|
12
|
-
import { buildToolsFromLayers,
|
|
12
|
+
import { buildToolsFromLayers, buildDiscoveryToolsWithAliases, activateServerTools, toProviderTools, sanitizeServerName, flattenPathMaps } from './tool-layers.js';
|
|
13
|
+
import { buildSystemPromptWithAliases, buildSystemPrompt } from './prompts/index.js';
|
|
13
14
|
import type { DiscoveryCache } from './discovery-cache.js';
|
|
14
15
|
import { unflattenParams, validateJsonSchema } from '@webmcp-auto-ui/core';
|
|
15
16
|
import type { JsonSchema } from '@webmcp-auto-ui/core';
|
|
@@ -17,7 +18,7 @@ import { autoRepairParams } from './auto-repair.js';
|
|
|
17
18
|
import { PipelineTrace } from './pipeline-trace.js';
|
|
18
19
|
|
|
19
20
|
// Re-export buildSystemPrompt for backward compat
|
|
20
|
-
export { buildSystemPrompt } from './
|
|
21
|
+
export { buildSystemPrompt } from './prompts/index.js';
|
|
21
22
|
|
|
22
23
|
const MAX_RESULT_LEN = 10_000;
|
|
23
24
|
|
|
@@ -28,11 +29,18 @@ const DISCOVERY_TOOL_NAMES = new Set([
|
|
|
28
29
|
]);
|
|
29
30
|
|
|
30
31
|
function isDiscoveryTool(prefixedName: string): boolean {
|
|
31
|
-
const match = prefixedName.match(/^.+?_(
|
|
32
|
+
const match = prefixedName.match(/^.+?_(data|ui)_(.+)$/);
|
|
32
33
|
if (!match) return false;
|
|
33
34
|
return DISCOVERY_TOOL_NAMES.has(match[2]);
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
/** Map a tool-name token (data/ui) back to its protocol discriminator (mcp/webmcp). */
|
|
38
|
+
function tokenToProtocol(token: string): 'mcp' | 'webmcp' | null {
|
|
39
|
+
if (token === 'data') return 'mcp';
|
|
40
|
+
if (token === 'ui') return 'webmcp';
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
36
44
|
/**
|
|
37
45
|
* Compress old tool_result blocks in conversation history.
|
|
38
46
|
* IMPORTANT: mutates messages in-place intentionally to reduce memory usage.
|
|
@@ -91,9 +99,6 @@ export interface AgentLoopOptions {
|
|
|
91
99
|
layers?: ToolLayer[];
|
|
92
100
|
maxIterations?: number;
|
|
93
101
|
maxTokens?: number;
|
|
94
|
-
maxTools?: number;
|
|
95
|
-
/** WASM-only: cap on conversation messages sent to the model. Default: derived from contextSize. */
|
|
96
|
-
maxMessages?: number;
|
|
97
102
|
temperature?: number;
|
|
98
103
|
topK?: number;
|
|
99
104
|
cacheEnabled?: boolean;
|
|
@@ -118,7 +123,7 @@ export interface AgentLoopOptions {
|
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
export async function runAgentLoop(
|
|
121
|
-
userMessage: string,
|
|
126
|
+
userMessage: string | ContentBlock[],
|
|
122
127
|
options: AgentLoopOptions
|
|
123
128
|
): Promise<AgentResult> {
|
|
124
129
|
const {
|
|
@@ -126,8 +131,6 @@ export async function runAgentLoop(
|
|
|
126
131
|
provider,
|
|
127
132
|
maxIterations = 5,
|
|
128
133
|
maxTokens,
|
|
129
|
-
maxTools,
|
|
130
|
-
maxMessages,
|
|
131
134
|
temperature,
|
|
132
135
|
topK,
|
|
133
136
|
cacheEnabled = true,
|
|
@@ -182,14 +185,14 @@ export async function runAgentLoop(
|
|
|
182
185
|
if (options.systemPrompt) {
|
|
183
186
|
baseSystemPrompt = options.systemPrompt;
|
|
184
187
|
} else {
|
|
185
|
-
const sp = buildSystemPromptWithAliases(options.layers ?? []
|
|
188
|
+
const sp = buildSystemPromptWithAliases(options.layers ?? [], {
|
|
189
|
+
providerKind: provider.promptKind ?? 'generic',
|
|
190
|
+
});
|
|
186
191
|
baseSystemPrompt = sp.prompt;
|
|
187
192
|
for (const [k, v] of sp.aliasMap) localAliasMap.set(k, v);
|
|
188
193
|
}
|
|
189
194
|
|
|
190
|
-
const systemPrompt =
|
|
191
|
-
? `${baseSystemPrompt}\n\nIMPORTANT: Limit your responses to ${maxTokens} tokens.`
|
|
192
|
-
: baseSystemPrompt;
|
|
195
|
+
const systemPrompt = baseSystemPrompt;
|
|
193
196
|
|
|
194
197
|
const messages: ChatMessage[] = [
|
|
195
198
|
...initialMessages.map(m => ({
|
|
@@ -207,7 +210,6 @@ export async function runAgentLoop(
|
|
|
207
210
|
const allToolCalls: ToolCall[] = [];
|
|
208
211
|
let lastText = '';
|
|
209
212
|
let finishedNormally = false;
|
|
210
|
-
let discoveryPhase = false;
|
|
211
213
|
let iterationsWithoutRender = 0;
|
|
212
214
|
let nudgedOnce = false;
|
|
213
215
|
let hasRendered = false;
|
|
@@ -267,7 +269,7 @@ export async function runAgentLoop(
|
|
|
267
269
|
const t0 = performance.now();
|
|
268
270
|
let streamingText = '';
|
|
269
271
|
const response = await provider.chat(messages, iterationTools, {
|
|
270
|
-
signal, cacheEnabled, system: iterationSystemPrompt, maxTokens,
|
|
272
|
+
signal, cacheEnabled, system: iterationSystemPrompt, maxTokens, temperature, topK,
|
|
271
273
|
onToken: callbacks.onToken ? (token) => {
|
|
272
274
|
callbacks.onToken!(token);
|
|
273
275
|
streamingText += token;
|
|
@@ -318,14 +320,6 @@ export async function runAgentLoop(
|
|
|
318
320
|
const toolResults: ContentBlock[] = [];
|
|
319
321
|
for (const block of toolBlocks) {
|
|
320
322
|
const call: ToolCall = { id: block.id, name: block.name, args: block.input };
|
|
321
|
-
const wasDiscovering = discoveryPhase;
|
|
322
|
-
if (isDiscoveryTool(block.name)) {
|
|
323
|
-
discoveryPhase = true;
|
|
324
|
-
call.guided = false;
|
|
325
|
-
} else {
|
|
326
|
-
call.guided = wasDiscovering;
|
|
327
|
-
discoveryPhase = false;
|
|
328
|
-
}
|
|
329
323
|
const t1 = performance.now();
|
|
330
324
|
|
|
331
325
|
try {
|
|
@@ -335,12 +329,12 @@ export async function runAgentLoop(
|
|
|
335
329
|
// Resolve alias (canonical name → real tool name) if needed
|
|
336
330
|
const resolvedName = localAliasMap.get(name) ?? name;
|
|
337
331
|
|
|
338
|
-
// Parse tool name: {serverName}_{
|
|
339
|
-
const toolMatch = resolvedName.match(/^(.+?)_(
|
|
332
|
+
// Parse tool name: {serverName}_{token}_{toolName} where token ∈ {data, ui}
|
|
333
|
+
const toolMatch = resolvedName.match(/^(.+?)_(data|ui)_(.+)$/);
|
|
340
334
|
|
|
341
335
|
// ── Discovery cache — resolve search/list/get locally if cached ──
|
|
342
336
|
if (discoveryCache && toolMatch) {
|
|
343
|
-
const cached = discoveryCache.resolve(toolMatch[1], toolMatch[3], block.input as Record<string, unknown
|
|
337
|
+
const cached = discoveryCache.resolve(toolMatch[1], toolMatch[3], block.input as Record<string, unknown>, trace);
|
|
344
338
|
if (cached !== null) {
|
|
345
339
|
result = cached;
|
|
346
340
|
// Store + push result, then continue to next tool block
|
|
@@ -358,7 +352,8 @@ export async function runAgentLoop(
|
|
|
358
352
|
// ── Intercept list_tools / search_tools (local pseudo-tools) ──
|
|
359
353
|
// These are read-only discovery operations — do NOT activate the server.
|
|
360
354
|
if (toolMatch && (toolMatch[3] === 'list_tools' || toolMatch[3] === 'search_tools')) {
|
|
361
|
-
const [, serverName,
|
|
355
|
+
const [, serverName, token, pseudoTool] = toolMatch;
|
|
356
|
+
const protocol = tokenToProtocol(token);
|
|
362
357
|
const layer = (options.layers ?? []).find(l => sanitizeServerName(l.serverName) === serverName && l.protocol === protocol);
|
|
363
358
|
if (!layer) {
|
|
364
359
|
result = 'Error: server not found';
|
|
@@ -384,10 +379,11 @@ export async function runAgentLoop(
|
|
|
384
379
|
|
|
385
380
|
// Parse tool name to extract server — activate on first contact
|
|
386
381
|
{
|
|
387
|
-
const activateMatch = resolvedName.match(/^(.+?)_(
|
|
382
|
+
const activateMatch = resolvedName.match(/^(.+?)_(data|ui)_(.+)$/);
|
|
388
383
|
if (activateMatch) {
|
|
389
|
-
const [, serverName,
|
|
390
|
-
const
|
|
384
|
+
const [, serverName, token] = activateMatch;
|
|
385
|
+
const protocol = tokenToProtocol(token);
|
|
386
|
+
const serverKey = `${serverName}_${token}`;
|
|
391
387
|
if (!activatedServers.has(serverKey)) {
|
|
392
388
|
activatedServers.add(serverKey);
|
|
393
389
|
const layer = (options.layers ?? []).find(l => sanitizeServerName(l.serverName) === serverName && l.protocol === protocol);
|
|
@@ -398,10 +394,11 @@ export async function runAgentLoop(
|
|
|
398
394
|
}
|
|
399
395
|
}
|
|
400
396
|
if (!toolMatch) {
|
|
401
|
-
trace.push('dispatch', name, `unknown tool format, expected {source}_{
|
|
402
|
-
result = `Error: unknown tool format "${name}". Expected {source}_{
|
|
397
|
+
trace.push('dispatch', name, `unknown tool format, expected {source}_{token}_{tool} where token in {data,ui}`, 'error');
|
|
398
|
+
result = `Error: unknown tool format "${name}". Expected {source}_{token}_{tool} where token in {data,ui}.`;
|
|
403
399
|
} else {
|
|
404
|
-
const [, serverName,
|
|
400
|
+
const [, serverName, token, realToolName] = toolMatch;
|
|
401
|
+
const protocol = tokenToProtocol(token);
|
|
405
402
|
|
|
406
403
|
// Auto-repair + validate params before dispatch
|
|
407
404
|
let toolInput = block.input as Record<string, unknown>;
|
|
@@ -587,7 +584,7 @@ export async function runAgentLoop(
|
|
|
587
584
|
|
|
588
585
|
// Track iterations without render — widget_display means a render happened
|
|
589
586
|
const renderedThisIteration = toolBlocks.some(b => {
|
|
590
|
-
const match = b.name.match(/^.+?_(
|
|
587
|
+
const match = b.name.match(/^.+?_(data|ui)_(.+)$/);
|
|
591
588
|
return match && match[2] === 'widget_display';
|
|
592
589
|
});
|
|
593
590
|
if (renderedThisIteration) {
|