update by Silence_Lurker

Init plugin
This commit is contained in:
2025-12-23 16:22:27 +08:00
parent 5635b3441a
commit fd244519cc
10 changed files with 878 additions and 1 deletions

1
.gitignore vendored
View File

@@ -136,3 +136,4 @@ dist
.yarn/install-state.gz
.pnp.*
.history

187
README.md
View File

@@ -1,3 +1,188 @@
# Amily-Databin
Databin组件优化数据存储持久化功能不直接提供用户界面默认仅供开发者进行调用。
Databin组件优化数据存储持久化功能不直接提供用户界面默认仅供开发者进行调用。
该组件的意义为降低开发者对数据存储的复杂度,提供一种简单的数据存储方式,并支持数据持久化。该组件维护且仅维护存储和读取数据,不提供用户界面。(当然,并不意味着该组件不可用于用户界面,我们鼓励用户自行设计用户界面)
## 安装
### 通过链接安装 (推荐)
1. 在 SillyTavern 的扩展页面,点击 "Install from URL"。
2. 输入以下链接: `https://amily-gitlab.amily49.cc/slvccans/Amily-Databin`
3. 点击 "Install"。
4. 重启 SillyTavern.
### 手动安装
1. 下载本仓库的 ZIP 压缩包。
2. 解压 ZIP 文件。
3.`Amily-Databin` 文件夹复制到 `SillyTavern/public/extensions` 目录下。
4. 重启 SillyTavern.
## API 用法
本插件会在客户端环境中注入一个全局的 `window.AmilyDatabin` 对象,用于进行精细化的数据交互。
**架构说明:** `SourceType` 常量表现在通过根目录的 `sourcetype.json` 文件进行动态管理。客户端会在加载时自动从服务器获取此配置,这使得系统具有很强的扩展性,未来增加新的数据类型也无需修改客户端代码。
### `AmilyDatabin.SourceType`
一个用于定义数据来源的常量表。
```javascript
{
CHAT_LOG: 1, // 用于聊天文件存储
CHARACTER_CARD: 2, // 用于角色卡存储
WORLD_BOOK: 3 // 用于世界书存储
}
```
### `AmilyDatabin.getData(source, fileName, objName = null)`
从服务器获取特定数据。`objName` 是可选的,如果省略,插件会从当前上下文中自动检测。
```javascript
/**
* 从服务器获取特定数据。
* @param {number} source - 数据来源标识 (使用 AmilyDatabin.SourceType)。
* @param {string} fileName - 文件名或唯一键。
* @param {string} [objName=null] - 可选。指定对象名如角色ID。若为null则自动检测。**注意:对于 `WORLD_BOOK` 类型,`objName` 无法自动检测,必须明确提供。**
* @returns {Promise<object|null>} 一个Promise解析为请求到的数据对象如果未找到则为 null。
*/
async function retrieveCurrentCharacterMemory() {
try {
// 此处省略了 objName插件将自动使用当前角色的ID
const memory = await window.AmilyDatabin.getData(
window.AmilyDatabin.SourceType.CHARACTER_CARD,
"character_memory.json"
);
if (memory) {
console.log("成功获取当前角色记忆:", memory);
} else {
console.log("没有找到当前角色的记忆。");
}
return memory;
} catch (error) {
console.error("获取数据失败:", error);
return null;
}
}
// 自动上下文调用示例:
retrieveCurrentCharacterMemory();
```
### `AmilyDatabin.saveData(source, fileName, fileContent, objName = null)`
将一个JavaScript对象保存到服务器的指定路径。`objName` 是可选的。
```javascript
/**
* 将一个数据对象保存到服务器的指定路径。
* @param {number} source - 数据来源标识 (使用 AmilyDatabin.SourceType)。
* @param {string} fileName - 文件名或唯一键。
* @param {string} [objName=null] - 可选。指定对象名。若为null则自动检测。**注意:对于 `WORLD_BOOK` 类型,`objName` 无法自动检测,必须明确提供。**
* @returns {Promise<boolean>} 一个Promise如果保存成功则解析为 true否则为 false。
*/
async function saveCurrentChatLog(chatHistory) {
try {
// 此处省略了 objName它将自动解析为当前聊天的ID
const success = await window.AmilyDatabin.saveData(
window.AmilyDatabin.SourceType.CHAT_LOG,
`log_${new Date().getTime()}.json`, // 唯一键示例
{ history: chatHistory, savedAt: new Date().toISOString() }
);
if (success) {
console.log("当前聊天的记录已成功保存。");
} else {
console.error("聊天记录保存失败。");
}
return success;
} catch (error) {
console.error("保存数据时出错:", error);
return false;
}
}
// 调用示例:
const currentChat = ["用户: 你好!", "角色: 你好!"];
saveCurrentChatLog(currentChat);
```
### `AmilyDatabin.deleteData(source, fileName, objName = null)`
从服务器删除一个指定的数据文件。`objName` 是可选的。
```javascript
/**
* 从服务器删除一个特定的数据文件。
* @param {number} source - 数据来源标识 (使用 AmilyDatabin.SourceType)。
* @param {string} fileName - 要删除的数据的文件名或唯一键。
* @param {string} [objName=null] - 可选。指定对象名。若为null则自动检测。**注意:对于 `WORLD_BOOK` 类型,`objName` 无法自动检测,必须明确提供。**
* @returns {Promise<boolean>} 一个Promise如果删除成功则解析为 true否则为 false。
*/
async function deleteCurrentCharacterMemory() {
try {
const success = await window.AmilyDatabin.deleteData(
window.AmilyDatabin.SourceType.CHARACTER_CARD,
"character_memory.json"
);
if (success) {
console.log("成功删除当前角色记忆。");
} else {
console.log("删除角色记忆失败。");
}
return success;
} catch (error) {
console.error("删除数据失败:", error);
return false;
}
}
// 调用示例:
deleteCurrentCharacterMemory();
```
## 调试方法
这些方法设计用于在浏览器控制台中进行快速调试。它们不与后端API交互。
### `AmilyDatabin.getDebugInstance()`
`AmilyDatabin` 对象本身输出到控制台。可用于检查其当前状态、`SourceType` 映射和可用方法。
```javascript
// 在浏览器控制台调用:
AmilyDatabin.getDebugInstance();
// 预期输出: { SourceType: { CHAT_LOG: 1, ... }, initialize: f, ... }
```
### `AmilyDatabin.getDebugChatId()`
尝试使用与主API方法相同的逻辑解析当前聊天ID并将其记录到控制台。
```javascript
// 在浏览器控制台调用:
AmilyDatabin.getDebugChatId();
// 预期输出: [Amily-Databin] Current Chat ID (Debug): "你的聊天ID"
```
### `AmilyDatabin.getDebugCardId()`
尝试使用与主API方法相同的逻辑解析当前角色卡ID并将其记录到控制台。
```javascript
// 在浏览器控制台调用:
AmilyDatabin.getDebugCardId();
// 预期输出: [Amily-Databin] Current Character Card ID (Debug): "你的角色卡ID"
```
## 开发者
主要逻辑分别位于 `index.js` (服务器端) 和 `public/client.js` (客户端)。
你可以直接通过全局的 `window.AmilyDatabin` 对象与此插件交互。

