shaun smith commited on
Commit
cc316dd
·
unverified ·
1 Parent(s): 0464cba

MCP Tool Progress Notifications and MCP SDK bump. (#2030)

Browse files

* bump SDK version

* MCP Tool Progress Notifications

* lint

README.md CHANGED
@@ -1,5 +1,5 @@
1
- # Chat UI
2
-
3
  ![Chat UI repository thumbnail](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/chat-ui/chat-ui-2026.png)
4
 
5
  A chat interface for LLMs. It is a SvelteKit app and it powers the [HuggingChat app on hf.co/chat](https://huggingface.co/chat).
 
1
+ # Chat UI
2
+
3
  ![Chat UI repository thumbnail](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/chat-ui/chat-ui-2026.png)
4
 
5
  A chat interface for LLMs. It is a SvelteKit app and it powers the [HuggingChat app on hf.co/chat](https://huggingface.co/chat).
package-lock.json CHANGED
@@ -13,7 +13,7 @@
13
  "@huggingface/hub": "^2.2.0",
14
  "@huggingface/inference": "^4.11.3",
15
  "@iconify-json/bi": "^1.1.21",
16
- "@modelcontextprotocol/sdk": "^1.21.1",
17
  "@resvg/resvg-js": "^2.6.2",
18
  "@sinclair/typebox": "^0.34.41",
19
  "autoprefixer": "^10.4.14",
@@ -680,7 +680,6 @@
680
  "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.927.0.tgz",
681
  "integrity": "sha512-CasoHKKE/K+6YcVqjE+v5dVyKqKBtfzZyvGi669HvJ1f4EPHbVRPPLIb0eAYd/aEmwHsB/nn9VnyN9Wq5OppUQ==",
682
  "license": "Apache-2.0",
683
- "peer": true,
684
  "dependencies": {
685
  "@aws-sdk/client-cognito-identity": "3.927.0",
686
  "@aws-sdk/core": "3.927.0",
@@ -957,6 +956,7 @@
957
  "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
958
  "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
959
  "license": "MIT",
 
960
  "dependencies": {
961
  "@babel/helper-validator-identifier": "^7.27.1",
962
  "js-tokens": "^4.0.0",
@@ -971,6 +971,7 @@
971
  "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
972
  "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
973
  "license": "MIT",
 
974
  "engines": {
975
  "node": ">=6.9.0"
976
  }
@@ -1072,7 +1073,6 @@
1072
  }
1073
  ],
1074
  "license": "MIT",
1075
- "peer": true,
1076
  "engines": {
1077
  "node": ">=18"
1078
  },
@@ -1096,7 +1096,6 @@
1096
  }
1097
  ],
1098
  "license": "MIT",
1099
- "peer": true,
1100
  "engines": {
1101
  "node": ">=18"
1102
  }
@@ -1665,6 +1664,18 @@
1665
  "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
1666
  "license": "MIT"
1667
  },
 
 
 
 
 
 
 
 
 
 
 
 
1668
  "node_modules/@huggingface/hub": {
1669
  "version": "2.2.0",
1670
  "resolved": "https://registry.npmjs.org/@huggingface/hub/-/hub-2.2.0.tgz",
@@ -2436,11 +2447,12 @@
2436
  }
2437
  },
2438
  "node_modules/@modelcontextprotocol/sdk": {
2439
- "version": "1.21.1",
2440
- "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.21.1.tgz",
2441
- "integrity": "sha512-UyLFcJLDvUuZbGnaQqXFT32CpPpGj7VS19roLut6gkQVhb439xUzYWbsUvdI3ZPL+2hnFosuugtYWE0Mcs1rmQ==",
2442
  "license": "MIT",
2443
  "dependencies": {
 
2444
  "ajv": "^8.17.1",
2445
  "ajv-formats": "^3.0.1",
2446
  "content-type": "^1.0.5",
@@ -2450,20 +2462,26 @@
2450
  "eventsource-parser": "^3.0.0",
2451
  "express": "^5.0.1",
2452
  "express-rate-limit": "^7.5.0",
 
 
2453
  "pkce-challenge": "^5.0.0",
2454
  "raw-body": "^3.0.0",
2455
- "zod": "^3.23.8",
2456
- "zod-to-json-schema": "^3.24.1"
2457
  },
2458
  "engines": {
2459
  "node": ">=18"
2460
  },
2461
  "peerDependencies": {
2462
- "@cfworker/json-schema": "^4.1.1"
 
2463
  },
2464
  "peerDependenciesMeta": {
2465
  "@cfworker/json-schema": {
2466
  "optional": true
 
 
 
2467
  }
2468
  }
2469
  },
@@ -3230,8 +3248,7 @@
3230
  "version": "0.34.41",
3231
  "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
3232
  "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
3233
- "license": "MIT",
3234
- "peer": true
3235
  },
