@webmcp-auto-ui/agent 2.5.28 → 2.5.30

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.28",
3
+ "version": "2.5.30",
4
4
  "description": "LLM agent loop + remote/WASM/local providers + MCP wrapper",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "type": "module",
@@ -5,22 +5,13 @@
5
5
  import { createWebMcpServer, parseFrontmatter } from '@webmcp-auto-ui/core';
6
6
  import { RAW_RECIPES } from './recipes/_generated.js';
7
7
 
8
- // Notebook widget recipes (vanilla renderers) — moved to @webmcp-auto-ui/ui
8
+ // Notebook widget recipe (vanilla renderer) — moved to @webmcp-auto-ui/ui
9
9
  // @ts-ignore — Vite raw imports, not resolved by tsc
10
- import compactRecipe from '@webmcp-auto-ui/ui/widgets/notebook/recipes/compact.md?raw';
11
- // @ts-ignore
12
- import workspaceRecipe from '@webmcp-auto-ui/ui/widgets/notebook/recipes/workspace.md?raw';
13
- // @ts-ignore
14
- import documentRecipe from '@webmcp-auto-ui/ui/widgets/notebook/recipes/document.md?raw';
15
- // @ts-ignore
16
- import editorialRecipe from '@webmcp-auto-ui/ui/widgets/notebook/recipes/editorial.md?raw';
17
-
18
- // Notebook widget renderers (vanilla JS) — import via subpath to avoid pulling
10
+ import notebookRecipe from '@webmcp-auto-ui/ui/widgets/notebook/recipes/notebook.md?raw';
11
+
12
+ // Notebook widget renderer (vanilla JS) — import via subpath to avoid pulling
19
13
  // the .svelte exports of the ui package root through tsc.
20
- import { render as renderCompact } from '@webmcp-auto-ui/ui/widgets/notebook/compact.js';
21
- import { render as renderWorkspace } from '@webmcp-auto-ui/ui/widgets/notebook/workspace.js';
22
- import { render as renderDocument } from '@webmcp-auto-ui/ui/widgets/notebook/document.js';
23
- import { render as renderEditorial } from '@webmcp-auto-ui/ui/widgets/notebook/editorial.js';
14
+ import { render as renderNotebook } from '@webmcp-auto-ui/ui/widgets/notebook/notebook.js';
24
15
  import { render as renderRecipeBrowser } from '@webmcp-auto-ui/ui/widgets/notebook/recipe-browser.js';
25
16
 
26
17
  // Inline recipe for recipe-browser (real vanilla widget)
