@zaofan/dsh-qqbot 1.11.2 → 1.11.3

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.
@@ -895,6 +895,14 @@ window.__ModuleLoader__.load({
895
895
  context: function () { return fetch(q('context')).then(function (r) { return r.json() }).catch(function () { return null }) },
896
896
  sessions: function () { return fetch(q('sessions')).then(function (r) { return r.json() }).catch(function () { return null }) },
897
897
  history: function (n) { return fetch(q('history') + '&limit=' + (n || 20)).then(function (r) { return r.json() }).catch(function () { return null }) },
898
+ /**
899
+ * 当前会话 **AI 最后一个正文块**(2026-10-27)
900
+ * 不是 QQ 消息流水,是 agent 真正输出的那段文字。
901
+ * 实现:宿主 kernel.get('sessions').get(sid).deriveMessages() 从后往前找 assistant。
902
+ */
903
+ lastAssistantText: function () {
904
+ return fetch(q('lastAssistantText')).then(function (r) { return r.json() }).catch(function () { return null })
905
+ },
898
906
  members: function () { return fetch(q('members')).then(function (r) { return r.json() }).catch(function () { return null }) },
899
907
  }
900
908
  }
@@ -93,7 +93,8 @@ qqbotExt.dock.peerId / scope / ns
93
93
  qqbotExt.dock.dataRoot / cwd
94
94
  qqbotExt.dock.context() // 实例 + 会话信息
95
95
  qqbotExt.dock.sessions() // 这个机器人管过哪些会话
96
- qqbotExt.dock.history(n) // 当前会话最近 n 条消息
96
+ qqbotExt.dock.history(n) // 当前会话最近 n 条消息(QQ 消息流水)
97
+ qqbotExt.dock.lastAssistantText() // ★ AI 最后一个正文块(她真正输出的那段话)
97
98
  qqbotExt.dock.members() // 群友台账
98
99
 
99
100
  // 能力(与代码扩展对齐,走白名单 RPC)
@@ -37,10 +37,11 @@
37
37
 
38
38
  <!-- 子标签 2:展示 dock 能拿到的会话数据(这是 dock 独有能力的演示) -->
39
39
  <div class="pane" data-pane="ctx">
40
- <div class="row"><span class="hint">下面这些是 dock 卡片独有的能力 —— 能直接读到当前实例和会话的真实数据。</span></div>
40
+ <div class="row"><span class="hint">下面这些是 dock 卡片独有的能力 —— 能直接读到当前实例和会话的真实数据。<br />
41
+ 「读 AI 最后正文」取的是她 <b>最后一次输出的那段话</b>(不是 QQ 消息流水)。</span></div>
41
42
  <div class="acts">
42
43
  <button class="btn" id="ctxBtn">读上下文</button>
43
- <button class="btn ghost" id="hisBtn">读最近消息</button>
44
+ <button class="btn ghost" id="hisBtn">读 AI 最后正文</button>
44
45
  </div>
45
46
  <pre class="info" id="info">点上面按钮看看</pre>
46
47
  </div>
