@webmcp-auto-ui/agent 2.5.27 → 2.5.29

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.
@@ -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, let others fork and try a dataset, or prepare a hackathon-ready playground. Keywords include "playground", "playbook", "experiment", "try", "prototype", "hackathon", "share a notebook", "template", "starter".
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
@@ -1148,37 +1142,29 @@ The user asks for a **notebook-like interactive playground** that combines text,
1148
1142
  - "I want to prototype a small analysis"
1149
1143
  - "Set up a hackathon starter"
1150
1144
  - "Make a reusable template for exploring CSVs / this API / these tables"
1145
+ - "Publish this analysis as a short memo"
1151
1146
 
1152
1147
  This recipe applies across domains (parliamentary data, biodiversity, news, business datasets, etc.) — it only prescribes the **shape** of the answer, not its content.
1153
1148
 
1154
1149
  ## How to use
1155
1150
 
1156
- ### Step 1 — Pick the right notebook layout
1157
-
1158
- Choose one of the four \`notebook-*\` widgets based on the user's implicit intent:
1159
-
1160
- | Layout | Use when |
1161
- |---|---|
1162
- | \`notebook-compact\` | Quick data exploration, reactive dataflow with named outputs, minimal chrome. **Default for most "playground" and "hackathon" requests.** |
1163
- | \`notebook-workspace\` | The user expects a multi-cell analyst workspace with sources, cell navigation, and a "publish" step. Use when they mention "dashboard", "app", "workspace". |
1164
- | \`notebook-document\` | The user plans to share and discuss with a team. Use when "collaborate", "review", "comment" appear. |
1165
- | \`notebook-editorial\` | The user wants a polished, article-like final deliverable mixing prose and code. Use for "memo", "report", "writeup", "blog-style". |
1151
+ ### Step 1 — Use the \`notebook\` widget
1166
1152
 
1167
- 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.
1168
1154
 
1169
1155
  ### Step 2 — Pre-fill the cells with context-aware seeds
1170
1156
 
1171
1157
  Never create an empty notebook. Always seed with 3–5 cells that give the user an immediate starting point:
1172
1158
 
1173
1159
  1. **First cell: markdown** — title + one-sentence context of what the notebook is for
1174
- 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
1175
- 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
1176
- 4. **Last cell: markdown** — a short "to you to play" note inviting the user to add cells, edit, or fork
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
1162
+ 4. **Last cell: markdown** — a short "to you to play" note inviting the user to add cells or edit
1177
1163
 
1178
1164
  Example seed for a generic data playground:
1179
1165
 
1180
1166
  \`\`\`
1181
- widget_display({name: "notebook-compact", params: {
1167
+ widget_display({name: "notebook", params: {
1182
1168
  title: "Exploration playground",
1183
1169
  cells: [
1184
1170
  {type: "md", content: "### Exploration playground\\n\\nStart by running the first SQL cell, then iterate."},
@@ -1198,47 +1184,71 @@ If a specific MCP server is connected, replace the generic \`source\` and \`sele
1198
1184
 
1199
1185
  Always keep queries **short** and **limited** so the first run returns quickly and visually.
1200
1186
 
1201
- ### Step 4 Share and fork
1187
+ SQL cells are dispatched automatically to the server's \`*_query_sql\` tool (first match). JS cells run in a Web Worker with upstream named outputs injected as scope.
1202
1188
 
1203
- After creating the notebook, mention to the user that they can:
1204
- - Click \`share\` in the toolbar to open the export modal (hyperskill link for in-session sharing, markdown/png/json for external export)
1205
- - Switch to \`view\` mode (read-only, no controls visible) when presenting to someone
1206
- - Access the \`⟲ history\` panel to see the trace of edits, and restore deleted cells
1189
+ ### Step 4 Exporting & publishing
1190
+
1191
+ The toolbar \`share\` button offers **four export formats**:
1192
+
1193
+ | Format | What it does |
1194
+ |---|---|
1195
+ | **Hyperskill link** | Copies both the canonical Hyperskill URL and a short domain-scoped URL (\`?n=<token>\`). The short URL opens the read-only public viewer at \`nb.hyperskills.net\`. |
1196
+ | **Markdown** | Downloads a \`.md\` file containing the notebook content. |
1197
+ | **PNG** | Snapshots the rendered notebook to an image. |
1198
+ | **JSON** | Exports the full widget state — re-importable for programmatic reuse. |
1199
+
1200
+ ### Step 5 — Working with connected data servers
1201
+
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:
1203
+ - **Recipes** published by each server (\`{server}_list_recipes()\`)
1204
+ - **Tools / tables** exposed by each server (\`{server}_list_tools()\`)
1205
+
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.
1207
1207
 
1208
- For hackathon contexts, prefer seeding a **document** layout (comments + avatars) so participants feel they are joining a shared space.
1208
+ Two toolbar buttons flank the left pane:
1209
+ - **\`+ md\`** — 3-tab modal (New / File / URL) to create a markdown cell from scratch, from a local \`.md\` file, or from a URL
1210
+ - **\`+ recipe\`** — 3-tab modal (Browser / File / URL) to import a recipe from a connected server, a local \`.recipe.md\` file, or a URL
1211
+
1212
+ Pass the server metadata via the \`servers:\` param:
1213
+
1214
+ \`\`\`ts
1215
+ widget_display({
1216
+ name: 'notebook',
1217
+ params: {
1218
+ title: '...',
1219
+ cells: [...],
1220
+ servers: [{ name: 'tricoteuses', url: 'https://...', kind: 'data' }]
1221
+ }
1222
+ })
1223
+ \`\`\`
1224
+
1225
+ **Filter rule**: only MCP *data* servers (\`kind: 'data'\`) belong in \`servers:\`. Do NOT include WebMCP UI servers such as \`autoui\`.
1226
+
1227
+ ### Step 6 — Hand-off guidance
1228
+
1229
+ After creating the notebook, mention to the user that they can:
1230
+ - **Share in four formats** via the toolbar \`share\` button (Hyperskill / Markdown / PNG / JSON)
1231
+ - **Switch to \`view\` mode** (read-only) when presenting
1232
+ - Access the \`⟲ history\` panel to see the edit trace and restore deleted cells
1233
+ - **Import recipes** from connected MCP servers via the left pane or the \`+ recipe\` modal
1209
1234
 
1210
1235
  ## Examples
1211
1236
 
1212
1237
  ### Generic CSV / table playground
1213
1238
  \`\`\`
1214
- // user: "I need a playground to play with this CSV"
1215
- widget_display({name: "notebook-compact", params: {
1239
+ widget_display({name: "notebook", params: {
1216
1240
  title: "CSV playground",
1217
1241
  cells: [
1218
1242
  {type: "md", content: "### CSV playground\\n\\nRun the SQL cell to see the first rows, then iterate."},
1219
1243
  {type: "sql", content: "select * from source limit 20", varname: "rows"},
1220
- {type: "js", content: "// summarize, chart, or filter rows here"}
1221
- ]
1222
- }})
1223
- \`\`\`
1224
-
1225
- ### Collaborative analysis
1226
- \`\`\`
1227
- // user: "Set up a notebook my team can edit together"
1228
- widget_display({name: "notebook-document", params: {
1229
- title: "Team analysis",
1230
- cells: [
1231
- {type: "md", content: "Kick-off: describe the question here."},
1232
- {type: "sql", content: "select * from source limit 10"},
1233
- {type: "md", content: "Your findings: add thoughts, highlights (<mark>key sentence</mark>), and comments on the code cells above."}
1244
+ {type: "js", content: "// summarize, chart, or filter rows here\\nconsole.table(rows)"}
1234
1245
  ]
1235
1246
  }})
1236
1247
  \`\`\`
1237
1248
 
1238
1249
  ### Final memo
1239
1250
  \`\`\`
1240
- // user: "Prepare a short memo of my findings"
1241
- widget_display({name: "notebook-editorial", params: {
1251
+ widget_display({name: "notebook", params: {
1242
1252
  title: "Findings memo",
1243
1253
  kicker: "memo",
1244
1254
  cells: [
@@ -1255,10 +1265,10 @@ widget_display({name: "notebook-editorial", params: {
1255
1265
  ## Common mistakes
1256
1266
 
1257
1267
  - **Empty notebook**: never call \`widget_display\` without at least 3 seed cells. The user expects something they can immediately run.
1258
- - **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.
1259
1268
  - **Heavy initial queries**: always \`LIMIT 10\` or \`LIMIT 20\` in seed SQL cells. Users will expand later if needed.
1260
- - **Missing \`varname\` on SQL cells** (in compact layout): the named output is what the compact layout showcases. Without it, the notebook loses half its reactive story.
1261
- - **Inventing UUIDs or fork IDs**: leave \`id\` and \`forkId\` unset — the widget generates sensible defaults. Only pass \`id\` when restoring an existing notebook.
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.
1270
+ - **Inventing UUIDs**: leave \`id\` unset — the widget generates a sensible default. Only pass \`id\` when restoring an existing notebook.
1271
+ - **Including \`autoui\` in \`servers:\`**: only MCP *data* servers (\`kind: 'data'\`) belong there.
1262
1272
  `,
