@gradio/core 0.23.2 → 0.25.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # @gradio/core
2
2
 
3
+ ## 0.25.0
4
+
5
+ ### Features
6
+
7
+ - [#11662](https://github.com/gradio-app/gradio/pull/11662) [`a78f5fa`](https://github.com/gradio-app/gradio/commit/a78f5fa466a4b11ffaaafc5099a64df49afb6e41) - Gradio vibe editor. Thanks @aliabid94!
8
+
9
+ ### Dependency updates
10
+
11
+ - @gradio/code@0.14.13
12
+ - @gradio/upload@0.16.13
13
+ - @gradio/video@0.14.23
14
+ - @gradio/client@1.16.0
15
+ - @gradio/image@0.22.15
16
+ - @gradio/button@0.5.9
17
+ - @gradio/gallery@0.15.29
18
+ - @gradio/file@0.12.26
19
+
20
+ ## 0.24.0
21
+
22
+ ### Dependency updates
23
+
24
+ - @gradio/dropdown@0.10.0
25
+
26
+ ## 0.24.0
27
+
28
+ ### Features
29
+
30
+ - [#11651](https://github.com/gradio-app/gradio/pull/11651) [`5b0e212`](https://github.com/gradio-app/gradio/commit/5b0e212ec0d54b5d793985de94c216bc5a73f610) - Allow users choose the MCP tools from MCP docs pane. Thanks @abidlabs!
31
+ - [#11622](https://github.com/gradio-app/gradio/pull/11622) [`ae9aaee`](https://github.com/gradio-app/gradio/commit/ae9aaeea62974f1fb533946a2a7c8461572778ef) - Expose Streamable HTTP endpoint in MCP Server at `/mcp`. Thanks @abidlabs!
32
+
33
+ ### Dependency updates
34
+
35
+ - @gradio/upload@0.16.12
36
+ - @gradio/video@0.14.22
37
+ - @gradio/code@0.14.12
38
+ - @gradio/client@1.15.7
39
+ - @gradio/gallery@0.15.28
40
+ - @gradio/image@0.22.14
41
+ - @gradio/button@0.5.8
42
+ - @gradio/file@0.12.25
43
+
3
44
  ## 0.23.2
4
45
 
5
46
  ### Fixes
@@ -35,6 +35,7 @@ export let api_prefix = "";
35
35
  export let max_file_size = void 0;
36
36
  export let initial_layout = void 0;
37
37
  export let css = null;
38
+ export let vibe_mode = false;
38
39
  let broken_connection = false;
39
40
  let {
40
41
  layout: _layout,
@@ -63,6 +64,7 @@ $:
63
64
  handle_load_triggers();
64
65
  old_dependencies = dependencies;
65
66
  }
67
+ let vibe_editor_width = 350;
66
68
  async function run() {
67
69
  await setupi18n(app.config?.i18n_translations || void 0);
68
70
  layout_creating = true;
@@ -87,6 +89,7 @@ let allow_video_trim = true;
87
89
  let ApiDocs = null;
88
90
  let ApiRecorder = null;
89
91
  let Settings = null;
92
+ let VibeEditor = null;
90
93
  async function loadApiDocs() {
91
94
  if (!ApiDocs || !ApiRecorder) {
92
95
  const api_docs_module = await import("./api_docs/ApiDocs.svelte");
@@ -109,6 +112,12 @@ async function loadSettings() {
109
112
  Settings = settings_module.default;
110
113
  }
111
114
  }
115
+ async function loadVibeEditor() {
116
+ if (!VibeEditor) {
117
+ const vibe_editor_module = await import("@gradio/vibeeditor");
118
+ VibeEditor = vibe_editor_module.default;
119
+ }
120
+ }
112
121
  async function set_api_docs_visible(visible) {
113
122
  api_recorder_visible = false;
114
123
  if (visible) {
@@ -753,6 +762,13 @@ onMount(() => {
753
762
  $is_screen_recording = isRecording;
754
763
  }
755
764
  );
765
+ const handleVibeEditorResize = (event) => {
766
+ vibe_editor_width = event.detail.width;
767
+ };
768
+ window.addEventListener(
769
+ "vibeEditorResize",
770
+ handleVibeEditorResize
771
+ );
756
772
  if (api_docs_visible) {
757
773
  loadApiDocs();
758
774
  }
@@ -762,6 +778,9 @@ onMount(() => {
762
778
  if (settings_visible) {
763
779
  loadSettings();
764
780
  }
781
+ if (vibe_mode) {
782
+ loadVibeEditor();
783
+ }
765
784
  });
766
785
  function screen_recording() {
767
786
  if ($is_screen_recording) {
@@ -782,7 +801,11 @@ function screen_recording() {
782
801
  </svelte:head>
783
802
 
784
803
  <div class="wrap" style:min-height={app_mode ? "100%" : "auto"}>
785
- <div class="contain" style:flex-grow={app_mode ? "1" : "auto"}>
804
+ <div
805
+ class="contain"
806
+ style:flex-grow={app_mode ? "1" : "auto"}
807
+ style:margin-right={vibe_mode ? `${vibe_editor_width}px` : "0"}
808
+ >
786
809
  {#if $_layout && app.config}
787
810
  <MountComponents
788
811
  rootNode={$_layout}
@@ -938,6 +961,10 @@ function screen_recording() {
938
961
  <Toast {messages} on:close={handle_error_close} />
939
962
  {/if}
940
963
 
964
+ {#if vibe_mode && VibeEditor}
965
+ <svelte:component this={VibeEditor} {app} {root} />
966
+ {/if}
967
+
941
968
  <style>
942
969
  .wrap {
943
970
  display: flex;
@@ -28,6 +28,7 @@ declare const __propDef: {
28
28
  max_file_size?: number | undefined;
29
29
  initial_layout?: ComponentMeta | undefined;
30
30
  css?: string | null | undefined;
31
+ vibe_mode?: boolean | undefined;
31
32
  search_params: URLSearchParams;
32
33
  render_complete?: boolean | undefined;
33
34
  add_new_message?: ((title: string, message: string, type: ToastMessage["type"]) => void) | undefined;
@@ -11,7 +11,7 @@ const dispatch = createEventDispatcher();
11
11
  <h2>
12
12
  <img src={api_logo} alt="" />
13
13
  <div class="title">
14
- API documentation
14
+ {#if current_language === "mcp"}MCP{:else}API{/if} documentation
15
15
  <div class="url">
16
16
  {root}
17
17
  </div>
@@ -13,6 +13,7 @@ import javascript from "./img/javascript.svg";
13
13
  import bash from "./img/bash.svg";
14
14
  import ResponseSnippet from "./ResponseSnippet.svelte";
15
15
  import mcp from "./img/mcp.svg";
16
+ import MCPSnippet from "./MCPSnippet.svelte";
16
17
  export let dependencies;
17
18
  export let root;
18
19
  export let app;
@@ -75,12 +76,35 @@ get_js_info().then((js_api_info) => {
75
76
  js_info = js_api_info;
76
77
  });
77
78
  const dispatch = createEventDispatcher();
78
- const mcp_server_url = `${root}gradio_api/mcp/sse`;
79
+ $:
80
+ selected_tools_array = Array.from(selected_tools);
81
+ $:
82
+ selected_tools_without_prefix = selected_tools_array.map(remove_tool_prefix);
83
+ $:
84
+ mcp_server_url = `${root}gradio_api/mcp/sse`;
85
+ $:
86
+ mcp_server_url_streamable = selected_tools_array.length > 0 && selected_tools_array.length < tools.length ? `${root}gradio_api/mcp/?tools=${selected_tools_without_prefix.join(",")}` : `${root}gradio_api/mcp/`;
87
+ $:
88
+ if (mcp_json_sse && selected_tools.size > 0) {
89
+ const baseUrl = selected_tools_array.length > 0 && selected_tools_array.length < tools.length ? `${root}gradio_api/mcp/sse?tools=${selected_tools_without_prefix.join(",")}` : `${root}gradio_api/mcp/sse`;
90
+ mcp_json_sse.mcpServers.gradio.url = baseUrl;
91
+ if (mcp_json_stdio) {
92
+ mcp_json_stdio.mcpServers.gradio.args[1] = baseUrl;
93
+ }
94
+ }
79
95
  let tools = [];
80
96
  let headers = [];
81
97
  let mcp_json_sse;
82
98
  let mcp_json_stdio;
83
99
  let file_data_present = false;
100
+ let selected_tools = /* @__PURE__ */ new Set();
101
+ let tool_prefix = space_id ? space_id.split("/").pop() + "_" : "";
102
+ function remove_tool_prefix(toolName) {
103
+ if (tool_prefix && toolName.startsWith(tool_prefix)) {
104
+ return toolName.slice(tool_prefix.length);
105
+ }
106
+ return toolName;
107
+ }
84
108
  const upload_file_mcp_server = {
85
109
  command: "uvx",
86
110
  args: [
@@ -92,9 +116,10 @@ const upload_file_mcp_server = {
92
116
  "<UPLOAD_DIRECTORY>"
93
117
  ]
94
118
  };
95
- async function fetchMcpTools() {
119
+ async function fetch_mcp_tools() {
96
120
  try {
97
- const response = await fetch(`${root}gradio_api/mcp/schema`);
121
+ let schema_url = `${root}gradio_api/mcp/schema`;
122
+ const response = await fetch(schema_url);
98
123
  const schema = await response.json();
99
124
  file_data_present = schema.map((tool) => tool.meta?.file_data_present).some((present) => present);
100
125
  tools = schema.map((tool) => ({
@@ -103,16 +128,20 @@ async function fetchMcpTools() {
103
128
  parameters: tool.inputSchema?.properties || {},
104
129
  expanded: false
105
130
  }));
131
+ selected_tools = new Set(tools.map((tool) => tool.name));
106
132
  headers = schema.map((tool) => tool.meta?.headers || []).flat();
107
133
  if (headers.length > 0) {
108
134
  mcp_json_sse = {
109
135
  mcpServers: {
110
136
  gradio: {
111
137
  url: mcp_server_url,
112
- headers: headers.reduce((accumulator, current_key) => {
113
- accumulator[current_key] = "<YOUR_HEADER_VALUE>";
114
- return accumulator;
115
- }, {})
138
+ headers: headers.reduce(
139
+ (accumulator, current_key) => {
140
+ accumulator[current_key] = "<YOUR_HEADER_VALUE>";
141
+ return accumulator;
142
+ },
143
+ {}
144
+ )
116
145
  }
117
146
  }
118
147
  };
@@ -171,7 +200,7 @@ onMount(() => {
171
200
  fetch(mcp_server_url).then((response) => {
172
201
  mcp_server_active = response.ok;
173
202
  if (mcp_server_active) {
174
- fetchMcpTools();
203
+ fetch_mcp_tools();
175
204
  if (!is_valid_language(lang_param)) {
176
205
  current_language = "mcp";
177
206
  }
@@ -268,135 +297,18 @@ onMount(() => {
268
297
  target="_blank">docs</a
269
298
  >) if you don't already have it installed.
270
299
  {:else if current_language == "mcp"}
271
- {#if mcp_server_active}
272
- <Block>
273
- <div class="mcp-url">
274
- <label
275
- ><span class="status-indicator active">●</span>MCP Server
276
- URL (SSE)</label
277
- >
278
- <div class="textbox">
279
- <input type="text" readonly value={mcp_server_url} />
280
- <CopyButton code={mcp_server_url} />
281
- </div>
282
- </div>
283
- </Block>
284
- <p>&nbsp;</p>
285
- <strong>Available MCP Tools</strong>
286
- <div class="mcp-tools">
287
- {#each tools as tool}
288
- <div class="tool-item">
289
- <button
290
- class="tool-header"
291
- on:click={() => (tool.expanded = !tool.expanded)}
292
- >
293
- <span
294
- ><span class="tool-name">{tool.name}</span> &nbsp;
295
- <span class="tool-description"
296
- >{tool.description
297
- ? tool.description
298
- : "⚠︎ No description provided in function docstring"}</span
299
- ></span
300
- >
301
- <span class="tool-arrow"
302
- >{tool.expanded ? "▼" : "▶"}</span
303
- >
304
- </button>
305
- {#if tool.expanded}
306
- <div class="tool-content">
307
- {#if Object.keys(tool.parameters).length > 0}
308
- <div class="tool-parameters">
309
- {#each Object.entries(tool.parameters) as [name, param]}
310
- <div class="parameter">
311
- <code>{name}</code>
312
- <span class="parameter-type">
313
- ({param.type}{param.default !== undefined
314
- ? `, default: ${JSON.stringify(param.default)}`
315
- : ""})
316
- </span>
317
- <p class="parameter-description">
318
- {param.description
319
- ? param.description
320
- : "⚠︎ No description for this parameter in function docstring"}
321
- </p>
322
- </div>
323
- {/each}
324
- </div>
325
- {:else}
326
- <p>Takes no input parameters</p>
327
- {/if}
328
- </div>
329
- {/if}
330
- </div>
331
- {/each}
332
- </div>
333
- <p>&nbsp;</p>
334
-
335
- <strong>SSE Transport</strong>: To add this MCP to clients that
336
- support SSE (e.g. Cursor, Windsurf, Cline), simply add the
337
- following configuration to your MCP config.
338
- <p>&nbsp;</p>
339
- <Block>
340
- <code>
341
- <div class="copy">
342
- <CopyButton
343
- code={JSON.stringify(mcp_json_sse, null, 2)}
344
- />
345
- </div>
346
- <div>
347
- <pre>{JSON.stringify(mcp_json_sse, null, 2)}</pre>
348
- </div>
349
- </code>
350
- </Block>
351
- {#if file_data_present}
352
- <p>&nbsp;</p>
353
- <em>Note about files</em>: Gradio MCP servers that have files
354
- as inputs need the files as URLs, so the
355
- <code>upload_files_to_gradio</code>
356
- tool is included for your convenience. This tool can upload files
357
- located in the specified <code>UPLOAD_DIRECTORY</code>
358
- argument (an absolute path in your local machine) or any of its
359
- subdirectories to the Gradio app. You can omit this tool if you
360
- are fine manually uploading files yourself and providing the URLs.
361
- Before using this tool, you must have
362
- <a
363
- href="https://docs.astral.sh/uv/getting-started/installation/"
364
- target="_blank">uv installed</a
365
- >.
366
- <p>&nbsp;</p>
367
- {/if}
368
-
369
- <strong>STDIO Transport</strong>: For clients that only support
370
- stdio (e.g. Claude Desktop), first
371
- <a href="https://nodejs.org/en/download/" target="_blank"
372
- >install Node.js</a
373
- >. Then, you can use the following command:
374
- <p>&nbsp;</p>
375
- <Block>
376
- <code>
377
- <div class="copy">
378
- <CopyButton
379
- code={JSON.stringify(mcp_json_stdio, null, 2)}
380
- />
381
- </div>
382
- <div>
383
- <pre>{JSON.stringify(mcp_json_stdio, null, 2)}</pre>
384
- </div>
385
- </code>
386
- </Block>
387
- <p>&nbsp;</p>
388
- <p>
389
- <a href={mcp_docs} target="_blank">
390
- Read more about MCP in the Gradio docs
391
- </a>
392
- </p>
393
- {:else}
394
- This Gradio app can also serve as an MCP server, with an MCP
395
- tool corresponding to each API endpoint. To enable this, launch
396
- this Gradio app with <code>.launch(mcp_server=True)</code> or
397
- set the <code>GRADIO_MCP_SERVER</code> env variable to
398
- <code>"True"</code>.
399
- {/if}
300
+ <MCPSnippet
301
+ {mcp_server_active}
302
+ {mcp_server_url}
303
+ {mcp_server_url_streamable}
304
+ tools={tools.filter((tool) => selected_tools.has(tool.name))}
305
+ all_tools={tools}
306
+ bind:selected_tools
307
+ {mcp_json_sse}
308
+ {mcp_json_stdio}
309
+ {file_data_present}
310
+ {mcp_docs}
311
+ />
400
312
  {:else}
401
313
  1. Confirm that you have cURL installed on your system.
402
314
  {/if}
@@ -570,6 +482,7 @@ onMount(() => {
570
482
  color: var(--body-text-color);
571
483
  line-height: 1;
572
484
  user-select: none;
485
+ font-size: var(--text-lg);
573
486
  }
574
487
 
575
488
  .current-lang {
@@ -590,7 +503,8 @@ onMount(() => {
590
503
 
591
504
  .snippet img {
592
505
  margin-right: var(--size-1-5);
593
- width: var(--size-3);
506
+ width: var(--size-4);
507
+ height: var(--size-4);
594
508
  }
595
509
 
596
510
  .header {
@@ -689,136 +603,4 @@ onMount(() => {
689
603
  .api-name {
690
604
  color: var(--color-accent);
691
605
  }
692
-
693
- .mcp-url {
694
- padding: var(--size-2);
695
- position: relative;
696
- }
697
-
698
- .mcp-url label {
699
- display: block;
700
- margin-bottom: var(--size-2);
701
- font-weight: 600;
702
- color: var(--body-text-color);
703
- }
704
-
705
- .mcp-url .textbox {
706
- display: flex;
707
- align-items: center;
708
- gap: var(--size-2);
709
- border: 1px solid var(--border-color-primary);
710
- border-radius: var(--radius-sm);
711
- padding: var(--size-2);
712
- background: var(--background-fill-primary);
713
- }
714
-
715
- .mcp-url input {
716
- flex: 1;
717
- border: none;
718
- background: none;
719
- color: var(--body-text-color);
720
- font-family: var(--font-mono);
721
- font-size: var(--text-md);
722
- width: 100%;
723
- }
724
-
725
- .mcp-url input:focus {
726
- outline: none;
727
- }
728
-
729
- .status-indicator {
730
- display: inline-block;
731
- margin-right: var(--size-1-5);
732
- position: relative;
733
- top: -1px;
734
- font-size: 0.8em;
735
- }
736
-
737
- .status-indicator.active {
738
- color: #4caf50;
739
- animation: pulse 1s infinite;
740
- }
741
-
742
- @keyframes pulse {
743
- 0% {
744
- opacity: 1;
745
- }
746
- 50% {
747
- opacity: 0.6;
748
- }
749
- 100% {
750
- opacity: 1;
751
- }
752
- }
753
-
754
- .mcp-tools {
755
- margin-top: var(--size-4);
756
- border: 1px solid var(--border-color-primary);
757
- border-radius: var(--radius-md);
758
- overflow: hidden;
759
- }
760
-
761
- .tool-item {
762
- border-bottom: 1px solid var(--border-color-primary);
763
- }
764
-
765
- .tool-item:last-child {
766
- border-bottom: none;
767
- }
768
-
769
- .tool-header {
770
- width: 100%;
771
- display: flex;
772
- justify-content: space-between;
773
- align-items: center;
774
- padding: var(--size-3);
775
- background: var(--background-fill-primary);
776
- border: none;
777
- cursor: pointer;
778
- text-align: left;
779
- }
780
-
781
- .tool-header:hover {
782
- background: var(--background-fill-secondary);
783
- }
784
-
785
- .tool-name {
786
- font-family: var(--font-mono);
787
- font-weight: 600;
788
- }
789
-
790
- .tool-arrow {
791
- color: var(--body-text-color-subdued);
792
- }
793
-
794
- .tool-content {
795
- padding: var(--size-3);
796
- background: var(--background-fill-secondary);
797
- }
798
-
799
- .tool-description {
800
- margin-bottom: var(--size-3);
801
- color: var(--body-text-color);
802
- }
803
- .parameter {
804
- margin-bottom: var(--size-2);
805
- padding: var(--size-2);
806
- background: var(--background-fill-primary);
807
- border-radius: var(--radius-sm);
808
- }
809
-
810
- .parameter code {
811
- font-weight: 600;
812
- color: var(--color-accent);
813
- }
814
-
815
- .parameter-type {
816
- color: var(--body-text-color-subdued);
817
- margin-left: var(--size-1);
818
- }
819
-
820
- .parameter-description {
821
- margin-top: var(--size-1);
822
- color: var(--body-text-color);
823
- }
824
606
  </style>