Back to home@KeynoWu

dsh-ai-news

DeepSeek Harness AI 新闻插件:多源聚合(HN/ArXiv/官方博客/中文媒体)+ 侧边栏大弹窗新闻流 + 面板内 LLM 总结

Stars
0
Language
JavaScript
Created
Aug 21, 2026
Updated
Aug 21, 2026
GitHub repo

Introduction

dsh-ai-news

DeepSeek Harness AI 新闻插件:多源聚合最新 AI 动态(国际媒体 / 中文媒体 / 论文),侧边栏一键打开大弹窗新闻流(2-3 列自适应),每条新闻支持卡片内一键 LLM 总结。

能力

能力说明
多源聚合Hacker News(AI 过滤)、ArXiv(cs.AI 论文)、OpenAI Blog、Google AI Blog、The Verge AI、量子位、InfoQ 中文,共 7 个默认源(全部可在 Config 增删)
分类筛选全部 / 国际 / 中文 / 论文 四个 tab,切换即按来源类型过滤(maxDays 窗口内)
时间窗口只显示最近 N 天新闻(Config.maxDays,默认 3;缓存保留全量,仅显示层过滤)
排序规则发布时间降序(最新在前);时间戳缺失的条目沉底(源未提供时间时用抓取时刻兜底并标记 timeFallback
侧边栏入口sidebar.footer.action 按钮(与设置按钮并列、位于其上方),点击打开大弹窗(全屏 mask + 1280px 面板,接近对话区尺寸)
自适应网格新闻流 2-3 列自适应(auto-fill minmax(320px, 1fr)):窄窗 2 列、宽窗 3 列
面板内总结每条新闻的「总结 ✦」→ 后台抓正文 + 调默认模型生成中文要点总结(3-5 条 + 原文链接),卡片内展开显示;不进对话、不唤醒 agent,结果按条目缓存(重复查看零成本)
文本清洗所有摘要/总结展示前经解码→去 HTML 标签→压缩空白,杜绝 <div> 等源码泄漏
ai_news 工具模型可直接调用 ai_news(refresh / limit / kind 参数)拉取新闻,Markdown 渲染
事件抓取完成 ctx.emit('ai-news/updated')(当前为手动刷新模式,事件为后续自动推送预留)

架构

┌─────────── node half(Host 侧,strip-types 直载)───────────┐
│  src/index.ts    插件入口:Config + apply + ai_news 工具     │
│  src/engine.ts   NewsEngine:内存缓存 + id 去重 + 并发刷新   │
│  src/fetchers.ts 多源抓取:RSS(轻量 XML 解析)/HN/ArXiv       │
│  src/extract.ts  文章正文提取(抓 HTML → 去噪 → 段落文本)   │
│  lib/gateway.js  NewsGateway(预编译,@Remote 装饰器)       │
│    aiNews.list / refresh / summarize → /api/aiNews/*        │
│    summarize:正文 → ctx.llm.stream(默认模型)→ 要点总结    │
└──────────────────────────────────────────────────────────────┘
┌─────────── browser half(client 插件,esbuild bundle)───────┐
│  src/client/index.tsx  侧边栏入口按钮 + 大弹窗 + 2-3 列网格   │
│    (lib/client.js 由 scripts/build-client.mjs 构建)        │
└──────────────────────────────────────────────────────────────┘

为什么 Gateway 要预编译?

@Remote 是标准装饰器(addInitializer),Node 的 strip-types 不支持装饰器语法。 沿用 dsh-omp-tools 同款方案:scripts/build-gateway.mjs 用 esbuild 把 src/gateway.ts 转译为 lib/gateway.js@deepseek-ai/* external),src/index.ts 运行时 import 构建产物。

模块实例一致性(关键!)

Host 的 dsh-api-gateway 通过同一模块实例的私有 markers WeakMap 发现 @Remote 方法。 因此本插件的 node_modules/@deepseek-ai 必须解析到 dsh 安装树的 @deepseek-ai/…/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai),与 api-gateway 保持一致; 否则装饰器标记互相不可见,remote 端点 404。@deepseek-ai/dsh-client-ui-slots 仅 tsc 需要, 通过 tsconfig paths 指向 omp-tools 的副本(dsh 树没有此包)。

总结链路

点击「总结 ✦」 → /api/aiNews/summarize {itemId}
  → engine.get(itemId) → 命中缓存? 直接返回
  → fetchArticleText(url) 抓正文(≤8000 字符)
  → ctx.agentDefaultModel.currentSelection() 取默认模型(provider/model)
  → ctx.llm.stream({provider, model, messages, temperature:0.3, maxTokens:800})
  → 聚合 text-delta → 中文要点总结 → 写入缓存 → 返回
client 面板内展开显示;按钮变「总结 ✓」;再点直接读缓存

开发

# 0) 依赖(symlink 复用 dsh 安装树 + omp-tools 工具链)
#    node_modules/@deepseek-ai -> dsh 安装树(模块实例一致性,见上文)
#    esbuild/typescript/react/zod 等 -> dsh-omp-tools/node_modules(工具链)

# 1) 构建(Gateway 装饰器转译 + client bundle)
npm run build          # = build:gateway + build:client

# 2) 类型检查
npm run typecheck

# 3) 起隔离验证实例(插件已在 profile cordis.patch.yml,无需 --patch)
dsh web --port 3100 --no-open

# 4) 浏览器验证(headless Chrome + CDP)
#    起 headless Chrome: Google Chrome --headless=new --window-size=1600,1000 \
#      --remote-debugging-port=9222 about:blank
#    用 CDP 脚本断言:侧边栏按钮 → 大弹窗 → 分类 tab → 列表 → 面板内总结
#    (验证脚本为开发期工具,不入库;本机保留在 scratch 目录即可)

使用(正式接入)

~/.dsh/profiles/web/cordis.patch.yml

- insert:
    - id: dsh-ai-news
      name: dsh-ai-news
      config:
        fetchTimeoutMs: 15000
        maxItems: 50
        maxDays: 3        # 只显示最近 N 天(0 = 不限)

可选配置(覆盖默认源 / 抓取参数):

    config:
      sources:
        - id: my-rss
          name: 我的源
          kind: international
          type: rss
          url: https://example.com/feed.xml

已知限制

  • 缓存为进程内内存:新闻与总结缓存随插件卸载 / dsh web 重启清空(重启后首次打开会自动重新抓取)。
  • 手动刷新按钮:页面内保留「刷新」按钮可随时重新抓取;尚未做后台定时自动拉取(ai-news/updated 事件已预留,后续可加 timer)。
  • 总结走默认模型:用 ctx.agentDefaultModel 的当前选择(默认 deepseek-v4-flash),每篇首次总结消耗一次模型调用。
  • 正文提取为启发式:抓 HTML 提取段落,部分站点(JS 渲染、反爬)可能拿不到正文,总结会报"无法获取文章内容"。