☰
Operit 原生角色卡管理工具:SoftwareSettings 角色卡完整管理接口的实现与脚本接入指南
2026/9/27 9:03:54 网站建设 项目流程
  • AI Agent
  • 人工智能
  • 大模型
  • AI 应用
  • 工具调用
  • 本地部署
  • MCP Clients
  • Agent 记忆

【免费下载链接】Operit

The most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent

项目地址:https://gitcode.com/gh_mirrors/op/Operit
点击查看免费下载

本文以 Operit 仓库 docs/TODO/character_card_software_settings_20260805 系列文档为主线,系统讲解 Operit 如何把角色卡(Character Card)的完整管理能力下沉到原生层,并以Tools.SoftwareSettings的形式开放给脚本与 AI Agent 使用。读完本文,你将掌握九个角色卡原生工具的名称、参数、返回值与字段边界,理解 JavaScript 桥、TypeScript 声明与 Operit Editor 三者的同步契约,并能直接编写脚本完成角色卡的列出、详情、创建、更新、删除、激活以及酒馆 JSON 导入导出。

背景:角色卡在 Operit 中的定位与旧实现的局限

角色卡是 Operit 会话人格的核心载体,承载角色的描述、开场白、聊天/语音附加内容、绑定的模型配置与记忆档案,以及工具访问白名单等完整配置。在本次改造之前,角色卡存在一个明显的断层:

  • 底层管理器CharacterCardManager已经具备角色卡的读取、创建、更新、删除、激活以及酒馆 JSON(Tavern JSON)导入导出能力;
  • 但脚本侧只有Tools.Chat.listCharacterCards()一个只读方法,其返回内容仅用于创建会话时的选卡,缺少完整字段与管理操作;
  • Tools.SoftwareSettings与operit_editor均无法管理角色卡,角色卡主要由设置 UI 消费。

这意味着 AI Agent 或第三方脚本无法通过工具调用完成"创建一张新卡、编辑人格设定、切换当前活跃卡、把卡片导出为酒馆 JSON"这类操作,管理能力被 UI 独占。本次改造的目标正是把CharacterCardManager的能力通过原生工具、JavaScript 桥与编辑器三层完整暴露出来。

九个原生工具:完整 API 契约

改造的核心动作是在StandardSoftwareSettingsModifyTools中直接调用CharacterCardManager,并由ToolRegistration注册对应原生工具,同时新增结构化结果类型,完整传递角色卡的配置字段与当前活跃角色卡 ID。完整的工具清单如下:

原生工具名语义关键参数返回内容
list_character_cards_settings列出全部角色卡与活跃卡 ID无totalCount、activeCharacterCardId、cards[]
get_character_card获取指定角色卡character_card_id单张卡片 +activeCharacterCardId
create_character_card创建角色卡(只接受可编辑字段)name(必填)+ 可编辑字段created、card、activeCharacterCardId、changedFields
update_character_card合并更新指定可编辑字段character_card_id+ 可编辑字段updated、card、activeCharacterCardId、changedFields
delete_character_card删除非默认角色卡character_card_iddeleted、characterCardId、activeCharacterCardId
set_active_character_card设置当前活跃角色卡character_card_idactiveCharacterCardId
clear_active_character_card清除活跃角色卡无activeCharacterCardId = null
import_character_card_from_tavern_json从酒馆 JSON 导入一张卡tavern_jsonimported、card、activeCharacterCardId
export_character_card_to_tavern_json导出指定卡为酒馆 JSONcharacter_card_idcharacterCardId、tavernJson

这九个工具的注册集中在 app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt,每个工具都通过handler.registerTool注册,executor统一从ToolGetter.getSoftwareSettingsModifyTools(context)获取执行器并在Dispatchers.IO上运行。例如create_character_card的描述生成器会动态拼出Create character card: <name>,get_character_card则拼出Get character card settings: <id>,方便模型在工具调用时直接理解上下文。

实现细节:每个工具的执行器做了什么

执行器实现位于 StandardSoftwareSettingsModifyTools.kt,几个关键行为可以从源码确认:

  • 列表(listCharacterCards):调用CharacterCardManager.getInstance(context).getAllCharacterCards()后逐张映射为CharacterCardResultItem,同时通过observeActiveCharacterCardId().first()读取当前活跃卡 ID。映射后的条目包含id、name、description、characterSetting、openingStatement、otherContentChat、otherContentVoice、attachedTagIds、advancedCustomPrompt、marks、模型/记忆绑定字段、toolAccessConfig以及isDefault、createdAt、updatedAt。
  • 详情(getCharacterCard):character_card_id缺失时返回Missing required parameter: character_card_id;卡片不存在时抛出Character card not found: <id>。
  • 创建(createCharacterCard):以CharacterCard(id = "", name = "")为底稿,要求name必填且不能为空白,其余可编辑字段按需叠加;随后由管理器分配 ID 并持久化。
  • 更新(updateCharacterCard):先按 ID 取出当前卡,仅合并调用方传入的字段;如果没有任何字段变更,会直接报错At least one character card update field is required,避免空操作。
  • 删除(deleteCharacterCard):默认卡default_character不可删除,源码中对此有显式拦截:The default character card cannot be deleted。
  • 导入/导出(Tavern JSON):分别委托CharacterCardManager.createCharacterCardFromTavernJson(tavernJson)与exportCharacterCardToTavernJson(id),失败路径会返回Result中的异常信息,成功路径返回完整卡片或 JSON 字符串。

