diff --git a/app/components/landing-hero.tsx b/app/components/landing-hero.tsx index a725534..58c8523 100644 --- a/app/components/landing-hero.tsx +++ b/app/components/landing-hero.tsx @@ -1,9 +1,48 @@ 'use client' -import { motion } from 'framer-motion' +import { useGSAP } from '@gsap/react' +import { gsap } from 'gsap' +import { ScrollTrigger } from 'gsap/ScrollTrigger' +import { useRef } from 'react' import { NetworkBackground } from './network-background' +gsap.registerPlugin(ScrollTrigger) + export function LandingHero() { + const heroRef = useRef(null) + + useGSAP(() => { + const tl = gsap.timeline() + + // Stagger entrance animation for child elements + tl.fromTo( + '.hero-element', + { opacity: 0, y: 20 }, + { + opacity: 1, + y: 0, + duration: 0.6, + ease: 'power2.out', + stagger: 0.1, + } + ) + + // Add ScrollTrigger for parallax effect + ScrollTrigger.create({ + trigger: heroRef.current, + start: 'top bottom', + end: 'bottom top', + scrub: 1, + onUpdate: (self) => { + const progress = self.progress + gsap.set(heroRef.current, { + y: -progress * 50, // Parallax effect + scale: 1 + progress * 0.05, // Slight zoom + }) + }, + }) + }) + return (
{/* Interactive System Visualization */} @@ -14,20 +53,15 @@ export function LandingHero() {
{/* Main Content */} - -
+
+
SYSTEM OPERATIONAL
-

+

Agent Orchestration
@@ -35,19 +69,19 @@ export function LandingHero() {

-

+

Visualizing real-time agent interactions. Hover over the nodes to interact with the neural network.

-
+
Live Simulation
- +
) diff --git a/package-lock.json b/package-lock.json index 87856ca..b41aed8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,44 +1,44 @@ { "name": "agentstack", - "version": "1.1.2", + "version": "1.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "agentstack", - "version": "1.1.2", + "version": "1.1.3", "license": "ISC", "dependencies": { - "@ai-sdk/google": "^3.0.9", - "@ai-sdk/google-vertex": "^4.0.16", - "@ai-sdk/openai": "^3.0.11", - "@ai-sdk/openai-compatible": "^2.0.11", - "@ai-sdk/react": "^3.0.39", + "@ai-sdk/google": "^3.0.10", + "@ai-sdk/google-vertex": "^4.0.17", + "@ai-sdk/openai": "^3.0.12", + "@ai-sdk/openai-compatible": "^2.0.13", + "@ai-sdk/react": "^3.0.40", "@dotenvx/dotenvx": "^1.51.4", "@e2b/code-interpreter": "^2.3.3", "@emotion/react": "^11.14.0", "@gsap/react": "^2.1.2", - "@mastra/ai-sdk": "^1.0.0-beta.14", + "@mastra/ai-sdk": "^1.0.0-beta.15", "@mastra/auth-supabase": "^1.0.0-beta.1", - "@mastra/client-js": "^1.0.0-beta.21", - "@mastra/cloudflare-d1": "^1.0.0-beta.9", + "@mastra/client-js": "^1.0.0-beta.22", + "@mastra/cloudflare-d1": "^1.0.0-beta.10", "@mastra/convex": "^0.1.0-beta.8", - "@mastra/core": "^1.0.0-beta.21", - "@mastra/deployer": "^1.0.0-beta.21", - "@mastra/evals": "^1.0.0-beta.4", - "@mastra/lance": "^1.0.0-beta.10", - "@mastra/libsql": "^1.0.0-beta.11", + "@mastra/core": "^1.0.0-beta.22", + "@mastra/deployer": "^1.0.0-beta.22", + "@mastra/evals": "^1.0.0-beta.5", + "@mastra/lance": "^1.0.0-beta.11", + "@mastra/libsql": "^1.0.0-beta.12", "@mastra/loggers": "^1.0.0-beta.4", - "@mastra/mcp": "^1.0.0-beta.9", - "@mastra/memory": "^1.0.0-beta.12", - "@mastra/mongodb": "^1.0.0-beta.11", - "@mastra/observability": "^1.0.0-beta.10", + "@mastra/mcp": "^1.0.0-beta.10", + "@mastra/memory": "^1.0.0-beta.13", + "@mastra/mongodb": "^1.0.0-beta.12", + "@mastra/observability": "^1.0.0-beta.11", "@mastra/otel-bridge": "^1.0.0-beta.11", - "@mastra/pg": "^1.0.0-beta.12", - "@mastra/qdrant": "^1.0.0-beta.3", - "@mastra/rag": "^2.0.0-beta.6", - "@mastra/react": "^0.1.0-beta.21", - "@mastra/upstash": "^1.0.0-beta.10", + "@mastra/pg": "^1.0.0-beta.13", + "@mastra/qdrant": "^1.0.0-beta.4", + "@mastra/rag": "^2.0.0-beta.7", + "@mastra/react": "^0.1.0-beta.22", + "@mastra/upstash": "^1.0.0-beta.11", "@mastra/vectorize": "^1.0.0-beta.3", "@mastra/voice-google": "^0.12.0-beta.2", "@mastra/voice-openai": "^0.12.0-beta.2", @@ -68,16 +68,16 @@ "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tooltip": "^1.2.8", "@radix-ui/react-use-controllable-state": "^1.2.2", - "@tanstack/react-query": "^5.90.17", + "@tanstack/react-query": "^5.90.18", "@tanstack/react-query-devtools": "^5.91.2", "@tanstack/react-table": "^8.21.3", "@tslab/typescript-for-tslab": "^5.1.3", "@vercel/otel": "^2.1.0", + "@xterm/xterm": "^6.0.0", "@xyflow/react": "^12.10.0", "a2a-ai-provider": "^0.4.0-alpha.2", - "ai": "^6.0.37", + "ai": "^6.0.38", "ai-sdk-ollama": "^3.1.1", - "ai-sdk-provider-claude-code": "^3.2.1", "ai-sdk-provider-gemini-cli": "^2.0.1", "ai-sdk-provider-opencode-sdk": "^1.0.0", "arraystat": "^1.7.81", @@ -205,7 +205,7 @@ "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.26", "ink-testing-library": "^4.0.0", - "mastra": "^1.0.0-beta.14", + "mastra": "^1.0.0-beta.15", "prettier": "^3.8.0", "tailwindcss": "^4.1.18", "tw-animate-css": "^1.4.0", @@ -257,13 +257,13 @@ } }, "node_modules/@ai-sdk/anthropic": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-3.0.14.tgz", - "integrity": "sha512-71BaVg60FM6tN0JaRY7kRb/6qZtHi5R9PFF3NES+kqonY3nVD4PCPP8DoMb/tqxC7f/XezlCqsHrveT2mGfi3A==", + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-3.0.15.tgz", + "integrity": "sha512-FCNy6pABPe5Qb1VPbdLLIi/XkQN2g/fKUcl1GcXxIU3Ofr+vOND8cyZfH20cMODR523FSGfwswJoJic8skr8qg==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.3", - "@ai-sdk/provider-utils": "4.0.7" + "@ai-sdk/provider": "3.0.4", + "@ai-sdk/provider-utils": "4.0.8" }, "engines": { "node": ">=18" @@ -273,13 +273,13 @@ } }, "node_modules/@ai-sdk/gateway": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.15.tgz", - "integrity": "sha512-OsWcXMfkF9U38YhU7926rYt4IAtJuZlnM1e8STN8hHb4qbiTaORBSXcFaJuOEZ1kYOf3DqqP7CxbmM543ePzIg==", + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.16.tgz", + "integrity": "sha512-OOY5CfRJiHvh/8np2vs1RQaCZ5hWv2qOeEmmeiABXK3gLQHUVnCO+1hhoLsZdHM5iElu6M407dAOfyvTsKJqcQ==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.3", - "@ai-sdk/provider-utils": "4.0.7", + "@ai-sdk/provider": "3.0.4", + "@ai-sdk/provider-utils": "4.0.8", "@vercel/oidc": "3.1.0" }, "engines": { @@ -290,13 +290,13 @@ } }, "node_modules/@ai-sdk/google": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@ai-sdk/google/-/google-3.0.9.tgz", - "integrity": "sha512-whRdK0gCZL92UbEHdmQ6edm3cp5ZZSqwE79AIvTEaJR+BeaMUJchTxz/I5w9l3EHGOiDxrKYssklqO3z45KGXg==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@ai-sdk/google/-/google-3.0.10.tgz", + "integrity": "sha512-qd2EM9SlD7wWFrq036hwKsuAgkCVxQbwJzctszdmzPs9yUZg795/gHtZRpKItZhbyHSNWhAHmJwEgKjD+HOzuQ==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.3", - "@ai-sdk/provider-utils": "4.0.7" + "@ai-sdk/provider": "3.0.4", + "@ai-sdk/provider-utils": "4.0.8" }, "engines": { "node": ">=18" @@ -306,15 +306,15 @@ } }, "node_modules/@ai-sdk/google-vertex": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@ai-sdk/google-vertex/-/google-vertex-4.0.16.tgz", - "integrity": "sha512-paY4NGCaqMbd0kssK27ssTMggDybNPIFudJ99QsdzRDJ/Kgo0EjeXZn7G/CoBY/Snmf0fA0PEZW34yV9kloFCQ==", + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@ai-sdk/google-vertex/-/google-vertex-4.0.17.tgz", + "integrity": "sha512-+I1tXUD1N250WepVfChUPQcLq0t2ph98AEqRlX5tpHCEoEyquB4EpOxX/6LA3qowvVcYmgNqxOANFwz5dQrXag==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/anthropic": "3.0.14", - "@ai-sdk/google": "3.0.9", - "@ai-sdk/provider": "3.0.3", - "@ai-sdk/provider-utils": "4.0.7", + "@ai-sdk/anthropic": "3.0.15", + "@ai-sdk/google": "3.0.10", + "@ai-sdk/provider": "3.0.4", + "@ai-sdk/provider-utils": "4.0.8", "google-auth-library": "^10.5.0" }, "engines": { @@ -325,13 +325,13 @@ } }, "node_modules/@ai-sdk/openai": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-3.0.11.tgz", - "integrity": "sha512-nX7Egt9EJtvImiq1D88sZCOlfAIJgKJGa987ptp40hJRp7CQ4snBLnEHt344m2tqB0LIpzdc53l02o+LlYsM2A==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-3.0.12.tgz", + "integrity": "sha512-zqLWEKuaKnjXhu7xCw1jgz/+yTbd3F7EtgU4T2Q8BAo8OJC5wZv14l+kwM7Jai7M1/2Y2T/zBkrfiIu+7NsvfQ==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.3", - "@ai-sdk/provider-utils": "4.0.7" + "@ai-sdk/provider": "3.0.4", + "@ai-sdk/provider-utils": "4.0.8" }, "engines": { "node": ">=18" @@ -341,13 +341,13 @@ } }, "node_modules/@ai-sdk/openai-compatible": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@ai-sdk/openai-compatible/-/openai-compatible-2.0.11.tgz", - "integrity": "sha512-6rbJyCs9m/jDSe9UuDXJ2gWaETzGXdJmnoi49sbW63r1DcHISkY/rkImG7ISnoE+GUw3DjqVzQ/2ELELTu5w8w==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai-compatible/-/openai-compatible-2.0.13.tgz", + "integrity": "sha512-DShpuHZ9wiy3QtxJ4/Uq5csLxgNgeA3w58isYhZ34pSod2cBlRmJl3EyQzxZ1HD8e6sQDa9fvc0cwF5/EugBMw==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.3", - "@ai-sdk/provider-utils": "4.0.7" + "@ai-sdk/provider": "3.0.4", + "@ai-sdk/provider-utils": "4.0.8" }, "engines": { "node": ">=18" @@ -357,9 +357,9 @@ } }, "node_modules/@ai-sdk/provider": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.3.tgz", - "integrity": "sha512-qGPYdoAuECaUXPrrz0BPX1SacZQuJ6zky0aakxpW89QW1hrY0eF4gcFm/3L9Pk8C5Fwe+RvBf2z7ZjDhaPjnlg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.4.tgz", + "integrity": "sha512-5KXyBOSEX+l67elrEa+wqo/LSsSTtrPj9Uoh3zMbe/ceQX4ucHI3b9nUEfNkGF3Ry1svv90widAt+aiKdIJasQ==", "license": "Apache-2.0", "dependencies": { "json-schema": "^0.4.0" @@ -369,12 +369,12 @@ } }, "node_modules/@ai-sdk/provider-utils": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.7.tgz", - "integrity": "sha512-ItzTdBxRLieGz1GHPwl9X3+HKfwTfFd9MdIa91aXRnOjUVRw68ENjAGKm3FcXGsBLkXDLaFWgjbTVdXe2igs2w==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.8.tgz", + "integrity": "sha512-ns9gN7MmpI8vTRandzgz+KK/zNMLzhrriiKECMt4euLtQFSBgNfydtagPOX4j4pS1/3KvHF6RivhT3gNQgBZsg==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.3", + "@ai-sdk/provider": "3.0.4", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, @@ -472,13 +472,13 @@ } }, "node_modules/@ai-sdk/react": { - "version": "3.0.39", - "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-3.0.39.tgz", - "integrity": "sha512-Q/39hAazwxItCbqEDWC4pa3+HXLVvTzeu/zu7ghANqRNCxzmqBb/GYEIU/wiYNRS05hP6R1l9bA9S4U6sx0iTA==", + "version": "3.0.40", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-3.0.40.tgz", + "integrity": "sha512-I/GUogzjduEtp7g3ZNvxjVCmR5KFRKzfjKM6X/aShQcKFYiAmzmUZexvQ9jX5TJxhuQwk65xJmtmU2iYcWRjRw==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider-utils": "4.0.7", - "ai": "6.0.37", + "@ai-sdk/provider-utils": "4.0.8", + "ai": "6.0.38", "swr": "^2.2.5", "throttleit": "2.1.0" }, @@ -515,28 +515,6 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/@anthropic-ai/claude-agent-sdk": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.2.5.tgz", - "integrity": "sha512-KWD8b+qPSlhMc9Znh4WDnftVj5eAmzEabr54hWKEZC33curAjtsmLItjrZhjPpGMJjIvb04ucbXZ8Om9kzjGiw==", - "license": "SEE LICENSE IN README.md", - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "^0.33.5", - "@img/sharp-darwin-x64": "^0.33.5", - "@img/sharp-linux-arm": "^0.33.5", - "@img/sharp-linux-arm64": "^0.33.5", - "@img/sharp-linux-x64": "^0.33.5", - "@img/sharp-linuxmusl-arm64": "^0.33.5", - "@img/sharp-linuxmusl-x64": "^0.33.5", - "@img/sharp-win32-x64": "^0.33.5" - }, - "peerDependencies": { - "zod": "^4.0.0" - } - }, "node_modules/@apidevtools/json-schema-ref-parser": { "version": "14.2.1", "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-14.2.1.tgz", @@ -4625,114 +4603,6 @@ "node": ">=18" } }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, "node_modules/@img/sharp-libvips-linux-ppc64": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", @@ -4781,98 +4651,6 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" - } - }, "node_modules/@img/sharp-linux-ppc64": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", @@ -4939,72 +4717,6 @@ "@img/sharp-libvips-linux-s390x": "1.2.4" } }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" - } - }, "node_modules/@img/sharp-wasm32": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", @@ -5062,25 +4774,6 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, "node_modules/@inquirer/external-editor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", @@ -5936,9 +5629,9 @@ ] }, "node_modules/@mastra/ai-sdk": { - "version": "1.0.0-beta.14", - "resolved": "https://registry.npmjs.org/@mastra/ai-sdk/-/ai-sdk-1.0.0-beta.14.tgz", - "integrity": "sha512-KlQv3cVzzzNMfiJGjFQFF5xgeAnczEKuY/thdGomkisTlDva1a3jbGZahGj3nCTvBowlP32UFJU4rUcDoBzdcg==", + "version": "1.0.0-beta.15", + "resolved": "https://registry.npmjs.org/@mastra/ai-sdk/-/ai-sdk-1.0.0-beta.15.tgz", + "integrity": "sha512-A4iXuakYNRpYK213HoC6L2aOfciHyEU2NBSyHwOv+IXp9l94jNto+/H0DXtV9+wqWH0ZLNHhg89ogZScm4olyQ==", "license": "Apache-2.0", "engines": { "node": ">=22.13.0" @@ -5961,13 +5654,13 @@ } }, "node_modules/@mastra/client-js": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@mastra/client-js/-/client-js-1.0.0-beta.21.tgz", - "integrity": "sha512-c75S/V8TeuLPSfC5kzPCeGbnHIzbCCN8Z9Iesx+P5oX8zR1WglMhE2Yn5uJrc11gp0KcJnBc1Y1dn0AcHL2maA==", + "version": "1.0.0-beta.22", + "resolved": "https://registry.npmjs.org/@mastra/client-js/-/client-js-1.0.0-beta.22.tgz", + "integrity": "sha512-Yw8kSvqVCRweGmvZVf7WMDySrBXhkOH7NkkSn7DfT2hiJTyzGamr9gtJ6nZmE2sx/G8oQSkIG+x0RYSaE8dbJw==", "license": "Apache-2.0", "dependencies": { "@lukeed/uuid": "^2.0.1", - "@mastra/core": "1.0.0-beta.21", + "@mastra/core": "1.0.0-beta.22", "@mastra/schema-compat": "1.0.0-beta.6", "json-schema": "^0.4.0" }, @@ -5979,9 +5672,9 @@ } }, "node_modules/@mastra/cloudflare-d1": { - "version": "1.0.0-beta.9", - "resolved": "https://registry.npmjs.org/@mastra/cloudflare-d1/-/cloudflare-d1-1.0.0-beta.9.tgz", - "integrity": "sha512-llk1ImFCOC1CFowdJWGDNcAHOkh5EyubnuvI1rP8oRjjrRGXzKW5j6FMEslDkR8hNBeYhCoKTgkuRlnq1JTVkw==", + "version": "1.0.0-beta.10", + "resolved": "https://registry.npmjs.org/@mastra/cloudflare-d1/-/cloudflare-d1-1.0.0-beta.10.tgz", + "integrity": "sha512-0g4lwlKaTPernjEPpTyRQ0wXYqqNA8br+a6b9e0xAmFgHSR1sXo37p548WsOl8OWofhEqq9TT2tBo8nnv4lNpA==", "dependencies": { "cloudflare": "^4.5.0" }, @@ -6008,9 +5701,9 @@ } }, "node_modules/@mastra/core": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@mastra/core/-/core-1.0.0-beta.21.tgz", - "integrity": "sha512-JSZkquAuHleyOUBPTHr1BUu+KQOju7K3ovl2oFCO99oQ3DStszp/gxz4Z6qcU52Xt7O6nzjZjIpcAKdQ6Yjw1A==", + "version": "1.0.0-beta.22", + "resolved": "https://registry.npmjs.org/@mastra/core/-/core-1.0.0-beta.22.tgz", + "integrity": "sha512-+aZopeOiMCGhnRfWVmmgVubrVG+sZcAR12YEkZNUxYfGOJGoVD/F5agoEwlUKtVCFNU8wacYgVCpR0LdBgEpUg==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -6179,14 +5872,14 @@ "license": "BSD-3-Clause" }, "node_modules/@mastra/deployer": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@mastra/deployer/-/deployer-1.0.0-beta.21.tgz", - "integrity": "sha512-qtqS8+aATA1L/dsZIOZN00JzDCiikhP1RyS3aiNw1R9KCd1F4waChj3SsNW5ItZY+dXKq5F4AvclMVX/VMQxgA==", + "version": "1.0.0-beta.22", + "resolved": "https://registry.npmjs.org/@mastra/deployer/-/deployer-1.0.0-beta.22.tgz", + "integrity": "sha512-5xMpKLNmBiabgnaAhJAskgB+FH8Ig5HyE84lZQwSqObSNP77ijxmHIPDFrE2V7YqdR0u95BA8o2Rq2UEXfYqPw==", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.28.5", "@babel/preset-typescript": "^7.27.1", - "@mastra/server": "1.0.0-beta.21", + "@mastra/server": "1.0.0-beta.22", "@optimize-lodash/rollup-plugin": "^5.0.2", "@rollup/plugin-alias": "6.0.0", "@rollup/plugin-commonjs": "29.0.0", @@ -6218,9 +5911,9 @@ } }, "node_modules/@mastra/evals": { - "version": "1.0.0-beta.4", - "resolved": "https://registry.npmjs.org/@mastra/evals/-/evals-1.0.0-beta.4.tgz", - "integrity": "sha512-z6fA59jV3zxW85gdVlZIeomXPO73V+o0NK4fV4AYwtJrdAkQBTGrynS+aU1TpYhcW06HDXaoZ7YikinCE1mUlQ==", + "version": "1.0.0-beta.5", + "resolved": "https://registry.npmjs.org/@mastra/evals/-/evals-1.0.0-beta.5.tgz", + "integrity": "sha512-bbGJ4BTRKn5dbjqHyi2tVo36P7cYrvIFkW0dL+o/hFY9GqNbx9FcBrTBgr24JFpFfpY67bHCEuQWUxSM8vpogQ==", "license": "Apache-2.0", "dependencies": { "compromise": "^14.14.4", @@ -6237,9 +5930,9 @@ } }, "node_modules/@mastra/lance": { - "version": "1.0.0-beta.10", - "resolved": "https://registry.npmjs.org/@mastra/lance/-/lance-1.0.0-beta.10.tgz", - "integrity": "sha512-JEgHhomppf9uc1xWCIiMIlf0K4Hwu4DS7NtBMq41rZQbqFnIhffa/S10neGzljZqn3AwHuZ3tODKNahdhptd3w==", + "version": "1.0.0-beta.11", + "resolved": "https://registry.npmjs.org/@mastra/lance/-/lance-1.0.0-beta.11.tgz", + "integrity": "sha512-sR3UXdrUXhlchE4gHvWpTq8IpRhyy5BZOYwVvFjXteHFQr8m9DYFiMm1T++6B0PdK3JKUgB5ItFQsoWPslQmoQ==", "dependencies": { "@lancedb/lancedb": "^0.22.3", "apache-arrow": "^18.1.0" @@ -6252,9 +5945,9 @@ } }, "node_modules/@mastra/libsql": { - "version": "1.0.0-beta.11", - "resolved": "https://registry.npmjs.org/@mastra/libsql/-/libsql-1.0.0-beta.11.tgz", - "integrity": "sha512-GLwS57q7lnbjpes3WzWwD/TTpOMRUi9MDkdPYQ1BAAEa7j39RGxS06TXPamy7T/7xN6zqliZbAkRs1TKQCNHiQ==", + "version": "1.0.0-beta.12", + "resolved": "https://registry.npmjs.org/@mastra/libsql/-/libsql-1.0.0-beta.12.tgz", + "integrity": "sha512-umdBxRACu0TckTy/J/JZ1Bvrzg4S+q8KGDIXWLe0KRl8izniiEWP9JG+C3zCLijExaaqA/iw6WC8xVnwRxvnIA==", "license": "Apache-2.0", "dependencies": { "@libsql/client": "^0.15.15" @@ -6283,9 +5976,9 @@ } }, "node_modules/@mastra/mcp": { - "version": "1.0.0-beta.9", - "resolved": "https://registry.npmjs.org/@mastra/mcp/-/mcp-1.0.0-beta.9.tgz", - "integrity": "sha512-wM3INUhYHSeAUNfI8J/INSLnOB07nAaYZqZU0o5USyaHx/ZQMnHhI7DGBUn1RJOady4NarnEy9+g5cbxnkd91g==", + "version": "1.0.0-beta.10", + "resolved": "https://registry.npmjs.org/@mastra/mcp/-/mcp-1.0.0-beta.10.tgz", + "integrity": "sha512-evf2z2OCk0lfO8KD07NOFAim4X9Lpy7CYrC5JeJFi5ryaOMVPA1LtWkEUgpOnAPYnhLm2M/mpVKV3a3OBVKrlQ==", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^14.2.1", @@ -6318,9 +6011,9 @@ } }, "node_modules/@mastra/memory": { - "version": "1.0.0-beta.12", - "resolved": "https://registry.npmjs.org/@mastra/memory/-/memory-1.0.0-beta.12.tgz", - "integrity": "sha512-BCL1u+mJnWgRbZdJRDntj4UcmRyTfjCb2qct/olgbFBl1nYYhuld6aK8dQgYS1QcGTOxDD/SIogs76BMfa0uyQ==", + "version": "1.0.0-beta.13", + "resolved": "https://registry.npmjs.org/@mastra/memory/-/memory-1.0.0-beta.13.tgz", + "integrity": "sha512-oFbT53z3UC+twhcHpKkgGfDwN0ikLJZhMHbwOK1YkLVolE6vn1brIDbLi1SHzDYz8ALw/a9K5dvgUZ9UVAh1PA==", "license": "Apache-2.0", "dependencies": { "@mastra/schema-compat": "1.0.0-beta.6", @@ -6339,9 +6032,9 @@ } }, "node_modules/@mastra/mongodb": { - "version": "1.0.0-beta.11", - "resolved": "https://registry.npmjs.org/@mastra/mongodb/-/mongodb-1.0.0-beta.11.tgz", - "integrity": "sha512-gVhCaPGg5bXv8O35jAMxzXZVXpbTzjuT+46tHviTjlFdJu/1T1d0DHjBn3vU1MSZCNzdRDuMUCwGYrVj/5dX3A==", + "version": "1.0.0-beta.12", + "resolved": "https://registry.npmjs.org/@mastra/mongodb/-/mongodb-1.0.0-beta.12.tgz", + "integrity": "sha512-fZE1ovARfqkGCRn4a/cfSlKGpOSRnqUoHisN/4PtPtUIEm1pzLIQIZyYEOW4+VESRW0y/DPPI6WXM+8P3nHjtA==", "dependencies": { "@types/mongodb": "^4.0.7", "cloudflare": "^4.5.0", @@ -6369,9 +6062,9 @@ } }, "node_modules/@mastra/observability": { - "version": "1.0.0-beta.10", - "resolved": "https://registry.npmjs.org/@mastra/observability/-/observability-1.0.0-beta.10.tgz", - "integrity": "sha512-uaVEupKgLYiiOtx5xASl4zPqEaqqkbI6dzwMUP05RaaMXTHqvD3X5+uVyrtL04PgXjVv1GNxPw9UxMYFUDGutg==", + "version": "1.0.0-beta.11", + "resolved": "https://registry.npmjs.org/@mastra/observability/-/observability-1.0.0-beta.11.tgz", + "integrity": "sha512-zhmqnMnbYvfbNoMZ5RqugLP7RvcsIyb6kNYE0xrzI8EjBZN4xXlz0REyuisZmOUYDqwQ0/eplG8CiCTUntawdQ==", "license": "Apache-2.0", "engines": { "node": ">=22.13.0" @@ -6407,6 +6100,18 @@ } } }, + "node_modules/@mastra/otel-bridge/node_modules/@mastra/observability": { + "version": "1.0.0-beta.10", + "resolved": "https://registry.npmjs.org/@mastra/observability/-/observability-1.0.0-beta.10.tgz", + "integrity": "sha512-uaVEupKgLYiiOtx5xASl4zPqEaqqkbI6dzwMUP05RaaMXTHqvD3X5+uVyrtL04PgXjVv1GNxPw9UxMYFUDGutg==", + "license": "Apache-2.0", + "engines": { + "node": ">=22.13.0" + }, + "peerDependencies": { + "@mastra/core": ">=1.0.0-0 <2.0.0-0" + } + }, "node_modules/@mastra/otel-exporter": { "version": "1.0.0-beta.12", "resolved": "https://registry.npmjs.org/@mastra/otel-exporter/-/otel-exporter-1.0.0-beta.12.tgz", @@ -6457,6 +6162,18 @@ } } }, + "node_modules/@mastra/otel-exporter/node_modules/@mastra/observability": { + "version": "1.0.0-beta.10", + "resolved": "https://registry.npmjs.org/@mastra/observability/-/observability-1.0.0-beta.10.tgz", + "integrity": "sha512-uaVEupKgLYiiOtx5xASl4zPqEaqqkbI6dzwMUP05RaaMXTHqvD3X5+uVyrtL04PgXjVv1GNxPw9UxMYFUDGutg==", + "license": "Apache-2.0", + "engines": { + "node": ">=22.13.0" + }, + "peerDependencies": { + "@mastra/core": ">=1.0.0-0 <2.0.0-0" + } + }, "node_modules/@mastra/otel-exporter/node_modules/@opentelemetry/core": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", @@ -6526,9 +6243,9 @@ } }, "node_modules/@mastra/pg": { - "version": "1.0.0-beta.12", - "resolved": "https://registry.npmjs.org/@mastra/pg/-/pg-1.0.0-beta.12.tgz", - "integrity": "sha512-rmAgq/qS8pfogK+kwYty46InHoAZu8qj4jseRIfIMz932sbAvRqIp2JdI0TQ3b17MrfO73XZKqsRfqpJGpjH2w==", + "version": "1.0.0-beta.13", + "resolved": "https://registry.npmjs.org/@mastra/pg/-/pg-1.0.0-beta.13.tgz", + "integrity": "sha512-SmMJBMV0q6dbi6Gzmy831Yyg03WxU+RvsIbVBlk0rrq4hbWerKWJCBL3iwdf3rndCdf0Lr7nR/9T0cKzn3wfng==", "license": "Apache-2.0", "dependencies": { "async-mutex": "^0.5.0", @@ -6543,9 +6260,9 @@ } }, "node_modules/@mastra/qdrant": { - "version": "1.0.0-beta.3", - "resolved": "https://registry.npmjs.org/@mastra/qdrant/-/qdrant-1.0.0-beta.3.tgz", - "integrity": "sha512-ICBcB1ZTrLgs4zf5xV2FfH9T6yzoxNHA5KqS32KXKfq38eR4qL7ImHpkTAzvROuqiGi2SLLEUZUVveIavUnNMw==", + "version": "1.0.0-beta.4", + "resolved": "https://registry.npmjs.org/@mastra/qdrant/-/qdrant-1.0.0-beta.4.tgz", + "integrity": "sha512-QeiFDOjab9hOFJY2KyBza2xmfHmdsNOi1zAuqSGIOvFVesVDtqp56IgggLpgQiVjhkAi/0L1JB6beEfRIyuYQg==", "license": "Apache-2.0", "dependencies": { "@qdrant/js-client-rest": "^1.15.1" @@ -6558,9 +6275,9 @@ } }, "node_modules/@mastra/rag": { - "version": "2.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@mastra/rag/-/rag-2.0.0-beta.6.tgz", - "integrity": "sha512-DR2JbEgNXTBVBBmj1RcrKSyn9rSY5+a2ASJgwrIXRK7EkNdFKlEOotn/Wcr7It84iLbwIu8tSYIBS5FkiI0Bjg==", + "version": "2.0.0-beta.7", + "resolved": "https://registry.npmjs.org/@mastra/rag/-/rag-2.0.0-beta.7.tgz", + "integrity": "sha512-Qvct5G9n/JRZbvCGVJUw7Ir7xQnxW5/vlZ1XI7xXzWtA7iFgVahkE8WN5JP7aDRQT8Q0ByG5/+d7ikeQWfUD8Q==", "license": "Apache-2.0", "dependencies": { "@paralleldrive/cuid2": "^2.3.1", @@ -6579,13 +6296,13 @@ } }, "node_modules/@mastra/react": { - "version": "0.1.0-beta.21", - "resolved": "https://registry.npmjs.org/@mastra/react/-/react-0.1.0-beta.21.tgz", - "integrity": "sha512-cirkAkA41QUmHVws5tKOvnqVoUeTIQj7h7rOHb6+9Vqsq8HhUe67JoEm8LhPofYL4N8vduHQuea91TZbrL46EA==", + "version": "0.1.0-beta.22", + "resolved": "https://registry.npmjs.org/@mastra/react/-/react-0.1.0-beta.22.tgz", + "integrity": "sha512-eKZxBMwEFttSjdpSI2FLWVYi+fbtBH/RwuNt9gMfQbRgcgkjd0ofgijZ43dmJPrrsjbou2fVCTdNn7Lz9m87yA==", "license": "Apache-2.0", "dependencies": { "@lukeed/uuid": "^2.0.1", - "@mastra/client-js": "1.0.0-beta.21", + "@mastra/client-js": "1.0.0-beta.22", "@radix-ui/react-tooltip": "^1.2.7", "hast-util-to-jsx-runtime": "^2.3.6", "lucide-react": "^0.522.0", @@ -6738,9 +6455,9 @@ } }, "node_modules/@mastra/server": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@mastra/server/-/server-1.0.0-beta.21.tgz", - "integrity": "sha512-uAj96cHHU2ZMxOPpvJJv/iCe+Nn6CupeiqelXPogoCm7BVpZP1fOwbbyRDMFzsV+3Hc8syvnyc8RoDijrjFmWg==", + "version": "1.0.0-beta.22", + "resolved": "https://registry.npmjs.org/@mastra/server/-/server-1.0.0-beta.22.tgz", + "integrity": "sha512-icV/VgJ6ylvd9IRMh9+7f+THfGsLD/33Euws2EL6K5svGHu5wNtAg32W0rAN7Dz/niZmza5SMxQo5Fb7LVDidw==", "license": "Apache-2.0", "dependencies": { "hono": "^4.11.3" @@ -6754,9 +6471,9 @@ } }, "node_modules/@mastra/upstash": { - "version": "1.0.0-beta.10", - "resolved": "https://registry.npmjs.org/@mastra/upstash/-/upstash-1.0.0-beta.10.tgz", - "integrity": "sha512-4sYxKwmq4Su4CyYZf8JO8bHhz6OdlT8gmDcLQX1b0Tg9M5TGpiXmIVegmcC5ag+EWQjgRmBl71hkH5INgzcbfg==", + "version": "1.0.0-beta.11", + "resolved": "https://registry.npmjs.org/@mastra/upstash/-/upstash-1.0.0-beta.11.tgz", + "integrity": "sha512-toywtsL3vcMDZHE2TJMA1qo+e5idrGIsvf5DziVOSQD1sEwhZHwd4J+XvmJ8jzDTLZksEz2lNPqH7DLTxwzC0w==", "license": "Apache-2.0", "dependencies": { "@upstash/redis": "^1.36.0", @@ -14426,9 +14143,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.90.17", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.17.tgz", - "integrity": "sha512-hDww+RyyYhjhUfoYQ4es6pbgxY7LNiPWxt4l1nJqhByjndxJ7HIjDxTBtfvMr5HwjYavMrd+ids5g4Rfev3lVQ==", + "version": "5.90.18", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.18.tgz", + "integrity": "sha512-rbGx6bHgPNVzutP7BEr+53UPKohpckqlMAad+To9UxTbeaQ+kC/1SDRj+QzkwbQ7qhLT/1IKp34yS6thda6fzA==", "license": "MIT", "funding": { "type": "github", @@ -14446,13 +14163,13 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.90.17", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.17.tgz", - "integrity": "sha512-PGc2u9KLwohDUSchjW9MZqeDQJfJDON7y4W7REdNBgiFKxQy+Pf7eGjiFWEj5xPqKzAeHYdAb62IWI1a9UJyGQ==", + "version": "5.90.18", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.18.tgz", + "integrity": "sha512-KqNZX0C5IFz4639zR1ilnQ288tQdJrMNLtzmlzyJ14xauBkhtLEy3mPU/V4KiHsr41eL1ILZbDP36TB12lYfCQ==", "license": "MIT", "peer": true, "dependencies": { - "@tanstack/query-core": "5.90.17" + "@tanstack/query-core": "5.90.18" }, "funding": { "type": "github", @@ -16422,6 +16139,15 @@ "integrity": "sha512-5xXB7kdQlFBP82ViMJTwwEc3gKCLGKR/eoxQm4zge7GPBl86tCdI0IdPJjoKd8mUSFXz5V7i/25sfsEkP4j46g==", "license": "MIT" }, + "node_modules/@xterm/xterm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.0.0.tgz", + "integrity": "sha512-TQwDdQGtwwDt+2cgKDLn0IRaSxYu1tSUjgKarSDkUM0ZNiSRXFpjxEsvc/Zgc5kq5omJ+V0a8/kIM2WD3sMOYg==", + "license": "MIT", + "workspaces": [ + "addons/*" + ] + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -16626,15 +16352,15 @@ } }, "node_modules/ai": { - "version": "6.0.37", - "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.37.tgz", - "integrity": "sha512-GUMBYx0TXKxXRcWy6DY3ryHJZ7cATxc99WPT7WCD8hGCYkdhFVItKPTtINeTlK+FlUomDqzjPGtiDcVftcw//w==", + "version": "6.0.38", + "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.38.tgz", + "integrity": "sha512-X8AaZFrdsPO1RNCAQLsaWfmE/SL9zgsiIZN3XqEHs3jIZ7ycR5aQZRg5XpNtbLWJxKXzK2b1ZXLx13AFOjksSg==", "license": "Apache-2.0", "peer": true, "dependencies": { - "@ai-sdk/gateway": "3.0.15", - "@ai-sdk/provider": "3.0.3", - "@ai-sdk/provider-utils": "4.0.7", + "@ai-sdk/gateway": "3.0.16", + "@ai-sdk/provider": "3.0.4", + "@ai-sdk/provider-utils": "4.0.8", "@opentelemetry/api": "1.9.0" }, "engines": { @@ -16690,52 +16416,6 @@ "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/ai-sdk-provider-claude-code": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ai-sdk-provider-claude-code/-/ai-sdk-provider-claude-code-3.2.1.tgz", - "integrity": "sha512-oNVO8bzk4surnG784ZwuB+pxQ/PPgxgvoXDrIyWr1b0u+iD+/9EtL1lwMeKuSLxKn7BF/MrPAgGWb+gftlXVXw==", - "license": "MIT", - "dependencies": { - "@ai-sdk/provider": "^3.0.0", - "@ai-sdk/provider-utils": "^4.0.1", - "@anthropic-ai/claude-agent-sdk": "^0.2.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^4.0.0" - } - }, - "node_modules/ai-sdk-provider-claude-code/node_modules/@ai-sdk/provider": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.2.tgz", - "integrity": "sha512-HrEmNt/BH/hkQ7zpi2o6N3k1ZR1QTb7z85WYhYygiTxOQuaml4CMtHCWRbric5WPU+RNsYI7r1EpyVQMKO1pYw==", - "license": "Apache-2.0", - "dependencies": { - "json-schema": "^0.4.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/ai-sdk-provider-claude-code/node_modules/@ai-sdk/provider-utils": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.4.tgz", - "integrity": "sha512-VxhX0B/dWGbpNHxrKCWUAJKXIXV015J4e7qYjdIU9lLWeptk0KMLGcqkB4wFxff5Njqur8dt8wRi1MN9lZtDqg==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "3.0.2", - "@standard-schema/spec": "^1.1.0", - "eventsource-parser": "^3.0.6" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, "node_modules/ai-sdk-provider-gemini-cli": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ai-sdk-provider-gemini-cli/-/ai-sdk-provider-gemini-cli-2.0.1.tgz", @@ -18797,9 +18477,9 @@ "license": "MIT" }, "node_modules/convex": { - "version": "1.31.4", - "resolved": "https://registry.npmjs.org/convex/-/convex-1.31.4.tgz", - "integrity": "sha512-iDm283Gb/CFRb30cvhH6Z9qlYof6dhtin415FarKUKB3K7gumO0rn8snY0CTvUrThV3UnCtttbuL/1oY7LscyA==", + "version": "1.31.5", + "resolved": "https://registry.npmjs.org/convex/-/convex-1.31.5.tgz", + "integrity": "sha512-E1IuJKFwMCHDToNGukBPs6c7RFaarR3t8chLF9n98TM5/Tgmj8lM6l7sKM1aJ3VwqGaB4wbeUAPY8osbCOXBhQ==", "license": "Apache-2.0", "dependencies": { "esbuild": "0.27.0", @@ -26501,15 +26181,15 @@ } }, "node_modules/mastra": { - "version": "1.0.0-beta.14", - "resolved": "https://registry.npmjs.org/mastra/-/mastra-1.0.0-beta.14.tgz", - "integrity": "sha512-6a6uErZ+OUl1fPUN2TK/Rs+FNY/H/AZH4DGMx30D/oBloy+nPdBQfKdN5iJEpdBE0z8MjNaKpUtz1m0XGIFfkA==", + "version": "1.0.0-beta.15", + "resolved": "https://registry.npmjs.org/mastra/-/mastra-1.0.0-beta.15.tgz", + "integrity": "sha512-itlV4K9vV9vuhqnTgZT0tl8RerJe7+tmGjXaTq7HjbFvVVsLYqzLPTVJphN5FZUmVvs15cWLstHR4/oP2mtYBQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@clack/prompts": "^0.11.0", "@expo/devcert": "^1.2.1", - "@mastra/deployer": "^1.0.0-beta.21", + "@mastra/deployer": "^1.0.0-beta.22", "@mastra/loggers": "^1.0.0-beta.4", "commander": "^14.0.2", "dotenv": "^17.2.3", diff --git a/package.json b/package.json index 41ac540..1e0e3f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "agentstack", - "version": "1.1.2", + "version": "1.1.3", "description": "Multi-agent frameworks and tools for building AI applications with Mastra.", "main": "index.js", "scripts": { @@ -45,36 +45,36 @@ "node": ">=20.9.0" }, "dependencies": { - "@ai-sdk/google": "^3.0.9", - "@ai-sdk/google-vertex": "^4.0.16", - "@ai-sdk/openai": "^3.0.11", - "@ai-sdk/openai-compatible": "^2.0.11", - "@ai-sdk/react": "^3.0.39", + "@ai-sdk/google": "^3.0.10", + "@ai-sdk/google-vertex": "^4.0.17", + "@ai-sdk/openai": "^3.0.12", + "@ai-sdk/openai-compatible": "^2.0.13", + "@ai-sdk/react": "^3.0.40", "@dotenvx/dotenvx": "^1.51.4", "@e2b/code-interpreter": "^2.3.3", "@emotion/react": "^11.14.0", "@gsap/react": "^2.1.2", - "@mastra/ai-sdk": "^1.0.0-beta.14", + "@mastra/ai-sdk": "^1.0.0-beta.15", "@mastra/auth-supabase": "^1.0.0-beta.1", - "@mastra/client-js": "^1.0.0-beta.21", - "@mastra/cloudflare-d1": "^1.0.0-beta.9", + "@mastra/client-js": "^1.0.0-beta.22", + "@mastra/cloudflare-d1": "^1.0.0-beta.10", "@mastra/convex": "^0.1.0-beta.8", - "@mastra/core": "^1.0.0-beta.21", - "@mastra/deployer": "^1.0.0-beta.21", - "@mastra/evals": "^1.0.0-beta.4", - "@mastra/lance": "^1.0.0-beta.10", - "@mastra/libsql": "^1.0.0-beta.11", + "@mastra/core": "^1.0.0-beta.22", + "@mastra/deployer": "^1.0.0-beta.22", + "@mastra/evals": "^1.0.0-beta.5", + "@mastra/lance": "^1.0.0-beta.11", + "@mastra/libsql": "^1.0.0-beta.12", "@mastra/loggers": "^1.0.0-beta.4", - "@mastra/mcp": "^1.0.0-beta.9", - "@mastra/memory": "^1.0.0-beta.12", - "@mastra/mongodb": "^1.0.0-beta.11", - "@mastra/observability": "^1.0.0-beta.10", + "@mastra/mcp": "^1.0.0-beta.10", + "@mastra/memory": "^1.0.0-beta.13", + "@mastra/mongodb": "^1.0.0-beta.12", + "@mastra/observability": "^1.0.0-beta.11", "@mastra/otel-bridge": "^1.0.0-beta.11", - "@mastra/pg": "^1.0.0-beta.12", - "@mastra/qdrant": "^1.0.0-beta.3", - "@mastra/rag": "^2.0.0-beta.6", - "@mastra/react": "^0.1.0-beta.21", - "@mastra/upstash": "^1.0.0-beta.10", + "@mastra/pg": "^1.0.0-beta.13", + "@mastra/qdrant": "^1.0.0-beta.4", + "@mastra/rag": "^2.0.0-beta.7", + "@mastra/react": "^0.1.0-beta.22", + "@mastra/upstash": "^1.0.0-beta.11", "@mastra/vectorize": "^1.0.0-beta.3", "@mastra/voice-google": "^0.12.0-beta.2", "@mastra/voice-openai": "^0.12.0-beta.2", @@ -104,16 +104,16 @@ "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tooltip": "^1.2.8", "@radix-ui/react-use-controllable-state": "^1.2.2", - "@tanstack/react-query": "^5.90.17", + "@tanstack/react-query": "^5.90.18", "@tanstack/react-query-devtools": "^5.91.2", "@tanstack/react-table": "^8.21.3", "@tslab/typescript-for-tslab": "^5.1.3", "@vercel/otel": "^2.1.0", + "@xterm/xterm": "^6.0.0", "@xyflow/react": "^12.10.0", "a2a-ai-provider": "^0.4.0-alpha.2", - "ai": "^6.0.37", + "ai": "^6.0.38", "ai-sdk-ollama": "^3.1.1", - "ai-sdk-provider-claude-code": "^3.2.1", "ai-sdk-provider-gemini-cli": "^2.0.1", "ai-sdk-provider-opencode-sdk": "^1.0.0", "arraystat": "^1.7.81", @@ -241,7 +241,7 @@ "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.26", "ink-testing-library": "^4.0.0", - "mastra": "^1.0.0-beta.14", + "mastra": "^1.0.0-beta.15", "prettier": "^3.8.0", "tailwindcss": "^4.1.18", "tw-animate-css": "^1.4.0", @@ -252,7 +252,7 @@ }, "overrides": { "jsondiffpatch": "0.7.3", - "ai": "^6.0.37", + "ai": "^6.0.38", "morgan": "^1.10.1", "js-yaml": "^4.1.1", "multer": "^2.0.2", @@ -264,4 +264,4 @@ "@typescript-eslint/parser": "^8.53.0", "zod": "^4.2.1" } -} +} \ No newline at end of file diff --git a/src/components/ai-elements/confirmation.tsx b/src/components/ai-elements/confirmation.tsx index 9b7eb8d..6a9562d 100644 --- a/src/components/ai-elements/confirmation.tsx +++ b/src/components/ai-elements/confirmation.tsx @@ -100,7 +100,7 @@ export const ConfirmationRequest = ({ children }: ConfirmationRequestProps) => { const { state } = useConfirmation() // Only show when approval is requested - // @ts-expect-error state only available in AI SDK v6 + if (state !== 'approval-requested') { return null } @@ -120,9 +120,7 @@ export const ConfirmationAccepted = ({ // Only show when approved and in response states if ( !approval?.approved || - // @ts-expect-error state only available in AI SDK v6 (state !== 'approval-responded' && - // @ts-expect-error state only available in AI SDK v6 state !== 'output-denied' && state !== 'output-available') ) { @@ -144,9 +142,7 @@ export const ConfirmationRejected = ({ // Only show when rejected and in response states if ( approval?.approved !== false || - // @ts-expect-error state only available in AI SDK v6 (state !== 'approval-responded' && - // @ts-expect-error state only available in AI SDK v6 state !== 'output-denied' && state !== 'output-available') ) { @@ -165,7 +161,6 @@ export const ConfirmationActions = ({ const { state } = useConfirmation() // Only show when approval is requested - // @ts-expect-error state only available in AI SDK v6 if (state !== 'approval-requested') { return null } diff --git a/src/components/ai-elements/tool.tsx b/src/components/ai-elements/tool.tsx index 44eada7..3df8141 100644 --- a/src/components/ai-elements/tool.tsx +++ b/src/components/ai-elements/tool.tsx @@ -40,7 +40,6 @@ const getStatusBadge = (status: ToolUIPart['state']) => { const labels: Record = { 'input-streaming': 'Pending', 'input-available': 'Running', - // @ts-expect-error state only available in AI SDK v6 'approval-requested': 'Awaiting Approval', 'approval-responded': 'Responded', 'output-available': 'Completed', @@ -51,7 +50,6 @@ const getStatusBadge = (status: ToolUIPart['state']) => { const icons: Record = { 'input-streaming': , 'input-available': , - // @ts-expect-error state only available in AI SDK v6 'approval-requested': , 'approval-responded': ( @@ -101,7 +99,7 @@ export type ToolContentProps = ComponentProps export const ToolContent = ({ className, ...props }: ToolContentProps) => ( - {errorText &&
{errorText}
} + {(Boolean(errorText)) &&
{errorText}
} {Output} diff --git a/src/components/ai-elements/tools/AGENTS.md b/src/components/ai-elements/tools/AGENTS.md new file mode 100644 index 0000000..a3e0448 --- /dev/null +++ b/src/components/ai-elements/tools/AGENTS.md @@ -0,0 +1,116 @@ + + +# Tools Directory (`/src/components/ai-elements/tools`) + +## Persona + +**Name:** `{tools_persona_name}` = "Tools UI Engineer" +**Role:** "I provide diverse, tool-specific UI components for agent tool execution—rendering unique interfaces for each tool type while maintaining cohesive interaction patterns across the ecosystem." +**Primary Goals:** + +1. Deliver tool-specific visualizations (weather cards, calculator displays, search results, code editors). +2. Handle loading, error, and streaming states with tool-appropriate feedback. +3. Maintain type safety with inferred tool schemas. +4. Enable rich interactions (downloads, filters, expansions, real-time updates). + +**MUST:** + +- Use Card components as containers but customize internal layouts per tool needs. +- Implement tool-specific UI patterns (scrollable lists, interactive forms, data visualizations). +- Support real-time progress updates and streaming data. +- Export all components through central index file. +- Follow established UI patterns while adapting to tool requirements. + +**FORBIDDEN:** + +- Force consistent internal layouts across different tool types. +- Inline business logic beyond UI rendering. +- Blocking renders without loading indicators. +- Hardcoded tool IDs or configurations. +- Missing accessibility features (ARIA labels, keyboard navigation). + +## Purpose + +Provides React components that render agent tool execution results in chat interfaces. Each tool component implements its own unique UI pattern within a Card container while maintaining consistent interaction patterns across the entire tool ecosystem. + +## Tool Surface (Current) + +| Component File | Tool Types | Description | UI Patterns | +| -------------- | ---------- | ----------- | ----------- | +| `browser-tool.tsx` | Browser, Screenshot, PDF, ClickExtract, FillForm, GoogleSearch, MonitorPage | Web automation and content extraction | Interactive buttons, scrollable content, image previews, download actions | +| `web-scraper-tool.tsx` | WebScraper | Single-page content scraping | Code blocks, structured data display, content highlighting | +| `batch-web-scraper-tool.tsx` | BatchWebScraper | Multi-URL bulk scraping | Progress tracking, result aggregation, batch status indicators | +| `site-map-extractor-tool.tsx` | SiteMapExtractor | Website structure analysis | Hierarchical tree views, link categorization, expandable sections | +| `link-extractor-tool.tsx` | LinkExtractor | Link discovery and categorization | Link filtering, categorization badges, external link indicators | +| `weather-tool.tsx` | Weather | Weather data and forecasts | Weather icons, temperature displays, forecast grids, location info | +| `financial-tools.tsx` | Financial (Company, Chart, Quote) | Market data and analysis | Data tables, financial charts, metric displays, time series | +| `polygon-tools.tsx` | Polygon (Crypto, Stock) | Real-time market data | Live data streams, price charts, market indicators | +| `research-tools.tsx` | Research (Arxiv, News) | Academic and news content | Paper metadata cards, news carousels, search result lists | +| `calculator-tool.tsx` | Calculator, Matrix, UnitConverter | Mathematical computations | Formula display, matrix grids, conversion interfaces | +| `e2b-sandbox-tool.tsx` | E2B Sandbox (FileOps, CodeExec, RunCommand) | Secure code execution | File explorers, code editors, terminal interfaces, execution logs | +| `execa-tool.tsx` | Execa | Shell command execution | Command history, streaming output, error highlighting, process status | +| `github-tools.tsx` | GitHub (Issues, PRs, Commits, Repo) | Repository management | Issue boards, PR timelines, commit graphs, repository stats | +| `types.ts` | Type Definitions | All tool type interfaces | TypeScript inference from Mastra schemas | +| `index.ts` | Component Exports | Central export registry | All tool components available for import | + +## System Flow + +```mermaid +flowchart TD + A[User Message] --> B[Chat Page] + B --> C[ChatProvider] + C --> D[Mastra API] + D --> E[Weather Agent] + E --> F[Weather Tool] + F --> G[Tool Execution] + G --> H[Progress Streaming] + H --> I[Chat Context] + I --> J[Chat Messages] + J --> K[AgentTools Component] + + K --> L{Tool Name Check} + L --> M[WeatherCard Component] + L --> N[Other Tool Components] + + M --> O[Weather UI Display] + N --> O + + classDef chat fill:#e1f5fe + classDef agent fill:#f3e5f5 + classDef tool fill:#e8f5e8 + classDef ui fill:#fff3e0 + + class A,B,C,I,J chat + class D,E agent + class F,G,H tool + class K,L,M,N,O ui +``` + +## Integration + +Tools are rendered in chat via `app/chat/components/agent-tools.tsx`: + +```tsx +// Tool name matching - each component handles specific tool names +if (toolName === 'web:scraper' && hasOutput) { + return +} +if (toolName === 'weatherTool' && hasOutput) { + return +} +// ... more tool checks +// Fallback to generic Tool component +return +``` + +All components receive: +- `toolCallId: string` +- `input: ToolInputType` +- `output?: ToolOutputType` +- `errorText?: string` + +## Change Log + +| Version | Date (UTC) | Change | +| ------- | ---------- | ------ | +| 1.0.0 | 2025-01-09 | Initial documentation following CLI pattern | diff --git a/src/components/ai-elements/tools/browser-tool.tsx b/src/components/ai-elements/tools/browser-tool.tsx new file mode 100644 index 0000000..5dee4f9 --- /dev/null +++ b/src/components/ai-elements/tools/browser-tool.tsx @@ -0,0 +1,467 @@ +'use client' + +import type { + BrowserUITool, + ClickAndExtractUITool, + FillFormUITool, + GoogleSearchUITool, + MonitorPageUITool, + PdfGeneratorUITool, + ScreenshotUITool, +} from './types' + +import { Badge } from '@/ui/badge' +import { Button } from '@/ui/button' +import { Card, CardContent, CardHeader, CardTitle } from '@/ui/card' +import { Input } from '@/ui/input' +import { ScrollArea } from '@/ui/scroll-area' +import { + AlertCircle, + CheckCircle, + Clipboard, + Download, + ExternalLink, + FileText, + Globe, + Image as ImageIcon, + Loader2, + Search, +} from 'lucide-react' +import { useEffect, useRef, useState, type ChangeEvent } from 'react' +import { CodeBlock, CodeBlockCopyButton } from '../code-block' + +/* Helpers */ +function formatBytes(bytes?: number) { + if (bytes == null) return 'N/A' + if (bytes === 0) return '0 B' + const units = ['B', 'KB', 'MB', 'GB', 'TB'] + let i = 0 + let num = bytes + while (num >= 1024 && i < units.length - 1) { + num /= 1024 + i++ + } + return `${num >= 10 ? Math.round(num) : num.toFixed(2)} ${units[i]}` +} + +function downloadFileFromBase64(filename: string, base64: string, mime = 'application/octet-stream') { + try { + const byteCharacters = atob(base64) + const byteNumbers = new Array(byteCharacters.length) + for (let i = 0; i < byteCharacters.length; i++) { + byteNumbers[i] = byteCharacters.charCodeAt(i) + } + const byteArray = new Uint8Array(byteNumbers) + const blob = new Blob([byteArray], { type: mime }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = filename + document.body.appendChild(a) + a.click() + a.remove() + URL.revokeObjectURL(url) + } catch { + // ignore + } +} + +function ErrorCard({ title, message }: { title: string; message: string }) { + return ( + + + + + {title} + + + +
{message}
+
+
+ ) +} + +function LoadingCard({ title, subtitle, icon }: { title: string; subtitle?: string; icon?: React.ReactNode }) { + return ( + + + + {icon} + {title} + + + {subtitle && ( + +
{subtitle}
+
+ )} +
+ ) +} + +/* Screenshot tool UI */ +interface ScreenshotCardProps { + toolCallId: string + input: ScreenshotUITool['input'] + output?: ScreenshotUITool['output'] + errorText?: string +} + +export function ScreenshotCard({ input, output, errorText }: ScreenshotCardProps) { + const [copied, setCopied] = useState(false) + + if (errorText) return + if (!output) { + return } /> + } + if ('error' in (output as any)) { + return + } + + const base64 = ((output as any).screenshot as string) ?? '' + const dataUrl = `data:image/png;base64,${base64}` + + const copyUrl = async () => { + try { + await navigator.clipboard.writeText(dataUrl) + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } catch { + // ignore + } + } + + const download = () => downloadFileFromBase64('screenshot.png', base64, 'image/png') + + return ( +
+ + + + + Screenshot + +
+ + {(output as any).success ? 'Success' : 'Done'} + + + +
+
+ + {base64 ? ( +
+ {`screenshot-${(input +
Content length: {base64.length} chars
+
+ ) : ( +
No screenshot data
+ )} +
+
+
+ ) +} + +/* PDF generator UI */ +interface PdfGeneratorCardProps { + toolCallId: string + input: PdfGeneratorUITool['input'] + output?: PdfGeneratorUITool['output'] + errorText?: string +} + +export function PdfGeneratorCard({ input, output, errorText }: PdfGeneratorCardProps) { + if (errorText) return + if (!output) { + return } /> + } + if ('error' in (output as any)) { + return + } + + const base64 = ((output as any).pdf as string) ?? '' + const downloadPdf = () => downloadFileFromBase64('page.pdf', base64, 'application/pdf') + + return ( + + + + + PDF Generated + +
+ + {(output as any).success ? 'Success' : 'Ready'} + + {base64 && ( + + )} + {(output as any).message && ( + + {(output as any).message} + + )} +
+
+ + {base64 ? ( +
+ + + View PDF + +
Size: {formatBytes((base64.length * 3) / 4)}
+
+ ) : ( +
No PDF content
+ )} +
+
+ ) +} + +/* Browser summary (generic) */ +interface BrowserToolCardProps { + toolCallId: string + input: BrowserUITool['input'] + output?: BrowserUITool['output'] + errorText?: string +} + +export function BrowserToolCard({ input, output, errorText }: BrowserToolCardProps) { + if (errorText) return + if (!output) return } /> + if (output && typeof output === 'object' && 'error' in output) { + return + } + + const contentLength = (output as any).contentLength ?? (output as any).message?.length + + return ( + + + + + Browser Result + +
+ {formatBytes(contentLength)} + {output && (output as any).message && message} +
+
+ +
+ {((output as any).sections && Array.isArray((output as any).sections)) ? ( +
+
Sections:
+ +
+ {((output as any).sections as any[]).map((s, i) => ( +
+
{s.title ?? `Section ${i + 1}`}
+ {s.summary &&
{s.summary}
} +
+ ))} +
+
+
+ ) : ( +
{(output as any).message ?? 'No readable content'}
+ )} +
+
+
+ ) +} + +/* Click & Extract */ +interface ClickAndExtractCardProps { + toolCallId: string + input: ClickAndExtractUITool['input'] + output?: ClickAndExtractUITool['output'] + errorText?: string +} + +export function ClickAndExtractCard({ input, output, errorText }: ClickAndExtractCardProps) { + if (errorText) return + if (!output) return } /> + if (output && typeof output === 'object' && 'error' in output) return + + const content = (output as any).content ?? (output as any).message ?? '' + + return ( + + + + + Extracted Content + +
+ {(output as any).contentLength ?? content.length} chars +
+
+ + {content ? ( + + + + + ) : ( +
No content
+ )} +
+
+ ) +} + +/* Fill Form */ +interface FillFormCardProps { + toolCallId: string + input: FillFormUITool['input'] + output?: FillFormUITool['output'] + errorText?: string +} + +export function FillFormCard({ input, output, errorText }: FillFormCardProps) { + if (errorText) return + if (!output) return } /> + if ('error' in (output as any)) return + + const finalUrl = (output as any).finalUrl ?? (output as any).message + + return ( + + + + + Fill Form + +
+ {(output as any).success ? 'Success' : 'Result'} +
+
+ + {finalUrl ? ( + + ) : ( +
{(output as any).message ?? 'No result available'}
+ )} +
+
+ ) +} + +/* Google Search */ +interface GoogleSearchCardProps { + toolCallId: string + input: GoogleSearchUITool['input'] + output?: GoogleSearchUITool['output'] + errorText?: string +} + +export function GoogleSearchCard({ input, output, errorText }: GoogleSearchCardProps) { + const [query, setQuery] = useState('') + if (errorText) return + if (!output) return } /> + if (output && typeof output === 'object' && 'error' in output) return + + // Some tools put results in different fields; try common ones + const results = (output as any).organic_results || (output as any).results || (output as any).data || [] + + const filtered = query ? results.filter((r: any) => JSON.stringify(r).toLowerCase().includes(query.toLowerCase())) : results + + return ( + + + + + Search Results + +
+ {(results?.length ?? 0)} results +
+
+ +
+ ) => setQuery(e.target.value)} placeholder="Filter results..." className="w-56 text-sm" /> + +
+ + {filtered.length === 0 ? ( +
No results
+ ) : ( + +
+ {filtered.map((r: any, idx: number) => ( +
+
{r.title ?? r.title}
+
{r.link ?? r.url ?? r.displayed_link}
+
{r.snippet ?? r.description ?? r.snippet}
+
+ ))} +
+
+ )} +
+
+ ) +} + +/* Monitor Page Card (basic) */ +interface MonitorPageCardProps { + toolCallId: string + input: MonitorPageUITool['input'] + output?: MonitorPageUITool['output'] + errorText?: string +} + +export function MonitorPageCard({ input, output, errorText }: MonitorPageCardProps) { + if (errorText) return + if (!output) return } /> + if ('error' in (output as any)) return + + const hasChanged = Boolean((output as any).changed) + + return ( + + + + + Monitor Page + +
+ + {hasChanged ? 'Changed' : 'No Change'} + +
+
+ +
+ {hasChanged ? 'Page changed. Check the latest diffs or logs.' : 'Page is stable.'} +
+
+
+ ) +} diff --git a/src/components/ai-elements/tools/calculator-tool.tsx b/src/components/ai-elements/tools/calculator-tool.tsx new file mode 100644 index 0000000..f3b6060 --- /dev/null +++ b/src/components/ai-elements/tools/calculator-tool.tsx @@ -0,0 +1,328 @@ +'use client' + +import type { + CalculatorUITool, + MatrixCalculatorUITool, + UnitConverterUITool, +} from './types' + +import { Badge } from '@/ui/badge' +import { Button } from '@/ui/button' +import { Card, CardContent, CardHeader, CardTitle } from '@/ui/card' +import { Input } from '@/ui/input' +import { ScrollArea } from '@/ui/scroll-area' +import { CodeBlock, CodeBlockCopyButton } from '../code-block' + +import { + AlertCircle, + ArrowRightCircle, + Calculator as CalculatorIcon, + CopyIcon, + Download, + Grid as GridIcon, + Loader2, +} from 'lucide-react' + +import { useEffect, useRef, useState, type ChangeEvent } from 'react' + +/* Helpers */ + +function ErrorCard({ title, message }: { title: string; message: string }) { + return ( + + + + + {title} + + + +
{message}
+
+
+ ) +} + +function LoadingCard({ title, subtitle, icon }: { title: string; subtitle?: string; icon?: React.ReactNode }) { + return ( + + + + {icon} + {title} + + + {subtitle && ( + +
{subtitle}
+
+ )} +
+ ) +} + +function downloadFile(filename: string, content: string, mime = 'text/plain') { + try { + const blob = new Blob([content], { type: mime }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = filename + document.body.appendChild(a) + a.click() + a.remove() + URL.revokeObjectURL(url) + } catch (err) { + // ignore + } +} + +/* Calculator UI Components */ + +/* 1) Calculator card */ +interface CalculatorCardProps { + toolCallId: string + input: CalculatorUITool['input'] + output?: CalculatorUITool['output'] + errorText?: string +} + +export function CalculatorCard({ input, output, errorText }: CalculatorCardProps) { + const [copied, setCopied] = useState(false) + const [showSteps, setShowSteps] = useState(false) + + const exprInput = input && typeof input === 'object' && 'expression' in input ? (input as any).expression : undefined + + if (errorText) return + if (!output) { + return } /> + } + if (output && typeof output === 'object' && 'error' in output) { + return + } + + const result = (output as any).result + const formatted = (output as any).formattedResult ?? String(result ?? '') + const expr = (output as any).expression ?? exprInput ?? (input as any)?.expression + const variables = (output as any).variables ?? ((input as any)?.variables ?? {}) + + const copy = async () => { + try { + await navigator.clipboard.writeText(String(formatted)) + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } catch { + // ignore + } + } + + const jsonVars = JSON.stringify(variables, null, 2) + + return ( +
+ + + + + Calculator + +
+ {(output as any).success ? 'Success' : 'Ready'} + + +
+
+ + +
+
Expression
+
{expr}
+ +
+
Result
+
{formatted}
+
+ +
+ +
+ + {showSteps && ( +
+
Variables
+ + + +
+ )} +
+
+
+
+ ) +} + +/* 2) Unit Converter Card */ +interface UnitConverterCardProps { + toolCallId: string + input: UnitConverterUITool['input'] + output?: UnitConverterUITool['output'] + errorText?: string +} + +export function UnitConverterCard({ input, output, errorText }: UnitConverterCardProps) { + const [copied, setCopied] = useState(false) + + const valInput = input && typeof input === 'object' && 'value' in input ? (input as any).value : undefined + const fromInput = input && typeof input === 'object' && 'fromUnit' in input ? (input as any).fromUnit : undefined + const toInput = input && typeof input === 'object' && 'toUnit' in input ? (input as any).toUnit : undefined + + if (errorText) return + if (!output) { + const subtitle = `${valInput ?? (input as any)?.value} ${fromInput ?? (input as any)?.fromUnit} → ${toInput ?? (input as any)?.toUnit}` + return } /> + } + if (output && typeof output === 'object' && 'error' in output) { + return + } + + const formatted = (output as any).formattedResult ?? String((output as any).result ?? '') + const result = (output as any).result + + const copy = async () => { + try { + await navigator.clipboard.writeText(String(formatted)) + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } catch { + // ignore + } + } + + return ( + + + + + Unit Converter + +
+ {fromInput ?? (input as any)?.fromUnit} → {toInput ?? (input as any)?.toUnit} + + +
+
+ +
+
Input
+
{(input as any).value} {(input as any).fromUnit}
+ +
+
Result
+
{formatted}
+ {result !== undefined &&
Raw: {String(result)}
} +
+
+
+
+ ) +} + +/* 3) Matrix Calculator Card */ +interface MatrixCalculatorCardProps { + toolCallId: string + input: MatrixCalculatorUITool['input'] + output?: MatrixCalculatorUITool['output'] + errorText?: string +} + +export function MatrixCalculatorCard({ input, output, errorText }: MatrixCalculatorCardProps) { + const [copied, setCopied] = useState(false) + const [showJson, setShowJson] = useState(false) + const operationInput = input && typeof input === 'object' && 'operation' in input ? (input as any).operation : undefined + + if (errorText) return + if (!output) { + return } /> + } + if (output && typeof output === 'object' && 'error' in output) { + return + } + + const result = (output as any).result + const hasResult = Array.isArray(result) && result.length > 0 + + const formatted = JSON.stringify(result ?? {}, null, 2) + + const copy = async () => { + try { + await navigator.clipboard.writeText(formatted) + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } catch { + // ignore + } + } + + return ( + + + + + Matrix: {operationInput ?? (input as any)?.operation} + +
+ {hasResult ? 'Done' : 'No Result'} + + + +
+
+ + + {hasResult ? ( +
+ {!showJson ? ( + +
+ {(result as any[]).map((row: any[], rIdx: number) => ( +
+ {row.map((val, cIdx) => ( +
+ {String(val)} +
+ ))} +
+ ))} +
+
+ ) : ( + + + + )} +
+ ) : ( +
No matrix result available
+ )} +
+
+ ) +} diff --git a/src/components/ai-elements/tools/e2b-sandbox-tool.tsx b/src/components/ai-elements/tools/e2b-sandbox-tool.tsx index 1c0e0bc..0055a8c 100644 --- a/src/components/ai-elements/tools/e2b-sandbox-tool.tsx +++ b/src/components/ai-elements/tools/e2b-sandbox-tool.tsx @@ -1,267 +1,853 @@ 'use client' +/** + * E2B Sandbox UI helpers + * + * This file exposes a small component (Card-style) per E2B UI tool. + * Each component uses its corresponding tool type from `./types` so that + * all imported types are actually referenced and the UI matches the + * tool's input/output shapes. + * + * Pattern follows other tool components (web-scraper, research-tools, site-map). + */ + +import type { + CheckFileExistsUITool, + CreateDirectoryUITool, + CreateSandboxUITool, + DeleteFileUITool, + GetFileInfoUITool, + GetFileSizeUITool, + ListFilesUITool, + RunCodeUITool, + RunCommandUITool, + WatchDirectoryUITool, + WriteFileUITool, + WriteFilesUITool, +} from './types' + import { Badge } from '@/ui/badge' -import { Card, CardContent, CardHeader, CardTitle } from '@/ui/card' -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/ui/tabs' import { Button } from '@/ui/button' +import { Card, CardContent, CardHeader, CardTitle } from '@/ui/card' import { Input } from '@/ui/input' -import { Label } from '@/ui/label' -import { Textarea } from '@/ui/textarea' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/ui/select' +import { ScrollArea } from '@/ui/scroll-area' +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/ui/tabs' import { - FileText, - Folder, - Terminal, - Code, - Play, - Upload, - Download, - Trash2, - Eye, - HardDrive, + AlertCircle, + CheckCircle, + Clock, + Code as CodeIcon, + CopyIcon, + Download, + FileText, + Folder, + List, + Loader2, + Play, + Terminal, + Trash2, } from 'lucide-react' -import type { E2bSandboxTool } from './types' -import { CodeBlock } from '../code-block' - -interface E2bSandboxToolProps { - toolCallId: string - input: E2bSandboxTool['input'] - output?: E2bSandboxTool['output'] - errorText?: string +import { useEffect, useRef, useState, type ChangeEvent } from 'react' +import { CodeBlock, CodeBlockCopyButton } from '../code-block' + +/* Generic helpers */ +function ErrorCard({ title, message }: { title: string; message: string }) { + return ( + + + + + {title} + + + +
{message}
+
+
+ ) } -export function E2bSandboxToolComponent({ - input, - output, - errorText, -}: E2bSandboxToolProps) { - if (errorText) { - return ( -
- - - - - Sandbox Operation Failed - - - -
- {errorText} -
-
-
-
- ) - } +function LoadingCard({ title, subtitle, icon }: { title: string; subtitle?: string; icon?: React.ReactNode }) { + return ( + + + + {icon} + {title} + + + {subtitle && ( + +
{subtitle}
+
+ )} +
+ ) +} - if (!output) { - return ( - - - - - Executing Sandbox Operation... - - - -
- Running {input.action} operation in E2B sandbox -
-
-
- ) +/* Small UI helpers */ + +// Nicely format bytes for human-oriented display +function formatBytes(bytes?: number) { + if (bytes == null) return 'N/A' + if (bytes === 0) return '0 B' + const units = ['B', 'KB', 'MB', 'GB', 'TB'] + let i = 0 + let num = bytes + while (num >= 1024 && i < units.length - 1) { + num /= 1024 + i++ + } + // fewer decimals for larger numbers + return `${num >= 10 ? Math.round(num) : num.toFixed(2)} ${units[i]}` +} + +// Map a loose language name to a shiki BundledLanguage we support +function mapToBundledLanguage(lang?: string): any { + if (!lang) return 'bash' + const l = lang.toLowerCase() + if (l.includes('ts')) return 'typescript' + if (l.includes('js') || l.includes('javascript')) return 'javascript' + if (l.includes('py') || l.includes('python')) return 'python' + if (l.includes('json')) return 'json' + if (l.includes('html')) return 'html' + return 'bash' +} + +// Download helper - create and trigger a file download in the browser +function downloadFile(filename: string, content: string, mime = 'text/plain') { + try { + const blob = new Blob([content], { type: mime }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = filename + document.body.appendChild(a) + a.click() + a.remove() + URL.revokeObjectURL(url) + } catch (err) { + console.error('Failed to download file', err) + } +} + +/* Create Sandbox Card */ +interface CreateSandboxCardProps { + toolCallId: string + input: CreateSandboxUITool['input'] + output?: CreateSandboxUITool['output'] + errorText?: string +} + +export function CreateSandboxCard(props: CreateSandboxCardProps) { + const { input, output, errorText } = props + const [copied, setCopied] = useState(false) + + if (errorText) return + + if (!output) { + return } /> + } + + const copyId = async () => { + if (!(output as any)?.sandboxId) return + try { + await navigator.clipboard.writeText((output as any)!.sandboxId) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } catch { + // ignore } + } + + return ( + + + + + Sandbox Created + +
+ +
+
+ +
+
+ Sandbox ID: {(output as any).sandboxId} +
+ {(input as any).timeoutMS !== undefined &&
Timeout: {(input as any).timeoutMS}ms
} +
+
+
+ ) +} + +/* Write File Card */ +interface WriteFileCardProps { + toolCallId: string + input: WriteFileUITool['input'] + output?: WriteFileUITool['output'] + errorText?: string +} + +export function WriteFileCard({ input, output, errorText }: WriteFileCardProps) { + if (errorText) return + if (!output) return } /> - const { action, sandboxId } = input - const result = output.result - - return ( -
- {/* Success Header */} - - - - - Sandbox Operation Completed - - - -
- - {action} - - - Sandbox: {sandboxId?.slice(0, 8)}... - + if ('error' in (output as any)) { + return + } + + return ( + + + + + File Written + + + {(output as any).success ? 'Success' : 'Failed'} + + + +
+
Path: {(output as any).path}
+
Success: {String((output as any).success)}
+
+
+
+ ) +} + +/* Write Files Card */ +interface WriteFilesCardProps { + toolCallId: string + input: WriteFilesUITool['input'] + output?: WriteFilesUITool['output'] + errorText?: string +} + +export function WriteFilesCard({ input, output, errorText }: WriteFilesCardProps) { + if (errorText) return + if (!output) return } /> + + if ('error' in (output as any)) { + return + } + + return ( +
+ + + + + Files Written + + + +
+
Success: {String((output as any).success)}
+
Files Written: {(output as any).filesWritten ?? (input as any).files?.length ?? 0}
+
+
+
+ + + + Files + + + +
+ {((input as any).files || []).map((f: any, idx: number) => ( +
+ +
{f.path}
+
+ ))} +
+
+
+
+
+ ) +} + +/* List Files Card */ +interface ListFilesCardProps { + toolCallId: string + input: ListFilesUITool['input'] + output?: ListFilesUITool['output'] + errorText?: string +} + +export function ListFilesCard({ input, output, errorText }: ListFilesCardProps) { + if (errorText) return + if (!output) return } /> + + const files = (output as any).files || [] + const fileCount = files.length + const dirCount = files.filter((f: any) => f.isDirectory).length + + // Search / filter state for better UX + const [fileQuery, setFileQuery] = useState('') + const filteredFiles = fileQuery + ? files.filter( + (f: any) => + (f.name || '').toLowerCase().includes(fileQuery.toLowerCase()) || + (f.path || '').toLowerCase().includes(fileQuery.toLowerCase()) + ) + : files + + return ( +
+ + + + + Directory: {(output as any).path} + + + +
+ + {fileCount} entries + + + {dirCount} directories + +
+
+
+ + {/* Search + Contents */} + + + Contents +
+ ) => setFileQuery(e.target.value)} + aria-label="Filter files" + /> + +
+
+ + +
+ {filteredFiles.length === 0 ? ( +
No files match your filter
+ ) : ( + filteredFiles.map((f: any, idx: number) => ( +
+ {f.isDirectory ? : } +
+
{f.name}
+
{f.path}
- - - - {/* Result Display */} - - - Operation Result - - - {action === 'createSandbox' && result?.sandboxId && ( -
-
- Sandbox ID:{' '} - {result.sandboxId} -
-
- Status:{' '} - Ready for operations -
-
- )} - - {action === 'runCode' && result?.execution && ( -
-
- Language:{' '} - {result.execution.language || 'python'} -
-
- Exit Code:{' '} - {result.execution.exitCode} -
- {result.execution.stdout && ( -
-
- Output: -
- -
- )} - {result.execution.stderr && ( -
-
- Errors: -
- -
- )} -
- )} - - {(action === 'readFile' || action === 'writeFile') && - result?.content && ( -
-
- File:{' '} - {result.path} -
-
- Content: -
- -
- )} - - {action === 'listFiles' && result?.files && ( -
-
- Directory:{' '} - {result.path} -
-
- - Files ({result.files.length}): - -
-
- {result.files.map((file, index) => ( -
- {file.isDirectory ? ( - - ) : ( - - )} - {file.name} - - ({file.path}) - -
- ))} -
-
- )} - - {action === 'runCommand' && result && ( -
-
- Command:{' '} - {result.command} -
-
- Exit Code:{' '} - {result.exitCode} -
-
- - Execution Time: - {' '} - {result.executionTime}ms -
- {result.stdout && ( -
-
- Output: -
- -
- )} - {result.stderr && ( -
-
- Errors: -
- -
- )} -
- )} - - {/* Default result display */} - {result && - typeof result === 'object' && - !result.hasOwnProperty('execution') && - !result.hasOwnProperty('content') && - !result.hasOwnProperty('files') && - !result.hasOwnProperty('command') && ( - - )} -
-
+
+ +
+
+ )) + )} +
+
+
+
+
+ ) +} + +/* Delete File Card */ +interface DeleteFileCardProps { + toolCallId: string + input: DeleteFileUITool['input'] + output?: DeleteFileUITool['output'] + errorText?: string +} + +export function DeleteFileCard({ input, output, errorText }: DeleteFileCardProps) { + if (errorText) return + if (!output) return } /> + if ('error' in (output as any)) return + + return ( + + + + + File Deleted + + + +
Path: {(output as any).path}
+
Success: {String((output as any).success)}
+
+
+ ) +} + +/* Create Directory Card */ +interface CreateDirectoryCardProps { + toolCallId: string + input: CreateDirectoryUITool['input'] + output?: CreateDirectoryUITool['output'] + errorText?: string +} + +export function CreateDirectoryCard({ input, output, errorText }: CreateDirectoryCardProps) { + if (errorText) return + if (!output) return } /> + if ('error' in (output as any)) return + + return ( + + + + + Directory Created + + + +
Path: {(output as any).path}
+
Success: {String((output as any).success)}
+
+
+ ) +} + +/* Get File Info Card */ +interface GetFileInfoCardProps { + toolCallId: string + input: GetFileInfoUITool['input'] + output?: GetFileInfoUITool['output'] + errorText?: string +} + +export function GetFileInfoCard({ input, output, errorText }: GetFileInfoCardProps) { + if (errorText) return + if (!output) return } /> + if ('error' in (output as any)) return + + return ( + + + + + File Info + + + +
+
Name: {(output as any).name}
+
+
Path: {(output as any).path}
+ +
+
Type: {(output as any).type}
+
Size: {formatBytes((output as any).size)} ({(output as any).size} bytes)
+ {(output as any).mode &&
Mode: {(output as any).mode}
} + {(output as any).permissions &&
Permissions: {(output as any).permissions}
} + {(output as any).owner &&
Owner: {(output as any).owner}
} + {(output as any).modifiedTime &&
Modified: {String((output as any).modifiedTime)}
} + {(output as any).symlinkTarget &&
Symlink: {(output as any).symlinkTarget}
} +
+
+
+ ) +} + +/* Check File Exists Card */ +interface CheckFileExistsCardProps { + toolCallId: string + input: CheckFileExistsUITool['input'] + output?: CheckFileExistsUITool['output'] + errorText?: string +} + +export function CheckFileExistsCard({ input, output, errorText }: CheckFileExistsCardProps) { + if (errorText) return + if (!output) return } /> + if ('error' in (output as any)) return + + return ( + + + + + File Existence + + + +
+
Path: {(output as any).path}
+
Exists: {String((output as any).exists)}
+ {(output as any).type &&
Type: {(output as any).type}
} +
+
+
+ ) +} + +/* Get File Size Card (keeps original behavior but aligned style) */ +interface GetFileSizeCardProps { + toolCallId: string + input: GetFileSizeUITool['input'] + output?: GetFileSizeUITool['output'] + errorText?: string +} + +export function GetFileSizeCard({ input, output, errorText }: GetFileSizeCardProps) { + if (errorText) { + return + } + + if (!output) { + return } /> + } + + if ('error' in (output as any)) { + return + } + + return ( + + + + + File Size + + + +
+

Path: {(output as any).path}

+

Size: {(output as any).size} bytes

+ {(output as any).humanReadableSize &&

Human Readable: {(output as any).humanReadableSize}

} + {(output as any).type &&

Type: {(output as any).type}

}
+
+
+ ) +} + +/* Watch Directory Card */ +interface WatchDirectoryCardProps { + toolCallId: string + input: WatchDirectoryUITool['input'] + output?: WatchDirectoryUITool['output'] + errorText?: string +} + +export function WatchDirectoryCard({ input, output, errorText }: WatchDirectoryCardProps) { + type WatchEvent = { type: string; name: string; timestamp: string } + + const [visibleEvents, setVisibleEvents] = useState(() => + output && 'events' in (output as any) && Array.isArray((output as any).events) ? ((output as any).events as WatchEvent[]) : [] + ) + + // Search and auto-scroll UX enhancements + const [eventQuery, setEventQuery] = useState('') + const [autoScroll, setAutoScroll] = useState(true) + const bottomRef = useRef(null) + + useEffect(() => { + if (output && 'events' in (output as any) && Array.isArray((output as any).events)) { + setVisibleEvents((output as any).events as WatchEvent[]) + } else { + setVisibleEvents([]) + } + }, [output]) + + // when events update, optionally auto-scroll to bottom + useEffect(() => { + if (autoScroll && bottomRef.current) { + bottomRef.current.scrollIntoView({ behavior: 'smooth', block: 'end' }) + } + }, [visibleEvents, autoScroll]) + + const copyEvents = async () => { + try { + await navigator.clipboard.writeText(JSON.stringify(visibleEvents, null, 2)) + } catch { + // ignore + } + } + + if (errorText) return + if (!output) return } /> + if ('error' in (output as any)) return + + const filteredEvents = eventQuery + ? visibleEvents.filter( + (e) => + e.name.toLowerCase().includes(eventQuery.toLowerCase()) || + e.type.toLowerCase().includes(eventQuery.toLowerCase()) ) + : visibleEvents + + return ( +
+ + + + + Watch Started + +
+ Events: {visibleEvents.length} + +
+
+ +
Path: {(output as any).path}
+
+
+ + + + Events +
+ ) => setEventQuery(e.target.value)} + /> + + +
+
+ + +
+ {filteredEvents.map((e: WatchEvent, i: number) => ( +
+ +
+
{e.name}
+
{new Date(String(e.timestamp)).toLocaleString()}
+
+ {e.type} +
+ ))} +
+
+ + + +
+ ) +} + +/* Run Command Card */ +interface RunCommandCardProps { + toolCallId: string + input: RunCommandUITool['input'] + output?: RunCommandUITool['output'] + errorText?: string +} + +export function RunCommandCard({ input, output, errorText }: RunCommandCardProps) { + if (errorText) return + if (!output) return } /> + if ('error' in (output as any)) return + + const stdout = (output as any).stdout ?? '' + const stderr = (output as any).stderr ?? '' + + // UX: filtering, line numbers, and auto-scroll toggles for stdout/stderr + const [stdoutQuery, setStdoutQuery] = useState('') + const [stderrQuery, setStderrQuery] = useState('') + const [showLineNumbers, setShowLineNumbers] = useState(false) + const [autoScrollStdout, setAutoScrollStdout] = useState(true) + const [autoScrollStderr, setAutoScrollStderr] = useState(true) + const stdoutFiltered = stdoutQuery ? stdout.split('\n').filter((l: string) => l.toLowerCase().includes(stdoutQuery.toLowerCase())).join('\n') : stdout + const stderrFiltered = stderrQuery ? stderr.split('\n').filter((l: string) => l.toLowerCase().includes(stderrQuery.toLowerCase())).join('\n') : stderr + const stdoutBottomRef = useRef(null) + const stderrBottomRef = useRef(null) + + useEffect(() => { + if (autoScrollStdout && stdoutBottomRef.current) stdoutBottomRef.current.scrollIntoView({ behavior: 'smooth', block: 'end' }) + }, [stdoutFiltered, autoScrollStdout]) + + useEffect(() => { + if (autoScrollStderr && stderrBottomRef.current) stderrBottomRef.current.scrollIntoView({ behavior: 'smooth', block: 'end' }) + }, [stderrFiltered, autoScrollStderr]) + + return ( +
+ + + + + Command Result + + + +
+
Command: {(output as any).command ?? (input as any).command}
+
+ + Exit: {(output as any).exitCode ?? 'N/A'} + + Time: {(output as any).executionTime ?? 'N/A'} ms +
+
+
+
+ + + + Stdout + Stderr + + + + + + Stdout +
+ ) => setStdoutQuery(e.target.value)} placeholder="Filter stdout..." className="w-40 text-xs" /> + + + +
+
+ + {stdout ? ( + <> + + + + +
+ + ) : ( +
No stdout
+ )} + + + + + + + + Stderr +
+ ) => setStderrQuery(e.target.value)} placeholder="Filter stderr..." className="w-40 text-xs" /> + + +
+
+ + {stderr ? ( + <> + + + + +
+ + ) : ( +
No stderr
+ )} + + + + +
+ ) +} + +/* Run Code Card */ +interface RunCodeCardProps { + toolCallId: string + input: RunCodeUITool['input'] + output?: RunCodeUITool['output'] + errorText?: string +} + +export function RunCodeCard({ input, output, errorText }: RunCodeCardProps) { + if (errorText) return + if (!output) return } /> + if ('error' in (output as any)) return + + const execution: any = (output as any).execution || {} + const logs: any = execution.logs || {} + + const stdout = logs.stdout || '' + const stderr = logs.stderr || '' + + return ( +
+ + + + + Execution Result + + + +
+
Language: {(input as any).runCodeOpts?.language ?? 'unknown'}
+
Success: {String(execution.success ?? false)}
+
Exit Code: {execution.exitCode ?? 'N/A'}
+
+
+
+ + + + Stdout + Stderr + + + + + Stdout + + {stdout ? ( + + + + ) : ( +
No stdout
+ )} +
+
+
+ + + + Stderr + + {stderr ? ( + + + + ) : ( +
No stderr
+ )} +
+
+
+
+
+ ) } diff --git a/src/components/ai-elements/tools/execa-tool.tsx b/src/components/ai-elements/tools/execa-tool.tsx new file mode 100644 index 0000000..77b1a2c --- /dev/null +++ b/src/components/ai-elements/tools/execa-tool.tsx @@ -0,0 +1,223 @@ +'use client' + +import { Badge } from '@/ui/badge' +import { Button } from '@/ui/button' +import { Card, CardContent, CardHeader, CardTitle } from '@/ui/card' +import { Input } from '@/ui/input' +import { ScrollArea } from '@/ui/scroll-area' +import { + AlertCircle, + CopyIcon, + Download, + FileText, + Loader2, + Terminal, +} from 'lucide-react' +import type { ChangeEvent } from 'react' +import { useEffect, useRef, useState } from 'react' +import { CodeBlock, CodeBlockCopyButton } from '../code-block' +import type { ExecaUITool } from './types' + +interface ExecaToolCardProps { + toolCallId: string + input: ExecaUITool['input'] + output?: ExecaUITool['output'] + errorText?: string +} + +/* Small helpers */ +function ErrorCard({ title, message }: { title: string; message: string }) { + return ( + + + + + {title} + + + +
{message}
+
+
+ ) +} + +function LoadingCard({ title, subtitle, icon }: { title: string; subtitle?: string; icon?: React.ReactNode }) { + return ( + + + + {icon} + {title} + + + {subtitle && ( + +
{subtitle}
+
+ )} +
+ ) +} + +function downloadFile(filename: string, content: string, mime = 'text/plain') { + try { + const blob = new Blob([content], { type: mime }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = filename + document.body.appendChild(a) + a.click() + a.remove() + URL.revokeObjectURL(url) + } catch (err) { + // ignore + } +} + +export function ExecaToolCard({ input, output, errorText }: ExecaToolCardProps) { + const [displayText, setDisplayText] = useState((output as { message?: string })?.message ?? '') + const [query, setQuery] = useState('') + const [showLineNumbers, setShowLineNumbers] = useState(false) + const contentBottomRef = useRef(null) + + useEffect(() => { + // Update display text when output changes + setDisplayText((output as { message?: string })?.message ?? '') + }, [(output as { message?: string })?.message]) + + // Auto-scroll when display text updates + useEffect(() => { + if (contentBottomRef.current) { + contentBottomRef.current.scrollIntoView({ behavior: 'smooth', block: 'end' }) + } + }, [displayText]) + + const filteredText = query + ? displayText + .split('\n') + .filter((l) => l.toLowerCase().includes(query.toLowerCase())) + .join('\n') + : displayText + + const copyCommand = async () => { + try { + await navigator.clipboard.writeText(`${(input as { command: string, args?: string[], cwd?: string }).command} ${(input as { command: string, args?: string[], cwd?: string }).args?.join(' ') ?? ''}`) + } catch { + // ignore + } + } + + const copyOutput = async () => { + try { + await navigator.clipboard.writeText(displayText) + } catch { + // ignore + } + } + + if (errorText) { + return + } + + if (!output) { + return ( + } + /> + ) + } + + // Determine a naive success indicator from message content (best-effort) + const isLikelySuccess = ((output as { message?: string })?.message || '').toLowerCase().includes('success') || !((output as { message?: string })?.message || '').toLowerCase().includes('error') + + return ( +
+ + + + + Command Output + +
+ + {isLikelySuccess ? 'Likely Success' : 'Possible Error'} + + +
+
+ +
+
+ Command: {(input as { command: string, args?: string[], cwd?: string }).command} +
+ {(input as { command: string, args?: string[], cwd?: string }).args && (input as { command: string, args?: string[], cwd?: string }).args!.length > 0 && ( +
+ {(input as { command: string, args?: string[], cwd?: string }).args!.map((a: string, i: number) => ( + + {a} + + ))} +
+ )} +
+
+
+ + + + Output +
+ ) => setQuery(e.target.value)} + placeholder="Filter lines..." + className="w-56 text-sm" + /> + + + + + +
+
+ + + {filteredText ? ( +
+ + + + +
+
+ ) : ( +
No output
+ )} + + + +
+ ) +} + +export default ExecaToolCard diff --git a/src/components/ai-elements/tools/github-tools.tsx b/src/components/ai-elements/tools/github-tools.tsx index 4ca4d8e..d480035 100644 --- a/src/components/ai-elements/tools/github-tools.tsx +++ b/src/components/ai-elements/tools/github-tools.tsx @@ -2,506 +2,504 @@ import { Badge } from '@/ui/badge' import { Card, CardContent, CardHeader, CardTitle } from '@/ui/card' +import { ScrollArea } from '@/ui/scroll-area' import { - GitFork, - Star, - Lock, - Globe, - ExternalLink, - GitPullRequest, - MessageSquare, - AlertCircle, - Loader2, - GitCommit, + AlertCircle, + ExternalLink, + GitCommit, + GitFork, + GitPullRequest, + Globe, + Loader2, + Lock, + MessageSquare, + Star, } from 'lucide-react' -import { ScrollArea } from '@/ui/scroll-area' import type { - ListRepositoriesUITool, - ListPullRequestsUITool, - GetIssueUITool, -} from './types' -import type { - Key, - ReactElement, - JSXElementConstructor, - ReactNode, - ReactPortal, + JSXElementConstructor, + Key, + ReactElement, + ReactNode, + ReactPortal, } from 'react' +import type { + GetIssueUITool, + ListPullRequestsUITool, + ListRepositoriesUITool, +} from './types' interface Repository { - url: string - isPrivate: boolean - name: string - stars: number - forks: number - description?: string - defaultBranch: string - updatedAt: string + url: string + isPrivate: boolean + name: string + stars: number + forks: number + description?: string + defaultBranch: string + updatedAt: string } interface PullRequest { - number: number - url: string - title: string - state: string - labels: string[] - author: string - createdAt: string - updatedAt: string - draft: boolean + number: number + url: string + title: string + state: string + labels: string[] + author: string + createdAt: string + updatedAt: string + draft: boolean } interface Issue { - number: number - url: string - title: string - author: string - createdAt: string - state: 'open' | 'closed' - labels: string[] - body?: string - comments: number + number: number + url: string + title: string + author: string + createdAt: string + state: 'open' | 'closed' + labels: string[] + body?: string + comments: number } interface Commit { - sha: string - html_url: string - message: string + sha: string + html_url: string + message: string + author?: { + name: string + date: string + } + commit?: { author?: { - name: string - date: string - } - commit?: { - author?: { - date: string - } + date: string } + } } // ... (Existing components) export function CommitHistoryList({ - input, - output, - errorText, + input, + output, + errorText, }: ToolProps) { - if (errorText) { - return ( - - - - - Commit History Failed - - - -
{errorText}
-
-
- ) - } - - if (!output) { - return ( - - - - - Fetching commits... - - - - ) - } - - const commits = output.commits ?? [] + if (errorText) { + return ( + + + + + Commit History Failed + + + +
{errorText}
+
+
+ ) + } + if (!output) { return ( - - - - - Recent Commits ({commits.length}) - - - - -
- {commits.map((commit: any) => ( -
-
-
-
- - {commit.message.split('\n')[0]} - - - {commit.sha.substring(0, 7)} - -
-
- - {commit.author?.name} - - - committed on{' '} - {new Date( - commit.author?.date ?? - commit.commit?.author?.date - ).toLocaleDateString()} - -
-
-
- ))} -
- - - + + + + + Fetching commits... + + + ) + } + + const commits = output.commits ?? [] + + return ( + + + + + Recent Commits ({commits.length}) + + + + +
+ {commits.map((commit: any) => ( +
+
+
+
+ + {commit.message.split('\n')[0]} + + + {commit.sha.substring(0, 7)} + +
+
+ + {commit.author?.name} + + + committed on{' '} + {new Date( + commit.author?.date ?? + commit.commit?.author?.date + ).toLocaleDateString()} + +
+
+
+ ))} +
+ + + + ) } interface ToolProps { - toolCallId: string - input: TInput - output?: TOutput - errorText?: string + toolCallId: string + input: TInput + output?: TOutput + errorText?: string } export function RepositoryCard({ - input, - output, - errorText, + output, + errorText, }: ToolProps< - ListRepositoriesUITool['input'], - ListRepositoriesUITool['output'] + ListRepositoriesUITool['input'], + ListRepositoriesUITool['output'] >) { - if (errorText) { - return ( - - - - - Repository List Failed - - - -
{errorText}
-
-
- ) - } + if (errorText) { + return ( + + + + + Repository List Failed + + + +
{errorText}
+
+
+ ) + } - if (!output) { - return ( - - - - - Fetching repositories... - - - - ) - } + if (!output) { + return ( + + + + + Fetching repositories... + + + + ) + } - const repos = output.repositories ?? [] + const repos = (output as { repositories?: Repository[] }).repositories ?? [] - return ( - - - - Repositories ({repos.length}) - - - - -
- {repos.map((repo) => ( -
-
-
- {repo.isPrivate ? ( - - ) : ( - - )} - - {repo.name} - -
-
-
- - {repo.stars} -
-
- - {repo.forks} -
-
-
- {repo.description && ( -

- {repo.description} -

- )} -
- - {repo.defaultBranch} - - - Updated{' '} - {new Date( - repo.updatedAt - ).toLocaleDateString()} - -
-
- ))} + return ( + + + + Repositories ({repos.length}) + + + + +
+ {repos.map((repo: Repository) => ( +
+
+
+ {repo.isPrivate ? ( + + ) : ( + + )} + + {repo.name} + +
+
+
+ + {repo.stars}
- - - - ) +
+ + {repo.forks} +
+
+
+ {repo.description && ( +

+ {repo.description} +

+ )} +
+ + {repo.defaultBranch} + + + Updated{' '} + {new Date( + repo.updatedAt + ).toLocaleDateString()} + +
+
+ ))} +
+
+
+
+ ) } export function PullRequestList({ - input, - output, - errorText, + output, + errorText, }: ToolProps< - ListPullRequestsUITool['input'], - ListPullRequestsUITool['output'] + ListPullRequestsUITool['input'], + ListPullRequestsUITool['output'] >) { - if (errorText) { - return ( - - - - - PR List Failed - - - -
{errorText}
-
-
- ) - } - - if (!output) { - return ( - - - - - Fetching pull requests... - - - - ) - } - - const prs = output.pullRequests || [] - + if (errorText) { return ( - - - - - Pull Requests ({prs.length}) - - - - -
- {prs.map((pr: PullRequest) => ( -
-
-
- - #{pr.number} - - - {pr.title} - -
- - {pr.state} - -
-
- {pr.labels.map((label) => ( - - {label} - - ))} -
-
-
- by {pr.author} -
- - {new Date( - pr.createdAt - ).toLocaleDateString()} - -
-
- ))} -
-
-
-
+ + + + + PR List Failed + + + +
{errorText}
+
+
) -} + } -export function IssueCard({ - input, - output, - errorText, -}: ToolProps) { - if (errorText) { - return ( - - - - - Issue Fetch Failed - - - -
{errorText}
-
-
- ) - } - - if (!output) { - return ( - - - - - Fetching issue #{input.issueNumber}... - - - - ) - } + if (!output) { + return ( + + + + + Fetching pull requests... + + + + ) + } - const issue = output.issue + const prs = (output as { pullRequests?: PullRequest[] }).pullRequests ?? [] - if (!issue) { - return null - } - - return ( - - -
-
- - - #{issue.number} - - - {issue.title} - - -
- Opened by {issue.author} - - - {new Date(issue.createdAt).toLocaleDateString()} - -
-
+ return ( + + + + + Pull Requests ({prs.length}) + + + + +
+ {prs.map((pr: PullRequest) => ( +
+
+
+ + #{pr.number} + + + {pr.title} + +
+ + {pr.state} + +
+
+ {pr.labels.map((label) => ( - {issue.state} + {label} + ))}
- - -
- {issue.labels.map((label) => ( - - {label} - - ))} +
+
+ by {pr.author} +
+ + {new Date( + pr.createdAt + ).toLocaleDateString()} +
+
+ ))} +
+ + + + ) +} - {issue.body && ( -
- {issue.body} -
- )} +export function IssueCard({ + input, + output, + errorText, +}: ToolProps) { + if (errorText) { + return ( + + + + + Issue Fetch Failed + + + +
{errorText}
+
+
+ ) + } -
-
- - {issue.comments} comments -
- - View on GitHub - -
- - + if (!output) { + return ( + + + + + Fetching issue #{(input as any).issueNumber}... + + + ) + } + + const issue = (output as { issue?: Issue }).issue + + if (!issue) { + return null + } + + return ( + + +
+
+ + + #{issue.number} + + + {issue.title} + + +
+ Opened by {issue.author} + + + {new Date(issue.createdAt).toLocaleDateString()} + +
+
+ + {issue.state} + +
+
+ +
+ {issue.labels.map((label) => ( + + {label} + + ))} +
+ + {issue.body && ( +
+ {issue.body} +
+ )} + +
+
+ + {issue.comments} comments +
+ + View on GitHub + +
+
+
+ ) } diff --git a/src/components/ai-elements/tools/index.ts b/src/components/ai-elements/tools/index.ts index 4593317..3ac819b 100644 --- a/src/components/ai-elements/tools/index.ts +++ b/src/components/ai-elements/tools/index.ts @@ -1,22 +1,29 @@ -export { WebScraperTool } from './web-scraper-tool' export { BatchWebScraperTool } from './batch-web-scraper-tool' -export { SiteMapExtractorTool } from './site-map-extractor-tool' -export { LinkExtractorTool } from './link-extractor-tool' export { - FinancialQuoteCard, - FinancialChart, - CompanyProfileCard, + BrowserToolCard, ClickAndExtractCard, + FillFormCard, + GoogleSearchCard, + MonitorPageCard, PdfGeneratorCard, ScreenshotCard +} from './browser-tool' +export { CalculatorCard, MatrixCalculatorCard, UnitConverterCard } from './calculator-tool' +export { + CheckFileExistsCard, CreateDirectoryCard, CreateSandboxCard, DeleteFileCard, GetFileInfoCard, GetFileSizeCard, ListFilesCard, RunCodeCard, RunCommandCard, WatchDirectoryCard, WriteFileCard, + WriteFilesCard +} from './e2b-sandbox-tool' +export { ExecaToolCard } from './execa-tool' +export { + CompanyProfileCard, FinancialChart, FinancialQuoteCard } from './financial-tools' export { - RepositoryCard, - PullRequestList, - IssueCard, - CommitHistoryList, + CommitHistoryList, IssueCard, PullRequestList, RepositoryCard } from './github-tools' -export { WeatherCard, ForecastView } from './weather-tool' +export { LinkExtractorTool } from './link-extractor-tool' +export { PolygonCryptoAggregatesCard, PolygonCryptoQuotesCard, PolygonCryptoSnapshotsCard, PolygonStockAggregatesCard, PolygonStockFundamentalsCard, PolygonStockQuotesCard } from './polygon-tools' export { - ArxivPaperCard, - SearchResultList, - NewsCarousel, + ArxivPaperCard, NewsCarousel, SearchResultList } from './research-tools' +export { SiteMapExtractorTool } from './site-map-extractor-tool' export * from './types' +export { ForecastView, WeatherCard } from './weather-tool' +export { WebScraperTool } from './web-scraper-tool' + diff --git a/src/components/ai-elements/tools/link-extractor-tool.tsx b/src/components/ai-elements/tools/link-extractor-tool.tsx index 4c109cb..7478601 100644 --- a/src/components/ai-elements/tools/link-extractor-tool.tsx +++ b/src/components/ai-elements/tools/link-extractor-tool.tsx @@ -2,151 +2,150 @@ import { Badge } from '@/ui/badge' import { Card, CardContent, CardHeader, CardTitle } from '@/ui/card' -import { ExternalLink, Link, CheckCircle, XCircle } from 'lucide-react' +import { CheckCircle, ExternalLink, Link, XCircle } from 'lucide-react' import type { LinkExtractorUITool } from './types' interface LinkExtractorToolProps { - toolCallId: string - input: LinkExtractorUITool['input'] - output?: LinkExtractorUITool['output'] - errorText?: string + toolCallId: string + input: LinkExtractorUITool['input'] + output?: LinkExtractorUITool['output'] + errorText?: string } export function LinkExtractorTool({ - input, - output, - errorText, + input, + output, + errorText, }: LinkExtractorToolProps) { - if (errorText) { - return ( -
- - - - - Link Extraction Failed - - - -
- {errorText} -
-
-
+ if (errorText) { + return ( +
+ + + + + Link Extraction Failed + + + +
+ {errorText}
- ) - } +
+
+
+ ) + } - if (!output) { - return ( - - - - - Extracting links from {input.url}... - - - -
- Finding internal and external links -
-
-
- ) - } + if (!output) { + return ( + + + + + Extracting links from {(input as { url: string }).url}... + + + +
+ Finding internal and external links +
+
+
+ ) + } - const { links, summary } = output + const { links, summary } = output as { links: any[], summary: any, url: string } - return ( -
- {/* Summary Header */} - - - - - Links Extracted from {output.url} - - - -
- - {summary.total} total links - - - {summary.internal} internal - - - {summary.external} external - - {summary.invalid > 0 && ( - - {summary.invalid} invalid - - )} -
-
-
+ return ( +
+ {/* Summary Header */} + + + + + Links Extracted from {(output as any).url} + + + +
+ + {summary.total} total links + + + {summary.internal} internal + + + {summary.external} external + + {summary.invalid > 0 && ( + + {summary.invalid} invalid + + )} +
+
+
- {/* Links List */} - - - Extracted Links - - -
- {links.map((link, index) => ( -
- {link.isValid ? ( - - ) : ( - - )} + {/* Links List */} + + + Extracted Links + + +
+ {links.map((link: any, index: number) => ( +
+ {link.isValid ? ( + + ) : ( + + )} -
-
- - {link.type} - - {link.text && ( - - {link.text} - - )} -
-
- {link.href} -
-
+
+
+ + {link.type} + + {link.text && ( + + {link.text} + + )} +
+
+ {link.href} +
+
- {link.isValid && ( - - - - )} -
- ))} -
-
-
-
- ) + {link.isValid && ( + + + + )} +
+ ))} +
+ + +
+ ) } diff --git a/src/components/ai-elements/tools/polygon-tools.tsx b/src/components/ai-elements/tools/polygon-tools.tsx new file mode 100644 index 0000000..1725184 --- /dev/null +++ b/src/components/ai-elements/tools/polygon-tools.tsx @@ -0,0 +1,418 @@ +'use client' + +import type { + PolygonCryptoAggregatesUITool, + PolygonCryptoQuotesUITool, + PolygonCryptoSnapshotsUITool, + PolygonStockAggregatesUITool, + PolygonStockFundamentalsUITool, + PolygonStockQuotesUITool, +} from './types' + +import { Badge } from '@/ui/badge' +import { Button } from '@/ui/button' +import { Card, CardContent, CardHeader, CardTitle } from '@/ui/card' +import { Input } from '@/ui/input' +import { ScrollArea } from '@/ui/scroll-area' +import { + AlertCircle, + ChartBar, + Clock, + CopyIcon, + Download, + ExternalLink, + FileText, + Loader2, + Search, +} from 'lucide-react' +import { useEffect, useRef, useState, type ChangeEvent } from 'react' +import { CodeBlock, CodeBlockCopyButton } from '../code-block' + +/* Utility helpers */ +function formatNumber(n?: number | string) { + if (n == null) return 'N/A' + const num = typeof n === 'string' ? Number(n) : n + if (Number.isNaN(num)) return String(n) + return num >= 1000 ? num.toLocaleString() : num.toString() +} + +function formatTime(ts?: number | string) { + if (!ts) return 'N/A' + // polygon often uses unix ms timestamps or ISO + const t = typeof ts === 'string' && /^\d+$/.test(ts) ? Number(ts) : ts + const date = typeof t === 'number' ? new Date(t) : new Date(String(t)) + return isNaN(date.getTime()) ? String(ts) : date.toLocaleString() +} + +function downloadJSON(filename: string, data: any) { + try { + const content = JSON.stringify(data, null, 2) + const blob = new Blob([content], { type: 'application/json' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = filename + document.body.appendChild(a) + a.click() + a.remove() + URL.revokeObjectURL(url) + } catch (e) { + // noop + } +} + +/* Small UI pieces */ +function LoadingCard({ title, subtitle, icon }: { title: string; subtitle?: string; icon?: React.ReactNode }) { + return ( + + + {icon}{title} + + {subtitle &&
{subtitle}
} +
+ ) +} + +function ErrorCard({ title, message }: { title: string; message?: string }) { + return ( + + + + + {title} + + +
{message}
+
+ ) +} + +/* Polygon Stock Quotes */ +export function PolygonStockQuotesCard({ + toolCallId, + input, + output, + errorText, +}: { + toolCallId: string + input: PolygonStockQuotesUITool['input'] + output?: PolygonStockQuotesUITool['output'] + errorText?: string +}) { + const [query, setQuery] = useState('') + const [copied, setCopied] = useState(false) + const bottomRef = useRef(null) + + useEffect(() => { + if (bottomRef.current) bottomRef.current.scrollIntoView({ behavior: 'smooth', block: 'end' }) + }, [output]) + + if (errorText) return + if (!output) return } /> + if ('error' in output) return + + const data = (output as any).data ?? [] + const filtered = query ? data.filter((p: any) => JSON.stringify(p).toLowerCase().includes(query.toLowerCase())) : data + + const copyRaw = async () => { + try { + await navigator.clipboard.writeText(JSON.stringify(data, null, 2)) + setCopied(true) + setTimeout(() => setCopied(false), 1200) + } catch { } + } + + return ( +
+ + + Quotes: {input.symbol} +
+ {(output as any).metadata?.count ?? data.length} points + + +
+
+ +
+ ) => setQuery(e.target.value)} placeholder="Filter quotes..." className="w-64 text-sm" /> + +
+ + {filtered.length === 0 ? ( +
No quotes match
+ ) : ( + +
+ {filtered.map((row: any, idx: number) => ( +
+
+
+ {formatTime(row.t ?? row.timestamp ?? row.tradetime ?? row.time) || `#${idx + 1}`} +
+
Close: {formatNumber(row.c ?? row.close ?? row.price)}
+
+
{formatNumber(row.v ?? row.volume ?? '')}
+
+ ))} +
+
+ + )} + + + + + + Raw Data + + + + + + + + +
+ ) +} + +/* Polygon Stock Aggregates */ +export function PolygonStockAggregatesCard({ + toolCallId, + input, + output, + errorText, +}: { + toolCallId: string + input: PolygonStockAggregatesUITool['input'] + output?: PolygonStockAggregatesUITool['output'] + errorText?: string +}) { + if (errorText) return + if (!output) return } /> + if ('error' in output) return + + const data = (output as any).data ?? [] + const meta = (output as any).metadata ?? {} + + return ( +
+ + + Aggregates: {input.symbol} +
+ {meta.count ?? data.length} bars + +
+
+ + {data.length === 0 ?
No aggregates
: ( + +
+ {data.map((row: any, i: number) => ( +
+
+
{formatTime(row.t ?? row.timestamp)}
+
O {formatNumber(row.o)} H {formatNumber(row.h)} L {formatNumber(row.l)} C {formatNumber(row.c)}
+
+
{formatNumber(row.v ?? row.vw ?? row.vwap ?? '')}
+
+ ))} +
+
+ )} +
+
+ + + + Raw Aggregates + + + + + + + + +
+ ) +} + +/* Polygon Stock Fundamentals */ +export function PolygonStockFundamentalsCard({ + toolCallId, + input, + output, + errorText, +}: { + toolCallId: string + input: PolygonStockFundamentalsUITool['input'] + output?: PolygonStockFundamentalsUITool['output'] + errorText?: string +}) { + if (errorText) return + if (!output) return } /> + if ('error' in output) return + + const data = (output as any).data ?? {} + const entries = typeof data === 'object' ? Object.entries(data) : [] + + return ( + + + Fundamentals: {input.symbol} +
+ +
+
+ + {entries.length === 0 ? ( +
No fundamental data available
+ ) : ( +
+ {entries.map(([k, v]) => ( +
+
{k}
+
{String(v)}
+
+ ))} +
+ )} +
+
+ ) +} + +/* Polygon Crypto Quotes */ +export function PolygonCryptoQuotesCard({ + toolCallId, + input, + output, + errorText, +}: { + toolCallId: string + input: PolygonCryptoQuotesUITool['input'] + output?: PolygonCryptoQuotesUITool['output'] + errorText?: string +}) { + const [filter, setFilter] = useState('') + + if (errorText) return + if (!output) return } /> + if ('error' in output) return + + const data = (output as any).data ?? [] + const filtered = filter ? data.filter((d: any) => JSON.stringify(d).toLowerCase().includes(filter.toLowerCase())) : data + + return ( +
+ + + Crypto Quotes: {input.symbol} +
+ ) => setFilter(e.target.value)} placeholder="Filter..." className="w-56 text-sm" /> + + +
+
+ + {filtered.length === 0 ?
No quotes
: ( + +
+ {filtered.map((r: any, i: number) => ( +
+
+
{formatTime(r.t ?? r.timestamp)}
+
Price: {formatNumber(r.c ?? r.price)}
+
+
{formatNumber(r.v ?? r.volume)}
+
+ ))} +
+
+ )} +
+
+
+ ) +} + +/* Polygon Crypto Aggregates */ +export function PolygonCryptoAggregatesCard({ + toolCallId, + input, + output, + errorText, +}: { + toolCallId: string + input: PolygonCryptoAggregatesUITool['input'] + output?: PolygonCryptoAggregatesUITool['output'] + errorText?: string +}) { + if (errorText) return + if (!output) return } /> + if ('error' in output) return + + const data = (output as any).data ?? [] + return ( + + + Crypto Aggregates: {input.symbol} +
+
+ +
+
{(output as any).metadata?.message ?? 'Aggregates retrieved'}
+
+
+
+ ) +} + +/* Polygon Crypto Snapshots */ +export function PolygonCryptoSnapshotsCard({ + toolCallId, + input, + output, + errorText, +}: { + toolCallId: string + input: PolygonCryptoSnapshotsUITool['input'] + output?: PolygonCryptoSnapshotsUITool['output'] + errorText?: string +}) { + if (errorText) return + if (!output) return } /> + if ('error' in output) return + + const data = (output as any).data ?? [] + return ( + + + Crypto Snapshots: {input.symbol} +
+
+ + {Array.isArray(data) ? ( + +
+ {data.map((s: any, i: number) => ( +
+
+
{formatTime(s.t ?? s.timestamp)}
+
Price: {formatNumber(s.c ?? s.price)}
+
+
{formatNumber(s.v ?? s.volume)}
+
+ ))} +
+
+ ) : ( +
No snapshots available
+ )} +
+
+ ) +} diff --git a/src/components/ai-elements/tools/site-map-extractor-tool.tsx b/src/components/ai-elements/tools/site-map-extractor-tool.tsx index 561ff5e..2958993 100644 --- a/src/components/ai-elements/tools/site-map-extractor-tool.tsx +++ b/src/components/ai-elements/tools/site-map-extractor-tool.tsx @@ -2,170 +2,170 @@ import { Badge } from '@/ui/badge' import { Card, CardContent, CardHeader, CardTitle } from '@/ui/card' -import { TreePine, Link, ExternalLink, FileText } from 'lucide-react' +import { ExternalLink, FileText, Link, TreePine } from 'lucide-react' import type { SiteMapExtractorUITool } from './types' interface SiteMapExtractorToolProps { - toolCallId: string - input: SiteMapExtractorUITool['input'] - output?: SiteMapExtractorUITool['output'] - errorText?: string + toolCallId: string + input: SiteMapExtractorUITool['input'] + output?: SiteMapExtractorUITool['output'] + errorText?: string } export function SiteMapExtractorTool({ - input, - output, - errorText, + input, + output, + errorText, }: SiteMapExtractorToolProps) { - if (errorText) { - return ( -
- - - - - Site Map Extraction Failed - - - -
- {errorText} -
-
-
+ if (errorText) { + return ( +
+ + + + + Site Map Extraction Failed + + + +
+ {errorText}
- ) - } +
+
+
+ ) + } - if (!output) { - return ( - - - - - Extracting site map from {input.url}... - - - -
- Crawling up to depth {input.maxDepth ?? 2}, max{' '} - {input.maxPages ?? 50} pages -
-
-
- ) - } + if (!output) { + return ( + + + + + Extracting site map from {(input as any).url}... + + + +
+ Crawling up to depth {(input as any).maxDepth ?? 2}, max{' '} + {(input as any).maxPages ?? 50} pages +
+
+
+ ) + } - const { pages, totalPages } = output + const { pages, totalPages } = output as any - // Group pages by depth for hierarchical display - const pagesByDepth = pages.reduce( - (acc, page) => { - if (!acc[page.depth]) { - acc[page.depth] = [] - } - acc[page.depth].push(page) - return acc - }, - {} as Record - ) + // Group pages by depth for hierarchical display + const pagesByDepth = pages.reduce( + (acc: Record, page: typeof pages[number]) => { + if (!acc[page.depth]) { + acc[page.depth] = [] + } + acc[page.depth].push(page) + return acc + }, + {} as Record + ) - return ( -
- {/* Summary Header */} - - - - - Site Map Extracted - - - -
- - {totalPages} pages discovered - - - Depth: {Math.max(...pages.map((p) => p.depth))} - -
-
-
+ return ( +
+ {/* Summary Header */} + + + + + Site Map Extracted + + + +
+ + {totalPages} pages discovered + + + Depth: {Math.max(...pages.map((p: typeof pages[number]) => p.depth))} + +
+
+
- {/* Site Structure */} - - - Site Structure - - -
- {Object.entries(pagesByDepth) - .sort(([a], [b]) => Number(a) - Number(b)) - .map(([depth, depthPages]) => ( -
-
-
- Depth {depth} - - {depthPages.length} pages - -
-
- {depthPages.map((page, index) => ( -
- -
-
- {page.title ?? - page.url - .split('/') - .pop() ?? - 'Untitled'} -
-
- {page.url} -
-
-
- - { - page.internalLinks - .length - }{' '} - internal - - {page.externalLinks.length > - 0 && ( - - { - page - .externalLinks - .length - }{' '} - external - - )} -
-
- ))} -
-
- ))} -
- - -
- ) + {/* Site Structure */} + + + Site Structure + + +
+ {Object.entries(pagesByDepth) + .sort(([a], [b]) => Number(a) - Number(b)) + .map(([depth, depthPages]) => ( +
+
+
+ Depth {depth} + + {(depthPages as typeof pages).length} pages + +
+
+ {(depthPages as typeof pages).map((page: typeof pages[number], index: number) => ( +
+ +
+
+ {page.title ?? + page.url + .split('/') + .pop() ?? + 'Untitled'} +
+
+ {page.url} +
+
+
+ + { + page.internalLinks + .length + }{' '} + internal + + {page.externalLinks.length > + 0 && ( + + { + page + .externalLinks + .length + }{' '} + external + + )} +
+
+ ))} +
+
+ ))} +
+ + +
+ ) } diff --git a/src/components/ai-elements/tools/types.ts b/src/components/ai-elements/tools/types.ts index b9f8574..452a491 100644 --- a/src/components/ai-elements/tools/types.ts +++ b/src/components/ai-elements/tools/types.ts @@ -1,148 +1,151 @@ -import type { InferUITool } from '@mastra/core/tools' import type { - activeDistTag, - addIssueComment, - alphaVantageCryptoTool, - alphaVantageStockTool, - alphaVantageTool, - amazonSearchTool, - apiDataFetcherTool, - archiveDataTool, - arxivPaperDownloaderTool, - arxivPdfParserTool, - arxivTool, - backupDataTool, - batchWebScraperTool, - browserTool, - chartDataProcessorTool, - chartGeneratorTool, - chartSupervisorTool, - chartTypeAdvisorTool, - checkFileExists, - clickAndExtractTool, - codeAnalysisTool, - codeChunkerTool, - codeSearchTool, - colorChangeTool, - contentCleanerTool, - copyDataFileTool, - copywriterTool, - createDataDirTool, - createDirectory, - createIssue, - createPullRequest, - createRelease, - createSandbox, - csvToExcalidrawTool, - csvToJsonTool, - dataExporterTool, - dataValidatorToolJSON, - deleteDataFileTool, - deleteFile, - diffReviewTool, - documentRerankerTool, - ebaySearchTool, - editorTool, - evaluateResultTool, - excalidrawToSVGTool, - execaTool, - extractLearningsTool, - extractTablesTool, - fillFormTool, - findFreeSlots, - findReferencesTool, - findSymbolTool, - finnhubAnalysisTool, - finnhubCompanyTool, - finnhubEconomicTool, - finnhubFinancialsTool, - finnhubQuotesTool, - finnhubTechnicalTool, - fsTool, - getDataFileInfoTool, - getFileContent, - getFileInfo, - getFileSize, - getIssue, - getPullRequest, - getRepoFileTree, - getRepositoryInfo, - getTodayEvents, - getUpcomingEvents, - googleAiOverviewTool, - googleAutocompleteTool, - googleFinanceTool, - googleNewsLiteTool, - googleNewsTool, - googleScholarTool, - googleSearch, - googleSearchTool, - googleTrendsTool, - homeDepotSearchTool, - htmlToMarkdownTool, - imageToCSVTool, - jsonToCsvTool, - jwtAuthTool, - linkExtractorTool, - listCommits, - listDataDirTool, - listEvents, - listFiles, - listIssues, - listPullRequests, - listRepositories, - listScrapedContentTool, - mastraChunker, - mdocumentChunker, - mergePullRequest, - monitorPageTool, - moveDataFileTool, - multiStringEditTool, - pdfGeneratorTool, - pdfToMarkdownTool, - pnpmBuild, - pnpmChangesetPublish, - pnpmChangesetStatus, - pnpmRun, - polygonCryptoAggregatesTool, - polygonCryptoQuotesTool, - polygonCryptoSnapshotsTool, - polygonStockAggregatesTool, - polygonStockFundamentalsTool, - polygonStockQuotesTool, - processSVGTool, - processXMLTool, - readCSVDataTool, - readDataFileTool, - readFile, - readPDF, - removeDataDirTool, - runCode, - runCommand, - scrapingSchedulerTool, - screenshotTool, - searchCode, - searchDataFilesTool, - siteMapExtractorTool, - svgToExcalidrawTool, - testGeneratorTool, - validateDataTool, - validateExcalidrawTool, - walmartSearchTool, - watchDirectory, - weatherTool, - webScraperTool, - writeDataFileTool, - writeFile, - writeFiles, - writeNoteTool, - yelpSearchTool, + activeDistTag, + addIssueComment, + alphaVantageCryptoTool, + alphaVantageStockTool, + alphaVantageTool, + amazonSearchTool, + apiDataFetcherTool, + archiveDataTool, + arxivPaperDownloaderTool, + arxivPdfParserTool, + arxivTool, + backupDataTool, + batchWebScraperTool, + browserTool, + calculatorTool, + chartDataProcessorTool, + chartGeneratorTool, + chartSupervisorTool, + chartTypeAdvisorTool, + checkFileExists, + clickAndExtractTool, + codeAnalysisTool, + codeChunkerTool, + codeSearchTool, + colorChangeTool, + contentCleanerTool, + copyDataFileTool, + copywriterTool, + createDataDirTool, + createDirectory, + createIssue, + createPullRequest, + createRelease, + createSandbox, + csvToExcalidrawTool, + csvToJsonTool, + dataExporterTool, + dataValidatorToolJSON, + deleteDataFileTool, + deleteFile, + diffReviewTool, + documentRerankerTool, + ebaySearchTool, + editorTool, + evaluateResultTool, + excalidrawToSVGTool, + execaTool, + extractLearningsTool, + extractTablesTool, + fillFormTool, + findFreeSlots, + findReferencesTool, + findSymbolTool, + finnhubAnalysisTool, + finnhubCompanyTool, + finnhubEconomicTool, + finnhubFinancialsTool, + finnhubQuotesTool, + finnhubTechnicalTool, + fsTool, + getDataFileInfoTool, + getFileContent, + getFileInfo, + getFileSize, + getIssue, + getPullRequest, + getRepoFileTree, + getRepositoryInfo, + getTodayEvents, + getUpcomingEvents, + googleAiOverviewTool, + googleAutocompleteTool, + googleFinanceTool, + googleNewsLiteTool, + googleNewsTool, + googleScholarTool, + googleSearch, + googleSearchTool, + googleTrendsTool, + homeDepotSearchTool, + htmlToMarkdownTool, + imageToCSVTool, + jsonToCsvTool, + jwtAuthTool, + linkExtractorTool, + listCommits, + listDataDirTool, + listEvents, + listFiles, + listIssues, + listPullRequests, + listRepositories, + listScrapedContentTool, + mastraChunker, + matrixCalculatorTool, + mdocumentChunker, + mergePullRequest, + monitorPageTool, + moveDataFileTool, + multiStringEditTool, + pdfGeneratorTool, + pdfToMarkdownTool, + pnpmBuild, + pnpmChangesetPublish, + pnpmChangesetStatus, + pnpmRun, + polygonCryptoAggregatesTool, + polygonCryptoQuotesTool, + polygonCryptoSnapshotsTool, + polygonStockAggregatesTool, + polygonStockFundamentalsTool, + polygonStockQuotesTool, + processSVGTool, + processXMLTool, + readCSVDataTool, + readDataFileTool, + readFile, + readPDF, + removeDataDirTool, + runCode, + runCommand, + scrapingSchedulerTool, + screenshotTool, + searchCode, + searchDataFilesTool, + siteMapExtractorTool, + svgToExcalidrawTool, + testGeneratorTool, + unitConverterTool, + validateDataTool, + validateExcalidrawTool, + walmartSearchTool, + watchDirectory, + weatherTool, + webScraperTool, + writeDataFileTool, + writeFile, + writeFiles, + writeNoteTool, + yelpSearchTool, } from '@/src/mastra/tools' +import type { InferUITool } from '@mastra/core/tools' export type ActiveDistTagUITool = InferUITool export type AddIssueCommentUITool = InferUITool export type AlphaVantageCryptoUITool = InferUITool< - typeof alphaVantageCryptoTool + typeof alphaVantageCryptoTool > export type AlphaVantageStockUITool = InferUITool export type AlphaVantageUITool = InferUITool @@ -150,7 +153,7 @@ export type AmazonSearchUITool = InferUITool export type ApiDataFetcherUITool = InferUITool export type ArchiveDataUITool = InferUITool export type ArxivPaperDownloaderUITool = InferUITool< - typeof arxivPaperDownloaderTool + typeof arxivPaperDownloaderTool > export type ArxivPdfParserUITool = InferUITool export type ArxivUITool = InferUITool @@ -158,7 +161,7 @@ export type BackupDataUITool = InferUITool export type BatchWebScraperUITool = InferUITool export type BrowserUITool = InferUITool export type ChartDataProcessorUITool = InferUITool< - typeof chartDataProcessorTool + typeof chartDataProcessorTool > export type ChartGeneratorUITool = InferUITool export type ChartSupervisorUITool = InferUITool @@ -183,7 +186,7 @@ export type CsvToExcalidrawUITool = InferUITool export type CsvToJsonUITool = InferUITool export type DataExporterUITool = InferUITool export type DataValidatorToolJSONUITool = InferUITool< - typeof dataValidatorToolJSON + typeof dataValidatorToolJSON > export type DeleteDataFileUITool = InferUITool export type DeleteFileUITool = InferUITool @@ -219,7 +222,7 @@ export type GetTodayEventsUITool = InferUITool export type GetUpcomingEventsUITool = InferUITool export type GoogleAiOverviewUITool = InferUITool export type GoogleAutocompleteUITool = InferUITool< - typeof googleAutocompleteTool + typeof googleAutocompleteTool > export type GoogleFinanceUITool = InferUITool export type GoogleNewsLiteUITool = InferUITool @@ -242,7 +245,7 @@ export type ListIssuesUITool = InferUITool export type ListPullRequestsUITool = InferUITool export type ListRepositoriesUITool = InferUITool export type ListScrapedContentUITool = InferUITool< - typeof listScrapedContentTool + typeof listScrapedContentTool > export type MastraChunkerUITool = InferUITool export type MdocumentChunkerUITool = InferUITool @@ -254,27 +257,27 @@ export type PdfGeneratorUITool = InferUITool export type PdfToMarkdownUITool = InferUITool export type PnpmBuildUITool = InferUITool export type PnpmChangesetPublishUITool = InferUITool< - typeof pnpmChangesetPublish + typeof pnpmChangesetPublish > export type PnpmChangesetStatusUITool = InferUITool export type PnpmRunUITool = InferUITool export type PolygonCryptoAggregatesUITool = InferUITool< - typeof polygonCryptoAggregatesTool + typeof polygonCryptoAggregatesTool > export type PolygonCryptoQuotesUITool = InferUITool< - typeof polygonCryptoQuotesTool + typeof polygonCryptoQuotesTool > export type PolygonCryptoSnapshotsUITool = InferUITool< - typeof polygonCryptoSnapshotsTool + typeof polygonCryptoSnapshotsTool > export type PolygonStockAggregatesUITool = InferUITool< - typeof polygonStockAggregatesTool + typeof polygonStockAggregatesTool > export type PolygonStockFundamentalsUITool = InferUITool< - typeof polygonStockFundamentalsTool + typeof polygonStockFundamentalsTool > export type PolygonStockQuotesUITool = InferUITool< - typeof polygonStockQuotesTool + typeof polygonStockQuotesTool > export type ProcessSVGUITool = InferUITool export type ProcessXMLUITool = InferUITool @@ -284,6 +287,9 @@ export type ReadFileUITool = InferUITool export type ReadPDFUITool = InferUITool export type RemoveDataDirUITool = InferUITool export type RunCodeUITool = InferUITool +export type CalculatorUITool = InferUITool +export type UnitConverterUITool = InferUITool +export type MatrixCalculatorUITool = InferUITool export type RunCommandUITool = InferUITool export type ScrapingSchedulerUITool = InferUITool export type ScreenshotUITool = InferUITool @@ -294,7 +300,7 @@ export type SvgToExcalidrawUITool = InferUITool export type TestGeneratorUITool = InferUITool export type ValidateDataUITool = InferUITool export type ValidateExcalidrawUITool = InferUITool< - typeof validateExcalidrawTool + typeof validateExcalidrawTool > export type WalmartSearchUITool = InferUITool export type WatchDirectoryUITool = InferUITool diff --git a/src/components/ai-elements/tools/web-scraper-tool.tsx b/src/components/ai-elements/tools/web-scraper-tool.tsx index 9f71b09..0759b1b 100644 --- a/src/components/ai-elements/tools/web-scraper-tool.tsx +++ b/src/components/ai-elements/tools/web-scraper-tool.tsx @@ -4,301 +4,300 @@ import { Badge } from '@/ui/badge' import { Card, CardContent, CardHeader, CardTitle } from '@/ui/card' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/ui/tabs' import { - ExternalLink, - FileText, - Globe, - Image as ImageIcon, - Link, + ExternalLink, + FileText, + Globe, + Image as ImageIcon, + Link, } from 'lucide-react' -import type { WebScraperUITool } from './types' import { CodeBlock } from '../code-block' +import type { WebScraperUITool } from './types' interface WebScraperToolProps { - toolCallId: string - input: WebScraperUITool['input'] - output?: WebScraperUITool['output'] - errorText?: string + toolCallId: string + input: WebScraperUITool['input'] + output?: WebScraperUITool['output'] + errorText?: string } export function WebScraperTool({ - input, - output, - errorText, + input, + output, + errorText, }: WebScraperToolProps) { - if (errorText) { - return ( -
- - - - - Web Scraping Failed - - - -
- {errorText} -
-
-
+ if (errorText) { + return ( +
+ + + + + Web Scraping Failed + + + +
+ {errorText}
- ) - } +
+
+
+ ) + } - if (!output) { - return ( - - - - - Scraping {input.url}... - - - -
- Extracting content with selector:{' '} - {input.selector || 'entire page'} -
-
-
- ) - } + if (!output) { + return ( + + + + + Scraping {(input as any).url}... + + + +
+ Extracting content with selector:{' '} + {(input as any).selector || 'entire page'} +
+
+
+ ) + } - const content = output.content || {} - const { - extractedData, - rawContent, - markdownContent, - } = content + const content = (output as any).content || {} + const { + extractedData, + rawContent, + markdownContent, + } = content - const { - metadata, - images, - structuredData, - } = output.analysis || {} + const { + metadata, + images, + } = (output as any).analysis || {} - return ( -
- {/* Success Header */} - - - - - Successfully scraped {output.url} - - - -
- - {extractedData.length} elements extracted - - {markdownContent && ( - - - Markdown generated - - )} - {images && images.length > 0 && ( - - - {images.length} images found - - )} -
-
-
+ return ( +
+ {/* Success Header */} + + + + + Successfully scraped {(output as any).url} + + + +
+ + {extractedData.length} elements extracted + + {markdownContent && ( + + + Markdown generated + + )} + {images && images.length > 0 && ( + + + {images.length} images found + + )} +
+
+
- {/* Content Tabs */} - - - - Extracted Data - - - Markdown - - - Metadata - - - Images - - - Raw HTML - - + {/* Content Tabs */} + + + + Extracted Data + + + Markdown + + + Metadata + + + Images + + + Raw HTML + + - - - - - Extracted Elements - - - - {extractedData.length === 0 ? ( -
- No elements matched the selector -
- ) : ( -
- {extractedData.map((item, index) => ( -
-
- Element {index + 1} -
- -
- ))} -
- )} -
-
-
+ + + + + Extracted Elements + + + + {extractedData.length === 0 ? ( +
+ No elements matched the selector +
+ ) : ( +
+ {extractedData.map((item: any, index: number) => ( +
+
+ Element {index + 1} +
+ +
+ ))} +
+ )} +
+
+
- - - - - Converted Markdown - - - - {markdownContent ? ( -
-
-                                        {markdownContent}
-                                    
-
- ) : ( -
- No markdown content available -
- )} -
-
-
+ + + + + Converted Markdown + + + + {markdownContent ? ( +
+
+                    {markdownContent}
+                  
+
+ ) : ( +
+ No markdown content available +
+ )} +
+
+
- - - - - Page Metadata - - - - {metadata && Object.keys(metadata).length > 0 ? ( -
- {Object.entries(metadata).map( - ([key, value]) => ( -
-
- {key - .replace( - /([A-Z])/g, - ' $1' - ) - .trim()} -
-
- {String(value || 'N/A')} -
-
- ) - )} -
- ) : ( -
- No metadata available -
- )} -
-
-
+ + + + + Page Metadata + + + + {metadata && Object.keys(metadata).length > 0 ? ( +
+ {Object.entries(metadata).map( + ([key, value]) => ( +
+
+ {key + .replace( + /([A-Z])/g, + ' $1' + ) + .trim()} +
+
+ {String(value || 'N/A')} +
+
+ ) + )} +
+ ) : ( +
+ No metadata available +
+ )} +
+
+
- - - - - Images Found - - - - {images && images.length > 0 ? ( -
- {images.map((image, index) => ( -
- -
-
- {image.alt || - `Image ${index + 1}`} -
-
- {image.src} -
-
- - - -
- ))} -
- ) : ( -
- No images found -
- )} -
-
-
+ + + + + Images Found + + + + {images && images.length > 0 ? ( +
+ {images.map((image: any, index: number) => ( +
+ +
+
+ {image.alt || + `Image ${index + 1}`} +
+
+ {image.src} +
+
+ + + +
+ ))} +
+ ) : ( +
+ No images found +
+ )} +
+
+
- - - - - Raw HTML Content - - - - {rawContent ? ( - - ) : ( -
- No raw content available -
- )} -
-
-
-
-
- ) + + + + + Raw HTML Content + + + + {rawContent ? ( + + ) : ( +
+ No raw content available +
+ )} +
+
+
+ +
+ ) } diff --git a/src/mastra/a2a/a2aCoordinatorAgent.ts b/src/mastra/a2a/a2aCoordinatorAgent.ts index c8af820..abc5af0 100644 --- a/src/mastra/a2a/a2aCoordinatorAgent.ts +++ b/src/mastra/a2a/a2aCoordinatorAgent.ts @@ -1,26 +1,26 @@ +import { GoogleGenerativeAIProviderOptions } from '@ai-sdk/google' import { Agent } from '@mastra/core/agent' import { - createAnswerRelevancyScorer, - createToxicityScorer, + createAnswerRelevancyScorer, + createToxicityScorer, } from '@mastra/evals/scorers/prebuilt' -import { copywriterAgent } from '../agents/copywriterAgent' -import { editorAgent } from '../agents/editorAgent' -import { researchAgent } from '../agents/researchAgent' -import { knowledgeIndexingAgent } from '../agents/knowledgeIndexingAgent' import { - codeArchitectAgent, - codeReviewerAgent, - testEngineerAgent, - refactoringAgent, + codeArchitectAgent, + codeReviewerAgent, + refactoringAgent, + testEngineerAgent, } from '../agents/codingAgents' import { contentStrategistAgent } from '../agents/contentStrategistAgent' +import { copywriterAgent } from '../agents/copywriterAgent' +import { editorAgent } from '../agents/editorAgent' +import { knowledgeIndexingAgent } from '../agents/knowledgeIndexingAgent' import { projectManagementAgent } from '../agents/projectManagementAgent' -import { researchSynthesisWorkflow } from '../workflows/research-synthesis-workflow' -import { repoIngestionWorkflow } from '../workflows/repo-ingestion-workflow' -import { specGenerationWorkflow } from '../workflows/spec-generation-workflow' +import { researchAgent } from '../agents/researchAgent' import { googleAI, googleAIFlashLite } from '../config/google' import { pgMemory } from '../config/pg-storage' -import type { RequestContext } from '@mastra/core/request-context' +import { repoIngestionWorkflow } from '../workflows/repo-ingestion-workflow' +import { researchSynthesisWorkflow } from '../workflows/research-synthesis-workflow' +import { specGenerationWorkflow } from '../workflows/spec-generation-workflow' // Import all agents // Import all workflows @@ -35,15 +35,15 @@ import type { RequestContext } from '@mastra/core/request-context' */ export const a2aCoordinatorAgent = new Agent({ - id: 'a2aCoordinator', - name: 'a2aCoordinator', - description: - 'A2A Coordinator that orchestrates multiple specialized agents in parallel. Routes tasks dynamically, coordinates workflows, and synthesizes results using the A2A protocol.', - instructions: ({ requestContext }) => { - const userId = requestContext.get('userId') - return { - role: 'system', - content: `You are an A2A (Agent-to-Agent) Coordinator that orchestrates multi-agent workflows. + id: 'a2aCoordinator', + name: 'a2aCoordinator', + description: + 'A2A Coordinator that orchestrates multiple specialized agents in parallel. Routes tasks dynamically, coordinates workflows, and synthesizes results using the A2A protocol.', + instructions: ({ requestContext }) => { + const userId = requestContext.get('userId') + return { + role: 'system', + content: `You are an A2A (Agent-to-Agent) Coordinator that orchestrates multi-agent workflows. userId: ${userId} CORE CAPABILITIES: - Orchestrate multiple agents working in parallel @@ -91,49 +91,49 @@ Use Promise.all() pattern for parallel execution. Maximize the use of E2B sandboxes via specialized agents for any code-related tasks. Use knowledgeIndexingAgent to provide semantic context for complex queries. `, - providerOptions: { - google: { - thinkingConfig: { - thinkingLevel: 'high', - includeThoughts: true, - thinkingBudget: -1, - }, - mediaResolution: 'MEDIA_RESOLUTION_MEDIUM', - responseModalities: ['TEXT', 'IMAGE'], - }, - }, - } - }, - model: googleAI, - memory: pgMemory, - options: {}, - agents: { - researchAgent, - knowledgeIndexingAgent, - editorAgent, - copywriterAgent, - codeArchitectAgent, - codeReviewerAgent, - testEngineerAgent, - refactoringAgent, - contentStrategistAgent, - projectManagementAgent, - }, - workflows: { - researchSynthesisWorkflow, - repoIngestionWorkflow, - specGenerationWorkflow, + providerOptions: { + google: { + thinkingConfig: { + thinkingLevel: 'high', + includeThoughts: true, + thinkingBudget: -1, + }, + mediaResolution: 'MEDIA_RESOLUTION_MEDIUM', + responseModalities: ['TEXT', 'IMAGE'], + } satisfies GoogleGenerativeAIProviderOptions, + }, + } + }, + model: googleAI, + memory: pgMemory, + options: {}, + agents: { + researchAgent, + knowledgeIndexingAgent, + editorAgent, + copywriterAgent, + codeArchitectAgent, + codeReviewerAgent, + testEngineerAgent, + refactoringAgent, + contentStrategistAgent, + projectManagementAgent, + }, + workflows: { + researchSynthesisWorkflow, + repoIngestionWorkflow, + specGenerationWorkflow, + }, + maxRetries: 5, + tools: {}, + scorers: { + relevancy: { + scorer: createAnswerRelevancyScorer({ model: googleAIFlashLite }), + sampling: { type: 'ratio', rate: 0.4 }, }, - maxRetries: 5, - tools: {}, - scorers: { - relevancy: { - scorer: createAnswerRelevancyScorer({ model: googleAIFlashLite }), - sampling: { type: 'ratio', rate: 0.4 }, - }, - safety: { - scorer: createToxicityScorer({ model: googleAIFlashLite }), - sampling: { type: 'ratio', rate: 0.3 }, - }, + safety: { + scorer: createToxicityScorer({ model: googleAIFlashLite }), + sampling: { type: 'ratio', rate: 0.3 }, }, + }, }) diff --git a/src/mastra/a2a/codingA2ACoordinator.ts b/src/mastra/a2a/codingA2ACoordinator.ts index 822b3df..e5718d7 100644 --- a/src/mastra/a2a/codingA2ACoordinator.ts +++ b/src/mastra/a2a/codingA2ACoordinator.ts @@ -8,6 +8,7 @@ import { googleAIFlashLite } from '../config/google' import { log } from '../config/logger' import { pgMemory } from '../config/pg-storage' +import { GoogleGenerativeAIProviderOptions } from '@ai-sdk/google' import { InternalSpans } from '@mastra/core/observability' import { codeArchitectAgent, @@ -197,7 +198,7 @@ When a user's request requires prolonged, structured work across multiple subtas }, mediaResolution: 'MEDIA_RESOLUTION_MEDIUM', responseModalities: ['TEXT', 'IMAGE'], - }, + } satisfies GoogleGenerativeAIProviderOptions, }, } }, diff --git a/src/mastra/agents/businessLegalAgents.ts b/src/mastra/agents/businessLegalAgents.ts index da0e6ab..9723b49 100644 --- a/src/mastra/agents/businessLegalAgents.ts +++ b/src/mastra/agents/businessLegalAgents.ts @@ -71,12 +71,11 @@ export const legalResearchAgent = new Agent({ instructions: ({ requestContext, }: { - requestContext: RequestContext + requestContext: RequestContext }) => { // runtimeContext is read at invocation time const userTier = requestContext.get('user-tier') ?? 'free' const language = requestContext.get('language') ?? 'en' - const responseFormat = requestContext.get('responseFormat') ?? 'json' const research = requestContext.get('research') ?? { depth: 'extensive', scope: 'full', @@ -88,37 +87,37 @@ export const legalResearchAgent = new Agent({ return { role: 'system', content: `You are a Senior Legal Research Analyst. Your goal is to research legal topics thoroughly using authoritative sources. - Your working with: - - User: ${userTier} - - Language: ${language} - - Research: Depth ${research.depth}, Scope ${research.scope} - - Analysis: Depth ${analysis.depth}, Scope ${analysis.scope} - -**Key Guidelines:** -- Focus on primary sources: statutes, case law, regulations -- Evaluate authority and jurisdiction -- Provide confidence assessments for findings -- Cite sources properly - -**Rules:** -- **Tool Efficiency:** Do NOT use the same tool repetitively or back-to-back for the same query. - -**Process:** -1. Break down legal issues into specific queries -2. Search authoritative databases -3. Evaluate relevance and authority -4. Extract key insights and follow-up questions -5. Synthesize findings with confidence levels - -**Examples:** -- Query: "Breach of contract remedies in California" - → Research California Civil Code, relevant case law, provide summary with citations -- Query: "Data privacy regulations for EU businesses" - → Analyze GDPR requirements, enforcement cases, compliance implications - -**Output:** Return findings in JSON format with queries, results, summary, sources, and confidence level. -${PGVECTOR_PROMPT} - `, + Your working with: + - User: ${userTier} + - Language: ${language} + - Research: Depth ${(research as any).depth ?? 'extensive'}, Scope ${(research as any).scope ?? 'full'} + - Analysis: Depth ${(analysis as any).depth ?? 'extensive'}, Scope ${(analysis as any).scope ?? 'full'} + + **Key Guidelines:** + - Focus on primary sources: statutes, case law, regulations + - Evaluate authority and jurisdiction + - Provide confidence assessments for findings + - Cite sources properly + + **Rules:** + - **Tool Efficiency:** Do NOT use the same tool repetitively or back-to-back for the same query. + + **Process:** + 1. Break down legal issues into specific queries + 2. Search authoritative databases + 3. Evaluate relevance and authority + 4. Extract key insights and follow-up questions + 5. Synthesize findings with confidence levels + + **Examples:** + - Query: "Breach of contract remedies in California" + → Research California Civil Code, relevant case law, provide summary with citations + - Query: "Data privacy regulations for EU businesses" + → Analyze GDPR requirements, enforcement cases, compliance implications + + **Output:** Return findings in JSON format with queries, results, summary, sources, and confidence level. + ${PGVECTOR_PROMPT} + `, providerOptions: { google: { thinkingConfig: { @@ -134,7 +133,7 @@ ${PGVECTOR_PROMPT} model: ({ requestContext, }: { - requestContext: RequestContext + requestContext: RequestContext }) => { const userTier = requestContext.get('user-tier') ?? 'free' if (userTier === 'enterprise') { @@ -154,7 +153,7 @@ ${PGVECTOR_PROMPT} linkExtractorTool, htmlToMarkdownTool, contentCleanerTool, - pgQueryTool, + // pgQueryTool, batchWebScraperTool, mdocumentChunker, evaluateResultTool, @@ -241,13 +240,12 @@ You are a Senior Contract Analyst. Analyze legal documents for risks, obligation `, providerOptions: { google: { - structuredOutput: true, thinkingConfig: { includeThoughts: true, thinkingBudget: -1, }, responseModalities: ['TEXT'], - }, + } satisfies GoogleGenerativeAIProviderOptions, }, } }, @@ -337,13 +335,13 @@ You are a Compliance Officer. Monitor regulatory compliance and identify risks a `, providerOptions: { google: { - structuredOutput: true, + thinkingConfig: { includeThoughts: true, thinkingBudget: -1, }, responseModalities: ['TEXT'], - }, + } satisfies GoogleGenerativeAIProviderOptions, }, } }, @@ -434,13 +432,12 @@ You are a Chief Strategy Officer with legal expertise. Align business strategy w `, providerOptions: { google: { - structuredOutput: true, thinkingConfig: { includeThoughts: true, thinkingBudget: -1, }, responseModalities: ['TEXT'], - }, + } satisfies GoogleGenerativeAIProviderOptions, }, } }, diff --git a/src/mastra/tools/github.ts b/src/mastra/tools/github.ts index b8f6a67..a0d7836 100644 --- a/src/mastra/tools/github.ts +++ b/src/mastra/tools/github.ts @@ -131,7 +131,7 @@ function mapTypeForOrg( case 'forks': case 'sources': case 'member': - return type as any + return type default: return undefined } @@ -409,6 +409,16 @@ interface GitHubIssue { pull_request?: Record | null } +interface GitHubCommit { + sha: string + commit?: { + message?: string + // commit.author may include an email and can be null per GitHub API + author?: { name?: string; email?: string; date?: string } | null + } | null + html_url?: string +} + export const listPullRequests = createTool({ id: 'github:listPullRequests', description: 'List pull requests for a repository', @@ -604,10 +614,10 @@ export const listCommits = createTool({ per_page: inputData.perPage, }) - const commits = (res.data ?? []).map((c: any) => ({ - sha: c.sha as string, + const commits = (res.data ?? []).map((c: GitHubCommit) => ({ + sha: c.sha, message: c.commit?.message ?? '', - author: (c.commit?.author?.name as string) ?? null, + author: c.commit?.author?.name ?? null, date: c.commit?.author?.date ?? '', url: c.html_url ?? '', })) diff --git a/src/utils/streamUtils.ts b/src/utils/streamUtils.ts index 37c86be..cb2ae9e 100644 --- a/src/utils/streamUtils.ts +++ b/src/utils/streamUtils.ts @@ -99,7 +99,7 @@ export function streamJSONEvent( */ export async function handleTextStream( streamResult: - | StreamTextResult + | StreamTextResult | { textStream: AsyncIterable }, streamController: ReadableStreamDefaultController ): Promise { diff --git a/tsconfig.json b/tsconfig.json index 785aee3..82a93e0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,92 +1,131 @@ { - "compilerOptions": { - "target": "ES2022", - "module": "esnext", - "moduleResolution": "bundler", - "esModuleInterop": true, - "resolveJsonModule": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "noEmit": false, - "outDir": "dist", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "incremental": true, - "isolatedModules": true, - "jsx": "react-jsx", - "baseUrl": ".", - "paths": { - "@/*": ["./*"] - }, - "plugins": [ - { - "name": "next" - } - ] - }, - "include": [ - "next-env.d.ts", - "vitest.config.ts", - "mdx-components.tsx", - "testsSetup.ts", - "eslint.config.js", - "prettier.config.js", - "eslint-config-next.d.ts", - "read_pdf_parse.js", - "postcss.config.mjs", - "next.config.ts", - "components.json", - "instrumentation.ts", - ".next/types/**/*.ts", - ".next/dev/types/**/*.ts", - "app/**/*.ts", - "app/**/*.tsx", - "src/mastra/workflows/*.ts", - "src/**/*.ts", - "src/**/*.tsx", - "src/mastra/types/**/*.d.ts", - "types/**/*.d.ts", - "utils/**/*.ts", - "utils/**/*.tsx", - "styles/**/*.ts", - "styles/**/*.tsx", - "ui/**/*.ts", - "ui/**/*.tsx", - "lib/**/*.ts", - "lib/**/*.tsx", - "hooks/**/*.ts", - "hooks/**/*.tsx", - "pages/**/*.ts", - "pages/**/*.tsx", - "convex/**/*.ts", - "convex/**/*.tsx", - "convex/**/*.d.ts", - "convex/mastra/**/*.ts", - "convex/**/*.js", - // Tests are excluded from the main typecheck run to avoid typechecking test-only imports - // that may pull in declaration files with unsupported syntax from node_modules. - "types/**/*.d.ts" + "compilerOptions": { + "target": "ES2022", + "module": "esnext", + "moduleResolution": "bundler", + "esModuleInterop": true, + "resolveJsonModule": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "noEmit": false, + "outDir": "dist", + "lib": [ + "dom", + "dom.iterable", + "esnext" ], - "exclude": [ - "node_modules", - "node_modules/**/*.ts", - "node_modules/**/*.tsx", - "node_modules/**/*.d.ts", - "/node_modules/**/*.tsx", - "/node_modules", - "/dist", - "dist", - ".mastra", - ".github", - ".cursor", - "public", - "coverage", - "scripts", - ".kilocode", - "docs", - "memory-bank", - "node_modules/@crawlee/http/internals/http-crawler.d.ts", - "node_modules/@mdx-js/loader/index.d.cts" + "allowJs": true, + "incremental": true, + "isolatedModules": true, + "jsx": "react-jsx", + "baseUrl": "./", + "paths": { + "@/*": [ + "./*" + ] + }, + "plugins": [ + { + "name": "next" + } ] + }, + "include": [ + "next-env.d.ts", + "vitest.config.ts", + "mdx-components.tsx", + "eslint.config.js", + "prettier.config.js", + "eslint-config-next.d.ts", + "postcss.config.mjs", + "next.config.ts", + "components.json", + "instrumentation.ts", + "/.next/types/**/*.ts", + "/.next/dev/types/**/*.ts", + "app/**/*.ts", + "/app/**/*.ts", + "app/**/*.tsx", + "/app/**/*.tsx", + "src/mastra/workflows/*.ts", + "/app/**/*.mdx ", + "src/**/*.ts", + "/src/**/*.js", + "/src/**/*.tsx", + "src/**/*.ts", + "src/**/*.tsx", + "src/mastra/types/**/*.d.ts", + "types/**/*.d.ts", + "utils/**/*.ts", + "/lib/**/*.ts", + "utils/**/*.tsx", + "styles/**/*.ts", + "styles/**/*.tsx", + "ui/**/*.ts", + "/ui/**/*.ts", + "/ui/**/*.tsx", + "ui/**/*.tsx", + "lib/**/*.ts", + "/lib/**/*.ts", + "/lib/**/*.tsx", + "lib/**/*.tsx", + "hooks/**/*.ts", + "/hooks/**/*.ts", + "/hooks/**/*.tsx", + "hooks/**/*.tsx", + "pages/**/*.ts", + "pages/**/*.tsx", + "convex/**/*.ts", + "/convex/**/*.ts", + "/convex/**/*.tsx", + "convex/**/*.tsx", + "convex/**/*.d.ts", + "convex/mastra/**/*.ts", + "convex/**/*.js", + // Tests are excluded from the main typecheck run to avoid typechecking test-only imports + // that may pull in declaration files with unsupported syntax from node_modules. + "types/**/*.d.ts", + "/tests/**/*.ts", + "/types/**.d.ts", + "/public/", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": [ + "node_modules", + "/node_modules/", + "/node_modules/**/*.js", + "/node_modules/**/*.json", + "node_modules/**/*.ts", + "node_modules/**/*.tsx", + "node_modules/**/*.d.ts", + "/node_modules/**/*.tsx", + "/node_modules/**/*.ts", + "/node_modules/**/*.d.ts", + "/dist", + "dist", + ".mastra", + "/.mastra/**/*", + ".github", + ".cursor", + "public", + "coverage", + "scripts", + ".kilocode", + "/.kilocode/**/*", + ".next", + "/.next", + "tests", + "/tests/**/*.ts", + "/tests/**/*.tsx", + "docs", + "/docs/**/*md", + "memory-bank", + "/memory-bank/**/*.md", + "node_modules/@crawlee/http/internals/http-crawler.d.ts", + "/node_modules/@crawlee/http/internals/http-crawler.d.ts", + "node_modules/@mdx-js/loader/index.d.cts", + "/node_modules/@mdx-js/loader/index.d.cts" + ] }