Skip to content

[enhancement] JSONStore.exists 与 Agent.resumeFromStore 在部分损坏 Store 目录上的语义不一致,建议提供内建自愈策略 #4

@2217173240

Description

@2217173240

[enhancement] JSONStore.exists 与 Agent.resumeFromStore 在部分损坏 Store 目录上的语义不一致,建议提供内建自愈策略

报告人 / Reporter

  • GitHub 用户名(期望):2217173240
  • 邮箱:alanturing648@gmail.com

环境 (Environment)

  • @shareai-lab/kode-sdk 版本:2.7.0

背景与现象 (Background)

在实际项目中(ts-agent 深度集成 Kode SDK,用于商用车资料检索),我们使用 JSONStore + Agent.resumeFromStore 来实现会话恢复。

Store 目录结构(摘自 store.ts 注释):

{baseDir}/{agentId}/
├── runtime/
│   ├── messages.json
│   ├── messages.wal
│   ├── tool-calls.json
│   ├── tool-calls.wal
│   └── todos.json
├── events/
│   ├── progress.log / progress.wal
│   ├── control.log  / control.wal
│   ├── monitor.log  / monitor.wal
├── snapshots/
└── meta.json

在某些异常场景下(例如进程非正常退出、磁盘清理工具误删部分文件等),会出现如下情况:

  • {baseDir}/{agentId} 目录仍然存在;
  • meta.jsonruntime/messages.json 缺失或损坏。

此时:

  • JSONStore.exists(agentId) 返回 true(只检查目录存在性);
  • Agent.resumeFromStore(agentId, deps, opts) 会在内部抛出 ResumeError('AGENT_NOT_FOUND' | 'CORRUPTED_DATA')

对集成方来说,这意味着:

  • 仅通过 exists() 无法区分“可恢复会话”与“残留/损坏的 Store 目录”;
  • 必须额外包一层逻辑:捕获 ResumeError,再手动清理 baseDir/agentId 目录并重新创建 Agent。

目前业务侧的补偿代码类似如下(简化版):

// ts-agent/src/kodeAgent.ts:70+
const exists = await deps.store.exists(agentId);
if (exists) {
  try {
    const agent = await Agent.resumeFromStore(agentId, deps, {
      strategy: 'manual',
      overrides: { model: llmProvider },
    });
    return agent;
  } catch (error: any) {
    console.warn(
      `[Agent] Resume failed for ${agentId}, removing stale store and recreating. Error: ${error?.message}`
    );
    const fs = require('fs');
    const path = require('path');
    const baseDir = (deps.store as any).baseDir || path.join(process.cwd(), '.kode');
    const agentDir = path.join(baseDir, agentId);
    if (fs.existsSync(agentDir)) {
      fs.rmSync(agentDir, { recursive: true, force: true });
    }
    const fresh = await Agent.create(
      {
        agentId,
        templateId: 'smart-librarian-tools',
        model: llmProvider,
        sandbox: { kind: 'local', workDir: process.cwd() },
      },
      deps
    );
    return fresh;
  }
}

// 不存在则直接创建新 Agent

当前行为 (Current Behavior)

  • JSONStore.exists(agentId) 实现如下,仅基于目录是否存在判断:

    // external/Kode-agent-sdk/src/infra/store.ts:720+
    async exists(agentId: string): Promise<boolean> {
      const fs = require('fs').promises;
      try {
        await fs.access(this.getAgentDir(agentId));
        return true;
      } catch {
        return false;
      }
    }
  • Agent.resumeFromStore 内部根据 Store.loadInfoloadMessages 等判断:

    // external/Kode-agent-sdk/src/core/agent.ts:640+
    const store = Agent.requireStore(deps);
    const info = await store.loadInfo(agentId);
    if (!info || !info.metadata) {
      throw new ResumeError('AGENT_NOT_FOUND', `Agent metadata not found: ${agentId}`);
    }
    const metadata = info.metadata as AgentMetadata | undefined;
    if (!metadata) {
      throw new ResumeError('CORRUPTED_DATA', `Agent metadata incomplete for: ${agentId}`);
    }
    // ...
    try {
      messages = await store.loadMessages(agentId);
    } catch (error: any) {
      throw new ResumeError('CORRUPTED_DATA', error?.message || 'Failed to load messages');
    }
  • 当目录存在但元数据/消息文件缺失或损坏时:

    • exists(agentId) 返回 true
    • resumeFromStoreAGENT_NOT_FOUNDCORRUPTED_DATA

预期需求 (Desired Behavior / DX)

从集成方视角,希望有一种“推荐的、可重用的”自愈模式,而不是每个项目都在业务层实现一遍上面的 try-catch + rm 逻辑。典型期望包括:

  • 提供一个官方的 helper,封装“存在性检查 + 恢复 + 自愈”的流程;
  • 或增强 JSONStore.exists 的语义,让“部分损坏的 Store 目录”也能被识别出来。

建议 (Suggested Enhancement)

  1. 在 SDK 内部新增一个“官方模式”的恢复 API,例如:

    static async resumeOrCreate(
      agentId: string,
      deps: AgentDependencies,
      opts?: {
        autoRun?: boolean;
        strategy?: ResumeStrategy;
        overrides?: Partial<AgentConfig>;
        onCorrupted?: (agentId: string, error: ResumeError) => Promise<void> | void;
      }
    ): Promise<Agent>

    默认行为可以是:

    • AGENT_NOT_FOUND:直接创建新 Agent;
    • CORRUPTED_DATA:删除 Store 对应目录后创建新 Agent(可通过 onCorrupted 自定义策略)。
  2. 或者增强 JSONStore.exists,在检查目录存在的基础上,额外验证 meta.json 是否存在且可解析:

    async exists(agentId: string): Promise<boolean> {
      const fs = require('fs').promises;
      try {
        await fs.access(this.getAgentDir(agentId));
        const info = await this.loadInfo(agentId);
        return !!info; // meta.json 存在且可解析
      } catch {
        return false;
      }
    }

    这样,“缺少 meta.json 的残留目录”会返回 false,上层可以直接创建新 Agent。

  3. docs/resume.mddocs/ERROR_HANDLING.md 中,给出推荐的“恢复 + 自愈”代码模板,避免每个用户重复造轮子,实现方式与官方建议保持一致。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions