Compare commits

..

1 Commits

Author SHA1 Message Date
Cohee
1d72a02995 Unify styling of max response/context fields 2025-03-11 00:18:20 +02:00
255 changed files with 4031 additions and 9789 deletions

View File

@@ -13,4 +13,3 @@ access.log
/cache
.DS_Store
/public/scripts/extensions/third-party
/colab

View File

@@ -3,9 +3,6 @@ module.exports = {
extends: [
'eslint:recommended',
],
plugins: [
'jsdoc',
],
env: {
es6: true,
},
@@ -81,7 +78,6 @@ module.exports = {
'public/scripts/extensions/tts/lib/**',
],
rules: {
'jsdoc/no-undefined-types': ['warn', { disableReporting: true, markVariablesAsUsed: true }],
'no-unused-vars': ['error', { args: 'none' }],
'no-control-regex': 'off',
'no-constant-condition': ['error', { checkLoops: false }],

View File

@@ -1,5 +1,4 @@
name: Bug Report 🐛
type: Bug
description: Report something that's not working the intended way. Support requests for external programs (reverse proxies, 3rd party servers, other peoples' forks) will be refused! Please use English only.
title: '[BUG] <title>'
labels: ['🐛 Bug']

View File

@@ -1,5 +1,4 @@
name: Feature Request ✨
type: Feature
description: Suggest an idea for future development of this project. Please use English only.
title: '[FEATURE_REQUEST] <title>'
labels: ['🦄 Feature Request']
@@ -33,7 +32,7 @@ body:
id: solution
attributes:
label: Describe the solution you'd like
placeholder: An outline of how you would like this to be implemented, include as much details as possible
placeholder: An outline of how you would like this to be implemented, include as much details as possible
validations:
required: true

2
.github/close-label.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
🐛 Bug: ✅ Fixed
🦄 Feature Request: ✅ Implemented

62
.github/issue-auto-comments.yml vendored Normal file
View File

@@ -0,0 +1,62 @@
comment:
footer: |
---
> I am a bot, and this is an automated message 🤖
labels:
- name: ✖️ Invalid
labeled:
issue:
action: close
body: >
Hello @{{ issue.user.login }} your ticket has been marked as invalid.
Please ensure you follow the issue template, provide all requested info,
and be sure to check the docs + previous issues prior to raising tickets.
pr:
body: Thank you @{{ pull_request.user.login }} for suggesting this. Please follow the pull request templates.
action: close
- name: 👩‍💻 Good First Issue
labeled:
issue:
body: >
This issue has been marked as a good first issue for first-time contributors to implement!
This is a great way to support the project, while also improving your skills, you'll also be credited as a contributor once your PR is merged.
If you're new to SillyTavern [here are a collection of resources](https://docs.sillytavern.app/)
If you need any support at all, feel free to reach out via [Discord](https://discord.gg/sillytavern).
- name: ❌ wontfix
labeled:
issue:
action: close
body: >
This ticked has been marked as 'wontfix', which usually means it is out-of-scope, or not feasible at this time.
You can still fork the project and make the changes yourself.
- name: ✅ Fixed
labeled:
issue:
body: >
Hello @{{ issue.user.login }}! It looks like all or part of this issue has now been implemented.
- name: ‼️ High Priority
labeled:
issue:
body: >
This ticket has been marked as high priority, and has been bumped to the top of the priority list.
You should expect an implementation to be pushed out soon. Thank you for your patience.
- name: 💀 Spam
labeled:
issue:
action: close
locking: lock
lock_reason: spam
body: >
This issue has been identified as spam, and is now locked.
Users who repeatedly raise spam issues may be blocked or reported.
- name: ⛔ Don't Merge
labeled:
pr:
body: This PR has been temporarily blocked from merging.

View File

@@ -1,69 +0,0 @@
labels:
- name: ✖️ Invalid
labeled:
issue:
action: close
body: >
Hey @{{ issue.user.login }}, this issue has been marked as invalid.
Please double-check that you've followed the issue template, included all necessary details, and reviewed the docs & previous issues before submitting.
If provided, follow the instructions given by maintainers.
- name: 👩‍💻 Good First Issue
labeled:
issue:
body: >
🏆 This issue has been marked as a good first issue for contributors to implement!
This is a great way to support the project. While also improving your skills, you'll also be credited as a contributor once your PR is merged.
If you're new to SillyTavern [here is the official documentation](https://docs.sillytavern.app/). The official contribution guide can be found [here](https://github.com/SillyTavern/SillyTavern/blob/release/CONTRIBUTING.md).
If you need any support, feel free to reach out via [Discord](https://discord.gg/sillytavern), or let us know in this issue or via [discussions](https://github.com/SillyTavern/SillyTavern/discussions).
- name: ❌ wontfix
labeled:
issue:
action: close
body: >
❌ This issue has been marked as 'wontfix', which usually means it is out-of-scope, not feasible at this time or will not be implemented for various reasons.
If you have any questions about this, feel free to reach out.
- name: 🛑 Out of Scope
labeled:
issue:
action: close
body: >
🛑 This issue has been marked as 'out of scope', as this can't or won't be implemented.
If you have any questions about this, feel free to reach out.
- name: ✅ Done (staging)
labeled:
issue:
body: >
✅ It looks like all or part of this issue has now been implemented as part of the `staging` branch.
If you currently are on the `release` branch, you can switch to `staging` to test this right away.
Note that `staging` is considered less stable than the official releases. To switch, follow existing instructions,
or simply enter the following command: `git switch staging`
- name: ✅ Done
labeled:
issue:
body: >
✅ It looks like all or part of this issue has now been implemented as part of the latest release.
- name: ‼️ High Priority
labeled:
issue:
body: >
🚨 This issue has been marked high priority, meaning it's important to the maintainers or community.
While we can't promise immediate changes, it is on our radar and will be addressed whenever possible. Thanks for your patience!
- name: 💀 Spam
labeled:
issue:
action: close
locking: lock
lock_reason: spam
body: >
💀 This issue has been flagged as spam and is now locked.
Please avoid posting spam - it disrupts the community and wastes everyone's time.

View File

@@ -1,3 +1,7 @@
# Add/remove 'critical' label if issue contains the words 'urgent' or 'critical'
#critical:
# - '(critical|urgent)'
🪟 Windows:
- '(🪟 Windows)'
@@ -11,10 +15,4 @@
- '(📱 Termux)'
🐧 Linux:
- '(🐧 Linux)'
🦊 Firefox:
- '\b(firefox|mozilla)\b'
📱 Mobile:
- '\b(iphone|ios|android|📱 Termux)\b'
- '(🐧 Linux)'

View File

@@ -1,51 +0,0 @@
labels:
- name: ✖️ Invalid
labeled:
pr:
action: close
body: >
Hey @{{ pull_request.user.login }}, thanks for your contribution!
Unfortunately, this PR has been marked as invalid.
Please check that you've followed the PR template, included all relevant details, and are targeting the correct branch (`staging` for regular contributions, `release` only for hotfixes).
If you need help, feel free to ask!
- name: ⛔ Don't Merge
labeled:
pr:
body: >
🚨 This PR has been temporarily blocked from merging.
- name: 💥💣 Breaking Changes
labeled:
pr:
body: >
⚠️ Heads up! This PR introduces breaking changes.
Make sure these changes are well-documented and that users will be properly informed when this is released.
- name: ⛔ Waiting For External/Upstream
labeled:
pr:
body: >
⛔ This PR is awaiting external or upstream changes or approval.
It can only be merged once those changes have been implemented and approved.
Please inform us of any progress on the upstream changes or approval.
- name: 🔬 Needs Testing
labeled:
pr:
body: >
🔬 This PR needs testing!
Any contributor can test and leave reviews, so feel free to help us out!
- name: 🟥 ⬤⬤⬤⬤⬤
labeled:
pr:
body: >
⚠️ This PR is over 1000 lines, which is larger than recommended.
Please make sure that it only addresses a single issue - PRs this large are hard to test and may be rejected.

View File

@@ -1,83 +0,0 @@
####################################
# Label PRs against 'release' #
####################################
❗ Against Release Branch:
- base-branch: 'release'
####################################
# Labels based on PR branch name #
####################################
🦋 Bug Fix:
- head-branch: ['^fix[/-]', '\bfixes\b']
🚑 Hot Fix:
- head-branch: ['^hotfix[/-]']
✨ New Feature:
- head-branch: ['^feat(ure)?[/-].*?\badd', '^add-']
✨ Feature Changes:
- head-branch: ['^feat(ure)?[/-](?!.*\badd\b)', '\bchanges?\b']
🤖 API / Model:
- head-branch: ['\bapi\b', '\bmodels?\b']
🏭 Backend Changes:
- head-branch: ['\bbackend\b', '\bendpoints?\b']
🐋 Docker:
- head-branch: ['\bdocker\b']
Extension:
- head-branch: ['\bextension\b', '\bext\b']
🦊 Firefox:
- head-branch: ['\bfirefox\b']
🧑‍🤝‍🧑 Group Chat:
- head-branch: ['\bgroups?\b']
🖼️ Image Gen:
- head-branch: ['\bimage-gen\b']
🌐 Language:
- head-branch: ['\btranslations?\b', '\blanguages?\b']
🐧 Linux:
- head-branch: ['\blinux\b']
🧩 Macros:
- head-branch: ['\bmacros?\b']
📱 Mobile:
- head-branch: ['\bmobile\b', '\bios\b', '\bandroid\b']
🚄 Performance:
- head-branch: ['\bperformance\b']
⚙️ Preset:
- head-branch: ['\bpresets?\b']
📜 Prompt:
- head-branch: ['\bprompt\b']
🧠 Reasoning:
- head-branch: ['\breasoning\b', '\breason\b', '\bthinking\b']
🚚 Refactor:
- head-branch: ['\brefactor(s|ed)?\b']
📜 STscript:
- head-branch: ['\bstscript\b', '\bslash-commands\b']
🏷️ Tags / Folders:
- head-branch: ['\btags\b']
🎙️ TTS / Voice:
- head-branch: ['\btts\b', '\bvoice\b']
🌟 UX:
- head-branch: ['\bux\b']
🗺️ World Info:
- head-branch: ['\bworld-info\b', '\bwi\b']

View File

@@ -1,46 +0,0 @@
####################################
# Labels based on changed files #
####################################
🏭 Backend Changes:
- changed-files:
- any-glob-to-any-file:
- "src/**"
- "default/config.yaml"
- "server.js"
- "plugins.js"
- "recover.js"
- "webpack.config.js"
- "Start.bat"
- "start.sh"
- "UpdateAndStart.bat"
- "UpdateForkAndStart.bat"
⚙️ config.yaml:
- changed-files:
- any-glob-to-any-file:
- "default/config.yaml"
🛠️ Build Changes:
- changed-files:
- any-glob-to-any-file:
- ".github/workflows/**"
- "docker/**"
- ".dockerignore"
- "Dockerfile"
- "webpack.config.js"
🌐 Language:
- changed-files:
- any-glob-to-any-file:
- "public/locales/**"
📥 Dependencies:
- changed-files:
- any-glob-to-any-file:
- "public/lib/**" # Every frontend lib counts as a dependency as well
- "package.json"
- "package-lock.json"
- "tests/package.json"
- "tests/package-lock.json"
- "src/electron/package.json"
- "src/electron/package-lock.json"

120
.github/readme.md vendored
View File

@@ -23,7 +23,7 @@ We have a [Documentation website](https://docs.sillytavern.app/) to answer most
SillyTavern (or ST for short) is a locally installed user interface that allows you to interact with text generation LLMs, image generation engines, and TTS voice models.
Beginning in February 2023 as a fork of TavernAI 1.2.8, SillyTavern now has over 200 contributors and 2 years of independent development under its belt, and continues to serve as a leading software for savvy AI hobbyists.
Beginning in February 2023 as a fork of TavernAI 1.2.8, SillyTavern now has over 100 contributors and 2 years of independent development under its belt, and continues to serve as a leading software for savvy AI hobbyists.
## Our Vision
@@ -113,9 +113,7 @@ SillyTavern has extensibility support.
Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern.app/).
## ⌛ Installation
### 🪟 Windows
# ⌛ Installation
> \[!WARNING]
>
@@ -123,7 +121,9 @@ Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern
> * DO NOT RUN START.BAT WITH ADMIN PERMISSIONS
> * INSTALLATION ON WINDOWS 7 IS IMPOSSIBLE AS IT CAN NOT RUN NODEJS 18.16
#### Installing via Git (recommended)
## 🪟 Windows
### Installing via Git
1. Install [NodeJS](https://nodejs.org/en) (latest LTS version is recommended)
2. Install [Git for Windows](https://gitforwindows.org/)
@@ -138,7 +138,7 @@ Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern
7. Once everything is cloned, double-click `Start.bat` to make NodeJS install its requirements.
8. The server will then start, and SillyTavern will pop up in your browser.
#### Installing via GitHub Desktop
### Installing via GitHub Desktop
(This allows git usage **only** in GitHub Desktop, if you want to use `git` on the command line too, you also need to install [Git for Windows](https://gitforwindows.org/))
@@ -152,7 +152,7 @@ Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern
9. After the installation process, if everything is working, the command console window should look like this and a SillyTavern tab should be open in your browser:
10. Connect to any of the [supported APIs](https://docs.sillytavern.app/usage/api-connections/) and start chatting!
### 🐧 Linux & 🍎 MacOS
## 🐧 Linux & 🍎 MacOS
For MacOS / Linux all of these will be done in a Terminal.
@@ -168,72 +168,6 @@ For MacOS / Linux all of these will be done in a Terminal.
* `./start.sh`
* `bash start.sh`
## 🐋 Installing via Docker
These instructions assume you have installed Docker, are able to access your command line for the installation of containers, and familiar with their general operation.
### Using the GitHub Container Registry
#### Docker Compose (easiest)
Grab the `docker-compose.yml` file from the [GitHub Repository](https://github.com/SillyTavern/SillyTavern/blob/release/docker/docker-compose.yml) and run the following command in the directory where the file is located. This will pull the latest release image from the GitHub Container Registry and start the container, automatically creating the necessary volumes.
```shell
docker-compose up
```
Customize the `docker-compose.yml` file to your needs. The default port is 8000. If you want to adjust the server configuration using environment variables, read the documentation [here](https://docs.sillytavern.app/administration/config-yaml/#environment-variables).
#### Docker CLI (advanced)
You will need two mandatory directory mappings and a port mapping to allow SillyTavern to function. In the command, replace your selections in the following places:
#### Container Variables
##### Volume Mappings
* `CONFIG_PATH` - The directory where SillyTavern configuration files will be stored on your host machine
* `DATA_PATH` - The directory where SillyTavern user data (including characters) will be stored on your host machine
* `PLUGINS_PATH` - (optional) The directory where SillyTavern server plugins will be stored on your host machine
* `EXTENSIONS_PATH` - (optional) The directory where global UI extensions will be stored on your host machine
##### Port Mappings
* `PUBLIC_PORT` - The port to expose the traffic on. This is mandatory, as you will be accessing the instance from outside of its virtual machine container. DO NOT expose this to the internet without implementing a separate service for security.
##### Additional Settings
* `SILLYTAVERN_VERSION` - On the right-hand side of this GitHub page, you'll see "Packages". Select the "sillytavern" package and you'll see the image versions. The image tag "latest" will keep you up-to-date with the current release. You can also utilize "staging" that points to the nightly image of the respective branch.
#### Running the container
1. Open your Command Line
2. Run the following command in a folder where you want to store the configuration and data files:
```bash
SILLYTAVERN_VERSION="latest"
PUBLIC_PORT="8000"
CONFIG_PATH="./config"
DATA_PATH="./data"
PLUGINS_PATH="./plugins"
EXTENSIONS_PATH="./extensions"
docker run \
--name="sillytavern" \
-p "$PUBLIC_PORT:8000/tcp" \
-v "$CONFIG_PATH:/home/node/app/config:rw" \
-v "$DATA_PATH:/home/node/app/data:rw" \
-v "$EXTENSIONS_PATH:/home/node/app/public/scripts/extensions/third-party:rw" \
-v "$PLUGINS_PATH:/home/node/app/plugins:rw" \
ghcr.io/sillytavern/sillytavern:"$SILLYTAVERN_VERSION"
```
> By default the container will run in the foreground. If you want to run it in the background, add the `-d` flag to the `docker run` command.
### Building the image yourself
We have a comprehensive guide on using SillyTavern in Docker [here](http://docs.sillytavern.app/installation/docker/) which covers installations on Windows, macOS and Linux! Give it a read if you wish to build the image yourself.
## ⚡ Installing via SillyTavern Launcher
SillyTavern Launcher is an installation wizard that will help you get setup with many options, including installing a backend for local inference.
@@ -305,6 +239,45 @@ chmod +x install.sh && ./install.sh
chmod +x launcher.sh && ./launcher.sh
```
## 🐋 Installing via Docker
These instructions assume you have installed Docker, are able to access your command line for the installation of containers, and familiar with their general operation.
### Building the image yourself
We have a comprehensive guide on using SillyTavern in Docker [here](http://docs.sillytavern.app/installation/docker/) which covers installations on Windows, macOS and Linux! Give it a read if you wish to build the image yourself.
### Using the GitHub Container Registry (easiest)
You will need two mandatory directory mappings and a port mapping to allow SillyTavern to function. In the command, replace your selections in the following places:
#### Container Variables
##### Volume Mappings
* [config] - The directory where SillyTavern configuration files will be stored on your host machine
* [data] - The directory where SillyTavern user data (including characters) will be stored on your host machine
* [plugins] - (optional) The directory where SillyTavern server plugins will be stored on your host machine
* [extensions] - (optional) The directory where global UI extensions will be stored on your host machine
##### Port Mappings
* [PublicPort] - The port to expose the traffic on. This is mandatory, as you will be accessing the instance from outside of its virtual machine container. DO NOT expose this to the internet without implementing a separate service for security.
##### Additional Settings
* [DockerNet] - The docker network that the container should be created with a connection to. If you don't know what it is, see the [official Docker documentation](https://docs.docker.com/reference/cli/docker/network/).
* [version] - On the right-hand side of this GitHub page, you'll see "Packages". Select the "sillytavern" package and you'll see the image versions. The image tag "latest" will keep you up-to-date with the current release. You can also utilize "staging" and "release" tags that point to the nightly images of the respective branches, but this may not be appropriate, if you are utilizing extensions that could be broken, and may need time to update.
#### Install command
1. Open your Command Line
2. Run the following command
`docker run --name='sillytavern' --net='[DockerNet]' -p '8000:8000/tcp' -v '[plugins]':'/home/node/app/plugins':'rw' -v '[config]':'/home/node/app/config':'rw' -v '[data]':'/home/node/app/data':'rw' -v '[extensions]':'/home/node/app/public/scripts/extensions/third-party':'rw' 'ghcr.io/sillytavern/sillytavern:[version]'`
> Note that 8000 is a default listening port. Don't forget to use an appropriate port if you change it in the config.
## 📱 Installing via Termux on Android OS
> \[!NOTE]
@@ -350,7 +323,6 @@ Start.bat --port 8000 --listen false
| Option | Description | Type |
|-------------------------|----------------------------------------------------------------------|----------|
| `--version` | Show version number | boolean |
| `--configPath` | Override the path to the config.yaml file | string |
| `--dataRoot` | Root directory for data storage | string |
| `--port` | Sets the port under which SillyTavern will run | number |
| `--listen` | SillyTavern will listen on all network interfaces | boolean |

View File

@@ -0,0 +1,28 @@
# Based on a label applied to an issue, the bot will add a comment with some additional info
name: 🎯 Auto-Reply to Labeled Tickets
on:
issues:
types:
- labeled
- unlabeled
pull_request_target:
types:
- labeled
- unlabeled
permissions:
contents: read
issues: write
pull-requests: write
jobs:
comment:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Label Commenter
uses: peaceiris/actions-label-commenter@v1
with:
config_file: .github/issue-auto-comments.yml
github_token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}

View File

@@ -0,0 +1,17 @@
# Detect and label pull requests that have merge conflicts
name: 🏗️ Check Merge Conflicts
on:
push:
branches:
- staging
jobs:
check-conflicts:
if: github.repository == 'SillyTavern/SillyTavern'
runs-on: ubuntu-latest
steps:
- uses: mschilde/auto-label-merge-conflicts@master
with:
CONFLICT_LABEL_NAME: "🚫 Merge Conflicts"
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
MAX_RETRIES: 5
WAIT_MS: 5000

View File

@@ -0,0 +1,82 @@
# Closes any issues that no longer have user interaction
name: 🎯 Close Stale Issues
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # Runs every day at midnight UTC
jobs:
stale:
runs-on: ubuntu-latest
steps:
# Comment on, then close issues that haven't been updated for ages
- name: Close Stale Issues
uses: actions/stale@v4
with:
repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
days-before-stale: 183
days-before-close: 7
operations-per-run: 30
remove-stale-when-updated: true
enable-statistics: true
stale-issue-message: >
This issue has gone 6 months without an update. To keep the ticket open, please indicate that it is still relevant in a comment below.
Otherwise it will be closed in 7 days.
stale-pr-message: >
This PR is stale because it has been open 6 months with no activity. Either remove the stale label or comment below with a short update,
otherwise this PR will be closed in 7 days.
close-issue-message: >
This issue was automatically closed because it has been stalled for over 6 months with no activity.
close-pr-message: >
This pull request was automatically closed because it has been stalled for over 6 months with no activity.
stale-issue-label: '⚰️ Stale'
close-issue-label: '🕸️ Inactive'
stale-pr-label: '⚰️ Stale'
close-pr-label: '🕸️ Inactive'
exempt-issue-labels: '📌 Keep Open'
exempt-pr-labels: '📌 Keep Open'
labels-to-add-when-unstale: '📌 Keep Open'
# Comment on, then close issues that required a response from the user, but didn't get one
- name: Close Issues without Response
uses: actions/stale@v4
with:
repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
days-before-stale: 7
days-before-close: 7
operations-per-run: 30
remove-stale-when-updated: true
stale-issue-message: >
Hi! Looks like additional info is required for this issue to be addressed.
Don't forget to provide this within the next few days to keep your ticket open.
close-issue-message: 'Issue closed due to no response from user.'
only-labels: '🚏 Awaiting User Response'
labels-to-remove-when-unstale: '🚏 Awaiting User Response, 🛑 No Response'
stale-issue-label: '🛑 No Response'
close-issue-label: '🕸️ Inactive'
exempt-issue-labels: '📌 Keep Open'
exempt-pr-labels: '📌 Keep Open'
# Comment on issues that we should have replied to
- name: Notify Repo Owner to Respond
uses: actions/stale@v4
with:
repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
days-before-stale: 7
days-before-close: 183
operations-per-run: 30
remove-stale-when-updated: true
stale-issue-message: Hey SillyTavern, - Don't forget to respond!
stale-pr-message: Hey SillyTavern, - Don't forget to respond!
only-labels: '👤 Awaiting Maintainer Response'
labels-to-remove-when-unstale: '👤 Awaiting Maintainer Response'
close-issue-message: 'Closed due to no response from repo author for over a year'
close-pr-message: 'Closed due to no response from repo author for over a year'
stale-issue-label: '👤 Awaiting Maintainer Response'
stale-pr-label: '👤 Awaiting Maintainer Response'
close-issue-label: '🕸️ Inactive'
close-pr-label: '🕸️ Inactive'
exempt-issue-labels: '📌 Keep Open'
exempt-pr-labels: '📌 Keep Open'

39
.github/workflows/get-pr-size.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
# Adds a comment to new PRs, showing the compressed size and size difference of new code
# And also labels the PR based on the number of lines changes
name: 🌈 Check PR Size
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
# Find and comment with compressed size
- name: Get Compressed Size
uses: preactjs/compressed-size-action@v2
with:
repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
pattern: './dist/**/*.{js,css,html}'
strip-hash: '\\b\\w{8}\\.'
exclude: '**/node_modules/**'
minimum-change-threshold: 100
# Check number of lines of code added
- name: Label based on Lines of Code
uses: codelytv/pr-size-labeler@v1
with:
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
xs_max_size: '10'
s_max_size: '100'
m_max_size: '500'
l_max_size: '1000'
s_label: '🟩 PR - Small'
m_label: '🟨 PR - Medium'
l_label: '🟧 PR - Large'
xl_label: '🟥 PR - XL'
fail_if_xl: 'false'
message_if_xl: >
It looks like this PR is very large (over 1000 lines).
Try to avoid addressing multiple issues in a single PR, and
in the future consider breaking large tasks down into smaller steps.
This it to make reviewing, testing, reverting and general quality management easier.

View File

@@ -1,116 +0,0 @@
name: 🛠️ Issues Manager
on:
issues:
types: [opened, edited, labeled, unlabeled]
# Re also listen to comments, to remove stale labels right away
issue_comment:
types: [created]
permissions:
contents: read
issues: write
jobs:
label-on-content:
name: 🏷️ Label Issues by Content
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
# Checkout
# https://github.com/marketplace/actions/checkout
uses: actions/checkout@v4.2.2
- name: Auto-Label Issues (Based on Issue Content)
# only auto label based on issue content once, on open (to prevent re-labeling removed labels)
if: github.event.action == 'opened'
# Issue Labeler
# https://github.com/marketplace/actions/regex-issue-labeler
uses: github/issue-labeler@v3.4
with:
configuration-path: .github/issues-auto-labels.yml
enable-versioned-regex: 0
repo-token: ${{ secrets.GITHUB_TOKEN }}
label-on-labels:
name: 🏷️ Label Issues by Labels
runs-on: ubuntu-latest
steps:
- name: ✅ Add "👍 Approved" for relevant labels
if: contains(fromJSON('["👩‍💻 Good First Issue", "🙏 Help Wanted", "🪲 Confirmed", "⚠️ High Priority", "❕ Medium Priority", "💤 Low Priority"]'), github.event.label.name)
# 🤖 Issues Helper
# https://github.com/marketplace/actions/issues-helper
uses: actions-cool/issues-helper@v3.6.0
with:
actions: 'add-labels'
token: ${{ secrets.GITHUB_TOKEN }}
labels: '👍 Approved'
- name: ❌ Remove progress labels when issue is marked done or stale
if: contains(fromJSON('["✅ Done", "✅ Done (staging)", "⚰️ Stale", "❌ wontfix"]'), github.event.label.name)
# 🤖 Issues Helper
# https://github.com/marketplace/actions/issues-helper
uses: actions-cool/issues-helper@v3.6.0
with:
actions: 'remove-labels'
token: ${{ secrets.GITHUB_TOKEN }}
labels: '🧑‍💻 In Progress,🤔 Unsure,🤔 Under Consideration'
- name: ❌ Remove temporary labels when confirmed labels are added
if: contains(fromJSON('["❌ wontfix","👍 Approved","👩‍💻 Good First Issue"]'), github.event.label.name)
# 🤖 Issues Helper
# https://github.com/marketplace/actions/issues-helper
uses: actions-cool/issues-helper@v3.6.0
with:
actions: 'remove-labels'
token: ${{ secrets.GITHUB_TOKEN }}
labels: '🤔 Unsure,🤔 Under Consideration'
- name: ❌ Remove no bug labels when "🪲 Confirmed" is added
if: github.event.label.name == '🪲 Confirmed'
# 🤖 Issues Helper
# https://github.com/marketplace/actions/issues-helper
uses: actions-cool/issues-helper@v3.6.0
with:
actions: 'remove-labels'
token: ${{ secrets.GITHUB_TOKEN }}
labels: '✖️ Not Reproducible,✖️ Not A Bug'
remove-stale-label:
name: 🗑️ Remove Stale Label on Comment
runs-on: ubuntu-latest
# Only run this on new comments, to automatically remove the stale label
if: github.event_name == 'issue_comment' && github.actor != 'github-actions[bot]'
steps:
- name: Remove Stale Label
# 🤖 Issues Helper
# https://github.com/marketplace/actions/issues-helper
uses: actions-cool/issues-helper@v3.6.0
with:
actions: 'remove-labels'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
labels: '⚰️ Stale,🕸️ Inactive,🚏 Awaiting User Response,🛑 No Response'
write-auto-comments:
name: 💬 Post Issue Comments Based on Labels
needs: [label-on-content, label-on-labels]
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
# Checkout
# https://github.com/marketplace/actions/checkout
uses: actions/checkout@v4.2.2
- name: Post Issue Comments Based on Labels
# Label Commenter
# https://github.com/marketplace/actions/label-commenter
uses: peaceiris/actions-label-commenter@v1.10.0
with:
config_file: .github/issues-auto-comments.yml
github_token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,45 +0,0 @@
name: 🔄 Update Issues on Push
on:
push:
branches:
- staging
- release
permissions:
contents: read
issues: write
jobs:
# This runs commits to staging/release, reading the commit messages. Check `pr-auto-manager.yml`:`update-linked-issues` for PR-linked updates.
update-linked-issues:
name: 🔗 Mark Linked Issues Done on Push
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
# Checkout
# https://github.com/marketplace/actions/checkout
uses: actions/checkout@v4.2.2
- name: Extract Linked Issues from Commit Message
id: extract_issues
run: |
ISSUES=$(git log ${{ github.event.before }}..${{ github.event.after }} --pretty=%B | grep -oiE '(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #([0-9]+)' | awk '{print $2}' | tr -d '#' | jq -R -s -c 'split("\n")[:-1]')
echo "issues=$ISSUES" >> $GITHUB_ENV
- name: Label Linked Issues
id: label_linked_issues
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
for ISSUE in $(echo $issues | jq -r '.[]'); do
if [ "${{ github.ref }}" == "refs/heads/staging" ]; then
LABEL="✅ Done (staging)"
gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL" --remove-label "🧑‍💻 In Progress"
elif [ "${{ github.ref }}" == "refs/heads/release" ]; then
LABEL="✅ Done"
gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL" --remove-label "🧑‍💻 In Progress"
fi
echo "Added label '$LABEL' (and removed '🧑‍💻 In Progress' if present) in issue #$ISSUE"
done

View File

@@ -1,100 +0,0 @@
name: 🕒 Close Stale Issues/PRs Workflow
on:
# Run the workflow every day
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # Runs every day at midnight UTC
permissions:
contents: read
issues: write
pull-requests: write
jobs:
mark-inactivity:
name: ⏳ Mark Issues/PRs without Activity
runs-on: ubuntu-latest
steps:
- name: Mark Issues/PRs without Activity
# Close Stale Issues and PRs
# https://github.com/marketplace/actions/close-stale-issues
uses: actions/stale@v9.1.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 183
days-before-close: 7
operations-per-run: 30
remove-stale-when-updated: true
enable-statistics: true
stale-issue-message: >
⏳ This issue has been inactive for 6 months. If it's still relevant, drop a comment below to keep it open.
Otherwise, it will be auto-closed in 7 days.
stale-pr-message: >
⏳ This PR has been inactive for 6 months. If it's still relevant, update it or remove the stale label.
Otherwise, it will be auto-closed in 7 days.
close-issue-message: >
🔒 This issue was auto-closed due to inactivity for over 6 months.
close-pr-message: >
🔒 This PR was auto-closed due to inactivity for over 6 months.
stale-issue-label: '⚰️ Stale'
close-issue-label: '🕸️ Inactive'
stale-pr-label: '⚰️ Stale'
close-pr-label: '🕸️ Inactive'
exempt-issue-labels: '📌 Keep Open'
exempt-pr-labels: '📌 Keep Open'
await-user-response:
name: ⚠️ Mark Issues/PRs Awaiting User Response
runs-on: ubuntu-latest
needs: mark-inactivity
steps:
- name: Mark Issues/PRs Awaiting User Response
# Close Stale Issues and PRs
# https://github.com/marketplace/actions/close-stale-issues
uses: actions/stale@v9.1.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 7
days-before-close: 7
operations-per-run: 30
remove-stale-when-updated: true
stale-issue-message: >
⚠️ Hey! We need some more info to move forward with this issue.
Please provide the requested details in the next few days to keep this ticket open.
close-issue-message: >
🔒 This issue was auto-closed due to no response from user.
only-labels: '🚏 Awaiting User Response'
labels-to-remove-when-unstale: '🚏 Awaiting User Response'
stale-issue-label: '🛑 No Response'
close-issue-label: '🕸️ Inactive'
exempt-issue-labels: '🚧 Alternative Exists'
alternative-exists:
name: 🔄 Mark Issues with Alternative Exists
runs-on: ubuntu-latest
needs: await-user-response
steps:
- name: Mark Issues with Alternative Exists
# Close Stale Issues and PRs
# https://github.com/marketplace/actions/close-stale-issues
uses: actions/stale@v9.1.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 7
days-before-close: 7
operations-per-run: 30
remove-stale-when-updated: true
stale-issue-message: >
🔄 An alternative solution has been provided for this issue.
Did this solve your problem? If so, we'll go ahead and close it.
If you still need help, drop a comment within the next 7 days to keep this open.
close-issue-message: >
✅ Closing this issue due to no confirmation on the alternative solution.
only-labels: '🚧 Alternative Exists'
stale-issue-label: '🚏 Awaiting User Response'
close-issue-label: '🕸️ Inactive'
exempt-issue-labels: '📌 Keep Open'

19
.github/workflows/labeler.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: "Issue Labeler"
on:
issues:
types: [opened, edited]
permissions:
issues: write
contents: read
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: github/issue-labeler@v3.4
with:
configuration-path: .github/labeler.yml
# not-before: 2020-01-15T02:54:32Z # optional and will result in any issues prior to this timestamp to be ignored.
enable-versioned-regex: 0
repo-token: ${{ github.token }}

View File

@@ -0,0 +1,17 @@
# When a new comment is added to an issue, if it had the Stale or Awaiting User Response labels, then those labels will be removed
name: 🎯 Remove Pending Labels on Close
on:
issues:
types: [closed]
jobs:
remove-labels:
runs-on: ubuntu-latest
steps:
- name: Remove Labels when Closed
uses: actions-cool/issues-helper@v2
with:
actions: remove-labels
token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
labels: '🚏 Awaiting User Response,⚰️ Stale,👤 Awaiting Maintainer Response'

View File

@@ -0,0 +1,42 @@
# When a new comment is added to an issue, if it had the Stale or Awaiting User Response labels, then those labels will be removed
name: 🎯 Add/ Remove Awaiting Response Labels
on:
issue_comment:
types: [created]
jobs:
remove-stale:
runs-on: ubuntu-latest
if: ${{ github.event.comment.author_association != 'COLLABORATOR' && github.event.comment.author_association != 'OWNER' }}
steps:
- name: Remove Stale labels when Updated
uses: actions-cool/issues-helper@v2
with:
actions: remove-labels
token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
labels: '🚏 Awaiting User Response,⚰️ Stale'
add-awaiting-author:
runs-on: ubuntu-latest
if: ${{!github.event.issue.pull_request && github.event.comment.author_association != 'COLLABORATOR' && github.event.comment.author_association != 'OWNER' && github.event.issue.state == 'open' }}
steps:
- name: Add Awaiting Author labels when Updated
uses: actions-cool/issues-helper@v2
with:
actions: add-labels
token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
labels: '👤 Awaiting Maintainer Response'
remove-awaiting-author:
runs-on: ubuntu-latest
if: ${{ github.event.comment.author_association == 'OWNER' }}
steps:
- name: Remove Awaiting Author labels when Updated
uses: actions-cool/issues-helper@v2
with:
actions: remove-labels
token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
labels: '👤 Awaiting Maintainer Response'

View File

@@ -1,28 +0,0 @@
name: 🚪 Issues/PRs On Close Handler
on:
issues:
types: [closed]
pull_request_target:
types: [closed]
permissions:
contents: read
issues: write
pull-requests: write
jobs:
remove-labels:
name: 🗑️ Remove Pending Labels on Close
runs-on: ubuntu-latest
steps:
- name: Remove Pending Labels on Close
# 🤖 Issues Helper
# https://github.com/marketplace/actions/issues-helper
uses: actions-cool/issues-helper@v3.6.0
with:
actions: remove-labels
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number || github.event.pull_request.number }}
labels: '🚏 Awaiting User Response,🧑‍💻 In Progress,📌 Keep Open,🚫 Merge Conflicts,🔬 Needs Testing,🔨 Needs Work,⚰️ Stale,⛔ Waiting For External/Upstream'

View File

@@ -1,29 +0,0 @@
name: 📨 Issues/PRs Open Handler
on:
issues:
types: [opened]
pull_request_target:
types: [opened]
permissions:
contents: read
issues: write
pull-requests: write
jobs:
label-maintainer:
name: 🏷️ Label if Author is a Repo Maintainer
runs-on: ubuntu-latest
if: contains(fromJson('["Cohee1207", "RossAscends", "Wolfsblvt"]'), github.actor)
steps:
- name: Label if Author is a Repo Maintainer
# 🤖 Issues Helper
# https://github.com/marketplace/actions/issues-helper
uses: actions-cool/issues-helper@v3.6.0
with:
actions: 'add-labels'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number || github.event.pull_request.number }}
labels: '👷 Maintainer'

View File

@@ -1,270 +0,0 @@
name: 🔀 Pull Request Manager
on:
workflow_dispatch: # Allow to manually call this workflow
pull_request_target:
types: [opened, synchronize, reopened, edited, labeled, unlabeled, closed]
pull_request_review_comment:
types: [created]
permissions:
contents: read
pull-requests: write
jobs:
run-eslint:
name: ✅ Check ESLint on PR
runs-on: ubuntu-latest
# Only needs to run when code is changed
if: github.event.action == 'opened' || github.event.action == 'synchronize'
# Override permissions, linter likely needs write access to issues
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Checkout Repository
# Checkout
# https://github.com/marketplace/actions/checkout
uses: actions/checkout@v4.2.2
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Setup Node.js
# Setup Node.js environment
# https://github.com/marketplace/actions/setup-node-js-environment
uses: actions/setup-node@v4.3.0
with:
node-version: 20
- name: Run npm install
run: npm ci
- name: Run ESLint
# Action ESLint
# https://github.com/marketplace/actions/action-eslint
uses: sibiraj-s/action-eslint@v3.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
eslint-args: '--ignore-path=.gitignore --quiet'
extensions: 'js'
annotations: true
ignore-patterns: |
dist/
lib/
label-by-size:
name: 🏷️ Label PR by Size
# This job should run after all others, to prevent possible concurrency issues
needs: [label-by-branches, label-by-files, remove-stale-label, check-merge-blocking-labels, write-auto-comments]
runs-on: ubuntu-latest
# Only needs to run when code is changed
if: always() && (github.event.action == 'opened' || github.event.action == 'synchronize')
# Override permissions, the labeler needs issues write access
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Label PR Size
# Pull Request Size Labeler
# https://github.com/marketplace/actions/pull-request-size-labeler
uses: codelytv/pr-size-labeler@v1.10.2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
xs_label: '🟩 ⬤○○○○'
xs_max_size: '20'
s_label: '🟩 ⬤⬤○○○'
s_max_size: '100'
m_label: '🟨 ⬤⬤⬤○○'
m_max_size: '500'
l_label: '🟧 ⬤⬤⬤⬤○'
l_max_size: '1000'
xl_label: '🟥 ⬤⬤⬤⬤⬤'
fail_if_xl: 'false'
files_to_ignore: |
"package-lock.json"
"public/lib/*"
label-by-branches:
name: 🏷️ Label PR by Branches
runs-on: ubuntu-latest
# Only label once when PR is created or when base branch is changed, to allow manual label removal
if: github.event.action == 'opened' || (github.event.action == 'synchronize' && github.event.changes.base)
steps:
- name: Checkout Repository
# Checkout
# https://github.com/marketplace/actions/checkout
uses: actions/checkout@v4.2.2
- name: Apply Labels Based on Branch Name and Target Branch
# Pull Request Labeler
# https://github.com/marketplace/actions/labeler
uses: actions/labeler@v5.0.0
with:
configuration-path: .github/pr-auto-labels-by-branch.yml
repo-token: ${{ secrets.GITHUB_TOKEN }}
label-by-files:
name: 🏷️ Label PR by Files
runs-on: ubuntu-latest
# Only needs to run when code is changed
if: github.event.action == 'opened' || github.event.action == 'synchronize'
steps:
- name: Checkout Repository
# Checkout
# https://github.com/marketplace/actions/checkout
uses: actions/checkout@v4.2.2
- name: Apply Labels Based on Changed Files
# Pull Request Labeler
# https://github.com/marketplace/actions/labeler
uses: actions/labeler@v5.0.0
with:
configuration-path: .github/pr-auto-labels-by-files.yml
repo-token: ${{ secrets.GITHUB_TOKEN }}
remove-stale-label:
name: 🗑️ Remove Stale Label on Comment
runs-on: ubuntu-latest
# Only runs on comments not done by the github actions bot
if: github.event_name == 'pull_request_review_comment' && github.actor != 'github-actions[bot]'
# Override permissions, issue labeler needs issues write access
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Remove Stale Label
# 🤖 Issues Helper
# https://github.com/marketplace/actions/issues-helper
uses: actions-cool/issues-helper@v3.6.0
with:
actions: 'remove-labels'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.pull_request.number }}
labels: '⚰️ Stale'
check-merge-blocking-labels:
name: 🚫 Check Merge Blocking Labels
needs: [label-by-branches, label-by-files]
runs-on: ubuntu-latest
# Run, even if the previous jobs were skipped/failed
if: always()
# Override permissions, as this needs to write a check
permissions:
checks: write
contents: read
pull-requests: read
steps:
- name: Check Merge Blocking
# GitHub Script
# https://github.com/marketplace/actions/github-script
id: label-check
uses: actions/github-script@v7.0.1
with:
script: |
const prLabels = context.payload.pull_request.labels.map(label => label.name);
const blockingLabels = [
"⛔ Don't Merge",
"🔨 Needs Work",
"🔬 Needs Testing",
"⛔ Waiting For External/Upstream",
"❗ Against Release Branch",
"💥💣 Breaking Changes"
];
const hasBlockingLabel = prLabels.some(label => blockingLabels.includes(label));
if (hasBlockingLabel) {
console.log("Blocking label detected. Setting warning status.");
await github.rest.checks.create({
owner: context.repo.owner,
repo: context.repo.repo,
name: "PR Label Warning",
head_sha: context.payload.pull_request.head.sha,
status: "completed",
conclusion: "neutral",
output: {
title: "Potential Merge Issue",
summary: "This PR has a merge-blocking label. Proceed with caution."
}
});
} else {
console.log("No merge-blocking labels found.");
}
write-auto-comments:
name: 💬 Post PR Comments Based on Labels
needs: [label-by-branches, label-by-files]
runs-on: ubuntu-latest
# Run, even if the previous jobs were skipped/failed
if: always()
steps:
- name: Checkout Repository
# Checkout
# https://github.com/marketplace/actions/checkout
uses: actions/checkout@v4.2.2
- name: Post PR Comments Based on Labels
# Label Commenter for PRs
# https://github.com/marketplace/actions/label-commenter
uses: peaceiris/actions-label-commenter@v1.10.0
with:
config_file: .github/pr-auto-comments.yml
github_token: ${{ secrets.GITHUB_TOKEN }}
# This runs on merged PRs to staging, reading the PR body and directly linked issues. Check `issues-updates-on-merge.yml`:`update-linked-issues` for commit-based updates.
update-linked-issues:
name: 🔗 Mark Linked Issues Done on Staging Merge
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'staging'
# Override permissions, We need to be able to write to issues
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Extract Linked Issues From PR Description
id: extract_issues
run: |
ISSUES=$(jq -r '.pull_request.body' "$GITHUB_EVENT_PATH" | grep -oiE '(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #([0-9]+)' | awk '{print $2}' | tr -d '#' | jq -R -s -c 'split("\n")[:-1]')
echo "issues=$ISSUES" >> $GITHUB_ENV
- name: Fetch Directly Linked Issues
id: fetch_linked_issues
run: |
PR_NUMBER=${{ github.event.pull_request.number }}
REPO=${{ github.repository }}
API_URL="https://api.github.com/repos/$REPO/pulls/$PR_NUMBER/issues"
ISSUES=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" "$API_URL" | jq -r '.[].number' | jq -R -s -c 'split("\n")[:-1]')
echo "linked_issues=$ISSUES" >> $GITHUB_ENV
- name: Merge Issue Lists
id: merge_issues
run: |
ISSUES=$(jq -c -n --argjson a "$issues" --argjson b "$linked_issues" '$a + $b | unique')
echo "final_issues=$ISSUES" >> $GITHUB_ENV
- name: Label Linked Issues
id: label_linked_issues
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
for ISSUE in $(echo $final_issues | jq -r '.[]'); do
gh issue edit $ISSUE -R ${{ github.repository }} --add-label "✅ Done (staging)" --remove-label "🧑‍💻 In Progress"
echo "Added label '✅ Done (staging)' (and removed '🧑‍💻 In Progress' if present) in issue #$ISSUE"
done

View File

@@ -1,28 +0,0 @@
name: ⚔️ Check Merge Conflicts
on:
# So that PRs touching the same files as the push are updated
push:
# So that the `dirtyLabel` is removed if conflicts are resolved
pull_request_target:
types: [synchronize]
permissions:
contents: read
pull-requests: write
jobs:
check-merge-conflicts:
name: ⚔️ Check Merge Conflicts
runs-on: ubuntu-latest
steps:
- name: Check Merge Conflicts
# Label Conflicting Pull Requests
# https://github.com/marketplace/actions/label-conflicting-pull-requests
uses: eps1lon/actions-label-merge-conflict@v3.0.3
with:
dirtyLabel: '🚫 Merge Conflicts'
repoToken: ${{ secrets.GITHUB_TOKEN }}
commentOnDirty: >
⚠️ This PR has conflicts that need to be resolved before it can be merged.

View File

@@ -12,4 +12,3 @@ access.log
.vscode
.git
/public/scripts/extensions/third-party
/colab

View File

@@ -12,13 +12,15 @@ WORKDIR ${APP_HOME}
# Set NODE_ENV to production
ENV NODE_ENV=production
# Bundle app source
COPY . ./
# Install app dependencies
COPY package*.json post-install.js ./
RUN \
echo "*** Install npm packages ***" && \
npm i --no-audit --no-fund --loglevel=error --no-progress --omit=dev && npm cache clean --force
# Bundle app source
COPY . ./
# Copy default chats, characters and user avatars to <folder>.default folder
RUN \
rm -f "config.yaml" || true && \

View File

@@ -114,8 +114,6 @@ backups:
chat:
# Enable automatic chat backups
enabled: true
# Verify integrity of chat files before saving
checkIntegrity: true
# Maximum number of chat backups to keep per user (starting from the most recent). Set to -1 to keep all backups.
maxTotalBackups: -1
# Interval in milliseconds to throttle chat backups per user
@@ -142,8 +140,6 @@ performance:
lazyLoadCharacters: false
# The maximum amount of memory that parsed character cards can use. Set to 0 to disable memory caching.
memoryCacheCapacity: '100mb'
# Enables disk caching for character cards. Improves performances with large card libraries.
useDiskCache: true
# Allow secret keys exposure via API
allowKeysExposure: false
@@ -155,7 +151,6 @@ whitelistImportDomains:
- cdn.discordapp.com
- files.catbox.moe
- raw.githubusercontent.com
- char-archive.evulid.cc
# API request overrides (for KoboldAI and Text Completion APIs)
## Note: host includes the port number if it's not the default (80 or 443)
## Format is an array of objects:
@@ -234,10 +229,6 @@ claude:
# should be ideal for most use cases.
# Any value other than a non-negative integer will be ignored and caching at depth will not be enabled.
cachingAtDepth: -1
# -- GOOGLE GEMINI API CONFIGURATION --
gemini:
# API endpoint version ("v1beta" or "v1alpha")
apiVersion: 'v1beta'
# -- SERVER PLUGIN CONFIGURATION --
enableServerPlugins: false
# Attempt to automatically update server plugins on startup

View File

@@ -540,7 +540,7 @@
"type": "context"
},
{
"filename": "presets/context/Metharme.json",
"filename": "presets/context/Pygmalion.json",
"type": "context"
},
{
@@ -563,10 +563,6 @@
"filename": "presets/context/Llama 3 Instruct.json",
"type": "context"
},
{
"filename": "presets/context/Llama 4 Instruct.json",
"type": "context"
},
{
"filename": "presets/context/Phi.json",
"type": "context"
@@ -619,6 +615,10 @@
"filename": "presets/instruct/OpenOrca-OpenChat.json",
"type": "instruct"
},
{
"filename": "presets/instruct/Pygmalion.json",
"type": "instruct"
},
{
"filename": "presets/instruct/Story.json",
"type": "instruct"
@@ -663,10 +663,6 @@
"filename": "presets/instruct/Llama 3 Instruct.json",
"type": "instruct"
},
{
"filename": "presets/instruct/Llama 4 Instruct.json",
"type": "instruct"
},
{
"filename": "presets/instruct/Phi.json",
"type": "instruct"
@@ -751,10 +747,6 @@
"filename": "presets/sysprompt/Neutral - Chat.json",
"type": "sysprompt"
},
{
"filename": "presets/sysprompt/Lightning 1.1.json",
"type": "sysprompt"
},
{
"filename": "presets/instruct/Mistral V1.json",
"type": "instruct"
@@ -794,21 +786,5 @@
{
"filename": "presets/context/DeepSeek-V2.5.json",
"type": "context"
},
{
"filename": "presets/instruct/GLM-4.json",
"type": "instruct"
},
{
"filename": "presets/context/GLM-4.json",
"type": "context"
},
{
"filename": "presets/reasoning/DeepSeek.json",
"type": "reasoning"
},
{
"filename": "presets/reasoning/Blank.json",
"type": "reasoning"
}
]

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": false,
"trim_sentences": false,
"single_line": true,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": false,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>New Roleplay:<|END_OF_TURN_TOKEN|>",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "***",
"chat_start": "***",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": false,
"trim_sentences": true,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "<|eot_id|>\n<|start_header_id|>user<|end_header_id|>\n\nWrite an example narrative / conversation that is not part of the main story.",
"chat_start": "<|eot_id|>\n<|start_header_id|>user<|end_header_id|>\n\nStart the role-play between {{char}} and {{user}}.",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": false,
"trim_sentences": true,
"single_line": false,

View File

@@ -1,10 +0,0 @@
{
"story_string": "[gMASK]<sop>{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}\n",
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,
"name": "GLM-4"
}

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "### Example:",
"chat_start": "### START ROLEPLAY:",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -1,8 +1,9 @@
{
"story_string": "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\n### Instruction:\n{{system}}\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{char}}'s description:{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality:{{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{user}}'s persona: {{persona}}\n{{/if}}\n\n",
"example_separator": "Example of an interaction:\n",
"chat_start": "This is the history of the roleplay:\n",
"story_string": "{{system}}\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{char}}'s description:{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality:{{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{user}}'s persona: {{persona}}\n{{/if}}",
"example_separator": "Example of an interaction:",
"chat_start": "This is the history of the roleplay:",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -1,10 +0,0 @@
{
"story_string": "<|begin_of_text|><|header_start|>system<|header_end|>\n\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}<|eot|>",
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,
"name": "Llama 4 Instruct"
}

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "***",
"chat_start": "***",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "This is how {{char}} should talk",
"chat_start": "\nThen the roleplay chat between {{user}} and {{char}} begins.\n",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,8 +3,9 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,
"name": "Metharme"
"name": "Pygmalion"
}

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "",
"chat_start": "",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -3,6 +3,7 @@
"example_separator": "### New Roleplay:",
"chat_start": "### New Roleplay:",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": true,
"trim_sentences": false,
"single_line": false,

View File

@@ -6,7 +6,7 @@
"stop_sequence": "<|im_end|>",
"wrap": true,
"macro": true,
"names_behavior": "force",
"names_behavior": "always",
"activation_regex": "",
"system_sequence_prefix": "",
"system_sequence_suffix": "",

View File

@@ -8,7 +8,7 @@
"stop_sequence": "<|END_OF_TURN_TOKEN|>",
"wrap": false,
"macro": true,
"names_behavior": "force",
"names_behavior": "always",
"activation_regex": "",
"skip_examples": false,
"output_suffix": "<|END_OF_TURN_TOKEN|>",

View File

@@ -6,7 +6,7 @@
"stop_sequence": "<end_of_turn>",
"wrap": true,
"macro": true,
"names_behavior": "force",
"names_behavior": "none",
"activation_regex": "",
"system_sequence_prefix": "",
"system_sequence_suffix": "",

View File

@@ -1,7 +1,7 @@
{
"input_sequence": "### Instruction:",
"output_sequence": "### Response:",
"last_output_sequence": "### Response: (length = unlimited)",
"output_sequence": "### Response: (length = unlimited)",
"last_output_sequence": "",
"system_sequence": "",
"stop_sequence": "",
"wrap": true,
@@ -12,8 +12,8 @@
"system_sequence_suffix": "",
"first_output_sequence": "",
"skip_examples": false,
"output_suffix": "\n\n",
"input_suffix": "\n\n",
"output_suffix": "",
"input_suffix": "",
"system_suffix": "",
"user_alignment_message": "",
"system_same_as_user": true,

View File

@@ -6,7 +6,7 @@
"stop_sequence": "<|eot_id|>",
"wrap": false,
"macro": true,
"names_behavior": "force",
"names_behavior": "always",
"activation_regex": "",
"system_sequence_prefix": "",
"system_sequence_suffix": "",
@@ -16,7 +16,7 @@
"input_suffix": "<|eot_id|>",
"system_suffix": "<|eot_id|>",
"user_alignment_message": "",
"system_same_as_user": false,
"system_same_as_user": true,
"last_system_sequence": "",
"name": "Llama 3 Instruct"
}

View File

@@ -1,22 +0,0 @@
{
"input_sequence": "<|header_start|>user<|header_end|>\n\n",
"output_sequence": "<|header_start|>assistant<|header_end|>\n\n",
"last_output_sequence": "",
"system_sequence": "<|header_start|>system<|header_end|>\n\n",
"stop_sequence": "<|eot|>",
"wrap": false,
"macro": true,
"names_behavior": "force",
"activation_regex": "",
"system_sequence_prefix": "",
"system_sequence_suffix": "",
"first_output_sequence": "",
"skip_examples": false,
"output_suffix": "<|eot|>",
"input_suffix": "<|eot|>",
"system_suffix": "<|eot|>",
"user_alignment_message": "",
"system_same_as_user": false,
"last_system_sequence": "",
"name": "Llama 4 Instruct"
}

View File

@@ -6,7 +6,7 @@
"stop_sequence": "",
"wrap": false,
"macro": true,
"names_behavior": "force",
"names_behavior": "always",
"activation_regex": "",
"system_sequence_prefix": "",
"system_sequence_suffix": "",

View File

@@ -6,7 +6,7 @@
"stop_sequence": "",
"wrap": false,
"macro": true,
"names_behavior": "force",
"names_behavior": "always",
"activation_regex": "",
"system_sequence_prefix": "",
"system_sequence_suffix": "",

View File

@@ -6,7 +6,7 @@
"stop_sequence": "",
"wrap": false,
"macro": true,
"names_behavior": "force",
"names_behavior": "always",
"activation_regex": "",
"system_sequence_prefix": "",
"system_sequence_suffix": "",

View File

@@ -6,7 +6,7 @@
"stop_sequence": "</s>",
"wrap": false,
"macro": true,
"names_behavior": "force",
"names_behavior": "always",
"activation_regex": "",
"system_sequence_prefix": "",
"system_sequence_suffix": "",

View File

@@ -8,7 +8,7 @@
"stop_sequence": "<|end|>",
"wrap": false,
"macro": true,
"names_behavior": "force",
"names_behavior": "always",
"activation_regex": "",
"skip_examples": false,
"output_suffix": "<|end|>\n",

View File

@@ -1,22 +1,22 @@
{
"input_sequence": "<|user|>\n",
"output_sequence": "<|assistant|>\n",
"first_output_sequence": "",
"input_sequence": "<|user|>",
"output_sequence": "<|model|>",
"last_output_sequence": "",
"system_sequence_prefix": "<|system|>\n",
"system_sequence_suffix": "",
"stop_sequence": "",
"system_sequence": "",
"stop_sequence": "<|user|>",
"wrap": false,
"macro": true,
"names_behavior": "force",
"names_behavior": "always",
"activation_regex": "",
"system_sequence_prefix": "<|system|>",
"system_sequence_suffix": "",
"first_output_sequence": "",
"skip_examples": false,
"output_suffix": "",
"input_suffix": "",
"system_sequence": "",
"system_suffix": "",
"user_alignment_message": "",
"last_system_sequence": "",
"system_same_as_user": true,
"name": "GLM-4"
"last_system_sequence": "",
"name": "Pygmalion"
}

View File

@@ -8,7 +8,7 @@
"stop_sequence": "<|end_of_text|>",
"wrap": false,
"macro": true,
"names_behavior": "force",
"names_behavior": "always",
"activation_regex": "",
"skip_examples": false,
"output_suffix": "<|end_of_text|>\n",

View File

@@ -1,6 +0,0 @@
{
"name": "Blank",
"prefix": "",
"suffix": "",
"separator": ""
}

View File

@@ -1,6 +0,0 @@
{
"name": "DeepSeek",
"prefix": "<think>\n",
"suffix": "\n</think>",
"separator": "\n\n"
}

View File

@@ -1,5 +1,4 @@
{
"name": "Actor",
"content": "You are an expert actor that can fully immerse yourself into any role given. You do not break character for any reason, even if someone tries addressing you as an AI or language model. Currently your role is {{char}}, which is described in detail below. As {{char}}, continue the exchange with {{user}}.",
"post_history": ""
"content": "You are an expert actor that can fully immerse yourself into any role given. You do not break character for any reason, even if someone tries addressing you as an AI or language model. Currently your role is {{char}}, which is described in detail below. As {{char}}, continue the exchange with {{user}}."
}

View File

@@ -1,5 +1,4 @@
{
"name": "Assistant - Expert",
"content": "You are a helpful assistant. Please answer truthfully and write out your thinking step by step to be sure you get the right answer. If you make a mistake or encounter an error in your thinking, say so out loud and attempt to correct it. If you don't know or aren't sure about something, say so clearly. You will act as a professional logician, mathematician, and physicist. You will also act as the most appropriate type of expert to answer any particular question or solve the relevant problem; state which expert type your are, if so. Also think of any particular named expert that would be ideal to answer the relevant question or solve the relevant problem; name and act as them, if appropriate.",
"post_history": ""
"content": "You are a helpful assistant. Please answer truthfully and write out your thinking step by step to be sure you get the right answer. If you make a mistake or encounter an error in your thinking, say so out loud and attempt to correct it. If you don't know or aren't sure about something, say so clearly. You will act as a professional logician, mathematician, and physicist. You will also act as the most appropriate type of expert to answer any particular question or solve the relevant problem; state which expert type your are, if so. Also think of any particular named expert that would be ideal to answer the relevant question or solve the relevant problem; name and act as them, if appropriate."
}

View File

@@ -1,5 +1,4 @@
{
"name": "Assistant - Simple",
"content": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions.",
"post_history": ""
"content": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions."
}

View File

@@ -1,5 +1,4 @@
{
"name": "Blank",
"content": "",
"post_history": ""
"content": ""
}

View File

@@ -1,5 +1,4 @@
{
"name": "Chain of Thought",
"content": "Elaborate on the topic using a Tree of Thoughts and backtrack when necessary to construct a clear, cohesive Chain of Thought reasoning. Always answer without hesitation.",
"post_history": ""
"content": "Elaborate on the topic using a Tree of Thoughts and backtrack when necessary to construct a clear, cohesive Chain of Thought reasoning. Always answer without hesitation."
}

View File

@@ -1,5 +0,0 @@
{
"name": "Lightning 1.1",
"content": "Take the role of {{char}} in a play that leaves a lasting impression on {{user}}. Write {{char}}'s next reply.\nNever skip or gloss over {{char}}s actions. Progress the scene at a naturally slow pace.",
"post_history": ""
}

View File

@@ -1,5 +1,4 @@
{
"name": "Neutral - Chat",
"content": "Write {{char}}'s next reply in a fictional chat between {{char}} and {{user}}.",
"post_history": ""
"content": "Write {{char}}'s next reply in a fictional chat between {{char}} and {{user}}."
}

View File

@@ -1,5 +1,4 @@
{
"name": "Roleplay - Detailed",
"content": "Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions. Keep the story immersive and engaging.",
"post_history": ""
"content": "Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions. Keep the story immersive and engaging."
}

View File

@@ -1,5 +1,4 @@
{
"name": "Roleplay - Immersive",
"content": "[System note: Write one reply only. Do not decide what {{user}} says or does. Write at least one paragraph, up to four. Be descriptive and immersive, providing vivid details about {{char}}'s actions, emotions, and the environment. Write with a high degree of complexity and burstiness. Do not repeat this message.]",
"post_history": ""
"content": "[System note: Write one reply only. Do not decide what {{user}} says or does. Write at least one paragraph, up to four. Be descriptive and immersive, providing vivid details about {{char}}'s actions, emotions, and the environment. Write with a high degree of complexity and burstiness. Do not repeat this message.]"
}

View File

@@ -1,5 +1,4 @@
{
"name": "Roleplay - Simple",
"content": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.",
"post_history": ""
"content": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}."
}

View File

@@ -1,5 +1,4 @@
{
"name": "Text Adventure",
"content": "[Enter Adventure Mode. Narrate the story based on {{user}}'s dialogue and actions after \">\". Describe the surroundings in vivid detail. Be detailed, creative, verbose, and proactive. Move the story forward by introducing fantasy elements and interesting characters.]",
"post_history": ""
"content": "[Enter Adventure Mode. Narrate the story based on {{user}}'s dialogue and actions after \">\". Describe the surroundings in vivid detail. Be detailed, creative, verbose, and proactive. Move the story forward by introducing fantasy elements and interesting characters.]"
}

View File

@@ -1,5 +1,4 @@
{
"name": "Writer - Creative",
"content": "You are an intelligent, skilled, versatile writer.\n\nYour task is to write a role-play based on the information below.",
"post_history": ""
"content": "You are an intelligent, skilled, versatile writer.\n\nYour task is to write a role-play based on the information below."
}

View File

@@ -1,5 +1,4 @@
{
"name": "Writer - Realistic",
"content": "Continue writing this story and portray characters realistically.",
"post_history": ""
"content": "Continue writing this story and portray characters realistically."
}

View File

@@ -2,7 +2,7 @@
"compilerOptions": {
"module": "ESNext",
"target": "ES2023",
"moduleResolution": "Bundler",
"moduleResolution": "Node",
"strictNullChecks": true,
"strictFunctionTypes": true,
"checkJs": true,

1455
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,29 +4,7 @@
"@agnai/sentencepiece-js": "^1.1.1",
"@agnai/web-tokenizers": "^0.1.3",
"@iconfu/svg-inject": "^1.2.3",
"@jimp/core": "^1.6.0",
"@jimp/js-bmp": "^1.6.0",
"@jimp/js-gif": "^1.6.0",
"@jimp/js-tiff": "^1.6.0",
"@jimp/plugin-blit": "^1.6.0",
"@jimp/plugin-circle": "^1.6.0",
"@jimp/plugin-color": "^1.6.0",
"@jimp/plugin-contain": "^1.6.0",
"@jimp/plugin-cover": "^1.6.0",
"@jimp/plugin-crop": "^1.6.0",
"@jimp/plugin-displace": "^1.6.0",
"@jimp/plugin-fisheye": "^1.6.0",
"@jimp/plugin-flip": "^1.6.0",
"@jimp/plugin-mask": "^1.6.0",
"@jimp/plugin-quantize": "^1.6.0",
"@jimp/plugin-resize": "^1.6.0",
"@jimp/plugin-rotate": "^1.6.0",
"@jimp/plugin-threshold": "^1.6.0",
"@jimp/wasm-avif": "^1.6.0",
"@jimp/wasm-jpeg": "^1.6.0",
"@jimp/wasm-png": "^1.6.0",
"@jimp/wasm-webp": "^1.6.0",
"@mozilla/readability": "^0.6.0",
"@mozilla/readability": "^0.5.0",
"@popperjs/core": "^2.11.8",
"@zeldafan0225/ai_horde": "^5.2.0",
"archiver": "^7.0.1",
@@ -40,7 +18,6 @@
"cookie-parser": "^1.4.6",
"cookie-session": "^2.1.0",
"cors": "^2.8.5",
"crc": "^4.3.2",
"csrf-sync": "^4.0.3",
"diff-match-patch": "^1.0.5",
"dompurify": "^3.2.4",
@@ -59,6 +36,7 @@
"ip-regex": "^5.0.0",
"ipaddr.js": "^2.2.0",
"is-docker": "^3.0.0",
"jimp": "^0.22.10",
"localforage": "^1.10.0",
"lodash": "^4.17.21",
"mime-types": "^2.1.35",
@@ -69,6 +47,7 @@
"node-persist": "^4.0.4",
"open": "^8.4.2",
"png-chunk-text": "^1.0.0",
"png-chunks-encode": "^1.0.0",
"png-chunks-extract": "^1.0.0",
"proxy-agent": "^6.5.0",
"rate-limiter-flexible": "^5.0.5",
@@ -111,11 +90,11 @@
"type": "git",
"url": "https://github.com/SillyTavern/SillyTavern.git"
},
"version": "1.12.14",
"version": "1.12.12",
"scripts": {
"start": "node server.js",
"debug": "node --inspect server.js",
"start:electron": "cd ./src/electron && npm run start",
"electron": "electron ./src/electron",
"start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js",
"start:bun": "bun server.js",
"start:no-csrf": "node server.js --disableCsrf",
@@ -146,13 +125,14 @@
"@types/jquery": "^3.5.32",
"@types/jquery-cropper": "^1.0.4",
"@types/jquery.transit": "^0.9.33",
"@types/jqueryui": "^1.12.24",
"@types/jqueryui": "^1.12.23",
"@types/lodash": "^4.17.16",
"@types/mime-types": "^2.1.4",
"@types/multer": "^1.4.12",
"@types/node": "^18.19.80",
"@types/node": "^18.19.78",
"@types/node-persist": "^3.1.8",
"@types/png-chunk-text": "^1.0.3",
"@types/png-chunks-encode": "^1.0.2",
"@types/png-chunks-extract": "^1.0.2",
"@types/response-time": "^2.3.8",
"@types/select2": "^4.0.63",
@@ -160,7 +140,6 @@
"@types/write-file-atomic": "^4.0.3",
"@types/yargs": "^17.0.33",
"@types/yauzl": "^2.10.3",
"eslint": "^8.57.1",
"eslint-plugin-jsdoc": "^48.10.0"
"eslint": "^8.57.1"
}
}

View File

@@ -3,17 +3,136 @@
*/
import fs from 'node:fs';
import path from 'node:path';
import crypto from 'node:crypto';
import process from 'node:process';
import yaml from 'yaml';
import _ from 'lodash';
import chalk from 'chalk';
import { createRequire } from 'node:module';
import { addMissingConfigValues } from './src/config-init.js';
/**
* Colorizes console output.
*/
const color = chalk;
const keyMigrationMap = [
{
oldKey: 'disableThumbnails',
newKey: 'thumbnails.enabled',
migrate: (value) => !value,
},
{
oldKey: 'thumbnailsQuality',
newKey: 'thumbnails.quality',
migrate: (value) => value,
},
{
oldKey: 'avatarThumbnailsPng',
newKey: 'thumbnails.format',
migrate: (value) => (value ? 'png' : 'jpg'),
},
{
oldKey: 'disableChatBackup',
newKey: 'backups.chat.enabled',
migrate: (value) => !value,
},
{
oldKey: 'numberOfBackups',
newKey: 'backups.common.numberOfBackups',
migrate: (value) => value,
},
{
oldKey: 'maxTotalChatBackups',
newKey: 'backups.chat.maxTotalBackups',
migrate: (value) => value,
},
{
oldKey: 'chatBackupThrottleInterval',
newKey: 'backups.chat.throttleInterval',
migrate: (value) => value,
},
{
oldKey: 'enableExtensions',
newKey: 'extensions.enabled',
migrate: (value) => value,
},
{
oldKey: 'enableExtensionsAutoUpdate',
newKey: 'extensions.autoUpdate',
migrate: (value) => value,
},
{
oldKey: 'extras.disableAutoDownload',
newKey: 'extensions.models.autoDownload',
migrate: (value) => !value,
},
{
oldKey: 'extras.classificationModel',
newKey: 'extensions.models.classification',
migrate: (value) => value,
},
{
oldKey: 'extras.captioningModel',
newKey: 'extensions.models.captioning',
migrate: (value) => value,
},
{
oldKey: 'extras.embeddingModel',
newKey: 'extensions.models.embedding',
migrate: (value) => value,
},
{
oldKey: 'extras.speechToTextModel',
newKey: 'extensions.models.speechToText',
migrate: (value) => value,
},
{
oldKey: 'extras.textToSpeechModel',
newKey: 'extensions.models.textToSpeech',
migrate: (value) => value,
},
{
oldKey: 'minLogLevel',
newKey: 'logging.minLogLevel',
migrate: (value) => value,
},
{
oldKey: 'cardsCacheCapacity',
newKey: 'performance.memoryCacheCapacity',
migrate: (value) => `${value}mb`,
},
// uncomment one release after 1.12.13
/*
{
oldKey: 'cookieSecret',
newKey: 'cookieSecret',
migrate: () => void 0,
remove: true,
},
*/
];
/**
* Gets all keys from an object recursively.
* @param {object} obj Object to get all keys from
* @param {string} prefix Prefix to prepend to all keys
* @returns {string[]} Array of all keys in the object
*/
function getAllKeys(obj, prefix = '') {
if (typeof obj !== 'object' || Array.isArray(obj) || obj === null) {
return [];
}
return _.flatMap(Object.keys(obj), key => {
const newPrefix = prefix ? `${prefix}.${key}` : key;
if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
return getAllKeys(obj[key], newPrefix);
} else {
return [newPrefix];
}
});
}
/**
* Converts the old config.conf file to the new config.yaml format.
*/
@@ -40,6 +159,71 @@ function convertConfig() {
}
}
/**
* Compares the current config.yaml with the default config.yaml and adds any missing values.
*/
function addMissingConfigValues() {
try {
const defaultConfig = yaml.parse(fs.readFileSync(path.join(process.cwd(), './default/config.yaml'), 'utf8'));
let config = yaml.parse(fs.readFileSync(path.join(process.cwd(), './config.yaml'), 'utf8'));
// Migrate old keys to new keys
const migratedKeys = [];
for (const { oldKey, newKey, migrate, remove } of keyMigrationMap) {
if (_.has(config, oldKey)) {
if (remove) {
_.unset(config, oldKey);
migratedKeys.push({
oldKey,
newValue: void 0,
});
continue;
}
const oldValue = _.get(config, oldKey);
const newValue = migrate(oldValue);
_.set(config, newKey, newValue);
_.unset(config, oldKey);
migratedKeys.push({
oldKey,
newKey,
oldValue,
newValue,
});
}
}
// Get all keys from the original config
const originalKeys = getAllKeys(config);
// Use lodash's defaultsDeep function to recursively apply default properties
config = _.defaultsDeep(config, defaultConfig);
// Get all keys from the updated config
const updatedKeys = getAllKeys(config);
// Find the keys that were added
const addedKeys = _.difference(updatedKeys, originalKeys);
if (addedKeys.length === 0 && migratedKeys.length === 0) {
return;
}
if (addedKeys.length > 0) {
console.log('Adding missing config values to config.yaml:', addedKeys);
}
if (migratedKeys.length > 0) {
console.log('Migrating config values in config.yaml:', migratedKeys);
}
fs.writeFileSync('./config.yaml', yaml.stringify(config));
} catch (error) {
console.error(color.red('FATAL: Could not add missing config values to config.yaml'), error);
}
}
/**
* Creates the default config files if they don't exist yet.
*/
@@ -102,13 +286,58 @@ function createDefaultFiles() {
}
}
/**
* Returns the MD5 hash of the given data.
* @param {Buffer} data Input data
* @returns {string} MD5 hash of the input data
*/
function getMd5Hash(data) {
return crypto
.createHash('md5')
.update(new Uint8Array(data))
.digest('hex');
}
/**
* Copies the WASM binaries from the sillytavern-transformers package to the dist folder.
*/
function copyWasmFiles() {
if (!fs.existsSync('./dist')) {
fs.mkdirSync('./dist');
}
const listDir = fs.readdirSync('./node_modules/sillytavern-transformers/dist');
for (const file of listDir) {
if (file.endsWith('.wasm')) {
const sourcePath = `./node_modules/sillytavern-transformers/dist/${file}`;
const targetPath = `./dist/${file}`;
// Don't copy if the file already exists and is the same checksum
if (fs.existsSync(targetPath)) {
const sourceChecksum = getMd5Hash(fs.readFileSync(sourcePath));
const targetChecksum = getMd5Hash(fs.readFileSync(targetPath));
if (sourceChecksum === targetChecksum) {
continue;
}
}
fs.copyFileSync(sourcePath, targetPath);
console.log(`${file} successfully copied to ./dist/${file}`);
}
}
}
try {
// 0. Convert config.conf to config.yaml
convertConfig();
// 1. Create default config files
createDefaultFiles();
// 2. Add missing config values
addMissingConfigValues(path.join(process.cwd(), './config.yaml'));
// 2. Copy transformers WASM binaries from node_modules
copyWasmFiles();
// 3. Add missing config values
addMissingConfigValues();
} catch (error) {
console.error(error);
}

View File

@@ -146,15 +146,3 @@ input.extension_missing[type="checkbox"] {
.extensions_info .extension_actions {
flex-wrap: nowrap;
}
.extensions_toolbar {
top: 0;
position: sticky;
display: flex;
flex-direction: row;
background-color: var(--SmartThemeBlurTintColor);
gap: 5px;
z-index: 1;
margin-bottom: 10px;
padding: 5px;
}

View File

@@ -359,15 +359,10 @@
content: attr(external_piece_text);
display: block;
width: 100%;
font-weight: 500;
font-weight: 600;
text-align: center;
}
.completion_prompt_manager_popup_entry_form_control #completion_prompt_manager_popup_entry_form_prompt:disabled {
visibility: hidden;
}
#completion_prompt_manager_popup_entry_source_block {
display: flex;
justify-content: center;
}

View File

@@ -87,7 +87,7 @@
}
#rm_group_members:empty::before {
content: attr(group_empty_text);
content: 'Group is empty';
font-weight: bolder;
width: 100%;
@@ -115,7 +115,7 @@
}
#rm_group_add_members:empty::before {
content: attr(no_characters_text);
content: 'No characters available';
font-weight: bolder;
width: 100%;

View File

@@ -13,7 +13,6 @@
backdrop-filter: blur(calc(var(--SmartThemeBlurStrength)*2));
color: var(--SmartThemeBodyColor);
z-index: 40000;
user-select: none;
}
.select2-container .select2-selection .select2-selection__clear {

View File

@@ -124,10 +124,6 @@
cursor: initial;
}
.world_entry .inline-drawer-header-pointer {
cursor: pointer;
}
.world_entry .killSwitch {
cursor: pointer;
}

40
public/global.d.ts vendored
View File

@@ -1,25 +1,18 @@
import libs from './lib';
import getContext from './scripts/st-context';
import { power_user } from './scripts/power-user';
// Global namespace modules
declare var ai;
declare var pdfjsLib;
declare var ePub;
declare var SillyTavern: {
getContext(): typeof getContext;
llm: any;
libs: typeof libs;
};
declare global {
// Custom types
declare type InstructSettings = typeof power_user.instruct;
// Global namespace modules
interface Window {
ai: any;
}
declare var pdfjsLib;
declare var ePub;
declare var SillyTavern: {
getContext(): typeof getContext;
llm: any;
libs: typeof libs;
};
// Jquery plugins
interface JQuery {
nanogallery2(options?: any): JQuery;
@@ -55,15 +48,4 @@ declare global {
* @param provider Translation provider
*/
async function translate(text: string, lang: string, provider: string = null): Promise<string>;
interface ConvertVideoArgs {
buffer: Uint8Array;
name: string;
}
/**
* Converts a video file to an animated WebP format using FFmpeg.
* @param args - The arguments for the conversion function.
*/
function convertVideoToAnimatedWebp(args: ConvertVideoArgs): Promise<Uint8Array>;
}

View File

@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="katman_1"
x="0px"
y="0px"
viewBox="0 0 438.67001 481.44999"
xml:space="preserve"
sodipodi:docname="XAI_Logo.svg"
width="438.67001"
height="481.45001"
inkscape:version="1.3 (0e150ed, 2023-07-21)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs4" /><sodipodi:namedview
id="namedview4"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="0.39645207"
inkscape:cx="219.44645"
inkscape:cy="238.36425"
inkscape:window-width="1512"
inkscape:window-height="856"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="1"
inkscape:current-layer="katman_1" />&#10;<g
id="g4"
transform="translate(-201.61,-56.91)">&#10; <polygon
points="631.96,538.36 640.28,93.18 557.09,211.99 565.4,538.36 "
id="polygon1" />&#10; <polygon
points="379.35,284.53 430.13,357.05 640.28,56.91 538.72,56.91 "
id="polygon2" />&#10; <polygon
points="353.96,465.84 303.17,393.31 201.61,538.36 303.17,538.36 "
id="polygon3" />&#10; <polygon
points="531.69,538.36 303.17,211.99 201.61,211.99 430.13,538.36 "
id="polygon4" />&#10;</g>&#10;</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

Some files were not shown because too many files have changed in this diff Show More