chenbhao commited on
Commit
f36b9c7
·
1 Parent(s): 5912f74

feat: Friend 消息 → 仅使用人设提示词

Browse files

修改的文件 (5个)

核心流程:Friend 消息 → 仅使用人设提示词

1. src/types/textInputTypes.ts

- 在 QueuedCommand 中添加 overrideSystemPrompt?: string 字段,用于存储替代系统提示词

2. src/skills/bundled/friendPrompt.ts

- 导出 loadPersona() 和 buildVrmSystemPrompt(),供 FriendService 调用

3. src/friend/FriendService.ts

- 在 sendText() 中构建 VRM 人设提示词,作为 overrideSystemPrompt 随消息入队

4. src/utils/handlePromptSubmit.ts

- 在 onQuery 类型中添加 overrideSystemPrompt 参数
- 从 commands[0] 提取并传递给 onQuery

5. src/screens/REPL.tsx

- onQuery 和 onQueryImpl 均接收 overrideSystemPrompt 参数
- 传入 buildEffectiveSystemPrompt(),当该值存在时完全替代默认系统提示词

数据流

FriendService.sendText()
→ buildVrmSystemPrompt() ← 只构建 VRM 人设提示词
→ enqueue({ overrideSystemPrompt, ... })
→ processQueueIfReady()
→ handlePromptSubmit()
→ executeUserInput()
→ onQuery(..., overrideSystemPrompt)
→ onQueryImpl(..., overrideSystemPrompt)
→ buildEffectiveSystemPrompt({ overrideSystemPrompt })
→ 返回 [overrideSystemPrompt] ← 完全绕过 ~900 行 VersperClaw CLI 提示词

现在 /friend 模式下的消息只会使用人设提示词(VRM 情绪工具指令 + IDENTITY.md + SOUL.md),不再注入 VersperClaw
的编程助手系统提示词。

src/friend/FriendService.ts CHANGED
@@ -21,6 +21,7 @@ import { edgeTts, qwenTts, registerAudioFile, getAudioFile } from './tts.js';
21
  import { splitSentences } from './text-utils.js';
22
  import { SileroVad } from './voice/vad-service.js';
23
  import { readFileSync } from 'node:fs';
 
24
 
25
  // ── Types ──────────────────────────────────────────────────────────────
26
 
@@ -169,6 +170,9 @@ class FriendService {
169
  listener({ text: trimmed });
170
  }
171
 
 
 
 
172
  // Dynamically import enqueue to avoid circular deps