3236
  "node_modules/@smithy/abort-controller": {
3237
  "version": "4.2.4",
@@ -3844,7 +3861,6 @@
3844
  "integrity": "sha512-EMYTY4+rNa7TaRZYzCqhQslEkACEZzWc363jOYuc90oJrgvlWTcgqTxcGSIJim48hPaXwYlHyatRnnMmTFf5tA==",
3845
  "devOptional": true,
3846
  "license": "MIT",
3847
- "peer": true,
3848
  "dependencies": {
3849
  "@sveltejs/acorn-typescript": "^1.0.5",
3850
  "@types/cookie": "^0.6.0",
@@ -3877,7 +3893,6 @@
3877
  "integrity": "sha512-wojIS/7GYnJDYIg1higWj2ROA6sSRWvcR1PO/bqEyFr/5UZah26c8Cz4u0NaqjPeVltzsVpt2Tm8d2io0V+4Tw==",
3878
  "devOptional": true,
3879
  "license": "MIT",
3880
- "peer": true,
3881
  "dependencies": {
3882
  "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1",
3883
  "debug": "^4.4.1",
@@ -3917,6 +3932,7 @@
3917
  "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",
3918
  "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
3919
  "license": "Apache-2.0",
 
3920
  "dependencies": {
3921
  "tslib": "^2.8.0"
3922
  }
@@ -3962,6 +3978,7 @@
3962
  "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz",
3963
  "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==",
3964
  "license": "MIT",
 
3965
  "engines": {
3966
  "node": ">=12",
3967
  "npm": ">=6"
@@ -4007,7 +4024,8 @@
4007
  "version": "5.0.4",
4008
  "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
4009
  "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
4010
- "license": "MIT"
 
4011
  },
4012
  "node_modules/@types/chai": {
4013
  "version": "5.2.2",
@@ -4236,7 +4254,6 @@
4236
  "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
4237
  "dev": true,
4238
  "license": "BSD-2-Clause",
4239
- "peer": true,
4240
  "dependencies": {
4241
  "@typescript-eslint/scope-manager": "6.21.0",
4242
  "@typescript-eslint/types": "6.21.0",
@@ -4635,7 +4652,6 @@
4635
  "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
4636
  "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
4637
  "license": "MIT",
4638
- "peer": true,
4639
  "bin": {
4640
  "acorn": "bin/acorn"
4641
  },
@@ -4819,6 +4835,7 @@
4819
  "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
4820
  "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
4821
  "license": "Apache-2.0",
 
4822
  "dependencies": {
4823
  "dequal": "^2.0.3"
4824
  }
@@ -5084,7 +5101,6 @@
5084
  }
5085
  ],
5086
  "license": "MIT",
5087
- "peer": true,
5088
  "dependencies": {
5089
  "caniuse-lite": "^1.0.30001718",
5090
  "electron-to-chromium": "^1.5.160",
@@ -5754,7 +5770,8 @@
5754
  "version": "0.5.16",
5755
  "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
5756
  "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
5757
- "license": "MIT"
 
5758
  },
5759
  "node_modules/domexception": {
5760
  "version": "4.0.0",
@@ -5828,7 +5845,6 @@
5828
  "resolved": "https://registry.npmjs.org/elysia/-/elysia-1.3.4.tgz",
5829
  "integrity": "sha512-kAfM3Zwovy3z255IZgTKVxBw91HbgKhYl3TqrGRdZqqr+Fd+4eKOfvxgaKij22+MZLczPzIHtscAmvfpI3+q/A==",
5830
  "license": "MIT",
5831
- "peer": true,
5832
  "dependencies": {
5833
  "cookie": "^1.0.2",
5834
  "exact-mirror": "0.1.2",
@@ -6029,7 +6045,6 @@
6029
  "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
6030
  "dev": true,
6031
  "license": "MIT",
6032
- "peer": true,
6033
  "dependencies": {
6034
  "@eslint-community/eslint-utils": "^4.2.0",
6035
  "@eslint-community/regexpp": "^4.6.1",
@@ -6667,7 +6682,6 @@
6667
  "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.0.0.tgz",
6668
  "integrity": "sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg==",
6669
  "license": "MIT",
6670
- "peer": true,
6671
  "dependencies": {
6672
  "@tokenizer/inflate": "^0.2.7",
6673
  "strtok3": "^10.2.2",
@@ -7171,6 +7185,16 @@
7171
  "node": ">=12.0.0"
7172
  }
7173
  },
 
 
 
 
 
 
 
 
 
 
7174
  "node_modules/hookable": {
7175
  "version": "5.5.3",
7176
  "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
@@ -7776,6 +7800,15 @@
7776
  "jiti": "bin/jiti.js"
7777
  }
7778
  },
 
 
 
 
 
 
 
 
 
7779
  "node_modules/joycon": {
7780
  "version": "3.1.1",
7781
  "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
@@ -7789,7 +7822,8 @@
7789
  "version": "4.0.0",
7790
  "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
7791
  "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
7792
- "license": "MIT"
 
7793
  },
7794
  "node_modules/js-yaml": {
7795
  "version": "4.1.0",
@@ -7891,6 +7925,12 @@
7891
  "dev": true,
7892
  "license": "MIT"
7893
  },
 
 
 
 
 
 
7894
  "node_modules/json-stable-stringify-without-jsonify": {
7895
  "version": "1.0.1",
7896
  "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
@@ -9561,7 +9601,6 @@
9561
  "integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==",
9562
  "devOptional": true,
9563
  "license": "Apache-2.0",
9564
- "peer": true,
9565
  "dependencies": {
9566
  "playwright-core": "1.55.1"
9567
  },
@@ -9607,7 +9646,6 @@
9607
  }
9608
  ],
9609
  "license": "MIT",
9610
- "peer": true,
9611
  "dependencies": {
9612
  "nanoid": "^3.3.11",
9613
  "picocolors": "^1.1.1",
@@ -9839,7 +9877,6 @@
9839
  "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
9840
  "dev": true,
9841
  "license": "MIT",
9842
- "peer": true,
9843
  "bin": {
9844
  "prettier": "bin/prettier.cjs"
9845
  },
@@ -9856,7 +9893,6 @@
9856
  "integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==",
9857
  "dev": true,
9858
  "license": "MIT",
9859
- "peer": true,
9860
  "peerDependencies": {
9861
  "prettier": "^3.0.0",
9862
  "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
@@ -9946,6 +9982,7 @@
9946
  "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
9947
  "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
9948
  "license": "MIT",
 
9949
  "dependencies": {
9950
  "ansi-regex": "^5.0.1",
9951
  "ansi-styles": "^5.0.0",
@@ -9960,6 +9997,7 @@
9960
  "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
9961
  "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
9962
  "license": "MIT",
 
9963
  "engines": {
9964
  "node": ">=10"
9965
  },
@@ -10168,7 +10206,8 @@
10168
  "version": "17.0.2",
10169
  "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
10170
  "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
10171
- "license": "MIT"
 
10172
  },
10173
  "node_modules/read-cache": {
10174
  "version": "1.0.0",
@@ -10332,7 +10371,6 @@
10332
  "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz",
10333
  "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==",
10334
  "license": "MIT",
10335
- "peer": true,
10336
  "dependencies": {
10337
  "@types/estree": "1.0.7"
10338
  },
@@ -11251,7 +11289,6 @@
11251
  "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.33.14.tgz",
11252
  "integrity": "sha512-kRlbhIlMTijbFmVDQFDeKXPLlX1/ovXwV0I162wRqQhRcygaqDIcu1d/Ese3H2uI+yt3uT8E7ndgDthQv5v5BA==",
11253
  "license": "MIT",
11254
- "peer": true,
11255
  "dependencies": {
11256
  "@ampproject/remapping": "^2.3.0",
11257
  "@jridgewell/sourcemap-codec": "^1.5.0",
@@ -11391,7 +11428,6 @@
11391
  "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
11392
  "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
11393
  "license": "MIT",
11394
- "peer": true,
11395
  "dependencies": {
11396
  "@alloc/quick-lru": "^5.2.0",
11397
  "arg": "^5.0.2",
@@ -11849,7 +11885,6 @@
11849
  "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
11850
  "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
11851
  "license": "Apache-2.0",
11852
- "peer": true,
11853
  "bin": {
11854
  "tsc": "bin/tsc",
11855
  "tsserver": "bin/tsserver"
@@ -12085,7 +12120,6 @@
12085
  "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
12086
  "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
12087
  "license": "MIT",
12088
- "peer": true,
12089
  "dependencies": {
12090
  "esbuild": "^0.25.0",
12091
  "fdir": "^6.4.4",
@@ -12221,7 +12255,6 @@
12221
  "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.2.tgz",
12222
  "integrity": "sha512-fyNn/Rp016Bt5qvY0OQvIUCwW2vnaEBLxP42PmKbNIoasSYjML+8xyeADOPvBe+Xfl/ubIw4og7Lt9jflRsCNw==",
12223
  "license": "MIT",
12224
- "peer": true,
12225
  "dependencies": {
12226
  "@types/chai": "^5.2.2",
12227
  "@vitest/expect": "3.2.2",
@@ -12544,7 +12577,6 @@
12544
  "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
12545
  "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
12546
  "license": "MIT",
12547
- "peer": true,
12548
  "engines": {
12549
  "node": ">=10.0.0"
12550
  },
@@ -12667,18 +12699,17 @@
12667
  "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.55.tgz",
12668
  "integrity": "sha512-219huNnkSLQnLsQ3uaRjXsxMrVm5C9W3OOpEVt2k5tvMKuA8nBSu38e0B//a+he9Iq2dvmk2VyYVlHqiHa4YBA==",
12669
  "license": "MIT",
12670
- "peer": true,
12671
  "funding": {
12672
  "url": "https://github.com/sponsors/colinhacks"
12673
  }
12674
  },
12675
  "node_modules/zod-to-json-schema": {
12676
- "version": "3.24.6",
12677
- "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz",
12678
- "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==",
12679
  "license": "ISC",
12680
  "peerDependencies": {
12681
- "zod": "^3.24.1"
12682
  }
12683
  }
12684
  }
 
13
  "@huggingface/hub": "^2.2.0",
14
  "@huggingface/inference": "^4.11.3",
15
  "@iconify-json/bi": "^1.1.21",
16
+ "@modelcontextprotocol/sdk": "^1.25.1",
17
  "@resvg/resvg-js": "^2.6.2",
18
  "@sinclair/typebox": "^0.34.41",
19
  "autoprefixer": "^10.4.14",
 
680
  "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.927.0.tgz",
681
  "integrity": "sha512-CasoHKKE/K+6YcVqjE+v5dVyKqKBtfzZyvGi669HvJ1f4EPHbVRPPLIb0eAYd/aEmwHsB/nn9VnyN9Wq5OppUQ==",
682
  "license": "Apache-2.0",
 
683
  "dependencies": {
684
  "@aws-sdk/client-cognito-identity": "3.927.0",
685
  "@aws-sdk/core": "3.927.0",
 
956
  "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
957
  "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
958
  "license": "MIT",
959
+ "peer": true,
960
  "dependencies": {
961
  "@babel/helper-validator-identifier": "^7.27.1",
962
  "js-tokens": "^4.0.0",
 
971
  "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
972
  "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
973
  "license": "MIT",
974
+ "peer": true,
975
  "engines": {
976
  "node": ">=6.9.0"
977
  }
 
1073
  }
1074
  ],
1075
  "license": "MIT",
 
1076
  "engines": {
1077
  "node": ">=18"
1078
  },
 
1096
  }
1097
  ],
1098
  "license": "MIT",
 
1099
  "engines": {
1100
  "node": ">=18"
1101
  }
 
1664
  "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
1665
  "license": "MIT"
1666
  },
1667
+ "node_modules/@hono/node-server": {
1668
+ "version": "1.19.7",
1669
+ "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.7.tgz",
1670
+ "integrity": "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==",
1671
+ "license": "MIT",
1672
+ "engines": {
1673
+ "node": ">=18.14.1"
1674
+ },
1675
+ "peerDependencies": {
1676
+ "hono": "^4"
1677
+ }
1678
+ },
1679
  "node_modules/@huggingface/hub": {
1680
  "version": "2.2.0",
1681
  "resolved": "https://registry.npmjs.org/@huggingface/hub/-/hub-2.2.0.tgz",
 
2447
  }
2448
  },
2449
  "node_modules/@modelcontextprotocol/sdk": {
2450
+ "version": "1.25.1",
2451
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.1.tgz",
2452
+ "integrity": "sha512-yO28oVFFC7EBoiKdAn+VqRm+plcfv4v0xp6osG/VsCB0NlPZWi87ajbCZZ8f/RvOFLEu7//rSRmuZZ7lMoe3gQ==",
2453
  "license": "MIT",
2454
  "dependencies": {
2455
+ "@hono/node-server": "^1.19.7",
2456
  "ajv": "^8.17.1",
2457
  "ajv-formats": "^3.0.1",
2458
  "content-type": "^1.0.5",
 
2462
  "eventsource-parser": "^3.0.0",
2463
  "express": "^5.0.1",
2464
  "express-rate-limit": "^7.5.0",
2465
+ "jose": "^6.1.1",
2466
+ "json-schema-typed": "^8.0.2",
2467
  "pkce-challenge": "^5.0.0",
2468
  "raw-body": "^3.0.0",
2469
+ "zod": "^3.25 || ^4.0",
2470
+ "zod-to-json-schema": "^3.25.0"
2471
  },
2472
  "engines": {
2473
  "node": ">=18"
2474
  },
2475
  "peerDependencies": {
2476
+ "@cfworker/json-schema": "^4.1.1",
2477
+ "zod": "^3.25 || ^4.0"
2478
  },
2479
  "peerDependenciesMeta": {
2480
  "@cfworker/json-schema": {
2481
  "optional": true
2482
+ },
2483
+ "zod": {
2484
+ "optional": false
2485
  }
2486
  }
2487
  },
 
3248
  "version": "0.34.41",
3249
  "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
3250
  "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
3251
+ "license": "MIT"
 
3252
  },
3253
  "node_modules/@smithy/abort-controller": {
3254
  "version": "4.2.4",
 
3861
  "integrity": "sha512-EMYTY4+rNa7TaRZYzCqhQslEkACEZzWc363jOYuc90oJrgvlWTcgqTxcGSIJim48hPaXwYlHyatRnnMmTFf5tA==",
3862
  "devOptional": true,
3863
  "license": "MIT",
 
3864
  "dependencies": {
3865
  "@sveltejs/acorn-typescript": "^1.0.5",
3866
  "@types/cookie": "^0.6.0",
 
3893
  "integrity": "sha512-wojIS/7GYnJDYIg1higWj2ROA6sSRWvcR1PO/bqEyFr/5UZah26c8Cz4u0NaqjPeVltzsVpt2Tm8d2io0V+4Tw==",
3894
  "devOptional": true,
3895
  "license": "MIT",
 
3896
  "dependencies": {
3897
  "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1",
3898
  "debug": "^4.4.1",
 
3932
  "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",
3933
  "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
3934
  "license": "Apache-2.0",
3935
+ "peer": true,
3936
  "dependencies": {
3937
  "tslib": "^2.8.0"
3938
  }
 
3978
  "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz",
3979
  "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==",
3980
  "license": "MIT",
3981
+ "peer": true,
3982
  "engines": {
3983
  "node": ">=12",
3984
  "npm": ">=6"
 
4024
  "version": "5.0.4",
4025
  "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
4026
  "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
4027
+ "license": "MIT",
4028
+ "peer": true
4029
  },
4030
  "node_modules/@types/chai": {
4031
  "version": "5.2.2",
 
4254
  "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
4255
  "dev": true,
4256
  "license": "BSD-2-Clause",
 
4257
  "dependencies": {
4258
  "@typescript-eslint/scope-manager": "6.21.0",
4259
  "@typescript-eslint/types": "6.21.0",
 
4652
  "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
4653
  "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
4654
  "license": "MIT",
 
4655
  "bin": {
4656
  "acorn": "bin/acorn"
4657
  },
 
4835
  "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
4836
  "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
4837
  "license": "Apache-2.0",
4838
+ "peer": true,
4839
  "dependencies": {
4840
  "dequal": "^2.0.3"
4841
  }
 
5101
  }
5102
  ],
5103
  "license": "MIT",
 
5104
  "dependencies": {
5105
  "caniuse-lite": "^1.0.30001718",
5106
  "electron-to-chromium": "^1.5.160",
 
5770
  "version": "0.5.16",
5771
  "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
5772
  "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
5773
+ "license": "MIT",
5774
+ "peer": true
5775
  },
5776
  "node_modules/domexception": {
5777
  "version": "4.0.0",
 
5845
  "resolved": "https://registry.npmjs.org/elysia/-/elysia-1.3.4.tgz",
5846
  "integrity": "sha512-kAfM3Zwovy3z255IZgTKVxBw91HbgKhYl3TqrGRdZqqr+Fd+4eKOfvxgaKij22+MZLczPzIHtscAmvfpI3+q/A==",
5847
  "license": "MIT",
 
5848
  "dependencies": {
5849
  "cookie": "^1.0.2",
5850
  "exact-mirror": "0.1.2",
 
6045
  "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
6046
  "dev": true,
6047
  "license": "MIT",
 
6048
  "dependencies": {
6049
  "@eslint-community/eslint-utils": "^4.2.0",
6050
  "@eslint-community/regexpp": "^4.6.1",
 
6682
  "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.0.0.tgz",
6683
  "integrity": "sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg==",
6684
  "license": "MIT",
 
6685
  "dependencies": {
6686
  "@tokenizer/inflate": "^0.2.7",
6687
  "strtok3": "^10.2.2",
 
7185
  "node": ">=12.0.0"
7186
  }
7187
  },
7188
+ "node_modules/hono": {
7189
+ "version": "4.11.3",
7190
+ "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.3.tgz",
7191
+ "integrity": "sha512-PmQi306+M/ct/m5s66Hrg+adPnkD5jiO6IjA7WhWw0gSBSo1EcRegwuI1deZ+wd5pzCGynCcn2DprnE4/yEV4w==",
7192
+ "license": "MIT",
7193
+ "peer": true,
7194
+ "engines": {
7195
+ "node": ">=16.9.0"
7196
+ }
7197
+ },
7198
  "node_modules/hookable": {
7199
  "version": "5.5.3",
7200
  "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
 
7800
  "jiti": "bin/jiti.js"
7801
  }
7802
  },
7803
+ "node_modules/jose": {
7804
+ "version": "6.1.3",
7805
+ "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz",
7806
+ "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==",
7807
+ "license": "MIT",
7808
+ "funding": {
7809
+ "url": "https://github.com/sponsors/panva"
7810
+ }
7811
+ },
7812
  "node_modules/joycon": {
7813
  "version": "3.1.1",
7814
  "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
 
7822
  "version": "4.0.0",
7823
  "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
7824
  "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
7825
+ "license": "MIT",
7826
+ "peer": true
7827
  },
7828
  "node_modules/js-yaml": {
7829
  "version": "4.1.0",
 
7925
  "dev": true,
7926
  "license": "MIT"
7927
  },
7928
+ "node_modules/json-schema-typed": {
7929
+ "version": "8.0.2",
7930
+ "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz",
7931
+ "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==",
7932
+ "license": "BSD-2-Clause"
7933
+ },
7934
  "node_modules/json-stable-stringify-without-jsonify": {
7935
  "version": "1.0.1",
7936
  "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
 
9601
  "integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==",
9602
  "devOptional": true,
9603
  "license": "Apache-2.0",
 
9604
  "dependencies": {
9605
  "playwright-core": "1.55.1"
9606
  },
 
9646
  }
9647
  ],
9648
  "license": "MIT",
 
9649
  "dependencies": {
9650
  "nanoid": "^3.3.11",
9651
  "picocolors": "^1.1.1",
 
9877
  "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
9878
  "dev": true,
9879
  "license": "MIT",
 
9880
  "bin": {
9881
  "prettier": "bin/prettier.cjs"
9882
  },
 
9893
  "integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==",
9894
  "dev": true,
9895
  "license": "MIT",
 
9896
  "peerDependencies": {
9897
  "prettier": "^3.0.0",
9898
  "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
 
9982
  "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
9983
  "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
9984
  "license": "MIT",
9985
+ "peer": true,
9986
  "dependencies": {
9987
  "ansi-regex": "^5.0.1",
9988
  "ansi-styles": "^5.0.0",
 
9997
  "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
9998
  "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
9999
  "license": "MIT",
10000
+ "peer": true,
10001
  "engines": {
10002
  "node": ">=10"
10003
  },
 
10206
  "version": "17.0.2",
10207
  "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
10208
  "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
10209
+ "license": "MIT",
10210
+ "peer": true
10211
  },
10212
  "node_modules/read-cache": {
10213
  "version": "1.0.0",
 
10371
  "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz",
10372
  "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==",
10373
  "license": "MIT",
 
10374
  "dependencies": {
10375
  "@types/estree": "1.0.7"
10376
  },
 
11289
  "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.33.14.tgz",
11290
  "integrity": "sha512-kRlbhIlMTijbFmVDQFDeKXPLlX1/ovXwV0I162wRqQhRcygaqDIcu1d/Ese3H2uI+yt3uT8E7ndgDthQv5v5BA==",
11291
  "license": "MIT",
 
11292
  "dependencies": {
11293
  "@ampproject/remapping": "^2.3.0",
11294
  "@jridgewell/sourcemap-codec": "^1.5.0",
 
11428
  "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
11429
  "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
11430
  "license": "MIT",
 
11431
  "dependencies": {
11432
  "@alloc/quick-lru": "^5.2.0",
11433
  "arg": "^5.0.2",
 
11885
  "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
11886
  "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
11887
  "license": "Apache-2.0",
 
11888
  "bin": {
11889
  "tsc": "bin/tsc",
11890
  "tsserver": "bin/tsserver"
 
12120
  "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
12121
  "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
12122
  "license": "MIT",
 
12123
  "dependencies": {
12124
  "esbuild": "^0.25.0",
12125
  "fdir": "^6.4.4",
 
12255
  "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.2.tgz",
12256
  "integrity": "sha512-fyNn/Rp016Bt5qvY0OQvIUCwW2vnaEBLxP42PmKbNIoasSYjML+8xyeADOPvBe+Xfl/ubIw4og7Lt9jflRsCNw==",
12257
  "license": "MIT",
 
12258
  "dependencies": {
12259
  "@types/chai": "^5.2.2",
12260
  "@vitest/expect": "3.2.2",
 
12577
  "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
12578
  "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
12579
  "license": "MIT",
 
12580
  "engines": {
12581
  "node": ">=10.0.0"
12582
  },
 
12699
  "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.55.tgz",
12700
  "integrity": "sha512-219huNnkSLQnLsQ3uaRjXsxMrVm5C9W3OOpEVt2k5tvMKuA8nBSu38e0B//a+he9Iq2dvmk2VyYVlHqiHa4YBA==",
12701
  "license": "MIT",
 
12702
  "funding": {
12703
  "url": "https://github.com/sponsors/colinhacks"
12704
  }
12705
  },
12706
  "node_modules/zod-to-json-schema": {
12707
+ "version": "3.25.1",
12708
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz",
12709
+ "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==",
12710
  "license": "ISC",
12711
  "peerDependencies": {
12712
+ "zod": "^3.25 || ^4"
12713
  }
12714
  }
12715
  }
package.json CHANGED
@@ -72,7 +72,7 @@
72
  "@huggingface/hub": "^2.2.0",
73
  "@huggingface/inference": "^4.11.3",
74
  "@iconify-json/bi": "^1.1.21",
75
- "@modelcontextprotocol/sdk": "^1.21.1",
76
  "@resvg/resvg-js": "^2.6.2",
77
  "@sinclair/typebox": "^0.34.41",
78
  "autoprefixer": "^10.4.14",
 
72
  "@huggingface/hub": "^2.2.0",
73
  "@huggingface/inference": "^4.11.3",
74
  "@iconify-json/bi": "^1.1.21",
75
+ "@modelcontextprotocol/sdk": "^1.25.1",
76
  "@resvg/resvg-js": "^2.6.2",
77
  "@sinclair/typebox": "^0.34.41",
78
  "autoprefixer": "^10.4.14",
src/lib/components/chat/ToolUpdate.svelte CHANGED
@@ -3,8 +3,10 @@
3
  import {
4
  isMessageToolCallUpdate,
5
  isMessageToolErrorUpdate,
 
6
  isMessageToolResultUpdate,
7
  } from "$lib/utils/messageUpdates";
 
8
  import LucideHammer from "~icons/lucide/hammer";
9
  import LucideCheck from "~icons/lucide/check";
10
  import { ToolResultStatus, type ToolFront } from "$lib/types/Tool";
@@ -27,6 +29,14 @@
27
  let toolDone = $derived(tool.some(isMessageToolResultUpdate));
28
  let isExecuting = $derived(!toolDone && !toolError && loading);
29
  let toolSuccess = $derived(toolDone && !toolError);
 
 
 
 
 
 
 
 
30
 
31
  const availableTools: ToolFront[] = $derived.by(
32
  () => (page.data as { tools?: ToolFront[] } | undefined)?.tools ?? []
@@ -120,7 +130,7 @@
120
  <div class="flex w-full select-none items-center gap-2">
121
  <button
122
  type="button"
123
- class="flex flex-1 cursor-pointer items-center gap-2 text-left"
124
  onclick={() => (isOpen = !isOpen)}
125
  >
126
  <span
@@ -137,6 +147,9 @@
137
  {availableTools.find((entry) => entry.name === toolFnName)?.displayName ?? toolFnName}
138
  </code>
139
  </span>
 
 
 
140
  </button>
141
 
142
  <button
 
3
  import {
4
  isMessageToolCallUpdate,
5
  isMessageToolErrorUpdate,
6
+ isMessageToolProgressUpdate,
7
  isMessageToolResultUpdate,
8
  } from "$lib/utils/messageUpdates";
9
+ import { formatToolProgressLabel } from "$lib/utils/toolProgress";
10
  import LucideHammer from "~icons/lucide/hammer";
11
  import LucideCheck from "~icons/lucide/check";
12
  import { ToolResultStatus, type ToolFront } from "$lib/types/Tool";
 
29
  let toolDone = $derived(tool.some(isMessageToolResultUpdate));
30
  let isExecuting = $derived(!toolDone && !toolError && loading);
31
  let toolSuccess = $derived(toolDone && !toolError);
32
+ let toolProgress = $derived.by(() => {
33
+ for (let i = tool.length - 1; i >= 0; i -= 1) {
34
+ const update = tool[i];
35
+ if (isMessageToolProgressUpdate(update)) return update;
36
+ }
37
+ return undefined;
38
+ });
39
+ let progressLabel = $derived.by(() => formatToolProgressLabel(toolProgress));
40
 
41
  const availableTools: ToolFront[] = $derived.by(
42
  () => (page.data as { tools?: ToolFront[] } | undefined)?.tools ?? []
 
130
  <div class="flex w-full select-none items-center gap-2">
131
  <button
132
  type="button"
133
+ class="flex flex-1 cursor-pointer flex-col items-start gap-1 text-left"
134
  onclick={() => (isOpen = !isOpen)}
135
  >
136
  <span
 
147
  {availableTools.find((entry) => entry.name === toolFnName)?.displayName ?? toolFnName}
148
  </code>
149
  </span>
150
+ {#if isExecuting && toolProgress}
151
+ <span class="text-xs text-gray-500 dark:text-gray-400">{progressLabel}</span>
152
+ {/if}
153
  </button>
154
 
155
  <button
src/lib/server/mcp/httpClient.ts CHANGED
@@ -23,6 +23,12 @@ export type McpToolTextResponse = {
23
  content?: unknown[];
24
  };
25
 
 
 
 
 
 
 
26
  export async function callMcpTool(
27
  server: McpServerConfig,
28
  tool: string,
@@ -31,7 +37,13 @@ export async function callMcpTool(
31
  timeoutMs = DEFAULT_TIMEOUT_MS,
32
  signal,
33
  client,
34
- }: { timeoutMs?: number; signal?: AbortSignal; client?: Client } = {}
 
 
 
 
 
 
35
  ): Promise<McpToolTextResponse> {
36
  // Bypass MCP protocol for Exa - call direct API
37
  if (isExaServer(server)) {
@@ -61,7 +73,13 @@ export async function callMcpTool(
61
  signal,
62
  timeout: timeoutMs,
63
  // Enable progress tokens so long-running tools keep extending the timeout.
64
- onprogress: () => {},
 
 
 
 
 
 
65
  resetTimeoutOnProgress: true,
66
  };
67
 
 
23
  content?: unknown[];
24
  };
25
 
26
+ export type McpToolProgress = {
27
+ progress: number;
28
+ total?: number;
29
+ message?: string;
30
+ };
31
+
32
  export async function callMcpTool(
33
  server: McpServerConfig,
34
  tool: string,
 
37
  timeoutMs = DEFAULT_TIMEOUT_MS,
38
  signal,
39
  client,
40
+ onProgress,
41
+ }: {
42
+ timeoutMs?: number;
43
+ signal?: AbortSignal;
44
+ client?: Client;
45
+ onProgress?: (progress: McpToolProgress) => void;
46
+ } = {}
47
  ): Promise<McpToolTextResponse> {
48
  // Bypass MCP protocol for Exa - call direct API
49
  if (isExaServer(server)) {
 
73
  signal,
74
  timeout: timeoutMs,
75
  // Enable progress tokens so long-running tools keep extending the timeout.
76
+ onprogress: (progress: McpToolProgress) => {
77
+ onProgress?.({
78
+ progress: progress.progress,
79
+ total: progress.total,
80
+ message: progress.message,
81
+ });
82
+ },
83
  resetTimeoutOnProgress: true,
84
  };
85
 
src/lib/server/textGeneration/mcp/toolInvocation.ts CHANGED
@@ -173,27 +173,42 @@ export async function* executeToolCalls({
173
  };
174
  }
175
 
176
- const q = createQueue<TaskResult>();
 
177
 
178
  const tasks = prepared.map(async (p, index) => {
179
  const mappingEntry = mapping[p.call.name];
180
  if (!mappingEntry) {
181
- q.push({
 
182
  index,
183
- error: `Unknown MCP function: ${p.call.name}`,
184
  uuid: p.uuid,
185
  paramsClean: p.paramsClean,
186
  });
 
 
 
 
 
 
187
  return;
188
  }
189
  const serverCfg = serverLookup.get(mappingEntry.server);
190
  if (!serverCfg) {
191
- q.push({
 
192
  index,
193
- error: `Unknown MCP server: ${mappingEntry.server}`,
194
  uuid: p.uuid,
195
  paramsClean: p.paramsClean,
196
  });
 
 
 
 
 
 
197
  return;
198
  }
199
  const client = clientMap.get(mappingEntry.server);
@@ -210,6 +225,16 @@ export async function* executeToolCalls({
210
  client,
211
  signal: abortSignal,
212
  timeoutMs: toolTimeoutMs,
 
 
 
 
 
 
 
 
 
 
213
  }
214
  );
215
  const { annotated } = processToolOutput(toolResponse.text ?? "");
@@ -217,7 +242,7 @@ export async function* executeToolCalls({
217
  { server: mappingEntry.server, tool: mappingEntry.tool },
218
  "[mcp] tool call completed"
219
  );
220
- q.push({
221
  index,
222
  output: annotated,
223
  structured: toolResponse.structured,
@@ -225,54 +250,44 @@ export async function* executeToolCalls({
225
  uuid: p.uuid,
226
  paramsClean: p.paramsClean,
227
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  } catch (err) {
229
  const message = err instanceof Error ? err.message : String(err);
230
  logger.warn(
231
  { server: mappingEntry.server, tool: mappingEntry.tool, err: message },
232
  "[mcp] tool call failed"
233
  );
234
- q.push({ index, error: message, uuid: p.uuid, paramsClean: p.paramsClean });
 
 
 
 
 
 
235
  }
236
  });
237
 
238
  // kick off and stream as they finish
239
- Promise.allSettled(tasks).then(() => q.close());
240
 
241
- const results: TaskResult[] = [];
242
- for await (const r of q.iterator()) {
243
- results.push(r);
244
- if (r.error) {
245
- yield {
246
- type: "update",
247
- update: {
248
- type: MessageUpdateType.Tool,
249
- subtype: MessageToolUpdateType.Error,
250
- uuid: r.uuid,
251
- message: r.error,
252
- },
253
- };
254
- } else {
255
- yield {
256
- type: "update",
257
- update: {
258
- type: MessageUpdateType.Tool,
259
- subtype: MessageToolUpdateType.Result,
260
- uuid: r.uuid,
261
- result: {
262
- status: ToolResultStatus.Success,
263
- call: { name: prepared[r.index].call.name, parameters: r.paramsClean },
264
- outputs: [
265
- {
266
- text: r.output ?? "",
267
- structured: r.structured,
268
- content: r.blocks,
269
- } as unknown as Record<string, unknown>,
270
- ],
271
- display: true,
272
- },
273
- },
274
- };
275
- }
276
  }
277
 
278
  // Collate outputs in original call order
 
173
  };
174
  }
175
 
176
+ const updatesQueue = createQueue<MessageUpdate>();
177
+ const results: TaskResult[] = [];
178
 
179
  const tasks = prepared.map(async (p, index) => {
180
  const mappingEntry = mapping[p.call.name];
181
  if (!mappingEntry) {
182
+ const message = `Unknown MCP function: ${p.call.name}`;
183
+ results.push({
184
  index,
185
+ error: message,
186
  uuid: p.uuid,
187
  paramsClean: p.paramsClean,
188
  });
189
+ updatesQueue.push({
190
+ type: MessageUpdateType.Tool,
191
+ subtype: MessageToolUpdateType.Error,
192
+ uuid: p.uuid,
193
+ message,
194
+ });
195
  return;
196
  }
197
  const serverCfg = serverLookup.get(mappingEntry.server);
198
  if (!serverCfg) {
199
+ const message = `Unknown MCP server: ${mappingEntry.server}`;
200
+ results.push({
201
  index,
202
+ error: message,
203
  uuid: p.uuid,
204
  paramsClean: p.paramsClean,
205
  });
206
+ updatesQueue.push({
207
+ type: MessageUpdateType.Tool,
208
+ subtype: MessageToolUpdateType.Error,
209
+ uuid: p.uuid,
210
+ message,
211
+ });
212
  return;
213
  }
214
  const client = clientMap.get(mappingEntry.server);
 
225
  client,
226
  signal: abortSignal,
227
  timeoutMs: toolTimeoutMs,
228
+ onProgress: (progress) => {
229
+ updatesQueue.push({
230
+ type: MessageUpdateType.Tool,
231
+ subtype: MessageToolUpdateType.Progress,
232
+ uuid: p.uuid,
233
+ progress: progress.progress,
234
+ total: progress.total,
235
+ message: progress.message,
236
+ });
237
+ },
238
  }
239
  );
240
  const { annotated } = processToolOutput(toolResponse.text ?? "");
 
242
  { server: mappingEntry.server, tool: mappingEntry.tool },
243
  "[mcp] tool call completed"
244
  );
245
+ results.push({
246
  index,
247
  output: annotated,
248
  structured: toolResponse.structured,
 
250
  uuid: p.uuid,
251
  paramsClean: p.paramsClean,
252
  });
253
+ updatesQueue.push({
254
+ type: MessageUpdateType.Tool,
255
+ subtype: MessageToolUpdateType.Result,
256
+ uuid: p.uuid,
257
+ result: {
258
+ status: ToolResultStatus.Success,
259
+ call: { name: p.call.name, parameters: p.paramsClean },
260
+ outputs: [
261
+ {
262
+ text: annotated ?? "",
263
+ structured: toolResponse.structured,
264
+ content: toolResponse.content,
265
+ } as unknown as Record<string, unknown>,
266
+ ],
267
+ display: true,
268
+ },
269
+ });
270
  } catch (err) {
271
  const message = err instanceof Error ? err.message : String(err);
272
  logger.warn(
273
  { server: mappingEntry.server, tool: mappingEntry.tool, err: message },
274
  "[mcp] tool call failed"
275
  );
276
+ results.push({ index, error: message, uuid: p.uuid, paramsClean: p.paramsClean });
277
+ updatesQueue.push({
278
+ type: MessageUpdateType.Tool,
279
+ subtype: MessageToolUpdateType.Error,
280
+ uuid: p.uuid,
281
+ message,
282
+ });
283
  }
284
  });
285
 
286
  // kick off and stream as they finish
287
+ Promise.allSettled(tasks).then(() => updatesQueue.close());
288
 
289
+ for await (const update of updatesQueue.iterator()) {
290
+ yield { type: "update", update };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
  }
292
 
293
  // Collate outputs in original call order
src/lib/types/MessageUpdate.ts CHANGED
@@ -54,6 +54,7 @@ export enum MessageToolUpdateType {
54
  Result = "result",
55
  Error = "error",
56
  ETA = "eta",
 
57
  }
58
 
59
  interface MessageToolUpdateBase<TSubtype extends MessageToolUpdateType> {
@@ -79,11 +80,19 @@ export interface MessageToolEtaUpdate extends MessageToolUpdateBase<MessageToolU
79
  eta: number;
80
  }
81
 
 
 
 
 
 
 
 
82
  export type MessageToolUpdate =
83
  | MessageToolCallUpdate
84
  | MessageToolResultUpdate
85
  | MessageToolErrorUpdate
86
- | MessageToolEtaUpdate;
 
87
 
88
  export enum MessageReasoningUpdateType {
89
  Stream = "stream",
 
54
  Result = "result",
55
  Error = "error",
56
  ETA = "eta",
57
+ Progress = "progress",
58
  }
59
 
60
  interface MessageToolUpdateBase<TSubtype extends MessageToolUpdateType> {
 
80
  eta: number;
81
  }
82
 
83
+ export interface MessageToolProgressUpdate
84
+ extends MessageToolUpdateBase<MessageToolUpdateType.Progress> {
85
+ progress: number;
86
+ total?: number;
87
+ message?: string;
88
+ }
89
+
90
  export type MessageToolUpdate =
91
  | MessageToolCallUpdate
92
  | MessageToolResultUpdate
93
  | MessageToolErrorUpdate
94
+ | MessageToolEtaUpdate
95
+ | MessageToolProgressUpdate;
96
 
97
  export enum MessageReasoningUpdateType {
98
  Stream = "stream",
src/lib/utils/messageUpdates.ts CHANGED
@@ -6,6 +6,7 @@ import {
6
  type MessageToolCallUpdate,
7
  type MessageToolResultUpdate,
8
  type MessageToolErrorUpdate,
 
9
  MessageUpdateType,
10
  MessageToolUpdateType,
11
  } from "$lib/types/MessageUpdate";
@@ -265,6 +266,11 @@ export const isMessageToolResultUpdate = (
265
  export const isMessageToolErrorUpdate = (update: MessageUpdate): update is MessageToolErrorUpdate =>
266
  isMessageToolUpdate(update) && update.subtype === MessageToolUpdateType.Error;
267
 
 
 
 
 
 
268
  const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
269
  const waitForEvent = (eventTarget: EventTarget, eventName: string) =>
270
  new Promise<boolean>((resolve) =>
 
6
  type MessageToolCallUpdate,
7
  type MessageToolResultUpdate,
8
  type MessageToolErrorUpdate,
9
+ type MessageToolProgressUpdate,
10
  MessageUpdateType,
11
  MessageToolUpdateType,
12
  } from "$lib/types/MessageUpdate";
 
266
  export const isMessageToolErrorUpdate = (update: MessageUpdate): update is MessageToolErrorUpdate =>
267
  isMessageToolUpdate(update) && update.subtype === MessageToolUpdateType.Error;
268
 
269
+ export const isMessageToolProgressUpdate = (
270
+ update: MessageUpdate
271
+ ): update is MessageToolProgressUpdate =>
272
+ isMessageToolUpdate(update) && update.subtype === MessageToolUpdateType.Progress;
273
+
274
  const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
275
  const waitForEvent = (eventTarget: EventTarget, eventName: string) =>
276
  new Promise<boolean>((resolve) =>
src/lib/utils/toolProgress.spec.ts ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { describe, expect, test } from "vitest";
2
+
3
+ import { MessageToolUpdateType, MessageUpdateType } from "$lib/types/MessageUpdate";
4
+ import { formatToolProgressLabel } from "./toolProgress";
5
+
6
+ describe("formatToolProgressLabel", () => {
7
+ test("returns empty string when progress is missing", () => {
8
+ expect(formatToolProgressLabel(undefined)).toBe("");
9
+ });
10
+
11
+ test("formats progress with message", () => {
12
+ expect(
13
+ formatToolProgressLabel({
14
+ type: MessageUpdateType.Tool,
15
+ subtype: MessageToolUpdateType.Progress,
16
+ uuid: "tool-1",
17
+ progress: 3,
18
+ total: 10,
19
+ message: "Indexing",
20
+ })
21
+ ).toBe("Indexing (3/10)");
22
+ });
23
+
24
+ test("formats progress without message", () => {
25
+ expect(
26
+ formatToolProgressLabel({
27
+ type: MessageUpdateType.Tool,
28
+ subtype: MessageToolUpdateType.Progress,
29
+ uuid: "tool-2",
30
+ progress: 7,
31
+ })
32
+ ).toBe("Progress: 7");
33
+ });
34
+
35
+ test("formats progress with message and no total", () => {
36
+ expect(
37
+ formatToolProgressLabel({
38
+ type: MessageUpdateType.Tool,
39
+ subtype: MessageToolUpdateType.Progress,
40
+ uuid: "tool-3",
41
+ progress: 12,
42
+ message: "ZeroGPU Initializing xxx",
43
+ })
44
+ ).toBe("ZeroGPU Initializing xxx (12)");
45
+ });
46
+ });
src/lib/utils/toolProgress.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { MessageToolProgressUpdate } from "$lib/types/MessageUpdate";
2
+
3
+ export function formatToolProgressLabel(progress?: MessageToolProgressUpdate): string {
4
+ if (!progress) return "";
5
+ const total = typeof progress.total === "number" ? `/${progress.total}` : "";
6
+ const value = `${progress.progress}${total}`;
7
+ if (progress.message && progress.message.trim().length > 0) {
8
+ return `${progress.message} (${value})`;
9
+ }
10
+ return `Progress: ${value}`;
11
+ }