systemprompt_models/artifacts/table/
mod.rs1pub mod column;
8pub mod hints;
9
10pub use column::Column;
11pub use hints::TableHints;
12
13use crate::artifacts::metadata::ExecutionMetadata;
14use crate::artifacts::traits::Artifact;
15use crate::artifacts::types::ArtifactType;
16use crate::execution::context::RequestContext;
17use schemars::JsonSchema;
18use serde::{Deserialize, Serialize};
19use serde_json::{Value as JsonValue, json};
20use systemprompt_identifiers::SkillId;
21
22#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
23pub struct TableResponse {
24 #[serde(rename = "x-artifact-type")]
25 pub artifact_type: String,
26 pub columns: Vec<Column>,
27 pub items: Vec<JsonValue>,
28 pub count: usize,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub execution_id: Option<String>,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 #[schemars(with = "Option<JsonValue>")]
33 pub hints: Option<JsonValue>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
37pub struct TableArtifact {
38 #[serde(rename = "x-artifact-type")]
39 #[serde(default = "default_artifact_type")]
40 pub artifact_type: String,
41 pub columns: Vec<Column>,
42 pub items: Vec<JsonValue>,
43 #[serde(skip_serializing_if = "Option::is_none")]
44 #[schemars(with = "Option<JsonValue>")]
45 pub hints: Option<JsonValue>,
46 #[serde(skip)]
47 #[schemars(skip)]
48 hints_builder: TableHints,
49 #[serde(skip)]
50 #[schemars(skip)]
51 metadata: ExecutionMetadata,
52}
53
54fn default_artifact_type() -> String {
55 "table".to_owned()
56}
57
58impl TableArtifact {
59 pub const ARTIFACT_TYPE_STR: &'static str = "table";
60
61 pub fn new(columns: Vec<Column>) -> Self {
62 Self {
63 artifact_type: "table".to_owned(),
64 columns,
65 items: Vec::new(),
66 hints: None,
67 hints_builder: TableHints::default(),
68 metadata: ExecutionMetadata::default(),
69 }
70 }
71
72 pub fn with_request(mut self, ctx: &RequestContext) -> Self {
73 self.metadata = ExecutionMetadata::with_request(ctx);
74 self
75 }
76
77 pub fn with_rows(mut self, items: Vec<JsonValue>) -> Self {
78 self.items = items;
79 self
80 }
81
82 pub fn with_hints(mut self, hints: TableHints) -> Self {
83 use crate::artifacts::traits::ArtifactSchema;
84 self.hints = Some(hints.generate_schema());
85 self.hints_builder = hints;
86 self
87 }
88
89 pub fn with_metadata(mut self, metadata: ExecutionMetadata) -> Self {
90 self.metadata = metadata;
91 self
92 }
93
94 pub fn with_execution_id(mut self, id: impl Into<String>) -> Self {
95 self.metadata.execution_id = Some(id.into());
96 self
97 }
98
99 pub fn with_skill(
100 mut self,
101 skill_id: impl Into<SkillId>,
102 skill_name: impl Into<String>,
103 ) -> Self {
104 self.metadata.skill_id = Some(skill_id.into());
105 self.metadata.skill_name = Some(skill_name.into());
106 self
107 }
108
109 pub fn to_response(&self) -> JsonValue {
110 use crate::artifacts::traits::ArtifactSchema;
111
112 let response = TableResponse {
113 artifact_type: "table".to_owned(),
114 columns: self.columns.clone(),
115 items: self.items.clone(),
116 count: self.items.len(),
117 execution_id: self.metadata.execution_id.clone(),
118 hints: Some(self.hints_builder.generate_schema()),
119 };
120 match serde_json::to_value(response) {
121 Ok(v) => v,
122 Err(e) => {
123 tracing::error!(error = %e, "Failed to serialize table response");
124 JsonValue::Null
125 },
126 }
127 }
128}
129
130impl Artifact for TableArtifact {
131 fn artifact_type(&self) -> ArtifactType {
132 ArtifactType::Table
133 }
134
135 fn to_schema(&self) -> JsonValue {
136 use crate::artifacts::traits::ArtifactSchema;
137
138 json!({
139 "type": "object",
140 "properties": {
141 "columns": {
142 "type": "array",
143 "description": "Column definitions"
144 },
145 "items": {
146 "type": "array",
147 "description": "Array of data records"
148 },
149 "count": {
150 "type": "integer",
151 "description": "Total number of records"
152 },
153 "_execution_id": {
154 "type": "string",
155 "description": "Execution ID for tracking"
156 }
157 },
158 "required": ["columns", "items"],
159 "x-artifact-type": "table",
160 "x-table-hints": self.hints_builder.generate_schema()
161 })
162 }
163}