1263
1273
  'parlementaire-profile': `---
1264
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, let others fork and try a dataset, or prepare a hackathon-ready playground. Keywords include "playground", "playbook", "experiment", "try", "prototype", "hackathon", "share a notebook", "template", "starter".
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
@@ -16,37 +16,29 @@ The user asks for a **notebook-like interactive playground** that combines text,
16
16
  - "I want to prototype a small analysis"
17
17
  - "Set up a hackathon starter"
18
18
  - "Make a reusable template for exploring CSVs / this API / these tables"
19
+ - "Publish this analysis as a short memo"
19
20
 
20
21
  This recipe applies across domains (parliamentary data, biodiversity, news, business datasets, etc.) — it only prescribes the **shape** of the answer, not its content.
21
22
 
22
23
  ## How to use
23
24
 
24
- ### Step 1 — Pick the right notebook layout
25
+ ### Step 1 — Use the `notebook` widget
25
26
 
26
- Choose one of the four `notebook-*` widgets based on the user's implicit intent:
27
-
28
- | Layout | Use when |
29
- |---|---|
30
- | `notebook-compact` | Quick data exploration, reactive dataflow with named outputs, minimal chrome. **Default for most "playground" and "hackathon" requests.** |
31
- | `notebook-workspace` | The user expects a multi-cell analyst workspace with sources, cell navigation, and a "publish" step. Use when they mention "dashboard", "app", "workspace". |
32
- | `notebook-document` | The user plans to share and discuss with a team. Use when "collaborate", "review", "comment" appear. |
33
- | `notebook-editorial` | The user wants a polished, article-like final deliverable mixing prose and code. Use for "memo", "report", "writeup", "blog-style". |
34
-
35
- 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.
36
28
 
37
29
  ### Step 2 — Pre-fill the cells with context-aware seeds
38
30
 
39
31
  Never create an empty notebook. Always seed with 3–5 cells that give the user an immediate starting point:
40
32
 
41
33
  1. **First cell: markdown** — title + one-sentence context of what the notebook is for
42
- 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
43
- 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
44
- 4. **Last cell: markdown** — a short "to you to play" note inviting the user to add cells, edit, or fork
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
36
+ 4. **Last cell: markdown** — a short "to you to play" note inviting the user to add cells or edit
45
37
 
46
38
  Example seed for a generic data playground:
47
39
 
48
40
  ```
49
- widget_display({name: "notebook-compact", params: {
41
+ widget_display({name: "notebook", params: {
50
42
  title: "Exploration playground",
51
43
  cells: [
52
44
  {type: "md", content: "### Exploration playground\n\nStart by running the first SQL cell, then iterate."},
@@ -66,47 +58,71 @@ If a specific MCP server is connected, replace the generic `source` and `select
66
58
 
67
59
  Always keep queries **short** and **limited** so the first run returns quickly and visually.
68
60
 
69
- ### Step 4 Share and fork
61
+ SQL cells are dispatched automatically to the server's `*_query_sql` tool (first match). JS cells run in a Web Worker with upstream named outputs injected as scope.
70
62
 
71
- After creating the notebook, mention to the user that they can:
72
- - Click `share` in the toolbar to open the export modal (hyperskill link for in-session sharing, markdown/png/json for external export)
73
- - Switch to `view` mode (read-only, no controls visible) when presenting to someone
74
- - Access the `⟲ history` panel to see the trace of edits, and restore deleted cells
63
+ ### Step 4 Exporting & publishing
64
+
65
+ The toolbar `share` button offers **four export formats**:
66
+
67
+ | Format | What it does |
68
+ |---|---|
69
+ | **Hyperskill link** | Copies both the canonical Hyperskill URL and a short domain-scoped URL (`?n=<token>`). The short URL opens the read-only public viewer at `nb.hyperskills.net`. |
70
+ | **Markdown** | Downloads a `.md` file containing the notebook content. |
71
+ | **PNG** | Snapshots the rendered notebook to an image. |
72
+ | **JSON** | Exports the full widget state — re-importable for programmatic reuse. |
73
+
74
+ ### Step 5 — Working with connected data servers
75
+
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:
77
+ - **Recipes** published by each server (`{server}_list_recipes()`)
78
+ - **Tools / tables** exposed by each server (`{server}_list_tools()`)
79
+
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.
81
+
82
+ Two toolbar buttons flank the left pane:
83
+ - **`+ md`** — 3-tab modal (New / File / URL) to create a markdown cell from scratch, from a local `.md` file, or from a URL
84
+ - **`+ recipe`** — 3-tab modal (Browser / File / URL) to import a recipe from a connected server, a local `.recipe.md` file, or a URL
85
+
86
+ Pass the server metadata via the `servers:` param:
87
+
88
+ ```ts
89
+ widget_display({
90
+ name: 'notebook',
91
+ params: {
92
+ title: '...',
93
+ cells: [...],
94
+ servers: [{ name: 'tricoteuses', url: 'https://...', kind: 'data' }]
95
+ }
96
+ })
97
+ ```
98
+
99
+ **Filter rule**: only MCP *data* servers (`kind: 'data'`) belong in `servers:`. Do NOT include WebMCP UI servers such as `autoui`.
75
100
 
76
- For hackathon contexts, prefer seeding a **document** layout (comments + avatars) so participants feel they are joining a shared space.
101
+ ### Step 6 Hand-off guidance
102
+
103
+ After creating the notebook, mention to the user that they can:
104
+ - **Share in four formats** via the toolbar `share` button (Hyperskill / Markdown / PNG / JSON)
105
+ - **Switch to `view` mode** (read-only) when presenting
106
+ - Access the `⟲ history` panel to see the edit trace and restore deleted cells
107
+ - **Import recipes** from connected MCP servers via the left pane or the `+ recipe` modal
77
108
 
78
109
  ## Examples
79
110
 
80
111
  ### Generic CSV / table playground
81
112
  ```
82
- // user: "I need a playground to play with this CSV"
83
- widget_display({name: "notebook-compact", params: {
113
+ widget_display({name: "notebook", params: {
84
114
  title: "CSV playground",
85
115
  cells: [
86
116
  {type: "md", content: "### CSV playground\n\nRun the SQL cell to see the first rows, then iterate."},
87
117
  {type: "sql", content: "select * from source limit 20", varname: "rows"},
88
- {type: "js", content: "// summarize, chart, or filter rows here"}
89
- ]
90
- }})
91
- ```
92
-
93
- ### Collaborative analysis
94
- ```
95
- // user: "Set up a notebook my team can edit together"
96
- widget_display({name: "notebook-document", params: {
97
- title: "Team analysis",
98
- cells: [
99
- {type: "md", content: "Kick-off: describe the question here."},
100
- {type: "sql", content: "select * from source limit 10"},
101
- {type: "md", content: "Your findings: add thoughts, highlights (<mark>key sentence</mark>), and comments on the code cells above."}
118
+ {type: "js", content: "// summarize, chart, or filter rows here\nconsole.table(rows)"}
102
119
  ]
103
120
  }})
104
121
  ```
105
122
 
106
123
  ### Final memo
107
124
  ```
108
- // user: "Prepare a short memo of my findings"
109
- widget_display({name: "notebook-editorial", params: {
125
+ widget_display({name: "notebook", params: {
110
126
  title: "Findings memo",
111
127
  kicker: "memo",
112
128
  cells: [
@@ -123,7 +139,7 @@ widget_display({name: "notebook-editorial", params: {
123
139
  ## Common mistakes
124
140
 
125
141
  - **Empty notebook**: never call `widget_display` without at least 3 seed cells. The user expects something they can immediately run.
126
- - **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.
127
142
  - **Heavy initial queries**: always `LIMIT 10` or `LIMIT 20` in seed SQL cells. Users will expand later if needed.
128
- - **Missing `varname` on SQL cells** (in compact layout): the named output is what the compact layout showcases. Without it, the notebook loses half its reactive story.
129
- - **Inventing UUIDs or fork IDs**: leave `id` and `forkId` unset — the widget generates sensible defaults. Only pass `id` when restoring an existing notebook.
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.
144
+ - **Inventing UUIDs**: leave `id` unset — the widget generates a sensible default. Only pass `id` when restoring an existing notebook.
145
+ - **Including `autoui` in `servers:`**: only MCP *data* servers (`kind: 'data'`) belong there.
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Shared Hawk proxy handler — used by apps' /api/hawk/+server.ts
3
+ * Hawk = OpenAI-compatible endpoint at https://hawk.hyperskills.net/v1
4
+ * Bearer token lives server-side in HAWK_API_KEY env var.
5
+ */
6
+ function sanitizeId(id: string | undefined): string {
7
+ if (!id) return 'x';
8
+ const clean = id.replace(/[^a-zA-Z0-9]/g, '');
9
+ return clean || 'x';
10
+ }
11
+
12
+ /**
13
+ * Some llama-cpp chat templates (Qwen, Mistral family) enforce alphanumeric
14
+ * tool_call IDs via Jinja raise_exception. Gemma's template drops tool_use_id
15
+ * entirely (cf. gemma4-prompt-builder.ts:194) — safe passthrough.
16
+ * Mirrors the convention of sanitizeServerName (tool-layers.ts:24).
17
+ */
18
+ function needsIdSanitize(model: string | null | undefined): boolean {
19
+ if (!model) return false;
20
+ return /^(qwen|mistral|ministral|devstral|codestral|bielik)/.test(model);
21
+ }
22
+
23
+ export async function hawkProxy(
24
+ body: Record<string, unknown>,
25
+ apiKey: string,
26
+ model?: string | null,
27
+ ): Promise<Response> {
28
+ if (!apiKey) {
29
+ return new Response('HAWK_API_KEY missing', { status: 500 });
30
+ }
31
+ const m = model ?? 'qwen35-4b';
32
+ const cloned = JSON.parse(JSON.stringify(body)) as Record<string, unknown>;
33
+ if (needsIdSanitize(m) && Array.isArray(cloned.messages)) {
34
+ for (const msg of cloned.messages as Array<Record<string, unknown>>) {
35
+ if (msg.role === 'assistant' && Array.isArray(msg.tool_calls)) {
36
+ for (const tc of msg.tool_calls as Array<Record<string, unknown>>) {
37
+ tc.id = sanitizeId(tc.id as string | undefined);
38
+ }
39
+ } else if (msg.role === 'tool' && typeof msg.tool_call_id === 'string') {
40
+ msg.tool_call_id = sanitizeId(msg.tool_call_id);
41
+ }
42
+ }
43
+ }
44
+ const res = await fetch('https://hawk.hyperskills.net/v1/chat/completions', {
45
+ method: 'POST',
46
+ headers: {
47
+ 'Content-Type': 'application/json',
48
+ 'Authorization': `Bearer ${apiKey}`,
49
+ },
50
+ body: JSON.stringify({ ...cloned, model: m }),
51
+ });
52
+ if (!res.ok) return new Response(await res.text(), { status: res.status });
53
+ return Response.json(await res.json());
54
+ }
@@ -0,0 +1,2 @@
1
+ export { llmProxy } from './llmProxy.js';
2
+ export { hawkProxy } from './hawkProxy.js';
@@ -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 {