第二篇知道了有什么。现在去调。
结果不是一个值
final ok = await client.callTool('desk.admit', {'count': 1});
回来的不是数字,而是 一份内容列表。可能是文本,可能是图片,也可能有好几项。所以把取值这件事收在一处。
Map<String, dynamic> decode(CallToolResult r) {
final first = r.content.first;
if (first is! TextContent) {
throw StateError('expected text content, got ${first.runtimeType}');
}
return jsonDecode(first.text) as Map<String, dynamic>;
}
去掉 is! TextContent 直接强转,等哪天服务端混进一张图片,它会在 完全不相干的地方 炸。在这里拦住,栈才读得懂。
admit 1 -> {waiting: 2}
拒绝不会以 throw 到来
调一下服务端第三篇里做的那个拒绝。
final refused = await client.callTool('desk.admit', {'count': 99});
final text = (refused.content.first as TextContent).text;
stdout.writeln('admit 99 -> isError=${refused.isError} "$text"');
admit 99 -> isError=true "only 2 waiting"
没有抛异常。 await 正常完成,结果上带着 isError: true,理由在文本里。
不知道这一点,就会写成:
try {
await client.callTool('desk.admit', {'count': 99});
// 走到这儿了,说明成功
} catch (e) {
// 以为拒绝会掉到这里……其实不会
}
拒绝进不了 catch,于是 被当成成功处理。 屏上写着「放进 99 人」,而服务端一个人也没放。