Skip to main content

kcode_k1_chat_web_code_output/
lib.rs

1#![forbid(unsafe_code)]
2
3use kcode_k1_chat_boxes::ToolCallId;
4pub use kcode_k1_web_code_ktool_protocol::{
5    Language, WEB_CODE_CHECK_METADATA_TYPE, WEB_CODE_DOCS_METADATA_TYPE,
6    WEB_CODE_OPEN_METADATA_TYPE, WEB_CODE_OVERWRITE_METADATA_TYPE, WEB_CODE_PUBLISH_METADATA_TYPE,
7};
8use serde::Serialize;
9
10#[derive(Clone, Debug, Eq, PartialEq)]
11pub struct WebCodeOutput {
12    pub tool_call_id: ToolCallId,
13    pub messages: Vec<String>,
14    pub result: Result<String, String>,
15    pub metadata_type: String,
16    pub metadata_contents: String,
17}
18
19#[derive(Clone, Copy, Debug, Eq, PartialEq)]
20pub enum PublishCheck {
21    ReusedSameSession,
22    Fresh,
23}
24
25impl PublishCheck {
26    pub const fn as_str(self) -> &'static str {
27        match self {
28            Self::ReusedSameSession => "reused_same_session",
29            Self::Fresh => "fresh",
30        }
31    }
32}
33
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
35pub enum PublishStatus {
36    Published,
37    Idempotent,
38    Conflict,
39}
40
41impl PublishStatus {
42    pub const fn as_str(self) -> &'static str {
43        match self {
44            Self::Published => "published",
45            Self::Idempotent => "idempotent",
46            Self::Conflict => "conflict",
47        }
48    }
49}
50
51#[derive(Clone, Copy, Debug, Eq, PartialEq)]
52pub enum DocumentPart {
53    Documentation,
54    Code,
55}
56
57impl DocumentPart {
58    pub const fn as_str(self) -> &'static str {
59        match self {
60            Self::Documentation => "documentation",
61            Self::Code => "code",
62        }
63    }
64}
65
66#[derive(Clone, Copy, Debug, Eq, PartialEq)]
67pub enum Operation {
68    Docs,
69    Open,
70    Overwrite,
71    Check,
72    Publish,
73}
74
75impl Operation {
76    pub const fn metadata_type(self) -> &'static str {
77        match self {
78            Self::Docs => WEB_CODE_DOCS_METADATA_TYPE,
79            Self::Open => WEB_CODE_OPEN_METADATA_TYPE,
80            Self::Overwrite => WEB_CODE_OVERWRITE_METADATA_TYPE,
81            Self::Check => WEB_CODE_CHECK_METADATA_TYPE,
82            Self::Publish => WEB_CODE_PUBLISH_METADATA_TYPE,
83        }
84    }
85}
86
87#[derive(Serialize)]
88struct DocsMetadata<'a> {
89    status: &'static str,
90    authority: &'a str,
91    name: &'a str,
92    version: &'a str,
93}
94
95#[derive(Serialize)]
96struct OpenMetadata<'a> {
97    status: &'static str,
98    authority: &'a str,
99    name: &'a str,
100    version: &'a str,
101    language: &'static str,
102    documentation_message_index: u64,
103    code_message_start: u64,
104    code_message_count: u64,
105}
106
107#[derive(Serialize)]
108struct OverwriteMetadata<'a> {
109    status: &'static str,
110    box_id: &'a str,
111    part: &'static str,
112}
113
114#[derive(Serialize)]
115struct CheckSuccessMetadata {
116    status: &'static str,
117    fresh: bool,
118}
119
120#[derive(Serialize)]
121struct CheckFailedMetadata<'a> {
122    status: &'static str,
123    diagnostics: &'a str,
124}
125
126#[derive(Serialize)]
127struct PublishMetadata<'a> {
128    status: &'static str,
129    source_object: &'a str,
130    winning: &'a str,
131    submitted: Option<&'a str>,
132    check: &'static str,
133}
134
135#[derive(Serialize)]
136struct ErrorMetadata<'a> {
137    status: &'static str,
138    code: &'a str,
139    source_object: Option<&'a str>,
140}
141
142pub fn docs(
143    tool_call_id: ToolCallId,
144    messages: Vec<String>,
145    result: Result<String, String>,
146    authority: &str,
147    name: &str,
148    version: &str,
149) -> WebCodeOutput {
150    build(
151        tool_call_id,
152        messages,
153        result,
154        WEB_CODE_DOCS_METADATA_TYPE,
155        &DocsMetadata {
156            status: "found",
157            authority,
158            name,
159            version,
160        },
161    )
162}
163
164#[allow(clippy::too_many_arguments)]
165pub fn open(
166    tool_call_id: ToolCallId,
167    messages: Vec<String>,
168    result: Result<String, String>,
169    authority: &str,
170    name: &str,
171    version: &str,
172    language: Language,
173    code_message_count: u64,
174) -> WebCodeOutput {
175    build(
176        tool_call_id,
177        messages,
178        result,
179        WEB_CODE_OPEN_METADATA_TYPE,
180        &OpenMetadata {
181            status: "opened",
182            authority,
183            name,
184            version,
185            language: language.as_str(),
186            documentation_message_index: 1,
187            code_message_start: 2,
188            code_message_count,
189        },
190    )
191}
192
193pub fn overwrite(
194    tool_call_id: ToolCallId,
195    messages: Vec<String>,
196    result: Result<String, String>,
197    box_id: &str,
198    part: DocumentPart,
199) -> WebCodeOutput {
200    build(
201        tool_call_id,
202        messages,
203        result,
204        WEB_CODE_OVERWRITE_METADATA_TYPE,
205        &OverwriteMetadata {
206            status: "overwritten",
207            box_id,
208            part: part.as_str(),
209        },
210    )
211}
212
213pub fn check_success(
214    tool_call_id: ToolCallId,
215    messages: Vec<String>,
216    result: Result<String, String>,
217) -> WebCodeOutput {
218    build(
219        tool_call_id,
220        messages,
221        result,
222        WEB_CODE_CHECK_METADATA_TYPE,
223        &CheckSuccessMetadata {
224            status: "success",
225            fresh: true,
226        },
227    )
228}
229
230pub fn check_failed(
231    tool_call_id: ToolCallId,
232    messages: Vec<String>,
233    result: Result<String, String>,
234    diagnostics: &str,
235) -> WebCodeOutput {
236    build(
237        tool_call_id,
238        messages,
239        result,
240        WEB_CODE_CHECK_METADATA_TYPE,
241        &CheckFailedMetadata {
242            status: "failed",
243            diagnostics,
244        },
245    )
246}
247
248#[allow(clippy::too_many_arguments)]
249pub fn publish(
250    tool_call_id: ToolCallId,
251    messages: Vec<String>,
252    result: Result<String, String>,
253    source_object: &str,
254    winning: &str,
255    submitted: Option<&str>,
256    check: PublishCheck,
257    status: PublishStatus,
258) -> WebCodeOutput {
259    build(
260        tool_call_id,
261        messages,
262        result,
263        WEB_CODE_PUBLISH_METADATA_TYPE,
264        &PublishMetadata {
265            status: status.as_str(),
266            source_object,
267            winning,
268            submitted,
269            check: check.as_str(),
270        },
271    )
272}
273
274pub fn error(
275    tool_call_id: ToolCallId,
276    messages: Vec<String>,
277    result: Result<String, String>,
278    operation: Operation,
279    code: &str,
280    source_object: Option<&str>,
281) -> WebCodeOutput {
282    build(
283        tool_call_id,
284        messages,
285        result,
286        operation.metadata_type(),
287        &ErrorMetadata {
288            status: "error",
289            code,
290            source_object,
291        },
292    )
293}
294
295fn build(
296    tool_call_id: ToolCallId,
297    messages: Vec<String>,
298    result: Result<String, String>,
299    metadata_type: &str,
300    metadata: &impl Serialize,
301) -> WebCodeOutput {
302    WebCodeOutput {
303        tool_call_id,
304        messages,
305        result,
306        metadata_type: metadata_type.to_owned(),
307        metadata_contents: serde_json::to_string(metadata)
308            .expect("fixed Web-code metadata is serializable"),
309    }
310}