192
README_en.md Normal file
View File

@@ -0,0 +1,192 @@
# Amily-Databin
A Databin component designed to optimize data storage persistence. It does not directly provide a user interface but is intended for developers to call for data operations.
The purpose of this component is to simplify data storage for developers, offering a straightforward method for data storage with persistence support. This component solely manages data storage and retrieval; it does not offer a user interface. (However, this does not mean the component cannot be used for user interfaces; users are encouraged to design their own user interfaces.)
## Installation
### Install via Link (Recommended)
1. In the SillyTavern extensions page, click "Install from URL".
2. Enter the following link: `https://amily-gitlab.amily49.cc/slvccans/Amily-Databin`
3. Click "Install".
4. Restart SillyTavern.
### Manual Installation
1. Download the ZIP archive of this repository.
2. Extract the ZIP file.
3. Copy the `Amily-Databin` folder to the `SillyTavern/public/extensions` directory.
4. Restart SillyTavern.
## Usage
This plugin acts as a data bucket component and does not provide a user interface. It is primarily intended for developers to call.
## API Usage
This plugin injects a global `window.AmilyDatabin` object into the client-side environment for simplified, granular data interaction.
**Architectural Note:** The `SourceType` constants table is dynamically managed via the `sourcetype.json` file. The client automatically fetches this configuration from the server upon loading, making the system extensible without requiring client-side code changes.
### `AmilyDatabin.SourceType`
A constants table used to define the source of the data.
```javascript
{
CHAT_LOG: 1, // For chat log storage
CHARACTER_CARD: 2, // For character card storage
WORLD_BOOK: 3 // For world book storage
}
```
### `AmilyDatabin.getData(source, fileName, objName = null)`
Retrieves specific data from the server. The `objName` is optional and will be auto-detected from the current context if omitted.
```javascript
/**
* Fetches specific data from the server.
* @param {number} source - The data source identifier (use AmilyDatabin.SourceType).
* @param {string} fileName - The file name or unique key for the data.
* @param {string} [objName=null] - Optional. The specific object name (e.g., character ID). If null, it's auto-detected. **Note: For `WORLD_BOOK` type, `objName` cannot be automatically detected and must be provided explicitly.**
* @returns {Promise<object|null>} A Promise that resolves to the requested data object, or null if not found.
*/
async function retrieveCurrentCharacterMemory() {
try {
// We omit objName, so the plugin will automatically use the current character's ID.
const memory = await window.AmilyDatabin.getData(
window.AmilyDatabin.SourceType.CHARACTER_CARD,
"character_memory.json"
);
if (memory) {
console.log("Retrieved current character memory:", memory);
} else {
console.log("No memory found for the current character.");
}
return memory;
} catch (error) {
console.error("Failed to retrieve data:", error);
return null;
}
}
// Example call for automatic context:
retrieveCurrentCharacterMemory();
```
### `AmilyDatabin.saveData(source, fileName, fileContent, objName = null)`
Saves a JavaScript object to a specific path on the server. The `objName` is optional.
```javascript
/**
* Saves a data object to a specific path on the server.
* @param {number} source - The data source identifier (use AmilyDatabin.SourceType).
* @param {string} fileName - The file name or unique key for the data.
* @param {object} fileContent - The JavaScript object to save.
* @param {string} [objName=null] - Optional. The specific object name. If null, it's auto-detected. **Note: For `WORLD_BOOK` type, `objName` cannot be automatically detected and must be provided explicitly.**
* @returns {Promise<boolean>} A Promise that resolves to true if successful, false otherwise.
*/
async function saveCurrentChatLog(chatHistory) {
try {
// objName is omitted here, it will be resolved to the current chat's ID automatically.
const success = await window.AmilyDatabin.saveData(
window.AmilyDatabin.SourceType.CHAT_LOG,
`log_${new Date().getTime()}.json`, // Example of a unique key
{ history: chatHistory, savedAt: new Date().toISOString() }
);
if (success) {
console.log("Chat log for current chat saved successfully.");
} else {
console.error("Failed to save chat log.");
}
return success;
} catch (error) {
console.error("Error during data saving:", error);
return false;
}
}
// Example call:
const currentChat = ["User: Hi!", "Character: Hello!"];
saveCurrentChatLog(currentChat);
```
### `AmilyDatabin.deleteData(source, fileName, objName = null)`
Deletes a specific data file from the server. The `objName` is optional.
```javascript
/**
* Deletes a specific data file from the server.
* @param {number} source - The data source identifier (use AmilyDatabin.SourceType).
* @param {string} [objName=null] - Optional. The specific object name. If null, it's auto-detected. **Note: For `WORLD_BOOK` type, `objName` cannot be automatically detected and must be provided explicitly.**
* @returns {Promise<boolean>} A Promise that resolves to true if successful, false otherwise.
*/
async function deleteCurrentCharacterMemory() {
try {
const success = await window.AmilyDatabin.deleteData(
window.AmilyDatabin.SourceType.CHARACTER_CARD,
"character_memory.json"
);
if (success) {
console.log("Successfully deleted current character memory.");
} else {
console.log("Failed to delete character memory.");
}
return success;
} catch (error) {
console.error("Failed to delete data:", error);
return false;
}
}
// Example call:
deleteCurrentCharacterMemory();
```
## Debug Methods
These methods are designed for quick debugging in the browser console. They do not interact with the backend API.
### `AmilyDatabin.getDebugInstance()`
Outputs the `AmilyDatabin` object itself to the console. Useful for inspecting its current state, `SourceType` map, and available methods.
```javascript
// Call in browser console:
AmilyDatabin.getDebugInstance();
// Expected output: { SourceType: { CHAT_LOG: 1, ... }, initialize: f, ... }
```
### `AmilyDatabin.getDebugChatId()`
Attempts to resolve the current chat ID using the same logic as the main API methods and logs it to the console.
```javascript
// Call in browser console:
AmilyDatabin.getDebugChatId();
// Expected output: [Amily-Databin] Current Chat ID (Debug): "your_chat_id_here"
```
### `AmilyDatabin.getDebugCardId()`
Attempts to resolve the current character card ID using the same logic as the main API methods and logs it to the console.
```javascript
// Call in browser console:
AmilyDatabin.getDebugCardId();
// Expected output: [Amily-Databin] Current Character Card ID (Debug): "your_character_id_here"
```
## Developer
The main logic is located in `index.js` (server-side) and `public/client.js` (client-side). The plugin registers itself with SillyTavern's extension API.
You can interact with this plugin via the global `window.AmilyDatabin` object directly.

