From 983960e2dd9e95f5c19e1e96d70bf52d4d461c91 Mon Sep 17 00:00:00 2001 From: wehub-resource-sync Date: Mon, 13 Jul 2026 12:44:08 +0800 Subject: [PATCH] chore: import upstream snapshot with attribution --- .changelogrc | 25 + .editorconfig | 15 + .env.sample | 45 + .github/CODE_OF_CONDUCT.md | 76 + .github/CONTRIBUTING.md | 197 + .github/FUNDING.yml | 8 + .github/ISSUE_TEMPLATE/BUG.md | 27 + .github/ISSUE_TEMPLATE/DOCS.md | 23 + .github/ISSUE_TEMPLATE/FEATURE_REQUEST.md | 14 + .github/ISSUE_TEMPLATE/IMPROVEMENT.md | 16 + .github/ISSUE_TEMPLATE/QUESTION.md | 14 + .github/PULL_REQUEST_TEMPLATE.md | 31 + .../assets/thanks/jetbrains-mono-black.svg | 4 + .../assets/thanks/jetbrains-mono-white.svg | 4 + .../thanks/macstadium-logo-dark-mode.svg | 43 + .../thanks/macstadium-logo-light-mode.svg | 43 + .../assets/thanks/openai-logo-dark-mode.svg | 15 + .../assets/thanks/openai-logo-light-mode.svg | 15 + .github/workflows/build.yml | 39 + .github/workflows/lint.yml | 36 + .github/workflows/tests.yml | 42 + .gitignore | 36 + .gitpod.yml | 19 + .husky/commit-msg | 1 + .husky/pre-commit | 1 + .lintstagedrc | 3 + .nvmrc | 1 + CHANGELOG.md | 362 + LICENSE.md | 21 + README.md | 183 + README.wehub.md | 7 + app/src/css/built-in-commands.scss | 220 + app/src/css/file-system-autocomplete.scss | 69 + app/src/css/style.scss | 863 + app/src/css/tool-ui.scss | 418 + app/src/css/voice-energy/_variables.scss | 8 + app/src/css/voice-energy/base.scss | 162 + app/src/css/voice-energy/idle.scss | 61 + app/src/css/voice-energy/listening.scss | 61 + app/src/css/voice-energy/main.scss | 5 + app/src/css/voice-energy/processing.scss | 88 + app/src/css/voice-energy/talking.scss | 82 + app/src/custom-aurora-components/index.ts | 1 + .../custom-aurora-components/timer/index.ts | 1 + .../custom-aurora-components/timer/timer.tsx | 71 + app/src/img/favicon.png | Bin 0 -> 11404 bytes app/src/img/logo.svg | 18 + app/src/img/mic.svg | 1 + app/src/index.html | 366 + app/src/js/built-in-commands/api.js | 7 + .../built-in-commands/built-in-commands.jsx | 750 + app/src/js/built-in-commands/index.js | 3 + app/src/js/built-in-commands/modal.jsx | 263 + .../js/built-in-commands/result-renderer.jsx | 145 + app/src/js/chatbot.js | 957 + app/src/js/client.js | 651 + app/src/js/constants.js | 22 + app/src/js/file-system-autocomplete.js | 386 + app/src/js/init.jsx | 252 + app/src/js/listener.js | 44 + app/src/js/main.js | 213 + app/src/js/onkeydown.js | 38 + app/src/js/recorder.js | 63 + app/src/js/render-aurora-component.js | 56 + app/src/js/sessions.js | 288 + app/src/js/suggestion-handler.js | 43 + app/src/js/tool-ui-handler.js | 1010 + app/src/js/voice-energy.js | 74 + app/src/sounds/off.mp3 | Bin 0 -> 2064 bytes app/src/sounds/on.mp3 | Bin 0 -> 3168 bytes app/tsconfig.json | 9 + app/vite.config.js | 143 + aurora/global.d.ts | 3 + aurora/preview/App.tsx | 1839 + aurora/preview/index.html | 31 + aurora/preview/main.tsx | 24 + aurora/preview/public/apple-music.svg | 3 + aurora/preview/public/baking-powder.jpeg | Bin 0 -> 6713 bytes aurora/preview/public/butter.jpeg | Bin 0 -> 7839 bytes aurora/preview/public/deezer.svg | 64 + aurora/preview/public/egg.webp | Bin 0 -> 111506 bytes aurora/preview/public/flour.jpeg | Bin 0 -> 53469 bytes aurora/preview/public/milk.jpeg | Bin 0 -> 5646 bytes aurora/preview/public/mockingbird.jpg | Bin 0 -> 27625 bytes aurora/preview/public/pancakes.jpeg | Bin 0 -> 113861 bytes aurora/preview/public/salt.jpg | Bin 0 -> 77428 bytes aurora/preview/public/spotify.svg | 11 + aurora/preview/public/sugar.jpg | Bin 0 -> 58023 bytes aurora/preview/public/youtube-music.svg | 25 + aurora/preview/style.css | 36 + aurora/preview/vite.config.js | 26 + aurora/src/components/button/button.sass | 61 + aurora/src/components/button/button.tsx | 114 + aurora/src/components/button/index.ts | 1 + aurora/src/components/card/card.sass | 12 + aurora/src/components/card/card.tsx | 25 + aurora/src/components/card/index.ts | 1 + aurora/src/components/checkbox/checkbox.sass | 39 + aurora/src/components/checkbox/checkbox.tsx | 74 + aurora/src/components/checkbox/index.ts | 1 + .../circular-progress/circular-progress.sass | 28 + .../circular-progress/circular-progress.tsx | 41 + .../src/components/circular-progress/index.ts | 1 + aurora/src/components/flexbox/flexbox.sass | 92 + aurora/src/components/flexbox/flexbox.tsx | 66 + aurora/src/components/flexbox/index.ts | 1 + aurora/src/components/form/form.sass | 4 + aurora/src/components/form/form.tsx | 51 + aurora/src/components/form/index.ts | 1 + .../components/icon-button/icon-button.sass | 70 + .../components/icon-button/icon-button.tsx | 113 + aurora/src/components/icon-button/index.ts | 1 + aurora/src/components/icon/icon.sass | 115 + aurora/src/components/icon/icon.tsx | 75 + aurora/src/components/icon/index.ts | 1 + aurora/src/components/image/image.sass | 76 + aurora/src/components/image/image.tsx | 54 + aurora/src/components/image/index.ts | 1 + aurora/src/components/input/index.ts | 1 + aurora/src/components/input/input.sass | 87 + aurora/src/components/input/input.tsx | 167 + aurora/src/components/link/index.ts | 1 + aurora/src/components/link/link.sass | 14 + aurora/src/components/link/link.tsx | 28 + aurora/src/components/lists/index.ts | 3 + .../src/components/lists/list-header/index.ts | 1 + .../lists/list-header/list-header.tsx | 24 + .../src/components/lists/list-item/index.ts | 1 + .../components/lists/list-item/list-item.tsx | 75 + aurora/src/components/lists/list/index.ts | 1 + aurora/src/components/lists/list/list.sass | 57 + aurora/src/components/lists/list/list.tsx | 17 + aurora/src/components/loader/index.ts | 1 + aurora/src/components/loader/loader.sass | 29 + aurora/src/components/loader/loader.tsx | 20 + aurora/src/components/progress/index.ts | 1 + aurora/src/components/progress/progress.sass | 34 + aurora/src/components/progress/progress.tsx | 34 + aurora/src/components/radios/index.ts | 2 + .../components/radios/radio-group/index.ts | 1 + .../radios/radio-group/radio-group.sass | 50 + .../radios/radio-group/radio-group.tsx | 53 + aurora/src/components/radios/radio/index.ts | 1 + aurora/src/components/radios/radio/radio.tsx | 24 + aurora/src/components/range-slider/index.ts | 1 + .../components/range-slider/range-slider.sass | 70 + .../components/range-slider/range-slider.tsx | 114 + .../src/components/scroll-container/index.ts | 1 + .../scroll-container/scroll-container.sass | 31 + .../scroll-container/scroll-container.tsx | 34 + aurora/src/components/selects/index.ts | 2 + .../components/selects/select-option/index.ts | 1 + .../selects/select-option/select-option.tsx | 28 + aurora/src/components/selects/select/index.ts | 1 + .../src/components/selects/select/select.sass | 77 + .../src/components/selects/select/select.tsx | 124 + aurora/src/components/status/index.ts | 1 + aurora/src/components/status/status.sass | 63 + aurora/src/components/status/status.tsx | 45 + aurora/src/components/switch/index.ts | 1 + aurora/src/components/switch/switch.sass | 48 + aurora/src/components/switch/switch.tsx | 63 + aurora/src/components/tabs/index.ts | 4 + .../src/components/tabs/tab-content/index.ts | 1 + .../tabs/tab-content/tab-content.tsx | 23 + aurora/src/components/tabs/tab-group/index.ts | 1 + .../components/tabs/tab-group/tab-group.sass | 38 + .../components/tabs/tab-group/tab-group.tsx | 37 + aurora/src/components/tabs/tab-list/index.ts | 1 + .../src/components/tabs/tab-list/tab-list.tsx | 22 + aurora/src/components/tabs/tab/index.ts | 1 + aurora/src/components/tabs/tab/tab.tsx | 28 + aurora/src/components/text/index.ts | 1 + aurora/src/components/text/text.sass | 42 + aurora/src/components/text/text.tsx | 49 + aurora/src/components/widget-wrapper/index.ts | 1 + .../widget-wrapper/widget-wrapper.sass | 23 + .../widget-wrapper/widget-wrapper.tsx | 39 + aurora/src/index.ts | 23 + aurora/src/lib/types.ts | 20 + aurora/src/lib/utils.ts | 3 + aurora/src/styles/_includes/animations.sass | 5 + aurora/src/styles/_includes/reset.sass | 46 + aurora/src/styles/_includes/variables.sass | 139 + aurora/src/styles/main.sass | 21 + aurora/style.css | 8 + aurora/tsconfig.build.json | 25 + aurora/tsconfig.json | 9 + bin/cmake/versions.json | 3 + bin/coqui/.gitkeep | 0 bin/flite/.gitkeep | 0 bin/llama.cpp/versions.json | 3 + bin/ninja/versions.json | 3 + bin/node/versions.json | 3 + bin/nvidia/versions.json | 12 + bin/pnpm/versions.json | 3 + bin/python/versions.json | 3 + bin/pytorch/versions.json | 3 + bin/uv/versions.json | 3 + bridges/nodejs/.npmrc | 2 + bridges/nodejs/package.json | 23 + bridges/nodejs/src/constants.ts | 128 + bridges/nodejs/src/main.ts | 97 + bridges/nodejs/src/sdk/aurora/button.ts | 9 + bridges/nodejs/src/sdk/aurora/card.ts | 9 + bridges/nodejs/src/sdk/aurora/checkbox.ts | 9 + .../src/sdk/aurora/circular-progress.ts | 9 + bridges/nodejs/src/sdk/aurora/flexbox.ts | 9 + bridges/nodejs/src/sdk/aurora/form.ts | 9 + bridges/nodejs/src/sdk/aurora/icon-button.ts | 9 + bridges/nodejs/src/sdk/aurora/icon.ts | 9 + bridges/nodejs/src/sdk/aurora/image.ts | 9 + bridges/nodejs/src/sdk/aurora/index.ts | 30 + bridges/nodejs/src/sdk/aurora/input.ts | 9 + bridges/nodejs/src/sdk/aurora/link.ts | 9 + bridges/nodejs/src/sdk/aurora/list-header.ts | 9 + bridges/nodejs/src/sdk/aurora/list-item.ts | 9 + bridges/nodejs/src/sdk/aurora/list.ts | 9 + bridges/nodejs/src/sdk/aurora/loader.ts | 9 + bridges/nodejs/src/sdk/aurora/progress.ts | 9 + bridges/nodejs/src/sdk/aurora/radio-group.ts | 9 + bridges/nodejs/src/sdk/aurora/radio.ts | 9 + bridges/nodejs/src/sdk/aurora/range-slider.ts | 9 + .../nodejs/src/sdk/aurora/scroll-container.ts | 9 + .../nodejs/src/sdk/aurora/select-option.ts | 9 + bridges/nodejs/src/sdk/aurora/select.ts | 9 + bridges/nodejs/src/sdk/aurora/status.ts | 9 + bridges/nodejs/src/sdk/aurora/switch.ts | 9 + bridges/nodejs/src/sdk/aurora/tab-content.ts | 9 + bridges/nodejs/src/sdk/aurora/tab-group.ts | 9 + bridges/nodejs/src/sdk/aurora/tab-list.ts | 9 + bridges/nodejs/src/sdk/aurora/tab.ts | 9 + bridges/nodejs/src/sdk/aurora/text.ts | 9 + .../nodejs/src/sdk/aurora/widget-wrapper.ts | 9 + bridges/nodejs/src/sdk/base-tool.ts | 1457 + bridges/nodejs/src/sdk/leon.ts | 202 + bridges/nodejs/src/sdk/memory.ts | 118 + bridges/nodejs/src/sdk/network.ts | 197 + bridges/nodejs/src/sdk/packages/lodash.ts | 1 + bridges/nodejs/src/sdk/params-helper.ts | 122 + bridges/nodejs/src/sdk/settings.ts | 134 + bridges/nodejs/src/sdk/tool-manager.ts | 55 + bridges/nodejs/src/sdk/tool-reporter.ts | 17 + bridges/nodejs/src/sdk/toolkit-config.ts | 164 + bridges/nodejs/src/sdk/types.ts | 45 + bridges/nodejs/src/sdk/utils.ts | 301 + bridges/nodejs/src/sdk/widget-component.ts | 51 + bridges/nodejs/src/sdk/widget.ts | 138 + bridges/nodejs/src/tool-runtime.ts | 170 + bridges/nodejs/src/version.ts | 1 + bridges/nodejs/tsconfig.json | 23 + bridges/python/dist/.gitkeep | 0 bridges/python/src/constants.py | 93 + bridges/python/src/main.py | 124 + bridges/python/src/pyproject.toml | 14 + bridges/python/src/sdk/aurora/button.py | 6 + bridges/python/src/sdk/aurora/card.py | 6 + bridges/python/src/sdk/aurora/checkbox.py | 6 + .../src/sdk/aurora/circular_progress.py | 6 + bridges/python/src/sdk/aurora/flexbox.py | 6 + bridges/python/src/sdk/aurora/form.py | 6 + bridges/python/src/sdk/aurora/icon.py | 6 + bridges/python/src/sdk/aurora/icon_button.py | 6 + bridges/python/src/sdk/aurora/image.py | 6 + bridges/python/src/sdk/aurora/input.py | 6 + bridges/python/src/sdk/aurora/link.py | 6 + bridges/python/src/sdk/aurora/list.py | 6 + bridges/python/src/sdk/aurora/list_header.py | 6 + bridges/python/src/sdk/aurora/list_item.py | 6 + bridges/python/src/sdk/aurora/loader.py | 6 + bridges/python/src/sdk/aurora/progress.py | 6 + bridges/python/src/sdk/aurora/radio.py | 6 + bridges/python/src/sdk/aurora/radio_group.py | 6 + bridges/python/src/sdk/aurora/range_slider.py | 6 + .../python/src/sdk/aurora/scroll_container.py | 6 + bridges/python/src/sdk/aurora/select.py | 6 + .../python/src/sdk/aurora/select_option.py | 6 + bridges/python/src/sdk/aurora/status.py | 6 + bridges/python/src/sdk/aurora/switch.py | 6 + bridges/python/src/sdk/aurora/tab.py | 6 + bridges/python/src/sdk/aurora/tab_content.py | 6 + bridges/python/src/sdk/aurora/tab_group.py | 6 + bridges/python/src/sdk/aurora/tab_list.py | 6 + bridges/python/src/sdk/aurora/text.py | 6 + .../python/src/sdk/aurora/widget_wrapper.py | 6 + bridges/python/src/sdk/base_tool.py | 1231 + bridges/python/src/sdk/leon.py | 164 + bridges/python/src/sdk/memory.py | 87 + bridges/python/src/sdk/network.py | 148 + bridges/python/src/sdk/params_helper.py | 131 + bridges/python/src/sdk/settings.py | 95 + bridges/python/src/sdk/tool_manager.py | 46 + bridges/python/src/sdk/toolkit_config.py | 150 + bridges/python/src/sdk/types.py | 82 + bridges/python/src/sdk/utils.py | 318 + bridges/python/src/sdk/widget.py | 119 + bridges/python/src/sdk/widget_component.py | 76 + bridges/python/src/version.py | 1 + config.sample.yml | 154 + .../synchronizer/google-drive.sample.json | 12 + core/config/voice/amazon.sample.json | 8 + core/config/voice/google-cloud.sample.json | 13 + core/config/voice/watson-stt.sample.json | 5 + core/config/voice/watson-tts.sample.json | 5 + core/context/.gitkeep | 0 core/context/ARCHITECTURE.md | 43 + core/context/LEON.md | 39 + core/data/en/answers.json | 359 + core/data/fr/answers.json | 69 + core/data/models/.gitkeep | 0 core/data/models/audio/asr/.gitkeep | 0 core/data/models/audio/tts/.gitkeep | 0 .../bert-base-french-europeana-cased/.gitkeep | 0 .../audio/tts/bert-base-uncased/.gitkeep | 0 core/data/models/audio/tts/config.json | 288 + core/data/models/audio/wake_word/.gitkeep | 0 .../data/models/audio/wake_word/Hey_Leon.onnx | Bin 0 -> 205430 bytes .../models/audio/wake_word/embedding.onnx | Bin 0 -> 1326578 bytes .../audio/wake_word/melspectrogram.onnx | Bin 0 -> 1087958 bytes core/data/models/llm/.gitkeep | 0 core/langs.json | 21 + eslint.config.mjs | 86 + jsconfig.json | 12 + logs/.gitkeep | 0 logs/prompts/.gitkeep | 1 + nodemon.json | 12 + nodemon.nolint.json | 12 + package.json | 157 + pnpm-lock.yaml | 9538 ++ pnpm-workspace.yaml | 17 + scripts/app/build-app.js | 18 + scripts/app/run-build-app.js | 14 + scripts/assets/CHANGELOG-TEMPLATE.md | 5 + scripts/assets/leon.lv | 5 + .../assets/nodejs-bridge-intent-object.json | 37 + .../assets/python-bridge-intent-object.json | 37 + scripts/build-aurora.js | 59 + scripts/build-server.js | 163 + scripts/check-os.js | 59 + scripts/check.js | 784 + scripts/clean-test-dbs.js | 42 + scripts/commit-msg.js | 36 + .../generate-client-interface-token.js | 52 + scripts/generate/generate-json-schemas.js | 98 + scripts/generate/generate-prompt.js | 99 + .../run-generate-client-interface-token.js | 14 + scripts/generate/run-generate-json-schemas.js | 14 + scripts/generate/run-generate-prompt.js | 16 + scripts/kill.js | 83 + scripts/lint.js | 48 + scripts/out/.gitkeep | 0 .../prompt-templates/create-skill-template.md | 7 + .../prompt-templates/create-tool-template.md | 49 + scripts/release/generate-changelog.js | 74 + scripts/release/prepare-release.js | 36 + scripts/release/update-version.js | 29 + scripts/run-agent-vitest.ts | 86 + scripts/run-built-in-command.js | 104 + scripts/run-clean-test-dbs.js | 14 + scripts/run-python-bridge.js | 32 + scripts/run-tcp-server.js | 82 + scripts/run-with-managed-node.js | 91 + scripts/setup/create-instance-id.js | 34 + scripts/setup/inspect-setup-state.js | 82 + scripts/setup/local-ai-capability.js | 54 + scripts/setup/post-setup.js | 79 + scripts/setup/preinstall.js | 1 + scripts/setup/run-setup.js | 98 + scripts/setup/set-ffprobe-permissions.js | 25 + scripts/setup/settings-merge.js | 41 + scripts/setup/setup-banner.js | 75 + scripts/setup/setup-cmake.js | 124 + scripts/setup/setup-config.js | 400 + scripts/setup/setup-core.js | 43 + scripts/setup/setup-dotenv.js | 118 + scripts/setup/setup-git-hooks.js | 36 + scripts/setup/setup-jokes.js | 187 + scripts/setup/setup-llama-cpp.js | 519 + scripts/setup/setup-local-llm.js | 175 + scripts/setup/setup-native-node-modules.js | 95 + scripts/setup/setup-ninja.js | 123 + scripts/setup/setup-node.js | 66 + scripts/setup/setup-nodejs-bridge-env.js | 69 + scripts/setup/setup-nvidia-libs.js | 358 + scripts/setup/setup-pnpm.js | 66 + scripts/setup/setup-preferences.js | 122 + scripts/setup/setup-python-bridge-env.js | 14 + scripts/setup/setup-python-project-env.js | 181 + scripts/setup/setup-python.js | 66 + scripts/setup/setup-pytorch.js | 186 + scripts/setup/setup-qmd-llm.js | 114 + scripts/setup/setup-remote-llm.js | 177 + scripts/setup/setup-runtime-binary.js | 181 + .../setup-skills/setup-skills-settings.js | 51 + scripts/setup/setup-skills/setup-skills.js | 47 + .../setup-skills/sync-skill-dependencies.js | 27 + scripts/setup/setup-status.js | 65 + scripts/setup/setup-tcp-server-env.js | 113 + scripts/setup/setup-tcp-server-models.js | 166 + scripts/setup/setup-tools-dependencies.js | 80 + scripts/setup/setup-tools-settings.js | 91 + scripts/setup/setup-ui.js | 75 + scripts/setup/setup-uv.js | 66 + scripts/setup/setup-voice-resources.js | 21 + scripts/setup/setup.js | 443 + scripts/setup/sync-source-dependencies.js | 128 + scripts/sync-skill-deps.js | 47 + scripts/train/run-train.js | 14 + scripts/train/train-skill-router-duty.js | 33 + scripts/train/train.js | 45 + server/src/ajv.ts | 25 + .../built-in-command-manager.ts | 605 + .../built-in-command-renderer.ts | 91 + .../src/built-in-command/built-in-command.ts | 208 + .../download-command/download-command.ts | 207 + .../commands/help-command/help-command.ts | 40 + .../commands/model-command/model-command.ts | 370 + .../commands/mood-command/mood-command.ts | 124 + .../commands/open-command/open-command.ts | 135 + .../restart-command/restart-command.ts | 44 + .../routing-command/routing-command.ts | 113 + .../session-command/session-command.ts | 289 + .../skill-command/skill-command-helpers.ts | 256 + .../commands/skill-command/skill-command.ts | 393 + .../allow-only-skill-sub-command.ts | 113 + .../sub-commands/disable-skill-sub-command.ts | 129 + .../sub-commands/enable-skill-sub-command.ts | 135 + .../sub-commands/list-skill-sub-command.ts | 76 + .../remove-allow-only-skill-sub-command.ts | 113 + .../sub-commands/remove-skill-sub-command.ts | 148 + .../sub-commands/skill-sub-command.ts | 26 + .../commands/status-command/status-command.ts | 235 + .../commands/stop-command/stop-command.ts | 42 + .../allow-only-tool-sub-command.ts | 111 + .../sub-commands/disable-tool-sub-command.ts | 127 + .../sub-commands/enable-tool-sub-command.ts | 133 + .../sub-commands/list-tool-sub-command.ts | 76 + .../remove-allow-only-tool-sub-command.ts | 111 + .../sub-commands/tool-sub-command.ts | 26 + .../tool-command/tool-command-helpers.ts | 319 + .../commands/tool-command/tool-command.ts | 381 + .../commands/voice-command/voice-command.ts | 430 + server/src/built-in-command/index.ts | 53 + server/src/config.ts | 352 + server/src/constants.ts | 598 + server/src/conversation-logger.ts | 299 + server/src/core/asr/asr-parser-base.ts | 5 + server/src/core/asr/asr-provider.ts | 152 + server/src/core/asr/asr.ts | 77 + .../src/core/asr/parsers/coqui-asr-parser.ts | 77 + .../asr/parsers/google-cloud-asr-parser.ts | 72 + server/src/core/asr/parsers/local-parser.ts | 149 + .../src/core/asr/parsers/watson-asr-parser.ts | 69 + server/src/core/asr/types.ts | 27 + server/src/core/brain/answer-queue.ts | 43 + server/src/core/brain/brain.ts | 562 + .../core/brain/dialog-action-skill-handler.ts | 201 + .../core/brain/logic-action-skill-handler.ts | 463 + server/src/core/brain/types.ts | 148 + .../config-state-event-emitter.ts | 8 + server/src/core/config-states/config-state.ts | 23 + server/src/core/config-states/model-state.ts | 249 + server/src/core/config-states/mood-state.ts | 131 + .../core/config-states/routing-mode-state.ts | 46 + .../context-manager/context-file-factory.ts | 54 + .../src/core/context-manager/context-file.ts | 6 + .../context-files/activity-context-file.ts | 568 + .../architecture-context-file.ts | 55 + .../browser-history-context-file.ts | 583 + .../context-files/gpu-compute-context-file.ts | 69 + .../context-files/habits-context-file.ts | 312 + .../context-files/home-context-file.ts | 46 + .../context-files/host-system-context-file.ts | 76 + .../context-files/leon-context-file.ts | 51 + .../leon-runtime-context-file.ts | 105 + .../local-inventory-context-file.ts | 713 + .../media-profile-context-file.ts | 221 + .../network-ecosystem-context-file.ts | 710 + .../context-files/owner-context-file.ts | 32 + .../context-files/storage-context-file.ts | 38 + .../system-resources-context-file.ts | 52 + .../workspace-intelligence-context-file.ts | 424 + .../core/context-manager/context-manager.ts | 822 + .../context-manager/context-probe-helper.ts | 1611 + .../context-manager/context-refresh-worker.ts | 96 + .../context-manager/context-state-store.ts | 38 + server/src/core/context-manager/index.ts | 3 + .../context-manager/owner-profile-sync.ts | 758 + .../src/core/context-manager/owner-profile.ts | 534 + .../src/core/http-server/api/command/index.ts | 11 + .../src/core/http-server/api/command/post.ts | 180 + .../api/conversation-history/get.ts | 95 + .../api/conversation-history/index.ts | 11 + .../http-server/api/extension-files/index.ts | 12 + .../http-server/api/extension-files/post.ts | 156 + .../core/http-server/api/fetch-widget/get.ts | 137 + .../http-server/api/fetch-widget/index.ts | 12 + .../http-server/api/file-system-list/index.ts | 12 + .../http-server/api/file-system-list/post.ts | 295 + .../core/http-server/api/inference/index.ts | 11 + .../core/http-server/api/inference/post.ts | 63 + server/src/core/http-server/api/info/get.ts | 115 + server/src/core/http-server/api/info/index.ts | 12 + .../core/http-server/api/open-path/index.ts | 12 + .../core/http-server/api/open-path/post.ts | 71 + .../core/http-server/api/run-action/index.ts | 12 + .../core/http-server/api/run-action/post.ts | 119 + .../core/http-server/api/sessions/index.ts | 11 + .../core/http-server/api/sessions/routes.ts | 165 + .../http-server/api/system-widgets/get.ts | 89 + .../http-server/api/system-widgets/index.ts | 11 + .../src/core/http-server/http-plugins/auth.ts | 36 + .../http-server/http-plugins/leon-services.ts | 89 + .../core/http-server/http-plugins/loader.ts | 196 + .../core/http-server/http-plugins/manager.ts | 140 + .../core/http-server/http-plugins/types.ts | 83 + server/src/core/http-server/http-server.ts | 218 + server/src/core/http-server/plugins/cors.ts | 40 + server/src/core/http-server/plugins/other.ts | 10 + server/src/core/index.ts | 88 + server/src/core/leon-interface/types.ts | 73 + server/src/core/llm-manager/inference.ts | 76 + .../llm-duties/action-calling-llm-duty.ts | 500 + .../llm-duties/paraphrase-llm-duty.ts | 122 + .../llm-manager/llm-duties/react-llm-duty.ts | 3439 + .../llm-duties/react-llm-duty/catalog.ts | 92 + .../llm-duties/react-llm-duty/constants.ts | 275 + .../llm-duties/react-llm-duty/execution.ts | 2749 + .../llm-duties/react-llm-duty/final-answer.ts | 413 + .../react-llm-duty/history-compaction.ts | 181 + .../react-llm-duty/human-in-the-loop.ts | 135 + .../llm-duties/react-llm-duty/metrics.ts | 520 + .../react-llm-duty/phase-helpers.ts | 566 + .../llm-duties/react-llm-duty/phase-policy.ts | 119 + .../llm-duties/react-llm-duty/phases.ts | 5 + .../react-llm-duty/plan-contract.ts | 49 + .../llm-duties/react-llm-duty/plan-widget.ts | 298 + .../llm-duties/react-llm-duty/planning.ts | 785 + .../react-llm-duty/recovery-planning.ts | 542 + .../llm-duties/react-llm-duty/types.ts | 182 + .../llm-duties/react-llm-duty/utils.ts | 1130 + .../llm-duties/skill-router-llm-duty.ts | 93 + .../llm-duties/slot-filling-llm-duty.ts | 125 + server/src/core/llm-manager/llm-duty.ts | 100 + server/src/core/llm-manager/llm-manager.ts | 216 + .../llm-provider-account-configs.ts | 94 + server/src/core/llm-manager/llm-provider.ts | 2869 + .../ai-sdk-remote-llm-provider.ts | 1130 + .../llm-providers/anthropic-llm-provider.ts | 193 + .../llm-providers/cerebras-llm-provider.ts | 18 + .../llm-providers/groq-llm-provider.ts | 18 + .../llm-providers/huggingface-llm-provider.ts | 18 + .../llm-providers/llamacpp-llm-provider.ts | 1058 + .../llm-providers/minimax-llm-provider.ts | 54 + .../llm-providers/moonshotai-llm-provider.ts | 15 + .../llm-providers/openai-llm-provider.ts | 15 + .../llm-providers/openrouter-llm-provider.ts | 15 + .../llm-providers/sglang-llm-provider.ts | 22 + .../llm-providers/z-ai-llm-provider.ts | 18 + server/src/core/llm-manager/llm-routing.ts | 226 + server/src/core/llm-manager/persona.ts | 658 + .../src/core/llm-manager/streaming-chunk.ts | 49 + server/src/core/llm-manager/types.ts | 195 + server/src/core/memory-manager/index.ts | 3 + .../src/core/memory-manager/memory-manager.ts | 2187 + .../core/memory-manager/memory-repository.ts | 673 + server/src/core/memory-manager/qmd-backend.ts | 766 + .../memory-manager/qmd/qmd-embed-worker.js | 114 + .../core/memory-manager/qmd/qmd-retrieval.ts | 1487 + .../src/core/memory-manager/qmd/qmd-store.ts | 604 + server/src/core/memory-manager/sql/schema.sql | 167 + server/src/core/memory-manager/summarizer.ts | 60 + server/src/core/memory-manager/types.ts | 111 + server/src/core/nlp/conversation.ts | 350 + .../nlp/nlu/nlu-process-result-updater.ts | 244 + server/src/core/nlp/nlu/nlu.ts | 1505 + .../core/nlp/nlu/workflow-progress-widget.ts | 202 + server/src/core/nlp/types.ts | 447 + .../src/core/post-turn-maintenance-queue.ts | 43 + server/src/core/pulse-manager.ts | 1615 + server/src/core/self-model-manager.ts | 1031 + server/src/core/server-lifecycle.ts | 18 + server/src/core/session-manager/index.ts | 593 + .../core/session-manager/session-context.ts | 24 + server/src/core/socket-server.ts | 1083 + server/src/core/tcp-client.ts | 153 + server/src/core/tool-executor.ts | 947 + server/src/core/toolkit-registry.ts | 668 + .../synthesizers/amazon-polly-synthesizer.ts | 101 + .../tts/synthesizers/flite-synthesizer.ts | 83 + .../google-cloud-tts-synthesizer.ts | 101 + .../tts/synthesizers/local-synthesizer.ts | 97 + .../synthesizers/watson-tts-synthesizer.ts | 95 + server/src/core/tts/tts-synthesizer-base.ts | 42 + server/src/core/tts/tts.ts | 193 + server/src/core/tts/types.ts | 34 + server/src/core/voice/voice-resource-state.ts | 78 + server/src/declarations.d.ts | 36 + server/src/global.d.ts | 11 + .../helpers/conversation-history-helper.ts | 198 + server/src/helpers/date-helper.ts | 58 + server/src/helpers/file-helper.ts | 366 + server/src/helpers/json-redaction-helper.ts | 52 + server/src/helpers/lang-helper.ts | 51 + server/src/helpers/loader-helper.ts | 50 + server/src/helpers/log-helper.ts | 109 + server/src/helpers/network-helper.ts | 938 + server/src/helpers/profile-helper.ts | 338 + server/src/helpers/runtime-helper.ts | 302 + server/src/helpers/skill-domain-helper.ts | 933 + server/src/helpers/string-helper.ts | 138 + server/src/helpers/system-helper.ts | 442 + server/src/index.ts | 289 + server/src/intent-object.sample.json | 43 + server/src/leon-roots.ts | 40 + server/src/pre-check.ts | 260 + server/src/schemas/core-schemas.ts | 127 + server/src/schemas/global-data-schemas.ts | 55 + server/src/schemas/skill-schemas.ts | 444 + server/src/schemas/tool-schemas.ts | 165 + server/src/schemas/toolkit-schemas.ts | 27 + server/src/schemas/voice-config-schemas.ts | 46 + server/src/telemetry.ts | 268 + server/src/tool-call-logger.ts | 437 + server/src/types.ts | 132 + server/src/updater.ts | 45 + server/src/utilities.ts | 30 + skills/agent/tiny-web-crawler/SKILL.md | 94 + .../tiny-web-crawler/scripts/crawl-web.mjs | 297 + .../tiny-web-crawler/scripts/fetch-page.mjs | 406 + skills/native/age_skill/locales/en.json | 18 + skills/native/age_skill/memory/.gitkeep | 0 skills/native/age_skill/skill.json | 19 + skills/native/age_skill/src/actions/run.ts | 53 + skills/native/age_skill/src/lib/.gitkeep | 0 .../src/lib/getTimeDifferenceBetweenDates.ts | 48 + .../native/age_skill/src/settings.sample.json | 1 + skills/native/age_skill/src/widgets/.gitkeep | 0 skills/native/age_skill/test/.gitkeep | 0 skills/native/akinator_skill/locales/en.json | 71 + skills/native/akinator_skill/memory/.gitkeep | 1 + skills/native/akinator_skill/skill.json | 53 + .../akinator_skill/src/actions/guess.py | 94 + .../src/actions/restart_game.py | 59 + .../akinator_skill/src/actions/retry.py | 29 + .../akinator_skill/src/actions/start_game.py | 56 + .../native/akinator_skill/src/lib/__init__.py | 5 + skills/native/akinator_skill/src/lib/main.py | 100 + .../native/akinator_skill/src/lib/memory.py | 33 + .../akinator_skill/src/settings.sample.json | 1 + .../akinator_skill/src/widgets/.gitkeep | 1 + skills/native/color_skill/locales/en.json | 30 + skills/native/color_skill/memory/.gitkeep | 0 skills/native/color_skill/skill.json | 33 + .../src/actions/tell_hexadecimal_color.py | 27 + skills/native/color_skill/src/lib/.gitkeep | 0 .../native/color_skill/src/lib/hexa_colors.py | 42 + .../color_skill/src/settings.sample.json | 1 + .../native/color_skill/src/widgets/.gitkeep | 0 skills/native/color_skill/test/.gitkeep | 0 skills/native/date_time_skill/locales/en.json | 53 + skills/native/date_time_skill/memory/.gitkeep | 0 skills/native/date_time_skill/skill.json | 56 + .../src/actions/current_date.ts | 15 + .../src/actions/current_date_time.ts | 20 + .../current_date_time_with_time_zone.ts | 44 + .../src/actions/current_time.ts | 16 + .../src/actions/current_week_number.ts | 39 + .../src/actions/days_countdown.ts | 47 + .../native/date_time_skill/src/lib/.gitkeep | 0 .../date_time_skill/src/lib/constants.ts | 1 + .../native/date_time_skill/src/lib/zeroPad.ts | 9 + .../native/date_time_skill/src/package.json | 5 + .../date_time_skill/src/settings.sample.json | 1 + .../date_time_skill/src/widgets/.gitkeep | 0 skills/native/date_time_skill/test/.gitkeep | 0 .../guess_the_number_skill/locales/en.json | 33 + .../guess_the_number_skill/memory/.gitkeep | 0 .../native/guess_the_number_skill/skill.json | 42 + .../src/actions/guess.py | 36 + .../src/actions/replay.py | 30 + .../src/actions/set_up.py | 12 + .../guess_the_number_skill/src/lib/.gitkeep | 0 .../guess_the_number_skill/src/lib/memory.py | 33 + .../src/settings.sample.json | 1 + .../src/widgets/.gitkeep | 0 .../guess_the_number_skill/test/.gitkeep | 0 .../have_i_been_pwned_skill/locales/en.json | 47 + .../have_i_been_pwned_skill/locales/fr.json | 46 + .../have_i_been_pwned_skill/memory/.gitkeep | 0 .../native/have_i_been_pwned_skill/skill.json | 26 + .../src/actions/run.py | 89 + .../have_i_been_pwned_skill/src/lib/.gitkeep | 0 .../src/settings.sample.json | 4 + .../src/widgets/.gitkeep | 0 .../have_i_been_pwned_skill/test/.gitkeep | 0 skills/native/help_skill/locales/en.json | 15 + skills/native/help_skill/memory/.gitkeep | 0 skills/native/help_skill/skill.json | 19 + skills/native/help_skill/src/actions/help.ts | 41 + skills/native/help_skill/src/lib/.gitkeep | 0 .../help_skill/src/settings.sample.json | 1 + skills/native/help_skill/src/widgets/.gitkeep | 0 skills/native/help_skill/test/.gitkeep | 0 .../native/introduction_skill/locales/en.json | 41 + .../native/introduction_skill/memory/.gitkeep | 0 skills/native/introduction_skill/skill.json | 33 + .../src/actions/introduce_leon.py | 14 + .../src/actions/remember.py | 31 + .../introduction_skill/src/lib/.gitkeep | 0 .../introduction_skill/src/lib/memory.py | 20 + .../src/settings.sample.json | 1 + .../introduction_skill/src/widgets/.gitkeep | 0 .../native/introduction_skill/test/.gitkeep | 0 .../native/is_it_down_skill/locales/en.json | 38 + .../native/is_it_down_skill/locales/fr.json | 38 + .../native/is_it_down_skill/memory/.gitkeep | 0 skills/native/is_it_down_skill/skill.json | 25 + .../is_it_down_skill/src/actions/run.py | 65 + .../native/is_it_down_skill/src/lib/.gitkeep | 0 .../is_it_down_skill/src/settings.sample.json | 1 + .../is_it_down_skill/src/widgets/.gitkeep | 0 skills/native/is_it_down_skill/test/.gitkeep | 0 skills/native/joke_skill/locales/en.json | 19 + skills/native/joke_skill/locales/fr.json | 25 + skills/native/joke_skill/memory/.gitkeep | 0 skills/native/joke_skill/skill.json | 19 + skills/native/joke_skill/test/.gitkeep | 0 skills/native/mbti_skill/locales/en.json | 83 + skills/native/mbti_skill/memory/.gitkeep | 0 skills/native/mbti_skill/skill.json | 31 + skills/native/mbti_skill/src/actions/quiz.py | 115 + .../native/mbti_skill/src/actions/set_up.py | 18 + skills/native/mbti_skill/src/lib/.gitkeep | 0 skills/native/mbti_skill/src/lib/memory.py | 58 + .../mbti_skill/src/settings.sample.json | 1 + skills/native/mbti_skill/src/widgets/.gitkeep | 0 skills/native/mbti_skill/test/.gitkeep | 0 .../meaning_of_life_skill/locales/en.json | 11 + .../meaning_of_life_skill/locales/fr.json | 11 + .../meaning_of_life_skill/memory/.gitkeep | 0 .../native/meaning_of_life_skill/skill.json | 19 + .../meaning_of_life_skill/test/.gitkeep | 0 .../music_audio_toolkit_skill/locales/en.json | 74 + .../music_audio_toolkit_skill/skill.json | 52 + .../src/actions/dub_audio.ts | 236 + .../src/actions/split_instrumental_vocal.ts | 86 + .../src/actions/transcribe_audio.ts | 172 + .../src/settings.sample.json | 13 + .../partner_assistant_skill/locales/en.json | 29 + .../partner_assistant_skill/memory/.gitkeep | 0 .../native/partner_assistant_skill/skill.json | 27 + .../src/actions/tell_about_assistant.py | 15 + .../partner_assistant_skill/src/lib/.gitkeep | 0 .../src/settings.sample.json | 1 + .../src/widgets/.gitkeep | 0 .../partner_assistant_skill/test/.gitkeep | 0 .../podcast_generator_skill/locales/en.json | 25 + .../native/podcast_generator_skill/skill.json | 28 + .../src/actions/generate.ts | 280 + .../src/settings.sample.json | 5 + .../random_number_skill/locales/en.json | 14 + .../random_number_skill/locales/fr.json | 14 + .../random_number_skill/memory/.gitkeep | 0 skills/native/random_number_skill/skill.json | 19 + .../random_number_skill/src/actions/run.py | 26 + .../random_number_skill/src/lib/.gitkeep | 0 .../src/settings.sample.json | 1 + .../random_number_skill/src/widgets/.gitkeep | 0 .../src/widgets/number_widget.py | 27 + .../native/random_number_skill/test/.gitkeep | 0 .../native/rochambeau_skill/locales/en.json | 43 + .../native/rochambeau_skill/memory/.gitkeep | 0 skills/native/rochambeau_skill/skill.json | 43 + .../rochambeau_skill/src/actions/play.py | 81 + .../rochambeau_skill/src/actions/rematch.py | 29 + .../native/rochambeau_skill/src/lib/.gitkeep | 0 .../rochambeau_skill/src/settings.sample.json | 1 + .../rochambeau_skill/src/widgets/.gitkeep | 0 skills/native/rochambeau_skill/test/.gitkeep | 0 .../search_web_toolkit_skill/locales/en.json | 37 + .../search_web_toolkit_skill/skill.json | 39 + .../src/actions/search.ts | 248 + .../src/settings.sample.json | 6 + .../native/skill_writer_skill/locales/en.json | 32 + skills/native/skill_writer_skill/skill.json | 30 + .../src/actions/create_skill.ts | 158 + .../src/actions/modify_skill.ts | 126 + .../src/lib/skill-plan-llm.ts | 503 + .../skill_writer_skill/src/lib/skill-plan.ts | 33 + .../src/lib/skill-prompt.ts | 49 + .../src/settings.sample.json | 3 + .../native/speed_test_skill/locales/en.json | 20 + .../native/speed_test_skill/locales/fr.json | 20 + .../native/speed_test_skill/memory/.gitkeep | 0 skills/native/speed_test_skill/skill.json | 18 + .../speed_test_skill/src/actions/run.py | 39 + .../native/speed_test_skill/src/lib/.gitkeep | 0 .../speed_test_skill/src/lib/speedtest.py | 2089 + .../speed_test_skill/src/settings.sample.json | 1 + .../speed_test_skill/src/widgets/.gitkeep | 0 skills/native/speed_test_skill/test/.gitkeep | 0 skills/native/timer_skill/locales/en.json | 49 + skills/native/timer_skill/memory/.gitkeep | 0 skills/native/timer_skill/skill.json | 43 + .../timer_skill/src/actions/cancel_timer.ts | 10 + .../timer_skill/src/actions/check_timer.ts | 45 + .../timer_skill/src/actions/set_timer.ts | 57 + skills/native/timer_skill/src/lib/.gitkeep | 0 skills/native/timer_skill/src/lib/memory.ts | 55 + .../timer_skill/src/settings.sample.json | 1 + .../native/timer_skill/src/widgets/.gitkeep | 0 .../src/widgets/components/timer.ts | 16 + .../timer_skill/src/widgets/timer-widget.ts | 53 + skills/native/timer_skill/test/.gitkeep | 0 skills/native/todo_list_skill/config/en.json | 285 + skills/native/todo_list_skill/config/fr.json | 280 + skills/native/todo_list_skill/locales/en.json | 116 + skills/native/todo_list_skill/memory/.gitkeep | 0 skills/native/todo_list_skill/skill.json | 117 + .../todo_list_skill/src/actions/add_todos.py | 57 + .../src/actions/complete_items.py | 48 + .../src/actions/create_list.py | 32 + .../src/actions/delete_list.py | 31 + .../src/actions/get_all_lists.py | 33 + .../src/actions/get_list_items.py | 72 + .../src/actions/rename_list.py | 42 + .../src/actions/uncomplete_items.py | 53 + .../native/todo_list_skill/src/lib/.gitkeep | 0 .../native/todo_list_skill/src/lib/memory.py | 210 + .../todo_list_skill/src/settings.sample.json | 1 + .../todo_list_skill/src/widgets/.gitkeep | 0 .../src/widgets/list_of_lists_widget.py | 38 + .../src/widgets/todos_list_widget.py | 54 + skills/native/todo_list_skill/test/.gitkeep | 0 .../video_summarizer_skill/locales/en.json | 68 + .../native/video_summarizer_skill/skill.json | 44 + .../src/actions/prepare_audio.ts | 162 + .../src/actions/summarize_transcription.ts | 213 + .../src/settings.sample.json | 8 + .../video_translator_skill/locales/en.json | 350 + .../video_translator_skill/memory/.gitkeep | 0 .../native/video_translator_skill/skill.json | 70 + .../src/actions/create_new_audio.ts | 733 + .../src/actions/detect_genders.ts | 87 + .../src/actions/download_video.ts | 249 + .../src/actions/extract_audio.ts | 137 + .../src/actions/get_speakers_references.ts | 356 + .../src/actions/merge_audio.ts | 214 + .../src/actions/translate_transcription.ts | 259 + .../video_translator_skill/src/lib/memory.ts | 82 + .../src/settings.sample.json | 6 + .../src/widgets/download-progress-widget.ts | 91 + .../voice_designer_skill/locales/en.json | 23 + skills/native/voice_designer_skill/skill.json | 27 + .../src/actions/design_and_speak.ts | 103 + .../src/settings.sample.json | 1 + .../weather_forecast_skill/locales/en.json | 40 + .../native/weather_forecast_skill/skill.json | 37 + .../src/actions/get_forecast.ts | 118 + .../src/settings.sample.json | 1 + .../src/widgets/weather-forecast-widget.ts | 206 + .../widget_playground_skill/locales/en.json | 16 + .../widget_playground_skill/memory/.gitkeep | 0 .../native/widget_playground_skill/skill.json | 19 + .../src/actions/run.ts | 224 + .../widget_playground_skill/src/lib/.gitkeep | 0 .../src/settings.sample.json | 1 + .../src/widgets/.gitkeep | 0 .../src/widgets/playground-test.ts | 106 + .../widget_playground_skill/test/.gitkeep | 0 skills/tsconfig.json | 18 + tcp_server/settings.json | 17 + tcp_server/src/lib/asr/api.py | 215 + tcp_server/src/lib/audio_input.py | 57 + tcp_server/src/lib/constants.py | 52 + tcp_server/src/lib/tcp_server.py | 254 + tcp_server/src/lib/tts/__init__.py | 0 tcp_server/src/lib/tts/api.py | 199 + tcp_server/src/lib/tts/attentions.py | 449 + tcp_server/src/lib/tts/commons.py | 150 + tcp_server/src/lib/tts/models.py | 1030 + tcp_server/src/lib/tts/modules.py | 571 + .../src/lib/tts/monotonic_align/__init__.py | 16 + .../src/lib/tts/monotonic_align/core.py | 46 + tcp_server/src/lib/tts/split_utils.py | 168 + tcp_server/src/lib/tts/text/__init__.py | 29 + tcp_server/src/lib/tts/text/cleaner.py | 37 + .../src/lib/tts/text/cleaner_multiling.py | 110 + tcp_server/src/lib/tts/text/cmudict.rep | 129530 +++++++++++++++ .../src/lib/tts/text/cmudict_cache.pickle | Bin 0 -> 6212655 bytes tcp_server/src/lib/tts/text/english.py | 298 + tcp_server/src/lib/tts/text/english_bert.py | 44 + .../lib/tts/text/english_utils/__init__.py | 0 .../tts/text/english_utils/abbreviations.py | 35 + .../lib/tts/text/english_utils/number_norm.py | 97 + .../lib/tts/text/english_utils/time_norm.py | 47 + .../lib/tts/text/fr_phonemizer/__init__.py | 0 .../src/lib/tts/text/fr_phonemizer/base.py | 140 + .../src/lib/tts/text/fr_phonemizer/cleaner.py | 122 + .../tts/text/fr_phonemizer/en_symbols.json | 79 + .../tts/text/fr_phonemizer/example_ipa.txt | 1 + .../tts/text/fr_phonemizer/fr_symbols.json | 89 + .../lib/tts/text/fr_phonemizer/fr_to_ipa.py | 30 + .../fr_phonemizer/french_abbreviations.py | 48 + .../tts/text/fr_phonemizer/french_symbols.txt | 1 + .../tts/text/fr_phonemizer/gruut_wrapper.py | 258 + .../lib/tts/text/fr_phonemizer/punctuation.py | 172 + tcp_server/src/lib/tts/text/french.py | 95 + tcp_server/src/lib/tts/text/french_bert.py | 44 + .../src/lib/tts/text/opencpop-strict.txt | 429 + tcp_server/src/lib/tts/text/symbols.py | 290 + tcp_server/src/lib/tts/transforms.py | 209 + tcp_server/src/lib/tts/utils.py | 404 + tcp_server/src/lib/utils.py | 36 + tcp_server/src/lib/wake_word/api.py | 91 + tcp_server/src/main.py | 172 + tcp_server/src/pyproject.toml | 23 + tcp_server/src/version.py | 1 + test/agent/e2e/provider-matrix.ts | 47 + test/agent/e2e/react-provider-smoke.spec.ts | 357 + test/agent/e2e/run-agent-provider-scenario.ts | 478 + .../unit/ai-sdk-remote-llm-provider.spec.ts | 124 + test/agent/unit/http-plugins.spec.ts | 99 + test/agent/unit/minimax-llm-provider.spec.ts | 165 + test/agent/unit/react-llm-duty.spec.ts | 1328 + .../e2e/controlled-skill-smoke.spec.ts | 118 + .../unit/action-calling-llm-duty.spec.ts | 151 + test/controlled/unit/config.spec.ts | 231 + .../unit/json-redaction-helper.spec.ts | 35 + test/controlled/unit/nlu-controlled.spec.ts | 617 + .../unit/paraphrase-llm-duty.spec.ts | 75 + test/controlled/unit/profile-helper.spec.ts | 237 + .../unit/skill-router-llm-duty.spec.ts | 84 + .../unit/slot-filling-llm-duty.spec.ts | 107 + tools/business_finance/toolkit.json | 8 + tools/calendar_scheduling/toolkit.json | 8 + tools/coding_development/opencode/__init__.py | 3 + .../opencode/settings.sample.json | 4 + .../opencode/src/nodejs/index.ts | 1 + .../opencode/src/nodejs/lib/.gitkeep | 0 .../opencode/src/nodejs/lib/prompt.md | 68 + .../opencode/src/nodejs/opencode-tool.ts | 2156 + .../opencode/src/python/lib/.gitkeep | 0 .../opencode/src/python/lib/prompt.md | 68 + .../opencode/src/python/opencode_tool.py | 1845 + tools/coding_development/opencode/tool.json | 111 + tools/coding_development/toolkit.json | 15 + tools/communication/cerebras/__init__.py | 3 + .../cerebras/settings.sample.json | 4 + .../cerebras/src/nodejs/cerebras-tool.ts | 352 + .../cerebras/src/nodejs/index.ts | 1 + .../cerebras/src/nodejs/lib/.gitkeep | 0 .../cerebras/src/python/cerebras_tool.py | 290 + .../cerebras/src/python/lib/.gitkeep | 0 tools/communication/cerebras/tool.json | 161 + tools/communication/inference/__init__.py | 3 + .../inference/settings.sample.json | 1 + .../inference/src/nodejs/index.ts | 1 + .../inference/src/nodejs/inference-tool.ts | 97 + .../inference/src/python/inference_tool.py | 93 + tools/communication/inference/tool.json | 101 + tools/communication/openrouter/__init__.py | 3 + .../openrouter/settings.sample.json | 4 + .../openrouter/src/nodejs/index.ts | 1 + .../openrouter/src/nodejs/lib/.gitkeep | 0 .../openrouter/src/nodejs/openrouter-tool.ts | 340 + .../openrouter/src/python/lib/.gitkeep | 0 .../openrouter/src/python/openrouter_tool.py | 272 + tools/communication/openrouter/tool.json | 162 + tools/communication/toolkit.json | 12 + tools/dialog/toolkit.json | 8 + tools/file_system/toolkit.json | 8 + tools/food_drink/toolkit.json | 8 + tools/games/toolkit.json | 8 + tools/health_fitness/toolkit.json | 8 + tools/media_generation/toolkit.json | 8 + tools/movies_tv/toolkit.json | 8 + .../music_audio/assemblyai_audio/__init__.py | 3 + .../assemblyai_audio/settings.sample.json | 3 + .../src/nodejs/assemblyai_audio-tool.ts | 276 + .../assemblyai_audio/src/nodejs/index.ts | 1 + .../assemblyai_audio/src/nodejs/lib/.gitkeep | 0 .../src/python/assemblyai_audio_tool.py | 240 + .../assemblyai_audio/src/python/lib/.gitkeep | 0 tools/music_audio/assemblyai_audio/tool.json | 39 + tools/music_audio/chatterbox_onnx/__init__.py | 3 + .../chatterbox_onnx/settings.sample.json | 1 + .../src/nodejs/chatterbox_onnx-tool.ts | 235 + .../chatterbox_onnx/src/nodejs/index.ts | 1 + .../chatterbox_onnx/src/nodejs/lib/.gitkeep | 0 .../src/python/chatterbox_onnx_tool.py | 241 + .../chatterbox_onnx/src/python/lib/.gitkeep | 0 tools/music_audio/chatterbox_onnx/tool.json | 132 + tools/music_audio/ecapa/__init__.py | 3 + tools/music_audio/ecapa/settings.sample.json | 1 + .../ecapa/src/nodejs/ecapa-tool.ts | 112 + tools/music_audio/ecapa/src/nodejs/index.ts | 1 + .../music_audio/ecapa/src/nodejs/lib/.gitkeep | 0 .../ecapa/src/python/ecapa_tool.py | 120 + .../music_audio/ecapa/src/python/lib/.gitkeep | 0 tools/music_audio/ecapa/tool.json | 45 + .../music_audio/elevenlabs_audio/__init__.py | 3 + .../elevenlabs_audio/settings.sample.json | 4 + .../src/nodejs/elevenlabs_audio-tool.ts | 275 + .../elevenlabs_audio/src/nodejs/index.ts | 1 + .../elevenlabs_audio/src/nodejs/lib/.gitkeep | 0 .../src/python/elevenlabs_audio_tool.py | 146 + .../elevenlabs_audio/src/python/lib/.gitkeep | 0 tools/music_audio/elevenlabs_audio/tool.json | 117 + tools/music_audio/faster_whisper/__init__.py | 3 + .../faster_whisper/settings.sample.json | 1 + .../src/nodejs/faster_whisper-tool.ts | 174 + .../faster_whisper/src/nodejs/index.ts | 1 + .../faster_whisper/src/nodejs/lib/.gitkeep | 0 .../src/python/faster_whisper_tool.py | 155 + .../faster_whisper/src/python/lib/.gitkeep | 0 tools/music_audio/faster_whisper/tool.json | 61 + tools/music_audio/openai_audio/__init__.py | 3 + .../openai_audio/settings.sample.json | 4 + .../openai_audio/src/nodejs/index.ts | 1 + .../openai_audio/src/nodejs/lib/.gitkeep | 0 .../src/nodejs/openai_audio-tool.ts | 157 + .../openai_audio/src/python/lib/.gitkeep | 0 .../src/python/openai_audio_tool.py | 133 + tools/music_audio/openai_audio/tool.json | 39 + tools/music_audio/qwen3_asr/__init__.py | 3 + .../qwen3_asr/settings.sample.json | 1 + .../music_audio/qwen3_asr/src/nodejs/index.ts | 1 + .../qwen3_asr/src/nodejs/lib/.gitkeep | 0 .../qwen3_asr/src/nodejs/qwen3_asr-tool.ts | 227 + .../qwen3_asr/src/python/lib/.gitkeep | 0 .../qwen3_asr/src/python/qwen3_asr_tool.py | 195 + tools/music_audio/qwen3_asr/tool.json | 72 + tools/music_audio/qwen3_tts/__init__.py | 3 + .../qwen3_tts/settings.sample.json | 1 + .../music_audio/qwen3_tts/src/nodejs/index.ts | 2 + .../qwen3_tts/src/nodejs/lib/.gitkeep | 0 .../qwen3_tts/src/nodejs/qwen3_tts-tool.ts | 316 + .../qwen3_tts/src/python/lib/.gitkeep | 0 .../qwen3_tts/src/python/qwen3_tts_tool.py | 310 + tools/music_audio/qwen3_tts/tool.json | 757 + tools/music_audio/toolkit.json | 16 + tools/music_audio/transcription-schema.ts | 33 + tools/music_audio/transcription_schema.py | 34 + .../ultimate_vocal_remover_onnx/__init__.py | 3 + .../settings.sample.json | 1 + .../src/nodejs/index.ts | 1 + .../src/nodejs/lib/.gitkeep | 0 .../ultimate_vocal_remover_onnx-tool.ts | 114 + .../src/python/lib/.gitkeep | 0 .../ultimate_vocal_remover_onnx_tool.py | 120 + .../ultimate_vocal_remover_onnx/tool.json | 94 + tools/news/toolkit.json | 8 + .../file/settings.sample.json | 1 + .../file/src/nodejs/file-tool.ts | 302 + .../file/src/nodejs/index.ts | 1 + tools/operating_system_control/file/tool.json | 138 + .../shell/__init__.py | 3 + .../shell/settings.sample.json | 1 + .../shell/src/nodejs/index.ts | 1 + .../shell/src/nodejs/lib/.gitkeep | 0 .../shell/src/nodejs/shell-tool.ts | 802 + .../shell/src/python/lib/.gitkeep | 0 .../shell/src/python/shell_tool.py | 597 + .../operating_system_control/shell/tool.json | 45 + tools/operating_system_control/toolkit.json | 18 + tools/productivity_collaboration/toolkit.json | 8 + tools/search_web/grok/__init__.py | 3 + tools/search_web/grok/settings.sample.json | 4 + tools/search_web/grok/src/nodejs/grok-tool.ts | 482 + tools/search_web/grok/src/nodejs/index.ts | 1 + tools/search_web/grok/src/nodejs/lib/.gitkeep | 0 tools/search_web/grok/src/python/grok_tool.py | 366 + tools/search_web/grok/src/python/lib/.gitkeep | 0 tools/search_web/grok/tool.json | 372 + tools/search_web/hosted/__init__.py | 1 + tools/search_web/hosted/settings.sample.json | 1 + .../hosted/src/nodejs/hosted-tool.ts | 380 + tools/search_web/hosted/src/nodejs/index.ts | 1 + tools/search_web/hosted/tool.json | 125 + tools/search_web/toolkit.json | 13 + tools/shopping/toolkit.json | 8 + tools/smart_home/toolkit.json | 8 + tools/social_media/toolkit.json | 8 + tools/sport/toolkit.json | 8 + .../context/settings.sample.json | 1 + .../context/src/nodejs/context-tool.ts | 444 + .../context/src/nodejs/index.ts | 1 + tools/structured_knowledge/context/tool.json | 108 + .../memory/settings.sample.json | 1 + .../memory/src/nodejs/index.ts | 1 + .../memory/src/nodejs/memory-tool.ts | 1255 + tools/structured_knowledge/memory/tool.json | 125 + tools/structured_knowledge/toolkit.json | 14 + tools/system_utilities/toolkit.json | 8 + tools/travel_transportation/toolkit.json | 8 + tools/tsconfig.json | 5 + tools/video_streaming/ffmpeg/__init__.py | 3 + .../ffmpeg/settings.sample.json | 1 + .../ffmpeg/src/nodejs/ffmpeg-tool.ts | 508 + .../ffmpeg/src/nodejs/index.ts | 1 + .../ffmpeg/src/nodejs/lib/.gitkeep | 0 .../ffmpeg/src/python/ffmpeg_tool.py | 401 + .../ffmpeg/src/python/lib/.gitkeep | 0 tools/video_streaming/ffmpeg/tool.json | 264 + tools/video_streaming/ffprobe/__init__.py | 3 + .../ffprobe/settings.sample.json | 1 + .../ffprobe/src/nodejs/ffprobe-tool.ts | 345 + .../ffprobe/src/nodejs/index.ts | 1 + .../ffprobe/src/nodejs/lib/.gitkeep | 0 .../ffprobe/src/python/ffprobe_tool.py | 347 + .../ffprobe/src/python/lib/.gitkeep | 0 tools/video_streaming/ffprobe/tool.json | 120 + tools/video_streaming/toolkit.json | 15 + tools/video_streaming/ytdlp/__init__.py | 3 + .../ytdlp/settings.sample.json | 1 + .../video_streaming/ytdlp/src/nodejs/index.ts | 1 + .../ytdlp/src/nodejs/lib/.gitkeep | 0 .../ytdlp/src/nodejs/yt-dlp.conf | 5 + .../ytdlp/src/nodejs/ytdlp-tool.ts | 703 + .../ytdlp/src/python/lib/.gitkeep | 0 .../ytdlp/src/python/yt-dlp.conf | 5 + .../ytdlp/src/python/ytdlp_tool.py | 698 + tools/video_streaming/ytdlp/tool.json | 162 + tools/weather/openmeteo/__init__.py | 3 + tools/weather/openmeteo/settings.sample.json | 1 + tools/weather/openmeteo/src/nodejs/index.ts | 1 + .../weather/openmeteo/src/nodejs/lib/.gitkeep | 0 .../openmeteo/src/nodejs/open-meteo-tool.ts | 361 + .../weather/openmeteo/src/python/lib/.gitkeep | 0 .../openmeteo/src/python/open_meteo_tool.py | 291 + tools/weather/openmeteo/tool.json | 36 + tools/weather/toolkit.json | 12 + tsconfig.json | 29 + vitest.config.ts | 30 + web-app/index.html | 13 + web-app/public/img/favicon.png | Bin 0 -> 10556 bytes web-app/public/img/logo-color-text.svg | 11 + web-app/public/img/logo-color.svg | 10 + web-app/public/img/logo-for-dark-bg-text.svg | 11 + web-app/public/img/logo-for-dark-bg.svg | 10 + web-app/public/img/logo-for-light-bg-text.svg | 11 + web-app/public/img/logo-for-light-bg.svg | 10 + web-app/src/components/badge/badge.sass | 25 + web-app/src/components/badge/badge.tsx | 20 + web-app/src/components/badge/index.ts | 1 + web-app/src/components/button/button.sass | 84 + web-app/src/components/button/button.tsx | 157 + web-app/src/components/button/index.ts | 1 + web-app/src/components/dialog/dialog.sass | 128 + web-app/src/components/dialog/dialog.tsx | 143 + web-app/src/components/dialog/index.ts | 1 + web-app/src/components/dropdown/dropdown.sass | 89 + web-app/src/components/dropdown/dropdown.tsx | 209 + web-app/src/components/dropdown/index.ts | 1 + web-app/src/components/feed/feed.sass | 7 + web-app/src/components/feed/feed.tsx | 5 + web-app/src/components/feed/index.ts | 1 + web-app/src/components/input/index.ts | 1 + web-app/src/components/input/input.sass | 70 + web-app/src/components/input/input.tsx | 78 + web-app/src/components/leon-message/index.ts | 1 + .../components/leon-message/leon-message.sass | 10 + .../components/leon-message/leon-message.tsx | 5 + .../src/components/markdown-content/index.ts | 1 + .../markdown-content/markdown-content.sass | 23 + .../markdown-content/markdown-content.tsx | 5 + web-app/src/components/message/index.ts | 1 + web-app/src/components/message/message.sass | 9 + web-app/src/components/message/message.tsx | 5 + web-app/src/components/owner-message/index.ts | 1 + .../owner-message/owner-message.sass | 8 + .../owner-message/owner-message.tsx | 5 + web-app/src/components/query-input/index.ts | 1 + .../components/query-input/query-input.sass | 53 + .../components/query-input/query-input.tsx | 5 + .../search-sessions-dialog/index.ts | 1 + .../search-sessions-dialog.sass | 98 + .../search-sessions-dialog.tsx | 267 + web-app/src/components/shortcut/index.ts | 1 + web-app/src/components/shortcut/shortcut.sass | 18 + web-app/src/components/shortcut/shortcut.tsx | 5 + .../src/components/task-list-item/index.ts | 1 + .../task-list-item/task-list-item.sass | 55 + .../task-list-item/task-list-item.tsx | 5 + web-app/src/components/task-list/index.ts | 1 + .../src/components/task-list/task-list.sass | 3 + .../src/components/task-list/task-list.tsx | 5 + .../src/components/thinking-message/index.ts | 1 + .../thinking-message/thinking-message.sass | 16 + .../thinking-message/thinking-message.tsx | 5 + web-app/src/components/toast/index.ts | 1 + web-app/src/components/toast/toast.sass | 167 + web-app/src/components/toast/toast.tsx | 240 + web-app/src/components/tool-call/index.ts | 1 + .../src/components/tool-call/tool-call.sass | 28 + .../src/components/tool-call/tool-call.tsx | 5 + web-app/src/components/tooltip/index.ts | 1 + web-app/src/components/tooltip/tooltip.sass | 80 + web-app/src/components/tooltip/tooltip.tsx | 152 + web-app/src/components/vibes/index.ts | 1 + web-app/src/components/vibes/vibes.sass | 98 + web-app/src/components/vibes/vibes.tsx | 5 + web-app/src/data/sessions.json | 423 + web-app/src/data/sessions.ts | 20 + web-app/src/layout/app-layout/app-layout.sass | 25 + web-app/src/layout/app-layout/app-layout.tsx | 17 + web-app/src/layout/app-layout/index.ts | 1 + web-app/src/layout/sidebar/index.ts | 1 + web-app/src/layout/sidebar/logo/index.ts | 1 + web-app/src/layout/sidebar/logo/logo.sass | 7 + web-app/src/layout/sidebar/logo/logo.tsx | 25 + web-app/src/layout/sidebar/menu-item/index.ts | 1 + .../layout/sidebar/menu-item/menu-item.sass | 140 + .../layout/sidebar/menu-item/menu-item.tsx | 191 + web-app/src/layout/sidebar/menu/index.ts | 1 + web-app/src/layout/sidebar/menu/menu.sass | 12 + web-app/src/layout/sidebar/menu/menu.tsx | 101 + .../layout/sidebar/session-list-item/index.ts | 1 + .../session-list-item/session-list-item.sass | 126 + .../session-list-item/session-list-item.tsx | 183 + .../src/layout/sidebar/session-list/index.ts | 1 + .../sidebar/session-list/session-list.sass | 37 + .../sidebar/session-list/session-list.tsx | 159 + .../layout/sidebar/session-search/index.ts | 1 + .../session-search/session-search.sass | 23 + .../sidebar/session-search/session-search.tsx | 5 + .../layout/sidebar/sidebar-footer/index.ts | 1 + .../sidebar-footer/sidebar-footer.sass | 40 + .../sidebar/sidebar-footer/sidebar-footer.tsx | 5 + web-app/src/layout/sidebar/sidebar.sass | 180 + web-app/src/layout/sidebar/sidebar.tsx | 231 + web-app/src/main.tsx | 33 + web-app/src/query-client.ts | 11 + web-app/src/router.tsx | 34 + web-app/src/routes/home-route.tsx | 5 + web-app/src/styles/_includes/reset.sass | 50 + web-app/src/styles/_includes/themes.sass | 108 + web-app/src/styles/_includes/variables.sass | 73 + web-app/src/styles/main.sass | 34 + web-app/src/theme.ts | 65 + web-app/tsconfig.json | 14 + web-app/vite.config.ts | 16 + 1244 files changed, 281996 insertions(+) create mode 100644 .changelogrc create mode 100644 .editorconfig create mode 100644 .env.sample create mode 100644 .github/CODE_OF_CONDUCT.md create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/BUG.md create mode 100644 .github/ISSUE_TEMPLATE/DOCS.md create mode 100644 .github/ISSUE_TEMPLATE/FEATURE_REQUEST.md create mode 100644 .github/ISSUE_TEMPLATE/IMPROVEMENT.md create mode 100644 .github/ISSUE_TEMPLATE/QUESTION.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/assets/thanks/jetbrains-mono-black.svg create mode 100644 .github/assets/thanks/jetbrains-mono-white.svg create mode 100644 .github/assets/thanks/macstadium-logo-dark-mode.svg create mode 100644 .github/assets/thanks/macstadium-logo-light-mode.svg create mode 100644 .github/assets/thanks/openai-logo-dark-mode.svg create mode 100644 .github/assets/thanks/openai-logo-light-mode.svg create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/tests.yml create mode 100644 .gitignore create mode 100644 .gitpod.yml create mode 100755 .husky/commit-msg create mode 100755 .husky/pre-commit create mode 100644 .lintstagedrc create mode 100644 .nvmrc create mode 100644 CHANGELOG.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 README.wehub.md create mode 100644 app/src/css/built-in-commands.scss create mode 100644 app/src/css/file-system-autocomplete.scss create mode 100644 app/src/css/style.scss create mode 100644 app/src/css/tool-ui.scss create mode 100644 app/src/css/voice-energy/_variables.scss create mode 100644 app/src/css/voice-energy/base.scss create mode 100644 app/src/css/voice-energy/idle.scss create mode 100644 app/src/css/voice-energy/listening.scss create mode 100644 app/src/css/voice-energy/main.scss create mode 100644 app/src/css/voice-energy/processing.scss create mode 100644 app/src/css/voice-energy/talking.scss create mode 100644 app/src/custom-aurora-components/index.ts create mode 100644 app/src/custom-aurora-components/timer/index.ts create mode 100644 app/src/custom-aurora-components/timer/timer.tsx create mode 100644 app/src/img/favicon.png create mode 100644 app/src/img/logo.svg create mode 100644 app/src/img/mic.svg create mode 100644 app/src/index.html create mode 100644 app/src/js/built-in-commands/api.js create mode 100644 app/src/js/built-in-commands/built-in-commands.jsx create mode 100644 app/src/js/built-in-commands/index.js create mode 100644 app/src/js/built-in-commands/modal.jsx create mode 100644 app/src/js/built-in-commands/result-renderer.jsx create mode 100644 app/src/js/chatbot.js create mode 100644 app/src/js/client.js create mode 100644 app/src/js/constants.js create mode 100644 app/src/js/file-system-autocomplete.js create mode 100644 app/src/js/init.jsx create mode 100644 app/src/js/listener.js create mode 100644 app/src/js/main.js create mode 100644 app/src/js/onkeydown.js create mode 100644 app/src/js/recorder.js create mode 100644 app/src/js/render-aurora-component.js create mode 100644 app/src/js/sessions.js create mode 100644 app/src/js/suggestion-handler.js create mode 100644 app/src/js/tool-ui-handler.js create mode 100644 app/src/js/voice-energy.js create mode 100644 app/src/sounds/off.mp3 create mode 100644 app/src/sounds/on.mp3 create mode 100644 app/tsconfig.json create mode 100644 app/vite.config.js create mode 100644 aurora/global.d.ts create mode 100644 aurora/preview/App.tsx create mode 100644 aurora/preview/index.html create mode 100644 aurora/preview/main.tsx create mode 100644 aurora/preview/public/apple-music.svg create mode 100644 aurora/preview/public/baking-powder.jpeg create mode 100644 aurora/preview/public/butter.jpeg create mode 100644 aurora/preview/public/deezer.svg create mode 100644 aurora/preview/public/egg.webp create mode 100644 aurora/preview/public/flour.jpeg create mode 100644 aurora/preview/public/milk.jpeg create mode 100644 aurora/preview/public/mockingbird.jpg create mode 100644 aurora/preview/public/pancakes.jpeg create mode 100644 aurora/preview/public/salt.jpg create mode 100644 aurora/preview/public/spotify.svg create mode 100644 aurora/preview/public/sugar.jpg create mode 100644 aurora/preview/public/youtube-music.svg create mode 100644 aurora/preview/style.css create mode 100644 aurora/preview/vite.config.js create mode 100644 aurora/src/components/button/button.sass create mode 100644 aurora/src/components/button/button.tsx create mode 100644 aurora/src/components/button/index.ts create mode 100644 aurora/src/components/card/card.sass create mode 100644 aurora/src/components/card/card.tsx create mode 100644 aurora/src/components/card/index.ts create mode 100644 aurora/src/components/checkbox/checkbox.sass create mode 100644 aurora/src/components/checkbox/checkbox.tsx create mode 100644 aurora/src/components/checkbox/index.ts create mode 100644 aurora/src/components/circular-progress/circular-progress.sass create mode 100644 aurora/src/components/circular-progress/circular-progress.tsx create mode 100644 aurora/src/components/circular-progress/index.ts create mode 100644 aurora/src/components/flexbox/flexbox.sass create mode 100644 aurora/src/components/flexbox/flexbox.tsx create mode 100644 aurora/src/components/flexbox/index.ts create mode 100644 aurora/src/components/form/form.sass create mode 100644 aurora/src/components/form/form.tsx create mode 100644 aurora/src/components/form/index.ts create mode 100644 aurora/src/components/icon-button/icon-button.sass create mode 100644 aurora/src/components/icon-button/icon-button.tsx create mode 100644 aurora/src/components/icon-button/index.ts create mode 100644 aurora/src/components/icon/icon.sass create mode 100644 aurora/src/components/icon/icon.tsx create mode 100644 aurora/src/components/icon/index.ts create mode 100644 aurora/src/components/image/image.sass create mode 100644 aurora/src/components/image/image.tsx create mode 100644 aurora/src/components/image/index.ts create mode 100644 aurora/src/components/input/index.ts create mode 100644 aurora/src/components/input/input.sass create mode 100644 aurora/src/components/input/input.tsx create mode 100644 aurora/src/components/link/index.ts create mode 100644 aurora/src/components/link/link.sass create mode 100644 aurora/src/components/link/link.tsx create mode 100644 aurora/src/components/lists/index.ts create mode 100644 aurora/src/components/lists/list-header/index.ts create mode 100644 aurora/src/components/lists/list-header/list-header.tsx create mode 100644 aurora/src/components/lists/list-item/index.ts create mode 100644 aurora/src/components/lists/list-item/list-item.tsx create mode 100644 aurora/src/components/lists/list/index.ts create mode 100644 aurora/src/components/lists/list/list.sass create mode 100644 aurora/src/components/lists/list/list.tsx create mode 100644 aurora/src/components/loader/index.ts create mode 100644 aurora/src/components/loader/loader.sass create mode 100644 aurora/src/components/loader/loader.tsx create mode 100644 aurora/src/components/progress/index.ts create mode 100644 aurora/src/components/progress/progress.sass create mode 100644 aurora/src/components/progress/progress.tsx create mode 100644 aurora/src/components/radios/index.ts create mode 100644 aurora/src/components/radios/radio-group/index.ts create mode 100644 aurora/src/components/radios/radio-group/radio-group.sass create mode 100644 aurora/src/components/radios/radio-group/radio-group.tsx create mode 100644 aurora/src/components/radios/radio/index.ts create mode 100644 aurora/src/components/radios/radio/radio.tsx create mode 100644 aurora/src/components/range-slider/index.ts create mode 100644 aurora/src/components/range-slider/range-slider.sass create mode 100644 aurora/src/components/range-slider/range-slider.tsx create mode 100644 aurora/src/components/scroll-container/index.ts create mode 100644 aurora/src/components/scroll-container/scroll-container.sass create mode 100644 aurora/src/components/scroll-container/scroll-container.tsx create mode 100644 aurora/src/components/selects/index.ts create mode 100644 aurora/src/components/selects/select-option/index.ts create mode 100644 aurora/src/components/selects/select-option/select-option.tsx create mode 100644 aurora/src/components/selects/select/index.ts create mode 100644 aurora/src/components/selects/select/select.sass create mode 100644 aurora/src/components/selects/select/select.tsx create mode 100644 aurora/src/components/status/index.ts create mode 100644 aurora/src/components/status/status.sass create mode 100644 aurora/src/components/status/status.tsx create mode 100644 aurora/src/components/switch/index.ts create mode 100644 aurora/src/components/switch/switch.sass create mode 100644 aurora/src/components/switch/switch.tsx create mode 100644 aurora/src/components/tabs/index.ts create mode 100644 aurora/src/components/tabs/tab-content/index.ts create mode 100644 aurora/src/components/tabs/tab-content/tab-content.tsx create mode 100644 aurora/src/components/tabs/tab-group/index.ts create mode 100644 aurora/src/components/tabs/tab-group/tab-group.sass create mode 100644 aurora/src/components/tabs/tab-group/tab-group.tsx create mode 100644 aurora/src/components/tabs/tab-list/index.ts create mode 100644 aurora/src/components/tabs/tab-list/tab-list.tsx create mode 100644 aurora/src/components/tabs/tab/index.ts create mode 100644 aurora/src/components/tabs/tab/tab.tsx create mode 100644 aurora/src/components/text/index.ts create mode 100644 aurora/src/components/text/text.sass create mode 100644 aurora/src/components/text/text.tsx create mode 100644 aurora/src/components/widget-wrapper/index.ts create mode 100644 aurora/src/components/widget-wrapper/widget-wrapper.sass create mode 100644 aurora/src/components/widget-wrapper/widget-wrapper.tsx create mode 100644 aurora/src/index.ts create mode 100644 aurora/src/lib/types.ts create mode 100644 aurora/src/lib/utils.ts create mode 100644 aurora/src/styles/_includes/animations.sass create mode 100644 aurora/src/styles/_includes/reset.sass create mode 100644 aurora/src/styles/_includes/variables.sass create mode 100644 aurora/src/styles/main.sass create mode 100644 aurora/style.css create mode 100644 aurora/tsconfig.build.json create mode 100644 aurora/tsconfig.json create mode 100644 bin/cmake/versions.json create mode 100644 bin/coqui/.gitkeep create mode 100644 bin/flite/.gitkeep create mode 100644 bin/llama.cpp/versions.json create mode 100644 bin/ninja/versions.json create mode 100644 bin/node/versions.json create mode 100644 bin/nvidia/versions.json create mode 100644 bin/pnpm/versions.json create mode 100644 bin/python/versions.json create mode 100644 bin/pytorch/versions.json create mode 100644 bin/uv/versions.json create mode 100644 bridges/nodejs/.npmrc create mode 100644 bridges/nodejs/package.json create mode 100644 bridges/nodejs/src/constants.ts create mode 100644 bridges/nodejs/src/main.ts create mode 100644 bridges/nodejs/src/sdk/aurora/button.ts create mode 100644 bridges/nodejs/src/sdk/aurora/card.ts create mode 100644 bridges/nodejs/src/sdk/aurora/checkbox.ts create mode 100644 bridges/nodejs/src/sdk/aurora/circular-progress.ts create mode 100644 bridges/nodejs/src/sdk/aurora/flexbox.ts create mode 100644 bridges/nodejs/src/sdk/aurora/form.ts create mode 100644 bridges/nodejs/src/sdk/aurora/icon-button.ts create mode 100644 bridges/nodejs/src/sdk/aurora/icon.ts create mode 100644 bridges/nodejs/src/sdk/aurora/image.ts create mode 100644 bridges/nodejs/src/sdk/aurora/index.ts create mode 100644 bridges/nodejs/src/sdk/aurora/input.ts create mode 100644 bridges/nodejs/src/sdk/aurora/link.ts create mode 100644 bridges/nodejs/src/sdk/aurora/list-header.ts create mode 100644 bridges/nodejs/src/sdk/aurora/list-item.ts create mode 100644 bridges/nodejs/src/sdk/aurora/list.ts create mode 100644 bridges/nodejs/src/sdk/aurora/loader.ts create mode 100644 bridges/nodejs/src/sdk/aurora/progress.ts create mode 100644 bridges/nodejs/src/sdk/aurora/radio-group.ts create mode 100644 bridges/nodejs/src/sdk/aurora/radio.ts create mode 100644 bridges/nodejs/src/sdk/aurora/range-slider.ts create mode 100644 bridges/nodejs/src/sdk/aurora/scroll-container.ts create mode 100644 bridges/nodejs/src/sdk/aurora/select-option.ts create mode 100644 bridges/nodejs/src/sdk/aurora/select.ts create mode 100644 bridges/nodejs/src/sdk/aurora/status.ts create mode 100644 bridges/nodejs/src/sdk/aurora/switch.ts create mode 100644 bridges/nodejs/src/sdk/aurora/tab-content.ts create mode 100644 bridges/nodejs/src/sdk/aurora/tab-group.ts create mode 100644 bridges/nodejs/src/sdk/aurora/tab-list.ts create mode 100644 bridges/nodejs/src/sdk/aurora/tab.ts create mode 100644 bridges/nodejs/src/sdk/aurora/text.ts create mode 100644 bridges/nodejs/src/sdk/aurora/widget-wrapper.ts create mode 100644 bridges/nodejs/src/sdk/base-tool.ts create mode 100644 bridges/nodejs/src/sdk/leon.ts create mode 100644 bridges/nodejs/src/sdk/memory.ts create mode 100644 bridges/nodejs/src/sdk/network.ts create mode 100644 bridges/nodejs/src/sdk/packages/lodash.ts create mode 100644 bridges/nodejs/src/sdk/params-helper.ts create mode 100644 bridges/nodejs/src/sdk/settings.ts create mode 100644 bridges/nodejs/src/sdk/tool-manager.ts create mode 100644 bridges/nodejs/src/sdk/tool-reporter.ts create mode 100644 bridges/nodejs/src/sdk/toolkit-config.ts create mode 100644 bridges/nodejs/src/sdk/types.ts create mode 100644 bridges/nodejs/src/sdk/utils.ts create mode 100644 bridges/nodejs/src/sdk/widget-component.ts create mode 100644 bridges/nodejs/src/sdk/widget.ts create mode 100644 bridges/nodejs/src/tool-runtime.ts create mode 100644 bridges/nodejs/src/version.ts create mode 100644 bridges/nodejs/tsconfig.json create mode 100644 bridges/python/dist/.gitkeep create mode 100644 bridges/python/src/constants.py create mode 100644 bridges/python/src/main.py create mode 100644 bridges/python/src/pyproject.toml create mode 100644 bridges/python/src/sdk/aurora/button.py create mode 100644 bridges/python/src/sdk/aurora/card.py create mode 100644 bridges/python/src/sdk/aurora/checkbox.py create mode 100644 bridges/python/src/sdk/aurora/circular_progress.py create mode 100644 bridges/python/src/sdk/aurora/flexbox.py create mode 100644 bridges/python/src/sdk/aurora/form.py create mode 100644 bridges/python/src/sdk/aurora/icon.py create mode 100644 bridges/python/src/sdk/aurora/icon_button.py create mode 100644 bridges/python/src/sdk/aurora/image.py create mode 100644 bridges/python/src/sdk/aurora/input.py create mode 100644 bridges/python/src/sdk/aurora/link.py create mode 100644 bridges/python/src/sdk/aurora/list.py create mode 100644 bridges/python/src/sdk/aurora/list_header.py create mode 100644 bridges/python/src/sdk/aurora/list_item.py create mode 100644 bridges/python/src/sdk/aurora/loader.py create mode 100644 bridges/python/src/sdk/aurora/progress.py create mode 100644 bridges/python/src/sdk/aurora/radio.py create mode 100644 bridges/python/src/sdk/aurora/radio_group.py create mode 100644 bridges/python/src/sdk/aurora/range_slider.py create mode 100644 bridges/python/src/sdk/aurora/scroll_container.py create mode 100644 bridges/python/src/sdk/aurora/select.py create mode 100644 bridges/python/src/sdk/aurora/select_option.py create mode 100644 bridges/python/src/sdk/aurora/status.py create mode 100644 bridges/python/src/sdk/aurora/switch.py create mode 100644 bridges/python/src/sdk/aurora/tab.py create mode 100644 bridges/python/src/sdk/aurora/tab_content.py create mode 100644 bridges/python/src/sdk/aurora/tab_group.py create mode 100644 bridges/python/src/sdk/aurora/tab_list.py create mode 100644 bridges/python/src/sdk/aurora/text.py create mode 100644 bridges/python/src/sdk/aurora/widget_wrapper.py create mode 100644 bridges/python/src/sdk/base_tool.py create mode 100644 bridges/python/src/sdk/leon.py create mode 100644 bridges/python/src/sdk/memory.py create mode 100644 bridges/python/src/sdk/network.py create mode 100644 bridges/python/src/sdk/params_helper.py create mode 100644 bridges/python/src/sdk/settings.py create mode 100644 bridges/python/src/sdk/tool_manager.py create mode 100644 bridges/python/src/sdk/toolkit_config.py create mode 100644 bridges/python/src/sdk/types.py create mode 100644 bridges/python/src/sdk/utils.py create mode 100644 bridges/python/src/sdk/widget.py create mode 100644 bridges/python/src/sdk/widget_component.py create mode 100644 bridges/python/src/version.py create mode 100644 config.sample.yml create mode 100644 core/config/synchronizer/google-drive.sample.json create mode 100644 core/config/voice/amazon.sample.json create mode 100644 core/config/voice/google-cloud.sample.json create mode 100644 core/config/voice/watson-stt.sample.json create mode 100644 core/config/voice/watson-tts.sample.json create mode 100644 core/context/.gitkeep create mode 100644 core/context/ARCHITECTURE.md create mode 100644 core/context/LEON.md create mode 100644 core/data/en/answers.json create mode 100644 core/data/fr/answers.json create mode 100644 core/data/models/.gitkeep create mode 100644 core/data/models/audio/asr/.gitkeep create mode 100644 core/data/models/audio/tts/.gitkeep create mode 100644 core/data/models/audio/tts/bert-base-french-europeana-cased/.gitkeep create mode 100644 core/data/models/audio/tts/bert-base-uncased/.gitkeep create mode 100644 core/data/models/audio/tts/config.json create mode 100644 core/data/models/audio/wake_word/.gitkeep create mode 100644 core/data/models/audio/wake_word/Hey_Leon.onnx create mode 100644 core/data/models/audio/wake_word/embedding.onnx create mode 100644 core/data/models/audio/wake_word/melspectrogram.onnx create mode 100644 core/data/models/llm/.gitkeep create mode 100644 core/langs.json create mode 100644 eslint.config.mjs create mode 100644 jsconfig.json create mode 100644 logs/.gitkeep create mode 100644 logs/prompts/.gitkeep create mode 100644 nodemon.json create mode 100644 nodemon.nolint.json create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml create mode 100644 scripts/app/build-app.js create mode 100644 scripts/app/run-build-app.js create mode 100644 scripts/assets/CHANGELOG-TEMPLATE.md create mode 100644 scripts/assets/leon.lv create mode 100644 scripts/assets/nodejs-bridge-intent-object.json create mode 100644 scripts/assets/python-bridge-intent-object.json create mode 100644 scripts/build-aurora.js create mode 100644 scripts/build-server.js create mode 100644 scripts/check-os.js create mode 100644 scripts/check.js create mode 100644 scripts/clean-test-dbs.js create mode 100644 scripts/commit-msg.js create mode 100644 scripts/generate/generate-client-interface-token.js create mode 100644 scripts/generate/generate-json-schemas.js create mode 100644 scripts/generate/generate-prompt.js create mode 100644 scripts/generate/run-generate-client-interface-token.js create mode 100644 scripts/generate/run-generate-json-schemas.js create mode 100644 scripts/generate/run-generate-prompt.js create mode 100644 scripts/kill.js create mode 100644 scripts/lint.js create mode 100644 scripts/out/.gitkeep create mode 100644 scripts/prompt-templates/create-skill-template.md create mode 100644 scripts/prompt-templates/create-tool-template.md create mode 100644 scripts/release/generate-changelog.js create mode 100644 scripts/release/prepare-release.js create mode 100644 scripts/release/update-version.js create mode 100644 scripts/run-agent-vitest.ts create mode 100644 scripts/run-built-in-command.js create mode 100644 scripts/run-clean-test-dbs.js create mode 100644 scripts/run-python-bridge.js create mode 100644 scripts/run-tcp-server.js create mode 100644 scripts/run-with-managed-node.js create mode 100644 scripts/setup/create-instance-id.js create mode 100644 scripts/setup/inspect-setup-state.js create mode 100644 scripts/setup/local-ai-capability.js create mode 100644 scripts/setup/post-setup.js create mode 100644 scripts/setup/preinstall.js create mode 100644 scripts/setup/run-setup.js create mode 100644 scripts/setup/set-ffprobe-permissions.js create mode 100644 scripts/setup/settings-merge.js create mode 100644 scripts/setup/setup-banner.js create mode 100644 scripts/setup/setup-cmake.js create mode 100644 scripts/setup/setup-config.js create mode 100644 scripts/setup/setup-core.js create mode 100644 scripts/setup/setup-dotenv.js create mode 100644 scripts/setup/setup-git-hooks.js create mode 100644 scripts/setup/setup-jokes.js create mode 100644 scripts/setup/setup-llama-cpp.js create mode 100644 scripts/setup/setup-local-llm.js create mode 100644 scripts/setup/setup-native-node-modules.js create mode 100644 scripts/setup/setup-ninja.js create mode 100644 scripts/setup/setup-node.js create mode 100644 scripts/setup/setup-nodejs-bridge-env.js create mode 100644 scripts/setup/setup-nvidia-libs.js create mode 100644 scripts/setup/setup-pnpm.js create mode 100644 scripts/setup/setup-preferences.js create mode 100644 scripts/setup/setup-python-bridge-env.js create mode 100644 scripts/setup/setup-python-project-env.js create mode 100644 scripts/setup/setup-python.js create mode 100644 scripts/setup/setup-pytorch.js create mode 100644 scripts/setup/setup-qmd-llm.js create mode 100644 scripts/setup/setup-remote-llm.js create mode 100644 scripts/setup/setup-runtime-binary.js create mode 100644 scripts/setup/setup-skills/setup-skills-settings.js create mode 100644 scripts/setup/setup-skills/setup-skills.js create mode 100644 scripts/setup/setup-skills/sync-skill-dependencies.js create mode 100644 scripts/setup/setup-status.js create mode 100644 scripts/setup/setup-tcp-server-env.js create mode 100644 scripts/setup/setup-tcp-server-models.js create mode 100644 scripts/setup/setup-tools-dependencies.js create mode 100644 scripts/setup/setup-tools-settings.js create mode 100644 scripts/setup/setup-ui.js create mode 100644 scripts/setup/setup-uv.js create mode 100644 scripts/setup/setup-voice-resources.js create mode 100644 scripts/setup/setup.js create mode 100644 scripts/setup/sync-source-dependencies.js create mode 100644 scripts/sync-skill-deps.js create mode 100644 scripts/train/run-train.js create mode 100644 scripts/train/train-skill-router-duty.js create mode 100644 scripts/train/train.js create mode 100644 server/src/ajv.ts create mode 100644 server/src/built-in-command/built-in-command-manager.ts create mode 100644 server/src/built-in-command/built-in-command-renderer.ts create mode 100644 server/src/built-in-command/built-in-command.ts create mode 100644 server/src/built-in-command/commands/download-command/download-command.ts create mode 100644 server/src/built-in-command/commands/help-command/help-command.ts create mode 100644 server/src/built-in-command/commands/model-command/model-command.ts create mode 100644 server/src/built-in-command/commands/mood-command/mood-command.ts create mode 100644 server/src/built-in-command/commands/open-command/open-command.ts create mode 100644 server/src/built-in-command/commands/restart-command/restart-command.ts create mode 100644 server/src/built-in-command/commands/routing-command/routing-command.ts create mode 100644 server/src/built-in-command/commands/session-command/session-command.ts create mode 100644 server/src/built-in-command/commands/skill-command/skill-command-helpers.ts create mode 100644 server/src/built-in-command/commands/skill-command/skill-command.ts create mode 100644 server/src/built-in-command/commands/skill-command/sub-commands/allow-only-skill-sub-command.ts create mode 100644 server/src/built-in-command/commands/skill-command/sub-commands/disable-skill-sub-command.ts create mode 100644 server/src/built-in-command/commands/skill-command/sub-commands/enable-skill-sub-command.ts create mode 100644 server/src/built-in-command/commands/skill-command/sub-commands/list-skill-sub-command.ts create mode 100644 server/src/built-in-command/commands/skill-command/sub-commands/remove-allow-only-skill-sub-command.ts create mode 100644 server/src/built-in-command/commands/skill-command/sub-commands/remove-skill-sub-command.ts create mode 100644 server/src/built-in-command/commands/skill-command/sub-commands/skill-sub-command.ts create mode 100644 server/src/built-in-command/commands/status-command/status-command.ts create mode 100644 server/src/built-in-command/commands/stop-command/stop-command.ts create mode 100644 server/src/built-in-command/commands/tool-command/sub-commands/allow-only-tool-sub-command.ts create mode 100644 server/src/built-in-command/commands/tool-command/sub-commands/disable-tool-sub-command.ts create mode 100644 server/src/built-in-command/commands/tool-command/sub-commands/enable-tool-sub-command.ts create mode 100644 server/src/built-in-command/commands/tool-command/sub-commands/list-tool-sub-command.ts create mode 100644 server/src/built-in-command/commands/tool-command/sub-commands/remove-allow-only-tool-sub-command.ts create mode 100644 server/src/built-in-command/commands/tool-command/sub-commands/tool-sub-command.ts create mode 100644 server/src/built-in-command/commands/tool-command/tool-command-helpers.ts create mode 100644 server/src/built-in-command/commands/tool-command/tool-command.ts create mode 100644 server/src/built-in-command/commands/voice-command/voice-command.ts create mode 100644 server/src/built-in-command/index.ts create mode 100644 server/src/config.ts create mode 100644 server/src/constants.ts create mode 100644 server/src/conversation-logger.ts create mode 100644 server/src/core/asr/asr-parser-base.ts create mode 100644 server/src/core/asr/asr-provider.ts create mode 100644 server/src/core/asr/asr.ts create mode 100644 server/src/core/asr/parsers/coqui-asr-parser.ts create mode 100644 server/src/core/asr/parsers/google-cloud-asr-parser.ts create mode 100644 server/src/core/asr/parsers/local-parser.ts create mode 100644 server/src/core/asr/parsers/watson-asr-parser.ts create mode 100644 server/src/core/asr/types.ts create mode 100644 server/src/core/brain/answer-queue.ts create mode 100644 server/src/core/brain/brain.ts create mode 100644 server/src/core/brain/dialog-action-skill-handler.ts create mode 100644 server/src/core/brain/logic-action-skill-handler.ts create mode 100644 server/src/core/brain/types.ts create mode 100644 server/src/core/config-states/config-state-event-emitter.ts create mode 100644 server/src/core/config-states/config-state.ts create mode 100644 server/src/core/config-states/model-state.ts create mode 100644 server/src/core/config-states/mood-state.ts create mode 100644 server/src/core/config-states/routing-mode-state.ts create mode 100644 server/src/core/context-manager/context-file-factory.ts create mode 100644 server/src/core/context-manager/context-file.ts create mode 100644 server/src/core/context-manager/context-files/activity-context-file.ts create mode 100644 server/src/core/context-manager/context-files/architecture-context-file.ts create mode 100644 server/src/core/context-manager/context-files/browser-history-context-file.ts create mode 100644 server/src/core/context-manager/context-files/gpu-compute-context-file.ts create mode 100644 server/src/core/context-manager/context-files/habits-context-file.ts create mode 100644 server/src/core/context-manager/context-files/home-context-file.ts create mode 100644 server/src/core/context-manager/context-files/host-system-context-file.ts create mode 100644 server/src/core/context-manager/context-files/leon-context-file.ts create mode 100644 server/src/core/context-manager/context-files/leon-runtime-context-file.ts create mode 100644 server/src/core/context-manager/context-files/local-inventory-context-file.ts create mode 100644 server/src/core/context-manager/context-files/media-profile-context-file.ts create mode 100644 server/src/core/context-manager/context-files/network-ecosystem-context-file.ts create mode 100644 server/src/core/context-manager/context-files/owner-context-file.ts create mode 100644 server/src/core/context-manager/context-files/storage-context-file.ts create mode 100644 server/src/core/context-manager/context-files/system-resources-context-file.ts create mode 100644 server/src/core/context-manager/context-files/workspace-intelligence-context-file.ts create mode 100644 server/src/core/context-manager/context-manager.ts create mode 100644 server/src/core/context-manager/context-probe-helper.ts create mode 100644 server/src/core/context-manager/context-refresh-worker.ts create mode 100644 server/src/core/context-manager/context-state-store.ts create mode 100644 server/src/core/context-manager/index.ts create mode 100644 server/src/core/context-manager/owner-profile-sync.ts create mode 100644 server/src/core/context-manager/owner-profile.ts create mode 100644 server/src/core/http-server/api/command/index.ts create mode 100644 server/src/core/http-server/api/command/post.ts create mode 100644 server/src/core/http-server/api/conversation-history/get.ts create mode 100644 server/src/core/http-server/api/conversation-history/index.ts create mode 100644 server/src/core/http-server/api/extension-files/index.ts create mode 100644 server/src/core/http-server/api/extension-files/post.ts create mode 100644 server/src/core/http-server/api/fetch-widget/get.ts create mode 100644 server/src/core/http-server/api/fetch-widget/index.ts create mode 100644 server/src/core/http-server/api/file-system-list/index.ts create mode 100644 server/src/core/http-server/api/file-system-list/post.ts create mode 100644 server/src/core/http-server/api/inference/index.ts create mode 100644 server/src/core/http-server/api/inference/post.ts create mode 100644 server/src/core/http-server/api/info/get.ts create mode 100644 server/src/core/http-server/api/info/index.ts create mode 100644 server/src/core/http-server/api/open-path/index.ts create mode 100644 server/src/core/http-server/api/open-path/post.ts create mode 100644 server/src/core/http-server/api/run-action/index.ts create mode 100644 server/src/core/http-server/api/run-action/post.ts create mode 100644 server/src/core/http-server/api/sessions/index.ts create mode 100644 server/src/core/http-server/api/sessions/routes.ts create mode 100644 server/src/core/http-server/api/system-widgets/get.ts create mode 100644 server/src/core/http-server/api/system-widgets/index.ts create mode 100644 server/src/core/http-server/http-plugins/auth.ts create mode 100644 server/src/core/http-server/http-plugins/leon-services.ts create mode 100644 server/src/core/http-server/http-plugins/loader.ts create mode 100644 server/src/core/http-server/http-plugins/manager.ts create mode 100644 server/src/core/http-server/http-plugins/types.ts create mode 100644 server/src/core/http-server/http-server.ts create mode 100644 server/src/core/http-server/plugins/cors.ts create mode 100644 server/src/core/http-server/plugins/other.ts create mode 100644 server/src/core/index.ts create mode 100644 server/src/core/leon-interface/types.ts create mode 100644 server/src/core/llm-manager/inference.ts create mode 100644 server/src/core/llm-manager/llm-duties/action-calling-llm-duty.ts create mode 100644 server/src/core/llm-manager/llm-duties/paraphrase-llm-duty.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/catalog.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/constants.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/execution.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/final-answer.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/history-compaction.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/human-in-the-loop.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/metrics.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/phase-helpers.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/phase-policy.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/phases.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/plan-contract.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/plan-widget.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/planning.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/recovery-planning.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/types.ts create mode 100644 server/src/core/llm-manager/llm-duties/react-llm-duty/utils.ts create mode 100644 server/src/core/llm-manager/llm-duties/skill-router-llm-duty.ts create mode 100644 server/src/core/llm-manager/llm-duties/slot-filling-llm-duty.ts create mode 100644 server/src/core/llm-manager/llm-duty.ts create mode 100644 server/src/core/llm-manager/llm-manager.ts create mode 100644 server/src/core/llm-manager/llm-provider-account-configs.ts create mode 100644 server/src/core/llm-manager/llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/ai-sdk-remote-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/anthropic-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/cerebras-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/groq-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/huggingface-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/llamacpp-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/minimax-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/moonshotai-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/openai-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/openrouter-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/sglang-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-providers/z-ai-llm-provider.ts create mode 100644 server/src/core/llm-manager/llm-routing.ts create mode 100644 server/src/core/llm-manager/persona.ts create mode 100644 server/src/core/llm-manager/streaming-chunk.ts create mode 100644 server/src/core/llm-manager/types.ts create mode 100644 server/src/core/memory-manager/index.ts create mode 100644 server/src/core/memory-manager/memory-manager.ts create mode 100644 server/src/core/memory-manager/memory-repository.ts create mode 100644 server/src/core/memory-manager/qmd-backend.ts create mode 100644 server/src/core/memory-manager/qmd/qmd-embed-worker.js create mode 100644 server/src/core/memory-manager/qmd/qmd-retrieval.ts create mode 100644 server/src/core/memory-manager/qmd/qmd-store.ts create mode 100644 server/src/core/memory-manager/sql/schema.sql create mode 100644 server/src/core/memory-manager/summarizer.ts create mode 100644 server/src/core/memory-manager/types.ts create mode 100644 server/src/core/nlp/conversation.ts create mode 100644 server/src/core/nlp/nlu/nlu-process-result-updater.ts create mode 100644 server/src/core/nlp/nlu/nlu.ts create mode 100644 server/src/core/nlp/nlu/workflow-progress-widget.ts create mode 100644 server/src/core/nlp/types.ts create mode 100644 server/src/core/post-turn-maintenance-queue.ts create mode 100644 server/src/core/pulse-manager.ts create mode 100644 server/src/core/self-model-manager.ts create mode 100644 server/src/core/server-lifecycle.ts create mode 100644 server/src/core/session-manager/index.ts create mode 100644 server/src/core/session-manager/session-context.ts create mode 100644 server/src/core/socket-server.ts create mode 100644 server/src/core/tcp-client.ts create mode 100644 server/src/core/tool-executor.ts create mode 100644 server/src/core/toolkit-registry.ts create mode 100644 server/src/core/tts/synthesizers/amazon-polly-synthesizer.ts create mode 100644 server/src/core/tts/synthesizers/flite-synthesizer.ts create mode 100644 server/src/core/tts/synthesizers/google-cloud-tts-synthesizer.ts create mode 100644 server/src/core/tts/synthesizers/local-synthesizer.ts create mode 100644 server/src/core/tts/synthesizers/watson-tts-synthesizer.ts create mode 100644 server/src/core/tts/tts-synthesizer-base.ts create mode 100644 server/src/core/tts/tts.ts create mode 100644 server/src/core/tts/types.ts create mode 100644 server/src/core/voice/voice-resource-state.ts create mode 100644 server/src/declarations.d.ts create mode 100644 server/src/global.d.ts create mode 100644 server/src/helpers/conversation-history-helper.ts create mode 100644 server/src/helpers/date-helper.ts create mode 100644 server/src/helpers/file-helper.ts create mode 100644 server/src/helpers/json-redaction-helper.ts create mode 100644 server/src/helpers/lang-helper.ts create mode 100644 server/src/helpers/loader-helper.ts create mode 100644 server/src/helpers/log-helper.ts create mode 100644 server/src/helpers/network-helper.ts create mode 100644 server/src/helpers/profile-helper.ts create mode 100644 server/src/helpers/runtime-helper.ts create mode 100644 server/src/helpers/skill-domain-helper.ts create mode 100644 server/src/helpers/string-helper.ts create mode 100644 server/src/helpers/system-helper.ts create mode 100644 server/src/index.ts create mode 100644 server/src/intent-object.sample.json create mode 100644 server/src/leon-roots.ts create mode 100644 server/src/pre-check.ts create mode 100644 server/src/schemas/core-schemas.ts create mode 100644 server/src/schemas/global-data-schemas.ts create mode 100644 server/src/schemas/skill-schemas.ts create mode 100644 server/src/schemas/tool-schemas.ts create mode 100644 server/src/schemas/toolkit-schemas.ts create mode 100644 server/src/schemas/voice-config-schemas.ts create mode 100644 server/src/telemetry.ts create mode 100644 server/src/tool-call-logger.ts create mode 100644 server/src/types.ts create mode 100644 server/src/updater.ts create mode 100644 server/src/utilities.ts create mode 100644 skills/agent/tiny-web-crawler/SKILL.md create mode 100755 skills/agent/tiny-web-crawler/scripts/crawl-web.mjs create mode 100755 skills/agent/tiny-web-crawler/scripts/fetch-page.mjs create mode 100644 skills/native/age_skill/locales/en.json create mode 100644 skills/native/age_skill/memory/.gitkeep create mode 100644 skills/native/age_skill/skill.json create mode 100644 skills/native/age_skill/src/actions/run.ts create mode 100644 skills/native/age_skill/src/lib/.gitkeep create mode 100644 skills/native/age_skill/src/lib/getTimeDifferenceBetweenDates.ts create mode 100644 skills/native/age_skill/src/settings.sample.json create mode 100644 skills/native/age_skill/src/widgets/.gitkeep create mode 100644 skills/native/age_skill/test/.gitkeep create mode 100644 skills/native/akinator_skill/locales/en.json create mode 100644 skills/native/akinator_skill/memory/.gitkeep create mode 100644 skills/native/akinator_skill/skill.json create mode 100644 skills/native/akinator_skill/src/actions/guess.py create mode 100644 skills/native/akinator_skill/src/actions/restart_game.py create mode 100644 skills/native/akinator_skill/src/actions/retry.py create mode 100644 skills/native/akinator_skill/src/actions/start_game.py create mode 100644 skills/native/akinator_skill/src/lib/__init__.py create mode 100644 skills/native/akinator_skill/src/lib/main.py create mode 100644 skills/native/akinator_skill/src/lib/memory.py create mode 100644 skills/native/akinator_skill/src/settings.sample.json create mode 100644 skills/native/akinator_skill/src/widgets/.gitkeep create mode 100644 skills/native/color_skill/locales/en.json create mode 100644 skills/native/color_skill/memory/.gitkeep create mode 100644 skills/native/color_skill/skill.json create mode 100644 skills/native/color_skill/src/actions/tell_hexadecimal_color.py create mode 100644 skills/native/color_skill/src/lib/.gitkeep create mode 100644 skills/native/color_skill/src/lib/hexa_colors.py create mode 100644 skills/native/color_skill/src/settings.sample.json create mode 100644 skills/native/color_skill/src/widgets/.gitkeep create mode 100644 skills/native/color_skill/test/.gitkeep create mode 100644 skills/native/date_time_skill/locales/en.json create mode 100644 skills/native/date_time_skill/memory/.gitkeep create mode 100644 skills/native/date_time_skill/skill.json create mode 100644 skills/native/date_time_skill/src/actions/current_date.ts create mode 100644 skills/native/date_time_skill/src/actions/current_date_time.ts create mode 100644 skills/native/date_time_skill/src/actions/current_date_time_with_time_zone.ts create mode 100644 skills/native/date_time_skill/src/actions/current_time.ts create mode 100644 skills/native/date_time_skill/src/actions/current_week_number.ts create mode 100644 skills/native/date_time_skill/src/actions/days_countdown.ts create mode 100644 skills/native/date_time_skill/src/lib/.gitkeep create mode 100644 skills/native/date_time_skill/src/lib/constants.ts create mode 100644 skills/native/date_time_skill/src/lib/zeroPad.ts create mode 100644 skills/native/date_time_skill/src/package.json create mode 100644 skills/native/date_time_skill/src/settings.sample.json create mode 100644 skills/native/date_time_skill/src/widgets/.gitkeep create mode 100644 skills/native/date_time_skill/test/.gitkeep create mode 100644 skills/native/guess_the_number_skill/locales/en.json create mode 100644 skills/native/guess_the_number_skill/memory/.gitkeep create mode 100644 skills/native/guess_the_number_skill/skill.json create mode 100644 skills/native/guess_the_number_skill/src/actions/guess.py create mode 100644 skills/native/guess_the_number_skill/src/actions/replay.py create mode 100644 skills/native/guess_the_number_skill/src/actions/set_up.py create mode 100644 skills/native/guess_the_number_skill/src/lib/.gitkeep create mode 100644 skills/native/guess_the_number_skill/src/lib/memory.py create mode 100644 skills/native/guess_the_number_skill/src/settings.sample.json create mode 100644 skills/native/guess_the_number_skill/src/widgets/.gitkeep create mode 100644 skills/native/guess_the_number_skill/test/.gitkeep create mode 100644 skills/native/have_i_been_pwned_skill/locales/en.json create mode 100644 skills/native/have_i_been_pwned_skill/locales/fr.json create mode 100644 skills/native/have_i_been_pwned_skill/memory/.gitkeep create mode 100644 skills/native/have_i_been_pwned_skill/skill.json create mode 100644 skills/native/have_i_been_pwned_skill/src/actions/run.py create mode 100644 skills/native/have_i_been_pwned_skill/src/lib/.gitkeep create mode 100644 skills/native/have_i_been_pwned_skill/src/settings.sample.json create mode 100644 skills/native/have_i_been_pwned_skill/src/widgets/.gitkeep create mode 100644 skills/native/have_i_been_pwned_skill/test/.gitkeep create mode 100644 skills/native/help_skill/locales/en.json create mode 100644 skills/native/help_skill/memory/.gitkeep create mode 100644 skills/native/help_skill/skill.json create mode 100644 skills/native/help_skill/src/actions/help.ts create mode 100644 skills/native/help_skill/src/lib/.gitkeep create mode 100644 skills/native/help_skill/src/settings.sample.json create mode 100644 skills/native/help_skill/src/widgets/.gitkeep create mode 100644 skills/native/help_skill/test/.gitkeep create mode 100644 skills/native/introduction_skill/locales/en.json create mode 100644 skills/native/introduction_skill/memory/.gitkeep create mode 100644 skills/native/introduction_skill/skill.json create mode 100644 skills/native/introduction_skill/src/actions/introduce_leon.py create mode 100644 skills/native/introduction_skill/src/actions/remember.py create mode 100644 skills/native/introduction_skill/src/lib/.gitkeep create mode 100644 skills/native/introduction_skill/src/lib/memory.py create mode 100644 skills/native/introduction_skill/src/settings.sample.json create mode 100644 skills/native/introduction_skill/src/widgets/.gitkeep create mode 100644 skills/native/introduction_skill/test/.gitkeep create mode 100644 skills/native/is_it_down_skill/locales/en.json create mode 100644 skills/native/is_it_down_skill/locales/fr.json create mode 100644 skills/native/is_it_down_skill/memory/.gitkeep create mode 100644 skills/native/is_it_down_skill/skill.json create mode 100644 skills/native/is_it_down_skill/src/actions/run.py create mode 100644 skills/native/is_it_down_skill/src/lib/.gitkeep create mode 100644 skills/native/is_it_down_skill/src/settings.sample.json create mode 100644 skills/native/is_it_down_skill/src/widgets/.gitkeep create mode 100644 skills/native/is_it_down_skill/test/.gitkeep create mode 100644 skills/native/joke_skill/locales/en.json create mode 100644 skills/native/joke_skill/locales/fr.json create mode 100644 skills/native/joke_skill/memory/.gitkeep create mode 100644 skills/native/joke_skill/skill.json create mode 100644 skills/native/joke_skill/test/.gitkeep create mode 100644 skills/native/mbti_skill/locales/en.json create mode 100644 skills/native/mbti_skill/memory/.gitkeep create mode 100644 skills/native/mbti_skill/skill.json create mode 100644 skills/native/mbti_skill/src/actions/quiz.py create mode 100644 skills/native/mbti_skill/src/actions/set_up.py create mode 100644 skills/native/mbti_skill/src/lib/.gitkeep create mode 100644 skills/native/mbti_skill/src/lib/memory.py create mode 100644 skills/native/mbti_skill/src/settings.sample.json create mode 100644 skills/native/mbti_skill/src/widgets/.gitkeep create mode 100644 skills/native/mbti_skill/test/.gitkeep create mode 100644 skills/native/meaning_of_life_skill/locales/en.json create mode 100644 skills/native/meaning_of_life_skill/locales/fr.json create mode 100644 skills/native/meaning_of_life_skill/memory/.gitkeep create mode 100644 skills/native/meaning_of_life_skill/skill.json create mode 100644 skills/native/meaning_of_life_skill/test/.gitkeep create mode 100644 skills/native/music_audio_toolkit_skill/locales/en.json create mode 100644 skills/native/music_audio_toolkit_skill/skill.json create mode 100644 skills/native/music_audio_toolkit_skill/src/actions/dub_audio.ts create mode 100644 skills/native/music_audio_toolkit_skill/src/actions/split_instrumental_vocal.ts create mode 100644 skills/native/music_audio_toolkit_skill/src/actions/transcribe_audio.ts create mode 100644 skills/native/music_audio_toolkit_skill/src/settings.sample.json create mode 100644 skills/native/partner_assistant_skill/locales/en.json create mode 100644 skills/native/partner_assistant_skill/memory/.gitkeep create mode 100644 skills/native/partner_assistant_skill/skill.json create mode 100644 skills/native/partner_assistant_skill/src/actions/tell_about_assistant.py create mode 100644 skills/native/partner_assistant_skill/src/lib/.gitkeep create mode 100644 skills/native/partner_assistant_skill/src/settings.sample.json create mode 100644 skills/native/partner_assistant_skill/src/widgets/.gitkeep create mode 100644 skills/native/partner_assistant_skill/test/.gitkeep create mode 100644 skills/native/podcast_generator_skill/locales/en.json create mode 100644 skills/native/podcast_generator_skill/skill.json create mode 100644 skills/native/podcast_generator_skill/src/actions/generate.ts create mode 100644 skills/native/podcast_generator_skill/src/settings.sample.json create mode 100644 skills/native/random_number_skill/locales/en.json create mode 100644 skills/native/random_number_skill/locales/fr.json create mode 100644 skills/native/random_number_skill/memory/.gitkeep create mode 100644 skills/native/random_number_skill/skill.json create mode 100644 skills/native/random_number_skill/src/actions/run.py create mode 100644 skills/native/random_number_skill/src/lib/.gitkeep create mode 100644 skills/native/random_number_skill/src/settings.sample.json create mode 100644 skills/native/random_number_skill/src/widgets/.gitkeep create mode 100644 skills/native/random_number_skill/src/widgets/number_widget.py create mode 100644 skills/native/random_number_skill/test/.gitkeep create mode 100644 skills/native/rochambeau_skill/locales/en.json create mode 100644 skills/native/rochambeau_skill/memory/.gitkeep create mode 100644 skills/native/rochambeau_skill/skill.json create mode 100644 skills/native/rochambeau_skill/src/actions/play.py create mode 100644 skills/native/rochambeau_skill/src/actions/rematch.py create mode 100644 skills/native/rochambeau_skill/src/lib/.gitkeep create mode 100644 skills/native/rochambeau_skill/src/settings.sample.json create mode 100644 skills/native/rochambeau_skill/src/widgets/.gitkeep create mode 100644 skills/native/rochambeau_skill/test/.gitkeep create mode 100644 skills/native/search_web_toolkit_skill/locales/en.json create mode 100644 skills/native/search_web_toolkit_skill/skill.json create mode 100644 skills/native/search_web_toolkit_skill/src/actions/search.ts create mode 100644 skills/native/search_web_toolkit_skill/src/settings.sample.json create mode 100644 skills/native/skill_writer_skill/locales/en.json create mode 100644 skills/native/skill_writer_skill/skill.json create mode 100644 skills/native/skill_writer_skill/src/actions/create_skill.ts create mode 100644 skills/native/skill_writer_skill/src/actions/modify_skill.ts create mode 100644 skills/native/skill_writer_skill/src/lib/skill-plan-llm.ts create mode 100644 skills/native/skill_writer_skill/src/lib/skill-plan.ts create mode 100644 skills/native/skill_writer_skill/src/lib/skill-prompt.ts create mode 100644 skills/native/skill_writer_skill/src/settings.sample.json create mode 100644 skills/native/speed_test_skill/locales/en.json create mode 100644 skills/native/speed_test_skill/locales/fr.json create mode 100644 skills/native/speed_test_skill/memory/.gitkeep create mode 100644 skills/native/speed_test_skill/skill.json create mode 100644 skills/native/speed_test_skill/src/actions/run.py create mode 100644 skills/native/speed_test_skill/src/lib/.gitkeep create mode 100644 skills/native/speed_test_skill/src/lib/speedtest.py create mode 100644 skills/native/speed_test_skill/src/settings.sample.json create mode 100644 skills/native/speed_test_skill/src/widgets/.gitkeep create mode 100644 skills/native/speed_test_skill/test/.gitkeep create mode 100644 skills/native/timer_skill/locales/en.json create mode 100644 skills/native/timer_skill/memory/.gitkeep create mode 100644 skills/native/timer_skill/skill.json create mode 100644 skills/native/timer_skill/src/actions/cancel_timer.ts create mode 100644 skills/native/timer_skill/src/actions/check_timer.ts create mode 100644 skills/native/timer_skill/src/actions/set_timer.ts create mode 100644 skills/native/timer_skill/src/lib/.gitkeep create mode 100644 skills/native/timer_skill/src/lib/memory.ts create mode 100644 skills/native/timer_skill/src/settings.sample.json create mode 100644 skills/native/timer_skill/src/widgets/.gitkeep create mode 100644 skills/native/timer_skill/src/widgets/components/timer.ts create mode 100644 skills/native/timer_skill/src/widgets/timer-widget.ts create mode 100644 skills/native/timer_skill/test/.gitkeep create mode 100644 skills/native/todo_list_skill/config/en.json create mode 100644 skills/native/todo_list_skill/config/fr.json create mode 100644 skills/native/todo_list_skill/locales/en.json create mode 100644 skills/native/todo_list_skill/memory/.gitkeep create mode 100644 skills/native/todo_list_skill/skill.json create mode 100644 skills/native/todo_list_skill/src/actions/add_todos.py create mode 100644 skills/native/todo_list_skill/src/actions/complete_items.py create mode 100644 skills/native/todo_list_skill/src/actions/create_list.py create mode 100644 skills/native/todo_list_skill/src/actions/delete_list.py create mode 100644 skills/native/todo_list_skill/src/actions/get_all_lists.py create mode 100644 skills/native/todo_list_skill/src/actions/get_list_items.py create mode 100644 skills/native/todo_list_skill/src/actions/rename_list.py create mode 100644 skills/native/todo_list_skill/src/actions/uncomplete_items.py create mode 100644 skills/native/todo_list_skill/src/lib/.gitkeep create mode 100644 skills/native/todo_list_skill/src/lib/memory.py create mode 100644 skills/native/todo_list_skill/src/settings.sample.json create mode 100644 skills/native/todo_list_skill/src/widgets/.gitkeep create mode 100644 skills/native/todo_list_skill/src/widgets/list_of_lists_widget.py create mode 100644 skills/native/todo_list_skill/src/widgets/todos_list_widget.py create mode 100644 skills/native/todo_list_skill/test/.gitkeep create mode 100644 skills/native/video_summarizer_skill/locales/en.json create mode 100644 skills/native/video_summarizer_skill/skill.json create mode 100644 skills/native/video_summarizer_skill/src/actions/prepare_audio.ts create mode 100644 skills/native/video_summarizer_skill/src/actions/summarize_transcription.ts create mode 100644 skills/native/video_summarizer_skill/src/settings.sample.json create mode 100644 skills/native/video_translator_skill/locales/en.json create mode 100644 skills/native/video_translator_skill/memory/.gitkeep create mode 100644 skills/native/video_translator_skill/skill.json create mode 100644 skills/native/video_translator_skill/src/actions/create_new_audio.ts create mode 100644 skills/native/video_translator_skill/src/actions/detect_genders.ts create mode 100644 skills/native/video_translator_skill/src/actions/download_video.ts create mode 100644 skills/native/video_translator_skill/src/actions/extract_audio.ts create mode 100644 skills/native/video_translator_skill/src/actions/get_speakers_references.ts create mode 100644 skills/native/video_translator_skill/src/actions/merge_audio.ts create mode 100644 skills/native/video_translator_skill/src/actions/translate_transcription.ts create mode 100644 skills/native/video_translator_skill/src/lib/memory.ts create mode 100644 skills/native/video_translator_skill/src/settings.sample.json create mode 100644 skills/native/video_translator_skill/src/widgets/download-progress-widget.ts create mode 100644 skills/native/voice_designer_skill/locales/en.json create mode 100644 skills/native/voice_designer_skill/skill.json create mode 100644 skills/native/voice_designer_skill/src/actions/design_and_speak.ts create mode 100644 skills/native/voice_designer_skill/src/settings.sample.json create mode 100644 skills/native/weather_forecast_skill/locales/en.json create mode 100644 skills/native/weather_forecast_skill/skill.json create mode 100644 skills/native/weather_forecast_skill/src/actions/get_forecast.ts create mode 100644 skills/native/weather_forecast_skill/src/settings.sample.json create mode 100644 skills/native/weather_forecast_skill/src/widgets/weather-forecast-widget.ts create mode 100644 skills/native/widget_playground_skill/locales/en.json create mode 100644 skills/native/widget_playground_skill/memory/.gitkeep create mode 100644 skills/native/widget_playground_skill/skill.json create mode 100644 skills/native/widget_playground_skill/src/actions/run.ts create mode 100644 skills/native/widget_playground_skill/src/lib/.gitkeep create mode 100644 skills/native/widget_playground_skill/src/settings.sample.json create mode 100644 skills/native/widget_playground_skill/src/widgets/.gitkeep create mode 100644 skills/native/widget_playground_skill/src/widgets/playground-test.ts create mode 100644 skills/native/widget_playground_skill/test/.gitkeep create mode 100644 skills/tsconfig.json create mode 100644 tcp_server/settings.json create mode 100644 tcp_server/src/lib/asr/api.py create mode 100644 tcp_server/src/lib/audio_input.py create mode 100644 tcp_server/src/lib/constants.py create mode 100644 tcp_server/src/lib/tcp_server.py create mode 100644 tcp_server/src/lib/tts/__init__.py create mode 100644 tcp_server/src/lib/tts/api.py create mode 100644 tcp_server/src/lib/tts/attentions.py create mode 100644 tcp_server/src/lib/tts/commons.py create mode 100644 tcp_server/src/lib/tts/models.py create mode 100644 tcp_server/src/lib/tts/modules.py create mode 100644 tcp_server/src/lib/tts/monotonic_align/__init__.py create mode 100644 tcp_server/src/lib/tts/monotonic_align/core.py create mode 100644 tcp_server/src/lib/tts/split_utils.py create mode 100644 tcp_server/src/lib/tts/text/__init__.py create mode 100644 tcp_server/src/lib/tts/text/cleaner.py create mode 100644 tcp_server/src/lib/tts/text/cleaner_multiling.py create mode 100644 tcp_server/src/lib/tts/text/cmudict.rep create mode 100644 tcp_server/src/lib/tts/text/cmudict_cache.pickle create mode 100644 tcp_server/src/lib/tts/text/english.py create mode 100644 tcp_server/src/lib/tts/text/english_bert.py create mode 100644 tcp_server/src/lib/tts/text/english_utils/__init__.py create mode 100644 tcp_server/src/lib/tts/text/english_utils/abbreviations.py create mode 100644 tcp_server/src/lib/tts/text/english_utils/number_norm.py create mode 100644 tcp_server/src/lib/tts/text/english_utils/time_norm.py create mode 100644 tcp_server/src/lib/tts/text/fr_phonemizer/__init__.py create mode 100644 tcp_server/src/lib/tts/text/fr_phonemizer/base.py create mode 100644 tcp_server/src/lib/tts/text/fr_phonemizer/cleaner.py create mode 100644 tcp_server/src/lib/tts/text/fr_phonemizer/en_symbols.json create mode 100644 tcp_server/src/lib/tts/text/fr_phonemizer/example_ipa.txt create mode 100644 tcp_server/src/lib/tts/text/fr_phonemizer/fr_symbols.json create mode 100644 tcp_server/src/lib/tts/text/fr_phonemizer/fr_to_ipa.py create mode 100644 tcp_server/src/lib/tts/text/fr_phonemizer/french_abbreviations.py create mode 100644 tcp_server/src/lib/tts/text/fr_phonemizer/french_symbols.txt create mode 100644 tcp_server/src/lib/tts/text/fr_phonemizer/gruut_wrapper.py create mode 100644 tcp_server/src/lib/tts/text/fr_phonemizer/punctuation.py create mode 100644 tcp_server/src/lib/tts/text/french.py create mode 100644 tcp_server/src/lib/tts/text/french_bert.py create mode 100644 tcp_server/src/lib/tts/text/opencpop-strict.txt create mode 100644 tcp_server/src/lib/tts/text/symbols.py create mode 100644 tcp_server/src/lib/tts/transforms.py create mode 100644 tcp_server/src/lib/tts/utils.py create mode 100644 tcp_server/src/lib/utils.py create mode 100644 tcp_server/src/lib/wake_word/api.py create mode 100644 tcp_server/src/main.py create mode 100644 tcp_server/src/pyproject.toml create mode 100644 tcp_server/src/version.py create mode 100644 test/agent/e2e/provider-matrix.ts create mode 100644 test/agent/e2e/react-provider-smoke.spec.ts create mode 100644 test/agent/e2e/run-agent-provider-scenario.ts create mode 100644 test/agent/unit/ai-sdk-remote-llm-provider.spec.ts create mode 100644 test/agent/unit/http-plugins.spec.ts create mode 100644 test/agent/unit/minimax-llm-provider.spec.ts create mode 100644 test/agent/unit/react-llm-duty.spec.ts create mode 100644 test/controlled/e2e/controlled-skill-smoke.spec.ts create mode 100644 test/controlled/unit/action-calling-llm-duty.spec.ts create mode 100644 test/controlled/unit/config.spec.ts create mode 100644 test/controlled/unit/json-redaction-helper.spec.ts create mode 100644 test/controlled/unit/nlu-controlled.spec.ts create mode 100644 test/controlled/unit/paraphrase-llm-duty.spec.ts create mode 100644 test/controlled/unit/profile-helper.spec.ts create mode 100644 test/controlled/unit/skill-router-llm-duty.spec.ts create mode 100644 test/controlled/unit/slot-filling-llm-duty.spec.ts create mode 100644 tools/business_finance/toolkit.json create mode 100644 tools/calendar_scheduling/toolkit.json create mode 100644 tools/coding_development/opencode/__init__.py create mode 100644 tools/coding_development/opencode/settings.sample.json create mode 100644 tools/coding_development/opencode/src/nodejs/index.ts create mode 100644 tools/coding_development/opencode/src/nodejs/lib/.gitkeep create mode 100644 tools/coding_development/opencode/src/nodejs/lib/prompt.md create mode 100644 tools/coding_development/opencode/src/nodejs/opencode-tool.ts create mode 100644 tools/coding_development/opencode/src/python/lib/.gitkeep create mode 100644 tools/coding_development/opencode/src/python/lib/prompt.md create mode 100644 tools/coding_development/opencode/src/python/opencode_tool.py create mode 100644 tools/coding_development/opencode/tool.json create mode 100644 tools/coding_development/toolkit.json create mode 100644 tools/communication/cerebras/__init__.py create mode 100644 tools/communication/cerebras/settings.sample.json create mode 100644 tools/communication/cerebras/src/nodejs/cerebras-tool.ts create mode 100644 tools/communication/cerebras/src/nodejs/index.ts create mode 100644 tools/communication/cerebras/src/nodejs/lib/.gitkeep create mode 100644 tools/communication/cerebras/src/python/cerebras_tool.py create mode 100644 tools/communication/cerebras/src/python/lib/.gitkeep create mode 100644 tools/communication/cerebras/tool.json create mode 100644 tools/communication/inference/__init__.py create mode 100644 tools/communication/inference/settings.sample.json create mode 100644 tools/communication/inference/src/nodejs/index.ts create mode 100644 tools/communication/inference/src/nodejs/inference-tool.ts create mode 100644 tools/communication/inference/src/python/inference_tool.py create mode 100644 tools/communication/inference/tool.json create mode 100644 tools/communication/openrouter/__init__.py create mode 100644 tools/communication/openrouter/settings.sample.json create mode 100644 tools/communication/openrouter/src/nodejs/index.ts create mode 100644 tools/communication/openrouter/src/nodejs/lib/.gitkeep create mode 100644 tools/communication/openrouter/src/nodejs/openrouter-tool.ts create mode 100644 tools/communication/openrouter/src/python/lib/.gitkeep create mode 100644 tools/communication/openrouter/src/python/openrouter_tool.py create mode 100644 tools/communication/openrouter/tool.json create mode 100644 tools/communication/toolkit.json create mode 100644 tools/dialog/toolkit.json create mode 100644 tools/file_system/toolkit.json create mode 100644 tools/food_drink/toolkit.json create mode 100644 tools/games/toolkit.json create mode 100644 tools/health_fitness/toolkit.json create mode 100644 tools/media_generation/toolkit.json create mode 100644 tools/movies_tv/toolkit.json create mode 100644 tools/music_audio/assemblyai_audio/__init__.py create mode 100644 tools/music_audio/assemblyai_audio/settings.sample.json create mode 100644 tools/music_audio/assemblyai_audio/src/nodejs/assemblyai_audio-tool.ts create mode 100644 tools/music_audio/assemblyai_audio/src/nodejs/index.ts create mode 100644 tools/music_audio/assemblyai_audio/src/nodejs/lib/.gitkeep create mode 100644 tools/music_audio/assemblyai_audio/src/python/assemblyai_audio_tool.py create mode 100644 tools/music_audio/assemblyai_audio/src/python/lib/.gitkeep create mode 100644 tools/music_audio/assemblyai_audio/tool.json create mode 100644 tools/music_audio/chatterbox_onnx/__init__.py create mode 100644 tools/music_audio/chatterbox_onnx/settings.sample.json create mode 100644 tools/music_audio/chatterbox_onnx/src/nodejs/chatterbox_onnx-tool.ts create mode 100644 tools/music_audio/chatterbox_onnx/src/nodejs/index.ts create mode 100644 tools/music_audio/chatterbox_onnx/src/nodejs/lib/.gitkeep create mode 100644 tools/music_audio/chatterbox_onnx/src/python/chatterbox_onnx_tool.py create mode 100644 tools/music_audio/chatterbox_onnx/src/python/lib/.gitkeep create mode 100644 tools/music_audio/chatterbox_onnx/tool.json create mode 100644 tools/music_audio/ecapa/__init__.py create mode 100644 tools/music_audio/ecapa/settings.sample.json create mode 100644 tools/music_audio/ecapa/src/nodejs/ecapa-tool.ts create mode 100644 tools/music_audio/ecapa/src/nodejs/index.ts create mode 100644 tools/music_audio/ecapa/src/nodejs/lib/.gitkeep create mode 100644 tools/music_audio/ecapa/src/python/ecapa_tool.py create mode 100644 tools/music_audio/ecapa/src/python/lib/.gitkeep create mode 100644 tools/music_audio/ecapa/tool.json create mode 100644 tools/music_audio/elevenlabs_audio/__init__.py create mode 100644 tools/music_audio/elevenlabs_audio/settings.sample.json create mode 100644 tools/music_audio/elevenlabs_audio/src/nodejs/elevenlabs_audio-tool.ts create mode 100644 tools/music_audio/elevenlabs_audio/src/nodejs/index.ts create mode 100644 tools/music_audio/elevenlabs_audio/src/nodejs/lib/.gitkeep create mode 100644 tools/music_audio/elevenlabs_audio/src/python/elevenlabs_audio_tool.py create mode 100644 tools/music_audio/elevenlabs_audio/src/python/lib/.gitkeep create mode 100644 tools/music_audio/elevenlabs_audio/tool.json create mode 100644 tools/music_audio/faster_whisper/__init__.py create mode 100644 tools/music_audio/faster_whisper/settings.sample.json create mode 100644 tools/music_audio/faster_whisper/src/nodejs/faster_whisper-tool.ts create mode 100644 tools/music_audio/faster_whisper/src/nodejs/index.ts create mode 100644 tools/music_audio/faster_whisper/src/nodejs/lib/.gitkeep create mode 100644 tools/music_audio/faster_whisper/src/python/faster_whisper_tool.py create mode 100644 tools/music_audio/faster_whisper/src/python/lib/.gitkeep create mode 100644 tools/music_audio/faster_whisper/tool.json create mode 100644 tools/music_audio/openai_audio/__init__.py create mode 100644 tools/music_audio/openai_audio/settings.sample.json create mode 100644 tools/music_audio/openai_audio/src/nodejs/index.ts create mode 100644 tools/music_audio/openai_audio/src/nodejs/lib/.gitkeep create mode 100644 tools/music_audio/openai_audio/src/nodejs/openai_audio-tool.ts create mode 100644 tools/music_audio/openai_audio/src/python/lib/.gitkeep create mode 100644 tools/music_audio/openai_audio/src/python/openai_audio_tool.py create mode 100644 tools/music_audio/openai_audio/tool.json create mode 100644 tools/music_audio/qwen3_asr/__init__.py create mode 100644 tools/music_audio/qwen3_asr/settings.sample.json create mode 100644 tools/music_audio/qwen3_asr/src/nodejs/index.ts create mode 100644 tools/music_audio/qwen3_asr/src/nodejs/lib/.gitkeep create mode 100644 tools/music_audio/qwen3_asr/src/nodejs/qwen3_asr-tool.ts create mode 100644 tools/music_audio/qwen3_asr/src/python/lib/.gitkeep create mode 100644 tools/music_audio/qwen3_asr/src/python/qwen3_asr_tool.py create mode 100644 tools/music_audio/qwen3_asr/tool.json create mode 100644 tools/music_audio/qwen3_tts/__init__.py create mode 100644 tools/music_audio/qwen3_tts/settings.sample.json create mode 100644 tools/music_audio/qwen3_tts/src/nodejs/index.ts create mode 100644 tools/music_audio/qwen3_tts/src/nodejs/lib/.gitkeep create mode 100644 tools/music_audio/qwen3_tts/src/nodejs/qwen3_tts-tool.ts create mode 100644 tools/music_audio/qwen3_tts/src/python/lib/.gitkeep create mode 100644 tools/music_audio/qwen3_tts/src/python/qwen3_tts_tool.py create mode 100644 tools/music_audio/qwen3_tts/tool.json create mode 100644 tools/music_audio/toolkit.json create mode 100644 tools/music_audio/transcription-schema.ts create mode 100644 tools/music_audio/transcription_schema.py create mode 100644 tools/music_audio/ultimate_vocal_remover_onnx/__init__.py create mode 100644 tools/music_audio/ultimate_vocal_remover_onnx/settings.sample.json create mode 100644 tools/music_audio/ultimate_vocal_remover_onnx/src/nodejs/index.ts create mode 100644 tools/music_audio/ultimate_vocal_remover_onnx/src/nodejs/lib/.gitkeep create mode 100644 tools/music_audio/ultimate_vocal_remover_onnx/src/nodejs/ultimate_vocal_remover_onnx-tool.ts create mode 100644 tools/music_audio/ultimate_vocal_remover_onnx/src/python/lib/.gitkeep create mode 100644 tools/music_audio/ultimate_vocal_remover_onnx/src/python/ultimate_vocal_remover_onnx_tool.py create mode 100644 tools/music_audio/ultimate_vocal_remover_onnx/tool.json create mode 100644 tools/news/toolkit.json create mode 100644 tools/operating_system_control/file/settings.sample.json create mode 100644 tools/operating_system_control/file/src/nodejs/file-tool.ts create mode 100644 tools/operating_system_control/file/src/nodejs/index.ts create mode 100644 tools/operating_system_control/file/tool.json create mode 100644 tools/operating_system_control/shell/__init__.py create mode 100644 tools/operating_system_control/shell/settings.sample.json create mode 100644 tools/operating_system_control/shell/src/nodejs/index.ts create mode 100644 tools/operating_system_control/shell/src/nodejs/lib/.gitkeep create mode 100644 tools/operating_system_control/shell/src/nodejs/shell-tool.ts create mode 100644 tools/operating_system_control/shell/src/python/lib/.gitkeep create mode 100644 tools/operating_system_control/shell/src/python/shell_tool.py create mode 100644 tools/operating_system_control/shell/tool.json create mode 100644 tools/operating_system_control/toolkit.json create mode 100644 tools/productivity_collaboration/toolkit.json create mode 100644 tools/search_web/grok/__init__.py create mode 100644 tools/search_web/grok/settings.sample.json create mode 100644 tools/search_web/grok/src/nodejs/grok-tool.ts create mode 100644 tools/search_web/grok/src/nodejs/index.ts create mode 100644 tools/search_web/grok/src/nodejs/lib/.gitkeep create mode 100644 tools/search_web/grok/src/python/grok_tool.py create mode 100644 tools/search_web/grok/src/python/lib/.gitkeep create mode 100644 tools/search_web/grok/tool.json create mode 100644 tools/search_web/hosted/__init__.py create mode 100644 tools/search_web/hosted/settings.sample.json create mode 100644 tools/search_web/hosted/src/nodejs/hosted-tool.ts create mode 100644 tools/search_web/hosted/src/nodejs/index.ts create mode 100644 tools/search_web/hosted/tool.json create mode 100644 tools/search_web/toolkit.json create mode 100644 tools/shopping/toolkit.json create mode 100644 tools/smart_home/toolkit.json create mode 100644 tools/social_media/toolkit.json create mode 100644 tools/sport/toolkit.json create mode 100644 tools/structured_knowledge/context/settings.sample.json create mode 100644 tools/structured_knowledge/context/src/nodejs/context-tool.ts create mode 100644 tools/structured_knowledge/context/src/nodejs/index.ts create mode 100644 tools/structured_knowledge/context/tool.json create mode 100644 tools/structured_knowledge/memory/settings.sample.json create mode 100644 tools/structured_knowledge/memory/src/nodejs/index.ts create mode 100644 tools/structured_knowledge/memory/src/nodejs/memory-tool.ts create mode 100644 tools/structured_knowledge/memory/tool.json create mode 100644 tools/structured_knowledge/toolkit.json create mode 100644 tools/system_utilities/toolkit.json create mode 100644 tools/travel_transportation/toolkit.json create mode 100644 tools/tsconfig.json create mode 100644 tools/video_streaming/ffmpeg/__init__.py create mode 100644 tools/video_streaming/ffmpeg/settings.sample.json create mode 100644 tools/video_streaming/ffmpeg/src/nodejs/ffmpeg-tool.ts create mode 100644 tools/video_streaming/ffmpeg/src/nodejs/index.ts create mode 100644 tools/video_streaming/ffmpeg/src/nodejs/lib/.gitkeep create mode 100644 tools/video_streaming/ffmpeg/src/python/ffmpeg_tool.py create mode 100644 tools/video_streaming/ffmpeg/src/python/lib/.gitkeep create mode 100644 tools/video_streaming/ffmpeg/tool.json create mode 100644 tools/video_streaming/ffprobe/__init__.py create mode 100644 tools/video_streaming/ffprobe/settings.sample.json create mode 100644 tools/video_streaming/ffprobe/src/nodejs/ffprobe-tool.ts create mode 100644 tools/video_streaming/ffprobe/src/nodejs/index.ts create mode 100644 tools/video_streaming/ffprobe/src/nodejs/lib/.gitkeep create mode 100644 tools/video_streaming/ffprobe/src/python/ffprobe_tool.py create mode 100644 tools/video_streaming/ffprobe/src/python/lib/.gitkeep create mode 100644 tools/video_streaming/ffprobe/tool.json create mode 100644 tools/video_streaming/toolkit.json create mode 100644 tools/video_streaming/ytdlp/__init__.py create mode 100644 tools/video_streaming/ytdlp/settings.sample.json create mode 100644 tools/video_streaming/ytdlp/src/nodejs/index.ts create mode 100644 tools/video_streaming/ytdlp/src/nodejs/lib/.gitkeep create mode 100644 tools/video_streaming/ytdlp/src/nodejs/yt-dlp.conf create mode 100644 tools/video_streaming/ytdlp/src/nodejs/ytdlp-tool.ts create mode 100644 tools/video_streaming/ytdlp/src/python/lib/.gitkeep create mode 100644 tools/video_streaming/ytdlp/src/python/yt-dlp.conf create mode 100644 tools/video_streaming/ytdlp/src/python/ytdlp_tool.py create mode 100644 tools/video_streaming/ytdlp/tool.json create mode 100644 tools/weather/openmeteo/__init__.py create mode 100644 tools/weather/openmeteo/settings.sample.json create mode 100644 tools/weather/openmeteo/src/nodejs/index.ts create mode 100644 tools/weather/openmeteo/src/nodejs/lib/.gitkeep create mode 100644 tools/weather/openmeteo/src/nodejs/open-meteo-tool.ts create mode 100644 tools/weather/openmeteo/src/python/lib/.gitkeep create mode 100644 tools/weather/openmeteo/src/python/open_meteo_tool.py create mode 100644 tools/weather/openmeteo/tool.json create mode 100644 tools/weather/toolkit.json create mode 100644 tsconfig.json create mode 100644 vitest.config.ts create mode 100644 web-app/index.html create mode 100644 web-app/public/img/favicon.png create mode 100644 web-app/public/img/logo-color-text.svg create mode 100644 web-app/public/img/logo-color.svg create mode 100644 web-app/public/img/logo-for-dark-bg-text.svg create mode 100644 web-app/public/img/logo-for-dark-bg.svg create mode 100644 web-app/public/img/logo-for-light-bg-text.svg create mode 100644 web-app/public/img/logo-for-light-bg.svg create mode 100644 web-app/src/components/badge/badge.sass create mode 100644 web-app/src/components/badge/badge.tsx create mode 100644 web-app/src/components/badge/index.ts create mode 100644 web-app/src/components/button/button.sass create mode 100644 web-app/src/components/button/button.tsx create mode 100644 web-app/src/components/button/index.ts create mode 100644 web-app/src/components/dialog/dialog.sass create mode 100644 web-app/src/components/dialog/dialog.tsx create mode 100644 web-app/src/components/dialog/index.ts create mode 100644 web-app/src/components/dropdown/dropdown.sass create mode 100644 web-app/src/components/dropdown/dropdown.tsx create mode 100644 web-app/src/components/dropdown/index.ts create mode 100644 web-app/src/components/feed/feed.sass create mode 100644 web-app/src/components/feed/feed.tsx create mode 100644 web-app/src/components/feed/index.ts create mode 100644 web-app/src/components/input/index.ts create mode 100644 web-app/src/components/input/input.sass create mode 100644 web-app/src/components/input/input.tsx create mode 100644 web-app/src/components/leon-message/index.ts create mode 100644 web-app/src/components/leon-message/leon-message.sass create mode 100644 web-app/src/components/leon-message/leon-message.tsx create mode 100644 web-app/src/components/markdown-content/index.ts create mode 100644 web-app/src/components/markdown-content/markdown-content.sass create mode 100644 web-app/src/components/markdown-content/markdown-content.tsx create mode 100644 web-app/src/components/message/index.ts create mode 100644 web-app/src/components/message/message.sass create mode 100644 web-app/src/components/message/message.tsx create mode 100644 web-app/src/components/owner-message/index.ts create mode 100644 web-app/src/components/owner-message/owner-message.sass create mode 100644 web-app/src/components/owner-message/owner-message.tsx create mode 100644 web-app/src/components/query-input/index.ts create mode 100644 web-app/src/components/query-input/query-input.sass create mode 100644 web-app/src/components/query-input/query-input.tsx create mode 100644 web-app/src/components/search-sessions-dialog/index.ts create mode 100644 web-app/src/components/search-sessions-dialog/search-sessions-dialog.sass create mode 100644 web-app/src/components/search-sessions-dialog/search-sessions-dialog.tsx create mode 100644 web-app/src/components/shortcut/index.ts create mode 100644 web-app/src/components/shortcut/shortcut.sass create mode 100644 web-app/src/components/shortcut/shortcut.tsx create mode 100644 web-app/src/components/task-list-item/index.ts create mode 100644 web-app/src/components/task-list-item/task-list-item.sass create mode 100644 web-app/src/components/task-list-item/task-list-item.tsx create mode 100644 web-app/src/components/task-list/index.ts create mode 100644 web-app/src/components/task-list/task-list.sass create mode 100644 web-app/src/components/task-list/task-list.tsx create mode 100644 web-app/src/components/thinking-message/index.ts create mode 100644 web-app/src/components/thinking-message/thinking-message.sass create mode 100644 web-app/src/components/thinking-message/thinking-message.tsx create mode 100644 web-app/src/components/toast/index.ts create mode 100644 web-app/src/components/toast/toast.sass create mode 100644 web-app/src/components/toast/toast.tsx create mode 100644 web-app/src/components/tool-call/index.ts create mode 100644 web-app/src/components/tool-call/tool-call.sass create mode 100644 web-app/src/components/tool-call/tool-call.tsx create mode 100644 web-app/src/components/tooltip/index.ts create mode 100644 web-app/src/components/tooltip/tooltip.sass create mode 100644 web-app/src/components/tooltip/tooltip.tsx create mode 100644 web-app/src/components/vibes/index.ts create mode 100644 web-app/src/components/vibes/vibes.sass create mode 100644 web-app/src/components/vibes/vibes.tsx create mode 100644 web-app/src/data/sessions.json create mode 100644 web-app/src/data/sessions.ts create mode 100644 web-app/src/layout/app-layout/app-layout.sass create mode 100644 web-app/src/layout/app-layout/app-layout.tsx create mode 100644 web-app/src/layout/app-layout/index.ts create mode 100644 web-app/src/layout/sidebar/index.ts create mode 100644 web-app/src/layout/sidebar/logo/index.ts create mode 100644 web-app/src/layout/sidebar/logo/logo.sass create mode 100644 web-app/src/layout/sidebar/logo/logo.tsx create mode 100644 web-app/src/layout/sidebar/menu-item/index.ts create mode 100644 web-app/src/layout/sidebar/menu-item/menu-item.sass create mode 100644 web-app/src/layout/sidebar/menu-item/menu-item.tsx create mode 100644 web-app/src/layout/sidebar/menu/index.ts create mode 100644 web-app/src/layout/sidebar/menu/menu.sass create mode 100644 web-app/src/layout/sidebar/menu/menu.tsx create mode 100644 web-app/src/layout/sidebar/session-list-item/index.ts create mode 100644 web-app/src/layout/sidebar/session-list-item/session-list-item.sass create mode 100644 web-app/src/layout/sidebar/session-list-item/session-list-item.tsx create mode 100644 web-app/src/layout/sidebar/session-list/index.ts create mode 100644 web-app/src/layout/sidebar/session-list/session-list.sass create mode 100644 web-app/src/layout/sidebar/session-list/session-list.tsx create mode 100644 web-app/src/layout/sidebar/session-search/index.ts create mode 100644 web-app/src/layout/sidebar/session-search/session-search.sass create mode 100644 web-app/src/layout/sidebar/session-search/session-search.tsx create mode 100644 web-app/src/layout/sidebar/sidebar-footer/index.ts create mode 100644 web-app/src/layout/sidebar/sidebar-footer/sidebar-footer.sass create mode 100644 web-app/src/layout/sidebar/sidebar-footer/sidebar-footer.tsx create mode 100644 web-app/src/layout/sidebar/sidebar.sass create mode 100644 web-app/src/layout/sidebar/sidebar.tsx create mode 100644 web-app/src/main.tsx create mode 100644 web-app/src/query-client.ts create mode 100644 web-app/src/router.tsx create mode 100644 web-app/src/routes/home-route.tsx create mode 100644 web-app/src/styles/_includes/reset.sass create mode 100644 web-app/src/styles/_includes/themes.sass create mode 100644 web-app/src/styles/_includes/variables.sass create mode 100644 web-app/src/styles/main.sass create mode 100644 web-app/src/theme.ts create mode 100644 web-app/tsconfig.json create mode 100644 web-app/vite.config.ts diff --git a/.changelogrc b/.changelogrc new file mode 100644 index 0000000..3f2db1d --- /dev/null +++ b/.changelogrc @@ -0,0 +1,25 @@ +{ + "app_name": "Leon", + "sections": [ + { + "title": "BREAKING CHANGES", + "grep": "BREAKING" + }, + { + "title": "Features", + "grep": "^feat" + }, + { + "title": "Bug Fixes", + "grep": "^fix" + }, + { + "title": "Performance Improvements", + "grep": "^perf" + }, + { + "title": "Documentation Changes", + "grep": "^docs" + } + ] +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ac3a4a1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +end_of_line = lf +insert_final_newline = true + +[*.py] +indent_size = 4 diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..c5a0109 --- /dev/null +++ b/.env.sample @@ -0,0 +1,45 @@ +# Leon profile secrets. +# Non-secret profile configuration lives in config.yml. + +# LLM provider API keys + +# Optional local llama.cpp API key +LEON_LLAMACPP_API_KEY= + +# Optional Linux high-performance local provider API key (OpenAI-compatible) +LEON_SGLANG_API_KEY= + +# OpenRouter API key +LEON_OPENROUTER_API_KEY= + +# Z.AI API key +LEON_ZAI_API_KEY= + +# MiniMax API key +LEON_MINIMAX_API_KEY= + +# OpenAI API key +LEON_OPENAI_API_KEY= + +# Anthropic API key +LEON_ANTHROPIC_API_KEY= + +# Moonshot AI API key +LEON_MOONSHOTAI_API_KEY= + +# HuggingFace API key +LEON_HUGGINGFACE_API_KEY= + +# Cerebras API key +LEON_CEREBRAS_API_KEY= + +# Groq API key +LEON_GROQ_API_KEY= + +# Misc + +# Optional token required by LeonClientInterface when client_interface.auth.enabled=true +LEON_CLIENT_INTERFACE_TOKEN= + +# Optional token required by HTTP plugins when http_plugins.auth.enabled=true +LEON_HTTP_PLUGIN_TOKEN= diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..07ec84a --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at . All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..2641e77 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,197 @@ +# Contributing + +Thanks a lot for your interest in contributing to Leon! :heart: + +**Leon needs open source to live**, the more skills he has, the more skillful he becomes. + +**Before submitting your contribution**, please take a moment to review this document. + +Please note we have a [code of conduct](https://github.com/leon-ai/leon/blob/develop/.github/CODE_OF_CONDUCT.md), please follow it in all your interactions with the project. + +## How You Can Help + +Here are few examples about how you could help on Leon, by: + +- [Creating a new module](https://docs.getleon.ai/packages-modules). +- [Working on new features](http://roadmap.getleon.ai) (what is in backlog or todo). +- [Suggesting new ideas](https://github.com/leon-ai/leon/issues/new/choose). +- [Reporting a bug](https://github.com/leon-ai/leon/issues/new?labels=bug&template=BUG.md). +- [Improving the documentation](https://github.com/leon-ai/docs.getleon.ai) (translations, typos, better writing, etc.). +- [Sponsoring Leon](http://sponsor.getleon.ai). + +## Pull Requests + +**Working on your first Pull Request?** You can learn how from this _free_ series [How to Contribute to an Open Source Project on GitHub](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github). + +- **Please first discuss** the change you wish to make via [issue](https://github.com/leon-ai/leon/issues), + email, or any other method with the owners of this repository before making a change. + It might avoid a waste of your time. + +- The `master` branch is actually used as a snapshot of the latest stable release. **Do not submit your PRs + against the `master` branch**. + +- Ensure your code **respect our coding standards** (cf. [.eslintrc.json](https://github.com/leon-ai/leon/blob/develop/.eslintrc.json)). + To do so, you can run: + + ```sh + pnpm run lint + ``` + +- Make sure your **code passes the tests**. You can run the tests via the following command: + + ```sh + npm test + ``` + + If you're adding new features to Leon, please include tests. + +## Development Setup + +Choose the setup method you want to go for. + +### Single-Click + +Gitpod will automatically set up an environment and run an instance for you. + +[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/leon-ai/leon) + +### Basic + +```sh +# Clone the repository +git clone https://github.com/leon-ai/leon.git leon + +# Go to the project root +cd leon + +# Install +pnpm install + +# Check the setup went well +pnpm run check + +# Run the development server +pnpm run dev:server + +# Run the development web app +pnpm run dev:app +``` + +## Versioning + +- We use [Semantic Versioning](https://semver.org) for releases. + +## Commits + +The commit message guideline is adapted from the [AngularJS Git Commit Guidelines](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines). + +### Types + +Types define which kind of changes you made to the project. + +| Types | Description | +| -------- | -------------------------------------------------------------------------------------------------------- | +| BREAKING | Changes including breaking changes. | +| build | New build version. | +| chore | Changes to the build process or auxiliary tools such as changelog generation. No production code change. | +| ci | Changes related to continuous integration only (GitHub Actions, CircleCI, etc.). | +| docs | Documentation only changes. | +| feat | A new feature. | +| fix | A bug fix. | +| perf | A code change that improves performance. | +| refactor | A code change that neither fixes a bug nor adds a feature. | +| style | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.). | +| test | Adding missing or correcting existing tests. | + +### Scopes + +Scopes define high-level nodes of Leon. + +- bridge/python +- bridge/nodejs +- hotword +- scripts +- server +- tcp server +- web app +- skill/skill_name + +### Examples + +```sh +git commit -m "feat(server): awesome new server feature" +git commit -m "docs(skill/leon): fix spelling" +git commit -m "chore: split training script into awesome blocks" +git commit -m "style(web app): remove chatbot useless parentheses" +``` + +### GUI Clients + +If you are using a GUI client such as GitKraken, you may need to disable the default Git executable to make sure to use your default shell. +Otherwise you may encounter an error such as "npx not found". + +## Sponsor + +You can also contribute by [sponsoring Leon](http://sponsor.getleon.ai). + +Please note that I dedicate most of my free time to Leon. + +By sponsoring the project you make the project sustainable and faster to develop features. + +The focus is not only limited to the activity you see on GitHub but also a lot of thinking about the direction of the project. Which is naturally related to the overall design, architecture, vision, learning process and so on... + +## Contributing to the Python Bridge or TCP HttpServer + +Leon makes use of two binaries, the Python bridge and the TCP server. These binaries are compiled from Python sources. + +The Python bridge is used to communicate between the core and skills made with Python. + +The TCP server is used to communicate between the core and third-party nodes, such as spaCy. + +### Set Up the Python Environment + +To contribute to these parts, you need to set up a Python environment running with a specific Python version and a specific Pipenv version. + +It is recommended to use Pyenv to manage your Python versions. + +If you are on GNU/Linux Ubuntu, you can run the following to install Pyenv, otherwise, please refer to the [Pyenv documentation to install it](https://github.com/pyenv/pyenv#installation): + +```bash +# Update registry +sudo apt-get update + +# Install Pyenv deps +sudo apt-get install make build-essential libssl-dev zlib1g-dev \ +libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \ +libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev + +# Install Pyenv +curl https://pyenv.run | bash + +# Add output lines to .bashrc + +# Restart shell +exec "$SHELL" +``` + +Once Pyenv installed, run: + +```bash +# Install Python +pyenv install 3.11.9 --force +pyenv global 3.11.9 +``` + +Your Python environment should be ready now. Leon uses `uv` as the Python dependency standard, and `postinstall` provisions the Python bridge and TCP server environments automatically from `pyproject.toml`: + +```bash +# Run the Python bridge +npm run python-bridge + +# Run the TCP server +npm run start:tcp-server +``` + +## Spread the Word + +Use [#LeonAI]() if you tweet about Leon and/or mention [@grenlouis](https://twitter.com/grenlouis). diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..7a12ea6 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,8 @@ +# These are supported funding model platforms + +github: [louistiti] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +custom: # http://sponsor.getleon.ai diff --git a/.github/ISSUE_TEMPLATE/BUG.md b/.github/ISSUE_TEMPLATE/BUG.md new file mode 100644 index 0000000..ca1f5db --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG.md @@ -0,0 +1,27 @@ +--- +name: 🐞 Bug Report +about: Report an unexpected problem or unintended behavior. +labels: bug +--- + + + +### Specs + +- Leon version: +- OS (or browser) version: +- Node.js version: +- Complete "leon check" (or "pnpm run check") output: +- (optional) Leon skill version: + +### Expected Behavior + +### Actual Behavior + +### How Do We Reproduce? + +### Extra (like a sample repo to reproduce the issue, etc.) diff --git a/.github/ISSUE_TEMPLATE/DOCS.md b/.github/ISSUE_TEMPLATE/DOCS.md new file mode 100644 index 0000000..8f1800b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/DOCS.md @@ -0,0 +1,23 @@ +--- +name: 📝 Documentation +about: Are the docs missing, confusing, etc.? Tell us more about it. +--- + + + +### Documentation Is: + +- [ ] Missing +- [ ] Needed +- [ ] Confusing +- [ ] Not Sure? + +### Explanation + +### Proposal diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md new file mode 100644 index 0000000..ebf304c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md @@ -0,0 +1,14 @@ +--- +name: ✨ Feature Request +about: Suggest a new feature idea. +labels: feature request +--- + + + +### Feature Use Case + +### Feature Proposal diff --git a/.github/ISSUE_TEMPLATE/IMPROVEMENT.md b/.github/ISSUE_TEMPLATE/IMPROVEMENT.md new file mode 100644 index 0000000..362140b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/IMPROVEMENT.md @@ -0,0 +1,16 @@ +--- +name: 🔧 Improvement +about: Suggest an idea which is not a feature. +labels: improvement +--- + + + +### Expected Behavior + +### Actual Behavior + +### Proposal diff --git a/.github/ISSUE_TEMPLATE/QUESTION.md b/.github/ISSUE_TEMPLATE/QUESTION.md new file mode 100644 index 0000000..1e32379 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/QUESTION.md @@ -0,0 +1,14 @@ +--- +name: ❓ Question +about: Ask a question about Leon. +labels: question +--- + + + +### Question diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..3b6342e --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,31 @@ + + +### What type of change does this PR introduce? + +- [ ] Bugfix +- [ ] Feature +- [ ] Refactor +- [ ] Documentation +- [ ] Not Sure? + +### Does this PR introduce breaking changes? + +- [ ] Yes +- [ ] No + +### List any relevant issue numbers: + +### Description: diff --git a/.github/assets/thanks/jetbrains-mono-black.svg b/.github/assets/thanks/jetbrains-mono-black.svg new file mode 100644 index 0000000..778d2bb --- /dev/null +++ b/.github/assets/thanks/jetbrains-mono-black.svg @@ -0,0 +1,4 @@ + + + + diff --git a/.github/assets/thanks/jetbrains-mono-white.svg b/.github/assets/thanks/jetbrains-mono-white.svg new file mode 100644 index 0000000..1381f6d --- /dev/null +++ b/.github/assets/thanks/jetbrains-mono-white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/.github/assets/thanks/macstadium-logo-dark-mode.svg b/.github/assets/thanks/macstadium-logo-dark-mode.svg new file mode 100644 index 0000000..6239d29 --- /dev/null +++ b/.github/assets/thanks/macstadium-logo-dark-mode.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/assets/thanks/macstadium-logo-light-mode.svg b/.github/assets/thanks/macstadium-logo-light-mode.svg new file mode 100644 index 0000000..7806548 --- /dev/null +++ b/.github/assets/thanks/macstadium-logo-light-mode.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/assets/thanks/openai-logo-dark-mode.svg b/.github/assets/thanks/openai-logo-dark-mode.svg new file mode 100644 index 0000000..cc4616c --- /dev/null +++ b/.github/assets/thanks/openai-logo-dark-mode.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/.github/assets/thanks/openai-logo-light-mode.svg b/.github/assets/thanks/openai-logo-light-mode.svg new file mode 100644 index 0000000..87ab03e --- /dev/null +++ b/.github/assets/thanks/openai-logo-light-mode.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..f0026c9 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,39 @@ +name: Build + +on: + push: + # branches: [master, develop] + branches: [master] + pull_request: + # branches: [master, develop] + branches: [master] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Use Python + uses: actions/setup-python@v2 + with: + python-version: 3.x + + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: 24.x + cache: pnpm + + - name: Enable Corepack + run: corepack enable + + - name: Install + run: pnpm install + + - name: Check setup + run: pnpm run check + + - name: Build + run: pnpm run build diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..cb1812c --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,36 @@ +name: Lint + +on: + push: + # branches: [master, develop] + branches: [master] + pull_request: + # branches: [master, develop] + branches: [master] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Use Python + uses: actions/setup-python@v2 + with: + python-version: 3.x + + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: 24.x + cache: pnpm + + - name: Enable Corepack + run: corepack enable + + - name: Install + run: pnpm install + + - name: Run linter + run: pnpm run lint diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..6b9fcd7 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,42 @@ +name: Tests + +on: + push: + # branches: [master, develop] + branches: [master] + pull_request: + # branches: [master, develop] + branches: [master] + +jobs: + tests: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Use Python + uses: actions/setup-python@v2 + with: + python-version: 3.x + + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: 24.x + cache: pnpm + + - name: Enable Corepack + run: corepack enable + + - name: Install + run: pnpm install + + - name: Run agent unit tests + run: pnpm run test:agent:unit + + - name: Run workflow unit tests + run: pnpm run test:workflow:unit + + - name: Run workflow e2e tests + run: pnpm run test:workflow:e2e diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6361a44 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +__pycache__/ +.idea/ +.fleet/ +.vscode/ +**/dist/* +**/build/ +**/node_modules/ +**/.venv/ +**/.last-skill-deps-sync +**/.last-source-deps-sync +skills/**/reports/* +test/coverage/ +**/tmp/* +core/config/**/*.json +scripts/out/*.md + +package-lock.json +*.pyc +.DS_Store +*.sublime-workspace +npm-debug.log +debug.log +# Keep ignoring a repo-root .env on the safe side. +.env +.last-native-node-modules-rebuild +bridges/nodejs/.last-nodejs-bridge-deps-sync +bridges/python/src/.last-python-bridge-deps-sync +tcp_server/src/.last-tcp-server-deps-sync +bridges/python/src/Pipfile.lock +tcp_server/src/Pipfile.lock +!bridges/python/**/.gitkeep +!bridges/nodejs/**/.gitkeep +!**/*.sample* +package.json.backup +.python-version +schemas/**/*.json diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..71d4290 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,19 @@ +image: gitpod/workspace-full + +tasks: + - before: npm install -g @leon-ai/cli + init: leon create birth + command: leon start + +ports: + - port: 1337 + onOpen: notify + +github: + prebuilds: + master: true + branches: true + pullRequests: true + addComment: true + addBadge: true + addLabel: true diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..39e63b7 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1 @@ +tsx scripts/commit-msg.js diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..c27d889 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +lint-staged diff --git a/.lintstagedrc b/.lintstagedrc new file mode 100644 index 0000000..2633255 --- /dev/null +++ b/.lintstagedrc @@ -0,0 +1,3 @@ +{ + "*.{js,jsx,ts,tsx,mjs,cjs}": ["eslint --fix --ignore-pattern .gitignore"] +} diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..b009dfb --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +lts/* diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..94491b3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,362 @@ +# [1.0.0-beta.8](https://github.com/leon-ai/leon/compare/v1.0.0-beta.7...v1.0.0-beta.8) (2023-05-01) / Binaries and TypeScript Rewrite + +_Please refer to [our latest blog post](https://blog.getleon.ai/binaries-and-typescript-rewrite-1-0-0-beta-8/) for more information on the new release of our dear Leon._ + +# [1.0.0-beta.7](https://github.com/leon-ai/leon/compare/v1.0.0-beta.6...v1.0.0-beta.7) (2022-08-24) / A Much Better NLP + +_Please [read this blog post](https://blog.getleon.ai/a-much-better-nlp-and-future-1-0-0-beta-7/) to know more about all the new features and the exciting future of Leon._ + +### BREAKING CHANGES + +- remove legacy packages [07743657](https://github.com/leon-ai/leon/commit/07743657cd2954e7f850c08eea7c032c24b28a96) + +### Features + +- create new NLP skills resolvers model + NLP global resolvers model [602604e4](https://github.com/leon-ai/leon/commit/602604e43788c6b6be8c402d54fe54342d0cd5d6) +- better isolate skill resolvers from global resolvers + finish up Akinator skill [905d248e](https://github.com/leon-ai/leon/commit/905d248ebf7e84b1ccc74450520228aef9a8804a) +- transfer language from core to skills + support thematics on Akinator skill [b35a249b](https://github.com/leon-ai/leon/commit/b35a249bf68000d6708aaee4abc4cd97f5b80035) +- actions on slot level + akinator skill progress [7101b8b4](https://github.com/leon-ai/leon/commit/7101b8b4b828b49e009da2fcdac7c5ed2e48c8f8) +- add Cartesian sample training on resolvers + enum entities [6ed88a59](https://github.com/leon-ai/leon/commit/6ed88a5946c77b356e49fe8b9cbe890b8dd1f037) +- map skills resolvers intents [eb5ade76](https://github.com/leon-ai/leon/commit/eb5ade76844dd14f5d5a5c5eeb434eed70fe62f4) +- train skills resolvers and remap as per changes [82df0a3c](https://github.com/leon-ai/leon/commit/82df0a3c235fbd50ad0cfe12e23a51f777dcd658) +- achieve Cartesian training [a1e9011d](https://github.com/leon-ai/leon/commit/a1e9011d5db48ed8e9f49cef2d813ee7e2400ec2) +- introduce suggestions [dcddacca](https://github.com/leon-ai/leon/commit/dcddacca2956529de0aea8ff98e1e6f16104966a) +- communicate suggestions to the client [4b5a8835](https://github.com/leon-ai/leon/commit/4b5a883510fd4421a491f999cc21d8f7dd369a03) +- shared skills memory [795acc5b](https://github.com/leon-ai/leon/commit/795acc5bdd29e9a27d1cf3b4407453648d573973) +- support dynamic variables on skill NLU settings for logic type [10d10a16](https://github.com/leon-ai/leon/commit/10d10a1690cb65970932ee7230e3f324ec67dbce) +- tmp resolvers mapping [b1a332ba](https://github.com/leon-ai/leon/commit/b1a332bab6af8b74a8c58c07bac3ef3a1cebad89) +- start to map resolvers between the core and skills [e88495a9](https://github.com/leon-ai/leon/commit/e88495a9a94e86026fd0c7c4c44f3ff06edb2e80) +- train affirmation and denial resolver [993d52e8](https://github.com/leon-ai/leon/commit/993d52e8686f335039ff3d5e2a82c1a37efb1825) +- Python TCP server and Node.js TCP client for IPC (wip) [5970ec9e](https://github.com/leon-ai/leon/commit/5970ec9e8e4c2784c50e2ddc76b34b71aa4310e6) +- introduce spaCy for complete NER (wip) [caa86fc8](https://github.com/leon-ai/leon/commit/caa86fc8a6850b18f67ba7bedb423be693a88d17) +- slot filling (wip) [76547d94](https://github.com/leon-ai/leon/commit/76547d9411c32e0eb2ccfdac3a4901d2d2fb37f6) +- share data across domains [f4f9fff9](https://github.com/leon-ai/leon/commit/f4f9fff9783861be183990d7869973c7a30c8104) +- dynamic variable binding on NLG [0367b44f](https://github.com/leon-ai/leon/commit/0367b44f211c1629fffe6981a730f171707bf0c0) +- context and slot filling preparation (wip) [975b8ebc](https://github.com/leon-ai/leon/commit/975b8ebcf00db91b44dd067be6dde5c1bf32fff1) +- annotate entities on the fly + prepare for dialog skill type and cross-domains data [4107932d](https://github.com/leon-ai/leon/commit/4107932d000086188d6f44ef67b73cc322fc58e5) +- new NLP training [d8023308](https://github.com/leon-ai/leon/commit/d8023308d0ef1f3eede37f21f45daa2f893031b0) + +- **server:** + - trigger next action suggestions or current ones [244d08c0](https://github.com/leon-ai/leon/commit/244d08c0bd0fea315269f52ab899f9b7fe083f51) + - introduce main NLP model and resolvers NLP model [e37526d9](https://github.com/leon-ai/leon/commit/e37526d9056d858ebcf17b81f6714f47b67c77cb) + - change log emojis [843bc428](https://github.com/leon-ai/leon/commit/843bc428b8deb397e2d051a8e0bfaf1b82b459a2) + - provide nextAction even when no slot is set and clean up NLU object on context switch [8377c63d](https://github.com/leon-ai/leon/commit/8377c63db4e4e42ed929171cd8b9abdb13c44b2a) + - report full traceback from skills execution [b69b1fea](https://github.com/leon-ai/leon/commit/b69b1fea16250421bc7d5def1c973dd43e453071) + - support on-the-fly entity annotation for built-in entities [567b030c](https://github.com/leon-ai/leon/commit/567b030c4fcf8df266c39cca61a146fb33b9e0fc) + - save slots within conversation context [fce47cdb](https://github.com/leon-ai/leon/commit/fce47cdbd570993ac5cca2b4ff5bc97969df4e40) + - resolve resolvers tmp [ceea47ff](https://github.com/leon-ai/leon/commit/ceea47ff7dd536bfd3adf3cc355e90e3e94b1cbd) + - prepare the next action on non-slot-filled skills [0acb31a9](https://github.com/leon-ai/leon/commit/0acb31a9c61c1c094b29f3d0ff2647d625eab0be) + - add more affirmative utterance samples [870ab2e8](https://github.com/leon-ai/leon/commit/870ab2e87eba2c548d38dc90d30553e7fa380c1e) + - restart a skill with the original utterance saved in context [f4446ef1](https://github.com/leon-ai/leon/commit/f4446ef17796d38d0f98d5b7e889503622a1a998) + - clean up context if the action loop does not meet the expected items [035c9d52](https://github.com/leon-ai/leon/commit/035c9d5240472ac19a84ae8c1a87844fa0d0af5d) + - add handsigns custom entity [1529c720](https://github.com/leon-ai/leon/commit/1529c72039092c7b8f37304d6064e04f2dc7b795) + - reprocess NLU in case of slot filling interruption [9e242d77](https://github.com/leon-ai/leon/commit/9e242d77d32109e9355eec422790a5a66fd18f9c) + - handle action loop when slots have all been filled at once [f8830502](https://github.com/leon-ai/leon/commit/f88305020a5bc79056b7ff9c1a31f8d3c3a7cdce) + - break the action loop from the skill [27dc801c](https://github.com/leon-ai/leon/commit/27dc801cf53de5af3d54b95f42d2b9e627090867) + - stop action loop from skill to core [99681e25](https://github.com/leon-ai/leon/commit/99681e257795a18361be379b93244088401f640b) + - introduce basic concept of action loop [c5b38400](https://github.com/leon-ai/leon/commit/c5b38400821e5bc5edc4402d007f815f24319d44) + - prepare action loop feature [19e1aa22](https://github.com/leon-ai/leon/commit/19e1aa22f6e989e90eb745e3a7b7ccb8ff5adbfa) + - add current utterance entities to differentiate from the whole context [8b56a185](https://github.com/leon-ai/leon/commit/8b56a1850c9d76e335f1bad1b4395d73ddc5ea19) + - when a context is activated, pick up the most probable classification [8e186879](https://github.com/leon-ai/leon/commit/8e1868798c8750c19b1719a44dc6fb8bca68b250) + - persist entities into contexts [87575773](https://github.com/leon-ai/leon/commit/875757739f6701f54805eeff2c7c350cff36c4ac) + - forward slots to skill + add original utterance [68e40f65](https://github.com/leon-ai/leon/commit/68e40f65df0d1fe29ccad991868a2408c6e1015e) + - handle case when all slots have been filled in one utterance [22e9234b](https://github.com/leon-ai/leon/commit/22e9234b3d2c97e83eaafaeeb5aa9d27c351c95a) + - trigger next action once all slots have been filled [9b870010](https://github.com/leon-ai/leon/commit/9b870010dd929bc1aed6d87696f1cc4e9f177c0b) + - complete slot filling before triggering the next action [9124687e](https://github.com/leon-ai/leon/commit/9124687eb0e17295a30f860752ee622ba44d1440) + - from modules to skills with type at the actions level [77ebaf4a](https://github.com/leon-ai/leon/commit/77ebaf4a9c78b2e471d39872e361ea05b163580d) + - verify if all slots are filled [e27c1b9c](https://github.com/leon-ai/leon/commit/e27c1b9c8f5c2f668f464f152ad227d65ba5ef6b) + - context and slot filling, keep context and await for entities [25adf406](https://github.com/leon-ai/leon/commit/25adf406c810e48b1277105dd6c269a2ed601d28) + - unstack oldest context [1ece25a4](https://github.com/leon-ai/leon/commit/1ece25a497acc9f9876fe158ace5da38beec31e6) + - context setup with slot for each conversation (wip) [8257eb87](https://github.com/leon-ai/leon/commit/8257eb8792c9f4fc90bcc1b393d3fddf8ff541dc) + - resolve slots from slot filling [960a6dc7](https://github.com/leon-ai/leon/commit/960a6dc71c2efb50ad6a8448d447ebd79c559c41) + - pickup questions for slot filling [3bbc2f8a](https://github.com/leon-ai/leon/commit/3bbc2f8a254d10f0c37cdb7abf016b3e418f594a) + - main slots structure (wip) [1d9b1809](https://github.com/leon-ai/leon/commit/1d9b18093b6e042ae49f557149a7822b4420cdb8) + - introduce resolvers for slot filling (wip) [334bf393](https://github.com/leon-ai/leon/commit/334bf393f2c43edd326d9de2e93c037ffeebeab5) + - slot filling PoC (tmp wip) [95bfcfe4](https://github.com/leon-ai/leon/commit/95bfcfe422f21a2946e50031a3623675dfe81b9d) + - slot filling (wip) [969a83e6](https://github.com/leon-ai/leon/commit/969a83e6081de20ec5e2bdd0329a21a3fe448f13) + - trigger unsupported language [1845eed7](https://github.com/leon-ai/leon/commit/1845eed71dadd5f693d76abd7633864014bf8af1) + - context (wip) [d1c2a11d](https://github.com/leon-ai/leon/commit/d1c2a11d8284ca4e1d4563b871c50c006e8ef8a0) + - context (wip) [a9a43ac4](https://github.com/leon-ai/leon/commit/a9a43ac478c46f3832d2af49c287bb574a70cc14) + - differenciate cities from countries for location entities [bf9bf231](https://github.com/leon-ai/leon/commit/bf9bf231f714e1edc1417e43af12fa54c00ba064) + - auto restart the TCP server when language is switching [9be7c700](https://github.com/leon-ai/leon/commit/9be7c700767672ac6e0c875d3b5ae7fa6414e4fa) + - support multi languages on TCP server [a808742c](https://github.com/leon-ai/leon/commit/a808742c927d45c18df45af133e67c98d4a0415a) + - add auto reconnect on TCP client [cbe89ed6](https://github.com/leon-ai/leon/commit/cbe89ed6ccfd727356eb34078a8a4348b2fd696f) + - make TCP client global [006e9fb0](https://github.com/leon-ai/leon/commit/006e9fb01148c2107f6acc6a562ace4809da92be) + - fully implement low-level networking for IPC [8acb82da](https://github.com/leon-ai/leon/commit/8acb82da9bacdb9b7952c4a4d130d094e07def5e) + - more accurate NLG [d5577b1e](https://github.com/leon-ai/leon/commit/d5577b1ef5cf1b8b4a924636ba4425b8b4ae133d) + - unknown_answers fallback on dialog type [28efe6e7](https://github.com/leon-ai/leon/commit/28efe6e7d542f19bf12ddede1815f7fa8cf01036) + - deep data mapping on enum NER [3ca48265](https://github.com/leon-ai/leon/commit/3ca48265e7115c8e0f02c65ba92d90412325ad76) + - NLG and entities mapping [8f2f935b](https://github.com/leon-ai/leon/commit/8f2f935b949ceb965941460d4ff1ed0084b72442) + - bootstrap skill structure [fe90c68e](https://github.com/leon-ai/leon/commit/fe90c68ea0e9b0e857b62aa9f3b0a42ba1ffed6b) + - on-the-fly language switching [f24513a2](https://github.com/leon-ai/leon/commit/f24513a22395d1903e485883f4813cdceccdbd18) + - new NLP containers [34b2aa56](https://github.com/leon-ai/leon/commit/34b2aa5655e55284d59db4569960c49965a0483c) + - (WIP) NLU refactoring [ca3f5f42](https://github.com/leon-ai/leon/commit/ca3f5f42da26eb634e10b56e9b84bd45b5543024) + - add skills domains [cf2a28aa](https://github.com/leon-ai/leon/commit/cf2a28aac2d936cc15e6aa9aa13747015d952053) +- **skill/akinator:** + - finish up [79e7df02](https://github.com/leon-ai/leon/commit/79e7df022f7daedf43db7f892e049a31924ce985) + - finished main business logic [76cae42f](https://github.com/leon-ai/leon/commit/76cae42fdeac0edcd3ebd6aa7718728617687b1b) + - backbone [02a2f714](https://github.com/leon-ai/leon/commit/02a2f71470bb4c0c6ca04526e89461d863d17145) +- **skill/birthday:** + remove birthday skill [be0b345d](https://github.com/leon-ai/leon/commit/be0b345d3f7fea562548e3fbed62b65c32eff4c0) +- **skill/color:** + introduce color skill [ce00989b](https://github.com/leon-ai/leon/commit/ce00989b01f65c5cbb5a2e13f454207c1ba7741c) +- **skill/guess_the_number:** + introduce the Guess the Number skill [fba80966](https://github.com/leon-ai/leon/commit/fba80966c937a32182e48670c47358babb539d64) +- **skill/introduction:** + - add one utterance sample [af0fdd1e](https://github.com/leon-ai/leon/commit/af0fdd1e18975bf8b60abb2957ddf79831281817) + - ask about owner info if necessary [c5cc9bdd](https://github.com/leon-ai/leon/commit/c5cc9bdd52afaaa710f9476d1e9918f3d168e243) +- **skill/mbti:** + - complete form resolver [aad9f3f1](https://github.com/leon-ai/leon/commit/aad9f3f1ef61499d438ea40c9d2d95764667678d) + - finish business logic [99a3f103](https://github.com/leon-ai/leon/commit/99a3f103e00b5a58745ee851d2fa95c61871f75a) + - questions mapping [ae4f69f7](https://github.com/leon-ai/leon/commit/ae4f69f7c7189ff75e004f68c9a2a8b6bb37b6bd) + - complete questionnaire [7f1f8871](https://github.com/leon-ai/leon/commit/7f1f8871598746c5475b24e086ea6e581f2a988e) + - main logic backbone [33109a4c](https://github.com/leon-ai/leon/commit/33109a4c8b5df82e7b98e48e66f8d53f0cc114fb) + - main NLU structure [skip ci] [86d5040a](https://github.com/leon-ai/leon/commit/86d5040a7dc2006036c7e67a2cf54a4c992e64aa) +- **skill/rochambeau:** + - add start answers [192dd0a8](https://github.com/leon-ai/leon/commit/192dd0a87ab5dc025bb90b20b187e36a58be54ea) + - introduce paper scissors rock [57370470](https://github.com/leon-ai/leon/commit/573704706c843d870f2498146bc3cd659bab4f06) + - init [7f5e30ac](https://github.com/leon-ai/leon/commit/7f5e30ac82f2a2d7579e361229a4044348915867) +- **web app:** + - join us on Discord [141c89ec](https://github.com/leon-ai/leon/commit/141c89ecbfd329a8e63d5a603d0ae6b42f9abf38) + - wait for TCP client to be connected first [bc228a68](https://github.com/leon-ai/leon/commit/bc228a68600c07871c489d6624bbc837971079a6) + ### Bug Fixes +- check script with new intent-object format [fdf0a389](https://github.com/leon-ai/leon/commit/fdf0a389b76caba5dd47996a43a34c0c7821c70a) +- check new resolvers paths [cfd8f7cb](https://github.com/leon-ai/leon/commit/cfd8f7cbe5e8fd9ce3d1659c725d7af261db8d71) +- use ports.ubuntu.com mirror for the offline TTS [skip ci] [3dd90396](https://github.com/leon-ai/leon/commit/3dd9039678820fceb7ccbb1c96358c8d2f188ede) +- set skill config only when a bridge is set [7513aa7d](https://github.com/leon-ai/leon/commit/7513aa7d20fee1fe9ca5442a7909d22fd1c3b39e) +- only set skill config when it is a logic type [9ce9a8bc](https://github.com/leon-ai/leon/commit/9ce9a8bc4fe0864730a08d8e9a436982f1365aa5) +- **docker:** + - usage of Ubuntu base image with pyenv and nvm (#408) [f507f6f7](https://github.com/leon-ai/leon/commit/f507f6f7e499f56768b3e624164cbcd58193b153) + - check should not allocate a pseudo-TTY (#359) [4372b45f](https://github.com/leon-ai/leon/commit/4372b45fc605893d4130cf7110dd87519b934345) +- **server:** + - make leon handle multiple socket.io-client instances [6e7c0aac](https://github.com/leon-ai/leon/commit/6e7c0aac57008b152b45f1b0f3886ae38777467b) + - fallback on global resolver during resolver classification [ec77dd0f](https://github.com/leon-ai/leon/commit/ec77dd0f02a8ae94fb3f02c7b7847b5509d71406) + - make use of current entities to match global entities [a8d82050](https://github.com/leon-ai/leon/commit/a8d82050c86b5c24c4c898c06e5ffc3882524c0b) + - multiple slots filling [2ac1bc63](https://github.com/leon-ai/leon/commit/2ac1bc63ccd11757d586adfb2e75ce04e3ffbcb5) + - context switching on action loop [6712ae55](https://github.com/leon-ai/leon/commit/6712ae5539ef44ed33e360cfcad71c760c4b13b1) + - check one-shot slot filling case causing infinite loop [782a3aaa](https://github.com/leon-ai/leon/commit/782a3aaa0a07dda667557bc84db906b3fa9b237c) + - clean up active context after all slots have been filled [faabc2c7](https://github.com/leon-ai/leon/commit/faabc2c7b0992fcea035eedf66103d84b101e1a7) + - correctly extract all spaCy entities [6aa60bfb](https://github.com/leon-ai/leon/commit/6aa60bfbd8c72e678fe3faf5e7f9dbd37dfd209f) + - intent not found [8280c658](https://github.com/leon-ai/leon/commit/8280c65897dba0fe470a3589d151b391c51e344e) + - fallback due to modules to skills refactoring [ef0c54b2](https://github.com/leon-ai/leon/commit/ef0c54b22667ef2bd1d2c07003f6b4beb5fa25c0) + - NER due to modules to skills refactoring [e4d3904c](https://github.com/leon-ai/leon/commit/e4d3904ceeb2a3ee2c0187a1817331fac916e1a7) + - **skill/akinator:** + remove direct end on guess action [f6461f73](https://github.com/leon-ai/leon/commit/f6461f733b4a5d944dfa4a987dd1109628c6cbca) + - **skill/color:** + more appropriate answer [cb18ed63](https://github.com/leon-ai/leon/commit/cb18ed6397cb0e0ad8fbea30c57d7d40137441ee) + - **skill/rochambeau:** + final logic [0ebc0518](https://github.com/leon-ai/leon/commit/0ebc0518e61b899c35dd13df65a43f69399e784d) + ### Performance Improvements +- check Pipfile instead of Pipfile.lock to judge whether Python packages must be installed [afdb71f7](https://github.com/leon-ai/leon/commit/afdb71f766f2956c5cb4a5e0be9025340d1a89db) + +### Documentation Changes + +- change newsletter link [4bf2a9af](https://github.com/leon-ai/leon/commit/4bf2a9af963f75aeff96f4a43da8ec1024ac583a) +- README - Edited sentence for clarity (#389) [e83a1c42](https://github.com/leon-ai/leon/commit/e83a1c4230897e8b63251ef86225cf773148c38e) +- edit newsletter link [fa558a44](https://github.com/leon-ai/leon/commit/fa558a447ade4071f352d56f14602690ed90f521) +- update sponsor [skip ci] [f30ddb6b](https://github.com/leon-ai/leon/commit/f30ddb6be5f531df2b0042be0ed5ffbe79f73b07) +- remove sponsor [skip ci] [5dbc010f](https://github.com/leon-ai/leon/commit/5dbc010fa643279a24081f3148022e2211af63f4) +- remove sponsor [skip ci] [f36dd20f](https://github.com/leon-ai/leon/commit/f36dd20f822cd33c9e8a03efc2849c8d8d1fc75e) +- remove sponsor [skip ci] [5ee57ddf](https://github.com/leon-ai/leon/commit/5ee57ddf2a9f7817ec35b2e70d49e5bb422d8f78) +- add @ant-media sponsor [skip ci] [b47cbc3a](https://github.com/leon-ai/leon/commit/b47cbc3a5ecb6591f7abb4f62feae8102b9a6468) +- add long dev notice to README [skip ci] [499be77d](https://github.com/leon-ai/leon/commit/499be77d509231b853f591e27f726381da5a50d8) +- move sponsor to new section [skip ci] [8825d687](https://github.com/leon-ai/leon/commit/8825d6877c19d86495e89a858b859b7ab1f9ae37) +- change Twitter handle [skip ci] [c1afc11c](https://github.com/leon-ai/leon/commit/c1afc11cdb283526540d0fecdf83efddf3f3a9f7) +- remove sponsor [skip ci] [99b401a6](https://github.com/leon-ai/leon/commit/99b401a668a6fb248e33c22782940402be7c9b17) +- add new sponsor self-hosted img [skip ci] [238d928c](https://github.com/leon-ai/leon/commit/238d928cace13d4ecd174ca14b136967d8845e0f) +- remove new sponsor link (broken) [skip ci] [254f2848](https://github.com/leon-ai/leon/commit/254f2848aab622b79cce16d10c58d53ff6db9a8f) +- in GitHub BUG.md from modules to skills [4a5480a3](https://github.com/leon-ai/leon/commit/4a5480a3ccc54ee34d42f6edcec2a40224dee7ed) +- change @FluxIndustries sponsorship [skip ci] [1a118b71](https://github.com/leon-ai/leon/commit/1a118b718e5d4ade123756ac94758a01c50b12ae) +- add @FluxIndustries sponsor [skip ci] [9a604d7c](https://github.com/leon-ai/leon/commit/9a604d7ccc0c6aaec257299078141dd0c3077933) +- new #LeonAI link [skip ci] [a0107d62](https://github.com/leon-ai/leon/commit/a0107d629473f7fd057d367926e83822d46f1227) +- changelog new version diff link fix [skip ci] [e14c2498](https://github.com/leon-ai/leon/commit/e14c249826db92af7b85422e566be6aa834a7fb7) + +# [1.0.0-beta.6](https://github.com/leon-ai/leon/compare/v1.0.0-beta.5...v1.0.0-beta.6) (2022-02-07) / Leon Over HTTP + Making Friends with Coqui STT + +### Features + +- simple coqui-ai stt integration [86a4816b](https://github.com/leon-ai/leon/commit/86a4816b777fee8ec9c89648c5866a75de56c017) +- HTTP API key generator [d10a7fa7](https://github.com/leon-ai/leon/commit/d10a7fa7880a0bf2fb1cae7904d1ef4257f05257) +- avoid unnecessary routes generation + +- **server:** + - make Coqui STT the default STT solution [70399187](https://github.com/leon-ai/leon/commit/7039918760c0ef7ba93bf45820e3cae774c42d8c) + - add HTTP API key middleware [cdf41499](https://github.com/leon-ai/leon/commit/cdf4149939cbe3f3ae81039957dba3377a78f5a6) + - expose queries over HTTP [b6428d03](https://github.com/leon-ai/leon/commit/b6428d038452619f1682c863892cd8f376efca84) + - add timeout action over HTTP [115f9c16](https://github.com/leon-ai/leon/commit/115f9c164559d761625cc6f362749f7d2417d300) + - handle built-in and trim entities over HTTP + add "disabled" HTTP API action option [82fb967a](https://github.com/leon-ai/leon/commit/82fb967af8f49421e3b2474184da3d34fb17294f) + - execute modules over HTTP [2e5b2c59](https://github.com/leon-ai/leon/commit/2e5b2c59da0bafe3acd966773c6fac3611b3bd0c) + - generate Fastify routes on the file to expose packages over HTTP [5b41713a](https://github.com/leon-ai/leon/commit/5b41713a68ee628e695212dbebc88f6b9a94b461) + +### Bug Fixes + +- do not ask to regenerate the HTTP API key if this one isn't available yet [d265377a](https://github.com/leon-ai/leon/commit/d265377a43fd4506cf12db46f261b891f2054ed2) +- Python deps tree check [c6c01291](https://github.com/leon-ai/leon/commit/c6c012915824227efdf0c50df6a8f1cd8d70ed42) +- hotword offline (#342) [f563d01d](https://github.com/leon-ai/leon/commit/f563d01d077499c836e94c86f85cedc2ad4d56e6) +- addressed comments by @JRMeyer [b1c6f5c8](https://github.com/leon-ai/leon/commit/b1c6f5c883103d57d4fe566af640fc3ac5ce713d) +- allow to detect STT offline capabilities [04d62288](https://github.com/leon-ai/leon/commit/04d622884165e0bde65785569a659f59cf9e8582) +- Amazon Polly is always configured on check script due to new structure [e6246d1f](https://github.com/leon-ai/leon/commit/e6246d1f8f9ec15a4ebe9600764afffbaa7e62d9) + +### Performance Improvements + +- check if Python deps tree has been updated before going through deps install [2d0b0f13](https://github.com/leon-ai/leon/commit/2d0b0f1365d8e4d6eadf9f7cc0a16b7b4b4306f4) + +# [1.0.0-beta.5](https://github.com/leon-ai/leon/compare/v1.0.0-beta.4...v1.0.0-beta.5) (2021-12-28) / Refocus + +_This release marks a major turn in the future versions of the Leon core. Please [read this blog post](https://blog.getleon.ai/i-ran-away-from-open-source/) to know more._ + +### BREAKING CHANGES + +- Node.js 16+ and npm 8+ minimum requirements [2f66f1c1](https://github.com/leon-ai/leon/commit/2f66f1c17bb2e4a1c18b4251d49de252b8d87344) + +### Features + +- **server:** support arrays on NER between conditions [7cf7f979](https://github.com/leon-ai/leon/commit/7cf7f9791254e1950fe9128ce1b3a58079cc2ada) + +### Bug Fixes + +- jest-extended new setup due to latest update [02f766d6](https://github.com/leon-ai/leon/commit/02f766d6a8453609ebaec78356aa6e6d4df0967b) + +### Performance Improvements + +- Windows setup on DeepSpeech dep removal [13f5a49f](https://github.com/leon-ai/leon/commit/13f5a49f678f8f67a93b67d4f558cddcf237e204) + +### Documentation Changes + +- URL redirect managed by registrar [c16d5b28](https://github.com/leon-ai/leon/commit/c16d5b280b758f7e18305e30678adec79f0a0716) + +# [1.0.0-beta.4](https://github.com/leon-ai/leon/compare/1.0.0-beta.2...v1.0.0-beta.4) (2021-05-01) / Getting Rid of Dust + +_This release includes a lot of changes that are made under the hood and are not displayed here, please **[read the blog post](https://blog.getleon.ai/getting-rid-of-dust-1-0-0-beta-4/)** to know more._ + +### BREAKING CHANGES + +- **package/checker:** introduce Have I Been Pwned v3 API with API key ([0ca89fe3](https://github.com/leon-ai/leon/commit/0ca89fe32d51c80cec5f9446acf14990390a5917)) +- **server:** + - AWS SDK new structure due to v3 and adapt Amazon Polly changes ([f15f2db7](https://github.com/leon-ai/leon/commit/f15f2db78e5781d05e5e2bcb186645966d17debf)) + - IBM Watson TTS and STT new structure ([f41ea0e9](https://github.com/leon-ai/leon/commit/f41ea0e9a1479bfd6a1cb2e8d1f70aec744c685b) | [2668c295](https://github.com/leon-ai/leon/commit/2668c295880ee753ef7ca26a91dbc7e0901febff)) + +### Features + +- **package/calendar:** introduce To-Do list module ([0cdd73d6](https://github.com/leon-ai/leon/commit/0cdd73d6c24a287915f691e3b12edacd75fd383a) | [857be947](https://github.com/leon-ai/leon/commit/857be947792c650ac35847e14fc41064008cef24) | [2041be14](https://github.com/leon-ai/leon/commit/2041be14dbc01640a61de96d1982cc20cd05a8b3) | [12e8f5c3](https://github.com/leon-ai/leon/commit/12e8f5c3bfb436aa212557cd99d9926aa431ab4f) | [8575e9e3](https://github.com/leon-ai/leon/commit/8575e9e3ef01499d9f7be6d313a85d48549e9107) | [5e128df0](https://github.com/leon-ai/leon/commit/5e128df023977525de3e66ce2826aace87569308) | [602aa694](https://github.com/leon-ai/leon/commit/602aa694ac49333f48c119cf2ca2aa7f54b8ae44) | [b9693df9](https://github.com/leon-ai/leon/commit/b9693df90cbc01067e18e64db4d377e41b3fd1d4) | [581da8cd](https://github.com/leon-ai/leon/commit/581da8cd9806323aabb0e85778d645df3c0948b9) | [53f7db55](https://github.com/leon-ai/leon/commit/53f7db55c6e916751f1d59c239628d5ea8914009) | [ae073971](https://github.com/leon-ai/leon/commit/ae0739717b6a17373d8f9bc69571c67c1c571b4a)) +- **package/checker:** introduce Have I Been Pwned module ([61c1b55a](https://github.com/leon-ai/leon/commit/61c1b55af5691c03f6a6dae0cf3f236a374f1fe7) | [5a999bc6](https://github.com/leon-ai/leon/commit/5a999bc63aa0c667c4e3092daac6a05a6c4b4499) | [36368664](https://github.com/leon-ai/leon/commit/36368664fce8bcf0c17c4c83818aeb418f1e2f23) | [a7a6d885](https://github.com/leon-ai/leon/commit/a7a6d885a83455163eeca74a355177d65db156b8) | [c73ba52b](https://github.com/leon-ai/leon/commit/c73ba52ba8575a64b3329e59a50050d15281d0ec) | [8374e548](https://github.com/leon-ai/leon/commit/8374e5481022de9b134f49180a8dfe28db136261) | [a476fd0f](https://github.com/leon-ai/leon/commit/a476fd0f38f18bf8035db213be2c55f83871038d)) +- **package/network:** add speedtest module ([09ad4340](https://github.com/leon-ai/leon/commit/09ad43406d3df8ca65f385a91c159def51f91811)) +- **server:** + - add regex entity type [3fda3526](https://github.com/leon-ai/leon/commit/3fda3526c7425bdea4b669474fa77efd61c06a8e) + - catch unsupported action entity type [5bc6c3f1](https://github.com/leon-ai/leon/commit/5bc6c3f116d6b9ece2cc3bebdbdb08f019ee90b9) + - NER backbone [24cf3c9a](https://github.com/leon-ai/leon/commit/24cf3c9a4facd05a4c626ff9d2e7c83a5ae15298) + - introduce actions module [b449376f](https://github.com/leon-ai/leon/commit/b449376f61dc995e2e264c6a14ba123926f5cc58) + +### Bug Fixes + +- set correct status code for GET /downloads [690f1841](https://github.com/leon-ai/leon/commit/690f1841d681a1e48e1837e3e166228d6c2ddaf6) +- take `.env` in consideration when using Docker [d38e6095](https://github.com/leon-ai/leon/commit/d38e6095f9b71467b8486430fba4bb7007ec4c5a) +- spinner test [9071c927](https://github.com/leon-ai/leon/commit/9071c92790be674687590e4a896bbf44bc26fb43) +- e2e tests by adding modules actions level [5cf77d90](https://github.com/leon-ai/leon/commit/5cf77d9011a80b326f229b2309a6910ac0f1cfa2) + +- **package/leon:** fix english translations [90225707](https://github.com/leon-ai/leon/commit/90225707f94154021cadeb9c61bdc48c3de5aa29) +- **package/network:** make use of new compatible speedtest lib [0c925626](https://github.com/leon-ai/leon/commit/0c925626df65858fa039972b3f3d5f38fde93eb6) +- **package/trend:** + - GitHub module new scraping [68414937](https://github.com/leon-ai/leon/commit/6841493740ca859000c1fd8d692b73fc79fcf500) + - when there is no star provided on the GitHub module [563fb409](https://github.com/leon-ai/leon/commit/563fb40955e2deb5c6d0bd064fc9cc8766a6fcaf) +- **server:** + - make use of Basic plugin from the main NLP container [e1d5bed3](https://github.com/leon-ai/leon/commit/e1d5bed3e688db566a0cb803dda5c2d57c599d8c) + - NER trim entity on after conditions [fa6a5a43](https://github.com/leon-ai/leon/commit/fa6a5a43a60b493aa403a44957082382494c129b) + +### Documentation Changes + +- add minimum Pipenv version requirement to README [72e46bd6](https://github.com/leon-ai/leon/commit/72e46bd6c175a4a149fb6b14522823b224d7c152) +- hunt broken links [b2a22792](https://github.com/leon-ai/leon/commit/b2a2279243e7566b57fb7f696024bdf08294e853) +- add "ci" commit type in CONTRIBUTING.md [09e2672b](https://github.com/leon-ai/leon/commit/09e2672b0b399f5ce9dd7cd446d04f4d6fd7c13a) +- use emojies in README [0ea7a78b](https://github.com/leon-ai/leon/commit/0ea7a78b7c94dc44c992913ae1c90fb1cf8a7692) +- add social badges to README [c55c7532](https://github.com/leon-ai/leon/commit/c55c7532b25bf420c4819be71b0f9c21ccc58711) +- Node.js 14 requirement [d1034bd1](https://github.com/leon-ai/leon/commit/d1034bd135fd5a6314a1571d4088fd85a8e6a1da) + +# [1.0.0-beta.2](https://github.com/leon-ai/leon/compare/1.0.0-beta.1...1.0.0-beta.2) (2019-04-24) + +### Features + +- can send custom HTTP headers + ([2685cdab](https://github.com/leon-ai/leon/commit/2685cdab07cc1a9ea418eab812e5163d2dd0da90)) +- allow HTML output + ([ec3f02df](https://github.com/leon-ai/leon/commit/ec3f02dfaf2f4b7623ce350350ebee28cf18740e)) +- NLU improvement with node-nlp + ([6585db71](https://github.com/leon-ai/leon/commit/6585db718ccae1d750a35783075cf61cc8fe84f1)) + +- **package/trend:** + - add answer when the Product Hunt developer token is not provided + ([f40b479b](https://github.com/leon-ai/leon/commit/f40b479b295247c5a8a0e6ed81afe56fadfd2730)) + - Product Hunt module done + ([37794306](https://github.com/leon-ai/leon/commit/3779430621bef970be0e8d048eb0b4bf160ae8a4)) + - basics done on the Product Hunt module + ([32cc7dbe](https://github.com/leon-ai/leon/commit/32cc7dbe36592fb9618d9c10da5f05a4be7e41b6)) + - complete dedicated answers according to the technology and given time + ([8997d691](https://github.com/leon-ai/leon/commit/8997d6917445f837c9647a5a9b4d6998d2df4952)) + - GitHub module done + ([7c6f3922](https://github.com/leon-ai/leon/commit/7c6f3922f299193ee0fb54d0fc97f8b436fc706b)) + - be able to choose a limit and a date range for the GitHub module + ([3c088371](https://github.com/leon-ai/leon/commit/3c0883716e1c10371c399843a578095a1e16781d)) + - format GitHub results in one message + ([9d026b94](https://github.com/leon-ai/leon/commit/9d026b94efa8871d421ae2b593b96622a98537ac)) + - simple GitHub module results + ([5baec074](https://github.com/leon-ai/leon/commit/5baec07455f453d4ad003f1da360b2663b7e15e0)) + - list GitHub trends in HTML raw + ([3441629e](https://github.com/leon-ai/leon/commit/3441629e3cde933b322cb114d9f1bc3ef0eb3944) | [6b932e94](https://github.com/leon-ai/leon/commit/6b932e947fc365ea6435fda798b7cca32708b443)) + - expressions dataset and structure + ([f406a5a0](https://github.com/leon-ai/leon/commit/f406a5a09894e12c56a1e76dda609adada00b0d7) | [f54c2272](https://github.com/leon-ai/leon/commit/f54c2272b4b4dc5c56b512b0ccc1519d77ef15a3)) + +### Bug Fixes + +- Leon was not fully installed with Docker if a `.env` file was existing + ([c8a68ab0](https://github.com/leon-ai/leon/commit/c8a68ab02eec9ddaf803b6e36cd7e91a4989cdea)) + +- **package/trend:** + when there is no contributor on GitHub module + ([d845e49b](https://github.com/leon-ai/leon/commit/d845e49b0f18caeb306e2d399c50a03883b2f55d)) +- **server:** + - skip Pipenv locking until they fix it + ([029381e3](https://github.com/leon-ai/leon/commit/029381e3256933f37f5c2950c4eb1f0192f55ec6) | [ecfdc73f](https://github.com/leon-ai/leon/commit/ecfdc73f8290dd9e1910df9519095516a1227763)) + +### Documentation Changes + +- add `What is Leon able to do?` section in the readme + ([87f53c91](https://github.com/leon-ai/leon/commit/87f53c91368141966959f3ad7299bb7b643828a5) | [d558fc8b](https://github.com/leon-ai/leon/commit/d558fc8b7c6494babf5dec799802227f77c33d8a)) +- open-source != open source + ([16a9372e](https://github.com/leon-ai/leon/commit/16a9372e05d4d31a7a39a65a52d4708b72499d4c) | [2155cd88](https://github.com/leon-ai/leon/commit/2155cd88decbbd671bd58840291d9330ce06ebba)) + +# [1.0.0-beta.1](https://github.com/leon-ai/leon/compare/1.0.0-beta.0...1.0.0-beta.1) (2019-02-24) + +### Features + +- add Docker support + ([209760db](https://github.com/leon-ai/leon/commit/209760dba747001300692fb6a6af97543de584d6)) + +### Bug Fixes + +- **package/checker:** + isitdown module fails with capital letters in URL + ([ada6aaef](https://github.com/leon-ai/leon/commit/ada6aaef4bada47e87d28f9f6eaa05b9e23f58d2)) +- **web app:** + enable environment variables + ([a438d6f9](https://github.com/leon-ai/leon/commit/a438d6f942812f74e3dda75a9875609f8bea21cd)) + +### Performance Improvements + +- **web app:** + favicon compression + ([33dbcb42](https://github.com/leon-ai/leon/commit/33dbcb425eaafba90176ff64e5f689eb36bc6ce1)) + +### Documentation Changes + +- update README to make the reader genderless + ([58662658](https://github.com/leon-ai/leon/commit/586626586b7a2f84cb2cd84028111976bc5172f0)) +- use "to rule them all" in README + ([c74dda4c](https://github.com/leon-ai/leon/commit/c74dda4cb9acc78de143ae01fdc6b4ef0a5ec3ef)) + +- **readme:** + add story write-up + ([08a68e37](https://github.com/leon-ai/leon/commit/08a68e376b6a9367425947380564120943376500)) + +# [1.0.0-beta.0](https://github.com/leon-ai/leon/compare/https://github.com/leon-ai/leon.git...1.0.0-beta.0) (2019-02-10) + +Initial release. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..2d4f245 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-present, Louis Grenard + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c4e4563 --- /dev/null +++ b/README.md @@ -0,0 +1,183 @@ +

+ +

+ +

+ Leon
+ Leon +

+ +_

Your open-source personal AI assistant.

_ + +

+ + +

+ +

+ I share Leon progress most regularly on X / @grenlouis +

+ +

+ Follow progress on X / @grenlouis · + Website · + Newsletter · + Roadmap · + Story +

+ +--- + +## ⚠️ Important Notice (as of 2026-03-29) + +> [!IMPORTANT] +> Leon is currently focused on the **2.0 Developer Preview** on the `develop` branch. +> +> - The new documentation is **not ready yet**. +> - The current docs site and older guides mostly reflect the legacy architecture. +> - If you want the legacy, more stable pre-agentic version of Leon, use the `master` branch. +> - If you want to explore or contribute to Leon's new core, `develop` is the right place. + +The most accurate high-level references for Leon's current state are: + +- [`core/context/LEON.md`](./core/context/LEON.md) +- [`core/context/ARCHITECTURE.md`](./core/context/ARCHITECTURE.md) + +## 👋 Introduction + +**Leon** is **your open-source personal AI assistant** built around **tools, context, memory, and agentic execution**. + +Leon is designed to stay practical, privacy-aware, and grounded in your real environment. It can operate locally, use dedicated tools instead of relying on free-form guessing, and complete tasks from start to finish across deterministic workflows and agent-style execution. + +## 🧠 What Leon Is Today + +Leon is no longer just a classic intent-classification assistant like it was for its first release in 2019. + +Today, Leon is being built as a more capable assistant that can understand a goal, choose how to handle it, use tools, remember useful information, and recover when something goes wrong. + +- Leon can run in different ways depending on the task: `smart` mode chooses for you, `controlled` mode follows deterministic native skills and actions, and `agent` mode can plan step by step. +- Leon supports native skills for controlled actions and agent skills for `SKILL.md`-backed workflows. +- Leon can use real tools to get work done instead of only replying with plain text. +- Leon can use context about your environment so answers stay grounded in what is actually happening on your machine and setup. +- Leon keeps layered memory so it can remember durable preferences, day-to-day context, and recent discussion context. +- Leon supports both local and remote AI providers, which helps balance privacy, control, and capability. +- Under the hood, Leon-native skills follow `Skills -> Actions -> Tools -> Functions (-> Binaries)`. + +Leon also keeps a compact self-model and a bounded proactive pulse system so it can stay more consistent over time without flooding itself with unnecessary context. + +## Why? + +- **Privacy matters**: Leon can work with local models and local context instead of forcing everything through third-party services. +- **Grounded behavior matters**: Leon prefers explicit tools, context, and memory over vague model-only responses. +- **Extensibility matters**: skills, toolkits, bridges, and binaries make it possible to keep Leon modular. +- **Open source matters**: anyone can inspect the architecture, build on top of it, and help shape where it goes next. + +## 🚀 Getting Started + +### Prerequisites + +- [Node.js](https://nodejs.org/) >= 24.0.0 +- Supported OSes: Linux, macOS, and Windows + +Recommended: manage Node.js with [Volta](https://volta.sh/). + +### Installation + +```sh +# Clone the repository +git clone https://github.com/leon-ai/leon.git + +# Go to the project root +cd leon + +# Install pnpm +npm install --global pnpm@latest + +# Install dependencies +pnpm install +``` + +### Run Leon + +```sh +# Run Leon +pnpm start +``` + +### Check Your Setup + +```sh +# Check the setup went well +pnpm run check +``` + +By default, Leon runs locally and the app is available on `http://localhost:5366`. + +## 🏗️ Architecture Snapshot + +At a high level, Leon currently consists of: + +- `server/`: the main runtime, routing, memory, context management, HTTP API, and agent/controlled execution +- `app/`: the web application +- `aurora/`: UI components and preview environment +- `skills/`: built-in capabilities, split between `native/` skills and `agent/` skills +- `bridges/`: Node.js and Python bridges plus toolkit definitions and tool runtimes +- `tcp_server/`: Python services used by parts of the runtime stack +- `core/context/`: generated identity and architecture context documents that describe Leon's current behavior + +This repository already includes skills and toolkits for areas such as search, productivity, system utilities, media workflows, coding assistance, memory-backed interactions, and voice/audio features. + +## 📚 Documentation Status + +The new docs for Leon 2.0 are not ready yet. + +For now: + +- treat this repository as the source of truth for the **2.0 Developer Preview** +- use [`core/context/LEON.md`](./core/context/LEON.md) for Leon's current identity and behavior +- use [`core/context/ARCHITECTURE.md`](./core/context/ARCHITECTURE.md) for the current architecture overview +- expect the public docs site to lag behind the new core until the updated documentation is published + +## ❤️ Contributing + +We are starting to progressively onboard contributors for the **2.0 Developer Preview**. + +If you want to follow the project or express interest in joining that onboarding: + +- [2.0 Developer Preview contributor form](https://forms.gle/6PCG2D5rYo1q8tKMA) +- [Roadmap](http://roadmap.getleon.ai) +- [Discord](https://discord.gg/MNQqqKg) +- [GitHub issues](https://github.com/leon-ai/leon/issues) + +### Why is there a small amount of contributors? + +Leon has been evolving for a long time, but the current 2.0 work is a major transition period. + +For a long time, Leon was a smaller assistant project with a simpler architecture. Today, the core is being rebuilt into a much more capable system around tools, memory, context, and agent-style execution. That means a lot of things are still moving, and it makes contribution harder than it will be once the new docs and architecture settle down. + +Another important reason is simply time: Leon is still developed largely during spare time. So progress can be uneven, and opening the project more broadly has to be balanced with keeping the direction coherent while the 2.0 Developer Preview is still taking shape. + +## 📖 The Story Behind Leon + +Leon started in 2017 and has been active since 2019. If you want the longer backstory, read [the story behind Leon](https://blog.getleon.ai/the-story-behind-leon/). + +## 🔔 Stay Tuned + +- [X / Twitter](https://x.com/grenlouis) is the main place where I share Leon progress updates +- [Newsletter](https://leonai.substack.com/subscribe) +- [Blog](https://blog.getleon.ai) +- [YouTube](https://www.youtube.com/channel/UCW6mk6j6nQUzFYY97r47emQ) + +## 👨 Author + +**Louis Grenard** ([@grenlouis](https://x.com/grenlouis)) + +## 👍 Sponsors + +You can also contribute by [sponsoring Leon](http://sponsor.getleon.ai). + +## Thanks + +| ![OpenAI logo.](./.github/assets/thanks/openai-logo-light-mode.svg?v=2#gh-light-mode-only)![OpenAI logo.](./.github/assets/thanks/openai-logo-dark-mode.svg?v=2#gh-dark-mode-only) | ![JetBrains logo.](./.github/assets/thanks/jetbrains-mono-black.svg?v=2#gh-light-mode-only)![JetBrains logo.](./.github/assets/thanks/jetbrains-mono-white.svg?v=2#gh-dark-mode-only) | ![MacStadium logo.](./.github/assets/thanks/macstadium-logo-light-mode.svg?v=2#gh-light-mode-only)![MacStadium logo.](./.github/assets/thanks/macstadium-logo-dark-mode.svg?v=2#gh-dark-mode-only) | +| --- | --- | --- | +| [openai.com/form/codex-for-oss](https://openai.com/form/codex-for-oss/) | [jb.gg/OpenSource](https://jb.gg/OpenSource) | [macstadium.com/company/opensource](https://macstadium.com/company/opensource) | diff --git a/README.wehub.md b/README.wehub.md new file mode 100644 index 0000000..71c0248 --- /dev/null +++ b/README.wehub.md @@ -0,0 +1,7 @@ +# WeHub 来源说明 + +- 原始项目:`leon-ai/leon` +- 原始仓库:https://github.com/leon-ai/leon +- 导入方式:上游默认分支的最新快照 +- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准 +- 本文件仅用于记录来源,不代表 WeHub 是原项目作者 diff --git a/app/src/css/built-in-commands.scss b/app/src/css/built-in-commands.scss new file mode 100644 index 0000000..015404f --- /dev/null +++ b/app/src/css/built-in-commands.scss @@ -0,0 +1,220 @@ +.built-in-commands-modal { + position: fixed; + inset: 0; + z-index: 120; + display: block; + opacity: 0; + visibility: visible; + pointer-events: none; + transition: + opacity 0.18s ease, + visibility 0.18s ease; +} + +.built-in-commands-modal--hidden { + opacity: 0; + visibility: hidden; + pointer-events: none; +} + +.built-in-commands-modal--open { + opacity: 1; + visibility: visible; + pointer-events: auto; +} + +.built-in-commands-modal__mask { + position: absolute; + inset: 0; + background: rgba(0, 0, 0, 0.56); + backdrop-filter: blur(10px); +} + +.built-in-commands-modal__panel { + position: absolute; + top: 33%; + left: 50%; + transform: translate(-50%, -33%) scale(0.985); + width: min(864px, 100%); + min-height: 400px; + max-height: min(78vh, 756px); + display: flex; + flex-direction: column; + border: 1px solid transparent; + border-radius: 24px; + background: + linear-gradient( + var(--a-color-background-surface), + var(--a-color-background-surface) + ) + padding-box, + linear-gradient(135deg, rgba(28, 117, 219, 0.8) 0%, rgba(237, 41, 122, 0.4) 100%) + border-box; + box-shadow: + 0 28px 60px rgba(0, 0, 0, 0.45), + 0 0 0 1px rgba(255, 255, 255, 0.03) inset; + overflow: hidden; + opacity: 0; + transition: + transform 0.18s cubic-bezier(0.18, 0.89, 0.32, 1.08), + opacity 0.18s ease; +} + +.built-in-commands-modal--open .built-in-commands-modal__panel { + transform: translate(-50%, -33%) scale(1); + opacity: 1; +} + +.built-in-commands-modal__section { + padding: 20px 22px; +} + +.built-in-commands-modal__section--top { + border-bottom: 1px solid rgba(255, 255, 255, 0.08); +} + +.built-in-commands-modal__section--bottom { + border-top: 1px solid rgba(255, 255, 255, 0.08); +} + +.built-in-commands-modal__section--middle { + flex: 0 0 512px; + height: 512px; + min-height: 512px; + padding: 12px; + overflow: hidden; +} + +.built-in-commands-modal__scroll-area { + height: 100%; +} + +.built-in-commands-modal__input-field { + flex: 1; +} + +.built-in-commands-modal__input-field .aurora-input-container { + --a-icon-container-width: 72px; +} + +.built-in-commands-modal__input-field .aurora-input { + height: 72px; + font-size: 28px; + font-weight: 600; +} + +.built-in-commands-modal__input-field .aurora-input-icon-container { + height: 72px; +} + +.built-in-commands-modal__return-button .aurora-button { + min-height: 44px; + min-width: 44px; + padding: 0 14px; + font-size: var(--a-font-size-md); +} + +.built-in-commands-modal__return-button .aurora-button .aurora-icon { + font-size: 22px; +} + +.built-in-commands-modal__suggestion-copy { + min-width: 0; +} + +.built-in-commands-modal .aurora-list-item > .aurora-flexbox .aurora-icon { + font-size: 28px; + padding: 23px; + border-radius: 12px; +} + +.built-in-commands-modal + .aurora-list-item--selected + .aurora-list-item-clickable-icon + .aurora-icon { + color: var(--a-color-accent); +} + +.built-in-commands-modal__result-item { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16px; + width: 100%; +} + +.built-in-commands-modal__result-copy, +.built-in-commands-modal__result-value { + min-width: 0; +} + +.built-in-commands-modal__result-value { + margin-left: auto; +} + +.built-in-commands-modal .aurora-scroll-container-scrollview { + color-scheme: dark; + scrollbar-width: thin; + scrollbar-color: rgba(255, 255, 255, 0.2) rgba(10, 14, 18, 0.9); +} + +.built-in-commands-modal .aurora-scroll-container-scrollview::-webkit-scrollbar { + width: 10px; +} + +.built-in-commands-modal + .aurora-scroll-container-scrollview::-webkit-scrollbar-track { + background: rgba(10, 14, 18, 0.9); + border-radius: 999px; +} + +.built-in-commands-modal + .aurora-scroll-container-scrollview::-webkit-scrollbar-thumb { + background: linear-gradient( + 180deg, + rgba(54, 65, 76, 0.95) 0%, + rgba(30, 38, 46, 0.95) 100% + ); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 999px; +} + +.built-in-commands-modal + .aurora-scroll-container-scrollview::-webkit-scrollbar-thumb:hover { + background: linear-gradient( + 180deg, + rgba(70, 82, 95, 0.98) 0%, + rgba(40, 49, 58, 0.98) 100% + ); +} + +@media (max-width: 900px) { + .built-in-commands-modal__panel { + width: auto; + min-height: 360px; + max-height: calc(100vh - 24px); + left: 12px; + right: 12px; + top: 18%; + transform: translate(0, 0) scale(0.985); + } + + .built-in-commands-modal--open .built-in-commands-modal__panel { + transform: translate(0, 0) scale(1); + } + + .built-in-commands-modal__section { + padding: 16px; + } + + .built-in-commands-modal__section--middle { + flex-basis: 280px; + height: 280px; + min-height: 280px; + } + + .built-in-commands-modal__result-item { + flex-direction: column; + gap: 6px; + } +} diff --git a/app/src/css/file-system-autocomplete.scss b/app/src/css/file-system-autocomplete.scss new file mode 100644 index 0000000..2178249 --- /dev/null +++ b/app/src/css/file-system-autocomplete.scss @@ -0,0 +1,69 @@ +.file-system-autocomplete { + position: fixed; + z-index: 150; + overflow-y: auto; + padding: 6px; + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 8px; + background: #111315; + box-shadow: + 0 18px 42px rgba(0, 0, 0, 0.42), + 0 0 0 1px rgba(255, 255, 255, 0.03) inset; + color: var(--white-color); +} + +.file-system-autocomplete--hidden { + display: none; +} + +.file-system-autocomplete__item { + display: flex; + align-items: center; + gap: 10px; + width: 100%; + min-height: 42px; + padding: 9px 10px; + border: 0; + border-radius: 6px; + background: transparent; + color: inherit; + cursor: pointer; + font: inherit; + line-height: 1.35; + text-align: left; +} + +.file-system-autocomplete__item:hover, +.file-system-autocomplete__item--selected { + background: rgba(28, 117, 219, 0.22); +} + +.file-system-autocomplete__item i { + flex: 0 0 auto; + width: 18px; + color: var(--blue-color); + font-size: 18px; +} + +.file-system-autocomplete__label { + min-width: 0; + overflow: hidden; + line-height: 1.35; + text-overflow: ellipsis; + white-space: nowrap; +} + +.file-system-autocomplete__empty { + padding: 10px; + color: rgba(255, 255, 255, 0.58); + font-size: 0.95rem; +} + +.file-system-autocomplete::-webkit-scrollbar { + width: 6px; +} + +.file-system-autocomplete::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.2); + border-radius: 12px; +} diff --git a/app/src/css/style.scss b/app/src/css/style.scss new file mode 100644 index 0000000..c630931 --- /dev/null +++ b/app/src/css/style.scss @@ -0,0 +1,863 @@ +@use 'sass:meta'; + +@import '@fontsource/source-sans-pro/200.css'; +@import '@fontsource/source-sans-pro/300.css'; +@import '@fontsource/source-sans-pro/400.css'; +@import '@fontsource/source-sans-pro/600.css'; +@import '@fontsource/source-sans-pro/700.css'; +@import '@fontsource/source-sans-pro/900.css'; +@import 'remixicon/fonts/remixicon.css'; + +@include meta.load-css('tool-ui'); +@include meta.load-css('voice-energy/main'); +@include meta.load-css('file-system-autocomplete'); + +html, +body, +div, +span, +applet, +object, +iframes, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +sub, +sup, +tt, +var, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + vertical-align: baseline; +} + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} + +blockquote, +q { + quotes: none; +} + +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ''; + content: none; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +* { + box-sizing: border-box; + outline: none; +} + +:root { + color-scheme: dark; + + --black-color: #000; + --light-black-color: #222426; + --white-color: #fff; + --grey-color: #323739; + --blue-color: #1c75db; + --pink-color: #ed297a; + --sessions-panel-width: 292px; + + --a-loader-size-md: 20px !important; +} + +a { + color: inherit; +} + +#feed ul li:not(.aurora-list-item) { + margin-left: 20px; +} + +body { + color: var(--white-color); + background-color: var(--black-color); + font-family: + 'Source Sans Pro', + system-ui, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + 'Helvetica Neue', + Arial, + 'Noto Sans', + sans-serif, + 'Apple Color Emoji', + 'Segoe UI Emoji', + 'Segoe UI Symbol', + 'Noto Color Emoji'; + font-weight: 400; +} + + +@keyframes plan-tool-status-cozy-shine { + 0% { + opacity: 0.4; + filter: drop-shadow(0 0 0 rgba(255, 255, 255, 0)); + } + + 50% { + opacity: 1; + filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.22)); + } + + 100% { + opacity: 0.4; + filter: drop-shadow(0 0 0 rgba(255, 255, 255, 0)); + } +} + +#feed + .bubble-container[data-message-id^='plan-'] + .aurora-list + .aurora-list-item--center:last-child + .aurora-status + .aurora-icon { + animation: plan-tool-status-cozy-shine 2.6s ease-in-out infinite; +} + +body > * { + transition: opacity 0.5s; +} +body.settingup > *:not(#init) { + opacity: 0; +} +#init .not-initialized { + visibility: hidden; +} +#init .initialized { + opacity: 0; + visibility: hidden; +} + +kbd { + font-family: 'Source Sans Pro', monospace; + display: inline-block; + background-color: var(--light-black-color); + color: rgba(255, 255, 255, 0.4); + border-radius: 4px; + text-align: center; + min-width: 16px; + min-height: 16px; + line-height: 16px !important; + padding: 2px 6px !important; + margin: 0 !important; +} + +#sessions-panel { + position: absolute; + left: 2%; + top: 2%; + bottom: 8%; + width: var(--sessions-panel-width); + border-right: 1px solid rgba(255, 255, 255, 0.12); + color: var(--white-color); + overflow: hidden; +} + +#sessions-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 14px 14px 0; +} + +#sessions-eyebrow { + color: rgba(255, 255, 255, 0.42); + font-size: 0.9rem; + font-weight: 700; + text-transform: uppercase; +} + +#new-session, +.session-action { + border: 0; + background: rgba(255, 255, 255, 0.08); + color: var(--white-color); + cursor: pointer; + transition: + background-color 0.18s, + color 0.18s, + transform 0.18s; +} + +#new-session { + width: 34px; + height: 34px; + border-radius: 8px; + font-size: 1.2rem; +} + +#new-session:hover, +.session-action:hover { + background: rgba(28, 117, 219, 0.22); + color: #86bdff; +} + +#sessions-list { + height: calc(100% - 48px); + padding-right: 14px; + overflow-y: auto; +} + +#sessions-list::-webkit-scrollbar { + width: 6px; +} + +#sessions-list::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.16); + border-radius: 12px; +} + +.session-group { + position: relative; + padding: 0 0 12px 14px; +} + +.session-group::before { + content: ''; + position: absolute; + left: 3px; + top: 22px; + bottom: 0; + width: 1px; + background: linear-gradient( + rgba(28, 117, 219, 0.7), + rgba(237, 41, 122, 0.22) + ); +} + +.session-group-title { + position: relative; + margin-bottom: 8px; + color: rgba(255, 255, 255, 0.44); + font-size: 0.78rem; + font-weight: 700; + text-transform: uppercase; +} + +.session-group-title::before { + content: ''; + position: absolute; + left: -14px; + top: 7px; + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--blue-color); + box-shadow: 0 0 12px rgba(28, 117, 219, 0.8); +} + +.session-item { + position: relative; + padding: 10px 8px; + border-radius: 8px; + cursor: pointer; + animation: sessionTimelineIn 0.24s ease-out both; +} + +.session-item:hover, +.session-item--active { + background: rgba(255, 255, 255, 0.07); +} + +.session-item--active::before { + content: ''; + position: absolute; + left: -11px; + top: 18px; + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--pink-color); + box-shadow: 0 0 10px rgba(237, 41, 122, 0.9); +} + +.session-title { + overflow: hidden; + color: rgba(255, 255, 255, 0.9); + font-size: 0.98rem; + font-weight: 700; + line-height: 1.2rem; + text-overflow: ellipsis; + white-space: nowrap; +} + +.session-meta { + overflow: hidden; + margin-top: 2px; + color: rgba(255, 255, 255, 0.36); + font-size: 0.8rem; + line-height: 1rem; + text-overflow: ellipsis; + white-space: nowrap; +} + +.session-actions { + display: flex; + gap: 4px; + margin-top: 8px; + opacity: 0; + transition: opacity 0.16s; +} + +.session-item:hover .session-actions, +.session-item--active .session-actions { + opacity: 1; +} + +.session-action { + width: 26px; + height: 26px; + border-radius: 6px; +} + +.session-action[aria-pressed='true'] { + color: #ff7caf; +} + +@keyframes sessionTimelineIn { + from { + opacity: 0; + transform: translateY(8px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +main { + position: absolute; + width: calc(94% - var(--sessions-panel-width)); + top: 0; + left: calc(4% + var(--sessions-panel-width)); + height: 100%; +} + +#footer { + display: flex; + position: absolute; + align-items: center; + justify-content: space-between; + left: calc(4% + var(--sessions-panel-width)); + bottom: 2%; + width: calc(94% - var(--sessions-panel-width)); + line-height: 18px; +} +#logo-container { + display: flex; + gap: 6px; + align-items: center; +} +#version { + color: var(--grey-color); +} + +textarea { + font-family: inherit; + text-align: center; + color: var(--white-color); + width: 100%; + border: none; + border-bottom: 2px solid var(--grey-color); + background: none; + font-weight: 600; + font-size: 4em; + padding-right: 39px; + height: 140px; + resize: none; + overflow-y: auto; +} +textarea::-webkit-scrollbar { + width: 6px; +} +textarea::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.2); + border-radius: 12px; +} + +#tip { + display: inline-flex; + margin-top: 2px; + color: var(--white-color); + line-height: 22px; + font-size: 0.9em; + gap: 20px; + li { + margin-left: 0; + } +} + +.hide { + display: none; +} + +#logo { + background: no-repeat url(../img/logo.svg); + width: 34px; + height: 34px; +} + +#top-container { + position: absolute; + top: 2%; + color: var(--grey-color); + display: flex; + width: 100%; + justify-content: space-between; +} +#mood { + position: relative; + font-size: 16px; +} +#info { + position: relative; + text-decoration: underline; + background: none; + border: none; + color: var(--grey-color); + cursor: pointer; + font-size: inherit; +} + +#feed { + position: absolute; + width: 100%; + top: 6%; + height: 58%; + overflow-y: auto; + border: 2px solid var(--grey-color); + border-radius: 12px; +} +#feed::-webkit-scrollbar { + width: 6px; +} +#feed::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.2); + border-radius: 12px; +} + +#no-bubble { + margin-top: 64px; + text-align: center; +} + +#is-typing { + position: absolute; + top: 65%; + padding: 0 8px; + opacity: 0; + transition: opacity 0.3s; +} +#is-typing.on { + opacity: 1; +} + +#is-typing .circle { + display: inline-block; + border-radius: 50%; + width: 10px; + height: 10px; + background-color: var(--white-color); + transform: scale(1); +} +#is-typing .circle:nth-child(1) { + animation: typing 0.2s linear infinite alternate; + background-color: #0071f0; +} +#is-typing .circle:nth-child(2) { + animation: typing 0.2s 0.2s linear infinite alternate; + background-color: var(--white-color); +} +#is-typing .circle:nth-child(3) { + animation: typing 0.2s linear infinite alternate; + background-color: #ec297a; +} +@keyframes typing { + 100% { + transform: scale(1.5); + } +} + +.llm-token { + opacity: 0; + transition: opacity 2.5s; +} + +.llm-token.fade-in { + animation: fadeIn 2.5s forwards; +} + +.reasoning-block-container { + padding: 6px; + text-align: left; +} + +.reasoning-block { + max-width: 72%; + border: 1px solid rgba(255, 255, 255, 0.16); + border-radius: 12px; + background-color: #111315; + overflow: hidden; + animation: fadeIn 0.2s ease-in forwards; +} + +.reasoning-header { + display: flex; + align-items: center; + gap: 6px; + padding: 8px 12px; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + background-color: rgba(255, 255, 255, 0.03); +} + +.reasoning-icon { + color: var(--blue-color); + font-size: 15px; +} + +.reasoning-title { + font-size: 0.85rem; + letter-spacing: 0.04em; + text-transform: uppercase; + color: rgba(255, 255, 255, 0.8); +} + +.reasoning-content { + padding: 10px 12px; + font-family: 'Courier New', Consolas, monospace; + font-size: 0.95rem; + line-height: 1.45; + color: rgba(255, 255, 255, 0.82); + white-space: pre-wrap; + word-break: break-word; + max-height: 296px; + overflow-y: auto; +} + +.reasoning-content::-webkit-scrollbar { + width: 6px; +} + +.reasoning-content::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.2); + border-radius: 12px; +} + +.reasoning-token { + opacity: 0; +} + +.reasoning-token.fade-in { + animation: fadeIn 0.35s forwards; +} + +.bubble-container { + padding: 6px; + display: flex; + flex-direction: column; + width: fit-content; + max-width: 85%; +} +.bubble-container.me { + margin-left: auto; + align-items: flex-end; + text-align: right; +} +.bubble-container.leon { + margin-right: auto; + align-items: flex-start; + text-align: left; +} +.show-more { + margin: 3px; + text-decoration: underline; +} +.show-more:hover { + cursor: pointer; + text-decoration: none; +} +.show-all { + max-height: 100% !important; +} + +.bubble { + padding: 10px 16px; + border-radius: 16px; + display: inline-block; + max-width: 100%; + word-break: break-word; + text-align: left; + opacity: 0; + animation: fadeIn 0.2s ease-in forwards; + overflow: hidden; + font-size: 1.8rem; + line-height: 2.4rem; +} +.bubble-metrics { + cursor: default; + margin-top: 2px; + padding: 0 4px; + display: inline-flex; + flex-wrap: wrap; + justify-content: flex-end; + gap: 10px; + font-size: 0.95rem; + line-height: 1.2rem; + color: var(--grey-color); + align-self: flex-end; + text-align: right; +} +.bubble-metric-item { + display: inline-flex; + align-items: center; + gap: 4px; +} +.bubble-metric-item i { + font-size: 1rem; +} +#feed .me .bubble-metrics { + text-align: right; +} +#feed .me .bubble { + background-color: #1c75db; + color: var(--white-color); + right: 0; +} +#feed .leon .bubble { + background-color: var(--light-black-color); + color: var(--white-color); +} +@keyframes fadeIn { + 100% { + opacity: 1; + } +} + +#input-container { + position: absolute; + width: 100%; + bottom: 13%; +} + +#mic-container { + position: absolute; + right: 0; + margin-top: 38px; +} + +.italic { + font-style: italic; +} + +#mic-button { + position: absolute; + border: none; + cursor: pointer; + height: 26px; + width: 26px; + border-radius: 50%; + background-color: #888; + -webkit-mask-image: url(../img/mic.svg); + mask-image: url(../img/mic.svg); + transition: background-color 0.2s; +} +#mic-button:not(.enabled) { + margin-left: -26px; +} +#mic-button:hover { + background-color: var(--white-color); +} +#mic-button.enabled { + background-color: #00e676; +} +#mic-button.enabled + #sonar { + width: 26px; + height: 26px; + border-radius: 50%; + opacity: 0.3; + background-color: #575757; + pointer-events: none; + animation: sonar 1.3s linear infinite; +} +@keyframes sonar { + 25% { + transform: scale(1.5); + } + 50% { + transform: scale(1.2); + } + 60% { + transform: scale(1.5); + } + 75% { + transform: scale(2); + } + 100% { + transform: scale(1); + } +} + +/* Clickable URL styles */ +.clickable-url { + text-decoration: underline; +} + +/* Clickable file path styles */ +.clickable-path { + cursor: pointer; + text-decoration: underline; +} + +@media (max-width: 940px) { + :root { + --sessions-panel-width: 100%; + } + + #sessions-panel { + left: 4%; + right: 4%; + top: 1%; + bottom: auto; + width: auto; + height: 168px; + border-right: 0; + border-bottom: 1px solid rgba(255, 255, 255, 0.12); + } + + #sessions-list { + display: flex; + gap: 12px; + height: 112px; + overflow-x: auto; + overflow-y: hidden; + } + + .session-group { + min-width: 220px; + } + + main { + top: 176px; + left: 4%; + width: 92%; + height: calc(100% - 176px); + } + + #footer { + display: none; + } + + #top-container { + top: 1%; + } + + #feed { + top: 7%; + height: 50%; + } + + #is-typing { + top: 58%; + } + + textarea { + font-size: 2.4em; + } + + #tip { + flex-wrap: wrap; + gap: 8px; + } +} diff --git a/app/src/css/tool-ui.scss b/app/src/css/tool-ui.scss new file mode 100644 index 0000000..ff377a8 --- /dev/null +++ b/app/src/css/tool-ui.scss @@ -0,0 +1,418 @@ +/* Tool Output Container Styles */ +.tool-group-container { + margin: 10px 6px; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 14px; + background: + linear-gradient( + 180deg, + rgba(255, 255, 255, 0.04) 0%, + rgba(255, 255, 255, 0.02) 100% + ), + #15181a; + box-shadow: + 0 10px 30px rgba(0, 0, 0, 0.24), + inset 0 1px 0 rgba(255, 255, 255, 0.03); + opacity: 0; + animation: fadeIn 0.3s ease-in forwards; + overflow: hidden; +} + +.tool-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + width: 100%; + padding: 14px 16px; + background: transparent; + border: 0; + cursor: pointer; + color: inherit; + text-align: left; + transition: background-color 0.2s ease; +} + +.tool-header:hover { + background-color: rgba(255, 255, 255, 0.03); +} + +.tool-icon { + color: var(--blue-color); + font-size: 18px; + flex-shrink: 0; +} + +.tool-name { + flex: 1; + font-weight: 600; + color: var(--white-color); + font-size: 0.95em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.expand-icon { + color: rgba(255, 255, 255, 0.48); + font-size: 18px; + transition: transform 0.2s ease; +} + +.expand-icon.rotated { + transform: rotate(180deg); +} + +.tool-content { + max-height: 0; + overflow: hidden; + transition: max-height 0.3s ease, border-top-color 0.2s ease; + border-top: 1px solid transparent; +} + +.tool-content.expanded { + max-height: 900px; + overflow-y: auto; + border-top-color: rgba(255, 255, 255, 0.06); +} + +.tool-content::-webkit-scrollbar { + width: 4px; +} + +.tool-content::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.1); + border-radius: 2px; +} + +.shell-output { + padding: 12px; + background-color: #0d1117; + border-radius: 0 0 14px 14px; + min-height: 40px; + font-family: 'Courier New', Consolas, monospace; + font-size: 0.9em; +} + +.shell-message { + margin: 2px 0; + line-height: 1.4; + color: #e6edf3; + word-break: break-word; +} + +.shell-prompt { + color: var(--pink-color); + font-weight: bold; + margin-right: 8px; +} + +.shell-message .clickable-path { + color: var(--blue-color); + background-color: rgba(28, 117, 219, 0.1); + padding: 1px 4px; + border-radius: 3px; + border: 1px solid rgba(28, 117, 219, 0.3); +} + +.shell-message .clickable-url { + color: var(--blue-color); +} + +.tool-activity-card { + background: + radial-gradient( + circle at top right, + rgba(28, 117, 219, 0.14), + transparent 32% + ), + linear-gradient( + 180deg, + rgba(255, 255, 255, 0.04) 0%, + rgba(255, 255, 255, 0.02) 100% + ), + #15181a; +} + +.agent-skill-activity-card { + background: + radial-gradient( + circle at top right, + rgba(237, 41, 122, 0.14), + transparent 32% + ), + linear-gradient( + 180deg, + rgba(255, 255, 255, 0.04) 0%, + rgba(255, 255, 255, 0.02) 100% + ), + #15181a; +} + +.agent-skill-activity-card .tool-icon { + color: #ed297a; +} + +.tool-activity-header { + align-items: flex-start; +} + +.tool-activity-heading { + display: flex; + align-items: flex-start; + gap: 12px; + min-width: 0; + flex: 1; +} + +.tool-activity-title-block { + display: flex; + flex-direction: column; + min-width: 0; + gap: 2px; +} + +.tool-title { + color: var(--white-color); + font-size: 1rem; + font-weight: 700; + line-height: 1.2; +} + +.tool-subtitle { + color: rgba(255, 255, 255, 0.58); + font-size: 0.86rem; + line-height: 1.2; +} + +.tool-activity-meta { + display: flex; + align-items: center; + gap: 10px; + flex-shrink: 0; +} + +.tool-status-chip { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 72px; + padding: 5px 10px; + border-radius: 999px; + border: 1px solid transparent; + font-size: 0.76rem; + font-weight: 700; + letter-spacing: 0.02em; + text-transform: uppercase; +} + +.tool-status-chip.running { + color: #9fd2ff; + background-color: rgba(28, 117, 219, 0.14); + border-color: rgba(28, 117, 219, 0.28); +} + +.tool-status-chip.success { + color: #93f0c1; + background-color: rgba(36, 178, 101, 0.15); + border-color: rgba(36, 178, 101, 0.28); +} + +.tool-status-chip.selected { + color: #93f0c1; + background-color: rgba(36, 178, 101, 0.15); + border-color: rgba(36, 178, 101, 0.28); +} + +.tool-status-chip.observed { + color: #f5d48a; + background-color: rgba(210, 157, 38, 0.15); + border-color: rgba(210, 157, 38, 0.3); +} + +.tool-status-chip.error { + color: #ffb0b0; + background-color: rgba(237, 41, 122, 0.14); + border-color: rgba(237, 41, 122, 0.28); +} + +.tool-activity-summary { + padding: 16px 16px 4px; + color: rgba(255, 255, 255, 0.82); + font-size: 0.95rem; + line-height: 1.45; +} + +.tool-activity-sections { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px; + padding: 12px 16px 16px; +} + +.tool-activity-sections.single { + grid-template-columns: 1fr; +} + +.tool-activity-panel { + border: 1px solid rgba(255, 255, 255, 0.07); + border-radius: 12px; + background-color: rgba(255, 255, 255, 0.025); + min-width: 0; +} + +.tool-panel-heading { + display: flex; + flex-direction: column; + gap: 2px; + padding: 12px 14px 10px; + border-bottom: 1px solid rgba(255, 255, 255, 0.06); +} + +.tool-panel-title { + color: var(--white-color); + font-size: 0.84rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.tool-panel-description { + color: rgba(255, 255, 255, 0.5); + font-size: 0.78rem; +} + +.tool-panel-body { + padding: 12px 14px 14px; + min-height: 72px; +} + +.tool-output-summary { + margin-bottom: 10px; + color: rgba(255, 255, 255, 0.86); + line-height: 1.45; +} + +.tool-empty-state { + color: rgba(255, 255, 255, 0.45); + font-size: 0.88rem; + line-height: 1.4; +} + +.tool-kv-list { + display: flex; + flex-direction: column; + gap: 10px; +} + +.tool-kv-row { + display: flex; + flex-direction: column; + gap: 4px; +} + +.tool-kv-key { + color: rgba(255, 255, 255, 0.52); + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.03em; + text-transform: uppercase; +} + +.tool-kv-value { + color: rgba(255, 255, 255, 0.88); + min-width: 0; +} + +.tool-rich-text { + color: rgba(255, 255, 255, 0.88); + line-height: 1.45; + word-break: break-word; +} + +.tool-command-output { + margin: 0; + max-height: 320px; + overflow: auto; + color: rgba(255, 255, 255, 0.86); + font-family: 'Courier New', Consolas, monospace; + font-size: 0.84rem; + line-height: 1.45; + white-space: pre-wrap; + word-break: break-word; +} + +.tool-rich-text .clickable-path { + color: var(--blue-color); + background-color: rgba(28, 117, 219, 0.1); + padding: 1px 4px; + border-radius: 3px; + border: 1px solid rgba(28, 117, 219, 0.3); +} + +.tool-rich-text .clickable-url { + color: var(--blue-color); +} + +.tool-value-list { + display: flex; + flex-direction: column; + gap: 8px; + margin-left: 18px; +} + +.tool-value-list li { + color: rgba(255, 255, 255, 0.88); + line-height: 1.4; +} + +.tool-raw-details { + margin: 0 16px 16px; + border-top: 1px solid rgba(255, 255, 255, 0.06); + padding-top: 12px; +} + +.tool-raw-details summary { + cursor: pointer; + color: rgba(255, 255, 255, 0.62); + font-size: 0.82rem; + font-weight: 700; + letter-spacing: 0.03em; + text-transform: uppercase; + list-style: none; +} + +.tool-raw-details summary::-webkit-details-marker { + display: none; +} + +.tool-raw-content { + margin-top: 12px; + padding: 12px 14px; + border-radius: 10px; + background-color: rgba(0, 0, 0, 0.3); + color: rgba(255, 255, 255, 0.78); + font-family: 'Courier New', Consolas, monospace; + font-size: 0.84rem; + line-height: 1.45; + overflow-x: auto; +} + +@media screen and (max-width: 700px) { + .tool-activity-sections { + grid-template-columns: 1fr; + } + + .tool-activity-header { + gap: 10px; + } + + .tool-activity-meta { + align-items: flex-end; + } + + .tool-status-chip { + min-width: 64px; + padding: 5px 8px; + } +} diff --git a/app/src/css/voice-energy/_variables.scss b/app/src/css/voice-energy/_variables.scss new file mode 100644 index 0000000..dfbd53c --- /dev/null +++ b/app/src/css/voice-energy/_variables.scss @@ -0,0 +1,8 @@ +@use 'sass:color'; + +$voice-neon-pink-color: #ed297a; +$voice-neon-blue-color: #1c75db; +$voice-neon-shadow-color: color.mix( + $voice-neon-pink-color, + $voice-neon-blue-color +); diff --git a/app/src/css/voice-energy/base.scss b/app/src/css/voice-energy/base.scss new file mode 100644 index 0000000..07795d9 --- /dev/null +++ b/app/src/css/voice-energy/base.scss @@ -0,0 +1,162 @@ +/** + * Overlay and containers + */ + +body.voice-mode-enabled { + #voice-overlay-transitor, + #voice-overlay-bg { + visibility: visible; + } + #voice-overlay-bg { + opacity: 1; + } +} +#voice-overlay-transitor { + position: fixed; + background-color: var(--black-color); + z-index: 10; + width: 12px; + height: 12px; + border-radius: 50%; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + will-change: transform; + animation: scaleIn 1s; +} +@keyframes scaleIn { + 0% { + transform: scale3d(0, 0, 1); + } + 100% { + transform: scale3d(172, 172, 1); + } +} + +#voice-status, +#voice-tips { + color: var(--grey-color); + text-align: center; +} +#voice-status { + font-size: 17px; + font-style: italic; +} +#voice-tips { + margin-top: 32px; + line-height: 18px; + font-size: 15px; +} + +#voice-overlay-bg { + visibility: hidden; + cursor: pointer; + opacity: 0; + position: fixed; + width: 100vw; + height: 100vh; + z-index: 100; + will-change: opacity; + display: flex; + justify-content: center; + // backdrop-filter: saturate(140%) blur(5px); + /*background-color: rgba(0, 0, 0, .9);*/ + background-color: var(--black-color); +} +@keyframes skipFadeIn { + 0% { + opacity: 1; + } + 100% { + opacity: 1; + } +} + +#voice-container { + opacity: 0; + position: relative; + top: 64px; + display: flex; + flex-direction: column; + width: 1024px; + height: 756px; + align-items: center; + gap: 64px; + animation: fadeIn 1s 3s both; +} + +#voice-energy-container { + --neon-size: 228px; + + // animation: fadeIn 1s 1.5s both; + //opacity: 0; + overflow: hidden; + position: relative; + height: 400px; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; +} +p#voice-speech { + width: 100%; + height: 100%; + flex: 1; + text-align: center; + font-size: 3rem; + font-weight: 600; +} + +/** + * Neons + */ + +.voice-neon { + position: absolute; + z-index: 10; + width: var(--neon-size); + height: var(--neon-size); +} + +#purple-neon-blur { + --neon-blur: calc(var(--neon-size) + 96px); + + position: absolute; + z-index: 0; + opacity: 0.7; + width: var(--neon-blur); + height: var(--neon-blur); +} + +#blue-neon-1 { + margin-top: -8px; + margin-left: 12px; +} + +#blue-neon-2 { + margin-top: 8px; + margin-right: 12px; +} + +/** + * Particles + */ + +.voice-particle { + position: absolute; + width: 3px; + height: 3px; + border-radius: 50%; + opacity: 1; + will-change: transform, opacity; + animation-duration: 1s; + animation-iteration-count: infinite; +} +.voice-particle.blue { + background-color: #c4e0ff; + box-shadow: 0 0 2px 2px var(--blue-color); +} +.voice-particle.pink { + background-color: #ffb9d7; + box-shadow: 0 0 2px 2px var(--pink-color); +} diff --git a/app/src/css/voice-energy/idle.scss b/app/src/css/voice-energy/idle.scss new file mode 100644 index 0000000..001e884 --- /dev/null +++ b/app/src/css/voice-energy/idle.scss @@ -0,0 +1,61 @@ +@use 'variables' as *; + +/** + * IDLE status + */ + +#voice-energy-container.idle { + .voice-particle { + visibility: hidden; + animation-play-state: paused; + opacity: 0; + } + .voice-neon { + margin: 0; + } + #purple-neon-blur { + transform: scale(1); + } + #purple-neon-blur circle { + filter: drop-shadow(0px 0px 64px $voice-neon-shadow-color); + animation: idleNeonBlurBreath 2.2s infinite alternate; + } + #pink-neon-1 { + transform: scale(1); + animation: idleBouncePinkNeon1 1.8s 1s infinite alternate; + } + #blue-neon-1 { + transform: scale(0.8); + animation: idleMoveBlueNeon1 1.8s infinite alternate; + } + #blue-neon-2 { + transform: scale(0.9); + animation: idleMoveBlueNeon2 1.8s 0.5s infinite alternate; + } +} + +@keyframes idleNeonBlurBreath { + 100% { + filter: drop-shadow(0px 0px 0px $voice-neon-shadow-color); + } +} +@keyframes idleBouncePurpleNeonBlur { + 100% { + transform: scale(1); + } +} +@keyframes idleBouncePinkNeon1 { + 100% { + transform: scale(1.1); + } +} +@keyframes idleMoveBlueNeon1 { + 100% { + transform: scale(0.9); + } +} +@keyframes idleMoveBlueNeon2 { + 100% { + transform: scale(1); + } +} diff --git a/app/src/css/voice-energy/listening.scss b/app/src/css/voice-energy/listening.scss new file mode 100644 index 0000000..f5a7f68 --- /dev/null +++ b/app/src/css/voice-energy/listening.scss @@ -0,0 +1,61 @@ +@use 'variables' as *; + +/** + * Listening status + */ + +#voice-energy-container.listening { + .voice-particle { + visibility: hidden; + animation-play-state: paused; + opacity: 0; + } + .voice-neon { + margin: 0; + } + #purple-neon-blur { + transform: scale(1); + } + #purple-neon-blur circle { + filter: drop-shadow(0px 0px 64px $voice-neon-shadow-color); + animation: listeningNeonBlurBreath 0.7s infinite alternate; + } + #pink-neon-1 { + transform: scale(1); + animation: listeningBouncePinkNeon1 0.3s 1s infinite alternate; + } + #blue-neon-1 { + transform: scale(0.8); + animation: listeningMoveBlueNeon1 0.3s infinite alternate; + } + #blue-neon-2 { + transform: scale(0.9); + animation: listeningMoveBlueNeon2 0.3s 0.5s infinite alternate; + } +} + +@keyframes listeningNeonBlurBreath { + 100% { + filter: drop-shadow(0px 0px 0px $voice-neon-shadow-color); + } +} +@keyframes listeningBouncePurpleNeonBlur { + 100% { + transform: scale(1); + } +} +@keyframes listeningBouncePinkNeon1 { + 100% { + transform: scale(1.1); + } +} +@keyframes listeningMoveBlueNeon1 { + 100% { + transform: scale(0.9); + } +} +@keyframes listeningMoveBlueNeon2 { + 100% { + transform: scale(1); + } +} diff --git a/app/src/css/voice-energy/main.scss b/app/src/css/voice-energy/main.scss new file mode 100644 index 0000000..e72ce4f --- /dev/null +++ b/app/src/css/voice-energy/main.scss @@ -0,0 +1,5 @@ +@use 'base'; +@use 'listening'; +@use 'idle'; +@use 'processing'; +@use 'talking'; diff --git a/app/src/css/voice-energy/processing.scss b/app/src/css/voice-energy/processing.scss new file mode 100644 index 0000000..93741fb --- /dev/null +++ b/app/src/css/voice-energy/processing.scss @@ -0,0 +1,88 @@ +@use 'sass:math'; + +/** + * Processing status + */ + +#voice-energy-container.processing { + #purple-neon-blur { + animation: processingBouncePurpleNeonBlur 1s infinite alternate; + } + #pink-neon-1 { + animation: processingBouncePinkNeon1 0.5s infinite alternate; + } + #blue-neon-1 { + animation: processingMoveBlueNeon1 0.5s infinite alternate; + } + #blue-neon-2 { + animation: processingMoveBlueNeon2 0.5s infinite alternate; + } +} + +@keyframes processingBouncePurpleNeonBlur { + 50% { + transform: scale(1.07); + } + 100% { + transform: scale(1); + } +} +@keyframes processingBouncePinkNeon1 { + 50% { + transform: scale(1.02); + } + 100% { + transform: scale(1); + } +} +@keyframes processingMoveBlueNeon1 { + 0% { + transform: translateX(0) translateY(0); + } + 33% { + transform: translateY(-3px) translateX(-2px); + } + 66% { + transform: translateY(-3px) translateX(3px); + } + 100% { + transform: translateY(-3px) translateX(1px); + } +} +@keyframes processingMoveBlueNeon2 { + 0% { + transform: translateX(0) translateY(0); + } + 33% { + transform: translateY(3px) translateX(2px); + } + 66% { + transform: translateY(3px) translateX(3px); + } + 100% { + transform: translateY(3px) translateX(-1px); + } +} + +@for $i from 0 through 31 { + .processing .voice-particle[data-particle='#{$i}'] { + animation-delay: #{$i * 0.1}s; + } + + .processing .voice-particle[data-particle='#{$i}'] { + animation-name: processingMoveParticle#{$i}; + } + + #voice-energy-container.processing { + @keyframes processingMoveParticle#{$i} { + 75% { + opacity: 0.1; + } + 100% { + opacity: 1; + transform: translateX(math.cos(11.25deg * $i) * 110px) + translateY(math.sin(11.25deg * $i) * 110px); + } + } + } +} diff --git a/app/src/css/voice-energy/talking.scss b/app/src/css/voice-energy/talking.scss new file mode 100644 index 0000000..1cd972e --- /dev/null +++ b/app/src/css/voice-energy/talking.scss @@ -0,0 +1,82 @@ +@use 'sass:math'; + +/** + * Talking status + */ + +#voice-energy-container.talking { + .voice-neon { + margin: 0; + } + #purple-neon-blur { + animation: talkingBouncePurpleNeonBlur 1s infinite alternate; + } + #pink-neon-1 { + transform: scale(1); + animation: talkingBouncePinkNeon1 0.5s 1s infinite alternate; + } + #blue-neon-1 { + transform: scale(0.8); + animation: talkingMoveBlueNeon1 0.5s infinite alternate; + } + #blue-neon-2 { + transform: scale(0.9); + animation: talkingMoveBlueNeon2 0.5s 0.3s infinite alternate; + } +} + +@keyframes talkingBouncePurpleNeonBlur { + 50% { + transform: scale(1.07); + } + 100% { + transform: scale(1); + } +} +@keyframes talkingBouncePinkNeon1 { + 100% { + transform: scale(1.1); + } +} +@keyframes talkingMoveBlueNeon1 { + 100% { + transform: scale(0.9); + } +} +@keyframes talkingMoveBlueNeon2 { + 100% { + transform: scale(1); + } +} + +.talking .voice-particle { + opacity: 0; + animation-duration: 2s; +} +@for $i from 0 through 31 { + .talking .voice-particle[data-particle='#{$i}'] { + animation-delay: #{$i * 0.2}s; + // animation-duration: #{$i * 0.5}s; + } + + .talking .voice-particle[data-particle='#{$i}'] { + animation-name: talkingMoveParticle#{$i}; + } + + #voice-energy-container.talking { + @keyframes talkingMoveParticle#{$i} { + 0% { + opacity: 1; + transform: translate(0); + } + 50% { + opacity: 0; + } + 100% { + opacity: 0; + transform: translateX(math.cos(math.random() * 360deg)) + translateY(math.sin(math.random() * 360deg)); + } + } + } +} diff --git a/app/src/custom-aurora-components/index.ts b/app/src/custom-aurora-components/index.ts new file mode 100644 index 0000000..4621391 --- /dev/null +++ b/app/src/custom-aurora-components/index.ts @@ -0,0 +1 @@ +export * from './timer' diff --git a/app/src/custom-aurora-components/timer/index.ts b/app/src/custom-aurora-components/timer/index.ts new file mode 100644 index 0000000..4621391 --- /dev/null +++ b/app/src/custom-aurora-components/timer/index.ts @@ -0,0 +1 @@ +export * from './timer' diff --git a/app/src/custom-aurora-components/timer/timer.tsx b/app/src/custom-aurora-components/timer/timer.tsx new file mode 100644 index 0000000..5a8396d --- /dev/null +++ b/app/src/custom-aurora-components/timer/timer.tsx @@ -0,0 +1,71 @@ +import { useState, useEffect } from 'react' + +import { CircularProgress, Flexbox, Text } from '@aurora' + +interface TimerProps { + initialTime: number + interval: number + totalTimeContent: string + initialProgress?: number + onEnd?: () => void +} + +function formatTime(seconds: number): string { + const minutes = seconds >= 60 ? Math.floor(seconds / 60) : 0 + const remainingSeconds = seconds % 60 + const formattedMinutes = minutes < 10 ? `0${minutes}` : minutes + const formattedSeconds = + remainingSeconds < 10 ? `0${remainingSeconds}` : remainingSeconds + + return `${formattedMinutes}:${formattedSeconds}` +} + +export function Timer({ + initialTime, + initialProgress, + interval, + totalTimeContent, + onEnd +}: TimerProps) { + const [progress, setProgress] = useState(initialProgress || 0) + const [timeLeft, setTimeLeft] = useState(initialTime) + + useEffect(() => { + setTimeLeft(initialTime) + setProgress(progress) + }, [initialTime]) + + useEffect(() => { + if (timeLeft <= 0) { + return + } + + const timer = setInterval(() => { + setTimeLeft((prevTime) => { + const newTime = prevTime - 1 + + if (newTime <= 0 && onEnd) { + onEnd() + } + + return newTime + }) + setProgress((prevProgress) => prevProgress + 100 / initialTime) + }, interval) + + return () => clearInterval(timer) + }, [initialTime, interval, timeLeft]) + + return ( + + + + {formatTime(timeLeft)} + + + {totalTimeContent} + + + + ) +} diff --git a/app/src/img/favicon.png b/app/src/img/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..b5e6f7b8e390bfa72dea95763e055e164b097f2d GIT binary patch literal 11404 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 z + + + logo + Created with Sketch. + + + + diff --git a/app/src/img/mic.svg b/app/src/img/mic.svg new file mode 100644 index 0000000..b2fa505 --- /dev/null +++ b/app/src/img/mic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/src/index.html b/app/src/index.html new file mode 100644 index 0000000..0460604 --- /dev/null +++ b/app/src/index.html @@ -0,0 +1,366 @@ + + + + + + + Leon + + + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ It is recommended to use a headset for a better voice experience. +
+ Otherwise, if your microphone is too sensitive or speakers are too + loud, +
+ Leon may hear his own voice and get confused. +
+
+

+
+
+ +
+
+
+ +
+
+

+ You can start to interact with me, don't be shy. +

+
+
+
+
+
+
+
+
+ +
+
+ + +
    +
  • enter to submit.
  • +
  • shift + enter for new line.
  • +
  • + shift + / to browse history. +
  • +
  • alt / cmd + c to listen.
  • +
  • / for commands.
  • +
  • @ for files.
  • +
+
+
+ + + + diff --git a/app/src/js/built-in-commands/api.js b/app/src/js/built-in-commands/api.js new file mode 100644 index 0000000..0e2c66b --- /dev/null +++ b/app/src/js/built-in-commands/api.js @@ -0,0 +1,7 @@ +import axios from 'axios' + +export async function requestBuiltInCommand(serverUrl, payload) { + const response = await axios.post(`${serverUrl}/api/v1/command`, payload) + + return response.data +} diff --git a/app/src/js/built-in-commands/built-in-commands.jsx b/app/src/js/built-in-commands/built-in-commands.jsx new file mode 100644 index 0000000..6a823f2 --- /dev/null +++ b/app/src/js/built-in-commands/built-in-commands.jsx @@ -0,0 +1,750 @@ +import { createRef } from 'react' +import { createRoot } from 'react-dom/client' + +import { requestBuiltInCommand } from './api' +import { BuiltInCommandsModal } from './modal' +import FileSystemAutocomplete from '../file-system-autocomplete' + +const AUTOCOMPLETE_DELAY_MS = 90 +const CLOSE_ANIMATION_DURATION_MS = 180 +const ROOT_COMMAND_INPUT = '/' +const EDITABLE_ACTION_KEYS = new Set(['Backspace', 'Delete']) +const NAVIGATION_DIRECTIONS = { + next: 1, + previous: -1 +} + +function isEditableElement(element) { + if (!element) { + return false + } + + const tagName = element.tagName?.toLowerCase() + + return ( + tagName === 'input' || + tagName === 'textarea' || + element.isContentEditable === true + ) +} + +export default class BuiltInCommands { + constructor({ + serverUrl, + input, + onSubmitToChat, + getActiveSessionId, + onCommandExecuted + }) { + this.serverUrl = serverUrl + this.input = input + this.onSubmitToChat = onSubmitToChat + this.getActiveSessionId = getActiveSessionId + this.onCommandExecuted = onCommandExecuted + this.sessionId = null + this.origin = 'shortcut' + this.commandValue = '' + this.selectedSuggestionIndex = -1 + this.suggestions = [] + this.recentSuggestions = [] + this.result = null + this.loadingMessage = null + this.pendingInput = null + this.isOpen = false + this.isClosing = false + this.isLoading = false + this.hasSubmitted = false + this.autocompleteTimeout = null + this.closeTimeout = null + this.shouldFocusInput = false + this.modalInputRef = createRef() + this.fileSystemAutocomplete = new FileSystemAutocomplete({ + serverUrl, + onValueChange: (value) => { + this.handleCommandChange(value) + } + }) + } + + init() { + this.mount() + this.attachEvents() + this.render() + } + + mount() { + this.container = document.createElement('div') + document.body.appendChild(this.container) + this.root = createRoot(this.container) + } + + attachEvents() { + document.addEventListener('keydown', (event) => { + this.handleDocumentKeyDown(event) + }) + + this.input.addEventListener('input', () => { + this.handleMainInput() + }) + + this.input.addEventListener('focus', () => { + this.handleMainInput() + }) + } + + render() { + const focusedInputElement = this.modalInputRef.current + const shouldRestoreCommandInputFocus = + focusedInputElement && document.activeElement === focusedInputElement + const selectionStart = shouldRestoreCommandInputFocus + ? focusedInputElement.selectionStart + : null + const selectionEnd = shouldRestoreCommandInputFocus + ? focusedInputElement.selectionEnd + : null + const { recentSelectedSuggestionIndex, suggestionSelectedSuggestionIndex } = + this.getSelectedSuggestionIndices() + + this.root.render( + { + this.handleCommandChange(value) + }} + onMaskClick={() => { + this.close() + }} + onSuggestionSelect={(suggestion) => { + this.handleSuggestionSelect(suggestion) + }} + onReturn={() => { + this.returnToSuggestions() + }} + /> + ) + + if (this.shouldFocusInput) { + this.shouldFocusInput = false + + window.requestAnimationFrame(() => { + this.focusCommandInput() + }) + } else if (shouldRestoreCommandInputFocus) { + window.requestAnimationFrame(() => { + this.restoreCommandInputFocus(selectionStart, selectionEnd) + }) + } + + if ( + this.isOpen && + !this.hasSubmitted && + !this.result && + this.selectedSuggestionIndex >= 0 + ) { + window.requestAnimationFrame(() => { + this.scrollSelectedSuggestionIntoView() + }) + } + + window.requestAnimationFrame(() => { + this.attachFileSystemAutocomplete() + }) + } + + attachFileSystemAutocomplete() { + const inputElement = this.modalInputRef.current + + if (!inputElement) { + return + } + + this.fileSystemAutocomplete.attach(inputElement) + } + + handleDocumentKeyDown(event) { + if (this.isOpen) { + if (event.metaKey || event.ctrlKey || event.altKey) { + return + } + + if (event.key === 'Escape') { + event.preventDefault() + this.close() + return + } + + if (event.key === 'ArrowDown') { + event.preventDefault() + this.blurCommandInput() + this.moveSelection(NAVIGATION_DIRECTIONS.next) + return + } + + if (event.key === 'ArrowUp') { + event.preventDefault() + this.blurCommandInput() + this.moveSelection(NAVIGATION_DIRECTIONS.previous) + return + } + + if (event.key === 'Tab') { + const suggestion = + this.selectedSuggestionIndex >= 0 + ? this.getVisibleSuggestions()[this.selectedSuggestionIndex] + : null + + if (suggestion) { + event.preventDefault() + this.applySuggestion(suggestion, { + appendTrailingSpace: true + }) + } + + return + } + + if (event.key === 'Enter' && !event.shiftKey) { + event.preventDefault() + + if (this.selectedSuggestionIndex >= 0) { + const suggestion = + this.getVisibleSuggestions()[this.selectedSuggestionIndex] + + if (suggestion) { + this.applySuggestion(suggestion) + void this.submit() + return + } + } + + this.submit() + return + } + + if (this.shouldHandleDetachedInputKey(event)) { + event.preventDefault() + this.handleDetachedInputKey(event) + return + } + + return + } + + if ( + event.key !== '/' || + event.metaKey || + event.ctrlKey || + event.altKey || + event.shiftKey + ) { + return + } + + const activeElement = document.activeElement + + if ( + activeElement === this.input || + (activeElement && isEditableElement(activeElement)) + ) { + return + } + + event.preventDefault() + this.open({ + origin: 'shortcut', + rawInput: '/' + }) + } + + handleMainInput() { + if (document.activeElement !== this.input) { + return + } + + const rawValue = this.input.value || '' + + if (!rawValue.startsWith('/')) { + return + } + + this.open({ + origin: 'input', + rawInput: rawValue + }) + } + + handleCommandChange(value) { + this.commandValue = value + this.hasSubmitted = false + if (!this.pendingInput) { + this.result = null + this.loadingMessage = null + this.queueAutocomplete() + } + this.render() + } + + open({ origin, rawInput }) { + window.clearTimeout(this.closeTimeout) + + if (this.isOpen) { + this.origin = origin + this.commandValue = this.normalizeCommandValue(rawInput) + this.result = null + this.loadingMessage = null + this.pendingInput = null + this.hasSubmitted = false + this.shouldFocusInput = true + this.input.value = '' + this.queueAutocomplete() + this.render() + return + } + + this.origin = origin + this.sessionId = null + this.commandValue = this.normalizeCommandValue(rawInput) + this.suggestions = [] + this.result = null + this.loadingMessage = null + this.pendingInput = null + this.selectedSuggestionIndex = -1 + this.hasSubmitted = false + this.isOpen = true + this.isClosing = false + this.shouldFocusInput = true + this.input.value = '' + + if (this.origin === 'input') { + this.input.blur() + } + + this.queueAutocomplete() + this.render() + } + + close() { + if (!this.isOpen || this.isClosing) { + return + } + + this.isClosing = true + this.isOpen = false + this.fileSystemAutocomplete.close() + this.render() + + this.closeTimeout = window.setTimeout(() => { + this.resetState() + this.render() + this.focusMainInput() + }, CLOSE_ANIMATION_DURATION_MS) + } + + queueAutocomplete() { + window.clearTimeout(this.autocompleteTimeout) + this.isLoading = true + + this.autocompleteTimeout = window.setTimeout(() => { + void this.fetchAutocomplete() + }, AUTOCOMPLETE_DELAY_MS) + } + + async fetchAutocomplete() { + try { + const data = await requestBuiltInCommand(this.serverUrl, { + mode: 'autocomplete', + input: this.buildCommandInput(), + session_id: this.sessionId, + conversation_session_id: this.getActiveSessionId?.() + }) + + if (!this.isOpen || this.hasSubmitted) { + return + } + + this.sessionId = data.session.id + this.suggestions = data.suggestions || [] + this.recentSuggestions = data.recent_suggestions || [] + this.loadingMessage = data.session.loading_message || null + this.pendingInput = data.session.pending_input || null + this.selectedSuggestionIndex = + this.getVisibleSuggestions().length > 0 ? 0 : -1 + this.isLoading = false + this.render() + } catch (error) { + if (!this.isOpen || this.hasSubmitted) { + return + } + + this.isLoading = false + this.result = { + title: 'Command Error', + tone: 'error', + blocks: [ + { + type: 'list', + items: [ + { + label: error.message || 'Failed to load built-in commands.', + tone: 'error' + } + ] + } + ] + } + this.loadingMessage = null + this.render() + } + } + + async submit() { + const commandInput = this.buildCommandInput() + + if (commandInput === ROOT_COMMAND_INPUT) { + return + } + + window.clearTimeout(this.autocompleteTimeout) + this.autocompleteTimeout = null + + await this.resolveLoadingMessageForSubmission(commandInput) + + this.isLoading = true + this.hasSubmitted = true + this.result = null + this.commandValue = '' + this.suggestions = [] + this.selectedSuggestionIndex = -1 + this.render() + + try { + const data = await requestBuiltInCommand(this.serverUrl, { + mode: 'execute', + input: commandInput, + session_id: this.sessionId, + conversation_session_id: this.getActiveSessionId?.() + }) + + if (data.client_action?.type === 'submit_to_chat') { + const wasSubmitted = this.onSubmitToChat?.(data.client_action) + + if (!wasSubmitted) { + throw new Error('Failed to submit the built-in command to chat.') + } + + this.isLoading = false + this.close() + return + } + + this.sessionId = data.session.id + this.isLoading = false + this.result = data.result + this.onCommandExecuted?.(commandInput, data) + this.loadingMessage = data.session.loading_message || null + this.recentSuggestions = data.recent_suggestions || [] + this.pendingInput = data.session.pending_input || null + this.commandValue = '' + this.render() + } catch (error) { + this.isLoading = false + this.result = { + title: 'Command Error', + tone: 'error', + blocks: [ + { + type: 'list', + items: [ + { + label: + error.message || 'Failed to execute the built-in command.', + tone: 'error' + } + ] + } + ] + } + this.loadingMessage = null + this.render() + } + } + + async resolveLoadingMessageForSubmission(commandInput) { + try { + const data = await requestBuiltInCommand(this.serverUrl, { + mode: 'autocomplete', + input: commandInput, + session_id: this.sessionId, + conversation_session_id: this.getActiveSessionId?.() + }) + + this.sessionId = data.session.id + this.loadingMessage = data.session.loading_message || null + } catch { + this.loadingMessage = null + } + } + + moveSelection(direction) { + if (this.hasSubmitted || this.result) { + return + } + + const visibleSuggestions = this.getVisibleSuggestions() + + if (visibleSuggestions.length === 0) { + return + } + + if (this.selectedSuggestionIndex === -1) { + this.selectedSuggestionIndex = 0 + } else { + this.selectedSuggestionIndex = + (this.selectedSuggestionIndex + + direction + + visibleSuggestions.length) % + visibleSuggestions.length + } + + this.render() + } + + handleSuggestionSelect(suggestion) { + const normalizedSuggestionValue = this.normalizeCommandValue(suggestion.value) + + if (normalizedSuggestionValue.trim() === this.commandValue.trim()) { + void this.submit() + return + } + + this.applySuggestion(suggestion, { + appendTrailingSpace: true + }) + } + + applySuggestion(suggestion, options = {}) { + this.commandValue = `${this.normalizeCommandValue(suggestion.value)}${ + options.appendTrailingSpace ? ' ' : '' + }` + this.loadingMessage = null + this.queueAutocomplete() + this.shouldFocusInput = true + this.render() + } + + returnToSuggestions() { + this.sessionId = null + this.hasSubmitted = false + this.result = null + this.loadingMessage = null + this.pendingInput = null + this.commandValue = '' + this.suggestions = [] + this.selectedSuggestionIndex = -1 + this.shouldFocusInput = true + this.queueAutocomplete() + this.render() + } + + focusCommandInput() { + const inputElement = this.modalInputRef.current + + if (!inputElement) { + return + } + + inputElement.focus() + + if (typeof inputElement.setSelectionRange === 'function') { + inputElement.setSelectionRange( + inputElement.value.length, + inputElement.value.length + ) + } + } + + restoreCommandInputFocus(selectionStart, selectionEnd) { + const inputElement = this.modalInputRef.current + + if (!inputElement) { + return + } + + if (document.activeElement !== inputElement) { + try { + inputElement.focus({ preventScroll: true }) + } catch { + inputElement.focus() + } + } + + if ( + typeof inputElement.setSelectionRange === 'function' && + selectionStart !== null && + selectionEnd !== null + ) { + inputElement.setSelectionRange(selectionStart, selectionEnd) + } + } + + blurCommandInput() { + const inputElement = this.modalInputRef.current + + if (!inputElement || document.activeElement !== inputElement) { + return + } + + inputElement.blur() + } + + focusMainInput() { + if (!this.input) { + return + } + + window.requestAnimationFrame(() => { + try { + this.input.focus({ preventScroll: true }) + } catch { + this.input.focus() + } + + if (typeof this.input.setSelectionRange === 'function') { + this.input.setSelectionRange( + this.input.value.length, + this.input.value.length + ) + } + }) + } + + scrollSelectedSuggestionIntoView() { + const selectedSuggestionElement = this.container?.querySelector( + '.aurora-list-item--selected' + ) + + if (!selectedSuggestionElement) { + return + } + + selectedSuggestionElement.scrollIntoView({ + block: 'nearest' + }) + } + + shouldHandleDetachedInputKey(event) { + const inputElement = this.modalInputRef.current + + if (!inputElement || document.activeElement === inputElement) { + return false + } + + return ( + event.key.length === 1 || + EDITABLE_ACTION_KEYS.has(event.key) + ) + } + + handleDetachedInputKey(event) { + if (event.key.length === 1) { + this.commandValue += event.key + } else if (event.key === 'Backspace') { + this.commandValue = this.commandValue.slice(0, -1) + } else if (event.key === 'Delete') { + this.commandValue = '' + } + + this.hasSubmitted = false + this.result = null + this.loadingMessage = null + this.queueAutocomplete() + this.shouldFocusInput = true + this.render() + } + + normalizeCommandValue(rawInput) { + const normalizedValue = String(rawInput || '').trim() + + if (!normalizedValue.startsWith('/')) { + return normalizedValue + } + + return normalizedValue.slice(1) + } + + buildCommandInput() { + if (this.pendingInput) { + return this.commandValue + } + + return `/${this.commandValue}`.trim() + } + + getVisibleSuggestions() { + if (this.commandValue.trim() === '') { + return [...this.recentSuggestions, ...this.suggestions] + } + + return this.suggestions + } + + getSelectedSuggestionIndices() { + if (this.commandValue.trim() !== '') { + return { + recentSelectedSuggestionIndex: -1, + suggestionSelectedSuggestionIndex: this.selectedSuggestionIndex + } + } + + const recentSuggestionsLength = this.recentSuggestions.length + + if (this.selectedSuggestionIndex < 0) { + return { + recentSelectedSuggestionIndex: -1, + suggestionSelectedSuggestionIndex: -1 + } + } + + if (this.selectedSuggestionIndex < recentSuggestionsLength) { + return { + recentSelectedSuggestionIndex: this.selectedSuggestionIndex, + suggestionSelectedSuggestionIndex: -1 + } + } + + return { + recentSelectedSuggestionIndex: -1, + suggestionSelectedSuggestionIndex: + this.selectedSuggestionIndex - recentSuggestionsLength + } + } + + resetState() { + window.clearTimeout(this.autocompleteTimeout) + this.isClosing = false + this.isLoading = false + this.sessionId = null + this.origin = 'shortcut' + this.commandValue = '' + this.suggestions = [] + this.result = null + this.loadingMessage = null + this.pendingInput = null + this.selectedSuggestionIndex = -1 + this.hasSubmitted = false + this.shouldFocusInput = false + this.autocompleteTimeout = null + } +} diff --git a/app/src/js/built-in-commands/index.js b/app/src/js/built-in-commands/index.js new file mode 100644 index 0000000..a3f47af --- /dev/null +++ b/app/src/js/built-in-commands/index.js @@ -0,0 +1,3 @@ +import '../../css/built-in-commands.scss' + +export { default as BuiltInCommands } from './built-in-commands.jsx' diff --git a/app/src/js/built-in-commands/modal.jsx b/app/src/js/built-in-commands/modal.jsx new file mode 100644 index 0000000..a7f0d63 --- /dev/null +++ b/app/src/js/built-in-commands/modal.jsx @@ -0,0 +1,263 @@ +import { + Button, + Flexbox, + Icon, + Input, + List, + ListHeader, + ListItem, + Loader, + ScrollContainer, + Text +} from '@aurora' + +import { BuiltInCommandResultRenderer } from './result-renderer' + +const SLASH_COMMAND_ICON_SVG = ( + + + +) + +function parseRemixIcon(rawIconName, rawIconType) { + const fallbackIcon = { + iconName: 'terminal-box', + type: 'line' + } + const normalizedIconName = String(rawIconName || '').trim() + const normalizedIconType = ['line', 'fill', 'notype'].includes(rawIconType) + ? rawIconType + : null + + if (!normalizedIconName) { + return fallbackIcon + } + + const iconWithoutPrefix = normalizedIconName.replace(/^ri-/, '') + + if (iconWithoutPrefix.endsWith('-line')) { + return { + iconName: iconWithoutPrefix.slice(0, -5), + type: 'line' + } + } + + if (iconWithoutPrefix.endsWith('-fill')) { + return { + iconName: iconWithoutPrefix.slice(0, -5), + type: 'fill' + } + } + + return { + iconName: iconWithoutPrefix, + type: normalizedIconType || 'notype' + } +} + +function SuggestionList({ + headerTitle, + suggestions, + selectedSuggestionIndex, + onSuggestionSelect +}) { + return ( + + {headerTitle} + {suggestions.map((suggestion, index) => { + const parsedIcon = parseRemixIcon( + suggestion.icon_name, + suggestion.icon_type + ) + + return ( + { + onSuggestionSelect(suggestion) + }} + > + + +
+ {suggestion.usage} + {suggestion.description} +
+
+
+ ) + })} +
+ ) +} + +function LoadingState({ loadingMessage }) { + return ( + + Working + + + + {loadingMessage || 'Working on it...'} + + + + ) +} + +function EmptyState() { + return ( + + Suggestions + + No matching built-in command. + + + ) +} + +export function BuiltInCommandsModal({ + isOpen, + isVisible, + isLoading, + loadingMessage, + commandValue, + suggestions, + recentSuggestions, + recentSelectedSuggestionIndex, + suggestionSelectedSuggestionIndex, + result, + pendingInput, + hasSubmitted, + inputRef, + onCommandChange, + onMaskClick, + onSuggestionSelect, + onReturn +}) { + const isCommandInputEmpty = commandValue.trim() === '' + const pendingInputIcon = pendingInput?.icon_name + ? parseRemixIcon(pendingInput.icon_name, pendingInput.icon_type) + : null + + return ( +
+
+
{ + event.stopPropagation() + }} + > +
+ + {hasSubmitted && result ? ( +
+
+ ) : null} +
+ +
+
+
+
+
+ + {isLoading ? ( + + ) : result ? ( + + ) : suggestions.length > 0 ? ( + + {isCommandInputEmpty && recentSuggestions.length > 0 ? ( + + ) : null} + + + ) : ( + + )} + +
+
+
+ + + navigate + + + tab complete + + + enter submit + + + esc close + + +
+
+
+ ) +} diff --git a/app/src/js/built-in-commands/result-renderer.jsx b/app/src/js/built-in-commands/result-renderer.jsx new file mode 100644 index 0000000..bfe8ffb --- /dev/null +++ b/app/src/js/built-in-commands/result-renderer.jsx @@ -0,0 +1,145 @@ +import { + Flexbox, + Icon, + Link, + List, + ListHeader, + ListItem, + Text +} from '@aurora' + +function InlineLabel({ item }) { + if (item.inline_link_label && item.inline_link_href) { + return ( + + {item.label}{' '} + + {item.inline_link_label} + . + + ) + } + + return {item.label} +} + +function ToneListItem({ item }) { + if (item.tone === 'success') { + return ( + + + + + + + ) + } + + if (item.tone === 'warning') { + return ( + + + + + + + ) + } + + if (item.tone === 'error') { + return ( + + + + + + + ) + } + + if (item.value || item.description) { + return ( + +
+
+ {item.label} + {item.description ? {item.description} : null} +
+ {item.value ? ( +
+ {item.href ? ( + + {item.value} + + ) : ( + + {item.value} + + )} +
+ ) : null} +
+
+ ) + } + + if (item.inline_link_label && item.inline_link_href) { + return ( + + + + ) + } + + return ( + + + + ) +} + +export function BuiltInCommandResultRenderer({ result }) { + const blocks = Array.isArray(result?.blocks) ? result.blocks : [] + + return ( + + {blocks.map((block, index) => { + if (block.type !== 'list') { + return null + } + + const header = block.header || (index === 0 ? result.title : '') + + return ( + + {header ? {header} : null} + {block.items.map((item, itemIndex) => ( + + ))} + + ) + })} + + ) +} diff --git a/app/src/js/chatbot.js b/app/src/js/chatbot.js new file mode 100644 index 0000000..3ce5cf3 --- /dev/null +++ b/app/src/js/chatbot.js @@ -0,0 +1,957 @@ +import { createElement } from 'react' +import { createRoot } from 'react-dom/client' +import axios from 'axios' + +import { WidgetWrapper, Flexbox, Loader, Text } from '@aurora' + +import renderAuroraComponent from './render-aurora-component' +import ToolUIHandler from './tool-ui-handler' + +const WIDGETS_TO_FETCH = [] +const WIDGETS_FETCH_CACHE = new Map() +const REPLACED_MESSAGES = new Set() +const AUTO_SCROLL_BOTTOM_THRESHOLD_PX = 24 +const MAXIMUM_BUBBLES_IN_MEMORY = 62 +const MAXIMUM_WIDGET_FETCH_CONCURRENCY = 4 +const SECONDS_PER_MINUTE = 60 + +function escapeHTML(value) { + return String(value || '') + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') +} + +export default class Chatbot { + constructor(socket, serverURL, sessionId = null) { + this.socket = socket + this.serverURL = serverURL + this.sessionId = sessionId + this.et = new EventTarget() + this.feed = document.querySelector('#feed') + this.typing = document.querySelector('#is-typing') + this.noBubbleMessage = document.querySelector('#no-bubble') + this.parsedBubbles = [] + this.reasoningBlocks = new Map() + this.feedAutoScrollEnabled = true + this.isProgrammaticFeedScroll = false + this.widgetHydrationPromise = null + + // Initialize tool UI handler + this.toolUIHandler = new ToolUIHandler( + this.feed, + this.scrollDown.bind(this), + this.formatMessage.bind(this) + ) + } + + async init() { + await this.loadFeed() + this.scrollDown() + + this.et.addEventListener('to-leon', (event) => { + this.createBubble({ + who: 'me', + string: event.detail.string, + sentAt: event.detail.sentAt + }) + }) + + this.et.addEventListener('me-received', (event) => { + this.createBubble({ + who: 'leon', + string: event.detail + }) + }) + + // Add event delegation for clickable paths + this.feed.addEventListener('click', (event) => { + if (event.target.classList.contains('clickable-path')) { + const path = event.target.getAttribute('data-path') + if (path) { + this.openPath(path) + } + } + }) + + this.feed.addEventListener( + 'scroll', + () => { + this.handleFeedScroll() + }, + { passive: true } + ) + } + + sendTo(who, string, sentAt = Date.now()) { + if (who === 'leon') { + this.et.dispatchEvent( + new CustomEvent('to-leon', { + detail: { + string, + sentAt + } + }) + ) + } + } + + receivedFrom(who, string) { + if (who === 'leon') { + this.et.dispatchEvent(new CustomEvent('me-received', { detail: string })) + } + } + + isTyping(who, value) { + if (who === 'leon') { + if (value) { + this.enableTyping() + } else if (value === false) { + this.disableTyping() + } + } + } + + enableTyping() { + if (!this.typing.classList.contains('on')) { + this.typing.classList.add('on') + } + } + + disableTyping() { + if (this.typing.classList.contains('on')) { + this.typing.classList.remove('on') + } + } + + isElementNearBottom(element) { + if (!element) { + return true + } + + const remainingScrollableDistance = + element.scrollHeight - (element.scrollTop + element.clientHeight) + + return remainingScrollableDistance <= AUTO_SCROLL_BOTTOM_THRESHOLD_PX + } + + handleFeedScroll() { + if (!this.feed || this.isProgrammaticFeedScroll) { + return + } + + this.feedAutoScrollEnabled = this.isElementNearBottom(this.feed) + } + + scrollDown(options = {}) { + if (!this.feed) { + return + } + + const { force = false } = options + + if (!force && !this.feedAutoScrollEnabled) { + return + } + + this.isProgrammaticFeedScroll = true + this.feed.scrollTo(0, this.feed.scrollHeight) + + requestAnimationFrame(() => { + this.isProgrammaticFeedScroll = false + this.feedAutoScrollEnabled = this.isElementNearBottom(this.feed) + }) + } + + scrollReasoningContentToBottom(reasoningBlock) { + if (!reasoningBlock?.content || !reasoningBlock.isAutoScrollEnabled) { + return + } + + reasoningBlock.isProgrammaticScroll = true + reasoningBlock.content.scrollTop = reasoningBlock.content.scrollHeight + + requestAnimationFrame(() => { + reasoningBlock.isProgrammaticScroll = false + reasoningBlock.isAutoScrollEnabled = this.isElementNearBottom( + reasoningBlock.content + ) + }) + } + + getWidgetPayload(formattedString) { + if ( + typeof formattedString !== 'string' || + !formattedString.includes('"component":"WidgetWrapper"') + ) { + return null + } + + try { + return JSON.parse(formattedString) + } catch { + return null + } + } + + getPlanWidgetInsertionPoint(widgetPayload) { + if (!widgetPayload || widgetPayload.widget !== 'PlanWidget') { + return null + } + + // Always append new plan widgets as new bubbles. + // Widget updates are handled via replaceMessageId targeting the same + // messageId, so insertion-point heuristics are unnecessary and can cause + // visual reuse across turns. + return null + } + + isPlanWidgetData(data) { + return Boolean(data && typeof data === 'object' && data.widget === 'PlanWidget') + } + + isSystemWidgetData(data) { + return Boolean( + data && + typeof data === 'object' && + data.historyMode && + data.historyMode === 'system_widget' + ) + } + + getTimelineItemWeight(item) { + if (item.who === 'owner') { + return 0 + } + + if (item.source === 'system_widget') { + return 1 + } + + return 2 + } + + async hydrateFetchedWidgets() { + if (this.widgetHydrationPromise) { + return this.widgetHydrationPromise + } + + const widgetContainers = [...WIDGETS_TO_FETCH].reverse() + WIDGETS_TO_FETCH.length = 0 + + if (widgetContainers.length === 0) { + return Promise.resolve() + } + + const hydrateWidgetContainer = async (widgetContainer) => { + const hasWidgetBeenFetched = WIDGETS_FETCH_CACHE.has( + widgetContainer.widgetId + ) + + if (hasWidgetBeenFetched) { + const fetchedWidget = WIDGETS_FETCH_CACHE.get(widgetContainer.widgetId) + widgetContainer.reactRootNode.render(fetchedWidget.reactNode) + + setTimeout(() => { + this.scrollDown() + }, 100) + + return + } + + const data = await axios.get( + `${this.serverURL}/api/v1/fetch-widget?skill_action=${widgetContainer.onFetch.actionName}&widget_id=${widgetContainer.widgetId}${this.sessionId ? `&session_id=${encodeURIComponent(this.sessionId)}` : ''}` + ) + const fetchedWidget = data.data.widget + const reactNode = fetchedWidget + ? renderAuroraComponent( + this.socket, + fetchedWidget.componentTree, + fetchedWidget.supportedEvents + ) + : createElement(WidgetWrapper, { + children: createElement(Flexbox, { + alignItems: 'center', + justifyContent: 'center', + children: createElement(Text, { + secondary: true, + children: 'This widget has been deleted.' + }) + }) + }) + + widgetContainer.reactRootNode.render(reactNode) + WIDGETS_FETCH_CACHE.set(widgetContainer.widgetId, { + ...fetchedWidget, + reactNode + }) + setTimeout(() => { + this.scrollDown() + }, 100) + } + + const workerCount = Math.min( + MAXIMUM_WIDGET_FETCH_CONCURRENCY, + widgetContainers.length + ) + let currentIndex = 0 + + this.widgetHydrationPromise = Promise.all( + Array.from({ length: workerCount }, async () => { + while (currentIndex < widgetContainers.length) { + const widgetContainer = widgetContainers[currentIndex] + currentIndex += 1 + + if (!widgetContainer) { + continue + } + + await hydrateWidgetContainer(widgetContainer) + } + }) + ) + .catch((error) => { + console.error('Failed to hydrate fetched widgets:', error) + }) + .finally(() => { + this.widgetHydrationPromise = null + }) + + return this.widgetHydrationPromise + } + + setSessionId(sessionId) { + this.sessionId = sessionId + } + + resetFeed() { + WIDGETS_TO_FETCH.length = 0 + this.feed.innerHTML = '' + this.noBubbleMessage = document.createElement('p') + this.noBubbleMessage.id = 'no-bubble' + this.noBubbleMessage.className = 'hide' + this.noBubbleMessage.textContent = + 'You can start to interact with me, don\'t be shy.' + this.feed.appendChild(this.noBubbleMessage) + this.parsedBubbles = [] + this.reasoningBlocks.clear() + this.feedAutoScrollEnabled = true + } + + async loadFeed() { + WIDGETS_TO_FETCH.length = 0 + this.resetFeed() + const sessionQuery = this.sessionId + ? `&session_id=${encodeURIComponent(this.sessionId)}` + : '' + + const [historyResponse, systemWidgetsResponse] = await Promise.all([ + axios.get( + `${this.serverURL}/api/v1/conversation-history?supports_widgets=true${sessionQuery}` + ), + axios.get( + `${this.serverURL}/api/v1/system-widgets?supports_widgets=true${sessionQuery}` + ) + ]) + const history = Array.isArray(historyResponse.data?.history) + ? historyResponse.data.history + : [] + const systemWidgets = Array.isArray(systemWidgetsResponse.data?.widgets) + ? systemWidgetsResponse.data.widgets + : [] + + const timelineItems = [...history, ...systemWidgets] + .map((item, index) => ({ + ...item, + sortIndex: index + })) + .sort((left, right) => { + if (left.sentAt !== right.sentAt) { + return left.sentAt - right.sentAt + } + + const leftWeight = this.getTimelineItemWeight(left) + const rightWeight = this.getTimelineItemWeight(right) + + if (leftWeight !== rightWeight) { + return leftWeight - rightWeight + } + + return left.sortIndex - right.sortIndex + }) + + this.parsedBubbles = history + + if (timelineItems.length === 0) { + this.noBubbleMessage.classList.remove('hide') + return + } + + for (let i = 0; i < timelineItems.length; i += 1) { + const bubble = timelineItems[i] + + if ( + bubble.originalString && + ToolUIHandler.isToolOutputMarker(bubble.originalString) + ) { + continue + } + + this.createBubble({ + who: bubble.who === 'owner' ? 'me' : bubble.who, + string: bubble.originalString ? bubble.originalString : bubble.string, + metrics: bubble.llmMetrics || null, + sentAt: bubble.sentAt, + save: false, + isCreatingFromLoadingFeed: true, + messageId: bubble.messageId + }) + } + + void this.hydrateFetchedWidgets() + } + + createBubble(params) { + const { + who, + string, + metrics = null, + save = true, + bubbleId, + isCreatingFromLoadingFeed = false, + messageId, + sentAt = null, + beforeElement = null + } = params + const container = document.createElement('div') + const bubble = document.createElement('p') + + if (!this.noBubbleMessage.classList.contains('hide')) { + this.noBubbleMessage.classList.add('hide') + } + + container.className = `bubble-container ${who}` + bubble.className = 'bubble' + + if (messageId) { + container.setAttribute('data-message-id', messageId) + } + + // Store original string before formatting + const originalString = string + const formattedString = this.formatMessage(string) + const widgetPayload = this.getWidgetPayload(formattedString) + const autoPlanInsertionPoint = this.getPlanWidgetInsertionPoint(widgetPayload) + const resolvedBeforeElement = beforeElement || autoPlanInsertionPoint + + bubble.innerHTML = formattedString + + if (bubbleId) { + container.classList.add(bubbleId) + } + + if (resolvedBeforeElement && resolvedBeforeElement.parentNode === this.feed) { + this.feed.insertBefore(container, resolvedBeforeElement) + } else { + this.feed.appendChild(container) + } + container.appendChild(bubble) + + if (who === 'leon' && metrics) { + container.appendChild(this.createMetricsElement(metrics, sentAt)) + } else if (who === 'me') { + const timestampElement = this.createTimestampElement(sentAt) + + if (timestampElement) { + container.appendChild(timestampElement) + } + } + + let widgetComponentTree = null + let widgetSupportedEvents = null + + /** + * Widget rendering + */ + if ( + formattedString.includes && + formattedString.includes('"component":"WidgetWrapper"') + ) { + const parsedWidget = widgetPayload || JSON.parse(formattedString) + container.setAttribute('data-widget-id', parsedWidget.id) + + /** + * On widget fetching, render the loader + */ + if (isCreatingFromLoadingFeed && parsedWidget.onFetch) { + const root = createRoot(container) + + root.render( + createElement(WidgetWrapper, { + children: createElement(Flexbox, { + alignItems: 'center', + justifyContent: 'center', + children: createElement(Loader) + }) + }) + ) + + WIDGETS_TO_FETCH.push({ + reactRootNode: root, + widgetId: parsedWidget.id, + onFetch: parsedWidget.onFetch + }) + + return container + } + + widgetComponentTree = parsedWidget.componentTree + widgetSupportedEvents = parsedWidget.supportedEvents + + /** + * On widget creation + */ + const root = createRoot(container) + + const reactNode = renderAuroraComponent( + this.socket, + widgetComponentTree, + widgetSupportedEvents + ) + + root.render(reactNode) + } + + if (save) { + this.saveBubble(who, originalString, formattedString, messageId, metrics, sentAt) + } + + return container + } + + formatReasoningPhaseTitle(phase) { + const normalizedPhase = + typeof phase === 'string' && phase.trim() + ? phase.replaceAll('_', ' ').toUpperCase() + : 'EXECUTION' + + return `REASONING - ${normalizedPhase}` + } + + createOrUpdateReasoningBlock(generationId, token, phase) { + if (!generationId || !token) { + return null + } + + if (!this.noBubbleMessage.classList.contains('hide')) { + this.noBubbleMessage.classList.add('hide') + } + + let reasoningBlock = this.reasoningBlocks.get(generationId) + + if (!reasoningBlock) { + const container = document.createElement('div') + const block = document.createElement('div') + const header = document.createElement('div') + const icon = document.createElement('i') + const title = document.createElement('span') + const content = document.createElement('div') + + container.className = 'reasoning-block-container leon' + container.setAttribute('data-reasoning-id', generationId) + block.className = 'reasoning-block' + header.className = 'reasoning-header' + icon.className = 'ri-brain-ai-3-line reasoning-icon' + title.className = 'reasoning-title' + title.textContent = this.formatReasoningPhaseTitle(phase) + content.className = 'reasoning-content' + + header.appendChild(icon) + header.appendChild(title) + block.appendChild(header) + block.appendChild(content) + container.appendChild(block) + this.feed.appendChild(container) + + reasoningBlock = { + container, + content, + text: '', + isAutoScrollEnabled: true, + isProgrammaticScroll: false + } + content.addEventListener( + 'scroll', + () => { + if (reasoningBlock.isProgrammaticScroll) { + return + } + + reasoningBlock.isAutoScrollEnabled = this.isElementNearBottom(content) + }, + { passive: true } + ) + this.reasoningBlocks.set(generationId, reasoningBlock) + } + + reasoningBlock.text += token + reasoningBlock.content.textContent = reasoningBlock.text + this.scrollReasoningContentToBottom(reasoningBlock) + + return reasoningBlock.container + } + + handleToolOutput(data) { + const result = this.toolUIHandler.handleToolOutput(data) + + // Save in memory if it's a new group + if (result && result.isNewGroup) { + const { toolkitName, toolName, answer } = data + const toolInfo = this.toolUIHandler.getToolGroupInfo( + result.groupId, + toolkitName, + toolName, + answer + ) + + this.saveBubble( + 'leon', + toolInfo.originalString, + toolInfo.formattedMessage, + toolInfo.messageId + ) + } + } + + saveBubble( + who, + originalString, + string, + messageId, + metrics = null, + sentAt = null + ) { + if (!this.noBubbleMessage.classList.contains('hide')) { + this.noBubbleMessage.classList.add('hide') + } + + if (this.parsedBubbles.length === MAXIMUM_BUBBLES_IN_MEMORY) { + this.parsedBubbles.shift() + } + + // Store both original and formatted strings + this.parsedBubbles.push({ + who, + sentAt, + string, + originalString, + messageId, + llmMetrics: metrics + }) + this.scrollDown() + } + + formatMessage(message) { + const isWidget = + message.includes && message.includes('"component":"WidgetWrapper"') + + if (typeof message === 'string' && !isWidget) { + message = escapeHTML(message) + message = message.replace(/\n/g, '
') + + // Handle HTTP/HTTPS URLs with simple regex + message = message.replace(/https?:\/\/[^\s<>"{}|\\^`[\]]+/gi, (match) => { + return `${match}` + }) + + // Handle file paths with delimiters for exact matching + message = message.replace( + /\[FILE_PATH\](.*?)\[\/FILE_PATH\]/g, + (match, filePath) => { + return `${filePath}` + } + ) + } + + return message + } + + formatMetricTimestamp(sentAt) { + if (typeof sentAt !== 'number' || !Number.isFinite(sentAt)) { + return '' + } + + const date = new Date(sentAt) + const now = new Date() + + if (Number.isNaN(date.getTime()) || Number.isNaN(now.getTime())) { + return '' + } + + const timeFormatter = new Intl.DateTimeFormat(undefined, { + hour: '2-digit', + minute: '2-digit', + hour12: false + }) + const formattedTime = timeFormatter.format(date) + const startOfToday = new Date( + now.getFullYear(), + now.getMonth(), + now.getDate() + ) + const startOfTargetDay = new Date( + date.getFullYear(), + date.getMonth(), + date.getDate() + ) + const dayDifference = Math.round( + (startOfToday.getTime() - startOfTargetDay.getTime()) / 86_400_000 + ) + + if (dayDifference === 0) { + return `Today, ${formattedTime}` + } + + if (dayDifference === 1) { + return `Yesterday, ${formattedTime}` + } + + if (dayDifference > 1 && dayDifference < 7) { + const weekdayFormatter = new Intl.DateTimeFormat(undefined, { + weekday: 'long' + }) + + return `${weekdayFormatter.format(date)}, ${formattedTime}` + } + + const monthDayFormatter = new Intl.DateTimeFormat(undefined, { + month: 'short', + day: 'numeric' + }) + + return `${monthDayFormatter.format(date)}, ${formattedTime}` + } + + formatFullMetricTimestamp(sentAt) { + if (typeof sentAt !== 'number' || !Number.isFinite(sentAt)) { + return '' + } + + const date = new Date(sentAt) + + if (Number.isNaN(date.getTime())) { + return '' + } + + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + const hours = String(date.getHours()).padStart(2, '0') + const minutes = String(date.getMinutes()).padStart(2, '0') + const seconds = String(date.getSeconds()).padStart(2, '0') + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` + } + + formatTimestampMarkup(sentAt) { + const formattedTimestamp = this.formatMetricTimestamp(sentAt) + const fullFormattedTimestamp = this.formatFullMetricTimestamp(sentAt) + + if (!formattedTimestamp) { + return '' + } + + return ` + + + ${formattedTimestamp} + + `.trim() + } + + formatTurnDuration(durationMs) { + const durationSeconds = Number(durationMs || 0) / 1_000 + const roundedDurationSeconds = Math.max(0, Number(durationSeconds.toFixed(1))) + + if (roundedDurationSeconds < SECONDS_PER_MINUTE) { + return `${roundedDurationSeconds.toFixed(1)}s` + } + + const minutes = Math.floor(roundedDurationSeconds / SECONDS_PER_MINUTE) + const seconds = roundedDurationSeconds % SECONDS_PER_MINUTE + + return `${minutes}m${seconds.toFixed(1)}s` + } + + formatMetrics(metrics, sentAt = null) { + if (!metrics) { + return '' + } + + const inputTokens = Number(metrics.inputTokens || 0) + const outputTokens = Number(metrics.outputTokens || 0) + const totalTokens = Number(metrics.totalTokens || inputTokens + outputTokens) + const turnDuration = this.formatTurnDuration(metrics.durationMs) + const tokensPerSecond = Number( + metrics.tokensPerSecond || metrics.averagedPhaseTokensPerSecond || 0 + ) + const tokenFormatter = new Intl.NumberFormat() + const timestampMarkup = this.formatTimestampMarkup(sentAt) + + return ` + + + ${tokenFormatter.format(totalTokens)} (i:${tokenFormatter.format(inputTokens)}/o:${tokenFormatter.format(outputTokens)}) tok + + + + ${turnDuration} + + + + ${tokensPerSecond.toFixed(2)} t/s + + ${timestampMarkup} + `.trim() + } + + createMetricsElement(metrics, sentAt = null) { + const metricsElement = document.createElement('div') + + metricsElement.className = 'bubble-metrics' + metricsElement.innerHTML = this.formatMetrics(metrics, sentAt) + + return metricsElement + } + + createTimestampElement(sentAt) { + const timestampMarkup = this.formatTimestampMarkup(sentAt) + + if (!timestampMarkup) { + return null + } + + const timestampElement = document.createElement('div') + + timestampElement.className = 'bubble-metrics' + timestampElement.innerHTML = timestampMarkup + + return timestampElement + } + + updateBubbleMetrics(container, metrics, sentAt = null) { + if (!container) { + return + } + + const existingMetricsElement = container.querySelector('.bubble-metrics') + + if (!metrics) { + if (existingMetricsElement) { + existingMetricsElement.remove() + } + + return + } + + if (existingMetricsElement) { + existingMetricsElement.innerHTML = this.formatMetrics(metrics, sentAt) + return + } + + container.appendChild(this.createMetricsElement(metrics, sentAt)) + } + + getLatestReasoningContainer() { + const reasoningContainers = this.feed.querySelectorAll( + '.reasoning-block-container' + ) + + if (reasoningContainers.length === 0) { + return null + } + + return reasoningContainers[reasoningContainers.length - 1] || null + } + + replaceMessage(replaceMessageId, newData) { + const existingBubble = document.querySelector( + `[data-message-id="${replaceMessageId}"]` + ) + const isPlanWidget = this.isPlanWidgetData(newData) + const nextSibling = existingBubble ? existingBubble.nextSibling : null + + if (existingBubble) { + existingBubble.remove() + + const bubbleIndex = this.parsedBubbles.findIndex( + (bubble) => bubble.messageId === replaceMessageId + ) + if (bubbleIndex !== -1) { + this.parsedBubbles.splice(bubbleIndex, 1) + } + } + + const isTextAnswerPayload = Boolean( + newData && + typeof newData === 'object' && + typeof newData.answer === 'string' && + !newData.widget && + !newData.componentTree + ) + const bubbleString = isTextAnswerPayload + ? newData.answer + : typeof newData === 'string' + ? newData + : JSON.stringify(newData) + const metrics = + isTextAnswerPayload && newData.llmMetrics ? newData.llmMetrics : null + + const shouldSaveMessage = !this.isSystemWidgetData(newData) + const beforeElement = isPlanWidget ? null : nextSibling + + this.createBubble({ + who: 'leon', + string: bubbleString, + save: shouldSaveMessage, + messageId: replaceMessageId, + beforeElement, + metrics, + sentAt: + newData && typeof newData === 'object' && typeof newData.sentAt === 'number' + ? newData.sentAt + : Date.now() + }) + + /** + * Only scroll down on the first replacement of this message + * to avoid repeating scrolling for every message replacement + */ + if (!REPLACED_MESSAGES.has(replaceMessageId)) { + REPLACED_MESSAGES.add(replaceMessageId) + this.scrollDown() + } + } + + openPath(filePath) { + // Send request to server to open the file path in system file explorer + fetch(`${this.serverURL}/api/v1/open-path`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ path: filePath }) + }) + .then((response) => response.json()) + .then((data) => { + if (!data.success) { + console.error('Failed to open path:', data.error) + } + }) + .catch((error) => { + console.error('Error opening path:', error) + }) + } +} diff --git a/app/src/js/client.js b/app/src/js/client.js new file mode 100644 index 0000000..18184ca --- /dev/null +++ b/app/src/js/client.js @@ -0,0 +1,651 @@ +import { io } from 'socket.io-client' + +import Chatbot from './chatbot' +import VoiceEnergy from './voice-energy' +import { ASR_DISABLED_MESSAGE, INIT_MESSAGES } from './constants' +import handleSuggestions from './suggestion-handler.js' + +const LEON_CLIENT_INTERFACE_PROTOCOL_VERSION = 1 +const LEON_EVENTS = { + init: 'leon:init', + utterance: 'leon:utterance', + ready: 'leon:ready', + answer: 'leon:answer', + isTyping: 'leon:is-typing', + suggest: 'leon:suggest', + llmToken: 'leon:llm-token', + llmReasoningToken: 'leon:llm-reasoning-token', + ownerUtterance: 'leon:owner-utterance', + error: 'leon:error' +} + +export default class Client { + constructor(client, serverUrl, input, options = {}) { + this.client = client + this._input = input + this.voiceSpeechElement = document.querySelector('#voice-speech') + this.serverUrl = serverUrl + this.socket = io(this.serverUrl) + this.activeSessionId = options.activeSessionId || null + this.history = localStorage.getItem('history') + this.parsedHistory = [] + this.chatbot = new Chatbot(this.socket, this.serverUrl, this.activeSessionId) + this.voiceEnergy = new VoiceEnergy(this) + this._recorder = {} + this._suggestions = [] + this._answerGenerationId = 'xxx' + this._activeStreamGenerationId = null + this._ttsAudioContext = null + this._isLeonGeneratingAnswer = false + this._isVoiceModeEnabled = false + this._hasSentInitMessages = false + this._chatbotInitPromise = null + // this._ttsAudioContextes = {} + } + + set input(newInput) { + if (typeof newInput !== 'undefined') { + this._input.value = newInput + } + } + + get input() { + return this._input + } + + set recorder(recorder) { + this._recorder = recorder + } + + get recorder() { + return this._recorder + } + + updateMood(mood) { + const moodContainer = document.querySelector('#mood') + + if (!moodContainer || !mood?.emoji || !mood?.type) { + return + } + + moodContainer.textContent = `Leon's mood: ${mood.emoji}` + moodContainer.setAttribute('title', mood.type) + } + + setSessionPanel(sessionPanel) { + this.sessionPanel = sessionPanel + } + + async setActiveSession(sessionId) { + if (!sessionId || sessionId === this.activeSessionId) { + return + } + + this.activeSessionId = sessionId + this.chatbot.setSessionId(sessionId) + this.socket.emit('session-change', sessionId) + await this.chatbot.loadFeed() + this.chatbot.scrollDown({ force: true }) + } + + async sendInitMessages() { + for (let i = 0; i < INIT_MESSAGES.length; i++) { + const messages = INIT_MESSAGES[i] + const message = messages[Math.floor(Math.random() * messages.length)] + const sendingDelay = Math.floor(Math.random() * 2000) + 1000 + const typingFactorDelay = Math.floor(Math.random() * 4) + 2 + + setTimeout(() => { + this.chatbot.isTyping('leon', true) + }, sendingDelay / typingFactorDelay) + + await new Promise((resolve) => setTimeout(resolve, sendingDelay)) + + this.chatbot.receivedFrom('leon', message) + this.chatbot.isTyping('leon', false) + } + } + + setInitStatus(statusName, statusType) { + window.leonInitStatusEvent.dispatchEvent( + new CustomEvent('initStatusChange', { + detail: { + statusName, + statusType + } + }) + ) + } + + waitForInitUICompletion() { + if (this._hasSentInitMessages || this.chatbot.parsedBubbles?.length > 0) { + return + } + + const trySendInitMessages = () => { + const initializedInitElement = document.querySelector('#init .initialized') + + if (!initializedInitElement) { + return false + } + + this._hasSentInitMessages = true + this.sendInitMessages() + return true + } + + if (trySendInitMessages()) { + return + } + + const interval = setInterval(() => { + if (trySendInitMessages()) { + clearInterval(interval) + } + }, 100) + } + + asrStartRecording() { + if (!window.leonConfigInfo.asr.enabled) { + alert(ASR_DISABLED_MESSAGE) + return + } + + if (!this._isVoiceModeEnabled) { + this.enableVoiceMode() + + this.voiceEnergy.status = 'listening' + + this.socket.emit('asr-start-record') + } + } + + init() { + this._chatbotInitPromise = this.chatbot.init() + this.voiceEnergy.init() + + if (window.leonConfigInfo?.tcpServer?.enabled === false) { + this.setInitStatus('tcpServerBoot', 'success') + } + + this.socket.on('connect', () => { + this.socket.emit(LEON_EVENTS.init, { + protocolVersion: LEON_CLIENT_INTERFACE_PROTOCOL_VERSION, + client: { + id: this.client, + type: 'web_app', + name: 'Leon Web App' + }, + sessionId: this.activeSessionId, + capabilities: { + supportsWidgets: true, + supportsTokenStreaming: true, + supportsVoice: true + } + }) + }) + + /** + * Init status listeners + */ + this.socket.on('init-llama-server-boot', (status) => { + this.setInitStatus('llamaServerBoot', status) + }) + + this.socket.on(LEON_EVENTS.ready, () => { + this.setInitStatus('clientCoreServerHandshake', 'success') + this.setInitStatus('tcpServerBoot', 'success') + + void this._chatbotInitPromise?.then(() => { + setTimeout(() => { + const body = document.querySelector('body') + body.classList.remove('settingup') + }, 250) + + this.waitForInitUICompletion() + }) + }) + + this.socket.on(LEON_EVENTS.answer, (data) => { + /*if (this._isVoiceModeEnabled) { + this.voiceEnergy.status = 'listening' + }*/ + + // Leon has finished to answer + this._isLeonGeneratingAnswer = false + + const isPlanWidget = + data && typeof data === 'object' && data.widget === 'PlanWidget' + + if (isPlanWidget) { + this.chatbot.isTyping('leon', false) + } + + /** + * Handle message replacement if replaceMessageId is provided + */ + if (data.replaceMessageId) { + this.chatbot.replaceMessage(data.replaceMessageId, data) + return + } + + /** + * Handle tool output messages + */ + if (data.isToolOutput) { + this.chatbot.handleToolOutput(data) + return + } + + /** + * Handle widget data directly + */ + if (data.widget || data.componentTree) { + const isSystemWidget = this.chatbot.isSystemWidgetData(data) + // Pass the entire widget data as JSON string for chatbot.js to handle + const widgetString = + typeof data === 'string' ? data : JSON.stringify(data) + + this.chatbot.createBubble({ + who: 'leon', + string: widgetString, + save: !isSystemWidget, + messageId: data.widget?.id || data.id || `msg-${Date.now()}` + }) + + return + } + + const answerText = typeof data === 'string' ? data : data.answer + const llmMetrics = + data && typeof data === 'object' && data.llmMetrics + ? data.llmMetrics + : null + + /** + * Just save the bubble if the newest bubble is from the streaming. + * Otherwise, create a new bubble + */ + const streamGenerationId = + this._activeStreamGenerationId || this._answerGenerationId + const streamedBubbleContainerElement = streamGenerationId + ? document.querySelector( + `.bubble-container.leon.${streamGenerationId}` + ) + : null + const isBubbleFromStreaming = Boolean(streamedBubbleContainerElement) + + if (isBubbleFromStreaming && streamedBubbleContainerElement) { + this.chatbot.saveBubble( + 'leon', + answerText, + answerText, + null, + llmMetrics, + data && typeof data === 'object' && typeof data.sentAt === 'number' + ? data.sentAt + : Date.now() + ) + + // Slightly delay the update to avoid the stream animation to be interrupted + setTimeout(() => { + // Update the text of the bubble (quick emoji fix) + streamedBubbleContainerElement.querySelector('p.bubble').innerHTML = + this.chatbot.formatMessage(answerText) + this.chatbot.updateBubbleMetrics( + streamedBubbleContainerElement, + llmMetrics, + data && typeof data === 'object' && typeof data.sentAt === 'number' + ? data.sentAt + : Date.now() + ) + }, 2_500) + } else { + this.chatbot.createBubble({ + who: 'leon', + string: answerText, + save: + !( + data && + typeof data === 'object' && + data.historyMode === 'system_widget' + ), + metrics: llmMetrics, + messageId: data && typeof data === 'object' ? data.messageId : null, + sentAt: + data && typeof data === 'object' && typeof data.sentAt === 'number' + ? data.sentAt + : Date.now() + }) + } + this.chatbot.scrollDown({ force: true }) + + this._activeStreamGenerationId = null + this._answerGenerationId = 'xxx' + void this.sessionPanel?.refresh() + }) + + this.socket.on(LEON_EVENTS.suggest, (data) => { + setTimeout(() => { + handleSuggestions(data, this.chatbot, this) + }, 400) + setTimeout(() => { + this.chatbot.scrollDown() + }, 450) + /*data?.forEach((suggestionText) => { + this.addSuggestion(suggestionText) + })*/ + }) + + this.socket.on(LEON_EVENTS.isTyping, (data) => { + this.chatbot.isTyping('leon', data) + }) + + this.socket.on(LEON_EVENTS.ownerUtterance, (data) => { + if (!data?.utterance) { + return + } + + this.chatbot.createBubble({ + who: 'me', + string: data.utterance, + messageId: data.messageId, + sentAt: typeof data.sentAt === 'number' ? data.sentAt : Date.now() + }) + }) + + this.socket.on('recognized', (data, cb) => { + this._input.value = data + this.send('utterance') + + cb('string-received') + }) + + this.socket.on('widget-send-utterance', (utterance) => { + this._input.value = utterance + this.send('utterance') + }) + + this.socket.on('new-mood', (mood) => { + this.updateMood(mood) + }) + + this.socket.on(LEON_EVENTS.llmToken, (data) => { + if (this._isVoiceModeEnabled) { + this.voiceEnergy.status = 'processing' + } + + this._isLeonGeneratingAnswer = true + const previousGenerationId = this._answerGenerationId + const newGenerationId = data.generationId + this._answerGenerationId = newGenerationId + this._activeStreamGenerationId = newGenerationId + const isSameGeneration = previousGenerationId === newGenerationId + let bubbleContainerElement = null + + if (!isSameGeneration) { + bubbleContainerElement = this.chatbot.createBubble({ + who: 'leon', + string: data.token, + save: false, + bubbleId: newGenerationId + }) + } else { + bubbleContainerElement = document.querySelector( + `.${previousGenerationId}` + ) + } + + const bubbleElement = bubbleContainerElement.querySelector('p.bubble') + + // Token is already appened when it's a new generation + if (isSameGeneration) { + // bubbleElement.textContent += data.token + + const tokenSpan = document.createElement('span') + tokenSpan.className = 'llm-token fade-in' + tokenSpan.textContent = data.token + + bubbleElement.appendChild(tokenSpan) + } + + this.chatbot.scrollDown() + }) + + this.socket.on(LEON_EVENTS.llmReasoningToken, (data) => { + if (!data?.generationId || !data?.token) { + return + } + + if (this._isVoiceModeEnabled) { + this.voiceEnergy.status = 'processing' + } + + this._isLeonGeneratingAnswer = true + this.chatbot.createOrUpdateReasoningBlock( + data.generationId, + data.token, + data.phase + ) + this.chatbot.scrollDown() + }) + + this.socket.on('asr-speech', (text) => { + if (!this._isVoiceModeEnabled) { + this.enableVoiceMode() + } + + this.voiceEnergy.status = 'listening' + this._input.value = text + + if (this.voiceSpeechElement) { + this.voiceSpeechElement.textContent = text + } + }) + + this.socket.on('asr-end-of-owner-speech', () => { + this.voiceEnergy.status = 'processing' + + setTimeout(() => { + this.send('utterance') + }, 200) + }) + + this.socket.on('asr-active-listening-disabled', () => { + this.voiceEnergy.status = 'idle' + }) + + /** + * Only used for "local" TTS provider as a PoC for now. + * Target to do a better implementation in the future + * with streaming support + */ + this.socket.on('tts-stream', (data) => { + this.voiceEnergy.status = 'talking' + + // const { audioId, chunk } = data + const { chunk } = data + this._ttsAudioContext = new AudioContext() + // this._ttsAudioContextes[audioId] = ctx + + const source = this._ttsAudioContext.createBufferSource() + this._ttsAudioContext.decodeAudioData(chunk, (buffer) => { + source.buffer = buffer + + source.connect(this._ttsAudioContext.destination) + source.start(0) + }) + }) + + /** + * When Leon got interrupted by the owner voice + * while he is speaking + */ + this.socket.on('tts-interruption', async () => { + if (this._ttsAudioContext) { + await this._ttsAudioContext.close() + } + }) + + this.socket.on('tts-end-of-speech', async () => { + this.voiceEnergy.status = 'listening' + + if (window.leonConfigInfo?.asr?.enabled) { + this.socket.emit('asr-start-record') + } + }) + + this.socket.on('audio-forwarded', (data, cb) => { + const ctx = new AudioContext() + const source = ctx.createBufferSource() + + ctx.decodeAudioData(data.buffer, (buffer) => { + source.buffer = buffer + + source.connect(ctx.destination) + source.start(0) + + /** + * When the after speech option is enabled and + * the answer is a final one + */ + if (window.leonConfigInfo.after_speech && data.is_final_answer) { + // Enable recording after the speech + 500ms + setTimeout(() => { + this._recorder.start() + this._recorder.enabled = true + + // Check every second if the recorder is enabled to stop it + const id = setInterval(() => { + if (this._recorder.enabled) { + if (this._recorder.countSilenceAfterTalk <= 8) { + // Stop recording if there was no noise for 8 seconds + if (this._recorder.countSilenceAfterTalk === 8) { + this._recorder.stop() + this._recorder.enabled = false + this._recorder.countSilenceAfterTalk = 0 + clearInterval(id) + } else if (!this._recorder.noiseDetected) { + this._recorder.countSilenceAfterTalk += 1 + } else { + clearInterval(id) + } + } + } + }, 1_000) + }, data.duration + 500) + } + }) + + cb('audio-received') + }) + + this.socket.on(LEON_EVENTS.error, (data) => { + console.error('Leon client interface error:', data) + }) + + if (this.history !== null) { + this.parsedHistory = JSON.parse(this.history) + } + } + + send(keyword) { + if (keyword === 'utterance') { + return this.sendUtterance(this._input.value) + } + + return false + } + + sendUtterance(value, options = {}) { + if (this._isLeonGeneratingAnswer) { + return false + } + + const trimmedValue = String(value || '').trim() + + if (trimmedValue === '') { + return false + } + + const sentAt = + typeof options.sentAt === 'number' ? options.sentAt : Date.now() + + this.socket.emit(LEON_EVENTS.utterance, { + value: trimmedValue, + sentAt, + sessionId: this.activeSessionId, + ...(options.commandContext + ? { commandContext: options.commandContext } + : {}) + }) + this.chatbot.sendTo('leon', trimmedValue, sentAt) + this.chatbot.scrollDown({ force: true }) + + this.save(trimmedValue) + + return true + } + + save(value = this._input.value) { + let val = value + + if (localStorage.getItem('history') === null) { + localStorage.setItem('history', JSON.stringify([])) + this.parsedHistory = JSON.parse(localStorage.getItem('history')) + } else if (this.parsedHistory.length >= 32) { + this.parsedHistory.shift() + } + + if (val[0] === ' ') { + val = val.substr(1, val.length - 1) + } + + if (this.parsedHistory[this.parsedHistory.length - 1] !== val) { + this.parsedHistory.push(val) + localStorage.setItem('history', JSON.stringify(this.parsedHistory)) + } + + this._input.value = '' + setTimeout(() => { + // Remove the last character to avoid the space + this._input.value = this._input.value.slice(0, -1) + }, 0) + } + + enableVoiceMode() { + if (!this._isVoiceModeEnabled) { + this._isVoiceModeEnabled = true + + const body = document.querySelector('body') + if (!body.classList.contains('voice-mode-enabled')) { + body.classList.add('voice-mode-enabled') + + const voiceOverlayTransitor = document.createElement('div') + voiceOverlayTransitor.id = 'voice-overlay-transitor' + body.appendChild(voiceOverlayTransitor) + voiceOverlayTransitor.addEventListener('animationend', () => { + voiceOverlayTransitor.removeEventListener('animationend', () => {}) + voiceOverlayTransitor.remove() + }) + } + } + } + disableVoiceMode() { + if (this._isVoiceModeEnabled) { + this._isVoiceModeEnabled = false + + const body = document.querySelector('body') + + const voiceContainer = document.querySelector('#voice-container') + if (voiceContainer) { + voiceContainer.style.animation = 'none' + voiceContainer.style.animation = null + } + + if (body.classList.contains('voice-mode-enabled')) { + body.classList.remove('voice-mode-enabled') + } + } + } +} diff --git a/app/src/js/constants.js b/app/src/js/constants.js new file mode 100644 index 0000000..3bfd4fe --- /dev/null +++ b/app/src/js/constants.js @@ -0,0 +1,22 @@ +export const INIT_MESSAGES = [ + [ + 'Hi, I\'m Leon, your open-source personal assistant. I\'m still evolving, but I\'m here to help.' + ], + [ + `Want to follow the project? + +- Regular progress updates: https://x.com/grenlouis +- Blog posts: https://blog.getleon.ai/ +- Email updates: https://leonai.substack.com/subscribe` + ], + [ + `Come hang out on Discord: https://discord.gg/MNQqqKg +That's where people will help shape the ecosystem and build what comes next.` + ], + [ + 'Leon is built independently in spare time. If you want to help accelerate development, you can support the project here: http://sponsor.getleon.ai/' + ] +] + +export const ASR_DISABLED_MESSAGE = + 'Voice mode is not enabled yet. Run /voice setup from the chat, wait for the resources to install, then restart Leon by using /restart.' diff --git a/app/src/js/file-system-autocomplete.js b/app/src/js/file-system-autocomplete.js new file mode 100644 index 0000000..bce3ff6 --- /dev/null +++ b/app/src/js/file-system-autocomplete.js @@ -0,0 +1,386 @@ +import axios from 'axios' + +const AUTOCOMPLETE_DELAY_MS = 80 +const CLOSE_DELAY_MS = 120 +const DROPDOWN_MARGIN_PX = 8 +const MINIMUM_DROPDOWN_HEIGHT_PX = 196 +const MAXIMUM_DROPDOWN_HEIGHT_PX = 280 +const FILE_SYSTEM_TRIGGER = '@' +const FOLDER_TYPE = 'folder' +const DEFAULT_FILE_ICON_NAME = 'file-line' +const DEFAULT_FOLDER_ICON_NAME = 'folder-3-line' +const NAVIGATION_DIRECTIONS = { + next: 1, + previous: -1 +} + +function isWhitespace(character) { + return character.trim() === '' +} + +function findPathToken(input) { + const selectionStart = input.selectionStart ?? input.value.length + let tokenStart = selectionStart + + while ( + tokenStart > 0 && + !isWhitespace(input.value.charAt(tokenStart - 1)) + ) { + tokenStart -= 1 + } + + if (input.value.charAt(tokenStart) !== FILE_SYSTEM_TRIGGER) { + return null + } + + return { + start: tokenStart, + end: selectionStart, + value: input.value.slice(tokenStart, selectionStart) + } +} + +export default class FileSystemAutocomplete { + constructor({ serverUrl, input = null, onValueChange = null }) { + this.serverUrl = serverUrl + this.input = null + this.onValueChange = onValueChange + this.dropdown = document.createElement('div') + this.dropdown.className = 'file-system-autocomplete file-system-autocomplete--hidden' + this.entries = [] + this.selectedEntryIndex = -1 + this.token = null + this.isOpen = false + this.requestCounter = 0 + this.autocompleteTimeout = null + this.closeTimeout = null + this.shouldScrollSelectedEntry = false + + this.handleInput = this.handleInput.bind(this) + this.handleKeyDown = this.handleKeyDown.bind(this) + this.handleFocus = this.handleFocus.bind(this) + this.handleClick = this.handleClick.bind(this) + this.handleBlur = this.handleBlur.bind(this) + this.handleWindowChange = this.handleWindowChange.bind(this) + + document.body.appendChild(this.dropdown) + + if (input) { + this.attach(input) + } + } + + attach(input) { + if (this.input === input) { + return + } + + window.clearTimeout(this.closeTimeout) + + if (this.input) { + this.removeInputListeners() + } + + this.input = input + this.input.addEventListener('input', this.handleInput) + this.input.addEventListener('keydown', this.handleKeyDown) + this.input.addEventListener('focus', this.handleFocus) + this.input.addEventListener('click', this.handleClick) + this.input.addEventListener('blur', this.handleBlur) + window.addEventListener('resize', this.handleWindowChange) + window.addEventListener('scroll', this.handleWindowChange, true) + } + + removeInputListeners() { + if (!this.input) { + return + } + + this.input.removeEventListener('input', this.handleInput) + this.input.removeEventListener('keydown', this.handleKeyDown) + this.input.removeEventListener('focus', this.handleFocus) + this.input.removeEventListener('click', this.handleClick) + this.input.removeEventListener('blur', this.handleBlur) + window.removeEventListener('resize', this.handleWindowChange) + window.removeEventListener('scroll', this.handleWindowChange, true) + this.input = null + } + + detach() { + this.removeInputListeners() + this.close() + } + + handleInput() { + window.clearTimeout(this.closeTimeout) + this.queueAutocomplete() + } + + handleFocus() { + window.clearTimeout(this.closeTimeout) + this.queueAutocomplete() + } + + handleClick() { + this.queueAutocomplete() + } + + handleBlur() { + this.queueClose() + } + + queueClose() { + window.clearTimeout(this.closeTimeout) + this.closeTimeout = window.setTimeout(() => { + this.close() + }, CLOSE_DELAY_MS) + } + + handleWindowChange() { + if (this.isOpen) { + this.positionDropdown() + } + } + + handleKeyDown(event) { + if (!this.isOpen) { + return + } + + if (event.key === 'Escape') { + event.preventDefault() + event.stopImmediatePropagation() + this.close() + return + } + + if (event.key === 'ArrowDown') { + event.preventDefault() + event.stopImmediatePropagation() + this.moveSelection(NAVIGATION_DIRECTIONS.next) + return + } + + if (event.key === 'ArrowUp') { + event.preventDefault() + event.stopImmediatePropagation() + this.moveSelection(NAVIGATION_DIRECTIONS.previous) + return + } + + if (event.key === 'Tab' || event.key === 'Enter') { + const selectedEntry = this.entries[this.selectedEntryIndex] + + if (selectedEntry) { + event.preventDefault() + event.stopImmediatePropagation() + this.applyEntry(selectedEntry) + } + } + } + + queueAutocomplete() { + window.clearTimeout(this.autocompleteTimeout) + this.autocompleteTimeout = window.setTimeout(() => { + void this.fetchAutocomplete() + }, AUTOCOMPLETE_DELAY_MS) + } + + async fetchAutocomplete() { + if (!this.input) { + this.close() + return + } + + if (document.activeElement !== this.input) { + this.queueClose() + return + } + + const token = findPathToken(this.input) + + if (!token) { + this.close() + return + } + + const requestId = this.requestCounter + 1 + this.requestCounter = requestId + this.token = token + + try { + const response = await axios.post( + `${this.serverUrl}/api/v1/file-system/list`, + { + value: token.value + } + ) + + if (requestId !== this.requestCounter) { + return + } + + this.entries = response.data.entries || [] + this.selectedEntryIndex = this.entries.length > 0 ? 0 : -1 + this.render() + } catch { + if (requestId !== this.requestCounter) { + return + } + + this.entries = [] + this.selectedEntryIndex = -1 + this.render() + } + } + + render() { + if (!this.input || !this.token) { + this.close() + return + } + + this.dropdown.innerHTML = '' + + if (this.entries.length === 0) { + const emptyElement = document.createElement('div') + emptyElement.className = 'file-system-autocomplete__empty' + emptyElement.textContent = 'No matching file system entry.' + this.dropdown.appendChild(emptyElement) + } else { + this.entries.forEach((entry, index) => { + const item = document.createElement('button') + const icon = document.createElement('i') + const label = document.createElement('span') + + item.type = 'button' + item.className = `file-system-autocomplete__item${ + index === this.selectedEntryIndex + ? ' file-system-autocomplete__item--selected' + : '' + }` + icon.className = `ri-${ + entry.iconName || + (entry.type === FOLDER_TYPE + ? DEFAULT_FOLDER_ICON_NAME + : DEFAULT_FILE_ICON_NAME) + }` + label.className = 'file-system-autocomplete__label' + label.textContent = entry.value + + item.addEventListener('mousedown', (event) => { + event.preventDefault() + }) + item.addEventListener('click', () => { + this.applyEntry(entry) + }) + + item.appendChild(icon) + item.appendChild(label) + this.dropdown.appendChild(item) + }) + } + + this.isOpen = true + this.dropdown.classList.remove('file-system-autocomplete--hidden') + this.positionDropdown() + + if (this.shouldScrollSelectedEntry) { + this.shouldScrollSelectedEntry = false + this.scrollSelectedEntryIntoView() + } + } + + positionDropdown() { + const inputRect = this.input.getBoundingClientRect() + const spaceBelow = window.innerHeight - inputRect.bottom + const spaceAbove = inputRect.top + const shouldOpenAbove = + spaceBelow < MINIMUM_DROPDOWN_HEIGHT_PX && spaceAbove > spaceBelow + const availableHeight = + (shouldOpenAbove ? spaceAbove : spaceBelow) - DROPDOWN_MARGIN_PX * 2 + const maxHeight = Math.min( + MAXIMUM_DROPDOWN_HEIGHT_PX, + Math.max(MINIMUM_DROPDOWN_HEIGHT_PX, availableHeight) + ) + + this.dropdown.style.left = `${inputRect.left}px` + this.dropdown.style.width = `${inputRect.width}px` + this.dropdown.style.maxHeight = `${maxHeight}px` + + if (shouldOpenAbove) { + this.dropdown.style.top = '' + this.dropdown.style.bottom = `${ + window.innerHeight - inputRect.top + DROPDOWN_MARGIN_PX + }px` + } else { + this.dropdown.style.top = `${inputRect.bottom + DROPDOWN_MARGIN_PX}px` + this.dropdown.style.bottom = '' + } + } + + moveSelection(direction) { + if (this.entries.length === 0) { + return + } + + this.selectedEntryIndex = + (this.selectedEntryIndex + direction + this.entries.length) % + this.entries.length + this.shouldScrollSelectedEntry = true + this.render() + } + + scrollSelectedEntryIntoView() { + const selectedEntryElement = this.dropdown.querySelector( + '.file-system-autocomplete__item--selected' + ) + + if (!selectedEntryElement) { + return + } + + selectedEntryElement.scrollIntoView({ + block: 'nearest' + }) + } + + applyEntry(entry) { + if (!this.input || !this.token) { + return + } + + const completedValue = entry.absolutePath || entry.value + const nextCharacter = this.input.value.charAt(this.token.end) + const shouldAddTrailingWhitespace = + nextCharacter === '' || !isWhitespace(nextCharacter) + const insertedValue = `${completedValue}${ + shouldAddTrailingWhitespace ? ' ' : '' + }` + const nextValue = `${this.input.value.slice(0, this.token.start)}${ + insertedValue + }${this.input.value.slice(this.token.end)}` + const nextCursorPosition = this.token.start + insertedValue.length + + this.input.value = nextValue + this.input.setSelectionRange(nextCursorPosition, nextCursorPosition) + this.input.dispatchEvent(new Event('input', { bubbles: true })) + + if (this.onValueChange) { + this.onValueChange(nextValue) + window.requestAnimationFrame(() => { + this.input?.setSelectionRange(nextCursorPosition, nextCursorPosition) + }) + } + + this.close() + } + + close() { + this.isOpen = false + this.entries = [] + this.selectedEntryIndex = -1 + this.token = null + this.dropdown.classList.add('file-system-autocomplete--hidden') + } +} diff --git a/app/src/js/init.jsx b/app/src/js/init.jsx new file mode 100644 index 0000000..1a2582f --- /dev/null +++ b/app/src/js/init.jsx @@ -0,0 +1,252 @@ +import { useEffect, useState, useRef } from 'react' +import { createRoot } from 'react-dom/client' +import { + WidgetWrapper, + Text, + Icon, + Flexbox, + List, + ListHeader, + ListItem, + Loader +} from '@aurora' + +const container = document.querySelector('#init') +const root = createRoot(container) +const LLAMA_SERVER_BOOT_STATUS = 'llamaServerBoot' +const INIT_ERROR_STATUS = 'error' +const INIT_ERROR_DISMISS_SECONDS = 10 +const INIT_ERROR_DISMISS_INTERVAL_MS = 1_000 + +function Item({ children, status }) { + if (status === 'error') { + return {children} + } + if (status === 'warning') { + return {children} + } + if (status === 'success') { + return {children} + } + if (status === 'loading') { + return {children} + } + + return {children} +} + +function LoadingListItem({ children }) { + return ( + + + + {children} + + + ) +} +function ErrorListItem({ children }) { + return ( + + + + {children} + + + ) +} +function WarningListItem({ children }) { + return ( + + + + {children} + + + ) +} +function SuccessListItem({ children }) { + return ( + + + + {children} + + + ) +} + +function Init() { + const parentRef = useRef(null) + const [config, setConfig] = useState(() => ({ ...window.leonConfigInfo })) + const usesLlamaCPP = + config.llm?.workflowProvider === 'llamacpp' || + config.llm?.agentProvider === 'llamacpp' + const [initErrorCountdown, setInitErrorCountdown] = useState(null) + const [areInitErrorsDismissed, setAreInitErrorsDismissed] = useState(false) + const [statusMap, setStatusMap] = useState({ + clientCoreServerHandshake: 'loading', + tcpServerBoot: + window.leonConfigInfo?.tcpServer?.enabled === false ? 'success' : 'loading', + [LLAMA_SERVER_BOOT_STATUS]: + window.leonConfigInfo?.llm?.workflowProvider === 'llamacpp' || + window.leonConfigInfo?.llm?.agentProvider === 'llamacpp' + ? 'loading' + : 'success' + }) + const hasInitError = Object.values(statusMap).some( + (status) => status === INIT_ERROR_STATUS + ) + + useEffect(() => { + setTimeout(() => { + if (parentRef.current) { + parentRef.current.classList.remove('not-initialized') + } + }, 250) + + function handleStatusChange(event) { + const { statusName, statusType } = event.detail + + if (statusType === INIT_ERROR_STATUS) { + setAreInitErrorsDismissed(false) + } + + setStatusMap((prev) => ({ ...prev, [statusName]: statusType })) + } + + window.leonInitStatusEvent.addEventListener( + 'initStatusChange', + handleStatusChange + ) + return () => + window.leonInitStatusEvent.removeEventListener( + 'initStatusChange', + handleStatusChange + ) + }, []) + + useEffect(() => { + if (!hasInitError || areInitErrorsDismissed) { + setInitErrorCountdown(null) + return + } + + let secondsLeft = INIT_ERROR_DISMISS_SECONDS + setInitErrorCountdown(secondsLeft) + + const interval = setInterval(() => { + secondsLeft -= 1 + setInitErrorCountdown(secondsLeft) + + if (secondsLeft <= 0) { + clearInterval(interval) + setAreInitErrorsDismissed(true) + } + }, INIT_ERROR_DISMISS_INTERVAL_MS) + + return () => clearInterval(interval) + }, [hasInitError, areInitErrorsDismissed]) + + const statuses = [] + for (let key of Object.keys(statusMap)) { + if (key === 'tcpServerBoot' && config.tcpServer?.enabled === false) { + statuses.push('success') + } else if (statusMap[key] === INIT_ERROR_STATUS && areInitErrorsDismissed) { + statuses.push('success') + } else if ( + key === LLAMA_SERVER_BOOT_STATUS && + !usesLlamaCPP + ) { + statuses.push('success') + } else { + statuses.push(statusMap[key]) + } + } + + const areAllStatusesSuccess = statuses.every((status) => status === 'success') + const getInitMessage = (status, defaultMessage) => { + if (status === INIT_ERROR_STATUS && initErrorCountdown !== null) { + return `An error occurred during the initialization. This message will disappear in ${initErrorCountdown} seconds` + } + + return defaultMessage + } + + useEffect(() => { + if (window.leonConfigInfo) { + setConfig({ ...window.leonConfigInfo }) + } + }, [window.leonConfigInfo]) + + return ( +
+
+ + + Leon is getting ready... + + {getInitMessage( + statusMap.clientCoreServerHandshake, + 'Client and core server handshaked' + )} + + {config.tcpServer?.enabled !== false && ( + + {getInitMessage(statusMap.tcpServerBoot, 'TCP server booted')} + + )} + {usesLlamaCPP && ( + + {getInitMessage( + statusMap[LLAMA_SERVER_BOOT_STATUS], + 'llama-server booted' + )} + + )} + + +
+
+ ) +} + +root.render() diff --git a/app/src/js/listener.js b/app/src/js/listener.js new file mode 100644 index 0000000..5b8f63f --- /dev/null +++ b/app/src/js/listener.js @@ -0,0 +1,44 @@ +const listener = {} + +listener.listening = ( + stream, + minDecibels, + maxBlankTime, + cbOnStart, + cbOnEnd +) => { + const ctx = new AudioContext() + const analyser = ctx.createAnalyser() + const streamNode = ctx.createMediaStreamSource(stream) + streamNode.connect(analyser) + analyser.minDecibels = minDecibels + + const data = new Uint8Array(analyser.frequencyBinCount) + let silenceStart = performance.now() + let triggered = false + + const loop = (time) => { + requestAnimationFrame(loop) + + analyser.getByteFrequencyData(data) + + if (data.some((v) => v)) { + if (triggered) { + triggered = false + + cbOnStart() + } + silenceStart = time + } + + if (!triggered && time - silenceStart > maxBlankTime) { + cbOnEnd() + + triggered = true + } + } + + loop() +} + +export default listener diff --git a/app/src/js/main.js b/app/src/js/main.js new file mode 100644 index 0000000..bd09a86 --- /dev/null +++ b/app/src/js/main.js @@ -0,0 +1,213 @@ +import axios from 'axios' +import '@aurora/style.css' + +window.leonInitStatusEvent = new EventTarget() + +import './init' +import Client from './client' +import { BuiltInCommands } from './built-in-commands' +import FileSystemAutocomplete from './file-system-autocomplete' +import SessionsPanel from './sessions' +// import Recorder from './recorder' +// import listener from './listener' +import { onkeydownstartrecording, onkeydowninput } from './onkeydown' + +const config = { + app: 'webapp', + server_host: import.meta.env.VITE_LEON_HOST, + server_port: import.meta.env.VITE_LEON_PORT, + min_decibels: -40, // Noise detection sensitivity + max_blank_time: 1_000 // Maximum time to consider a blank (ms) +} +const serverUrl = + import.meta.env.VITE_LEON_NODE_ENV === 'production' + ? '' + : `${config.server_host}:${config.server_port}` + +document.addEventListener('DOMContentLoaded', async () => { + try { + const [response, sessionsResponse] = await Promise.all([ + axios.get(`${serverUrl}/api/v1/info`), + axios.get(`${serverUrl}/api/v1/sessions`) + ]) + const input = document.querySelector('#utterance') + const mic = document.querySelector('#mic-button') + const v = document.querySelector('#version small') + const infoButton = document.querySelector('#info') + const client = new Client(config.app, serverUrl, input, { + activeSessionId: sessionsResponse.data.active_session_id + }) + const sessionsPanel = new SessionsPanel({ + serverUrl, + socket: client.socket, + activeSessionId: sessionsResponse.data.active_session_id, + initialPayload: sessionsResponse.data, + onSelect: (sessionId) => client.setActiveSession(sessionId) + }) + const fileSystemAutocomplete = new FileSystemAutocomplete({ + serverUrl, + input + }) + const builtInCommands = new BuiltInCommands({ + serverUrl, + input, + getActiveSessionId: () => sessionsPanel.getActiveSessionId(), + onCommandExecuted: (commandInput) => { + if (commandInput.trim().startsWith('/session')) { + void sessionsPanel.refresh() + } + }, + onSubmitToChat: (clientAction) => { + return client.sendUtterance(clientAction.utterance, { + commandContext: { + forcedRoutingMode: clientAction.command_context?.forced_routing_mode, + forcedSkillName: clientAction.command_context?.forced_skill_name, + forcedToolName: clientAction.command_context?.forced_tool_name + } + }) + } + }) + // let rec = {} + // let chunks = [] + + window.leonConfigInfo = response.data + const infoKeys = [ + 'timeZone', + 'telemetry', + 'gpu', + 'graphicsComputeAPI', + 'totalVRAM', + 'freeVRAM', + 'usedVRAM', + 'llm', + 'asr', + 'tts', + 'mood', + 'version' + ] + const infoToDisplay = {} + infoKeys.forEach((key) => { + infoToDisplay[key] = window.leonConfigInfo[key] + }) + + v.textContent += window.leonConfigInfo.version + + client.updateMood(window.leonConfigInfo.mood) + client.setSessionPanel(sessionsPanel) + sessionsPanel.init() + client.init() + fileSystemAutocomplete.attach(input) + builtInCommands.init() + + infoButton.addEventListener('click', () => { + alert(JSON.stringify(infoToDisplay, null, 2)) + }) + + /*if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + navigator.mediaDevices + .getUserMedia({ audio: true }) + .then((stream) => { + if (MediaRecorder) { + rec = new Recorder(stream, mic, window.leonConfigInfo) + client.recorder = rec + + rec.ondataavailable((e) => { + chunks.push(e.data) + }) + + rec.onstart(() => { + /!* *!/ + }) + + rec.onstop(() => { + const blob = new Blob(chunks) + chunks = [] + rec.enabled = false + + // Ensure there are some data + if (blob.size >= 1_000) { + client.socket.emit('recognize', blob) + } + }) + + listener.listening( + stream, + config.min_decibels, + config.max_blank_time, + () => { + // Noise detected + rec.noiseDetected = true + }, + () => { + // Noise ended + + rec.noiseDetected = false + if (rec.enabled && !rec.hotwordTriggered) { + rec.stop() + rec.enabled = false + rec.hotwordTriggered = false + rec.countSilenceAfterTalk = 0 + } + } + ) + + client.socket.on('enable-record', () => { + rec.hotwordTriggered = true + rec.start() + setTimeout(() => { + rec.hotwordTriggered = false + }, config.max_blank_time) + rec.enabled = true + }) + } else { + console.error('MediaRecorder is not supported on your browser.') + } + }) + .catch((err) => { + console.error( + 'MediaDevices.getUserMedia() threw the following error:', + err + ) + }) + } else { + console.error( + 'MediaDevices.getUserMedia() is not supported on your browser.' + ) + }*/ + + document.addEventListener('keydown', (e) => { + onkeydownstartrecording(e, () => { + client.asrStartRecording() + /*if (rec.enabled === false) { + input.value = '' + rec.start() + rec.enabled = true + } else { + rec.stop() + rec.enabled = false + }*/ + }) + }) + + input.addEventListener('keydown', (e) => { + onkeydowninput(e, client) + }) + + mic.addEventListener('click', (e) => { + e.preventDefault() + + client.asrStartRecording() + + /*if (rec.enabled === false) { + rec.start() + rec.enabled = true + } else { + rec.stop() + rec.enabled = false + }*/ + }) + } catch (e) { + alert(`Error: ${e.message}; ${JSON.stringify(e.response?.data)}`) + console.error(e) + } +}) diff --git a/app/src/js/onkeydown.js b/app/src/js/onkeydown.js new file mode 100644 index 0000000..6152b50 --- /dev/null +++ b/app/src/js/onkeydown.js @@ -0,0 +1,38 @@ +let index = -1 +let parsedHistory = null + +const onkeydowninput = (e, client) => { + const key = e.which || e.keyCode + + if (localStorage.getItem('history') !== null && (key === 38 || key === 40)) { + parsedHistory = JSON.parse(localStorage.getItem('history')).reverse() + } + + if (key === 13 && !e.shiftKey) { + if (client.send('utterance')) { + parsedHistory = JSON.parse(localStorage.getItem('history')).reverse() + index = -1 + } + } else if (localStorage.getItem('history') !== null) { + if (e.shiftKey) { + if (key === 38 && index < parsedHistory.length - 1) { + index += 1 + client.input = parsedHistory[index] + } else if (key === 40 && index - 1 >= 0) { + index -= 1 + client.input = parsedHistory[index] + } else if (key === 40 && index - 1 < 0) { + client.input = '' + index = -1 + } + } + } +} + +const onkeydownstartrecording = (e, cb) => { + if ((e.metaKey || e.altKey) && e.key === 'c') { + cb() + } +} + +export { onkeydowninput, onkeydownstartrecording } diff --git a/app/src/js/recorder.js b/app/src/js/recorder.js new file mode 100644 index 0000000..7db714c --- /dev/null +++ b/app/src/js/recorder.js @@ -0,0 +1,63 @@ +import on from '../sounds/on.mp3' +import off from '../sounds/off.mp3' + +export default class Recorder { + constructor(stream, el, info) { + this.recorder = new MediaRecorder(stream, { audioBitsPerSecond: 16000 }) + this.el = el + this.audioOn = new Audio(on) + this.audioOff = new Audio(off) + this.playSound = true + this.info = info + this.enabled = false + this.hotwordTriggered = false + this.noiseDetected = false + this.countSilenceAfterTalk = 0 + } + + start(playSound = true) { + if (this.info.asr.enabled === false) { + console.warn('ASR disabled') + } else { + this.playSound = playSound + this.recorder.start(playSound) + } + } + + stop(playSound = true) { + if (this.info.asr.enabled === false) { + console.warn('ASR disabled') + } else { + this.playSound = playSound + this.recorder.stop(playSound) + } + } + + onstart(cb) { + this.recorder.onstart = (e) => { + if (this.playSound) { + this.audioOn.play() + } + this.el.classList.add('enabled') + + cb(e) + } + } + + onstop(cb) { + this.recorder.onstop = (e) => { + if (this.playSound) { + this.audioOff.play() + } + this.el.classList.remove('enabled') + + cb(e) + } + } + + ondataavailable(cb) { + this.recorder.ondataavailable = (e) => { + cb(e) + } + } +} diff --git a/app/src/js/render-aurora-component.js b/app/src/js/render-aurora-component.js new file mode 100644 index 0000000..26390b3 --- /dev/null +++ b/app/src/js/render-aurora-component.js @@ -0,0 +1,56 @@ +import { createElement } from 'react' + +import * as auroraComponents from '@aurora' + +import * as customAuroraComponents from '../custom-aurora-components' + +export default function renderAuroraComponent( + socket, + component, + supportedEvents +) { + if (component) { + // `import/namespace` cannot statically validate dynamic component lookups. + // eslint-disable-next-line import/namespace + let reactComponent = auroraComponents[component.component] + /** + * Find custom component if a former component is not found + */ + if (!reactComponent) { + // eslint-disable-next-line import/namespace + reactComponent = customAuroraComponents[component.component] + } + + if (!reactComponent) { + console.error(`Component ${component.component} not found`) + return null + } + + // Check if the browsed component has a supported event and bind it + if (reactComponent && Array.isArray(component.events)) { + component.events.forEach((event) => { + if (supportedEvents.includes(event.type)) { + component.props[event.type] = (data) => { + const { method } = event + + socket.emit('widget-event', { method, data }) + } + } + }) + } + + // When children is a component, then wrap it in an array to render properly + const isComponent = !!component.props?.children?.component + if (isComponent) { + component.props.children = [component.props.children] + } + + if (component.props?.children && Array.isArray(component.props.children)) { + component.props.children = component.props.children.map((child) => { + return renderAuroraComponent(socket, child, supportedEvents) + }) + } + + return createElement(reactComponent, component.props) + } +} diff --git a/app/src/js/sessions.js b/app/src/js/sessions.js new file mode 100644 index 0000000..bc07d00 --- /dev/null +++ b/app/src/js/sessions.js @@ -0,0 +1,288 @@ +import axios from 'axios' + +const DAY_MS = 24 * 60 * 60 * 1_000 +const GROUP_DATE_FORMATTER = new Intl.DateTimeFormat(undefined, { + month: 'long', + day: 'numeric', + year: 'numeric' +}) + +function createElement(tagName, className, textContent = '') { + const element = document.createElement(tagName) + + if (className) { + element.className = className + } + + if (textContent) { + element.textContent = textContent + } + + return element +} + +function getDayKey(timestamp) { + const date = new Date(timestamp) + + return new Date( + date.getFullYear(), + date.getMonth(), + date.getDate() + ).getTime() +} + +function getGroupLabel(timestamp) { + const now = Date.now() + const todayKey = getDayKey(now) + const yesterdayKey = todayKey - DAY_MS + const itemKey = getDayKey(timestamp) + + if (itemKey === todayKey) { + return 'Today' + } + + if (itemKey === yesterdayKey) { + return 'Yesterday' + } + + return GROUP_DATE_FORMATTER.format(new Date(timestamp)) +} + +export default class SessionsPanel { + constructor({ + serverUrl, + socket, + activeSessionId, + initialPayload, + onSelect + }) { + this.serverUrl = serverUrl + this.socket = socket + this.activeSessionId = activeSessionId + this.sessions = initialPayload?.sessions || [] + this.supportedProviders = initialPayload?.supported_providers || [] + this.currentModelTarget = initialPayload?.current_model_target || '' + this.onSelect = onSelect + this.container = document.querySelector('#sessions-panel') + this.list = document.querySelector('#sessions-list') + this.newButton = document.querySelector('#new-session') + } + + init() { + this.newButton.addEventListener('click', () => { + void this.createSession() + }) + this.list.addEventListener('click', (event) => { + void this.handleClick(event) + }) + this.render() + } + + getActiveSessionId() { + return this.activeSessionId + } + + async refresh() { + const previousActiveSessionId = this.activeSessionId + const response = await axios.get(`${this.serverUrl}/api/v1/sessions`) + + this.applyPayload(response.data) + + if ( + response.data.active_session_id && + response.data.active_session_id !== previousActiveSessionId + ) { + await this.onSelect?.(response.data.active_session_id) + } + } + + async createSession() { + const response = await axios.post(`${this.serverUrl}/api/v1/sessions`) + + this.applyPayload(response.data) + await this.selectSession(response.data.session.id) + } + + async selectSession(sessionId) { + this.activeSessionId = sessionId + this.socket.emit('session-change', sessionId) + await this.onSelect?.(sessionId) + await axios.patch(`${this.serverUrl}/api/v1/sessions/${sessionId}`, { + is_active: true + }) + await this.refresh() + } + + async updateSession(sessionId, payload) { + const response = await axios.patch( + `${this.serverUrl}/api/v1/sessions/${sessionId}`, + payload + ) + + this.applyPayload(response.data) + } + + async deleteSession(sessionId) { + const wasActiveSession = this.activeSessionId === sessionId + const response = await axios.delete( + `${this.serverUrl}/api/v1/sessions/${sessionId}` + ) + + this.applyPayload(response.data) + + if (wasActiveSession) { + await this.selectSession(response.data.active_session_id) + } + } + + async handleClick(event) { + const button = event.target.closest('button') + const item = event.target.closest('.session-item') + + if (!item) { + return + } + + const sessionId = item.getAttribute('data-session-id') + + if (!button) { + await this.selectSession(sessionId) + return + } + + const action = button.getAttribute('data-action') + + if (action === 'rename') { + const currentTitle = item.getAttribute('data-session-title') || '' + const title = window.prompt('Session title', currentTitle) + + if (title && title.trim()) { + await this.updateSession(sessionId, { title: title.trim() }) + } + } else if (action === 'pin') { + await this.updateSession(sessionId, { + is_pinned: button.getAttribute('aria-pressed') !== 'true' + }) + } else if (action === 'delete') { + await this.deleteSession(sessionId) + } else if (action === 'model') { + await this.updateSessionModel(sessionId) + } + } + + async updateSessionModel(sessionId) { + const provider = window.prompt( + `Provider (${this.supportedProviders.join(', ')})` + ) + + if (!provider) { + return + } + + const model = window.prompt('Model') + + if (!model) { + return + } + + await this.updateSession(sessionId, { + provider: provider.trim(), + model: model.trim() + }) + } + + applyPayload(payload) { + this.sessions = payload.sessions || [] + this.supportedProviders = payload.supported_providers || [] + this.currentModelTarget = payload.current_model_target || '' + this.activeSessionId = payload.active_session_id || this.activeSessionId + this.render() + } + + render() { + this.list.innerHTML = '' + + const pinnedSessions = this.sessions.filter((session) => session.isPinned) + const unpinnedSessions = this.sessions.filter((session) => !session.isPinned) + + if (pinnedSessions.length > 0) { + this.renderGroup('Pinned', pinnedSessions) + } + + const groupedSessions = new Map() + + for (const session of unpinnedSessions) { + const timestamp = session.lastMessageAt || session.updatedAt + const groupLabel = getGroupLabel(timestamp) + const group = groupedSessions.get(groupLabel) || [] + + group.push(session) + groupedSessions.set(groupLabel, group) + } + + for (const [label, sessions] of groupedSessions.entries()) { + this.renderGroup(label, sessions) + } + } + + renderGroup(label, sessions) { + const group = createElement('section', 'session-group') + const heading = createElement('h2', 'session-group-title', label) + + group.appendChild(heading) + + for (const session of sessions) { + group.appendChild(this.createSessionItem(session)) + } + + this.list.appendChild(group) + } + + createSessionItem(session) { + const item = createElement('article', 'session-item') + const title = createElement('div', 'session-title', session.title) + const meta = createElement( + 'div', + 'session-meta', + session.modelTarget || this.currentModelTarget || 'Default model' + ) + const actions = createElement('div', 'session-actions') + + item.setAttribute('data-session-id', session.id) + item.setAttribute('data-session-title', session.title) + + if (session.id === this.activeSessionId) { + item.classList.add('session-item--active') + } + + actions.appendChild( + this.createActionButton( + 'pin', + session.isPinned ? 'ri-pushpin-fill' : 'ri-pushpin-line', + session.isPinned + ) + ) + actions.appendChild(this.createActionButton('rename', 'ri-edit-line')) + actions.appendChild(this.createActionButton('model', 'ri-brain-line')) + actions.appendChild(this.createActionButton('delete', 'ri-delete-bin-line')) + + item.appendChild(title) + item.appendChild(meta) + item.appendChild(actions) + + return item + } + + createActionButton(action, iconClassName, isPressed = false) { + const button = createElement('button', 'session-action') + const icon = createElement('i', iconClassName) + + button.type = 'button' + button.setAttribute('data-action', action) + button.setAttribute('aria-label', action) + button.setAttribute('aria-pressed', String(isPressed)) + button.appendChild(icon) + + return button + } +} diff --git a/app/src/js/suggestion-handler.js b/app/src/js/suggestion-handler.js new file mode 100644 index 0000000..89ef909 --- /dev/null +++ b/app/src/js/suggestion-handler.js @@ -0,0 +1,43 @@ +import { createElement } from 'react' +import { createRoot } from 'react-dom/client' + +import { WidgetWrapper, List, ListHeader, ListItem } from '@aurora' + +export default function handleSuggestions(data, chatbot, client) { + const container = document.createElement('div') + container.className = 'bubble-container leon' + + chatbot.feed.appendChild(container) + + const root = createRoot(container) + + root.render( + createElement(WidgetWrapper, { + noPadding: true, + children: createElement(List, { + children: [ + createElement(ListHeader, { + children: 'Suggestions' + }), + ...data.map((suggestionText) => { + return createElement(ListItem, { + children: suggestionText, + name: 'suggestion', + value: suggestionText, + onClick: (suggestion) => { + const parent = container.parentNode + + if (parent) { + parent.removeChild(container) + } + + client.input.value = suggestion.value + client.send('utterance') + } + }) + }) + ] + }) + }) + ) +} diff --git a/app/src/js/tool-ui-handler.js b/app/src/js/tool-ui-handler.js new file mode 100644 index 0000000..3942071 --- /dev/null +++ b/app/src/js/tool-ui-handler.js @@ -0,0 +1,1010 @@ +const COMMAND_OUTPUT_MAX_DISPLAY_CHARS = 80_000 +const ANSI_ESCAPE_PATTERN = + // eslint-disable-next-line no-control-regex + /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\))/g + +/** + * Tool UI Handler + * Renders tool executions as expandable activity cards. + */ +export default class ToolUIHandler { + constructor(feedElement, scrollDownCallback, formatMessageCallback) { + this.feed = feedElement + this.scrollDown = scrollDownCallback + this.formatMessage = formatMessageCallback + this.toolGroups = new Map() + } + + /** + * Handle tool output messages with interactive activity cards. + */ + handleToolOutput(data) { + if (data.activityType === 'agent_skill') { + return this.handleAgentSkillActivity(data) + } + + const { + toolkitName, + toolName, + toolGroupId, + answer, + replaceMessageId, + key + } = data + + if (replaceMessageId) { + this.replaceToolMessage(replaceMessageId, data) + return + } + + const answerKey = key ? key.split('.').pop() : 'unknown' + const groupId = toolGroupId || `${toolkitName}_${toolName}_${Date.now()}` + const mode = + data.toolDisplayMode === 'activity_card' ? 'activity_card' : 'legacy' + + let toolGroupContainer = this.toolGroups.get(groupId) + + if (!toolGroupContainer) { + toolGroupContainer = this.createToolGroupContainer({ + groupId, + toolkitName, + toolName, + answerKey, + mode, + data + }) + this.toolGroups.set(groupId, toolGroupContainer) + } + + if (toolGroupContainer.mode === 'activity_card') { + this.updateActivityCard(toolGroupContainer, data, answerKey) + } else { + this.addLegacyToolMessage(toolGroupContainer, answer) + } + + this.scrollDown() + + return { + groupId, + isNewGroup: toolGroupContainer.isNew + } + } + + handleAgentSkillActivity(data) { + const agentSkill = data.agentSkill || {} + const skillId = agentSkill.id || agentSkill.name || 'agent-skill' + const groupId = data.toolGroupId || `agent_skill_${skillId}_${Date.now()}` + + let activityContainer = this.toolGroups.get(groupId) + + if (!activityContainer) { + activityContainer = this.createAgentSkillActivityCard({ + groupId, + agentSkill + }) + this.toolGroups.set(groupId, activityContainer) + } + + this.updateAgentSkillActivityCard(activityContainer, data) + this.scrollDown() + + return { + groupId, + isNewGroup: activityContainer.isNew + } + } + + createToolGroupContainer(params) { + return params.mode === 'activity_card' + ? this.createActivityCardContainer(params) + : this.createLegacyToolGroupContainer(params) + } + + getRemixIconClass(iconName) { + const fallbackIconName = 'ri-magic-line' + if (typeof iconName !== 'string') { + return fallbackIconName + } + + const trimmedIconName = iconName.trim() + if (!trimmedIconName || trimmedIconName.includes(' ')) { + return fallbackIconName + } + + return trimmedIconName.startsWith('ri-') + ? trimmedIconName + : `ri-${trimmedIconName}` + } + + getToolActivityIconClass(data) { + return this.getRemixIconClass(data.toolIconName || data.toolkitIconName) + } + + /** + * Create the legacy shell-like tool group container. + */ + createLegacyToolGroupContainer({ + groupId, + toolkitName, + toolName, + answerKey + }) { + const groupContainer = document.createElement('div') + groupContainer.className = 'tool-group-container' + groupContainer.setAttribute('data-tool-group-id', groupId) + + const toolHeader = document.createElement('button') + toolHeader.className = 'tool-header' + toolHeader.setAttribute('type', 'button') + toolHeader.innerHTML = ` + + ${toolkitName} toolkit → ${toolName} → ${answerKey} + + ` + + const toolContent = document.createElement('div') + toolContent.className = 'tool-content' + + const shellOutput = document.createElement('div') + shellOutput.className = 'shell-output' + + toolContent.appendChild(shellOutput) + groupContainer.appendChild(toolHeader) + groupContainer.appendChild(toolContent) + + this.addExpandCollapseHandler(toolHeader, toolContent) + this.feed.appendChild(groupContainer) + + return { + mode: 'legacy', + container: groupContainer, + toolHeader, + toolContent, + shellOutput, + isNew: true + } + } + + createActivityCardContainer({ + groupId, + toolkitName, + toolName, + answerKey, + data + }) { + const groupContainer = document.createElement('div') + groupContainer.className = 'tool-group-container tool-activity-card' + groupContainer.setAttribute('data-tool-group-id', groupId) + + const toolHeader = document.createElement('button') + toolHeader.className = 'tool-header tool-activity-header' + toolHeader.setAttribute('type', 'button') + + const heading = document.createElement('div') + heading.className = 'tool-activity-heading' + + const icon = document.createElement('i') + icon.className = `${this.getToolActivityIconClass(data)} tool-icon` + + const titleBlock = document.createElement('div') + titleBlock.className = 'tool-activity-title-block' + + const title = document.createElement('span') + title.className = 'tool-title' + title.textContent = data.stepLabel || this.humanizeFunctionName(answerKey) + + const subtitle = document.createElement('span') + subtitle.className = 'tool-subtitle' + subtitle.textContent = `${toolkitName} toolkit • ${toolName}` + + titleBlock.appendChild(title) + titleBlock.appendChild(subtitle) + heading.appendChild(icon) + heading.appendChild(titleBlock) + + const meta = document.createElement('div') + meta.className = 'tool-activity-meta' + + const statusChip = document.createElement('span') + statusChip.className = 'tool-status-chip running' + statusChip.textContent = 'Running' + + const expandIcon = document.createElement('i') + expandIcon.className = 'ri-arrow-down-s-line expand-icon' + + meta.appendChild(statusChip) + meta.appendChild(expandIcon) + toolHeader.appendChild(heading) + toolHeader.appendChild(meta) + + const toolContent = document.createElement('div') + toolContent.className = 'tool-content' + + const summary = document.createElement('div') + summary.className = 'tool-activity-summary' + summary.textContent = 'Preparing tool activity...' + + const sections = document.createElement('div') + sections.className = 'tool-activity-sections' + + const inputPanel = this.createActivityPanel( + 'Input', + 'Parameters sent to the function' + ) + const outputPanel = this.createActivityPanel( + 'Result', + 'What the function returned' + ) + + sections.appendChild(inputPanel.panel) + sections.appendChild(outputPanel.panel) + + const rawDetails = document.createElement('details') + rawDetails.className = 'tool-raw-details' + + const rawSummary = document.createElement('summary') + rawSummary.textContent = 'Raw data' + + const rawContent = document.createElement('div') + rawContent.className = 'tool-raw-content' + + rawDetails.appendChild(rawSummary) + rawDetails.appendChild(rawContent) + + toolContent.appendChild(summary) + toolContent.appendChild(sections) + toolContent.appendChild(rawDetails) + groupContainer.appendChild(toolHeader) + groupContainer.appendChild(toolContent) + + this.addExpandCollapseHandler(toolHeader, toolContent) + this.feed.appendChild(groupContainer) + + return { + mode: 'activity_card', + container: groupContainer, + toolHeader, + toolContent, + summary, + title, + subtitle, + statusChip, + inputBody: inputPanel.body, + outputBody: outputPanel.body, + rawContent, + rawDetails, + rawInput: null, + rawOutput: null, + commandOutputText: '', + preparationLog: [], + isNew: true + } + } + + createAgentSkillActivityCard({ groupId, agentSkill }) { + const groupContainer = document.createElement('div') + groupContainer.className = + 'tool-group-container tool-activity-card agent-skill-activity-card' + groupContainer.setAttribute('data-tool-group-id', groupId) + + const skillName = agentSkill.name || agentSkill.id || 'Agent Skill' + const skillPath = agentSkill.skillPath || 'SKILL.md' + + const toolHeader = document.createElement('button') + toolHeader.className = 'tool-header tool-activity-header' + toolHeader.setAttribute('type', 'button') + + const heading = document.createElement('div') + heading.className = 'tool-activity-heading' + + const icon = document.createElement('i') + icon.className = 'ri-book-ai-line tool-icon' + + const titleBlock = document.createElement('div') + titleBlock.className = 'tool-activity-title-block' + + const title = document.createElement('span') + title.className = 'tool-title' + title.textContent = `Agent Skill: ${skillName}` + + const subtitle = document.createElement('span') + subtitle.className = 'tool-subtitle' + subtitle.textContent = skillPath + subtitle.setAttribute('title', skillPath) + + titleBlock.appendChild(title) + titleBlock.appendChild(subtitle) + heading.appendChild(icon) + heading.appendChild(titleBlock) + + const meta = document.createElement('div') + meta.className = 'tool-activity-meta' + + const statusChip = document.createElement('span') + statusChip.className = 'tool-status-chip selected' + statusChip.textContent = 'In use' + + const expandIcon = document.createElement('i') + expandIcon.className = 'ri-arrow-down-s-line expand-icon' + + meta.appendChild(statusChip) + meta.appendChild(expandIcon) + toolHeader.appendChild(heading) + toolHeader.appendChild(meta) + + const toolContent = document.createElement('div') + toolContent.className = 'tool-content' + + const summary = document.createElement('div') + summary.className = 'tool-activity-summary' + summary.textContent = 'Following SKILL.md instructions for this step.' + + const sections = document.createElement('div') + sections.className = 'tool-activity-sections single' + + const skillPanel = this.createActivityPanel( + 'Skill', + 'Agent Skill context for this step' + ) + sections.appendChild(skillPanel.panel) + + toolContent.appendChild(summary) + toolContent.appendChild(sections) + groupContainer.appendChild(toolHeader) + groupContainer.appendChild(toolContent) + + this.addExpandCollapseHandler(toolHeader, toolContent) + this.feed.appendChild(groupContainer) + + return { + mode: 'agent_skill', + container: groupContainer, + title, + subtitle, + statusChip, + skillBody: skillPanel.body, + isNew: true + } + } + + /** + * Create a titled content panel used by the activity card sections. + */ + createActivityPanel(title, description) { + const panel = document.createElement('section') + panel.className = 'tool-activity-panel' + + const heading = document.createElement('div') + heading.className = 'tool-panel-heading' + + const titleElement = document.createElement('span') + titleElement.className = 'tool-panel-title' + titleElement.textContent = title + + const descriptionElement = document.createElement('span') + descriptionElement.className = 'tool-panel-description' + descriptionElement.textContent = description + + const body = document.createElement('div') + body.className = 'tool-panel-body' + + heading.appendChild(titleElement) + heading.appendChild(descriptionElement) + panel.appendChild(heading) + panel.appendChild(body) + + return { + panel, + body + } + } + + /** + * Add expand/collapse functionality to tool header. + */ + addExpandCollapseHandler(toolHeader, toolContent) { + toolHeader.addEventListener('click', () => { + const isExpanded = toolContent.classList.contains('expanded') + const expandIcon = toolHeader.querySelector('.expand-icon') + + if (isExpanded) { + toolContent.classList.remove('expanded') + expandIcon?.classList.remove('rotated') + } else { + toolContent.classList.add('expanded') + expandIcon?.classList.add('rotated') + } + }) + } + + /** + * Update the activity card with the latest input/output state. + */ + updateActivityCard(toolGroupContainer, data, answerKey) { + const title = + data.stepLabel || + this.humanizeFunctionName(data.functionName || answerKey) + toolGroupContainer.title.textContent = title + + if (data.functionName) { + const functionLabel = this.humanizeFunctionName(data.functionName) + toolGroupContainer.subtitle.textContent = + `${data.toolkitName} toolkit • ${data.toolName} • ${functionLabel}` + } + + if (data.toolPhase === 'input') { + toolGroupContainer.summary.textContent = + data.stepLabel || data.functionName + ? `Preparing ${title.toLowerCase()}...` + : 'Preparing tool activity...' + this.setStatusChip(toolGroupContainer.statusChip, 'running') + + const parsedInput = this.parseToolInput(data.toolInput) + toolGroupContainer.rawInput = parsedInput ?? data.toolInput ?? null + this.renderValuePreview( + toolGroupContainer.inputBody, + parsedInput ?? data.toolInput, + 'No input' + ) + + if (!toolGroupContainer.rawOutput) { + this.renderPlaceholder( + toolGroupContainer.outputBody, + 'Waiting for function output...' + ) + } + } + + if (data.toolPhase === 'preparation') { + const progressMessage = data.message || data.answer || '' + this.setStatusChip(toolGroupContainer.statusChip, 'running') + + if (progressMessage) { + toolGroupContainer.summary.textContent = progressMessage + toolGroupContainer.preparationLog.push(progressMessage) + this.renderPreparationLog( + toolGroupContainer.outputBody, + toolGroupContainer.preparationLog + ) + toolGroupContainer.rawOutput = { + preparation: toolGroupContainer.preparationLog + } + } + } + + if (data.toolPhase === 'output_delta') { + const outputDelta = data.outputDelta || data.answer || '' + this.setStatusChip(toolGroupContainer.statusChip, 'running') + + if (outputDelta) { + toolGroupContainer.summary.textContent = 'Receiving command output...' + toolGroupContainer.commandOutputText = this.mergeCommandOutput( + toolGroupContainer.commandOutputText, + outputDelta + ) + this.renderCommandOutputLog( + toolGroupContainer.outputBody, + toolGroupContainer.commandOutputText + ) + toolGroupContainer.rawOutput = { + output: toolGroupContainer.commandOutputText + } + } + } + + if (data.toolPhase === 'output') { + const isError = data.status === 'error' + const isObserved = data.status === 'observed' + toolGroupContainer.summary.textContent = + data.message || + (isError + ? 'The function failed.' + : isObserved + ? 'The function returned an observation.' + : 'The function completed.') + this.setStatusChip( + toolGroupContainer.statusChip, + isError ? 'error' : isObserved ? 'observed' : 'success' + ) + + const outputPayload = { + message: data.message, + output: data.output + } + toolGroupContainer.rawOutput = outputPayload + this.renderOutputPreview(toolGroupContainer.outputBody, data) + } + + this.renderRawData(toolGroupContainer) + + if (toolGroupContainer.isNew) { + toolGroupContainer.isNew = false + } + } + + updateAgentSkillActivityCard(activityContainer, data) { + const agentSkill = data.agentSkill || {} + const skillName = agentSkill.name || agentSkill.id || 'Agent Skill' + const skillPath = agentSkill.skillPath || '' + + activityContainer.title.textContent = `Agent Skill: ${skillName}` + activityContainer.subtitle.textContent = skillPath || 'SKILL.md' + activityContainer.subtitle.setAttribute( + 'title', + skillPath || 'SKILL.md' + ) + this.setStatusChip(activityContainer.statusChip, 'selected') + this.renderValuePreview( + activityContainer.skillBody, + { + name: skillName, + description: agentSkill.description || '', + root_path: agentSkill.rootPath || '', + skill_path: skillPath + }, + 'No Agent Skill metadata' + ) + + if (activityContainer.isNew) { + activityContainer.isNew = false + } + } + + /** + * Add a tool message to the legacy shell output. + */ + addLegacyToolMessage(toolGroupContainer, message) { + const messageElement = document.createElement('div') + messageElement.className = 'shell-message' + + const formattedMessage = this.formatMessage(message) + messageElement.innerHTML = `> ${formattedMessage}` + + toolGroupContainer.shellOutput.appendChild(messageElement) + + if (toolGroupContainer.isNew) { + toolGroupContainer.isNew = false + } + } + + /** + * Render the output preview block. + */ + renderOutputPreview(container, data) { + container.innerHTML = '' + + if (data.message) { + const summary = document.createElement('div') + summary.className = 'tool-output-summary' + summary.innerHTML = this.formatMessage(data.message) + container.appendChild(summary) + } + + if ( + typeof data.output === 'undefined' || + data.output === null || + (typeof data.output === 'object' && + !Array.isArray(data.output) && + Object.keys(data.output).length === 0) + ) { + if (!data.message) { + this.renderPlaceholder(container, 'No output') + } + return + } + + const preview = this.buildValueNode(data.output) + container.appendChild(preview) + } + + /** + * Render preparation progress before the final tool output is available. + */ + renderPreparationLog(container, messages) { + container.innerHTML = '' + + if (!messages.length) { + this.renderPlaceholder(container, 'Waiting for function output...') + return + } + + const list = document.createElement('ul') + list.className = 'tool-value-list' + + messages.forEach((message) => { + const item = document.createElement('li') + item.textContent = message + list.appendChild(item) + }) + + container.appendChild(list) + } + + /** + * Merge terminal output chunks while respecting carriage-return progress + * updates used by CLI tools to repaint the current line. + */ + mergeCommandOutput(currentOutput, nextChunk) { + const cleanChunk = this.cleanCommandOutputChunk(nextChunk) + if (!cleanChunk) { + return currentOutput || '' + } + + let output = currentOutput || '' + let replaceCurrentLine = false + + for (const char of cleanChunk) { + if (char === '\r') { + replaceCurrentLine = true + continue + } + + if (char === '\n') { + output += '\n' + replaceCurrentLine = false + continue + } + + if (replaceCurrentLine) { + const lineStartIndex = output.lastIndexOf('\n') + 1 + output = output.slice(0, lineStartIndex) + replaceCurrentLine = false + } + + output += char + } + + if (output.length <= COMMAND_OUTPUT_MAX_DISPLAY_CHARS) { + return output + } + + return output.slice(output.length - COMMAND_OUTPUT_MAX_DISPLAY_CHARS) + } + + /** + * Strip terminal control sequences that do not render usefully in HTML. + */ + cleanCommandOutputChunk(chunk) { + const withoutAnsi = String(chunk || '').replace(ANSI_ESCAPE_PATTERN, '') + const output = [] + + for (const char of withoutAnsi) { + if (char === '\b') { + output.pop() + continue + } + + output.push(char) + } + + return output.join('') + } + + /** + * Render live command output in the result panel. + */ + renderCommandOutputLog(container, outputText) { + container.innerHTML = '' + + if (!outputText) { + this.renderPlaceholder(container, 'Waiting for function output...') + return + } + + const output = document.createElement('pre') + output.className = 'tool-command-output' + output.textContent = outputText + container.appendChild(output) + output.scrollTop = output.scrollHeight + } + + /** + * Render a value preview block. + */ + renderValuePreview(container, value, emptyLabel) { + container.innerHTML = '' + + if ( + value === null || + typeof value === 'undefined' || + value === '' || + (Array.isArray(value) && value.length === 0) || + (typeof value === 'object' && + !Array.isArray(value) && + Object.keys(value).length === 0) + ) { + this.renderPlaceholder(container, emptyLabel) + return + } + + container.appendChild(this.buildValueNode(value)) + } + + /** + * Render an empty state placeholder. + */ + renderPlaceholder(container, text) { + container.innerHTML = '' + const placeholder = document.createElement('div') + placeholder.className = 'tool-empty-state' + placeholder.textContent = text + container.appendChild(placeholder) + } + + /** + * Build the most appropriate preview node for a value. + */ + buildValueNode(value) { + if (Array.isArray(value)) { + return this.buildArrayNode(value) + } + + if (value && typeof value === 'object') { + return this.buildObjectNode(value) + } + + return this.buildScalarNode(value) + } + + /** + * Build a list preview for array values. + */ + buildArrayNode(value) { + const list = document.createElement('ul') + list.className = 'tool-value-list' + + value.slice(0, 8).forEach((item) => { + const itemElement = document.createElement('li') + itemElement.appendChild(this.buildScalarNode(this.stringifyCompact(item))) + list.appendChild(itemElement) + }) + + if (value.length > 8) { + const more = document.createElement('li') + more.className = 'tool-empty-state' + more.textContent = `+${value.length - 8} more item(s)` + list.appendChild(more) + } + + return list + } + + /** + * Build a key/value preview for object values. + */ + buildObjectNode(value) { + const entries = Object.entries(value) + if (entries.length === 0) { + const empty = document.createElement('div') + empty.className = 'tool-empty-state' + empty.textContent = 'No data' + return empty + } + + const wrapper = document.createElement('div') + wrapper.className = 'tool-kv-list' + + entries.slice(0, 8).forEach(([key, itemValue]) => { + const row = document.createElement('div') + row.className = 'tool-kv-row' + + const keyElement = document.createElement('span') + keyElement.className = 'tool-kv-key' + keyElement.textContent = this.humanizeFunctionName(key) + + const valueElement = document.createElement('div') + valueElement.className = 'tool-kv-value' + valueElement.appendChild( + this.buildScalarNode(this.stringifyCompact(itemValue)) + ) + + row.appendChild(keyElement) + row.appendChild(valueElement) + wrapper.appendChild(row) + }) + + if (entries.length > 8) { + const more = document.createElement('div') + more.className = 'tool-empty-state' + more.textContent = `+${entries.length - 8} more field(s)` + wrapper.appendChild(more) + } + + return wrapper + } + + /** + * Build a formatted scalar value preview. + */ + buildScalarNode(value) { + const wrapper = document.createElement('div') + wrapper.className = 'tool-rich-text' + wrapper.innerHTML = this.formatMessage( + typeof value === 'string' ? value : String(value ?? '') + ) + return wrapper + } + + /** + * Render raw input/output payloads behind a disclosure block. + */ + renderRawData(toolGroupContainer) { + const payload = {} + + if (toolGroupContainer.rawInput !== null) { + payload['input'] = toolGroupContainer.rawInput + } + + if (toolGroupContainer.rawOutput !== null) { + payload['result'] = toolGroupContainer.rawOutput + } + + if (Object.keys(payload).length === 0) { + toolGroupContainer.rawDetails.removeAttribute('open') + toolGroupContainer.rawContent.innerHTML = '' + return + } + + toolGroupContainer.rawContent.innerHTML = this.formatMessage( + JSON.stringify(payload, null, 2) + ) + } + + /** + * Parse tool input JSON when possible. + */ + parseToolInput(toolInput) { + if (typeof toolInput !== 'string' || !toolInput.trim()) { + return null + } + + try { + return JSON.parse(toolInput) + } catch { + return toolInput + } + } + + /** + * Update the status chip for the activity card. + */ + setStatusChip(chip, status) { + chip.classList.remove('running', 'success', 'error', 'selected', 'observed') + + if (status === 'error') { + chip.classList.add('error') + chip.textContent = 'Failed' + return + } + + if (status === 'success') { + chip.classList.add('success') + chip.textContent = 'Done' + return + } + + if (status === 'selected') { + chip.classList.add('selected') + chip.textContent = 'In use' + return + } + + if (status === 'observed') { + chip.classList.add('observed') + chip.textContent = 'Observed' + return + } + + chip.classList.add('running') + chip.textContent = 'Running' + } + + /** + * Humanize function and field names for display. + */ + humanizeFunctionName(value) { + return String(value || 'unknown') + .replace(/([a-z0-9])([A-Z])/g, '$1 $2') + .replace(/[_-]+/g, ' ') + .replace(/\s+/g, ' ') + .trim() + .replace(/^\w/, (char) => char.toUpperCase()) + } + + /** + * Produce a compact preview string for nested values. + */ + stringifyCompact(value) { + if (typeof value === 'string') { + const trimmed = value.trim() + if (!trimmed) { + return '(empty)' + } + + return trimmed.length > 180 ? `${trimmed.slice(0, 177)}...` : trimmed + } + + if (value === null || typeof value === 'undefined') { + return '(empty)' + } + + if (typeof value === 'object') { + try { + const serialized = JSON.stringify(value) + return serialized.length > 180 + ? `${serialized.slice(0, 177)}...` + : serialized + } catch { + return String(value) + } + } + + return String(value) + } + + /** + * Replace a tool message (for progress updates, etc.). + */ + replaceToolMessage(replaceMessageId, newData) { + const existingMessage = document.querySelector( + `[data-message-id="${replaceMessageId}"]` + ) + + if (existingMessage && existingMessage.closest('.tool-group-container')) { + const formattedMessage = this.formatMessage(newData.answer) + existingMessage.innerHTML = `> ${formattedMessage}` + } else { + this.handleToolOutput(newData) + } + } + + /** + * Get tool group info for saving to localStorage. + */ + getToolGroupInfo(groupId, toolkitName, toolName, message) { + return { + originalString: `[TOOL_OUTPUT:${groupId}] ${toolkitName} → ${toolName}`, + messageId: `tool-${groupId}`, + formattedMessage: this.formatMessage(message) + } + } + + /** + * Check if a message is a tool output marker. + */ + static isToolOutputMarker(messageString) { + return messageString && messageString.startsWith('[TOOL_OUTPUT:') + } + + /** + * Clear all tool groups. + */ + clearToolGroups() { + this.toolGroups.clear() + } + + /** + * Get the number of active tool groups. + */ + getToolGroupCount() { + return this.toolGroups.size + } + + /** + * Get a specific tool group by ID. + */ + getToolGroup(groupId) { + return this.toolGroups.get(groupId) + } + + /** + * Remove a tool group. + */ + removeToolGroup(groupId) { + const toolGroup = this.toolGroups.get(groupId) + if (toolGroup) { + toolGroup.container.remove() + this.toolGroups.delete(groupId) + } + } +} diff --git a/app/src/js/voice-energy.js b/app/src/js/voice-energy.js new file mode 100644 index 0000000..e85c47a --- /dev/null +++ b/app/src/js/voice-energy.js @@ -0,0 +1,74 @@ +const STATUS = { + listening: 'Listening...', + processing: 'Processing...', + talking: 'Talking...', + idle: 'Idle' +} + +export default class VoiceEnergy { + constructor(client) { + this.client = client + this.voiceEnergyContainerElement = document.querySelector( + '#voice-energy-container' + ) + this.voiceOverlayElement = document.querySelector('#voice-overlay-bg') + this.statusElement = document.querySelector('#voice-status') + this._status = 'idle' + } + + get status() { + return this._status + } + + set status(newStatus) { + if (this._status !== newStatus) { + this._status = newStatus + + if (this.statusElement) { + this.statusElement.textContent = STATUS[newStatus] + } + + // Clean up speech text when listening + if (newStatus === 'listening' && this.client.voiceSpeechElement) { + this.client.voiceSpeechElement.textContent = '' + } + + if (this.voiceEnergyContainerElement) { + this.voiceEnergyContainerElement.className = '' + this.voiceEnergyContainerElement.classList.add(newStatus) + } + } + } + + init() { + if (this.voiceEnergyContainerElement) { + if (this.voiceOverlayElement) { + this.voiceOverlayElement.addEventListener('click', (e) => { + e.preventDefault() + this.client.disableVoiceMode() + }) + } + + const particles = new Set() + const particleColors = ['blue', 'pink'] + + for (let i = 0; i < 32; i += 1) { + const particle = document.createElement('div') + const randomColor = Math.floor(Math.random() * 2) + let random = Math.floor(Math.random() * 32) + + while (particles.has(random)) { + random = Math.floor(Math.random() * 32) + } + + particles.add(random) + particle.setAttribute('data-particle', String(random)) + particle.classList.add('voice-particle', particleColors[randomColor]) + particle.style.transform = `rotate(${ + i * 11.25 + }deg) translate(110px) rotate(-${i * 11.25}deg)` + this.voiceEnergyContainerElement.appendChild(particle) + } + } + } +} diff --git a/app/src/sounds/off.mp3 b/app/src/sounds/off.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..d3d5b7bb70194a5087ed3d36481b23d23fcc5206 GIT binary patch literal 2064 zcmZ9N3pA8@AIG0(W{klYBeR(yF^qCIF|}_O3})RG5>wj6G;$3qHc5=z7@96*G}_lj zsCDa&5>r~Y65S|-a*Zq{CYK8F>^x@QJ?DKt=RD8<{Qu86|L^zz{r%4Khvrk+!2iPx z4iA*9DM=n20ATO{UdlEp3@HIpPD(i|C0|O}-_%NJlhP+;TFN&mkQ9m5P8Vy}AIwd5 z?upqD9*fA;BZMr*-Ope7GCQ;({;;?2S1ko*(QbxYw@hGGwv^r>jmcu~vIc%g_dxMSYvp!h&Umyn$ zU@#z0ND{sCv6{$jJK`8qo_M*1bkF&9-fB`xl^)un(~Y#3RTv7~Oh=vwa!?l&iMWx_ zHUh|R^g^pP(T$KT-XK?*qnWgs1r)_2ljP8u4p=bB4+D(&;gLz4MzePPUU8LHSOFCQ zBEF_XrbJdYi2IYvfs%lS$?+GViATDM*QVtw7`geJcQ#PExqWWSe)ASfOQR0Ux zDFPr0%MCEbVkq~~mV7_jgc%*Z#r5S-t&B5*I=TP-+srdcO19&Zo!$8c1kOu9c@OGr zy7EHBZgPh6gB(WD*u`!gRqO@EhIZyJ`jRC9sxUH&a3QI*afg>yu05HUtgDe>AgjYF zW!Jkp=vq2@cp2-Or9Nz-1a2+mGtESNd#BWFqb*>rJnyRRhH3*!R`D4f)a~xQjH_Pu zIEQX{(xYMI*f#q5*e)Yy*OqGpPe-S0H9bGi!`USiPq%hfvr|r%yDj2s^TRth+GthO zM?^;U47%k|F`Pd}Nza~YdVD}~Rs;<`Z|rLf1;BtDI$BwlSmzbgXPvPUK^)-dGfkBg zQoziiR_4oQ)9w{h>oWuCDHI|D!41f_pZcl#aor}px|;^_$#v0AQ|?K9sT7S|ZTb8Z zt_-mg;7$NS*R&;m z*7FBbcLWRrDnb;UAS4xN6X`&ca5~sV_#e6taZ7=&&;?9NX5xiPz$cCt76S}WH!|p0 z3i2oli1%;R<`xv``L)Vj0}BrM@vtL)RMza%g#)J;ZzfG#H{;fOVYLBTyD?n8EXccj za*EWSR?7LrJ;g(#Zpp&`0cC8lJ01uefc+T3`4nu}W+i8yCA(nOuB@WK@i332wbF}Z z((Ti1fC5j%1l8TWFjE}(Bov7p@q58TUwtU3te+?}YmdRs*d@Y>i;0kB1Jt$uURTeT zbL0;tIniZGz8(VtW`{D-EatlQ8Z^&f{bq~)s5+?!iE{USIb$wgOJTibg&KNn)Ymb zNAEP$_{TB=-XFxUtteJHvHzUQu=Y)8fUyDR#kLPNgDCQ!{JYv}E#mng9G~Hi=JmW6B*-a;d7Os>*R4l&2ZppLNswbWFI&h65oaT@wM;*wB|6YiVdZeeh(oDx~MC=+z1TsGwV=2aI_E_878*tccq zxoC0CckQQ-v6@{LcNSJlMBa<`?9YR@6K>3S7FAhCbUa!jkIbL$HM8ubsnN_=igxDA zP_#r#5pdt46c4nZ31Qmd65aJa5tMtlItcqHK;Jl0{t_zt;QrcA-wG7^e&;#6sy`{S zLWddlw2xmm){cMNFex}x;~w^el`z?H)R1HvR~j6cx9^XqyjFqortIgu1n;~{lcl+W zJl{~4#{3ow&-j=8rPQ0J7hYLbe*1Z%dYrbRpZU(LWcL-5x8EUgEpQG5#UB>F0_&F2Ap*XBzLQ(Yq+sn$Jc>)^? R0AMk!2LMP1_$|4#{{oirkRJd5 literal 0 HcmV?d00001 diff --git a/app/src/sounds/on.mp3 b/app/src/sounds/on.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..985e532196e73047bf0471e80f10fb11178a0908 GIT binary patch literal 3168 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 literal 0 HcmV?d00001 diff --git a/app/tsconfig.json b/app/tsconfig.json new file mode 100644 index 0000000..470851e --- /dev/null +++ b/app/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "noEmit": true + }, + "include": ["./src/**/*", "../aurora/src/**/*", "../aurora/global.d.ts"], + "exclude": ["./dist", "../node_modules"] +} diff --git a/app/vite.config.js b/app/vite.config.js new file mode 100644 index 0000000..aac1793 --- /dev/null +++ b/app/vite.config.js @@ -0,0 +1,143 @@ +import dns from 'node:dns' +import fs from 'node:fs' +import { fileURLToPath } from 'node:url' + +import dotenv from 'dotenv' +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import YAML from 'yaml' + +import { + PROFILE_CONFIG_PATH, + PROFILE_DOT_ENV_PATH +} from '../server/src/leon-roots.ts' + +const APP_DEV_SERVER_PORT = 5_173 +const NODE_MODULES_PATH_SEGMENT = '/node_modules/' +const REACT_VENDOR_PACKAGES = ['react', 'react-dom', 'scheduler'] +const REALTIME_VENDOR_PACKAGES = [ + 'socket.io-client', + 'socket.io-parser', + 'engine.io-client', + 'engine.io-parser' +] +const UI_VENDOR_PACKAGE_PREFIXES = ['@ark-ui/', '@zag-js/', '@floating-ui/'] + +dotenv.config({ path: PROFILE_DOT_ENV_PATH }) + +dns.setDefaultResultOrder('verbatim') + +function readAppLeonConfig() { + if (!fs.existsSync(PROFILE_CONFIG_PATH)) { + throw new Error(`Profile config file not found at "${PROFILE_CONFIG_PATH}".`) + } + + const config = YAML.parse(fs.readFileSync(PROFILE_CONFIG_PATH, 'utf8')) + const server = config?.server + + if ( + !server || + typeof server.host !== 'string' || + !Number.isInteger(server.port) + ) { + throw new Error( + `Profile config file "${PROFILE_CONFIG_PATH}" must define server.host and server.port.` + ) + } + + return { + host: server.host, + port: server.port + } +} + +function normalizeModuleId(moduleId) { + return moduleId.replaceAll('\\', '/') +} + +function isNodeModule(moduleId) { + return normalizeModuleId(moduleId).includes(NODE_MODULES_PATH_SEGMENT) +} + +function includesVendorPackage(moduleId, packageName) { + return normalizeModuleId(moduleId).includes( + `${NODE_MODULES_PATH_SEGMENT}${packageName}/` + ) +} + +function includesVendorPackagePrefix(moduleId, packagePrefix) { + return normalizeModuleId(moduleId).includes( + `${NODE_MODULES_PATH_SEGMENT}${packagePrefix}` + ) +} + +// Map necessary Leon's env vars as Vite only expose VITE_* +const leonConfig = readAppLeonConfig() +process.env.VITE_LEON_NODE_ENV = process.env.LEON_NODE_ENV +process.env.VITE_LEON_HOST = leonConfig.host +process.env.VITE_LEON_PORT = String(leonConfig.port) + +export default defineConfig({ + root: 'app/src', + resolve: { + alias: [ + { + find: '@aurora/style.css', + replacement: fileURLToPath( + new URL('../aurora/style.css', import.meta.url) + ) + }, + { + find: '@aurora', + replacement: fileURLToPath( + new URL('../aurora/src/index.ts', import.meta.url) + ) + } + ] + }, + build: { + outDir: '../dist', + emptyOutDir: true, + rolldownOptions: { + output: { + codeSplitting: { + groups: [ + { + name: 'react-vendor', + test: (moduleId) => + REACT_VENDOR_PACKAGES.some((packageName) => + includesVendorPackage(moduleId, packageName) + ), + priority: 30 + }, + { + name: 'realtime-vendor', + test: (moduleId) => + REALTIME_VENDOR_PACKAGES.some((packageName) => + includesVendorPackage(moduleId, packageName) + ), + priority: 20 + }, + { + name: 'ui-vendor', + test: (moduleId) => + UI_VENDOR_PACKAGE_PREFIXES.some((packagePrefix) => + includesVendorPackagePrefix(moduleId, packagePrefix) + ), + priority: 10 + }, + { + name: 'vendor', + test: isNodeModule, + priority: 0 + } + ] + } + } + } + }, + server: { + port: APP_DEV_SERVER_PORT + }, + plugins: [react()] +}) diff --git a/aurora/global.d.ts b/aurora/global.d.ts new file mode 100644 index 0000000..5c53896 --- /dev/null +++ b/aurora/global.d.ts @@ -0,0 +1,3 @@ +declare module '*.css' +declare module '*.scss' +declare module '*.sass' diff --git a/aurora/preview/App.tsx b/aurora/preview/App.tsx new file mode 100644 index 0000000..c1c07c4 --- /dev/null +++ b/aurora/preview/App.tsx @@ -0,0 +1,1839 @@ +import { useState, useEffect } from 'react' + +import { + Button, + Card, + Checkbox, + CircularProgress, + Flexbox, + Form, + Icon, + IconButton, + Image, + Input, + Link, + List, + ListHeader, + ListItem, + Loader, + Progress, + Radio, + RadioGroup, + RangeSlider, + ScrollContainer, + Select, + SelectOption, + Status, + Switch, + Tab, + TabContent, + TabGroup, + TabList, + Text, + WidgetWrapper +} from '../src' + +interface SectionProps extends React.PropsWithChildren { + title: string +} + +const Section: React.FC = (props) => { + const { title, children } = props + + return ( +
+

{title}

+ {children} +
+ ) +} + +function formatTime(seconds: number): string { + const minutes = Math.floor(seconds / 60) + const remainingSeconds = seconds % 60 + const formattedMinutes = minutes < 10 ? `0${minutes}` : minutes + const formattedSeconds = + remainingSeconds < 10 ? `0${remainingSeconds}` : remainingSeconds + + return `${formattedMinutes}:${formattedSeconds}` +} + +function Timer({ + value, + initialTime, + interval +}: { + value: number + initialTime: number + interval: number +}) { + const [progress, setProgress] = useState(0) + const [timeLeft, setTimeLeft] = useState(initialTime) + + useEffect(() => { + setTimeLeft(initialTime) + setProgress(0) + }, [initialTime, value]) + + useEffect(() => { + if (timeLeft === 0) { + return + } + + const timer = setInterval(() => { + setTimeLeft((prevTime) => prevTime - 1) + setProgress((prevProgress) => prevProgress + 100 / initialTime) + }, interval) + + return () => clearInterval(timer) + }, [initialTime, interval, timeLeft]) + + return ( + + + + {formatTime(timeLeft)} + + + Total 10 minutes + + + + ) +} + +export const App: React.FC = () => { + const [isSending, setIsSending] = useState(false) + const [isSendingIconButton, setIsSendingIconButton] = useState(false) + const [isPlayButtonActivated, setIsPlayButtonActivated] = useState(false) + const [isPlayButton2Activated, setIsPlayButton2Activated] = useState(false) + + return ( + <> +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + Hello world + + + + Text 1 + Text 2 + + + + +
+
+ + + alert(JSON.stringify(data))} + /> + alert(JSON.stringify(data))} + /> + + + +
+
+ + + + + + + + + + + + +
+
+ WIP (+ search with chip)... N.B. create example with LLM list/search +
+
+ + + + + 1 + + + 2 + + + 3 + + + 4 + + + 5 + + + + + + 1 + + + + + 2 + + + + + 3 + + + + + + + 1 + + + + + +
+
+ +
{ + alert(JSON.stringify(data)) + }} + > + + + + + + + + + + + + Random size + + + + + + + + + + + + + +
+
+
+
+ + + + Test here + + + + + + + + + + + + +
+
+ + + + + { + setIsSendingIconButton(true) + + alert(JSON.stringify(data)) + + setTimeout(() => { + setIsSendingIconButton(false) + }, 2_000) + }} + /> + + + + + + + + + + + + + + + console.log('data', data)} + /> + console.log('data', data)} + /> + + + + console.log('data', data)} + /> + console.log('data', data)} + /> + + + + + + + console.log('Shuffle', data.isActivated)} + /> + + + { + console.log('Play', data.isActivated) + setIsPlayButtonActivated(data.isActivated) + }} + /> + + + console.log('Repeat', data.isActivated)} + /> + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + Docs + + + Docs + + + Next + + + + + + Docs + + + + Docs + + + Next + + + + + +
+
+ + + + Shopping List + + console.log('Checkbox', data)} + /> + + + + + + + + + + + + + + + + + + + + + You are all set + + + + Installation is done + + + + + + Configuration is done + + + + + + Leon is now ready to use + + + + + + + + + + The voice provider is missing + + + + + + NLP models are broken + + + + + + Leon cannot run properly + + + + + + + Select your music provider + alert(JSON.stringify(data))} + > + + + alert(JSON.stringify(data))} + > + + + alert(JSON.stringify(data))} + > + + + alert(JSON.stringify(data))} + > + + + + + + + + + + Pancakes Ingredients + + + + + + Flour + 1 ½ cups + + + + + + + + Baking powder + 3 ½ teaspoons + + + + + + + + Sugar + 1 tablespoon + + + + + + + + Salt + ¼ teaspoon + + + + + + + + Milk + 1 ¼ cups + + + + + + + + Butter + 3 tablespoons butter + + + + + + + + Egg + 1 egg + + + + + + +
+
+ + + +
+
+ WIP (need methods from SDK to control)... N.B. make blurred bg +
+
+ + + + + + + + + + + + + + + + +
+
+ + alert(JSON.stringify(data))} + > + + + + + + + + +
+
+ + + + console.log(data)} + /> + console.log(data)} + /> + console.log(data)} + /> + + + + + console.log(data)} + /> + console.log(data)} + /> + + + +
+
+ + + + + + Card 1 + + + Card 2 + + + Card 3 + + + Card 4 + + + Card 5 + + + + + + + + + Card 1 + + + Card 2 + + + Card 3 + + + Card 4 + + + Card 5 + + + + + +
+
+ + + + + + +
+
+ + + Normal + Edited + Warning + + Danger + + + Success + + + +
+
+ + + alert(JSON.stringify(data))} + /> + alert(JSON.stringify(data))} + /> + alert(JSON.stringify(data))} + /> + + +
+
+ + + + Tab 1 + Tab 2 + + Tab 3 + + + + Tab 1 content + + + Tab 2 content + + + Tab 3 content + + + +
+
+ + + Text xs + Text sm + Text md + Text lg + Text xl + Text + Text regular + Text semi-bold + Text secondary + + +
+
+ + + + console.log('Text input value:', value)} + /> + + + + + + + + + + +
+
WIP (need methods from SDK to control)...
+
+ + + + + 42 + + + + + + + + Paris + + Thursday, 1 June + + + + + + + + + + + + + + + + + } + /> + + + + 18° + + Thunderstorms + + + + + + + + + + + + + + } + /> + + 1 + + + UV Index + + + + + + + + + + + + + } + /> + + 10 m/s + + + Wind + + + + + + + + + + + + + } + /> + + 98% + + + Humidity + + + + + + + Today + Tomorrow + Next 7 days + + + + + + + + 10:00 + + + + + + + + + + + + + + + + } + /> + + 15° + + + + + + + 11:00 + + + + + + + + + + + + + + + + } + /> + + 15° + + + + + + + 12:00 + + + + + + + + + + + + + + + + } + /> + + 15° + + + + + + + 13:00 + + + + + + + + + + + + + + + + } + /> + + 15° + + + + + + + 14:00 + + + + + + + + + + + + + + + + } + /> + + 15° + + + + + + + + Tab 2 content + + + Tab 3 content + + + + + + + + + + Mockingbird + + Eminem + + + + + + 1:44 + + + 4:12 + + + + + console.log('Shuffle', data.isActivated)} + /> + + + { + console.log('Play', data.isActivated) + setIsPlayButton2Activated(data.isActivated) + }} + /> + + + console.log('Repeat', data.isActivated)} + /> + + + + +
+ + ) +} diff --git a/aurora/preview/index.html b/aurora/preview/index.html new file mode 100644 index 0000000..5c3569e --- /dev/null +++ b/aurora/preview/index.html @@ -0,0 +1,31 @@ + + + + + + Aurora + + +
+ + + + diff --git a/aurora/preview/main.tsx b/aurora/preview/main.tsx new file mode 100644 index 0000000..e268d9b --- /dev/null +++ b/aurora/preview/main.tsx @@ -0,0 +1,24 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' + +import '@fontsource/source-sans-pro/200.css' +import '@fontsource/source-sans-pro/300.css' +import '@fontsource/source-sans-pro/400.css' +import '@fontsource/source-sans-pro/600.css' +import '@fontsource/source-sans-pro/700.css' +import '@fontsource/source-sans-pro/900.css' +import 'remixicon/fonts/remixicon.css' +import '../src/styles/main.sass' +import { App } from './App.tsx' + +const rootElement = document.getElementById('root') + +if (rootElement != null) { + ReactDOM.createRoot(rootElement).render( + + + + ) +} else { + console.error('Error: Root element not found!') +} diff --git a/aurora/preview/public/apple-music.svg b/aurora/preview/public/apple-music.svg new file mode 100644 index 0000000..74cabe3 --- /dev/null +++ b/aurora/preview/public/apple-music.svg @@ -0,0 +1,3 @@ + + + diff --git a/aurora/preview/public/baking-powder.jpeg b/aurora/preview/public/baking-powder.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..0a262d28457314fa99c3d2e0f3ae772b49e3c8bc GIT binary patch literal 6713 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 literal 0 HcmV?d00001 diff --git a/aurora/preview/public/butter.jpeg b/aurora/preview/public/butter.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9c8c5de0cdcb4010d14daf8a183e1387e5d1a169 GIT binary patch literal 7839 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 NPu2*`5*qZf_&<0C-n9S# literal 0 HcmV?d00001 diff --git a/aurora/preview/public/deezer.svg b/aurora/preview/public/deezer.svg new file mode 100644 index 0000000..52fdd94 --- /dev/null +++ b/aurora/preview/public/deezer.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/aurora/preview/public/egg.webp b/aurora/preview/public/egg.webp new file mode 100644 index 0000000000000000000000000000000000000000..6ddef5cf882ea199241b9792c42dff7ec02d0cbe GIT binary patch literal 111506 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

;(H1ghcYBB%Yb=b4^80Lz~4};!u`h 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 pI}O;-0w5AVModCa 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 Fe*nGaRQCV? literal 0 HcmV?d00001 diff --git a/aurora/preview/public/mockingbird.jpg b/aurora/preview/public/mockingbird.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f834c462f40b29e28fb1cf86fd1bbb0d38b1b9b4 GIT binary patch literal 27625 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 M6HvL#ga57lFAC8!-~a#s literal 0 HcmV?d00001 diff --git a/aurora/preview/public/pancakes.jpeg b/aurora/preview/public/pancakes.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..14543fa4a93bba961ba3d1a4a81a55340e3f8332 GIT binary patch literal 113861 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�AA>fof;G*y{R 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 L3ryE1|4scLy}Jf9 literal 0 HcmV?d00001 diff --git a/aurora/preview/public/salt.jpg b/aurora/preview/public/salt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d1e9ac221025b82da90b80630cbb0dad6691cca GIT binary patch literal 77428 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 literal 0 HcmV?d00001 diff --git a/aurora/preview/public/spotify.svg b/aurora/preview/public/spotify.svg new file mode 100644 index 0000000..a1370d0 --- /dev/null +++ b/aurora/preview/public/spotify.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/aurora/preview/public/sugar.jpg b/aurora/preview/public/sugar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..14d0c7003b2580698b7d36776ecca49eaab44e65 GIT binary patch literal 58023 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%0A% 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 VpHu6UIS__N%O%kI)=2s3|Jj6KG93T_ literal 0 HcmV?d00001 diff --git a/aurora/preview/public/youtube-music.svg b/aurora/preview/public/youtube-music.svg new file mode 100644 index 0000000..62e2175 --- /dev/null +++ b/aurora/preview/public/youtube-music.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/aurora/preview/style.css b/aurora/preview/style.css new file mode 100644 index 0000000..bfbf7bd --- /dev/null +++ b/aurora/preview/style.css @@ -0,0 +1,36 @@ +.aurora-preview-page { + min-height: 100vh; + padding: 32px; + background: + radial-gradient(circle at top left, rgba(28, 117, 219, 0.16), transparent 30%), + radial-gradient(circle at top right, rgba(237, 41, 122, 0.14), transparent 30%), + var(--black-color); + color: var(--white-color); +} + +.aurora-preview-shell { + width: min(1_440px, 100%); + margin: 0 auto; +} + +.aurora-preview-header { + margin-bottom: 24px; +} + +.aurora-preview-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 20px; +} + +.aurora-preview-section { + display: flex; + flex-direction: column; + gap: 16px; +} + +.aurora-preview-widget { + display: flex; + flex-direction: column; + gap: 16px; +} diff --git a/aurora/preview/vite.config.js b/aurora/preview/vite.config.js new file mode 100644 index 0000000..8cef38b --- /dev/null +++ b/aurora/preview/vite.config.js @@ -0,0 +1,26 @@ +import { fileURLToPath } from 'node:url' + +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +const AURORA_PREVIEW_DEV_SERVER_PORT = 5_175 + +export default defineConfig({ + root: fileURLToPath(new URL('.', import.meta.url)), + resolve: { + alias: [ + { + find: '@aurora/style.css', + replacement: fileURLToPath(new URL('../style.css', import.meta.url)) + }, + { + find: '@aurora', + replacement: fileURLToPath(new URL('../src/index.ts', import.meta.url)) + } + ] + }, + server: { + port: AURORA_PREVIEW_DEV_SERVER_PORT + }, + plugins: [react()] +}) diff --git a/aurora/src/components/button/button.sass b/aurora/src/components/button/button.sass new file mode 100644 index 0000000..f4bf657 --- /dev/null +++ b/aurora/src/components/button/button.sass @@ -0,0 +1,61 @@ +@use '../../styles/main.sass' as * + +.aurora-button + position: relative + display: inline-block + font-size: var(--a-font-size-md) + line-height: var(--a-line-height-md) + font-weight: var(--a-font-weight-semi-bold) + border-radius: var(--a-border-radius-md) + height: var(--a-button-size-md) + border: none + cursor: pointer + padding: 0 var(--a-space-lg) + box-shadow: 0 0 10px 2px transparent + transition: opacity var(--a-transition-duration-main) var(--a-transition-timing-main), transform var(--a-transition-duration-main), background-color var(--a-transition-duration-main) var(--a-transition-timing-main), border-color var(--a-transition-duration-main) var(--a-transition-timing-main), color var(--a-transition-duration-main) var(--a-transition-timing-main), box-shadow var(--a-transition-duration-main) var(--a-transition-timing-main) + &:hover:not(&--disabled, &--loading) + transform: scale3d(1.01, 1.01, 1.01) + &:active:not(&--disabled, &--loading) + transform: scale3d(.96, .96, .96) + + &--primary + color: var(--a-color-text) + background-color: var(--a-color-accent) + &:hover:not(.aurora-button--disabled, .aurora-button--loading) + background-color: var(--a-color-accent-hover) + + &--secondary + background-color: transparent + color: var(--a-color-accent) + border: 1px solid var(--a-color-accent) + &:hover:not(.aurora-button--disabled, .aurora-button--loading), &:hover:not(.aurora-button--disabled, .aurora-button--loading) .aurora-icon + border-color: var(--a-color-accent-hover) + color: var(--a-color-accent-hover) + .aurora-icon + color: var(--a-color-accent) + + &--danger + background-color: var(--a-color-background-danger) + color: var(--a-color-text-danger) + &:hover:not(.aurora-button--disabled, .aurora-button--loading) + background-color: var(--a-color-danger-hover) + + &--light + background-color: transparent + color: var(--a-color-accent) + &:hover:not(.aurora-button--disabled, .aurora-button--loading), &:hover:not(.aurora-button--disabled, .aurora-button--loading) .aurora-icon + color: var(--a-color-accent-hover) + .aurora-icon + color: var(--a-color-accent) + + &--disabled + opacity: var(--a-opacity-disabled) + cursor: not-allowed + + &--loading + opacity: var(--a-opacity-disabled) + cursor: wait + + .aurora-loader + &::before, &::after + background-color: var(--a-color-white) diff --git a/aurora/src/components/button/button.tsx b/aurora/src/components/button/button.tsx new file mode 100644 index 0000000..f27f10d --- /dev/null +++ b/aurora/src/components/button/button.tsx @@ -0,0 +1,114 @@ +import classNames from 'clsx' + +import { generateKeyId } from '../../lib/utils' +import { Flexbox, Icon, Loader } from '../..' + +import './button.sass' + +interface ButtonOnClickData { + name: string | undefined + value: string | number | undefined +} + +export interface ButtonProps { + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + children?: any + // children?: React.ReactNode + type?: 'button' | 'submit' + iconName?: string + iconPosition?: 'left' | 'right' + secondary?: boolean + danger?: boolean + light?: boolean + disabled?: boolean + loading?: boolean + name?: string + value?: string | number | undefined + onClick?: (data: ButtonOnClickData) => void +} + +export function Button({ + children, + type = 'button', + iconName, + iconPosition = 'left', + secondary, + danger, + light, + disabled, + loading, + name, + value, + onClick +}: ButtonProps) { + let variant = 'primary' + + if (secondary) { + variant = 'secondary' + } else if (danger) { + variant = 'danger' + } else if (light) { + variant = 'light' + } + + return ( + + ) +} diff --git a/aurora/src/components/button/index.ts b/aurora/src/components/button/index.ts new file mode 100644 index 0000000..14757e7 --- /dev/null +++ b/aurora/src/components/button/index.ts @@ -0,0 +1 @@ +export * from './button' diff --git a/aurora/src/components/card/card.sass b/aurora/src/components/card/card.sass new file mode 100644 index 0000000..7feacf5 --- /dev/null +++ b/aurora/src/components/card/card.sass @@ -0,0 +1,12 @@ +@use '../../styles/main.sass' as * + +.aurora-card + position: relative + display: inline-block + width: auto + padding: var(--a-space-md) + background-color: var(--a-color-background-surface-secondary) + border-radius: var(--a-border-radius-md) + + &--full-width + width: 100% diff --git a/aurora/src/components/card/card.tsx b/aurora/src/components/card/card.tsx new file mode 100644 index 0000000..a29be03 --- /dev/null +++ b/aurora/src/components/card/card.tsx @@ -0,0 +1,25 @@ +import classNames from 'clsx' + +import { generateKeyId } from '../../lib/utils' + +import './card.sass' + +export interface CardProps { + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + children: any + // children: React.ReactNode + fullWidth?: boolean +} + +export function Card({ children, fullWidth }: CardProps) { + return ( +

+ ) +} diff --git a/aurora/src/components/card/index.ts b/aurora/src/components/card/index.ts new file mode 100644 index 0000000..efb3293 --- /dev/null +++ b/aurora/src/components/card/index.ts @@ -0,0 +1 @@ +export * from './card' diff --git a/aurora/src/components/checkbox/checkbox.sass b/aurora/src/components/checkbox/checkbox.sass new file mode 100644 index 0000000..59f1d90 --- /dev/null +++ b/aurora/src/components/checkbox/checkbox.sass @@ -0,0 +1,39 @@ +@use '../../styles/main.sass' as * + +.aurora-checkbox + display: flex + align-items: center + gap: var(--a-space-sm) + cursor: pointer + &[data-disabled] + cursor: not-allowed + +.aurora-checkbox-placeholder + width: var(--a-checkbox-radio-size) + height: var(--a-checkbox-radio-size) + +.aurora-checkbox-control + display: flex + justify-content: center + align-items: center + width: var(--a-checkbox-radio-size) + height: var(--a-checkbox-radio-size) + border-radius: var(--a-border-radius-xs) + border: 1px solid var(--a-color-input-border) + background-color: var(--a-color-input-background) + transition: background-color var(--a-transition-duration-main) var(--a-transition-timing-main), border-color var(--a-transition-duration-main) var(--a-transition-timing-main) + + &[data-hover]:not([data-state="checked"]) + border-color: var(--a-color-input-border-hover) + background-color: var(--a-color-input-background-hover) + &[data-state="checked"] + border-color: transparent + background-color: var(--a-color-input-border-focus) + &[data-disabled] + opacity: var(--a-opacity-disabled) + +.aurora-checkbox-label + color: var(--a-color-text) + font-size: var(--a-font-size-md) + &[data-disabled] + opacity: var(--a-opacity-disabled) diff --git a/aurora/src/components/checkbox/checkbox.tsx b/aurora/src/components/checkbox/checkbox.tsx new file mode 100644 index 0000000..609fdbc --- /dev/null +++ b/aurora/src/components/checkbox/checkbox.tsx @@ -0,0 +1,74 @@ +import { useState } from 'react' +import { + Checkbox as ArkCheckbox, + type CheckboxCheckedChangeDetails, + type CheckboxRootProps as ArkCheckboxProps +} from '@ark-ui/react/checkbox' + +import { Icon } from '../icon' + +import './checkbox.sass' + +interface CheckboxOnChangeData { + name: string + value: string | undefined + isChecked: boolean +} + +export interface CheckboxProps + extends Pick< + ArkCheckboxProps, + 'value' | 'checked' | 'disabled' | 'required' + > { + name: string + label?: string + onChange?: (data: CheckboxOnChangeData) => void +} + +export function Checkbox({ + name, + label, + checked, + value, + disabled, + required, + onChange +}: CheckboxProps) { + const [isChecked, setIsChecked] = useState(checked) + + return ( + { + setIsChecked(event.checked as boolean) + + const data = { + name, + value, + isChecked: !!event.checked + } + + if (onChange) { + onChange(data) + } + }} + > + + + {isChecked ? ( + + ) : ( +
+ )} + + + {label} + + + ) +} diff --git a/aurora/src/components/checkbox/index.ts b/aurora/src/components/checkbox/index.ts new file mode 100644 index 0000000..31d7689 --- /dev/null +++ b/aurora/src/components/checkbox/index.ts @@ -0,0 +1 @@ +export * from './checkbox' diff --git a/aurora/src/components/circular-progress/circular-progress.sass b/aurora/src/components/circular-progress/circular-progress.sass new file mode 100644 index 0000000..cc7b82f --- /dev/null +++ b/aurora/src/components/circular-progress/circular-progress.sass @@ -0,0 +1,28 @@ +.aurora-circular-progress + position: relative + + &--sm + width: 64px + height: 64px + &--md + width: 128px + height: 128px + &--lg + width: 256px + height: 256px + + path + transition: stroke-dashoffset var(--a-transition-duration-main) var(--a-transition-timing-main) + &:nth-child(1) + stroke: var(--a-color-background-surface-secondary) + stroke-width: 32px + &:nth-child(2) + stroke: var(--a-color-accent) + stroke-width: 12px + stroke-linecap: round + +.aurora-circular-progress-content + position: absolute + top: 50% + left: 50% + transform: translate(-50%, -50%) diff --git a/aurora/src/components/circular-progress/circular-progress.tsx b/aurora/src/components/circular-progress/circular-progress.tsx new file mode 100644 index 0000000..9cdece2 --- /dev/null +++ b/aurora/src/components/circular-progress/circular-progress.tsx @@ -0,0 +1,41 @@ +import classNames from 'clsx' + +import { generateKeyId } from '../../lib/utils' + +import './circular-progress.sass' + +export interface CircularProgressProps { + value: number + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + children?: any + // children?: React.ReactNode + size?: 'sm' | 'md' | 'lg' +} + +export function CircularProgress({ + value, + children, + size = 'md' +}: CircularProgressProps) { + const total = 100 + + return ( +
+ + + + +
{children}
+
+ ) +} diff --git a/aurora/src/components/circular-progress/index.ts b/aurora/src/components/circular-progress/index.ts new file mode 100644 index 0000000..985e8a5 --- /dev/null +++ b/aurora/src/components/circular-progress/index.ts @@ -0,0 +1 @@ +export * from './circular-progress' diff --git a/aurora/src/components/flexbox/flexbox.sass b/aurora/src/components/flexbox/flexbox.sass new file mode 100644 index 0000000..6dc395f --- /dev/null +++ b/aurora/src/components/flexbox/flexbox.sass @@ -0,0 +1,92 @@ +@use '../../styles/main.sass' as * + +.aurora-flexbox + position: relative + display: flex + flex-direction: column + height: 100% + + &--padding + padding: var(--a-space-xl) var(--a-space-md) + &--padding-x + padding-left: var(--a-space-md) + padding-right: var(--a-space-md) + &--padding-y + padding-top: var(--a-space-xl) + padding-bottom: var(--a-space-xl) + + &--full-width + width: 100% + + &--flex + display: flex + &--inline-flex + display: inline-flex + + &--row + flex-direction: row + &--row-reverse + flex-direction: row-reverse + &--column + flex-direction: column + &--column-reverse + flex-direction: column-reverse + + &--align-flex-start + align-items: flex-start + &--align-center + align-items: center + &--align-flex-end + align-items: flex-end + &--align-stretch + align-items: stretch + &--align-baseline + align-items: baseline + + &--justify-flex-start + justify-content: flex-start + &--justify-center + justify-content: center + &--justify-flex-end + justify-content: flex-end + &--justify-space-between + justify-content: space-between + &--justify-space-around + justify-content: space-around + &--justify-space-evenly + justify-content: space-evenly + &--justify-stretch + justify-content: stretch + + &--gap-xs + gap: var(--a-space-xs) + &--gap-sm + gap: var(--a-space-sm) + &--gap-md + gap: var(--a-space-md) + &--gap-lg + gap: var(--a-space-lg) + &--gap-xl + gap: var(--a-space-xl) + + &--row-gap-xs + row-gap: var(--a-space-xs) + &--row-gap-sm + row-gap: var(--a-space-sm) + &--row-gap-md + row-gap: var(--a-space-md) + &--row-gap-lg + row-gap: var(--a-space-lg) + &--row-gap-xl + row-gap: var(--a-space-xl) + + &--column-gap-xs + column-gap: var(--a-space-xs) + &--column-gap-sm + column-gap: var(--a-space-sm) + &--column-gap-md + column-gap: var(--a-space-md) + &--column-gap-lg + column-gap: var(--a-space-lg) + &--column-gap-xl + column-gap: var(--a-space-xl) diff --git a/aurora/src/components/flexbox/flexbox.tsx b/aurora/src/components/flexbox/flexbox.tsx new file mode 100644 index 0000000..77171ff --- /dev/null +++ b/aurora/src/components/flexbox/flexbox.tsx @@ -0,0 +1,66 @@ +import classNames from 'clsx' + +import { type Size } from '../../lib/types' +import { generateKeyId } from '../../lib/utils' + +import './flexbox.sass' + +export interface FlexboxProps { + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + children: any + // children: React.ReactNode + fullWidth?: boolean + display?: 'flex' | 'inline-flex' + alignItems?: 'center' | 'flex-start' | 'flex-end' | 'baseline' | 'stretch' + justifyContent?: + | 'center' + | 'flex-start' + | 'flex-end' + | 'space-between' + | 'space-around' + | 'space-evenly' + | 'stretch' + flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse' + gap?: Size + rowGap?: Size + columnGap?: Size + padding?: boolean + paddingX?: boolean + paddingY?: boolean +} + +export function Flexbox({ + children, + fullWidth, + display, + alignItems, + justifyContent, + flexDirection, + gap, + rowGap, + columnGap, + padding, + paddingX, + paddingY +}: FlexboxProps) { + return ( +
+ {children} +
+ ) +} diff --git a/aurora/src/components/flexbox/index.ts b/aurora/src/components/flexbox/index.ts new file mode 100644 index 0000000..b258a66 --- /dev/null +++ b/aurora/src/components/flexbox/index.ts @@ -0,0 +1 @@ +export * from './flexbox' diff --git a/aurora/src/components/form/form.sass b/aurora/src/components/form/form.sass new file mode 100644 index 0000000..e829832 --- /dev/null +++ b/aurora/src/components/form/form.sass @@ -0,0 +1,4 @@ +@use '../../styles/main.sass' as * + +.aurora-form + position: relative diff --git a/aurora/src/components/form/form.tsx b/aurora/src/components/form/form.tsx new file mode 100644 index 0000000..99460e2 --- /dev/null +++ b/aurora/src/components/form/form.tsx @@ -0,0 +1,51 @@ +import { generateKeyId } from '../../lib/utils' + +import './form.sass' + +export interface FormProps { + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + children?: any + // children?: React.ReactNode + onSubmit: (data: Record) => void +} + +export function Form({ children, onSubmit }: FormProps) { + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault() + + const form = event.currentTarget + const formData = new FormData(form) + const data: Record = {} + + for (const [key, value] of formData.entries()) { + if (data[key] && key.endsWith('[]')) { + if (Array.isArray(data[key])) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + ;(data[key] as []).push(value) + } else { + data[key] = [data[key], value] + } + } else { + if (key.endsWith('[]')) { + data[key] = [value] + } else { + data[key] = value + } + } + } + + onSubmit(data) + } + + return ( +
+ {children} +
+ ) +} diff --git a/aurora/src/components/form/index.ts b/aurora/src/components/form/index.ts new file mode 100644 index 0000000..5415177 --- /dev/null +++ b/aurora/src/components/form/index.ts @@ -0,0 +1 @@ +export * from './form' diff --git a/aurora/src/components/icon-button/icon-button.sass b/aurora/src/components/icon-button/icon-button.sass new file mode 100644 index 0000000..1bf83e9 --- /dev/null +++ b/aurora/src/components/icon-button/icon-button.sass @@ -0,0 +1,70 @@ +@use '../../styles/main.sass' as * + +.aurora-icon-button + position: relative + width: var(--a-button-size-md) + height: var(--a-button-size-md) + display: flex + align-items: center + justify-content: center + padding: 0 + text-align: center + &.aurora-button:hover:not(.aurora-button--disabled, .aurora-button--loading) + transform: scale3d(1.03, 1.03, 1.03) + &.aurora-button:active:not(.aurora-button--disabled, .aurora-button--loading) + transform: scale3d(.96, .96, .96) + &.aurora-button.aurora-button--light:hover:not(.aurora-button--disabled, .aurora-button--loading) + transform: scale3d(1.06, 1.06, 1.06) + &.aurora-button.aurora-button--light:active:not(.aurora-button--disabled, .aurora-button--loading) + transform: scale3d(.96, .96, .96) + + &--square + width: var(--a-button-size-md) + height: var(--a-button-size-md) + border-radius: var(--a-border-radius-md) + &--circle + width: var(--a-button-size-md) + height: var(--a-button-size-md) + border-radius: 50% + + &--xs + width: 22px + height: 22px + &--sm + width: 30px + height: 30px + &--md + width: var(--a-button-size-md) + height: var(--a-button-size-md) + &--lg + width: 56px + height: 56px + &--xl + width: 96px + height: 96px + &--xxl + width: 164px + height: 164px + + &.aurora-button--light .aurora-icon + color: var(--a-color-text) + + &.aurora-button--secondary:hover, &.aurora-button--light:hover + background-color: transparent + + + &.aurora-button--light:hover .aurora-icon + color: var(--a-color-text) + + &.aurora-button--light.aurora-button--secondary + background-color: transparent + border: none + .aurora-icon + color: var(--a-color-white-secondary) + &:hover:not(.aurora-button--disabled, .aurora-button--loading) .aurora-icon + color: var(--a-color-text) + &:hover.aurora-icon-button--activated .aurora-icon + color: var(--a-color-accent) + + &.aurora-button--light.aurora-icon-button--activated .aurora-icon + color: var(--a-color-accent) diff --git a/aurora/src/components/icon-button/icon-button.tsx b/aurora/src/components/icon-button/icon-button.tsx new file mode 100644 index 0000000..b65614a --- /dev/null +++ b/aurora/src/components/icon-button/icon-button.tsx @@ -0,0 +1,113 @@ +import { useState } from 'react' +import classNames from 'clsx' + +import { Icon, Loader } from '../..' +import { type IconProps } from '../icon' +import { generateKeyId } from '../../lib/utils' + +import './icon-button.sass' + +interface IconButtonOnClickData { + name: string | undefined + value: string | number | undefined + isActivated: boolean +} + +export interface IconButtonProps { + iconName: string + name?: string + value?: string | number | undefined + type?: 'button' | 'submit' + iconType?: IconProps['type'] + size?: IconProps['size'] + shape?: IconProps['bgShape'] + activated?: boolean + secondary?: boolean + danger?: boolean + light?: boolean + disabled?: boolean + loading?: boolean + onClick?: (data: IconButtonOnClickData) => void +} + +export function IconButton({ + iconName, + name, + value, + type = 'button', + iconType = 'line', + size, + shape, + activated, + secondary, + danger, + light, + disabled, + loading, + onClick +}: IconButtonProps) { + const [isActivated, setIsActivated] = useState(activated || false) + + let variant = 'primary' + + if (danger) { + variant = 'danger' + } + + return ( + + ) +} diff --git a/aurora/src/components/icon-button/index.ts b/aurora/src/components/icon-button/index.ts new file mode 100644 index 0000000..876ec6f --- /dev/null +++ b/aurora/src/components/icon-button/index.ts @@ -0,0 +1 @@ +export * from './icon-button' diff --git a/aurora/src/components/icon/icon.sass b/aurora/src/components/icon/icon.sass new file mode 100644 index 0000000..4b0a417 --- /dev/null +++ b/aurora/src/components/icon/icon.sass @@ -0,0 +1,115 @@ +@use '../../styles/main.sass' as * + +.aurora-icon + position: relative + display: inline-flex + align-items: center + justify-content: center + border-radius: var(--a-border-radius-xs) + color: var(--a-color-white) + font-size: var(--a-font-size-md) + background-color: transparent + padding: var(--a-space-xs) + transition: opacity var(--a-transition-duration-main) var(--a-transition-timing-main), color var(--a-transition-duration-main) var(--a-transition-timing-main), background-color var(--a-transition-duration-main) var(--a-transition-timing-main), transform var(--a-transition-duration-main) var(--a-transition-timing-main) + + &--animated + opacity: 0 + animation: aurora-animation-fade-in var(--a-transition-duration-main) var(--a-transition-timing-main) var(--a-transition-duration-main) forwards + + &--xs + width: 12px + height: 12px + font-size: var(--a-font-size-xs) + border-radius: var(--a-border-radius-xs) + &--sm + width: 20px + height: 20px + font-size: var(--a-font-size-sm) + border-radius: var(--a-border-radius-xs) + &--md + width: 28px + height: 28px + font-size: var(--a-font-size-md) + border-radius: var(--a-border-radius-xs) + &--lg + width: 56px + height: 56px + font-size: var(--a-font-size-lg) + border-radius: var(--a-border-radius-md) + &--xl + width: 96px + height: 96px + font-size: var(--a-font-size-xl) + border-radius: var(--a-border-radius-md) + &--xxl + width: 128px + height: 128px + font-size: var(--a-font-size-xxl) + border-radius: var(--a-border-radius-md) + + &--square + border-radius: var(--a-border-radius-xs) + &--circle + border-radius: var(--a-border-radius-circle) + + &--white + color: var(--a-color-white) + &--transparent-white + color: var(--a-color-transparent-white) + &--black + color: var(--a-color-black) + &--blue + color: var(--a-color-blue) + &--secondary-blue + color: var(--a-color-secondary-blue) + &--transparent-blue + color: var(--a-color-transparent-blue) + &--red + color: var(--a-color-red) + &--secondary-red + color: var(--a-color-secondary-red) + &--transparent-red + color: var(--a-color-transparent-red) + &--green + color: var(--a-color-green) + &--secondary-green + color: var(--a-color-secondary-green) + &--transparent-green + color: var(--a-color-transparent-green) + &--yellow + color: var(--a-color-yellow) + &--secondary-yellow + color: var(--a-color-secondary-yellow) + &--transparent-yellow + color: var(--a-color-transparent-yellow) + + &--bg-white + background-color: var(--a-color-white) + &--bg-transparent-white + background-color: var(--a-color-transparent-white) + &--bg-black + background-color: var(--a-color-black) + &--bg-blue + background-color: var(--a-color-blue) + &--bg-secondary-blue + background-color: var(--a-color-secondary-blue) + &--bg-transparent-blue + background-color: var(--a-color-transparent-blue) + &--bg-red + background-color: var(--a-color-red) + &--bg-secondary-red + background-color: var(--a-color-secondary-red) + &--bg-transparent-red + background-color: var(--a-color-transparent-red) + &--bg-green + background-color: var(--a-color-green) + &--bg-secondary-green + background-color: var(--a-color-secondary-green) + &--bg-transparent-green + background-color: var(--a-color-transparent-green) + &--bg-yellow + background-color: var(--a-color-yellow) + &--bg-secondary-yellow + background-color: var(--a-color-secondary-yellow) + &--bg-transparent-yellow + background-color: var(--a-color-transparent-yellow) diff --git a/aurora/src/components/icon/icon.tsx b/aurora/src/components/icon/icon.tsx new file mode 100644 index 0000000..f6a5170 --- /dev/null +++ b/aurora/src/components/icon/icon.tsx @@ -0,0 +1,75 @@ +import classNames from 'clsx' + +import type { Color, Size, IconType } from '../../lib/types' +import { generateKeyId } from '../../lib/utils' + +import './icon.sass' + +export interface IconProps { + iconName?: string + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + svg?: any + // svg?: React.ReactNode + type?: IconType + color?: Color + size?: Size | 'xxl' + bgShape?: 'square' | 'circle' + bgColor?: Color + animated?: boolean +} + +const REMIX_SIZE_MAPPING = { + xs: 'xs', + sm: 'sm', + md: '1x', + lg: 'lg', + xl: 'xl', + xxl: '2x' +} +const REMIX_ICON_TYPE_SUFFIXES = ['-line', '-fill'] + +/** + * @see https://remixicon.com/ + */ +export function Icon({ + iconName, + svg, + type = 'line', + color, + size = 'md', + bgShape, + bgColor, + animated +}: IconProps) { + let iconClassName = `ri-${iconName}` + const hasExplicitTypeSuffix = REMIX_ICON_TYPE_SUFFIXES.some((suffix) => + iconName?.endsWith(suffix) + ) + + if (type && type !== 'notype' && !hasExplicitTypeSuffix) { + iconClassName = `${iconClassName}-${type}` + } + + return ( + + {svg ? ( + svg + ) : ( + + )} + + ) +} diff --git a/aurora/src/components/icon/index.ts b/aurora/src/components/icon/index.ts new file mode 100644 index 0000000..0af8038 --- /dev/null +++ b/aurora/src/components/icon/index.ts @@ -0,0 +1 @@ +export * from './icon' diff --git a/aurora/src/components/image/image.sass b/aurora/src/components/image/image.sass new file mode 100644 index 0000000..3277f96 --- /dev/null +++ b/aurora/src/components/image/image.sass @@ -0,0 +1,76 @@ +@use '../../styles/main.sass' as * + +.aurora-image + position: relative + border-radius: var(--a-border-radius-md) + background-repeat: no-repeat + background-size: cover + background-position: center center + + &--overlay + &::before + content: '' + position: absolute + width: 100% + height: 100% + background-color: rgba(0, 0, 0, .2) + transition: background-color var(--a-transition-duration-main) var(--a-transition-timing-main) + &:hover + &::before + background-color: rgba(0, 0, 0, 0) + + &--gradient + &::after + content: '' + position: absolute + top: auto + bottom: 0 + width: 100% + height: 64px + background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--a-color-background-surface)) + &--gradient-top + &::after + top: 0 + bottom: auto + background-image: linear-gradient(to top, rgba(0, 0, 0, 0), var(--a-color-background-surface)) + &--gradient-bottom + &::after + top: auto + bottom: 0 + background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--a-color-background-surface)) + &--gradient-left + &::after + left: 0 + top: 0 + bottom: 0 + width: 64px + height: 100% + background-image: linear-gradient(to left, rgba(0, 0, 0, 0), var(--a-color-background-surface)) + &--gradient-right + &::after + right: 0 + top: 0 + bottom: 0 + width: 64px + height: 100% + background-image: linear-gradient(to right, rgba(0, 0, 0, 0), var(--a-color-background-surface)) + + &--cover + background-size: cover + &--contain + background-size: contain + + &--square + border-radius: var(--a-border-radius-md) + &--circle + border-radius: var(--a-border-radius-circle) + + &--blue-border + border: 1px solid var(--a-color-blue) + &--white-border + border: 1px solid var(--a-color-white) + + &--radius-top + border-radius: var(--a-border-radius-md) var(--a-border-radius-md) 0 0 + &--radius-bottom + border-radius: 0 0 var(--a-border-radius-md) var(--a-border-radius-md) diff --git a/aurora/src/components/image/image.tsx b/aurora/src/components/image/image.tsx new file mode 100644 index 0000000..5cb490c --- /dev/null +++ b/aurora/src/components/image/image.tsx @@ -0,0 +1,54 @@ +import classNames from 'clsx' + +import { generateKeyId } from '../../lib/utils' + +import './image.sass' + +export interface ImageProps { + src: string + width?: number | string + height?: number | string + shape?: 'circle' | 'square' + borderColor?: 'white' | 'blue' + backgroundSize?: 'cover' | 'contain' + radiusTop?: boolean + radiusBottom?: boolean + overlay?: boolean + gradient?: boolean + gradientPosition?: 'top' | 'bottom' | 'left' | 'right' +} + +export function Image({ + src, + width, + height, + shape, + borderColor, + backgroundSize, + radiusTop, + radiusBottom, + overlay, + gradient, + gradientPosition +}: ImageProps) { + return ( +
+ ) +} diff --git a/aurora/src/components/image/index.ts b/aurora/src/components/image/index.ts new file mode 100644 index 0000000..556dbfd --- /dev/null +++ b/aurora/src/components/image/index.ts @@ -0,0 +1 @@ +export * from './image' diff --git a/aurora/src/components/input/index.ts b/aurora/src/components/input/index.ts new file mode 100644 index 0000000..114afe8 --- /dev/null +++ b/aurora/src/components/input/index.ts @@ -0,0 +1 @@ +export * from './input' diff --git a/aurora/src/components/input/input.sass b/aurora/src/components/input/input.sass new file mode 100644 index 0000000..be56fe9 --- /dev/null +++ b/aurora/src/components/input/input.sass @@ -0,0 +1,87 @@ +@use '../../styles/main.sass' as * + +.aurora-input-container + --a-icon-container-width: calc(var(--a-input-size-md) + var(--a-space-sm)) + + position: relative + display: flex + flex-direction: column + +.aurora-input + position: relative + display: inline-block + color: var(--a-color-text) + background-color: var(--a-color-input-background) + font-size: var(--a-font-size-md) + border: 1px solid var(--a-color-input-border) + border-radius: var(--a-border-radius-md) + height: var(--a-input-size-md) + padding: 0 var(--a-space-md) + width: 100% + outline: none + transition: background-color var(--a-transition-duration-main) var(--a-transition-timing-main), border-color var(--a-transition-duration-main) var(--a-transition-timing-main) + &::-webkit-calendar-picker-indicator + cursor: pointer + background-color: var(--a-color-grey-blue-dark) + border-radius: var(--a-border-radius-xs) + &:hover + border-color: var(--a-color-input-border-hover) + background-color: var(--a-color-input-background-hover) + &:hover:not([disabled]) ~ .aurora-input-icon-container + border-color: var(--a-color-input-border-hover) + &:focus + border-color: var(--a-color-input-border-focus) + background-color: var(--a-color-input-background-hover) + &:focus:not([disabled]) + &~ .aurora-input-icon-container + border-color: var(--a-color-input-border-focus) + i + color: var(--a-color-accent) + &:placeholder-shown ~ .aurora-input-icon-container i + color: var(--color-secondary-white) + + &--multiline + height: calc(var(--a-input-size-md) * 2) + padding: var(--a-space-sm) var(--a-space-md) + resize: vertical + min-height: calc(var(--a-input-size-md) * 2) + max-height: 512px + &~ .aurora-input-icon-container + height: 100% + + &--disabled, &--disabled:hover + opacity: var(--a-opacity-disabled) + color: inherit + background-color: var(--a-color-input-background) + border-color: var(--a-color-input-border) + cursor: not-allowed + &--disabled ~ .aurora-input-icon-container + opacity: var(--a-opacity-disabled) + i + color: inherit + opacity: var(--a-opacity-disabled) + + &--with-icon + padding-left: calc(var(--a-icon-container-width) + var(--a-space-md)) + +.aurora-input-icon-container + position: absolute + left: 0 + top: 0 + bottom: 0 + display: flex + align-items: center + justify-content: center + color: var(--a-color-text) + pointer-events: none + border-right: 1px solid var(--a-color-input-border) + width: var(--a-icon-container-width) + height: var(--a-input-size-md) + transition: background-color var(--a-transition-duration-main) var(--a-transition-timing-main), border-color var(--a-transition-duration-main) var(--a-transition-timing-main) + i + color: var(--a-color-text) + transition: color var(--a-transition-duration-main) var(--a-transition-timing-main) + +.aurora-input-hint-container + padding-left: var(--a-space-md) + margin-top: var(--a-space-xs) diff --git a/aurora/src/components/input/input.tsx b/aurora/src/components/input/input.tsx new file mode 100644 index 0000000..9ef4ef8 --- /dev/null +++ b/aurora/src/components/input/input.tsx @@ -0,0 +1,167 @@ +import { useEffect, useState } from 'react' +import classNames from 'clsx' + +import { Text, Icon } from '../..' +import type { IconProps } from '../icon' + +import './input.sass' + +export interface InputProps { + name: string + placeholder: string + required?: boolean + value?: string + type?: + | 'text' + | 'password' + | 'email' + | 'tel' + | 'url' + | 'number' + | 'date' + | 'time' + | 'datetime-local' + | 'month' + | 'week' + | 'color' + iconName?: string + iconSVG?: IconProps['svg'] + iconType?: IconProps['type'] + iconSize?: IconProps['size'] + hint?: string + disabled?: boolean + height?: number | 'auto' + minLength?: number + maxLength?: number + min?: number + max?: number + step?: number + pattern?: string + multiline?: boolean + autofocus?: boolean + onFocus?: () => void + onBlur?: () => void + onKeyDown?: (event: React.KeyboardEvent) => void + inputRef?: React.Ref + onChange?: (value: string) => void +} + +export function Input({ + name, + placeholder, + required = false, + type = 'text', + iconName, + iconSVG, + iconType = 'fill', + iconSize = 'md', + hint, + value, + disabled, + height = 'auto', + minLength, + maxLength, + pattern, + multiline, + autofocus, + onFocus, + onBlur, + onKeyDown, + inputRef, + onChange +}: InputProps) { + const [inputValue, setInputValue] = useState(value || '') + + useEffect(() => { + setInputValue(value || '') + }, [value]) + + if (!multiline) { + if (!maxLength) { + maxLength = 64 + } + + if (height !== 'auto') { + height = 'auto' + } + } + + return ( +
+ {multiline ? ( +