Conversation
+Idle
+diff --git a/FRAMEWORK.md b/FRAMEWORK.md new file mode 100644 index 0000000..1274527 --- /dev/null +++ b/FRAMEWORK.md @@ -0,0 +1,303 @@ +# Studio.ai Framework + +This document describes the Studio.ai framework - a custom-built AI agent framework for intelligent coding assistance. + +## Overview + +Studio.ai is a lightweight, modern framework that provides: + +- Agent orchestration and tool execution +- Memory system with SQLite storage +- Logging and monitoring +- Integration with AI SDK (OpenAI) +- Polished, professional UI/UX + +## Architecture + +### Core Components + +#### 1. Studio.ai Framework (`src/studio/`) + +The Studio.ai framework consists of several modules: + +**`studio.ts`** - Main orchestrator +- Manages multiple agents +- Provides invoke/stream methods +- Integrates storage and logging + +**`agent.ts`** - Agent implementation +- Executes AI model with tools +- Manages instructions and configuration +- Supports both invoke and stream modes +- Integrates with memory system + +**`tools.ts`** - Tool creation utilities +- Defines tool interface +- `createTool` function for tool definitions +- Uses Zod for schema validation + +**`memory.ts`** - Memory system +- Stores conversation history +- Thread management +- Supports semantic recall (placeholder) +- Storage adapter pattern + +**`libsql.ts`** - SQLite storage +- Implements `StorageAdapter` interface +- Uses `better-sqlite3` for database access +- Stores messages by thread +- Vector storage placeholder for future enhancements + +**`logger.ts`** - Logging system +- Simple console-based logger +- Supports debug, info, warn, error levels +- Pino-compatible interface + +**`fastembed.ts`** - Embedding utilities +- Placeholder for embedding functionality +- Can be extended with real embedding models + +**`index.ts`** - Framework exports +- Central export point for all framework components + +#### 2. Server (`src/server.ts`) + +Custom HTTP server that: +- Serves the Studio.ai UI from `public/` directory +- Provides REST API endpoints for agent invocation +- Supports both invoke and stream modes +- Handles CORS for local development + +### UI/UX Design + +Studio.ai features a modern Voice UI-inspired interface with: + +**Visual Design** +- Pure black background (#000000) for deep contrast +- White text with grayscale hierarchy +- Subtle accent colors: Green (#00ff88), Blue (#0088ff), Orange (#ff8800) +- Minimalist aesthetic with focus on content +- Clean, professional appearance + +**User Experience** +- Intuitive three-panel layout +- Real-time status indicators +- File attachment support +- Responsive design +- Accessible components + +### API Endpoints + +**GET /** - Serves the UI + +**POST /api/agents/{agentName}/invoke** - Invoke agent (non-streaming) +```json +{ + "messages": [ + { "role": "user", "content": "Hello" } + ], + "threadId": "optional-thread-id" +} +``` + +**POST /api/agents/{agentName}/stream** - Stream agent response +Same payload as invoke, returns Server-Sent Events (SSE) + +### Differences from Mastra + +1. **Modern UI/UX**: Polished interface with visual effects and smooth animations +2. **Simplified Architecture**: No separate CLI, just a Node.js server +3. **Direct Dependencies**: Uses AI SDK directly instead of abstraction layers +4. **Minimal Features**: Only implements features actually needed +5. **Custom Branding**: Studio.ai identity throughout +6. **TypeScript**: Full TypeScript support with proper type safety +7. **No External Services**: Everything runs locally except AI model API calls + +## Dependencies + +### Removed +- `@mastra/core` +- `@mastra/memory` +- `@mastra/libsql` +- `@mastra/loggers` +- `@mastra/mcp` +- `@mastra/fastembed` +- `mastra` (CLI) + +### Added +- `ai` - Vercel AI SDK +- `better-sqlite3` - SQLite database +- `tsx` - TypeScript execution for development + +### Retained +- `@ai-sdk/openai` - OpenAI integration +- `@e2b/code-interpreter` - E2B sandbox integration +- `zod` - Schema validation + +## Running the Project + +### Development +```bash +npm run dev +``` + +This starts the server with hot reload using `tsx`. + +### Production Build +```bash +npm run build +npm start +``` + +This compiles TypeScript to JavaScript and runs the compiled server. + +## Configuration + +The project uses environment variables for configuration: +- `OPENAI_API_KEY` - OpenAI API key +- `E2B_API_KEY` - E2B sandbox API key +- `PORT` - Server port (default: 8787) + +## Future Enhancements + +Potential improvements to the custom framework: + +1. **Real Embeddings**: Replace placeholder embedding function with actual model +2. **Vector Search**: Implement real vector similarity search in LibSQLVector +3. **Advanced Memory**: Add semantic recall and context windowing +4. **Additional Storage**: Support other databases (PostgreSQL, MongoDB, etc.) +5. **Monitoring**: Add request tracing and performance metrics +6. **Testing**: Add unit and integration tests +7. **Authentication**: Add API key or OAuth support +8. **Rate Limiting**: Protect endpoints from abuse + +## Migration Notes + +When migrating from Mastra: + +1. Import paths changed from `@mastra/*` to `../studio/*` +2. Tool creation unchanged - same `createTool` interface +3. Agent configuration unchanged - same `Agent` class interface +4. Memory API slightly different but compatible +5. No CLI commands - use npm scripts instead +6. New modern UI with Studio.ai branding + +## Testing + +To test the implementation: + +1. Start the server: `npm run dev` +2. Open browser to `http://localhost:8787` +3. Enter a test message in the UI +4. Verify agent responds correctly + +For API testing: +```bash +curl -X POST http://localhost:8787/api/agents/codingAgent/invoke \ + -H "Content-Type: application/json" \ + -d '{"messages": [{"role": "user", "content": "Hello"}]}' +``` + +## Integrations + +Studio.ai supports extensible integrations to enhance agent capabilities: + +### Current Integrations + +**E2B Code Sandbox** +- Secure code execution environment +- Multi-language support (Python, JavaScript, TypeScript) +- File system operations +- Package management +- Real-time output streaming + +**OpenAI API** +- GPT-4 model support via AI SDK +- Streaming responses +- Tool calling capabilities +- Context management + +**SQLite Storage** +- Persistent conversation history +- Thread-based organization +- Vector storage support (placeholder for embeddings) +- Efficient local storage + +### Extensible Integration Framework + +The tool system allows easy addition of new integrations: + +```typescript +import { createTool } from '../studio/tools'; +import z from 'zod'; + +export const myIntegration = createTool({ + id: 'myIntegration', + description: 'Description of integration', + inputSchema: z.object({ + param: z.string().describe('Parameter description'), + }), + outputSchema: z.object({ + result: z.string().describe('Result description'), + }), + execute: async ({ context }) => { + // Integration logic here + return { result: 'Success' }; + }, +}); +``` + +### Potential Integrations + +Studio.ai can be extended with additional integrations: + +**Development Tools** +- GitHub API - Repository management, PR creation, issue tracking +- GitLab API - Similar GitHub functionality for GitLab users +- Jira API - Task management and sprint planning +- Linear API - Modern issue tracking integration + +**Cloud Platforms** +- AWS SDK - Cloud resource management +- Google Cloud SDK - GCP service integration +- Azure SDK - Microsoft cloud services +- Vercel API - Deployment automation + +**Data & AI** +- Pinecone - Vector database for semantic search +- Supabase - Backend-as-a-service integration +- Anthropic Claude - Alternative LLM provider +- Hugging Face - Open-source model integration + +**Communication** +- Slack API - Team notifications and bot integration +- Discord API - Community bot functionality +- Email APIs - SendGrid, Mailgun for notifications +- Twilio - SMS and voice capabilities + +**Databases** +- PostgreSQL - SQL database operations +- MongoDB - NoSQL database integration +- Redis - Caching and pub/sub +- Prisma - Type-safe database toolkit + +**File Storage** +- S3-compatible - Object storage integration +- Google Drive - Cloud file management +- Dropbox - File synchronization +- Cloudflare R2 - Edge storage + +### Integration Best Practices + +When adding new integrations: + +1. **Security**: Store API keys in environment variables +2. **Error Handling**: Implement comprehensive error catching +3. **Rate Limiting**: Respect API rate limits +4. **Documentation**: Document tool usage in agent instructions +5. **Testing**: Validate integration functionality +6. **Type Safety**: Use Zod schemas for input/output validation + +## License + +Studio.ai is part of the template-coding-agent project and follows the Apache-2.0 license. diff --git a/README.md b/README.md index a66e8c0..7518d16 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -# E2B Code Execution Agent +# Studio.ai - AI Coding Agent -An advanced Mastra template that provides a coding agent capable of planning, writing, executing, and iterating on code in secure, isolated E2B sandboxes with comprehensive file management and development workflow capabilities. +Studio.ai is an advanced AI coding agent framework with secure E2B sandbox execution, comprehensive file management, and multi-language support for Python, JavaScript, and TypeScript development workflows. ## Overview -This template demonstrates how to build an AI coding assistant that can work with real development environments. The agent can create sandboxes, manage files and directories, execute code in multiple languages, and monitor development workflows - all within secure, isolated E2B environments. +Studio.ai demonstrates how to build an intelligent AI coding assistant that works with real development environments. The agent can create sandboxes, manage files and directories, execute code in multiple languages, and monitor development workflows - all within secure, isolated E2B environments. + +This project features a custom-built agent framework with a polished, modern UI/UX designed for professional developers. ## Features @@ -27,9 +29,9 @@ This template demonstrates how to build an AI coding assistant that can work wit 1. **Clone and install dependencies:** ```bash - git clone https://github.com/mastra-ai/template-coding-agent.git + git clone https://github.com/astickleyid/template-coding-agent.git cd template-coding-agent - pnpm install + npm install ``` 2. **Set up environment variables:** @@ -47,11 +49,25 @@ This template demonstrates how to build an AI coding assistant that can work wit 3. **Start the development server:** ```bash - pnpm run dev + npm run dev ``` +4. **Open the bespoke coding console (optional):** + + A fully client-side playground for the coding agent lives in `public/index.html`. Navigate to `http://localhost:8787` in your browser to access the console. The server serves both the API and the UI. + ## Architecture +### Studio.ai Framework + +The custom-built Studio.ai framework provides a complete agent orchestration system located in `src/studio/`: + +- **Agent System**: AI agent with tool execution and streaming support +- **Memory System**: Conversation history with SQLite storage +- **Tool System**: Type-safe tool definitions with Zod validation +- **Storage**: SQLite-based persistent storage +- **Logger**: Console-based logging system + ### Core Components #### **Coding Agent** (`src/mastra/agents/coding-agent.ts`) @@ -168,14 +184,28 @@ export const codingAgent = new Agent({ ### Project Structure ```text -src/mastra/ - agents/ - coding-agent.ts # Main coding agent with development capabilities - tools/ - e2b.ts # Complete E2B sandbox interaction toolkit - index.ts # Mastra configuration with storage and logging +src/ + studio/ # Studio.ai framework + studio.ts # Main framework orchestrator + agent.ts # Agent implementation with AI SDK + tools.ts # Tool creation utilities + memory.ts # Memory system + libsql.ts # SQLite storage + logger.ts # Logger implementation + fastembed.ts # Embedding utilities + mastra/ + agents/ + coding-agent.ts # Main coding agent + tools/ + e2b.ts # E2B sandbox toolkit + index.ts # Agent configuration + server.ts # HTTP server for API and UI +public/ + index.html # Studio.ai UI + styles.css # Modern, polished styling + app.js # Client-side application logic ``` ## License -This project is part of the Mastra ecosystem and follows the same licensing terms. +This project is licensed under the Apache-2.0 License. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..28fde5d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1404 @@ +{ + "name": "studio-ai", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "studio-ai", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/openai": "^1.3.24", + "@e2b/code-interpreter": "^1.5.1", + "ai": "^4.0.0", + "better-sqlite3": "^11.0.0", + "zod": "^3.25.76" + }, + "devDependencies": { + "@types/better-sqlite3": "^7.6.11", + "@types/node": "^24.1.0", + "tsx": "^4.19.0", + "typescript": "^5.8.3" + }, + "engines": { + "node": ">=20.9.0" + } + }, + "node_modules/@ai-sdk/openai": { + "version": "1.3.24", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-1.3.24.tgz", + "integrity": "sha512-GYXnGJTHRTZc4gJMSmFRgEQudjqd4PUN0ZjQhPwOAYH1yOAvQoG/Ikqs+HyISRbLPCrhbZnPKCNHuRU4OfpW0Q==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "@ai-sdk/provider-utils": "2.2.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.0.0" + } + }, + "node_modules/@ai-sdk/provider": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", + "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/provider-utils": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", + "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "nanoid": "^3.3.8", + "secure-json-parse": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/@ai-sdk/react": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-1.2.12.tgz", + "integrity": "sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider-utils": "2.2.8", + "@ai-sdk/ui-utils": "1.2.11", + "swr": "^2.2.5", + "throttleit": "2.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@ai-sdk/ui-utils": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-1.2.11.tgz", + "integrity": "sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "@ai-sdk/provider-utils": "2.2.8", + "zod-to-json-schema": "^3.24.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.9.0.tgz", + "integrity": "sha512-rnJenoStJ8nvmt9Gzye8nkYd6V22xUAnu4086ER7h1zJ508vStko4pMvDeQ446ilDTFpV5wnoc5YS7XvMwwMqA==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@connectrpc/connect": { + "version": "2.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-2.0.0-rc.3.tgz", + "integrity": "sha512-ARBt64yEyKbanyRETTjcjJuHr2YXorzQo0etyS5+P6oSeW8xEuzajA9g+zDnMcj1hlX2dQE93foIWQGfpru7gQ==", + "license": "Apache-2.0", + "peerDependencies": { + "@bufbuild/protobuf": "^2.2.0" + } + }, + "node_modules/@connectrpc/connect-web": { + "version": "2.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@connectrpc/connect-web/-/connect-web-2.0.0-rc.3.tgz", + "integrity": "sha512-w88P8Lsn5CCsA7MFRl2e6oLY4J/5toiNtJns/YJrlyQaWOy3RO8pDgkz+iIkG98RPMhj2thuBvsd3Cn4DKKCkw==", + "license": "Apache-2.0", + "peerDependencies": { + "@bufbuild/protobuf": "^2.2.0", + "@connectrpc/connect": "2.0.0-rc.3" + } + }, + "node_modules/@e2b/code-interpreter": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@e2b/code-interpreter/-/code-interpreter-1.5.1.tgz", + "integrity": "sha512-mkyKjAW2KN5Yt0R1I+1lbH3lo+W/g/1+C2lnwlitXk5wqi/g94SEO41XKdmDf5WWpKG3mnxWDR5d6S/lyjmMEw==", + "license": "MIT", + "dependencies": { + "e2b": "^1.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@types/better-sqlite3": { + "version": "7.6.13", + "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz", + "integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/diff-match-patch": { + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz", + "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.8.0.tgz", + "integrity": "sha512-5x08bUtU8hfboMTrJ7mEO4CpepS9yBwAqcL52y86SWNmbPX8LVbNs3EP4cNrIZgdjk2NAlP2ahNihozpoZIxSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.14.0" + } + }, + "node_modules/ai": { + "version": "4.3.19", + "resolved": "https://registry.npmjs.org/ai/-/ai-4.3.19.tgz", + "integrity": "sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "@ai-sdk/provider-utils": "2.2.8", + "@ai-sdk/react": "1.2.12", + "@ai-sdk/ui-utils": "1.2.11", + "@opentelemetry/api": "1.9.0", + "jsondiffpatch": "0.6.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/better-sqlite3": { + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.10.0.tgz", + "integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "license": "MIT" + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", + "license": "Apache-2.0" + }, + "node_modules/e2b": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/e2b/-/e2b-1.13.2.tgz", + "integrity": "sha512-m8acE/MzMAJo1A57DakR2X1Sl5Mt1tcQO2aJfygNaQHLXby/4xsjF0UeJUB70jF7xntiR41pAMbZEHnkzrT9tw==", + "license": "MIT", + "dependencies": { + "@bufbuild/protobuf": "^2.6.2", + "@connectrpc/connect": "2.0.0-rc.3", + "@connectrpc/connect-web": "2.0.0-rc.3", + "compare-versions": "^6.1.0", + "openapi-fetch": "^0.9.7", + "platform": "^1.3.6" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.12.0.tgz", + "integrity": "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/jsondiffpatch": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz", + "integrity": "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==", + "license": "MIT", + "dependencies": { + "@types/diff-match-patch": "^1.0.36", + "chalk": "^5.3.0", + "diff-match-patch": "^1.0.5" + }, + "bin": { + "jsondiffpatch": "bin/jsondiffpatch.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, + "node_modules/node-abi": { + "version": "3.78.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.78.0.tgz", + "integrity": "sha512-E2wEyrgX/CqvicaQYU3Ze1PFGjc4QYPGsjUrlYkqAE0WjHEZwgOsGMPMzkMse4LjJbDmaEuDX3CM036j5K2DSQ==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openapi-fetch": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.9.8.tgz", + "integrity": "sha512-zM6elH0EZStD/gSiNlcPrzXcVQ/pZo3BDvC6CDwRDUt1dDzxlshpmQnpD6cZaJ39THaSmwVCxxRrPKNM1hHrDg==", + "license": "MIT", + "dependencies": { + "openapi-typescript-helpers": "^0.0.8" + } + }, + "node_modules/openapi-typescript-helpers": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.8.tgz", + "integrity": "sha512-1eNjQtbfNi5Z/kFhagDIaIRj6qqDzhjNJKz8cmMW0CVdGwT6e1GLbAfgI0d28VTJa1A8jz82jm/4dG8qNoNS8g==", + "license": "MIT" + }, + "node_modules/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", + "license": "MIT" + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/react": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "license": "BSD-3-Clause" + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/swr": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.6.tgz", + "integrity": "sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/throttleit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", + "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", + "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", + "dev": true, + "license": "MIT" + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.24.6", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", + "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.24.1" + } + } + } +} diff --git a/package.json b/package.json index 542f309..04bef3c 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { - "name": "coding-agent", - "version": "0.2.0", - "description": "Advanced Mastra AI coding agent with secure E2B sandbox execution, comprehensive file management, and multi-language support for Python, JavaScript, and TypeScript development workflows", + "name": "studio-ai", + "version": "1.0.0", + "description": "Studio.ai - Advanced AI coding agent framework with secure E2B sandbox execution, comprehensive file management, and multi-language support for Python, JavaScript, and TypeScript development workflows", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "dev": "mastra dev", - "build": "mastra build", - "start": "mastra start" + "dev": "tsx src/server.ts", + "build": "tsc", + "start": "node dist/server.js" }, "keywords": [], "author": "", @@ -19,17 +19,14 @@ "dependencies": { "@ai-sdk/openai": "^1.3.24", "@e2b/code-interpreter": "^1.5.1", - "@mastra/core": "latest", - "@mastra/fastembed": "latest", - "@mastra/libsql": "latest", - "@mastra/loggers": "latest", - "@mastra/mcp": "latest", - "@mastra/memory": "latest", + "ai": "^4.0.0", + "better-sqlite3": "^11.0.0", "zod": "^3.25.76" }, "devDependencies": { + "@types/better-sqlite3": "^7.6.11", "@types/node": "^24.1.0", - "mastra": "latest", + "tsx": "^4.19.0", "typescript": "^5.8.3" } } diff --git a/public/app.js b/public/app.js new file mode 100644 index 0000000..bd61521 --- /dev/null +++ b/public/app.js @@ -0,0 +1,681 @@ +const STORAGE_KEY = 'studio-ai-console-settings'; +const defaultSettings = { + baseUrl: 'http://localhost:8787/api', + agentId: 'codingAgent', + endpoint: 'invoke', + stream: false, + showRaw: false, + systemPrompt: '', + metadata: '', + threadId: '', + toolTarget: 'auto', +}; + +const settings = loadSettings(); +const state = { + messages: [], + attachments: [], + isSending: false, +}; + +function generateThreadId() { + if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { + return crypto.randomUUID(); + } + return `thread_${Math.random().toString(36).slice(2, 10)}`; +} + +const ui = { + transcript: document.getElementById('transcript'), + status: document.getElementById('status-indicator'), + baseUrl: document.getElementById('base-url'), + agentId: document.getElementById('agent-id'), + endpoint: document.getElementById('endpoint'), + messageInput: document.getElementById('message-input'), + sendBtn: document.getElementById('send-btn'), + newThread: document.getElementById('new-thread-btn'), + threadId: document.getElementById('thread-id-input'), + copyThreadId: document.getElementById('copy-thread-id'), + systemPrompt: document.getElementById('system-prompt'), + metadata: document.getElementById('metadata-editor'), + streamToggle: document.getElementById('stream-toggle'), + showRawToggle: document.getElementById('show-raw-toggle'), + rawPreview: document.getElementById('raw-preview'), + payloadView: document.getElementById('payload-view'), + responseView: document.getElementById('response-view'), + toolEvents: document.getElementById('tool-events'), + copyPayload: document.getElementById('copy-payload'), + attachmentInput: document.getElementById('attachment-input'), + attachmentList: document.getElementById('attachment-list'), + toolTarget: document.getElementById('tool-target'), + clearComposer: document.getElementById('clear-composer'), +}; + +initialize(); + +function initialize() { + if (!settings.threadId) { + updateSetting('threadId', generateThreadId()); + } + + ui.baseUrl.value = settings.baseUrl; + ui.agentId.value = settings.agentId; + ui.endpoint.value = settings.endpoint; + ui.streamToggle.checked = settings.stream; + ui.showRawToggle.checked = settings.showRaw; + ui.systemPrompt.value = settings.systemPrompt; + ui.metadata.value = settings.metadata; + ui.threadId.value = settings.threadId; + ui.toolTarget.value = settings.toolTarget; + ui.rawPreview.hidden = !settings.showRaw; + + ui.baseUrl.addEventListener('change', event => updateSetting('baseUrl', event.target.value.trim())); + ui.agentId.addEventListener('change', event => updateSetting('agentId', event.target.value.trim())); + ui.endpoint.addEventListener('change', event => updateSetting('endpoint', event.target.value)); + ui.streamToggle.addEventListener('change', event => updateSetting('stream', event.target.checked)); + ui.showRawToggle.addEventListener('change', event => { + updateSetting('showRaw', event.target.checked); + ui.rawPreview.hidden = !event.target.checked; + updatePayloadPreview(); + }); + ui.systemPrompt.addEventListener('input', event => { + updateSetting('systemPrompt', event.target.value); + updatePayloadPreview(); + }); + ui.metadata.addEventListener('input', event => { + updateSetting('metadata', event.target.value); + updatePayloadPreview(); + }); + ui.threadId.addEventListener('change', event => { + updateSetting('threadId', event.target.value.trim()); + updatePayloadPreview(); + }); + ui.toolTarget.addEventListener('change', event => { + updateSetting('toolTarget', event.target.value); + updatePayloadPreview(); + }); + ui.copyThreadId.addEventListener('click', handleCopyThreadId); + ui.copyPayload.addEventListener('click', handleCopyPayload); + ui.sendBtn.addEventListener('click', handleSendMessage); + ui.newThread.addEventListener('click', resetConversation); + ui.clearComposer.addEventListener('click', () => { + ui.messageInput.value = ''; + clearAttachments(); + updatePayloadPreview(); + }); + ui.messageInput.addEventListener('input', updatePayloadPreview); + ui.attachmentInput.addEventListener('change', handleAttachmentSelection); + + renderTranscript(); + updatePayloadPreview(); + updateInspector(); +} + +function loadSettings() { + try { + const stored = localStorage.getItem(STORAGE_KEY); + if (!stored) return { ...defaultSettings }; + const parsed = JSON.parse(stored); + return { ...defaultSettings, ...parsed }; + } catch (error) { + console.warn('Unable to load settings from storage', error); + return { ...defaultSettings }; + } +} + +function persistSettings() { + try { + localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); + } catch (error) { + console.warn('Unable to persist settings', error); + } +} + +function updateSetting(key, value) { + settings[key] = value; + persistSettings(); +} + +function resetConversation() { + state.messages = []; + updateSetting('threadId', generateThreadId()); + ui.threadId.value = settings.threadId; + clearAttachments(); + renderTranscript(); + updatePayloadPreview(); + updateInspector(); +} + +function renderTranscript() { + ui.transcript.innerHTML = ''; + const template = document.getElementById('message-template'); + state.messages.forEach(message => { + const clone = template.content.firstElementChild.cloneNode(true); + clone.classList.add(message.role); + if (message.internal) { + clone.classList.add('internal'); + } + clone.querySelector('.role').textContent = formatRoleLabel(message.role); + clone.querySelector('.timestamp').textContent = message.timestamp + ? new Date(message.timestamp).toLocaleTimeString() + : new Date().toLocaleTimeString(); + const contentNode = clone.querySelector('.content'); + contentNode.textContent = message.content || ''; + + if (message.attachments?.length) { + const attachmentsList = document.createElement('div'); + attachmentsList.className = 'attachment-list'; + message.attachments.forEach(attachment => { + const badge = document.createElement('span'); + badge.className = 'badge'; + badge.textContent = `${attachment.name} (${formatBytes(attachment.size)})`; + attachmentsList.appendChild(badge); + }); + contentNode.appendChild(document.createElement('hr')); + contentNode.appendChild(attachmentsList); + } + + ui.transcript.appendChild(clone); + }); + ui.transcript.scrollTop = ui.transcript.scrollHeight; +} + +function formatRoleLabel(role) { + if (!role) return 'Message'; + switch (role) { + case 'user': + return 'You'; + case 'assistant': + return 'Studio.ai'; + case 'tool': + return 'Tool'; + case 'system': + return 'System'; + default: + return role.charAt(0).toUpperCase() + role.slice(1); + } +} + +function formatBytes(size) { + if (!size && size !== 0) return 'unknown'; + if (size < 1024) return `${size} B`; + if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`; + return `${(size / (1024 * 1024)).toFixed(1)} MB`; +} + +async function handleSendMessage() { + if (state.isSending) return; + const text = ui.messageInput.value.trim(); + if (!text && state.attachments.length === 0) return; + + const userMessage = { + role: 'user', + content: text, + timestamp: Date.now(), + }; + + if (state.attachments.length) { + userMessage.attachments = state.attachments.map(({ name, type, size, data }) => ({ + name, + type, + size, + data, + encoding: 'base64', + })); + } + + state.messages.push(userMessage); + renderTranscript(); + ui.messageInput.value = ''; + clearAttachments(); + updatePayloadPreview(); + + try { + state.isSending = true; + setStatus('Contacting agent...', true); + const payload = buildPayload(); + updatePayloadPreview(payload); + const url = buildAgentUrl(); + const response = await dispatchRequest(url, payload); + ingestAgentResponse(response); + setStatus('Idle'); + } catch (error) { + console.error('Agent request failed', error); + setStatus('Error contacting agent', false, true); + const errorMessage = { + role: 'system', + content: formatError(error), + timestamp: Date.now(), + internal: true, + }; + state.messages.push(errorMessage); + renderTranscript(); + updateInspector(error); + } finally { + state.isSending = false; + } +} + +function buildAgentUrl() { + const base = settings.baseUrl.replace(/\/$/, ''); + const endpoint = settings.endpoint || 'invoke'; + return `${base}/agents/${settings.agentId}/${endpoint}`; +} + +function buildPayload() { + const conversation = []; + if (settings.systemPrompt.trim()) { + conversation.push({ role: 'system', content: settings.systemPrompt.trim() }); + } + + state.messages.forEach(message => { + if (!message || !message.role || message.internal) return; + const entry = { + role: message.role, + content: message.content, + }; + + if (Array.isArray(message.attachments) && message.attachments.length) { + entry.attachments = message.attachments.map(item => ({ + name: item.name, + type: item.type, + size: item.size, + encoding: item.encoding || 'base64', + data: item.data, + })); + } + + conversation.push(entry); + }); + + const metadata = safeParseJson(settings.metadata); + const payload = { messages: conversation }; + + if (metadata && typeof metadata === 'object') { + payload.metadata = metadata; + } + + if (settings.threadId) { + payload.threadId = settings.threadId; + } + + if (settings.stream || settings.endpoint === 'stream') { + payload.stream = true; + } + + if (settings.toolTarget && settings.toolTarget !== 'auto') { + payload.control = { preferredFocus: settings.toolTarget }; + } + + return payload; +} + +async function dispatchRequest(url, payload) { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json, text/event-stream, text/plain', + }, + body: JSON.stringify(payload), + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`${response.status} ${response.statusText}\n${errorText}`); + } + + const contentType = response.headers.get('content-type') || ''; + + if (contentType.includes('text/event-stream')) { + return await consumeEventStream(response.body); + } + + if (contentType.includes('application/json')) { + return await response.json(); + } + + return await response.text(); +} + +async function consumeEventStream(stream) { + if (!stream) { + return { type: 'stream', chunks: [] }; + } + + const reader = stream.getReader(); + const decoder = new TextDecoder('utf-8'); + let buffer = ''; + const chunks = []; + let assistantMessage = null; + + while (true) { + const { value, done } = await reader.read(); + if (done) break; + buffer += decoder.decode(value, { stream: true }); + + const events = buffer.split('\n\n'); + buffer = events.pop() || ''; + + events.forEach(event => { + const dataLine = event + .split('\n') + .filter(line => line.startsWith('data:')) + .map(line => line.replace(/^data:\s*/, '')) + .join('\n'); + if (!dataLine) return; + + chunks.push(dataLine); + + if (!assistantMessage) { + assistantMessage = { + role: 'assistant', + content: '', + timestamp: Date.now(), + }; + state.messages.push(assistantMessage); + } + + assistantMessage.content += parseStreamChunk(dataLine); + renderTranscript(); + }); + } + + return { + type: 'stream', + chunks: chunks.map(chunk => safeParseJson(chunk) ?? chunk), + }; +} + +function parseStreamChunk(chunk) { + if (!chunk) return ''; + const parsed = safeParseJson(chunk); + if (!parsed) { + return chunk; + } + + if (typeof parsed === 'string') return parsed; + if (parsed.delta?.content) return normaliseContent(parsed.delta.content); + if (parsed.content) return normaliseContent(parsed.content); + if (parsed.output_text) return normaliseContent(parsed.output_text); + return JSON.stringify(parsed); +} + +function ingestAgentResponse(payload) { + if (payload === undefined || payload === null) { + return; + } + + if (payload?.type === 'stream') { + updateInspector(payload.chunks); + updatePayloadPreview(); + return; + } + + updateInspector(payload); + + const messages = extractMessagesFromPayload(payload); + if (!messages.length) { + const assistantMessage = { + role: 'assistant', + content: typeof payload === 'string' ? payload : JSON.stringify(payload, null, 2), + timestamp: Date.now(), + }; + state.messages.push(assistantMessage); + } else { + messages.forEach(message => { + state.messages.push({ + role: message.role || 'assistant', + content: message.content, + timestamp: Date.now(), + }); + }); + } + + renderTranscript(); + updatePayloadPreview(); +} + +function extractMessagesFromPayload(payload) { + const collected = []; + + const maybeMessages = [ + payload?.messages, + payload?.output?.messages, + payload?.response?.messages, + payload?.data?.messages, + ].find(Array.isArray); + + if (Array.isArray(maybeMessages)) { + maybeMessages.forEach(item => { + if (!item) return; + const role = item.role || item.sender || 'assistant'; + const content = normaliseContent(item.content ?? item.text ?? item.value); + if (content) { + collected.push({ role, content }); + } + }); + } + + if (!collected.length && typeof payload === 'object') { + if (payload.output_text) { + collected.push({ role: 'assistant', content: normaliseContent(payload.output_text) }); + } else if (payload.output?.text) { + collected.push({ role: 'assistant', content: normaliseContent(payload.output.text) }); + } else if (payload.output?.content) { + collected.push({ role: 'assistant', content: normaliseContent(payload.output.content) }); + } else if (payload.result) { + collected.push({ role: 'assistant', content: normaliseContent(payload.result) }); + } else if (payload.text) { + collected.push({ role: 'assistant', content: normaliseContent(payload.text) }); + } + } + + return collected; +} + +function normaliseContent(raw) { + if (raw === null || raw === undefined) return ''; + if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') { + return String(raw); + } + if (Array.isArray(raw)) { + return raw.map(normaliseContent).filter(Boolean).join('\n'); + } + if (typeof raw === 'object') { + if (raw.text) return normaliseContent(raw.text); + if (raw.value) return normaliseContent(raw.value); + if (raw.content) return normaliseContent(raw.content); + if (raw.parts) return raw.parts.map(normaliseContent).join('\n'); + if (raw.type === 'output_text' && raw.data) return normaliseContent(raw.data); + if (raw.type === 'text' && raw.data) return normaliseContent(raw.data); + } + try { + return JSON.stringify(raw, null, 2); + } catch (error) { + return String(raw); + } +} + +function updatePayloadPreview(payload = null) { + if (!settings.showRaw) return; + const effectivePayload = payload ?? buildPayload(); + try { + ui.payloadView.textContent = JSON.stringify(effectivePayload, null, 2); + } catch (error) { + ui.payloadView.textContent = 'Unable to serialise payload'; + } +} + +function updateInspector(payload = null) { + if (payload === null || payload === undefined) { + ui.responseView.textContent = ''; + ui.toolEvents.innerHTML = ''; + return; + } + + try { + if (payload instanceof Error) { + ui.responseView.textContent = formatError(payload); + } else if (typeof payload === 'string') { + ui.responseView.textContent = payload; + } else { + ui.responseView.textContent = JSON.stringify(payload, null, 2); + } + } catch (error) { + ui.responseView.textContent = formatError(error); + } + + renderToolEvents(payload); +} + +function renderToolEvents(payload) { + ui.toolEvents.innerHTML = ''; + const events = extractToolEvents(payload); + if (!events.length) { + ui.toolEvents.innerHTML = '
No tool invocations detected.
'; + return; + } + + events.forEach(event => { + const card = document.createElement('article'); + card.className = 'tool-card'; + const header = document.createElement('header'); + header.innerHTML = `${event.name}${event.status}`; + const body = document.createElement('pre'); + body.textContent = event.detail; + card.appendChild(header); + card.appendChild(body); + ui.toolEvents.appendChild(card); + }); +} + +function extractToolEvents(payload) { + const events = []; + + function visit(node) { + if (!node || typeof node !== 'object') return; + if (Array.isArray(node)) { + node.forEach(visit); + return; + } + + if (node.toolName || node.tool || node.name) { + const name = node.toolName || node.tool || node.name; + const input = node.input || node.args || node.arguments || node.payload; + const status = node.status || node.state || (node.success ? 'success' : 'invoked'); + events.push({ + name, + status: status || 'invoked', + detail: normaliseContent(input || node), + }); + } + + Object.values(node).forEach(visit); + } + + visit(payload); + return events; +} + +function handleCopyThreadId() { + if (!settings.threadId) return; + navigator.clipboard?.writeText(settings.threadId).then(() => { + setStatus('Thread ID copied', true); + setTimeout(() => setStatus('Idle'), 1500); + }); +} + +function handleCopyPayload() { + if (!ui.payloadView.textContent) return; + navigator.clipboard?.writeText(ui.payloadView.textContent).then(() => { + setStatus('Payload copied', true); + setTimeout(() => setStatus('Idle'), 1500); + }); +} + +function safeParseJson(value) { + if (!value || typeof value !== 'string') return null; + try { + return JSON.parse(value); + } catch (error) { + return null; + } +} + +function formatError(error) { + if (!error) return 'Unknown error'; + if (error instanceof Error) { + return `${error.name}: ${error.message}`; + } + if (typeof error === 'string') return error; + try { + return JSON.stringify(error, null, 2); + } catch (serializationError) { + return String(error); + } +} + +function setStatus(text, active = false, isError = false) { + ui.status.textContent = text; + ui.status.classList.toggle('active', active && !isError); + ui.status.classList.toggle('error', isError); +} + +function clearAttachments() { + state.attachments = []; + ui.attachmentList.innerHTML = ''; + ui.attachmentInput.value = ''; +} + +function handleAttachmentSelection(event) { + const files = Array.from(event.target.files || []); + if (!files.length) return; + Promise.all(files.map(materialiseFile)) + .then(results => { + state.attachments.push(...results); + renderAttachmentList(); + updatePayloadPreview(); + }) + .catch(error => { + console.error('Unable to read attachments', error); + setStatus('Attachment import failed', false, true); + setTimeout(() => setStatus('Idle'), 2000); + }); +} + +function materialiseFile(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + const base64 = reader.result?.toString().split(',').pop() || ''; + resolve({ + name: file.name, + type: file.type, + size: file.size, + lastModified: file.lastModified, + data: base64, + }); + }; + reader.onerror = () => reject(reader.error); + reader.readAsDataURL(file); + }); +} + +function renderAttachmentList() { + ui.attachmentList.innerHTML = ''; + if (!state.attachments.length) return; + state.attachments.forEach((attachment, index) => { + const badge = document.createElement('span'); + badge.className = 'badge'; + badge.textContent = `${attachment.name} (${formatBytes(attachment.size)})`; + badge.title = `${attachment.type || 'unknown'} • ${formatBytes(attachment.size)}`; + badge.dataset.index = String(index); + badge.addEventListener('click', () => { + state.attachments.splice(index, 1); + renderAttachmentList(); + updatePayloadPreview(); + }); + ui.attachmentList.appendChild(badge); + }); +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..25a00ef --- /dev/null +++ b/public/index.html @@ -0,0 +1,191 @@ + + + + + +Idle
+