Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/ts/cbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ export function registerCBS(arg:CBSRegisterArg) {
}))
},
alias: ['worldinfo'],
description: 'Returns all active lorebook entries as a JSON array. Combines character lorebook, chat-specific lorebook, and module lorebooks. Each entry is JSON.stringify\'d.\n\nUsage:: {{lorebook}}',
description: 'Returns all lorebook entries as a JSON array. Combines character lorebook, chat-specific lorebook, and module lorebooks. Each entry is JSON.stringify\'d.\n\nUsage:: {{lorebook}}',
});

registerFunction({
Expand Down Expand Up @@ -2366,5 +2366,11 @@ Usage:: {{#when condition}}...{{/when}} or {{#when::not::condition}}...{{/when}}
description: 'Defines the position which can be used in various features such as @@position <positionName> decorator.\n\nUsage:: {{position::positionName}}',
})

registerFunction({
name: 'loreinject',
callback: 'doc_only',
alias: ['lore_inject'],
description: 'Injects content from lorebook entries that have @@inject_at decorators matching the specified target name. Searches through active lorebooks for entries with @@inject_at <targetName> decorator and returns their content. Only works with lorebooks that are currently active based on their keywords.\n\nUsage:: {{loreinject::targetName}}\n\nExample:\nLorebook entry with "@@inject_at myTarget" at the beginning will be injected when using {{loreinject::myTarget}}',
})

}
76 changes: 65 additions & 11 deletions src/ts/process/index.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,60 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}

const lorepmt = await loadLoreBookV3Prompt()

const loreinjectRegex = /{{(?:loreinject|lore_inject)::(.+?)}}/g

const loreinjectParser = (text: string, processedTargets: Set<string> = new Set()): string => {
let hasMoreInjects = true
let result = text
let iterationCount = 0
const maxIterations = 100

while (hasMoreInjects && iterationCount < maxIterations) {
hasMoreInjects = false
iterationCount++

result = result.replace(loreinjectRegex, (match, targetName) => {
if (!targetName || targetName.trim() === '') {
return ''
}

// Avoiding infinite recursion
if (processedTargets.has(targetName)) {
return ''
}

// find inject.operation == 'insert' && inject.location == {targetName}
const matchingLorebooks = lorepmt.actives.filter(v => {
return v.inject && v.inject.operation === 'insert' && v.inject.location === targetName
})

// return matching lorebooks
if (matchingLorebooks.length > 0) {
const newProcessedTargets = new Set(processedTargets)
newProcessedTargets.add(targetName)

const processedPrompts = matchingLorebooks.map(v => {
return loreinjectParser(v.prompt, newProcessedTargets)
})

const joined = processedPrompts.join('\n')
if (loreinjectRegex.test(joined)) {
hasMoreInjects = true
}

return joined
}

return ''
})

loreinjectRegex.lastIndex = 0
}

return result
}

