Compare commits
14 Commits
1ca5663298
...
7ede927d5a
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ede927d5a | |||
| 6081448a7e | |||
| 73122c10fd | |||
| b84db7fac7 | |||
| 911df3df77 | |||
| acf1f5fb53 | |||
| 1044b39c3f | |||
| a729d68600 | |||
| b83886554f | |||
| 5a8bcebdf4 | |||
| a479d3e32d | |||
| f399d7383c | |||
| e8e019eb76 | |||
| 3c2fd5d760 |
0
.yoi/tickets/00001KVTNAY20/artifacts/.gitkeep
Normal file
0
.yoi/tickets/00001KVTNAY20/artifacts/.gitkeep
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
{"id":"orch-plan-20260623-192711-1","ticket_id":"00001KVTNAY20","kind":"accepted_plan","accepted_plan":{"summary":"Ticket 00001KVTNAY20 は implementation_ready。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` と branch `work/00001KVTNAY20-worker-runtime-spawn` で、Workspace Worker runtime spawn abstraction を実装し、routing record の IntentPacket を基準に coder/reviewer sibling loop へ進める。root/original workspace では git/read/write/validate/merge/cleanup を行わない。","branch":"work/00001KVTNAY20-worker-runtime-spawn","worktree":"/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn","role_plan":"Orchestrator: acceptance/routing, worktree creation, final integration/validation/cleanup. Coder: implementation in dedicated child worktree with narrow write scope. Reviewer: read-only review by default against recorded IntentPacket, validation evidence, and diff. Orchestrator handles merge into orchestration branch after reviewer approval."},"author":"yoi-orchestrator","at":"2026-06-23T19:27:11Z"}
|
||||
{"id":"orch-plan-20260623-193340-2","ticket_id":"00001KVTNAY20","kind":"waiting_capacity_note","note":"Coder sibling execution is temporarily blocked by runtime/provider startup failures, not by Ticket requirements. `builtin:coder` started but both initial run and retry failed with provider API error `Unsupported content type`; alternate `inherit` / `builtin:default` / `builtin:companion` recovery attempts did not produce a socket within 10s. Worktree `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` remains clean at orchestration commit `b8388655`; no implementation diff exists yet. Human/tooling follow-up is needed before continuing multi-agent implementation, unless Orchestrator is explicitly authorized to implement directly.","author":"yoi-orchestrator","at":"2026-06-23T19:33:40Z"}
|
||||
158
.yoi/tickets/00001KVTNAY20/item.md
Normal file
158
.yoi/tickets/00001KVTNAY20/item.md
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
---
|
||||
title: 'Abstract Workspace Worker runtime spawn operations'
|
||||
state: 'inprogress'
|
||||
created_at: '2026-06-23T16:34:39Z'
|
||||
updated_at: '2026-06-23T19:33:48Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-23T19:25:09Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Workspace web / Workspace backend から Worker を起動・停止・操作する UI/API を作るには、現在 read-only live view として実装されている runtime bridge を、Worker 操作も扱える backend abstraction に拡張する必要がある。
|
||||
|
||||
現状:
|
||||
|
||||
- `crates/workspace-server/src/hosts.rs` の `LocalRuntimeBridge` は local runtime metadata を読んで `HostSummary` / `WorkerSummary` を返す read-only bridge である。
|
||||
- `/api/hosts`、`/api/workers`、`/api/hosts/{host_id}/workers` はこの bridge を直接使っている。
|
||||
- Worker 起動の最終境界は `yoi pod [POD_OPTIONS]` process launch である。
|
||||
- 既存の `client::spawn::SpawnConfig` は `yoi pod` 起動 options の typed 表現に近いが、`ticket_role` のような Ticket/Orchestration domain の情報も混ざっている。
|
||||
- Workspace backend には Worker spawn / stop / protocol proxy の抽象境界がまだない。
|
||||
- Worker 起動を web backend から実装する際、workspace root / cwd / pod name / profile / role-session claim の経路が TUI とズレると、Panel 表示や workspace 所属判定が壊れる。
|
||||
|
||||
この Ticket では、Workspace backend から Worker spawn 操作を実装する前段として、**Pod process 起動境界**と**Ticket / Orchestration intent 境界**を分離して整理する。低レベル起動は Ticket system を知らず、Ticket/Orchestration 情報は上位 resolver / launch policy が低レベル config へ落とす。
|
||||
|
||||
## 要件
|
||||
|
||||
### Layering / responsibility split
|
||||
|
||||
起動系は少なくとも以下の層に分ける。
|
||||
|
||||
1. **Pod process launch layer**
|
||||
- `yoi pod [POD_OPTIONS]` を起動する唯一の低レベル境界。
|
||||
- Ticket / Orchestration / Role / TicketId を直接知らない。
|
||||
- `workspace_root`、`pod_name`、`profile`、`manifest`、`project`、`store`、`cwd`、`initial_input`、`workflow`、`require_pod_state` のような process 起動 options だけを扱う。
|
||||
2. **Worker runtime layer**
|
||||
- Workspace backend / API から見える Worker 操作境界。
|
||||
- hosts/workers live view、worker lookup、spawn/stop/protocol proxy の entrypoint を持つ。
|
||||
- API intent を低レベル Pod process launch config へ解決する。
|
||||
3. **Ticket / Orchestration resolver layer**
|
||||
- Ticket ID、Ticket role、Orchestrator/Coder/Reviewer といった workflow domain を扱う。
|
||||
- Role/Profile/Workflow/Ticket context を解決し、低レベル Pod process launch config と必要な launch policy / prompt input を作る。
|
||||
- Ticket/Orchestration 情報を低レベル launcher に直接漏らさない。
|
||||
|
||||
### Pod process launch abstraction
|
||||
|
||||
- `SpawnConfig` をそのまま Workspace backend API の入力として扱わない。
|
||||
- 低レベルの起動 config は Ticket/Orchestration domain を持たない形に整理する。
|
||||
- 既存 `SpawnConfig` を改名/分割するか、別の `PodProcessLaunchConfig` / `PodLaunchOptions` を導入する。
|
||||
- `ticket_role` は低レベル process config から分離する。
|
||||
- 必要なら `PodLaunchPolicy` / `ProfileLaunchPolicy` のような別引数/別 layer に移す。
|
||||
- `--ticket-role` は現状 hidden CLI marker として存在してよいが、汎用 `yoi pod` 起動 config の概念には含めない。
|
||||
- 低レベル launcher は `Command::new("yoi")` 相当の process 起動と acceptance evidence 取得に責務を限定する。
|
||||
- TUI/Panel、SpawnPod tool、Workspace backend はこの低レベル launcher を共有できるようにする。
|
||||
|
||||
### Worker runtime abstraction
|
||||
|
||||
- `LocalRuntimeBridge` 相当の read-only live view を、Worker 操作用の抽象境界へ整理する。
|
||||
- trait 名は実装時に決めてよいが、概念としては `WorkerRuntime` / `WorkspaceWorkerRuntime` / `HostRuntime` のような境界を作る。
|
||||
- 最低限、以下の責務を同じ abstraction から扱えるようにする。
|
||||
- hosts list
|
||||
- workers list
|
||||
- worker detail / lookup
|
||||
- worker spawn request
|
||||
- worker stop request
|
||||
- 将来の protocol method proxy / event stream の接続点
|
||||
- v0 では local implementation のみでよい。
|
||||
- 例: `LocalPodRuntime` / `LocalWorkspaceRuntime`。
|
||||
- 将来 Host protocol / remote worker backend を差し替えられるよう、Workspace API handler が concrete local implementation に密結合しすぎない形にする。
|
||||
|
||||
### Spawn operation abstraction
|
||||
|
||||
- Backend API から Worker を起動するための typed request / result を設計する。
|
||||
- Browser から `workspace_root` / `cwd` / executable path / raw profile selector を自由入力させない。
|
||||
- Frontend/API request は intent を中心にする。
|
||||
- 例: generic worker profile launch、orchestrator start、ticket coder/reviewer start。
|
||||
- ticket_id が必要な operation は path または typed field から受ける。
|
||||
- Backend / resolver が以下を解決する。
|
||||
- canonical workspace root
|
||||
- process cwd
|
||||
- pod name
|
||||
- profile / manifest / project
|
||||
- initial input / workflow
|
||||
- optional launch policy
|
||||
- role-session claim
|
||||
- Orchestrator の dedicated worktree 起動では、runtime workspace identity と cwd を混同しない。
|
||||
- `workspace_root` は original/main workspace
|
||||
- `cwd` は orchestration worktree
|
||||
- Coder / Reviewer / Orchestrator の Ticket-specific 起動経路は、低レベル Pod process launch config を生成する上位 resolver として扱う。
|
||||
- Workspace backend が独自に `Command::new("yoi")` を組み立てて挙動を分岐させない。
|
||||
|
||||
### Ticket / Orchestration information boundary
|
||||
|
||||
- Ticket ID、Ticket role、Orchestration role は低レベル `PodProcessLaunchConfig` に入れない。
|
||||
- Ticket/Orchestration resolver は以下を出力する。
|
||||
- low-level Pod process launch config
|
||||
- optional profile/launch policy
|
||||
- role-session claim metadata
|
||||
- model-visible initial input / workflow selection
|
||||
- Role は Profile と同一視しない。
|
||||
- Role は workflow 上の責務。
|
||||
- Profile は Pod recipe。
|
||||
- Role/Profile/Ticket の対応は上位 resolver の責務であり、低レベル launcher の責務ではない。
|
||||
- Role を使わない generic Worker 起動では Ticket/Orchestration 情報を一切要求しない。
|
||||
|
||||
### API surface planning
|
||||
|
||||
- 実装する API はこの Ticket で確定しなくてもよいが、初期案として以下を検討する。
|
||||
- generic: `POST /api/workers/spawn`
|
||||
- operation: `POST /api/workers/{worker_id}/stop`
|
||||
- orchestration: `POST /api/orchestrator/start`
|
||||
- ticket-specific: `POST /api/tickets/{ticket_id}/workers`
|
||||
- 起動 operation は HTTP command として扱う。
|
||||
- 状態観測 / stream / transcript は後続 Ticket で SSE/WebSocket を検討する。
|
||||
- spawn success は process start だけでなく、socket/connect/snapshot 等の acceptance evidence を持つこと。
|
||||
|
||||
### Role-session / Panel integration
|
||||
|
||||
- Backend spawn でも Panel が Worker を見つけられるようにする。
|
||||
- 起動成功後に必要な local role-session claim を作る、または既存 helper を共有する。
|
||||
- Runtime registry、Pod metadata、role-session registry のどれを authority / hint として扱うかを明確にする。
|
||||
- stale/missing/already-running の扱いを typed error として返す。
|
||||
|
||||
### Safety / authority boundary
|
||||
|
||||
- Browser は local Unix socket path や runtime registry path を直接知らない。
|
||||
- Backend が worker identity を解決し、対象 Worker が current Workspace から見えることを確認する。
|
||||
- user permission model はこの Ticket の scope 外だが、将来挟める場所を backend abstraction に残す。
|
||||
- Raw Pod protocol を browser から受ける場合でも、backend が最低限の method allow/block を挟める構造にする。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Worker operation UI の完成。
|
||||
- WebSocket/SSE event stream の完成。
|
||||
- Full permission / user auth model の設計。
|
||||
- Remote Host protocol implementation。
|
||||
- Pod protocol TypeScript 型生成の実装。
|
||||
- Workspace identity `.yoi/workspace.toml` 実装。
|
||||
- StopPod / registry locking の追加修正。
|
||||
- Ticket/Orchestration domain を廃止すること。
|
||||
- `--ticket-role` hidden CLI marker の即時削除。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
この Ticket は planning から開始する。ready に進める前に以下を満たす。
|
||||
|
||||
- Workspace backend runtime abstraction の責務境界が明文化されている。
|
||||
- `yoi pod [POD_OPTIONS]` process launch 境界と Ticket/Orchestration resolver 境界が分離されている。
|
||||
- 低レベル Pod process launch config が Ticket ID / Ticket role / Orchestration role を直接持たない方針が明記されている。
|
||||
- 既存 `SpawnConfig` の `ticket_role` をどう分離するかが決まっている。
|
||||
- 現在の `LocalRuntimeBridge` をどう trait / service に置き換えるかが決まっている。
|
||||
- Worker spawn request / result の typed shape が設計されている。
|
||||
- Orchestrator / Coder / Reviewer の起動時に `workspace_root` と `cwd` をどう決めるかが明記されている。
|
||||
- TUI/Panel、SpawnPod tool、Workspace backend が低レベル Pod process launcher を共有する方針が明記されている。
|
||||
- Ticket/Orchestration resolver が低レベル launch config・launch policy・role-session claim を生成する方針が明記されている。
|
||||
- Backend API endpoint の初期案が整理されている。
|
||||
- role-session claim / Pod metadata / runtime registry との連携方針が明記されている。
|
||||
- 実装まで含める場合は `cargo test -p yoi-workspace-server`、`cargo check -p yoi`、`cd web/workspace && deno task check && deno task build`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
169
.yoi/tickets/00001KVTNAY20/thread.md
Normal file
169
.yoi/tickets/00001KVTNAY20/thread.md
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
<!-- event: create author: "yoi ticket" at: 2026-06-23T16:34:39Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-23T18:26:48Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-23T18:26:48Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-23T19:25:09Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-23T19:26:52Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- Dashboard Queue により人間が Orchestrator routing を許可した queued Ticket として確認した。
|
||||
- Ticket body は Workspace backend の Worker runtime / Pod process launch / Ticket-Orchestration resolver の境界分離、typed spawn request/result、role-session 連携、安全境界、non-goals、validation を具体的に列挙している。
|
||||
- `TicketRelationQuery` では blocking relation は 0 件、`TicketOrchestrationPlanQuery` では既存の ordering / blocker / conflict / accepted-plan 記録は 0 件だった。
|
||||
- orchestration worktree は `## orchestration` で dirty changes なし、既存 implementation worktree は別 Ticket `00001KVSMJJNV-paused-ctrlx-cancel` と orchestration worktree のみで、この Ticket 用 worktree/branch はまだ無い。
|
||||
- `crates/client/src/spawn.rs`、`crates/client/src/ticket_role.rs`、`crates/workspace-server/src/hosts.rs`、`crates/workspace-server/src/server.rs` を bounded に確認し、Ticket に書かれた現状認識と実装対象の code map が一致している。残る不確実性は local tactic / bounded investigation に収まる。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `item.md`、`thread.md`。thread は create、planning->ready、ready->queued のみで、未解決 blocker は記録されていない。
|
||||
- related Ticket / orchestration plan records: relation 0 件、orchestration plan 0 件。
|
||||
- code paths: `crates/client/src/spawn.rs`、`crates/client/src/ticket_role.rs`、`crates/workspace-server/src/hosts.rs`、`crates/workspace-server/src/server.rs`。
|
||||
- workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` の `git status --short --branch` は clean な `## orchestration`。visible Pods は `yoi` peer と current `yoi-orchestrator` のみ。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Workspace backend から Worker spawn/stop/proxy を実装できる前段として、低レベル Pod process launch 境界と Worker runtime 境界、Ticket/Orchestration resolver 境界を分離し、既存 read-only `LocalRuntimeBridge` を操作境界へ拡張できる形に整理する。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- 低レベル Pod process launch layer は `yoi pod [POD_OPTIONS]` 起動だけを扱い、Ticket ID / Ticket role / Orchestration role を直接知らない。
|
||||
- `SpawnConfig` をそのまま Workspace backend API 入力にしない。`ticket_role` は低レベル process config から分離する。
|
||||
- Browser/API から `workspace_root` / `cwd` / executable path / raw profile selector を自由入力させない。backend/resolver が canonical workspace root、cwd、pod name、profile、initial input、workflow、launch policy、role-session claim を解決する。
|
||||
- Orchestrator dedicated worktree 起動では runtime `workspace_root` と process `cwd` を混同しない。`workspace_root` は original/main workspace、`cwd` は orchestration worktree。
|
||||
- Workspace backend が独自に `Command::new("yoi")` を組み立てて分岐する設計にしない。共有可能な低レベル launcher / config / acceptance evidence 境界を使う。
|
||||
- この Ticket では Worker operation UI、SSE/WebSocket stream、full auth/permission、remote Host protocol、TypeScript protocol generation、Workspace identity `.yoi/workspace.toml`、StopPod/registry locking の追加修正は non-goal。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- Workspace backend runtime abstraction の責務境界を code/docs/tests で追える形にする。
|
||||
- Pod process launch config と Ticket/Orchestration resolver 境界を分離し、低レベル config が Ticket/role/orchestration domain を持たないことを型・モジュール境界で示す。
|
||||
- `LocalRuntimeBridge` 相当を Worker runtime trait/service として整理し、hosts/workers list、worker lookup、spawn/stop request、将来 proxy/stream 接続点を表現できるようにする。
|
||||
- Worker spawn request/result の typed shape と acceptance evidence の扱いを導入する。
|
||||
- role-session claim / Pod metadata / runtime registry の連携方針を実装境界または明文化された設計として残す。
|
||||
- validation として少なくとも `cargo test -p yoi-workspace-server`、`cargo check -p yoi`、`cd web/workspace && deno task check && deno task build`、`git diff --check` を実施する。`nix build .#yoi --no-link` は変更量・依存/packaging 影響に応じて Orchestrator が最終判断する。
|
||||
|
||||
Implementation latitude:
|
||||
- trait / struct 名は Ticket の例示に縛られず、既存 module organization に沿ってよい。
|
||||
- `SpawnConfig` を rename/split するか、新規 `PodProcessLaunchConfig` / `PodLaunchOptions` を導入するかは coder が code map を見て選んでよい。
|
||||
- API endpoint の完全実装ではなく、backend abstraction と typed request/result の初期 shape / handler 接続点を優先してよい。
|
||||
- tests は既存 workspace-server/client test style に合わせて最小限でよい。
|
||||
|
||||
Escalate if:
|
||||
- Browser から raw local path / raw executable / raw profile selector を受ける必要が出る。
|
||||
- Ticket/Orchestration 情報を低レベル launcher に持たせないと実装できないと判断した場合。
|
||||
- workspace_root / cwd / runtime identity / role-session authority の境界を変える必要が出る。
|
||||
- public API endpoint shape をこの Ticket の初期案から大きく固定する必要が出る。
|
||||
- existing Panel/role-session semantics を破壊する変更が必要になる。
|
||||
|
||||
Validation:
|
||||
- `cargo test -p yoi-workspace-server`
|
||||
- `cargo check -p yoi`
|
||||
- `cd web/workspace && deno task check && deno task build`
|
||||
- `git diff --check`
|
||||
- 必要に応じて `nix build .#yoi --no-link`
|
||||
|
||||
Current code map:
|
||||
- Primary: `crates/workspace-server/src/hosts.rs`, `crates/workspace-server/src/server.rs`, `crates/client/src/spawn.rs`, `crates/client/src/ticket_role.rs`。
|
||||
- Secondary if needed: workspace API/client integration, role-session helpers, Pod runtime command utilities, docs/resources prompts only when implementation requires。
|
||||
- Avoid: unrelated UI completion, broad permission model, remote Host protocol, root/original workspace operations。
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- Ticket/role/orchestration fields leaking into the low-level launcher.
|
||||
- Workspace runtime abstraction becoming a UI-specific concrete local bridge instead of a backend boundary.
|
||||
- Browser/API accepting authority-bearing raw paths or executable/profile selectors.
|
||||
- `workspace_root` and `cwd` confusion for dedicated Orchestrator/Coder/Reviewer launches.
|
||||
- acceptance evidence treated as mere process start.
|
||||
- role-session claim / metadata / runtime registry authority and hint semantics left ambiguous.
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから、worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` を作成し、multi-agent-workflow で sibling coder/reviewer loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T19:27:22Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、blocking relation は 0 件、accepted plan は `orch-plan-20260623-192711-1` のみだった。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- orchestration worktree は clean な `## orchestration` で、この Ticket 用 implementation worktree/branch はまだ作成していない。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T19:30:10Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` と branch `work/00001KVTNAY20-worker-runtime-spawn` を作成した。
|
||||
- child worktree では sparse-checkout を設定し、tracked `.yoi` project records は見える一方で `.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVTNAY20-worker-runtime` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
- 初回 spawn は workspace root read scope が不足して失敗したため、implementation side effect は残さず scope を修正して再試行した。現在 reachable child Pod として起動済み。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T19:31:58Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration recovery:
|
||||
|
||||
- `yoi-coder-00001KVTNAY20-worker-runtime` は provider API error `Unsupported content type` で初回実行・再送とも assistant output を生成できなかった。
|
||||
- child worktree `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` は実装差分なしで、last commit は routing acceptance commit `5a8bcebd ticket: accept worker runtime spawn task` のままだった。
|
||||
- 失敗 Pod は停止して scope を回収した。
|
||||
- 実装 side effect の回復として、同じ child worktree/branch を使い、別 profile で Coder role を再起動する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T19:33:48Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration blocked:
|
||||
|
||||
- Coder sibling execution is blocked by runtime/provider failures, not by Ticket requirements or repository state.
|
||||
- `builtin:coder` Pod `yoi-coder-00001KVTNAY20-worker-runtime` started, but both initial run and retry failed before assistant output with provider API error: `Unsupported content type`.
|
||||
- That Pod was stopped and scope reclaimed. child worktree status remained clean with no implementation diff.
|
||||
- Recovery attempts using `inherit` (`yoi-coder-00001KVTNAY20-worker-runtime-2`), `builtin:default` (`...-3`), and `builtin:companion` (`...-4`) did not produce sockets within 10s.
|
||||
- Worktree `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` and branch `work/00001KVTNAY20-worker-runtime-spawn` are prepared and clean at orchestration commit `b8388655`.
|
||||
- `orch-plan-20260623-193340-2` に waiting-capacity note を残した。
|
||||
|
||||
Next action:
|
||||
- Coder Pod/profile/provider startup issue の解消後に同じ worktree/branch で multi-agent workflow を再開する。
|
||||
- あるいは人間が明示的に Orchestrator direct implementation を許可する場合のみ、Orchestrator がこの child worktree で実装へ進む。
|
||||
|
||||
---
|
||||
0
.yoi/tickets/00001KVV01P5Z/artifacts/.gitkeep
Normal file
0
.yoi/tickets/00001KVV01P5Z/artifacts/.gitkeep
Normal file
90
.yoi/tickets/00001KVV01P5Z/item.md
Normal file
90
.yoi/tickets/00001KVV01P5Z/item.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
---
|
||||
title: 'Planning Ticket API and UI without queue operations'
|
||||
state: 'planning'
|
||||
created_at: '2026-06-23T19:41:51Z'
|
||||
updated_at: '2026-06-23T19:41:51Z'
|
||||
assignee: null
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Ticket 管理 UI を作るにあたり、最初から DB migration や Queue 操作まで含めると authority 境界が大きくなりすぎる。現行の Ticket authority は `.yoi/tickets/<ticket-id>/` の flat file backend であり、Workspace server 側にも Ticket 用 SQLite schema の器はあるが、現時点では authority ではない。
|
||||
|
||||
この Ticket では migration を行わず、まず Workspace backend に Ticket 操作用 API を整備し、その API を操作する最小 UI を実装する。対象は Planning Ticket の作成・確認に限定し、`ready -> queued` の Queue 操作や Orchestrator 起動には踏み込まない。
|
||||
|
||||
## 目的
|
||||
|
||||
- Workspace web から Ticket を確認し、Planning 状態の Ticket を作成できるようにする。
|
||||
- UI は backend API を通じて Ticket を操作し、frontend が `.yoi/tickets` の内部ファイル構造や authority path に依存しないようにする。
|
||||
- 将来 DB authority / migration に進む余地を残しつつ、この Ticket では現行 file backend を正として扱う。
|
||||
|
||||
## 要件
|
||||
|
||||
### Backend API
|
||||
|
||||
- Workspace server に Ticket 管理用 API を追加または整理する。
|
||||
- v0 では現行 `LocalTicketBackend` / project record reader を authority として使い、DB migration はしない。
|
||||
- API は少なくとも以下を扱う。
|
||||
- Ticket 一覧取得
|
||||
- Ticket 詳細取得
|
||||
- Planning 状態の Ticket 作成
|
||||
- 作成 API は title と本文/背景/受け入れ条件などの必要最小限の入力を受け、canonical Ticket ID を返す。
|
||||
- frontend から raw `.yoi/tickets` path や内部 artifact path を直接指定させない。
|
||||
- Ticket ID は canonical ID のみを扱い、title slug や legacy alias を API contract にしない。
|
||||
- API の error は typed response として扱う。
|
||||
- invalid input
|
||||
- duplicate / conflict
|
||||
- backend unavailable
|
||||
- workspace not found / outside current workspace
|
||||
|
||||
### UI
|
||||
|
||||
- Workspace web に Ticket 管理画面または Ticket 作成導線を追加する。
|
||||
- v0 UI は Planning Ticket の作成までに限定する。
|
||||
- 作成フォームは最低限以下を扱う。
|
||||
- title
|
||||
- 背景 / 要件の本文
|
||||
- 受け入れ条件
|
||||
- 作成後は作成された canonical Ticket ID と状態を表示し、詳細画面または一覧へ反映する。
|
||||
- UI は API response を authority とし、frontend 側で Ticket file layout を再実装しない。
|
||||
|
||||
### Scope boundary
|
||||
|
||||
- Queue 操作は実装しない。
|
||||
- `ready -> queued`
|
||||
- Panel / Workspace UI からの Queue button
|
||||
- Orchestrator / Coder / Reviewer 起動
|
||||
- role-session claim 作成
|
||||
- Ticket DB migration は実装しない。
|
||||
- 既存 `.yoi/tickets` authority を変更しない。
|
||||
- 既存 Ticket CLI / Pod tool の挙動を壊さない。
|
||||
|
||||
### Safety / authority
|
||||
|
||||
- Browser は local path / runtime path / socket path を直接 authority として渡さない。
|
||||
- Workspace backend が current workspace の Ticket backend root を解決する。
|
||||
- Ticket 作成は current workspace の `.yoi/tickets` に限定する。
|
||||
- 将来 permission model を挟めるよう、API handler と backend operation の境界を分ける。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Ticket storage の DB migration。
|
||||
- SQLite `tickets` schema を authority に昇格すること。
|
||||
- Queue / ready / inprogress / close などの lifecycle mutation UI。
|
||||
- Orchestrator 起動、Worker spawn、role-session claim 連携。
|
||||
- Ticket relation / artifact / orchestration-plan 編集 UI。
|
||||
- SSE/WebSocket による live Ticket update。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
- Workspace server に Ticket list/detail/create planning 用 API がある。
|
||||
- Planning Ticket 作成 API が canonical Ticket ID を返す。
|
||||
- 作成された Ticket は既存 `yoi ticket list/show` から確認できる。
|
||||
- Workspace web から Planning Ticket を作成できる。
|
||||
- UI から Queue 操作はできない。
|
||||
- DB migration や SQLite Ticket authority 化を行っていない。
|
||||
- `cargo test -p yoi-workspace-server` が通る。
|
||||
- `cargo check -p yoi` が通る。
|
||||
- `cd web/workspace && deno task check && deno task build` が通る。
|
||||
- `git diff --check` が通る。
|
||||
- `nix build .#yoi --no-link` が通る。
|
||||
7
.yoi/tickets/00001KVV01P5Z/thread.md
Normal file
7
.yoi/tickets/00001KVV01P5Z/thread.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<!-- event: create author: "yoi ticket" at: 2026-06-23T19:41:51Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
0
.yoi/tickets/00001KVWECEQG/artifacts/.gitkeep
Normal file
0
.yoi/tickets/00001KVWECEQG/artifacts/.gitkeep
Normal file
162
.yoi/tickets/00001KVWECEQG/item.md
Normal file
162
.yoi/tickets/00001KVWECEQG/item.md
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
---
|
||||
title: 'Abstract Worker runtime registry and overview reporting'
|
||||
state: 'queued'
|
||||
created_at: '2026-06-24T09:11:38Z'
|
||||
updated_at: '2026-06-24T09:22:55Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T09:22:55Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Workspace backend には現状 `LocalRuntimeBridge` があり、local Pod metadata から `HostSummary` / `WorkerSummary` を返す read-only live view として動いている。しかしこれは concrete local 実装に近く、将来の Backend internal runtime、local Pod runtime、remote / multi-machine runtime を同じ control plane から扱う抽象境界にはまだなっていない。
|
||||
|
||||
今後の Ticket / Worker 管理 UI では、Backend が Worker を直接 `yoi pod` や local metadata path として扱うのではなく、複数の Worker runtime を束ねる control plane になる必要がある。Companion / Intake / routing-only Orchestrator のような filesystem を必須としない Worker は Backend internal runtime で動かせるべきであり、Coder / Reviewer / build-heavy Worker は local / remote の filesystem-capable runtime に配置できるべきである。
|
||||
|
||||
また、Worker session を Backend が raw log として全量・恒久的に収集する設計にはしない。raw session / provider trace / detailed event stream は execution runtime 側の prune 可能な debug/source log とし、Backend は Worker run overview、usage aggregate、lifecycle event、Ticket / role / runtime link、artifact reference、failure summary のような後から使える durable projection を持つ。
|
||||
|
||||
この Ticket では、既存 `LocalRuntimeBridge` をレベル上げして、Workspace backend の Worker runtime registry / runtime abstraction として整理する。
|
||||
|
||||
## 目的
|
||||
|
||||
- Workspace backend が複数の Worker runtime を扱える抽象境界を持つ。
|
||||
- 既存 local Pod metadata read-only bridge を `LocalPodRuntime` 相当の runtime 実装として位置付ける。
|
||||
- Backend が runtime registry を持ち、API handler が concrete local bridge に直接依存しないようにする。
|
||||
- raw session を Backend authority にせず、overview / metrics / durable outcome を中心に扱う方針を型と API 境界に反映する。
|
||||
- 後続の spawn / stop / protocol proxy / remote runtime / internal runtime 実装に進める基盤を作る。
|
||||
|
||||
## 要件
|
||||
|
||||
### Worker runtime abstraction
|
||||
|
||||
- `LocalRuntimeBridge` をそのまま API handler から直接使う構造をやめ、Worker runtime trait / service 境界を導入する。
|
||||
- 概念名は実装時に決めてよいが、`WorkerRuntime` / `WorkspaceWorkerRuntime` / `RuntimeRegistry` / `WorkerRuntimeRegistry` のような責務が明確な名前にする。
|
||||
- v0 では少なくとも以下の read operations を抽象化する。
|
||||
- runtime / host list
|
||||
- runtime / host detail
|
||||
- worker list
|
||||
- worker detail / lookup
|
||||
- 後続 operation の接続点を型として残す。
|
||||
- spawn worker
|
||||
- stop worker
|
||||
- send input / interrupt / compact などの worker command routing
|
||||
- bounded transcript / debug session read
|
||||
- event stream / run overview stream
|
||||
- v0 で未実装の operation は unsupported として typed error を返せるようにする。
|
||||
|
||||
### Runtime registry
|
||||
|
||||
- Workspace backend は単一の concrete `LocalRuntimeBridge` ではなく、runtime registry 経由で Worker / Host を取得する。
|
||||
- registry は複数 runtime を保持できる構造にする。
|
||||
- backend internal runtime
|
||||
- local Pod runtime
|
||||
- future remote runtime
|
||||
- v0 では local Pod runtime のみ登録してよい。
|
||||
- runtime_id / host_id / worker_id は API contract 上 opaque id として扱う。
|
||||
- `pod_name` は local Pod runtime の implementation detail / display hint とし、外部操作の主キーにはしない。
|
||||
- API handler は runtime_id / worker_id を registry に解決させ、raw local path / socket path / metadata path を browser に出さない。
|
||||
|
||||
### Runtime capability model
|
||||
|
||||
- Runtime / Host detail は capability summary を返す。
|
||||
- 少なくとも以下のような区別ができること。
|
||||
- can_list_workers
|
||||
- can_get_worker
|
||||
- can_spawn_worker
|
||||
- can_stop_worker
|
||||
- can_accept_input
|
||||
- can_stream_events
|
||||
- can_read_bounded_transcript / debug session
|
||||
- has_workspace_fs
|
||||
- has_shell
|
||||
- has_git
|
||||
- supports_worktrees
|
||||
- supports_backend_internal_tools / ticket tools
|
||||
- Companion / Intake / routing-only Orchestrator は filesystem なし runtime でも動かせる、Coder / Reviewer は filesystem-capable runtime が必要、という placement 判断を後続で表現できる shape にする。
|
||||
|
||||
### Worker identity / visibility
|
||||
|
||||
- Worker identity は runtime scoped に扱う。
|
||||
- runtime_id
|
||||
- worker_id
|
||||
- optional active run id
|
||||
- optional active session id / segment id は implementation detail または debug field
|
||||
- Workspace UI の通常表示では current workspace から見える Worker だけを返す。
|
||||
- local Pod runtime では `PodMetadata.workspace_root` を current workspace root と比較して visibility を決める。
|
||||
- `cwd` と runtime workspace identity を混同しない。
|
||||
- dedicated Orchestrator worktree があっても、runtime workspace identity は original/main workspace root である。
|
||||
- workspace root が無い / 不一致 / metadata invalid な Worker は diagnostics または debug scope として扱い、通常 UI の authority を歪めない。
|
||||
|
||||
### Session / overview boundary
|
||||
|
||||
- Backend は raw session log を恒久 authority として持たない。
|
||||
- raw session / provider trace / verbose event stream は execution runtime 側に残し、runtime retention / prune 対象とする。
|
||||
- Backend が durable に持つものは以下を中心にする。
|
||||
- Worker run overview
|
||||
- lifecycle event
|
||||
- usage aggregate
|
||||
- Ticket / role / runtime / worker link
|
||||
- durable outcome summary
|
||||
- failure summary
|
||||
- artifact / report reference
|
||||
- Runtime interface は必要に応じて bounded transcript / debug session tail を読める接続点を持つが、これは debug / live UI 用であり Backend DB の durable authority ではない。
|
||||
- usage dashboard は raw session ingest ではなく、runtime からの usage event / aggregate を元に構築できる形にする。
|
||||
|
||||
### Backend internal runtime planning
|
||||
|
||||
- Backend internal runtime はこの Ticket で完全実装しなくてよいが、registry / capability / identity model がそれを表現できること。
|
||||
- Backend internal runtime は filesystem tool を前提にしない Worker 用とする。
|
||||
- Companion
|
||||
- Intake
|
||||
- Ticket planning / routing assistant
|
||||
- Dashboard assistant
|
||||
- Backend internal Worker は Ticket / Workspace API を tool として使う形を想定し、raw local filesystem authority を要求しない。
|
||||
|
||||
### Local Pod runtime migration
|
||||
|
||||
- 既存 `LocalRuntimeBridge` の read-only local metadata 実装を `LocalPodRuntime` 相当へ移す、または薄い adapter として registry に登録する。
|
||||
- 既存 API の挙動を壊さない。
|
||||
- `GET /api/hosts`
|
||||
- `GET /api/workers`
|
||||
- `GET /api/hosts/{host_id}/workers`
|
||||
- 追加可能であれば worker detail endpoint を追加する。
|
||||
- `GET /api/workers/{worker_id}`
|
||||
- `GET /api/hosts/{host_id}/workers/{worker_id}`
|
||||
- local Pod metadata の raw content / snapshot content / socket path は API response に出さない。
|
||||
|
||||
### API / error boundary
|
||||
|
||||
- API response は runtime registry 経由の typed response にする。
|
||||
- unknown runtime / host / worker は typed error として返す。
|
||||
- runtime unavailable、operation unsupported、worker not visible、invalid query は区別できるようにする。
|
||||
- Browser は local Unix socket path、runtime registry file path、Pod metadata path、raw session path を authority として渡さない。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Worker spawn / stop の本実装。
|
||||
- Remote runtime protocol の本実装。
|
||||
- Backend internal runtime で実際に LLM Worker を起動すること。
|
||||
- raw session 全量の Backend DB ingest。
|
||||
- Session log schema migration。
|
||||
- Ticket storage migration。
|
||||
- Worker operation UI の完成。
|
||||
- SSE/WebSocket event stream の完成。
|
||||
- Permission / auth model の完成。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
この Ticket は planning から開始する。ready に進める前に以下を満たす。
|
||||
|
||||
- Worker runtime / runtime registry / local Pod runtime の責務境界が明文化されている。
|
||||
- 既存 `LocalRuntimeBridge` をどう level-up / rename / adapter 化するかが決まっている。
|
||||
- Backend が複数 runtime を保持できる registry 構造の方針が決まっている。
|
||||
- runtime_id / host_id / worker_id の identity 方針が決まっている。
|
||||
- local Pod `pod_name` を external operation key にしない方針が明記されている。
|
||||
- Runtime capability model の最小 field が整理されている。
|
||||
- current workspace visibility と workspace_root / cwd の扱いが明記されている。
|
||||
- raw session を Backend durable authority にしない方針が明記されている。
|
||||
- Backend に残す Worker run overview / usage aggregate / lifecycle projection の方針が明記されている。
|
||||
- bounded transcript / debug session read は runtime-local optional operation とする方針が明記されている。
|
||||
- 既存 `/api/hosts` / `/api/workers` を registry 経由へ移す方針が明記されている。
|
||||
- 実装まで含める場合は `cargo test -p yoi-workspace-server`、`cargo check -p yoi`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
33
.yoi/tickets/00001KVWECEQG/thread.md
Normal file
33
.yoi/tickets/00001KVWECEQG/thread.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<!-- event: create author: "yoi ticket" at: 2026-06-24T09:11:38Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-24T09:21:22Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-24T09:21:22Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T09:22:55Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
0
.yoi/tickets/00001KVWPVHFJ/artifacts/.gitkeep
Normal file
0
.yoi/tickets/00001KVWPVHFJ/artifacts/.gitkeep
Normal file
148
.yoi/tickets/00001KVWPVHFJ/item.md
Normal file
148
.yoi/tickets/00001KVWPVHFJ/item.md
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
---
|
||||
title: 'Pod/session storage cleanup CLI を追加する'
|
||||
state: 'ready'
|
||||
created_at: '2026-06-24T11:39:41Z'
|
||||
updated_at: '2026-06-24T11:39:41Z'
|
||||
assignee: null
|
||||
readiness: 'implementation_ready'
|
||||
risk_flags: ['pod-lifecycle', 'persistence', 'destructive-operation', 'cli-ux', 'session-history', 'authority-boundary']
|
||||
---
|
||||
|
||||
## User claims / request snapshot
|
||||
|
||||
- Pod 名を指定して Pod を消去する CLI コマンドを実装する。
|
||||
- Pod から参照されていないセッションを削除するコマンドを用意する。
|
||||
- 古い Pod / セッションを削除するコマンドを用意する。
|
||||
- コマンド名は以下で合意済み:
|
||||
- `yoi pod delete <NAME> [--force] [--dry-run]`
|
||||
- `yoi pod prune [--older-than <DURATION>] [--force] [--dry-run]`
|
||||
- `yoi session prune --unreferenced [--older-than <DURATION>] [--force] [--dry-run]`
|
||||
|
||||
## Confirmed facts / sources
|
||||
|
||||
- 関連 closed Ticket `00001KTJ7MACG` は fresh-start 専用 UX を実装しない方針で closed 済み。ただし resolution で、Pod 名を明示的に空ける archive/delete と storage cleanup/prune commands は必要になれば別 Ticket として扱う、と記録されている。
|
||||
- `crates/pod-store/src/lib.rs` では Pod metadata authority は `{data_dir}/pods/{pod_name}/metadata.json` であり、`PodMetadataStore::delete_by_name` / `FsPodStore::delete_by_name` が既に存在する。
|
||||
- `crates/session-store/src/fs_store.rs` / `crates/session-store/src/lib.rs` では session log は `{sessions_root}/{session_id}/{segment_id}.jsonl` と trace jsonl で、`FsStore` は `list_sessions`, `list_segments`, `lookup_session_of` を持つ。確認範囲では削除用 public API は見当たらない。
|
||||
- `crates/yoi/src/main.rs` では `yoi pod ...` は現在 `pod::entrypoint::run_cli_from("yoi pod", args)` に委譲されており、Pod runtime spawn/restore 用 entrypoint として使われている。
|
||||
- `crates/yoi/src/session_cli.rs` では `yoi session ...` は現在 `analyze <SESSION_JSONL_PATH> --json` のみ。
|
||||
- `crates/pod/src/entrypoint.rs` では `--pod <NAME>` は name-keyed Pod state があれば restore、なければ fresh create する。sessions dir は `--store` または `manifest::paths::sessions_dir()`、Pod store は `manifest::paths::data_dir()/pods` から解決している。
|
||||
- duplicate / related search では、直接同じ目的の open Ticket は見つからなかった。関連 closed Ticket は `00001KTJ7MACG`, `00001KSTRGFX0`, `00001KSXXRRC8`。
|
||||
|
||||
## Unverified hypotheses
|
||||
|
||||
- live Pod protection は runtime socket / Pod registry / discovery layer と組み合わせて判定できる可能性が高いが、実装時に正確な helper/API を確認する必要がある。
|
||||
- orphan session 判定は「active Pod metadata から参照されない SessionId」を基本にできそうだが、fork/segment lineage、trace file、古い closed metadata、manual session restore use case をどこまで保存対象にするかは実装時に注意する必要がある。
|
||||
- `yoi pod delete` を runtime entrypoint に足すより、product CLI 側で `yoi pod delete` を捕捉するほうが安全かもしれないが、既存 `yoi pod` の意味と衝突しない設計確認が必要。
|
||||
|
||||
## Undecided points / open questions
|
||||
|
||||
- Blocking open question は現時点ではない。
|
||||
- 実装中に CLI boundary が既存 `yoi pod` runtime entrypoint と衝突する場合は、Orchestrator / maintainer に escalate する。
|
||||
- orphan session 判定で session lineage semantics や manual restore use case への影響が大きい場合は、削除範囲を安全側に狭めるか follow-up に分ける。
|
||||
|
||||
## Background
|
||||
|
||||
以前の fresh-start Ticket では、restore bypass 専用 path を作らず、Pod 名の衝突解消や古い履歴蓄積は Pod/session storage cleanup commands として扱う方針になった。現在も Pod metadata と session logs は durable authority が分かれており、手で `~/.yoi/pods` や `~/.yoi/sessions` を消すのは危険で discoverable ではない。公式 CLI と safety rails が必要。
|
||||
|
||||
## Requirements
|
||||
|
||||
- Pod 名を指定して、name-keyed Pod metadata を削除できる CLI を追加する。
|
||||
- コマンド名は `yoi pod delete <NAME> [--force] [--dry-run]` とする。
|
||||
- 削除後、同じ Pod 名の通常起動は既存の `missing -> spawn fresh` path に乗る。
|
||||
- session logs/history は `pod delete` では削除しない。
|
||||
- live/reachable Pod の metadata 削除は拒否する。
|
||||
- 実装が live 判定できない場合は安全側に倒し、削除せず診断する。
|
||||
- live Pod を止める操作や stop semantics の変更はこの Ticket の主目的にしない。
|
||||
- orphan session cleanup CLI を追加する。
|
||||
- コマンド名は `yoi session prune --unreferenced [--older-than <DURATION>] [--force] [--dry-run]` とする。
|
||||
- Pod metadata の active pointer から参照されていない session/segment を候補として列挙できる。
|
||||
- 実削除は `--force` が必要。
|
||||
- 初期実装は dry-run / report を重視し、削除対象と根拠を表示する。
|
||||
- old Pod / old session cleanup CLI を追加する。
|
||||
- Pod 側は `yoi pod prune [--older-than <DURATION>] [--force] [--dry-run]` とする。
|
||||
- 「古い」の判定は暗黙 default を持たせず、`--older-than <DURATION>` のような明示 threshold を要求する。
|
||||
- threshold 未指定で「古い」と判断して削除しない。
|
||||
- destructive operation は共通で:
|
||||
- default は dry-run または削除拒否にする。
|
||||
- 実削除には `--force` を要求する。
|
||||
- 削除対象、保持対象、拒否理由を bounded に表示する。
|
||||
- product CLI help/docs を更新し、manual data-dir surgery ではなく公式 command を案内する。
|
||||
- `yoi pod` が既存 runtime entrypoint として使われている境界を壊さない。
|
||||
- management subcommands を product CLI 側で捕捉するか、runtime entrypoint 側に安全に追加するかは実装判断でよいが、既存 spawn/restore options と互換的に動くこと。
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `yoi pod delete <NAME>` 相当の公式 CLI で stopped/restorable Pod metadata を削除できる。
|
||||
- 削除後、同名 Pod 起動は existing metadata restore ではなく fresh create path になる。
|
||||
- live/reachable Pod に対する delete/prune は拒否され、理由が表示される。
|
||||
- `pod delete` は session logs を削除しない。
|
||||
- Pod metadata から参照されていない session を dry-run で列挙でき、`--force` 指定時だけ削除できる。
|
||||
- 古い Pod / session cleanup は `--older-than` 等の明示条件なしでは削除しない。
|
||||
- prune/delete の出力は、削除予定/削除済み/保持/拒否をユーザーが確認できる。
|
||||
- focused tests が以下を cover する:
|
||||
- stopped/restorable Pod delete success。
|
||||
- live Pod delete refusal。
|
||||
- Pod delete 後の same-name missing/fresh behavior。
|
||||
- referenced session is preserved。
|
||||
- unreferenced session prune dry-run and force behavior。
|
||||
- old Pod/session prune requires explicit threshold。
|
||||
- CLI parsing/help。
|
||||
|
||||
## Binding decisions / invariants
|
||||
|
||||
- No silent restore bypass. Fresh same-name start は、ユーザーが明示的に metadata を削除した結果としてのみ発生する。
|
||||
- Pod metadata delete の副作用として session history を自動削除しない。
|
||||
- live/reachable Pod metadata を削除しない。
|
||||
- 暗黙の “old” threshold を持たせない。old Pod/session cleanup では age criteria をユーザーが明示する。
|
||||
- destructive deletion には明示的な `--force` を要求し、dry-run/report behavior を提供する。
|
||||
- Pod metadata authority は `pod-store`、session log authority は `session-store` のままにする。
|
||||
- legacy top-level resume flags や bare Pod-name inference を再導入しない。
|
||||
- この Ticket では Panel/TUI を broad Pod manager にしない。CLI 実装で十分とし、Panel integration は必要なら follow-up に分ける。
|
||||
|
||||
## Implementation latitude
|
||||
|
||||
- 合意済み command spelling は維持する。ただし clap/parser 上の曖昧さを避けるための minor option shape 調整は、既存 UX を壊さない範囲で許容する。
|
||||
- product CLI 側で management subcommands を捕捉するか、runtime entrypoint 側へ安全に追加するかは実装判断でよい。
|
||||
- 必要なら product CLI から使う shared cleanup module を作ってよい。
|
||||
- 必要なら `session-store` に削除 API を追加してよい。その場合は path safety と trace/log cleanup の tests を追加する。
|
||||
- Orphan session detection は初期実装では active `PodMetadata.active.session_id` references を authority としてよい。より高度な lineage-aware retention は、referenced sessions を削除しない限り follow-up に分けてよい。
|
||||
- Output は初期実装では human-readable でよい。JSON output は周辺 CLI と自然に揃えられる場合を除き follow-up でよい。
|
||||
|
||||
## Readiness
|
||||
|
||||
- readiness: implementation_ready
|
||||
- risk_flags: [pod-lifecycle, persistence, destructive-operation, cli-ux, session-history, authority-boundary]
|
||||
|
||||
## Escalation conditions
|
||||
|
||||
以下の場合は実装を進める前に Orchestrator / maintainer に escalate する。
|
||||
|
||||
- live Pod detection を安全に拒否できるほど reliable にできない。
|
||||
- orphan detection が session lineage semantics の変更を必要とする。
|
||||
- Pod delete の副作用として sessions を削除する必要が出る。
|
||||
- storage migration や compatibility fallback が必要になる。
|
||||
- command design が `yoi pod` runtime entrypoint usage と衝突する。
|
||||
- cleanup が Panel role-session/Ticket claims、worktrees、branches、Ticket state を mutate しようとする。
|
||||
|
||||
## Validation
|
||||
|
||||
- `cargo fmt --check`
|
||||
- focused `cargo test` for `yoi`, `pod-store`, `session-store`, and affected Pod/discovery code
|
||||
- `cargo check -p yoi -p pod -p pod-store -p session-store`
|
||||
- `target/debug/yoi ticket doctor` または `yoi ticket doctor`
|
||||
- `git diff --check`
|
||||
|
||||
Reviewer は path safety、live/refusal behavior、dry-run/force semantics、session history を accidental に削除しないことを重点確認する。
|
||||
|
||||
## Related work
|
||||
|
||||
- Related closed Ticket: `00001KTJ7MACG` — Add Pod archive and fresh-start path.
|
||||
- Related closed Ticket: `00001KSTRGFX0` — Split Pod metadata into a dedicated pod-store crate.
|
||||
- Related closed Ticket: `00001KSXXRRC8` — Pod tools: unify pod listing and rename restore operation.
|
||||
- Files inspected:
|
||||
- `crates/yoi/src/main.rs`
|
||||
- `crates/yoi/src/session_cli.rs`
|
||||
- `crates/pod/src/entrypoint.rs`
|
||||
- `crates/pod-store/src/lib.rs`
|
||||
- `crates/session-store/src/fs_store.rs`
|
||||
- `crates/session-store/src/lib.rs`
|
||||
7
.yoi/tickets/00001KVWPVHFJ/thread.md
Normal file
7
.yoi/tickets/00001KVWPVHFJ/thread.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<!-- event: create author: ticket-intake at: 2026-06-24T11:39:41Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
0
.yoi/tickets/00001KVWPW3KX/artifacts/.gitkeep
Normal file
0
.yoi/tickets/00001KVWPW3KX/artifacts/.gitkeep
Normal file
122
.yoi/tickets/00001KVWPW3KX/item.md
Normal file
122
.yoi/tickets/00001KVWPW3KX/item.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
---
|
||||
title: 'TUI Console: 連続した Thinking block を一つの表示グループにまとめる'
|
||||
state: 'ready'
|
||||
created_at: '2026-06-24T11:39:59Z'
|
||||
updated_at: '2026-06-24T11:56:52Z'
|
||||
assignee: null
|
||||
readiness: 'implementation_ready'
|
||||
risk_flags: ['tui-rendering', 'reasoning-display', 'block-aggregation', 'text-selection']
|
||||
---
|
||||
|
||||
## User claims / request snapshot
|
||||
|
||||
- ユーザーは、TUI Console で連続した `Thinking` を `Read` tool 表示のように一つにまとめて表示したいと依頼した。
|
||||
- 対象 workspace は `yoi`。
|
||||
- Panel handoff の orchestrator Pod は `yoi-orchestrator`。
|
||||
|
||||
## Confirmed facts / sources
|
||||
|
||||
- 既存 Ticket 確認では、同じ目的の active duplicate は見当たらなかった。
|
||||
- 関連 closed Ticket:
|
||||
- `00001KT5D44Z0` — reasoning / thinking persistence を block lifecycle に統一済み。
|
||||
- `00001KVMT2J25` — in-flight snapshot が unfinished thinking block を含め、TUI が snapshot から unfinished thinking を seed して live delta 継続できるようにした。
|
||||
- `00001KVHX0WBE` — Dashboard / Console / TUI の呼称と module boundary を整理済み。今回の対象は Console / single-Pod chat surface。
|
||||
- `00001KTKCK8W8` — chat view の Markdown rendering 改善。今回と同じく表示層の変更であり、history / context 変更は避ける方針が近い。
|
||||
- `00001KSVP63K8` は planning の in-flight composer injection で、今回の Thinking 表示集約とは別件。
|
||||
- `crates/tui/src/block.rs` では `Block::Thinking(ThinkingBlock)` が独立した history block として存在し、`ThinkingState::{Streaming, Finished, Incomplete}` を持つ。
|
||||
- `crates/tui/src/app.rs` では `Event::ThinkingStart` ごとに新しい `Block::Thinking` を push し、`ThinkingDelta` は最後の streaming thinking に追記し、`ThinkingDone` で finished にする。
|
||||
- `crates/tui/src/ui.rs` の `compute_history` は block 列を走査し、`Block::ToolCall` だけ `crate::tool::render_tool(...)` に委譲して複数 block 消費を許している。
|
||||
- `crates/tui/src/tool.rs` の `Read` renderer は、連続する `Read` tool call block を `render_read_aggregate` でまとめ、1つの header と path list として表示している。
|
||||
- `crates/tui/src/ui.rs` の `render_thinking` は現在、各 `ThinkingBlock` を個別に header / body preview / detail として描画している。連続 Thinking をまとめる専用 path は見当たらない。
|
||||
|
||||
## Unverified hypotheses
|
||||
|
||||
- 実装は `Read` と同様に `compute_history` 側で連続する `Block::Thinking` をまとめる renderer を導入する形が自然そう。
|
||||
- 「連続」は、同じ turn 内で他の block を挟まない `Block::Thinking` の連なりとして扱うのが妥当そう。
|
||||
- Normal mode では 1 header + 最新または先頭 preview、Detail mode では各 Thinking body を連結または小見出し付きで読める形にすればよさそう。
|
||||
|
||||
## Undecided points / open questions
|
||||
|
||||
- blocking な未決定点はない。
|
||||
- 表示文言の細部(例: `Thoughts — 3 blocks` / `Thinking... (3 blocks)` / elapsed 表示の集約方法)は実装者判断でよい。
|
||||
- ただし、連続していない Thinking や turn を跨ぐ Thinking までまとめるべきではない、という invariant は維持する。
|
||||
|
||||
## Background
|
||||
|
||||
Provider / model によっては 1 turn 内で Thinking / reasoning block が複数連続して発生する。現状の Console 表示では、それぞれが個別の Thinking 表示になり、会話ログが冗長に見える可能性がある。`Read` tool は連続する `Read` call を 1つの表示グループにまとめる既存 UX があるため、Thinking でも同様の表示集約を行う。
|
||||
|
||||
## Requirements
|
||||
|
||||
- TUI Console の history rendering で、連続する `Block::Thinking` を一つの logical display group として表示する。
|
||||
- 対象は Console / single-Pod chat view の表示層に限定する。
|
||||
- `Read` tool の連続 aggregation と同じく、rendering 時に複数 block を消費して一つの表示にまとめられること。
|
||||
- 連続していない Thinking、別 turn の Thinking、間に `AssistantText` / `ToolCall` / `User` / `System` などを挟む Thinking はまとめない。
|
||||
- `Streaming` / `Finished` / `Incomplete` が混在しても、状態が誤解されない header / body 表示にする。
|
||||
- Normal / Detail / Overview mode の既存意味を保つ。
|
||||
- Pod history、session log、worker history、prompt context、protocol event model、reasoning persistence は変更しない。
|
||||
- In-flight snapshot から復元された unfinished Thinking と live delta continuation の表示が退行しない。
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- 1 turn 内で `Thinking` block が複数連続する場合、Console history 上では 1つの Thinking group として表示される。
|
||||
- 連続 Thinking group は、少なくとも group header と読み取り可能な preview / detail body を持つ。
|
||||
- Normal mode で冗長な `Thought` / `Thinking...` header が連続表示されない。
|
||||
- Detail mode では、集約された各 Thinking の本文が欠落せず読める。
|
||||
- Overview mode でも 1 group として扱われ、行数が不必要に増えない。
|
||||
- 間に non-Thinking block がある場合や turn を跨ぐ場合は、別 group として表示される。
|
||||
- Text selection / copy の既存方針が壊れない。Thinking は現在 text-like selectable block ではないため、集約後も不用意に selectable transcript text にしない。
|
||||
- Read tool aggregation、ToolCall rendering、AssistantText rendering に退行がない。
|
||||
- Focused TUI rendering test が追加または更新される。
|
||||
|
||||
## Binding decisions / invariants
|
||||
|
||||
- これは TUI Console の表示改善であり、reasoning / thinking の protocol、persistence、provider event semantics の変更ではない。
|
||||
- Thinking content を history / context に別形式で保存し直さない。
|
||||
- 未完了 Thinking を finalized assistant history と混同しない。
|
||||
- `Read` aggregation と同じく render-time aggregation として扱い、source block sequence 自体は保持する。
|
||||
- Turn boundary を跨いで group 化しない。
|
||||
- Non-Thinking block を跨いで group 化しない。
|
||||
- Dashboard / Panel の Ticket rows や web UI は対象外。
|
||||
|
||||
## Implementation latitude
|
||||
|
||||
- `compute_history` に `Block::Thinking` の consecutive aggregation path を追加し、`tool::render_tool` と同様に consumed count を返す helper を作ってよい。
|
||||
- `render_thinking` を単体 renderer として残しつつ、複数 block 用の `render_thinking_aggregate` を追加してよい。
|
||||
- Header 文言、elapsed 表示、複数 state 混在時の summary は実装者判断でよい。ただし streaming / incomplete を隠さない。
|
||||
- Detail mode で各 block の境界を薄い separator / index / blank line で示すか、単純連結するかは実装者判断でよい。
|
||||
- Existing tests に加えて、synthetic `App { blocks: [...] }` から `compute_history` output を見る focused unit test を追加するのが自然。
|
||||
|
||||
## Readiness
|
||||
|
||||
- readiness: implementation_ready
|
||||
- risk_flags: [tui-rendering, reasoning-display, block-aggregation, text-selection]
|
||||
|
||||
## Escalation conditions
|
||||
|
||||
- protocol / pod / persistence 層の変更が必要だと分かった場合。
|
||||
- Thinking を selectable / copyable transcript text として扱う UX 変更が必要になる場合。
|
||||
- Provider-specific reasoning metadata の扱いに踏み込む必要が出た場合。
|
||||
- Console 以外の Dashboard / web / protocol UI surface まで範囲が広がる場合。
|
||||
- 表示集約のために broad TUI rendering rewrite が必要になる場合。
|
||||
|
||||
## Validation
|
||||
|
||||
- `cargo test -p tui` または focused `cargo test -p tui thinking` / rendering tests。
|
||||
- `cargo fmt --check`。
|
||||
- `git diff --check`。
|
||||
- 必要に応じて `cargo check -p tui`。
|
||||
- 変更範囲が TUI / package integration に広がる場合のみ `nix build .#yoi` を検討。
|
||||
|
||||
## Related work
|
||||
|
||||
- Tickets:
|
||||
- `00001KT5D44Z0` — Unify reasoning persistence with block lifecycle
|
||||
- `00001KVMT2J25` — Pod protocol: in-flight LLM response reconnect snapshot should include unfinished blocks
|
||||
- `00001KVHX0WBE` — Dashboard / Console 呼称導入と TUI モジュール境界整理
|
||||
- `00001KTKCK8W8` — TUI chat view should render Markdown tables
|
||||
- related but not duplicate: `00001KSVP63K8`
|
||||
- Files:
|
||||
- `crates/tui/src/block.rs`
|
||||
- `crates/tui/src/app.rs`
|
||||
- `crates/tui/src/ui.rs`
|
||||
- `crates/tui/src/tool.rs`
|
||||
23
.yoi/tickets/00001KVWPW3KX/thread.md
Normal file
23
.yoi/tickets/00001KVWPW3KX/thread.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<!-- event: create author: LocalTicketBackend at: 2026-06-24T11:39:59Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: ticket-intake at: 2026-06-24T11:56:52Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
ユーザーが draft 内容を確認し、Ticket `00001KVWPW3KX` を ready にするよう明示した。Ticket 本文には implementation_ready、blocking open questions なし、対象範囲・invariants・validation が記録済みで、Orchestrator が implementation routing を判断できる。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: ticket-intake at: 2026-06-24T11:56:52Z from: planning to: ready reason: user_confirmed_ready field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
ユーザー確認済みのため planning から ready へ移行する。blocking open questions はなく、Orchestrator は通常の routing 判断に進める。
|
||||
|
||||
---
|
||||
|
|
@ -63,7 +63,7 @@ impl ResolvedAuth {
|
|||
}
|
||||
}
|
||||
|
||||
fn header_value_for_diagnostics(headers: &HeaderMap, name: &'static HeaderName) -> Option<String> {
|
||||
fn header_value_for_diagnostics(headers: &HeaderMap, name: &str) -> Option<String> {
|
||||
headers
|
||||
.get(name)
|
||||
.and_then(|value| value.to_str().ok())
|
||||
|
|
@ -74,10 +74,25 @@ fn header_value_for_diagnostics(headers: &HeaderMap, name: &'static HeaderName)
|
|||
|
||||
fn response_header_diagnostics(headers: &HeaderMap) -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"content_type": header_value_for_diagnostics(headers, &CONTENT_TYPE),
|
||||
"content_encoding": header_value_for_diagnostics(headers, &CONTENT_ENCODING),
|
||||
"transfer_encoding": header_value_for_diagnostics(headers, &TRANSFER_ENCODING),
|
||||
"content_length": header_value_for_diagnostics(headers, &CONTENT_LENGTH),
|
||||
"content_type": header_value_for_diagnostics(headers, CONTENT_TYPE.as_str()),
|
||||
"content_encoding": header_value_for_diagnostics(headers, CONTENT_ENCODING.as_str()),
|
||||
"transfer_encoding": header_value_for_diagnostics(headers, TRANSFER_ENCODING.as_str()),
|
||||
"content_length": header_value_for_diagnostics(headers, CONTENT_LENGTH.as_str()),
|
||||
})
|
||||
}
|
||||
|
||||
fn request_header_diagnostics(headers: &HeaderMap) -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"content_type": header_value_for_diagnostics(headers, CONTENT_TYPE.as_str()),
|
||||
"content_encoding": header_value_for_diagnostics(headers, CONTENT_ENCODING.as_str()),
|
||||
"accept": header_value_for_diagnostics(headers, ACCEPT.as_str()),
|
||||
"openai_beta": header_value_for_diagnostics(headers, "openai-beta"),
|
||||
"session_id_present": headers.contains_key("session-id"),
|
||||
"thread_id_present": headers.contains_key("thread-id"),
|
||||
"legacy_session_id_present": headers.contains_key("session_id"),
|
||||
"legacy_thread_id_present": headers.contains_key("thread_id"),
|
||||
"x_client_request_id_present": headers.contains_key("x-client-request-id"),
|
||||
"chatgpt_account_id_present": headers.contains_key("chatgpt-account-id"),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -211,6 +226,11 @@ impl<S: Scheme> HttpTransport<S> {
|
|||
let value = HeaderValue::from_str(cache_key).map_err(|e| {
|
||||
ClientError::Config(format!("invalid Codex conversation header: {e}"))
|
||||
})?;
|
||||
// Codex CLI sends hyphenated session/thread headers to the
|
||||
// ChatGPT Codex backend. Keep the legacy underscore header for
|
||||
// existing traces/backends while exposing the current Codex shape.
|
||||
headers.insert(HeaderName::from_static("session-id"), value.clone());
|
||||
headers.insert(HeaderName::from_static("thread-id"), value.clone());
|
||||
headers.insert(HeaderName::from_static("session_id"), value.clone());
|
||||
headers.insert(HeaderName::from_static("x-client-request-id"), value);
|
||||
}
|
||||
|
|
@ -451,6 +471,7 @@ impl<S: Scheme + Clone + 'static> LlmClient for HttpTransport<S> {
|
|||
json!({
|
||||
"elapsed_ms": headers_started.elapsed().as_millis() as u64,
|
||||
"headers_len": headers.len(),
|
||||
"headers": request_header_diagnostics(&headers),
|
||||
}),
|
||||
);
|
||||
headers
|
||||
|
|
@ -486,6 +507,7 @@ impl<S: Scheme + Clone + 'static> LlmClient for HttpTransport<S> {
|
|||
json!({
|
||||
"elapsed_ms": stream_headers_started.elapsed().as_millis() as u64,
|
||||
"headers_len": headers.len(),
|
||||
"headers": request_header_diagnostics(&headers),
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
@ -520,15 +542,19 @@ impl<S: Scheme + Clone + 'static> LlmClient for HttpTransport<S> {
|
|||
return Err(error);
|
||||
}
|
||||
};
|
||||
let final_request_headers = request_header_diagnostics(&headers);
|
||||
let body_compression = request_body.encoding().to_string();
|
||||
emit_transport_trace(
|
||||
&request,
|
||||
"transport_body_encode_done",
|
||||
json!({
|
||||
"elapsed_ms": encode_started.elapsed().as_millis() as u64,
|
||||
"encoding": request_body.encoding(),
|
||||
"encoding": body_compression.as_str(),
|
||||
"body_compression": body_compression.as_str(),
|
||||
"raw_json_bytes": request_body.raw_json_bytes(),
|
||||
"wire_bytes": request_body.wire_bytes(),
|
||||
"request_shape": body_shape.clone(),
|
||||
"headers": final_request_headers.clone(),
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
@ -586,6 +612,8 @@ impl<S: Scheme + Clone + 'static> LlmClient for HttpTransport<S> {
|
|||
"context_length_exceeded": context_length_exceeded,
|
||||
"provider_usage_absent": context_length_exceeded,
|
||||
"request_shape": body_shape.clone(),
|
||||
"request_headers": final_request_headers.clone(),
|
||||
"body_compression": body_compression.as_str(),
|
||||
}),
|
||||
);
|
||||
return Err(error);
|
||||
|
|
@ -817,10 +845,26 @@ mod tests {
|
|||
let encoded = transport.encode_request_body(&body, &mut headers).unwrap();
|
||||
|
||||
assert_eq!(headers.get(ACCEPT).unwrap(), "text/event-stream");
|
||||
assert_eq!(headers.get("session-id").unwrap(), "segment-123");
|
||||
assert_eq!(headers.get("thread-id").unwrap(), "segment-123");
|
||||
assert_eq!(headers.get("session_id").unwrap(), "segment-123");
|
||||
assert_eq!(headers.get("x-client-request-id").unwrap(), "segment-123");
|
||||
assert_eq!(headers.get(CONTENT_ENCODING).unwrap(), "zstd");
|
||||
|
||||
let diagnostics = request_header_diagnostics(&headers);
|
||||
assert_eq!(diagnostics["content_type"], "application/json");
|
||||
assert_eq!(diagnostics["content_encoding"], "zstd");
|
||||
assert_eq!(diagnostics["accept"], "text/event-stream");
|
||||
assert!(diagnostics["session_id_present"].as_bool().unwrap());
|
||||
assert!(diagnostics["thread_id_present"].as_bool().unwrap());
|
||||
assert!(diagnostics["legacy_session_id_present"].as_bool().unwrap());
|
||||
assert!(
|
||||
diagnostics["x_client_request_id_present"]
|
||||
.as_bool()
|
||||
.unwrap()
|
||||
);
|
||||
assert!(diagnostics["chatgpt_account_id_present"].as_bool().unwrap());
|
||||
|
||||
let RequestBody::CompressedJson {
|
||||
bytes: compressed,
|
||||
raw_json_bytes,
|
||||
|
|
@ -850,6 +894,8 @@ mod tests {
|
|||
let encoded = transport.encode_request_body(&body, &mut headers).unwrap();
|
||||
|
||||
assert_eq!(headers.get(ACCEPT).unwrap(), "text/event-stream");
|
||||
assert!(headers.get("session-id").is_none());
|
||||
assert!(headers.get("thread-id").is_none());
|
||||
assert!(headers.get("session_id").is_none());
|
||||
assert!(headers.get("x-client-request-id").is_none());
|
||||
assert!(headers.get(CONTENT_ENCODING).is_none());
|
||||
|
|
|
|||
|
|
@ -235,9 +235,16 @@ impl InFlightInner {
|
|||
self.remove_first_text_matching(&text);
|
||||
}
|
||||
}
|
||||
LoggedItem::Reasoning { text, .. } => {
|
||||
LoggedItem::Reasoning { text, summary, .. } => {
|
||||
if !text.is_empty() {
|
||||
self.remove_first_thinking_matching(text);
|
||||
}
|
||||
for summary_text in summary {
|
||||
if !summary_text.is_empty() {
|
||||
self.remove_first_thinking_matching(summary_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
LoggedItem::ToolCall { call_id, .. } => {
|
||||
self.remove_tool_call(call_id);
|
||||
}
|
||||
|
|
@ -474,4 +481,29 @@ mod tests {
|
|||
let guard = in_flight.snapshot_guard();
|
||||
assert!(snapshot_from_guard(&guard).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn committed_reasoning_summary_clears_matching_in_flight_thinking_blocks() {
|
||||
let (event_tx, _) = broadcast::channel(16);
|
||||
let in_flight = InFlightEvents::new(event_tx);
|
||||
let first = in_flight.thinking_start();
|
||||
in_flight.thinking_delta(first, "summary A".into());
|
||||
in_flight.thinking_done(first, "".into());
|
||||
let second = in_flight.thinking_start();
|
||||
in_flight.thinking_delta(second, "summary B".into());
|
||||
in_flight.thinking_done(second, "".into());
|
||||
|
||||
in_flight.clear_for_committed_item_then(
|
||||
&LoggedItem::Reasoning {
|
||||
text: String::new(),
|
||||
summary: vec!["summary A".into(), "summary B".into()],
|
||||
encrypted_content: Some("opaque".into()),
|
||||
signature: None,
|
||||
},
|
||||
|| (),
|
||||
);
|
||||
|
||||
let guard = in_flight.snapshot_guard();
|
||||
assert!(snapshot_from_guard(&guard).is_empty());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,6 +264,7 @@ fn init(workspace: &Path) -> Result<TicketCliOutput, TicketCliError> {
|
|||
fs::create_dir_all(&yoi_dir)?;
|
||||
let tickets_dir = workspace.join(DEFAULT_TICKET_BACKEND_RELATIVE_PATH);
|
||||
fs::create_dir_all(&tickets_dir)?;
|
||||
fs::write(tickets_dir.join(".gitkeep"), b"")?;
|
||||
|
||||
let mut file = fs::OpenOptions::new()
|
||||
.write(true)
|
||||
|
|
@ -1117,6 +1118,7 @@ mod tests {
|
|||
);
|
||||
assert!(initialized.stdout.contains("ensured\t.yoi/tickets"));
|
||||
assert!(temp.path().join(".yoi/tickets").exists());
|
||||
assert!(temp.path().join(".yoi/tickets/.gitkeep").exists());
|
||||
|
||||
let config = fs::read_to_string(temp.path().join(".yoi/ticket.config.toml")).unwrap();
|
||||
assert!(config.contains("[backend]\n"));
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user