Spec conformance: meta support and spec updates (#415)
* feat: add _meta to content blocks and embedded resources; update schemas * feat: set default protocol version; add _meta to content blocks/resources; update schemas * chore: format content.rs via rustfmt * chore(protocol): keep LATEST at 2025-03-26 per review until full 2025-06-18 compliance * feat(prompt): add constructors with optional meta for image and resource - Keep text helper; meta is currently ignored for text until schema supports it. * refactor(prompt): simplify constructors so meta is optional; remove duplicate non-meta variants * fix: modify code comment about version * refactor(prompt): rename meta parameters in new_resource function for clarity
This commit is contained in:
parent
b514bc4358
commit
4eb413b6c6
9 changed files with 3427 additions and 47 deletions
|
|
@ -149,6 +149,7 @@ impl ProtocolVersion {
|
||||||
pub const V_2025_06_18: Self = Self(Cow::Borrowed("2025-06-18"));
|
pub const V_2025_06_18: Self = Self(Cow::Borrowed("2025-06-18"));
|
||||||
pub const V_2025_03_26: Self = Self(Cow::Borrowed("2025-03-26"));
|
pub const V_2025_03_26: Self = Self(Cow::Borrowed("2025-03-26"));
|
||||||
pub const V_2024_11_05: Self = Self(Cow::Borrowed("2024-11-05"));
|
pub const V_2024_11_05: Self = Self(Cow::Borrowed("2024-11-05"));
|
||||||
|
// Keep LATEST at 2025-03-26 until full 2025-06-18 compliance and automated testing are in place.
|
||||||
pub const LATEST: Self = Self::V_2025_03_26;
|
pub const LATEST: Self = Self::V_2025_03_26;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ pub struct Annotations {
|
||||||
pub audience: Option<Vec<Role>>,
|
pub audience: Option<Vec<Role>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub priority: Option<f32>,
|
pub priority: Option<f32>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none", rename = "lastModified")]
|
||||||
pub timestamp: Option<DateTime<Utc>>,
|
pub last_modified: Option<DateTime<Utc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Annotations {
|
impl Annotations {
|
||||||
|
|
@ -30,7 +30,7 @@ impl Annotations {
|
||||||
);
|
);
|
||||||
Annotations {
|
Annotations {
|
||||||
priority: Some(priority),
|
priority: Some(priority),
|
||||||
timestamp: Some(timestamp),
|
last_modified: Some(timestamp),
|
||||||
audience: None,
|
audience: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +72,7 @@ impl<T: AnnotateAble> Annotated<T> {
|
||||||
self.annotations.as_ref().and_then(|a| a.priority)
|
self.annotations.as_ref().and_then(|a| a.priority)
|
||||||
}
|
}
|
||||||
pub fn timestamp(&self) -> Option<DateTime<Utc>> {
|
pub fn timestamp(&self) -> Option<DateTime<Utc>> {
|
||||||
self.annotations.as_ref().and_then(|a| a.timestamp)
|
self.annotations.as_ref().and_then(|a| a.last_modified)
|
||||||
}
|
}
|
||||||
pub fn with_audience(self, audience: Vec<Role>) -> Annotated<T>
|
pub fn with_audience(self, audience: Vec<Role>) -> Annotated<T>
|
||||||
where
|
where
|
||||||
|
|
@ -92,7 +92,7 @@ impl<T: AnnotateAble> Annotated<T> {
|
||||||
annotations: Some(Annotations {
|
annotations: Some(Annotations {
|
||||||
audience: Some(audience),
|
audience: Some(audience),
|
||||||
priority: None,
|
priority: None,
|
||||||
timestamp: None,
|
last_modified: None,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +114,7 @@ impl<T: AnnotateAble> Annotated<T> {
|
||||||
raw: self.raw,
|
raw: self.raw,
|
||||||
annotations: Some(Annotations {
|
annotations: Some(Annotations {
|
||||||
priority: Some(priority),
|
priority: Some(priority),
|
||||||
timestamp: None,
|
last_modified: None,
|
||||||
audience: None,
|
audience: None,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +128,7 @@ impl<T: AnnotateAble> Annotated<T> {
|
||||||
Annotated {
|
Annotated {
|
||||||
raw: self.raw,
|
raw: self.raw,
|
||||||
annotations: Some(Annotations {
|
annotations: Some(Annotations {
|
||||||
timestamp: Some(timestamp),
|
last_modified: Some(timestamp),
|
||||||
..annotations
|
..annotations
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +136,7 @@ impl<T: AnnotateAble> Annotated<T> {
|
||||||
Annotated {
|
Annotated {
|
||||||
raw: self.raw,
|
raw: self.raw,
|
||||||
annotations: Some(Annotations {
|
annotations: Some(Annotations {
|
||||||
timestamp: Some(timestamp),
|
last_modified: Some(timestamp),
|
||||||
priority: None,
|
priority: None,
|
||||||
audience: None,
|
audience: None,
|
||||||
}),
|
}),
|
||||||
|
|
@ -211,7 +211,7 @@ pub trait AnnotateAble: sealed::Sealed {
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.annotate(Annotations {
|
self.annotate(Annotations {
|
||||||
timestamp: Some(timestamp),
|
last_modified: Some(timestamp),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ use super::{AnnotateAble, Annotated, resource::ResourceContents};
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
pub struct RawTextContent {
|
pub struct RawTextContent {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
|
/// Optional protocol-level metadata for this content block
|
||||||
|
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
|
||||||
|
pub meta: Option<super::Meta>,
|
||||||
}
|
}
|
||||||
pub type TextContent = Annotated<RawTextContent>;
|
pub type TextContent = Annotated<RawTextContent>;
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
|
@ -20,6 +23,9 @@ pub struct RawImageContent {
|
||||||
/// The base64-encoded image
|
/// The base64-encoded image
|
||||||
pub data: String,
|
pub data: String,
|
||||||
pub mime_type: String,
|
pub mime_type: String,
|
||||||
|
/// Optional protocol-level metadata for this content block
|
||||||
|
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
|
||||||
|
pub meta: Option<super::Meta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ImageContent = Annotated<RawImageContent>;
|
pub type ImageContent = Annotated<RawImageContent>;
|
||||||
|
|
@ -27,6 +33,7 @@ pub type ImageContent = Annotated<RawImageContent>;
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
pub struct RawEmbeddedResource {
|
pub struct RawEmbeddedResource {
|
||||||
|
/// Optional protocol-level metadata for this content block
|
||||||
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
|
||||||
pub meta: Option<super::Meta>,
|
pub meta: Option<super::Meta>,
|
||||||
pub resource: ResourceContents,
|
pub resource: ResourceContents,
|
||||||
|
|
@ -79,13 +86,17 @@ impl RawContent {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text<S: Into<String>>(text: S) -> Self {
|
pub fn text<S: Into<String>>(text: S) -> Self {
|
||||||
RawContent::Text(RawTextContent { text: text.into() })
|
RawContent::Text(RawTextContent {
|
||||||
|
text: text.into(),
|
||||||
|
meta: None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn image<S: Into<String>, T: Into<String>>(data: S, mime_type: T) -> Self {
|
pub fn image<S: Into<String>, T: Into<String>>(data: S, mime_type: T) -> Self {
|
||||||
RawContent::Image(RawImageContent {
|
RawContent::Image(RawImageContent {
|
||||||
data: data.into(),
|
data: data.into(),
|
||||||
mime_type: mime_type.into(),
|
mime_type: mime_type.into(),
|
||||||
|
meta: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,6 +220,7 @@ mod tests {
|
||||||
let image_content = RawImageContent {
|
let image_content = RawImageContent {
|
||||||
data: "base64data".to_string(),
|
data: "base64data".to_string(),
|
||||||
mime_type: "image/png".to_string(),
|
mime_type: "image/png".to_string(),
|
||||||
|
meta: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = serde_json::to_string(&image_content).unwrap();
|
let json = serde_json::to_string(&image_content).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -114,49 +114,59 @@ impl PromptMessage {
|
||||||
content: PromptMessageContent::Text { text: text.into() },
|
content: PromptMessageContent::Text { text: text.into() },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new image message. `meta` and `annotations` are optional.
|
||||||
#[cfg(feature = "base64")]
|
#[cfg(feature = "base64")]
|
||||||
pub fn new_image(
|
pub fn new_image(
|
||||||
role: PromptMessageRole,
|
role: PromptMessageRole,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
mime_type: &str,
|
mime_type: &str,
|
||||||
|
meta: Option<crate::model::Meta>,
|
||||||
annotations: Option<Annotations>,
|
annotations: Option<Annotations>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mime_type = mime_type.into();
|
|
||||||
|
|
||||||
let base64 = BASE64_STANDARD.encode(data);
|
let base64 = BASE64_STANDARD.encode(data);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
role,
|
role,
|
||||||
content: PromptMessageContent::Image {
|
content: PromptMessageContent::Image {
|
||||||
image: RawImageContent {
|
image: RawImageContent {
|
||||||
data: base64,
|
data: base64,
|
||||||
mime_type,
|
mime_type: mime_type.into(),
|
||||||
|
meta,
|
||||||
}
|
}
|
||||||
.optional_annotate(annotations),
|
.optional_annotate(annotations),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new resource message
|
/// Create a new resource message. `resource_meta`, `resource_content_meta`, and `annotations` are optional.
|
||||||
pub fn new_resource(
|
pub fn new_resource(
|
||||||
role: PromptMessageRole,
|
role: PromptMessageRole,
|
||||||
uri: String,
|
uri: String,
|
||||||
mime_type: String,
|
mime_type: Option<String>,
|
||||||
text: Option<String>,
|
text: Option<String>,
|
||||||
|
resource_meta: Option<crate::model::Meta>,
|
||||||
|
resource_content_meta: Option<crate::model::Meta>,
|
||||||
annotations: Option<Annotations>,
|
annotations: Option<Annotations>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let resource_contents = ResourceContents::TextResourceContents {
|
let resource_contents = match text {
|
||||||
uri,
|
Some(t) => ResourceContents::TextResourceContents {
|
||||||
mime_type: Some(mime_type),
|
uri,
|
||||||
text: text.unwrap_or_default(),
|
mime_type,
|
||||||
meta: None,
|
text: t,
|
||||||
|
meta: resource_content_meta,
|
||||||
|
},
|
||||||
|
None => ResourceContents::BlobResourceContents {
|
||||||
|
uri,
|
||||||
|
mime_type,
|
||||||
|
blob: String::new(),
|
||||||
|
meta: resource_content_meta,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
role,
|
role,
|
||||||
content: PromptMessageContent::Resource {
|
content: PromptMessageContent::Resource {
|
||||||
resource: RawEmbeddedResource {
|
resource: RawEmbeddedResource {
|
||||||
meta: None,
|
meta: resource_meta,
|
||||||
resource: resource_contents,
|
resource: resource_contents,
|
||||||
}
|
}
|
||||||
.optional_annotate(annotations),
|
.optional_annotate(annotations),
|
||||||
|
|
@ -164,6 +174,16 @@ impl PromptMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Note: PromptMessage text content does not carry protocol-level _meta per current schema.
|
||||||
|
/// This function exists for API symmetry but ignores the meta parameter.
|
||||||
|
pub fn new_text_with_meta<S: Into<String>>(
|
||||||
|
role: PromptMessageRole,
|
||||||
|
text: S,
|
||||||
|
_meta: Option<crate::model::Meta>,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_text(role, text)
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new resource link message
|
/// Create a new resource link message
|
||||||
pub fn new_resource_link(role: PromptMessageRole, resource: super::resource::Resource) -> Self {
|
pub fn new_resource_link(role: PromptMessageRole, resource: super::resource::Resource) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -184,6 +204,7 @@ mod tests {
|
||||||
let image_content = RawImageContent {
|
let image_content = RawImageContent {
|
||||||
data: "base64data".to_string(),
|
data: "base64data".to_string(),
|
||||||
mime_type: "image/png".to_string(),
|
mime_type: "image/png".to_string(),
|
||||||
|
meta: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = serde_json::to_string(&image_content).unwrap();
|
let json = serde_json::to_string(&image_content).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,20 @@ use serde_json::json;
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_embedded_text_resource_with_meta() {
|
fn serialize_embedded_text_resource_with_meta() {
|
||||||
// Inner contents meta
|
// Inner contents meta
|
||||||
let mut inner_meta = Meta::new();
|
let mut resource_content_meta = Meta::new();
|
||||||
inner_meta.insert("inner".to_string(), json!(2));
|
resource_content_meta.insert("inner".to_string(), json!(2));
|
||||||
|
|
||||||
// Top-level embedded resource meta
|
// Top-level embedded resource meta
|
||||||
let mut top_meta = Meta::new();
|
let mut resource_meta = Meta::new();
|
||||||
top_meta.insert("top".to_string(), json!(1));
|
resource_meta.insert("top".to_string(), json!(1));
|
||||||
|
|
||||||
let content: Content = RawContent::Resource(rmcp::model::RawEmbeddedResource {
|
let content: Content = RawContent::Resource(rmcp::model::RawEmbeddedResource {
|
||||||
meta: Some(top_meta),
|
meta: Some(resource_meta),
|
||||||
resource: ResourceContents::TextResourceContents {
|
resource: ResourceContents::TextResourceContents {
|
||||||
uri: "str://example".to_string(),
|
uri: "str://example".to_string(),
|
||||||
mime_type: Some("text/plain".to_string()),
|
mime_type: Some("text/plain".to_string()),
|
||||||
text: "hello".to_string(),
|
text: "hello".to_string(),
|
||||||
meta: Some(inner_meta),
|
meta: Some(resource_content_meta),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.no_annotation();
|
.no_annotation();
|
||||||
|
|
@ -97,19 +97,19 @@ fn deserialize_embedded_text_resource_with_meta() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_embedded_blob_resource_with_meta() {
|
fn serialize_embedded_blob_resource_with_meta() {
|
||||||
let mut inner_meta = Meta::new();
|
let mut resource_content_meta = Meta::new();
|
||||||
inner_meta.insert("blob_inner".to_string(), json!(true));
|
resource_content_meta.insert("blob_inner".to_string(), json!(true));
|
||||||
|
|
||||||
let mut top_meta = Meta::new();
|
let mut resource_meta = Meta::new();
|
||||||
top_meta.insert("blob_top".to_string(), json!("t"));
|
resource_meta.insert("blob_top".to_string(), json!("t"));
|
||||||
|
|
||||||
let content: Content = RawContent::Resource(rmcp::model::RawEmbeddedResource {
|
let content: Content = RawContent::Resource(rmcp::model::RawEmbeddedResource {
|
||||||
meta: Some(top_meta),
|
meta: Some(resource_meta),
|
||||||
resource: ResourceContents::BlobResourceContents {
|
resource: ResourceContents::BlobResourceContents {
|
||||||
uri: "str://blob".to_string(),
|
uri: "str://blob".to_string(),
|
||||||
mime_type: Some("application/octet-stream".to_string()),
|
mime_type: Some("application/octet-stream".to_string()),
|
||||||
blob: "Zm9v".to_string(),
|
blob: "Zm9v".to_string(),
|
||||||
meta: Some(inner_meta),
|
meta: Some(resource_content_meta),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.no_annotation();
|
.no_annotation();
|
||||||
|
|
|
||||||
|
|
@ -176,19 +176,19 @@
|
||||||
"$ref": "#/definitions/Role"
|
"$ref": "#/definitions/Role"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lastModified": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
"priority": {
|
"priority": {
|
||||||
"type": [
|
"type": [
|
||||||
"number",
|
"number",
|
||||||
"null"
|
"null"
|
||||||
],
|
],
|
||||||
"format": "float"
|
"format": "float"
|
||||||
},
|
|
||||||
"timestamp": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
],
|
|
||||||
"format": "date-time"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -859,6 +859,7 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"_meta": {
|
"_meta": {
|
||||||
|
"description": "Optional protocol-level metadata for this content block",
|
||||||
"type": [
|
"type": [
|
||||||
"object",
|
"object",
|
||||||
"null"
|
"null"
|
||||||
|
|
@ -876,6 +877,14 @@
|
||||||
"RawImageContent": {
|
"RawImageContent": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"_meta": {
|
||||||
|
"description": "Optional protocol-level metadata for this content block",
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"description": "The base64-encoded image",
|
"description": "The base64-encoded image",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|
@ -933,6 +942,14 @@
|
||||||
"RawTextContent": {
|
"RawTextContent": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"_meta": {
|
||||||
|
"description": "Optional protocol-level metadata for this content block",
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
"text": {
|
"text": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -168,6 +168,7 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"_meta": {
|
"_meta": {
|
||||||
|
"description": "Optional protocol-level metadata for this content block",
|
||||||
"type": [
|
"type": [
|
||||||
"object",
|
"object",
|
||||||
"null"
|
"null"
|
||||||
|
|
@ -292,19 +293,19 @@
|
||||||
"$ref": "#/definitions/Role"
|
"$ref": "#/definitions/Role"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lastModified": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
"priority": {
|
"priority": {
|
||||||
"type": [
|
"type": [
|
||||||
"number",
|
"number",
|
||||||
"null"
|
"null"
|
||||||
],
|
],
|
||||||
"format": "float"
|
"format": "float"
|
||||||
},
|
|
||||||
"timestamp": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
],
|
|
||||||
"format": "date-time"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -1232,6 +1233,14 @@
|
||||||
"description": "Image content with base64-encoded data",
|
"description": "Image content with base64-encoded data",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"_meta": {
|
||||||
|
"description": "Optional protocol-level metadata for this content block",
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
"annotations": {
|
"annotations": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
|
@ -1362,6 +1371,7 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"_meta": {
|
"_meta": {
|
||||||
|
"description": "Optional protocol-level metadata for this content block",
|
||||||
"type": [
|
"type": [
|
||||||
"object",
|
"object",
|
||||||
"null"
|
"null"
|
||||||
|
|
@ -1379,6 +1389,14 @@
|
||||||
"RawImageContent": {
|
"RawImageContent": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"_meta": {
|
||||||
|
"description": "Optional protocol-level metadata for this content block",
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"description": "The base64-encoded image",
|
"description": "The base64-encoded image",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|
@ -1436,6 +1454,14 @@
|
||||||
"RawTextContent": {
|
"RawTextContent": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"_meta": {
|
||||||
|
"description": "Optional protocol-level metadata for this content block",
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
"text": {
|
"text": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue