Compare commits

...

12 Commits

Author SHA1 Message Date
eda932b4e9 Update memory structure 2025-07-20 11:27:31 +08:00
6cba3cca22 Shorten dialogue intervals 2025-07-20 11:27:11 +08:00
60a48c5211 Add data reload 2025-07-20 11:26:41 +08:00
dbfdf83dc6 Add image message 2025-07-20 11:12:26 +08:00
3a5caf86a1 Split memory agent 2025-07-20 11:11:47 +08:00
c479282fe4 Update to streaming processing response
Update regex
2025-07-20 00:45:59 +08:00
d1ee8f9fcf Update memory agent description 2025-07-17 13:07:21 +08:00
11bdaff54d Add mute tool, default disabled 2025-07-17 13:07:03 +08:00
7d911f2fb6 Add temperature config 2025-07-17 12:45:08 +08:00
7e1a1ad0aa Update temperature to 1.3 2025-07-15 12:23:28 +08:00
679bf15be5 Change to subject lock 2025-07-15 12:23:06 +08:00
ea4e6123b3 Add Memory Agent 2025-07-15 10:37:28 +08:00
7 changed files with 357 additions and 259 deletions

View File

@ -1,12 +1,17 @@
package top.jie65535.mirai
import com.aallam.openai.api.chat.ChatCompletionChunk
import com.aallam.openai.api.chat.ChatCompletionRequest
import com.aallam.openai.api.chat.ChatMessage
import com.aallam.openai.api.chat.ChatRole
import com.aallam.openai.api.chat.ToolCall
import com.aallam.openai.api.model.ModelId
import io.ktor.util.collections.*
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
@ -24,7 +29,6 @@ import net.mamoe.mirai.event.events.GroupMessageEvent
import net.mamoe.mirai.event.events.MessageEvent
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.data.Image.Key.queryUrl
import net.mamoe.mirai.message.data.MessageSource.Key.quote
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
import net.mamoe.mirai.utils.info
import top.jie65535.mirai.tools.*
@ -61,6 +65,7 @@ object JChatGPT : KotlinPlugin(
// 注册聊天权限
PermissionService.INSTANCE.register(chatPermission, "JChatGPT Chat Permission")
PluginConfig.reload()
PluginData.reload()
// 设置Token
LargeLanguageModels.reload()
@ -144,6 +149,14 @@ object JChatGPT : KotlinPlugin(
"\"${event.senderName}\" 私聊中"
}
}
replace("{memory}") {
val memoryText = PluginData.contactMemory[event.subject.id]
if (memoryText.isNullOrEmpty()) {
"暂无相关记忆"
} else memoryText
}
return prompt.toString()
}
@ -300,59 +313,128 @@ object JChatGPT : KotlinPlugin(
private val thinkRegex = Regex("<think>[\\s\\S]*?</think>")
private suspend fun startChat(event: MessageEvent) {
if (!requestMap.add(event.sender.id)) {
event.subject.sendMessage("再等等...")
if (!requestMap.add(event.subject.id)) {
logger.warning("The current Contact is busy!")
return
}
val history = mutableListOf<ChatMessage>()
if (PluginConfig.prompt.isNotEmpty()) {
val prompt = getSystemPrompt(event)
if (PluginConfig.logPrompt) {
logger.info("Prompt: $prompt")
}
history.add(ChatMessage(ChatRole.System, prompt))
}
val historyText = getHistory(event)
logger.info("History: $historyText")
history.add(ChatMessage.User(historyText))
try {
val history = mutableListOf<ChatMessage>()
if (PluginConfig.prompt.isNotEmpty()) {
val prompt = getSystemPrompt(event)
if (PluginConfig.logPrompt) {
logger.info("Prompt: $prompt")
}
history.add(ChatMessage(ChatRole.System, prompt))
}
val historyText = getHistory(event)
logger.info("History: $historyText")
history.add(ChatMessage.User(historyText))
var done: Boolean
// 至少循环3次
var retry = max(PluginConfig.retryMax, 3)
do {
try {
val startedAt = OffsetDateTime.now().toEpochSecond().toInt()
val response = chatCompletion(history)
// 移除思考内容
val responseContent = response.content?.replace(thinkRegex, "")?.trim()
history.add(ChatMessage.Assistant(
content = responseContent,
name = response.name,
toolCalls = response.toolCalls
))
val responseFlow = chatCompletions(history)
var responseMessageBuilder: StringBuilder? = null
val responseToolCalls = mutableListOf<ToolCall.Function>()
val toolCallTasks = mutableListOf<Deferred<ChatMessage>>()
// 处理聊天流式响应
responseFlow.collect { chunk ->
val delta = chunk.choices[0].delta
if (delta == null) return@collect
if (response.toolCalls.isNullOrEmpty()) {
done = true
} else {
done = false
// 处理函数调用
for (toolCall in response.toolCalls) {
require(toolCall is ToolCall.Function) { "Tool call is not a function" }
val functionResponse = toolCall.execute(event)
history.add(
ChatMessage(
role = ChatRole.Tool,
toolCallId = toolCall.id,
name = toolCall.function.name,
content = functionResponse
)
)
if (toolCall.function.name == "endConversation") {
done = true
// 处理内容更新
if (delta.content != null) {
if (responseMessageBuilder == null) {
responseMessageBuilder = StringBuilder(delta.content)
} else {
responseMessageBuilder.append(delta.content)
}
}
// 处理工具调用更新
val toolCalls = delta.toolCalls
if (toolCalls != null) {
for (toolCallChunk in toolCalls) {
val index = toolCallChunk.index
val toolId = toolCallChunk.id
val function = toolCallChunk.function
// 新的请求
if (index >= responseToolCalls.size) {
// 处理已完成的工具调用
responseToolCalls.lastOrNull()?.let { toolCall ->
toolCallTasks.add(async {
val functionResponse = toolCall.execute(event)
ChatMessage(
role = ChatRole.Tool,
toolCallId = toolCall.id,
name = toolCall.function.name,
content = functionResponse
)
})
}
// 加入新的工具调用
if (toolId != null && function != null) {
responseToolCalls.add(ToolCall.Function(toolId, function))
}
} else if (function != null) {
// 拼接函数名字
if (function.nameOrNull != null) {
val currentTool = responseToolCalls[index]
responseToolCalls[index] = currentTool.copy(
function = currentTool.function.copy(
nameOrNull = currentTool.function.nameOrNull.orEmpty() + function.name
)
)
}
// 拼接函数参数
if (function.argumentsOrNull != null) {
val currentTool = responseToolCalls[index]
responseToolCalls[index] = currentTool.copy(
function = currentTool.function.copy(
argumentsOrNull = currentTool.function.argumentsOrNull.orEmpty() + function.arguments
)
)
}
}
}
}
}
// 移除思考内容
val responseContent = responseMessageBuilder?.replace(thinkRegex, "")?.trim()
// 记录AI回答
history.add(ChatMessage.Assistant(
content = responseContent,
toolCalls = responseToolCalls
))
// 处理最后一个工具调用
if (responseToolCalls.size > toolCallTasks.size) {
val toolCallMessage = responseToolCalls.last().let { toolCall ->
val functionResponse = toolCall.execute(event)
ChatMessage(
role = ChatRole.Tool,
toolCallId = toolCall.id,
name = toolCall.function.name,
content = functionResponse
)
}
if (toolCallTasks.isNotEmpty()) {
// 等待之前的所有工具完成
history.addAll(toolCallTasks.awaitAll())
}
// 将最后一个也加入对话历史中
history.add(toolCallMessage)
// 如果调用中包含结束对话工具则表示完成,反之则继续循环
done = history.any { it.name == "endConversation" }
} else {
done = true
}
if (!done) {
@ -360,11 +442,6 @@ object JChatGPT : KotlinPlugin(
buildString {
append("系统提示:本次运行还剩${retry-1}")
// if (response.toolCalls.isNullOrEmpty()) {
// append("\n在上一轮对话中未检测到调用任何工具请检查工具调用语法是否正确")
// append("\n如果你确实不需要调用其它工具比如发送消息请调用`endConversation`来结束对话。")
// }
val newMessages = getAfterHistory(startedAt, event)
if (newMessages.isNotEmpty()) {
append("\n以下是上次运行至今的新消息\n\n$newMessages")
@ -378,224 +455,32 @@ object JChatGPT : KotlinPlugin(
} else {
done = false
logger.warning("调用llm时发生异常重试中", e)
event.subject.sendMessage(event.message.quote() + "出错了...正在重试...")
event.subject.sendMessage("出错了...正在重试...")
}
}
} while (!done && 0 < --retry)
} catch (ex: Throwable) {
logger.warning(ex)
event.subject.sendMessage(event.message.quote() + "很抱歉,发生异常,请稍后重试")
event.subject.sendMessage("很抱歉,发生异常,请稍后重试")
} finally {
// 一段时间后才允许再次提问,防止高频对话
launch {
delay(5.seconds)
requestMap.remove(event.sender.id)
delay(1.seconds)
requestMap.remove(event.subject.id)
}
}
}
// private suspend fun startChat(event: MessageEvent) {
// if (!requestMap.add(event.sender.id)) {
// // CD中不再引用消息否则可能导致和机器人无限循环对话
// event.subject.sendMessage("再等等...")
// return
// }
//
// val history = mutableListOf<ChatMessage>()
// if (PluginConfig.prompt.isNotEmpty()) {
// val prompt = getSystemPrompt(event)
// if (PluginConfig.logPrompt) {
// logger.info("Prompt: $prompt")
// }
// history.add(ChatMessage(ChatRole.System, prompt))
// }
// val historyText = getHistory(event)
// logger.info("History: $historyText")
// history.add(ChatMessage.User(historyText))
//
// try {
// var done = true
// // 至少重试两次
// var retry = max(PluginConfig.retryMax, 3)
// val finalToolCalls = mutableMapOf<Int, ToolCall.Function>()
// val contentBuilder = StringBuilder()
// do {
// finalToolCalls.clear()
// contentBuilder.setLength(0)
//
// try {
// var sent = false
// // 流式处理响应
// withTimeout(PluginConfig.timeout) {
// chatCompletions(history, retry > 1).collect { chunk ->
// val delta = chunk.choices[0].delta
// if (delta == null) return@collect
//
// // 处理工具调用
// val toolCalls = delta.toolCalls
// if (toolCalls != null) {
// for (toolCall in toolCalls) {
// val index = toolCall.index
// val toolId = toolCall.id
// val function = toolCall.function
// // 取出未完成的函数调用
// val incompleteCall = finalToolCalls[index]
// // 如果是新的函数调用,保存起来
// if (incompleteCall == null && toolId != null && function != null) {
// // 添加函数调用
// finalToolCalls[index] = ToolCall.Function(toolId, function)
// } else if (incompleteCall != null && function != null && function.argumentsOrNull != null) {
// // 更新参数内容
// finalToolCalls[index] = incompleteCall.copy(
// function = incompleteCall.function.copy(
// argumentsOrNull = incompleteCall.function.arguments + function.arguments
// )
// )
// }
// }
// }
//
// // 处理响应内容
// val contentChunk = delta.content
// // 避免连续发送多次,只拆分第一次进行发送
// if (contentChunk != null && !sent) {
// // 填入内容
// contentBuilder.append(contentChunk)
// sent = parseStreamingContent(contentBuilder, event)
// }
// }
// }
//
// val lastBlock = contentBuilder.toString().trim()
// if (lastBlock.isNotEmpty()) {
// event.subject.sendMessage(
// if (lastBlock.length > PluginConfig.messageMergeThreshold) {
// event.buildForwardMessage {
// event.bot says toMessage(event.subject, lastBlock)
// }
// } else {
// toMessage(event.subject, lastBlock)
// }
// )
// }
//
// if (finalToolCalls.isNotEmpty()) {
// val toolCalls = finalToolCalls.values.toList()
// history.add(ChatMessage.Assistant(toolCalls = toolCalls))
// for (toolCall in toolCalls) {
// val functionResponse = toolCall.execute(event)
// history.add(
// ChatMessage(
// role = ChatRole.Tool,
// toolCallId = toolCall.id,
// name = toolCall.function.name,
// content = functionResponse
// )
// )
// done = false
// }
// } else {
// done = true
// }
// } catch (e: Exception) {
// if (retry <= 1) {
// throw e
// } else {
// done = false
// logger.warning("调用llm时发生异常重试中", e)
// event.subject.sendMessage(event.message.quote() + "出错了...正在重试...")
// }
// }
// } while (!done && 0 < --retry)
// } catch (ex: Throwable) {
// logger.warning(ex)
// event.subject.sendMessage(event.message.quote() + "很抱歉,发生异常,请稍后重试")
// } finally {
// // 一段时间后才允许再次提问,防止高频对话
// launch {
// delay(10.seconds)
// requestMap.remove(event.sender.id)
// }
// }
// }
// /**
// * 解析流消息
// */
// private fun parseStreamingContent(contentBuilder: StringBuilder, event: MessageEvent): Boolean {
// // 处理推理内容
// val thinkBeginAt = contentBuilder.indexOf("<think")
// if (thinkBeginAt >= 0) {
// val thinkEndAt = contentBuilder.indexOf("</think>")
// if (thinkEndAt > 0) {
// // 去除思考内容
// contentBuilder.delete(thinkBeginAt, thinkEndAt + "</think>".length)
// }
// // 跳过本轮处理
// return false
// }
//
// // 处理代码块
// val codeBlockBeginAt = contentBuilder.indexOf("```")
// if (codeBlockBeginAt >= 0) {
// val codeBlockEndAt = contentBuilder.indexOf("```", codeBlockBeginAt + 3)
// if (codeBlockEndAt >= 0) {
// val codeBlockContentBegin = contentBuilder.indexOf("\n", codeBlockBeginAt + 3)
// if (codeBlockContentBegin in codeBlockBeginAt..codeBlockEndAt) {
// val codeBlockContent = contentBuilder.substring(codeBlockContentBegin, codeBlockEndAt).trim()
// contentBuilder.delete(codeBlockBeginAt, codeBlockEndAt + 3)
// launch {
// // 发送代码块内容
// event.subject.sendMessage(
// if (codeBlockContent.length < PluginConfig.messageMergeThreshold) {
// toMessage(event.subject, codeBlockContent)
// } else {
// // 消息内容太长则转为转发消息避免刷屏
// event.buildForwardMessage {
// event.bot says toMessage(event.subject, codeBlockContent)
// }
// }
// )
// }
// }
// }
// // 跳过本轮处理
// return true
// }
//
// // 徒手trimStart
// var contentBeginAt = 0
// while (contentBeginAt < contentBuilder.length) {
// if (contentBuilder[contentBeginAt].isWhitespace()) {
// contentBeginAt++
// } else {
// break
// }
// }
//
// // 对空行进行分割输出
// val emptyLineAt = contentBuilder.indexOf("\n\n", contentBeginAt)
// if (emptyLineAt > 0) {
// val lineContent = contentBuilder.substring(contentBeginAt, emptyLineAt)
// contentBuilder.delete(0, emptyLineAt + 2)
// launch {
// // 发送消息内容
// event.subject.sendMessage(toMessage(event.subject, lineContent))
// }
// return true
// }
// return false
// }
private val regexAtQq = Regex("@(\\d+)")
private val regexAtQq = Regex("""@(\d{5,12})""")
private val regexLaTeX = Regex(
"\\\\\\((.+?)\\\\\\)|" + // 匹配行内公式 \(...\)
"\\\\\\[(.+?)\\\\\\]|" + // 匹配独立公式 \[...\]
"\\$\\s(.+?)\\s\\$|" // 匹配行内公式 $...$
"""\\\((.+?)\\\)|""" + // 匹配行内公式 \(...\)
"""\\\[(.+?)\\]|""" + // 匹配独立公式 \[...\]
"""\$(.+?)\$""" // 匹配行内公式 $...$
)
private val regexImage = Regex("""!\[(.*?)]\(([^\s"']+).*?\)""")
private data class MessageChunk(val range: IntRange, val content: Message)
/**
@ -612,6 +497,7 @@ object JChatGPT : KotlinPlugin(
PlainText(content)
} else {
val t = mutableListOf<MessageChunk>()
// @某人
regexAtQq.findAll(content).forEach {
val qq = it.groups[1]?.value?.toLongOrNull()
if (qq != null && contact is Group) {
@ -619,6 +505,16 @@ object JChatGPT : KotlinPlugin(
}
}
// 图片
regexImage.findAll(content).forEach {
// val placeholder = it.groupValues[1]
val url = it.groupValues[2]
t.add(MessageChunk(
it.range,
Image(url)))
}
// LeTeX渲染
regexLaTeX.findAll(content).forEach {
it.groups.forEach { group ->
if (group == null || group.value.isEmpty()) return@forEach
@ -636,6 +532,7 @@ object JChatGPT : KotlinPlugin(
}
}
// 构造消息链
buildMessageChain {
var index = 0
for ((range, msg) in t.sortedBy { it.range.start }) {
@ -663,6 +560,12 @@ object JChatGPT : KotlinPlugin(
// 发送组合消息
SendCompositeMessage(),
// 记忆代理
MemoryAppend(),
// 记忆修改
MemoryReplace(),
// 结束循环
StopLoopAgent(),
@ -686,44 +589,48 @@ object JChatGPT : KotlinPlugin(
// Epic 免费游戏
EpicFreeGame(),
// 群管代理
GroupManageAgent(),
)
// private fun chatCompletions(
// private suspend fun chatCompletion(
// chatMessages: List<ChatMessage>,
// hasTools: Boolean = true
// ): Flow<ChatCompletionChunk> {
// val llm = this.llm ?: throw NullPointerException("OpenAI Token 未设置,无法开始")
// ): ChatMessage {
// val llm = LargeLanguageModels.chat ?: throw NullPointerException("OpenAI Token 未设置,无法开始")
// val availableTools = if (hasTools) {
// myTools.filter { it.isEnabled }.map { it.tool }
// } else null
// val request = ChatCompletionRequest(
// model = ModelId(PluginConfig.chatModel),
// temperature = PluginConfig.chatTemperature,
// messages = chatMessages,
// tools = availableTools,
// )
// logger.info("API Requesting... Model=${PluginConfig.chatModel}")
// return llm.chatCompletions(request)
// val response = llm.chatCompletion(request)
// val message = response.choices.first().message
// logger.info("Response: $message ${response.usage}")
// return message
// }
private suspend fun chatCompletion(
private fun chatCompletions(
chatMessages: List<ChatMessage>,
hasTools: Boolean = true
): ChatMessage {
): Flow<ChatCompletionChunk> {
val llm = LargeLanguageModels.chat ?: throw NullPointerException("OpenAI Token 未设置,无法开始")
val availableTools = if (hasTools) {
myTools.filter { it.isEnabled }.map { it.tool }
} else null
val request = ChatCompletionRequest(
model = ModelId(PluginConfig.chatModel),
temperature = PluginConfig.chatTemperature,
messages = chatMessages,
tools = availableTools,
)
logger.info("API Requesting... Model=${PluginConfig.chatModel}")
val response = llm.chatCompletion(request)
val message = response.choices.first().message
logger.info("Response: $message ${response.usage}")
return message
return llm.chatCompletions(request)
}
private fun getNameCard(member: Member): String {

View File

@ -45,6 +45,7 @@ object PluginCommands : CompositeCommand(
@SubCommand
suspend fun CommandSender.reload() {
PluginConfig.reload()
PluginData.reload()
LargeLanguageModels.reload()
sendMessage("OK")
}

View File

@ -14,6 +14,9 @@ object PluginConfig : AutoSavePluginConfig("Config") {
@ValueDescription("Chat模型")
var chatModel: String by value("qwen-max")
@ValueDescription("Chat模型温度默认为null")
var chatTemperature: Double? by value(null)
@ValueDescription("推理模型API")
var reasoningModelApi: String by value("https://dashscope.aliyuncs.com/compatible-mode/v1/")
@ -47,6 +50,9 @@ object PluginConfig : AutoSavePluginConfig("Config") {
@ValueDescription("好友是否自动拥有对话权限,默认是")
val friendHasChatPermission: Boolean by value(true)
@ValueDescription("机器人是否可以禁言别人,默认禁止")
val canMute: Boolean by value(false)
@ValueDescription("群荣誉等级权限门槛,达到这个等级相当于自动拥有对话权限。")
val temperaturePermission: Int by value(50)

View File

@ -1,7 +1,35 @@
package top.jie65535.mirai
import net.mamoe.mirai.console.data.AutoSavePluginData
import net.mamoe.mirai.console.data.value
object PluginData : AutoSavePluginData("data") {
/**
* 联系人记忆
*/
val contactMemory by value(mutableMapOf<Long, String>())
/**
* 添加对话记忆
*/
fun appendContactMemory(contactId: Long, newMemory: String) {
val memory = contactMemory[contactId]
if (memory.isNullOrEmpty()) {
contactMemory[contactId] = newMemory
} else {
contactMemory[contactId] = "$memory\n$newMemory"
}
}
/**
* 替换对话记忆
*/
fun replaceContactMemory(contactId: Long, oldMemory: String, newMemory: String) {
val memory = contactMemory[contactId]
if (memory.isNullOrEmpty()) {
contactMemory[contactId] = newMemory
} else {
contactMemory[contactId] = memory.replace(oldMemory, newMemory)
}
}
}

View File

@ -0,0 +1,68 @@
package top.jie65535.mirai.tools
import com.aallam.openai.api.chat.Tool
import com.aallam.openai.api.core.Parameters
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.add
import kotlinx.serialization.json.int
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.long
import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonArray
import kotlinx.serialization.json.putJsonObject
import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.event.events.GroupMessageEvent
import net.mamoe.mirai.event.events.MessageEvent
import top.jie65535.mirai.PluginConfig
import kotlin.time.Duration.Companion.seconds
class GroupManageAgent : BaseAgent(
tool = Tool.function(
name = "mute",
description = "可用于禁言指定群成员,只有你是管理员且目标非管理或群主时有效,非必要不要轻易禁言别人,否则你可能会被禁用这个特权!",
parameters = Parameters.buildJsonObject {
put("type", "object")
putJsonObject("properties") {
putJsonObject("target") {
put("type", "integer")
put("description", "目标QQ号")
}
putJsonObject("durationM") {
put("type", "integer")
put("description", "禁言时长分钟目前暂时只支持1~10分钟后续视情况增加上限")
}
}
putJsonArray("required") {
add("target")
add("durationM")
}
}
)
) {
override val isEnabled: Boolean
get() = PluginConfig.canMute
override suspend fun execute(args: JsonObject?, event: MessageEvent): String {
requireNotNull(args)
val target = args.getValue("target").jsonPrimitive.long
val duration = args.getValue("durationM").jsonPrimitive.int
if (event !is GroupMessageEvent) {
return "非群聊环境无法禁言"
}
if (event.group.botPermission == MemberPermission.MEMBER) {
return "你并非管理,无法禁言他人"
}
val member = event.group[target]
if (member == null) {
return "未找到目标群成员"
}
if (member.isMuted) {
return "该目标已被禁言,还剩 " + member.muteTimeRemaining.seconds.toString() + " 解除。"
}
// 禁言指定时长
member.mute(duration.coerceIn(1, 10) * 60)
return "已禁言目标"
}
}

View File

@ -0,0 +1,41 @@
package top.jie65535.mirai.tools
import com.aallam.openai.api.chat.Tool
import com.aallam.openai.api.core.Parameters
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.add
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonArray
import kotlinx.serialization.json.putJsonObject
import net.mamoe.mirai.event.events.MessageEvent
import top.jie65535.mirai.JChatGPT
import top.jie65535.mirai.PluginData
class MemoryAppend : BaseAgent(
tool = Tool.function(
name = "memoryAppend",
description = "新增记忆项",
parameters = Parameters.buildJsonObject {
put("type", "object")
putJsonObject("properties") {
putJsonObject("memory") {
put("type", "string")
put("description", "记忆项")
}
}
putJsonArray("required") {
add("memory")
}
}
)
) {
override suspend fun execute(args: JsonObject?, event: MessageEvent): String {
requireNotNull(args)
val contactId = event.subject.id
val memoryText = args.getValue("memory").jsonPrimitive.content
JChatGPT.logger.info("Remember ($contactId): \"$memoryText\"")
PluginData.appendContactMemory(contactId, memoryText)
return "OK"
}
}

View File

@ -0,0 +1,47 @@
package top.jie65535.mirai.tools
import com.aallam.openai.api.chat.Tool
import com.aallam.openai.api.core.Parameters
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.add
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonArray
import kotlinx.serialization.json.putJsonObject
import net.mamoe.mirai.event.events.MessageEvent
import top.jie65535.mirai.JChatGPT
import top.jie65535.mirai.PluginData
class MemoryReplace : BaseAgent(
tool = Tool.Companion.function(
name = "memoryReplace",
description = "替换记忆项",
parameters = Parameters.Companion.buildJsonObject {
put("type", "object")
putJsonObject("properties") {
putJsonObject("oldMemory") {
put("type", "string")
put("description", "原记忆项")
}
putJsonObject("newMemory") {
put("type", "string")
put("description", "新记忆项")
}
}
putJsonArray("required") {
add("oldMemory")
add("newMemory")
}
}
)
) {
override suspend fun execute(args: JsonObject?, event: MessageEvent): String {
requireNotNull(args)
val contactId = event.subject.id
val oldMemoryText = args.getValue("oldMemory").jsonPrimitive.content
val newMemoryText = args.getValue("newMemory").jsonPrimitive.content
JChatGPT.logger.info("Replace memory ($contactId): \"$oldMemoryText\" -> \"$newMemoryText\"")
PluginData.replaceContactMemory(contactId, oldMemoryText, newMemoryText)
return "OK"
}
}