const normalActives = lorepmt.actives.filter(v => {
return v.pos === '' && v.inject === null
})
Expand All @@ -477,18 +531,18 @@ export async function sendChat(chatProcessIndex = -1,arg:{
for(const lorebook of normalActives){
unformated.lorebook.push({
role: lorebook.role,
content: risuChatParser(lorebook.prompt, {chara: currentChar})
content: risuChatParser(loreinjectParser(lorebook.prompt), {chara: currentChar})
})
}

const descActives = lorepmt.actives.filter(v => {
return v.pos === 'after_desc' || v.pos === 'before_desc' || v.pos === 'personality' || v.pos === 'scenario'
return (v.pos === 'after_desc' || v.pos === 'before_desc' || v.pos === 'personality' || v.pos === 'scenario') && v.inject === null
})

for(const lorebook of descActives){
const c = {
role: lorebook.role,
content: risuChatParser(lorebook.prompt, {chara: currentChar})
content: risuChatParser(loreinjectParser(lorebook.prompt), {chara: currentChar})
}
if(lorebook.pos === 'before_desc'){
unformated.description.unshift(c)
Expand Down Expand Up @@ -521,18 +575,18 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}

const postEverythingLorebooks = lorepmt.actives.filter(v => {
return v.pos === 'depth' && v.depth === 0 && v.role !== 'assistant'
return v.pos === 'depth' && v.depth === 0 && v.role !== 'assistant' && v.inject === null
})
for(const lorebook of postEverythingLorebooks){
unformated.postEverything.push({
role: lorebook.role,
content: risuChatParser(lorebook.prompt, {chara: currentChar})
content: risuChatParser(loreinjectParser(lorebook.prompt), {chara: currentChar})
})
}

//Since assistant needs to be prefill, we need to add assistant lorebooks after user/system lorebooks
const postEverythingAssistantLorebooks = lorepmt.actives.filter(v => {
return v.pos === 'depth' && v.depth === 0 && v.role === 'assistant'
return v.pos === 'depth' && v.depth === 0 && v.role === 'assistant' && v.inject === null
})

const injectionLorebooks = lorepmt.actives.filter(v => {
Expand All @@ -547,7 +601,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
for(const lorebook of postEverythingAssistantLorebooks){
unformated.postEverything.push({
role: lorebook.role,
content: risuChatParser(lorebook.prompt, {chara: currentChar})
content: risuChatParser(loreinjectParser(lorebook.prompt), {chara: currentChar})
})
}

Expand Down Expand Up @@ -952,13 +1006,13 @@ export async function sendChat(chatProcessIndex = -1,arg:{
console.log(JSON.stringify(chats, null, 2))

const depthPrompts = lorepmt.actives.filter(v => {
return (v.pos === 'depth' && v.depth > 0) || v.pos === 'reverse_depth'
return ((v.pos === 'depth' && v.depth > 0) || v.pos === 'reverse_depth') && v.inject === null
})

for(const depthPrompt of depthPrompts){
const chat:OpenAIChat = {
role: depthPrompt.role,
content: risuChatParser(depthPrompt.prompt, {chara: currentChar})
content: risuChatParser(loreinjectParser(depthPrompt.prompt), {chara: currentChar})

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find what 'depthPrompt' work. AI said it is character's system prompt and need to use 'loreinjectParser', but well.. I'm not sure.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whatever depthPrompt is, there will be no errors in depthPrompt caused by 'loreinjectParser'.

}
currentTokens += await tokenizer.tokenizeChat(chat)
}
Expand Down Expand Up @@ -1086,7 +1140,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
for(const depthPrompt of depthPrompts){
const chat:OpenAIChat = {
role: depthPrompt.role,
content: risuChatParser(depthPrompt.prompt, {chara: currentChar})
content: risuChatParser(loreinjectParser(depthPrompt.prompt), {chara: currentChar})
}
const depth = depthPrompt.pos === 'depth' ? (depthPrompt.depth) : (unformated.chats.length - depthPrompt.depth)
unformated.chats.splice(depth,0,chat)
Expand Down Expand Up @@ -1387,7 +1441,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
const depthPrompt = currentChar.depth_prompt
formated.splice(formated.length - depthPrompt.depth, 0, {
role: 'system',
content: risuChatParser(depthPrompt.prompt, {chara: currentChar})
content: risuChatParser(loreinjectParser(depthPrompt.prompt), {chara: currentChar})
})
}

Expand Down
7 changes: 4 additions & 3 deletions src/ts/process/lorebook.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ export async function loadLoreBookV3Prompt(){
priority:number
source:string
inject:{
operation:'append'|'prepend'|'replace',
operation:'append'|'prepend'|'replace'|'insert',
location:string,
param:string
lore:boolean
Expand All @@ -255,7 +255,7 @@ export async function loadLoreBookV3Prompt(){
let activated = true
let pos = ''
let inject:{
operation:'append'|'prepend'|'replace',
operation:'append'|'prepend'|'replace'|'insert',
location:string,
param:string
lore:boolean
Expand Down Expand Up @@ -392,11 +392,12 @@ export async function loadLoreBookV3Prompt(){
}
case 'inject_at':{
inject??= {
operation: 'append',
operation: 'insert',
location: '',
param: '',
lore: false
}
inject.operation = 'insert'
inject.location = arg.join(' ')
inject.lore = false
return
Expand Down