Skip to content

Variables(变量)

变量就是在对话里存一些键值对,用它来记住状态。

它分了五个层级:全局、会话、分支、楼层、页。层级越靠下,优先级越高——页级值会覆盖楼层级值,依此类推。

什么时候需要看这页

  • 你要写入或读取变量
  • 你要了解变量的五级优先级是怎么工作的
  • 你要看某个变量当前到底取的是哪个层级的值
  • 你要批量同步变量

一个简单例子

假设你在一个 RPG 会话里记录了冒险者的金币数:

bash
# 写一个分支级别的变量
curl -X PUT http://localhost:3000/variables \
  -H 'Content-Type: application/json' \
  -d '{
    "scope": "branch",
    "session_id": "sess_001",
    "branch_id": "main",
    "key": "gold",
    "value": 500
  }'

# 解析当前上下文里真正生效的 gold 值
curl "http://localhost:3000/variables/resolve?session_id=sess_001&branch_id=main"

先理解几个词

这里的意思
scope变量的作用域,一共五级
global全局范围
chat会话范围
branch分支范围
floor楼层范围
page页范围
resolve按优先级合并五级变量,得到最终胜出的值

作用域

scope说明
global全局变量
chat会话级变量
branch分支级变量
floor楼层级变量
page页级变量

优先级从高到低:page > floor > branch > chat > global

global 写入和解析时会把 scope_id 规范化为固定值 global

branch 的宿主由 session_id + branch_id 共同确定。对 branch 来说,scope_id 是服务端内部使用的规范化字符串。调用方更适合使用 scope_refsession_idbranch_id

branch 写入的前置条件是:目标 branch 必须已经被注册为 branch host。通常在创建 session、创建 floor、预留分支或导入聊天时,服务端会自动维护这个 registry。只要 branch host 已存在,即使该分支当前还没有 floor,也允许直接写入 branch 变量。

sessionfloorpage 等宿主被删除时,对应作用域变量会一起清理。/variables 列表和详情不会继续暴露宿主已经失效的孤儿变量。

三个观察面

变量系统现在同时提供三个观察面:

  1. PUT /variablesGET /variablesGET /variables/resolve
    • 这是显式 durable write / durable read
    • GET /variables/resolve 仍然只返回 durable truth
  2. GET /pages/:pageId/variables/staged
    • 这是当前页的候选写入检查面
    • 只读,不改变 durable truth
  3. GET /pages/:pageId/variables/promotions
    • 这是当前页已经发生的 durable promotion 轨迹
    • 只读,不改变 durable truth

这三组接口要分开理解。/variables/resolve 不会把 staged write 和 promotion trace 混进去。

与宏兼容层的关系

/variables 描述的是 TavernHeadless 底层五级变量真相模型。

当前 ST 宏兼容层只是运行时视图,不会改变 /variables 资源本身的语义。

也就是说:

  • /variables 仍然以 globalchatbranchfloorpage 五级作用域为准
  • 宏系统中的 local / global 只是提示词装配阶段的兼容视图
  • getvargetglobalvar.name$name 这类宏,不会把底层资源模型改成两级变量系统

当前兼容层的运行时映射规则是:

text
local 兼容视图  -> 以 branch 语义为主的读取与 staged overlay
global 兼容视图 -> global 读取与 staged overlay

因此:

  • getvar / .name 读取 local 兼容视图
  • getglobalvar / $name 读取 global 兼容视图
  • setvarsetglobalvar 的同轮 staged 可见性彼此隔离
  • 真正持久化时,仍然通过既有变量提交链路落到 TavernHeadless 的底层作用域模型
  • 当前 variableCommit 仍只做 page -> floor 提交;不会自动改成 toScope=branch,也不会做多跳 promotion

当前宏兼容层也支持对结构化 JSON 变量做路径访问,例如:

text
{{getvar::资产.金币}}
{{getglobalvar::账户.余额}}
{{getvar::装备["剑.名"]}}
{{setvar::资产.金币::3}}
{{deletevar::资产.银币}}

这里要注意两点:

  1. 兼容层总是先按完整 flat key 查找,找不到时才回退到路径语义。
  2. 路径写入持久化的是 root key 对应的 JSON 值,不会在底层额外生成 资产.金币 这样的变量键。

补充说明:

  • 当宏读取到对象值时,对外文本结果和 runtime_trace.macro.mutation_preview / staged_mutations 中的 value 会稳定输出为 JSON 字符串。
  • POST /sessions/:id/prompt-runtime/preview 对一个尚未物化的新分支同时传入 branch_idsource_floor_id 时,local 兼容视图会先继承 source floor 当时可见的 local 值,再进入 preview overlay。
  • 这一继承语义现在只接受精确的 branch_local_variable_snapshot。如果 source floor 缺少该快照,服务端会返回 409 branch_local_snapshot_missing,而不会退回到当前 branch/chat 可见值。

如果你需要查看宏系统的兼容边界、warning、trace 和 dry-run 调试字段,请参考 MacrosChat

Variable 对象

