From fc278efac7fa9125dff783359f4ec3d351e27396 Mon Sep 17 00:00:00 2001 From: huangruiteng <14976749+huangruiteng@users.noreply.github.com> Date: Tue, 15 Sep 2026 18:22:55 +0800 Subject: [PATCH] docs(rfc): record the shipped managed selection surfaces and promotion gates The RFC still described the managed host as resolved from the operator credential. It now records what the repository ships and what the managed stack will ship: the Turn host is selected, never inferred (shipped default `dsh`, `LOOPX_TURN_HOST` re-points it, an explicit `--host` wins), the steward channel selects its own executor (shipped default `codex`, because it is the only interactive Chat transport today), and a configured credential only authenticates the selection instead of changing it. - The role table gains the steward channel executor row and states each selection source, including the `individual` versus `managed` executor kind. - The steward-channel section replaces the credential-resolved binding rule and records the promotion gate for the managed host (an interactive Chat transport), so the credential is explicitly not the promotion signal. - The milestone table records the steward channel's M1 contract as selected -- endpoint, model, source and executor kind -- and states the session-identity gap that still blocks a channel answer from proving which session served it. - Evidence and dsh-pin rows are re-pointed at the replacement PRs (#4443, #4446) and the dsh pin PR #4420. Docs only: no runtime is promoted, no default behavior changes here, and the English and Chinese mirrors are updated together. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> --- .../rfcs/harness-selection-dsh-pi-v0.md | 200 ++++++++++++++++++ .../rfcs/harness-selection-dsh-pi-v0.zh-CN.md | 161 ++++++++++++++ 2 files changed, 361 insertions(+) diff --git a/docs/architecture/rfcs/harness-selection-dsh-pi-v0.md b/docs/architecture/rfcs/harness-selection-dsh-pi-v0.md index ecdf7e31ab..765a656dcf 100644 --- a/docs/architecture/rfcs/harness-selection-dsh-pi-v0.md +++ b/docs/architecture/rfcs/harness-selection-dsh-pi-v0.md @@ -13,6 +13,122 @@ The first choice minimizes the cost of qualifying an existing passive observer; the second requires lifecycle, provider, crash-recovery and outcome evidence that a plugin event fixture cannot supply. No quantitative winner is claimed. +Two DSH roles appear in this document and must not be conflated. The **bounded +managed Turn host** (LoopX's adapter choice for one governed Turn) is +credential-bound; its default-host resolution lands with the managed stack +recorded below, not with `main` today. The **L1 event source and session-owning +runtime** role stays opt-in and is not promoted by that binding; it still needs +the C0, C1, overhead, retention and Mode B rows. + +## Managed Execution Surface (2026-09-15) + +Selection is constrained by what the repository ships today, not only by what an +upstream harness can do. The managed bounded execution unit is the governed Turn: + +- `loopx turn run-once` accepts `--host codex-cli|dsh|generic-cli` with + `--execution-mode isolated-headless`: LoopX decides, a host adapter invokes the + agent CLI, an independent validator proves the postcondition, and only a passing + result is committed; +- `loopx host-mode-plan` selects `isolated_headless_turn` for the + `continue_without_ui` intent only when the host declares `typed_host_adapter`; + without that declaration it reports the mode as not ready and names the missing + capability; +- session ownership (`managed_runtime` versus `attached_host`) is not decided + here. It belongs to + [Agent Session Execution Modes](./agent-session-execution-modes-v0.md), which + also owns the M1-M4 integration milestones and the cross-frontend projection row. + +Three evidence states appear below and must not be read across them. The list is +dated 2026-09-15 and is written to land with the managed stack: + +- **already on `main` on 2026-09-15:** `loopx turn run-once --host + codex-cli|dsh|generic-cli`, the `dsh` host adapter, the `host-mode-plan` gate + above, and the dsh pin `deepseek-harness-sdk==0.1.2a3`; +- **not on `main` on 2026-09-15; expected to land with this document:** the + explicit host selection (`loopx/control_plane/turn_driver/host_binding.py`, + PR #4443), the steward channel's explicit executor selection + (`loopx/chat_manager.py`, PR #4446) and the `0.1.5rc1` dsh pin (PR #4420). A + later reader who finds those PRs merged can read those rows as shipped; a + reader who does not must treat them as stack-only; +- **local live qualification, not a repository gate:** rows marked as local + evidence below. Reproducing them needs an operator credential, and CI asserts + none of them. + +| Role | Source | Selection today | Promotion gate | +| --- | --- | --- | --- | +| Default managed execution host | LoopX Turn plus the `dsh` host adapter, bound to an operator-supplied model endpoint | shipped product default: `dsh` for bounded managed Turns, environment-independent; `LOOPX_TURN_HOST` re-points it and an explicit `--host` wins; in the managed stack (PR #4443), not yet on `main` | keep the typed host request/result, independent validation, and the operator-owned credential boundary; do not replace it without an equal or stronger contract | +| Steward channel executor | the interactive Chat transport the steward answers on | shipped product default: `codex`; `LOOPX_MANAGER_ENDPOINT` re-points it; in the managed stack (PR #4446), not yet on `main` | an interactive Chat transport on the managed host, so the steward channel can select it; a discovered credential is never the promotion signal | +| Supported alternative Turn host | LoopX Turn plus the `codex-cli` adapter | explicitly selectable; it is the `individual` executor kind, so it is billed to one person's CLI login | no managed lane may silently depend on an individual's personal CLI subscription; an individual lane must be selected, not reached by default | +| L1 event source and session-owning runtime candidate | DSH | opt-in, not promoted; the bounded Turn host role is the default row above | the C0, C1, overhead, retention and Mode B rows in this document being run and reviewed | +| Optional visible host loop | Pi | not a managed runtime | declare a per-binding session mode with readback, prove single-executor behavior under restart, "conversation is not a receipt", non-authoritative host-local state, and one real-host restart row | + +### Managed host binding and live qualification (2026-09-15) + +A managed host binding names four things: the host adapter, the provider, the +model, and where the credential comes from. The DSH binding is the DSH Turn host +with provider `deepseek-official`, model `deepseek-flash` (DeepSeek V4.1 Flash), +an endpoint from the operator environment (`DEEPSEEK_BASE_URL`) and a credential +from the operator environment (`DEEPSEEK_API_KEY`). + +LoopX **selects** the default host for bounded managed Turns and never infers it +(`loopx/control_plane/turn_driver/host_binding.py`): the shipped default is `dsh`, +`LOOPX_TURN_HOST` re-points it, and an explicit `--host` wins over both. The +operator credential is not a selection input. This distinction is the whole +point of the binding: discovering a key is not a decision to change where work +runs, and a surface that resolves its host from the environment makes a chosen +configuration indistinguishable from an incidental one. A lane selected onto the +DSH host therefore never depends on an individual developer's CLI subscription +being available, funded, or logged in. + +The steward channel is a **different** surface with a different default. Its +shipped executor is `codex`, because that is the only transport that can hold an +interactive steward session today; `LOOPX_MANAGER_ENDPOINT` re-points it, and a +credential never re-points it. Its model follows the executor it selected rather +than the environment, so a configured coordinator credential does not swap the +steward onto an operator model while the executor stays on the CLI endpoint. + +Evidence for this binding, separated by source: + +- repository-covered without any provider call: the shipped default is `dsh`, an + explicit `LOOPX_TURN_HOST` re-points it, an explicit `--host` still wins, and a + configured credential changes none of those selections (tests in PR #4443, not + yet on `main`); +- local live qualification with the real SDK and runtime + (`deepseek-harness-sdk==0.1.5rc1`, the pin PR #4420 proposes; `main` still + pins `0.1.2a3` and the same pair also passed there): the in-process + `--host dsh` path and the `generic-cli` subprocess path; +- local live qualification: one governed Turn reached `validated_progress` — the + host executed the bounded action, an independent validator proved the + postcondition, and only then did writeback and quota spend follow; +- local live qualification: a Turn whose postcondition was not proved + fail-closed instead — no writeback, and the quota slot spend count stayed at + zero. + +Open gaps before this binding is a promoted production default: + +- the runtime snapshot bundled as `deepseek-harness-runtime-bin==0.1.5rc1` + cannot boot the stock `headless` profile as shipped: a profile row pulls + `@deepseek-ai/dsh-session-title-first-prompt-llm`, which imports the omitted + `@deepseek-ai/dsh-session-title-llm`, and resolution runs inside the packaged + snapshot, so installing that package into a profile directory does not change + it. The current local workaround is a binding overlay that disables the + affected row. The managed host path is unaffected: it does not select + `headless`, and the default `sdk` profile boots and exits cleanly; +- the LoopX DSH Turn composition must name the tool rows a managed action needs + (`@deepseek-ai/dsh-tool-fs`, `@deepseek-ai/dsh-tool-bash`). Without them a live + model can answer but cannot act, and the Turn ends in a validation failure + rather than in work. +- the host-mode plan still maps the unattended intent to the compatibility path: + `isolated_headless_turn` carries `turn_host: generic-cli` + (`loopx/host_mode_planner.py`), so the `loopx turn plan` command it prints + names `--host generic-cli` instead of the selected `dsh` default recorded above, + which is correct as a labelled rollback path but is not labelled as one. The + plan's `--host-identity` list deliberately covers visible + hosts only, because a headless-only host such as `dsh` cannot own a visible + session; the unattended mapping itself still needs a decision between naming + the resolved default, offering a `dsh` variant, or labelling the emitted + command as the rollback path. + ## Evidence Baseline LoopX was inspected at `bf217e1e01bec79f357c9ecbd580cf2dfa73db8b`. @@ -29,6 +145,14 @@ The implementation paths below are repository-relative: - `apps/desktop/loopx-control-plane/src-tauri/src/services.rs`: service process management must not be mistaken for the complete managed Agent lifecycle. +The dsh pin moved in two steps, and reading this document needs both states. +`main` today pins `deepseek-harness-sdk==0.1.2a3`. The managed stack moves that +pin to the newest released upstream channel rather than an unreleased tag: +`deepseek-harness-sdk==0.1.5rc1` / `deepseek-harness-runtime-bin==0.1.5rc1` on +PyPI (PR #4420), matching `latest` for `@deepseek-ai/dsh` on npm (checked +2026-09-15). Upstream `next` and `alpha` tags are newer than that channel and are +not adopted here. + Upstream references were inspected on 2026-09-06, pinned independently of the versions validated by LoopX: @@ -60,6 +184,15 @@ These are integration-cost and contract observations, not claims that Pi lacks events or DSH cannot support other models. Both expose control-capable APIs; passivity is a property of the selected adapter and its loaded dependencies. +The two LoopX surfaces that depend on dsh do not move together. The bounded Turn +host uses the Python SDK/runtime pin recorded above (`0.1.5rc1`, the released +channel). The dsh-side plugin (`packages/dsh-loopx-plugin`) still builds its +development and client surfaces against `0.1.1-rc.2` while its clean-Docker smoke +already asserts `dsh --version == 0.1.5-rc.1`, and the 0.1.5 line no longer +publishes `@deepseek-ai/dsh-client-runtime` (last released 0.1.1-rc.2), moving +the client runner to `@deepseek-ai/dsh-cordis-client-runner`. That upgrade is +tracked as its own pin item and does not change the L1 observer contract above. + ## Data and Authority Flow The operator needs to distinguish missing evidence, unhealthy execution and @@ -134,6 +267,13 @@ Keep raw logs and credentials owner-local. Public evidence should contain only generalized methodology, pinned revisions, aggregate results and safe references. No live model execution or retention deletion is authorized by this document. +Milestone ownership stays with +[Agent Session Execution Modes](./agent-session-execution-modes-v0.md). This +document owns the C0, C1, overhead and retention evidence for the L1 observer +arm, and the Mode B acceptance above for a session-owning runtime; the M1-M4 +integration milestones and the cross-frontend projection row remain that +document's, and nothing here defines mode inference or a second executor. + ## Delivery Sequence This comparison plus combined CLI readback can be reviewed now. A Mode B panel @@ -144,3 +284,63 @@ Implement deletion only after the owner selects the retention profile. Revisit runtime preference if Pi satisfies the same isolation/lifecycle tests at lower measured integration and operational cost, or DSH fails them. Do not introduce L2 advice, retry control or a new scheduler to make an L1 experiment pass. + +## Steward Channel Chat Transport (2026-09-15) + +The governed Turn surface and the steward (manager) chat channel resolve their +default host from the same operator credential, but they need different host +shapes. A Turn is one bounded work segment, which the shipped DSH adapter +serves today. The steward channel additionally needs a transport that can hold +an interactive session, and the shipped DSH surface explicitly does not promise +cross-turn DSH session continuity. + +Behaviour in the managed stack (PR #4446, not yet on `main`): the steward channel +selects `codex` as its shipped executor and keeps the vendor model default, and an +operator credential re-points neither one -- it is reported as a fact +(`operator_credential_configured`, variable name only) and authenticates only the +endpoint that actually runs on the operator provider. Selecting the managed host +for this channel reports `available: false` with the typed +`managed_host_chat_transport_unsupported` reason, and a session request for that +host fails as the same typed host-tool gate instead of silently falling back to an +individual CLI login. Promoting the managed host to the steward default is gated +on that transport, not on a credential. + +| Option | Shape | Cost and risk | +| --- | --- | --- | +| A. Turn-backed steward transport (preferred) | Each steward chat turn runs one governed Turn on the managed host (`loopx turn run-once --host dsh`, `isolated-headless`), with bounded chat history as context | No duplex streaming and no cross-turn host session; each turn is a fresh segment. Requires an explicit tool/sandbox authority and a per-turn cost bound before it ships | +| B. ACP or stdio adapter | Reuse the ACP stdio adapter path (as the Kiro CLI chat endpoint does) when the managed host exposes such an interface | Lowest transport cost, but depends on an upstream interface that no shipped evidence covers yet | +| C. Codex endpoint bound to the operator provider | Start the Codex app-server itself against the operator provider so the existing transport and tool surface stay | Keeps streaming, but must prove the session no longer authenticates with an individual login; the provider config becomes host-state authority and needs its own gate | + +Selection rule: prefer A, because it reuses the Turn authority, typed host +failure, journal and quota semantics LoopX already validates; keep B as the +cheaper replacement if the upstream interface appears; evaluate C only if +duplex streaming is required for the steward experience. Whichever option ships +must demonstrate, for one steward session, that the model work lands on the +operator credential and that no default path reaches an individual +subscription. This document authorizes no new scheduler, retry authority or +second monitoring subsystem to make that demonstration pass. + +## Steward Channel Readiness by Milestone (2026-09-15) + +The steward channel consumes both this document's host selection and the manager +milestones in +[capable-manager-semantic-handoff-v0](./capable-manager-semantic-handoff-v0.md). +This section records which steward-channel behaviours those milestones can rely +on today and which stay unverified. It states product contracts, not conversation +content: no live channel transcript, audience identity, dated incident or +operator-local path is recorded here. + +| Milestone | Steward-channel contract in scope | Evidence state on 2026-09-15 | +| --- | --- | --- | +| Manager M1 — useful host agent | The channel resolves and reports its effective executor, model and source, the executor selection does not follow a credential, and a host without a chat transport fails with a typed reason instead of a silent individual-login fallback | Stack-only (PR #4446, with the Turn-side readback in PR #4443): selected endpoint and model with their sources, `executor_kind`, the `channel_binding` readback, and the gated `managed_host_chat_transport_unsupported` request. The upstream **session identity** is still not projected to the channel, so a channel answer cannot yet prove which session served it | +| Manager M2 — semantic continuation | Receiver resolution across registered running lanes; typed per-source coverage and freshness; a goal-level milestone the report can lead with instead of coverage disclaimers | Not implemented. Delegation resolves against the supplied delegation catalog, so a request whose owning lane is absent from that catalog is refused or routed to an unrelated lane; a provider read failure surfaces as raw error text instead of a typed source row; the manager context exposes deliveries and coverage but no goal-level milestone field to synthesize from | +| Manager M3 — automatic complete exchange | A persisted answer that exceeds or violates the channel's outbound text contract is split and re-sent under a stable answer identity; an ambiguous or failed send is reconciled instead of replaced by a local notice; the return path survives a transport restart; rich markdown renders as structured text | Partially mitigated. `loopx/extensions/lark/outbound.py` fails closed on an over-limit or malformed payload, and the channel reports that local failure without re-delivering the persisted answer; one answer carries no idempotency identity, so a retry can duplicate it; structured rendering is not guaranteed | +| Host modes M0-M1 | The channel's executor selection and its bounded one-segment execution | Selection is covered by PR #4446 and the Turn-side selection by PR #4443; bounded one-segment execution is covered by the Mode B acceptance above. The steward channel itself still runs on the interactive CLI transport, so the managed host's own one-segment execution is not yet reachable from the channel | +| Host modes M2-M3 | Attached-host parity, typed unavailability, and mode-aware projection with no mode inference and no second executor | Not implemented for the channel; an external audience still degrades to `restricted`, and the channel projects neither its mode nor its session status | + +Two boundaries stay fixed across all five rows. The channel remains an entry point +and projection of one manager Session: it owns no profile, no permission state, no +second executor and no work authority, so a richer answer contract must not widen +what the channel may read or change. And no row is promoted by this document; the +M1-M4 integration milestones and the cross-frontend projection row still belong to +[Agent Session Execution Modes](./agent-session-execution-modes-v0.md). diff --git a/docs/architecture/rfcs/harness-selection-dsh-pi-v0.zh-CN.md b/docs/architecture/rfcs/harness-selection-dsh-pi-v0.zh-CN.md index d91cf53bc6..b1fabf1715 100644 --- a/docs/architecture/rfcs/harness-selection-dsh-pi-v0.zh-CN.md +++ b/docs/architecture/rfcs/harness-selection-dsh-pi-v0.zh-CN.md @@ -12,6 +12,99 @@ Pi 保留为 managed runtime 候选。前者利用已存在的被动 observer 必须证明生命周期、provider、崩溃恢复和真实结果,插件事件 fixture 不能替代这些证据。 本评估不提供缺乏测量依据的评分或性能排名。 +本文区分 DSH 的两个角色,二者不可混同:**托管有界 Turn 宿主**(LoopX 为一次受治理 +Turn 选择的适配器)是出货默认值,宿主由配置显式选择、从不由凭据推断,该选择随下文 +记录的托管栈落地,而不是今天的 `main`;**L1 事件源与会话归属 runtime** 角色仍是 +opt-in,不因前者被晋级,仍需本文 C0、C1、开销、保留与 Mode B 各行。 + +## 托管执行面(2026-09-15) + +选型受仓库今天实际交付的能力约束,而不只取决于上游 harness 能做什么。托管的单次执行 +单元是有界 Turn: + +- `loopx turn run-once` 接受 `--host codex-cli|dsh|generic-cli` 与 + `--execution-mode isolated-headless`:LoopX 决定,宿主适配器调用 agent CLI,独立 + validator 证明后置条件,只有通过的结果才会被提交; +- `loopx host-mode-plan` 只有在宿主声明 `typed_host_adapter` 时,才为 + `continue_without_ui` 意图选择 `isolated_headless_turn`;缺少该声明时报该模式未就绪, + 并指出缺失的能力; +- 会话归属(`managed_runtime` 与 `attached_host`)不在本文决定,属于 + [Agent 会话执行模式](./agent-session-execution-modes-v0.zh-CN.md),该文档同时拥有 + M1-M4 接入里程碑与跨前端投影行。 + +下文区分三种证据状态,不可互相套用;该列表以 2026-09-15 为准,并计划与托管栈一起 +落地: + +- **2026-09-15 已在 `main` 上**:`loopx turn run-once --host + codex-cli|dsh|generic-cli`、`dsh` 宿主适配器、上面的 `host-mode-plan` 门槛,以及 + `main` 固定的 `deepseek-harness-sdk==0.1.2a3`; +- **2026-09-15 尚未进入 `main`、计划随本文落地**:显式选择宿主的默认值 + (`loopx/control_plane/turn_driver/host_binding.py`,PR #4443)与 `0.1.5rc1` 的 dsh + 固定版本(PR #4420)。后续读者若看到这两个 PR 已合并,可把这两行读作已交付; + 否则只能按栈内状态理解; +- **本地真实验证,不是仓库门禁**:下文标注为本地证据的行。它们需要 operator 凭据 + 才能复现,CI 不做断言。 + +| 角色 | 来源 | 当前选型 | 晋级门槛 | +| --- | --- | --- | --- | +| 默认托管执行宿主 | LoopX Turn 加 `dsh` 宿主适配器,并绑定到运维方提供的模型端点 | 出货默认值:托管有界 Turn 走 `dsh`,与环境无关;`LOOPX_TURN_HOST` 可改指,显式 `--host` 优先;在托管栈中(PR #4443),尚未进入 `main` | 保持类型化 host request/result、独立验证与凭据归属运维方的边界;没有同等或更强的契约不替换 | +| 管家通道执行器 | 管家回答所依赖的交互式 Chat 传输 | 出货默认值:`codex`;`LOOPX_MANAGER_ENDPOINT` 可改指;在托管栈中(PR #4446),尚未进入 `main` | 托管宿主具备交互式 Chat 传输,管家通道才能选择它;凭据的存在从不是晋级信号 | +| 受支持的替代 Turn 宿主 | LoopX Turn 加 `codex-cli` 适配器 | 可显式选择;它属于 `individual` 执行器类型,账落在某个人的 CLI 登录上 | 任何托管通道都不得静默依赖某个人的 CLI 订阅;个人通道必须被显式选择,而不是默认走到 | +| L1 事件源与会话归属 runtime 候选 | DSH | opt-in,未晋级;有界 Turn 宿主角色见上一行默认值 | 本文 C0、C1、开销、保留与 Mode B 各行被真实执行并通过评审 | +| 可选的可见宿主循环 | Pi | 不是 managed runtime | 先声明按绑定持久化且可回读的会话模式,证明重启下的单执行器行为、"对话不是回执"、宿主本地状态非权威,并提供一条真实宿主重启行 | + +### 托管宿主绑定与真实环境验证(2026-09-15) + +一个托管宿主绑定要说明四件事:宿主适配器、provider、模型,以及凭据来自哪里。 +DSH 绑定是 DSH Turn 宿主 + provider `deepseek-official` + 模型 `deepseek-flash` +(DeepSeek V4.1 Flash),端点取自运维方环境(`DEEPSEEK_BASE_URL`),凭据取自 +运维方环境(`DEEPSEEK_API_KEY`)。 + +LoopX **选择**托管有界 Turn 的默认宿主,而从不由环境推断 +(`loopx/control_plane/turn_driver/host_binding.py`):出货默认值是 `dsh`, +`LOOPX_TURN_HOST` 可改指,显式 `--host` 优先于两者。operator 凭据不是选型输入。 +这个区分正是该绑定的意义:发现一把 key 不等于决定换运行位置;一个按环境解析宿主的 +面,会让"选定的配置"和"偶然生效的配置"无法区分。因此被选到 DSH 宿主的通道不会依赖 +某个开发者本机 CLI 订阅是否可用、是否还有额度或是否已登录。 + +管家通道是**另一个**面,默认值也不同。它的出货执行器是 `codex`,因为这是今天唯一 +能承载交互式管家会话的传输;`LOOPX_MANAGER_ENDPOINT` 可改指,凭据不能改指。它的 +模型跟随它所选择的执行器而不是跟随环境,因此配置了 operator 凭据不会在端点仍是 +CLI 的情况下把管家悄悄换成 operator 模型。 + +该绑定的证据按来源区分: + +- 仓库覆盖、无需任何 provider 调用:出货默认值是 `dsh`,显式 `LOOPX_TURN_HOST` + 可改指,显式 `--host` 仍然优先,且配置凭据不改变以上任何一项选择 + (PR #4443 的测试,尚未进入 `main`); +- 本地真实验证:在真实 SDK 与 runtime(`deepseek-harness-sdk==0.1.5rc1`,即 PR + #4420 提出的固定版本;`main` 今天仍固定在 `0.1.2a3`,同一对路径在那里也通过)下, + 进程内 `--host dsh` 路径与 `generic-cli` 子进程路径均通过; +- 本地真实验证:一次托管 Turn 达到 `validated_progress`,宿主执行有界动作,独立 + validator 证明后置条件,随后才发生写回与配额扣减; +- 本地真实验证:一次后置条件未被证明的 Turn 反向失败关闭,没有写回,配额槽消耗计数 + 保持为 0。 + +在该绑定成为正式默认值之前仍存在的缺口: + +- `deepseek-harness-runtime-bin==0.1.5rc1` 捆绑的 runtime 快照无法按原样启动 + `headless` profile:其中一行会拉起 + `@deepseek-ai/dsh-session-title-first-prompt-llm`,该包 import 了未被收录的 + `@deepseek-ai/dsh-session-title-llm`;解析发生在打包快照内部,因此把该包装进 + profile 目录不会改变结果。当前本地做法是用一条绑定 overlay 关闭受影响的行。 + 托管宿主路径不受影响:它不选择 `headless` profile,默认 `sdk` profile 能正常 + 启动并干净退出; +- LoopX 的 DSH Turn 组合必须显式列出托管动作所需的工具行 + (`@deepseek-ai/dsh-tool-fs`、`@deepseek-ai/dsh-tool-bash`)。缺少它们时,真实模型 + 只能作答而无法动手,Turn 会以验证失败而不是产出工作结束。 +- 宿主模式计划仍把无人值守意图映射到兼容路径:`isolated_headless_turn` 的 + `turn_host` 取 `generic-cli`(`loopx/host_mode_planner.py`),因此它打印的 + `loopx turn plan` 命令写的是 `--host generic-cli`,而不是上文记录的已选 `dsh` + 默认值;作为回滚路径本身没错,但没有被标注为回滚路径。该计划的 + `--host-identity` 列表只覆盖可见宿主是有意为之——像 + `dsh` 这种仅 headless 的宿主无法拥有可见会话;但无人值守映射本身仍需在"写出解析 + 后的默认值 / 提供 `dsh` 变体 / 把该命令标注为回滚路径"之间做出决定。 + ## 证据基线 LoopX 检查基线为 `bf217e1e01bec79f357c9ecbd580cf2dfa73db8b`: @@ -27,6 +120,13 @@ LoopX 检查基线为 `bf217e1e01bec79f357c9ecbd580cf2dfa73db8b`: - `apps/desktop/loopx-control-plane/src-tauri/src/services.rs`:已有服务进程管理不等于 RFC 所要求的完整 managed Agent 生命周期。 +dsh 固定版本经历了两步,理解本文需要同时知道这两个状态:今天的 `main` 固定 +`deepseek-harness-sdk==0.1.2a3`;托管栈把该固定版本升到最新发布通道,而不是未发布的 +tag:PyPI 上的 `deepseek-harness-sdk==0.1.5rc1` / +`deepseek-harness-runtime-bin==0.1.5rc1`(PR #4420),与 npm `@deepseek-ai/dsh` 的 +`latest` 一致(2026-09-15 核对)。上游 `next` 与 `alpha` tag 比该通道更新,这里不 +采纳。 + 2026-09-06 独立检查的上游版本,不等同于 LoopX 已验证的安装版本: - [DSH d347e703 README](https://github.com/deepseek-ai/deepseek-harness/blob/d347e703908d0406b7a7ef80e3a0e594d86b2215/README.md): @@ -56,6 +156,14 @@ LoopX 检查基线为 `bf217e1e01bec79f357c9ecbd580cf2dfa73db8b`: 这是接入成本和合同差异,不是说 Pi 没有事件,或 DSH 不能使用其他模型。 两个 harness 都有控制 API;“被动”是具体 adapter 和实际加载依赖的性质。 +依赖 dsh 的两个 LoopX 面并不一起移动:有界 Turn 宿主使用上文记录的 Python +SDK/runtime 固定版本(`0.1.5rc1`,已发布通道);而 dsh 侧插件 +(`packages/dsh-loopx-plugin`)的开发与客户端面仍构建在 `0.1.1-rc.2` 上,尽管其 +clean-Docker smoke 已断言 `dsh --version == 0.1.5-rc.1`。0.1.5 线不再发布 +`@deepseek-ai/dsh-client-runtime`(最后发布版本为 `0.1.1-rc.2`),客户端 runner 改为 +`@deepseek-ai/dsh-cordis-client-runner`。该升级作为独立的 pin 项跟踪,不改变上文的 +L1 observer 契约。 + ## 数据流与权限 用户需要区分“没有证据”“执行有异常”“观察过程不可信”,而不是只得到一个绿灯: @@ -114,6 +222,12 @@ goal ledger 不得被标成当前 session 健康。输出只供操作者,不 原始日志、凭据留在 owner-local;公共材料只保留通用方法、固定版本、聚合结果和 安全引用。本文件不授权真实模型执行或删除现有记录。 +里程碑归属仍由 +[Agent 会话执行模式](./agent-session-execution-modes-v0.zh-CN.md) 决定:本文负责 +L1 observer 这条臂的 C0、C1、开销与保留证据,以及上面针对会话归属 runtime 的 Mode B +验收;M1-M4 接入里程碑与跨前端投影行仍归该文档,本文不定义模式推断,也不定义第二个 +执行器。 + ## 后续交付次序 先评审对比结论和 CLI 读取增量;Mode B 面板必须先具备精确 session 读取与有界刷新, @@ -121,3 +235,50 @@ goal ledger 不得被标成当前 session 健康。输出只供操作者,不 提交仓库。删除功能等 retention profile 决定后再做。若 Pi 在相同隔离及生命周期 验收下具有更低的实测接入/运维成本,或 DSH 无法通过,再调整偏好。 不得为了让 L1 实验通过而加入 L2 建议、重试权限或新 scheduler。 + +## 管家通道的会话传输(2026-09-15) + +受治理的 Turn 面与管家(manager)会话通道各自**显式选择**宿主,互不推断;但两者需要 +的宿主形态不同:Turn 是一次有界工作片段,现有 DSH adapter 已支持;管家通道还需要一个 +能持有交互会话的传输,而现有 DSH 面明确不承诺跨 turn 的 DSH 会话连续性。 + +托管栈中的行为(PR #4446,尚未进入 `main`):管家通道把 `codex` 作为出货执行器,并 +保持厂商默认模型,operator 凭据不改指其中任何一项——它只作为事实被回报 +(`operator_credential_configured`,仅变量名),并且只为真正跑在 operator provider 上 +的那个端点提供认证。若为该通道选择托管宿主,解析结果给出 `available: false` 与 typed +`managed_host_chat_transport_unsupported`;针对该宿主的会话请求以同一个 typed +host-tool gate 失败,不会静默回落到个人 +CLI 登录。 + +| 路线 | 形态 | 代价与风险 | +| --- | --- | --- | +| A. turn-backed 管家传输(优先) | 每个管家 chat turn 在托管宿主上执行一次受治理 Turn(`loopx turn run-once --host dsh`,`isolated-headless`),把有界会话历史作为上下文 | 无双工流式、无跨 turn 宿主会话,每个 turn 都是新 segment;上线前需要明确的工具/沙箱权威与单 turn 成本上限 | +| B. ACP 或 stdio 适配 | 当托管宿主暴露此类接口时,复用 ACP stdio 适配路径(Kiro CLI chat 端点已走此路) | 传输成本最低,但依赖上游接口,目前没有已交付证据 | +| C. codex 端点绑定 operator provider | 让 Codex app-server 直接以 operator provider 启动,保留现有传输与工具面 | 保留流式,但必须证明会话不再以个人登录认证;provider 配置成为宿主状态权威,需要单独 gate | + +选型规则:优先 A,因为它复用 LoopX 已经验证过的 Turn 权威、typed host failure、 +journal 与配额语义;B 作为上游接口出现时的低成本替代;只有在管家体验确需双工 +流式时才评估 C。无论采用哪条路线,都必须证明「一次管家会话的模型工作落在 +operator 凭据上,且不存在任何默认指向个人订阅的路径」。本文件不授权为此新增 +scheduler、重试权限或第二套监控子系统。 + +## 按里程碑看管家通道的就绪度(2026-09-15) + +管家通道同时消费本文的宿主选型与 +[管家语义交接](./capable-manager-semantic-handoff-v0.zh-CN.md) 中的管家里程碑。 +本节记录这些里程碑当前可以依赖管家通道的哪些行为、哪些仍未验证。这里只写产品 +契约,不写会话内容:不记录真实会话原文、受众身份、带日期的具体事故,或 operator +本机路径。 + +| 里程碑 | 管家通道在范围内的契约 | 2026-09-15 的证据状态 | +| --- | --- | --- | +| 管家 M1 — 可用的宿主 agent | 通道解析并回报其生效执行器、模型与来源,执行器选型不跟随凭据;没有 chat 传输的宿主以 typed reason 失败,而不是静默回落到个人登录 | 仅存在于托管栈(PR #4446,配套 Turn 侧读取见 PR #4443):带来源的已选端点与模型、`executor_kind`、`channel_binding` 读取,以及被 gate 的 `managed_host_chat_transport_unsupported` 请求。上游**会话身份**尚未投影到通道,因此通道回答还无法证明是哪一次会话给出的 | +| 管家 M2 — 语义续接 | 跨所有已注册运行中 lane 的接收者解析;按来源的 typed 覆盖与新鲜度;报告可以先用目标级里程碑开头,而不是先给覆盖免责声明 | 未实现。委托只按传入的委托目录解析,因此拥有该事项的 lane 不在目录中时会被拒绝或投给无关 lane;provider 读取失败以原始错误文本出现在回答里,而不是 typed 来源行;管家上下文只提供交付与覆盖,没有可综合的目标级里程碑字段 | +| 管家 M3 — 自动完成一次交流 | 超出或违反通道出站文本契约的已保存回答,按稳定答案身份分片重发;含糊或失败的发送要协调而不是用本地提示替代;回传路径要能跨传输重启存活;富文本要渲染成结构化文本 | 部分缓解。`loopx/extensions/lark/outbound.py` 在超限或载荷不合法时 fail closed,通道只回报这个本地失败、不重新投递已保存的回答;一条回答没有幂等身份,重试可能重复发送;结构化渲染没有保证 | +| 宿主模式 M0-M1 | 通道的执行器选型与其有界单段执行 | 选型由 PR #4446 覆盖,Turn 侧选型由 PR #4443 覆盖;有界单段执行由上面的 Mode B 验收覆盖。管家通道本身仍跑在交互式 CLI 传输上,因此托管宿主自己的单段执行尚未能从通道抵达 | +| 宿主模式 M2-M3 | attached-host 对齐、typed 不可用,以及不做模式推断、不引入第二执行器的模式感知投影 | 通道尚未实现;外部受众仍降级为 `restricted`,通道既不投影模式也不投影会话状态 | + +五行的两条边界固定不变:通道始终是同一个 manager Session 的入口与投影,不拥有 +profile、权限状态、第二执行器或工作权威,因此更丰富的回答契约不得扩大通道可读或 +可改的范围;本文也不提升任何一行的状态——M1-M4 接入里程碑与跨前端投影行仍归 +[Agent 会话执行模式](./agent-session-execution-modes-v0.zh-CN.md)。