Skip to content

feat(chat): observe unfinished work in attached Agent conversations - #6599

Open
loopx-agent wants to merge 4 commits into
mainfrom
codex/attached-session-live-observation-20261016
Open

loopx-agent wants to merge 4 commits into
mainfrom
codex/attached-session-live-observation-20261016

Conversation

@loopx-agent

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

The attached Agent reader currently waits for saved host records, leaving unfinished messages and tools invisible. This adds read-only observation from the same original Desktop owner inside the existing Agent work page. Opening that page is sufficient; no extra setup or confirmation is added.

Continues the working-session journey from #6482, targeting docs/architecture/rfcs/desktop-execution-frontends-v0.md Slice B. Intended base: main. This does not close the full Slice B acceptance.

Author Declaration

Written by: model_agent — OpenAI Codex, GPT-6 family, submitted through loopx-agent.

Implemented against the Desktop execution-frontends RFC and docs/integrations/session-runtime-control-plane-adapter.md at ebc01b2a46abb493f8a2300ce07bc54036cc7a29, plus the accepted original-session observation request.

Criterion Disposition Owner / validation
Original-session work visibility Implemented for bounded unfinished visible text/tools Native Chat provider; real HTTP/Unix-peer tests and packaged browser
Exact binding, single executor, unchanged permissions Implemented for this read-only slice Owner/thread/version/revision guards, binding rechecks, zero-input tests
Pause reading, return, source isolation and persistence Implemented Existing transcript/history owner; packaged Ego journey
Complete native event/token parity, approvals, busy input and other providers Deferred in the existing acceptance No broader completion claim

Self-check: source diff, current main, instructions, provider ownership, public boundary and the checks below. No private transcripts or installed-App screenshots are published.

Scope And Continuation

  • Reuses the native Chat provider, saved history, credential detector and record renderer. Python adapts private Unix IPC; no generic control-plane decision owner is duplicated.
  • Follows/unfollows the discovered original owner. Only current visible unfinished work enters the compact patch baseline; reasoning, user input and configuration metadata are excluded.
  • Keeps ordinary RPC/input limits unchanged. The observation path separately bounds frames at 64 MiB, browser output at 32 rows / 256 KiB and concurrent readers at two. Initial snapshot parsing remains a material cost.
  • Transient disconnects reconnect; unsupported versions, malformed baselines, gaps and limits show a saved-history fallback. Leaving releases the observer even during continuous unchanged updates.
  • Bounded companion refactor: shares frame decoding and the local unavailable reset. No new setting, capability, executor or approval surface.

The App frontend changes; existing CLI and Lark entrypoints do not. This is independently reversible observation work. Native-input qualification, approval callbacks, complete parity, Windows transport and installed adoption remain with the existing working-session/release acceptance.

Validation

Tested author revision: 1db44f2e8ae1450e7b807269793480ad03201392. Run state: finished. Input classes: synthetic, public_fixture, authorized_private_read_only.

Check kind Result Evidence / limitation
unit / integration passed uv run --extra test python -m pytest -q tests/presentation/test_codex_attached_conversation.py: 47 tests; production HTTP + disposable Unix owner, completion maps/patches, identity, privacy, bounds, reconnect and unsubscribe; zero native inputs
static passed Dashboard tsc --noEmit, changed-Python Ruff, focused stream/API mypy, browser scenario syntax, bundle build and scripts/chat_bundle.py verify --source
real_entrypoint passed Packaged frontend in Ego Lite with production REST/SSE and isolated peer: live updates, frozen history, return, Agent switching, deduplication and saved completion; 390 px English and keyboard checked
real_backend passed Original Codex Desktop 26.1007.71326, authorized read-only observation: native visible-tool updates and follow/unfollow. No start, resume, history-load, approval or input; this does not qualify installed LoopX adoption
static / manual passed Diff advisory before tracked full-tree semantic smoke; vocabulary stays provider-local. Privacy scan, synthetic PNG inspection, whitespace and DCO checks pass
integration failed, policy only Risk-based premerge executed 5 direct and 17 selected checks, all passing. Its quality receipt was stale; a fresh exact-scope receipt subsequently passed, then advancing main made it stale again. No green merge-readiness claim
real_entrypoint not_run Full extended repository browser scenario awaits CI; only its syntax and the separate packaged Ego journeys ran locally

