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.
Unified · Split
| @@ -37,7 +37,6 @@ · 36 unmodified lines | ||
| 37 | 37 | "packages/bot": { |
| 38 | 38 | "name": "@assistant/bot", |
| 39 | 39 | "dependencies": { |
| 40 | − "@assistant/agent-executor-adapter": "workspace:*", | |
| 41 | 40 | "@assistant/core": "workspace:*", |
| 42 | 41 | "@assistant/server": "workspace:*", |
| 43 | 42 | "@elysiajs/eden": "latest", |
| @@ -55,21 +54,21 @@ · 11 unmodified lines | ||
| 55 | 54 | "packages/core": { |
| 56 | 55 | "name": "@assistant/core", |
| 57 | 56 | "dependencies": { |
| 58 | − "@assistant/agent-executor-adapter": "workspace:*", | |
| 59 | 57 | "@mariozechner/pi-ai": "^0.52.6", |
| 60 | − "@sinclair/typebox": "^0.34.48", | |
| 58 | + "@modelcontextprotocol/sdk": "^1.26.0", | |
| 61 | 59 | }, |
| 62 | 60 | "devDependencies": { |
| 63 | 61 | "@elysiajs/eden": "^1.4.6", |
| 64 | 62 | "elysia": "^1.4.22", |
| 63 | + "zod": "^4.3.6", | |
| 65 | 64 | }, |
| 66 | 65 | }, |
| 67 | 66 | "packages/server": { |
| 68 | 67 | "name": "@assistant/server", |
| 69 | 68 | "dependencies": { |
| 70 | − "@assistant/agent-executor-adapter": "workspace:*", | |
| 71 | 69 | "@assistant/core": "workspace:*", |
| 72 | 70 | "@elysiajs/eden": "latest", |
| 71 | + "convex": "^1.31.7", | |
| 73 | 72 | "elysia": "latest", |
| 74 | 73 | }, |
| 75 | 74 | "devDependencies": { |
| @@ -238,12 +237,16 @@ · 162 unmodified lines | ||
| 238 | 237 | |
| 239 | 238 | "@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=="], |
| 240 | 239 | |
| 240 | + "@hono/node-server": ["@hono/node-server@1.19.9", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw=="], | |
| 241 | + | |
| 241 | 242 | "@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=="], |
| 242 | 243 | |
| 243 | 244 | "@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=="], |
| 244 | 245 | |
| 245 | 246 | "@mistralai/mistralai": ["@mistralai/mistralai@1.10.0", "", { "dependencies": { "zod": "^3.20.0", "zod-to-json-schema": "^3.24.1" } }, "sha512-tdIgWs4Le8vpvPiUEWne6tK0qbVc+jMenujnvTqOjogrJUsCSQhus0tHTU1avDDh5//Rq2dFgP9mWRAdIEoBqg=="], |
| 246 | 247 | |
| 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 | + | |
| 247 | 250 | "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="], |
| 248 | 251 | |
| 249 | 252 | "@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 | ||
| 398 | 401 | |
| 399 | 402 | "@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.7", "", {}, "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g=="], |
| 400 | 403 | |
| 404 | + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], | |
| 405 | + | |
| 401 | 406 | "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], |
| 402 | 407 | |
| 403 | 408 | "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 | ||
| 418 | 423 | |
| 419 | 424 | "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], |
| 420 | 425 | |
| 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 | + | |
| 421 | 428 | "bowser": ["bowser@2.13.1", "", {}, "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw=="], |
| 422 | 429 | |
| 423 | 430 | "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], |
| @@ -426,16 +433,30 @@ · 2 unmodified lines | ||
| 426 | 433 | |
| 427 | 434 | "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="], |
| 428 | 435 | |
| 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 | + | |
| 429 | 442 | "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], |
| 430 | 443 | |
| 431 | 444 | "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], |
| 432 | 445 | |
| 433 | 446 | "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], |
| 434 | 447 | |
| 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 | + | |
| 435 | 452 | "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=="], |
| 436 | 453 | |
| 437 | 454 | "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], |
| 438 | 455 | |
| 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 | + | |
| 439 | 460 | "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], |
| 440 | 461 | |
| 441 | 462 | "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], |
| @@ -446,24 +467,40 @@ · 4 unmodified lines | ||
| 446 | 467 | |
| 447 | 468 | "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=="], |
| 448 | 469 | |
| 470 | + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], | |
| 471 | + | |
| 449 | 472 | "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], |
| 450 | 473 | |
| 451 | 474 | "discord-api-types": ["discord-api-types@0.38.38", "", {}, "sha512-7qcM5IeZrfb+LXW07HvoI5L+j4PQeMZXEkSm1htHAHh4Y9JSMXBWjy/r7zmUCOj4F7zNjMcm7IMWr131MT2h0Q=="], |
| 452 | 475 | |
| 453 | 476 | "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=="], |
| 454 | 477 | |
| 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 | + | |
| 455 | 480 | "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], |
| 456 | 481 | |
| 457 | 482 | "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], |
| 458 | 483 | |
| 484 | + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], | |
| 485 | + | |
| 459 | 486 | "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=="], |
| 460 | 487 | |
| 461 | 488 | "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=="], |
| 462 | 489 | |
| 463 | 490 | "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], |
| 464 | 491 | |
| 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 | + | |
| 465 | 500 | "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=="], |
| 466 | 501 | |
| 502 | + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], | |
| 503 | + | |
| 467 | 504 | "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=="], |
| 468 | 505 | |
| 469 | 506 | "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 | ||
| 472 | 509 | |
| 473 | 510 | "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], |
| 474 | 511 | |
| 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 | + | |
| 475 | 518 | "exact-mirror": ["exact-mirror@0.2.6", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-7s059UIx9/tnOKSySzUk5cPGkoILhTE4p6ncf6uIPaQ+9aRBQzQjc9+q85l51+oZ+P6aBxh084pD0CzBQPcFUA=="], |
| 476 | 519 | |
| 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 | + | |
| 477 | 524 | "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], |
| 478 | 525 | |
| 479 | 526 | "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="], |
| @@ -490,16 +537,28 @@ · 10 unmodified lines | ||
| 490 | 537 | |
| 491 | 538 | "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=="], |
| 492 | 539 | |
| 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 | + | |
| 493 | 542 | "find-my-way-ts": ["find-my-way-ts@0.1.6", "", {}, "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA=="], |
| 494 | 543 | |
| 495 | 544 | "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], |
| 496 | 545 | |
| 497 | 546 | "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], |
| 498 | 547 | |
| 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 | + | |
| 499 | 554 | "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=="], |
| 500 | 555 | |
| 501 | 556 | "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=="], |
| 502 | 557 | |
| 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 | + | |
| 503 | 562 | "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=="], |
| 504 | 563 | |
| 505 | 564 | "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 | ||
| 508 | 567 | |
| 509 | 568 | "google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="], |
| 510 | 569 | |
| 570 | + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], | |
| 571 | + | |
| 511 | 572 | "gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="], |
| 512 | 573 | |
| 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 | + | |
| 513 | 582 | "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], |
| 514 | 583 | |
| 515 | 584 | "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], |
| 516 | 585 | |
| 586 | + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], | |
| 587 | + | |
| 517 | 588 | "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], |
| 518 | 589 | |
| 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=="], | |
| 520 | 595 | |
| 521 | 596 | "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], |
| 522 | 597 | |
| 598 | + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], | |
| 599 | + | |
| 523 | 600 | "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], |
| 524 | 601 | |
| 525 | 602 | "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], |
| 526 | 603 | |
| 604 | + "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="], | |
| 605 | + | |
| 527 | 606 | "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], |
| 528 | 607 | |
| 529 | 608 | "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=="], |
| 530 | 609 | |
| 531 | 610 | "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], |
| 532 | 611 | |
| 612 | + "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], | |
| 613 | + | |
| 533 | 614 | "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=="], |
| 534 | 615 | |
| 535 | 616 | "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 | ||
| 544 | 625 | |
| 545 | 626 | "magic-bytes.js": ["magic-bytes.js@1.13.0", "", {}, "sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg=="], |
| 546 | 627 | |
| 628 | + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], | |
| 629 | + | |
| 630 | + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], | |
| 631 | + | |
| 547 | 632 | "memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="], |
| 548 | 633 | |
| 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 | + | |
| 549 | 640 | "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], |
| 550 | 641 | |
| 551 | 642 | "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], |
| @@ -558,6 +649,8 @@ · 6 unmodified lines | ||
| 558 | 649 | |
| 559 | 650 | "multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="], |
| 560 | 651 | |
| 652 | + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], | |
| 653 | + | |
| 561 | 654 | "netmask": ["netmask@2.0.2", "", {}, "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="], |
| 562 | 655 | |
| 563 | 656 | "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], |
| @@ -566,6 +659,14 @@ · 2 unmodified lines | ||
| 566 | 659 | |
| 567 | 660 | "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=="], |
| 568 | 661 | |
| 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 | + | |
| 569 | 670 | "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=="], |
| 570 | 671 | |
| 571 | 672 | "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], |
| @@ -576,22 +677,36 @@ · 4 unmodified lines | ||
| 576 | 677 | |
| 577 | 678 | "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], |
| 578 | 679 | |
| 680 | + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], | |
| 681 | + | |
| 579 | 682 | "partial-json": ["partial-json@0.1.7", "", {}, "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA=="], |
| 580 | 683 | |
| 581 | 684 | "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], |
| 582 | 685 | |
| 583 | 686 | "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=="], |
| 584 | 687 | |
| 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 | + | |
| 585 | 692 | "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], |
| 586 | 693 | |
| 587 | 694 | "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=="], |
| 588 | 695 | |
| 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 | + | |
| 589 | 698 | "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=="], |
| 590 | 699 | |
| 591 | 700 | "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], |
| 592 | 701 | |
| 593 | 702 | "pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="], |
| 594 | 703 | |
| 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 | + | |
| 595 | 710 | "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], |
| 596 | 711 | |
| 597 | 712 | "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 | ||
| 600 | 715 | |
| 601 | 716 | "rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="], |
| 602 | 717 | |
| 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 | + | |
| 603 | 720 | "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], |
| 604 | 721 | |
| 722 | + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], | |
| 723 | + | |
| 605 | 724 | "scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="], |
| 606 | 725 | |
| 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 | + | |
| 607 | 732 | "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], |
| 608 | 733 | |
| 609 | 734 | "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], |
| 610 | 735 | |
| 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 | + | |
| 611 | 744 | "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], |
| 612 | 745 | |
| 613 | 746 | "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], |
| @@ -618,6 +751,8 @@ · 4 unmodified lines | ||
| 618 | 751 | |
| 619 | 752 | "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], |
| 620 | 753 | |
| 754 | + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], | |
| 755 | + | |
| 621 | 756 | "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=="], |
| 622 | 757 | |
| 623 | 758 | "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 | ||
| 630 | 765 | |
| 631 | 766 | "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], |
| 632 | 767 | |
| 768 | + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], | |
| 769 | + | |
| 633 | 770 | "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=="], |
| 634 | 771 | |
| 635 | 772 | "ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="], |
| @@ -638,6 +775,8 @@ · 2 unmodified lines | ||
| 638 | 775 | |
| 639 | 776 | "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], |
| 640 | 777 | |
| 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 | + | |
| 641 | 780 | "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], |
| 642 | 781 | |
| 643 | 782 | "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], |
| @@ -646,8 +785,12 @@ · 2 unmodified lines | ||
| 646 | 785 | |
| 647 | 786 | "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], |
| 648 | 787 | |
| 788 | + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], | |
| 789 | + | |
| 649 | 790 | "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], |
| 650 | 791 | |
| 792 | + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], | |
| 793 | + | |
| 651 | 794 | "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], |
| 652 | 795 | |
| 653 | 796 | "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 | ||
| 656 | 799 | |
| 657 | 800 | "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=="], |
| 658 | 801 | |
| 802 | + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], | |
| 803 | + | |
| 659 | 804 | "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=="], |
| 660 | 805 | |
| 661 | − "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], | |
| 806 | + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], | |
| 662 | 807 | |
| 663 | 808 | "zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], |
| 664 | 809 | |
| @@ -672,10 +817,18 @@ · 7 unmodified lines | ||
| 672 | 817 | |
| 673 | 818 | "@mariozechner/pi-ai/undici": ["undici@7.21.0", "", {}, "sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg=="], |
| 674 | 819 | |
| 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 | + | |
| 675 | 826 | "node-fetch/data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], |
| 676 | 827 | |
| 677 | 828 | "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], |
| 678 | 829 | |
| 830 | + "socks/ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], | |
| 831 | + | |
| 679 | 832 | "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], |
| 680 | 833 | |
| 681 | 834 | "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], |
| @@ -6,12 +6,12 @@ · 5 unmodified lines | ||
| 6 | 6 | ".": "./src/index.ts" |
| 7 | 7 | }, |
| 8 | 8 | "dependencies": { |
| 9 | − "@assistant/agent-executor-adapter": "workspace:*", | |
| 10 | 9 | "@mariozechner/pi-ai": "^0.52.6", |
| 11 | − "@sinclair/typebox": "^0.34.48" | |
| 10 | + "@modelcontextprotocol/sdk": "^1.26.0" | |
| 12 | 11 | }, |
| 13 | 12 | "devDependencies": { |
| 14 | 13 | "@elysiajs/eden": "^1.4.6", |
| 15 | − "elysia": "^1.4.22" | |
| 14 | + "elysia": "^1.4.22", | |
| 15 | + "zod": "^4.3.6" | |
| 16 | 16 | } |
| 17 | 17 | } |
| @@ -1,62 +1,72 @@ | ||
| 1 | 1 | 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"; | |
| 4 | 5 | import { createAgent } from "./agent"; |
| 5 | −import type { Message, GenerateResult } from "./model"; | |
| 6 | +import type { Message, GenerateResult, ToolDef } from "./model"; | |
| 6 | 7 | |
| 7 | 8 | /** |
| 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. | |
| 9 | 11 | */ |
| 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", | |
| 14 | 28 | { |
| 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 | + }, | |
| 21 | 33 | }, |
| 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; | |
| 48 | 52 | } |
| 49 | 53 | |
| 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; | |
| 53 | 57 | |
| 54 | 58 | let callCount = 0; |
| 55 | 59 | const events: string[] = []; |
| 56 | 60 | |
| 57 | − const mockGenerate = async (messages: Message[]): Promise<GenerateResult> => { | |
| 61 | + const mockGenerate = async (messages: Message[], tools?: ToolDef[]): Promise<GenerateResult> => { | |
| 58 | 62 | callCount++; |
| 63 | + | |
| 64 | + // First call: verify tools were passed from MCP | |
| 59 | 65 | if (callCount === 1) { |
| 66 | + expect(tools).toBeDefined(); | |
| 67 | + expect(tools!.length).toBeGreaterThan(0); | |
| 68 | + expect(tools![0].name).toBe("run_code"); | |
| 69 | + | |
| 60 | 70 | return { |
| 61 | 71 | toolCalls: [{ |
| 62 | 72 | id: "call_1", |
| @@ -65,11 +75,13 @@ test("agent calls model, sends code to executor, returns result", async () => { · 2 unmodified lines | ||
| 65 | 75 | }], |
| 66 | 76 | }; |
| 67 | 77 | } |
| 78 | + | |
| 79 | + // Second call: return final text | |
| 68 | 80 | return { text: "The current time is 2026-02-07." }; |
| 69 | 81 | }; |
| 70 | 82 | |
| 71 | 83 | const agent = createAgent({ |
| 72 | − executor: executor as any, | |
| 84 | + executorUrl: `http://127.0.0.1:${port}`, | |
| 73 | 85 | generate: mockGenerate, |
| 74 | 86 | workspaceId: "ws_test", |
| 75 | 87 | actorId: "actor_test", |
| @@ -80,7 +92,7 @@ test("agent calls model, sends code to executor, returns result", async () => { · 4 unmodified lines | ||
| 80 | 92 | }); |
| 81 | 93 | |
| 82 | 94 | expect(result.text).toBe("The current time is 2026-02-07."); |
| 83 | − expect(result.codeRuns).toBe(1); | |
| 95 | + expect(result.toolCalls).toBe(1); | |
| 84 | 96 | expect(callCount).toBe(2); |
| 85 | 97 | expect(events).toContain("status"); |
| 86 | 98 | expect(events).toContain("code_generated"); |
| @@ -91,16 +103,18 @@ test("agent calls model, sends code to executor, returns result", async () => { · 4 unmodified lines | ||
| 91 | 103 | server.stop(true); |
| 92 | 104 | }); |
| 93 | 105 | |
| 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; | |
| 97 | 109 | |
| 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(); | |
| 99 | 113 | return { text: "I don't need to run any code for that. Hello!" }; |
| 100 | 114 | }; |
| 101 | 115 | |
| 102 | 116 | const agent = createAgent({ |
| 103 | − executor: executor as any, | |
| 117 | + executorUrl: `http://127.0.0.1:${port}`, | |
| 104 | 118 | generate: mockGenerate, |
| 105 | 119 | workspaceId: "ws_test", |
| 106 | 120 | actorId: "actor_test", |
| @@ -109,7 +123,7 @@ test("agent handles model returning text immediately (no code)", async () => { · 2 unmodified lines | ||
| 109 | 123 | const result = await agent.run("Say hello"); |
| 110 | 124 | |
| 111 | 125 | 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); | |
| 113 | 127 | |
| 114 | 128 | server.stop(true); |
| 115 | 129 | }); |
| @@ -1,75 +1,61 @@ | ||
| 1 | 1 | /** |
| 2 | − * Agent loop — orchestrates Claude + executor. | |
| 2 | + * Agent loop — orchestrates Claude + executor via MCP. | |
| 3 | 3 | * |
| 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) | |
| 6 | 6 | * 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) | |
| 8 | 8 | * 5. Feed result back to Claude |
| 9 | 9 | * 6. Loop until Claude responds with text |
| 10 | 10 | */ |
| 11 | 11 | |
| 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"; | |
| 13 | 14 | import type { TaskEvent } from "./events"; |
| 14 | −import type { Message, GenerateResult } from "./model"; | |
| 15 | +import type { Message, GenerateResult, ToolCall, ToolDef } from "./model"; | |
| 15 | 16 | |
| 16 | 17 | // --------------------------------------------------------------------------- |
| 17 | 18 | // Types |
| 18 | 19 | // --------------------------------------------------------------------------- |
| 19 | 20 | |
| 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>; | |
| 27 | 25 | } |
| 28 | 26 | |
| 29 | 27 | 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>; | |
| 32 | 30 | readonly workspaceId: string; |
| 33 | 31 | readonly actorId: string; |
| 34 | 32 | readonly clientId?: string; |
| 35 | 33 | readonly context?: string; |
| 36 | − readonly maxCodeRuns?: number; | |
| 37 | − readonly timeoutMs?: number; | |
| 34 | + readonly maxToolCalls?: number; | |
| 38 | 35 | } |
| 39 | 36 | |
| 40 | 37 | export interface AgentResult { |
| 41 | 38 | readonly text: string; |
| 42 | − readonly codeRuns: number; | |
| 39 | + readonly toolCalls: number; | |
| 43 | 40 | } |
| 44 | 41 | |
| 45 | 42 | // --------------------------------------------------------------------------- |
| 46 | 43 | // System prompt |
| 47 | 44 | // --------------------------------------------------------------------------- |
| 48 | 45 | |
| 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"); | |
| 62 | 50 | |
| 63 | 51 | const contextSection = context ? `\n## Context\n\n${context}\n` : ""; |
| 64 | 52 | |
| 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. | |
| 68 | 54 | ${contextSection} |
| 69 | 55 | ## Available Tools |
| 70 | 56 | |
| 71 | −${toolGuidance} | |
| 72 | −${discoveryNote} | |
| 57 | +${toolSection} | |
| 58 | + | |
| 73 | 59 | ## Instructions |
| 74 | 60 | |
| 75 | 61 | - Use the \`run_code\` tool to execute TypeScript code |
| @@ -80,124 +66,156 @@ ${discoveryNote} · 4 unmodified lines | ||
| 80 | 66 | - Be concise and accurate — base your response on actual tool results`; |
| 81 | 67 | } |
| 82 | 68 | |
| 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 | + | |
| 83 | 106 | // --------------------------------------------------------------------------- |
| 84 | 107 | // Agent |
| 85 | 108 | // --------------------------------------------------------------------------- |
| 86 | 109 | |
| 87 | −export function createAgent(options: Omit<AgentOptions, "onEvent">) { | |
| 110 | +export function createAgent(options: AgentOptions) { | |
| 88 | 111 | return { |
| 89 | 112 | async run(prompt: string, onEvent?: (event: TaskEvent) => void): Promise<AgentResult> { |
| 90 | 113 | const { |
| 91 | − executor, | |
| 114 | + executorUrl, | |
| 92 | 115 | generate, |
| 93 | 116 | workspaceId, |
| 94 | 117 | actorId, |
| 95 | 118 | clientId, |
| 96 | 119 | context, |
| 97 | − maxCodeRuns = 20, | |
| 98 | − timeoutMs = 30_000, | |
| 120 | + maxToolCalls = 20, | |
| 99 | 121 | } = options; |
| 100 | 122 | |
| 101 | 123 | function emit(event: TaskEvent): void { |
| 102 | 124 | onEvent?.(event); |
| 103 | 125 | } |
| 104 | 126 | |
| 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)}`; | |
| 113 | 134 | emit({ type: "error", error: msg }); |
| 114 | 135 | emit({ type: "completed" }); |
| 115 | − return { text: msg, codeRuns: 0 }; | |
| 136 | + return { text: msg, toolCalls: 0 }; | |
| 116 | 137 | } |
| 117 | 138 | |
| 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); | |
| 126 | 143 | |
| 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 }); | |
| 137 | 147 | emit({ type: "completed" }); |
| 138 | − return { text, codeRuns: codeRunCount }; | |
| 148 | + return { text: msg, toolCalls: 0 }; | |
| 139 | 149 | } |
| 140 | 150 | |
| 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 | |
| 143 | 203 | messages.push({ role: "assistant", content: "", toolCalls: [toolCall] }); |
| 144 | 204 | messages.push({ |
| 145 | 205 | role: "tool", |
| 146 | 206 | toolCallId: toolCall.id, |
| 147 | − content: `Error: Unknown tool "${toolCall.name}". Use run_code to execute TypeScript code.`, | |
| 207 | + content: result.content, | |
| 148 | 208 | }); |
| 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; | |
| 172 | 209 | } |
| 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 }); | |
| 194 | 210 | } |
| 195 | − } | |
| 196 | 211 | |
| 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 | + } | |
| 201 | 219 | }, |
| 202 | 220 | }; |
| 203 | 221 | } |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | export { createAgent } from "./agent"; |
| 2 | −export type { AgentOptions, AgentResult, ToolDescriptor } from "./agent"; | |
| 2 | +export type { AgentOptions, AgentResult, McpTool } from "./agent"; | |
| 3 | 3 | export type { TaskEvent, TaskStatusEvent, TaskCodeGeneratedEvent, TaskCodeResultEvent, TaskAgentMessageEvent, TaskErrorEvent, TaskCompletedEvent } from "./events"; |
| 4 | 4 | export { createModel } from "./model"; |
| 5 | −export type { Message, ToolCall, GenerateResult, ModelOptions } from "./model"; | |
| 5 | +export type { Message, ToolCall, ToolDef, GenerateResult, ModelOptions } from "./model"; | |
| @@ -1,5 +1,7 @@ | ||
| 1 | 1 | /** |
| 2 | 2 | * LLM adapter — wraps pi-ai to implement a simple generate interface. |
| 3 | + * | |
| 4 | + * Tools are passed dynamically per call (from MCP tools/list). | |
| 3 | 5 | */ |
| 4 | 6 | |
| 5 | 7 | import { |
| @@ -15,7 +17,6 @@ import { · 9 unmodified lines | ||
| 15 | 17 | type TextContent, |
| 16 | 18 | type ToolCall as PiToolCall, |
| 17 | 19 | } from "@mariozechner/pi-ai"; |
| 18 | −import { Type } from "@sinclair/typebox"; | |
| 19 | 20 | |
| 20 | 21 | // --------------------------------------------------------------------------- |
| 21 | 22 | // Types |
| @@ -34,6 +35,12 @@ export interface ToolCall { · 12 unmodified lines | ||
| 34 | 35 | args: Record<string, unknown>; |
| 35 | 36 | } |
| 36 | 37 | |
| 38 | +export interface ToolDef { | |
| 39 | + name: string; | |
| 40 | + description?: string; | |
| 41 | + inputSchema?: Record<string, unknown>; | |
| 42 | +} | |
| 43 | + | |
| 37 | 44 | export interface GenerateResult { |
| 38 | 45 | text?: string; |
| 39 | 46 | toolCalls?: ToolCall[]; |
| @@ -48,19 +55,16 @@ export interface ModelOptions { · 8 unmodified lines | ||
| 48 | 55 | } |
| 49 | 56 | |
| 50 | 57 | // --------------------------------------------------------------------------- |
| 51 | −// run_code tool (the only tool the model can call) | |
| 58 | +// Tool conversion (MCP → pi-ai) | |
| 52 | 59 | // --------------------------------------------------------------------------- |
| 53 | 60 | |
| 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 | +} | |
| 64 | 68 | |
| 65 | 69 | // --------------------------------------------------------------------------- |
| 66 | 70 | // Message conversion |
| @@ -178,12 +182,14 @@ export function createModel(options: ModelOptions = {}) { · 111 unmodified lines | ||
| 178 | 182 | const model = getModel(provider as Parameters<typeof getModel>[0], modelId as never); |
| 179 | 183 | |
| 180 | 184 | return { |
| 181 | − async generate(messages: Message[]): Promise<GenerateResult> { | |
| 185 | + async generate(messages: Message[], tools?: ToolDef[]): Promise<GenerateResult> { | |
| 182 | 186 | const { systemPrompt, piMessages } = convertMessages(messages); |
| 183 | 187 | |
| 188 | + const piTools: PiTool[] = tools?.map(convertTool) ?? []; | |
| 189 | + | |
| 184 | 190 | const context: PiContext = { |
| 185 | 191 | messages: piMessages, |
| 186 | − tools: [RUN_CODE_TOOL], | |
| 192 | + tools: piTools, | |
| 187 | 193 | }; |
| 188 | 194 | if (systemPrompt !== undefined) { |
| 189 | 195 | context.systemPrompt = systemPrompt; |
| @@ -12,7 +12,6 @@ · 11 unmodified lines | ||
| 12 | 12 | }, |
| 13 | 13 | "dependencies": { |
| 14 | 14 | "@assistant/core": "workspace:*", |
| 15 | − "@assistant/agent-executor-adapter": "workspace:*", | |
| 16 | 15 | "convex": "^1.31.7", |
| 17 | 16 | "elysia": "latest", |
| 18 | 17 | "@elysiajs/eden": "latest" |
| @@ -1,13 +1,13 @@ | ||
| 1 | 1 | /** |
| 2 | 2 | * Assistant Server entry point. |
| 3 | 3 | * |
| 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. | |
| 5 | 6 | */ |
| 6 | 7 | |
| 7 | 8 | import { readFileSync } from "node:fs"; |
| 8 | 9 | import { createApp } from "./routes"; |
| 9 | 10 | import { createModel } from "@assistant/core"; |
| 10 | −import { createExecutorClient } from "@assistant/agent-executor-adapter"; | |
| 11 | 11 | |
| 12 | 12 | // --------------------------------------------------------------------------- |
| 13 | 13 | // API key resolution |
| @@ -38,6 +38,7 @@ function getAnthropicApiKey(): string | undefined { · 24 unmodified lines | ||
| 38 | 38 | |
| 39 | 39 | const PORT = Number(Bun.env.PORT ?? 3000); |
| 40 | 40 | const EXECUTOR_URL = Bun.env.EXECUTOR_URL ?? "http://localhost:4001"; |
| 41 | +const CONVEX_URL = Bun.env.CONVEX_URL ?? "http://127.0.0.1:3210"; | |
| 41 | 42 | |
| 42 | 43 | const apiKey = getAnthropicApiKey(); |
| 43 | 44 | if (!apiKey) { |
| @@ -48,16 +49,26 @@ if (!apiKey) { · 4 unmodified lines | ||
| 48 | 49 | // Boot |
| 49 | 50 | // --------------------------------------------------------------------------- |
| 50 | 51 | |
| 51 | −const executor = createExecutorClient(EXECUTOR_URL); | |
| 52 | 52 | const model = createModel({ apiKey }); |
| 53 | 53 | |
| 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) { | |
| 57 | 62 | console.error("Failed to bootstrap executor context. Is the executor running at", EXECUTOR_URL, "?"); |
| 58 | 63 | process.exit(1); |
| 59 | 64 | } |
| 60 | 65 | |
| 66 | +const anonCtx = await bootstrapResp.json() as { | |
| 67 | + workspaceId: string; | |
| 68 | + actorId: string; | |
| 69 | + clientId: string; | |
| 70 | +}; | |
| 71 | + | |
| 61 | 72 | console.log(`[assistant] executor context: workspace=${anonCtx.workspaceId} actor=${anonCtx.actorId}`); |
| 62 | 73 | |
| 63 | 74 | // Build context string |
| @@ -66,11 +77,9 @@ if (Bun.env.POSTHOG_PROJECT_ID) { · 2 unmodified lines | ||
| 66 | 77 | contextLines.push(`- PostHog project ID: ${Bun.env.POSTHOG_PROJECT_ID}`); |
| 67 | 78 | } |
| 68 | 79 | |
| 69 | −const CONVEX_URL = Bun.env.CONVEX_URL ?? "http://127.0.0.1:3210"; | |
| 70 | − | |
| 71 | 80 | const app = createApp({ |
| 72 | − executor, | |
| 73 | − generate: (messages) => model.generate(messages), | |
| 81 | + executorUrl: EXECUTOR_URL, | |
| 82 | + generate: (messages, tools) => model.generate(messages, tools), | |
| 74 | 83 | workspaceId: anonCtx.workspaceId, |
| 75 | 84 | actorId: anonCtx.actorId, |
| 76 | 85 | clientId: anonCtx.clientId, |
| @@ -7,8 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | import { Elysia, t } from "elysia"; |
| 9 | 9 | 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"; | |
| 12 | 11 | import { ConvexHttpClient } from "convex/browser"; |
| 13 | 12 | import { api } from "@executor/convex/_generated/api"; |
| 14 | 13 | |
| @@ -17,8 +16,8 @@ import { api } from "@executor/convex/_generated/api"; · 2 unmodified lines | ||
| 17 | 16 | // --------------------------------------------------------------------------- |
| 18 | 17 | |
| 19 | 18 | 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>; | |
| 22 | 21 | readonly workspaceId: string; |
| 23 | 22 | readonly actorId: string; |
| 24 | 23 | readonly clientId?: string; |
| @@ -32,7 +31,7 @@ export interface ServerOptions { · 7 unmodified lines | ||
| 32 | 31 | |
| 33 | 32 | export function createApp(options: ServerOptions) { |
| 34 | 33 | const agent = createAgent({ |
| 35 | − executor: options.executor, | |
| 34 | + executorUrl: options.executorUrl, | |
| 36 | 35 | generate: options.generate, |
| 37 | 36 | workspaceId: options.workspaceId, |
| 38 | 37 | actorId: options.actorId, |
| @@ -68,18 +67,18 @@ export function createApp(options: ServerOptions) { · 29 unmodified lines | ||
| 68 | 67 | }); |
| 69 | 68 | |
| 70 | 69 | // Fire and forget — agent runs, writes results to Convex |
| 71 | − let codeRuns = 0; | |
| 70 | + let toolCalls = 0; | |
| 72 | 71 | |
| 73 | 72 | agent.run(body.prompt, (event: TaskEvent) => { |
| 74 | 73 | if (event.type === "code_result") { |
| 75 | − codeRuns++; | |
| 74 | + toolCalls++; | |
| 76 | 75 | } |
| 77 | 76 | |
| 78 | 77 | if (event.type === "agent_message") { |
| 79 | 78 | convex.mutation(api.database.updateAgentTask, { |
| 80 | 79 | agentTaskId, |
| 81 | 80 | resultText: event.text, |
| 82 | − codeRuns, | |
| 81 | + codeRuns: toolCalls, | |
| 83 | 82 | }).catch((err) => console.error(`[agent task ${agentTaskId}] convex write error:`, err)); |
| 84 | 83 | } |
| 85 | 84 | |
| @@ -87,7 +86,7 @@ export function createApp(options: ServerOptions) { · 1 unmodified line | ||
| 87 | 86 | convex.mutation(api.database.updateAgentTask, { |
| 88 | 87 | agentTaskId, |
| 89 | 88 | status: "completed", |
| 90 | − codeRuns, | |
| 89 | + codeRuns: toolCalls, | |
| 91 | 90 | }).catch((err) => console.error(`[agent task ${agentTaskId}] convex write error:`, err)); |
| 92 | 91 | } |
| 93 | 92 | |
| @@ -96,7 +95,7 @@ export function createApp(options: ServerOptions) { · 2 unmodified lines | ||
| 96 | 95 | agentTaskId, |
| 97 | 96 | status: "failed", |
| 98 | 97 | error: event.error, |
| 99 | − codeRuns, | |
| 98 | + codeRuns: toolCalls, | |
| 100 | 99 | }).catch((err) => console.error(`[agent task ${agentTaskId}] convex write error:`, err)); |
| 101 | 100 | } |
| 102 | 101 | }).catch((err) => { |
| @@ -105,7 +104,7 @@ export function createApp(options: ServerOptions) { · 2 unmodified lines | ||
| 105 | 104 | agentTaskId, |
| 106 | 105 | status: "failed", |
| 107 | 106 | error: err instanceof Error ? err.message : String(err), |
| 108 | − codeRuns, | |
| 107 | + codeRuns: toolCalls, | |
| 109 | 108 | }).catch((err2) => console.error(`[agent task ${agentTaskId}] convex write error:`, err2)); |
| 110 | 109 | }); |
| 111 | 110 | |
| @@ -50,9 +50,8 @@ · 49 unmodified lines | ||
| 50 | 50 | "assistant/packages/core": { |
| 51 | 51 | "name": "@assistant/core", |
| 52 | 52 | "dependencies": { |
| 53 | − "@assistant/agent-executor-adapter": "workspace:*", | |
| 54 | 53 | "@mariozechner/pi-ai": "^0.52.6", |
| 55 | − "@sinclair/typebox": "^0.34.48", | |
| 54 | + "@modelcontextprotocol/sdk": "^1.26.0", | |
| 56 | 55 | }, |
| 57 | 56 | "devDependencies": { |
| 58 | 57 | "@elysiajs/eden": "^1.4.6", |
| @@ -62,7 +61,6 @@ · 3 unmodified lines | ||
| 62 | 61 | "assistant/packages/server": { |
| 63 | 62 | "name": "@assistant/server", |
| 64 | 63 | "dependencies": { |
| 65 | − "@assistant/agent-executor-adapter": "workspace:*", | |
| 66 | 64 | "@assistant/core": "workspace:*", |
| 67 | 65 | "@elysiajs/eden": "latest", |
| 68 | 66 | "convex": "^1.31.7", |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | import { Elysia, t } from "elysia"; |
| 2 | 2 | import { ExecutorDatabase } from "./database"; |
| 3 | 3 | import { TaskEventHub } from "./events"; |
| 4 | −import { handleMcpRequest } from "./mcp-server"; | |
| 4 | +import { handleMcpRequest, type McpWorkspaceContext } from "./mcp-server"; | |
| 5 | 5 | import { LocalBunRuntime } from "./runtimes/local-bun-runtime"; |
| 6 | 6 | import { VercelSandboxRuntime } from "./runtimes/vercel-sandbox-runtime"; |
| 7 | 7 | import { ExecutorService, getTaskTerminalState } from "./service"; |
| @@ -151,6 +151,14 @@ function isInternalAuthorized(request: Request): boolean { · 143 unmodified lines | ||
| 151 | 151 | return header.slice("Bearer ".length) === internalToken; |
| 152 | 152 | } |
| 153 | 153 | |
| 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 | + | |
| 154 | 162 | // ── Elysia app ── |
| 155 | 163 | |
| 156 | 164 | const app = new Elysia() |
| @@ -163,9 +171,23 @@ const app = new Elysia() · 6 unmodified lines | ||
| 163 | 171 | .options("/*", () => new Response(null, { status: 204 })) |
| 164 | 172 | |
| 165 | 173 | // ── 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 | + }) | |
| 169 | 191 | |
| 170 | 192 | // ── Health ── |
| 171 | 193 | .get("/api/health", () => ({ |
| @@ -262,53 +284,6 @@ const app = new Elysia() · 90 unmodified lines | ||
| 262 | 284 | query: t.Object({ workspaceId: t.String() }), |
| 263 | 285 | }) |
| 264 | 286 | |
| 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 | − | |
| 312 | 287 | // ── Tasks ── |
| 313 | 288 | .get("/api/tasks", async ({ query, set }) => { |
| 314 | 289 | if (!query.workspaceId) { |
| @@ -2,7 +2,7 @@ import { expect, test } from "bun:test"; · 1 unmodified line | ||
| 2 | 2 | import { Client } from "@modelcontextprotocol/sdk/client/index.js"; |
| 3 | 3 | import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; |
| 4 | 4 | import { handleMcpRequest } from "./mcp-server"; |
| 5 | −import type { AnonymousContext, CreateTaskInput, TaskRecord } from "./types"; | |
| 5 | +import type { AnonymousContext, CreateTaskInput, TaskRecord, ToolDescriptor } from "./types"; | |
| 6 | 6 | |
| 7 | 7 | class FakeMcpService { |
| 8 | 8 | private readonly tasks = new Map<string, TaskRecord>(); |
| @@ -71,6 +71,12 @@ class FakeMcpService { · 62 unmodified lines | ||
| 71 | 71 | this.sessions.set(context.sessionId, context); |
| 72 | 72 | return context; |
| 73 | 73 | } |
| 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 | + } | |
| 74 | 80 | } |
| 75 | 81 | |
| 76 | 82 | async function withMcpClient<T>( |
| @@ -2,39 +2,32 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; · 1 unmodified line | ||
| 2 | 2 | import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js"; |
| 3 | 3 | import { z } from "zod"; |
| 4 | 4 | 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 | +// --------------------------------------------------------------------------- | |
| 6 | 10 | |
| 7 | 11 | interface McpExecutorService { |
| 8 | 12 | createTask(input: CreateTaskInput): Promise<{ task: TaskRecord }>; |
| 9 | 13 | getTask(taskId: string, workspaceId?: string): Promise<TaskRecord | null>; |
| 10 | 14 | bootstrapAnonymousContext(sessionId?: string): Promise<AnonymousContext>; |
| 15 | + listTools(context?: { workspaceId: string; actorId?: string; clientId?: string }): Promise<ToolDescriptor[]>; | |
| 11 | 16 | } |
| 12 | 17 | |
| 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 | +// --------------------------------------------------------------------------- | |
| 25 | 21 | |
| 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; | |
| 33 | 25 | clientId?: string; |
| 34 | − sessionId?: string; | |
| 35 | − waitForResult?: boolean; | |
| 36 | − resultTimeoutMs?: number; | |
| 37 | −}; | |
| 26 | +} | |
| 27 | + | |
| 28 | +// --------------------------------------------------------------------------- | |
| 29 | +// Helpers | |
| 30 | +// --------------------------------------------------------------------------- | |
| 38 | 31 | |
| 39 | 32 | function asCodeBlock(language: string, value: string): string { |
| 40 | 33 | return `\n\n\`\`\`${language}\n${value}\n\`\`\``; |
| @@ -78,54 +71,82 @@ async function waitForTerminalTask( · 37 unmodified lines | ||
| 78 | 71 | const deadline = Date.now() + waitTimeoutMs; |
| 79 | 72 | while (Date.now() < deadline) { |
| 80 | 73 | 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; | |
| 87 | 76 | await Bun.sleep(300); |
| 88 | 77 | } |
| 89 | 78 | return await service.getTask(taskId, workspaceId); |
| 90 | 79 | } |
| 91 | 80 | |
| 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 | +// --------------------------------------------------------------------------- | |
| 108 | 84 | |
| 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")}`; | |
| 117 | 99 | } |
| 118 | 100 | |
| 119 | −function createRunCodeTool(service: McpExecutorService) { | |
| 101 | +// --------------------------------------------------------------------------- | |
| 102 | +// run_code tool handler | |
| 103 | +// --------------------------------------------------------------------------- | |
| 104 | + | |
| 105 | +function createRunCodeTool( | |
| 106 | + service: McpExecutorService, | |
| 107 | + boundContext?: McpWorkspaceContext, | |
| 108 | +) { | |
| 120 | 109 | 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 | + }, | |
| 122 | 122 | extra: { sessionId?: string }, |
| 123 | 123 | ): Promise<{ |
| 124 | 124 | content: Array<{ type: "text"; text: string }>; |
| 125 | 125 | structuredContent?: Record<string, unknown>; |
| 126 | 126 | isError?: boolean; |
| 127 | 127 | }> => { |
| 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 | + } | |
| 129 | 150 | |
| 130 | 151 | const created = await service.createTask({ |
| 131 | 152 | code: input.code, |
| @@ -164,13 +185,7 @@ function createRunCodeTool(service: McpExecutorService) { · 32 unmodified lines | ||
| 164 | 185 | if (!getTaskTerminalState(task.status)) { |
| 165 | 186 | return { |
| 166 | 187 | 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 }, | |
| 174 | 189 | }; |
| 175 | 190 | } |
| 176 | 191 | |
| @@ -194,31 +209,79 @@ function createRunCodeTool(service: McpExecutorService) { · 17 unmodified lines | ||
| 194 | 209 | }; |
| 195 | 210 | } |
| 196 | 211 | |
| 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> { | |
| 198 | 244 | const mcp = new McpServer( |
| 199 | 245 | { name: "executor", version: "0.1.0" }, |
| 200 | 246 | { capabilities: { tools: {} } }, |
| 201 | 247 | ); |
| 202 | 248 | |
| 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 | + | |
| 203 | 259 | mcp.registerTool( |
| 204 | 260 | "run_code", |
| 205 | 261 | { |
| 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, | |
| 209 | 264 | }, |
| 210 | − createRunCodeTool(service), | |
| 265 | + createRunCodeTool(service, context), | |
| 211 | 266 | ); |
| 212 | 267 | |
| 213 | 268 | return mcp; |
| 214 | 269 | } |
| 215 | 270 | |
| 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> { | |
| 217 | 280 | const transport = new WebStandardStreamableHTTPServerTransport({ |
| 218 | 281 | sessionIdGenerator: undefined, |
| 219 | 282 | enableJsonResponse: true, |
| 220 | 283 | }); |
| 221 | − const mcp = createMcpServer(service); | |
| 284 | + const mcp = await createMcpServer(service, context); | |
| 222 | 285 | |
| 223 | 286 | try { |
| 224 | 287 | await mcp.connect(transport); |