feat(model): add json schema generation support for all model types (#176)
* feat(model): add json schema generation support for all model types This commit adds JSON Schema support for all model types by implementing `schemars::JsonSchema` trait. The feature is gated behind the new `schemars` feature flag. This enables automatic schema generation for API documentation and validation purposes. Added tests to verify schema generation for client and server JSON-RPC messages. * fix(model): add manual json schema implementation for `NumberOrString` This commit adds a manual implementation of `JsonSchema` trait for the `NumberOrString` enum to properly represent its union type nature in JSON Schema. The schema now correctly specifies that the type can be either a number or a string using the `oneOf` validation keyword. * fix(model): skip extensions field in json schema generation The `Extensions` type was incorrectly included in JSON schema generation, which could lead to confusing API documentation. This commit adds `#[schemars(skip)]` attribute to all `extensions` fields in request and notification structs, and removes the manual `JsonSchema` implementation for the `Extensions` type since it's an internal implementation detail that shouldn't be exposed in the schema.
This commit is contained in:
parent
5d92061ece
commit
e9a5ae9901
6 changed files with 2790 additions and 1 deletions
|
|
@ -10,6 +10,7 @@ use super::{
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct Annotations {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub audience: Option<Vec<Role>>,
|
||||
|
|
@ -36,6 +37,7 @@ impl Annotations {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct Annotated<T: AnnotateAble> {
|
||||
#[serde(flatten)]
|
||||
pub raw: T,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ pub type ExperimentalCapabilities = BTreeMap<String, JsonObject>;
|
|||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct PromptsCapability {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub list_changed: Option<bool>,
|
||||
|
|
@ -15,6 +16,7 @@ pub struct PromptsCapability {
|
|||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct ResourcesCapability {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub subscribe: Option<bool>,
|
||||
|
|
@ -24,6 +26,7 @@ pub struct ResourcesCapability {
|
|||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct ToolsCapability {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub list_changed: Option<bool>,
|
||||
|
|
@ -31,6 +34,7 @@ pub struct ToolsCapability {
|
|||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct RootsCapabilities {
|
||||
pub list_changed: Option<bool>,
|
||||
}
|
||||
|
|
@ -46,6 +50,7 @@ pub struct RootsCapabilities {
|
|||
/// .build();
|
||||
/// ```
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct ClientCapabilities {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub experimental: Option<ExperimentalCapabilities>,
|
||||
|
|
@ -70,6 +75,7 @@ pub struct ClientCapabilities {
|
|||
/// ```
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct ServerCapabilities {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub experimental: Option<ExperimentalCapabilities>,
|
||||
|
|
|
|||
|
|
@ -8,12 +8,14 @@ use super::{AnnotateAble, Annotated, resource::ResourceContents};
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct RawTextContent {
|
||||
pub text: String,
|
||||
}
|
||||
pub type TextContent = Annotated<RawTextContent>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct RawImageContent {
|
||||
/// The base64-encoded image
|
||||
pub data: String,
|
||||
|
|
@ -23,6 +25,7 @@ pub struct RawImageContent {
|
|||
pub type ImageContent = Annotated<RawImageContent>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct RawEmbeddedResource {
|
||||
pub resource: ResourceContents,
|
||||
}
|
||||
|
|
@ -39,6 +42,7 @@ impl EmbeddedResource {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct RawAudioContent {
|
||||
pub data: String,
|
||||
pub mime_type: String,
|
||||
|
|
@ -48,6 +52,7 @@ pub type AudioContent = Annotated<RawAudioContent>;
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub enum RawContent {
|
||||
Text(RawTextContent),
|
||||
Image(RawImageContent),
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use super::{
|
|||
/// A prompt that can be used to generate text from a model
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct Prompt {
|
||||
/// The name of the prompt
|
||||
pub name: String,
|
||||
|
|
@ -42,6 +43,7 @@ impl Prompt {
|
|||
|
||||
/// Represents a prompt argument that can be passed to customize the prompt
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct PromptArgument {
|
||||
/// The name of the argument
|
||||
pub name: String,
|
||||
|
|
@ -56,6 +58,7 @@ pub struct PromptArgument {
|
|||
/// Represents the role of a message sender in a prompt conversation
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub enum PromptMessageRole {
|
||||
User,
|
||||
Assistant,
|
||||
|
|
@ -64,6 +67,7 @@ pub enum PromptMessageRole {
|
|||
/// Content types that can be included in prompt messages
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub enum PromptMessageContent {
|
||||
/// Plain text content
|
||||
Text { text: String },
|
||||
|
|
@ -84,6 +88,7 @@ impl PromptMessageContent {
|
|||
|
||||
/// A message in a prompt conversation
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct PromptMessage {
|
||||
/// The role of the message sender
|
||||
pub role: PromptMessageRole,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use super::Annotated;
|
|||
/// Represents a resource in the extension with metadata
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct RawResource {
|
||||
/// URI representing the resource location (e.g., "file:///path/to/file" or "str:///content")
|
||||
pub uri: String,
|
||||
|
|
@ -28,6 +29,7 @@ pub type Resource = Annotated<RawResource>;
|
|||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct RawResourceTemplate {
|
||||
pub uri_template: String,
|
||||
pub name: String,
|
||||
|
|
@ -41,6 +43,7 @@ pub type ResourceTemplate = Annotated<RawResourceTemplate>;
|
|||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub enum ResourceContents {
|
||||
TextResourceContents {
|
||||
uri: String,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use super::JsonObject;
|
|||
/// A tool that can be used by a model.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct Tool {
|
||||
/// The name of the tool
|
||||
pub name: Cow<'static, str>,
|
||||
|
|
@ -33,6 +34,7 @@ pub struct Tool {
|
|||
/// received from untrusted servers.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct ToolAnnotations {
|
||||
/// A human-readable title for the tool.
|
||||
pub title: Option<String>,
|
||||
|
|
|
|||
Loading…
Reference in a new issue