Remaining coverage: private protocol compatibility and initial snapshot cost are explicit limits. Full native input/approval, sustained load, other providers and installed-App adoption are unqualified. Exact-head independent review and current-base quality/CI gates remain required before merge.

Frontend / Visual Evidence

UI impact: changed. Source data: synthetic. Existing opening navigation and primary actions are unchanged; the new rows use the existing transcript composition.

Before: saved records only After: unfinished original-host work
Before After

These full-viewport images use an isolated conversation fixture, which omits the separate managed executor; its unavailable banner is retained. The same frontend was separately paired with the real original owner, whose private screenshots remain unpublished.

Attention/craft review: the transcript remains the focus. Live source labeling explains an otherwise invisible state; tools reuse collapsed details. Existing pause/return controls handle reading without a new panel or configuration flow. No new cards, animation, color tokens or Goal-workspace layout are introduced. Uncertainty remains visible. Responsive layout is unchanged; narrow/English interaction was nevertheless checked.

Type / Area / Direction

New feature with focused validation and documentation. Native Chat capability/provider, presentation surface and host integration. Direction: operator surface and IM integration / Desktop RFC Slice B. Shared-authority and TypeScript migration fixture impact: N/A; no Goal authority, storage routing or shared decision semantics change.

Boundary Checklist

  • No private state, credentials, raw native traces, private screenshots, internal links or device paths in the diff/body.
  • No maintainer-owned benchmark execution duplicated.
  • Scope stays within original-session observation; remaining acceptance is explicit.
  • Before/after visual evidence included.
  • Every commit carries a DCO sign-off.

Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent; model=gpt-6.1-sol; provider=OpenAI; runtime_reported; reasoning_effort=max

Request changes conclusion (author-owned PR; GitHub blocks formal self-review)

评审 6599@1db44f2e8ae1450e7b807269793480ad03201392。[P2] “较新记录”返回尾部后保留过期实时草稿。 在 A 显示时回看,宿主更新为 B,再点“较新记录”到尾部,回看提示已消失而 A 仍持续显示。原生订阅与 B 都有效;同一状态下重新回看再点“回到最新”立即显示 B。应让两条恢复跟随路径都发布 latestLive.current,并在没有后续事件时验证。

动机

正在 Goal 中跟进某个既有 Codex App Agent、需要看到尚未保存的可见工作内容的本机负责人。

原来工作页只显示已保存记录,未完成的消息和工具内容不可见;现在页面跟随同一原宿主的只读快照与补丁,但从回看历史经“较新记录”回到尾部时,会静默保留旧实时草稿。

真实 HTTP/Unix 对端与打包页面已证明实时更新、回看冻结、显式回到最新、Agent 隔离及完成转入已保存历史;同样的入口独立复现了“较新记录”恢复后旧草稿持续显示。

本 PR 不启动第二执行者,不授权原生输入或审批,不证明完整 token/event 对齐、Windows 传输、其他 provider、持续负载或已安装 App 采用。

当前需补齐所有恢复到实时尾部的路径;完整 Slice B 的输入、审批、跨平台及安装采用仍沿原有验收继续。

本次从普通用户要判断交付、跟进原工作内容的任务出发。Agent 能从已有上下文准备的技术资料不应再让人重复输入;原本缺失的真实意图或执行权限仍须确认,不能从展示数据推出授权。当前验证限定到真实可用的这个增量,不把测试、回执、截图或 PR 数量当成长程 Goal 的完成证据。

改动思路

Python 留在已有 Codex provider/HTTP 传输边界是合理的:只解析版本化原生数据与 IO,不创建通用控制面决策。LiveView 保存过滤后的当前内容,SSE 重查原绑定;React 将实时行与原保存历史共用 renderer。

原生 Chat provider 适配私有 Unix IPC;既有绑定、活动观察、保存历史及输入 receipt 保持各自 owner,前端只组合一个短暂可见投影。

返回方式(同一原生 B) 当前观察
回看 → 回到最新 B 立即显示
回看 → 较新记录到尾部 提示消失,仍显示 A
切换其他 Agent 旧实时行移除,原订阅释放

表中前两行是同一当前 head、同一真实 HTTP/Unix 对端的独立浏览器结果;不是从截图或单元测试推断。

帧读取已合并到 DesktopClient.read_frame,provider-local 状态与既有 renderer 的复用合理。当前应在同一组件统一恢复跟随时的最新投影发布,覆盖两条返回路径;无需新缓存、设置或第二订阅 owner。 保留原 owner 能让后续规则修改与回滚落在一个地方;重新创建配置或第二个原生执行者既扩大风险,也不能解决已经复现的入口问题。以上比较明确区分原状态、预期改进与当前缺口。

