khive_mcp/tools/request.rs
1//! Parameter type for the single `request` MCP tool.
2
3use rmcp::schemars;
4use serde::{Deserialize, Serialize};
5
6/// Input for `request` — a DSL string (function-call or JSON form) plus
7/// optional presentation controls (`presentation` and `presentation_per_op`).
8#[derive(Debug, Default, Serialize, Deserialize, schemars::JsonSchema)]
9pub struct RequestParams {
10 /// One or more operations as a function-call DSL or JSON-form string.
11 ///
12 /// Examples:
13 /// - `gtd.next()`
14 /// - `gtd.assign(title="ship", priority="p1")`
15 /// - `create(kind="entity", name="A") | link(source_id=$prev.id, target_id="b", relation="extends")`
16 /// - `[create(kind="entity", entity_kind="concept", name="A"), create(kind="entity", entity_kind="concept", name="B")]`
17 /// - `[{"tool":"gtd.next","args":{}}, {"tool":"gtd.complete","args":{"id":"abc"}}]`
18 ///
19 /// Max 100 operations per batch.
20 #[schemars(
21 description = "Function-call DSL or JSON-form batch. See request tool description."
22 )]
23 pub ops: String,
24
25 /// Presentation mode for the response.
26 ///
27 /// - `"agent"` (default): token-efficient — short UUIDs, compact timestamps,
28 /// empty fields dropped.
29 /// - `"verbose"`: full canonical shape, no transformation.
30 /// - `"human"`: delegated to CLI layer (same as verbose at runtime level).
31 ///
32 /// When omitted, defaults to `"agent"`.
33 #[serde(default)]
34 #[schemars(description = "Presentation mode: \"agent\" (default), \"verbose\", or \"human\"")]
35 pub presentation: Option<String>,
36
37 /// Per-operation presentation overrides.
38 ///
39 /// When provided, entries override `presentation` per op by index.
40 /// `null` entries fall back to the batch-level `presentation`.
41 ///
42 /// When omitted, all ops use `presentation`.
43 #[serde(default)]
44 #[schemars(description = "Per-op presentation mode override (optional)")]
45 pub presentation_per_op: Option<Vec<Option<String>>>,
46
47 /// File path for result sink.
48 ///
49 /// When set, the full results are written as JSONL to this path and the
50 /// caller receives a self-describing manifest instead of the raw results:
51 /// `{path, rows, per_column_null_counts, schema_fingerprint, checksum}`.
52 ///
53 /// The manifest lets agents detect bulk-export corruption (e.g. 10 000 null
54 /// rows) in one call rather than after a downstream judgment fleet has graded
55 /// blind. Parent directories are created if absent.
56 ///
57 /// The resolved destination MUST stay within the allowed export root
58 /// (default `~/.khive/exports`, overridable via `KHIVE_SAVE_TO_ROOT`).
59 /// Relative paths are joined under the root; absolute paths are accepted
60 /// only if they resolve inside it. Paths containing `..` traversal
61 /// components and symlinked destinations are rejected.
62 ///
63 /// When omitted, results are returned inline (default behaviour).
64 #[serde(default)]
65 #[schemars(
66 description = "File path to sink results as JSONL (returns manifest, not raw results)"
67 )]
68 pub save_to: Option<String>,
69
70 /// Output serialization format for all ops in this request (ADR-078).
71 ///
72 /// - `"json"` (default): compact, lossless JSON.
73 /// - `"auto"`: shape-aware — markdown table for homogeneous record arrays,
74 /// flat key-value block for single records, compact-JSON fallback.
75 /// - `"table"`: force markdown-table renderer regardless of shape.
76 ///
77 /// Overrides `KHIVE_OUTPUT_FORMAT` and the TOML `default_output_format`.
78 /// When omitted, the server's resolved default (env → toml → builtin `json`) is used.
79 #[serde(default)]
80 #[schemars(description = "Output format: \"json\" (default), \"auto\", or \"table\"")]
81 pub format: Option<String>,
82
83 /// Per-operation output format overrides (ADR-078).
84 ///
85 /// When provided, entries override `format` per op by index.
86 /// `null` entries fall back to the batch-level `format`.
87 ///
88 /// When omitted, all ops use `format`.
89 #[serde(default)]
90 #[schemars(description = "Per-op output format override (optional)")]
91 pub format_per_op: Option<Vec<Option<String>>>,
92
93 /// Caller-supplied correlation id (khive#948), forwarded unchanged onto
94 /// the daemon request frame and echoed back on the response so a
95 /// benchmark harness can join its own pre-send sample to the server-side
96 /// audit row for this request. Purely a correlation label — it never
97 /// changes how a request is dispatched. When omitted, the request
98 /// carries no id and its audit row has no `request_id` key.
99 #[serde(default)]
100 #[schemars(
101 description = "Caller-supplied correlation id, echoed back and stamped into the audit event (optional)"
102 )]
103 pub request_id: Option<u64>,
104}