|
import { chat_metadata, characters, substituteParams, chat, extension_prompt_roles, extension_prompt_types, name2, neutralCharacterName } from '../../script.js'; |
|
import { extension_settings } from '../extensions.js'; |
|
import { getGroupMembers, groups } from '../group-chats.js'; |
|
import { power_user } from '../power-user.js'; |
|
import { searchCharByName, getTagsList, tags, tag_map } from '../tags.js'; |
|
import { onlyUniqueJson, sortIgnoreCaseAndAccents } from '../utils.js'; |
|
import { world_names } from '../world-info.js'; |
|
import { SlashCommandClosure } from './SlashCommandClosure.js'; |
|
import { SlashCommandEnumValue, enumTypes } from './SlashCommandEnumValue.js'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const enumIcons = { |
|
default: '◊', |
|
|
|
|
|
variable: '𝑥', |
|
localVariable: 'L', |
|
globalVariable: 'G', |
|
scopeVariable: 'S', |
|
|
|
|
|
character: '👤', |
|
group: '🧑🤝🧑', |
|
persona: '🧙♂️', |
|
qr: 'QR', |
|
closure: '𝑓', |
|
macro: '{{', |
|
tag: '🏷️', |
|
world: '🌐', |
|
preset: '⚙️', |
|
file: '📄', |
|
message: '💬', |
|
reasoning: '💡', |
|
voice: '🎤', |
|
server: '🖥️', |
|
popup: '🗔', |
|
image: '🖼️', |
|
|
|
true: '✔️', |
|
false: '❌', |
|
null: '🚫', |
|
undefined: '❓', |
|
|
|
|
|
boolean: '🔲', |
|
string: '📝', |
|
number: '1️⃣', |
|
array: '[]', |
|
enum: '📚', |
|
dictionary: '{}', |
|
|
|
|
|
system: '⚙️', |
|
user: '👤', |
|
assistant: '🤖', |
|
|
|
|
|
constant: '🔵', |
|
normal: '🟢', |
|
disabled: '❌', |
|
vectorized: '🔗', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getStateIcon: (state) => { |
|
return state ? enumIcons.true : enumIcons.false; |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getWiStatusIcon: (entry) => { |
|
if (entry.constant) return enumIcons.constant; |
|
if (entry.disable) return enumIcons.disabled; |
|
if (entry.vectorized) return enumIcons.vectorized; |
|
return enumIcons.normal; |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getRoleIcon: (role) => { |
|
switch (role) { |
|
case extension_prompt_roles.SYSTEM: return enumIcons.system; |
|
case extension_prompt_roles.USER: return enumIcons.user; |
|
case extension_prompt_roles.ASSISTANT: return enumIcons.assistant; |
|
default: return enumIcons.default; |
|
} |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getDataTypeIcon: (type) => { |
|
|
|
type = type.replace(/\?$/, ''); |
|
return enumIcons[type] ?? enumIcons.default; |
|
}, |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
export const commonEnumProviders = { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean: (mode = 'trueFalse') => () => { |
|
switch (mode) { |
|
case 'onOff': return [new SlashCommandEnumValue('on', null, 'macro', enumIcons.true), new SlashCommandEnumValue('off', null, 'macro', enumIcons.false)]; |
|
case 'onOffToggle': return [new SlashCommandEnumValue('on', null, 'macro', enumIcons.true), new SlashCommandEnumValue('off', null, 'macro', enumIcons.false), new SlashCommandEnumValue('toggle', null, 'macro', enumIcons.boolean)]; |
|
case 'trueFalse': return [new SlashCommandEnumValue('true', null, 'macro', enumIcons.true), new SlashCommandEnumValue('false', null, 'macro', enumIcons.false)]; |
|
default: throw new Error(`Invalid boolean enum provider mode: ${mode}`); |
|
} |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
variables: (...type) => (_, scope) => { |
|
const types = type.flat(); |
|
const isAll = types.includes('all'); |
|
return [ |
|
...isAll || types.includes('scope') ? scope.allVariableNames.map(name => new SlashCommandEnumValue(name, null, enumTypes.variable, enumIcons.scopeVariable)) : [], |
|
...isAll || types.includes('local') ? Object.keys(chat_metadata.variables ?? []).map(name => new SlashCommandEnumValue(name, null, enumTypes.name, enumIcons.localVariable)) : [], |
|
...isAll || types.includes('global') ? Object.keys(extension_settings.variables.global ?? []).map(name => new SlashCommandEnumValue(name, null, enumTypes.macro, enumIcons.globalVariable)) : [], |
|
].filter((item, idx, list)=>idx == list.findIndex(it=>it.value == item.value)); |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
numbersAndVariables: (executor, scope) => [ |
|
...commonEnumProviders.variables('all')(executor, scope), |
|
new SlashCommandEnumValue( |
|
'any variable name', |
|
null, |
|
enumTypes.variable, |
|
enumIcons.variable, |
|
(input) => /^\w*$/.test(input), |
|
(input) => input, |
|
), |
|
new SlashCommandEnumValue( |
|
'any number', |
|
null, |
|
enumTypes.number, |
|
enumIcons.number, |
|
(input) => input == '' || !Number.isNaN(Number(input)), |
|
(input) => input, |
|
), |
|
], |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
characters: (mode = 'all') => () => { |
|
return [ |
|
...['all', 'character'].includes(mode) ? characters.map(char => new SlashCommandEnumValue(char.name, null, enumTypes.name, enumIcons.character)) : [], |
|
...['all', 'group'].includes(mode) ? groups.map(group => new SlashCommandEnumValue(group.name, null, enumTypes.qr, enumIcons.group)) : [], |
|
...(name2 === neutralCharacterName) ? [new SlashCommandEnumValue(neutralCharacterName, null, enumTypes.name, '🥸')] : [], |
|
]; |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
groupMembers: (groupId = undefined) => () => getGroupMembers(groupId).map((character, index) => new SlashCommandEnumValue(String(index), character.name, enumTypes.enum, enumIcons.character)), |
|
|
|
|
|
|
|
|
|
|
|
|
|
personas: () => Object.values(power_user.personas).map(persona => new SlashCommandEnumValue(persona, null, enumTypes.name, enumIcons.persona)), |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tags: (mode = 'all') => () => { |
|
let assignedTags = mode === 'assigned' ? new Set(Object.values(tag_map).flat()) : new Set(); |
|
return tags.filter(tag => mode === 'all' || (mode === 'assigned' && assignedTags.has(tag.id))) |
|
.map(tag => new SlashCommandEnumValue(tag.name, null, enumTypes.command, enumIcons.tag)); |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tagsForChar: (mode = 'all') => ( executor) => { |
|
|
|
const charName = executor.namedArgumentList.find(it => it.name == 'name')?.value; |
|
if (charName instanceof SlashCommandClosure) throw new Error('Argument \'name\' does not support closures'); |
|
const key = searchCharByName(substituteParams(charName), { suppressLogging: true }); |
|
const assigned = key ? getTagsList(key) : []; |
|
return tags.filter(it => mode === 'all' || mode === 'existing' && assigned.includes(it) || mode === 'not-existing' && !assigned.includes(it)) |
|
.map(tag => new SlashCommandEnumValue(tag.name, null, enumTypes.command, enumIcons.tag)); |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
messages: ({ allowIdAfter = false, allowVars = false } = {}) => (executor, scope) => { |
|
const nameFilter = executor.namedArgumentList.find(it => it.name == 'name')?.value || ''; |
|
return [ |
|
...chat.map((message, index) => new SlashCommandEnumValue(String(index), `${message.name}: ${message.mes}`, enumTypes.number, message.is_user ? enumIcons.user : message.is_system ? enumIcons.system : enumIcons.assistant)).filter(value => !nameFilter || value.description.startsWith(`${nameFilter}:`)), |
|
...allowIdAfter ? [new SlashCommandEnumValue(String(chat.length), '>> After Last Message >>', enumTypes.enum, '➕')] : [], |
|
...allowVars ? commonEnumProviders.variables('all')(executor, scope) : [], |
|
]; |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
messageNames: () => chat |
|
.map(message => ({ |
|
name: message.name, |
|
icon: message.is_user ? enumIcons.user : enumIcons.assistant, |
|
})) |
|
.filter(onlyUniqueJson) |
|
.sort((a, b) => sortIgnoreCaseAndAccents(a.name, b.name)) |
|
.map(name => new SlashCommandEnumValue(name.name, null, null, name.icon)), |
|
|
|
|
|
|
|
|
|
|
|
|
|
worlds: () => world_names.map(worldName => new SlashCommandEnumValue(worldName, null, enumTypes.name, enumIcons.world)), |
|
|
|
|
|
|
|
|
|
|
|
|
|
injects: () => { |
|
if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) return []; |
|
return Object.entries(chat_metadata.script_injects) |
|
.map(([id, inject]) => { |
|
const positionName = (Object.entries(extension_prompt_types)).find(([_, value]) => value === inject.position)?.[0] ?? 'unknown'; |
|
return new SlashCommandEnumValue(id, `${enumIcons.getRoleIcon(inject.role ?? extension_prompt_roles.SYSTEM)}[Inject](${positionName}, depth: ${inject.depth}, scan: ${inject.scan ?? false}) ${inject.value}`, |
|
enumTypes.enum, '💉'); |
|
}); |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
types: () => [ |
|
new SlashCommandEnumValue('string', null, enumTypes.type, enumIcons.string), |
|
new SlashCommandEnumValue('number', null, enumTypes.type, enumIcons.number), |
|
new SlashCommandEnumValue('boolean', null, enumTypes.type, enumIcons.boolean), |
|
new SlashCommandEnumValue('array', null, enumTypes.type, enumIcons.array), |
|
new SlashCommandEnumValue('object', null, enumTypes.type, enumIcons.dictionary), |
|
new SlashCommandEnumValue('null', null, enumTypes.type, enumIcons.null), |
|
new SlashCommandEnumValue('undefined', null, enumTypes.type, enumIcons.undefined), |
|
], |
|
}; |
|
|