dsh-fish-soul 0.14.0 → 0.14.1

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  让一个 QQ 小号背后有"同一个人":固定人格、按人记记忆、有自己的生活节奏、会主动开口;同一个"她"同时出现在 QQ、B站、抖音。
4
4
 
5
- DSH 插件(单角色 `feiyu`)。版本 **0.14.0**。
5
+ DSH 插件(单角色 `feiyu`)。版本 **0.14.1**。
6
6
 
7
7
  ## 能力
8
8
 
package/lib/db.js CHANGED
@@ -400,6 +400,17 @@ export function randomCanonicalId() {
400
400
  return `p_${Math.floor(Math.random() * 0xffffffff).toString(16).padStart(8, '0')}`;
401
401
  }
402
402
 
403
+ /** 桌面端 / 主人兜底:拿到 canonical_id='master' 的 person 行,没有就建一个。 */
404
+ export function ensureMasterPerson(db, nowMs) {
405
+ const row = db.prepare("SELECT * FROM person WHERE canonical_id = 'master'").get();
406
+ if (row) return row;
407
+ db.prepare(`
408
+ INSERT INTO person (canonical_id, display_name, relation_stage, interaction_count, first_seen_at, last_seen_at)
409
+ VALUES ('master', '主人', 'close', 0, ?, ?)
410
+ `).run(nowMs, nowMs);
411
+ return db.prepare("SELECT * FROM person WHERE canonical_id = 'master'").get();
412
+ }
413
+
403
414
  /**
404
415
  * person 原子自动注册(审查 #05):按 qq_uin Upsert。
405
416
  * 主人 QQ 固定映射 canonical_id='master'、relation_stage='close'。
package/lib/index.js CHANGED
@@ -14,7 +14,7 @@ import { readFileSync, writeFileSync, existsSync, renameSync } from 'node:fs';
14
14
  import { loadHostDeps } from './hostdeps.mjs';
15
15
  import {
16
16
  openDatabase, configPath, fishSoulDir, resolveOrCreatePerson, resolveOrCreateBiliPerson, resolveOrCreatePlatformPerson,
17
- findPersonByQq, findPersonByBili, findPersonByDouyin, readVecMeta, getKv, setKv, getProfile
17
+ findPersonByQq, findPersonByBili, findPersonByDouyin, readVecMeta, getKv, setKv, getProfile, ensureMasterPerson
18
18
  } from './db.js';
19
19
  import { BackupService, applyPendingRestore } from './backup.js';
20
20
  import { HistoryImporter } from './history-import.js';
@@ -450,22 +450,28 @@ async function startup(ctx, config, { log, gate }) {
450
450
  sp = list.find((x) => x.displayName === want || x.userId === want) ??
451
451
  list.find((x) => x.displayName.includes(want) || want.includes(x.displayName)) ?? sp;
452
452
  }
453
+ const ch = session?.channel ?? 'dsh';
454
+ let ownerId = sp?.ownerId ?? UNKNOWN_OWNER;
455
+ let person = sp?.person ?? null;
456
+ // #57:桌面端(dsh channel)认作主人——DSH 桌面端是主人自己的环境,没有"别人"。
457
+ if (ch === 'dsh' && ownerId === UNKNOWN_OWNER) {
458
+ person = ensureMasterPerson(db, clock.now());
459
+ ownerId = `user:${person.canonical_id}`;
460
+ }
453
461
  return {
454
- ownerId: sp?.ownerId ?? UNKNOWN_OWNER,
455
- person: sp?.person ?? null,
462
+ ownerId,
463
+ person,
456
464
  query: sp?.query ?? '',
457
- displayName: sp?.displayName ?? '对方',
458
- channel: session?.channel ?? 'dsh',
465
+ displayName: person?.display_name ?? sp?.displayName ?? '对方',
466
+ channel: ch,
459
467
  channelId: session?.channelId ?? ''
460
468
  };
461
469
  }
462
470
 
463
- const UNKNOWN_VIEW = { ownerId: UNKNOWN_OWNER, person: null, displayName: '对方', channel: 'dsh', channelId: '' };
464
-
465
471
  /** 工具调用:按调用所在会话(toolCtx.agent.id)认人;认不出就是 unknown(不读写任何人的记忆)。 */
466
472
  function sessionForTool(toolCtx, speakerName) {
467
473
  const session = sessionFor(toolCtx?.agent?.id ?? toolCtx?.sessionId);
468
- return session === undefined ? UNKNOWN_VIEW : speakerView(session, speakerName);
474
+ return session === undefined ? speakerView(undefined, speakerName) : speakerView(session, speakerName);
469
475
  }
470
476
 