5
config.yaml Normal file
View File

@@ -0,0 +1,5 @@
name: "Amily-Databin"
author: "Silence_Lurker"
description: "A data bin extension for SillyTavern extension."
version: "1.0.0"
st_version: "1.11.0"

134
index.js Normal file
View File

@@ -0,0 +1,134 @@
const express = require('express');
const fs = require('fs').promises;
const path = require('path');
const {
plugins,
plugin_name_to_folder_name,
plugin_data_path,
} = require('../../../public/script.js');
const extensionName = "Amily-Databin";
const extensionVersion = "0.0.1-a";
const storageBasePath = path.join(plugin_data_path, 'cc.amily49.amily-databin');
let sourceTypes = {}; // Will be loaded from sourcetype.json
/**
* Builds a safe file path and prevents path traversal attacks.
*/
function getSafeFilePath(source, objName, file) {
if (typeof source !== 'string' && typeof source !== 'number' || typeof objName !== 'string' || typeof file !== 'string') {
return null;
}
const sanitize = (part) => String(part).replace(/\.\./g, '').replace(/[/\]/g, '');
const safeSource = sanitize(source);
const safeObjName = sanitize(objName);
const safeFile = sanitize(file);
if (!safeSource || !safeObjName || !safeFile) return null;
return path.join(storageBasePath, safeSource, safeObjName, safeFile);
}
// #region Server-side Business Logic per SourceType
// These functions implement the "strategy" for each source type.
/** Generic save handler */
async function defaultSaveStrategy(filePath, data) {
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf8');
}
// #endregion
(async () => {
try {
// Load source types from the file on startup.
const sourceTypesRaw = await fs.readFile(path.join(__dirname, 'sourcetype.json'), 'utf8');
sourceTypes = JSON.parse(sourceTypesRaw);
// Ensure the base storage directory exists.
await fs.mkdir(storageBasePath, { recursive: true });
} catch (error) {
console.error(`[${extensionName}] Critical startup error:`, error);
return; // Stop loading the plugin
}
const router = express.Router();
// Endpoint to serve the source type map to the client
router.get('/sourcetype', (req, res) => {
res.json(sourceTypes);
});
router.get('/data', async (req, res) => {
const filePath = getSafeFilePath(req.query.source, req.query.objName, req.query.file);
if (!filePath) return res.status(400).send("Invalid parameters.");
try {
const fileContent = await fs.readFile(filePath, 'utf8');
res.json(JSON.parse(fileContent));
} catch (error) {
if (error.code === 'ENOENT') return res.status(404).send('Not found.');
console.error(`[${extensionName}] Error reading file ${filePath}:`, error);
res.status(500).send('Internal Server Error');
}
});
router.post('/data', async (req, res) => {
const { source, objName, file, data } = req.body;
const filePath = getSafeFilePath(source, objName, file);
if (!filePath) return res.status(400).send("Invalid parameters.");
if (data === undefined) return res.status(400).send("'data' is required.");
const sourceType = parseInt(source, 10);
try {
// Strategy pattern based on source type
switch (sourceType) {
case sourceTypes.CHAT_LOG:
case sourceTypes.CHARACTER_CARD:
case sourceTypes.WORLD_BOOK:
// For now, all implemented types use the default save strategy.
await defaultSaveStrategy(filePath, data);
res.status(200).send('Data saved successfully.');
break;
default:
// If the source type is known but not implemented, or unknown.
res.status(501).send(`Save handler for source type '${sourceType}' is not implemented.`);
break;
}
} catch (error) {
console.error(`[${extensionName}] Error in POST /data for source ${sourceType}:`, error);
res.status(500).send('Internal Server Error');
}
});
router.delete('/data', async (req, res) => {
const filePath = getSafeFilePath(req.query.source, req.query.objName, req.query.file);
if (!filePath) return res.status(400).send("Invalid parameters.");
try {
await fs.unlink(filePath);
res.status(200).send('Data deleted successfully.');
} catch (error) {
if (error.code === 'ENOENT') return res.status(200).send('Not found.');
console.error(`[${extensionName}] Error deleting file ${filePath}:`, error);
res.status(500).send('Internal Server Error');
}
});
plugins[extensionName] = {
name: extensionName,
version: extensionVersion,
is_enabled: true,
folder_name: plugin_name_to_folder_name[extensionName],
router: router,
assets: ['client.js'],
};
console.log(`[${extensionName}] version ${extensionVersion} loaded. Storage path: ${storageBasePath}`);
})();

