Skip to content

Commit 62ad0b4

Browse files
authored
Editable sequence breakers (#1092)
- gemini 2.0 flash - fix image model receive for reel - add dry sequence breakers to ui - openai chat format using prompt templates
1 parent 4a6ec0d commit 62ad0b4

21 files changed

+246
-90
lines changed

.vscode/tasks.json

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
{
22
"version": "2.0.0",
33
"tasks": [
4-
{
5-
"type": "typescript",
6-
"tsconfig": "tsconfig.json",
7-
"option": "watch",
8-
"problemMatcher": ["$tsc-watch"],
9-
"group": {
10-
"kind": "build",
11-
"isDefault": true
12-
},
13-
"isBackground": true,
14-
"label": "tsc: watch - tsconfig.json"
15-
},
4+
// {
5+
// "type": "typescript",
6+
// "tsconfig": "tsconfig.json",
7+
// "option": "watch",
8+
// "problemMatcher": ["$tsc-watch"],
9+
// "group": {
10+
// "kind": "build",
11+
// "isDefault": true
12+
// },
13+
// "isBackground": true,
14+
// "label": "tsc: watch - tsconfig.json"
15+
// },
1616
{
1717
"type": "typescript",
1818
"tsconfig": "srv.tsconfig.json",
@@ -27,13 +27,13 @@
2727
{
2828
"type": "shell",
2929
"command": "pnpm",
30-
"args": ["tsc", "-p", "tsconfig.json", "--noEmit"],
30+
"args": ["tsc", "-p", "tsconfig.json", "--noEmit", "-w"],
3131
"problemMatcher": "$tsc-watch",
3232
"label": "tsc: watch no-emit",
3333
"isBackground": true,
3434
"group": {
3535
"kind": "build",
36-
"isDefault": false
36+
"isDefault": true
3737
}
3838
}
3939
]

common/adapters.ts

+4
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export const JSON_SCHEMA_SUPPORTED: { [key in AIAdapter | ThirdPartyFormat]?: bo
8585
export const THIRDPARTY_HANDLERS: { [svc in ThirdPartyFormat]: AIAdapter } = {
8686
openai: 'openai',
8787
'openai-chat': 'openai',
88+
'openai-chatv2': 'openai',
8889
claude: 'claude',
8990
aphrodite: 'kobold',
9091
exllamav2: 'kobold',
@@ -109,6 +110,7 @@ export const THIRDPARTY_FORMATS = [
109110
'kobold',
110111
'openai',
111112
'openai-chat',
113+
'openai-chatv2',
112114
'claude',
113115
'ooba',
114116
'llamacpp',
@@ -277,13 +279,15 @@ export const GOOGLE_MODELS = {
277279
GEMINI_15_FLASH_002: { id: 'gemini-1.5-flash-002', label: 'Gemini 1.5 Flash 002' },
278280
GEMINI_15_FLASH_8B: { id: 'gemini-1.5-flash-8b', label: 'Gemini 1.5 Flash 8B' },
279281
GEMINI_EXP_1114: { id: 'gemini-exp-1114', label: 'Gemini Exp 1114' },
282+
GEMINI_20_FLASH: { id: 'gemini-2.0-flash-exp', label: 'Gemini 2.0 Flash' },
280283
}
281284

282285
export const GOOGLE_LIMITS: Record<string, number> = {
283286
'gemini-1.5-pro': 2097152,
284287
'gemini-1.0-pro-latest': 32768,
285288
'gemini-1.5-flash': 1048576,
286289
'gemini-1.5-flash-8b': 1048576,
290+
'gemini-2.0-flash-exp': 1048576,
287291
}
288292

289293
/** Note: claude-v1 and claude-instant-v1 not included as they may point

common/prompt-order.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ export function promptOrderToSections(opts: OrderOptions) {
4747
? formatHolders[opts.format] || formatHolders.Universal
4848
: formatHolders.Universal
4949

50-
const system = holders.system
51-
const defs = order.map((o) => holders[o.placeholder]).join('\n')
50+
const system = holders.system_prompt || holders.system
51+
const defs = order.map((o) => getOrderHolder(opts.format!, o.placeholder)).join('\n')
5252
const history = holders.history
5353
const post = holders.post
5454

common/prompt.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ export async function createPromptParts(opts: PromptOpts, encoder: TokenCounter)
263263
return { lines: lines.reverse(), parts, template: prompt }
264264
}
265265

266+
export type AssembledPrompt = Awaited<ReturnType<typeof assemblePrompt>>
267+
266268
/**
267269
* This is only ever invoked server-side
268270
*
@@ -281,7 +283,7 @@ export async function assemblePrompt(
281283
const template = getTemplate(opts)
282284

283285
const history = { lines, order: 'asc' } as const
284-
let { parsed, inserts, length } = await injectPlaceholders(template, {
286+
let { parsed, inserts, length, sections } = await injectPlaceholders(template, {
285287
opts,
286288
parts,
287289
history,
@@ -291,7 +293,7 @@ export async function assemblePrompt(
291293
jsonValues: opts.jsonValues,
292294
})
293295

294-
return { lines: history.lines, prompt: parsed, inserts, parts, post, length }
296+
return { lines: history.lines, prompt: parsed, inserts, parts, post, length, sections }
295297
}
296298

297299
export function getTemplate(opts: Pick<GenerateRequestV2, 'settings' | 'chat'>) {

common/requests/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ function startRequest(request: GenerateRequestV2, prompt: string) {
6060
switch (request.settings!.thirdPartyFormat) {
6161
case 'openai':
6262
case 'openai-chat':
63+
case 'openai-chatv2':
6364
return handleOAI(opts, payload)
6465

6566
case 'aphrodite':

common/requests/openai.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ export async function* handleOAI(opts: PayloadOpts, payload: any) {
5454
}
5555

5656
const suffix = gen.thirdPartyUrl?.endsWith('/') ? '' : '/'
57-
const urlPath =
58-
gen.thirdPartyFormat === 'openai-chat' ? `${suffix}chat/completions` : `${suffix}completions`
57+
const urlPath = gen.thirdPartyFormat?.startsWith('openai-chat')
58+
? `${suffix}chat/completions`
59+
: `${suffix}completions`
5960
const fullUrl = `${gen.thirdPartyUrl}${urlPath}`
6061

6162
if (!gen.streamResponse) {

common/template-parser.ts

+26-11
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export type TemplateOpts = {
3838
sections?: {
3939
flags: { [key in Section]?: boolean }
4040
sections: { [key in Section]: string[] }
41+
done: boolean
4142
}
4243

4344
/**
@@ -184,6 +185,7 @@ export async function parseTemplate(
184185
const sections: TemplateOpts['sections'] = {
185186
flags: {},
186187
sections: { system: [], history: [], post: [] },
188+
done: false,
187189
}
188190

189191
opts.sections = sections
@@ -205,6 +207,7 @@ export async function parseTemplate(
205207
const ast = parser.parse(template, {}) as PNode[]
206208
readInserts(opts, ast)
207209
let output = render(template, opts, ast)
210+
opts.sections.done = true
208211
let unusedTokens = 0
209212
let linesAddedCount = 0
210213

@@ -333,16 +336,23 @@ function render(template: string, opts: TemplateOpts, existingAst?: PNode[]) {
333336
}
334337

335338
const output: string[] = []
339+
let prevMarker: Section = 'system'
336340

337341
for (let i = 0; i < ast.length; i++) {
338342
const parent = ast[i]
339343

340344
const result = renderNode(parent, opts)
341345

342-
const marker = getMarker(parent)
343-
fillSection(opts, marker, result)
346+
const marker = getMarker(opts, parent, prevMarker)
347+
prevMarker = marker
344348

345-
if (result) output.push(result)
349+
if (!opts.sections?.done) {
350+
fillSection(opts, marker, result)
351+
}
352+
353+
if (result) {
354+
output.push(result)
355+
}
346356
}
347357
return output.join('').replace(/\n\n+/g, '\n\n')
348358
} catch (err) {
@@ -623,6 +633,9 @@ function renderIterator(holder: IterableHolder, children: CNode[], opts: Templat
623633
if (isHistory && opts.limit?.output) {
624634
const id = HISTORY_MARKER
625635
opts.limit.output[id] = { src: holder, lines: output }
636+
if (opts.sections) {
637+
opts.sections.flags.history = true
638+
}
626639
return id
627640
}
628641

@@ -788,38 +801,40 @@ function fillSection(opts: TemplateOpts, marker: Section | undefined, result: st
788801
const flags = opts.sections.flags
789802
const sections = opts.sections.sections
790803

791-
if (!flags.system) {
804+
if (!flags.system && marker === 'system') {
792805
sections.system.push(result)
793806
return
794807
}
795808

796809
if (marker === 'history') {
797810
flags.system = true
798-
flags.history = true
799811
return
800812
}
801813

802814
sections.post.push(result)
803815
}
804816

805-
function getMarker(node: PNode): Section | undefined {
806-
if (typeof node === 'string') return
817+
function getMarker(opts: TemplateOpts, node: PNode, previous: Section): Section {
818+
if (!opts.sections) return previous
819+
if (opts.sections.flags.history) return 'post'
820+
821+
if (typeof node === 'string') return previous
807822

808823
switch (node.kind) {
809824
case 'placeholder': {
810825
if (node.value === 'history') return 'history'
811826
if (node.value === 'system_prompt') return 'system'
812-
return
827+
return previous
813828
}
814829

815830
case 'each':
816831
if (node.value === 'history') return 'history'
817-
return
832+
return previous
818833

819834
case 'if':
820835
if (node.value === 'system_prompt') return 'system'
821-
return
836+
return previous
822837
}
823838

824-
return
839+
return previous
825840
}

srv/adapter/agnaistic.ts

+1
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ export function getHandlers(settings: Partial<AppSchema.GenSettings>) {
423423
return handlers[settings.thirdPartyFormat!]
424424

425425
case 'openai-chat':
426+
case 'openai-chatv2':
426427
return handlers.openai
427428

428429
case 'featherless':

srv/adapter/generate.ts

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
import { getCachedSubscriptionModels } from '../db/subscriptions'
3535
import { sendOne } from '../api/ws'
3636
import { ResponseSchema } from '/common/types/library'
37+
import { toChatMessages } from './template-chat-payload'
3738

3839
let version = ''
3940

@@ -232,6 +233,7 @@ export async function createInferenceStream(opts: InferenceRequest) {
232233
guidance: opts.guidance,
233234
previous: opts.previous,
234235
placeholders: opts.placeholders,
236+
characters: {},
235237
lists: opts.lists,
236238
jsonSchema: opts.jsonSchema,
237239
imageData: opts.imageData,
@@ -392,6 +394,7 @@ export async function createChatStream(
392394
*/
393395

394396
const prompt = await assemblePrompt(opts, opts.parts, opts.lines, encoder)
397+
const messages = await toChatMessages(opts, prompt, encoder)
395398

396399
const size = encoder(
397400
[
@@ -421,6 +424,7 @@ export async function createChatStream(
421424
log,
422425
members: opts.members.concat(opts.sender),
423426
prompt: prompt.prompt,
427+
messages,
424428
parts: prompt.parts,
425429
sender: opts.sender,
426430
mappedSettings,

srv/adapter/openai.ts

+13-11
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { sanitiseAndTrim } from '/common/requests/util'
2-
import { ChatRole, CompletionItem, ModelAdapter } from './type'
2+
import { ChatRole, ModelAdapter } from './type'
33
import { defaultPresets } from '../../common/presets'
44
import { OPENAI_CHAT_MODELS, OPENAI_MODELS } from '../../common/adapters'
55
import { AppSchema } from '../../common/types/schema'
6-
import { config } from '../config'
76
import { AppLog } from '../middleware'
87
import { requestFullCompletion, toChatCompletionPayload } from './chat-completion'
98
import { decryptText } from '../db/util'
@@ -42,23 +41,26 @@ export const handleOAI: ModelAdapter = async function* (opts) {
4241
stream: (gen.streamResponse && kind !== 'summary') ?? defaultPresets.openai.streamResponse,
4342
temperature: gen.temp ?? defaultPresets.openai.temp,
4443
max_tokens: maxResponseLength,
44+
max_completion_tokens: maxResponseLength,
4545
top_p: gen.topP ?? 1,
4646
stop: [`\n${handle}:`].concat(gen.stopSequences!),
4747
}
4848

4949
body.presence_penalty = gen.presencePenalty ?? defaultPresets.openai.presencePenalty
5050
body.frequency_penalty = gen.frequencyPenalty ?? defaultPresets.openai.frequencyPenalty
5151

52-
const useChat =
53-
(isThirdParty && gen.thirdPartyFormat === 'openai-chat') || !!OPENAI_CHAT_MODELS[oaiModel]
52+
const isChatFormat =
53+
gen.thirdPartyFormat === 'openai-chat' || gen.thirdPartyFormat == 'openai-chatv2'
54+
const useChat = (isThirdParty && isChatFormat) || !!OPENAI_CHAT_MODELS[oaiModel]
5455
if (useChat) {
55-
const messages: CompletionItem[] = config.inference.flatChatCompletion
56-
? [{ role: 'system', content: opts.prompt }]
57-
: await toChatCompletionPayload(
58-
opts,
59-
getTokenCounter('openai', OPENAI_MODELS.Turbo),
60-
body.max_tokens
61-
)
56+
const messages =
57+
gen.thirdPartyFormat === 'openai-chatv2' && opts.messages
58+
? opts.messages
59+
: await toChatCompletionPayload(
60+
opts,
61+
getTokenCounter('openai', OPENAI_MODELS.Turbo),
62+
body.max_tokens
63+
)
6264

6365
body.messages = messages
6466
yield { prompt: messages }

srv/adapter/payloads.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,18 @@ function getBasePayload(opts: AdapterProps, stops: string[] = []) {
4444

4545
const json_schema = opts.jsonSchema ? toJsonSchema(opts.jsonSchema) : undefined
4646

47-
const characterNames = Object.values(opts.characters || {}).map((c) => c.name)
47+
const characterNames = Object.values(opts.characters || {})
48+
.map((c) => c.name.split(' '))
49+
.concat(opts.members.map((m) => m.handle.split(' ')))
50+
.flat()
51+
4852
const sequenceBreakers = Array.from(
49-
new Set([
50-
opts.char.name,
51-
opts.replyAs.name,
52-
...characterNames,
53-
...opts.members.map((m) => m.handle),
54-
]).values()
53+
new Set(
54+
[opts.char.name.split(' '), opts.replyAs.name.split(' '), ...characterNames].flat()
55+
).values()
5556
)
5657
.concat(gen.drySequenceBreakers || [])
58+
.flat()
5759
.filter((t) => !!t)
5860

5961
if (!gen.temp) {

0 commit comments

Comments
 (0)