diff --git a/example/ai-agent-app/.gitignore b/example/ai-agent-app/.gitignore deleted file mode 100644 index 82024b8c..00000000 --- a/example/ai-agent-app/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -.venv/ -node_modules/ -__pycache__/ -*.pyc -.env -.claude/ -dist/ -htmlcov/ -.coverage diff --git a/example/ai-agent-app/artisan b/example/ai-agent-app/artisan deleted file mode 100644 index 95887b0b..00000000 --- a/example/ai-agent-app/artisan +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python3 - -import sys -from bootstrap.application import app - -if __name__ == "__main__": - status = app.handle_command() - sys.exit(status if isinstance(status, int) else 0) diff --git a/example/ai-agent-app/bootstrap/__init__.py b/example/ai-agent-app/bootstrap/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/example/ai-agent-app/bootstrap/application.py b/example/ai-agent-app/bootstrap/application.py deleted file mode 100644 index 152e0772..00000000 --- a/example/ai-agent-app/bootstrap/application.py +++ /dev/null @@ -1,18 +0,0 @@ -from pathlib import Path - -from fastapi_startkit import Application -from fastapi_startkit.inertia import InertiaProvider -from fastapi_startkit.logging import LogProvider -from fastapi_startkit.vite import ViteProvider - -from providers.fastapi_provider import FastAPIProvider - -app: Application = Application( - base_path=Path(__file__).parent.parent, - providers=[ - LogProvider, - FastAPIProvider, - ViteProvider, - InertiaProvider, - ], -) diff --git a/example/ai-agent-app/memory.md b/example/ai-agent-app/memory.md deleted file mode 100644 index 68a47ee0..00000000 --- a/example/ai-agent-app/memory.md +++ /dev/null @@ -1,42 +0,0 @@ - +-------------------+ - | Input/Event | - +-------------------+ - | - v - +-------------------+ - | Memory Router | - | classify memory | - +-------------------+ - | | | - +-----------+ | +-------------+ - | | | - v v v - - +---------------+ +---------------+ +---------------+ - | Semantic Mem | | Episodic Mem | | Task Memory | - | facts/knowledge| | events/logs | | goals/progress| - +---------------+ +---------------+ +---------------+ - | | | - +----------------+------------------+ - | - v - +------------------+ - | Retrieval Layer | - | ranking/hybrid | - +------------------+ - | - v - +------------------+ - | Working Memory | - | active context | - +------------------+ - | - v - LLM - | - v - +------------------+ - | Reflection Layer | - | summarization | - | consolidation | - +------------------+ diff --git a/example/ai-agent-app/memory.py b/example/ai-agent-app/memory.py deleted file mode 100644 index 6a337504..00000000 --- a/example/ai-agent-app/memory.py +++ /dev/null @@ -1,177 +0,0 @@ -# Agent Memory System - -## Goals - -Build a production-grade memory system for AI agents that supports: - -- semantic memory -- episodic memory -- task memory -- retrieval ranking -- memory consolidation -- reflection -- decay/forgetting - ---- - -# Architecture - -## Components - -### 1. Memory Router - -Responsible for: -- classifying memory -- routing to correct store -- embedding generation -- deduplication - ---- - -### 2. Semantic Memory - -Stores: -- user preferences -- knowledge -- facts -- long-term summaries - -Storage: -- PostgreSQL -- pgvector - -Features: -- embedding search -- hybrid retrieval -- deduplication -- confidence scoring - ---- - -### 3. Episodic Memory - -Stores: -- actions -- events -- failures -- tool outputs -- timelines - -Storage: -- append-only PostgreSQL table - -Features: -- chronological retrieval -- summarization -- temporal filtering - ---- - -### 4. Task Memory - -Stores: -- objectives -- todos -- completed steps -- agent progress - -Storage: -- structured relational tables - -Features: -- task lifecycle -- dependencies -- state transitions - ---- - -### 5. Retrieval Layer - -Supports: -- semantic search -- keyword search -- recency ranking -- importance ranking - -Retrieval score formula: - -score = - similarity - + recency - + importance - + task relevance - + confidence - ---- - -### 6. Reflection Engine - -Responsible for: -- summarization -- extracting patterns -- converting episodes into semantic knowledge - -Example: -Repeated deployment failures -→ deployment validation checklist - ---- - -### 7. Memory Decay - -Supports: -- TTL -- archival -- confidence decay -- stale memory cleanup - ---- - -# Database Tables - -## semantic_memories - -- id -- content -- embedding -- confidence -- created_at -- updated_at - -## episodic_events - -- id -- event_type -- content -- outcome -- timestamp - -## tasks - -- id -- title -- status -- created_at -- updated_at - -## task_steps - -- id -- task_id -- step -- status - ---- - -# Fluent API - -```python -memory.capture(...) - -memory.search(...) - -memory.semantic.add(...) - -memory.tasks.create(...) - -memory.reflect() diff --git a/example/ai-agent-app/package-lock.json b/example/ai-agent-app/package-lock.json deleted file mode 100644 index 25254f2d..00000000 --- a/example/ai-agent-app/package-lock.json +++ /dev/null @@ -1,1754 +0,0 @@ -{ - "name": "ai-agent-app", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "ai-agent-app", - "version": "0.1.0", - "dependencies": { - "@inertiajs/react": "^3.0.0", - "fastapi-vite-plugin": "^0.0.3", - "react": "^19.0.0", - "react-dom": "^19.0.0" - }, - "devDependencies": { - "@inertiajs/vite": "^3.0.0", - "@tailwindcss/vite": "^4.2.4", - "@types/node": "^25.6.0", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "concurrently": "^9.0.0", - "tailwindcss": "^4.0.0", - "typescript": "^6.0.3", - "vite": "^8.0.0" - } - }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@inertiajs/core": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-3.2.0.tgz", - "integrity": "sha512-9HXCyI8GjwN/KK3KSYZifuncZPc3jioDe/jDQVFZEJJEn89lhaE5+ope3l6sI+GaLLTs0MSZcOhyizlA5L7lig==", - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.31", - "es-toolkit": "^1.33.0", - "laravel-precognition": "^2.0.0" - }, - "peerDependencies": { - "axios": "^1.15.2" - }, - "peerDependenciesMeta": { - "axios": { - "optional": true - } - } - }, - "node_modules/@inertiajs/react": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@inertiajs/react/-/react-3.2.0.tgz", - "integrity": "sha512-Mg2d3Rw0/Cdmc94ZUS2ivWY0k0Jyjtci5g0em2F0N6treV5kLK15PgH1OYlDx8Xgin0mG3uchh+tQuv/Hh95uQ==", - "license": "MIT", - "dependencies": { - "@inertiajs/core": "3.2.0", - "es-toolkit": "^1.33.0", - "laravel-precognition": "^2.0.0" - }, - "peerDependencies": { - "react": "^19.0.0", - "react-dom": "^19.0.0" - } - }, - "node_modules/@inertiajs/vite": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@inertiajs/vite/-/vite-3.2.0.tgz", - "integrity": "sha512-J8mVzsZj3igxpQ9ZF7z5aw29uRJ3XrmpuJuYDZ8CzOBgC5k93AY4x0qk1q+CPLWBSlXD6jf1qfFHn9LWwGgawA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inertiajs/core": "3.2.0", - "tinyglobby": "^0.2.15" - }, - "peerDependencies": { - "vite": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.132.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz", - "integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz", - "integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz", - "integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz", - "integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz", - "integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz", - "integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz", - "integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz", - "integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz", - "integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz", - "integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz", - "integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz", - "integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz", - "integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz", - "integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==", - "cpu": [ - "wasm32" - ], - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz", - "integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz", - "integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "license": "MIT" - }, - "node_modules/@tailwindcss/node": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", - "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.21.0", - "jiti": "^2.6.1", - "lightningcss": "1.32.0", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.3.0" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz", - "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.3.0", - "@tailwindcss/oxide-darwin-arm64": "4.3.0", - "@tailwindcss/oxide-darwin-x64": "4.3.0", - "@tailwindcss/oxide-freebsd-x64": "4.3.0", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", - "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", - "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", - "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", - "@tailwindcss/oxide-linux-x64-musl": "4.3.0", - "@tailwindcss/oxide-wasm32-wasi": "4.3.0", - "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", - "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz", - "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz", - "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz", - "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz", - "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz", - "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz", - "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz", - "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz", - "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz", - "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz", - "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.10.0", - "@emnapi/runtime": "^1.10.0", - "@emnapi/wasi-threads": "^1.2.1", - "@napi-rs/wasm-runtime": "^1.1.4", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", - "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz", - "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/vite": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.0.tgz", - "integrity": "sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tailwindcss/node": "4.3.0", - "@tailwindcss/oxide": "4.3.0", - "tailwindcss": "4.3.0" - }, - "peerDependencies": { - "vite": "^5.2.0 || ^6 || ^7 || ^8" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/node": { - "version": "25.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", - "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" - } - }, - "node_modules/@types/react": { - "version": "19.2.15", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", - "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", - "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rolldown/pluginutils": "^1.0.0" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", - "babel-plugin-react-compiler": "^1.0.0", - "vite": "^8.0.0" - }, - "peerDependenciesMeta": { - "@rolldown/plugin-babel": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - } - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/concurrently": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", - "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "4.1.2", - "rxjs": "7.8.2", - "shell-quote": "1.8.3", - "supports-color": "8.1.1", - "tree-kill": "1.2.2", - "yargs": "17.7.2" - }, - "bin": { - "conc": "dist/bin/concurrently.js", - "concurrently": "dist/bin/concurrently.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, - "license": "MIT" - }, - "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/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/enhanced-resolve": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz", - "integrity": "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/es-toolkit": { - "version": "1.46.1", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.46.1.tgz", - "integrity": "sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/fastapi-vite-plugin": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/fastapi-vite-plugin/-/fastapi-vite-plugin-0.0.3.tgz", - "integrity": "sha512-BzUPUquR5/pHZ36Id7jtudQHyn09r2SuP2EnmjUHXLJWpcZyh0i2w7bWtriwA9wLjgw+ZLmlWgI/Rf8EyYtdOw==", - "license": "MIT", - "dependencies": { - "picocolors": "^1.0.0", - "tinyglobby": "^0.2.12", - "vite-plugin-full-reload": "^1.1.0" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "vite": "^8.0.0" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/jiti": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", - "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", - "devOptional": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/laravel-precognition": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/laravel-precognition/-/laravel-precognition-2.0.0.tgz", - "integrity": "sha512-dmA4HGc9m+TsVNsJs9/XQBI8u6j7coilN+qKkBuhuXQzH3HypwS/c5dFQ4UqUGjBbcxIM7zdk91kM/SRZwIvWQ==", - "license": "MIT", - "dependencies": { - "es-toolkit": "^1.32.0" - }, - "peerDependencies": { - "axios": "^1.4.0" - }, - "peerDependenciesMeta": { - "axios": { - "optional": true - } - } - }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", - "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/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.12", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/react": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", - "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", - "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rolldown": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.2.tgz", - "integrity": "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==", - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.132.0", - "@rolldown/pluginutils": "^1.0.0" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.2", - "@rolldown/binding-darwin-arm64": "1.0.2", - "@rolldown/binding-darwin-x64": "1.0.2", - "@rolldown/binding-freebsd-x64": "1.0.2", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.2", - "@rolldown/binding-linux-arm64-gnu": "1.0.2", - "@rolldown/binding-linux-arm64-musl": "1.0.2", - "@rolldown/binding-linux-ppc64-gnu": "1.0.2", - "@rolldown/binding-linux-s390x-gnu": "1.0.2", - "@rolldown/binding-linux-x64-gnu": "1.0.2", - "@rolldown/binding-linux-x64-musl": "1.0.2", - "@rolldown/binding-openharmony-arm64": "1.0.2", - "@rolldown/binding-wasm32-wasi": "1.0.2", - "@rolldown/binding-win32-arm64-msvc": "1.0.2", - "@rolldown/binding-win32-x64-msvc": "1.0.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/tailwindcss": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz", - "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", - "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "devOptional": true, - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/vite": { - "version": "8.0.14", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.14.tgz", - "integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==", - "license": "MIT", - "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.15", - "rolldown": "1.0.2", - "tinyglobby": "^0.2.16" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite-plugin-full-reload": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz", - "integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==", - "license": "MIT", - "dependencies": { - "picocolors": "^1.0.0", - "picomatch": "^2.3.1" - } - }, - "node_modules/vite-plugin-full-reload/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - } - } -} diff --git a/example/ai-agent-app/package.json b/example/ai-agent-app/package.json deleted file mode 100644 index a1e0d953..00000000 --- a/example/ai-agent-app/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "ai-agent-app", - "private": true, - "type": "module", - "version": "0.1.0", - "scripts": { - "dev": "concurrently \"npx vite dev\" \"uv run python artisan serve\"", - "build": "vite build", - "preview": "vite preview" - }, - "dependencies": { - "@inertiajs/react": "^3.0.0", - "fastapi-vite-plugin": "^0.0.3", - "react": "^19.0.0", - "react-dom": "^19.0.0" - }, - "devDependencies": { - "@inertiajs/vite": "^3.0.0", - "@tailwindcss/vite": "^4.2.4", - "@types/node": "^25.6.0", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "concurrently": "^9.0.0", - "tailwindcss": "^4.0.0", - "typescript": "^6.0.3", - "vite": "^8.0.0" - } -} diff --git a/example/ai-agent-app/packages/__init__.py b/example/ai-agent-app/packages/__init__.py deleted file mode 100644 index c3ec158e..00000000 --- a/example/ai-agent-app/packages/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -from packages.agent import ( - Agent, - AgentResponse, - AgentSnapshot, - Document, - provider, - model, - max_steps, - max_tokens, - timeout, - top_p, - memory, -) - -__all__ = [ - "Agent", - "AgentResponse", - "AgentSnapshot", - "Document", - "provider", - "model", - "max_steps", - "max_tokens", - "timeout", - "top_p", - "memory", -] diff --git a/example/ai-agent-app/packages/agent.py b/example/ai-agent-app/packages/agent.py deleted file mode 100644 index af6b013c..00000000 --- a/example/ai-agent-app/packages/agent.py +++ /dev/null @@ -1,765 +0,0 @@ -""" -Agent wrapper — a Laravel-inspired declarative API for building AI agents. - -Uses the Anthropic and OpenAI SDKs directly as provider backends. -The public API (Agent, AgentResponse, decorators) is provider-agnostic. - -Usage:: - - from packages.agent import Agent, AgentResponse, provider, model, max_tokens - - @provider("anthropic") - @model("claude-sonnet-4-6") - @max_tokens(2048) - class SalesAgent(Agent): - def messages(self): - return [{"role": "system", "content": "You are a helpful sales assistant."}] - - def tools(self): - return [lookup_crm, send_email] - - def provider_options(self): - return { - "anthropic": {"thinking": {"type": "enabled", "budget_tokens": 1024}}, - } - - agent = SalesAgent() - response = agent.prompt("Summarize this lead...") - for chunk in agent.stream("Write a follow-up email..."): - print(chunk, end="", flush=True) -""" - -from __future__ import annotations - -import fnmatch -import json -import os -from dataclasses import dataclass, field -from typing import Any, Callable, Iterator, Optional, Type - - -# ─── Decorators ──────────────────────────────────────────────────────────────── - - -def provider(name: str): - """Set the LLM provider: 'anthropic', 'openai', 'google', etc.""" - def decorator(cls): - cls._provider = name - return cls - return decorator - - -def model(name: str = ""): - """Set the model identifier (e.g. 'claude-sonnet-4-6', 'gpt-4o').""" - def decorator(cls): - cls._model = name - return cls - return decorator - - -def max_steps(n: int = 10): - """Maximum agentic loop iterations before stopping.""" - def decorator(cls): - cls._max_steps = n - return cls - return decorator - - -def max_tokens(n: int = 4096): - """Maximum output tokens per response.""" - def decorator(cls): - cls._max_tokens = n - return cls - return decorator - - -def timeout(seconds: float = 30.0): - """Request timeout in seconds.""" - def decorator(cls): - cls._timeout = seconds - return cls - return decorator - - -def top_p(value: float = 1.0): - """Top-p nucleus sampling parameter.""" - def decorator(cls): - cls._top_p = value - return cls - return decorator - - -def memory(backend: str = ""): - """Attach a named memory backend to this agent.""" - def decorator(cls): - cls._memory_backend = backend - return cls - return decorator - - -# ─── Response Objects ────────────────────────────────────────────────────────── - - -@dataclass -class AgentResponse: - """Returned by Agent.prompt(). Wraps the LLM response.""" - content: str = "" - tool_calls: list[dict] = field(default_factory=list) - usage: dict = field(default_factory=dict) - raw: Any = None - - def text(self) -> str: - """Return the text content.""" - return self.content - - def json(self) -> Any: - """Parse the content as JSON.""" - return json.loads(self.content) - - def __str__(self) -> str: - return self.content - - def __bool__(self) -> bool: - return bool(self.content) - - -@dataclass -class AgentSnapshot: - """ - Record-and-replay snapshot for testing. - - - If the file at ``path`` **does not exist**: the agent calls the real API, - saves the response as JSON, then returns it. - - If the file **exists**: the saved response is loaded and returned without - hitting the API. - - This lets tests run against real responses on first run and be fully - offline and deterministic on every subsequent run. - - Example:: - - agent.fake({"*analyze*": AgentSnapshot(path="tests/fixtures/analysis.json")}) - """ - path: str - - def exists(self) -> bool: - """Return True if the snapshot file is already recorded.""" - return os.path.exists(self.path) - - def load(self) -> AgentResponse: - """Load the recorded response from disk.""" - with open(self.path) as f: - data = json.load(f) - return AgentResponse( - content=data.get("content", ""), - tool_calls=data.get("tool_calls", []), - usage=data.get("usage", {}), - ) - - def save(self, response: AgentResponse) -> None: - """Persist a real API response to disk for future replays.""" - os.makedirs(os.path.dirname(self.path) or ".", exist_ok=True) - with open(self.path, "w") as f: - json.dump( - { - "content": response.content, - "tool_calls": response.tool_calls, - "usage": response.usage, - }, - f, - indent=2, - ) - - def resolve(self, agent: "Agent", message: str, **run_kwargs: Any) -> AgentResponse: - """ - Return the response — from disk if recorded, or from the real API - (which is then saved for future runs). - """ - if self.exists(): - return self.load() - response = agent._run(message, **run_kwargs) - self.save(response) - return response - - -# ─── Attachment Helper ───────────────────────────────────────────────────────── - - -class Document: - """Attach documents to agent.prompt() calls.""" - - def __init__(self, content: str, name: str = "", media_type: str = "text/plain"): - self.content = content - self.name = name - self.media_type = media_type - - @classmethod - def from_path(cls, path: str) -> "Document": - """Load a document from a local file path.""" - with open(path) as f: - content = f.read() - return cls(content=content, name=path) - - @classmethod - def from_storage(cls, key: str) -> "Document": - """Load a document from application storage (storage/).""" - return cls.from_path(f"storage/{key}") - - def to_anthropic_block(self) -> dict: - """Return an Anthropic-compatible content block for this document.""" - return { - "type": "document", - "source": {"type": "text", "media_type": self.media_type, "data": self.content}, - "title": self.name, - } - - -# ─── Agent Base Class ────────────────────────────────────────────────────────── - - -class Agent: - """ - Base class for all agents. Subclass this and override lifecycle methods. - - Class-level configuration (set via decorators or subclass attributes):: - - _provider = "anthropic" # LLM provider - _model = "" # model ID (empty = provider default) - _max_steps = 10 # max agentic loop iterations - _max_tokens = 4096 # max output tokens - _timeout = 30.0 # request timeout in seconds - _top_p = 1.0 # top-p nucleus sampling - _memory_backend = "" # memory backend name (reserved) - """ - - _provider: str = "anthropic" - _model: str = "" - _max_steps: int = 10 - _max_tokens: int = 4096 - _timeout: float = 30.0 - _top_p: float = 1.0 - _memory_backend: str = "" - - # Provider → default model - _DEFAULT_MODELS: dict[str, str] = { - "anthropic": "claude-sonnet-4-6", - "openai": "gpt-4o", - "google": "gemini-2.0-flash", - } - - def __init__(self): - self._fakes: dict[str, AgentResponse | AgentSnapshot] = {} - self._call_log: list[dict] = [] - - # ── Lifecycle — override in subclasses ────────────────────────────────── - - def messages(self) -> list[dict]: - """ - Return initial messages / few-shot examples. - Use role 'system' for the system prompt. - - Example:: - - def messages(self): - return [ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "What is 2+2?"}, - {"role": "assistant", "content": "4"}, - ] - """ - return [] - - def schema(self) -> Optional[Type]: - """ - Return a Pydantic model class for structured output, or None for plain text. - - The agent forces the LLM to return a valid instance of this model. - Access it via response.json() or response.content (raw JSON string). - - Example:: - - from pydantic import BaseModel - - class LeadSummary(BaseModel): - name: str - score: int - - def schema(self): - return LeadSummary - """ - return None - - def tools(self) -> list[Callable]: - """ - Return a list of callable tools the agent may invoke. - - Each tool should have a docstring and type-annotated parameters. - LangChain's StructuredTool.from_function() builds the schema automatically. - - Example:: - - def tools(self): - return [search_web, lookup_crm, send_email] - """ - return [] - - def middleware(self) -> list[Callable]: - """ - Return middleware callables that wrap each LLM request. - Each middleware receives (message, next) and must call next(message). - - Example:: - - def rate_limit(message, next): - time.sleep(0.5) - return next(message) - - def middleware(self): - return [rate_limit] - """ - return [] - - def provider_options(self) -> dict: - """ - Return provider-specific options keyed by provider name. - Passed as model_kwargs to the LangChain chat model constructor. - - Example:: - - def provider_options(self): - return { - "anthropic": { - "thinking": {"type": "enabled", "budget_tokens": 1024}, - }, - "openai": { - "frequency_penalty": 0.5, - }, - } - """ - return {} - - def before(self, message: str) -> str: - """Called before the message is sent. Return the (possibly modified) message.""" - return message - - def after(self, response: AgentResponse) -> AgentResponse: - """Called after the LLM responds. Return the (possibly modified) response.""" - return response - - # ── Public API ────────────────────────────────────────────────────────── - - def prompt( - self, - message: str, - *, - system: str | None = None, - model: str | None = None, - messages: list[dict] | None = None, - attachments: list[Document] | None = None, - provider_options: dict | None = None, - ) -> AgentResponse: - """ - Send a prompt and return an AgentResponse. - - Runs the full agentic loop: if the model calls tools, they are - executed and results fed back until the model stops or _max_steps - is reached. - - Args: - message: The user message. - system: Override the system prompt for this call only. - model: Override the model for this call only. - messages: Extra conversation history to prepend. - attachments: Documents to include with the message. - provider_options: Per-provider options merged for this call only. - """ - message = self.before(message) - - _run_kwargs = dict( - system=system, - model=model, - extra_messages=messages, - attachments=attachments, - provider_options=provider_options, - ) - - match = self._match_fake(message) - if match is not None: - if isinstance(match, AgentSnapshot): - response = match.resolve(self, message, **_run_kwargs) - else: - response = match - self._log_call("prompt", message) - return self.after(response) - - def _call(msg: str) -> AgentResponse: - return self._run(msg, **_run_kwargs) - - response = self._apply_middleware(message, _call) - self._log_call("prompt", message) - return self.after(response) - - def stream( - self, - message: str, - *, - system: str | None = None, - model: str | None = None, - provider_options: dict | None = None, - ) -> Iterator[str]: - """ - Stream a response token by token. - - Note: tool execution is not supported during streaming. - Use prompt() for agentic tool loops. - - Example:: - - for chunk in agent.stream("Write a report..."): - print(chunk, end="", flush=True) - """ - message = self.before(message) - self._log_call("stream", message) - yield from self._stream(message, system=system, model=model, provider_options=provider_options) - - def fake(self, patterns: dict[str, AgentResponse | AgentSnapshot]) -> "Agent": - """ - Register fake responses for testing. Keys are glob patterns matched - against the prompt text (case-insensitive glob). - - - ``AgentResponse`` — always returned as-is (fully offline). - - ``AgentSnapshot`` — replayed from disk if the file exists; otherwise - the real API is called, the response is saved, and replayed next time. - - Example:: - - agent.fake({ - "*hello*": AgentResponse(content="Hello!"), - "*analyze*": AgentSnapshot(path="tests/fixtures/analysis.json"), - }) - """ - for pattern, value in patterns.items(): - self._fakes[pattern] = value # snapshots are stored un-resolved - return self - - def assert_prompted(self, times: int | None = None) -> None: - """ - Assert that prompt() or stream() was called. - - Args: - times: If given, assert exactly this many calls. Otherwise assert >= 1. - """ - calls = [c for c in self._call_log if c["method"] in ("prompt", "stream")] - if times is not None: - assert len(calls) == times, f"Expected {times} prompt call(s), got {len(calls)}" - else: - assert len(calls) > 0, "Expected at least one prompt() or stream() call, but none were made" - - def assert_not_prompted(self) -> None: - """Assert that prompt() and stream() were never called.""" - self.assert_prompted(times=0) - - def reset(self) -> "Agent": - """Clear fakes and call log. Useful between test cases.""" - self._fakes.clear() - self._call_log.clear() - return self - - # ── Internal helpers ──────────────────────────────────────────────────── - - def _match_fake(self, message: str) -> Optional[AgentResponse | AgentSnapshot]: - for pattern, value in self._fakes.items(): - if fnmatch.fnmatch(message.lower(), pattern.lower()): - return value - return None - - def _log_call(self, method: str, message: str) -> None: - self._call_log.append({"method": method, "message": message}) - - def _apply_middleware( - self, message: str, final: Callable[[str], AgentResponse] - ) -> AgentResponse: - """Build a left-to-right middleware chain and invoke it.""" - chain = list(self.middleware()) - - def build(mw_list: list, fn: Callable) -> Callable: - if not mw_list: - return fn - head, *tail = mw_list - next_fn = build(tail, fn) - return lambda msg: head(msg, next_fn) - - return build(chain, final)(message) - - def _execute_tool(self, name: str, inputs: dict) -> Any: - """Find a tool by function name and call it with the given inputs.""" - for tool in self.tools(): - if callable(tool) and tool.__name__ == name: - return tool(**inputs) - raise ValueError(f"Tool {name!r} not found") - - def _resolve_model(self, override: str | None = None) -> str: - if override: - return override - if self._model: - return self._model - return self._DEFAULT_MODELS.get(self._provider, "") - - def _get_provider_options(self, override: dict | None = None) -> dict: - options = dict(self.provider_options().get(self._provider, {})) - if override: - provider_specific = override.get(self._provider, override) - if isinstance(provider_specific, dict): - options.update(provider_specific) - return options - - def _build_messages( - self, - message: str, - system: str | None = None, - extra_messages: list[dict] | None = None, - attachments: list[Document] | None = None, - ) -> tuple[str | None, list[dict]]: - base = self.messages() - - resolved_system = system - if resolved_system is None: - sys_entries = [m for m in base if m.get("role") == "system"] - if sys_entries: - resolved_system = sys_entries[0]["content"] - - history = [m for m in base if m.get("role") != "system"] - if extra_messages: - history.extend(extra_messages) - - if attachments: - content: Any = [{"type": "text", "text": message}] - for doc in attachments: - content.append(doc.to_anthropic_block()) - history.append({"role": "user", "content": content}) - else: - history.append({"role": "user", "content": message}) - - return resolved_system, history - - def _tools_schema(self) -> list[dict]: - """Convert tools() callables to Anthropic-style tool definitions.""" - import inspect - result = [] - for tool in self.tools(): - if not callable(tool): - continue - sig = inspect.signature(tool) - try: - import typing - hints = typing.get_type_hints(tool) - except Exception: - hints = {} - properties = { - name: {"type": _python_type_to_json(hints.get(name, str))} - for name in sig.parameters - } - result.append({ - "name": tool.__name__, - "description": inspect.getdoc(tool) or tool.__name__, - "input_schema": { - "type": "object", - "properties": properties, - "required": [ - n for n, p in sig.parameters.items() - if p.default is inspect.Parameter.empty - ], - }, - }) - return result - - # ── Provider dispatch ─────────────────────────────────────────────────── - - def _run( - self, - message: str, - system: str | None, - model: str | None, - extra_messages: list[dict] | None, - attachments: list[Document] | None, - provider_options: dict | None, - ) -> AgentResponse: - resolved_system, messages = self._build_messages(message, system, extra_messages, attachments) - resolved_model = self._resolve_model(model) - options = self._get_provider_options(provider_options) - - if self._provider == "anthropic": - return self._run_anthropic(resolved_system, messages, resolved_model, options) - if self._provider == "openai": - return self._run_openai(resolved_system, messages, resolved_model, options) - raise ValueError(f"Unsupported provider: {self._provider!r}. Use 'anthropic' or 'openai'.") - - def _stream( - self, - message: str, - system: str | None, - model: str | None, - provider_options: dict | None, - ) -> Iterator[str]: - resolved_system, messages = self._build_messages(message, system) - resolved_model = self._resolve_model(model) - options = self._get_provider_options(provider_options) - - if self._provider == "anthropic": - yield from self._stream_anthropic(resolved_system, messages, resolved_model, options) - elif self._provider == "openai": - yield from self._stream_openai(resolved_system, messages, resolved_model, options) - else: - raise ValueError(f"Unsupported provider: {self._provider!r}. Use 'anthropic' or 'openai'.") - - # ── Anthropic ────────────────────────────────────────────────────────── - - def _run_anthropic( - self, - system: str | None, - messages: list[dict], - model: str, - options: dict, - ) -> AgentResponse: - from anthropic import Anthropic - - client = Anthropic() - params: dict[str, Any] = { - "model": model, - "max_tokens": self._max_tokens, - "messages": messages, - **options, - } - if system: - params["system"] = system - tools_schema = self._tools_schema() - if tools_schema: - params["tools"] = tools_schema - - # Agentic tool loop - for _step in range(self._max_steps): - resp = client.messages.create(**params) - - if resp.stop_reason != "tool_use": - break - - # Collect tool calls and execute them - tool_uses = [b for b in resp.content if b.type == "tool_use"] - tool_results = [] - for tu in tool_uses: - try: - result = self._execute_tool(tu.name, tu.input) - except Exception as exc: - result = f"Error: {exc}" - tool_results.append({ - "type": "tool_result", - "tool_use_id": tu.id, - "content": str(result), - }) - - # Feed results back into the conversation - params["messages"] = [ - *params["messages"], - {"role": "assistant", "content": resp.content}, - {"role": "user", "content": tool_results}, - ] - - content = "".join( - b.text for b in resp.content if hasattr(b, "text") - ) - tool_calls = [ - {"name": b.name, "input": b.input} - for b in resp.content if b.type == "tool_use" - ] - return AgentResponse( - content=content, - tool_calls=tool_calls, - usage={"input": resp.usage.input_tokens, "output": resp.usage.output_tokens}, - raw=resp, - ) - - def _stream_anthropic( - self, - system: str | None, - messages: list[dict], - model: str, - options: dict, - ) -> Iterator[str]: - from anthropic import Anthropic - - client = Anthropic() - params: dict[str, Any] = { - "model": model, - "max_tokens": self._max_tokens, - "messages": messages, - **options, - } - if system: - params["system"] = system - - with client.messages.stream(**params) as stream: - for text in stream.text_stream: - yield text - - # ── OpenAI ───────────────────────────────────────────────────────────── - - def _run_openai( - self, - system: str | None, - messages: list[dict], - model: str, - options: dict, - ) -> AgentResponse: - from openai import OpenAI - - client = OpenAI() - all_messages: list[dict] = [] - if system: - all_messages.append({"role": "system", "content": system}) - all_messages.extend(messages) - - params: dict[str, Any] = { - "model": model, - "max_tokens": self._max_tokens, - "messages": all_messages, - **options, - } - - resp = client.chat.completions.create(**params) - content = resp.choices[0].message.content or "" - return AgentResponse( - content=content, - usage={ - "input": resp.usage.prompt_tokens if resp.usage else 0, - "output": resp.usage.completion_tokens if resp.usage else 0, - }, - raw=resp, - ) - - def _stream_openai( - self, - system: str | None, - messages: list[dict], - model: str, - options: dict, - ) -> Iterator[str]: - from openai import OpenAI - - client = OpenAI() - all_messages: list[dict] = [] - if system: - all_messages.append({"role": "system", "content": system}) - all_messages.extend(messages) - - params: dict[str, Any] = { - "model": model, - "max_tokens": self._max_tokens, - "messages": all_messages, - "stream": True, - **options, - } - - for chunk in client.chat.completions.create(**params): - delta = chunk.choices[0].delta.content - if delta: - yield delta diff --git a/example/ai-agent-app/providers/__init__.py b/example/ai-agent-app/providers/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/example/ai-agent-app/providers/fastapi_provider.py b/example/ai-agent-app/providers/fastapi_provider.py deleted file mode 100644 index cfc9542e..00000000 --- a/example/ai-agent-app/providers/fastapi_provider.py +++ /dev/null @@ -1,23 +0,0 @@ -from pathlib import Path - -from fastapi_startkit.fastapi import FastAPIProvider as BaseFastAPIProvider -from starlette.templating import Jinja2Templates - - -class FastAPIProvider(BaseFastAPIProvider): - def register(self) -> None: - super().register() - - templates_dir = Path(self.app.base_path) / "templates" - templates = Jinja2Templates(directory=str(templates_dir)) - self.app.bind("templates", templates) - - def boot(self) -> None: - super().boot() - - inertia = self.app.make("inertia") - inertia.share("app_name", "AI Agent App") - inertia.version("1.0.0") - - from routes.web import router - self.app.include_router(router) diff --git a/example/ai-agent-app/public/.gitkeep b/example/ai-agent-app/public/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/example/ai-agent-app/public/hot b/example/ai-agent-app/public/hot deleted file mode 100644 index f762bcfc..00000000 --- a/example/ai-agent-app/public/hot +++ /dev/null @@ -1 +0,0 @@ -http://[::1]:5173 \ No newline at end of file diff --git a/example/ai-agent-app/pyproject.toml b/example/ai-agent-app/pyproject.toml deleted file mode 100644 index b3af7491..00000000 --- a/example/ai-agent-app/pyproject.toml +++ /dev/null @@ -1,25 +0,0 @@ -[project] -name = "ai-agent-app" -version = "0.1.0" -description = "AI Agent app built with FastAPI Startkit + Inertia.js + React" -requires-python = ">=3.12" -dependencies = [ - "anthropic>=0.104.1", - "fastapi-startkit[fastapi]", - "jinja2>=3.1", - "python-multipart>=0.0.9", -] - -[tool.uv.sources] -fastapi-startkit = { path = "../../fastapi_startkit", editable = true } - -[dependency-groups] -dev = [ - "pytest>=8.0", - "pytest-asyncio>=0.24", - "httpx>=0.27", -] - -[tool.pytest.ini_options] -asyncio_mode = "auto" -testpaths = ["tests"] diff --git a/example/ai-agent-app/resources/css/app.css b/example/ai-agent-app/resources/css/app.css deleted file mode 100644 index f1d8c73c..00000000 --- a/example/ai-agent-app/resources/css/app.css +++ /dev/null @@ -1 +0,0 @@ -@import "tailwindcss"; diff --git a/example/ai-agent-app/resources/js/Pages/Chat/Index.tsx b/example/ai-agent-app/resources/js/Pages/Chat/Index.tsx deleted file mode 100644 index 5e202198..00000000 --- a/example/ai-agent-app/resources/js/Pages/Chat/Index.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import { useState, useRef, useEffect } from "react" - -interface Message { - role: "user" | "assistant" - content: string -} - -export default function Index() { - const [messages, setMessages] = useState([]) - const [input, setInput] = useState("") - const [loading, setLoading] = useState(false) - const bottomRef = useRef(null) - - useEffect(() => { - bottomRef.current?.scrollIntoView({ behavior: "smooth" }) - }, [messages, loading]) - - async function send() { - const text = input.trim() - if (!text || loading) return - - setMessages(prev => [...prev, { role: "user", content: text }]) - setInput("") - setLoading(true) - - try { - const res = await fetch("/chat", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ message: text }), - }) - const data = await res.json() - setMessages(prev => [...prev, { role: "assistant", content: data.reply }]) - } catch { - setMessages(prev => [...prev, { role: "assistant", content: "Something went wrong. Please try again." }]) - } finally { - setLoading(false) - } - } - - function handleKeyDown(e: React.KeyboardEvent) { - if (e.key === "Enter" && !e.shiftKey) { - e.preventDefault() - send() - } - } - - return ( -
- {/* Header */} -
-
- - - -
-
-

AI Assistant

-

Powered by Claude

-
-
- - {/* Messages */} -
- {messages.length === 0 && ( -
-
- - - -
-

Send a message to start the conversation.

-
- )} - - {messages.map((msg, i) => ( -
- {/* Avatar */} -
- {msg.role === "user" ? "U" : "AI"} -
- - {/* Bubble */} -
- {msg.content} -
-
- ))} - - {/* Typing indicator */} - {loading && ( -
-
- AI -
-
- - - -
-
- )} - -
-
- - {/* Input */} -
-
-