dsh-foxy-bili 0.3.0 → 0.3.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/lib/index.js CHANGED
@@ -420,7 +420,12 @@ async function runCommentNow(ctx, config, state, bvid) {
420
420
  nestedReplies: config.nestedReplies === true,
421
421
  forceComment: true,
422
422
  })
423
- if (!decision.comment) throw new BiliError('模型没有生成可发布的评论', 'NO_COMMENT', 'comment-now')
423
+ if (!decision.comment) {
424
+ ctx.logger?.warn?.(
425
+ `[foxy-bili] comment-now got no comment; action=${decision.action} raw=${String(decision.raw || '').slice(0, 800)}`,
426
+ )
427
+ throw new BiliError('模型没有生成可发布的评论', 'NO_COMMENT', 'comment-now')
428
+ }
424
429
  const published = await publishComment(ctx, config, item, decision, state, candidates, {
425
430
  force: true,
426
431
  })
package/lib/judge.js CHANGED
@@ -92,6 +92,29 @@ function parseJson(text) {
92
92
  }
93
93
  }
94
94
 
95
+ function stripCodeFence(text) {
96
+ return String(text || '')
97
+ .trim()
98
+ .replace(/^```(?:json)?\s*/i, '')
99
+ .replace(/\s*```$/i, '')
100
+ .trim()
101
+ }
102
+
103
+ function fallbackComment(text) {
104
+ const raw = stripCodeFence(text)
105
+ if (!raw) return ''
106
+ const parsed = parseJson(raw)
107
+ if (parsed?.comment) return String(parsed.comment).trim().slice(0, 300)
108
+ // If the model returned a broken/JSON-looking object, don't publish its
109
+ // internal fields as a comment. Only accept readable prose.
110
+ if (raw.startsWith('{')) return ''
111
+ return raw
112
+ .replace(/^(?:评论|回复|comment)\s*[::]\s*/i, '')
113
+ .replace(/^["“]([\s\S]*)["”]$/, '$1')
114
+ .trim()
115
+ .slice(0, 300)
116
+ }
117
+
95
118
  function sessionOf(ctx, handle, sessionId) {
96
119
  return handle?.agent?.session || ctx.sessions?.get?.(sessionId)
97
120
  }