具体改动

整份 base-to-head:14 files, +1303/-50; two frontend files, four runtime/HTTP files, two public documents, three browser fixture/scenario files, one 469-line test addition and two synthetic PNGs.

  • read_frame:Share frame decoding, keeping the ordinary 8 MiB RPC limit and a separately requested live limit. Length checked before body allocation; malformed object raises a provider-local protocol error.
  • LiveView:Add compact exact-thread revisioned visible-work projection instead of retaining raw history. Snapshot/patch version and shape checks; bounded turns/items/fields/view; private and completed items omitted.
  • observations:Follow/unfollow only the discovered original owner. Owner/thread/host/version fencing, bounded frame read and finally-unsubscribe; no input method.
  • _codex_attached_live:Expose scoped SSE through the existing local HTTP routing. Exact Goal/Agent/binding; two-reader bound; binding checks and heartbeat; protocol stops versus transient retry distinguished.
  • AttachedAgentConversations:Append short-lived live rows, freeze while looking back, clear on binding change and completion. Live identity prevents cross-Agent reuse; latestLive buffers updates while following is paused, but older(true) fails to publish that buffer at the tail.
  • AttachedConversationRecord:Use current prop text for live rows while retaining stored-detail continuation for durable rows. Live tool title states in-progress; no acceptance or execution permission inferred.

DesktopClient.read_frame 把原有解帧聚合到一个函数,普通调用仍保留 8 MiB 上限。新 Codex-only LiveView 丢弃旧完成 Turn 内容、隐藏推理/用户/配置字段,保留允许的可见项;身份、原宿主版本、baseRevision、索引和大小不连续就拒绝。该原生状态词留在 provider,不成为通用 LoopX actor 或执行状态。

observations 只向发现的原 owner 发送 following/unfollowing,finally 释放;HTTP 路由重查精确 Goal/Agent/binding,限制两个读者,区分暂时断线可重连与协议不兼容停读。额外真实 Unix/HTTP 用例中,第三读者收到 unavailable;9,437,591 字节的原始帧只输出一条当前可见行;撤销绑定使两个原订阅停止。新注册但无绑定的 Agent、同进程另一 Goal、额外 thread 参数与外部 Origin 均拒绝,输入数保持 0,保存历史未因观察被写入。

前端同一个 renderer 接收临时实时文本,原保存记录继续用原 detail/continuation 逻辑。观察区标记内容来自正在运行的原宿主,回看冻结插入、切换 Agent 清除旧行,完成后转到保存历史。新 liveView/latestLive 双缓冲却没有接入 older(true) 的尾部恢复:该分支只重置 following/reading/unread,新增的 setLiveView 只在 latest() 中执行。这是本轮独立重现的当前缺口,单元与普通 wheel 的绿测没有覆盖它。

三个既有 browser/Unix fixture/scenario 文件增加合成快照、补丁、并发客户端及释放;469 行测试覆盖过滤、完成 map、断线、错 owner/version/revision、字段/帧边界和离开页面。两张 PNG 为合成记录,保留未接独立执行服务的提示;RFC 与 integration guide 明说实验范围、64 MiB 帧/32 行/256 KiB 视图和未完成资格。

独立规范依据是 docs/architecture/rfcs/desktop-execution-frontends-v0.md,不可变 revision ebc01b2a46abb493f8a2300ce07bc54036cc7a29。条款映射:Common invariants 的原 owner、精确绑定和无第二执行者获证;companion docs/integrations/session-runtime-control-plane-adapter.md 同 revision 的 Experimental owner-local Codex App conversations 中有界阅读、回看和恢复路径,本次恢复到最新仍 not_met;Attached mode 的完整输入、interrupt/resume 等继续 deferred,不额外要求此观察切片关闭整个 Slice B。新改过的 checkpoint 未被倒用为独立规范。

对主干的风险

主要阻塞是恢复后的内容真实性,不是额外执行或原生输入。后台已有 B,UI 声称结束回看却仍展示 A,且把“回到最新”控件一起隐藏;如果宿主此后没有新的可见变化,SSE 的去重不会再发送一个碰巧修正它的事件。负责人会漏看新结果,或误把旧工具/消息当作当前工作。点击另一次回看再返回虽可恢复,但这是不必要的额外步骤。