字段类型说明
idstring变量 ID
scopestring作用域
scope_idstring作用域关联的资源 ID
scope_refobjectbranch 返回,包含 session_idbranch_id
keystring变量键名
valueany变量值(任意 JSON)
updated_atinteger更新时间

scope_ref

当变量来自 branch 作用域时,响应会额外返回:

json
{
  "scope_ref": {
    "session_id": "session-a",
    "branch_id": "alt-1"
  }
}

设置变量(Upsert)

http
PUT /variables

如果相同 account_id + scope + scope_id + key 的变量已存在则更新,否则创建。

请求体

字段类型必填说明
scopestring作用域:global / chat / branch / floor / page
scope_idstring条件必填branch 作用域时必填;branch 时可选
session_idstring条件必填branch 作用域可与 branch_id 一起提供
branch_idstring条件必填branch 作用域可与 session_id 一起提供
keystring键名(至少 1 字符)
valueany值(任意 JSON,不可为 undefined

branch 的两种写法

写法一:显式提供分支宿主

json
{
  "scope": "branch",
  "session_id": "session-a",
  "branch_id": "alt-1",
  "key": "route",
  "value": "campfire"
}

写法二:直接提供内部 scope_id

json
{
  "scope": "branch",
  "scope_id": "branch:session-a:alt-1",
  "key": "route",
  "value": "campfire"
}

如果同时提供 scope_idsession_id + branch_id,服务端会校验两者是否一致;不一致时返回 400

无论使用哪种写法,branch 写入前都需要该 branch 已经至少有一条 floor。变量接口不会替你惰性创建 branch 宿主。

响应

  • 200:更新成功
  • 201:创建成功

返回 { "data": Variable }

错误

状态码说明
400请求体校验失败、上下文不一致、变量值不合法
404目标宿主不存在,或当前账号不可访问
409目标已锁定,例如写入 generatingcommittedfloor / page

批量设置变量

http
PUT /variables/batch

批量 upsert 变量。每个条目的语义与单条 PUT /variables 相同。

请求体

字段类型必填说明
itemsVariableWrite[]变量数组,1-100 条

每个 items 元素都可以使用单条 upsert 的字段。

去重校验

同一批次内,规范化后的 scope + scope_id + key 组合不可重复,否则返回 400。 这意味着两个 branch 条目即使一个使用 scope_id,另一个使用 session_id + branch_id,只要最终目标相同,也会被视为重复。

响应 200

json
{
  "data": {
    "results": [
      {
        "index": 0,
        "action": "created",
        "data": {
          "id": "var_001",
          "scope": "branch",
          "scope_id": "branch:session-a:alt-1",
          "scope_ref": {
            "session_id": "session-a",
            "branch_id": "alt-1"
          },
          "key": "route",
          "value": "campfire",
          "updated_at": 1735689600000
        }
      },
      {
        "index": 1,
        "action": "updated",
        "data": {
          "id": "var_002",
          "scope": "chat",
          "scope_id": "sess_001",
          "key": "mood",
          "value": "tense",
          "updated_at": 1735689605000
        }
      }
    ],
    "meta": { "total": 2, "created": 1, "updated": 1 }
  }
}

错误

状态码说明
400请求体校验失败、items 为空或超过 100 条、同批次目标重复
404某个变量宿主不存在,或当前账号不可访问
409某个目标已锁定,例如写入 generatingcommittedfloor / page

查询变量

http
GET /variables

查询参数

参数类型默认值说明
scopestring-按作用域过滤
scope_idstring-按关联 ID 过滤
session_idstring-scope=branch 时可与 branch_id 一起过滤
branch_idstring-scope=branch 时可与 session_id 一起过滤
keystring-按键名过滤
limitinteger50返回条数上限
offsetinteger0偏移量
sort_bystringupdated_atupdated_at / key
sort_orderstringdescasc / desc

说明

  • session_idbranch_id 只在 scope=branch 时可用。
  • scope=branch 时,可以使用 scope_id,也可以使用 session_id + branch_id
  • 只传 scope=branch 而不带过滤参数时,会列出当前账号下所有分支变量。

响应 200

返回 { "data": Variable[], "meta": ListMeta }

获取变量详情

http
GET /variables/:id

响应 200

返回 { "data": Variable }

如果变量宿主已经失效,该接口会按不存在处理,不会继续暴露孤儿变量。

错误

状态码说明
404变量不存在,或当前账号不可访问

删除变量

http
DELETE /variables/:id

响应 200

json
{ "data": { "id": "var_001", "deleted": true } }

如果传入的是历史孤儿变量 ID,服务端仍会接受删除,用于清理宿主已失效的数据。

错误

状态码说明
404变量不存在,或当前账号不可访问
409目标已锁定,例如删除 generatingcommittedfloor / page 变量

解析当前上下文可见变量

http
GET /variables/resolve

这个接口返回当前 session / branch / floor / page 上下文里最终可见的变量快照。

查询参数

参数类型必填说明
session_idstring会话 ID
branch_idstring分支 ID
floor_idstring楼层 ID
page_idstring页 ID
include_layersboolean是否附带各层原始快照,默认 false

解析规则

  • 如果提供 page_id,服务端会从页反查楼层和分支。
  • 如果提供 floor_id,服务端会从楼层反查分支。
  • 如果显式提供 branch_id,服务端会校验它是否与 page_idfloor_id 推导出的分支一致。

响应 200

json
{
  "data": {
    "context": {
      "account_id": "default-admin",
      "session_id": "session-a",
      "branch_id": "alt-1",
      "floor_id": "floor-a",
      "page_id": "page-a",
      "global_scope_id": "global"
    },
    "resolved": [
      {
        "key": "route",
        "value": "campfire",
        "source_scope": "branch",
        "source_scope_id": "branch:session-a:alt-1",
        "source_scope_ref": {
          "session_id": "session-a",
          "branch_id": "alt-1"
        },
        "updated_at": 1735689720100
      }
    ],
    "layers": {
      "branch": {
        "scope": "branch",
        "scope_id": "branch:session-a:alt-1",
        "scope_ref": {
          "session_id": "session-a",
          "branch_id": "alt-1"
        },
        "items": [
          {
            "id": "var_branch_route",
            "scope": "branch",
            "scope_id": "branch:session-a:alt-1",
            "scope_ref": {
              "session_id": "session-a",
              "branch_id": "alt-1"
            },
            "key": "route",
            "value": "campfire",
            "updated_at": 1735689720100
          }
        ]
      }
    }
  }
}

返回字段

data.context

字段类型说明
account_idstring当前账号
session_idstring当前会话
branch_idstring当前分支(如果可以解析到)
floor_idstring当前楼层(如果提供)
page_idstring当前页(如果提供)
global_scope_idstring全局作用域固定值,通常为 global

data.resolved[]

字段类型说明
keystring变量键
valueany当前胜出值
source_scopestring胜出值来自哪个作用域
source_scope_idstring胜出值来自哪个作用域 ID
source_scope_refobject胜出值来自 branch 时,补充返回 { session_id, branch_id }
updated_atinteger胜出值更新时间

resolved 会按 key 排序。

data.layers

只有当 include_layers=true 时才会返回。

每个层级对象结构相同:

字段类型说明
scopestring当前层级
scope_idstring当前层级 ID
scope_refobject当层级为 branch 时,补充返回 { session_id, branch_id }
itemsVariable[]该层级下原始变量列表

错误

状态码说明
400查询参数不合法,或 session_id / branch_id / floor_id / page_id 上下文不一致
404目标宿主不存在,或当前账号不可访问

兼容规则

GET /variables/resolve 只返回 durable truth。

它不会:

  • 读取当前 turn 的 tool buffer
  • 读取 page_staged_variable_write
  • 读取 variable_promotion_trace

如果你要看页级候选写入或 promotion 轨迹,需要使用下面两个只读 inspect 接口。

查看页级候选变量写入

http
GET /pages/:pageId/variables/staged

这个接口返回某个 page 上已经持久化的 staged write ledger。

响应 200

json
{
  "data": {
    "page_id": "page-a",
    "floor_id": "floor-a",
    "session_id": "session-a",
    "branch_id": "main",
    "items": [
      {
        "id": "staged_001",
        "key": "mood",
        "op": "set",
        "value": "steady",
        "intent": "promote_to_floor_on_accept",
        "conflict_policy": "replace",
        "reason": "builtin:set_variable",
        "source": { "toolName": "set_variable", "providerId": "builtin" },
        "evidence": { "runId": "run-1", "generationAttemptNo": 1 },
        "status": "promoted",
        "decision_reason": null,
        "created_at": 1735689720000,
        "resolved_at": 1735689720100
      }
    ]
  }
}

说明

  • status=staged 表示已经入 ledger,但还没有走到 accepted page materialization / promotion 终态。
  • status=accepted_page_only 表示该条目已经物化到 variable(scope='page'),但没有进入 page -> floor promotion。
  • status=promoted 表示该条目已经完成 page -> floor promotion。

查看页级变量提升轨迹

http
GET /pages/:pageId/variables/promotions

这个接口只返回真正已经发生的 durable promotion。

响应 200

json
{
  "data": {
    "page_id": "page-a",
    "floor_id": "floor-a",
    "session_id": "session-a",
    "branch_id": "main",
    "items": [
      {
        "id": "trace_001",
        "staged_write_id": "staged_001",
        "key": "mood",
        "from_scope": "page",
        "from_scope_id": "page-a",
        "to_scope": "floor",
        "to_scope_id": "floor-a",
        "conflict_policy": "replace",
        "source_variable_id": "var_page_001",
        "target_variable_id": "var_floor_001",
        "value": "steady",
        "created_at": 1735689720100
      }
    ]
  }
}

这条轨迹当前只记录 page -> floor。更高层级 promotion 没有在本轮开放执行入口。

官方集成层对应方法

  • @tavern/sdkclient.variables.resolveContext(...)
  • @tavern/sdkclient.variables.getPageStagedWrites(...)client.variables.getPagePromotions(...)
  • @tavern/client-helpersflattenVariableSnapshot(...)sortVariableInspectorRows(...)flattenPageStagedVariableWrites(...)groupVariablePromotionTrace(...)