diff --git a/CHANGELOG.md b/CHANGELOG.md index 85a3f5c..77e51c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 0.8.0 (2026-06-02) + +### Added +- Vite-built embedded web console served through the Worker `ASSETS` binding, including text chat, conversation history, health summary, and a voice panel using `@cloudflare/voice/react`. (aegis-oss#40) +- `AegisVoiceAdapter` standalone Worker export and Agents SDK `/agents/aegis-voice-adapter/operator` routing for Cloudflare-native voice calls. (aegis-oss#40) +- Built `public/` SPA assets in the package so a fresh checkout can deploy a working console without a private Stackbilt UI dependency. (aegis-oss#40) + +### Changed +- `npm run deploy` and `npm run dev` now build the embedded UI before invoking Wrangler, and `wrangler.toml.example` includes `ASSETS`, `CHAT_SESSION`, `AegisVoiceAdapter`, `DB`, and `AI` bindings. +- The browser console uses Workers AI for its base chat path and treats Claude/Groq keys as optional executor upgrades. + +### Fixed +- `/agents/*` voice routes now enforce the same `AEGIS_TOKEN` via bearer header, cookie, or query token before reaching the Agents SDK router. +- HTTP message routes skip Groq title generation when `GROQ_API_KEY` is unset. + ## 0.7.0 (2026-06-02) ### Added diff --git a/README.md b/README.md index 33c2890..ccf5d47 100644 --- a/README.md +++ b/README.md @@ -58,14 +58,12 @@ npx wrangler d1 execute my-agent --file=schema.sql # Set secrets npx wrangler secret put AEGIS_TOKEN # Random bearer token for auth -npx wrangler secret put ANTHROPIC_API_KEY # Claude API key -npx wrangler secret put GROQ_API_KEY # Groq key (free tier available) # Deploy -npx wrangler deploy +npm run deploy ``` -Visit `https://your-worker.workers.dev` and authenticate with your AEGIS_TOKEN. +Visit `https://your-worker.workers.dev` and authenticate with your AEGIS_TOKEN. The embedded console uses Workers AI for the base chat and voice path; Claude and Groq keys are optional executor upgrades. Talk to the same deployment from a terminal: diff --git a/docs/configuration.md b/docs/configuration.md index ceee430..1c73db5 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -137,12 +137,28 @@ Set via `npx wrangler secret put `: | Secret | Required | Purpose | |--------|----------|---------| | `AEGIS_TOKEN` | Yes | Bearer token for chat UI auth | -| `ANTHROPIC_API_KEY` | Yes | Claude API key | +| `ANTHROPIC_API_KEY` | No | Claude executor API key | | `GROQ_API_KEY` | No | Groq API key for fast classification | | `GITHUB_TOKEN` | No | GitHub PAT for repo access | | `BRAVE_API_KEY` | No | Brave Search API key | | `RESEND_API_KEY` | No | Resend API key for email | +Base chat and voice operation use the Cloudflare Workers AI binding configured in `wrangler.toml`. + +## Embedded web console + +Standalone deployments serve the Vite-built web console from `web/public/` through the `ASSETS` binding: + +```toml +[assets] +directory = "./public" +binding = "ASSETS" +not_found_handling = "single-page-application" +run_worker_first = ["/api/*", "/health", "/agents/*"] +``` + +`npm run build:ui` builds `src/ui/` into `public/`. `npm run deploy` and `npm run dev` run that build before Wrangler starts. + ## Service bindings (optional) Configure in `wrangler.toml` for inter-Worker communication: @@ -198,3 +214,17 @@ Fresh databases created from `schema.sql` include the required `conversations.us ALTER TABLE conversations ADD COLUMN user_id TEXT NOT NULL DEFAULT 'operator'; CREATE INDEX IF NOT EXISTS idx_conversations_user_updated ON conversations(user_id, updated_at); ``` + +## Voice Durable Object + +The browser voice UI uses `@cloudflare/voice/react` and connects through the Agents SDK path `/agents/aegis-voice-adapter/operator`. Configure the matching Durable Object binding: + +```toml +[[durable_objects.bindings]] +name = "AegisVoiceAdapter" +class_name = "AegisVoiceAdapter" + +[[migrations]] +tag = "v2-aegis-voice-adapter" +new_sqlite_classes = ["AegisVoiceAdapter"] +``` diff --git a/docs/getting-started.md b/docs/getting-started.md index 5341917..949b260 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -6,8 +6,8 @@ Deploy your own AEGIS agent on Cloudflare Workers in under 10 minutes. - [Node.js](https://nodejs.org/) 18+ - A [Cloudflare](https://cloudflare.com) account (free tier works) -- An [Anthropic](https://console.anthropic.com) API key (for Claude) -- Optional: [Groq](https://console.groq.com) API key (free tier available, used for fast classification) +- Workers AI enabled in your Cloudflare account +- Optional: external model keys for Claude or Groq if you want those executors ## 1. Clone and install @@ -37,7 +37,10 @@ npx wrangler d1 create my-agent This prints a `database_id` — paste it into `wrangler.toml` under `[[d1_databases]]`. -The example Wrangler config also includes the `CHAT_SESSION` Durable Object binding and SQLite-backed migration required by `/chat/ws`. +The example Wrangler config also includes: +- the `ASSETS` binding for the Vite-built web console in `public/` +- the `CHAT_SESSION` Durable Object binding required by `/chat/ws` +- the `AegisVoiceAdapter` Durable Object binding required by the browser voice call flow Then run the schema migration: @@ -56,16 +59,16 @@ Edit `config.ts` to set your name, persona traits, and which integrations to ena ## 5. Set secrets -At minimum, you need an auth token and an AI model key: +At minimum, you need an auth token: ```bash npx wrangler secret put AEGIS_TOKEN # A random bearer token you'll use to authenticate -npx wrangler secret put ANTHROPIC_API_KEY # Your Claude API key ``` Optional secrets for additional capabilities: ```bash +npx wrangler secret put ANTHROPIC_API_KEY # Claude executors npx wrangler secret put GROQ_API_KEY # Fast classification (Llama 3.3 70B) npx wrangler secret put GITHUB_TOKEN # Repository scanning, issue management npx wrangler secret put BRAVE_API_KEY # Web research @@ -75,10 +78,10 @@ npx wrangler secret put RESEND_API_KEY # Email notifications ## 6. Deploy ```bash -npx wrangler deploy +npm run deploy ``` -Your agent is now live at `https://your-worker-name.your-subdomain.workers.dev`. +The deploy script builds the embedded SPA into `public/` and then runs `wrangler deploy`. Your agent is now live at `https://your-worker-name.your-subdomain.workers.dev`. ## 7. Authenticate @@ -102,12 +105,10 @@ For local development without deploying: # Create a .dev.vars file with your secrets cat > ../.dev.vars << 'EOF' AEGIS_TOKEN=test-token -ANTHROPIC_API_KEY=sk-ant-... -GROQ_API_KEY=gsk_... EOF # Run locally -npx wrangler dev +npm run dev ``` ## Next steps diff --git a/docs/publishing.md b/docs/publishing.md index d6d799d..5f02e14 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -7,8 +7,8 @@ Push a semver tag from `main`: ```bash -git tag v0.7.0 -git push origin v0.7.0 +git tag v0.8.0 +git push origin v0.8.0 ``` The workflow installs dependencies, runs typecheck/tests, then publishes `web/package.json` to npm. diff --git a/web/package-lock.json b/web/package-lock.json index 7197e17..e3d15bc 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "@stackbilt/aegis-core", - "version": "0.7.0", + "version": "0.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@stackbilt/aegis-core", - "version": "0.7.0", + "version": "0.8.0", "license": "Apache-2.0", "dependencies": { "@cloudflare/voice": "^0.1.3", @@ -15,10 +15,18 @@ "@stackbilt/llm-providers": "^1.6.4", "agents": "^0.12.3", "hono": "^4.12.12", + "partysocket": "^1.1.19", + "react": "^19.2.7", + "react-dom": "^19.2.7", "zod": "^4.4.3" }, + "bin": { + "aegis": "cli/aegis.mjs" + }, "devDependencies": { "@cloudflare/workers-types": "^4.20241218.0", + "@types/react": "^19.2.16", + "@types/react-dom": "^19.2.3", "typescript": "^5.7.3", "vite": "^8.0.5", "vitest": "^4.0.18", @@ -2059,6 +2067,26 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/react": { + "version": "19.2.16", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.16.tgz", + "integrity": "sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==", + "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/@vercel/oidc": { "version": "3.2.0", "license": "Apache-2.0", @@ -2243,6 +2271,23 @@ "node": "^18 || >=20" } }, + "node_modules/agents/node_modules/partysocket": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/partysocket/-/partysocket-1.1.18.tgz", + "integrity": "sha512-SyuvH9VavWOSa14v6dYdp3yfSUDII4BQB1+TkGOFBkjfZKjnDBiba4fhdhwBlqGBkqw4ea3gTA1DYhSffX24Wg==", + "license": "MIT", + "dependencies": { + "event-target-polyfill": "^0.0.4" + }, + "peerDependencies": { + "react": ">=17" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, "node_modules/ai": { "version": "6.0.175", "license": "Apache-2.0", @@ -2542,6 +2587,13 @@ "node": ">= 8" } }, + "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/debug": { "version": "4.4.3", "license": "MIT", @@ -3577,7 +3629,9 @@ } }, "node_modules/partysocket": { - "version": "1.1.18", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/partysocket/-/partysocket-1.1.19.tgz", + "integrity": "sha512-hPwsXSdUc8PKNCinET6TD3JQOxzQ2JaP0bUZQXBVl6UM8UuLn1odgf1LcJXHy4UHSQwWL/RU3AnyhEsGM+W+sg==", "license": "MIT", "dependencies": { "event-target-polyfill": "^0.0.4" @@ -3701,13 +3755,26 @@ } }, "node_modules/react": { - "version": "19.2.6", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.7" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "license": "MIT", @@ -3772,6 +3839,12 @@ "version": "2.1.2", "license": "MIT" }, + "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/semver": { "version": "7.7.4", "dev": true, diff --git a/web/package.json b/web/package.json index fe9867c..938b029 100755 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "@stackbilt/aegis-core", - "version": "0.7.0", + "version": "0.8.0", "description": "Persistent AI agent framework for Cloudflare Workers. Multi-tier memory, autonomous goals, dreaming cycles, MCP native.", "license": "Apache-2.0", "publishConfig": { @@ -80,8 +80,9 @@ "./kernel/patterns": "./src/kernel/patterns.ts" }, "scripts": { - "dev": "wrangler dev", - "deploy": "wrangler deploy", + "dev": "npm run build:ui && wrangler dev", + "deploy": "npm run build:ui && wrangler deploy", + "build:ui": "vite build --config vite.ui.config.ts", "d1:create": "wrangler d1 create aegis-web", "d1:migrate": "wrangler d1 execute aegis-web --file=schema.sql", "d1:migrate:local": "wrangler d1 execute aegis-web --file=schema.sql --local", @@ -96,10 +97,15 @@ "@stackbilt/llm-providers": "^1.6.4", "agents": "^0.12.3", "hono": "^4.12.12", + "partysocket": "^1.1.19", + "react": "^19.2.7", + "react-dom": "^19.2.7", "zod": "^4.4.3" }, "devDependencies": { "@cloudflare/workers-types": "^4.20241218.0", + "@types/react": "^19.2.16", + "@types/react-dom": "^19.2.3", "typescript": "^5.7.3", "vite": "^8.0.5", "vitest": "^4.0.18", @@ -108,6 +114,10 @@ "files": [ "cli/**/*.mjs", "src/**/*.ts", + "src/**/*.tsx", + "src/ui/**/*.css", + "src/ui/**/*.html", + "public/**/*", "schema.sql" ], "keywords": [ diff --git a/web/public/assets/index-CQHn03rW.css b/web/public/assets/index-CQHn03rW.css new file mode 100644 index 0000000..d61d3b3 --- /dev/null +++ b/web/public/assets/index-CQHn03rW.css @@ -0,0 +1 @@ +:root{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;color:#edf0ef;background:#101317;font-family:IBM Plex Sans,Aptos,Segoe UI,sans-serif;line-height:1.45}*{box-sizing:border-box}body{background-color:#101317;background-image:linear-gradient(90deg,#f6bd6014 1px,#0000 1px),linear-gradient(#76b38414 1px,#0000 1px),none;background-position:0 0,0 0,0 0;background-repeat:repeat,repeat,repeat;background-size:48px 48px;background-attachment:scroll,scroll,scroll;background-origin:padding-box,padding-box,padding-box;background-clip:border-box,border-box,border-box;min-width:320px;min-height:100vh;margin:0}button,input,textarea{font:inherit}button{color:#11130f;cursor:pointer;background:#e7b75f;border:1px solid #3a4440;border-radius:6px;font-weight:700}button:disabled{cursor:not-allowed;opacity:.45}input,textarea{color:#f2f4f1;background:#151a1d;border:1px solid #39413f;border-radius:6px;width:100%}input:focus,textarea:focus,button:focus-visible{outline-offset:2px;outline:2px solid #76b384}.shell{grid-template-columns:minmax(240px,320px) minmax(0,1fr) minmax(260px,340px);min-height:100vh;display:grid}.rail,.voice-panel{background:#0d1113f0;border-color:#28302d;flex-direction:column;gap:18px;padding:18px;display:flex}.rail{border-right:1px solid #28302d}.voice-panel{border-left:1px solid #28302d}.brand{align-items:center;gap:12px;min-height:64px;display:flex}.brand-mark{color:#76b384;border:1px solid #76b384;border-radius:6px;place-items:center;width:44px;height:44px;font-family:IBM Plex Mono,Cascadia Mono,monospace;font-size:1.4rem;font-weight:800;display:grid}.brand h1,.topbar h2{letter-spacing:0;margin:0}.brand p,.eyebrow,.runtime-status,.conversation small,.voice-state,label,dt{color:#9aa39d;font-size:.82rem}.token-panel,.health-panel,.conversation-panel{flex-direction:column;gap:10px;display:flex}.token-row,.panel-title,.voice-actions,.voice-text{align-items:center;gap:8px;display:flex}.token-row button,.panel-title button{width:42px;height:38px}.token-row input,.voice-text input{height:38px;padding:0 10px}.panel-title{text-transform:uppercase;letter-spacing:0;justify-content:space-between;min-height:38px;font-weight:800}.health-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:0;display:grid}.health-grid div{background:#151a1d;border:1px solid #2f3835;border-radius:6px;padding:10px}.health-grid dd{margin:4px 0 0;font-family:IBM Plex Mono,Cascadia Mono,monospace;font-weight:800}.new-chat{min-height:38px}.conversation-list{flex-direction:column;gap:6px;max-height:40vh;display:flex;overflow:auto}.conversation{text-align:left;color:#eef0ef;background:#151a1d;gap:4px;min-height:58px;padding:10px;display:grid}.conversation.active{border-color:#76b384}.workspace{grid-template-rows:auto minmax(0,1fr) auto;min-width:0;display:grid}.topbar{background:#101317c7;border-bottom:1px solid #28302d;justify-content:space-between;align-items:center;gap:24px;min-height:84px;padding:18px 22px;display:flex}.eyebrow{text-transform:uppercase;margin:0 0 4px;font-weight:800}.runtime-status{white-space:nowrap;align-items:center;gap:8px;display:flex}.dot{background:#8e403b;border-radius:50%;width:10px;height:10px}.dot.online{background:#76b384}.message-surface{flex-direction:column;gap:12px;padding:22px;display:flex;overflow:auto}.empty-state{color:#b8beb9;text-align:center;place-items:center;min-height:100%;display:grid}.message{background:#151a1deb;border:1px solid #2d3633;border-radius:6px;grid-template-columns:92px minmax(0,1fr);gap:12px;max-width:980px;padding:12px;display:grid}.message.user{border-color:#6f5d38}.message-role{color:#e7b75f;text-transform:uppercase;font-family:IBM Plex Mono,Cascadia Mono,monospace;font-size:.78rem;font-weight:800}.message-content{white-space:pre-wrap;overflow-wrap:anywhere}.composer{background:#0d1113f0;border-top:1px solid #28302d;grid-template-columns:minmax(0,1fr) 96px;gap:10px;padding:18px 22px;display:grid}.composer textarea{resize:vertical;min-height:72px;padding:10px}.composer button{min-height:72px}.meter{background:#151a1d;border:1px solid #39413f;border-radius:999px;height:12px;overflow:hidden}.meter span{background:#76b384;height:100%;display:block}.voice-actions button{flex:1;min-height:40px}.voice-transcript{gap:8px;min-height:180px;max-height:42vh;display:grid;overflow:auto}.voice-transcript p{background:#151a1d;border:1px solid #2f3835;border-radius:6px;gap:4px;margin:0;padding:10px;display:grid}.voice-transcript strong{color:#e7b75f;text-transform:uppercase;font-size:.76rem}.error{color:#f0a39d;margin:0}.voice-text button{width:70px;min-height:38px}@media (width<=1100px){.shell{grid-template-columns:minmax(220px,280px) minmax(0,1fr)}.voice-panel{border-top:1px solid #28302d;border-left:none;grid-column:1/-1}}@media (width<=760px){.shell{grid-template-columns:1fr}.rail,.voice-panel{border-inline:none}.topbar,.composer,.message{grid-template-columns:1fr}} diff --git a/web/public/assets/index-CTKpNJEr.js b/web/public/assets/index-CTKpNJEr.js new file mode 100644 index 0000000..8d94eae --- /dev/null +++ b/web/public/assets/index-CTKpNJEr.js @@ -0,0 +1,74 @@ +var e=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports);(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var t=e((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var ee=Array.isArray;function S(){}var C={H:null,A:null,T:null,S:null},te=Object.prototype.hasOwnProperty;function ne(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function re(e,t){return ne(e.type,t,e.props)}function w(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function ie(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var ae=/\/+/g;function oe(e,t){return typeof e==`object`&&e&&e.key!=null?ie(``+e.key):t.toString(36)}function se(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(S,S):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function ce(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,ce(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+oe(e,0):a,ee(o)?(i=``,c!=null&&(i=c.replace(ae,`$&/`)+`/`),ce(o,r,i,``,function(e){return e})):o!=null&&(w(o)&&(o=re(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(ae,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(ee(e))for(var u=0;u{n.exports=t()})),r=e((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,ee||(ee=!0,w());else{var t=n(l);t!==null&&oe(x,t.startTime-e)}}var ee=!1,S=-1,C=5,te=-1;function ne(){return g?!0:!(e.unstable_now()-tet&&ne());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&oe(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?w():ee=!1}}}var w;if(typeof y==`function`)w=function(){y(re)};else if(typeof MessageChannel<`u`){var ie=new MessageChannel,ae=ie.port2;ie.port1.onmessage=re,w=function(){ae.postMessage(null)}}else w=function(){_(re,0)};function oe(t,n){S=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(S),S=-1):h=!0,oe(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,ee||(ee=!0,w()))),r},e.unstable_shouldYield=ne,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),i=e(((e,t)=>{t.exports=r()})),a=e((e=>{var t=n();function r(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=a()})),s=e((e=>{var t=i(),r=n(),a=o();function s(e){var t=`https://react.dev/errors/`+e;if(1pe||(e.current=fe[pe],fe[pe]=null,pe--)}function O(e,t){pe++,fe[pe]=e.current,e.current=t}var he=me(null),ge=me(null),_e=me(null),ve=me(null);function ye(e,t){switch(O(_e,t),O(ge,e),O(he,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Vd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Vd(t),e=Hd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}D(he),O(he,e)}function be(){D(he),D(ge),D(_e)}function xe(e){e.memoizedState!==null&&O(ve,e);var t=he.current,n=Hd(t,e.type);t!==n&&(O(ge,e),O(he,n))}function Se(e){ge.current===e&&(D(he),D(ge)),ve.current===e&&(D(ve),Qf._currentValue=de)}var Ce,we;function Te(e){if(Ce===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);Ce=t&&t[1]||``,we=-1)`:-1i||c[r]!==l[i]){var u=` +`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{Ee=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?Te(n):``}function Oe(e,t){switch(e.tag){case 26:case 27:case 5:return Te(e.type);case 16:return Te(`Lazy`);case 13:return e.child!==t&&t!==null?Te(`Suspense Fallback`):Te(`Suspense`);case 19:return Te(`SuspenseList`);case 0:case 15:return De(e.type,!1);case 11:return De(e.type.render,!1);case 1:return De(e.type,!0);case 31:return Te(`Activity`);default:return``}}function ke(e){try{var t=``,n=null;do t+=Oe(e,n),n=e,e=e.return;while(e);return t}catch(e){return` +Error generating stack: `+e.message+` +`+e.stack}}var Ae=Object.prototype.hasOwnProperty,je=t.unstable_scheduleCallback,Me=t.unstable_cancelCallback,Ne=t.unstable_shouldYield,Pe=t.unstable_requestPaint,Fe=t.unstable_now,Ie=t.unstable_getCurrentPriorityLevel,Le=t.unstable_ImmediatePriority,Re=t.unstable_UserBlockingPriority,ze=t.unstable_NormalPriority,Be=t.unstable_LowPriority,Ve=t.unstable_IdlePriority,He=t.log,Ue=t.unstable_setDisableYieldValue,We=null,Ge=null;function Ke(e){if(typeof He==`function`&&Ue(e),Ge&&typeof Ge.setStrictMode==`function`)try{Ge.setStrictMode(We,e)}catch{}}var qe=Math.clz32?Math.clz32:Xe,Je=Math.log,Ye=Math.LN2;function Xe(e){return e>>>=0,e===0?32:31-(Je(e)/Ye|0)|0}var Ze=256,Qe=262144,$e=4194304;function et(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function tt(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=et(n))):i=et(o):i=et(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=et(n))):i=et(o)):i=et(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function nt(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function rt(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function it(){var e=$e;return $e<<=1,!($e&62914560)&&($e=4194304),e}function at(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function ot(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function st(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),yn=!1;if(vn)try{var bn={};Object.defineProperty(bn,`passive`,{get:function(){yn=!0}}),window.addEventListener(`test`,bn,bn),window.removeEventListener(`test`,bn,bn)}catch{yn=!1}var xn=null,Sn=null,Cn=null;function wn(){if(Cn)return Cn;var e,t=Sn,n=t.length,r,i=`value`in xn?xn.value:xn.textContent,a=i.length;for(e=0;e=nr),ar=` `,or=!1;function sr(e,t){switch(e){case`keyup`:return er.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function cr(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var lr=!1;function ur(e,t){switch(e){case`compositionend`:return cr(t);case`keypress`:return t.which===32?(or=!0,ar):null;case`textInput`:return e=t.data,e===ar&&or?null:e;default:return null}}function dr(e,t){if(lr)return e===`compositionend`||!tr&&sr(e,t)?(e=wn(),Cn=Sn=xn=null,lr=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Nr(n)}}function Fr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Fr(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Ir(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Gt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Gt(e.document)}return t}function Lr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var Rr=vn&&`documentMode`in document&&11>=document.documentMode,zr=null,Br=null,Vr=null,Hr=!1;function Ur(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Hr||zr==null||zr!==Gt(r)||(r=zr,`selectionStart`in r&&Lr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Vr&&Mr(Vr,r)||(Vr=r,r=Ed(Br,`onSelect`),0>=o,i-=o,Fi=1<<32-qe(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),o=a(_,o,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),j&&Li(i,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(i,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(i,h),o=a(y,o,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(i,h),j&&Li(i,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(i,v.value,l),v!==null&&(o=a(v,o,g),d===null?u=v:d.sibling=v,d=v);return j&&Li(i,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,i,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),o=a(v,o,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(i,e)}),j&&Li(i,g),u}function b(e,r,a,c){if(typeof a==`object`&&a&&a.type===y&&a.key===null&&(a=a.props.children),typeof a==`object`&&a){switch(a.$$typeof){case _:a:{for(var l=a.key;r!==null;){if(r.key===l){if(l=a.type,l===y){if(r.tag===7){n(e,r.sibling),c=i(r,a.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===w&&Fa(l)===r.type){n(e,r.sibling),c=i(r,a.props),Ha(c,a),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}a.type===y?(c=Si(a.props.children,e.mode,c,a.key),c.return=e,e=c):(c=xi(a.type,a.key,a.props,null,e.mode,c),Ha(c,a),c.return=e,e=c)}return o(e);case v:a:{for(l=a.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===a.containerInfo&&r.stateNode.implementation===a.implementation){n(e,r.sibling),c=i(r,a.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=Ti(a,e.mode,c),c.return=e,e=c}return o(e);case w:return a=Fa(a),b(e,r,a,c)}if(ue(a))return h(e,r,a,c);if(se(a)){if(l=se(a),typeof l!=`function`)throw Error(s(150));return a=l.call(a),g(e,r,a,c)}if(typeof a.then==`function`)return b(e,r,Va(a),c);if(a.$$typeof===S)return b(e,r,ua(e,a),c);Ua(e,a)}return typeof a==`string`&&a!==``||typeof a==`number`||typeof a==`bigint`?(a=``+a,r!==null&&r.tag===6?(n(e,r.sibling),c=i(r,a),c.return=e,e=c):(n(e,r),c=Ci(a,e.mode,c),c.return=e,e=c),o(e)):n(e,r)}return function(e,t,n,r){try{Ba=0;var i=b(e,t,n,r);return za=null,i}catch(t){if(t===ka||t===ja)throw t;var a=_i(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Ga=Wa(!0),Ka=Wa(!1),qa=!1;function Ja(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Ya(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Xa(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Za(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,W&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=mi(e),pi(e,null,n),t}return ui(e,r,t,n),mi(e)}function Qa(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,lt(e,n)}}function $a(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var eo=!1;function to(){if(eo){var e=ba;if(e!==null)throw e}}function no(e,t,n,r){eo=!1;var i=e.updateQueue;qa=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,p=f!==s.lane;if(p?(q&f)===f:(r&f)===f){f!==0&&f===ya&&(eo=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var m=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(m=g.payload,typeof m==`function`){d=m.call(_,d,f);break a}d=m;break a;case 3:m.flags=m.flags&-65537|128;case 0:if(m=g.payload,f=typeof m==`function`?m.call(_,d,f):m,f==null)break a;d=h({},d,f);break a;case 2:qa=!0}}f=s.callback,f!==null&&(e.flags|=64,p&&(e.flags|=8192),p=i.callbacks,p===null?i.callbacks=[f]:p.push(f))}else p={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;p=s,s=p.next,p.next=null,i.lastBaseUpdate=p,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Kl|=o,e.lanes=o,e.memoizedState=d}}function ro(e,t){if(typeof e!=`function`)throw Error(s(191,e));e.call(t)}function io(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=T.T,s={};T.T=s,zs(e,!1,t,n);try{var c=i(),l=T.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Rs(e,t,Ca(c,r),pu(e)):Rs(e,t,r,pu(e))}catch(n){Rs(e,t,{then:function(){},status:`rejected`,reason:n},pu())}finally{E.p=a,o!==null&&s.types!==null&&(o.types=s.types),T.T=o}}function Os(){}function ks(e,t,n,r){if(e.tag!==5)throw Error(s(476));var i=As(e).queue;Ds(e,i,t,de,n===null?Os:function(){return js(e),n(r)})}function As(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:de,baseState:de,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Bo,lastRenderedState:de},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Bo,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function js(e){var t=As(e);t.next===null&&(t=e.alternate.memoizedState),Rs(e,t.next.queue,{},pu())}function Ms(){return la(Qf)}function Ns(){return R().memoizedState}function Ps(){return R().memoizedState}function Fs(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=pu();e=Xa(n);var r=Za(t,e,n);r!==null&&(hu(r,t,n),Qa(r,t,n)),t={cache:ha()},e.payload=t;return}t=t.return}}function Is(e,t,n){var r=pu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Bs(e)?Vs(t,n):(n=di(e,t,n,r),n!==null&&(hu(n,e,r),Hs(n,t,r)))}function Ls(e,t,n){Rs(e,t,n,pu())}function Rs(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Bs(e))Vs(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,jr(s,o))return ui(e,t,i,0),G===null&&li(),!1}catch{}if(n=di(e,t,i,r),n!==null)return hu(n,e,r),Hs(n,t,r),!0}return!1}function zs(e,t,n,r){if(r={lane:2,revertLane:dd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Bs(e)){if(t)throw Error(s(479))}else t=di(e,n,r,2),t!==null&&hu(t,e,2)}function Bs(e){var t=e.alternate;return e===P||t!==null&&t===P}function Vs(e,t){xo=bo=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Hs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,lt(e,n)}}var Us={readContext:la,use:Ro,useCallback:L,useContext:L,useEffect:L,useImperativeHandle:L,useLayoutEffect:L,useInsertionEffect:L,useMemo:L,useReducer:L,useRef:L,useState:L,useDebugValue:L,useDeferredValue:L,useTransition:L,useSyncExternalStore:L,useId:L,useHostTransitionStatus:L,useFormState:L,useActionState:L,useOptimistic:L,useMemoCache:L,useCacheRefresh:L};Us.useEffectEvent=L;var Ws={readContext:la,use:Ro,useCallback:function(e,t){return Fo().memoizedState=[e,t===void 0?null:t],e},useContext:la,useEffect:ms,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),fs(4194308,4,bs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return fs(4194308,4,e,t)},useInsertionEffect:function(e,t){fs(4,2,e,t)},useMemo:function(e,t){var n=Fo();t=t===void 0?null:t;var r=e();if(So){Ke(!0);try{e()}finally{Ke(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Fo();if(n!==void 0){var i=n(t);if(So){Ke(!0);try{n(t)}finally{Ke(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Is.bind(null,P,e),[r.memoizedState,e]},useRef:function(e){var t=Fo();return e={current:e},t.memoizedState=e},useState:function(e){e=Xo(e);var t=e.queue,n=Ls.bind(null,P,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:Ss,useDeferredValue:function(e,t){return Ts(Fo(),e,t)},useTransition:function(){var e=Xo(!1);return e=Ds.bind(null,P,e.queue,!0,!1),Fo().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=P,i=Fo();if(j){if(n===void 0)throw Error(s(407));n=n()}else{if(n=t(),G===null)throw Error(s(349));q&127||Go(r,t,n)}i.memoizedState=n;var a={value:n,getSnapshot:t};return i.queue=a,ms(qo.bind(null,r,a,e),[e]),r.flags|=2048,us(9,{destroy:void 0},Ko.bind(null,r,a,n,t),null),n},useId:function(){var e=Fo(),t=G.identifierPrefix;if(j){var n=Ii,r=Fi;n=(r&~(1<<32-qe(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=Co++,0<\/script>`,a=a.removeChild(a.firstChild);break;case`select`:a=typeof r.is==`string`?o.createElement(`select`,{is:r.is}):o.createElement(`select`),r.multiple?a.multiple=!0:r.size&&(a.size=r.size);break;default:a=typeof r.is==`string`?o.createElement(i,{is:r.is}):o.createElement(i)}}a[gt]=t,a[_t]=r;a:for(o=t.child;o!==null;){if(o.tag===5||o.tag===6)a.appendChild(o.stateNode);else if(o.tag!==4&&o.tag!==27&&o.child!==null){o.child.return=o,o=o.child;continue}if(o===t)break a;for(;o.sibling===null;){if(o.return===null||o.return===t)break a;o=o.return}o.sibling.return=o.return,o=o.sibling}t.stateNode=a;a:switch(Pd(a,i,r),i){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Lc(t)}}return B(t),Rc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Lc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(s(166));if(e=_e.current,Yi(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,i=Hi,i!==null)switch(i.tag){case 27:case 5:r=i.memoizedProps}e[gt]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||Md(e.nodeValue,n)),e||Ki(t,!0)}else e=Bd(e).createTextNode(r),e[gt]=t,t.stateNode=e}return B(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Yi(t),n!==null){if(e===null){if(!r)throw Error(s(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(s(557));e[gt]=t}else Xi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;B(t),e=!1}else n=Zi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(_o(t),t):(_o(t),null);if(t.flags&128)throw Error(s(558))}return B(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(i=Yi(t),r!==null&&r.dehydrated!==null){if(e===null){if(!i)throw Error(s(318));if(i=t.memoizedState,i=i===null?null:i.dehydrated,!i)throw Error(s(317));i[gt]=t}else Xi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;B(t),i=!1}else i=Zi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=i),i=!0;if(!i)return t.flags&256?(_o(t),t):(_o(t),null)}return _o(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,i=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(i=r.alternate.memoizedState.cachePool.pool),a=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(a=r.memoizedState.cachePool.pool),a!==i&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Bc(t,t.updateQueue),B(t),null);case 4:return be(),e===null&&Sd(t.stateNode.containerInfo),B(t),null;case 10:return ra(t.type),B(t),null;case 19:if(D(N),r=t.memoizedState,r===null)return B(t),null;if(i=(t.flags&128)!=0,a=r.rendering,a===null)if(i)Vc(r,!1);else{if(Y!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(a=vo(e),a!==null){for(t.flags|=128,Vc(r,!1),e=a.updateQueue,t.updateQueue=e,Bc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)bi(n,e),n=n.sibling;return O(N,N.current&1|2),j&&Li(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Fe()>nu&&(t.flags|=128,i=!0,Vc(r,!1),t.lanes=4194304)}else{if(!i)if(e=vo(a),e!==null){if(t.flags|=128,i=!0,e=e.updateQueue,t.updateQueue=e,Bc(t,e),Vc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!a.alternate&&!j)return B(t),null}else 2*Fe()-r.renderingStartTime>nu&&n!==536870912&&(t.flags|=128,i=!0,Vc(r,!1),t.lanes=4194304);r.isBackwards?(a.sibling=t.child,t.child=a):(e=r.last,e===null?t.child=a:e.sibling=a,r.last=a)}return r.tail===null?(B(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Fe(),e.sibling=null,n=N.current,O(N,i?n&1|2:n&1),j&&Li(t,r.treeForkCount),e);case 22:case 23:return _o(t),lo(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(B(t),t.subtreeFlags&6&&(t.flags|=8192)):B(t),n=t.updateQueue,n!==null&&Bc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&D(Ta),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),ra(M),B(t),null;case 25:return null;case 30:return null}throw Error(s(156,t.tag))}function Uc(e,t){switch(Bi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return ra(M),be(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return Se(t),null;case 31:if(t.memoizedState!==null){if(_o(t),t.alternate===null)throw Error(s(340));Xi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(_o(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(s(340));Xi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return D(N),null;case 4:return be(),null;case 10:return ra(t.type),null;case 22:case 23:return _o(t),lo(),e!==null&&D(Ta),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return ra(M),null;case 25:return null;default:return null}}function Wc(e,t){switch(Bi(t),t.tag){case 3:ra(M),be();break;case 26:case 27:case 5:Se(t);break;case 4:be();break;case 31:t.memoizedState!==null&&_o(t);break;case 13:_o(t);break;case 19:D(N);break;case 10:ra(t.type);break;case 22:case 23:_o(t),lo(),e!==null&&D(Ta);break;case 24:ra(M)}}function Gc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Z(t,t.return,e)}}function Kc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Z(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Z(t,t.return,e)}}function qc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{io(t,n)}catch(t){Z(e,e.return,t)}}}function Jc(e,t,n){n.props=Zs(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Z(e,t,n)}}function Yc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Z(e,t,n)}}function Xc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){Z(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Z(e,t,n)}else n.current=null}function Zc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Z(e,e.return,t)}}function Qc(e,t,n){try{var r=e.stateNode;Fd(r,e.type,n,t),r[_t]=t}catch(t){Z(e,e.return,t)}}function $c(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zd(e.type)||e.tag===4}function el(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||$c(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Zd(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function tl(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=ln));else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(tl(e,t,n),e=e.sibling;e!==null;)tl(e,t,n),e=e.sibling}function nl(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode),e=e.child,e!==null))for(nl(e,t,n),e=e.sibling;e!==null;)nl(e,t,n),e=e.sibling}function rl(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Pd(t,r,n),t[gt]=e,t[_t]=n}catch(t){Z(e,e.return,t)}}var il=!1,V=!1,al=!1,ol=typeof WeakSet==`function`?WeakSet:Set,H=null;function sl(e,t){if(e=e.containerInfo,Rd=sp,e=Ir(e),Lr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var i=r.anchorOffset,a=r.focusNode;r=r.focusOffset;try{n.nodeType,a.nodeType}catch{n=null;break a}var o=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||i!==0&&f.nodeType!==3||(c=o+i),f!==a||r!==0&&f.nodeType!==3||(l=o+r),f.nodeType===3&&(o+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===i&&(c=o),p===a&&++d===r&&(l=o),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(zd={focusedElem:e,selectionRange:n},sp=!1,H=t;H!==null;)if(t=H,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,H=e;else for(;H!==null;){switch(t=H,a=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Pd(a,r,n),a[gt]=e,k(a),r=a;break a;case`link`:var o=Vf(`link`,`href`,i).get(r+(n.href||``));if(o){for(var c=0;cg&&(o=g,g=h,h=o);var _=Pr(s,h),v=Pr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,T.T=null,n=lu,lu=null;var a=au,o=su;if(X=0,ou=au=null,su=0,W&6)throw Error(s(331));var c=W;if(W|=4,Il(a.current),Ol(a,a.current,o,n),W=c,id(0,!1),Ge&&typeof Ge.onPostCommitFiberRoot==`function`)try{Ge.onPostCommitFiberRoot(We,a)}catch{}return!0}finally{E.p=i,T.T=r,Vu(e,t)}}function Wu(e,t,n){t=Di(n,t),t=rc(e.stateNode,t,2),e=Za(e,t,2),e!==null&&(ot(e,2),rd(e))}function Z(e,t,n){if(e.tag===3)Wu(e,e,n);else for(;t!==null;){if(t.tag===3){Wu(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(iu===null||!iu.has(r))){e=Di(n,e),n=ic(2),r=Za(t,n,2),r!==null&&(ac(n,r,t,e),ot(r,2),rd(r));break}}t=t.return}}function Gu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Bl;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Wl=!0,i.add(n),e=Ku.bind(null,e,t,n),t.then(e,e))}function Ku(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,G===e&&(q&n)===n&&(Y===4||Y===3&&(q&62914560)===q&&300>Fe()-eu?!(W&2)&&Su(e,0):Jl|=n,Xl===q&&(Xl=0)),rd(e)}function qu(e,t){t===0&&(t=it()),e=fi(e,t),e!==null&&(ot(e,t),rd(e))}function Ju(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),qu(e,n)}function Yu(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,i=e.memoizedState;i!==null&&(n=i.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(s(314))}r!==null&&r.delete(t),qu(e,n)}function Xu(e,t){return je(e,t)}var Zu=null,Qu=null,$u=!1,ed=!1,td=!1,nd=0;function rd(e){e!==Qu&&e.next===null&&(Qu===null?Zu=Qu=e:Qu=Qu.next=e),ed=!0,$u||($u=!0,ud())}function id(e,t){if(!td&&ed){td=!0;do for(var n=!1,r=Zu;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-qe(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,ld(r,a))}else a=q,a=tt(r,r===G?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||nt(r,a)||(n=!0,ld(r,a));r=r.next}while(n);td=!1}}function ad(){od()}function od(){ed=$u=!1;var e=0;nd!==0&&Gd()&&(e=nd);for(var t=Fe(),n=null,r=Zu;r!==null;){var i=r.next,a=sd(r,t);a===0?(r.next=null,n===null?Zu=i:n.next=i,i===null&&(Qu=n)):(n=r,(e!==0||a&3)&&(ed=!0)),r=i}X!==0&&X!==5||id(e,!1),nd!==0&&(nd=0)}function sd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=qt(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),k(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+qt(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+qt(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+qt(n.imageSizes)+`"]`)):i+=`[href="`+qt(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=h({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),k(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+qt(r)+`"][href="`+qt(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=h({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),k(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=Ot(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=h({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);k(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=Ot(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),k(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=Ot(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),k(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var i=(i=_e.current)?gf(i):null;if(!i)throw Error(s(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=Ot(i).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var a=Ot(i).hoistableStyles,o=a.get(e);if(o||(i=i.ownerDocument||i,o={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},a.set(e,o),(a=i.querySelector(jf(e)))&&!a._p&&(o.instance=a,o.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),a||Nf(i,e,n,o.state))),t&&r===null)throw Error(s(528,``));return o}if(t&&r!==null)throw Error(s(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=Ot(i).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(s(444,e))}}function Af(e){return`href="`+qt(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return h({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),k(t),e.head.appendChild(t))}function Pf(e){return`[src="`+qt(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+qt(n.href)+`"]`);if(r)return t.instance=r,k(r),r;var i=h({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),k(r),Pd(r,`style`,i),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:i=Af(n.href);var a=e.querySelector(jf(i));if(a)return t.state.loading|=4,t.instance=a,k(a),a;r=Mf(n),(i=mf.get(i))&&Rf(r,i),a=(e.ownerDocument||e).createElement(`link`),k(a);var o=a;return o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),t.state.loading|=4,Lf(a,n.precedence,e),t.instance=a;case`script`:return a=Pf(n.src),(i=e.querySelector(Ff(a)))?(t.instance=i,k(i),i):(r=n,(i=mf.get(a))&&(r=h({},n),zf(r,i)),e=e.ownerDocument||e,i=e.createElement(`script`),k(i),Pd(i,`link`,r),e.head.appendChild(i),t.instance=i);case`void`:return null;default:throw Error(s(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,k(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),k(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=s()})),l=n(),u=c();(!globalThis.EventTarget||!globalThis.Event)&&console.error(` + PartySocket requires a global 'EventTarget' class to be available! + You can polyfill this global by adding this to your code before any partysocket imports: + + \`\`\` + import 'partysocket/event-target-polyfill'; + \`\`\` + Please file an issue at https://github.com/partykit/partykit if you're still having trouble. +`);var d=class extends Event{message;error;constructor(e,t){super(`error`,t),this.message=e.message,this.error=e}},f=class extends Event{code;reason;wasClean=!0;constructor(e=1e3,t=``,n){super(`close`,n),this.code=e,this.reason=t}},p={Event,ErrorEvent:d,CloseEvent:f};function m(e,t){if(!e)throw Error(t)}function h(e){return new e.constructor(e.type,e)}function g(e){return`data`in e?new MessageEvent(e.type,e):`code`in e||`reason`in e?new f(e.code||1999,e.reason||`unknown reason`,e):`error`in e?new d(e.error,e):new Event(e.type,e)}var _=typeof process<`u`&&process.versions?.node!==void 0,v=typeof navigator<`u`&&navigator.product===`ReactNative`,y=_||v?g:h,b={maxReconnectionDelay:1e4,minReconnectionDelay:3e3,minUptime:5e3,reconnectionDelayGrowFactor:1.3,connectionTimeout:4e3,maxRetries:1/0,maxEnqueuedMessages:1/0,startClosed:!1,debug:!1},x=!1,ee=class e extends EventTarget{_ws;_retryCount=-1;_uptimeTimeout;_connectTimeout;_shouldReconnect=!0;_connectLock=!1;_binaryType=`blob`;_closeCalled=!1;_messageQueue=[];_debugLogger=console.log.bind(console);_url;_protocols;_options;constructor(e,t,n={}){super(),this._url=e,this._protocols=t,this._options=n,this._options.startClosed&&(this._shouldReconnect=!1),this._options.debugLogger&&(this._debugLogger=this._options.debugLogger),this._connect()}static get CONNECTING(){return 0}static get OPEN(){return 1}static get CLOSING(){return 2}static get CLOSED(){return 3}get CONNECTING(){return e.CONNECTING}get OPEN(){return e.OPEN}get CLOSING(){return e.CLOSING}get CLOSED(){return e.CLOSED}get binaryType(){return this._ws?this._ws.binaryType:this._binaryType}set binaryType(e){this._binaryType=e,this._ws&&(this._ws.binaryType=e)}get retryCount(){return Math.max(this._retryCount,0)}get bufferedAmount(){return this._messageQueue.reduce((e,t)=>(typeof t==`string`?e+=t.length:t instanceof Blob?e+=t.size:e+=t.byteLength,e),0)+(this._ws?this._ws.bufferedAmount:0)}get extensions(){return this._ws?this._ws.extensions:``}get protocol(){return this._ws?this._ws.protocol:``}get readyState(){return this._ws?this._ws.readyState:this._options.startClosed?e.CLOSED:e.CONNECTING}get url(){return this._ws?this._ws.url:``}get shouldReconnect(){return this._shouldReconnect}onclose=null;onerror=null;onmessage=null;onopen=null;close(e=1e3,t){if(this._closeCalled=!0,this._shouldReconnect=!1,this._clearTimeouts(),!this._ws){this._debug(`close enqueued: no ws instance`);return}if(this._ws.readyState===this.CLOSED){this._debug(`close: already closed`);return}this._ws.close(e,t)}reconnect(e,t){this._shouldReconnect=!0,this._closeCalled=!1,this._retryCount=-1,!this._ws||this._ws.readyState===this.CLOSED||this._disconnect(e,t),this._connect()}send(e){if(this._ws&&this._ws.readyState===this.OPEN)this._debug(`send`,e),this._ws.send(e);else{let{maxEnqueuedMessages:t=b.maxEnqueuedMessages}=this._options;this._messageQueue.length`,...e)}_getNextDelay(){let{reconnectionDelayGrowFactor:e=b.reconnectionDelayGrowFactor,minReconnectionDelay:t=b.minReconnectionDelay,maxReconnectionDelay:n=b.maxReconnectionDelay}=this._options,r=0;return this._retryCount>0&&(r=t*e**(this._retryCount-1),r>n&&(r=n)),this._debug(`next delay`,r),r}_wait(){return new Promise(e=>{setTimeout(e,this._getNextDelay())})}_getNextProtocols(e){if(!e)return Promise.resolve(null);if(typeof e==`string`||Array.isArray(e))return Promise.resolve(e);if(typeof e==`function`){let t=e();if(!t)return Promise.resolve(null);if(typeof t==`string`||Array.isArray(t))return Promise.resolve(t);if(t.then)return t}throw Error(`Invalid protocols`)}_getNextUrl(e){if(typeof e==`string`)return Promise.resolve(e);if(typeof e==`function`){let t=e();if(typeof t==`string`)return Promise.resolve(t);if(t.then)return t}throw Error(`Invalid URL`)}_connect(){if(this._connectLock||!this._shouldReconnect)return;this._connectLock=!0;let{maxRetries:e=b.maxRetries,connectionTimeout:t=b.connectionTimeout}=this._options;if(this._retryCount>=e){this._debug(`max retries reached`,this._retryCount,`>=`,e),this._connectLock=!1;return}this._retryCount++,this._debug(`connect`,this._retryCount),this._removeListeners(),this._wait().then(()=>Promise.all([this._getNextUrl(this._url),this._getNextProtocols(this._protocols||null)])).then(([e,n])=>{if(this._closeCalled){this._connectLock=!1;return}!this._options.WebSocket&&typeof WebSocket>`u`&&!x&&(console.error(`‼️ No WebSocket implementation available. You should define options.WebSocket. + +For example, if you're using node.js, run \`npm install ws\`, and then in your code: + +import PartySocket from 'partysocket'; +import WS from 'ws'; + +const partysocket = new PartySocket({ + host: "127.0.0.1:1999", + room: "test-room", + WebSocket: WS +}); + +`),x=!0);let r=this._options.WebSocket||WebSocket;this._debug(`connect`,{url:e,protocols:n}),this._ws=n?new r(e,n):new r(e),this._ws.binaryType=this._binaryType,this._connectLock=!1,this._addListeners(),this._connectTimeout=setTimeout(()=>this._handleTimeout(),t)}).catch(e=>{this._connectLock=!1,this._handleError(new p.ErrorEvent(Error(e.message),this))})}_handleTimeout(){this._debug(`timeout event`),this._handleError(new p.ErrorEvent(Error(`TIMEOUT`),this))}_disconnect(e=1e3,t){if(this._clearTimeouts(),this._ws){this._removeListeners();try{(this._ws.readyState===this.OPEN||this._ws.readyState===this.CONNECTING)&&this._ws.close(e,t),this._handleClose(new p.CloseEvent(e,t,this))}catch{}}}_acceptOpen(){this._debug(`accept open`),this._retryCount=0}_handleOpen=e=>{this._debug(`open event`);let{minUptime:t=b.minUptime}=this._options;clearTimeout(this._connectTimeout),this._uptimeTimeout=setTimeout(()=>this._acceptOpen(),t),m(this._ws,`WebSocket is not defined`),this._ws.binaryType=this._binaryType,this._messageQueue.forEach(e=>{this._ws?.send(e)}),this._messageQueue=[],this.onopen&&this.onopen(e),this.dispatchEvent(y(e))};_handleMessage=e=>{this._debug(`message event`),this.onmessage&&this.onmessage(e),this.dispatchEvent(y(e))};_handleError=e=>{this._debug(`error event`,e.message),this._disconnect(void 0,e.message===`TIMEOUT`?`timeout`:void 0),this.onerror&&this.onerror(e),this._debug(`exec error listeners`),this.dispatchEvent(y(e)),this._connect()};_handleClose=e=>{this._debug(`close event`),this._clearTimeouts(),this._shouldReconnect&&this._connect(),this.onclose&&this.onclose(e),this.dispatchEvent(y(e))};_removeListeners(){this._ws&&(this._debug(`removeListeners`),this._ws.removeEventListener(`open`,this._handleOpen),this._ws.removeEventListener(`close`,this._handleClose),this._ws.removeEventListener(`message`,this._handleMessage),this._ws.removeEventListener(`error`,this._handleError))}_addListeners(){this._ws&&(this._debug(`addListeners`),this._ws.addEventListener(`open`,this._handleOpen),this._ws.addEventListener(`close`,this._handleClose),this._ws.addEventListener(`message`,this._handleMessage),this._ws.addEventListener(`error`,this._handleError))}_clearTimeouts(){clearTimeout(this._connectTimeout),clearTimeout(this._uptimeTimeout)}},S=e=>e[1]!==null&&e[1]!==void 0;function C(){if(crypto?.randomUUID)return crypto.randomUUID();let e=Date.now(),t=performance?.now&&performance.now()*1e3||0;return`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,function(n){let r=Math.random()*16;return e>0?(r=(e+r)%16|0,e=Math.floor(e/16)):(r=(t+r)%16|0,t=Math.floor(t/16)),(n===`x`?r:r&3|8).toString(16)})}function te(e,t,n={}){let{host:r,path:i,protocol:a,room:o,party:s,basePath:c,prefix:l,query:u}=e,d=r.replace(/^(http|https|ws|wss):\/\//,``);if(d.endsWith(`/`)&&(d=d.slice(0,-1)),i?.startsWith(`/`))throw Error(`path must not start with a slash`);let f=s??`main`,p=i?`/${i}`:``,m=a||(d.startsWith(`localhost:`)||d.startsWith(`127.0.0.1:`)||d.startsWith(`192.168.`)||d.startsWith(`10.`)||d.startsWith(`172.`)&&d.split(`.`)[1]>=`16`&&d.split(`.`)[1]<=`31`||d.startsWith(`[::ffff:7f00:1]:`)?t:`${t}s`),h=`${m}://${d}/${c||`${l||`parties`}/${f}/${o}`}${p}`,g=(e={})=>`${h}?${new URLSearchParams([...Object.entries(n),...Object.entries(e).filter(S)])}`,_=typeof u==`function`?async()=>g(await u()):g(u);return{host:d,path:p,room:o,name:f,protocol:m,partyUrl:h,urlProvider:_}}var ne=class extends ee{_pk;_pkurl;name;room;host;path;basePath;constructor(e){let t=re(e);if(super(t.urlProvider,t.protocols,t.socketOptions),this.partySocketOptions=e,this.setWSProperties(t),!e.startClosed&&!this.room&&!this.basePath)throw this.close(),Error(`Either room or basePath must be provided to connect. Use startClosed: true to create a socket and set them via updateProperties before calling reconnect().`);e.disableNameValidation||(e.party?.includes(`/`)&&console.warn(`PartySocket: party name "${e.party}" contains forward slash which may cause routing issues. Consider using a name without forward slashes or set disableNameValidation: true to bypass this warning.`),e.room?.includes(`/`)&&console.warn(`PartySocket: room name "${e.room}" contains forward slash which may cause routing issues. Consider using a name without forward slashes or set disableNameValidation: true to bypass this warning.`))}updateProperties(e){let t=re({...this.partySocketOptions,...e,host:e.host??this.host,room:e.room??this.room,path:e.path??this.path,basePath:e.basePath??this.basePath});this._url=t.urlProvider,this._protocols=t.protocols,this._options=t.socketOptions,this.setWSProperties(t)}setWSProperties(e){let{_pk:t,_pkurl:n,name:r,room:i,host:a,path:o,basePath:s}=e;this._pk=t,this._pkurl=n,this.name=r,this.room=i,this.host=a,this.path=o,this.basePath=s}reconnect(e,t){if(!this.host)throw Error("The host must be set before connecting, use `updateProperties` method to set it or pass it to the constructor.");if(!this.room&&!this.basePath)throw Error("The room (or basePath) must be set before connecting, use `updateProperties` method to set it or pass it to the constructor.");super.reconnect(e,t)}get id(){return this._pk}get roomUrl(){return this._pkurl}static async fetch(e,t){let n=te(e,`http`),r=typeof n.urlProvider==`string`?n.urlProvider:await n.urlProvider();return(e.fetch??fetch)(r,t)}};function re(e){let{id:t,host:n,path:r,party:i,room:a,protocol:o,query:s,protocols:c,...l}=e,u=t||C(),d=te(e,`ws`,{_pk:u});return{_pk:u,_pkurl:d.partyUrl,name:d.name,room:d.room,host:d.host,path:d.path,basePath:e.basePath,protocols:c,socketOptions:l,urlProvider:d.urlProvider}}function w(e){if(e===e.toUpperCase()&&e!==e.toLowerCase())return e.toLowerCase().replace(/_/g,`-`);let t=e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`);return t=t.startsWith(`-`)?t.slice(1):t,t.replace(/_/g,`-`).replace(/-$/,``)}var ie=` +class AudioCaptureProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.buffer = []; + this.sampleRate = sampleRate; + this.targetRate = 16000; + this.ratio = this.sampleRate / this.targetRate; + } + + process(inputs) { + const input = inputs[0]; + if (!input || !input[0]) return true; + + const channelData = input[0]; + + // Linear interpolation resampling (e.g. 48kHz → 16kHz). + // Nearest-neighbor (picking every Nth sample) introduces aliasing + // artifacts, especially on sibilants (s, f, th). Linear interpolation + // blends adjacent samples, acting as a basic low-pass filter. + for (let i = 0; i < channelData.length; i += this.ratio) { + const idx = Math.floor(i); + const frac = i - idx; + if (idx + 1 < channelData.length) { + this.buffer.push(channelData[idx] * (1 - frac) + channelData[idx + 1] * frac); + } else if (idx < channelData.length) { + this.buffer.push(channelData[idx]); + } + } + + if (this.buffer.length >= 1600) { + const chunk = new Float32Array(this.buffer); + this.port.postMessage({ type: 'audio', samples: chunk }, [chunk.buffer]); + this.buffer = []; + } + + return true; + } +} + +registerProcessor('audio-capture-processor', AudioCaptureProcessor); +`;function ae(e){let t=new ArrayBuffer(e.length*2),n=new DataView(t);for(let t=0;tthis.onopen?.(),e.onclose=()=>this.onclose?.(),e.onerror=()=>this.onerror?.(),e.onmessage=e=>{this.onmessage?.(e.data)},this.#e=e}disconnect(){this.#e?.close(),this.#e=null}},ce=class{#e=`idle`;#t=[];#n=null;#r=0;#i=!1;#a=!1;#o=null;#s=null;#c=null;#l=null;#u=null;#d=!1;#f;#p;#m;#h;#g;#_=null;#v;#y=null;#b=!1;#x=null;#S=null;#C=null;#w=!1;#T=[];#E=!1;#D=null;#O=0;#k=new Map;constructor(e){this.#v=e,this.#f=e.silenceThreshold??.04,this.#p=e.silenceDurationMs??500,this.#m=e.interruptThreshold??.05,this.#h=e.interruptChunks??2,this.#g=e.maxTranscriptMessages??200}get status(){return this.#e}get transcript(){return this.#t}get metrics(){return this.#n}get audioLevel(){return this.#r}get isMuted(){return this.#i}get connected(){return this.#a}get error(){return this.#o}get interimTranscript(){return this.#l}get serverProtocolVersion(){return this.#u}addEventListener(e,t){let n=this.#k.get(e);n||(n=new Set,this.#k.set(e,n)),n.add(t)}removeEventListener(e,t){this.#k.get(e)?.delete(t)}#A(e,t){let n=this.#k.get(e);if(n)for(let e of n)e(t)}#j(){this.#t.length>this.#g&&(this.#t=this.#t.slice(-this.#g))}connect(){if(this.#_)return;let e=this.#v.transport??new se({agent:this.#v.agent,name:this.#v.name,host:this.#v.host,query:this.#v.query});e.onopen=()=>{this.#a=!0,this.#o=null,e.sendJSON({type:`hello`,protocol_version:1}),this.#A(`connectionchange`,!0),this.#A(`error`,null),this.#d&&e.sendJSON({type:`start_call`})},e.onclose=()=>{this.#a=!1,this.#A(`connectionchange`,!1)},e.onerror=()=>{this.#o=`Connection lost. Reconnecting...`,this.#A(`error`,this.#o)},e.onmessage=e=>{typeof e==`string`?this.#M(e):e instanceof Blob?e.arrayBuffer().then(e=>{this.#T.push(e),this.#I()}):e instanceof ArrayBuffer&&(this.#T.push(e),this.#I())},this.#_=e,e.connect()}disconnect(){this.endCall(),this.#_?.disconnect(),this.#_=null,this.#a=!1,this.#A(`connectionchange`,!1)}async startCall(){if(!this.#_?.connected){this.#o=`Cannot start call: not connected. Call connect() first.`,this.#A(`error`,this.#o);return}this.#d=!0,this.#o=null,this.#n=null,this.#A(`error`,null),this.#A(`metricschange`,null);let e={type:`start_call`};this.#v.preferredFormat&&(e.preferred_format=this.#v.preferredFormat),this.#_.sendJSON(e),this.#v.audioInput?(this.#v.audioInput.onAudioLevel=e=>this.#z(e),this.#v.audioInput.onAudioData=e=>{this.#_?.connected&&!this.#i&&this.#_.sendBinary(e)},await this.#v.audioInput.start()):await this.#L()}endCall(){this.#d=!1,this.#_?.connected&&this.#_.sendJSON({type:`end_call`}),this.#v.audioInput?(this.#v.audioInput.stop(),this.#v.audioInput.onAudioLevel=null,this.#v.audioInput.onAudioData=null):this.#R(),this.#D?.stop(),this.#D=null,this.#T=[],this.#E=!1,this.#P(),this.#B(),this.#e=`idle`,this.#A(`statuschange`,`idle`)}toggleMute(){this.#i=!this.#i,this.#i&&(this.#r=0,this.#A(`audiolevelchange`,0)),this.#i&&this.#w&&(this.#w=!1,this.#C&&=(clearTimeout(this.#C),null),this.#_?.connected&&this.#_.sendJSON({type:`end_of_speech`})),this.#A(`mutechange`,this.#i)}sendText(e){this.#_?.connected&&this.#_.sendJSON({type:`text_message`,text:e})}sendJSON(e){this.#_?.connected&&this.#_.sendJSON(e)}get lastCustomMessage(){return this.#s}get audioFormat(){return this.#c}#M(e){let t;try{t=JSON.parse(e)}catch{return}switch(t.type){case`welcome`:this.#u=t.protocol_version,t.protocol_version!==1&&console.warn(`[VoiceClient] Protocol version mismatch: client=1, server=${t.protocol_version}`);break;case`audio_config`:this.#c=t.format;break;case`status`:this.#e=t.status,(t.status===`listening`||t.status===`idle`)&&(this.#o=null,this.#A(`error`,null)),this.#A(`statuschange`,this.#e);break;case`transcript_interim`:this.#l=t.text,this.#A(`interimtranscript`,this.#l);break;case`transcript`:this.#l=null,this.#A(`interimtranscript`,null),t.role===`user`&&this.#E&&(this.#D?.stop(),this.#D=null,this.#T=[],this.#E=!1),this.#t=[...this.#t,{role:t.role,text:t.text,timestamp:Date.now()}],this.#j(),this.#A(`transcriptchange`,this.#t);break;case`transcript_start`:this.#t=[...this.#t,{role:`assistant`,text:``,timestamp:Date.now()}],this.#j(),this.#A(`transcriptchange`,this.#t);break;case`transcript_delta`:{if(this.#t.length===0)break;let e=[...this.#t],n=e[e.length-1];n.role===`assistant`&&(e[e.length-1]={...n,text:n.text+t.text},this.#t=e,this.#A(`transcriptchange`,this.#t));break}case`transcript_end`:{if(this.#t.length===0)break;let e=[...this.#t],n=e[e.length-1];n.role===`assistant`&&(e[e.length-1]={...n,text:t.text},this.#t=e,this.#A(`transcriptchange`,this.#t));break}case`metrics`:this.#n={llm_ms:t.llm_ms,tts_ms:t.tts_ms,first_audio_ms:t.first_audio_ms,total_ms:t.total_ms},this.#A(`metricschange`,this.#n);break;case`error`:this.#o=t.message,this.#A(`error`,this.#o);break;default:this.#s=t,this.#A(`custommessage`,t);break}}async#N(){return this.#y||=new AudioContext({sampleRate:48e3}),this.#y.state===`suspended`&&await this.#y.resume(),this.#y}#P(){this.#y&&(this.#y.close().catch(()=>{}),this.#y=null,this.#b=!1)}async#F(e){try{let t=await this.#N(),n;if(this.#c===`pcm16`){let r=new Int16Array(e);n=t.createBuffer(1,r.length,16e3);let i=n.getChannelData(0);for(let e=0;e{r.onended=()=>{this.#D===r&&(this.#D=null),e()},r.start()})}catch(e){console.error(`[VoiceClient] Audio playback error:`,e)}}async#I(){if(!(this.#E||this.#T.length===0)){for(this.#E=!0;this.#T.length>0;){let e=this.#T.shift();await this.#F(e)}this.#E=!1}}async#L(){try{let e=await navigator.mediaDevices.getUserMedia({audio:{sampleRate:{ideal:48e3},channelCount:1,echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}});this.#S=e;let t=await this.#N();if(!this.#b){let e=new Blob([ie],{type:`application/javascript`}),n=URL.createObjectURL(e);await t.audioWorklet.addModule(n),URL.revokeObjectURL(n),this.#b=!0}let n=t.createMediaStreamSource(e),r=new AudioWorkletNode(t,`audio-capture-processor`);this.#x=r,r.port.onmessage=e=>{if(e.data.type===`audio`&&!this.#i){let t=e.data.samples,n=oe(t),r=ae(t);this.#_?.connected&&this.#_.sendBinary(r),this.#z(n)}},n.connect(r),r.connect(t.destination)}catch(e){console.error(`[VoiceClient] Mic error:`,e),this.#o=`Microphone access denied. Please allow microphone access and try again.`,this.#A(`error`,this.#o)}}#R(){this.#x?.disconnect(),this.#x=null,this.#S?.getTracks().forEach(e=>e.stop()),this.#S=null,this.#B()}#z(e){this.#i||(this.#r=e,this.#A(`audiolevelchange`,e),this.#E&&e>this.#m?(this.#O++,this.#O>=this.#h&&(this.#D?.stop(),this.#D=null,this.#T=[],this.#E=!1,this.#O=0,this.#_?.connected&&this.#_.sendJSON({type:`interrupt`}))):this.#O=0,e>this.#f?(this.#w||(this.#w=!0,this.#_?.connected&&this.#_.sendJSON({type:`start_of_speech`})),this.#C&&=(clearTimeout(this.#C),null)):this.#w&&(this.#C||=setTimeout(()=>{this.#w=!1,this.#C=null,this.#_?.connected&&this.#_.sendJSON({type:`end_of_speech`})},this.#p)))}#B(){this.#C&&=(clearTimeout(this.#C),null),this.#w=!1,this.#O=0,this.#r=0,this.#A(`audiolevelchange`,0)}};function le(e){let t=(0,l.useMemo)(()=>e.query?JSON.stringify(e.query):``,[e.query]),n=(0,l.useMemo)(()=>`${e.agent}:${e.name??`default`}:${e.host??``}:${e.silenceThreshold??``}:${e.silenceDurationMs??``}:${e.interruptThreshold??``}:${e.interruptChunks??``}:${t}`,[e.agent,e.name,e.host,e.silenceThreshold,e.silenceDurationMs,e.interruptThreshold,e.interruptChunks,t]),r=(0,l.useRef)(null),i=(0,l.useRef)(n),a=(0,l.useRef)(e.onReconnect);a.current=e.onReconnect;let[o,s]=(0,l.useState)(`idle`),[c,u]=(0,l.useState)([]),[d,f]=(0,l.useState)(null),[p,m]=(0,l.useState)(0),[h,g]=(0,l.useState)(!1),[_,v]=(0,l.useState)(!1),[y,b]=(0,l.useState)(null),[x,ee]=(0,l.useState)(null);(0,l.useEffect)(()=>{let t=i.current!==n;i.current=n,t&&a.current?.(),s(`idle`),u([]),f(null),m(0),g(!1),v(!1),b(null),ee(null);let o=new ce(e);r.current=o,o.connect();let c=e=>s(e),l=e=>u(e),d=e=>f(e),p=e=>m(e),h=e=>g(e),_=e=>v(e),y=e=>b(e),x=e=>ee(e);return o.addEventListener(`statuschange`,c),o.addEventListener(`transcriptchange`,l),o.addEventListener(`interimtranscript`,x),o.addEventListener(`metricschange`,d),o.addEventListener(`audiolevelchange`,p),o.addEventListener(`mutechange`,h),o.addEventListener(`connectionchange`,_),o.addEventListener(`error`,y),()=>{o.removeEventListener(`statuschange`,c),o.removeEventListener(`transcriptchange`,l),o.removeEventListener(`interimtranscript`,x),o.removeEventListener(`metricschange`,d),o.removeEventListener(`audiolevelchange`,p),o.removeEventListener(`mutechange`,h),o.removeEventListener(`connectionchange`,_),o.removeEventListener(`error`,y),o.disconnect()}},[n]);let S=(0,l.useCallback)(()=>r.current.startCall(),[]),C=(0,l.useCallback)(()=>r.current.endCall(),[]),te=(0,l.useCallback)(()=>r.current.toggleMute(),[]),ne=(0,l.useCallback)(e=>r.current.sendText(e),[]),re=(0,l.useCallback)(e=>r.current.sendJSON(e),[]),[w,ie]=(0,l.useState)(null);return(0,l.useEffect)(()=>{let e=r.current;if(!e)return;let t=e=>ie(e);return e.addEventListener(`custommessage`,t),()=>e.removeEventListener(`custommessage`,t)},[n]),{status:o,transcript:c,interimTranscript:x,metrics:d,audioLevel:p,isMuted:h,connected:_,error:y,startCall:S,endCall:C,toggleMute:te,sendText:ne,sendJSON:re,lastCustomMessage:w}}var ue=e((e=>{var t=Symbol.for(`react.transitional.element`);function n(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.jsx=n,e.jsxs=n})),T=e(((e,t)=>{t.exports=ue()}))(),E=`aegis_token`;function de(){let[e,t]=(0,l.useState)(()=>localStorage.getItem(E)??``),[n,r]=(0,l.useState)(e),[i,a]=(0,l.useState)([]),[o,s]=(0,l.useState)(null),[c,u]=(0,l.useState)([]),[d,f]=(0,l.useState)(``),[p,m]=(0,l.useState)(`Ready`),[h,g]=(0,l.useState)(null),[_,v]=(0,l.useState)(``),y=(0,l.useRef)(null),b=le({agent:`AegisVoiceAdapter`,name:`operator`,query:e?{token:e}:void 0}),x=(0,l.useMemo)(()=>{let t={};return e&&(t.Authorization=`Bearer ${e}`),t},[e]);(0,l.useEffect)(()=>{document.cookie=e?`aegis_token=${encodeURIComponent(e)};path=/;max-age=31536000;SameSite=Strict;Secure`:`aegis_token=;path=/;max-age=0;SameSite=Strict;Secure`},[e]),(0,l.useEffect)(()=>{ee(),e&&S()},[e]),(0,l.useEffect)(()=>{y.current?.scrollTo({top:y.current.scrollHeight})},[c]);async function ee(){let e=await fetch(`/health?format=json`,{headers:{Accept:`application/json`}});e.ok&&g(await e.json())}async function S(){let e=await fetch(`/api/conversations`,{headers:x});if(!e.ok){m(e.status===401?`Add your AEGIS token`:`Conversations failed: ${e.status}`);return}a((await e.json()).conversations)}async function C(e){s(e);let t=await fetch(`/api/conversations/${encodeURIComponent(e)}/messages`,{headers:x});if(!t.ok){m(`History failed: ${t.status}`);return}u((await t.json()).messages)}function te(){let e=n.trim();localStorage.setItem(E,e),t(e),m(e?`Token saved`:`Token cleared`)}async function ne(t=d.trim()){if(!t)return;if(!e){m(`Add your AEGIS token`);return}let n={id:crypto.randomUUID(),role:`user`,content:t},r=crypto.randomUUID();u(e=>[...e,n,{id:r,role:`assistant`,content:``}]),f(``),m(`Streaming`);let i=await fetch(`/api/message/stream`,{method:`POST`,headers:{...x,"Content-Type":`application/json`},body:JSON.stringify({text:t,conversationId:o,executor:`workers_ai`})});if(!i.ok||!i.body){m(`Message failed: ${i.status}`);return}let a=``;for await(let e of fe(i.body))e.type===`start`&&typeof e.conversationId==`string`&&s(e.conversationId),e.type===`delta`&&typeof e.text==`string`&&(a+=e.text,u(e=>e.map(e=>e.id===r?{...e,content:a}:e))),e.type===`error`&&m(typeof e.error==`string`?e.error:`Stream error`),e.type===`done`&&(m(`Ready`),S())}function re(){let e=_.trim();e&&(b.sendText(e),v(``))}let w=i.find(e=>e.id===o),ie=h?.tasks_24h?.reduce((e,t)=>e+Number(t.errors??0),0)??0;return(0,T.jsxs)(`main`,{className:`shell`,children:[(0,T.jsxs)(`aside`,{className:`rail`,"aria-label":`AEGIS navigation`,children:[(0,T.jsxs)(`section`,{className:`brand`,children:[(0,T.jsx)(`div`,{className:`brand-mark`,"aria-hidden":`true`,children:`A`}),(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`h1`,{children:`AEGIS`}),(0,T.jsx)(`p`,{children:`Edge-native operator console`})]})]}),(0,T.jsxs)(`section`,{className:`token-panel`,"aria-label":`Access token`,children:[(0,T.jsx)(`label`,{htmlFor:`token`,children:`Access token`}),(0,T.jsxs)(`div`,{className:`token-row`,children:[(0,T.jsx)(`input`,{id:`token`,type:`password`,value:n,onChange:e=>r(e.target.value),autoComplete:`off`}),(0,T.jsx)(`button`,{type:`button`,onClick:te,"aria-label":`Save token`,children:`OK`})]})]}),(0,T.jsxs)(`section`,{className:`health-panel`,"aria-label":`Health dashboard`,children:[(0,T.jsxs)(`div`,{className:`panel-title`,children:[(0,T.jsx)(`span`,{children:`Health`}),(0,T.jsx)(`button`,{type:`button`,onClick:ee,"aria-label":`Refresh health`,children:`R`})]}),(0,T.jsxs)(`dl`,{className:`health-grid`,children:[(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`dt`,{children:`Status`}),(0,T.jsx)(`dd`,{children:h?.status??`unknown`})]}),(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`dt`,{children:`Version`}),(0,T.jsx)(`dd`,{children:h?.version??`-`})]}),(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`dt`,{children:`Kernel`}),(0,T.jsx)(`dd`,{children:h?.kernel?Object.values(h.kernel).reduce((e,t)=>e+t,0):`-`})]}),(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`dt`,{children:`Task errors`}),(0,T.jsx)(`dd`,{children:ie})]})]})]}),(0,T.jsxs)(`section`,{className:`conversation-panel`,"aria-label":`Conversations`,children:[(0,T.jsxs)(`div`,{className:`panel-title`,children:[(0,T.jsx)(`span`,{children:`Conversations`}),(0,T.jsx)(`button`,{type:`button`,onClick:S,"aria-label":`Refresh conversations`,children:`R`})]}),(0,T.jsx)(`button`,{type:`button`,className:`new-chat`,onClick:()=>{s(null),u([])},children:`New session`}),(0,T.jsx)(`div`,{className:`conversation-list`,children:i.map(e=>(0,T.jsxs)(`button`,{type:`button`,className:e.id===o?`conversation active`:`conversation`,onClick:()=>C(e.id),children:[(0,T.jsx)(`span`,{children:e.title||`Untitled`}),(0,T.jsx)(`small`,{children:e.updated_at?new Date(e.updated_at).toLocaleString():`recent`})]},e.id))})]})]}),(0,T.jsxs)(`section`,{className:`workspace`,children:[(0,T.jsxs)(`header`,{className:`topbar`,children:[(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`p`,{className:`eyebrow`,children:`Self-sufficient deploy`}),(0,T.jsx)(`h2`,{children:w?.title||`Operator session`})]}),(0,T.jsxs)(`div`,{className:`runtime-status`,"aria-live":`polite`,children:[(0,T.jsx)(`span`,{className:e?`dot online`:`dot`,"aria-hidden":`true`}),p]})]}),(0,T.jsx)(`section`,{className:`message-surface`,ref:y,"aria-label":`Messages`,children:c.length===0?(0,T.jsx)(`div`,{className:`empty-state`,children:(0,T.jsx)(`p`,{children:`Ask the agent to inspect memory, explain its health, or plan the next deployment step.`})}):c.map(e=>(0,T.jsxs)(`article`,{className:`message ${e.role}`,children:[(0,T.jsx)(`div`,{className:`message-role`,children:e.role}),(0,T.jsx)(`div`,{className:`message-content`,children:e.content||`...`})]},e.id))}),(0,T.jsxs)(`form`,{className:`composer`,onSubmit:e=>{e.preventDefault(),ne()},children:[(0,T.jsx)(`textarea`,{value:d,onChange:e=>f(e.target.value),placeholder:`Message AEGIS`,rows:3}),(0,T.jsx)(`button`,{type:`submit`,"aria-label":`Send message`,children:`Send`})]})]}),(0,T.jsxs)(`aside`,{className:`voice-panel`,"aria-label":`Voice call`,children:[(0,T.jsxs)(`div`,{className:`panel-title`,children:[(0,T.jsx)(`span`,{children:`Voice`}),(0,T.jsx)(`span`,{className:`voice-state`,children:b.status})]}),(0,T.jsx)(`div`,{className:`meter`,"aria-label":`Audio level`,children:(0,T.jsx)(`span`,{style:{width:`${Math.round(b.audioLevel*100)}%`}})}),(0,T.jsxs)(`div`,{className:`voice-actions`,children:[(0,T.jsx)(`button`,{type:`button`,onClick:()=>b.connected?b.endCall():void b.startCall(),children:b.connected?`End call`:`Start call`}),(0,T.jsx)(`button`,{type:`button`,onClick:b.toggleMute,disabled:!b.connected,children:b.isMuted?`Unmute`:`Mute`})]}),b.error?(0,T.jsx)(`p`,{className:`error`,children:b.error}):null,(0,T.jsxs)(`div`,{className:`voice-transcript`,children:[b.transcript.slice(-8).map((e,t)=>(0,T.jsxs)(`p`,{children:[(0,T.jsx)(`strong`,{children:e.role}),(0,T.jsx)(`span`,{children:e.text})]},`${e.role}-${t}`)),b.interimTranscript?(0,T.jsxs)(`p`,{children:[(0,T.jsx)(`strong`,{children:`interim`}),(0,T.jsx)(`span`,{children:b.interimTranscript})]}):null]}),(0,T.jsxs)(`div`,{className:`voice-text`,children:[(0,T.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:`Send text to voice agent`}),(0,T.jsx)(`button`,{type:`button`,onClick:re,disabled:!b.connected,children:`Send`})]})]})]})}async function*fe(e){let t=e.getReader(),n=new TextDecoder,r=``;for(;;){let{value:e,done:i}=await t.read();if(i)break;r+=n.decode(e,{stream:!0});let a=r.split(` + +`);r=a.pop()??``;for(let e of a){let t=e.split(` +`).find(e=>e.startsWith(`data: `));t&&(yield JSON.parse(t.slice(6)))}}}(0,u.createRoot)(document.getElementById(`root`)).render((0,T.jsx)(de,{})); \ No newline at end of file diff --git a/web/public/index.html b/web/public/index.html new file mode 100644 index 0000000..fb41afc --- /dev/null +++ b/web/public/index.html @@ -0,0 +1,14 @@ + + + + + + + AEGIS + + + + +
+ + diff --git a/web/src/agent-routing.ts b/web/src/agent-routing.ts new file mode 100644 index 0000000..7d45605 --- /dev/null +++ b/web/src/agent-routing.ts @@ -0,0 +1,38 @@ +import { routeAgentRequest } from 'agents'; +import type { Env } from './types.js'; + +export async function routeAegisAgentRequest( + request: Request, + env: Env, +): Promise { + const { pathname } = new URL(request.url); + if (!pathname.startsWith('/agents/')) { + return undefined; + } + + const token = extractBearer(request.headers.get('Authorization')) + ?? getCookie(request.headers.get('Cookie') ?? '', 'aegis_token') + ?? new URL(request.url).searchParams.get('token'); + + if (!token || token !== env.AEGIS_TOKEN) { + return new Response('Unauthorized', { status: 401 }); + } + + try { + const response = await routeAgentRequest(request, env); + return response ?? new Response('Agent route not found', { status: 404 }); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + return new Response(`Agent route failed: ${message}`, { status: 503 }); + } +} + +function extractBearer(header: string | null): string | null { + if (!header?.startsWith('Bearer ')) return null; + return header.slice(7); +} + +function getCookie(cookieHeader: string, name: string): string | null { + const match = cookieHeader.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`)); + return match?.[1] ?? null; +} diff --git a/web/src/assets.ts b/web/src/assets.ts new file mode 100644 index 0000000..3bc0ed9 --- /dev/null +++ b/web/src/assets.ts @@ -0,0 +1,6 @@ +export async function serveSpaIndex(request: Request, assets: Fetcher): Promise { + const url = new URL(request.url); + url.pathname = '/index.html'; + url.search = ''; + return assets.fetch(new Request(url, request)); +} diff --git a/web/src/auth.ts b/web/src/auth.ts index cd0532e..0507856 100755 --- a/web/src/auth.ts +++ b/web/src/auth.ts @@ -7,6 +7,7 @@ export async function bearerAuth(c: Context<{ Bindings: Env }>, next: Next): Pro c.req.path === '/health' || c.req.path === '/pulse' || ((c.req.path === '/' || c.req.path === '/chat' || c.req.path === '/manifest.json' || c.req.path === '/sw.js') && c.req.method === 'GET') || + (c.req.method === 'GET' && (c.req.path.startsWith('/assets/') || c.req.path === '/favicon.svg')) || c.req.path.startsWith('/tech') || c.req.path === '/api/feedback' || c.req.path === '/observe' || diff --git a/web/src/index.ts b/web/src/index.ts index e7e3425..27b12bb 100755 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -9,6 +9,7 @@ import { Hono } from 'hono'; import OAuthProvider from '@cloudflare/workers-oauth-provider'; import { bearerAuth } from './auth.js'; +import { routeAegisAgentRequest } from './agent-routing.js'; import { runScheduledTasks } from './kernel/scheduled/index.js'; import type { Env } from './types.js'; import { handleMcpRequest } from './mcp-server.js'; @@ -84,10 +85,15 @@ const oauthProvider = new OAuthProvider({ }); export default { - fetch: oauthProvider.fetch.bind(oauthProvider), + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + const agentResponse = await routeAegisAgentRequest(request, env); + if (agentResponse) return agentResponse; + return oauthProvider.fetch(request, env, ctx); + }, async scheduled(_event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise { ctx.waitUntil(runScheduledTasks(buildEdgeEnv(env))); }, }; export { ChatSession } from './durable-objects/chat-session.js'; +export { AegisVoiceAdapter } from './adapters/voice/cloudflare-agent.js'; diff --git a/web/src/routes/messages.ts b/web/src/routes/messages.ts index 191f2fe..8dcf078 100755 --- a/web/src/routes/messages.ts +++ b/web/src/routes/messages.ts @@ -3,6 +3,7 @@ import { bodyLimit } from 'hono/body-limit'; import { createIntent, dispatch, dispatchStream } from '../kernel/dispatch.js'; import { askGroq } from '../groq.js'; import type { Env, MessageMetadata } from '../types.js'; +import type { Executor } from '../kernel/types.js'; import { buildEdgeEnv } from '../edge-env.js'; // 100 KB — generous for chat text, blocks payload abuse @@ -47,7 +48,7 @@ async function generateConversationTitle( // ─── Send Message (edge-native kernel) ─────────────────────── messages.post('/api/message', bodyLimit({ maxSize: MESSAGE_BODY_LIMIT }), async (c) => { - const body = await c.req.json<{ text: string; conversationId?: string }>(); + const body = await c.req.json<{ text: string; conversationId?: string; executor?: Executor }>(); if (!body.text?.trim()) { return c.json({ error: 'text is required' }, 400); } @@ -80,7 +81,7 @@ messages.post('/api/message', bodyLimit({ maxSize: MESSAGE_BODY_LIMIT }), async ).bind(userMessageId, conversationId, 'user', text).run(); // Fire-and-forget title generation for new conversations (#21) - if (isNewConversation && c.executionCtx) { + if (isNewConversation && c.executionCtx && c.env.GROQ_API_KEY) { c.executionCtx.waitUntil( generateConversationTitle(c.env.DB, conversationId, text, c.env.GROQ_API_KEY, c.env.GROQ_MODEL || 'llama-3.3-70b-versatile', groqBaseUrl(c.env)), ); @@ -88,7 +89,9 @@ messages.post('/api/message', bodyLimit({ maxSize: MESSAGE_BODY_LIMIT }), async // Dispatch through edge kernel const edgeEnv = buildEdgeEnv(c.env, c.executionCtx); - const intent = createIntent(conversationId, text); + const intent = createIntent(conversationId, text, { + forcedExecutor: body.executor, + }); try { const result = await dispatch(intent, edgeEnv); @@ -146,7 +149,7 @@ messages.post('/api/message', bodyLimit({ maxSize: MESSAGE_BODY_LIMIT }), async // ─── Streaming Message (SSE) ───────────────────────────────── messages.post('/api/message/stream', bodyLimit({ maxSize: MESSAGE_BODY_LIMIT }), async (c) => { - const body = await c.req.json<{ text: string; conversationId?: string }>(); + const body = await c.req.json<{ text: string; conversationId?: string; executor?: Executor }>(); if (!body.text?.trim()) { return c.json({ error: 'text is required' }, 400); } @@ -169,14 +172,16 @@ messages.post('/api/message/stream', bodyLimit({ maxSize: MESSAGE_BODY_LIMIT }), await c.env.DB.prepare('INSERT INTO messages (id, conversation_id, role, content) VALUES (?, ?, ?, ?)').bind(userMessageId, conversationId, 'user', text).run(); // Fire-and-forget title generation for new conversations (#21) - if (isNewConvStream && c.executionCtx) { + if (isNewConvStream && c.executionCtx && c.env.GROQ_API_KEY) { c.executionCtx.waitUntil( generateConversationTitle(c.env.DB, conversationId, text, c.env.GROQ_API_KEY, c.env.GROQ_MODEL || 'llama-3.3-70b-versatile', groqBaseUrl(c.env)), ); } const edgeEnv = buildEdgeEnv(c.env, c.executionCtx); - const intent = createIntent(conversationId, text); + const intent = createIntent(conversationId, text, { + forcedExecutor: body.executor, + }); const { readable, writable } = new TransformStream(); const writer = writable.getWriter(); diff --git a/web/src/routes/pages.ts b/web/src/routes/pages.ts index 6f1d29c..f47c6a0 100644 --- a/web/src/routes/pages.ts +++ b/web/src/routes/pages.ts @@ -3,6 +3,7 @@ import { Hono } from 'hono'; import { bodyLimit } from 'hono/body-limit'; import type { Env } from '../types.js'; +import { serveSpaIndex } from '../assets.js'; import { chatPage } from '../ui.js'; import { landingPage } from '../landing.js'; import { dashboardPage, getDashboardData } from '../dashboard.js'; @@ -15,6 +16,9 @@ const pages = new Hono<{ Bindings: Env }>(); // ─── Landing ──────────────────────────────────────────────── pages.get('/', (c) => { + if (c.env.ASSETS) { + return serveSpaIndex(c.req.raw, c.env.ASSETS); + } return c.html(chatPage()); }); @@ -25,6 +29,9 @@ pages.get('/about', (c) => { // ─── Chat ─────────────────────────────────────────────────── pages.get('/chat', (c) => { + if (c.env.ASSETS) { + return serveSpaIndex(c.req.raw, c.env.ASSETS); + } return c.html(chatPage()); }); diff --git a/web/src/types.ts b/web/src/types.ts index 25641b0..e22c0a2 100755 --- a/web/src/types.ts +++ b/web/src/types.ts @@ -4,7 +4,9 @@ export interface Env { DB: D1Database; AI: Ai; AEGIS_TOKEN: string; + ASSETS?: Fetcher; CHAT_SESSION?: DurableObjectNamespace; + AegisVoiceAdapter?: DurableObjectNamespace; // OAuth 2.1 (injected by OAuthProvider wrapper at runtime) OAUTH_PROVIDER: OAuthHelpers; diff --git a/web/src/ui/index.html b/web/src/ui/index.html new file mode 100644 index 0000000..011ef70 --- /dev/null +++ b/web/src/ui/index.html @@ -0,0 +1,13 @@ + + + + + + + AEGIS + + +
+ + + diff --git a/web/src/ui/main.tsx b/web/src/ui/main.tsx new file mode 100644 index 0000000..da21a01 --- /dev/null +++ b/web/src/ui/main.tsx @@ -0,0 +1,356 @@ +import { useEffect, useMemo, useRef, useState } from 'react'; +import { createRoot } from 'react-dom/client'; +import { useVoiceAgent } from '@cloudflare/voice/react'; +import './styles.css'; + +type Conversation = { + id: string; + title: string | null; + created_at?: string; + updated_at?: string; +}; + +type Message = { + id: string; + role: 'user' | 'assistant' | string; + content: string; + metadata?: Record | null; +}; + +type HealthPayload = { + status: string; + version: string; + mode: string; + kernel?: Record; + tasks_24h?: Array<{ task_name: string; runs: number; ok: number; errors: number }>; + docs_sync_status?: { status: string; lastSyncAge: number | null }; +}; + +const TOKEN_KEY = 'aegis_token'; + +function App() { + const [token, setToken] = useState(() => localStorage.getItem(TOKEN_KEY) ?? ''); + const [tokenDraft, setTokenDraft] = useState(token); + const [conversations, setConversations] = useState([]); + const [conversationId, setConversationId] = useState(null); + const [messages, setMessages] = useState([]); + const [prompt, setPrompt] = useState(''); + const [status, setStatus] = useState('Ready'); + const [health, setHealth] = useState(null); + const [voiceText, setVoiceText] = useState(''); + const messagesRef = useRef(null); + + const voice = useVoiceAgent({ + agent: 'AegisVoiceAdapter', + name: 'operator', + query: token ? { token } : undefined, + }); + + const authHeaders = useMemo>( + () => { + const headers: Record = {}; + if (token) headers.Authorization = `Bearer ${token}`; + return headers; + }, + [token], + ); + + useEffect(() => { + document.cookie = token + ? `aegis_token=${encodeURIComponent(token)};path=/;max-age=31536000;SameSite=Strict;Secure` + : 'aegis_token=;path=/;max-age=0;SameSite=Strict;Secure'; + }, [token]); + + useEffect(() => { + void refreshHealth(); + if (token) void refreshConversations(); + }, [token]); + + useEffect(() => { + messagesRef.current?.scrollTo({ top: messagesRef.current.scrollHeight }); + }, [messages]); + + async function refreshHealth() { + const res = await fetch('/health?format=json', { + headers: { Accept: 'application/json' }, + }); + if (res.ok) { + setHealth(await res.json()); + } + } + + async function refreshConversations() { + const res = await fetch('/api/conversations', { headers: authHeaders }); + if (!res.ok) { + setStatus(res.status === 401 ? 'Add your AEGIS token' : `Conversations failed: ${res.status}`); + return; + } + const data = await res.json() as { conversations: Conversation[] }; + setConversations(data.conversations); + } + + async function loadConversation(id: string) { + setConversationId(id); + const res = await fetch(`/api/conversations/${encodeURIComponent(id)}/messages`, { + headers: authHeaders, + }); + if (!res.ok) { + setStatus(`History failed: ${res.status}`); + return; + } + const data = await res.json() as { messages: Message[] }; + setMessages(data.messages); + } + + function saveToken() { + const next = tokenDraft.trim(); + localStorage.setItem(TOKEN_KEY, next); + setToken(next); + setStatus(next ? 'Token saved' : 'Token cleared'); + } + + async function sendMessage(text = prompt.trim()) { + if (!text) return; + if (!token) { + setStatus('Add your AEGIS token'); + return; + } + + const optimisticUser: Message = { id: crypto.randomUUID(), role: 'user', content: text }; + const assistantId = crypto.randomUUID(); + setMessages((current) => [ + ...current, + optimisticUser, + { id: assistantId, role: 'assistant', content: '' }, + ]); + setPrompt(''); + setStatus('Streaming'); + + const res = await fetch('/api/message/stream', { + method: 'POST', + headers: { + ...authHeaders, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ text, conversationId, executor: 'workers_ai' }), + }); + + if (!res.ok || !res.body) { + setStatus(`Message failed: ${res.status}`); + return; + } + + let assistantText = ''; + for await (const frame of readSse(res.body)) { + if (frame.type === 'start' && typeof frame.conversationId === 'string') { + setConversationId(frame.conversationId); + } + if (frame.type === 'delta' && typeof frame.text === 'string') { + assistantText += frame.text; + setMessages((current) => current.map((message) => ( + message.id === assistantId ? { ...message, content: assistantText } : message + ))); + } + if (frame.type === 'error') { + setStatus(typeof frame.error === 'string' ? frame.error : 'Stream error'); + } + if (frame.type === 'done') { + setStatus('Ready'); + void refreshConversations(); + } + } + } + + function sendVoiceText() { + const text = voiceText.trim(); + if (!text) return; + voice.sendText(text); + setVoiceText(''); + } + + const activeConversation = conversations.find((conversation) => conversation.id === conversationId); + const taskErrors = health?.tasks_24h?.reduce((sum, task) => sum + Number(task.errors ?? 0), 0) ?? 0; + + return ( +
+ + +
+
+
+

Self-sufficient deploy

+

{activeConversation?.title || 'Operator session'}

+
+
+
+
+ +
+ {messages.length === 0 ? ( +
+

Ask the agent to inspect memory, explain its health, or plan the next deployment step.

+
+ ) : messages.map((message) => ( +
+
{message.role}
+
{message.content || '...'}
+
+ ))} +
+ +
{ + event.preventDefault(); + void sendMessage(); + }} + > +