173
  import('../utils/messageQueueManager.js').then(({ enqueue }) => {
174
  enqueue({
@@ -177,6 +181,7 @@ class FriendService {
177
  skipSlashCommands: true,
178
  bridgeOrigin: true,
179
  origin: { kind: 'channel', server: 'friend' },
 
180
  });
181
  }).catch((err) => {
182
  console.error('[FriendService] enqueue failed:', err);
 
21
  import { splitSentences } from './text-utils.js';
22
  import { SileroVad } from './voice/vad-service.js';
23
  import { readFileSync } from 'node:fs';
24
+ import { buildVrmSystemPrompt } from '../skills/bundled/friendPrompt.js';
25
 
26
  // ── Types ──────────────────────────────────────────────────────────────
27
 
 
170
  listener({ text: trimmed });
171
  }
172
 
173
+ // Build the override system prompt (persona-only, no VersperClaw CLI prompt)
174
+ const overrideSystemPrompt = buildVrmSystemPrompt();
175
+
176
  // Dynamically import enqueue to avoid circular deps
177
  import('../utils/messageQueueManager.js').then(({ enqueue }) => {
178
  enqueue({
 
181
  skipSlashCommands: true,
182
  bridgeOrigin: true,
183
  origin: { kind: 'channel', server: 'friend' },
184
+ overrideSystemPrompt,
185
  });
186
  }).catch((err) => {
187
  console.error('[FriendService] enqueue failed:', err);
src/screens/REPL.tsx CHANGED
@@ -3565,6 +3565,7 @@ export function REPL({
3565
  additionalAllowedTools: string[],
3566
  mainLoopModelParam: string,
3567
  effort?: EffortValue,
 
3568
  ) => {
3569
  // Prepare IDE integration for new prompt. Read mcpClients fresh from
3570
  // store — useManageMCPConnections may have populated it since the
@@ -3753,6 +3754,7 @@ export function REPL({
3753
  customSystemPrompt,
3754
  defaultSystemPrompt,
3755
  appendSystemPrompt,
 
3756
  })
3757
  toolUseContext.renderedSystemPrompt = systemPrompt
3758
 
@@ -3867,6 +3869,7 @@ export function REPL({
3867
  ) => Promise<boolean>,
3868
  input?: string,
3869
  effort?: EffortValue,
 
3870
  ): Promise<void> => {
3871
  // If this is a teammate, mark them as active when starting a turn
3872
  if (isAgentSwarmsEnabled()) {
@@ -3947,6 +3950,7 @@ export function REPL({
3947
  additionalAllowedTools,
3948
  mainLoopModelParam,
3949
  effort,
 
3950
  )
3951
  } finally {
3952
  // queryGuard.end() atomically checks generation and transitions
 
3565
  additionalAllowedTools: string[],
3566
  mainLoopModelParam: string,
3567
  effort?: EffortValue,
3568
+ overrideSystemPrompt?: string,
3569
  ) => {
3570
  // Prepare IDE integration for new prompt. Read mcpClients fresh from
3571
  // store — useManageMCPConnections may have populated it since the
 
3754
  customSystemPrompt,
3755
  defaultSystemPrompt,
3756
  appendSystemPrompt,
3757
+ overrideSystemPrompt,
3758
  })
3759
  toolUseContext.renderedSystemPrompt = systemPrompt
3760
 
 
3869
  ) => Promise<boolean>,
3870
  input?: string,
3871
  effort?: EffortValue,
3872
+ overrideSystemPrompt?: string,
3873
  ): Promise<void> => {
3874
  // If this is a teammate, mark them as active when starting a turn
3875
  if (isAgentSwarmsEnabled()) {
 
3950
  additionalAllowedTools,
3951
  mainLoopModelParam,
3952
  effort,
3953
+ overrideSystemPrompt,
3954
  )
3955
  } finally {
3956
  // queryGuard.end() atomically checks generation and transitions
src/skills/bundled/friendPrompt.ts CHANGED
@@ -13,7 +13,7 @@ import path from 'node:path'
13
 
14
  const FRIEND_URL = 'http://127.0.0.1:3456/friend/'
15
 
16
- function loadPersona(): string {
17
  const homeDir = process.env.HOME || process.env.USERPROFILE || ''
18
  const baseDir = path.join(homeDir, '.config', 'VersperClaw', 'friend')
19
  const parts: string[] = []
@@ -37,7 +37,7 @@ function loadPersona(): string {
37
  return parts.join('\n\n')
38
  }
39
 
40
- function buildVrmSystemPrompt(): string {
41
  const prefs = getPrefs()
42
  const moodIndex = (prefs as any)._moodIndex ?? 60
43
 
 
13
 
14
  const FRIEND_URL = 'http://127.0.0.1:3456/friend/'
15
 
16
+ export function loadPersona(): string {
17
  const homeDir = process.env.HOME || process.env.USERPROFILE || ''
18
  const baseDir = path.join(homeDir, '.config', 'VersperClaw', 'friend')
19
  const parts: string[] = []
 
37
  return parts.join('\n\n')
38
  }
39
 
40
+ export function buildVrmSystemPrompt(): string {
41
  const prefs = getPrefs()
42
  const moodIndex = (prefs as any)._moodIndex ?? 60
43
 
src/types/textInputTypes.ts CHANGED
@@ -355,6 +355,12 @@ export type QueuedCommand = {
355
  * unified the queue but lost the isolation the dual-queue accidentally had).
356
  */
357
  agentId?: AgentId
 
 
 
 
 
 
358
  }
359
 
360
  /**
 
355
  * unified the queue but lost the isolation the dual-queue accidentally had).
356
  */
357
  agentId?: AgentId
358
+ /**
359
+ * When set, completely replaces the default system prompt for this query.
360
+ * Used by Friend mode to use ONLY the persona prompt instead of the full
361
+ * VersperClaw CLI system prompt.
362
+ */
363
+ overrideSystemPrompt?: string
364
  }
365
 
366
  /**
src/utils/handlePromptSubmit.ts CHANGED
@@ -69,6 +69,7 @@ type BaseExecutionParams = {
69
  onBeforeQuery?: (input: string, newMessages: Message[]) => Promise<boolean>,
70
  input?: string,
71
  effort?: EffortValue,
 
72
  ) => Promise<void>
73
  setAppState: (updater: (prev: AppState) => AppState) => void
74
  onBeforeQuery?: (input: string, newMessages: Message[]) => Promise<boolean>
@@ -556,6 +557,7 @@ async function executeUserInput(params: ExecuteUserInputParams): Promise<void> {
556
  primaryCmd && typeof primaryCmd.value === 'string'
557
  ? primaryCmd.value
558
  : undefined
 
559
  const shouldCallBeforeQuery = primaryMode === 'prompt'
560
  await onQuery(
561
  newMessages,
@@ -568,6 +570,7 @@ async function executeUserInput(params: ExecuteUserInputParams): Promise<void> {
568
  shouldCallBeforeQuery ? onBeforeQuery : undefined,
569
  primaryInput,
570
  effort,
 
571
  )
572
  } else {
573
  // Local slash commands that skip messages (e.g., /model, /theme).
 
69
  onBeforeQuery?: (input: string, newMessages: Message[]) => Promise<boolean>,
70
  input?: string,
71
  effort?: EffortValue,
72
+ overrideSystemPrompt?: string,
73
  ) => Promise<void>
74
  setAppState: (updater: (prev: AppState) => AppState) => void
75
  onBeforeQuery?: (input: string, newMessages: Message[]) => Promise<boolean>
 
557
  primaryCmd && typeof primaryCmd.value === 'string'
558
  ? primaryCmd.value
559
  : undefined
560
+ const overrideSystemPrompt = commands[0]?.overrideSystemPrompt
561
  const shouldCallBeforeQuery = primaryMode === 'prompt'
562
  await onQuery(
563
  newMessages,
 
570
  shouldCallBeforeQuery ? onBeforeQuery : undefined,
571
  primaryInput,
572
  effort,
573
+ overrideSystemPrompt,
574
  )
575
  } else {
576
  // Local slash commands that skip messages (e.g., /model, /theme).