Sessions
Session(会话)是一次对话,也是一条工作线。你通过 Turns(轮次)给它工作。一个 Turn 是一个请求,加上之后的所有 Agent 工作。每个 Session 都属于一个 Agent。
本页介绍 Session 和 Turn 的路由。所有路由都在 /v1/sessions 下,接受用户令牌或 session cookie。见 身份验证。
| 术语 | 含义 |
|---|---|
| Item | Turn 中的一条记录,例如用户消息、模型回答、工具调用或工具结果。 |
| Revision | session.revision。一个数字,Session 每次变化它都会增加。 |
| Timeline | Session 所有保存下来的 Versions。每次变化都会添加一个新的 Version。 |
| Timeline head | session.head。Timeline 上当前 Version 的 ID。 |
| Version | 历史中一个保存下来的点。OpenBot 保存 Version 之后,它就不会再变化。 |
大多数写操作需要 expected。这是你最后看到的 revision。如果从那以后 Session 发生了变化,OpenBot 返回 409 和 SessionConflict。请重新读取 Session,然后再试。
创建 Session
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title":"Trip plan"}' \ https://api.example.com/v1/sessions所有字段都是可选的。title 是一个简短的名字。OpenBot 会去掉首尾空格。剩下的部分必须有 1 到 100 个字符。没有标题的 Session,其 metadata 中没有 title 字段。agent 是在这个 Session 中工作的 Agent 的 ID。不填时,由你的 Main Agent 在其中工作。你需要在这个 Agent 上拥有 agents.delegate。settings 可以包含 mode 和 model。没有指定模型时,Session 使用 Agent 的模型。两者都没有模型时,OpenBot 返回 400、SessionModelInvalid 和原因 missing。没有默认模型。见 Models。要设置记忆开关,见 Memory。创建 Session 不会调用模型。
OpenBot 返回 201 和 Session 视图。下面是它的简短形式:
{ "session": { "id": "a41c9e0f", "revision": 0, "head": "v-7d21", "metadata": { "title": "Trip plan" }, "settings": { "mode": "build" }, "pending": [], "turns": [], "inheritedTurns": [] }, "state": { "version": { "id": "v-7d21" }, "value": { "conversation": { "history": [] } } }, "agent": "agt_3f9a…", "kind": "direct", "parent": null, "response": null, "activity": "inactive"}agent 是这个 Session 的 Agent。kind 的取值:客户端启动的工作是 direct;另一个 Agent 分派的工作是 delegated;Agent 在其中决定一个 request 的 Session 是 review;触发器启动的工作是 trigger;Channel 中的一个聊天是 channel。parent 指出启动委派工作的 Session、Turn 和工具调用。见 委派。
response 是最新一个 Turn 的回答。activity 的取值:有 Turn 正在这台服务器上运行时是 active;没有任何东西在运行时是 inactive;保存的 Turn 显示它在运行、但没有服务器在运行它时是 historical。
列出和读取 Sessions
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ "https://api.example.com/v1/sessions?archived=false"列表是一个摘要数组。每个摘要包含 session、agent、kind、parent、status(Idle、Running、Waiting、Completed、Failed 或 Interrupted)、turn、一个简短的 response 和 activity。不填 archived 会得到所有 Sessions。加上 agent=<id> 可以列出某个 Agent 的 Sessions。除非你加上 kind=review,否则列表中不包括 review Sessions。
GET /v1/sessions/:sessionId 返回完整视图。读取永远不会启动工作。
要等待变化,请使用长轮询。当 revision 不再等于 after,或者超时结束时,OpenBot 会回答。最长等待 30 秒。
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ "https://api.example.com/v1/sessions/$SESSION/wait?after=3&timeoutMs=30000"重命名、归档和删除
curl -X PATCH -H "Authorization: Bearer $OPENBOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{"expected":3,"title":"Trip to Rome","archived":true}' \ https://api.example.com/v1/sessions/$SESSIONexpected 是 Session 当前的 revision。title 的规则和创建 Session 时相同。发送 "title": null 可以移除标题。不填某个字段,就保留它的值。
DELETE /v1/sessions/:sessionId 删除 Session,并返回 204。它的 Session Agents 会被归档。如果有 Turn 正在运行,OpenBot 返回 409 和 SessionBusy。
启动 Turn
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{"expected":0,"input":"Plan three days in Rome."}' \ https://api.example.com/v1/sessions/$SESSION/turns| 字段 | 含义 |
|---|---|
expected |
必填。当前的 session.revision。 |
input |
必填。文本,或者一个用户消息列表(见下文)。 |
stream |
可选。true 会发送实时事件。见 以流的形式获取回答。 |
background |
可选。只允许 true。每个 Turn 都在后台运行。 |
overrides |
可选。只对这个 Turn 生效的设置:mode 和 model。 |
input 只接受文本。下面三种形式是一样的:
"Plan three days in Rome."[{ "role": "user", "content": "Plan three days in Rome." }][ { "type": "message", "role": "user", "content": [{ "type": "input_text", "text": "Plan three days in Rome." }] }]未知字段会返回 400。
后台回答
没有 stream 时,OpenBot 立即返回 202。响应中有 status: "in_progress":
{ "id": "t-19aa", "object": "response", "created_at": 1792486800, "session": "a41c9e0f", "version": "v-7d21", "background": true, "status": "in_progress", "output": [], "error": null, "incomplete_details": null}请求结束后,工作会继续进行。之后用 GET /v1/sessions/:sessionId(response 字段)、等待路由,或 GET /v1/sessions/:sessionId/turns/:turnId 读取结果。
最终的 status 是 completed、incomplete、failed 或 cancelled。output 中的每一项都是一条 assistant 消息,包含 output_text 部分。usage 显示 token 用量。
以流的形式获取回答
使用 "stream": true 时,OpenBot 返回 200 和 Server-Sent Events(SSE)。SSE 是一种简单的格式,用来通过 HTTP 传送事件流。
curl -N -H "Authorization: Bearer $OPENBOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{"expected":0,"input":"Plan three days in Rome.","stream":true}' \ https://api.example.com/v1/sessions/$SESSION/turnsevent: response.output_text.deltadata: {"type":"response.output_text.delta","session":"a41c9e0f","turn":"t-19aa","step":1,"sequence_number":4,"item_id":"i-02","output_index":0,"content_index":0,"delta":"Day 1: ","logprobs":[]}事件按这个顺序到达:response.created、response.in_progress、response.output_item.added、response.content_part.added、多个 response.output_text.delta、response.output_text.done、response.content_part.done、response.output_item.done。最后一个事件是 response.completed、response.incomplete、response.failed 或 response.cancelled 之一。
这个流只是观察 Turn。如果你关闭它,Turn 会继续运行。
常见错误
| 状态码 | 错误 | 何时出现 |
|---|---|---|
400 |
SessionModelInvalid |
overrides 中的模型不存在。 |
404 |
SessionNotFound |
你没有这个 ID 的 Session。 |
409 |
SessionBusy |
这个 Session 已经有一个未完成的 Turn。 |
409 |
SessionConflict |
expected 已过时,或者 Turn 无法启动。 |
503 |
SessionExecutionUnavailable |
OpenBot 没有可以运行这个 Turn 的模型。 |
503 |
SessionStorageUnavailable |
OpenBot 无法连接到它的数据库。 |
Turn 也可以停下来等待:等待关于某项能力的决定,或者等待它分派给另一个 Agent 的工作。这时它的状态是 Waiting。等待在服务器重启后依然有效。见 Requests 和 委派。
读取 Turns 和 Items
GET /v1/sessions/:sessionId/turns 列出 Turn 记录,最早的排在前面。使用 limit(1 到 100,默认 50)和 after(一个 Turn ID)。回答是 { "items": [...], "next": "<turnId>" | null }。列表中也包括 Fork 从来源 Session 复制过来的 Turns。
GET /v1/sessions/:sessionId/turns/:turnId 返回 { "turn": {...}, "response": {...} }。Turn 记录包含 status、settings、steps、usage、start 和 end。start 是 Turn 之前的 Version。end 是 Turn 之后的 Version。如果 Turn 为 Session 所有者以外的另一个成员工作,它会有 author,也就是那个成员的用户 ID。在 Channel 中,它是写下这条消息的人。
GET /v1/sessions/:sessionId/turns/:turnId/items 列出一个 Turn 的 Items,使用相同的 after 和 limit。每个 Item 包含 id、content 和 origin(session、turn、step)。
引导、排队和中断
Steer(引导)向正在运行的 Turn 添加一条消息。Agent 在下一步读取它。
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{"input":"Keep it cheap."}' \ https://api.example.com/v1/sessions/$SESSION/turns/$TURN/steerOpenBot 返回 202,以及 session、turn、item、revision 和 version。如果这个 Turn 没有在运行,你会得到 409。有 author 的 Turn 只接受这个 author 发来的 steer 消息。
Queue(排队)把一条消息保存起来,留到之后处理:POST /v1/sessions/:sessionId/queue,请求体为 { "input": ..., "expected"?: <revision> }。当前 Turn 结束时,OpenBot 把下一条排队的消息作为一个新 Turn 启动。回答是 202,包含 session、item 和 revision。
Interrupt(中断)停止一个 Turn:POST /v1/sessions/:sessionId/turns/:turnId/interrupt,请求体为 {}。Turn 的状态变成 Interrupted,响应的状态变成 cancelled。已经结束的 Turn 会返回 409。
Resume(恢复)在重启后做清理:POST /v1/sessions/:sessionId/resume。如果保存的 Turn 仍然显示它在运行,但没有服务器在运行它(activity: "historical"),OpenBot 会把它标记为 Interrupted。它不会重新运行这个 Turn。Waiting 状态的 Turn 不受影响,因为它的等待已经保存下来。
待办列表
每个 Session 都有一个待办列表。当工作不止一步时,Agent 用工具 openbot_todos 来维护它。每一项都有 id、content 和 status。status 是 pending、in_progress 或 done。同一时间只能有一项是 in_progress。
只要还有一项不是 done,Agent 就会继续工作。如果 Agent 想在还有未完成项时结束 Turn,OpenBot 会加一条提醒,列出未完成的项,Agent 就会再做一步。对列表的每一种状态,OpenBot 只提醒一次。所以如果 Agent 再次停下,而列表没有变化,Turn 就会结束。
用 GET /v1/sessions/:sessionId/todos 读取列表:
{ "items": [ { "id": "read", "content": "Read the open issues", "status": "done" }, { "id": "fix", "content": "Fix the login bug", "status": "in_progress" } ]}用 PUT /v1/sessions/:sessionId/todos 替换整个列表。请发送你读到的 Session 的 Version 和 revision:
{ "expected": "<version>", "revision": 7, "items": [ { "id": "fix", "content": "Fix the login bug", "status": "pending" } ]}返回的是 Session 视图。旧的 Version 或 revision 会返回 409 和 SessionConflict。如果两项的 id 相同,或者不止一项是 in_progress,也会返回同样的错误。
列表是 Timeline 的一部分。对旧 Version 做 Fork 或恢复时,得到的是那个 Version 的列表。
等待
Agent 可以用工具 openbot_wait 等待。它给出 seconds,或者给出 until 和一个日期时间,例如 2026-10-23T09:00:00Z。Turn 会变成 Waiting。时间到了以后,这个工具调用会得到 { "waited": true, "at": "<time>" },Turn 接着运行。
OpenBot 会保存每一次等待。重启以后,等待会继续,直到时间到。如果等待的时间在没有服务器运行时就过了,它会在启动后马上继续。中断 Turn 会结束它的等待。
如果要同时等几个 Agent 的工作,Agent 在同一步里用几个 openbot_delegate 调用把任务交给它们。它们全部完成后,Turn 才会继续。见 委派。
计划模式
在 plan 模式下,Agent 可以查资料,但还不改动任何东西。它只能用只读取的工具:列出和读取 Agents 的 Agent 工具、App 的资源和 prompt,以及组织在 appReadRules 中列出的 App 工具。它也能用待办工具和等待工具。
计划写好后,Agent 调用 openbot_submit_plan,把步骤作为待办列表,再加一段简短的总结。OpenBot 会保存这个列表,并为能力 plans.run 创建一个 request。Turn 会等待。
- 请求被允许时,Session 切换到
build模式。一个新的 Turn 会带着所有工具开始,Agent 执行计划。 - 请求被拒绝时,Agent 会得到原因,并留在
plan模式。
批准设置决定由谁回答,以及没人及时回答时会怎样:
{ "approver": "person", "timeoutMs": 600000, "onTimeout": "run" }| 字段 | 取值 | 作用 |
|---|---|---|
approver |
chain、person |
chain 问 Agent 的上一级决策者,所以 Grant 或 Rule 可以回答。person 总是问人。 |
timeoutMs |
1 秒到 7 天 | 请求等待多久。 |
onTimeout |
run、stay |
run 表示没人及时回答时就执行计划。stay 表示 Session 留在 plan 模式。 |
你可以在四个地方设置它。设置了的地方里,最具体的那个生效,即使它更宽松:
- Session:创建时的
planApproval,或者用PATCH /v1/sessions/:sessionId。发送null可以移除它。 - Agent:Agent 上的
planApproval。 - 你自己:
PATCH /v1/me/settings,内容是{ "expectedVersion": 0, "planApproval": { ... } }。用GET /v1/me/settings读取你的设置。 - 组织:设置中的
planApproval。它只是默认值,不能禁止更宽松的设置。
模型和执行模式
GET /v1/sessions/:sessionId/models 显示你可以选择的模型:
{ "selected": { "_tag": "Config.Selection", "provider": "development", "model": "mock-text" }, "providers": [ { "id": "development", "name": "Development scenarios (simulated)" } ], "models": [ { "_tag": "Config.Model", "provider": "development", "id": "mock-text", "name": "mock-text (simulated)", "reasoningEfforts": [], "serviceTiers": [] } ]}用 PUT /v1/sessions/:sessionId/model 为 Session 选择模型:
{ "expected": 4, "selection": { "_tag": "Config.Selection", "provider": "development", "model": "mock-slow" }}错误的选择会返回 400 和 SessionModelInvalid。reason 是 provider-not-found、model-not-found 或 unsupported-option。如果只想在一个 Turn 中使用某个模型,请在启动 Turn 时把选择放在 overrides.model 中。OpenBot 如何得到它的模型,见 Models。
执行模式是 build 或 plan。build 是普通模式:Agent 直接做事。在 plan 模式下,Agent 先写一个计划。见 计划模式。用 PUT /v1/sessions/:sessionId/mode 和 { "expected": 4, "mode": "plan" } 设置模式,或者在创建 Session 时用 settings.mode 设置。OpenBot 把模式保存在 Session 上,并把它复制到每个新 Turn 的 settings 中。
PUT /v1/sessions/:sessionId/settings 一次替换所有设置:{ "expected": 4, "settings": { "mode": "build" } }。
从某个 Version 分叉
Fork(分叉)会创建一个新的 Session,它从另一个 Session 的某个 Version 开始。来源 Session 不会变化。
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{"version":"v-7d21","title":"Rome, plan B"}' \ https://api.example.com/v1/sessions/$SESSION/fork所有字段都是可选的:version、title 和 settings。没有 title 时,Fork 保留来源的标题。没有 version 时,Fork 从最新的完整点开始。OpenBot 返回 201 和新的 Session 视图。它的 session.forkedFrom 指出来源 Session 和 Version。
要查找 Versions,请使用 GET /v1/sessions/:sessionId/versions。要查看某个 Version 时的历史,请使用 GET /v1/sessions/:sessionId/history?version=<versionId>。
重新生成回答
要为同一个问题得到新的回答,请从那个 Turn 之前的 Version 分叉。然后用相同的输入启动一个新的 Turn。
- 用
GET /v1/sessions/$SESSION/turns/$TURN读取这个 Turn。记下turn.start。turn.input列出了输入 Items 的 ID。用 Items 路由读取它们的文本。 - 用
{ "version": "<turn.start>" }分叉。记下新的session.id和session.revision。 - 在新的 Session 中,用相同的
input启动一个 Turn。
导出和导入
GET /v1/sessions/:sessionId/record 把整个 Session 导出为一条记录。这条记录包含 formatVersion、session、versions 和 messages。
PUT /v1/sessions/:sessionId/record 导入一条记录。请求体是 { "record": {...}, "expected": ... }:
- 使用
"expected": null,从这条记录创建一个新的 Session。 - 要替换一个已有的 Session,请把
expected设为它当前的session对象,这个对象来自GET /v1/sessions/:sessionId。
记录中的 session.id 必须和路径一致。如果不一致,OpenBot 返回 400 和 SessionInvalidRecord。如果有 Turn 正在运行,OpenBot 返回 409 和 SessionBusy。
导入只恢复数据。它不会重新启动 Turn。
所有字段见 Sessions 参考。