字段边界:哪些可写,哪些由管理器维护

SoftwareSettings负责角色卡配置本身,Chat只在创建会话或发送消息时引用角色卡。更重要的是写入接口只接受可编辑字段:角色卡 ID、创建时间、默认角色卡属性由CharacterCardManager维护,调用方无法通过更新接口改变它们。这一点在 index.md 中被明确为接口边界。

可编辑字段(即CharacterCardWriteOptions,定义于 examples/types/software_settings.d.ts):

字段类型说明
namestring创建时必填;更新时可选
descriptionstring角色简介
character_settingstring角色设定(人格描述)
opening_statementstring开场白
other_content_chatstring聊天附加内容
other_content_voicestring语音附加内容
advanced_custom_promptstring高级自定义提示词
marksstring标记/备注
attached_tag_idsstring \| string[]关联标签 ID,支持字符串数组或其 JSON 字符串表示
chat_model_binding_mode'FOLLOW_GLOBAL' \| 'FIXED_CONFIG'会话模型绑定模式
chat_model_config_idstring绑定的模型配置 ID,空字符串清除绑定
chat_model_indexnumber绑定模型在配置中的索引,须大于等于 0
memory_profile_binding_mode'FOLLOW_GLOBAL' \| 'FIXED_PROFILE'记忆档案绑定模式
memory_profile_idstring绑定的记忆档案 ID,空字符串清除绑定
tool_access_enabledboolean是否启用该卡的工具访问控制
allowed_builtin_toolsstring \| string[]允许的内置工具白名单
allowed_packagesstring \| string[]允许的沙箱包白名单
allowed_skillsstring \| string[]允许的技能白名单
allowed_mcp_serversstring \| string[]允许的 MCP 服务器白名单

从 StandardSoftwareSettingsModifyTools.kt 的applyCharacterCardUpdates实现可以看到字段校验的细节:

  • 布尔参数(tool_access_enabled)复用parseBooleanParameter,接受1/true/yes/y/on与0/false/no/n/off的宽松写法;
  • 字符串数组参数(attached_tag_ids、allowed_*)通过parseStringArrayParameter解析,必须是合法 JSON 数组且每个元素为字符串,解析后自动去重、剔除空项;
  • chat_model_binding_mode与memory_profile_binding_mode只接受各自枚举的两个取值,其余值直接抛Invalid ... mode异常;
  • chat_model_index必须是整数且>= 0;
  • 所有数组/绑定白名单在写入前会经过normalized()处理,保证存储形态一致。

原生层设计:单一实现,副作用不分散

文档明确要求:"角色卡工具使用既有管理器,确保主题、Waifu 设置、自定义表情、聊天绑定和提示词标签的副作用仍由单一实现处理。" 这意味着工具层只做参数解析、校验与结果映射,所有副作用(如切换活跃卡时联动切换 Waifu 设置、头像、提示词标签、模型绑定刷新)都收敛在CharacterCardManager内部。

这一设计在 CharacterCardManager.kt 中可以得到印证:DEFAULT_CHARACTER_CARD_ID = "default_character"(第 96 行),createCharacterCard为非默认卡分配UUID.randomUUID(),setActiveCharacterCard/clearActiveCharacterCard会同步处理活跃状态与关联的 Waifu、头像等衍生数据;删除活跃卡后活跃状态会回落到默认卡。工具层绝不复制这套副作用逻辑。

脚本层:JavaScript 桥与调用方式

原生工具通过 app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsTools.kt 暴露为Tools.SoftwareSettings的方法,方法名与原生工具一一对应:

// 列出全部角色卡与活跃卡 ID Tools.SoftwareSettings.listCharacterCards(); // 获取指定角色卡 Tools.SoftwareSettings.getCharacterCard(characterCardId); // 创建角色卡(options 中 name 必填) Tools.SoftwareSettings.createCharacterCard({ name: "新角色", description: "..." }); // 合并更新(第二个参数只传要改的字段) Tools.SoftwareSettings.updateCharacterCard(characterCardId, { marks: "v2" }); // 删除非默认卡 Tools.SoftwareSettings.deleteCharacterCard(characterCardId); // 激活 / 清除活跃卡 Tools.SoftwareSettings.setActiveCharacterCard(characterCardId); Tools.SoftwareSettings.clearActiveCharacterCard(); // 酒馆 JSON 导入 / 导出 Tools.SoftwareSettings.importCharacterCardFromTavernJson(tavernJson); Tools.SoftwareSettings.exportCharacterCardToTavernJson(characterCardId);

桥层实现为toolCall("get_character_card", { character_card_id: characterCardId })这类透传调用,把 JS 参数原样映射为原生工具的parameters。值得注意的是,会话工具Tools.Chat.listCharacterCards()(对应list_character_cards)继续保留,会话选卡场景的既有调用方式不受影响,这与 index.md 中"继续保留Tools.Chat.listCharacterCards()"的预期结果一致。

