Skip to content
Merged
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
50 changes: 44 additions & 6 deletions .github/workflows/stg-deploy-stack.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deploy to DEV (API Only)
name: Deploy to DEV (Web + API)

on: workflow_dispatch

Expand All @@ -17,6 +17,20 @@ jobs:
- name: Checkout
uses: actions/checkout@v3

- name: Install Node and PNPM
uses: ./.github/actions/install-node-pnpm
with:
node-version: ${{ env.node-version }}
pnpm-version: ${{ env.pnpm-version }}

- name: Get cached dependencies
# cache is automatically saved after this job completes. jobs depending on this one will get the latest cached files
id: cache-step
uses: actions/cache@v3
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}

- name: Install SSH Key
uses: shimataro/ssh-key-action@v2
with:
Expand All @@ -27,19 +41,43 @@ jobs:
run: |
ssh-keyscan -H ${{ secrets.SSH_SERVER }} >> ~/.ssh/known_hosts

- name: Build
- name: Install project dependencies
if: steps.cache-step.outputs.cache-hit != 'true'
run: |
ls -la
echo $NODE_ENV
pnpm install --frozen-lockfile

- name: Build frontend
env:
INJECT_SCRIPT: ${{ secrets.INJECT_SCRIPT }}
run: |
pnpm run build:prod
cp dist/index.html dist/original.html
node .github/inject.js

- name: Build API
run: |
docker build -f Dockerfile -t ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:latest --build-arg SHA=$GITHUB_SHA .
docker build -f Dockerfile -t ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:staging --build-arg SHA=$GITHUB_SHA .
docker tag ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:staging ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:$GITHUB_SHA

- name: Log in to Container Registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin

- name: Publish
run: |
docker push ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:latest
docker push ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:staging
docker push ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:$GITHUB_SHA

- name: Update Service
- name: Update Frontend
uses: shallwefootball/s3-upload-action@master
with:
aws_key_id: ${{ secrets.S3_ASSET_ACCESS_KEY }}
aws_secret_access_key: ${{ secrets.S3_ASSET_SECRET_KEY }}
aws_bucket: ${{ secrets.S3_PRD_ASSET_BUCKET }}
source_dir: 'dist'
destination_dir: ''

