History

Use MCP for agent-executor communication instead of custom REST

Agent is now a pure MCP client — connects to executor's /mcp endpoint, gets tools via tools/list (run_code description includes sandbox tool inventory), executes code via tools/call. Removes hardcoded run_code tool definition, POST /api/tasks/run endpoint, and Eden Treaty adapter dependency from the agent path. Model accepts tools dynamically.

Rhys Sullivan committed 9 months ago

Commit c479a7d1 parent c1282e913 files · +585 −345Browse files

Unified · Split

13 files
  1. assistant/bun.lock +159 −6
  2. assistant/packages/core/package.json +3 −3
  3. assistant/packages/core/src/agent.test.ts +66 −52
  4. assistant/packages/core/src/agent.ts +138 −120
  5. assistant/packages/core/src/index.ts +2 −2
  6. assistant/packages/core/src/model.ts +20 −14
  7. assistant/packages/server/package.json +0 −1
  8. assistant/packages/server/src/index.ts +19 −10
  9. assistant/packages/server/src/routes.ts +10 −11
  10. bun.lock +1 −3
  11. executor/apps/server/src/index.ts +26 −51
  12. executor/apps/server/src/mcp-server.test.ts +7 −1
  13. executor/apps/server/src/mcp-server.ts +134 −71
assistant/bun.lock+159−6
@@ -37,7 +37,6 @@ · 36 unmodified lines
3737 "packages/bot": {
3838 "name": "@assistant/bot",
3939 "dependencies": {
40− "@assistant/agent-executor-adapter": "workspace:*",
4140 "@assistant/core": "workspace:*",
4241 "@assistant/server": "workspace:*",
4342 "@elysiajs/eden": "latest",
@@ -55,21 +54,21 @@ · 11 unmodified lines
5554 "packages/core": {
5655 "name": "@assistant/core",
5756 "dependencies": {
58− "@assistant/agent-executor-adapter": "workspace:*",
5957 "@mariozechner/pi-ai": "^0.52.6",
60− "@sinclair/typebox": "^0.34.48",
58+ "@modelcontextprotocol/sdk": "^1.26.0",
6159 },
6260 "devDependencies": {
6361 "@elysiajs/eden": "^1.4.6",
6462 "elysia": "^1.4.22",
63+ "zod": "^4.3.6",
6564 },
6665 },
6766 "packages/server": {
6867 "name": "@assistant/server",
6968 "dependencies": {
70− "@assistant/agent-executor-adapter": "workspace:*",
7169 "@assistant/core": "workspace:*",
7270 "@elysiajs/eden": "latest",
71+ "convex": "^1.31.7",
7372 "elysia": "latest",
7473 },
7574 "devDependencies": {
@@ -238,12 +237,16 @@ · 162 unmodified lines
238237
239238 "@google/genai": ["@google/genai@1.40.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-fhIww8smT0QYRX78qWOiz/nIQhHMF5wXOrlXvj33HBrz3vKDBb+wibLcEmTA+L9dmPD4KmfNr7UF3LDQVTXNjA=="],
240239
240+ "@hono/node-server": ["@hono/node-server@1.19.9", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw=="],
241+
241242 "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
242243
243244 "@mariozechner/pi-ai": ["@mariozechner/pi-ai@0.52.8", "", { "dependencies": { "@anthropic-ai/sdk": "^0.73.0", "@aws-sdk/client-bedrock-runtime": "^3.983.0", "@google/genai": "^1.40.0", "@mistralai/mistralai": "1.10.0", "@sinclair/typebox": "^0.34.41", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "chalk": "^5.6.2", "openai": "6.10.0", "partial-json": "^0.1.7", "proxy-agent": "^6.5.0", "undici": "^7.19.1", "zod-to-json-schema": "^3.24.6" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-+aFCUbKJcskDJhr9wPcMBTy0x/xWio5v1dkxRYXUBPWp+Zt9DSdT5Kmd/IIQ+a0TOZDF4ajt4GY/oAw37X7XTw=="],
244245
245246 "@mistralai/mistralai": ["@mistralai/mistralai@1.10.0", "", { "dependencies": { "zod": "^3.20.0", "zod-to-json-schema": "^3.24.1" } }, "sha512-tdIgWs4Le8vpvPiUEWne6tK0qbVc+jMenujnvTqOjogrJUsCSQhus0tHTU1avDDh5//Rq2dFgP9mWRAdIEoBqg=="],
246247
248+ "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.26.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg=="],
249+
247250 "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="],
248251
249252 "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw=="],
@@ -398,6 +401,8 @@ · 148 unmodified lines
398401
399402 "@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.7", "", {}, "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g=="],
400403
404+ "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
405+
401406 "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
402407
403408 "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
@@ -418,6 +423,8 @@ · 14 unmodified lines
418423
419424 "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
420425
426+ "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
427+
421428 "bowser": ["bowser@2.13.1", "", {}, "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw=="],
422429
423430 "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
@@ -426,16 +433,30 @@ · 2 unmodified lines
426433
427434 "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="],
428435
436+ "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
437+
438+ "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
439+
440+ "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
441+
429442 "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
430443
431444 "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
432445
433446 "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
434447
448+ "content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="],
449+
450+ "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
451+
435452 "convex": ["convex@1.31.7", "", { "dependencies": { "esbuild": "0.27.0", "prettier": "^3.0.0" }, "peerDependencies": { "@auth0/auth0-react": "^2.0.1", "@clerk/clerk-react": "^4.12.8 || ^5.0.0", "react": "^18.0.0 || ^19.0.0-0 || ^19.0.0" }, "optionalPeers": ["@auth0/auth0-react", "@clerk/clerk-react", "react"], "bin": { "convex": "bin/main.js" } }, "sha512-PtNMe1mAIOvA8Yz100QTOaIdgt2rIuWqencVXrb4McdhxBHZ8IJ1eXTnrgCC9HydyilGT1pOn+KNqT14mqn9fQ=="],
436453
437454 "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
438455
456+ "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
457+
458+ "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="],
459+
439460 "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
440461
441462 "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
@@ -446,24 +467,40 @@ · 4 unmodified lines
446467
447468 "degenerator": ["degenerator@5.0.1", "", { "dependencies": { "ast-types": "^0.13.4", "escodegen": "^2.1.0", "esprima": "^4.0.1" } }, "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ=="],
448469
470+ "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
471+
449472 "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
450473
451474 "discord-api-types": ["discord-api-types@0.38.38", "", {}, "sha512-7qcM5IeZrfb+LXW07HvoI5L+j4PQeMZXEkSm1htHAHh4Y9JSMXBWjy/r7zmUCOj4F7zNjMcm7IMWr131MT2h0Q=="],
452475
453476 "discord.js": ["discord.js@14.25.1", "", { "dependencies": { "@discordjs/builders": "^1.13.0", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.2", "@discordjs/rest": "^2.6.0", "@discordjs/util": "^1.2.0", "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.38.33", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-2l0gsPOLPs5t6GFZfQZKnL1OJNYFcuC/ETWsW4VtKVD/tg4ICa9x+jb9bkPffkMdRpRpuUaO/fKkHCBeiCKh8g=="],
454477
478+ "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
479+
455480 "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
456481
457482 "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
458483
484+ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
485+
459486 "effect": ["effect@3.19.16", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-7+XC3vGrbAhCHd8LTFHvnZjRpZKZ8YHRZqJTkpNoxcJ2mCyNs2SwI+6VkV/ij8Y3YW7wfBN4EbU06/F5+m/wkQ=="],
460487
461488 "elysia": ["elysia@1.4.22", "", { "dependencies": { "cookie": "^1.1.1", "exact-mirror": "^0.2.6", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.4.0" }, "peerDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "@types/bun": ">= 1.2.0", "file-type": ">= 20.0.0", "openapi-types": ">= 12.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["@types/bun", "typescript"] }, "sha512-Q90VCb1RVFxnFaRV0FDoSylESQQLWgLHFmWciQJdX9h3b2cSasji9KWEUvaJuy/L9ciAGg4RAhUVfsXHg5K2RQ=="],
462489
463490 "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
464491
492+ "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
493+
494+ "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
495+
496+ "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
497+
498+ "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
499+
465500 "esbuild": ["esbuild@0.27.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.0", "@esbuild/android-arm": "0.27.0", "@esbuild/android-arm64": "0.27.0", "@esbuild/android-x64": "0.27.0", "@esbuild/darwin-arm64": "0.27.0", "@esbuild/darwin-x64": "0.27.0", "@esbuild/freebsd-arm64": "0.27.0", "@esbuild/freebsd-x64": "0.27.0", "@esbuild/linux-arm": "0.27.0", "@esbuild/linux-arm64": "0.27.0", "@esbuild/linux-ia32": "0.27.0", "@esbuild/linux-loong64": "0.27.0", "@esbuild/linux-mips64el": "0.27.0", "@esbuild/linux-ppc64": "0.27.0", "@esbuild/linux-riscv64": "0.27.0", "@esbuild/linux-s390x": "0.27.0", "@esbuild/linux-x64": "0.27.0", "@esbuild/netbsd-arm64": "0.27.0", "@esbuild/netbsd-x64": "0.27.0", "@esbuild/openbsd-arm64": "0.27.0", "@esbuild/openbsd-x64": "0.27.0", "@esbuild/openharmony-arm64": "0.27.0", "@esbuild/sunos-x64": "0.27.0", "@esbuild/win32-arm64": "0.27.0", "@esbuild/win32-ia32": "0.27.0", "@esbuild/win32-x64": "0.27.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA=="],
466501
502+ "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
503+
467504 "escodegen": ["escodegen@2.1.0", "", { "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2" }, "optionalDependencies": { "source-map": "~0.6.1" }, "bin": { "esgenerate": "bin/esgenerate.js", "escodegen": "bin/escodegen.js" } }, "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w=="],
468505
469506 "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
@@ -472,8 +509,18 @@ · 2 unmodified lines
472509
473510 "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
474511
512+ "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
513+
514+ "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="],
515+
516+ "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="],
517+
475518 "exact-mirror": ["exact-mirror@0.2.6", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-7s059UIx9/tnOKSySzUk5cPGkoILhTE4p6ncf6uIPaQ+9aRBQzQjc9+q85l51+oZ+P6aBxh084pD0CzBQPcFUA=="],
476519
520+ "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
521+
522+ "express-rate-limit": ["express-rate-limit@8.2.1", "", { "dependencies": { "ip-address": "10.0.1" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g=="],
523+
477524 "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
478525
479526 "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="],
@@ -490,16 +537,28 @@ · 10 unmodified lines
490537
491538 "file-type": ["file-type@21.3.0", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", "token-types": "^6.1.1", "uint8array-extras": "^1.4.0" } }, "sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA=="],
492539
540+ "finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="],
541+
493542 "find-my-way-ts": ["find-my-way-ts@0.1.6", "", {}, "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA=="],
494543
495544 "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
496545
497546 "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
498547
548+ "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
549+
550+ "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
551+
552+ "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
553+
499554 "gaxios": ["gaxios@7.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2", "rimraf": "^5.0.1" } }, "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ=="],
500555
501556 "gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="],
502557
558+ "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
559+
560+ "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
561+
503562 "get-uri": ["get-uri@6.0.5", "", { "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4" } }, "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg=="],
504563
505564 "glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
@@ -508,28 +567,50 @@ · 2 unmodified lines
508567
509568 "google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="],
510569
570+ "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
571+
511572 "gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="],
512573
574+ "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
575+
576+ "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
577+
578+ "hono": ["hono@4.11.8", "", {}, "sha512-eVkB/CYCCei7K2WElZW9yYQFWssG0DhaDhVvr7wy5jJ22K+ck8fWW0EsLpB0sITUTvPnc97+rrbQqIr5iqiy9Q=="],
579+
580+ "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
581+
513582 "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
514583
515584 "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
516585
586+ "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
587+
517588 "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
518589
519− "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
590+ "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
591+
592+ "ip-address": ["ip-address@10.0.1", "", {}, "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA=="],
593+
594+ "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
520595
521596 "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
522597
598+ "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
599+
523600 "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
524601
525602 "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
526603
604+ "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],
605+
527606 "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="],
528607
529608 "json-schema-to-ts": ["json-schema-to-ts@3.1.1", "", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="],
530609
531610 "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
532611
612+ "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="],
613+
533614 "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="],
534615
535616 "jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="],
@@ -544,8 +625,18 @@ · 8 unmodified lines
544625
545626 "magic-bytes.js": ["magic-bytes.js@1.13.0", "", {}, "sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg=="],
546627
628+ "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
629+
630+ "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
631+
547632 "memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="],
548633
634+ "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
635+
636+ "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
637+
638+ "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
639+
549640 "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
550641
551642 "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
@@ -558,6 +649,8 @@ · 6 unmodified lines
558649
559650 "multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="],
560651
652+ "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
653+
561654 "netmask": ["netmask@2.0.2", "", {}, "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="],
562655
563656 "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
@@ -566,6 +659,14 @@ · 2 unmodified lines
566659
567660 "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],
568661
662+ "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
663+
664+ "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
665+
666+ "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
667+
668+ "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
669+
569670 "openai": ["openai@6.10.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-ITxOGo7rO3XRMiKA5l7tQ43iNNu+iXGFAcf2t+aWVzzqRaS0i7m1K2BhxNdaveB+5eENhO0VY1FkiZzhBk4v3A=="],
570671
571672 "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
@@ -576,22 +677,36 @@ · 4 unmodified lines
576677
577678 "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
578679
680+ "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
681+
579682 "partial-json": ["partial-json@0.1.7", "", {}, "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA=="],
580683
581684 "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
582685
583686 "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
584687
688+ "path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="],
689+
690+ "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],
691+
585692 "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="],
586693
587694 "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="],
588695
696+ "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
697+
589698 "proxy-agent": ["proxy-agent@6.5.0", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.1", "https-proxy-agent": "^7.0.6", "lru-cache": "^7.14.1", "pac-proxy-agent": "^7.1.0", "proxy-from-env": "^1.1.0", "socks-proxy-agent": "^8.0.5" } }, "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A=="],
590699
591700 "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
592701
593702 "pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="],
594703
704+ "qs": ["qs@6.14.1", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ=="],
705+
706+ "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
707+
708+ "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
709+
595710 "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
596711
597712 "react-reconciler": ["react-reconciler@0.31.0", "", { "dependencies": { "scheduler": "^0.25.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ=="],
@@ -600,14 +715,32 @@ · 2 unmodified lines
600715
601716 "rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="],
602717
718+ "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
719+
603720 "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
604721
722+ "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
723+
605724 "scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="],
606725
726+ "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="],
727+
728+ "serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="],
729+
730+ "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
731+
607732 "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
608733
609734 "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
610735
736+ "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
737+
738+ "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
739+
740+ "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
741+
742+ "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
743+
611744 "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
612745
613746 "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
@@ -618,6 +751,8 @@ · 4 unmodified lines
618751
619752 "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
620753
754+ "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
755+
621756 "string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
622757
623758 "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
@@ -630,6 +765,8 @@ · 6 unmodified lines
630765
631766 "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="],
632767
768+ "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
769+
633770 "token-types": ["token-types@6.1.2", "", { "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww=="],
634771
635772 "ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="],
@@ -638,6 +775,8 @@ · 2 unmodified lines
638775
639776 "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
640777
778+ "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
779+
641780 "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
642781
643782 "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="],
@@ -646,8 +785,12 @@ · 2 unmodified lines
646785
647786 "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
648787
788+ "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
789+
649790 "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],
650791
792+ "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
793+
651794 "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
652795
653796 "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
@@ -656,9 +799,11 @@ · 2 unmodified lines
656799
657800 "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
658801
802+ "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
803+
659804 "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
660805
661− "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
806+ "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
662807
663808 "zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],
664809
@@ -672,10 +817,18 @@ · 7 unmodified lines
672817
673818 "@mariozechner/pi-ai/undici": ["undici@7.21.0", "", {}, "sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg=="],
674819
820+ "@mistralai/mistralai/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
821+
822+ "@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
823+
824+ "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
825+
675826 "node-fetch/data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
676827
677828 "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
678829
830+ "socks/ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
831+
679832 "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
680833
681834 "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
assistant/packages/core/package.json+3−3
@@ -6,12 +6,12 @@ · 5 unmodified lines
66 ".": "./src/index.ts"
77 },
88 "dependencies": {
9− "@assistant/agent-executor-adapter": "workspace:*",
109 "@mariozechner/pi-ai": "^0.52.6",
11− "@sinclair/typebox": "^0.34.48"
10+ "@modelcontextprotocol/sdk": "^1.26.0"
1211 },
1312 "devDependencies": {
1413 "@elysiajs/eden": "^1.4.6",
15− "elysia": "^1.4.22"
14+ "elysia": "^1.4.22",
15+ "zod": "^4.3.6"
1616 }
1717 }
assistant/packages/core/src/agent.test.ts+66−52
@@ -1,62 +1,72 @@
11 import { test, expect } from "bun:test";
2−import { Elysia, t } from "elysia";
3−import { treaty } from "@elysiajs/eden";
2+import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3+import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
4+import { z } from "zod";
45 import { createAgent } from "./agent";
5−import type { Message, GenerateResult } from "./model";
6+import type { Message, GenerateResult, ToolDef } from "./model";
67
78 /**
8− * Minimal mock executor with sync /api/tasks/run endpoint.
9+ * Create a mock MCP server that exposes run_code.
10+ * Returns the Bun HTTP server so we can get the port.
911 */
10−function createMockExecutor() {
11− return new Elysia()
12− .get("/api/tools", ({ query }) => {
13− return [
12+function createMockMcpServer() {
13+ const server = Bun.serve({
14+ port: 0,
15+ async fetch(request) {
16+ const transport = new WebStandardStreamableHTTPServerTransport({
17+ sessionIdGenerator: undefined,
18+ enableJsonResponse: true,
19+ });
20+
21+ const mcp = new McpServer(
22+ { name: "mock-executor", version: "0.1.0" },
23+ { capabilities: { tools: {} } },
24+ );
25+
26+ mcp.registerTool(
27+ "run_code",
1428 {
15− path: "utils.get_time",
16− description: "Get the current time",
17− approval: "auto" as const,
18− source: "local",
19− argsType: "{}",
20− returnsType: "{ iso: string; unix: number }",
29+ description: "Execute TypeScript code in a sandbox.\n\nAvailable tools in the sandbox:\n - tools.utils.get_time({}): { iso: string; unix: number } — Get the current time",
30+ inputSchema: {
31+ code: z.string(),
32+ },
2133 },
22− ];
23− }, {
24− query: t.Object({
25− workspaceId: t.String(),
26− actorId: t.Optional(t.String()),
27− clientId: t.Optional(t.String()),
28− }),
29− })
30− .post("/api/tasks/run", ({ body }) => {
31− return {
32− taskId: `task_${Date.now()}`,
33− status: "completed" as const,
34− stdout: 'result: {"iso":"2026-02-07T00:00:00Z","unix":1770422400000}',
35− stderr: "",
36− exitCode: 0,
37− };
38− }, {
39− body: t.Object({
40− code: t.String(),
41− workspaceId: t.String(),
42− actorId: t.String(),
43− clientId: t.Optional(t.String()),
44− timeoutMs: t.Optional(t.Number()),
45− }),
46− })
47− .listen(0);
34+ async (input) => {
35+ return {
36+ content: [{ type: "text" as const, text: `taskId: task_123\nstatus: completed\nruntimeId: local-bun\n\n\`\`\`text\nresult: {"iso":"2026-02-07T00:00:00Z","unix":1770422400000}\n\`\`\`` }],
37+ };
38+ },
39+ );
40+
41+ try {
42+ await mcp.connect(transport);
43+ return await transport.handleRequest(request);
44+ } finally {
45+ await transport.close().catch(() => {});
46+ await mcp.close().catch(() => {});
47+ }
48+ },
49+ });
50+
51+ return server;
4852 }
4953
50−test("agent calls model, sends code to executor, returns result", async () => {
51− const server = createMockExecutor();
52− const executor = treaty<typeof server>(`http://127.0.0.1:${server.server!.port}`);
54+test("agent connects via MCP, calls run_code, returns result", async () => {
55+ const server = createMockMcpServer();
56+ const port = server.port;
5357
5458 let callCount = 0;
5559 const events: string[] = [];
5660
57− const mockGenerate = async (messages: Message[]): Promise<GenerateResult> => {
61+ const mockGenerate = async (messages: Message[], tools?: ToolDef[]): Promise<GenerateResult> => {
5862 callCount++;
63+
64+ // First call: verify tools were passed from MCP
5965 if (callCount === 1) {
66+ expect(tools).toBeDefined();
67+ expect(tools!.length).toBeGreaterThan(0);
68+ expect(tools![0].name).toBe("run_code");
69+
6070 return {
6171 toolCalls: [{
6272 id: "call_1",
@@ -65,11 +75,13 @@ test("agent calls model, sends code to executor, returns result", async () => { · 2 unmodified lines
6575 }],
6676 };
6777 }
78+
79+ // Second call: return final text
6880 return { text: "The current time is 2026-02-07." };
6981 };
7082
7183 const agent = createAgent({
72− executor: executor as any,
84+ executorUrl: `http://127.0.0.1:${port}`,
7385 generate: mockGenerate,
7486 workspaceId: "ws_test",
7587 actorId: "actor_test",
@@ -80,7 +92,7 @@ test("agent calls model, sends code to executor, returns result", async () => { · 4 unmodified lines
8092 });
8193
8294 expect(result.text).toBe("The current time is 2026-02-07.");
83− expect(result.codeRuns).toBe(1);
95+ expect(result.toolCalls).toBe(1);
8496 expect(callCount).toBe(2);
8597 expect(events).toContain("status");
8698 expect(events).toContain("code_generated");
@@ -91,16 +103,18 @@ test("agent calls model, sends code to executor, returns result", async () => { · 4 unmodified lines
91103 server.stop(true);
92104 });
93105
94−test("agent handles model returning text immediately (no code)", async () => {
95− const server = createMockExecutor();
96− const executor = treaty<typeof server>(`http://127.0.0.1:${server.server!.port}`);
106+test("agent handles model returning text immediately (no tool calls)", async () => {
107+ const server = createMockMcpServer();
108+ const port = server.port;
97109
98− const mockGenerate = async (): Promise<GenerateResult> => {
110+ const mockGenerate = async (_messages: Message[], tools?: ToolDef[]): Promise<GenerateResult> => {
111+ // Tools should still be available even if we don't use them
112+ expect(tools).toBeDefined();
99113 return { text: "I don't need to run any code for that. Hello!" };
100114 };
101115
102116 const agent = createAgent({
103− executor: executor as any,
117+ executorUrl: `http://127.0.0.1:${port}`,
104118 generate: mockGenerate,
105119 workspaceId: "ws_test",
106120 actorId: "actor_test",
@@ -109,7 +123,7 @@ test("agent handles model returning text immediately (no code)", async () => { · 2 unmodified lines
109123 const result = await agent.run("Say hello");
110124
111125 expect(result.text).toBe("I don't need to run any code for that. Hello!");
112− expect(result.codeRuns).toBe(0);
126+ expect(result.toolCalls).toBe(0);
113127
114128 server.stop(true);
115129 });
assistant/packages/core/src/agent.ts+138−120
@@ -1,75 +1,61 @@
11 /**
2− * Agent loop — orchestrates Claude + executor.
2+ * Agent loop — orchestrates Claude + executor via MCP.
33 *
4− * 1. Fetch tool inventory from executor
5− * 2. Build system prompt with tool descriptions
4+ * 1. Connect to executor MCP server
5+ * 2. List tools (gets run_code with sandbox tool inventory in description)
66 * 3. Call Claude → get run_code({ code }) tool call
7− * 4. Send code to executor via sync endpoint (blocks until done)
7+ * 4. Forward to executor via MCP tools/call (blocks until done)
88 * 5. Feed result back to Claude
99 * 6. Loop until Claude responds with text
1010 */
1111
12−import type { ExecutorClient } from "@assistant/agent-executor-adapter";
12+import { Client } from "@modelcontextprotocol/sdk/client/index.js";
13+import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
1314 import type { TaskEvent } from "./events";
14−import type { Message, GenerateResult } from "./model";
15+import type { Message, GenerateResult, ToolCall, ToolDef } from "./model";
1516
1617 // ---------------------------------------------------------------------------
1718 // Types
1819 // ---------------------------------------------------------------------------
1920
20−export interface ToolDescriptor {
21− path: string;
22− description: string;
23− approval: "auto" | "required";
24− source?: string;
25− argsType?: string;
26− returnsType?: string;
21+export interface McpTool {
22+ name: string;
23+ description?: string;
24+ inputSchema?: Record<string, unknown>;
2725 }
2826
2927 export interface AgentOptions {
30− readonly executor: ExecutorClient;
31− readonly generate: (messages: Message[]) => Promise<GenerateResult>;
28+ readonly executorUrl: string;
29+ readonly generate: (messages: Message[], tools?: ToolDef[]) => Promise<GenerateResult>;
3230 readonly workspaceId: string;
3331 readonly actorId: string;
3432 readonly clientId?: string;
3533 readonly context?: string;
36− readonly maxCodeRuns?: number;
37− readonly timeoutMs?: number;
34+ readonly maxToolCalls?: number;
3835 }
3936
4037 export interface AgentResult {
4138 readonly text: string;
42− readonly codeRuns: number;
39+ readonly toolCalls: number;
4340 }
4441
4542 // ---------------------------------------------------------------------------
4643 // System prompt
4744 // ---------------------------------------------------------------------------
4845
49−function buildSystemPrompt(tools: ToolDescriptor[], context?: string): string {
50− const toolGuidance = tools
51− .map((t) => {
52− const args = t.argsType ?? "unknown";
53− const returns = t.returnsType ?? "unknown";
54− const approval = t.approval === "required" ? " (approval required)" : "";
55− return `- tools.${t.path}(${args}): Promise<${returns}>${approval} — ${t.description}`;
56− })
57− .join("\n");
58−
59− const discoveryNote = tools.some((t) => t.path === "discover")
60− ? `\n\n## Tool Discovery\n\nUse \`tools.discover({ query })\` to search for tools by keyword when you need to find specific capabilities.\n`
61− : "";
46+function buildSystemPrompt(tools: McpTool[], context?: string): string {
47+ const toolSection = tools
48+ .map((t) => `### ${t.name}\n${t.description ?? "No description."}`)
49+ .join("\n\n");
6250
6351 const contextSection = context ? `\n## Context\n\n${context}\n` : "";
6452
65− return `You are an AI assistant that executes tasks by generating TypeScript code.
66−
67−You have access to tools via the \`tools\` object. Generate TypeScript code that calls these tools to accomplish the user's task.
53+ return `You are an AI assistant that executes tasks by writing TypeScript code.
6854 ${contextSection}
6955 ## Available Tools
7056
71−${toolGuidance}
72−${discoveryNote}
57+${toolSection}
58+
7359 ## Instructions
7460
7561 - Use the \`run_code\` tool to execute TypeScript code
@@ -80,124 +66,156 @@ ${discoveryNote} · 4 unmodified lines
8066 - Be concise and accurate — base your response on actual tool results`;
8167 }
8268
69+// ---------------------------------------------------------------------------
70+// MCP client helpers
71+// ---------------------------------------------------------------------------
72+
73+async function connectMcp(executorUrl: string, workspaceId: string, actorId: string, clientId?: string): Promise<Client> {
74+ const url = new URL(`${executorUrl}/mcp`);
75+ url.searchParams.set("workspaceId", workspaceId);
76+ url.searchParams.set("actorId", actorId);
77+ if (clientId) url.searchParams.set("clientId", clientId);
78+
79+ const transport = new StreamableHTTPClientTransport(url);
80+ const client = new Client({ name: "assistant-agent", version: "0.1.0" });
81+ await client.connect(transport);
82+ return client;
83+}
84+
85+async function listMcpTools(client: Client): Promise<McpTool[]> {
86+ const result = await client.listTools();
87+ return result.tools.map((t) => ({
88+ name: t.name,
89+ description: t.description,
90+ inputSchema: t.inputSchema as Record<string, unknown> | undefined,
91+ }));
92+}
93+
94+async function callMcpTool(client: Client, name: string, args: Record<string, unknown>): Promise<{
95+ content: string;
96+ isError: boolean;
97+}> {
98+ const result = await client.callTool({ name, arguments: args });
99+ const text = (result.content as Array<{ type: string; text?: string }>)
100+ .filter((c) => c.type === "text" && c.text)
101+ .map((c) => c.text!)
102+ .join("\n");
103+ return { content: text, isError: result.isError === true };
104+}
105+
83106 // ---------------------------------------------------------------------------
84107 // Agent
85108 // ---------------------------------------------------------------------------
86109
87−export function createAgent(options: Omit<AgentOptions, "onEvent">) {
110+export function createAgent(options: AgentOptions) {
88111 return {
89112 async run(prompt: string, onEvent?: (event: TaskEvent) => void): Promise<AgentResult> {
90113 const {
91− executor,
114+ executorUrl,
92115 generate,
93116 workspaceId,
94117 actorId,
95118 clientId,
96119 context,
97− maxCodeRuns = 20,
98− timeoutMs = 30_000,
120+ maxToolCalls = 20,
99121 } = options;
100122
101123 function emit(event: TaskEvent): void {
102124 onEvent?.(event);
103125 }
104126
105− // 1. Fetch tool inventory
106− emit({ type: "status", message: "Loading tools..." });
107− const { data: tools, error: toolsError } = await executor.api.tools.get({
108− query: { workspaceId, actorId, clientId },
109− });
110−
111− if (toolsError || !tools) {
112− const msg = "Failed to load tools from executor";
127+ // 1. Connect to executor MCP
128+ emit({ type: "status", message: "Connecting..." });
129+ let mcp: Client;
130+ try {
131+ mcp = await connectMcp(executorUrl, workspaceId, actorId, clientId);
132+ } catch (err) {
133+ const msg = `Failed to connect to executor MCP: ${err instanceof Error ? err.message : String(err)}`;
113134 emit({ type: "error", error: msg });
114135 emit({ type: "completed" });
115− return { text: msg, codeRuns: 0 };
136+ return { text: msg, toolCalls: 0 };
116137 }
117138
118− // 2. Build system prompt + messages
119− const systemPrompt = buildSystemPrompt(tools as ToolDescriptor[], context);
120− const messages: Message[] = [
121− { role: "system", content: systemPrompt },
122− { role: "user", content: prompt },
123− ];
124−
125− emit({ type: "status", message: "Thinking..." });
139+ try {
140+ // 2. List tools (run_code description includes sandbox tool inventory)
141+ emit({ type: "status", message: "Loading tools..." });
142+ const tools = await listMcpTools(mcp);
126143
127− let codeRunCount = 0;
128−
129− // 3. Agent loop
130− while (codeRunCount < maxCodeRuns) {
131− const response = await generate(messages);
132−
133− // No tool calls → done
134− if (!response.toolCalls || response.toolCalls.length === 0) {
135− const text = response.text ?? "";
136− emit({ type: "agent_message", text });
144+ if (tools.length === 0) {
145+ const msg = "No tools available from executor";
146+ emit({ type: "error", error: msg });
137147 emit({ type: "completed" });
138− return { text, codeRuns: codeRunCount };
148+ return { text: msg, toolCalls: 0 };
139149 }
140150
141− for (const toolCall of response.toolCalls) {
142− if (toolCall.name !== "run_code") {
151+ // 3. Build system prompt + messages
152+ const systemPrompt = buildSystemPrompt(tools, context);
153+ const messages: Message[] = [
154+ { role: "system", content: systemPrompt },
155+ { role: "user", content: prompt },
156+ ];
157+
158+ // Convert MCP tools to model tool defs
159+ const toolDefs: ToolDef[] = tools.map((t) => ({
160+ name: t.name,
161+ description: t.description,
162+ inputSchema: t.inputSchema,
163+ }));
164+
165+ emit({ type: "status", message: "Thinking..." });
166+
167+ let toolCallCount = 0;
168+
169+ // 4. Agent loop
170+ while (toolCallCount < maxToolCalls) {
171+ const response = await generate(messages, toolDefs);
172+
173+ // No tool calls → done
174+ if (!response.toolCalls || response.toolCalls.length === 0) {
175+ const text = response.text ?? "";
176+ emit({ type: "agent_message", text });
177+ emit({ type: "completed" });
178+ return { text, toolCalls: toolCallCount };
179+ }
180+
181+ for (const toolCall of response.toolCalls) {
182+ toolCallCount++;
183+
184+ // Emit events
185+ if (toolCall.name === "run_code" && toolCall.args["code"]) {
186+ emit({ type: "code_generated", code: String(toolCall.args["code"]) });
187+ }
188+ emit({ type: "status", message: `Running ${toolCall.name}...` });
189+
190+ // 5. Forward to executor via MCP
191+ const result = await callMcpTool(mcp, toolCall.name, toolCall.args);
192+
193+ // Emit result
194+ emit({
195+ type: "code_result",
196+ taskId: "",
197+ status: result.isError ? "failed" : "completed",
198+ stdout: result.isError ? undefined : result.content,
199+ error: result.isError ? result.content : undefined,
200+ });
201+
202+ // 6. Feed result back to model
143203 messages.push({ role: "assistant", content: "", toolCalls: [toolCall] });
144204 messages.push({
145205 role: "tool",
146206 toolCallId: toolCall.id,
147− content: `Error: Unknown tool "${toolCall.name}". Use run_code to execute TypeScript code.`,
207+ content: result.content,
148208 });
149− continue;
150− }
151−
152− const code = String(toolCall.args["code"] ?? "");
153− codeRunCount++;
154−
155− emit({ type: "code_generated", code });
156− emit({ type: "status", message: "Running code..." });
157−
158− // 4. Sync call to executor — blocks until task completes
159− const { data: result, error: runError } = await executor.api.tasks.run.post({
160− code,
161− workspaceId,
162− actorId,
163− clientId,
164− timeoutMs,
165− });
166−
167− if (runError || !result) {
168− const errMsg = "Failed to execute code on executor";
169− messages.push({ role: "assistant", content: "", toolCalls: [toolCall] });
170− messages.push({ role: "tool", toolCallId: toolCall.id, content: `Error: ${errMsg}` });
171− continue;
172209 }
173−
174− const r = result as { taskId?: string; status: string; stdout?: string; stderr?: string; error?: string; exitCode?: number };
175−
176− // 5. Emit result event
177− emit({
178− type: "code_result",
179− taskId: r.taskId ?? "",
180− status: r.status,
181− exitCode: r.exitCode,
182− stdout: r.stdout,
183− stderr: r.stderr,
184− error: r.error,
185− });
186−
187− // 6. Feed result back to model
188− const resultContent = r.status === "completed"
189− ? `Code executed successfully.\n${r.stdout ? `\nOutput:\n${r.stdout}` : ""}${r.stderr ? `\nStderr:\n${r.stderr}` : ""}`
190− : `Code execution failed (${r.status}).\n${r.error ? `Error: ${r.error}` : ""}${r.stderr ? `\nStderr:\n${r.stderr}` : ""}`;
191−
192− messages.push({ role: "assistant", content: "", toolCalls: [toolCall] });
193− messages.push({ role: "tool", toolCallId: toolCall.id, content: resultContent });
194210 }
195− }
196211
197− const text = "Reached maximum number of code executions.";
198− emit({ type: "agent_message", text });
199− emit({ type: "completed" });
200− return { text, codeRuns: codeRunCount };
212+ const text = "Reached maximum number of tool calls.";
213+ emit({ type: "agent_message", text });
214+ emit({ type: "completed" });
215+ return { text, toolCalls: toolCallCount };
216+ } finally {
217+ await mcp.close().catch(() => {});
218+ }
201219 },
202220 };
203221 }
assistant/packages/core/src/index.ts+2−2
@@ -1,5 +1,5 @@
11 export { createAgent } from "./agent";
2−export type { AgentOptions, AgentResult, ToolDescriptor } from "./agent";
2+export type { AgentOptions, AgentResult, McpTool } from "./agent";
33 export type { TaskEvent, TaskStatusEvent, TaskCodeGeneratedEvent, TaskCodeResultEvent, TaskAgentMessageEvent, TaskErrorEvent, TaskCompletedEvent } from "./events";
44 export { createModel } from "./model";
5−export type { Message, ToolCall, GenerateResult, ModelOptions } from "./model";
5+export type { Message, ToolCall, ToolDef, GenerateResult, ModelOptions } from "./model";
assistant/packages/core/src/model.ts+20−14
@@ -1,5 +1,7 @@
11 /**
22 * LLM adapter — wraps pi-ai to implement a simple generate interface.
3+ *
4+ * Tools are passed dynamically per call (from MCP tools/list).
35 */
46
57 import {
@@ -15,7 +17,6 @@ import { · 9 unmodified lines
1517 type TextContent,
1618 type ToolCall as PiToolCall,
1719 } from "@mariozechner/pi-ai";
18−import { Type } from "@sinclair/typebox";
1920
2021 // ---------------------------------------------------------------------------
2122 // Types
@@ -34,6 +35,12 @@ export interface ToolCall { · 12 unmodified lines
3435 args: Record<string, unknown>;
3536 }
3637
38+export interface ToolDef {
39+ name: string;
40+ description?: string;
41+ inputSchema?: Record<string, unknown>;
42+}
43+
3744 export interface GenerateResult {
3845 text?: string;
3946 toolCalls?: ToolCall[];
@@ -48,19 +55,16 @@ export interface ModelOptions { · 8 unmodified lines
4855 }
4956
5057 // ---------------------------------------------------------------------------
51−// run_code tool (the only tool the model can call)
58+// Tool conversion (MCP → pi-ai)
5259 // ---------------------------------------------------------------------------
5360
54−const RUN_CODE_TOOL: PiTool = {
55− name: "run_code",
56− description:
57− "Execute TypeScript code in a sandboxed environment. The code has access to a `tools` object with typed methods for interacting with external services. Use `return` to return a value.",
58− parameters: Type.Object({
59− code: Type.String({
60− description: "TypeScript code to execute. Use `await tools.<namespace>.<method>(input)` to call tools. Use `return` to return a value.",
61− }),
62− }),
63−};
61+function convertTool(tool: ToolDef): PiTool {
62+ return {
63+ name: tool.name,
64+ description: tool.description ?? "",
65+ parameters: (tool.inputSchema ?? { type: "object", properties: {} }) as PiTool["parameters"],
66+ };
67+}
6468
6569 // ---------------------------------------------------------------------------
6670 // Message conversion
@@ -178,12 +182,14 @@ export function createModel(options: ModelOptions = {}) { · 111 unmodified lines
178182 const model = getModel(provider as Parameters<typeof getModel>[0], modelId as never);
179183
180184 return {
181− async generate(messages: Message[]): Promise<GenerateResult> {
185+ async generate(messages: Message[], tools?: ToolDef[]): Promise<GenerateResult> {
182186 const { systemPrompt, piMessages } = convertMessages(messages);
183187
188+ const piTools: PiTool[] = tools?.map(convertTool) ?? [];
189+
184190 const context: PiContext = {
185191 messages: piMessages,
186− tools: [RUN_CODE_TOOL],
192+ tools: piTools,
187193 };
188194 if (systemPrompt !== undefined) {
189195 context.systemPrompt = systemPrompt;
assistant/packages/server/package.json+0−1
@@ -12,7 +12,6 @@ · 11 unmodified lines
1212 },
1313 "dependencies": {
1414 "@assistant/core": "workspace:*",
15− "@assistant/agent-executor-adapter": "workspace:*",
1615 "convex": "^1.31.7",
1716 "elysia": "latest",
1817 "@elysiajs/eden": "latest"
assistant/packages/server/src/index.ts+19−10
@@ -1,13 +1,13 @@
11 /**
22 * Assistant Server entry point.
33 *
4− * Connects to the executor, sets up the agent, and serves the API.
4+ * Bootstraps executor context, sets up the agent, and serves the API.
5+ * The agent connects to the executor via MCP — no Eden Treaty needed here.
56 */
67
78 import { readFileSync } from "node:fs";
89 import { createApp } from "./routes";
910 import { createModel } from "@assistant/core";
10−import { createExecutorClient } from "@assistant/agent-executor-adapter";
1111
1212 // ---------------------------------------------------------------------------
1313 // API key resolution
@@ -38,6 +38,7 @@ function getAnthropicApiKey(): string | undefined { · 24 unmodified lines
3838
3939 const PORT = Number(Bun.env.PORT ?? 3000);
4040 const EXECUTOR_URL = Bun.env.EXECUTOR_URL ?? "http://localhost:4001";
41+const CONVEX_URL = Bun.env.CONVEX_URL ?? "http://127.0.0.1:3210";
4142
4243 const apiKey = getAnthropicApiKey();
4344 if (!apiKey) {
@@ -48,16 +49,26 @@ if (!apiKey) { · 4 unmodified lines
4849 // Boot
4950 // ---------------------------------------------------------------------------
5051
51−const executor = createExecutorClient(EXECUTOR_URL);
5252 const model = createModel({ apiKey });
5353
54−// Bootstrap an anonymous context on the executor for this server instance
55−const { data: anonCtx, error: bootstrapError } = await executor.api.auth.anonymous.bootstrap.post({});
56−if (bootstrapError || !anonCtx) {
54+// Bootstrap an anonymous context on the executor
55+const bootstrapResp = await fetch(`${EXECUTOR_URL}/api/auth/anonymous/bootstrap`, {
56+ method: "POST",
57+ headers: { "content-type": "application/json" },
58+ body: JSON.stringify({}),
59+});
60+
61+if (!bootstrapResp.ok) {
5762 console.error("Failed to bootstrap executor context. Is the executor running at", EXECUTOR_URL, "?");
5863 process.exit(1);
5964 }
6065
66+const anonCtx = await bootstrapResp.json() as {
67+ workspaceId: string;
68+ actorId: string;
69+ clientId: string;
70+};
71+
6172 console.log(`[assistant] executor context: workspace=${anonCtx.workspaceId} actor=${anonCtx.actorId}`);
6273
6374 // Build context string
@@ -66,11 +77,9 @@ if (Bun.env.POSTHOG_PROJECT_ID) { · 2 unmodified lines
6677 contextLines.push(`- PostHog project ID: ${Bun.env.POSTHOG_PROJECT_ID}`);
6778 }
6879
69−const CONVEX_URL = Bun.env.CONVEX_URL ?? "http://127.0.0.1:3210";
70−
7180 const app = createApp({
72− executor,
73− generate: (messages) => model.generate(messages),
81+ executorUrl: EXECUTOR_URL,
82+ generate: (messages, tools) => model.generate(messages, tools),
7483 workspaceId: anonCtx.workspaceId,
7584 actorId: anonCtx.actorId,
7685 clientId: anonCtx.clientId,
assistant/packages/server/src/routes.ts+10−11
@@ -7,8 +7,7 @@ · 6 unmodified lines
77
88 import { Elysia, t } from "elysia";
99 import { createAgent } from "@assistant/core";
10−import type { ExecutorClient } from "@assistant/agent-executor-adapter";
11−import type { GenerateResult, Message, TaskEvent } from "@assistant/core";
10+import type { GenerateResult, Message, ToolDef, TaskEvent } from "@assistant/core";
1211 import { ConvexHttpClient } from "convex/browser";
1312 import { api } from "@executor/convex/_generated/api";
1413
@@ -17,8 +16,8 @@ import { api } from "@executor/convex/_generated/api"; · 2 unmodified lines
1716 // ---------------------------------------------------------------------------
1817
1918 export interface ServerOptions {
20− readonly executor: ExecutorClient;
21− readonly generate: (messages: Message[]) => Promise<GenerateResult>;
19+ readonly executorUrl: string;
20+ readonly generate: (messages: Message[], tools?: ToolDef[]) => Promise<GenerateResult>;
2221 readonly workspaceId: string;
2322 readonly actorId: string;
2423 readonly clientId?: string;
@@ -32,7 +31,7 @@ export interface ServerOptions { · 7 unmodified lines
3231
3332 export function createApp(options: ServerOptions) {
3433 const agent = createAgent({
35− executor: options.executor,
34+ executorUrl: options.executorUrl,
3635 generate: options.generate,
3736 workspaceId: options.workspaceId,
3837 actorId: options.actorId,
@@ -68,18 +67,18 @@ export function createApp(options: ServerOptions) { · 29 unmodified lines
6867 });
6968
7069 // Fire and forget — agent runs, writes results to Convex
71− let codeRuns = 0;
70+ let toolCalls = 0;
7271
7372 agent.run(body.prompt, (event: TaskEvent) => {
7473 if (event.type === "code_result") {
75− codeRuns++;
74+ toolCalls++;
7675 }
7776
7877 if (event.type === "agent_message") {
7978 convex.mutation(api.database.updateAgentTask, {
8079 agentTaskId,
8180 resultText: event.text,
82− codeRuns,
81+ codeRuns: toolCalls,
8382 }).catch((err) => console.error(`[agent task ${agentTaskId}] convex write error:`, err));
8483 }
8584
@@ -87,7 +86,7 @@ export function createApp(options: ServerOptions) { · 1 unmodified line
8786 convex.mutation(api.database.updateAgentTask, {
8887 agentTaskId,
8988 status: "completed",
90− codeRuns,
89+ codeRuns: toolCalls,
9190 }).catch((err) => console.error(`[agent task ${agentTaskId}] convex write error:`, err));
9291 }
9392
@@ -96,7 +95,7 @@ export function createApp(options: ServerOptions) { · 2 unmodified lines
9695 agentTaskId,
9796 status: "failed",
9897 error: event.error,
99− codeRuns,
98+ codeRuns: toolCalls,
10099 }).catch((err) => console.error(`[agent task ${agentTaskId}] convex write error:`, err));
101100 }
102101 }).catch((err) => {
@@ -105,7 +104,7 @@ export function createApp(options: ServerOptions) { · 2 unmodified lines
105104 agentTaskId,
106105 status: "failed",
107106 error: err instanceof Error ? err.message : String(err),
108− codeRuns,
107+ codeRuns: toolCalls,
109108 }).catch((err2) => console.error(`[agent task ${agentTaskId}] convex write error:`, err2));
110109 });
111110
bun.lock+1−3
@@ -50,9 +50,8 @@ · 49 unmodified lines
5050 "assistant/packages/core": {
5151 "name": "@assistant/core",
5252 "dependencies": {
53− "@assistant/agent-executor-adapter": "workspace:*",
5453 "@mariozechner/pi-ai": "^0.52.6",
55− "@sinclair/typebox": "^0.34.48",
54+ "@modelcontextprotocol/sdk": "^1.26.0",
5655 },
5756 "devDependencies": {
5857 "@elysiajs/eden": "^1.4.6",
@@ -62,7 +61,6 @@ · 3 unmodified lines
6261 "assistant/packages/server": {
6362 "name": "@assistant/server",
6463 "dependencies": {
65− "@assistant/agent-executor-adapter": "workspace:*",
6664 "@assistant/core": "workspace:*",
6765 "@elysiajs/eden": "latest",
6866 "convex": "^1.31.7",
executor/apps/server/src/index.ts+26−51
@@ -1,7 +1,7 @@
11 import { Elysia, t } from "elysia";
22 import { ExecutorDatabase } from "./database";
33 import { TaskEventHub } from "./events";
4−import { handleMcpRequest } from "./mcp-server";
4+import { handleMcpRequest, type McpWorkspaceContext } from "./mcp-server";
55 import { LocalBunRuntime } from "./runtimes/local-bun-runtime";
66 import { VercelSandboxRuntime } from "./runtimes/vercel-sandbox-runtime";
77 import { ExecutorService, getTaskTerminalState } from "./service";
@@ -151,6 +151,14 @@ function isInternalAuthorized(request: Request): boolean { · 143 unmodified lines
151151 return header.slice("Bearer ".length) === internalToken;
152152 }
153153
154+function parseMcpContext(url: URL): McpWorkspaceContext | undefined {
155+ const workspaceId = url.searchParams.get("workspaceId");
156+ const actorId = url.searchParams.get("actorId");
157+ if (!workspaceId || !actorId) return undefined;
158+ const clientId = url.searchParams.get("clientId") ?? undefined;
159+ return { workspaceId, actorId, clientId };
160+}
161+
154162 // ── Elysia app ──
155163
156164 const app = new Elysia()
@@ -163,9 +171,23 @@ const app = new Elysia() · 6 unmodified lines
163171 .options("/*", () => new Response(null, { status: 204 }))
164172
165173 // ── MCP (raw protocol passthrough) ──
166− .post("/mcp", async ({ request }) => await handleMcpRequest(service, request))
167− .get("/mcp", async ({ request }) => await handleMcpRequest(service, request))
168− .delete("/mcp", async ({ request }) => await handleMcpRequest(service, request))
174+ // Optional query params: ?workspaceId=...&actorId=... to bind workspace context.
175+ // When bound, run_code description includes sandbox tool inventory and input is simplified.
176+ .post("/mcp", async ({ request }) => {
177+ const url = new URL(request.url);
178+ const context = parseMcpContext(url);
179+ return await handleMcpRequest(service, request, context);
180+ })
181+ .get("/mcp", async ({ request }) => {
182+ const url = new URL(request.url);
183+ const context = parseMcpContext(url);
184+ return await handleMcpRequest(service, request, context);
185+ })
186+ .delete("/mcp", async ({ request }) => {
187+ const url = new URL(request.url);
188+ const context = parseMcpContext(url);
189+ return await handleMcpRequest(service, request, context);
190+ })
169191
170192 // ── Health ──
171193 .get("/api/health", () => ({
@@ -262,53 +284,6 @@ const app = new Elysia() · 90 unmodified lines
262284 query: t.Object({ workspaceId: t.String() }),
263285 })
264286
265− // ── Sync run (blocks until task completes, returns result inline) ──
266− .post("/api/tasks/run", async ({ body, set }) => {
267− try {
268− const { task } = await service.createTask(body);
269− // createTask fires executeTask in background when autoExecute is on.
270− // We need to wait for it to finish.
271− const deadline = Date.now() + (body.timeoutMs ?? 30_000) + 15_000;
272−
273− while (Date.now() < deadline) {
274− const current = await service.getTask(task.id);
275− if (!current) break;
276−
277− if (current.status === "completed" || current.status === "failed" || current.status === "timed_out" || current.status === "denied") {
278− return {
279− taskId: current.id,
280− status: current.status,
281− stdout: current.stdout,
282− stderr: current.stderr,
283− exitCode: current.exitCode,
284− error: current.error,
285− };
286− }
287−
288− await Bun.sleep(200);
289− }
290−
291− return {
292− taskId: task.id,
293− status: "timed_out" as const,
294− error: "Task did not complete within deadline",
295− };
296− } catch (cause) {
297− set.status = 400;
298− return { error: cause instanceof Error ? cause.message : String(cause) };
299− }
300− }, {
301− body: t.Object({
302− code: t.String(),
303− timeoutMs: t.Optional(t.Number()),
304− runtimeId: t.Optional(t.String()),
305− metadata: t.Optional(t.Record(t.String(), t.Unknown())),
306− workspaceId: t.String(),
307− actorId: t.String(),
308− clientId: t.Optional(t.String()),
309− }),
310− })
311−
312287 // ── Tasks ──
313288 .get("/api/tasks", async ({ query, set }) => {
314289 if (!query.workspaceId) {
executor/apps/server/src/mcp-server.test.ts+7−1
@@ -2,7 +2,7 @@ import { expect, test } from "bun:test"; · 1 unmodified line
22 import { Client } from "@modelcontextprotocol/sdk/client/index.js";
33 import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
44 import { handleMcpRequest } from "./mcp-server";
5−import type { AnonymousContext, CreateTaskInput, TaskRecord } from "./types";
5+import type { AnonymousContext, CreateTaskInput, TaskRecord, ToolDescriptor } from "./types";
66
77 class FakeMcpService {
88 private readonly tasks = new Map<string, TaskRecord>();
@@ -71,6 +71,12 @@ class FakeMcpService { · 62 unmodified lines
7171 this.sessions.set(context.sessionId, context);
7272 return context;
7373 }
74+
75+ async listTools(_context?: { workspaceId: string; actorId?: string; clientId?: string }): Promise<ToolDescriptor[]> {
76+ return [
77+ { path: "utils.get_time", description: "Get the current time", approval: "auto" },
78+ ];
79+ }
7480 }
7581
7682 async function withMcpClient<T>(
executor/apps/server/src/mcp-server.ts+134−71
@@ -2,39 +2,32 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; · 1 unmodified line
22 import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
33 import { z } from "zod";
44 import { getTaskTerminalState } from "./service";
5−import type { AnonymousContext, CreateTaskInput, TaskRecord } from "./types";
5+import type { AnonymousContext, CreateTaskInput, TaskRecord, ToolDescriptor } from "./types";
6+
7+// ---------------------------------------------------------------------------
8+// Service interface
9+// ---------------------------------------------------------------------------
610
711 interface McpExecutorService {
812 createTask(input: CreateTaskInput): Promise<{ task: TaskRecord }>;
913 getTask(taskId: string, workspaceId?: string): Promise<TaskRecord | null>;
1014 bootstrapAnonymousContext(sessionId?: string): Promise<AnonymousContext>;
15+ listTools(context?: { workspaceId: string; actorId?: string; clientId?: string }): Promise<ToolDescriptor[]>;
1116 }
1217
13−const RUN_CODE_INPUT = {
14− code: z.string().min(1),
15− timeoutMs: z.number().int().min(1).max(600_000).optional(),
16− runtimeId: z.string().optional(),
17− metadata: z.record(z.string(), z.any()).optional(),
18− workspaceId: z.string().optional(),
19− actorId: z.string().optional(),
20− clientId: z.string().optional(),
21− sessionId: z.string().optional(),
22− waitForResult: z.boolean().optional(),
23− resultTimeoutMs: z.number().int().min(100).max(900_000).optional(),
24−} as const;
18+// ---------------------------------------------------------------------------
19+// Workspace context (optional, from query params)
20+// ---------------------------------------------------------------------------
2521
26−type RunCodeInput = {
27− code: string;
28− timeoutMs?: number;
29− runtimeId?: string;
30− metadata?: Record<string, unknown>;
31− workspaceId?: string;
32− actorId?: string;
22+export interface McpWorkspaceContext {
23+ workspaceId: string;
24+ actorId: string;
3325 clientId?: string;
34− sessionId?: string;
35− waitForResult?: boolean;
36− resultTimeoutMs?: number;
37−};
26+}
27+
28+// ---------------------------------------------------------------------------
29+// Helpers
30+// ---------------------------------------------------------------------------
3831
3932 function asCodeBlock(language: string, value: string): string {
4033 return `\n\n\`\`\`${language}\n${value}\n\`\`\``;
@@ -78,54 +71,82 @@ async function waitForTerminalTask( · 37 unmodified lines
7871 const deadline = Date.now() + waitTimeoutMs;
7972 while (Date.now() < deadline) {
8073 const task = await service.getTask(taskId, workspaceId);
81− if (!task) {
82− return null;
83− }
84− if (getTaskTerminalState(task.status)) {
85− return task;
86− }
74+ if (!task) return null;
75+ if (getTaskTerminalState(task.status)) return task;
8776 await Bun.sleep(300);
8877 }
8978 return await service.getTask(taskId, workspaceId);
9079 }
9180
92−async function resolveExecutionContext(
93− service: McpExecutorService,
94− input: RunCodeInput,
95− mcpSessionId?: string,
96−): Promise<{ workspaceId: string; actorId: string; clientId?: string; sessionId?: string }> {
97− if (input.workspaceId || input.actorId) {
98− if (!input.workspaceId || !input.actorId) {
99− throw new Error("workspaceId and actorId must be provided together");
100− }
101− return {
102− workspaceId: input.workspaceId,
103− actorId: input.actorId,
104− clientId: input.clientId,
105− sessionId: input.sessionId,
106− };
107− }
81+// ---------------------------------------------------------------------------
82+// Build run_code description with sandbox tool inventory
83+// ---------------------------------------------------------------------------
10884
109− const seededSessionId = input.sessionId ?? (mcpSessionId ? `mcp_${mcpSessionId}` : undefined);
110− const anonymous = await service.bootstrapAnonymousContext(seededSessionId);
111− return {
112− workspaceId: anonymous.workspaceId,
113− actorId: anonymous.actorId,
114− clientId: input.clientId ?? anonymous.clientId,
115− sessionId: anonymous.sessionId,
116− };
85+function buildRunCodeDescription(tools?: ToolDescriptor[]): string {
86+ const base =
87+ "Execute TypeScript code in a sandboxed runtime. The code has access to a `tools` object with typed methods for calling external services. Use `return` to return a value. Waits for completion and returns stdout/stderr.";
88+
89+ if (!tools || tools.length === 0) return base;
90+
91+ const toolLines = tools.map((t) => {
92+ const args = t.argsType ?? "unknown";
93+ const returns = t.returnsType ?? "unknown";
94+ const approval = t.approval === "required" ? " [approval required]" : "";
95+ return ` - tools.${t.path}(${args}): ${returns}${approval} — ${t.description}`;
96+ });
97+
98+ return `${base}\n\nAvailable tools in the sandbox:\n${toolLines.join("\n")}`;
11799 }
118100
119−function createRunCodeTool(service: McpExecutorService) {
101+// ---------------------------------------------------------------------------
102+// run_code tool handler
103+// ---------------------------------------------------------------------------
104+
105+function createRunCodeTool(
106+ service: McpExecutorService,
107+ boundContext?: McpWorkspaceContext,
108+) {
120109 return async (
121− input: RunCodeInput,
110+ input: {
111+ code: string;
112+ timeoutMs?: number;
113+ runtimeId?: string;
114+ metadata?: Record<string, unknown>;
115+ workspaceId?: string;
116+ actorId?: string;
117+ clientId?: string;
118+ sessionId?: string;
119+ waitForResult?: boolean;
120+ resultTimeoutMs?: number;
121+ },
122122 extra: { sessionId?: string },
123123 ): Promise<{
124124 content: Array<{ type: "text"; text: string }>;
125125 structuredContent?: Record<string, unknown>;
126126 isError?: boolean;
127127 }> => {
128− const context = await resolveExecutionContext(service, input, extra.sessionId);
128+ // Resolve context: bound context takes priority, then input, then anonymous
129+ let context: { workspaceId: string; actorId: string; clientId?: string; sessionId?: string };
130+
131+ if (boundContext) {
132+ context = { ...boundContext, sessionId: input.sessionId };
133+ } else if (input.workspaceId && input.actorId) {
134+ context = {
135+ workspaceId: input.workspaceId,
136+ actorId: input.actorId,
137+ clientId: input.clientId,
138+ sessionId: input.sessionId,
139+ };
140+ } else {
141+ const seededSessionId = input.sessionId ?? (extra.sessionId ? `mcp_${extra.sessionId}` : undefined);
142+ const anonymous = await service.bootstrapAnonymousContext(seededSessionId);
143+ context = {
144+ workspaceId: anonymous.workspaceId,
145+ actorId: anonymous.actorId,
146+ clientId: input.clientId ?? anonymous.clientId,
147+ sessionId: anonymous.sessionId,
148+ };
149+ }
129150
130151 const created = await service.createTask({
131152 code: input.code,
@@ -164,13 +185,7 @@ function createRunCodeTool(service: McpExecutorService) { · 32 unmodified lines
164185 if (!getTaskTerminalState(task.status)) {
165186 return {
166187 content: [textContent(`Task ${task.id} is still ${task.status}`)],
167− structuredContent: {
168− taskId: task.id,
169− status: task.status,
170− workspaceId: context.workspaceId,
171− actorId: context.actorId,
172− sessionId: context.sessionId,
173− },
188+ structuredContent: { taskId: task.id, status: task.status, workspaceId: context.workspaceId, actorId: context.actorId, sessionId: context.sessionId },
174189 };
175190 }
176191
@@ -194,31 +209,79 @@ function createRunCodeTool(service: McpExecutorService) { · 17 unmodified lines
194209 };
195210 }
196211
197−function createMcpServer(service: McpExecutorService): McpServer {
212+// ---------------------------------------------------------------------------
213+// Input schema — when context is bound, workspace fields aren't needed
214+// ---------------------------------------------------------------------------
215+
216+const FULL_INPUT = {
217+ code: z.string().min(1),
218+ timeoutMs: z.number().int().min(1).max(600_000).optional(),
219+ runtimeId: z.string().optional(),
220+ metadata: z.record(z.string(), z.any()).optional(),
221+ workspaceId: z.string().optional(),
222+ actorId: z.string().optional(),
223+ clientId: z.string().optional(),
224+ sessionId: z.string().optional(),
225+ waitForResult: z.boolean().optional(),
226+ resultTimeoutMs: z.number().int().min(100).max(900_000).optional(),
227+} as const;
228+
229+const BOUND_INPUT = {
230+ code: z.string().min(1),
231+ timeoutMs: z.number().int().min(1).max(600_000).optional(),
232+ runtimeId: z.string().optional(),
233+ metadata: z.record(z.string(), z.any()).optional(),
234+} as const;
235+
236+// ---------------------------------------------------------------------------
237+// MCP server factory
238+// ---------------------------------------------------------------------------
239+
240+async function createMcpServer(
241+ service: McpExecutorService,
242+ context?: McpWorkspaceContext,
243+): Promise<McpServer> {
198244 const mcp = new McpServer(
199245 { name: "executor", version: "0.1.0" },
200246 { capabilities: { tools: {} } },
201247 );
202248
249+ // If workspace context is provided, fetch tool inventory for richer description
250+ let tools: ToolDescriptor[] | undefined;
251+ if (context) {
252+ tools = await service.listTools({
253+ workspaceId: context.workspaceId,
254+ actorId: context.actorId,
255+ clientId: context.clientId,
256+ });
257+ }
258+
203259 mcp.registerTool(
204260 "run_code",
205261 {
206− description:
207− "Run JavaScript/TypeScript code in the executor runtime. Defaults to waiting for terminal result and returns stdout/stderr.",
208− inputSchema: RUN_CODE_INPUT,
262+ description: buildRunCodeDescription(tools),
263+ inputSchema: context ? BOUND_INPUT : FULL_INPUT,
209264 },
210− createRunCodeTool(service),
265+ createRunCodeTool(service, context),
211266 );
212267
213268 return mcp;
214269 }
215270
216−export async function handleMcpRequest(service: McpExecutorService, request: Request): Promise<Response> {
271+// ---------------------------------------------------------------------------
272+// Request handler
273+// ---------------------------------------------------------------------------
274+
275+export async function handleMcpRequest(
276+ service: McpExecutorService,
277+ request: Request,
278+ context?: McpWorkspaceContext,
279+): Promise<Response> {
217280 const transport = new WebStandardStreamableHTTPServerTransport({
218281 sessionIdGenerator: undefined,
219282 enableJsonResponse: true,
220283 });
221− const mcp = createMcpServer(service);
284+ const mcp = await createMcpServer(service, context);
222285
223286 try {
224287 await mcp.connect(transport);