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
6 changes: 5 additions & 1 deletion packages/core/src/middlewares/chat/chat_time_limit_check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,11 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {
}

return {
model: resolved.effectiveModel ?? conversation.model,
model:
ctx.chatluna.conversation.pickModel(
resolved.constraint,
conversation
) ?? conversation.model,
conversationId: conversation.id
}
}
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/middlewares/chat/read_chat_message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {
await ctx.chatluna.messageTransformer.transform(
session,
message,
resolved.effectiveModel ?? '',
ctx.chatluna.conversation.pickModel(
resolved.constraint,
resolved.conversation
) ?? '',
undefined,
{
quote: false,
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/middlewares/chat/rollback_chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ async function rollbackConversation(
inputMessage = await ctx.chatluna.messageTransformer.transform(
session,
transformMessageContentToElements(humanContent),
resolved.effectiveModel ?? current.model,
ctx.chatluna.conversation.pickModel(resolved.constraint, current) ??
current.model,
undefined,
{
quote: false,
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/middlewares/model/resolve_model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {

try {
const modelName =
resolved.effectiveModel ??
resolved.conversation?.model ??
config.defaultModel ??
'empty'
ctx.chatluna.conversation.pickModel(
resolved.constraint,
resolved.conversation
) ?? 'empty'
const presetName =
resolved.effectivePreset ??
resolved.conversation?.preset ??
Expand Down
22 changes: 16 additions & 6 deletions packages/core/src/middlewares/system/conversation_manage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,10 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {
session.text('chatluna.conversation.default_title'),
model:
createModel ??
resolved.effectiveModel ??
ctx.chatluna.conversation.pickModel(
resolved.constraint,
resolved.conversation
) ??
config.defaultModel,
preset:
createPreset ??
Expand Down Expand Up @@ -223,6 +226,7 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {
const pagination = new Pagination<ConversationListEntry>({
formatItem: (item) =>
formatConversationLine(
ctx,
session,
item.conversation,
resolved,
Expand Down Expand Up @@ -265,7 +269,12 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {

context.message = [
session.text('chatluna.conversation.messages.current_header'),
formatConversationLine(session, resolved.conversation, resolved)
formatConversationLine(
ctx,
session,
resolved.conversation,
resolved
)
].join('\n')
return ChainMiddlewareRunStatus.STOP
})
Expand Down Expand Up @@ -998,6 +1007,7 @@ function formatConversationError(
}

function formatConversationLine(
ctx: Context,
session: Session,
conversation: ConversationRecord,
resolved: ResolvedConversationContext,
Expand All @@ -1010,10 +1020,10 @@ function formatConversationLine(
resolved.binding?.activeConversationId
)
const effectiveModel =
resolved.constraint.fixedModel ??
conversation.model ??
resolved.constraint.defaultModel ??
'-'
ctx.chatluna.conversation.pickModel(
resolved.constraint,
conversation
) ?? '-'
const effectivePreset =
resolved.constraint.fixedPreset ??
conversation.preset ??
Expand Down
82 changes: 70 additions & 12 deletions packages/core/src/services/conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { createHash, randomUUID } from 'crypto'
import fs from 'fs/promises'
import path from 'path'
import type { Context, Session } from 'koishi'
import { ModelType } from 'koishi-plugin-chatluna/llm-core/platform/types'
import { parseRawModelName } from 'koishi-plugin-chatluna/llm-core/utils/count_tokens'
import type { Config } from '../config'
import {
deserializeConversation,
Expand Down Expand Up @@ -281,17 +283,17 @@ export class ConversationService {
))
? conversation
: null
const effectiveModel = this.pickModel(constraint, allowedConversation)

return {
bindingKey,
presetLane: getPresetLane(bindingKey),
binding: binding ?? null,
conversation: allowedConversation,
effectiveModel:
constraint.fixedModel ??
allowedConversation?.model ??
constraint.defaultModel ??
this.config.defaultModel,
conversation:
allowedConversation != null && effectiveModel != null
? { ...allowedConversation, model: effectiveModel }
: allowedConversation,
effectiveModel,
effectivePreset:
constraint.fixedPreset ??
allowedConversation?.preset ??
Expand Down Expand Up @@ -325,7 +327,7 @@ export class ConversationService {
return {
...target,
mode,
conversation,
conversation: target.conversation ?? conversation,
conversationId: conversation.id
}
}
Expand Down Expand Up @@ -361,11 +363,18 @@ export class ConversationService {
current.bindingKey
))
) {
const effectiveModel = this.pickModel(
current.constraint,
conversation
)

current = {
...current,
conversation,
effectiveModel:
current.constraint.fixedModel ?? conversation.model,
conversation:
effectiveModel != null
? { ...conversation, model: effectiveModel }
: conversation,
effectiveModel,
effectivePreset:
current.constraint.fixedPreset ??
conversation.preset,
Expand All @@ -392,13 +401,20 @@ export class ConversationService {
conversationId: current.conversation.id
}
)
const effectiveModel = this.pickModel(
current.constraint,
conversation
)

return {
...current,
mode,
conversation,
conversation:
effectiveModel != null
? { ...conversation, model: effectiveModel }
: conversation,
conversationId: conversation.id,
effectiveModel: conversation.model,
effectiveModel,
effectivePreset: conversation.preset,
effectiveChatMode: conversation.chatMode
}
Expand Down Expand Up @@ -1895,6 +1911,48 @@ export class ConversationService {
await fs.mkdir(target, { recursive: true })
return target
}

pickModel(
constraint: ResolvedConstraint,
conversation?: ConversationRecord | null
) {
for (const model of [
constraint.fixedModel,
conversation?.model,
constraint.defaultModel,
this.config.defaultModel
]) {
if (
model == null ||
model.trim().length < 1 ||
model === '无' ||
model === 'empty'
) {
continue
}

const [platform, name] = parseRawModelName(model)

if (platform == null || name == null) {
continue
}

const platformModels =
this.ctx.chatluna.platform.listPlatformModels(
platform,
ModelType.llm
).value

if (
platformModels.length > 0 &&
platformModels.some((m) => m.name === name)
) {
return model
}
}

return null
}
}

function isConstraintMatched(constraint: ConstraintRecord, session: Session) {
Expand Down
39 changes: 39 additions & 0 deletions packages/core/tests/conversation-service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,45 @@ it('ConversationService defaults resolveConversation mode to context and sets nu
assert.equal(resolved.conversationId, null)
})

it('ConversationService skips unavailable models before using config default', async () => {
const conversation = createConversation({
model: 'missing-platform/old-model'
})
const { service } = await createService({
tables: {
chatluna_conversation: [conversation as unknown as TableRow],
chatluna_binding: [
{
bindingKey: conversation.bindingKey,
activeConversationId: conversation.id,
lastConversationId: null,
updatedAt: new Date()
}
],
chatluna_constraint: [
{
id: 1,
name: 'unavailable-models',
enabled: true,
priority: 10,
createdBy: 'admin',
createdAt: new Date(),
updatedAt: new Date(),
users: null,
excludeUsers: null,
fixedModel: 'missing-platform/fixed-model',
defaultModel: 'missing-platform/default-model'
} as unknown as TableRow
]
}
})

const resolved = await service.ensureActiveConversation(createSession())

assert.equal(resolved.effectiveModel, 'test-platform/test-model')
assert.equal(resolved.conversation.model, 'test-platform/test-model')
})

it('ConversationService resolveConversation uses explicit binding key constraints', async () => {
const remote = createConversation({
id: 'conversation-remote-binding',
Expand Down
31 changes: 31 additions & 0 deletions packages/core/tests/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '../src/services/conversation_types'
import { ChatLunaService } from '../src/services/chat'
import { ConversationService } from '../src/services/conversation'
import { ModelType } from '../src/llm-core/platform/types'

export async function expectRejected(
promise: Promise<unknown>,
Expand Down Expand Up @@ -312,6 +313,24 @@ export async function createService(
}
},
chatluna: {
platform: {
chatChains: {
value: [{ name: 'plugin' }]
},
listPlatformModels: (platform: string) => ({
value:
platform === 'test-platform'
? [
{
name: 'test-model',
type: ModelType.llm,
maxTokens: 4096,
capabilities: []
}
]
: []
})
},
conversation: {
getArchive: async (id: string) =>
database.tables.chatluna_archive.find(
Expand Down Expand Up @@ -364,6 +383,18 @@ export async function createMemoryService(
app.plugin(memory)
app.plugin(ChatLunaService, createConfig(options.config))
await app.start()
;(
app.chatluna.platform as unknown as {
_models: Record<string, unknown[]>
}
)._models['test-platform'] = [
{
name: 'test-model',
type: ModelType.llm,
maxTokens: 4096,
capabilities: []
}
]

for (const [table, rows] of Object.entries(options.tables ?? {})) {
for (const row of rows ?? []) {
Expand Down
10 changes: 6 additions & 4 deletions packages/extension-agent/src/trigger/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,12 @@ export class ChatLunaAgentTriggerExecutor {
constraint.fixedPreset ??
constraint.defaultPreset ??
this.ctx.chatluna.config.defaultPreset
const model =
constraint.fixedModel ??
constraint.defaultModel ??
this.ctx.chatluna.config.defaultModel
const model = this.ctx.chatluna.conversation.pickModel(constraint)

if (model == null) {
throw new Error('No available model found.')
}

const chatMode =
constraint.fixedChatMode ??
constraint.defaultChatMode ??
Expand Down