Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions benchmark/runtime/context_delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ def preflight_context_instruction(env: dict[str, str], path: Path, digest: str,
source = ["--capture-file", str(path), "--capture-sha256", digest]
project = [*prefix, "context-project", *source,
"--goal-id", env["LOOPX_GOAL_ID"], "--agent-id", env["LOOPX_AGENT_ID"],
"--turn-instance-id", turn_id, "--context-delivery", "on", "--runtime-profile", "generic_cli", "--codex-context-dir", env["LOOPX_CODEX_CONTEXT_DIR"],
"--decision-output-root", str(path.parent / "decisions")]
"--turn-instance-id", turn_id, "--context-delivery", "on", "--runtime-profile", "generic_cli", "--codex-context-dir", env["LOOPX_CODEX_CONTEXT_DIR"]]
full = [*prefix, "context-read", *source]
return ("Present that same immutable packet with:\n```sh\n" + shlex.join(project)
+ "\n```\nFollow the returned command and all next_command pages; reconstruct any delta against "
Expand Down
90 changes: 90 additions & 0 deletions docs/reference/required-work-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ selection and fulfillment policy in both ordinary packets and TurnEnvelope.
`work_context.complete` means no known source failure, not that pending reads
have been consumed. TurnEnvelope signs the same content and obligations; its
size warning never truncates current requirements or removes a pending read.
Full progressive reads carry the complete-Goal, no-summary and fresh-guard
obligations. Only a fulfilled registered narrative adds the generated-region
and canonical-Todo ownership explanation; pending reads do not repeat that
inapplicable explanation. Todo-bound semantic replanning also uses the same
autonomous Vision authoring contract in its action and settlement projections,
so exact in-response references retain complete replacement and replan rules.
Ordinary settlement and all execution/receipt checks keep their existing rules.
An existing receipt-bound Todo retains its original Task identity during a
semantic replan. Only an unbound fallback yields to the original Todo-less
planning obligation; that obligation must match its signed Goal, Agent and
Turn. Neither route admits ordinary work while delivery remains withheld.

Preferences remain conditional on scoped records. The existing preference and
Explore hooks return their actual read context through registered adapters;
Expand All @@ -55,6 +66,15 @@ preserve their off-state. User Todo inventory views disappear only from exact
Todo responses; scoped User decisions and gates remain in the work context
and retain their existing admission/notification authority.

Todo context retains complete scoped records and canonical read provenance,
including the record schema, snapshot digest, count and provider revision. It
omits the known canonical reader's `contract_fields` dictionary: field names
describe the reader's record format, not additional task requirements. Empty
scoped User results still retain their source proof. Unknown read schemas and
malformed dictionaries remain verbatim. The explicit canonical Todo commands
keep their full read metadata; this default context compaction requires no
cross-Turn baseline and leaves all record values, gates and stops intact.

Source failure retains the unresolved read, identifies the unavailable source,
and blocks dependent delivery until recovery and a fresh guard. Reading current
content is not an execution grant or proof of Goal completion.
Expand Down Expand Up @@ -117,6 +137,37 @@ upgrades installed automations nor proves model adoption or token/latency gains.
To roll back, install the prior revision and regenerate prompts; changing a
transport flag does not restore the old exact Todo schema.

## Opt-in native reuse

The existing [native context delivery option](../heartbeat-automation-prompt.md#opt-in-native-context-delivery)
uses one TypeScript codec for ordinary quota and TurnEnvelope. Within a confirmed
baseline, both representations repeat `planning_horizon.core_goal`'s original
objective, provenance and availability, including a changed or missing objective.
The complete `acceptance_contract` and registered planning trees use exact
reuse, subtree changes or a complete refresh; the acceptance tree is not treated
as the original Goal sentence. Unknown horizon fields remain current input.

The same codec retains complete static closure guidance in quota channels and
the Turn contract capsule. Current closure decisions, conditions, identities,
commands and unknown controls remain current input. Explore's registered owner
also permits exact reuse of branch evidence audits and its evidence-link template;
branch identity, selection, status, resume facts and orchestration gates remain
current. Reordering, refutation, removed evidence and changed guidance reconstruct
the exact current source; no timestamp, revision or text is normalized away.

Object edits may group complete current fields in `values`, alongside recursive
`changed` edits and `removed` keys. Array edits use exact indices in `items` and
`values`, with `length` for resizing. These literals are present in the current
input; grouping saves repeated wrappers rather than omitting controls. The
codec compares this encoding with ordinary edits and full replacement before
choosing. A reader that does not recognize the edit recovers the full capture.

These are presentation rules within the existing default-off option, not a new
configuration or admission policy. Missing retention, a changed epoch, a damaged
patch or an incompatible reader automatically recovers the same original full
capture. Recovery never reruns the guard, asks the owner, spends quota or grants
execution. Wire reduction alone does not establish actual model costs or outcomes.

## 中文

普通 Heartbeat/quota 默认在 `agent_channel.work_context` 返回完整选定 Todo、
Expand All @@ -138,6 +189,9 @@ Goal adapter 仍完整读取文件、校验 UTF-8,并以全部字节计算修
偏好只在对应作用域有记录时出现;Explore 和偏好沿用各自 hook 的真实 adapter,
读取范围由 capability owner 决定。来源失败保留未完成必读项并阻止依赖交付,恢复后
重新准入;User gate 仍生效。大小告警不截断验收或移除剩余必读项。
已有 receipt 绑定的 Todo 在语义重规划中保留原 Task 身份;只有未绑定的备选任务才让位于
原无 Todo 规划义务,该义务必须与签名中的 Goal、Agent 和 Turn 一致。两条路径都不会
在普通交付被禁止时授权执行业务工作。

已选定工作时,验收 adapter 复用 canonical owner 的精确 Todo 读取,顶层 `tasks`
只携带该工作的关联观察;完整 Goal 合同、已配置 scope、检查、受阻工作和累计 outcome
Expand All @@ -160,3 +214,39 @@ Goal adapter 仍完整读取文件、校验 UTF-8,并以全部字节计算修

安装后重新生成旧展开式 heartbeat 提示;此 PR 不热更新 runtime/automation,
也不证明模型已采用或获得质量收益。回滚需恢复旧版本并重新生成提示。

既有默认关闭的原生 context delivery 由同一 TypeScript codec 处理普通 quota 与
TurnEnvelope。确认基线保留后,两入口仍逐轮发送 `planning_horizon.core_goal` 的
原始目标、来源和可用性,包括目标改变或缺失。完整 `acceptance_contract` 与已登记
规划树按精确复用、子树变化或全量交付;累计验收树不等于原始目标句。未知 horizon
字段仍作为本轮输入。quota 通道与 Turn 契约摘要复用完整静态收口指导,当前收口判断、
条件、身份、命令与未知控制仍逐轮发送。Explore owner 登记分支证据审计与证据关联
模板的精确复用;分支身份、选择、状态、恢复事实与编排门仍是当前输入。重排、反证、
移除与指导变更完整重建当前来源,不规范化时间戳、修订或正文。
对象编辑可以在 `values` 中合并携带本轮完整字段,同时保留递归 `changed` 与删除
`removed`;数组的 `items` 与 `values` 使用精确索引,`length` 调整长度。
字段仍在本轮输入中,只减少重复 wrapper;codec 比较普通编辑、合并字段
与完整替换后选择,无法识别该编辑的读者恢复完整 capture。
这些只改变既有选项内的展示,不新增配置或准入。保留不明、epoch 改变、patch 损坏
或读者不兼容时,自动恢复同一原始 full capture,不重跑 guard、不问询、不扣额,
也不授予执行权限。传输减少本身不证明实际模型费用或结果改善。

### Saved context cache / 已保存上下文缓存

For `quota context-project`, enabling context delivery no longer requires a
second cache-directory setup step. Omitting `--decision-output-root` reuses the
native session's private context directory. An explicit missing leaf is created
with mode `0700` under an existing parent; existing directories must remain
private, physically addressed and owned by the current user. Existing symlinks,
non-directories and unsafe permissions are rejected without changing them.
Normal platform parent aliases are resolved before validating the leaf.
Read-only recovery never creates a cache. With context delivery off, projection
remains inert and reads the original capture. Failures retain that capture's
exact digest and Turn receipt; they never rerun admission or spend quota.

`quota context-project` 开启上下文投递后,不再要求另外手工准备缓存目录。
省略 `--decision-output-root` 时复用原生会话的私有上下文目录;显式指定的新目录
在已存在的父目录下以 `0700` 创建。已有目录仍须属于当前用户、权限私有且不是
符号链接;不修改不安全目录的权限。平台正常的父路径别名先解析再检查末级目录。
只读恢复不创建缓存;关闭上下文投递时保持无副作用,读取原始 capture。失败仍保留
原始摘要和 Turn 回执,不重新准入或扣减额度。
14 changes: 10 additions & 4 deletions loopx/cli_commands/quota_capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,20 @@ def project_saved_context_capture(args: argparse.Namespace) -> dict[str, Any]:

if not activation["enabled"]:
raise ValueError("context delivery is off")
root = Path(args.decision_output_root).expanduser().absolute()
metadata = root.lstat()
if root.resolve(strict=True) != root or not stat.S_ISDIR(metadata.st_mode) or metadata.st_uid != os.getuid() or metadata.st_mode & 0o077:
raise ValueError("saved projection needs an existing private physical capture root")
directory = codex_context_directory(directory=args.codex_context_dir,
root=args.codex_context_root, create=True)
if not directory:
raise ValueError("native context is unavailable")
# The session already owns a private recovery location. Callers need
# only supply a separate cache root when they want another location.
# Create a missing leaf privately; never chmod or follow an existing
# leaf. Normal platform parent aliases (such as /tmp) remain usable.
root = Path(args.decision_output_root or directory).expanduser().absolute()
root = root.parent.resolve(strict=True) / root.name
root.mkdir(mode=0o700, exist_ok=True)
metadata = root.lstat()
if not stat.S_ISDIR(metadata.st_mode) or metadata.st_uid != os.getuid() or metadata.st_mode & 0o077:
raise ValueError("saved projection needs a private physical capture root owned by this user")
cache = Path(tempfile.mkdtemp(prefix="context-", dir=root))
projected = project_codex_context(payload, directory=directory, capture_directory=cache,
goal_id=args.goal_id, agent_id=args.agent_id, surface="quota_packet",
Expand Down
24 changes: 17 additions & 7 deletions loopx/cli_commands/turn_decision.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@
from ..control_plane.quota.heartbeat_receipt import (
find_heartbeat_receipt,
heartbeat_receipt_settlement_replan_obligation_id,
heartbeat_receipt_settlement_todo_id,
)
from ..control_plane.goals.first_party_host_admission import FirstPartyHostRuntimeRejected
from ..control_plane.turn_driver.driver import build_loopx_turn_plan, selected_turn_todo
from ..control_plane.scheduler.execution_context import (
SchedulerExecutionContextResolution,
scheduler_execution_context_for_turn,
)
from ..status import AUTONOMOUS_REPLAN_PERIODIC_LOOKBACK, collect_status
Expand All @@ -57,6 +59,7 @@ def _attach_original_replan_settlement(
decision: dict[str, Any], *, registry_path: Path, runtime_root: Path,
goal_id: str, agent_id: str,
turn_instance_id: str | None, goal_ref: Mapping[str, object] | None,
receipt_bound_todo_id: str | None = None,
) -> dict[str, Any]:
"""Give an outer executor the existing quota-owned scoped plan.

Expand All @@ -68,11 +71,15 @@ def _attach_original_replan_settlement(
if not turn_instance_id or not obligation or decision.get("should_run") is not True:
return decision
agent = (decision.get("interaction_contract") or {}).get("agent_channel") or {}
selected = decision.get("selected_todo")
original_task = (isinstance(selected, Mapping) and receipt_bound_todo_id is not None
and selected.get("todo_id") == receipt_bound_todo_id)
if (agent.get("must_attempt") is True and agent.get("delivery_allowed") is False
and decision.get("effective_action") == EffectiveAction.AUTONOMOUS_REPLAN_REQUIRED.value):
and decision.get("effective_action") == EffectiveAction.AUTONOMOUS_REPLAN_REQUIRED.value
and not original_task):
# A fallback business Todo is context, not the selected owner of a
# required semantic replan. Bind the existing obligation so launch,
# writeback and spend all retain that same governance identity.
# required semantic replan. An original receipt-bound Task already
# owns its replan, so only an unbound fallback yields to the obligation.
decision.pop("selected_todo", None)
if decision.get("selected_todo"):
return decision
Expand Down Expand Up @@ -125,8 +132,8 @@ def _build_turn_decision(
*,
registry_path: Path,
runtime_root: Path,
status_payload: Mapping[str, Any],
scheduler_execution_context: Mapping[str, Any],
status_payload: dict[str, Any],
scheduler_execution_context: Mapping[str, Any] | SchedulerExecutionContextResolution,
operator_inbox_urgency_projector: Callable[..., dict[str, Any]],
turn_start_hook_dispatch: Mapping[str, Any] | None = None,
goal_ref: Mapping[str, object] | None = None,
Expand Down Expand Up @@ -154,6 +161,7 @@ def _build_turn_decision(
agent_id=args.agent_id, turn_instance_id=turn_instance_id, goal_ref=goal_ref)
if turn_instance_id else None)
bound_replan = heartbeat_receipt_settlement_replan_obligation_id(receipt) if receipt else None
bound_todo = heartbeat_receipt_settlement_todo_id(receipt) if receipt else None

def build_turn_decision(
*, requested_action_todo_id: str | None = None
Expand Down Expand Up @@ -194,6 +202,7 @@ def build_turn_decision(
decision, registry_path=registry_path, runtime_root=runtime_root,
goal_id=args.goal_id, agent_id=args.agent_id,
turn_instance_id=turn_instance_id, goal_ref=goal_ref,
receipt_bound_todo_id=bound_todo,
)

return build_turn_decision
Expand Down Expand Up @@ -234,7 +243,7 @@ class FreshTurnDecisionOwner:
"""

status_payload: Mapping[str, Any]
scheduler_execution_context: Mapping[str, Any]
scheduler_execution_context: Mapping[str, Any] | SchedulerExecutionContextResolution
operator_inbox_urgency_projector: Callable[..., dict[str, Any]]
build_turn_decision: Callable[..., dict[str, Any]]
requested_todo_id: str | None = None
Expand Down Expand Up @@ -343,7 +352,8 @@ def current_turn_host_launch_decision(
)
_attach_original_replan_settlement(current, registry_path=registry_path,
runtime_root=runtime_root, goal_id=identity.goal_id, agent_id=identity.agent_id,
turn_instance_id=identity.turn_instance_id, goal_ref=goal_ref)
turn_instance_id=identity.turn_instance_id, goal_ref=goal_ref,
receipt_bound_todo_id=identity.todo_id or None)
launch = {"current": current, "planned_effective_action": planned_effective_action}
# The shared typed launch owner retains refusal precedence (including
# Stop/witness failures) and compares the original effective action.
Expand Down
13 changes: 11 additions & 2 deletions loopx/control_plane/capabilities/explore_turn_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {projectExploreMeasurementFeedback} from "./explore_measurements.ts";
* selection, eligibility, source revisions and pagination stay outside this
* split. Exact array edits retain every change, including its status,
* provenance and applicability; no timestamp or revision is normalized away. */
export function exploreReusableContextPaths(): string[][] {
export function exploreReusableContextPaths(content: JsonObject = {}): (string | number)[][] {
return [
...["recent_nodes", "recent_findings", "writeback_results", "measurement_feedback",
"path_delta_attachment_template", "linked_question_attachment_template",
Expand All @@ -23,7 +23,16 @@ export function exploreReusableContextPaths(): string[][] {
"record_node_template", "record_finding_template", "guidance",
"result_writeback_option", "result_writeback_inline_option", "result_writeback_inline_field",
"result_attachment_schema", "path_delta_attachment_schema"].map(key => ["graph", key]),
["harness", "guidance"],
["harness", "guidance"], ["harness", "link_evidence_template"],
// The branch's identity, selection, status and resume facts stay fresh.
// Its evidence audit is a read model, not an eligibility or execution grant.
...["selected_branches", "comparison_candidates", "rejected_candidates", "frontier"].flatMap(lane => {
const branches = (content.harness as JsonObject | undefined)?.[lane];
return Array.isArray(branches) ? branches.flatMap((branch, index) =>
branch !== null && typeof branch === "object" && !Array.isArray(branch)
&& typeof branch.todo_id === "string" && branch.todo_id
? [["harness", lane, index, "typed_evidence_audit"]] : []) : [];
}),
];
}

Expand Down
4 changes: 2 additions & 2 deletions loopx/control_plane/capability_hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import {exploreReusableContextPaths} from "./capabilities/explore_turn_context.t

/** The registered owner selects reusable read-model subtrees. Unknown hooks
* remain complete; payloads cannot nominate their own execution fields. */
export function reusableTurnContextPaths(source: JsonObject): string[][] {
export function reusableTurnContextPaths(source: JsonObject): (string | number)[][] {
return source.source === "turn_start_capability_hook" && source.hook_id === "explore.turn_context"
&& source.capability_id === "explore" && source.kind === "explore_turn_context"
? exploreReusableContextPaths() : [];
? exploreReusableContextPaths(source.content as JsonObject | undefined) : [];
}

export const CAPABILITY_HOOK_REGISTRATION_SCHEMA_VERSION =
Expand Down
Loading
Loading