ボタンは名前を呼ぶだけ — 押したときホストがすること
5 分第3回で値が画面に入ってきた。逆向きが残っている。
onTap にコードが無い
{ "type": "button", "label": "Call next", "onTap": { "type": "tool", "tool": "queue.next" } },
{ "type": "button", "label": "Take a ticket", "onTap": { "type": "tool", "tool": "queue.take" } }onTap は { type, tool } だ。「このボタンを押すと queue.next というツールを呼ぶ」までがすべてで、そのツールが何をするかは書いていない。
書けもしない。このファイルはサーバー講座で作ったサーバーが送ってきたもので、実行はそのサーバーで起きる。
受ける側
rt.buildUI(
context: c,
// 名前がここに来る。ホストはこの名前が何なのか知らない。
onToolCall: (tool, params) async => fired.add(tool),
)第1回で空の関数にしておいた場所だ。実アプリなら、ここにクライアント講座3回目の一行が入る。
onToolCall: (tool, params) async {
// 名前は画面から来た。そのまま渡す。
final r = await client.callTool(tool, params);
final state = jsonDecode((r.content.first as TextContent).text)
as Map<String, dynamic>;
state.forEach(rt.stateManager.set);
},tool をそのまま渡す。if (tool == 'queue.next') のような分岐は無い — 入れた瞬間、サーバーがツールを一つ増やすたびにホストを直すことになる。
絵では確かめられない
ここで初めてキャプチャが足りなくなる。step4.png にはボタンが二つ見える。だがそのボタンが 押されたとき何を送るか は見えない。
onTap を丸ごと消しても絵は同じだ。
だからハーネスが押す。
fired.clear();
await tester.tap(find.text('Call next'));
await tester.pump(const Duration(milliseconds: 40));
await tester.tap(find.text('Take a ticket'));
await tester.pump(const Duration(milliseconds: 40));
say('pressed -> the host was asked for: ${fired.join(", ")}');pressed -> the host was asked for: queue.next, queue.takefired は onToolCall が受け取った名前を順に入れたリストだ。この行が run.log に残り、検査がそれを読む。
# ホストがツール名を知っていれば失敗
grep -rq 'queue\.next\|queue\.take' $SRC && \
die "step4: the host knows the tool names"
# 押したとき、画面が求めた名前が来なければ失敗
grep -q 'the host was asked for: queue.next, queue.take' $LOG || \
die "step4: pressing did not send the tool names the screen asked for"二行は揃って初めて意味になる。上だけなら「ホストに名前が無い」までで、下だけなら名前がホストに埋まっていても通る。重ねて初めて 画面が渡した名前がそのまま出て行った になる。
onTap を消して回すと下の行が捕まる。
[5/8] step4 — the button names a tool and stops there
step4: pressing did not send the tool names the screen asked for失敗は画面で処理しない
queue.next が断られたらどうなるか。サーバー講座 第3回のカウンターは、待っている人がいなければ呼ぶのを断る。
断りも結果だ。サーバーが isError と理由を返し、それが他の値と一緒に状態として入ってくる。
{ "type": "text", "text": "{{notice}}", "style": { "fontSize": 15, "color": "#9ca3af" } }step4.json の下のほうにあるこの一行がその場所だ。画面定義にエラー処理の文法は別に無い — 理由も状態の一値でしかない。
レンダー
step4 896 B, 12 lines, type "page" -> step4.png43、その下に 2 waiting、ボタン二つ、その下に灰色で called 43。
自分で回してみる
cd content/sample/course-ui
bash verify.sh
cat captures/run.log持ち帰るもの
onTap: { type: 'tool', tool: ... }— 画面は名前までしか知らないonToolCallはそのまま渡す — 名前で分岐しない- 押してみる検査 — キャプチャが見られないものはログに残す
次回
最後。画面一つが違う形になること — そして数を知らない一覧。
サンプルを実行する
makemind-academy/course_ui/git clone https://github.com/makemind-academy/course_ui cd course_ui bash verify.sh