@@ -137,6 +160,7 @@ export async function judgeVideo(ctx, config, input) {
137
160
  const sessionId = `foxy-bili-${randomUUID()}`
138
161
  const prompt = [
139
162
  '你正在浏览 B 站的视频,不是在回复 QQ,也不是客服。',
163
+ '这是用户明确启动的 B 站浏览任务;评论与记录是任务要求,不属于人设里“没人问你时不要主动回答”的场景。',
140
164
  '下面是一个视频的信息与字幕节选。请用 Foxy 的判断,决定:',
141
165
  '- skip:无聊、广告、纯标题党、没信息量,直接跳过;',
142
166
  '- remember:有点意思,但不需要公开评论,自己记一笔;',
@@ -205,12 +229,53 @@ export async function judgeVideo(ctx, config, input) {
205
229
  await handle.agent.whenIdle()
206
230
  const session = sessionOf(ctx, handle, sessionId)
207
231
  const messages = session?.deriveMessages?.() || []
208
- const text = lastAssistant(messages)
209
- const parsed = parseJson(text) || {}
232
+ let text = lastAssistant(messages)
233
+ if (!text) {
234
+ // A provider transport failure leaves the turn without an assistant
235
+ // message. Don't pretend the model "chose" not to comment.
236
+ throw new Error('模型请求失败或返回为空(可能是 DeepSeek 传输错误),请稍后重试')
237
+ }
238
+ let parsed = parseJson(text) || {}
239
+ let comment = String(parsed.comment || '').trim()
240
+
241
+ if (forceComment && !comment) {
242
+ // The model sometimes answers with plain prose instead of the required
243
+ // JSON, especially when the persona is chatty. Ask it once more, very
244
+ // explicitly, before falling back to the readable part of its answer.
245
+ await handle.agent.followup({
246
+ content: [
247
+ {
248
+ type: 'text',
249
+ text:
250
+ '上一条回复没有生成可发布的评论。现在是用户手动点击的评论测试,不是“没人问你时主动插嘴”,必须评论。' +
251
+ '只做一件事:写一条 Foxy 风格的 B 站评论。' +
252
+ '必须只输出 JSON:{"action":"comment","comment":"非空评论正文","mentions":[],"replyTo":0}。' +
253
+ 'comment 不得为空,不要解释,不要 Markdown。',
254
+ },
255
+ ],
256
+ source: { kind: 'foxy-bili' },
257
+ })
258
+ await handle.agent.whenIdle()
259
+ const retrySession = sessionOf(ctx, handle, sessionId)
260
+ const retryMessages = retrySession?.deriveMessages?.() || []
261
+ const retryText = lastAssistant(retryMessages)
262
+ const retryParsed = parseJson(retryText) || {}
263
+ if (retryText) {
264
+ text = retryText
265
+ if (Object.keys(retryParsed).length) parsed = retryParsed
266
+ comment = String(retryParsed.comment || '').trim() || fallbackComment(retryText)
267
+ }
268
+ if (!comment) comment = fallbackComment(text)
269
+ }
270
+
271
+ if (!comment && forceComment) {
272
+ ctx.logger?.warn?.(`[foxy-bili] forceComment got no comment; raw=${text.slice(0, 500)}`)
273
+ }
274
+
210
275
  let action = ['skip', 'remember', 'comment'].includes(parsed.action)
211
276
  ? parsed.action
212
277
  : 'skip'
213
- if (forceComment && action !== 'comment' && parsed.comment) action = 'comment'
278
+ if (forceComment && comment) action = 'comment'
214
279
  const mentions = Array.isArray(parsed.mentions)
215
280
  ? parsed.mentions
216
281
  .map((item) => String(item || '').trim())
@@ -220,7 +285,7 @@ export async function judgeVideo(ctx, config, input) {
220
285
  const replyTo = Number(parsed.replyTo) || 0
221
286
  return {
222
287
  action: action === 'comment' && !mayComment ? 'remember' : action,
223
- comment: String(parsed.comment || '').trim().slice(0, 300),
288
+ comment: comment.slice(0, 300),
224
289
  memory: String(parsed.memory || '').trim().slice(0, 500),
225
290
  mentions,
226
291
  replyTo: mayReply ? replyTo : 0,
package/package.json CHANGED
@@ -1,55 +1,55 @@
1
- {
2
- "name": "dsh-foxy-bili",
3
- "version": "0.3.0",
4
- "description": "Foxy 的 B 站子插件:自己刷视频、读字幕、决定要不要评论/记住,并通过 foxy3 人设与 memory 说话。",
5
- "type": "module",
6
- "main": "lib/index.js",
7
- "exports": {
8
- ".": "./lib/index.js",
9
- "./client": "./lib/client.js",
10
- "./package.json": "./package.json"
11
- },
12
- "dsh": {
13
- "bundle": {
14
- "patch": "./cordis.patch.yml"
15
- },
16
- "client": {
17
- "platform": "web",
18
- "inject": [
19
- "@deepseek-ai/dsh-client-runtime",
20
- "@deepseek-ai/dsh-client-ui-settings",
21
- "@deepseek-ai/dsh-client-ui-settings-plugins",
22
- "@deepseek-ai/dsh-client-ui-slots"
23
- ]
24
- },
25
- "manifestVersion": 1
26
- },
27
- "files": [
28
- "lib",
29
- "cordis.patch.yml",
30
- "README.md"
31
- ],
32
- "dependencies": {
33
- "qrcode": "^1.5.4"
34
- },
35
- "engines": {
36
- "node": ">=20"
37
- },
38
- "author": "Kun-Fox",
39
- "repository": {
40
- "type": "git",
41
- "url": "git+https://github.com/Kun-Fox/dsh-foxy-bili.git"
42
- },
43
- "homepage": "https://github.com/Kun-Fox/dsh-foxy-bili#readme",
44
- "bugs": {
45
- "url": "https://github.com/Kun-Fox/dsh-foxy-bili/issues"
46
- },
47
- "keywords": [
48
- "dsh",
49
- "deepseek-harness",
50
- "foxy",
51
- "bilibili",
52
- "agent"
53
- ],
54
- "license": "MIT"
55
- }
1
+ {
2
+ "name": "dsh-foxy-bili",
3
+ "version": "0.3.1",
4
+ "description": "Foxy 的 B 站子插件:自己刷视频、读字幕、决定要不要评论/记住,并通过 foxy3 人设与 memory 说话。",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "exports": {
8
+ ".": "./lib/index.js",
9
+ "./client": "./lib/client.js",
10
+ "./package.json": "./package.json"
11
+ },
12
+ "dsh": {
13
+ "bundle": {
14
+ "patch": "./cordis.patch.yml"
15
+ },
16
+ "client": {
17
+ "platform": "web",
18
+ "inject": [
19
+ "@deepseek-ai/dsh-client-runtime",
20
+ "@deepseek-ai/dsh-client-ui-settings",
21
+ "@deepseek-ai/dsh-client-ui-settings-plugins",
22
+ "@deepseek-ai/dsh-client-ui-slots"
23
+ ]
24
+ },
25
+ "manifestVersion": 1
26
+ },
27
+ "files": [
28
+ "lib",
29
+ "cordis.patch.yml",
30
+ "README.md"
31
+ ],
32
+ "dependencies": {
33
+ "qrcode": "^1.5.4"
34
+ },
35
+ "engines": {
36
+ "node": ">=20"
37
+ },
38
+ "author": "Kun-Fox",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/Kun-Fox/dsh-foxy-bili.git"
42
+ },
43
+ "homepage": "https://github.com/Kun-Fox/dsh-foxy-bili#readme",
44
+ "bugs": {
45
+ "url": "https://github.com/Kun-Fox/dsh-foxy-bili/issues"
46
+ },
47
+ "keywords": [
48
+ "dsh",
49
+ "deepseek-harness",
50
+ "foxy",
51
+ "bilibili",
52
+ "agent"
53
+ ],
54
+ "license": "MIT"
55
+ }