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/commands/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {

hideSlashGroups(root)

ctx.command('chatluna.chat <message:text>')
ctx.command('chatluna.chat [message:text]')
.option('conversation', '-c <conversation:string>')
.option('preset', '-p <preset:string>')
.option('type', '-t <type: string>')
.action(async ({ options, session }, message) => {
if (message == null || message.trim().length === 0) {
return session.text('.messages.message_required')
}

const renderType = options.type ?? config.outputMode
const presetLane = options.preset?.trim() || undefined
const allPresetLanes = presetLane == null
Expand Down
18 changes: 16 additions & 2 deletions packages/core/src/commands/conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,11 +259,23 @@ export function apply(ctx: Context, _config: Config, chain: ChatChain) {
)
})

ctx.command('chatluna.use.model <model:string>', {
ctx.command('chatluna.use.model [model:string]', {
authority: 1
})
.option('preset', '-p <preset:string>')
.option('auto', '-a')
.action(async ({ options, session }, model) => {
const value = model?.trim() || undefined
if (options.auto && value != null) {
return session.text(
'commands.chatluna.use.model.messages.auto_with_model'
)
}
if (!options.auto && value == null) {
return session.text(
'commands.chatluna.use.model.messages.model_required'
)
}
await chain.receiveCommand(
session,
'conversation_use_model',
Expand All @@ -272,7 +284,8 @@ export function apply(ctx: Context, _config: Config, chain: ChatChain) {
presetLane: options.preset?.trim() || undefined
},
conversation_use: {
model: model?.trim() || undefined
model: value,
auto: options.auto || undefined
}
},
ctx
Expand Down Expand Up @@ -435,6 +448,7 @@ declare module '../chains/chain' {
}
conversation_use?: {
model?: string
auto?: boolean
preset?: string
chatMode?: string
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/commands/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {
})
})

ctx.command('chatluna.model.test <model:string>').action(
ctx.command('chatluna.model.test [model:string]').action(
async ({ session }, model) => {
await chain.receiveCommand(session, 'test_model', {
model
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ commands:
model: Target model name.
options:
preset: Preset lane.
auto: Resume following the default model.
messages:
model_required: Specify a target model, or use `-a` to resume following the default model.
auto_with_model: Cannot specify a model together with `-a`.
preset:
description: Switch the conversation preset.
arguments:
Expand Down Expand Up @@ -147,6 +151,7 @@ commands:
message: Message content to send.
messages:
invalid-render-type: 'Invalid rendering type. Supported types: `text` and `voice`.'
message_required: 'Please enter a message to send. Usage: `chatluna chat Hello, world!`'
rollback:
description: Regenerate last conversation content.
options:
Expand Down Expand Up @@ -238,6 +243,7 @@ commands:
model: Model name (e.g., openai/gpt-3.5-turbo) or platform name (e.g., openai).
usage: 'chatluna model test openai/gpt-3.5-turbo'
messages:
model_required: 'No model specified and no global default model set. Usage: `chatluna model test openai/gpt-3.5-turbo`.'
platform_not_found: 'Platform {0} not found. Please check the platform name or ensure the adapter is installed.'
platform_unavailable: 'Platform {0} is unavailable. Please check the configuration or wait for the platform to load.'
model_not_found: 'Model {0} not found. Please verify the model name is correct.'
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/locales/zh-CN.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ commands:
model: 目标模型名称。
options:
preset: 预设分流。
auto: 恢复当前会话跟随默认模型。
messages:
model_required: 请指定目标模型,或使用 `-a` 恢复跟随默认模型。
auto_with_model: 不能同时指定模型和使用 `-a`。
preset:
description: 切换当前会话使用的预设。
arguments:
Expand Down Expand Up @@ -147,6 +151,7 @@ commands:
message: 要发送的消息内容。
messages:
invalid-render-type: 渲染类型无效。请使用有效的渲染类型,目前支持的类有 `text` 和 `voice`。
message_required: 请输入要发送的消息内容。用法:`chatluna chat 你好,世界!`
rollback:
description: 重新生成上一次的对话内容。
options:
Expand Down Expand Up @@ -238,6 +243,7 @@ commands:
model: 模型名称(如 openai/gpt-3.5-turbo)或平台名称(如 openai)。
usage: 'chatluna model test openai/gpt-3.5-turbo'
messages:
model_required: 未指定模型且未设置全局默认模型。用法:`chatluna model test openai/gpt-3.5-turbo`。
platform_not_found: '未找到平台 {0},请检查平台名称或确认平台适配器已安装。'
platform_unavailable: '平台 {0} 不可用,请检查配置或等待平台加载。'
model_not_found: '未找到模型 {0},请检查模型名称是否正确。'
Expand Down
18 changes: 12 additions & 6 deletions packages/core/src/middlewares/model/test_model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {

let platformName: string
let modelName: string
const target = model?.trim() ?? config.defaultModel.trim()

if (!target || target === '无' || target === 'empty') {
context.message = session.text('.model_required')
return ChainMiddlewareRunStatus.STOP
}

try {
// Check if the input contains '/'
if (!model.includes('/')) {
if (!target.includes('/')) {
// Get all models from the specified platform
const platformModels = services.listPlatformModels(
model,
target,
ModelType.llm
)

Expand All @@ -36,7 +42,7 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {
platformModels.value.length === 0
) {
context.message = session.text('.platform_not_found', [
model
target
])
return ChainMiddlewareRunStatus.STOP
}
Expand All @@ -46,17 +52,17 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {
Math.random() * platformModels.value.length
)
const selectedModel = platformModels.value[randomIndex]
platformName = model
platformName = target
modelName = selectedModel.name
} else {
// Parse the full model name
;[platformName, modelName] = parseRawModelName(model)
;[platformName, modelName] = parseRawModelName(target)

// Validate that parsing succeeded
if (!platformName || !modelName) {
context.message = session.text(
'.invalid_model_format',
[model]
[target]
)
return ChainMiddlewareRunStatus.STOP
}
Expand Down
8 changes: 7 additions & 1 deletion packages/core/src/middlewares/system/conversation_manage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,13 @@ export function apply(ctx: Context, config: Config, chain: ChatChain) {
conversationId: resolvedConversationId(context),
presetLane:
context.options.conversation_manage?.presetLane,
[field]: context.options.conversation_use?.[field]
[field]: context.options.conversation_use?.[field],
...(field === 'model'
? {
auto: context.options.conversation_use
?.auto
}
: {})
}
)

Expand Down
85 changes: 74 additions & 11 deletions packages/core/src/services/conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@
fixedModel: firstDefined(constraints, 'fixedModel'),
fixedPreset: firstDefined(constraints, 'fixedPreset'),
fixedChatMode: firstDefined(constraints, 'fixedChatMode'),
autoUpdateModel: firstDefined(constraints, 'autoUpdateModel'),
autoUpdateModel:
firstDefined(constraints, 'autoUpdateModel') ?? true,
lockConversation: firstBoolean(
constraints,
'lockConversation',
Expand Down Expand Up @@ -1666,6 +1667,7 @@
session: Session,
options: ResolveConversationOptions & {
model?: string
auto?: boolean
preset?: string
chatMode?: string
}
Expand Down Expand Up @@ -1712,6 +1714,25 @@

this.checkChatMode(options.chatMode)

if (options.auto === true) {
await this.updateManagedConstraintByBindingKey(
session,
conversation.bindingKey,
{ autoUpdateModel: true }
)
} else if (options.model != null) {
await this.updateManagedConstraintByBindingKey(
session,
conversation.bindingKey,
{ autoUpdateModel: false }
)
}

const autoModel =
options.auto === true
? this.pickModel(resolved.constraint, null)
: undefined

const updated = await this.runtime.withConversationLock(
conversation.id,
async () => {
Expand All @@ -1720,7 +1741,10 @@

await this.runtime.clearConversationInterfaceLocked(current)
return this.touchConversation(conversation.id, {
model: options.model?.trim(),
...(autoModel != null ? { model: autoModel } : {}),
...(options.model != null
? { model: options.model.trim() }
: {}),
preset: options.preset,
chatMode: options.chatMode
})
Expand Down Expand Up @@ -1841,28 +1865,67 @@
async updateManagedConstraint(
session: Session,
patch: Partial<ConstraintRecord>
) {
return this.updateManagedConstraintFor(
session,
session,
buildManagedConstraintName(session),
patch
)
}

async updateManagedConstraintByBindingKey(
session: Session,
bindingKey: string,
patch: Partial<ConstraintRecord>
) {
const name = managedNameFromBindingKey(bindingKey)
if (name == null) {
return undefined
}

const parts = getBaseBindingKey(bindingKey).split(':')
const direct = parts[0] === 'personal' && parts[3] === 'direct'
const target = {
...session,
platform: parts[1] as string,
selfId: parts[2] as string,
isDirect: direct,
userId: direct ? (parts[4] as string) : session.userId,
guildId: direct ? undefined : (parts[3] as string),
channelId: undefined
} as Session
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return this.updateManagedConstraintFor(session, target, name, patch)
}

private async updateManagedConstraintFor(
session: Session,
target: Session,
name: string,
patch: Partial<ConstraintRecord>
) {
this.checkChatMode(patch.defaultChatMode)
this.checkChatMode(patch.fixedChatMode)

const current = await this.getManagedConstraint(session)
const current = await this.firstRow('chatluna_constraint', { name })
const now = new Date()
const guildId = session.isDirect
const guildId = target.isDirect

Check warning on line 1913 in packages/core/src/services/conversation.ts

View check run for this annotation

codefactor.io / CodeFactor

packages/core/src/services/conversation.ts#L1913

Replace `(target.guildId·??·target.channelId·??·null)` with `target.guildId·??·target.channelId·??·null` (prettier/prettier)
? null
: (session.guildId ?? session.channelId ?? null)
: (target.guildId ?? target.channelId ?? null)
const record: ConstraintRecord = {
id: current?.id,
name: buildManagedConstraintName(session),
name,
enabled: true,
priority: 1000,
createdBy: session.userId,
createdAt: now,
platform: session.platform,
selfId: session.selfId,
platform: target.platform,
selfId: target.selfId,
guildId,
channelId: null,
direct: session.isDirect,
users: session.isDirect ? JSON.stringify([session.userId]) : null,
direct: target.isDirect,
users: target.isDirect ? JSON.stringify([target.userId]) : null,
excludeUsers: null,
routeMode: null,
routeKey: null,
Expand All @@ -1888,7 +1951,7 @@
await this.ctx.root.parallel('chatluna/after-constraint-update', {
constraint: record
})
return (await this.getManagedConstraint(session)) ?? record
return (await this.firstRow('chatluna_constraint', { name })) ?? record
}

pickModel(
Expand Down
Loading