diff --git a/common/prompt.ts b/common/prompt.ts index 63127473b..02c2b44dd 100644 --- a/common/prompt.ts +++ b/common/prompt.ts @@ -422,10 +422,6 @@ export async function buildPromptParts( const post = createPostPrompt(opts) - if (opts.continue) { - post.unshift(`${char.name}: ${opts.continue}`) - } - const linesForMemory = [...lines].reverse() const books: AppSchema.MemoryBook[] = [] if (replyAs.characterBook) books.push(replyAs.characterBook) diff --git a/common/template-parser.ts b/common/template-parser.ts index 07f03f914..f931e4746 100644 --- a/common/template-parser.ts +++ b/common/template-parser.ts @@ -138,7 +138,30 @@ export async function parseTemplate( parts.ujb = render(parts.ujb, opts) } - const ast = parser.parse(template, {}) as PNode[] + let ast = parser.parse(template, {}) as PNode[] + + /** + * Continuing the previous message: + * In this case our goal is to end the prompt as close to the + * last message as possible. + */ + if (opts.continue) { + const historyIndex = ast.findIndex( + (node) => + typeof node !== 'string' && + ((node.kind === 'placeholder' && node.value === 'history') || + (node.kind === 'each' && node.value === 'history')) + ) + if (historyIndex !== -1) { + const node = ast[historyIndex] as PlaceHolder | IteratorNode + // replace iterator with normalized history + if (node.kind === 'each' && node.value === 'history') { + ast[historyIndex] = { kind: 'placeholder', value: 'history' } as PlaceHolder + } + ast = ast.slice(0, historyIndex + 1) + } + } + readInserts(opts, ast) let output = render(template, opts, ast) let unusedTokens = 0 diff --git a/common/util.ts b/common/util.ts index 521b44144..24ecc992e 100644 --- a/common/util.ts +++ b/common/util.ts @@ -175,6 +175,15 @@ export function trimSentence(text: string) { return index === -1 ? text.trimEnd() : text.slice(0, index + 1).trimEnd() } +export function concatenateSentence(text: string, next: string) { + if (!text || !next) return `${text}${next}` + if (next.startsWith('\n')) { + return `${text.trimEnd()}\n${next.trimStart()}` + } + + return `${text.trimEnd()}${next}` +} + export function slugify(str: string) { return str .toLowerCase() diff --git a/srv/api/chat/message.ts b/srv/api/chat/message.ts index 120bdac4d..d812f1590 100644 --- a/srv/api/chat/message.ts +++ b/srv/api/chat/message.ts @@ -9,6 +9,7 @@ import { v4 } from 'uuid' import { Response } from 'express' import { publishMany } from '../ws/handle' import { getScenarioEventType } from '/common/scenario' +import { concatenateSentence } from '/common/util' type GenRequest = UnwrapBody @@ -331,7 +332,9 @@ export const generateMessageV2 = handle(async (req, res) => { return } - const responseText = body.kind === 'continue' ? `${body.continuing.msg} ${generated}` : generated + const responseText = + body.kind === 'continue' ? concatenateSentence(body.continuing.msg, generated) : generated + const actions: AppSchema.ChatAction[] = [] switch (body.kind) { @@ -568,7 +571,8 @@ async function handleGuestGenerate(body: GenRequest, req: AppRequest, res: Respo if (error) return - const responseText = body.kind === 'continue' ? `${body.continuing.msg} ${generated}` : generated + const responseText = + body.kind === 'continue' ? concatenateSentence(body.continuing.msg, generated) : generated const characterId = body.kind === 'self' ? undefined : body.replyAs?._id || body.char?._id const senderId = body.kind === 'self' ? 'anon' : undefined diff --git a/tests/__snapshots__/prompt.spec.js.snap b/tests/__snapshots__/prompt.spec.js.snap index f05e4c982..8ccc1ccb6 100644 --- a/tests/__snapshots__/prompt.spec.js.snap +++ b/tests/__snapshots__/prompt.spec.js.snap @@ -32,7 +32,6 @@ How MainChar speaks: SAMPLECHAT MainChar MainChar: FIRST -MainChar: ORIGINAL MainChar:" `; @@ -99,7 +98,6 @@ Scenario: MAIN MainChar This is how OtherBot should talk: SAMPLECHAT OtherBot MainChar: FIRST ChatOwner: SECOND -MainChar: ORIGINAL OtherBot:" `; @@ -165,7 +163,6 @@ SAMPLECHAT OtherBot System: New conversation started. Previous conversations are examples only. MainChar: FIRST ChatOwner: SECOND -MainChar: ORIGINAL OtherBot:" `;