1use crate::schema::types::*;
10use std::collections::HashMap;
11
12pub fn copilot_json_v3() -> ProviderSchema {
22 ProviderSchema {
23 version: SchemaVersion::new("copilot", FormatType::Json, 3, "Copilot Chat JSON v3"),
24 extension_version_min: Some("0.25.0".into()),
25 extension_version_max: Some("0.36.99".into()),
26 host_version_min: Some("1.98.0".into()),
27 introduced: Some("2025-02".into()),
28 deprecated: Some("2026-01".into()),
29 storage: StorageLocation {
30 description: "VS Code workspace storage, one JSON file per session".into(),
31 path_pattern: "{APPDATA}/Code/User/workspaceStorage/{hash}/chatSessions/{uuid}.json"
32 .into(),
33 platform_paths: HashMap::from([
34 (
35 "windows".into(),
36 "%APPDATA%/Code/User/workspaceStorage/{hash}/chatSessions/".into(),
37 ),
38 (
39 "macos".into(),
40 "~/Library/Application Support/Code/User/workspaceStorage/{hash}/chatSessions/"
41 .into(),
42 ),
43 (
44 "linux".into(),
45 "~/.config/Code/User/workspaceStorage/{hash}/chatSessions/".into(),
46 ),
47 ]),
48 storage_type: StorageType::Hybrid,
49 file_extensions: vec![".json".into()],
50 },
51 session_schema: SessionFormatSchema {
52 description: "Single JSON object containing the full session state".into(),
53 format: FormatType::Json,
54 fields: copilot_session_fields_v3(),
55 nested_objects: copilot_nested_objects_v3(),
56 example: Some(serde_json::json!({
57 "version": 3,
58 "sessionId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
59 "creationDate": 1700000000000_i64,
60 "lastMessageDate": 1700001000000_i64,
61 "isImported": false,
62 "initialLocation": "panel",
63 "requests": []
64 })),
65 },
66 db_keys: copilot_db_keys_json(),
67 notes: vec![
68 "Legacy JSON format used from Copilot Chat 0.25.x through 0.36.x".into(),
69 "Session version field is always 3".into(),
70 "Response format is {\"value\": [{\"value\": \"text\"}, ...]}".into(),
71 ],
72 breaking_changes: vec![],
73 tags: vec![
74 "vscode".into(),
75 "copilot".into(),
76 "json".into(),
77 "file-based".into(),
78 "hybrid-storage".into(),
79 ],
80 }
81}
82
83pub fn copilot_jsonl_v1() -> ProviderSchema {
94 ProviderSchema {
95 version: SchemaVersion::new("copilot", FormatType::Jsonl, 1, "Copilot Chat JSONL v1"),
96 extension_version_min: Some("0.37.0".into()),
97 extension_version_max: None,
98 host_version_min: Some("1.109.0".into()),
99 introduced: Some("2026-01".into()),
100 deprecated: None,
101 storage: StorageLocation {
102 description: "VS Code workspace storage, one JSONL file per session (event-sourced)"
103 .into(),
104 path_pattern: "{APPDATA}/Code/User/workspaceStorage/{hash}/chatSessions/{uuid}.jsonl"
105 .into(),
106 platform_paths: HashMap::from([
107 (
108 "windows".into(),
109 "%APPDATA%/Code/User/workspaceStorage/{hash}/chatSessions/".into(),
110 ),
111 (
112 "macos".into(),
113 "~/Library/Application Support/Code/User/workspaceStorage/{hash}/chatSessions/"
114 .into(),
115 ),
116 (
117 "linux".into(),
118 "~/.config/Code/User/workspaceStorage/{hash}/chatSessions/".into(),
119 ),
120 ]),
121 storage_type: StorageType::Hybrid,
122 file_extensions: vec![".jsonl".into()],
123 },
124 session_schema: SessionFormatSchema {
125 description: "JSONL event-sourced format. First line is kind:0 (full snapshot). \
126 Subsequent lines are kind:1 (request update) or kind:2 (response update)."
127 .into(),
128 format: FormatType::Jsonl,
129 fields: copilot_jsonl_event_fields(),
130 nested_objects: copilot_nested_objects_jsonl(),
131 example: Some(serde_json::json!({
132 "kind": 0,
133 "data": {
134 "version": 3,
135 "sessionId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
136 "creationDate": 1700000000000_i64,
137 "lastMessageDate": 1700001000000_i64,
138 "initialLocation": "panel",
139 "requests": []
140 }
141 })),
142 },
143 db_keys: copilot_db_keys_jsonl(),
144 notes: vec![
145 "JSONL event-sourced format introduced with Copilot Chat 0.37.x (Jan 2026)".into(),
146 "kind:0 = full session snapshot, kind:1 = request update, kind:2 = response update"
147 .into(),
148 "Response format changed to array of parts: [{\"kind\":\"\",\"value\":\"text\"}]".into(),
149 "modelState field added: {\"value\": 0|1|2, \"completedAt\": timestamp}".into(),
150 "Timing field changed from startTime/endTime to created/lastRequestStarted/lastRequestEnded".into(),
151 ],
152 breaking_changes: vec![
153 "File extension changed from .json to .jsonl".into(),
154 "Response format: object → array of typed parts".into(),
155 "Timing field names renamed (startTime→created, endTime→lastRequestEnded)".into(),
156 "Added modelState field (required for VS Code to show session as non-empty)".into(),
157 "Index format changed from array of UUIDs to map of UUID→entry objects".into(),
158 ],
159 tags: vec![
160 "vscode".into(),
161 "copilot".into(),
162 "jsonl".into(),
163 "event-sourced".into(),
164 "file-based".into(),
165 "hybrid-storage".into(),
166 ],
167 }
168}
169
170pub fn cursor_v1() -> ProviderSchema {
179 ProviderSchema {
180 version: SchemaVersion::new("cursor", FormatType::Json, 1, "Cursor Chat v1"),
181 extension_version_min: None,
182 extension_version_max: None,
183 host_version_min: None,
184 introduced: Some("2024-01".into()),
185 deprecated: None,
186 storage: StorageLocation {
187 description: "Cursor app data, one JSON file per session in chatSessions/".into(),
188 path_pattern: "{APPDATA}/Cursor/User/workspaceStorage/{hash}/chatSessions/{uuid}.json"
189 .into(),
190 platform_paths: HashMap::from([
191 (
192 "windows".into(),
193 "%APPDATA%/Cursor/User/workspaceStorage/{hash}/chatSessions/".into(),
194 ),
195 (
196 "macos".into(),
197 "~/Library/Application Support/Cursor/User/workspaceStorage/{hash}/chatSessions/"
198 .into(),
199 ),
200 (
201 "linux".into(),
202 "~/.config/Cursor/User/workspaceStorage/{hash}/chatSessions/".into(),
203 ),
204 ]),
205 storage_type: StorageType::FilePerSession,
206 file_extensions: vec![".json".into()],
207 },
208 session_schema: SessionFormatSchema {
209 description: "JSON format similar to Copilot Chat v3, stored in Cursor's workspace storage".into(),
210 format: FormatType::Json,
211 fields: cursor_session_fields(),
212 nested_objects: HashMap::new(),
213 example: None,
214 },
215 db_keys: vec![],
216 notes: vec![
217 "Cursor uses a VS Code fork with similar session format".into(),
218 "Sessions stored in Cursor's own workspaceStorage directory".into(),
219 "Field names and structure closely match Copilot Chat JSON v3".into(),
220 ],
221 breaking_changes: vec![],
222 tags: vec![
223 "cursor".into(),
224 "json".into(),
225 "file-based".into(),
226 "vscode-fork".into(),
227 ],
228 }
229}
230
231pub fn claude_code_v1() -> ProviderSchema {
239 ProviderSchema {
240 version: SchemaVersion::new("claude-code", FormatType::Jsonl, 1, "Claude Code v1"),
241 extension_version_min: None,
242 extension_version_max: None,
243 host_version_min: None,
244 introduced: Some("2025-03".into()),
245 deprecated: None,
246 storage: StorageLocation {
247 description: "Claude Code stores JSONL sessions in ~/.claude/projects/{project}/".into(),
248 path_pattern: "{HOME}/.claude/projects/{project_hash}/{uuid}.jsonl".into(),
249 platform_paths: HashMap::from([
250 ("windows".into(), "%USERPROFILE%/.claude/projects/".into()),
251 ("macos".into(), "~/.claude/projects/".into()),
252 ("linux".into(), "~/.claude/projects/".into()),
253 ]),
254 storage_type: StorageType::FilePerSession,
255 file_extensions: vec![".jsonl".into()],
256 },
257 session_schema: SessionFormatSchema {
258 description: "JSONL format with one message event per line. Each line has type, role, content fields.".into(),
259 format: FormatType::Jsonl,
260 fields: claude_code_fields(),
261 nested_objects: HashMap::new(),
262 example: Some(serde_json::json!({
263 "type": "human",
264 "message": {"role": "user", "content": "Hello"},
265 "timestamp": "2025-06-15T10:30:00Z"
266 })),
267 },
268 db_keys: vec![],
269 notes: vec![
270 "Claude Code CLI stores sessions as JSONL in ~/.claude/projects/".into(),
271 "Each line is a message event with type (human/assistant/system/tool_use/tool_result)".into(),
272 "Project identified by hash of project path".into(),
273 ],
274 breaking_changes: vec![],
275 tags: vec![
276 "anthropic".into(),
277 "claude-code".into(),
278 "cli".into(),
279 "jsonl".into(),
280 "file-based".into(),
281 ],
282 }
283}
284
285pub fn codex_cli_v1() -> ProviderSchema {
293 ProviderSchema {
294 version: SchemaVersion::new("codex-cli", FormatType::Jsonl, 1, "Codex CLI v1"),
295 extension_version_min: None,
296 extension_version_max: None,
297 host_version_min: None,
298 introduced: Some("2025-05".into()),
299 deprecated: None,
300 storage: StorageLocation {
301 description: "Codex CLI stores JSONL sessions in ~/.codex/sessions/".into(),
302 path_pattern: "{HOME}/.codex/sessions/{uuid}.jsonl".into(),
303 platform_paths: HashMap::from([
304 ("windows".into(), "%USERPROFILE%/.codex/sessions/".into()),
305 ("macos".into(), "~/.codex/sessions/".into()),
306 ("linux".into(), "~/.codex/sessions/".into()),
307 ]),
308 storage_type: StorageType::FilePerSession,
309 file_extensions: vec![".jsonl".into()],
310 },
311 session_schema: SessionFormatSchema {
312 description: "JSONL format with OpenAI message events".into(),
313 format: FormatType::Jsonl,
314 fields: codex_cli_fields(),
315 nested_objects: HashMap::new(),
316 example: None,
317 },
318 db_keys: vec![],
319 notes: vec![
320 "OpenAI Codex CLI stores sessions as JSONL in ~/.codex/sessions/".into(),
321 "Uses OpenAI API message format (role/content pairs)".into(),
322 ],
323 breaking_changes: vec![],
324 tags: vec![
325 "openai".into(),
326 "codex".into(),
327 "cli".into(),
328 "jsonl".into(),
329 "file-based".into(),
330 ],
331 }
332}
333
334pub fn gemini_cli_v1() -> ProviderSchema {
342 ProviderSchema {
343 version: SchemaVersion::new("gemini-cli", FormatType::Json, 1, "Gemini CLI v1"),
344 extension_version_min: None,
345 extension_version_max: None,
346 host_version_min: None,
347 introduced: Some("2025-06".into()),
348 deprecated: None,
349 storage: StorageLocation {
350 description: "Gemini CLI stores JSON sessions in ~/.gemini/tmp/".into(),
351 path_pattern: "{HOME}/.gemini/tmp/{session_id}.json".into(),
352 platform_paths: HashMap::from([
353 ("windows".into(), "%USERPROFILE%/.gemini/tmp/".into()),
354 ("macos".into(), "~/.gemini/tmp/".into()),
355 ("linux".into(), "~/.gemini/tmp/".into()),
356 ]),
357 storage_type: StorageType::FilePerSession,
358 file_extensions: vec![".json".into()],
359 },
360 session_schema: SessionFormatSchema {
361 description: "JSON format with Google Gemini API message structure".into(),
362 format: FormatType::Json,
363 fields: gemini_cli_fields(),
364 nested_objects: HashMap::new(),
365 example: None,
366 },
367 db_keys: vec![],
368 notes: vec![
369 "Google Gemini CLI stores sessions as JSON in ~/.gemini/tmp/".into(),
370 "Uses Gemini API message format (contents with parts)".into(),
371 ],
372 breaking_changes: vec![],
373 tags: vec![
374 "google".into(),
375 "gemini".into(),
376 "cli".into(),
377 "json".into(),
378 "file-based".into(),
379 ],
380 }
381}
382
383pub fn continue_dev_v1() -> ProviderSchema {
391 ProviderSchema {
392 version: SchemaVersion::new("continue-dev", FormatType::Json, 1, "Continue.dev v1"),
393 extension_version_min: None,
394 extension_version_max: None,
395 host_version_min: None,
396 introduced: Some("2024-01".into()),
397 deprecated: None,
398 storage: StorageLocation {
399 description: "Continue.dev stores sessions in ~/.continue/sessions/".into(),
400 path_pattern: "{HOME}/.continue/sessions/{session_id}.json".into(),
401 platform_paths: HashMap::from([
402 (
403 "windows".into(),
404 "%USERPROFILE%/.continue/sessions/".into(),
405 ),
406 ("macos".into(), "~/.continue/sessions/".into()),
407 ("linux".into(), "~/.continue/sessions/".into()),
408 ]),
409 storage_type: StorageType::FilePerSession,
410 file_extensions: vec![".json".into()],
411 },
412 session_schema: SessionFormatSchema {
413 description: "JSON format with Continue.dev's session structure".into(),
414 format: FormatType::Json,
415 fields: continue_dev_fields(),
416 nested_objects: HashMap::new(),
417 example: None,
418 },
419 db_keys: vec![],
420 notes: vec![
421 "Continue.dev extension stores sessions in ~/.continue/sessions/".into(),
422 "Uses a chat-model-agnostic format with provider metadata".into(),
423 ],
424 breaking_changes: vec![],
425 tags: vec![
426 "continuedev".into(),
427 "vscode-extension".into(),
428 "json".into(),
429 "file-based".into(),
430 ],
431 }
432}
433
434pub fn openai_api_v1() -> ProviderSchema {
443 ProviderSchema {
444 version: SchemaVersion::new("openai-api", FormatType::OpenAiApi, 1, "OpenAI API v1"),
445 extension_version_min: None,
446 extension_version_max: None,
447 host_version_min: None,
448 introduced: Some("2023-03".into()),
449 deprecated: None,
450 storage: StorageLocation {
451 description: "OpenAI-compatible API — conversations are ephemeral unless saved by the client".into(),
452 path_pattern: "N/A — API-based, no local storage".into(),
453 platform_paths: HashMap::new(),
454 storage_type: StorageType::CloudApi,
455 file_extensions: vec![],
456 },
457 session_schema: SessionFormatSchema {
458 description: "OpenAI Chat Completions API format (messages array with role/content)".into(),
459 format: FormatType::OpenAiApi,
460 fields: openai_api_fields(),
461 nested_objects: openai_api_nested_objects(),
462 example: Some(serde_json::json!({
463 "model": "gpt-4o",
464 "messages": [
465 {"role": "system", "content": "You are a helpful assistant."},
466 {"role": "user", "content": "Hello!"},
467 {"role": "assistant", "content": "Hi! How can I help?"}
468 ],
469 "temperature": 0.7
470 })),
471 },
472 db_keys: vec![],
473 notes: vec![
474 "Standard OpenAI Chat Completions API format".into(),
475 "Used by: Ollama, vLLM, LM Studio, LocalAI, Jan, GPT4All, Llamafile, TextGen WebUI".into(),
476 "Also used by cloud providers: OpenAI, Groq, Together, Fireworks, DeepSeek".into(),
477 "Conversations are request/response pairs — no persistent session storage".into(),
478 ],
479 breaking_changes: vec![],
480 tags: vec![
481 "openai".into(),
482 "api".into(),
483 "cloud".into(),
484 "local".into(),
485 "universal".into(),
486 ],
487 }
488}
489
490pub fn build_all_provider_schemas() -> Vec<ProviderSchema> {
496 vec![
497 copilot_json_v3(),
498 copilot_jsonl_v1(),
499 cursor_v1(),
500 claude_code_v1(),
501 codex_cli_v1(),
502 gemini_cli_v1(),
503 continue_dev_v1(),
504 openai_api_v1(),
505 ]
506}
507
508fn copilot_session_fields_v3() -> Vec<FieldSchema> {
513 vec![
514 FieldSchema {
515 name: "version".into(),
516 serialized_name: None,
517 data_type: DataType::Integer,
518 required: true,
519 default_value: Some(serde_json::json!(3)),
520 description: "Session format version (always 3)".into(),
521 constraints: vec![FieldConstraint::Enum {
522 values: vec![serde_json::json!(3)],
523 }],
524 semantic_tag: Some("schema_version".into()),
525 since_version: None,
526 removed_in: None,
527 },
528 FieldSchema {
529 name: "sessionId".into(),
530 serialized_name: Some("session_id".into()),
531 data_type: DataType::Uuid,
532 required: false,
533 default_value: None,
534 description: "Unique session identifier (UUID). May be absent in file; use filename."
535 .into(),
536 constraints: vec![],
537 semantic_tag: Some("session_id".into()),
538 since_version: None,
539 removed_in: None,
540 },
541 FieldSchema {
542 name: "creationDate".into(),
543 serialized_name: Some("creation_date".into()),
544 data_type: DataType::Timestamp,
545 required: true,
546 default_value: Some(serde_json::json!(0)),
547 description: "Session creation timestamp (milliseconds since epoch)".into(),
548 constraints: vec![],
549 semantic_tag: Some("created_at".into()),
550 since_version: None,
551 removed_in: None,
552 },
553 FieldSchema {
554 name: "lastMessageDate".into(),
555 serialized_name: Some("last_message_date".into()),
556 data_type: DataType::Timestamp,
557 required: true,
558 default_value: Some(serde_json::json!(0)),
559 description: "Last message timestamp (milliseconds since epoch)".into(),
560 constraints: vec![],
561 semantic_tag: Some("updated_at".into()),
562 since_version: None,
563 removed_in: None,
564 },
565 FieldSchema {
566 name: "isImported".into(),
567 serialized_name: Some("is_imported".into()),
568 data_type: DataType::Boolean,
569 required: false,
570 default_value: Some(serde_json::json!(false)),
571 description: "Whether this session was imported from another source".into(),
572 constraints: vec![],
573 semantic_tag: Some("is_imported".into()),
574 since_version: None,
575 removed_in: None,
576 },
577 FieldSchema {
578 name: "initialLocation".into(),
579 serialized_name: Some("initial_location".into()),
580 data_type: DataType::Enum(vec![
581 "panel".into(),
582 "terminal".into(),
583 "notebook".into(),
584 "editor".into(),
585 ]),
586 required: true,
587 default_value: Some(serde_json::json!("panel")),
588 description: "Where the session was initiated in VS Code".into(),
589 constraints: vec![],
590 semantic_tag: Some("session_location".into()),
591 since_version: None,
592 removed_in: None,
593 },
594 FieldSchema {
595 name: "customTitle".into(),
596 serialized_name: Some("custom_title".into()),
597 data_type: DataType::Optional(Box::new(DataType::String)),
598 required: false,
599 default_value: None,
600 description: "User-set title for the session".into(),
601 constraints: vec![],
602 semantic_tag: Some("title".into()),
603 since_version: None,
604 removed_in: None,
605 },
606 FieldSchema {
607 name: "requesterUsername".into(),
608 serialized_name: Some("requester_username".into()),
609 data_type: DataType::Optional(Box::new(DataType::String)),
610 required: false,
611 default_value: None,
612 description: "Display name of the user who initiated the session".into(),
613 constraints: vec![],
614 semantic_tag: Some("user_name".into()),
615 since_version: None,
616 removed_in: None,
617 },
618 FieldSchema {
619 name: "responderUsername".into(),
620 serialized_name: Some("responder_username".into()),
621 data_type: DataType::Optional(Box::new(DataType::String)),
622 required: false,
623 default_value: None,
624 description: "Display name of the AI responder".into(),
625 constraints: vec![],
626 semantic_tag: Some("assistant_name".into()),
627 since_version: None,
628 removed_in: None,
629 },
630 FieldSchema {
631 name: "requests".into(),
632 serialized_name: None,
633 data_type: DataType::Array(Box::new(DataType::Object("ChatRequest".into()))),
634 required: true,
635 default_value: Some(serde_json::json!([])),
636 description: "Array of chat request/response pairs".into(),
637 constraints: vec![],
638 semantic_tag: Some("messages".into()),
639 since_version: None,
640 removed_in: None,
641 },
642 ]
643}
644
645fn copilot_nested_objects_v3() -> HashMap<String, Vec<FieldSchema>> {
646 let mut map = HashMap::new();
647
648 map.insert(
649 "ChatRequest".into(),
650 vec![
651 FieldSchema {
652 name: "timestamp".into(),
653 serialized_name: None,
654 data_type: DataType::Optional(Box::new(DataType::Timestamp)),
655 required: false,
656 default_value: None,
657 description: "Request timestamp (milliseconds since epoch)".into(),
658 constraints: vec![],
659 semantic_tag: Some("message_timestamp".into()),
660 since_version: None,
661 removed_in: None,
662 },
663 FieldSchema {
664 name: "message".into(),
665 serialized_name: None,
666 data_type: DataType::Optional(Box::new(DataType::Object("ChatMessage".into()))),
667 required: false,
668 default_value: None,
669 description: "The user's message".into(),
670 constraints: vec![],
671 semantic_tag: Some("user_message".into()),
672 since_version: None,
673 removed_in: None,
674 },
675 FieldSchema {
676 name: "response".into(),
677 serialized_name: None,
678 data_type: DataType::Optional(Box::new(DataType::Json)),
679 required: false,
680 default_value: None,
681 description: "AI response. Legacy format: {\"value\": [{\"value\": \"text\"}]}".into(),
682 constraints: vec![],
683 semantic_tag: Some("assistant_response".into()),
684 since_version: None,
685 removed_in: None,
686 },
687 FieldSchema {
688 name: "requestId".into(),
689 serialized_name: Some("request_id".into()),
690 data_type: DataType::Optional(Box::new(DataType::Uuid)),
691 required: false,
692 default_value: None,
693 description: "Unique request identifier".into(),
694 constraints: vec![],
695 semantic_tag: Some("request_id".into()),
696 since_version: None,
697 removed_in: None,
698 },
699 FieldSchema {
700 name: "modelId".into(),
701 serialized_name: Some("model_id".into()),
702 data_type: DataType::Optional(Box::new(DataType::String)),
703 required: false,
704 default_value: None,
705 description: "LLM model used for this request (e.g., 'gpt-4o', 'claude-3.5-sonnet')".into(),
706 constraints: vec![],
707 semantic_tag: Some("model_id".into()),
708 since_version: None,
709 removed_in: None,
710 },
711 FieldSchema {
712 name: "agent".into(),
713 serialized_name: None,
714 data_type: DataType::Optional(Box::new(DataType::Json)),
715 required: false,
716 default_value: None,
717 description: "Agent information (for agent-mode sessions)".into(),
718 constraints: vec![],
719 semantic_tag: Some("agent".into()),
720 since_version: Some("0.29.0".into()),
721 removed_in: None,
722 },
723 FieldSchema {
724 name: "isCanceled".into(),
725 serialized_name: Some("is_canceled".into()),
726 data_type: DataType::Optional(Box::new(DataType::Boolean)),
727 required: false,
728 default_value: None,
729 description: "Whether the request was canceled by the user".into(),
730 constraints: vec![],
731 semantic_tag: Some("is_canceled".into()),
732 since_version: None,
733 removed_in: None,
734 },
735 FieldSchema {
736 name: "variableData".into(),
737 serialized_name: Some("variable_data".into()),
738 data_type: DataType::Optional(Box::new(DataType::Json)),
739 required: false,
740 default_value: None,
741 description: "Context variables (files, selections, terminal output)".into(),
742 constraints: vec![],
743 semantic_tag: Some("context".into()),
744 since_version: None,
745 removed_in: None,
746 },
747 ],
748 );
749
750 map.insert(
751 "ChatMessage".into(),
752 vec![
753 FieldSchema {
754 name: "text".into(),
755 serialized_name: None,
756 data_type: DataType::Optional(Box::new(DataType::String)),
757 required: false,
758 default_value: None,
759 description: "Message text content".into(),
760 constraints: vec![],
761 semantic_tag: Some("message_text".into()),
762 since_version: None,
763 removed_in: None,
764 },
765 FieldSchema {
766 name: "parts".into(),
767 serialized_name: None,
768 data_type: DataType::Optional(Box::new(DataType::Array(Box::new(DataType::Json)))),
769 required: false,
770 default_value: None,
771 description: "Complex message parts (for multi-modal messages)".into(),
772 constraints: vec![],
773 semantic_tag: Some("message_parts".into()),
774 since_version: None,
775 removed_in: None,
776 },
777 ],
778 );
779
780 map
781}
782
783fn copilot_jsonl_event_fields() -> Vec<FieldSchema> {
788 vec![
789 FieldSchema {
790 name: "kind".into(),
791 serialized_name: None,
792 data_type: DataType::Enum(vec!["0".into(), "1".into(), "2".into()]),
793 required: true,
794 default_value: None,
795 description: "Event kind: 0=full snapshot, 1=request update, 2=response update".into(),
796 constraints: vec![],
797 semantic_tag: Some("event_type".into()),
798 since_version: Some("0.37.0".into()),
799 removed_in: None,
800 },
801 FieldSchema {
802 name: "data".into(),
803 serialized_name: None,
804 data_type: DataType::Json,
805 required: true,
806 default_value: None,
807 description: "Event payload. For kind:0, the full session object. For kind:1/2, update deltas.".into(),
808 constraints: vec![],
809 semantic_tag: Some("event_data".into()),
810 since_version: Some("0.37.0".into()),
811 removed_in: None,
812 },
813 ]
814}
815
816fn copilot_nested_objects_jsonl() -> HashMap<String, Vec<FieldSchema>> {
817 let mut map = copilot_nested_objects_v3();
818
819 if let Some(request_fields) = map.get_mut("ChatRequest") {
821 request_fields.push(FieldSchema {
822 name: "modelState".into(),
823 serialized_name: Some("model_state".into()),
824 data_type: DataType::Optional(Box::new(DataType::Object("ModelState".into()))),
825 required: false,
826 default_value: None,
827 description: "Model processing state. value: 0=Pending, 1=Complete, 2=Cancelled".into(),
828 constraints: vec![],
829 semantic_tag: Some("model_state".into()),
830 since_version: Some("0.37.0".into()),
831 removed_in: None,
832 });
833 request_fields.push(FieldSchema {
834 name: "timeSpentWaiting".into(),
835 serialized_name: Some("time_spent_waiting".into()),
836 data_type: DataType::Optional(Box::new(DataType::Integer)),
837 required: false,
838 default_value: None,
839 description: "Time spent waiting for response (milliseconds)".into(),
840 constraints: vec![],
841 semantic_tag: Some("latency".into()),
842 since_version: Some("0.37.0".into()),
843 removed_in: None,
844 });
845 }
846
847 map.insert(
849 "ModelState".into(),
850 vec![
851 FieldSchema {
852 name: "value".into(),
853 serialized_name: None,
854 data_type: DataType::Enum(vec!["0".into(), "1".into(), "2".into()]),
855 required: true,
856 default_value: None,
857 description: "0=Pending, 1=Complete, 2=Cancelled".into(),
858 constraints: vec![],
859 semantic_tag: Some("completion_state".into()),
860 since_version: Some("0.37.0".into()),
861 removed_in: None,
862 },
863 FieldSchema {
864 name: "completedAt".into(),
865 serialized_name: Some("completed_at".into()),
866 data_type: DataType::Optional(Box::new(DataType::Timestamp)),
867 required: false,
868 default_value: None,
869 description: "Timestamp when the model finished processing".into(),
870 constraints: vec![],
871 semantic_tag: Some("completed_at".into()),
872 since_version: Some("0.37.0".into()),
873 removed_in: None,
874 },
875 ],
876 );
877
878 map
879}
880
881fn copilot_db_keys_json() -> Vec<DbKeySchema> {
886 vec![
887 DbKeySchema {
888 key: "chat.ChatSessionStore.index".into(),
889 description: "Session index mapping session IDs to metadata. Old format uses array of UUID strings.".into(),
890 value_type: DataType::Json,
891 value_fields: vec![
892 FieldSchema {
893 name: "version".into(),
894 serialized_name: None,
895 data_type: DataType::Integer,
896 required: true,
897 default_value: Some(serde_json::json!(1)),
898 description: "Index version".into(),
899 constraints: vec![],
900 semantic_tag: Some("index_version".into()),
901 since_version: None,
902 removed_in: None,
903 },
904 FieldSchema {
905 name: "entries".into(),
906 serialized_name: None,
907 data_type: DataType::Array(Box::new(DataType::Uuid)),
908 required: true,
909 default_value: None,
910 description: "Array of session UUID strings (old format)".into(),
911 constraints: vec![],
912 semantic_tag: Some("session_index".into()),
913 since_version: None,
914 removed_in: Some("0.37.0".into()),
915 },
916 ],
917 required: true,
918 since_version: None,
919 removed_in: None,
920 renamed_to: None,
921 },
922 DbKeySchema {
923 key: "memento/interactive-session".into(),
924 description: "Session input history and active session state".into(),
925 value_type: DataType::Json,
926 value_fields: vec![],
927 required: false,
928 since_version: None,
929 removed_in: None,
930 renamed_to: None,
931 },
932 DbKeySchema {
933 key: "memento/interactive-session-view-copilot".into(),
934 description: "Current active session view state (which session is open)".into(),
935 value_type: DataType::Json,
936 value_fields: vec![],
937 required: false,
938 since_version: None,
939 removed_in: None,
940 renamed_to: None,
941 },
942 ]
943}
944
945fn copilot_db_keys_jsonl() -> Vec<DbKeySchema> {
946 vec![
947 DbKeySchema {
948 key: "chat.ChatSessionStore.index".into(),
949 description: "Session index mapping session IDs to rich metadata entries.".into(),
950 value_type: DataType::Json,
951 value_fields: copilot_index_entry_fields(),
952 required: true,
953 since_version: Some("0.37.0".into()),
954 removed_in: None,
955 renamed_to: None,
956 },
957 DbKeySchema {
958 key: "agentSessions.model.cache".into(),
959 description: "Model cache that drives Chat sidebar visibility. Sessions MUST have entries here to appear in VS Code UI.".into(),
960 value_type: DataType::Array(Box::new(DataType::Object("ModelCacheEntry".into()))),
961 value_fields: copilot_model_cache_fields(),
962 required: true,
963 since_version: Some("0.37.0".into()),
964 removed_in: None,
965 renamed_to: None,
966 },
967 DbKeySchema {
968 key: "agentSessions.state.cache".into(),
969 description: "Session read/archived state for UI indicators".into(),
970 value_type: DataType::Array(Box::new(DataType::Object("StateCacheEntry".into()))),
971 value_fields: copilot_state_cache_fields(),
972 required: false,
973 since_version: Some("0.37.0".into()),
974 removed_in: None,
975 renamed_to: None,
976 },
977 DbKeySchema {
978 key: "memento/interactive-session".into(),
979 description: "Session input history and active session state".into(),
980 value_type: DataType::Json,
981 value_fields: vec![],
982 required: false,
983 since_version: None,
984 removed_in: None,
985 renamed_to: None,
986 },
987 DbKeySchema {
988 key: "memento/interactive-session-view-copilot".into(),
989 description: "Current active session view state (which session is open)".into(),
990 value_type: DataType::Json,
991 value_fields: vec![],
992 required: false,
993 since_version: None,
994 removed_in: None,
995 renamed_to: None,
996 },
997 ]
998}
999
1000fn copilot_index_entry_fields() -> Vec<FieldSchema> {
1001 vec![
1002 FieldSchema {
1003 name: "version".into(),
1004 serialized_name: None,
1005 data_type: DataType::Integer,
1006 required: true,
1007 default_value: Some(serde_json::json!(1)),
1008 description: "Index format version".into(),
1009 constraints: vec![],
1010 semantic_tag: Some("index_version".into()),
1011 since_version: None,
1012 removed_in: None,
1013 },
1014 FieldSchema {
1015 name: "entries".into(),
1016 serialized_name: None,
1017 data_type: DataType::Object("Map<UUID, IndexEntry>".into()),
1018 required: true,
1019 default_value: None,
1020 description: "Map of session UUID → IndexEntry objects (new format)".into(),
1021 constraints: vec![],
1022 semantic_tag: Some("session_index".into()),
1023 since_version: Some("0.37.0".into()),
1024 removed_in: None,
1025 },
1026 ]
1027}
1028
1029fn copilot_model_cache_fields() -> Vec<FieldSchema> {
1030 vec![
1031 FieldSchema {
1032 name: "providerType".into(),
1033 serialized_name: Some("provider_type".into()),
1034 data_type: DataType::String,
1035 required: true,
1036 default_value: Some(serde_json::json!("local")),
1037 description: "Always 'local' for local sessions".into(),
1038 constraints: vec![],
1039 semantic_tag: None,
1040 since_version: Some("0.37.0".into()),
1041 removed_in: None,
1042 },
1043 FieldSchema {
1044 name: "providerLabel".into(),
1045 serialized_name: Some("provider_label".into()),
1046 data_type: DataType::String,
1047 required: true,
1048 default_value: Some(serde_json::json!("Local")),
1049 description: "Always 'Local' for local sessions".into(),
1050 constraints: vec![],
1051 semantic_tag: None,
1052 since_version: Some("0.37.0".into()),
1053 removed_in: None,
1054 },
1055 FieldSchema {
1056 name: "resource".into(),
1057 serialized_name: None,
1058 data_type: DataType::Uri,
1059 required: true,
1060 default_value: None,
1061 description: "Resource URI: vscode-chat-session://local/{base64(sessionId)}".into(),
1062 constraints: vec![FieldConstraint::Pattern {
1063 pattern: "^vscode-chat-session://local/[A-Za-z0-9+/=]+$".into(),
1064 }],
1065 semantic_tag: Some("resource_uri".into()),
1066 since_version: Some("0.37.0".into()),
1067 removed_in: None,
1068 },
1069 FieldSchema {
1070 name: "icon".into(),
1071 serialized_name: None,
1072 data_type: DataType::String,
1073 required: false,
1074 default_value: Some(serde_json::json!("vm")),
1075 description: "Icon identifier for the UI".into(),
1076 constraints: vec![],
1077 semantic_tag: None,
1078 since_version: Some("0.37.0".into()),
1079 removed_in: None,
1080 },
1081 FieldSchema {
1082 name: "label".into(),
1083 serialized_name: None,
1084 data_type: DataType::String,
1085 required: true,
1086 default_value: None,
1087 description: "Session title displayed in sidebar".into(),
1088 constraints: vec![],
1089 semantic_tag: Some("title".into()),
1090 since_version: Some("0.37.0".into()),
1091 removed_in: None,
1092 },
1093 FieldSchema {
1094 name: "status".into(),
1095 serialized_name: None,
1096 data_type: DataType::Integer,
1097 required: true,
1098 default_value: Some(serde_json::json!(1)),
1099 description: "Status: 1 = valid".into(),
1100 constraints: vec![],
1101 semantic_tag: None,
1102 since_version: Some("0.37.0".into()),
1103 removed_in: None,
1104 },
1105 FieldSchema {
1106 name: "timing".into(),
1107 serialized_name: None,
1108 data_type: DataType::Object("ChatSessionTiming".into()),
1109 required: true,
1110 default_value: None,
1111 description: "Session timing (created, lastRequestStarted, lastRequestEnded)".into(),
1112 constraints: vec![],
1113 semantic_tag: Some("timing".into()),
1114 since_version: Some("0.37.0".into()),
1115 removed_in: None,
1116 },
1117 FieldSchema {
1118 name: "isEmpty".into(),
1119 serialized_name: Some("is_empty".into()),
1120 data_type: DataType::Boolean,
1121 required: true,
1122 default_value: Some(serde_json::json!(false)),
1123 description: "Whether the session has no requests. MUST be false for VS Code to load.".into(),
1124 constraints: vec![],
1125 semantic_tag: Some("is_empty".into()),
1126 since_version: Some("0.37.0".into()),
1127 removed_in: None,
1128 },
1129 FieldSchema {
1130 name: "lastResponseState".into(),
1131 serialized_name: Some("last_response_state".into()),
1132 data_type: DataType::Enum(vec![
1133 "0".into(),
1134 "1".into(),
1135 "2".into(),
1136 "3".into(),
1137 "4".into(),
1138 ]),
1139 required: true,
1140 default_value: Some(serde_json::json!(1)),
1141 description: "0=Pending, 1=Complete, 2=Cancelled, 3=Failed, 4=NeedsInput".into(),
1142 constraints: vec![],
1143 semantic_tag: Some("response_state".into()),
1144 since_version: Some("0.37.0".into()),
1145 removed_in: None,
1146 },
1147 ]
1148}
1149
1150fn copilot_state_cache_fields() -> Vec<FieldSchema> {
1151 vec![
1152 FieldSchema {
1153 name: "resource".into(),
1154 serialized_name: None,
1155 data_type: DataType::Uri,
1156 required: true,
1157 default_value: None,
1158 description: "Resource URI (same as model cache)".into(),
1159 constraints: vec![],
1160 semantic_tag: Some("resource_uri".into()),
1161 since_version: Some("0.37.0".into()),
1162 removed_in: None,
1163 },
1164 FieldSchema {
1165 name: "read".into(),
1166 serialized_name: None,
1167 data_type: DataType::Optional(Box::new(DataType::Timestamp)),
1168 required: false,
1169 default_value: None,
1170 description: "Timestamp when the session was last read by the user".into(),
1171 constraints: vec![],
1172 semantic_tag: Some("last_read".into()),
1173 since_version: Some("0.37.0".into()),
1174 removed_in: None,
1175 },
1176 ]
1177}
1178
1179fn cursor_session_fields() -> Vec<FieldSchema> {
1184 let mut fields = copilot_session_fields_v3();
1186 fields.push(FieldSchema {
1188 name: "workspaceId".into(),
1189 serialized_name: Some("workspace_id".into()),
1190 data_type: DataType::Optional(Box::new(DataType::String)),
1191 required: false,
1192 default_value: None,
1193 description: "Cursor workspace identifier".into(),
1194 constraints: vec![],
1195 semantic_tag: Some("workspace_id".into()),
1196 since_version: None,
1197 removed_in: None,
1198 });
1199 fields
1200}
1201
1202fn claude_code_fields() -> Vec<FieldSchema> {
1207 vec![
1208 FieldSchema {
1209 name: "type".into(),
1210 serialized_name: None,
1211 data_type: DataType::Enum(vec![
1212 "human".into(),
1213 "assistant".into(),
1214 "system".into(),
1215 "tool_use".into(),
1216 "tool_result".into(),
1217 ]),
1218 required: true,
1219 default_value: None,
1220 description: "Message event type".into(),
1221 constraints: vec![],
1222 semantic_tag: Some("message_role".into()),
1223 since_version: None,
1224 removed_in: None,
1225 },
1226 FieldSchema {
1227 name: "message".into(),
1228 serialized_name: None,
1229 data_type: DataType::Object("ClaudeMessage".into()),
1230 required: true,
1231 default_value: None,
1232 description: "Message content object with role and content fields".into(),
1233 constraints: vec![],
1234 semantic_tag: Some("message".into()),
1235 since_version: None,
1236 removed_in: None,
1237 },
1238 FieldSchema {
1239 name: "timestamp".into(),
1240 serialized_name: None,
1241 data_type: DataType::String,
1242 required: false,
1243 default_value: None,
1244 description: "ISO 8601 timestamp".into(),
1245 constraints: vec![],
1246 semantic_tag: Some("message_timestamp".into()),
1247 since_version: None,
1248 removed_in: None,
1249 },
1250 FieldSchema {
1251 name: "costUSD".into(),
1252 serialized_name: Some("cost_usd".into()),
1253 data_type: DataType::Optional(Box::new(DataType::Float)),
1254 required: false,
1255 default_value: None,
1256 description: "Cost in USD for this message".into(),
1257 constraints: vec![],
1258 semantic_tag: Some("cost".into()),
1259 since_version: None,
1260 removed_in: None,
1261 },
1262 FieldSchema {
1263 name: "durationMs".into(),
1264 serialized_name: Some("duration_ms".into()),
1265 data_type: DataType::Optional(Box::new(DataType::Integer)),
1266 required: false,
1267 default_value: None,
1268 description: "Processing duration in milliseconds".into(),
1269 constraints: vec![],
1270 semantic_tag: Some("latency".into()),
1271 since_version: None,
1272 removed_in: None,
1273 },
1274 ]
1275}
1276
1277fn codex_cli_fields() -> Vec<FieldSchema> {
1282 vec![
1283 FieldSchema {
1284 name: "role".into(),
1285 serialized_name: None,
1286 data_type: DataType::Enum(vec![
1287 "system".into(),
1288 "user".into(),
1289 "assistant".into(),
1290 "tool".into(),
1291 ]),
1292 required: true,
1293 default_value: None,
1294 description: "Message role (OpenAI format)".into(),
1295 constraints: vec![],
1296 semantic_tag: Some("message_role".into()),
1297 since_version: None,
1298 removed_in: None,
1299 },
1300 FieldSchema {
1301 name: "content".into(),
1302 serialized_name: None,
1303 data_type: DataType::String,
1304 required: true,
1305 default_value: None,
1306 description: "Message content text".into(),
1307 constraints: vec![],
1308 semantic_tag: Some("message_text".into()),
1309 since_version: None,
1310 removed_in: None,
1311 },
1312 FieldSchema {
1313 name: "timestamp".into(),
1314 serialized_name: None,
1315 data_type: DataType::Optional(Box::new(DataType::Timestamp)),
1316 required: false,
1317 default_value: None,
1318 description: "Message timestamp".into(),
1319 constraints: vec![],
1320 semantic_tag: Some("message_timestamp".into()),
1321 since_version: None,
1322 removed_in: None,
1323 },
1324 ]
1325}
1326
1327fn gemini_cli_fields() -> Vec<FieldSchema> {
1332 vec![
1333 FieldSchema {
1334 name: "role".into(),
1335 serialized_name: None,
1336 data_type: DataType::Enum(vec!["user".into(), "model".into()]),
1337 required: true,
1338 default_value: None,
1339 description: "Message role (Gemini uses 'model' for assistant)".into(),
1340 constraints: vec![],
1341 semantic_tag: Some("message_role".into()),
1342 since_version: None,
1343 removed_in: None,
1344 },
1345 FieldSchema {
1346 name: "parts".into(),
1347 serialized_name: None,
1348 data_type: DataType::Array(Box::new(DataType::Object("GeminiPart".into()))),
1349 required: true,
1350 default_value: None,
1351 description: "Content parts array (Gemini multi-part format)".into(),
1352 constraints: vec![],
1353 semantic_tag: Some("message_parts".into()),
1354 since_version: None,
1355 removed_in: None,
1356 },
1357 ]
1358}
1359
1360fn continue_dev_fields() -> Vec<FieldSchema> {
1365 vec![
1366 FieldSchema {
1367 name: "sessionId".into(),
1368 serialized_name: Some("session_id".into()),
1369 data_type: DataType::Uuid,
1370 required: true,
1371 default_value: None,
1372 description: "Session identifier".into(),
1373 constraints: vec![],
1374 semantic_tag: Some("session_id".into()),
1375 since_version: None,
1376 removed_in: None,
1377 },
1378 FieldSchema {
1379 name: "title".into(),
1380 serialized_name: None,
1381 data_type: DataType::Optional(Box::new(DataType::String)),
1382 required: false,
1383 default_value: None,
1384 description: "Session title".into(),
1385 constraints: vec![],
1386 semantic_tag: Some("title".into()),
1387 since_version: None,
1388 removed_in: None,
1389 },
1390 FieldSchema {
1391 name: "dateCreated".into(),
1392 serialized_name: Some("date_created".into()),
1393 data_type: DataType::String,
1394 required: true,
1395 default_value: None,
1396 description: "ISO 8601 creation date".into(),
1397 constraints: vec![],
1398 semantic_tag: Some("created_at".into()),
1399 since_version: None,
1400 removed_in: None,
1401 },
1402 FieldSchema {
1403 name: "history".into(),
1404 serialized_name: None,
1405 data_type: DataType::Array(Box::new(DataType::Object("ContinueMessage".into()))),
1406 required: true,
1407 default_value: None,
1408 description: "Array of history step objects".into(),
1409 constraints: vec![],
1410 semantic_tag: Some("messages".into()),
1411 since_version: None,
1412 removed_in: None,
1413 },
1414 ]
1415}
1416
1417fn openai_api_fields() -> Vec<FieldSchema> {
1422 vec![
1423 FieldSchema {
1424 name: "model".into(),
1425 serialized_name: None,
1426 data_type: DataType::String,
1427 required: true,
1428 default_value: None,
1429 description: "Model identifier (e.g., 'gpt-4o', 'llama3.3')".into(),
1430 constraints: vec![],
1431 semantic_tag: Some("model_id".into()),
1432 since_version: None,
1433 removed_in: None,
1434 },
1435 FieldSchema {
1436 name: "messages".into(),
1437 serialized_name: None,
1438 data_type: DataType::Array(Box::new(DataType::Object("OpenAIMessage".into()))),
1439 required: true,
1440 default_value: None,
1441 description: "Array of message objects with role and content".into(),
1442 constraints: vec![],
1443 semantic_tag: Some("messages".into()),
1444 since_version: None,
1445 removed_in: None,
1446 },
1447 FieldSchema {
1448 name: "temperature".into(),
1449 serialized_name: None,
1450 data_type: DataType::Optional(Box::new(DataType::Float)),
1451 required: false,
1452 default_value: Some(serde_json::json!(1.0)),
1453 description: "Sampling temperature (0.0 – 2.0)".into(),
1454 constraints: vec![
1455 FieldConstraint::Min {
1456 value: serde_json::json!(0.0),
1457 },
1458 FieldConstraint::Max {
1459 value: serde_json::json!(2.0),
1460 },
1461 ],
1462 semantic_tag: Some("temperature".into()),
1463 since_version: None,
1464 removed_in: None,
1465 },
1466 FieldSchema {
1467 name: "tools".into(),
1468 serialized_name: None,
1469 data_type: DataType::Optional(Box::new(DataType::Array(Box::new(DataType::Object(
1470 "Tool".into(),
1471 ))))),
1472 required: false,
1473 default_value: None,
1474 description: "Available tools/functions for function calling".into(),
1475 constraints: vec![],
1476 semantic_tag: Some("tools".into()),
1477 since_version: None,
1478 removed_in: None,
1479 },
1480 FieldSchema {
1481 name: "stream".into(),
1482 serialized_name: None,
1483 data_type: DataType::Optional(Box::new(DataType::Boolean)),
1484 required: false,
1485 default_value: Some(serde_json::json!(false)),
1486 description: "Whether to stream the response".into(),
1487 constraints: vec![],
1488 semantic_tag: Some("streaming".into()),
1489 since_version: None,
1490 removed_in: None,
1491 },
1492 ]
1493}
1494
1495fn openai_api_nested_objects() -> HashMap<String, Vec<FieldSchema>> {
1496 let mut map = HashMap::new();
1497
1498 map.insert(
1499 "OpenAIMessage".into(),
1500 vec![
1501 FieldSchema {
1502 name: "role".into(),
1503 serialized_name: None,
1504 data_type: DataType::Enum(vec![
1505 "system".into(),
1506 "user".into(),
1507 "assistant".into(),
1508 "tool".into(),
1509 ]),
1510 required: true,
1511 default_value: None,
1512 description: "Message role".into(),
1513 constraints: vec![],
1514 semantic_tag: Some("message_role".into()),
1515 since_version: None,
1516 removed_in: None,
1517 },
1518 FieldSchema {
1519 name: "content".into(),
1520 serialized_name: None,
1521 data_type: DataType::String,
1522 required: true,
1523 default_value: None,
1524 description: "Message content".into(),
1525 constraints: vec![],
1526 semantic_tag: Some("message_text".into()),
1527 since_version: None,
1528 removed_in: None,
1529 },
1530 FieldSchema {
1531 name: "tool_calls".into(),
1532 serialized_name: None,
1533 data_type: DataType::Optional(Box::new(DataType::Array(Box::new(DataType::Object(
1534 "ToolCall".into(),
1535 ))))),
1536 required: false,
1537 default_value: None,
1538 description: "Tool/function calls made by the assistant".into(),
1539 constraints: vec![],
1540 semantic_tag: Some("tool_calls".into()),
1541 since_version: None,
1542 removed_in: None,
1543 },
1544 ],
1545 );
1546
1547 map
1548}