@musnows/scriverse 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/store.js CHANGED
@@ -5561,6 +5561,7 @@ export class Store {
5561
5561
  return {
5562
5562
  workId,
5563
5563
  roleplayCharacterId: optionalString(conversation, "roleplay_character_id"),
5564
+ roleplayUserCharacterId: optionalString(conversation, "roleplay_user_character_id"),
5564
5565
  summary: requiredString(conversation, "compacted_summary"),
5565
5566
  compactedMessageCount,
5566
5567
  totalMessageCount,
@@ -5704,14 +5705,27 @@ export class Store {
5704
5705
  this.audit(workId, "ai-conversation.deleted", "ai-conversation", conversationId, {});
5705
5706
  });
5706
5707
  }
5707
- setAiConversationRoleplayCharacter(conversationId, characterId) {
5708
+ setAiConversationRoleplayCharacter(conversationId, characterId, userCharacterId) {
5708
5709
  const conversation = this.db.get("SELECT * FROM ai_conversations WHERE id = ?", conversationId);
5709
5710
  if (!conversation)
5710
5711
  throw notFound("AI 对话");
5711
5712
  const workId = requiredString(conversation, "work_id");
5712
5713
  const previousCharacterId = optionalString(conversation, "roleplay_character_id");
5713
- if (previousCharacterId === characterId)
5714
+ const previousUserCharacterId = optionalString(conversation, "roleplay_user_character_id");
5715
+ if (!characterId && userCharacterId) {
5716
+ throw new AppError(400, "ROLEPLAY_USER_CHARACTER_REQUIRES_AI", "请先选择 AI 扮演的角色");
5717
+ }
5718
+ const nextUserCharacterId = !characterId
5719
+ ? null
5720
+ : userCharacterId === undefined
5721
+ ? previousCharacterId === characterId ? previousUserCharacterId : null
5722
+ : userCharacterId;
5723
+ if (characterId && characterId === nextUserCharacterId) {
5724
+ throw new AppError(400, "ROLEPLAY_CHARACTER_SAME_AS_USER", "AI 扮演角色与用户扮演角色不能相同");
5725
+ }
5726
+ if (previousCharacterId === characterId && previousUserCharacterId === nextUserCharacterId) {
5714
5727
  return this.getAiConversationSummary(conversationId);
5728
+ }
5715
5729
  const messageCount = Number(this.db.get("SELECT COUNT(*) AS count FROM ai_conversation_messages WHERE conversation_id = ?", conversationId)?.count ?? 0);
5716
5730
  if (messageCount > 0) {
5717
5731
  throw new AppError(409, previousCharacterId ? "ROLEPLAY_CHARACTER_LOCKED" : "ROLEPLAY_CONVERSATION_STARTED", previousCharacterId ? "角色扮演对话开始后不能退出模式或更换角色卡" : "当前对话已经开始,不能中途切换为角色扮演");
@@ -5725,11 +5739,22 @@ export class Store {
5725
5739
  throw new AppError(409, "ROLEPLAY_CHARACTER_MERGED", "已合并角色不能用于角色扮演");
5726
5740
  }
5727
5741
  }
5742
+ if (nextUserCharacterId) {
5743
+ const userCharacter = this.getCharacter(nextUserCharacterId);
5744
+ if (String(userCharacter.workId) !== workId) {
5745
+ throw new AppError(400, "ROLEPLAY_USER_CHARACTER_WORK_MISMATCH", "用户扮演的角色不属于当前作品");
5746
+ }
5747
+ if (userCharacter.mergedIntoCharacterId) {
5748
+ throw new AppError(409, "ROLEPLAY_USER_CHARACTER_MERGED", "已合并角色不能用于关系扮演");
5749
+ }
5750
+ }
5728
5751
  this.db.transaction(() => {
5729
- this.db.run("UPDATE ai_conversations SET roleplay_character_id = ?, task_type = CASE WHEN ? IS NOT NULL THEN 'roleplay' ELSE task_type END, updated_at = ? WHERE id = ?", characterId, characterId, now(), conversationId);
5752
+ this.db.run("UPDATE ai_conversations SET roleplay_character_id = ?, roleplay_user_character_id = ?, task_type = CASE WHEN ? IS NOT NULL THEN 'roleplay' ELSE task_type END, updated_at = ? WHERE id = ?", characterId, nextUserCharacterId, characterId, now(), conversationId);
5730
5753
  this.audit(workId, "ai-conversation.roleplay-updated", "ai-conversation", conversationId, {
5731
5754
  previousCharacterId,
5732
- characterId
5755
+ characterId,
5756
+ previousUserCharacterId,
5757
+ userCharacterId: nextUserCharacterId
5733
5758
  });
5734
5759
  });
5735
5760
  return this.getAiConversationSummary(conversationId);
@@ -5748,7 +5773,7 @@ export class Store {
5748
5773
  throw new AppError(409, "AI_CONVERSATION_TASK_LOCKED", "对话开始后不能切换任务类型");
5749
5774
  }
5750
5775
  this.db.transaction(() => {
5751
- this.db.run("UPDATE ai_conversations SET task_type = ?, roleplay_character_id = CASE WHEN ? = 'roleplay' THEN roleplay_character_id ELSE NULL END, updated_at = ? WHERE id = ?", taskType, taskType, now(), conversationId);
5776
+ this.db.run("UPDATE ai_conversations SET task_type = ?, roleplay_character_id = CASE WHEN ? = 'roleplay' THEN roleplay_character_id ELSE NULL END, roleplay_user_character_id = CASE WHEN ? = 'roleplay' THEN roleplay_user_character_id ELSE NULL END, updated_at = ? WHERE id = ?", taskType, taskType, taskType, now(), conversationId);
5752
5777
  this.audit(workId, "ai-conversation.task-type-updated", "ai-conversation", conversationId, {
5753
5778
  previousTaskType,
5754
5779
  taskType
@@ -6041,7 +6066,7 @@ export class Store {
6041
6066
  ?? JSON.stringify(EMPTY_AI_INJECTED_ENTITIES);
6042
6067
  const systemClockText = optionalString(conversation, "system_clock_text") ?? "";
6043
6068
  this.db.transaction(() => {
6044
- this.db.run("INSERT INTO ai_conversations (id, work_id, roleplay_character_id, task_type, context_scope_json, title, compacted_summary, compacted_message_count, agent_tools_json, injected_entities_json, system_clock_text, created_at, updated_at, created_by_user_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", forkId, workId, optionalString(conversation, "roleplay_character_id"), optionalString(conversation, "task_type"), optionalString(conversation, "context_scope_json"), title.slice(0, 200), forkSummary, forkCompactedCount, conversation.agent_tools_json == null
6069
+ this.db.run("INSERT INTO ai_conversations (id, work_id, roleplay_character_id, roleplay_user_character_id, task_type, context_scope_json, title, compacted_summary, compacted_message_count, agent_tools_json, injected_entities_json, system_clock_text, created_at, updated_at, created_by_user_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", forkId, workId, optionalString(conversation, "roleplay_character_id"), optionalString(conversation, "roleplay_user_character_id"), optionalString(conversation, "task_type"), optionalString(conversation, "context_scope_json"), title.slice(0, 200), forkSummary, forkCompactedCount, conversation.agent_tools_json == null
6045
6070
  ? JSON.stringify(normalizeWorkAgentTools(this.getWorkAiSettings(workId).agentTools))
6046
6071
  : String(conversation.agent_tools_json), injectedEntitiesJson, systemClockText, timestamp, timestamp, currentRequestActor()?.userId ?? null);
6047
6072
  for (const message of messages.slice(0, targetIndex + 1)) {
@@ -6084,6 +6109,7 @@ export class Store {
6084
6109
  }
6085
6110
  mapAiConversation(row) {
6086
6111
  const roleplayCharacterId = optionalString(row, "roleplay_character_id");
6112
+ const roleplayUserCharacterId = optionalString(row, "roleplay_user_character_id");
6087
6113
  const firstUserMessage = this.db.get(`SELECT metadata_json FROM ai_conversation_messages
6088
6114
  WHERE conversation_id = ? AND role = 'user'
6089
6115
  ORDER BY created_at, rowid
@@ -6097,6 +6123,9 @@ export class Store {
6097
6123
  const roleplayCharacter = roleplayCharacterId
6098
6124
  ? this.db.get("SELECT id, name, code FROM characters WHERE id = ? AND work_id = ?", roleplayCharacterId, requiredString(row, "work_id"))
6099
6125
  : undefined;
6126
+ const roleplayUserCharacter = roleplayCharacterId && roleplayUserCharacterId
6127
+ ? this.db.get("SELECT id, name, code FROM characters WHERE id = ? AND work_id = ?", roleplayUserCharacterId, requiredString(row, "work_id"))
6128
+ : undefined;
6100
6129
  return {
6101
6130
  id: requiredString(row, "id"),
6102
6131
  workId: requiredString(row, "work_id"),
@@ -6115,6 +6144,11 @@ export class Store {
6115
6144
  name: requiredString(roleplayCharacter, "name"),
6116
6145
  code: requiredString(roleplayCharacter, "code")
6117
6146
  } : null,
6147
+ roleplayUserCharacter: roleplayUserCharacter ? {
6148
+ id: requiredString(roleplayUserCharacter, "id"),
6149
+ name: requiredString(roleplayUserCharacter, "name"),
6150
+ code: requiredString(roleplayUserCharacter, "code")
6151
+ } : null,
6118
6152
  agentTools: row.agent_tools_json == null || row.agent_tools_json === undefined
6119
6153
  ? null
6120
6154
  : normalizeWorkAgentTools(row.agent_tools_json),