fix: tuiからのPod作成の挙動を修正・開発時にcargo runでpodを起動する経路を実装
This commit is contained in:
parent
14862fbc37
commit
f1d8f42fd5
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -2,3 +2,4 @@
|
|||
.direnv
|
||||
*.local*
|
||||
.env
|
||||
.worktree
|
||||
|
|
|
|||
1
TODO.md
1
TODO.md
|
|
@ -2,6 +2,7 @@
|
|||
- [ ] 内部 Worker / 内部 Pod の Workflow 化 → [tickets/internal-worker-workflow.md](tickets/internal-worker-workflow.md)
|
||||
- [ ] Agent Skills を Workflow として ingest → [tickets/agent-skills.md](tickets/agent-skills.md)
|
||||
- [ ] パーミッション: パターンベースのツール実行制御 → [tickets/permission-extension-point.md](tickets/permission-extension-point.md)
|
||||
- [ ] Resume 時の Scope claim の改善 → [tickets/resume-scope-claim.md](tickets/resume-scope-claim.md)
|
||||
- [ ] Pod CLI: マニフェスト関連フラグの整理 → [tickets/pod-cli-manifest-flags.md](tickets/pod-cli-manifest-flags.md)
|
||||
- [ ] OpenAI Responses: sampling パラメータの取り扱い → [tickets/responses-sampling-params.md](tickets/responses-sampling-params.md)
|
||||
- [ ] llm-worker のエラー耐性
|
||||
|
|
|
|||
|
|
@ -268,12 +268,11 @@ async fn wait_for_ready(
|
|||
form: &mut Form,
|
||||
overlay_toml: &str,
|
||||
) -> Result<SpawnReady, SpawnError> {
|
||||
let (pod_bin, pod_args) = resolve_pod_command();
|
||||
let pod_bin = resolve_pod_command();
|
||||
let cwd = std::env::current_dir().map_err(SpawnError::Io)?;
|
||||
|
||||
let mut command = Command::new(&pod_bin);
|
||||
command
|
||||
.args(&pod_args)
|
||||
.arg("--overlay")
|
||||
.arg(overlay_toml)
|
||||
.current_dir(&cwd)
|
||||
|
|
@ -375,28 +374,21 @@ fn build_overlay_toml(form: &Form) -> String {
|
|||
toml::to_string(&toml::Value::Table(root)).expect("overlay serialisation cannot fail")
|
||||
}
|
||||
|
||||
/// Resolves the program (and any leading args) used to launch a child Pod.
|
||||
/// Resolves the binary used to launch a child Pod. Must point at a
|
||||
/// `pod`-compatible executable — the parent reads the child's stderr
|
||||
/// directly looking for `INSOMNIA-READY`, so any wrapper that emits
|
||||
/// extra lines on stderr will pollute that handshake.
|
||||
///
|
||||
/// `INSOMNIA_POD_COMMAND` is split on whitespace so devshells can point it
|
||||
/// at e.g. `cargo run -p pod --quiet --`; the first token is the program
|
||||
/// and the rest are prepended before `--overlay` and friends.
|
||||
fn resolve_pod_command() -> (PathBuf, Vec<String>) {
|
||||
/// `INSOMNIA_POD_COMMAND` overrides the lookup (used by tests to inject
|
||||
/// a mock binary). Otherwise we defer to `PATH` — missing binary
|
||||
/// surfaces as the spawn `io::Error`.
|
||||
fn resolve_pod_command() -> PathBuf {
|
||||
if let Ok(cmd) = std::env::var("INSOMNIA_POD_COMMAND") {
|
||||
let mut tokens = cmd.split_whitespace();
|
||||
if let Some(program) = tokens.next() {
|
||||
let args = tokens.map(str::to_owned).collect();
|
||||
return (PathBuf::from(program), args);
|
||||
if !cmd.is_empty() {
|
||||
return PathBuf::from(cmd);
|
||||
}
|
||||
}
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
if let Some(dir) = exe.parent() {
|
||||
let candidate = dir.join("pod");
|
||||
if candidate.is_file() {
|
||||
return (candidate, Vec::new());
|
||||
}
|
||||
}
|
||||
}
|
||||
(PathBuf::from("pod"), Vec::new())
|
||||
PathBuf::from("pod")
|
||||
}
|
||||
|
||||
struct StderrTail {
|
||||
|
|
|
|||
21
devshell.nix
21
devshell.nix
|
|
@ -1,4 +1,23 @@
|
|||
{ pkgs }:
|
||||
let
|
||||
# Dev-only wrapper. tui の spawn 経路は `pod` バイナリを直に exec し、
|
||||
# stderr の `INSOMNIA-READY` 行で握手するので、cargo の進捗や rustc の
|
||||
# warning が混ざると tail に余計な行が積もり本当のエラーが押し出される。
|
||||
# ここで一度ビルドを切り離し、成功時はビルド出力を一切捨てて素のバイナリ
|
||||
# を exec、失敗時のみ build log を stderr に流して exit する。
|
||||
pod-dev = pkgs.writeShellScriptBin "pod" ''
|
||||
set -u
|
||||
buildlog=$(mktemp)
|
||||
trap 'rm -f "$buildlog"' EXIT
|
||||
if ! cargo build --quiet -p pod 2>"$buildlog"; then
|
||||
cat "$buildlog" >&2
|
||||
exit 1
|
||||
fi
|
||||
manifest=$(cargo locate-project --workspace --message-format plain 2>/dev/null)
|
||||
target_dir=''${CARGO_TARGET_DIR:-$(dirname "$manifest")/target}
|
||||
exec "$target_dir/debug/pod" "$@"
|
||||
'';
|
||||
in
|
||||
pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
nixfmt
|
||||
|
|
@ -6,12 +25,12 @@ pkgs.mkShell {
|
|||
git
|
||||
rustc
|
||||
cargo
|
||||
pod-dev
|
||||
];
|
||||
buildInputs = with pkgs; [
|
||||
pkg-config
|
||||
openssl
|
||||
];
|
||||
INSOMNIA_POD_COMMAND = "cargo run -p pod --quiet --";
|
||||
shellHook = ''
|
||||
echo "dev-shell-loaded"
|
||||
'';
|
||||
|
|
|
|||
40
tickets/resume-scope-claim.md
Normal file
40
tickets/resume-scope-claim.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Resume 時の Scope Claim の改善
|
||||
|
||||
## 背景
|
||||
|
||||
`tickets/dynamic-scope.md` で in-process Scope の縮小(SpawnPod による委譲時の Write revoke)と pod-registry 上の delegation 記録が揃った。これにより「セッション中に scope が縮む」状態を Pod / registry の双方が一貫して表現できる。
|
||||
|
||||
一方で `tui -r` 経由の resume は、`crates/tui/src/spawn.rs` の `build_overlay_toml` を通じて fresh spawn と同じロジックで overlay を合成する。manifest cascade に scope 宣言が無い場合、cwd 直下に `write` 再帰の rule を毎回付ける挙動。
|
||||
|
||||
このため次のような衝突が起きる:
|
||||
|
||||
- セッション S が稼働中に SpawnPod で子 C を作り、cwd 配下のサブパスを委譲した
|
||||
- 親が exit、子 C は registry 上にエントリが残存(あるいはまだ稼働中)
|
||||
- ユーザーが S を resume しようとすると、新しい Pod が cwd 全体に `write` を claim → 委譲された部分と overlap して registry が拒否
|
||||
|
||||
resume の意図は「過去のセッションの続きを取る」であって「過去の effective scope より広い範囲を新たに掴み直す」ではない。現状は後者になっており、過去に手放した scope を resume が勝手に取り戻そうとする形になっている。
|
||||
|
||||
## ゴール
|
||||
|
||||
セッション resume 時に claim する scope が、当該セッションが最後に持っていた effective scope に揃う。委譲済み・他 Pod が保持中の部分は claim 対象から外れ、resume された Pod は当時と同じ範囲だけで動作する。
|
||||
|
||||
## 要件
|
||||
|
||||
- resume 時の overlay 合成は cwd 盲信ではなく、当該セッションが過去に持っていた scope を反映する。情報源は session log / registry / その他のいずれでも良いが、何らかの永続情報から復元できること
|
||||
- 過去の scope 情報が取得できないセッション(旧形式 / 破損)は、明示的なエラーで止めるか、ユーザーに確認させてから fresh claim にフォールバックする(黙って広げない)
|
||||
- claim 試行が registry の既存 allocation と衝突した場合、エラーメッセージで衝突相手の Pod 名 と target rule の双方が伝わる(現状は Pod 名のみ)
|
||||
- 委譲済みエントリ(`delegated_from` を持つ allocation)が同じセッションの委譲チェーンに属する場合、resume はその範囲を claim せずに進行する
|
||||
|
||||
## 完了条件
|
||||
|
||||
- 「親 Pod がセッション中に SpawnPod を実行 → 子に委譲 → 親 exit → 親セッションを resume」のフローが、既存子 allocation を残したまま衝突なしで成功する
|
||||
- 既存の無関係な Pod と衝突するケースは、衝突 rule と相手 Pod 名を含む明確なエラーで失敗する
|
||||
- 単体テスト or 統合テストで上記 2 ケースが検証される
|
||||
- 既存の fresh spawn (resume なし) の挙動には変化なし
|
||||
|
||||
## 範囲外
|
||||
|
||||
- 過去スコープの永続化スキーマを新規導入するかの判断は実装時に決める(session log の既存フィールドで足りるなら追加しない)
|
||||
- 自動的に既存 Pod を kill / reclaim して claim を通す挙動
|
||||
- protocol 経由の外部からの GrantScope / RevokeScope(`tickets/dynamic-scope.md` の範囲外宣言を継承)
|
||||
- registry 側のエラー型の全面再設計(rule 情報を含めるための最小限の拡張のみで足りる想定)
|
||||
Loading…
Reference in New Issue
Block a user