1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//! `ToolReply` — typed wire shape for the JSON-RPC `result`
//! field returned by tool handlers.
use serde_json::{json, Value};
/// JSON value returned by a tool handler. Wraps `serde_json::Value`
/// with ergonomic constructors for the most common shapes.
///
/// Wire-shape struct — caller-built; field additions are
/// deliberate semver-major. Intentionally **not**
/// `#[non_exhaustive]`.
#[derive(Debug, Clone, PartialEq)]
pub struct ToolReply {
/// The JSON value the SDK serialises into the JSON-RPC `result`
/// field. Public so handlers can build custom shapes when the
/// constructors below don't fit.
pub value: Value,
}
impl ToolReply {
/// Plain text reply: `{ "ok": true, "text": "..." }`.
pub fn ok(text: impl Into<String>) -> Self {
Self {
value: json!({ "ok": true, "text": text.into() }),
}
}
/// Arbitrary JSON reply — caller's `value` is returned as-is.
pub fn ok_json(value: Value) -> Self {
Self { value }
}
/// Empty reply: `null`. Useful for fire-and-forget tools.
pub fn empty() -> Self {
Self { value: Value::Null }
}
/// Borrow the inner `serde_json::Value`.
pub fn as_value(&self) -> &Value {
&self.value
}
/// Consume into the inner `serde_json::Value`.
pub fn into_value(self) -> Value {
self.value
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ok_constructs_ok_text_shape() {
let r = ToolReply::ok("hello");
assert_eq!(r.value["ok"], true);
assert_eq!(r.value["text"], "hello");
}
#[test]
fn ok_json_passes_value_through() {
let r = ToolReply::ok_json(json!({"a": 1, "b": "two"}));
assert_eq!(r.value["a"], 1);
assert_eq!(r.value["b"], "two");
}
#[test]
fn empty_returns_null() {
let r = ToolReply::empty();
assert!(r.value.is_null());
}
#[test]
fn as_value_and_into_value_round_trip() {
let r = ToolReply::ok("x");
let snapshot = r.value.clone();
assert_eq!(r.as_value(), &snapshot);
assert_eq!(r.into_value(), snapshot);
}
}