#595·Trellis

[OMP] Late-bound task context breaks prompt-cache prefix stability in 0.6.16

Author: mudsskyCreated Sep 1, 2026Updated Sep 4, 2026

Bug Description

Trellis 0.6.16 的 OMP extension 会在每次 context hook 中同步当前 task context。若 OMP session 在 session_start 时尚未绑定 task、之后才通过常规 task.py create / task.py start 绑定,历史中不存在持久化的 trellis-task-context,当前实现会执行:

typescript
if (replacement && !replaced) projectedMessages.push(replacement)

这会把非持久化 task context 追加到每次 provider payload 的当前尾部。随着持久历史增长,相邻请求变为:

request 1: history H + task context C
request 2: history H + new message N + task context C

因此 request 1 不再是 request 2 的前缀,破坏 OMP/OpenAI Responses prompt cache 所需的 append-only prefix stability,造成缓存命中率下降、输入成本和延迟增加。

这不是罕见的手工操作:Trellis 的 active task 是 session-scoped,常规流程通常是在已经启动的 OMP session 中创建并自动激活 task,因此 task 天然是在 session_start 之后绑定。

该问题可能是 #533 的 task-context freshness 修复引入的副作用:task context 现在可以刷新,但缺失 context 的首次同步使用了移动的尾部位置。

Steps to Reproduce

使用同一个 Trellis OMP extension 实例进行生命周期测试,不需要调用模型或 provider:

  1. 启动 OMP session,此时对应 session runtime mapping 中没有 current_task
  2. 触发 session_start,确认没有持久化 trellis-task-context
  3. 在该 session 的 .trellis/.runtime/sessions/<context-key>.json 中绑定一个有效 task,等价于在会话内执行常规 task.py create / task.py start
  4. 使用持久消息历史调用一次 context hook,记录返回的 projected messages。
  5. 向持久消息历史追加一个合成消息。
  6. 再次调用同一个 extension 实例的 context hook。
  7. 比较两次 projected messages 的 item 顺序和前缀关系。

Observed with 0.6.16:

late-bound task:
  projected item count: 4 -> 5
  task context index:   3 -> 4
  request 1 is a prefix of request 2: false

Controls:

0.6.16, task already bound at session_start:
  projected item count: 4 -> 5
  request 1 is a prefix of request 2: true

0.6.15, late-bound task:
  projected item count: 3 -> 4
  moving task context injection: absent
  request 1 is a prefix of request 2: true

The comparison uses synthetic messages only. No production prompt, response, credentials, cache key, session ID, request body, or provider call is required.

Expected Behavior

Binding a task after session_start should refresh/inject task context without moving an earlier request item on every subsequent provider call.

Possible fixes:

  • persist the task context once when a task first becomes bound;
  • reserve a stable context slot and replace that slot in projections;
  • otherwise ensure adjacent provider payloads remain append-only after the one-time task transition.

Archiving or switching tasks may reasonably invalidate the cache once, but should not cause the task context to move to a new tail position on every API call.

Temporary workaround: immediately after binding a task, exit and resume the same OMP session so session_start runs again with the same session identity and persists the task context before long tool loops begin.

Trellis Version

0.6.16

Regression control: 0.6.15 does not reproduce the moving-tail behavior.

Node.js Version

v24.14.1

Operating System

macOS 26.6.2