2 編目の道具は引数を取らなかった。今回は取る。そして 受け取ったものを信じない。
スキーマ
inputSchema: const {
'type': 'object',
'properties': {
'count': {'type': 'integer', 'description': 'How many to admit, 1 or more'},
},
'required': ['count'],
},
これを付ければ呼ぶ側が何を送ればよいか分かる。モデルならここに合わせて引数を作る。
ところがスキーマは保証ではない
'type': 'integer' と書いたから整数が来るのではない。スキーマは 呼ぶ側への案内 であり、その側が守らないかもしれないし守れないかもしれない。
だからハンドラがもう一度見る。
handler: (args) async {
final n = args['count'];
// The schema says integer; the caller may still send anything.
if (n is! int || n < 1) {
return CallToolResult(
content: [TextContent(text: 'desk.admit: count must be 1 or more')],
isError: true,
);
}
// And the desk cannot admit people who are not there.
if (n > waiting) {
return CallToolResult(
content: [TextContent(text: 'only $waiting waiting')],
isError: true,
);
}
waiting -= n;
return CallToolResult(
content: [TextContent(text: jsonEncode({'waiting': waiting}))],
);
},
二つの拒否は性質が違う
検査が二つあり、理由が違う。
n < 1 — 値そのものが成り立たない。0 人を入れよは常に誤りだ。入力の問題。
n > waiting — 値は正常だが今の状態では不可能だ。3 人待ちで 99 人は入れられない。だが 100 人待ちなら 99 は正常だ。状態の問題。
これを分けねばならない理由はメッセージにある。
count must be 1 or more ← 送り直しても同じく誤り
only 3 waiting ← 3 以下で送ればよい
isError: true でひとまとめにすれば、呼ぶ側は再試行すべきか諦めるべきか分からない。