Skip to content

feat: 支持多机实时日志上报,实现跨主机 agent 运行监控 #18

Description

@Camille1024

背景

当前 ui/ dashboard 的日志数据来源是本地文件系统agents/*/logs/run-*/),server 直接 fs.readdirSync 读取。这意味着:

  • dashboard 只能看到当前部署主机上跑出的 agent 日志
  • 如果多位成员各自在本地跑 blueprint-absorber,其他人的运行记录对 dashboard 完全不可见
  • 无法实现跨主机的统一进度监控

目标

不引入重量级外部数据库,以最小改动实现:任何成员在本地跑 agent,日志实时汇聚到部署在服务器上的 dashboard,所有人都能在同一个界面监控。

方案设计

总体思路

成员 A 本地 run.sh          成员 B 本地 run.sh
      │                            │
      │  每条 JSONL event           │
      ▼                            ▼
POST /api/ingest  ────────▶  dashboard server(服务器)
                                   │
                      写入本地文件(保持现有目录结构)
                                   │
                      WebSocket 推送给前端
                                   ▼
                             浏览器实时看到

原有文件结构完全不变,server 侧"读文件"逻辑无需修改,ingest 端点只是另一条写入路径。


改动一:agent 侧——run.sh 加上报 hook

在现有的 JSONL 解析 pipeline 末尾,每 emit 一行到本地 .jsonl 文件时,同时 POST 到远程 server:

# run.sh 新增环境变量(可选,不设则纯本地模式)
INGEST_URL="${KIP_INGEST_URL:-}"   # e.g. http://kip.opensii.ai:8081/api/ingest
INGEST_TOKEN="${KIP_INGEST_TOKEN:-}"

上报逻辑插入到现有 python 日志解析脚本中(约 10 行):

import urllib.request, os

INGEST_URL   = os.getenv("KIP_INGEST_URL", "")
INGEST_TOKEN = os.getenv("KIP_INGEST_TOKEN", "")

def ingest(row: dict):
    if not INGEST_URL:
        return
    payload = json.dumps({
        "agent":  meta["agent"],
        "runId":  RUN_TS,
        "hintFile": meta["hint_file"],
        "row":    row,
    }).encode()
    req = urllib.request.Request(
        INGEST_URL,
        data=payload,
        headers={"Content-Type": "application/json",
                 "Authorization": f"Bearer {INGEST_TOKEN}"},
        method="POST",
    )
    try:
        urllib.request.urlopen(req, timeout=3)
    except Exception:
        pass  # 上报失败不影响本地运行

每次 emit(...) 后调用 ingest(row),fire-and-forget,超时 3s,失败静默,不阻塞 agent。


改动二:server 侧——新增 /api/ingest 端点

// ui/server/src/routes/ingest.ts
POST /api/ingest
Body: { agent: string, runId: string, hintFile: string, row: object }
Auth: Bearer token(读环境变量 KIP_INGEST_TOKEN,为空则不校验)

逻辑:

  1. 校验 token(如果配置了)
  2. 确保 agents/<agent>/logs/<runId>/ 目录存在(mkdir -p
  3. 追加 rowagents/<agent>/logs/<runId>/absorber.jsonl
  4. 如果是第一条 event,写 meta.json(包含 agent/hintFile/startedAt)
  5. 如果 row.event === "session_end",更新 meta.json 的 completedAt/status
  6. 通过现有 WebSocket 机制广播这条 event 给正在查看该日志的前端连接

改动三:start.sh / 部署文档

新增可选环境变量说明:

KIP_INGEST_TOKEN=<随机字符串>   # server 侧设置,用于校验上报来源
KIP_INGEST_URL=http://<server>:8081/api/ingest   # 成员本地设置

两者都是可选的:不设 KIP_INGEST_URL 则纯本地模式,行为与现在完全一致。


改动范围

文件 变更
agents/blueprint-absorber/run.sh(python 内联脚本) ingest() 调用,约 +15 行
ui/server/src/routes/ingest.ts 新文件,约 +60 行
ui/server/src/index.ts 注册新路由,+2 行
ui/start.sh 新增环境变量说明注释

无数据库依赖,无第三方服务,不破坏现有本地工作流。

后续扩展(out of scope)

  • 支持 blueprint-prover 等未来 agent(run.sh 结构一致,同样适用)
  • ingest 端点加速率限制(防止异常打满磁盘)
  • dashboard 上显示"来源主机"字段,区分本地运行与远程上报

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions