跳到主要内容
路径文档

第一次会话

一句话版:一条用户消息在 DSH 里走完会话 → 轮次 → 步骤三级生命周期:agent 循环驱动模型推理 + 工具执行,每一步都被记录、可回滚、可恢复。

经过 快速上手 你已经能跑。现在跟随第一条消息到底走了什么。

一、生命周期层级

Session(会话) 持久化边界,可恢复 / 可 fork
└── Turn(轮次) 一次用户消息 + agent 完整响应
└── Step(步骤) 一次模型调用 或 一次工具执行

一句:一个会话装一段长期对话;一个轮次从你发一条开始到 agent 应答完;一个步骤是轮次里的每次推进(模型推理或工具执行)。agent-loop 的 README 原话:它"驱动会话/轮次/步骤生命周期"。

二、一次消息的旅程

  1. 创建/恢复会话:ctx.agents.create({ sessionId })resume({ resumeSessionId }):恢复会从持久化日志重建历史,轮次编号继续
  2. Setup 事务:构造私有会话、agent、带作用域上下文:受回滚保护,失败即回滚
  3. 发布:session/createdagent/createdagent/session-start 依次宣告
  4. 驱动循环:模型推理 → 工具调用 → 结果回填 → 下一轮(见 Agent 主循环)
  5. Teardown:停止并 drain → 撤销作用域 → detach agent → detach 会话

关键特性:

  • 创建与恢复属于同一个受回滚保护的事务
  • sessionId 全局唯一;两个并发操作可同时准备,最终 enter() 裁决发布
  • resumeSessionIdsessionId 互斥
  • 声明式配置把 agents[].id 当稳定 label,通常生成 ${label}-session-<uuid>

三、源码佐证(agent-loop)

// 配置驱动创建:循环 fiber 拥有 agent
ctx.agentLoop.create(id, options, meta)

// 编程式创建:返回 AgentHandle(唯一 teardown 能力)
ctx.agents.create({ sessionId, agentOptions, setup, signal })

// 恢复持久化会话:从日志重建历史
ctx.agents.resume({ resumeSessionId, agentOptions, setup })

signal(AbortSignal)只作用于创建期/加载期,会在 handle 可见前脱离;resume 依赖持久化后端,无后端时明确报错。

四、配置一个 agent

agents 挂在 agent-loop 插件的 config 下(不是顶层段):

- id: agent-loop
name: '@deepseek-ai/dsh-agent-loop'
config:
agents:
- id: main
provider: deepseek-official
model: deepseek-v4-flash
maxTokens: 65536
cwd: /path/to/workspace
- id: resume-demo
resumeSessionId: <已有会话 id>

同级配置还有 maxParallelToolCalls(循环级并行,默认 10,1 = 串行)。

五、端到端:你发一条消息,发生了什么

假设你问"这个仓库有多少行代码":

这一切的持久化记录(默认 zstd、两级目录):

zstdcat ~/.dsh/sessions/*/*/session.jsonl.zstd | tail -30

注意:内容是会话日志(surface);agent/*控制面事件(状态、错误、请求),两者见 事件系统

六、可观测性(扩展点)

每次请求/响应发布一系列 agent/* 事件(控制面),持久化真正落在 session/event:

  • agent/statusagent/createdagent/disposedagent/request-erroragent/pre-step
  • 配合 ctx.tools/session 事件,你可以挂策略、压缩、重试、UI 渲染

七、验证

# 跑一个会话后看会话文件(默认 zstd 压缩、两级目录)
ls ~/.dsh/sessions/*/*/session.jsonl.zstd

# 解压后看事件流(3级结构一目了然)
zstdcat ~/.dsh/sessions/*/*/session.jsonl.zstd \
| jq -r 'select(.type | test("turn/|step/|user/message|assistant/message|tool/call|tool/result")) | [.seq, .type] | @tsv'

下一步