TypeScript 声明:严格类型约束

类型声明位于 examples/types/software_settings.d.ts,为输入输出提供严格类型:

  • 两个绑定模式枚举:CharacterCardChatModelBindingMode = 'FOLLOW_GLOBAL' | 'FIXED_CONFIG'、CharacterCardMemoryProfileBindingMode = 'FOLLOW_GLOBAL' | 'FIXED_PROFILE';
  • CharacterCardWriteOptions覆盖全部可编辑字段(见上文字段表);
  • 九个方法均返回带Promise的结构化结果类型:CharacterCardsResultData、CharacterCardResultData、CharacterCardCreateResultData、CharacterCardUpdateResultData、CharacterCardDeleteResultData、CharacterCardActivationResultData、CharacterCardImportResultData、CharacterCardExportResultData。

例如创建接口的签名是createCharacterCard(options: CharacterCardWriteOptions & { name: string }): Promise<CharacterCardCreateResultData>,在类型层强制name必填;更新接口则是updateCharacterCard(characterCardId: string, updates: CharacterCardWriteOptions),对应原生实现的合并语义。

Operit Editor:九个角色卡管理工具的注册

脚本侧之外,operit_editor也同步注册了九个角色卡管理工具,形成"包内可调用"的管理能力。同步范围在 2_ScriptApiAndOperitEditor.md 中被明确为三个文件,契约必须一致:

  • examples/operit_editor.ts:编辑器源文件;
  • examples/operit_editor.js:其 JavaScript 产物;
  • app/src/main/assets/packages/operit_editor.js:内置包副本。

editor 侧同样覆盖列卡、详情、创建、更新、删除、激活、清除活跃、导入、导出九个工具,且元数据统一使用 JSON 字符串数组来表示数组参数(如attached_tag_ids、allowed_builtin_tools等),与原生parseStringArrayParameter的解析约定对齐。

数组参数的两种写法约定

文档特别强调:"数组参数支持 string array 及其 JSON 字符串表示,editor 元数据统一使用 JSON 字符串数组。" 也就是说,在脚本与 editor 层,同一个数组字段有两种等价写法:

// 写法一:直接传字符串数组 Tools.SoftwareSettings.updateCharacterCard(id, { allowed_packages: ["worldbook", "deepsearching"] }); // 写法二:传 JSON 字符串(editor 元数据统一采用此形态) Tools.SoftwareSettings.updateCharacterCard(id, { allowed_packages: '["worldbook", "deepsearching"]' });

原生parseStringArrayParameter对二者统一处理:JSON 数组逐元素校验为字符串、去空、去重后再持久化。

源码复核与交付检查

交付环节(3_VerificationAndDelivery.md)围绕五个检查项完成静态复核,不执行编译、构建或测试命令:

  1. 原生工具注册名、软件设置执行器和 JavaScript 桥一一对应(ToolRegistration 九个名字 ↔StandardSoftwareSettingsModifyTools九个方法 ↔ JsTools 九个桥方法);
  2. TypeScript 参数和结果类型与原生字段一致;
  3. operit_editor.ts的工具定义、参数校验和调用覆盖全部角色卡接口;
  4. JavaScript 产物与应用内置副本同步(examples/operit_editor.js与app/src/main/assets/packages/operit_editor.js哈希一致,git diff --check无空白错误);
  5. 现有Tools.Chat.listCharacterCards()继续保留。

复核确认了原生注册名、JavaScript 桥、TypeScript 声明和 editor 的接口数量与名称完全一致,工具注册、JavaScript 桥、类型声明和 editor 入口四条链路闭环。

小结:从 UI 独占到工具开放

本次改造把角色卡从"UI 独占、脚本只读"升级为"原生工具 + JavaScript 桥 + TypeScript 声明 + Operit Editor"四层完整开放的配置管理接口:

  • 原生层由StandardSoftwareSettingsModifyTools承载九个工具,ToolRegistration注册,CharacterCardManager作为唯一副作用实现;
  • 脚本层以Tools.SoftwareSettings九个方法提供完整增删改查与激活/导入导出能力,会话层Tools.Chat.listCharacterCards()保持兼容;
  • 类型层用CharacterCardWriteOptions与九个结构化结果类型约束输入输出;
  • 编辑器层同步注册九个工具,三份产物契约一致。

对开发者而言,这意味着任何沙箱脚本、toolpkg 包或 AI Agent 都可以在运行期以结构化数据驱动角色卡全生命周期管理——从批量整理卡片、按规则切换活跃角色,到跨设备以酒馆 JSON 迁移人格设定,都不再需要依赖人工在设置 UI 中逐项操作。相关文档与代码可继续参阅 任务总览、原生实现 与 类型声明。

  • AI Agent
  • 人工智能
  • 大模型
  • AI 应用
  • 工具调用
  • 本地部署
  • MCP Clients
  • Agent 记忆

【免费下载链接】Operit

The most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent

项目地址:https://gitcode.com/gh_mirrors/op/Operit
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询