Core protocols and utilities for working with Large Language Models (LLMs). This module provides the foundation for all LangTools implementations.
The primary protocol for LLM service implementations:
public protocol LangTools {
associatedtype Model: RawRepresentable
associatedtype ErrorResponse: Codable & Error
func perform<Request: LangToolsRequest>(request: Request) async throws -> Request.Response
func stream<Request: LangToolsStreamableRequest>(request: Request) -> AsyncThrowingStream<Request.Response, Error>
static var requestValidators: [(any LangToolsRequest) -> Bool] { get }
static func chatRequest(model: Model, messages: [any LangToolsMessage], tools: [any LangToolsTool]?, toolEventHandler: @escaping (LangToolsToolEvent) -> Void) throws -> any LangToolsChatRequest
}
Base protocol for all requests:
public protocol LangToolsRequest: Encodable {
associatedtype Response: Decodable
associatedtype LangTool: LangTools
static var endpoint: String { get }
static var httpMethod: HTTPMethod { get }
}
Protocol for chat-based interactions:
public protocol LangToolsChatRequest: LangToolsRequest where Response: LangToolsChatResponse {
associatedtype Message: LangToolsMessage
var messages: [Message] { get set }
}
Protocol for streaming responses:
public protocol LangToolsStreamableRequest: LangToolsRequest where Response: LangToolsStreamableResponse {
var stream: Bool? { get set }
}
Protocol for chat messages:
public protocol LangToolsMessage: Codable {
associatedtype Role: LangToolsRole
associatedtype Content: LangToolsContent
var role: Role { get }
var content: Content { get }
}
Protocol for message roles:
public protocol LangToolsRole: Codable, Hashable {
var isAssistant: Bool { get }
var isUser: Bool { get }
var isSystem: Bool { get }
var isTool: Bool { get }
}
Protocol for tool definitions:
public protocol LangToolsTool: Codable {
associatedtype ToolSchema: LangToolsToolSchema
var name: String { get }
var description: String? { get }
var tool_schema: ToolSchema { get }
var callback: (([String:JSON]) async throws -> String?)? { get }
}
The framework provides standard error types:
public enum LangToolError: Error {
case invalidData
case streamParsingFailure
case invalidURL
case requestFailed
case invalidContentType
case jsonParsingFailure(Error)
case responseUnsuccessful(statusCode: Int, Error?)
case apiError(Codable & Error)
case failiedToDecodeStream(buffer: String, error: Error)
}
The framework includes a flexible JSON type for handling dynamic data:
public enum JSON: Codable {
case string(String)
case number(Double)
case bool(Bool)
case object([String: JSON])
case array([JSON])
case null
// Convenience accessors
var stringValue: String?
var doubleValue: Double?
var intValue: Int?
var boolValue: Bool?
var arrayValue: [JSON]?
var objectValue: [String: JSON]?
}
-
Request Validation
- Implement
requestValidators
to verify request compatibility - Check model support and request parameters
- Validate before sending to the API
- Implement
-
Error Handling
- Use specific error types for better error handling
- Provide detailed error messages
- Handle network and parsing errors appropriately
-
Streaming
- Implement proper buffer management
- Handle partial responses correctly
- Maintain state during streaming
-
Tool Integration
- Define clear tool schemas
- Implement robust argument parsing
- Handle tool errors gracefully
-
Response Processing
- Validate response data
- Handle different content types
- Process streaming chunks efficiently
extension LangTools {
public func systemMessage(_ message: String) -> any LangToolsMessage {
LangToolsMessageImpl(role: .system, string: message)
}
public func assistantMessage(_ message: String) -> any LangToolsMessage {
LangToolsMessageImpl(role: .assistant, string: message)
}
public func userMessage(_ message: String) -> any LangToolsMessage {
LangToolsMessageImpl(role: .user, string: message)
}
}
let tool = Tool(
name: "my_tool",
description: "Tool description",
tool_schema: .init(
properties: [
"param": .init(
type: "string",
description: "Parameter description"
)
],
required: ["param"]
),
callback: { args in
// Tool implementation
return "Result"
}
)
For implementation examples, see: