From 148d7fc2846599b7f435eba789509452bf1c8782 Mon Sep 17 00:00:00 2001 From: Claude Lin & Lay Date: Sun, 23 Aug 2026 00:07:05 +0900 Subject: [PATCH 1/2] feat(sidecar): put turn-taking into the room manners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 宛先なしの問いに二人の参加者が同内容を二重に返した。Master が口頭で「片方が しゃべった時は順番を待ってその会話を見てから話し始める」と伝えたところ挙動は 成立したため、足りていないのは能力ではなく部屋の規律である。口頭の補いを `instructions` へ移す。 - 「部屋の作法」に 2 項追加。先に誰かが答えていたらその発言を読んでから決める こと、送信直前に届いている発言をもう一度見て、既に言われていたら送らずに 足りないことだけ足すこと。全体宛の問いに全員が答える必要はない、を前者に 添える。 - 沈黙の許可としてではなく順番として書く。宛先の節が扱うのは誰に向いた発言かで あり、「答えなくてよい」だけを独立で渡すと全体宛に誰も答えない状態を招く。 - 覗けないものは書かない。参加者は床の状態を見られず、部屋のツールは `say_to_room` 一本である。書けるのは届いた発言までであり、同時に書き始めた 二人は取りこぼす。その範囲は #47。 - 往復ハーネスが 3 つの記述の存在を検査する。 protocol もツール一覧も変えていない。 #49 Co-Authored-By: Claude Opus 5 --- sidecar/src/index.ts | 5 +++++ sidecar/test/round-trip.test.mjs | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/sidecar/src/index.ts b/sidecar/src/index.ts index a919a04..b7dbb4f 100644 --- a/sidecar/src/index.ts +++ b/sidecar/src/index.ts @@ -129,6 +129,11 @@ const INSTRUCTIONS = [ "- 一度の発言は簡潔に。長い説明が必要なときは、まず要点だけ返してください。", "- 他の参加者の発言を、自分の文脈として取り込まないでください。それぞれが", " 自分の文脈から同じ会話に参加しています。", + "- 先に誰かが答えていたら、その発言を読んでから自分の発言を決めてください。", + " 全体宛の問いに、全員が答える必要はありません。", + "- 送る直前に、届いている発言をもう一度見てください。組み立てている間にも", + " 発言は届きます。言おうとしていたことが既に言われていたら送らず、", + " 足りないことがあるときだけ足してください。", ].join("\n"); const mcp = new Server( diff --git a/sidecar/test/round-trip.test.mjs b/sidecar/test/round-trip.test.mjs index 3ea2815..8e2ae0b 100644 --- a/sidecar/test/round-trip.test.mjs +++ b/sidecar/test/round-trip.test.mjs @@ -177,6 +177,26 @@ test("a room post reaches the channel, and say_to_room reaches the room", async /人間と AI を区別しません/, "instructions must state that participants are not split into human and AI", ); + // Turn-taking. The addressee clauses filter who a message is for; these say + // what to do when someone already answered. Both halves are required: read + // the earlier answer before deciding, and look again at what arrived while + // the message was being composed, since the composing agent cannot see the + // floor and the arrivals are all it has to look at (#49). + assert.match( + init.result.instructions ?? "", + /先に誰かが答えていたら、その発言を読んでから自分の発言を決めて/, + "instructions must tell the agent to read an earlier answer before deciding its own", + ); + assert.match( + init.result.instructions ?? "", + /送る直前に、届いている発言をもう一度見て/, + "instructions must tell the agent to re-read what arrived just before sending", + ); + assert.match( + init.result.instructions ?? "", + /全員が答える必要はありません/, + "instructions must state that a room-wide question needs no answer from everyone", + ); notify("notifications/initialized", {}); From be277335129f443ff10b0fe6de668eca5e0420fd Mon Sep 17 00:00:00 2001 From: Claude Lin & Lay Date: Sun, 23 Aug 2026 00:08:49 +0900 Subject: [PATCH 2/2] docs: record turn-taking as a room manner, not a protocol change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 実装に合わせて要求仕様の「部屋の作法」節を更新する。 - 作法 3 項追加。順番の中身(先に届いた答えを読んでから決める / 送信直前の 読み直し / 全体宛に全員が答える必要はない)と、それを口頭で補えば成立した 2026-08-22 の実測。 - 順番と沈黙を別軸として書く理由。宛先の節は誰に向いた発言かを扱っており、 「答えなくてよい」だけを独立で渡すと全体宛に誰も答えない状態を招く。 - 「見よ」と言える範囲が届いた発言までである理由。床の状態は覗けず、ツールは 書き込み専用の `say_to_room` 一本である。同時に書き始めた二人の取りこぼしは #47 であり、この作法を入れてなお痛むと観測されてから判断する。 - 実装済みへ 1 行。`instructions` のみの変更である旨を含む。 #49 Co-Authored-By: Claude Opus 5 --- docs/0-requirements.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/0-requirements.md b/docs/0-requirements.md index 8ad1c80..6861a05 100644 --- a/docs/0-requirements.md +++ b/docs/0-requirements.md @@ -172,6 +172,9 @@ push の形(参照実装 `Liplus-Project/github-webhook-mcp` `local-mcp/src/in - 宛先は任意である。必須にすると人間の入力費用が上がる。 - 宛先の相手は人間でもセッションでもよく、指定の仕方は変わらない。画面の宛先の選択肢は「自分以外の参加者」であり、人間も同じ列に並ぶ。 - 届いた発言はすべて他の参加者のものである。自分の発言は戻らないため、エージェントは自分を認識する必要がない。 +- 先に誰かが答えていたら、その発言を読んでから自分の発言を決める。送る直前にも届いている発言をもう一度見て、言おうとしていたことが既に言われていたら送らず、足りないことがあるときだけ足す。全体宛の問いに全員が答える必要はない。宛先なしの問いに二人の参加者が同内容を二重に返した実測(2026-08-22)に対し、口頭で「順番を待ってその会話を見てから話し始める」と伝えたところ挙動は成立した。足りていなかったのは参加者の能力ではなく、これが部屋の規律に書かれていないことである。 +- 順番は沈黙とは別軸である。宛先の節が扱うのは誰に向いた発言かであり、こちらは先に答えが出たときにどうするかである。混ぜて「答えなくてよい」だけを渡すと、全体宛の発言に誰も答えない状態を招く。書き方は「黙れ」ではなく「見てから決める」に寄せる。 +- 作法が「見よ」と言えるのは届いた発言までである。参加者は床の状態——誰が今組み立てているか——を覗けず、部屋のツールは書き込み専用の `say_to_room` 一本である。届いた発言なら、組み立て中に届いた分も channel が随時運んでいるため送信直前に読み直せる。同時に書き始めた二人は取りこぼす。その残りは状態を出す側と床を読む側の二点セットであり、この作法を入れてなお同時発火が痛むと観測されてから判断する(#47)。規律の無い状態での観測を根拠に protocol を変えない。 ### MCP サーバの実装方式 @@ -200,6 +203,7 @@ liplus-desktop の `stream_parser.rs` および `spawn_stream_pty` / `spawn_stre - サーバの `.mcp.json` 登録(既存内容はマージして保持、登録鍵は参加者ごと、前回起動のエントリは掃除)と、成立条件を満たす CLI 起動フラグの適用 - 部屋の作法(`instructions`)の初版 - 発言の宛先(部屋 → `post.to` → channel の `meta.to`、送信は `say_to_room` の `to`)と、それを判定材料として名指しする `instructions` +- 順番の作法(先に届いた答えを読んでから決める、送信直前の読み直し。`instructions` のみで、protocol もツールも増やしていない) - 参加者モデル(統一 `post` フレーム、発言者以外の全参加者への配送、接続同一性による自分の発言の抑止と名簿の同一性、人間を含む名簿) - 参加の時点の名乗り(起動ごとに選ぶ名前と色。人間側の名前欄と同じ形、`localStorage` に保持) - 宣言色(`hello` の `hue` / `room_join` の `hue`。宣言 > 自分の accent > 名前からの導出)