471
477
  const retrievalCfg = () => ({
@@ -696,10 +702,11 @@ async function startup(ctx, config, { log, gate }) {
696
702
  });
697
703
  if (person !== null) life.noteInteraction(ownerOf(person));
698
704
  const groupId = source.groupId ?? source.group_id ?? null;
705
+ // #56:桌面端(person=null)也把消息文本传进去——世界书扫描要用,身份仍是 unknown。
699
706
  beginTurn(agentId, {
700
707
  channel: person === null ? 'dsh' : (groupId != null ? 'qq-group' : 'qq-private'),
701
708
  channelId: person === null ? '' : (groupId != null ? `group:${groupId}` : `private:${qqUin}`),
702
- speakers: person !== null ? [{ person, userId: qqUin, displayName: person.display_name, text: messageText(message) }] : [],
709
+ speakers: [{ person, userId: qqUin, displayName: person?.display_name ?? '对方', text: messageText(message) }],
703
710
  workspacePath: ''
704
711
  });
705
712
  // #41:别的插件把自己的 QQ 消息转进它建的会话 —— 那个会话不走我们的 create/resume,人格卡没挂上。
package/lib/llm.js CHANGED
@@ -142,7 +142,9 @@ export class LlmRouter {
142
142
  return [{ type: 'text', text: prompt }];
143
143
  }
144
144
 
145
- async call(prompt, { signal, maxTokens = 600, feature = 'other', thinkFallback = false, images = [], _target, _tried } = {}) {
145
+ // #58:默认 600 对推理模型太小——光思考就 1000+ token,第一次必然白卷还白烧思考费。
146
+ // 提到 1500 让大多数推理模型的第一轮能容下思考;maxTokens 是上限不是必花,普通模型不受影响。
147
+ async call(prompt, { signal, maxTokens = 1500, feature = 'other', thinkFallback = false, images = [], _target, _tried } = {}) {
146
148
  const llm = this.llm();
147
149
  if (llm === null) return null;
148
150
  const f = FEATURE_IDS.has(feature) ? feature : 'other';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-fish-soul",
3
- "version": "0.14.0",
4
- "description": "鱼 · 人格、按人记忆(可纠正、有印象、能导入旧聊天记录)、日程自走与主动开口,直连 SnowLuma 收发 QQ(群里会自己插话),B站 / 抖音小号私信与自己刷视频;按功能选模型并统计用量花费,能听会说 QQ 语音、收藏表情包、学群里的梗,可选上网查;心情影响说话、去 AI 味、每个群的设定、按聊天选模型、每晚写日记(DSH 插件,单角色 feiyu ,v0.14.0)",
3
+ "version": "0.14.1",
4
+ "description": "鱼 · 人格、按人记忆(可纠正、有印象、能导入旧聊天记录)、日程自走与主动开口,直连 SnowLuma 收发 QQ(群里会自己插话),B站 / 抖音小号私信与自己刷视频;按功能选模型并统计用量花费,能听会说 QQ 语音、收藏表情包、学群里的梗,可选上网查;心情影响说话、去 AI 味、每个群的设定、按聊天选模型、每晚写日记(DSH 插件,单角色 feiyu ,v0.14.1)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
7
7
  "files": [
@@ -62,7 +62,7 @@
62
62
  }
63
63
  },
64
64
  "scripts": {
65
- "test": "node test/smoke.mjs && node test/douyin-browser.mjs && node test/startup-gate.mjs && node test/outbox.mjs && node test/import-coverage.mjs && node test/update-check.mjs && node test/issue-fixes.mjs && node test/import-resume.mjs && node test/maibot-extras.mjs && node test/worldinfo.mjs && node test/memory-bulk.mjs && node test/backup-restore.mjs && node test/douyin-group.mjs && node test/review-fixes.mjs && node test/at-reads-video.mjs && node test/search-source.mjs && node test/followups.mjs && node test/detail-config.mjs && node test/qq-send-any-image.mjs && node test/qq-read-attachment.mjs && node test/qq-batch-window.mjs && node test/comment-video.mjs && node test/frames.mjs && node test/face-name.mjs && node test/comment-reply.mjs && node test/chat-comment.mjs && node test/at-target.mjs && node test/client-lint.mjs",
65
+ "test": "node test/smoke.mjs && node test/douyin-browser.mjs && node test/startup-gate.mjs && node test/outbox.mjs && node test/import-coverage.mjs && node test/update-check.mjs && node test/issue-fixes.mjs && node test/import-resume.mjs && node test/maibot-extras.mjs && node test/worldinfo.mjs && node test/memory-bulk.mjs && node test/backup-restore.mjs && node test/douyin-group.mjs && node test/review-fixes.mjs && node test/at-reads-video.mjs && node test/search-source.mjs && node test/followups.mjs && node test/detail-config.mjs && node test/qq-send-any-image.mjs && node test/qq-read-attachment.mjs && node test/qq-batch-window.mjs && node test/comment-video.mjs && node test/frames.mjs && node test/face-name.mjs && node test/comment-reply.mjs && node test/chat-comment.mjs && node test/at-target.mjs && node test/client-lint.mjs && node test/dsh-desktop.mjs",
66
66
  "eval": "node test/eval/persona-eval.mjs"
67
67
  }
68
68
  }