obsidian插件-yuhanbo-opencode:OpenCode 个人AI助手

OpenCode AI助手是一款将 OpenCode CLI 深度集成到 Obsidian 的插件,实现了 AI 辅助写作、知识库问答、全文 BM25 搜索、定时任务自动化等功能。本文将深入剖析其代码架构、核心模块与实现原理,帮助开发者理解插件的设计思路和技术细节。

程序小店:程序小店 - obsidian插件-OpenCode AI助手

核心架构

插件主类 IFlowPlugin

IFlowPlugin 类是插件的核心入口,继承自 Obsidian 的 Plugin 基类。它负责:

  1. 设置管理:通过 PluginSettingTab 提供可视化配置界面
  2. 视图注册:注册 IFlowChatView 侧边栏视图,提供 AI 对话界面
  3. 命令注册:注册"打开 AI 面板"、"管理定时任务"、"搜索笔记"等命令
  4. 适配器管理:创建和管理 OpenCodeAdapter 实例,与 CLI 后端通信

设置系统

插件支持丰富的配置选项,通过 IFlowPluginSettings 接口定义:

设置通过 Obsidian 的 loadData() 和 saveData() API 持久化存储。

HTTP + SSE 双通道通信

OpenCodeAdapter 类实现了与 OpenCode CLI 后端的双通道通信:

连接流程:

  1. SSE 事件流:用于接收流式响应,实时更新对话内容

会话管理

每个对话窗口对应一个独立的 session。session 创建时指定工作目录(cwd),确保文件操作限定在当前 Obsidian 仓库内。

流式消息处理

SSE 连接接收的事件类型包括:

通过 pendingMessages 队列和 AsyncIterable 接口,实现非阻塞的消息流式推送。

为避免 Agent 工具调用间隙误触发 task_finish,插件实现了 idle 防抖:

只有在连续 500ms 无新事件时,才发送任务完成信号。

索引构建

WeightedSearchIndex 类实现了 BM25 算法的变种,支持中英文混合检索:

中文处理采用 n-gram 分词,避免词表依赖:

搜索算法

BM25 评分公式:

关键参数:

用户可通过 searchKeywordWeights 自定义关键词权重,提升重要词汇的检索优先级。

  • b:文档长度归一化系数(默认 0.75)

search() 方法返回结构化结果:

每个结果包含:

  • snippet:智能截取的上下文摘要
  • score:BM25 评分
  • matches:匹配词的统计信息

Skills 路径解析

路径规范化

skills-paths.js 提供路径规范化函数:

绝对路径识别

Windows 绝对路径判断:

Skills 目录同步

ensureProjectSkills() 自动将 Skills 目录链接/复制到项目工作目录:

定时任务系统

任务数据结构


interface IFlowScheduledTask {
    id: string;
    name: string;
    sourcePath: string;      // 提示词模板文件路径
    targetPath: string;      // 输出文件夹(save 模式)
    writeMode: 'save' | 'insert' | 'replace';
    scheduleType: 'once' | 'daily';
    schedule: string;        // cron 表达式
    sendEmail: boolean;
}

三种写入模式

模式行为
saveAI 结果写入 targetPath 指定文件夹的新文件
insert解析 sourcePath 中的 [[WikiLink]],结果追加到被引用文件末尾
replace解析 WikiLink,结果覆盖被引用文件

WikiLink 解析示例:

插件读取 测试3.md 内容,嵌入提示词,发送给 AI,然后将翻译结果写入 测试3.md(insert 或 replace)。

SMTP 配置


interface EmailSettings {
    emailEnabled: boolean;
    emailHost: string;     // 默认 smtp.qq.com
    emailPort: number;     // 默认 465(SSL)
    emailSecure: boolean;
    emailUser: string;
    emailPass: string;
    emailFrom: string;
    emailTo: string;
}

发送流程

任务完成后,调用 Node.js 内置 tls 模块发送邮件:

流程图


flowchart TD
    %% 主流程:启动与初始化
    A[用户打开 AI 面板] --> B[IFlowPlugin.onload]
    B --> C[OpenCodeAdapter.connect]
    C --> D{端口是否被占用}
    
    D -->|是| E[检查服务健康状态]
    E -->|健康| J[复用现有 Session]
    E -->|不健康| G[杀掉旧进程]
    G --> H[startProcess 启动服务]
    
    D -->|否| H
    H --> I[等待端口就绪]
    I --> J
    
    J --> K[建立 SSE 长连接]
    K --> L[等待用户输入]

    %% 交互循环
    L --> M[HTTP POST /message]
    M --> N[SSE 接收流式响应]
    
    N --> O{事件类型}
    O -->|assistant| P[更新对话文本 UI]
    O -->|tool_call| Q[解析工具参数]
    
    %% 工具调用分发
    Q --> Q1{调用何种工具?}
    Q1 -->|本地搜索| U
    Q1 -->|定时任务| AA
    
    %% 搜索模块逻辑 (集成)
    subgraph 搜索模块
        U[提取搜索关键词] --> V[WeightedSearchIndex.build]
        V --> W[分词与提取 Tokens]
        W --> X[检索倒排索引]
        X --> Y[BM25 评分重排]
        Y --> Z[格式化搜索结果]
    end
    
    %% 定时任务逻辑 (集成)
    subgraph 定时任务
        AA[解析 Cron 与 Action] --> AB[注册到调度器]
        AB --> AC{任务触发}
        AC --> AD[执行写入模式]
        AD --> AE[save/insert/replace]
    end

    %% 回传结果给 AI
    Z --> R[显示工具执行结果]
    AE --> R
    R -->|将结果反馈给 AI| M
    
    %% 结束与通知
    O -->|task_finish| S[结束流响应]
    S --> T[可选邮件通知/UI 状态归位]
    T --> L

主要改进点说明:

这样修改后的流程图更符合一个基于 SSE 的 AI 插件/Agent 的真实运行机制。

  1. 服务自愈闭环:
  2. 当检查到“不健康”时,增加“杀掉进程”并指向“启动服务”的逻辑,确保流程能走通。
  3. 启动成功后统一进入 Session 创建阶段。
  4. 工具调用集成 (Tool Call Integration):
  5. 将原本孤立的“搜索模块”和“定时任务”通过 tool_call 事件连接。
  6. 核心逻辑改进:工具执行完(R 节点)后,流程指向了 M (HTTP POST /message)。这是符合 AI Agent 逻辑的:AI 调用工具 -> 得到结果 -> 带着结果再次请求 AI -> AI 总结回复。
  7. 增加等待状态:
  8. 增加了 L[等待用户输入],使得流程在任务完成后能回到待命状态,形成交互闭环。
  9. 搜索模块内部细节优化:
  10. 将搜索逻辑从“用户触发”改为“提取关键词”,因为在 AI 场景下,搜索通常是由 AI 根据用户意图发起的。
  11. 定时任务执行逻辑:
  12. 明确了从解析到注册再到触发的异步过程。
THE END