7
manifest.json Normal file
View File

@@ -0,0 +1,7 @@
{
"name": "Amily-Databin",
"author": "Amily",
"version": "0.0.1-a",
"description": "A SillyTavern plugin for data management.",
"entry": "index.js"
}

14
package.json Normal file
View File

@@ -0,0 +1,14 @@
{
"name": "amily-databin",
"version": "0.0.1-a",
"description": "A SillyTavern plugin for data management.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"SillyTavern"
],
"author": "Amily",
"license": "ISC"
}

173
public/client.js Normal file
View File

@@ -0,0 +1,173 @@
(function() {
const extensionName = "Amily-Databin";
const apiBaseUrl = `/api/plugins/${extensionName}`;
// ----------------------------------------------------------------
// Private Helper Functions
// ----------------------------------------------------------------
/**
* Retrieves the current context from SillyTavern and maps it to the expected object name.
* This function attempts to get context dynamically from SillyTavern's global objects.
*/
function _getDynamicObjectName(source) {
const { SillyTavern } = window;
let context = null;
if (SillyTavern && typeof SillyTavern.getContext === 'function') {
context = SillyTavern.getContext();
} else {
console.error(`[${extensionName}] window.SillyTavern.getContext() not found. Dynamic context resolution is not possible.`);
return null;
}
if (!context) {
console.error(`[${extensionName}] SillyTavern context is null or undefined.`);
return null;
}
let resolvedObjectName = null;
switch (source) {
case AmilyDatabin.SourceType.CHAT_LOG:
resolvedObjectName = context.chatId;
break;
case AmilyDatabin.SourceType.CHARACTER_CARD:
resolvedObjectName = context.characterId;
break;
case AmilyDatabin.SourceType.WORLD_BOOK:
// From the provided getContext() structure, there is no direct 'current world book name' key.
// The user must provide objName for WORLD_BOOK type, or implement custom logic to detect it.
console.warn(`[${extensionName}] 'WORLD_BOOK' type's object name cannot be automatically resolved from SillyTavern.getContext(). Please provide 'objName' explicitly.`);
break;
default:
console.error(`[${extensionName}] Unknown source type for dynamic resolution: ${source}`);
return null;
}
if (!resolvedObjectName) {
console.warn(`[${extensionName}] Could not dynamically resolve object name for source type ${source}. Context key might be missing or not active.`);
}
return resolvedObjectName;
}
// ----------------------------------------------------------------
// Public API Method Implementations
// ----------------------------------------------------------------
async function initialize() {
try {
const response = await fetch(`${apiBaseUrl}/sourcetype`);
if (!response.ok) throw new Error(`Failed to fetch source types: ${response.status}`);
this.SourceType = await response.json(); // 'this' refers to AmilyDatabin object
console.log(`[${extensionName}] Client initialized with source types:`, this.SourceType);
} catch (error) {
console.error(`[${extensionName}] Initialization failed:`, error);
}
}
async function getData(source, fileName, objName = null) {
const objectName = objName ?? _getDynamicObjectName(source);
if (!objectName) {
console.error(`[${extensionName}] 'objName' could not be resolved for getData (Source: ${source}, File: ${fileName}).`);
return null;
}
try {
const queryParams = new URLSearchParams({ source, objName: objectName, file: fileName });
const response = await fetch(`${apiBaseUrl}/data?${queryParams.toString()}`);
if (response.status === 404) return null;
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return await response.json();
} catch (error) {
console.error(`[${extensionName}] getData failed (Source: ${source}, ObjName: ${objectName}, File: ${fileName}):`, error);
return null;
}
}
async function saveData(source, fileName, fileContent, objName = null) {
const objectName = objName ?? _getDynamicObjectName(source);
if (!objectName) {
console.error(`[${extensionName}] 'objName' could not be resolved for saveData (Source: ${source}, File: ${fileName}).`);
return false;
}
try {
const response = await fetch(`${apiBaseUrl}/data`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ source, objName: objectName, file: fileName, data: fileContent }),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
}
console.log(`[${extensionName}] Data saved to: ${source}/${objectName}/${fileName}`);
return true;
} catch (error) {
console.error(`[${extensionName}] saveData failed (Source: ${source}, ObjName: ${objectName}, File: ${fileName}):`, error);
return false;
}
}
async function deleteData(source, fileName, objName = null) {
const objectName = objName ?? _getDynamicObjectName(source);
if (!objectName) {
console.error(`[${extensionName}] 'objName' could not be resolved for deleteData (Source: ${source}, File: ${fileName}).`);
return false;
}
try {
const queryParams = new URLSearchParams({ source, objName: objectName, file: fileName });
const response = await fetch(`${apiBaseUrl}/data?${queryParams.toString()}`, { method: 'DELETE' });
if (!response.ok) {
const errorText = await response.text();
throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
}
console.log(`[${extensionName}] Data deleted from: ${source}/${objectName}/${fileName}`);
return true;
} catch (error) {
console.error(`[${extensionName}] deleteData failed (Source: ${source}, ObjName: ${objectName}, File: ${fileName}):`, error);
return false;
}
}
// ----------------------------------------------------------------
// Debug Methods
// ----------------------------------------------------------------
function getDebugInstance() {
console.log(`[${extensionName}] AmilyDatabin Instance:`, AmilyDatabin);
return AmilyDatabin;
}
function getDebugChatId() {
const chatId = _getDynamicObjectName(AmilyDatabin.SourceType.CHAT_LOG);
console.log(`[${extensionName}] Current Chat ID (Debug):`, chatId);
return chatId;
}
function getDebugCardId() {
const cardId = _getDynamicObjectName(AmilyDatabin.SourceType.CHARACTER_CARD);
console.log(`[${extensionName}] Current Character Card ID (Debug):`, cardId);
return cardId;
}
// ----------------------------------------------------------------
// Global Object Definition
// ----------------------------------------------------------------
const AmilyDatabin = {
SourceType: {},
initialize,
getData,
saveData,
deleteData,
// Debug methods
getDebugInstance,
getDebugChatId,
getDebugCardId
};
window.AmilyDatabin = AmilyDatabin;
// Automatically initialize the module.
window.AmilyDatabin.initialize.bind(window.AmilyDatabin)();
})();