- name: Update Backend
run: |
sh .github/deploy.sh ${{ secrets.SSH_SERVER }}
sh .github/deploy-stg.sh ${{ secrets.SSH_SERVER }}
21 changes: 21 additions & 0 deletions .zed/debug.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Project-local debug tasks
//
// For more documentation on how to configure debug tasks,
// see: https://zed.dev/docs/debugger
[
{
"label": "Launch API (Zed)",
"adapter": "JavaScript",
"program": "${ZED_WORKTREE_ROOT}/srv/start.js",
"sourceMaps": true,
"console": "integratedTerminal",
"request": "launch",
"trace": true,
"type": "node",
"outFiles": [
"${ZED_WORKTREE_ROOT}/srv/**/*.js",
"${ZED_WORKTREE_ROOT}/common/**/*.js",
"!**/node_modules/**"
]
}
]
113 changes: 37 additions & 76 deletions common/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,31 @@ export type ChatNode = {

export type ChatDepths = Record<number, string[]>

export function runPresetParsers(parsers: PresetParser[], message: string) {
export function runPresetParsers(
parsers: PresetParser[],
message: string,
opts?: { preset?: boolean }
) {
let current = message || ''

for (const parser of parsers) {
if (!parser.text?.trim()) continue
switch (parser.type) {
case 'remove-prompt':
case 'remove': {
current = current.split(parser.text.replace(/\\n/g, '\n')).join('')
break
if (parser.type === 'remove-prompt' && !opts?.preset) continue
const remove = parser.text.replace(/(?<!\\)\\n/g, '\n').replaceAll('\\\\n', '\\n')
current = current.split(remove).join('')
continue
}

case 'replace-prompt':
case 'replace': {
const from = parser.text.replace(/\\n/g, '\n')
const to = (parser.to || '').replace(/\\n/g, '\n')
if (parser.type === 'replace-prompt' && !opts?.preset) continue
const from = parser.text.replace(/(?<!\\)\\n/g, '\n').replaceAll('\\\\n', '\\n')
const to = (parser.to || '').replace(/(?<!\\)\\n/g, '\n').replaceAll('\\\\n', '\\n')
current = current.split(from).join(to)
break
continue
}
}
}
Expand Down Expand Up @@ -68,10 +77,28 @@ export function toQuickGraph(
}
}

let index = -1
for (const msg of messages) {
if (!msg.parent) continue
const parent = tree[msg.parent]
index++

// Handle chats before graphs existed
if (!msg.parent) {
// Ignore root message, always has no parent
if (index === 0) continue
const parentSrc = messages[index - 1]
const parent = tree[parentSrc?._id]
if (!parent) {
orphans.push({ _id: msg._id, age: msg.createdAt, parent: msg.parent })
continue
}

tree[msg._id].parent = parent._id
parent.childCount++
parent.children[msg._id] = true
continue
}

const parent = tree[msg.parent]
if (!parent) {
orphans.push({ _id: msg._id, age: msg.createdAt, parent: msg.parent })
continue
Expand Down Expand Up @@ -106,10 +133,10 @@ export function getDeletionChanges(graph: QuickChatGraph, deleteIds: string[]) {
const head = deletes[0]
const tail = deletes.slice(-1)[0]

let nextLeafId = method === 'tail' ? head.parent || '' : undefined
let nextLeafId = method === 'tail' ? head?.parent || '' : undefined
let parents =
method === 'middle'
? { ids: Object.keys(tail.children), parentId: head.parent || '' }
? { ids: tail ? Object.keys(tail.children) : [], parentId: head.parent || '' }
: undefined

const leaf = graph.tree[nextLeafId || '']
Expand Down Expand Up @@ -176,75 +203,9 @@ export function toChatGraph(messages: AppSchema.ChatMessage[]): { tree: ChatTree
}
}

// for (const { msg } of Object.values(tree)) {
// if (!msg.parent) {
// log(`root? %s`, msg._id.slice(0, 4))
// continue
// }

// const parent = tree[msg.parent]
// if (!parent) continue
// log('assigned to %s: %s', parent.msg._id.slice(0, 4), msg._id.slice(0, 4))
// parent.children[msg._id] = true
// }

return { tree, root: messages[0]?._id || '' }
}

export function updateChatTreeNode(tree: ChatTree, msg: AppSchema.ChatMessage) {
const next: ChatTree = { ...tree }

next[msg._id] = {
msg,
children: {},
depth: getMessageDepth(tree, msg.parent || '') + 1,
}

for (const node of Object.values(next)) {
if (!node.msg.parent) continue

if (node.msg.parent !== msg._id) continue

if (!parent) continue

next[msg._id].children[node.msg._id] = true
}

const nextParent = next[msg.parent || '']
if (nextParent) {
nextParent.children[msg._id] = true
}

return next
}

export function removeChatTreeNodes(tree: ChatTree, ids: string[]) {
const next = { ...tree }

for (const id of ids) {
const node = next[id]
if (!node) continue

const parent = node.msg.parent ? next[node.msg.parent] : null
if (parent) {
delete parent.children[id]

for (const childId in node.children) {
parent.children[childId] = true

const child = next[childId]
if (!child) continue

child.msg.parent = node.msg.parent
}
}

delete next[id]
}

return next
}

export function getChatDepths(tree: ChatTree) {
const depths: ChatDepths = {}

Expand Down
6 changes: 5 additions & 1 deletion common/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ModelFormat, replaceArrayTags, replaceTags } from './presets/templates'
import { OPENAI_CONTEXTS } from './presets/openai'
import { NOVEL_MODELS } from './presets/novel'
import { extractReasoning } from './reasoning'
import { runPresetParsers } from './chat'

export type JsonOutput = { values: any; response: string; history: string; imageCaption: string }
export type TickHandler<T = JsonOutput> = (
Expand Down Expand Up @@ -323,11 +324,14 @@ export async function assemblePrompt(
const post = createPostPrompt(opts)
const template = getTemplate(opts)

const parsers = opts.settings?.parsers || []
const parsedLines = opts.lines.map((line) => runPresetParsers(parsers, line, { preset: true }))

let { parsed, inserts, length, sections, linesAddedCount, history, addedLines, blocks } =
await injectPlaceholders(template, {
opts: { ...opts, schema: opts.jsonSchema },
parts: opts.parts,
lines: opts.lines,
lines: parsedLines,
history: opts.history,
characters: opts.characters,
lastMessage: opts.lastMessage,
Expand Down
14 changes: 12 additions & 2 deletions common/requests/payloads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,15 @@ function getBasePayload(opts: MinOpts, stops: string[] = []) {
}

if (format === 'llamacpp') {
const budget =
reasoningEffort === 'none'
? 0
: reasoningEffort === 'low'
? gen.maxTokens! * 0.2
: reasoningEffort === 'medium'
? gen.maxTokens! * 0.5
: gen.maxTokens! * 0.75

const body = {
prompt: messages ? undefined : prompt,
messages,
Expand All @@ -401,6 +410,7 @@ function getBasePayload(opts: MinOpts, stops: string[] = []) {
tfs_z: gen.tailFreeSampling,
json_schema,
reasoning_effort: reasoningEffort,
thinking_budget_tokens: budget,
chat_template_kwargs: { enable_thinking: reasoningEffort !== 'none' },
}
return body
Expand Down Expand Up @@ -648,7 +658,7 @@ export function toImageJinjaTemplate(opts: { jinja?: string; format?: ModelForma
{%- if message['content'] is string %}
{{- message['content'] }}
{%- else %}

{%- for block in message['content'] %}
{%- if block['type'] == 'text' %}
{{- block['text'] }}
Expand All @@ -658,7 +668,7 @@ export function toImageJinjaTemplate(opts: { jinja?: string; format?: ModelForma
{{- raise_exception('Only text and image blocks are supported in message content!') }}
{%- endif %}
{%- endfor %}

{%- endif %}
{%- elif message['role'] == 'system' %}
{{- message['content'] }}
Expand Down
1 change: 1 addition & 0 deletions common/types/image-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type BaseImageSettings = {
suffix?: string
negative?: string

autofix?: boolean
template?: string
clipSkip?: number
width: number
Expand Down
6 changes: 5 additions & 1 deletion common/types/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ export interface UserGenPreset extends GenSettings {
userId: string
}

export type PresetParser = { type: 'replace' | 'remove'; text: string; to?: string }
export type PresetParser = {
type: 'replace' | 'remove' | 'remove-prompt' | 'replace-prompt'
text: string
to?: string
}

export type Sampler =
| 'topK'
Expand Down
1 change: 1 addition & 0 deletions common/types/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ export namespace AppSchema {

// Emphemeral (lost on page refresh):
reasoning?: string
deleted?: boolean
}

export type ScenarioEventType = 'world' | 'character' | 'hidden' | 'ooc'
Expand Down
14 changes: 6 additions & 8 deletions srv/adapter/kobold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,13 @@ export const handleThirdParty: ModelAdapter = async function* (opts) {
}
}

if (opts.gen.service === 'kobold') {
let meta: any = {
fmt: opts.gen.thirdPartyFormat,
wait,
time: round((Date.now() - start) / 1000, 2),
}
if (body.model) meta.model = body.model
yield { meta }
let meta: any = {
fmt: opts.conn.format,
wait,
time: round((Date.now() - start) / 1000, 2),
}
if (body.model) meta.model = body.model
yield { meta }

const parsed = sanitise(accum)
const trimmed = trimResponseV2(parsed, opts.replyAs, members, opts.gen, stop_sequence)
Expand Down
3 changes: 2 additions & 1 deletion srv/adapter/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,8 @@ function patchPayload(opts: AdapterProps, body: any, messages: CompletionItem<st
}

function applyReasoningPayload(opts: AdapterProps, body: any) {
if (opts.conn.provider?.provider === 'known-zai') {
const provider = opts.conn.provider?.provider
if (provider === 'known-zai' || provider === 'known-deepseek') {
body.thinking = { type: opts.gen.reasoning?.enabled ? 'enabled' : 'disabled' }
return
}
Expand Down
Loading
Loading