Skip to main content

vtcode_core/open_responses/
mod.rs

1//! Open Responses specification conformance layer.
2//!
3//! This module implements the [Open Responses](https://www.openresponses.org/) specification
4//! for vendor-neutral LLM interfaces. It provides:
5//!
6//! - Unified item types with state machine semantics
7//! - Semantic streaming events (not raw token deltas)
8//! - Response objects with standardized structure
9//! - Error handling with structured error types
10//! - Extension points for VT Code-specific item types
11//!
12//! The implementation bridges VT Code's internal event system (`ThreadEvent`)
13//! to Open Responses-compliant structures while maintaining backwards compatibility.
14
15mod bridge;
16mod content;
17mod error;
18mod events;
19mod integration;
20mod items;
21mod request;
22mod response;
23mod status;
24mod usage;
25
26pub use bridge::{DualEventEmitter, ResponseBuilder};
27pub use content::{ContentPart, ContentPartId, ImageDetail, InputFileContent, InputImageContent};
28pub use error::{OpenResponseError, OpenResponseErrorCode, OpenResponseErrorType};
29pub use events::{ResponseStreamEvent, SequencedEvent, StreamEventEmitter, VecStreamEmitter};
30pub use integration::{
31    OpenResponsesCallback, OpenResponsesIntegration, OpenResponsesProvider, ToOpenResponse,
32};
33pub use items::{
34    CustomItem, FunctionCallItem, FunctionCallOutputItem, MessageItem, MessageRole, OutputItem,
35    OutputItemId, ReasoningItem,
36};
37pub use request::{Request, SpecificToolChoice, ToolChoice, ToolChoiceMode};
38pub use response::{
39    IncompleteDetails, IncompleteReason, Response, ResponseId, ResponseStatus, generate_item_id,
40    generate_response_id,
41};
42pub use status::ItemStatus;
43pub use usage::{InputTokensDetails, OpenUsage, OutputTokensDetails};
44
45/// VT Code extension prefix for custom item types and events.
46pub const VTCODE_EXTENSION_PREFIX: &str = "vtcode";
47
48/// Validates that a custom type follows the Open Responses extension naming convention.
49/// Custom types must be prefixed with an implementor slug (e.g., `vtcode:file_change`).
50pub fn is_valid_extension_type(type_name: &str) -> bool {
51    if let Some((prefix, name)) = type_name.split_once(':') {
52        !prefix.is_empty()
53            && !name.is_empty()
54            && prefix
55                .chars()
56                .all(|c| c.is_ascii_alphanumeric() || c == '_')
57            && name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
58    } else {
59        false
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn test_valid_extension_types() {
69        assert!(is_valid_extension_type("vtcode:file_change"));
70        assert!(is_valid_extension_type("acme:search_result"));
71        assert!(is_valid_extension_type("openai:web_search_call"));
72    }
73
74    #[test]
75    fn test_invalid_extension_types() {
76        assert!(!is_valid_extension_type("file_change"));
77        assert!(!is_valid_extension_type(":file_change"));
78        assert!(!is_valid_extension_type("vtcode:"));
79        assert!(!is_valid_extension_type("vt-code:file_change"));
80        assert!(!is_valid_extension_type(""));
81    }
82}