161
showdisplay.tmp Normal file
View File

@@ -0,0 +1,161 @@
export function getContext() {
return {
accountStorage,
chat,
characters,
groups,
name1,
name2,
characterId: this_chid,
groupId: selected_group,
chatId: selected_group
? groups.find(x => x.id == selected_group)?.chat_id
: (characters[this_chid]?.chat),
getCurrentChatId,
getRequestHeaders,
reloadCurrentChat,
renameChat,
saveSettingsDebounced,
onlineStatus: online_status,
maxContext: Number(max_context),
chatMetadata: chat_metadata,
saveMetadataDebounced,
streamingProcessor,
eventSource,
eventTypes: event_types,
addOneMessage,
deleteLastMessage,
deleteMessage,
generate: Generate,
sendStreamingRequest,
sendGenerationRequest,
stopGeneration,
tokenizers,
getTextTokens,
/** @deprecated Use getTokenCountAsync instead */
getTokenCount,
getTokenCountAsync,
extensionPrompts: extension_prompts,
setExtensionPrompt,
updateChatMetadata,
saveChat: saveChatConditional,
openCharacterChat,
openGroupChat,
saveMetadata,
sendSystemMessage,
activateSendButtons,
deactivateSendButtons,
saveReply,
substituteParams,
substituteParamsExtended,
SlashCommandParser,
SlashCommand,
SlashCommandArgument,
SlashCommandNamedArgument,
ARGUMENT_TYPE,
executeSlashCommandsWithOptions,
/** @deprecated Use SlashCommandParser.addCommandObject() instead */
registerSlashCommand,
/** @deprecated Use executeSlashCommandWithOptions instead */
executeSlashCommands,
timestampToMoment,
/** @deprecated Handlebars for extensions are no longer supported. */
registerHelper: () => { },
registerMacro: MacrosParser.registerMacro.bind(MacrosParser),
unregisterMacro: MacrosParser.unregisterMacro.bind(MacrosParser),
registerFunctionTool: ToolManager.registerFunctionTool.bind(ToolManager),
unregisterFunctionTool: ToolManager.unregisterFunctionTool.bind(ToolManager),
isToolCallingSupported: ToolManager.isToolCallingSupported.bind(ToolManager),
canPerformToolCalls: ToolManager.canPerformToolCalls.bind(ToolManager),
ToolManager,
registerDebugFunction,
/** @deprecated Use renderExtensionTemplateAsync instead. */
renderExtensionTemplate,
renderExtensionTemplateAsync,
registerDataBankScraper: ScraperManager.registerDataBankScraper.bind(ScraperManager),
/** @deprecated Use callGenericPopup or Popup instead. */
callPopup,
callGenericPopup,
showLoader,
hideLoader,
mainApi: main_api,
extensionSettings: extension_settings,
ModuleWorkerWrapper,
getTokenizerModel,
generateQuietPrompt,
generateRaw,
writeExtensionField,
getThumbnailUrl,
selectCharacterById,
messageFormatting,
shouldSendOnEnter,
isMobile,
t,
translate,
getCurrentLocale,
addLocaleData,
tags,
tagMap: tag_map,
menuType: menu_type,
createCharacterData: create_save,
/** @deprecated Legacy snake-case naming, compatibility with old extensions */
event_types: event_types,
Popup,
POPUP_TYPE,
POPUP_RESULT,
chatCompletionSettings: oai_settings,
textCompletionSettings: textgenerationwebui_settings,
powerUserSettings: power_user,
getCharacters,
getCharacterCardFields,
uuidv4,
humanizedDateTime,
updateMessageBlock,
appendMediaToMessage,
ensureMessageMediaIsArray,
getMediaDisplay,
getMediaIndex,
swipe: {
left: swipe_left,
right: swipe_right,
show: showSwipeButtons,
hide: hideSwipeButtons,
refresh: refreshSwipeButtons,
isAllowed: () => isSwipingAllowed,
},
variables: {
local: {
get: getLocalVariable,
set: setLocalVariable,
},
global: {
get: getGlobalVariable,
set: setGlobalVariable,
},
},
loadWorldInfo,
saveWorldInfo,
reloadWorldInfoEditor: reloadEditor,
updateWorldInfoList,
convertCharacterBook,
getWorldInfoPrompt,
CONNECT_API_MAP,
getTextGenServer,
extractMessageFromData,
getPresetManager,
getChatCompletionModel,
printMessages,
clearChat,
ChatCompletionService,
TextCompletionService,
ConnectionManagerRequestService,
updateReasoningUI,
parseReasoningFromString,
unshallowCharacter,
unshallowGroupMembers,
openThirdPartyExtensionMenu,
symbols: {
ignore: IGNORE_SYMBOL,
},
};
}

5
sourcetype.json Normal file
View File

@@ -0,0 +1,5 @@
{
"CHAT_LOG": 1,
"CHARACTER_CARD": 2,
"WORLD_BOOK": 3
}