dsh-fish-soul 0.15.39 → 0.15.40
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 +1 -1
- package/lib/client.douyin.js +1 -1
- package/lib/gateway.js +19 -2
- package/lib/index.js +17 -7
- package/package.json +2 -2
package/README.md
CHANGED
package/lib/client.douyin.js
CHANGED
|
@@ -163,7 +163,7 @@ window.__ModuleLoader__.load({
|
|
|
163
163
|
Row({ title: "主人的名字", desc: "仅作显示(提示词里怎么称呼);不授予任何权限" }, Input({ ...bind("masterName"), placeholder: "她私信列表里你的名字" })),
|
|
164
164
|
Row({ title: "回所有能私信她的人", desc: d.replyAll ? "建议在抖音隐私设置里把「谁可以私信我」设为互关好友" : null },
|
|
165
165
|
sw("回所有能私信她的人", d.replyAll === true, (v) => save({ top: { replyAll: v } }))),
|
|
166
|
-
d.replyAll ? null : Row({ title: "白名单", stack: true }, Area({ ...bind("allowList"), placeholder: "对方的抖音数字 uid,每行一个;昵称不参与放行" })),
|
|
166
|
+
d.replyAll ? null : Row({ title: "白名单", stack: true }, Area({ ...bind("allowList"), placeholder: "对方的抖音数字 uid,每行一个;昵称不参与放行" }))),
|
|
167
167
|
Group({ title: "群聊" },
|
|
168
168
|
Row({ title: "群里被叫到时回", desc: "群聊按说话的人分开认,不会当成一个人;没人 @ 她或叫她名字时只看不说" },
|
|
169
169
|
sw("群里被叫到时回", d.groupReply === true, (v) => save({ top: { groupReply: v } }))),
|
package/lib/gateway.js
CHANGED
|
@@ -278,7 +278,9 @@ export class ChatGateway {
|
|
|
278
278
|
this.decisions.unshift({
|
|
279
279
|
at: Date.now(), kind, channelId, title: title || this.titleOf(channelId),
|
|
280
280
|
who: String(who ?? '').slice(0, 24), text: String(text ?? '').replace(/\s+/g, ' ').slice(0, 80), reason,
|
|
281
|
-
|
|
281
|
+
// #78:以前写死 5 条,用户把「召回条数」调到 10 后动态页永远只显示 5 条,
|
|
282
|
+
// 看起来像「设置没生效」。上限跟 topK 走(再留个 20 的硬顶,别让一条动态撑爆)。
|
|
283
|
+
...(Array.isArray(memories) && memories.length > 0 ? { memories: memories.slice(0, Math.min(20, Math.max(5, Number(this.getConfig?.()?.retrieval?.topK) || 5))) } : {}),
|
|
282
284
|
// #78:这一轮记忆到底有没有参与。没跑 / 认不出人 / 跑了没召回到,界面要分得开 ——
|
|
283
285
|
// 以前三种都是"什么都不显示",看不出问题在哪儿
|
|
284
286
|
...(Number(recallAt) > 0 ? { recallAt: Number(recallAt), speakerUnknown: speakerUnknown === true } : {}),
|
|
@@ -1371,7 +1373,9 @@ export class ChatGateway {
|
|
|
1371
1373
|
// 以前每条都重算 fromUs ⇒ 被它们改成 false ⇒ 回复生成了却不发(DSH 里看得见,QQ / 抖音收不到)。
|
|
1372
1374
|
// 现在只有我们自己的来源置 true;只有真人在界面里打字(kind 'user')才置 false;别的宿主上下文不管。
|
|
1373
1375
|
if (OUR_SOURCES.has(kind)) st.fromUs = true;
|
|
1374
|
-
else if (kind === 'user') st.fromUs = false;
|
|
1376
|
+
else if (kind === 'user') { st.fromUs = false; st.dshTyped = true; } // #78:DSH 桌面端打字,不外发但要记动态
|
|
1377
|
+
// 其他宿主上下文(runtime-context / model-selection 等):不动 fromUs ——
|
|
1378
|
+
// 它们不是我们发的消息,但也不是真人打字,重置会把 B站/抖音 的回复憋回去(smoke #13 守着)
|
|
1375
1379
|
// 共享会话里一个会话对应多个通道(QQ + B站):这一轮从哪个通道进来的,来源里也带着 ——
|
|
1376
1380
|
// 开轮时 dispatch 已经登记过,这里兜的是「插件重启后宿主重放消息」那条路(否则会回错平台)
|
|
1377
1381
|
if (OUR_SOURCES.has(kind) && msg?.source?.channelId) st.channelId = String(msg.source.channelId);
|
|
@@ -1409,6 +1413,19 @@ export class ChatGateway {
|
|
|
1409
1413
|
};
|
|
1410
1414
|
if (!completed || !st.fromUs) {
|
|
1411
1415
|
if (st.fromUs) this.note('failed', { channelId: st.channelId ?? this.bound.get(sessionId)?.channel_id ?? '', reason: `这一轮没正常结束(${d.reason?.kind ?? '未知'})` });
|
|
1416
|
+
// #78:DSH 桌面端打字的轮次不外发,但**要记动态** —— 以前在 DSH 里聊,动态页整片空白。
|
|
1417
|
+
if (st.dshTyped === true) {
|
|
1418
|
+
const recall = this.soul.recallInfo?.(sessionId, st) ?? { memories: [], at: 0, unknown: false };
|
|
1419
|
+
this.note('dsh', {
|
|
1420
|
+
channelId: st.channelId ?? this.bound.get(sessionId)?.channel_id ?? '',
|
|
1421
|
+
text: String(st.text ?? '').slice(0, 60),
|
|
1422
|
+
reason: '在 DSH 里聊的,不外发',
|
|
1423
|
+
memories: recall.memories ?? [],
|
|
1424
|
+
recallAt: recall.at ?? 0,
|
|
1425
|
+
speakerUnknown: recall.unknown === true,
|
|
1426
|
+
recallMiss: recall.miss ?? ''
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1412
1429
|
this.interjectTurns.delete(sessionId);
|
|
1413
1430
|
settle(false);
|
|
1414
1431
|
return;
|
package/lib/index.js
CHANGED
|
@@ -71,7 +71,7 @@ const defineTool = hostDeps.defineTool;
|
|
|
71
71
|
export const name = 'dsh-fish-soul';
|
|
72
72
|
|
|
73
73
|
/** 只给测试用:换掉抖音专用浏览器的启动 / 页面驱动(抖音网页在测试里打不开)。正式运行时是空的。 */
|
|
74
|
-
export const testHooks = { douyin: null, memory: null };
|
|
74
|
+
export const testHooks = { douyin: null, memory: null, gateway: null };
|
|
75
75
|
// agents / workspaceRegistry:给每个 QQ 聊天建会话;sessionTitle / attachments / agentPresets /
|
|
76
76
|
// agentDefaultModel 是可选的,运行时用 ctx.get 取,缺了就降级(不写进 inject,免得整个插件不激活)。
|
|
77
77
|
export const inject = ['webServer', 'tools', 'systemPrompt', 'llm', 'agents', 'workspaceRegistry'];
|
|
@@ -856,10 +856,15 @@ async function startup(ctx, config, { log, gate }) {
|
|
|
856
856
|
// mountSectionsFor 有幂等保护(sectionsMounted),所有会话都在 inbox 时补挂一次做保险。
|
|
857
857
|
mountSectionsFor(payload?.agent);
|
|
858
858
|
if (source.kind === SOURCE_QQ || source.kind === SOURCE_PROACTIVE || source.kind === SOURCE_BILI || source.kind === SOURCE_DOUYIN) return;
|
|
859
|
-
if (gateway?.isOurSession(agentId)) return;
|
|
860
859
|
if (agentId === undefined || agentId === null) return;
|
|
860
|
+
// #78:**在 DSH 界面里打开我们的会话打字**时,isOurSession 是 true,但消息不走
|
|
861
|
+
// gateway.dispatch(那条路只服务 QQ / B站 / 抖音 的入站),于是没有 beginTurn、
|
|
862
|
+
// 也没有 note —— 动态页整片空白。用户原话:「只能在 QQ 上说话才能正常调起功能」。
|
|
863
|
+
// 现在这条路也登记一轮:身份按 DSH 桌面端算(#57:桌面端就是主人自己的环境)。
|
|
864
|
+
const ours = gateway?.isOurSession(agentId) === true;
|
|
861
865
|
const qqUin = String(source.userId ?? source.qqUin ?? source.user_id ?? '');
|
|
862
|
-
|
|
866
|
+
// 我们的会话在 DSH 里被打开时,说话的人就是主人自己 —— 不去猜 QQ 号(那会建出幽灵 person)
|
|
867
|
+
const person = ours || qqUin === '' ? null : resolveOrCreatePerson(db, {
|
|
863
868
|
qqUin, nickname: String(source.nickname ?? ''), nowMs: clock.now(), masterQqUin: currentConfig.masterQqUin ?? ''
|
|
864
869
|
});
|
|
865
870
|
if (person !== null) life.noteInteraction(ownerOf(person));
|
|
@@ -868,11 +873,14 @@ async function startup(ctx, config, { log, gate }) {
|
|
|
868
873
|
else life.noteInteraction('user:master');
|
|
869
874
|
const groupId = source.groupId ?? source.group_id ?? null;
|
|
870
875
|
// #56:桌面端(person=null)也把消息文本传进去——世界书扫描要用,身份仍是 unknown。
|
|
876
|
+
// 我们的会话在 DSH 里打字:沿用这个会话真正的 channelId(记忆/日志仍按它归),
|
|
877
|
+
// 只是说话人按主人算 —— 这样瞬态块能跑、动态页也能显示这一轮想起了什么。
|
|
878
|
+
const boundChannel = ours ? (gateway?.chatForSession(agentId)?.channel_id ?? '') : '';
|
|
871
879
|
beginTurn(agentId, {
|
|
872
|
-
channel: person === null ? 'dsh' : (groupId != null ? 'qq-group' : 'qq-private'),
|
|
873
|
-
channelId: person === null ? '' : (groupId != null ? `group:${groupId}` : `private:${qqUin}`),
|
|
874
|
-
speakers: [{ person, userId: qqUin, displayName: person?.display_name ?? '对方', text: messageText(message) }],
|
|
875
|
-
workspacePath: ''
|
|
880
|
+
channel: ours ? sessionChannelOf(boundChannel) : (person === null ? 'dsh' : (groupId != null ? 'qq-group' : 'qq-private')),
|
|
881
|
+
channelId: ours ? boundChannel : (person === null ? '' : (groupId != null ? `group:${groupId}` : `private:${qqUin}`)),
|
|
882
|
+
speakers: [{ person, userId: qqUin, displayName: person?.display_name ?? (ours ? '主人' : '对方'), text: messageText(message) }],
|
|
883
|
+
workspacePath: ours ? (gateway?.chatForSession(agentId)?.workspace_path ?? '') : ''
|
|
876
884
|
});
|
|
877
885
|
// #41:别的插件把自己的 QQ 消息转进它建的会话 —— 那个会话不走我们的 create/resume,人格卡没挂上。
|
|
878
886
|
// 认出身份后(有人说话)用宿主给的 `agent.ctx` 补挂,仍然只对这一个 agent 生效,不碰全局。
|
|
@@ -921,6 +929,7 @@ async function startup(ctx, config, { log, gate }) {
|
|
|
921
929
|
slang.start();
|
|
922
930
|
ctx.effect(() => () => slang.stop(), 'dsh-fish-soul: slang');
|
|
923
931
|
|
|
932
|
+
testHooks.gateway = null;
|
|
924
933
|
gateway = new ChatGateway({
|
|
925
934
|
ctx, db, clock, getConfig, log, channel, bili, browser, douyin, douyinBrowser, canvasConvert, voice, stickers, slang,
|
|
926
935
|
// 按感觉挑表情:复用记忆那套嵌入模型(主人拍板)。没配就跟以前一样按文件名发
|
|
@@ -1075,6 +1084,7 @@ async function startup(ctx, config, { log, gate }) {
|
|
|
1075
1084
|
|
|
1076
1085
|
log('info', '[fish-soul] 路由已挂:设置页接口可用');
|
|
1077
1086
|
|
|
1087
|
+
testHooks.gateway = gateway;
|
|
1078
1088
|
step(STARTUP_STEPS[15]);
|
|
1079
1089
|
// 只挂与具体 agent 无关的全局钩子(互动登记)。人格卡 / 瞬态块是 per-agent 的,
|
|
1080
1090
|
// 在 gateway 的 setup(agentCtx) 里挂,这里不再注册任何全局 prompt 段。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-fish-soul",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.40",
|
|
4
4
|
"description": "鱼 · 人格、按人记忆(可纠正、有印象、能导入旧聊天记录)、日程自走与主动开口,直连 SnowLuma 收发 QQ(群里会自己插话),B站 / 抖音小号私信与自己刷视频;按功能选模型并统计用量花费,能听会说 QQ 语音、收藏表情包、学群里的梗,可选上网查;心情影响说话、去 AI 味、每个群的设定、按聊天选模型、每晚写日记、每周记忆存档与可选周记(DSH 插件,单角色 feiyu ,v0.15.37)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
|
-
"test": "node test/safe-download.mjs && node test/douyin-exact-id.mjs && node test/douyin-pb-init.mjs && node test/douyin-conversation.mjs && node test/douyin-inbox.mjs && node test/douyin-quarantine.mjs && node test/douyin-send-target.mjs && node test/douyin-gap-dedupe.mjs && node test/douyin-read-fail-retry.mjs && node test/douyin-read-cache.mjs && node test/douyin-read-fail-retry-poll.mjs && node test/douyin-inbox-contract.mjs && node test/memory-owner-reassign.mjs && node test/douyin-poll-and-timer-safety.mjs && node test/p2-limits.mjs && node test/resource-safety.mjs && node test/leftover-edge-cases.mjs && node test/douyin-master-uid.mjs && node test/douyin-identity-e2e.mjs && node test/douyin-post-jobs.mjs && node test/retrieval-filtered-vectors.mjs && node test/security-boundaries.mjs && node test/smoke.mjs && node test/douyin-browser.mjs && node test/douyin-music.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/memory-tiers.mjs && node test/memory-weekly.mjs && node test/memory-storage.mjs && node test/memory-storage-restore.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/quota-caps.mjs && node test/client-lint.mjs && node test/client-panels.mjs && node test/dsh-desktop.mjs && node test/issue-59-interject.mjs && node test/issue-59-diagnose.mjs && node test/sticker-manage.mjs && node test/bili-emotes.mjs && node test/qq-outbound-sanitize.mjs && node test/person-delete.mjs && node test/qq-group-admin.mjs && node test/douyin-recovery.mjs && node test/session-preset.mjs && node test/qq-connect-error.mjs && node test/douyin-comment-bridge.mjs && node test/bili-comment-emoji.mjs && node test/douyin-state-echo.mjs && node test/issue-75-proactive.mjs && node test/issue-76-capability.mjs && node test/douyin-http-browse.mjs && node test/douyin-verify-backoff.mjs && node test/douyin-digg-bridge.mjs && node test/memory-evidence-transcript.mjs && node test/chat-archive-default.mjs && node test/dream-transcript-wire.mjs && node test/douyin-frames-collect.mjs && node test/master-qq-uin-rebind.mjs && node test/douyin-session-health.mjs && node test/douyin-delivered.mjs && node test/douyin-card-share.mjs && node test/douyin-push-drop.mjs && node test/douyin-uid-binding.mjs && node test/image-webp-fallback.mjs && node test/douyin-emoji-fallback.mjs && node test/relay-other-platform.mjs && node test/voice-volcengine.mjs && node test/voice-minimax-dashscope.mjs && node test/bili-switch-persist.mjs && node test/cross-channel-context.mjs && node test/reply-target.mjs && node test/shared-session.mjs && node test/memory-source-label.mjs && node test/pending-delivery.mjs && node test/recall-window-78.mjs && node test/self-update.mjs",
|
|
67
|
+
"test": "node test/safe-download.mjs && node test/douyin-exact-id.mjs && node test/douyin-pb-init.mjs && node test/douyin-conversation.mjs && node test/douyin-inbox.mjs && node test/douyin-quarantine.mjs && node test/douyin-send-target.mjs && node test/douyin-gap-dedupe.mjs && node test/douyin-read-fail-retry.mjs && node test/douyin-read-cache.mjs && node test/douyin-read-fail-retry-poll.mjs && node test/douyin-inbox-contract.mjs && node test/memory-owner-reassign.mjs && node test/douyin-poll-and-timer-safety.mjs && node test/p2-limits.mjs && node test/resource-safety.mjs && node test/leftover-edge-cases.mjs && node test/douyin-master-uid.mjs && node test/douyin-identity-e2e.mjs && node test/douyin-post-jobs.mjs && node test/retrieval-filtered-vectors.mjs && node test/security-boundaries.mjs && node test/smoke.mjs && node test/douyin-browser.mjs && node test/douyin-music.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/memory-tiers.mjs && node test/memory-weekly.mjs && node test/memory-storage.mjs && node test/memory-storage-restore.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/quota-caps.mjs && node test/client-lint.mjs && node test/client-panels.mjs && node test/dsh-desktop.mjs && node test/issue-59-interject.mjs && node test/issue-59-diagnose.mjs && node test/sticker-manage.mjs && node test/bili-emotes.mjs && node test/qq-outbound-sanitize.mjs && node test/person-delete.mjs && node test/qq-group-admin.mjs && node test/douyin-recovery.mjs && node test/session-preset.mjs && node test/qq-connect-error.mjs && node test/douyin-comment-bridge.mjs && node test/bili-comment-emoji.mjs && node test/douyin-state-echo.mjs && node test/issue-75-proactive.mjs && node test/issue-76-capability.mjs && node test/douyin-http-browse.mjs && node test/douyin-verify-backoff.mjs && node test/douyin-digg-bridge.mjs && node test/memory-evidence-transcript.mjs && node test/chat-archive-default.mjs && node test/dream-transcript-wire.mjs && node test/douyin-frames-collect.mjs && node test/master-qq-uin-rebind.mjs && node test/douyin-session-health.mjs && node test/douyin-delivered.mjs && node test/douyin-card-share.mjs && node test/douyin-push-drop.mjs && node test/douyin-uid-binding.mjs && node test/image-webp-fallback.mjs && node test/douyin-emoji-fallback.mjs && node test/relay-other-platform.mjs && node test/voice-volcengine.mjs && node test/voice-minimax-dashscope.mjs && node test/bili-switch-persist.mjs && node test/cross-channel-context.mjs && node test/reply-target.mjs && node test/shared-session.mjs && node test/memory-source-label.mjs && node test/pending-delivery.mjs && node test/recall-window-78.mjs && node test/client-syntax.mjs && node test/self-update.mjs",
|
|
68
68
|
"eval": "node test/eval/persona-eval.mjs"
|
|
69
69
|
}
|
|
70
70
|
}
|