@@ -987,10 +978,7 @@ Call widget_display({name: "js-sandbox", params: {code: "document.getElementById
987
978
 
988
979
  /** Derived from RECIPES + notebook widget recipes — always in sync with registered widgets */
989
980
  const _NOTEBOOK_RECIPE_SOURCES: string[] = [
990
- compactRecipe as string,
991
- workspaceRecipe as string,
992
- documentRecipe as string,
993
- editorialRecipe as string,
981
+ notebookRecipe as string,
994
982
  recipeBrowserRecipe,
995
983
  ];
996
984
  export const NATIVE_WIDGET_NAMES = [...RECIPES, ..._NOTEBOOK_RECIPE_SOURCES].map(r => {
@@ -1011,12 +999,9 @@ for (const recipe of RECIPES) {
1011
999
  autoui.registerWidget(recipe, undefined);
1012
1000
  }
1013
1001
 
1014
- // Notebook widgets — vanilla renderers (resolved via WidgetRenderer vanilla path)
1002
+ // Notebook widget — vanilla renderer (resolved via WidgetRenderer vanilla path)
1015
1003
  const NOTEBOOK_WIDGETS: Array<[string, (container: HTMLElement, data: any) => any]> = [
1016
- [compactRecipe as string, renderCompact],
1017
- [workspaceRecipe as string, renderWorkspace],
1018
- [documentRecipe as string, renderDocument],
1019
- [editorialRecipe as string, renderEditorial],
1004
+ [notebookRecipe as string, renderNotebook],
1020
1005
  [recipeBrowserRecipe, renderRecipeBrowser],
1021
1006
  ];
1022
1007
  for (const [recipe, renderer] of NOTEBOOK_WIDGETS) {
package/src/loop.ts CHANGED
@@ -9,7 +9,7 @@ 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, buildDiscoveryToolsWithAliases, activateServerTools, toProviderTools, sanitizeServerName, flattenPathMaps } from './tool-layers.js';
12
+ import { buildToolsFromLayers, buildDiscoveryToolsWithAliases, activateServerTools, toProviderTools, sanitizeServerName } from './tool-layers.js';
13
13
  import { buildSystemPromptWithAliases, buildSystemPrompt } from './prompts/index.js';
14
14
  import type { DiscoveryCache } from './discovery-cache.js';
15
15
  import { unflattenParams, validateJsonSchema } from '@webmcp-auto-ui/core';
@@ -168,9 +168,9 @@ export async function runAgentLoop(
168
168
  // Use local alias maps (parallel-safe — no global singleton)
169
169
  const activatedServers = new Set<string>();
170
170
  const localAliasMap = new Map<string, string>();
171
- // Snapshot pathMaps locally (parallel-safe). Reading the global flattenPathMaps
172
- // singleton at dispatch-time races when two loops run concurrently.
173
- const localPathMaps = new Map<string, Record<string, string[]>>(flattenPathMaps);
171
+ // Local pathMaps for flattened schemas populated as servers are lazily activated
172
+ // (see activateServerTools call below). Parallel-safe: scoped to this loop run.
173
+ const localPathMaps = new Map<string, Record<string, string[]>>();
174
174
  const trace = new PipelineTrace();
175
175
 
176
176
  const disc = buildDiscoveryToolsWithAliases(options.layers ?? [], schemaOptions, trace);
@@ -398,7 +398,10 @@ export async function runAgentLoop(
398
398
  activatedServers.add(serverKey);
399
399
  const layer = (options.layers ?? []).find(l => sanitizeServerName(l.serverName) === serverName && l.protocol === protocol);
400
400
  if (layer) {
401
- activeTools = activateServerTools(activeTools, layer, schemaOptions, trace);
401
+ const act = activateServerTools(activeTools, layer, schemaOptions, trace);
402
+ activeTools = act.tools;
403
+ // Merge new pathMaps so unflattenParams works for lazily-activated tools.
404
+ for (const [k, v] of act.pathMaps) localPathMaps.set(k, v);
402
405
  }
403
406
  }
404
407
  }
@@ -5,16 +5,17 @@ export interface HawkModelEntry {
5
5
  }
6
6
 
7
7
  export const HAWK_MODELS: HawkModelEntry[] = [
8
- { id: 'qwen35-2b', label: 'Qwen 3.5 2B — 49 tok/s', tokps: 49 },
9
- { id: 'bielik-1.5b-v3', label: 'Bielik 1.5B — 47 tok/s', tokps: 47 },
10
- { id: 'gemma4-e2b', label: 'Gemma 4 E2B — 43 tok/s', tokps: 43 },
11
- { id: 'ministral3-3b', label: 'Ministral 3B35 tok/s', tokps: 35 },
12
- { id: 'qwen3-4b', label: 'Qwen 3 4B 28 tok/s', tokps: 28 },
13
- { id: 'gemma4-e4b', label: 'Gemma 4 E4B26 tok/s', tokps: 26 },
14
- { id: 'qwen35-4b', label: 'Qwen 3.5 4B23 tok/s', tokps: 23 },
15
- { id: 'qwen36-35b-a3b', label: 'Qwen 3.6 35B MoE 22 tok/s', tokps: 22 },
16
- { id: 'gemma4-26b-a4b', label: 'Gemma 4 26B MoE — 20 tok/s', tokps: 20 },
17
- { id: 'ministral-8b', label: 'Ministral 8B16 tok/s', tokps: 16 },
8
+ { id: 'qwen35-2b', label: 'Qwen 3.5 2B — 49 tok/s', tokps: 49 },
9
+ { id: 'bielik-1.5b-v3', label: 'Bielik 1.5B — 47 tok/s', tokps: 47 },
10
+ { id: 'gemma4-e2b', label: 'Gemma 4 E2B — 43 tok/s', tokps: 43 },
11
+ { id: 'deepseek-coder-16b', label: 'DeepSeek Coder 16B 41 tok/s', tokps: 41 },
12
+ { id: 'ministral3-3b', label: 'Ministral 3B35 tok/s', tokps: 35 },
13
+ { id: 'qwen3-4b', label: 'Qwen 3 4B28 tok/s', tokps: 28 },
14
+ { id: 'gemma4-e4b', label: 'Gemma 4 E4B26 tok/s', tokps: 26 },
15
+ { id: 'qwen35-4b', label: 'Qwen 3.5 4B23 tok/s', tokps: 23 },
16
+ { id: 'qwen36-35b-a3b', label: 'Qwen 3.6 35B MoE — 22 tok/s', tokps: 22 },
17
+ { id: 'gemma4-26b-a4b', label: 'Gemma 4 26B MoE 20 tok/s', tokps: 20 },
18
+ { id: 'ministral-8b', label: 'Ministral 8B — 16 tok/s', tokps: 16 },
18
19
  ];
19
20
 
20
21
  export function listHawkModels(): HawkModelEntry[] {
@@ -313,11 +313,13 @@ export class WasmProvider implements LLMProvider {
313
313
  }
314
314
  }
315
315
 
316
- // Strip hallucinated framework tokens the model should never emit on its own:
317
- // - <|tool_response>...<tool_response|> (injected by the framework, never generated)
318
- // - <|channel>thought...<channel|> (ghost thought channels if Gemma emits one
319
- // without <|think|> activation stray artefacts from pretraining)
320
- // - <|think|> (stray thinking-mode markers)
316
+ // Strip hallucinated framework tokens the model should never emit on its own.
317
+ // Thinking mode is disabled for Gemma (since commit 164a24d) but the model
318
+ // may still leak these tokens as pretraining artefacts — keep the defensive
319
+ // strip regardless of activation.
320
+ // - <|tool_response>...<tool_response|> (framework-injected, never generated)
321
+ // - <|channel>thought...<channel|> (ghost thought channels)
322
+ // - <|think|> (stray pretraining artefacts)
321
323
  fullText = fullText
322
324
  .replace(/<\|tool_response>[\s\S]*?<tool_response\|>/g, '')
323
325
  .replace(/<\|channel>thought[\s\S]*?<channel\|>/g, '')
@@ -932,7 +932,7 @@ component("gallery", {
932
932
  'hackathon-assemblee-nationale': `---
933
933
  id: hackathon-assemblee-nationale-mcp-webmcp
934
934
  name: Hackathon Assemblée Nationale · MCP & WebMCP starter
935
- components_used: [notebook-document, notebook-compact]
935
+ components_used: [notebook]
936
936
  when: the user mentions the Assemblée Nationale hackathon, wants to experiment with parliamentary data (Tricoteuses, Legifrance), or asks for a starter notebook to explore deputies, votes, amendments, or legislative texts in a hackathon context. Keywords include "hackathon Assemblée Nationale", "MCP WebMCP hackathon", "tricoteuses playbook", "parlement playground", "hackathon parlementaire".
937
937
  servers: [autoui, tricoteuses]
938
938
  layout:
@@ -951,14 +951,9 @@ This recipe is a **specialization** of the generic \`notebook-playbook\` recipe
951
951
 
952
952
  ## How to use
953
953
 
954
- ### Step 1 — Pick the document layout
954
+ ### Step 1 — Use the \`notebook\` widget
955
955
 
956
- Default to \`notebook-document\` for the hackathon. Reasons:
957
- - Participants expect to collaborate and leave traces for each other (avatars, comments)
958
- - The document layout reads naturally as "hackathon brief + starter code" rather than "dev tool"
959
- - Margin comments can be seeded to hint at directions to explore
960
-
961
- If the participant asks for a minimal dev-focused playground instead, fall back to \`notebook-compact\`.
956
+ The single \`notebook\` widget fits the hackathon brief: prose, SQL and JS share one drag-and-droppable flow, suited both to a "brief + starter code" read and to free exploration.
962
957
 
963
958
  ### Step 2 — Seed the cells
964
959
 
@@ -974,7 +969,7 @@ The notebook should contain 5–7 cells covering:
974
969
  Example template (to be refined with actual hackathon organizers' briefs):
975
970
 
976
971
  \`\`\`
977
- widget_display({name: "notebook-document", params: {
972
+ widget_display({name: "notebook", params: {
978
973
  title: "Hackathon Assemblée Nationale · starter",
979
974
  cells: [
980
975
  {
@@ -1039,7 +1034,6 @@ These recipes produce more specialized layouts than a generic notebook, and are
1039
1034
  - **Forgetting the hackathon framing**: without the "bienvenue" and "à vous" markdown cells, participants land on a bare notebook and lose the playbook feeling.
1040
1035
  - **SQL without LIMIT**: Tricoteuses queries without \`LIMIT\` can return thousands of rows and slow down the first impression.
1041
1036
  - **Inventing data**: do not seed with fake French parliamentary content (fake deputies, fake votes). If the actual data is not known at seed time, use generic queries (\`SELECT * FROM scrutins LIMIT 5\`) and let the user discover from there.
1042
- - **Picking the wrong layout**: if the user is solo and wants to code fast, \`notebook-compact\` is better than \`notebook-document\`. Default to document for hackathon context because of the collaborative framing, not as a hard rule.
1043
1037
  `,
1044
1038
  'hummingbird-data': `---
1045
1039
  id: hummingbird-data
@@ -1133,8 +1127,8 @@ Do NOT render any widget.
1133
1127
  'notebook-playbook': `---
1134
1128
  id: create-interactive-notebook-playbook
1135
1129
  name: Create an interactive notebook playbook
1136
- components_used: [notebook-compact, notebook-workspace, notebook-document, notebook-editorial]
1137
- when: the user wants to experiment with data, prototype a small analysis, share a reusable scenario, or prepare a hackathon-ready playground. Keywords include "playground", "playbook", "experiment", "try", "prototype", "hackathon", "share a notebook", "template", "starter", "publish".
1130
+ components_used: [notebook]
1131
+ when: the user wants to experiment with data, prototype a small analysis, share a reusable scenario, or prepare a hackathon-ready playground. Keywords include "playground", "playbook", "experiment", "try", "prototype", "hackathon", "share a notebook", "template", "starter", "publish", "memo", "report".
1138
1132
  servers: [autoui]
1139
1133
  layout:
1140
1134
  type: single
@@ -1154,32 +1148,23 @@ This recipe applies across domains (parliamentary data, biodiversity, news, busi
1154
1148
 
1155
1149
  ## How to use
1156
1150
 
1157
- ### Step 1 — Pick the right notebook layout
1158
-
1159
- Choose one of the four \`notebook-*\` widgets based on the user's implicit intent:
1151
+ ### Step 1 — Use the \`notebook\` widget
1160
1152
 
1161
- | Layout | Use when |
1162
- |---|---|
1163
- | \`notebook-compact\` | Quick data exploration, reactive dataflow with named outputs, minimal chrome. **Default for most "playground" and "hackathon" requests.** |
1164
- | \`notebook-workspace\` | The user expects a multi-cell analyst workspace with sources, cell navigation, \`run all\`, and a \`publish\` step. Use when they mention "dashboard", "app", "workspace", "publish". |
1165
- | \`notebook-document\` | The user plans to share and discuss with a team. Use when "collaborate", "review", "comment", "reply" appear. |
1166
- | \`notebook-editorial\` | The user wants a polished, article-like final deliverable mixing prose and code. Use for "memo", "report", "writeup", "blog-style". |
1167
-
1168
- When in doubt, pick \`notebook-compact\`.
1153
+ There is a single notebook widget. Prose paragraphs (\`md\`), SQL queries (\`sql\`) and JS code (\`js\`) share one ordered flow, all drag-and-droppable together. Publication-ready serif prose, suitable for playgrounds, memos, collaborative reviews and analyst workspaces alike.
1169
1154
 
1170
1155
  ### Step 2 — Pre-fill the cells with context-aware seeds
1171
1156
 
1172
1157
  Never create an empty notebook. Always seed with 3–5 cells that give the user an immediate starting point:
1173
1158
 
1174
1159
  1. **First cell: markdown** — title + one-sentence context of what the notebook is for
1175
- 2. **Second cell: markdown or code** — if an MCP data source is connected, a starter query that returns something visible (e.g. \`SELECT * FROM {table} LIMIT 10\`). Otherwise a markdown cell describing the next step
1176
- 3. **Third cell: code** — a transformation or a visualization that uses the output of step 2. Use \`varname\` on the SQL cell (\`varname: "rows"\`) and reference it in the JS cell this activates the **reactive dataflow** (the downstream JS cell is flagged stale automatically when its upstream re-runs)
1160
+ 2. **Second cell: sql or md** — if an MCP data source is connected, a starter query that returns something visible (e.g. \`SELECT * FROM {table} LIMIT 10\`). Otherwise a markdown cell describing the next step
1161
+ 3. **Third cell: code** — a transformation or a visualization that uses the output of step 2. Use \`varname\` on the SQL cell (\`varname: "rows"\`) and reference it in the JS cell to activate the reactive dataflow
1177
1162
  4. **Last cell: markdown** — a short "to you to play" note inviting the user to add cells or edit
1178
1163
 
1179
1164
  Example seed for a generic data playground:
1180
1165
 
1181
1166
  \`\`\`
1182
- widget_display({name: "notebook-compact", params: {
1167
+ widget_display({name: "notebook", params: {
1183
1168
  title: "Exploration playground",
1184
1169
  cells: [
1185
1170
  {type: "md", content: "### Exploration playground\\n\\nStart by running the first SQL cell, then iterate."},
@@ -1203,7 +1188,7 @@ SQL cells are dispatched automatically to the server's \`*_query_sql\` tool (fir
1203
1188
 
1204
1189
  ### Step 4 — Exporting & publishing
1205
1190
 
1206
- All four notebook layouts share the same \`share\` button in the toolbar, offering **four export formats**:
1191
+ The toolbar \`share\` button offers **four export formats**:
1207
1192
 
1208
1193
  | Format | What it does |
1209
1194
  |---|---|
@@ -1212,27 +1197,23 @@ All four notebook layouts share the same \`share\` button in the toolbar, offeri
1212
1197
  | **PNG** | Snapshots the rendered notebook to an image. |
1213
1198
  | **JSON** | Exports the full widget state — re-importable for programmatic reuse. |
1214
1199
 
1215
- **Layout-specific share affordances:**
1216
- - \`notebook-workspace\` has a dedicated \`publish\` button (primary, accent-coloured) that flips \`mode: 'view'\`, tags the notebook \`published\` (from \`draft\`), and copies the Hyperskill link in one gesture. Use this when the user wants a clean hand-off.
1217
- - \`notebook-document\` shows a single \`share\` link (live invite/collaboration is not available in this build; presence avatars only render when the \`presence\` param is explicitly provided).
1218
-
1219
1200
  ### Step 5 — Working with connected data servers
1220
1201
 
1221
- When one or more MCP data servers are connected, every notebook layout exposes a **collapsible left pane** (bookmark-bar styling, collapsed by default) that lists:
1202
+ When one or more MCP data servers are connected, the notebook exposes a **collapsible left pane** (bookmark-bar styling, collapsed by default) that lists:
1222
1203
  - **Recipes** published by each server (\`{server}_list_recipes()\`)
1223
1204
  - **Tools / tables** exposed by each server (\`{server}_list_tools()\`)
1224
1205
 
1225
- Clicking any recipe opens a viewer modal. Each fenced code block inside the recipe has a \`↳ inject\` button that drops the snippet into the notebook as a new cell — the user never has to copy-paste.
1206
+ Clicking any recipe opens a viewer modal. Each fenced code block inside the recipe has a \`↳ inject\` button that drops the snippet into the notebook as a new cell.
1226
1207
 
1227
- Two toolbar buttons flank the left pane on every layout:
1208
+ Two toolbar buttons flank the left pane:
1228
1209
  - **\`+ md\`** — 3-tab modal (New / File / URL) to create a markdown cell from scratch, from a local \`.md\` file, or from a URL
1229
1210
  - **\`+ recipe\`** — 3-tab modal (Browser / File / URL) to import a recipe from a connected server, a local \`.recipe.md\` file, or a URL
1230
1211
 
1231
- Pass the server metadata via the \`servers:\` param so these affordances populate correctly:
1212
+ Pass the server metadata via the \`servers:\` param:
1232
1213
 
1233
1214
  \`\`\`ts
1234
1215
  widget_display({
1235
- name: 'notebook-compact',
1216
+ name: 'notebook',
1236
1217
  params: {
1237
1218
  title: '...',
1238
1219
  cells: [...],
@@ -1241,26 +1222,21 @@ widget_display({
1241
1222
  })
1242
1223
  \`\`\`
1243
1224
 
1244
- **Filter rule**: only MCP *data* servers (\`kind: 'data'\`) belong in \`servers:\`. Do NOT include WebMCP UI servers such as \`autoui\` — they expose no queryable data.
1225
+ **Filter rule**: only MCP *data* servers (\`kind: 'data'\`) belong in \`servers:\`. Do NOT include WebMCP UI servers such as \`autoui\`.
1245
1226
 
1246
1227
  ### Step 6 — Hand-off guidance
1247
1228
 
1248
1229
  After creating the notebook, mention to the user that they can:
1249
1230
  - **Share in four formats** via the toolbar \`share\` button (Hyperskill / Markdown / PNG / JSON)
1250
1231
  - **Switch to \`view\` mode** (read-only) when presenting
1251
- - Use **\`run all\`** (workspace) or **\`publish\`** (workspace) for one-shot execution and publication
1252
- - **Reply** to margin comments in a document layout (\`+ reply\` under each comment)
1253
1232
  - Access the \`⟲ history\` panel to see the edit trace and restore deleted cells
1254
1233
  - **Import recipes** from connected MCP servers via the left pane or the \`+ recipe\` modal
1255
1234
 
1256
- For hackathon contexts, prefer seeding a \`notebook-document\` layout so participants can leave margin comments and replies on cells (presence stays opt-in — pass a \`presence\` array only if you have real editors to show).
1257
-
1258
1235
  ## Examples
1259
1236
 
1260
1237
  ### Generic CSV / table playground
1261
1238
  \`\`\`
1262
- // user: "I need a playground to play with this CSV"
1263
- widget_display({name: "notebook-compact", params: {
1239
+ widget_display({name: "notebook", params: {
1264
1240
  title: "CSV playground",
1265
1241
  cells: [
1266
1242
  {type: "md", content: "### CSV playground\\n\\nRun the SQL cell to see the first rows, then iterate."},
@@ -1270,37 +1246,9 @@ widget_display({name: "notebook-compact", params: {
1270
1246
  }})
1271
1247
  \`\`\`
1272
1248
 
1273
- ### Publishable analyst workspace
1274
- \`\`\`
1275
- // user: "Set up an analysis I can publish to the team as an app"
1276
- widget_display({name: "notebook-workspace", params: {
1277
- title: "Sales review",
1278
- cells: [
1279
- {type: "md", name: "intro", content: "What this analysis covers."},
1280
- {type: "sql", name: "fetch_sales", content: "select * from sales limit 100"},
1281
- {type: "js", name: "plot", content: "// chart the rows"}
1282
- ]
1283
- }})
1284
- // Then tell the user: click \`run all\` to execute, then \`publish\` to flip to view mode and copy the Hyperskill link.
1285
- \`\`\`
1286
-
1287
- ### Collaborative analysis with comments
1288
- \`\`\`
1289
- // user: "Set up a notebook my team can edit and comment on"
1290
- widget_display({name: "notebook-document", params: {
1291
- title: "Team analysis",
1292
- cells: [
1293
- {type: "md", content: "Kick-off: describe the question here."},
1294
- {type: "sql", content: "select * from source limit 10", comment: {who: "reviewer", when: "2m", body: "Should we filter to last quarter only?"}},
1295
- {type: "md", content: "Your findings: add thoughts, <mark>highlights</mark>, and reply to the comment on the query above."}
1296
- ]
1297
- }})
1298
- \`\`\`
1299
-
1300
1249
  ### Final memo
1301
1250
  \`\`\`
1302
- // user: "Prepare a short memo of my findings"
1303
- widget_display({name: "notebook-editorial", params: {
1251
+ widget_display({name: "notebook", params: {
1304
1252
  title: "Findings memo",
1305
1253
  kicker: "memo",
1306
1254
  cells: [
@@ -1317,12 +1265,10 @@ widget_display({name: "notebook-editorial", params: {
1317
1265
  ## Common mistakes
1318
1266
 
1319
1267
  - **Empty notebook**: never call \`widget_display\` without at least 3 seed cells. The user expects something they can immediately run.
1320
- - **Wrong layout for the intent**: do not use \`notebook-editorial\` for quick exploration — it signals "finished article" and intimidates. Use \`notebook-compact\` unless the user explicitly asks for a publication feel.
1321
1268
  - **Heavy initial queries**: always \`LIMIT 10\` or \`LIMIT 20\` in seed SQL cells. Users will expand later if needed.
1322
- - **Missing \`varname\` on SQL cells** (in compact layout): the named output is what the compact layout showcases, and it drives the stale-flag dataflow. Without it, the notebook loses half its reactive story.
1269
+ - **Missing \`varname\` on SQL cells**: the named output drives the reactive dataflow (downstream JS cells go stale when their upstream re-runs). Without it, the notebook loses half its story.
1323
1270
  - **Inventing UUIDs**: leave \`id\` unset — the widget generates a sensible default. Only pass \`id\` when restoring an existing notebook.
1324
- - **Faking presence**: do not pass a \`presence\` array to \`notebook-document\` unless there are real editors to show. Presence is opt-in by design — empty \`presence\` hides the avatar row entirely.
1325
- - **Including \`autoui\` in \`servers:\`**: only MCP *data* servers (\`kind: 'data'\`) belong there. UI servers like \`autoui\` would pollute the left pane.
1271
+ - **Including \`autoui\` in \`servers:\`**: only MCP *data* servers (\`kind: 'data'\`) belong there.
1326
1272
  `,
1327
1273
  'parlementaire-profile': `---
1328
1274
  id: display-parliamentary-profile-with-hemicycle-and-votes
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  id: hackathon-assemblee-nationale-mcp-webmcp
3
3
  name: Hackathon Assemblée Nationale · MCP & WebMCP starter
4
- components_used: [notebook-document, notebook-compact]
4
+ components_used: [notebook]
5
5
  when: the user mentions the Assemblée Nationale hackathon, wants to experiment with parliamentary data (Tricoteuses, Legifrance), or asks for a starter notebook to explore deputies, votes, amendments, or legislative texts in a hackathon context. Keywords include "hackathon Assemblée Nationale", "MCP WebMCP hackathon", "tricoteuses playbook", "parlement playground", "hackathon parlementaire".
6
6
  servers: [autoui, tricoteuses]
7
7
  layout:
@@ -20,14 +20,9 @@ This recipe is a **specialization** of the generic `notebook-playbook` recipe
20
20
 
21
21
  ## How to use
22
22
 
23
- ### Step 1 — Pick the document layout
23
+ ### Step 1 — Use the `notebook` widget
24
24
 
25
- Default to `notebook-document` for the hackathon. Reasons:
26
- - Participants expect to collaborate and leave traces for each other (avatars, comments)
27
- - The document layout reads naturally as "hackathon brief + starter code" rather than "dev tool"
28
- - Margin comments can be seeded to hint at directions to explore
29
-
30
- If the participant asks for a minimal dev-focused playground instead, fall back to `notebook-compact`.
25
+ The single `notebook` widget fits the hackathon brief: prose, SQL and JS share one drag-and-droppable flow, suited both to a "brief + starter code" read and to free exploration.
31
26
 
32
27
  ### Step 2 — Seed the cells
33
28
 
@@ -43,7 +38,7 @@ The notebook should contain 5–7 cells covering:
43
38
  Example template (to be refined with actual hackathon organizers' briefs):
44
39
 
45
40
  ```
46
- widget_display({name: "notebook-document", params: {
41
+ widget_display({name: "notebook", params: {
47
42
  title: "Hackathon Assemblée Nationale · starter",
48
43
  cells: [
49
44
  {
@@ -108,4 +103,3 @@ These recipes produce more specialized layouts than a generic notebook, and are
108
103
  - **Forgetting the hackathon framing**: without the "bienvenue" and "à vous" markdown cells, participants land on a bare notebook and lose the playbook feeling.
109
104
  - **SQL without LIMIT**: Tricoteuses queries without `LIMIT` can return thousands of rows and slow down the first impression.
110
105
  - **Inventing data**: do not seed with fake French parliamentary content (fake deputies, fake votes). If the actual data is not known at seed time, use generic queries (`SELECT * FROM scrutins LIMIT 5`) and let the user discover from there.
111
- - **Picking the wrong layout**: if the user is solo and wants to code fast, `notebook-compact` is better than `notebook-document`. Default to document for hackathon context because of the collaborative framing, not as a hard rule.
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  id: create-interactive-notebook-playbook
3
3
  name: Create an interactive notebook playbook
4
- components_used: [notebook-compact, notebook-workspace, notebook-document, notebook-editorial]
5
- when: the user wants to experiment with data, prototype a small analysis, share a reusable scenario, or prepare a hackathon-ready playground. Keywords include "playground", "playbook", "experiment", "try", "prototype", "hackathon", "share a notebook", "template", "starter", "publish".
4
+ components_used: [notebook]
5
+ when: the user wants to experiment with data, prototype a small analysis, share a reusable scenario, or prepare a hackathon-ready playground. Keywords include "playground", "playbook", "experiment", "try", "prototype", "hackathon", "share a notebook", "template", "starter", "publish", "memo", "report".
6
6
  servers: [autoui]
7
7
  layout:
8
8
  type: single
@@ -22,32 +22,23 @@ This recipe applies across domains (parliamentary data, biodiversity, news, busi
22
22
 
23
23
  ## How to use
24
24
 
25
- ### Step 1 — Pick the right notebook layout
25
+ ### Step 1 — Use the `notebook` widget
26
26
 
27
- Choose one of the four `notebook-*` widgets based on the user's implicit intent:
28
-
29
- | Layout | Use when |
30
- |---|---|
31
- | `notebook-compact` | Quick data exploration, reactive dataflow with named outputs, minimal chrome. **Default for most "playground" and "hackathon" requests.** |
32
- | `notebook-workspace` | The user expects a multi-cell analyst workspace with sources, cell navigation, `run all`, and a `publish` step. Use when they mention "dashboard", "app", "workspace", "publish". |
33
- | `notebook-document` | The user plans to share and discuss with a team. Use when "collaborate", "review", "comment", "reply" appear. |
34
- | `notebook-editorial` | The user wants a polished, article-like final deliverable mixing prose and code. Use for "memo", "report", "writeup", "blog-style". |
35
-
36
- When in doubt, pick `notebook-compact`.
27
+ There is a single notebook widget. Prose paragraphs (`md`), SQL queries (`sql`) and JS code (`js`) share one ordered flow, all drag-and-droppable together. Publication-ready serif prose, suitable for playgrounds, memos, collaborative reviews and analyst workspaces alike.
37
28
 
38
29
  ### Step 2 — Pre-fill the cells with context-aware seeds
39
30
 
40
31
  Never create an empty notebook. Always seed with 3–5 cells that give the user an immediate starting point:
41
32
 
42
33
  1. **First cell: markdown** — title + one-sentence context of what the notebook is for
43
- 2. **Second cell: markdown or code** — if an MCP data source is connected, a starter query that returns something visible (e.g. `SELECT * FROM {table} LIMIT 10`). Otherwise a markdown cell describing the next step
44
- 3. **Third cell: code** — a transformation or a visualization that uses the output of step 2. Use `varname` on the SQL cell (`varname: "rows"`) and reference it in the JS cell this activates the **reactive dataflow** (the downstream JS cell is flagged stale automatically when its upstream re-runs)
34
+ 2. **Second cell: sql or md** — if an MCP data source is connected, a starter query that returns something visible (e.g. `SELECT * FROM {table} LIMIT 10`). Otherwise a markdown cell describing the next step
35
+ 3. **Third cell: code** — a transformation or a visualization that uses the output of step 2. Use `varname` on the SQL cell (`varname: "rows"`) and reference it in the JS cell to activate the reactive dataflow
45
36
  4. **Last cell: markdown** — a short "to you to play" note inviting the user to add cells or edit
46
37
 
47
38
  Example seed for a generic data playground:
48
39
 
49
40
  ```
50
- widget_display({name: "notebook-compact", params: {
41
+ widget_display({name: "notebook", params: {
51
42
  title: "Exploration playground",
52
43
  cells: [
53
44
  {type: "md", content: "### Exploration playground\n\nStart by running the first SQL cell, then iterate."},
@@ -71,7 +62,7 @@ SQL cells are dispatched automatically to the server's `*_query_sql` tool (first
71
62
 
72
63
  ### Step 4 — Exporting & publishing
73
64
 
74
- All four notebook layouts share the same `share` button in the toolbar, offering **four export formats**:
65
+ The toolbar `share` button offers **four export formats**:
75
66
 
76
67
  | Format | What it does |
77
68
  |---|---|
@@ -80,27 +71,23 @@ All four notebook layouts share the same `share` button in the toolbar, offering
80
71
  | **PNG** | Snapshots the rendered notebook to an image. |
81
72
  | **JSON** | Exports the full widget state — re-importable for programmatic reuse. |
82
73
 
83
- **Layout-specific share affordances:**
84
- - `notebook-workspace` has a dedicated `publish` button (primary, accent-coloured) that flips `mode: 'view'`, tags the notebook `published` (from `draft`), and copies the Hyperskill link in one gesture. Use this when the user wants a clean hand-off.
85
- - `notebook-document` shows a single `share` link (live invite/collaboration is not available in this build; presence avatars only render when the `presence` param is explicitly provided).
86
-
87
74
  ### Step 5 — Working with connected data servers
88
75
 
89
- When one or more MCP data servers are connected, every notebook layout exposes a **collapsible left pane** (bookmark-bar styling, collapsed by default) that lists:
76
+ When one or more MCP data servers are connected, the notebook exposes a **collapsible left pane** (bookmark-bar styling, collapsed by default) that lists:
90
77
  - **Recipes** published by each server (`{server}_list_recipes()`)
91
78
  - **Tools / tables** exposed by each server (`{server}_list_tools()`)
92
79
 
93
- Clicking any recipe opens a viewer modal. Each fenced code block inside the recipe has a `↳ inject` button that drops the snippet into the notebook as a new cell — the user never has to copy-paste.
80
+ Clicking any recipe opens a viewer modal. Each fenced code block inside the recipe has a `↳ inject` button that drops the snippet into the notebook as a new cell.
94
81
 
95
- Two toolbar buttons flank the left pane on every layout:
82
+ Two toolbar buttons flank the left pane:
96
83
  - **`+ md`** — 3-tab modal (New / File / URL) to create a markdown cell from scratch, from a local `.md` file, or from a URL
97
84
  - **`+ recipe`** — 3-tab modal (Browser / File / URL) to import a recipe from a connected server, a local `.recipe.md` file, or a URL
98
85
 
99
- Pass the server metadata via the `servers:` param so these affordances populate correctly:
86
+ Pass the server metadata via the `servers:` param:
100
87
 
101
88
  ```ts
102
89
  widget_display({
103
- name: 'notebook-compact',
90
+ name: 'notebook',
104
91
  params: {
105
92
  title: '...',
106
93
  cells: [...],
@@ -109,26 +96,21 @@ widget_display({
109
96
  })
110
97
  ```
111
98
 
112
- **Filter rule**: only MCP *data* servers (`kind: 'data'`) belong in `servers:`. Do NOT include WebMCP UI servers such as `autoui` — they expose no queryable data.
99
+ **Filter rule**: only MCP *data* servers (`kind: 'data'`) belong in `servers:`. Do NOT include WebMCP UI servers such as `autoui`.
113
100
 
114
101
  ### Step 6 — Hand-off guidance
115
102
 
116
103
  After creating the notebook, mention to the user that they can:
117
104
  - **Share in four formats** via the toolbar `share` button (Hyperskill / Markdown / PNG / JSON)
118
105
  - **Switch to `view` mode** (read-only) when presenting
119
- - Use **`run all`** (workspace) or **`publish`** (workspace) for one-shot execution and publication
120
- - **Reply** to margin comments in a document layout (`+ reply` under each comment)
121
106
  - Access the `⟲ history` panel to see the edit trace and restore deleted cells
122
107
  - **Import recipes** from connected MCP servers via the left pane or the `+ recipe` modal
123
108
 
124
- For hackathon contexts, prefer seeding a `notebook-document` layout so participants can leave margin comments and replies on cells (presence stays opt-in — pass a `presence` array only if you have real editors to show).
125
-
126
109
  ## Examples
127
110
 
128
111
  ### Generic CSV / table playground
129
112
  ```
130
- // user: "I need a playground to play with this CSV"
131
- widget_display({name: "notebook-compact", params: {
113
+ widget_display({name: "notebook", params: {
132
114
  title: "CSV playground",
133
115
  cells: [
134
116
  {type: "md", content: "### CSV playground\n\nRun the SQL cell to see the first rows, then iterate."},
@@ -138,37 +120,9 @@ widget_display({name: "notebook-compact", params: {
138
120
  }})
139
121
  ```
140
122
 
141
- ### Publishable analyst workspace
142
- ```
143
- // user: "Set up an analysis I can publish to the team as an app"
144
- widget_display({name: "notebook-workspace", params: {
145
- title: "Sales review",
146
- cells: [
147
- {type: "md", name: "intro", content: "What this analysis covers."},
148
- {type: "sql", name: "fetch_sales", content: "select * from sales limit 100"},
149
- {type: "js", name: "plot", content: "// chart the rows"}
150
- ]
151
- }})
152
- // Then tell the user: click `run all` to execute, then `publish` to flip to view mode and copy the Hyperskill link.
153
- ```
154
-
155
- ### Collaborative analysis with comments
156
- ```
157
- // user: "Set up a notebook my team can edit and comment on"
158
- widget_display({name: "notebook-document", params: {
159
- title: "Team analysis",
160
- cells: [
161
- {type: "md", content: "Kick-off: describe the question here."},
162
- {type: "sql", content: "select * from source limit 10", comment: {who: "reviewer", when: "2m", body: "Should we filter to last quarter only?"}},
163
- {type: "md", content: "Your findings: add thoughts, <mark>highlights</mark>, and reply to the comment on the query above."}
164
- ]
165
- }})
166
- ```
167
-
168
123
  ### Final memo
169
124
  ```
170
- // user: "Prepare a short memo of my findings"
171
- widget_display({name: "notebook-editorial", params: {
125
+ widget_display({name: "notebook", params: {
172
126
  title: "Findings memo",
173
127
  kicker: "memo",
174
128
  cells: [
@@ -185,9 +139,7 @@ widget_display({name: "notebook-editorial", params: {
185
139
  ## Common mistakes
186
140
 
187
141
  - **Empty notebook**: never call `widget_display` without at least 3 seed cells. The user expects something they can immediately run.
188
- - **Wrong layout for the intent**: do not use `notebook-editorial` for quick exploration — it signals "finished article" and intimidates. Use `notebook-compact` unless the user explicitly asks for a publication feel.
189
142
  - **Heavy initial queries**: always `LIMIT 10` or `LIMIT 20` in seed SQL cells. Users will expand later if needed.
190
- - **Missing `varname` on SQL cells** (in compact layout): the named output is what the compact layout showcases, and it drives the stale-flag dataflow. Without it, the notebook loses half its reactive story.
143
+ - **Missing `varname` on SQL cells**: the named output drives the reactive dataflow (downstream JS cells go stale when their upstream re-runs). Without it, the notebook loses half its story.
191
144
  - **Inventing UUIDs**: leave `id` unset — the widget generates a sensible default. Only pass `id` when restoring an existing notebook.
192
- - **Faking presence**: do not pass a `presence` array to `notebook-document` unless there are real editors to show. Presence is opt-in by design — empty `presence` hides the avatar row entirely.
193
- - **Including `autoui` in `servers:`**: only MCP *data* servers (`kind: 'data'`) belong there. UI servers like `autoui` would pollute the left pane.
145
+ - **Including `autoui` in `servers:`**: only MCP *data* servers (`kind: 'data'`) belong there.
@@ -456,19 +456,31 @@ export function buildDiscoveryTools(layers: ToolLayer[]): ProviderTool[] {
456
456
  return tools;
457
457
  }
458
458
 
459
+ /** Result of activateServerTools — extended tool set + per-call path maps for newly activated tools */
460
+ export interface ActivateServerToolsResult {
461
+ tools: ProviderTool[];
462
+ /** Path maps for flattened schemas of newly added tools (empty if flatten is off). */
463
+ pathMaps: Map<string, Record<string, string[]>>;
464
+ }
465
+
459
466
  /**
460
467
  * Add all tools from a specific server layer to the active tool set.
461
468
  * Called when a server is "touched" for the first time.
469
+ *
470
+ * Returns `{ tools, pathMaps }` — `pathMaps` is non-empty when `schemaOptions.flatten`
471
+ * is on, and must be merged into the loop-local pathMaps so `unflattenParams` works
472
+ * for lazily-activated tools. Backward-compat: if you only need `tools`, read `.tools`.
462
473
  */
463
474
  export function activateServerTools(
464
475
  currentTools: ProviderTool[],
465
476
  layer: ToolLayer,
466
477
  schemaOptions?: SchemaTransformOptions,
467
478
  trace?: PipelineTrace,
468
- ): ProviderTool[] {
479
+ ): ActivateServerToolsResult {
469
480
  const prefix = `${sanitizeServerName(layer.serverName)}_${protocolToken(layer.protocol)}_`;
470
481
  const existing = new Set(currentTools.map(t => t.name));
471
482
  const newTools = [...currentTools];
483
+ const pathMaps = new Map<string, Record<string, string[]>>();
472
484
 
473
485
  const layerTools = layer.protocol === 'mcp'
474
486
  ? toProviderTools(layer.tools, schemaOptions, trace)
@@ -476,12 +488,22 @@ export function activateServerTools(
476
488
 
477
489
  for (const tool of layerTools) {
478
490
  const prefixed = `${prefix}${tool.name}`;
479
- if (!existing.has(prefixed)) {
480
- newTools.push({ ...tool, name: prefixed });
491
+ if (existing.has(prefixed)) continue;
492
+
493
+ let finalTool = { ...tool, name: prefixed };
494
+
495
+ if (schemaOptions?.flatten) {
496
+ const { schema: flatSchema, pathMap } = flattenSchema(finalTool.input_schema as import('@webmcp-auto-ui/core').JsonSchema);
497
+ if (Object.keys(pathMap).length > 0) {
498
+ finalTool.input_schema = flatSchema as Record<string, unknown>;
499
+ pathMaps.set(prefixed, pathMap);
500
+ }
481
501
  }
502
+
503
+ newTools.push(finalTool);
482
504
  }
483
505
 
484
- return newTools;
506
+ return { tools: newTools, pathMaps };
485
507
  }
486
508
 
487
509
  /**
@@ -374,9 +374,7 @@ export function createTraceObserver(ctx: TraceObserverContext): TraceObserver {
374
374
 
375
375
  function flush(): void {
376
376
  if (ids === null) return;
377
- ctx.updateWidget(ids.dagId, buildCytoscapeData());
378
377
  ctx.updateWidget(ids.treeId, buildTreeData());
379
- ctx.updateWidget(ids.sankeyId, buildSankeyData());
380
378
  }
381
379
 
382
380
  const callbacks: Partial<AgentCallbacks> = {
@@ -602,11 +600,11 @@ export function createTraceObserver(ctx: TraceObserverContext): TraceObserver {
602
600
  callbacks,
603
601
  mount(): { dagId: string; treeId: string; sankeyId: string } | null {
604
602
  if (ids !== null) return ids;
605
- const dag = ctx.addWidget('animated-flow', buildCytoscapeData(), 'cytoscape');
606
603
  const tree = ctx.addWidget('tree', buildTreeData(), 'd3');
607
- const sankey = ctx.addWidget('sankey', buildSankeyData(), 'autoui');
608
- if (!dag || !tree || !sankey) return null;
609
- ids = { dagId: dag.id, treeId: tree.id, sankeyId: sankey.id };
604
+ if (!tree) return null;
605
+ // dagId/sankeyId kept as empty strings for shape compatibility — the
606
+ // cytoscape + sankey sub-widgets were removed in favor of the tree only.
607
+ ids = { dagId: '', treeId: tree.id, sankeyId: '' };
610
608
  // Synchronous immediate flush — guarantees widgets reflect full buffer
611
609
  // when trace is toggled mid-run (retroactive within current session).
612
610
  flush();
@@ -633,19 +631,10 @@ export function createTraceObserver(ctx: TraceObserverContext): TraceObserver {
633
631
  flushTimer = null;
634
632
  }
635
633
  if (ids !== null) {
636
- ctx.updateWidget(ids.dagId, {
637
- elements: [],
638
- style: CYTOSCAPE_STYLE,
639
- layout: { name: 'cose', animate: true },
640
- });
641
634
  ctx.updateWidget(ids.treeId, {
642
635
  root: { name: 'conv', children: [] },
643
636
  orientation: 'horizontal',
644
637
  });
645
- ctx.updateWidget(ids.sankeyId, {
646
- nodes: [],
647
- links: [],
648
- });
649
638
  }
650
639
  },
651
640
  detach(): void {