@@ -64,12 +64,13 @@
64
64
  hisBtn.addEventListener('click', function () {
65
65
  if (!qqbotExt.dock) return setInfo('这个卡片没有 dock 上下文')
66
66
  setInfo('读取中…')
67
- qqbotExt.dock.history(8).then(function (r) {
68
- if (!r || !r.ok) return setInfo(r || '(空)')
69
- var rows = (r.messages || []).map(function (m) {
70
- return '[' + (m.k || 'text') + '] ' + String(m.n || '') + ': ' + String(m.x || '').slice(0, 60)
71
- })
72
- setInfo(rows.length ? rows.join('\n') : '(这个会话还没有历史消息)')
67
+ // ★ 2026-10-27(主人要求):读 **AI 最后一个正文块**,不是 QQ 消息流水。
68
+ // 实现抄 session_watch_lib.mjs 的 lastAssistantText():
69
+ // 宿主 kernel.get('sessions').get(sid).deriveMessages() 从后往前找 assistant。
70
+ qqbotExt.dock.lastAssistantText().then(function (r) {
71
+ if (!r) return setInfo('没有响应')
72
+ if (!r.ok) return setInfo('读不到:' + (r.reason || r.via || '未知') + (r.sid ? ('\nsid=' + r.sid) : ''))
73
+ setInfo('(AI 最后一段正文,' + r.text.length + ' 字符)\n\n' + r.text)
73
74
  })
74
75
  })
75
76
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaofan/dsh-qqbot",
3
- "version": "1.11.2",
3
+ "version": "1.11.3",
4
4
  "description": "QQ Bot IM channel plugin for deepseek-harness (dsh)",
5
5
  "type": "module",
6
6
  "main": "./entry.js",
package/settings-host.js CHANGED
@@ -5481,6 +5481,43 @@ const WHY_MAP = { busy: '目标会话回合活跃,已等待至回合结束仍超
5481
5481
  return writeJson(res, 200, { ok: true, messages: rows });
5482
5482
  }
5483
5483
 
5484
+ // ★ 2026-10-27(主人要求):取当前会话「AI 最后一个正文块」。
5485
+ // 原来卡片读的是 .qqbot/msg-history(QQ 消息流水),跟 AI 的正文不是一回事。
5486
+ // 实现抄 examples/ext-tools/lib/session_watch_lib.mjs 的 lastAssistantText():
5487
+ // 宿主 kernel.get('sessions').get(sid).deriveMessages() 从后往前找 assistant 角色。
5488
+ // (那条路还支持 turn/end 事件累积,但这里只要"最后一次的正文",直接取更省事。)
5489
+ if (what === 'lastAssistantText') {
5490
+ const sid = String(q?.get('sid') || '').trim();
5491
+ if (!sid) return writeJson(res, 200, { ok: false, reason: '缺 sid(当前会话 id)', text: '' });
5492
+ let text = '';
5493
+ let via = '';
5494
+ try {
5495
+ const sessions = ctx.get?.('sessions');
5496
+ const sess = sessions && typeof sessions.get === 'function' ? sessions.get(sid) : null;
5497
+ if (sess && typeof sess.deriveMessages === 'function') {
5498
+ const msgs = sess.deriveMessages() || [];
5499
+ for (let i = msgs.length - 1; i >= 0; i--) {
5500
+ const m = msgs[i];
5501
+ const role = String(m?.role ?? m?.type ?? '');
5502
+ if (!role.includes('assistant')) continue;
5503
+ // content 可能是字符串、数组(每项带 text)、或对象
5504
+ const c = m?.content;
5505
+ let t = '';
5506
+ if (typeof c === 'string') t = c;
5507
+ else if (Array.isArray(c)) t = c.map((x) => (typeof x === 'string' ? x : String(x?.text ?? ''))).join('');
5508
+ else if (c && typeof c === 'object') t = String(c.text ?? '');
5509
+ t = t.trim();
5510
+ if (t) { text = t; via = 'deriveMessages'; break; }
5511
+ }
5512
+ } else {
5513
+ via = 'sessions.get 拿不到会话';
5514
+ }
5515
+ } catch (e) {
5516
+ via = '异常: ' + (e instanceof Error ? e.message : String(e));
5517
+ }
5518
+ return writeJson(res, 200, { ok: !!text, text, via, sid });
5519
+ }
5520
+
5484
5521
  if (what === 'members') {
5485
5522
  // 群友台账(people-memo 落的那份)
5486
5523
  let out = {};
@@ -5703,7 +5740,11 @@ const WHY_MAP = { busy: '目标会话回合活跃,已等待至回合结束仍超
5703
5740
  dataRoot: dr,
5704
5741
  logger: console,
5705
5742
  selfName: id,
5706
- kind: 'ui',
5743
+ // ★ 2026-10-27:kind 不能传 'ui' —— store 会落到 .qqbot-extensions/ui/data/,
5744
+ // 而 listExtUi 正是扫 ui/ 下每个子目录找 card.html,会把 data/ 当成一个扩展目录。
5745
+ // 用点开头:路径变成 .qqbot-extensions/.ui-data/data/<extId>.json,
5746
+ // 既不在 ui/ 下,也不会被 EXT_ID_RE(不允许 '.')当成扩展 id。
5747
+ kind: '.ui-data',
5707
5748
  appId: String(viewOf(ctx.settings, capNs)?.value?.appId || ''),
5708
5749
  owners: (() => {
5709
5750
  try {