最小修复在原组件:所有回到 following 的路径都应用最新缓冲,保留身份 fencing 与历史分页;可用小的共同恢复 helper,避免两处继续漂移。在既有打包场景同时覆盖 Back to latest 与 Newer records 到尾部,并在 B 后停止事件,断言内容立即为 B。无需新状态、自动重连或放宽任何权限。

47 项源码测试通过(55.45s);普通 wheel 的独立 site-packages 环境同样 47 项通过(21.83s)。四个变化的运行时文件与 37 个 Chat 文件均与 head 逐字节相同。Ruff、配置内 mypy 19 文件、Dashboard TypeScript/build、正常 wheel、advisory 后完整语义 smoke 通过;风险 canary 5 direct +17 selected 全通过、无 manual hold。

9 MiB 用例使用真正的 Unix 帧和 HTTP,但原宿主内容是合成数据;它证明独立读限与紧凑投影,不证明私有 Desktop 协议的所有版本或持续成本。没有读取活动会话的私有历史,也没有把作者的原宿主观察当成本轮独立资格。

语义审查覆盖本次局部联合/状态词、实际 producer 和 consumer、default-off/未绑定、同容器未覆盖主体及新主体。advisory 未检出支持的命名载体,并不证明动态构造没有语义变化;此处另逐一追踪。原强制的身份、同意、版本与恢复条件没有被改成“建议”。本 Goal 的 CI policy 是 not_consulted:本轮未查询、轮询、dispatch 或等待远端 CI,局部 canary 也不替代托管/发布或合并资格。

我的整体评价

结论 REQUEST_CHANGES;delivery verdict 为 not_yet_proven。当前观察增量有用,provider 归属与大小边界合理;必须先修复已经重现的返回路径,不能因其余测试通过而批准旧实时内容被静默当作当前。

long_horizon=preserved:执行、调度和接受事实仍由原 owner 决定,局部读回/生命周期与反例保持边界;不据此认证持续部署。user_experience=regression:“较新记录”移除回看提示并恢复 following,却不发布缓存的最新实时投影;不再有变化时页面无限保留旧草稿,要求用户重新进入回看再点回到最新。

帧读取已合并到 DesktopClient.read_frame,provider-local 状态与既有 renderer 的复用合理。当前应在同一组件统一恢复跟随时的最新投影发布,覆盖两条返回路径;无需新缓存、设置或第二订阅 owner。 当前需补齐所有恢复到实时尾部的路径;完整 Slice B 的输入、审批、跨平台及安装采用仍沿原有验收继续。 验收/运行时通过、独立代码评审、原始首屏确认和 exact-head merge readiness 各有其边界;本结论不授予 merge、bypass、dismiss、resolve、输入或安装权限。

English verdict: REQUEST_CHANGES - 1db44f2; Newer records can resume following while retaining a stale live draft. Reconcile the buffered projection on every return-to-tail path; source/wheel/provider checks pass but do not cover this reproduced packaged-UI defect.

function latest() {
historyEpoch.current++; after.current = null; history.current = null; revision.current = "";
following.current = true; setReadingHistory(false); setUnread(false); setMessages([]); setBefore(null);
setLiveView(latestLive.current);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 同时覆盖“较新记录”抵达尾部时的恢复。实际打包页中,实时草稿 A → 回看 → 原宿主更新为 B → “较新记录”到尾部后,回看提示已消失但仍显示 A;同状态再点“回到最新”会立即显示 B。older(true) 在第221行恢复 following,却没有发布 latestLive.current;若原宿主不再产生可见变化,旧草稿会一直保留。请让两条恢复路径都应用最新缓冲,并在 B 后无新事件的真实 browser 场景中断言显示 B,保留 Agent 切换/完成/身份 fencing。

…path

Look-back froze live insertion correctly, but only "Back to latest"
republished the newer buffered draft. Returning to the tail through "Newer
records" resumed following while the previous draft stayed visible, so a
finished look-back could show stale work as current until some later host
event happened to replace it.

Restore following through one helper both paths share, so the frozen draft is
replaced whenever the tail is resumed. Qualify it in the packaged browser
scenario: after a second live draft arrives while reading history, "Newer
records" must publish it immediately, without a new subscription.

Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
@mergify

mergify Bot commented Oct 16, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @loopx-agent.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 16, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-rebase Mergify: the pull request has merge conflicts with its base branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant