Outputs are the results generated by agents executing tasks within orbits. OrbitAI provides a comprehensive output system that supports multiple formats, type-safe structured data, and rich metadata about execution.
public struct TaskOutput { let rawOutput: String // The actual content let usageMetrics: UsageMetrics // Token usage let toolsUsed: [ToolUsage] // Tool execution data let agentId: OrbitAIID // Which agent produced this let taskId: OrbitAIID // For which task let timestamp: Date // When it was generated}
Type Safety
Use Swift’s type system for compile-time safety:
Copy
struct Report: Codable, Sendable { let title: String let summary: String let findings: [Finding]}// Type-safe accesslet report: Report = try output.decode(as: Report.self)// Compiler ensures correct types
Error Recovery
Automatic fallback strategies for parsing failures:
Copy
// Attempts multiple parsing strategieslet data = try output.decodeWithFallback(as: Report.self)// Fallback order:// 1. Direct decode// 2. Unwrap common wrappers// 3. Normalize field names// 4. Partial extraction with defaults// 5. Clean markdown artifacts
public struct TaskOutput: Codable, Sendable { // Core content public let rawOutput: String public let structuredOutput: StructuredOutput? // Execution metadata public let usageMetrics: UsageMetrics public let toolsUsed: [ToolUsage] // Traceability public let agentId: OrbitAIID public let taskId: OrbitAIID public let timestamp: Date // Validation (if applicable) public let validationResult: TaskValidationResult?}
Property
Type
Description
rawOutput
String
Raw text output from agent
structuredOutput
StructuredOutput?
Parsed structured data
usageMetrics
UsageMetrics
Token and API usage stats
toolsUsed
[ToolUsage]
Tools executed during task
agentId
OrbitAIID
Agent that produced output
taskId
OrbitAIID
Task that was executed
timestamp
Date
When output was generated
validationResult
TaskValidationResult?
Manager validation result
Copy
// TaskOutput is typically created by the system// But you can create manually if neededlet output = TaskOutput( rawOutput: "Analysis complete. Found 42 anomalies.", structuredOutput: nil, usageMetrics: UsageMetrics( promptTokens: 150, completionTokens: 50, totalTokens: 200, successfulRequests: 1, totalRequests: 1 ), toolsUsed: [ ToolUsage( toolName: "data_analyzer", executionTime: 2.5, success: true, inputSize: 1024, outputSize: 512 ) ], agentId: analyst.id, taskId: task.id, timestamp: Date())
// Define expected structurestruct AnalysisResult: Codable, Sendable { let summary: String let anomalies: Int let severity: String let recommendations: [String]}// Decode with type safetydo { let result = try output.decode(as: AnalysisResult.self) print("Summary: \(result.summary)") print("Anomalies: \(result.anomalies)") print("Severity: \(result.severity)") for rec in result.recommendations { print("- \(rec)") }} catch { print("Failed to decode: \(error)") // Fall back to raw output print("Raw: \(output.rawOutput)")}
The aggregated result from an entire orbit execution.
Structure
Accessing
Filtering Results
Exporting
Copy
public struct OrbitOutput: Codable, Sendable { // Task results public let taskOutputs: [TaskOutput] // Aggregated metrics public let usageMetrics: UsageMetrics // Execution timing public let executionTime: TimeInterval // Orbit metadata public let orbitId: OrbitAIID public let orbitName: String public let completedAt: Date // Process information public let processType: Process?}
Property
Type
Description
taskOutputs
[TaskOutput]
All task results in order
usageMetrics
UsageMetrics
Total usage across all tasks
executionTime
TimeInterval
Total execution duration
orbitId
OrbitAIID
Orbit identifier
orbitName
String
Human-readable orbit name
completedAt
Date
Completion timestamp
processType
Process?
Sequential/Hierarchical/etc
Copy
let result = try await orbit.start()// Access all outputsprint("Total tasks: \(result.taskOutputs.count)")for (index, output) in result.taskOutputs.enumerated() { print("\n=== Task \(index) ===") print("Output: \(output.rawOutput)") print("Agent: \(output.agentId)") print("Tokens: \(output.usageMetrics.totalTokens)")}// Aggregated metricsprint("\n=== Total Metrics ===")print("Tokens: \(result.usageMetrics.totalTokens)")print(" Prompt: \(result.usageMetrics.promptTokens)")print(" Completion: \(result.usageMetrics.completionTokens)")print("API calls: \(result.usageMetrics.totalRequests)")print("Success rate: \(result.usageMetrics.successfulRequests)/\(result.usageMetrics.totalRequests)")// Timingprint("\nExecution time: \(result.executionTime)s")print("Completed: \(result.completedAt)")
Copy
let result = try await orbit.start()// Get outputs from specific agentlet analystOutputs = result.taskOutputs.filter { $0.agentId == analystAgent.id}// Get outputs that used specific toollet searchOutputs = result.taskOutputs.filter { $0.toolsUsed.contains { $0.toolName == "web_search" }}// Find longest executionlet longest = result.taskOutputs.max { ($0.usageMetrics.totalTokens) < ($1.usageMetrics.totalTokens)}// Calculate average execution time per tasklet avgTime = result.executionTime / Double(result.taskOutputs.count)print("Average time per task: \(avgTime)s")
Parsed structured data with optional schema validation.
Structure
Creating
Validation
Copy
public struct StructuredOutput: Codable, Sendable { // Parsed data public let data: Metadata // Schema (if validated) public let schema: JSONSchema? // Validation result public let isValid: Bool public let validationErrors: [String]? // Original raw output public let rawJSON: String}
OrbitAI supports multiple output formats to suit different use cases.
Text
JSON
Markdown
CSV
XML
Structured
Format: Plain text output
Copy
let task = ORTask( description: "Summarize the article", expectedOutput: "Brief summary in plain text", outputFormat: .text // Default)let result = try await orbit.start()let output = result.taskOutputs.first!// Access as stringprint(output.rawOutput)// "The article discusses AI trends in healthcare..."
Use Cases:
Human-readable reports
Summaries
Descriptions
General text generation
Format: Generic JSON output
Copy
let task = ORTask( description: "Generate product data in JSON format", expectedOutput: "JSON object with product details", outputFormat: .json)let result = try await orbit.start()let output = result.taskOutputs.first!// Parse JSONif let jsonData = output.rawOutput.data(using: .utf8), let json = try? JSONSerialization.jsonObject(with: jsonData) as? [String: Any] { print("Product name: \(json["name"] ?? "")") print("Price: \(json["price"] ?? 0)")}// Or use structured outputif let structured = output.structuredOutput { print("Name: \(structured.data["name"]?.stringValue ?? "")")}
Use Cases:
API responses
Data interchange
Configuration files
Flexible structures
Format: Markdown formatted text
Copy
let task = ORTask( description: "Write documentation", expectedOutput: "Documentation in Markdown format", outputFormat: .markdown)let result = try await orbit.start()let output = result.taskOutputs.first!// Output is markdown-formattedprint(output.rawOutput)// # Documentation// ## Section 1// Content here...// Save as .md filetry output.rawOutput.write( to: URL(fileURLWithPath: "./docs.md"), atomically: true, encoding: .utf8)
Use Cases:
Documentation
Blog posts
README files
Technical writing
Format: Comma-separated values
Copy
let task = ORTask( description: "Generate sales report", expectedOutput: "CSV with sales data", outputFormat: .csv)let result = try await orbit.start()let output = result.taskOutputs.first!// Output is CSV formatprint(output.rawOutput)// Date,Product,Quantity,Revenue// 2024-01-01,Widget A,100,1000.00// 2024-01-02,Widget B,150,1500.00// Save as CSVtry output.rawOutput.write( to: URL(fileURLWithPath: "./sales.csv"), atomically: true, encoding: .utf8)// Parse CSVlet rows = output.rawOutput.components(separatedBy: "\n")for row in rows { let columns = row.components(separatedBy: ",") print(columns)}
Use Cases:
Data exports
Spreadsheet imports
Tabular data
Reports
Format: XML structured output
Copy
let task = ORTask( description: "Generate configuration", expectedOutput: "Configuration in XML format", outputFormat: .xml)let result = try await orbit.start()let output = result.taskOutputs.first!// Output is XML formatprint(output.rawOutput)// <?xml version="1.0"?>// <config>// <setting name="timeout">30</setting>// <setting name="retries">3</setting>// </config>// Parse XMLlet xmlData = output.rawOutput.data(using: .utf8)!let parser = XMLParser(data: xmlData)// ... XML parsing logic
Use Cases:
Legacy system integration
Configuration files
SOAP APIs
Structured documents
Format: Type-safe structured output with schema
Copy
// Define schemalet schema = JSONSchema( type: .object, properties: [ "name": JSONSchema(type: .string), "age": JSONSchema(type: .integer), "email": JSONSchema(type: .string) ], required: ["name", "email"])let task = ORTask( description: "Generate user profile", expectedOutput: "User profile data", outputFormat: .structured(schema))let result = try await orbit.start()let output = result.taskOutputs.first!// Access validated structured outputif let structured = output.structuredOutput { if structured.isValid { let name = structured.data["name"]?.stringValue let age = structured.data["age"]?.intValue let email = structured.data["email"]?.stringValue print("User: \(name ?? "Unknown")") print("Age: \(age ?? 0)") print("Email: \(email ?? "N/A")") }}
Create a Codable struct representing your desired output:
Copy
struct AnalysisReport: Codable, Sendable { let title: String let executiveSummary: String let findings: [Finding] let recommendations: [Recommendation] let metadata: Metadata struct Finding: Codable, Sendable { let category: String let description: String let severity: Severity let evidence: [String] } struct Recommendation: Codable, Sendable { let title: String let description: String let priority: Priority let estimatedImpact: String } struct Metadata: Codable, Sendable { let analysisDate: Date let analyst: String let confidence: Double let version: String } enum Severity: String, Codable { case critical, high, medium, low } enum Priority: String, Codable { case urgent, high, medium, low }}
Use nested types to organize complex data structures logically.
2
Create Task with Structured Output
Use the withStructuredOutput factory method:
Copy
let task = ORTask.withStructuredOutput( description: """ Analyze the Q4 2024 business performance data and generate a comprehensive report with findings and recommendations. Focus on: - Revenue trends - Cost analysis - Market position - Growth opportunities """, expectedType: AnalysisReport.self, agent: analystAgent.id, context: [dataTask.id])
The system automatically:
Generates appropriate JSON schema from the type
Instructs the LLM to return structured JSON
Validates the output against the schema
Provides type-safe decoding
3
Execute and Access
Execute the orbit and decode the structured output:
Copy
let orbit = try await Orbit.create( name: "Business Analysis", agents: [analystAgent], tasks: [task])let result = try await orbit.start()// Type-safe decodingif let output = result.taskOutputs.first { do { let report = try output.decode(as: AnalysisReport.self) // Access with full type safety print("Title: \(report.title)") print("Summary: \(report.executiveSummary)") print("\nFindings (\(report.findings.count)):") for finding in report.findings { print("- [\(finding.severity)] \(finding.category)") print(" \(finding.description)") } print("\nRecommendations:") for rec in report.recommendations { print("- [\(rec.priority)] \(rec.title)") } print("\nConfidence: \(report.metadata.confidence)") } catch { print("Decoding failed: \(error)") // Fall back to raw output print("Raw output: \(output.rawOutput)") }}
4
Handle Decoding Errors
Implement fallback strategies:
Copy
// Try with automatic fallbacklet report = try output.decodeWithFallback(as: AnalysisReport.self)// Or handle explicitlydo { let report = try output.decode(as: AnalysisReport.self) processReport(report)} catch DecodingError.keyNotFound(let key, _) { print("Missing key: \(key.stringValue)") // Try partial decode or use defaults} catch DecodingError.typeMismatch(let type, let context) { print("Type mismatch for \(type) at \(context.codingPath)") // Try type coercion} catch { print("Unexpected error: \(error)") // Fall back to raw output processing}
struct Customer: Codable, Sendable { let id: UUID let name: String let email: String let phone: String let address: Address struct Address: Codable, Sendable { let street: String let city: String let state: String let zip: String }}// Generate customer datalet task = ORTask.withStructuredOutput( description: "Generate customer record from form data", expectedType: Customer.self, agent: dataAgent.id)let result = try await orbit.start()let customer = try result.taskOutputs.first!.decode(as: Customer.self)// Insert into databasetry await database.insert(customer)
API Responses
Copy
struct APIResponse: Codable, Sendable { let status: String let data: ResponseData let metadata: ResponseMetadata struct ResponseData: Codable, Sendable { let items: [Item] let total: Int let page: Int } struct ResponseMetadata: Codable, Sendable { let requestId: String let timestamp: Date let version: String }}// Generate API responselet task = ORTask.withStructuredOutput( description: "Format query results as API response", expectedType: APIResponse.self, agent: apiAgent.id)let result = try await orbit.start()let response = try result.taskOutputs.first!.decode(as: APIResponse.self)// Return as HTTP responselet encoder = JSONEncoder()encoder.dateEncodingStrategy = .iso8601let jsonData = try encoder.encode(response)return Response(body: jsonData, contentType: .json)
UI Rendering
Copy
struct DashboardData: Codable, Sendable { let title: String let widgets: [Widget] let refreshInterval: Int struct Widget: Codable, Sendable { let id: String let type: WidgetType let title: String let data: Metadata let position: Position enum WidgetType: String, Codable { case chart, table, metric, text } struct Position: Codable, Sendable { let x: Int let y: Int let width: Int let height: Int } }}// Generate dashboard configurationlet task = ORTask.withStructuredOutput( description: "Create dashboard layout for sales metrics", expectedType: DashboardData.self, agent: uiAgent.id)let result = try await orbit.start()let dashboard = try result.taskOutputs.first!.decode(as: DashboardData.self)// Render UIawait renderDashboard(dashboard)
Workflow Chaining
Copy
// Task 1: Generate structured datastruct Analysis: Codable, Sendable { let insights: [String] let metrics: [String: Double]}let analysisTask = ORTask.withStructuredOutput( description: "Analyze data and generate insights", expectedType: Analysis.self, agent: analystAgent.id)// Task 2: Use structured output from Task 1struct Report: Codable, Sendable { let summary: String let details: [Detail]}let reportTask = ORTask.withStructuredOutput( description: """ Create report based on analysis: {task_0_output} """, expectedType: Report.self, agent: reportAgent.id, context: [analysisTask.id])// Execute workflowlet result = try await orbit.start()// Access both structured outputslet analysis = try result.taskOutputs[0].decode(as: Analysis.self)let report = try result.taskOutputs[1].decode(as: Report.self)print("Insights: \(analysis.insights.count)")print("Report sections: \(report.details.count)")
// If some fields missing, use defaultsstruct PartialUser: Codable { let name: String let email: String let age: Int = 0 // Default let phone: String? = nil // Optional}
5
Markdown Cleaning
Remove markdown formatting artifacts:
Copy
let cleaned = jsonString .replacingOccurrences(of: "```json", with: "") .replacingOccurrences(of: "```", with: "") .trimmingCharacters(in: .whitespacesAndNewlines)// Try parsing cleaned version
do { let result = try await orbit.start() guard let output = result.taskOutputs.first else { throw OrbitAIError.taskExecutionFailed( "No output generated" ) }} catch { print("Error: \(error)")}
Causes:
Task failed silently
Agent produced empty response
Output filtering removed content
Malformed JSON
Error: Cannot parse JSON output
Copy
do { let data = try output.decode(as: Report.self)} catch DecodingError.dataCorrupted { print("Invalid JSON format") // Use fallback parsing let data = try output.decodeWithFallback(as: Report.self)}
Causes:
LLM generated invalid JSON
Extra text before/after JSON
Unclosed brackets/quotes
Schema Mismatch
Error: Output doesn’t match expected structure
Copy
do { let data = try output.decode(as: Report.self)} catch DecodingError.keyNotFound(let key, _) { print("Missing field: \(key.stringValue)")} catch DecodingError.typeMismatch(let type, _) { print("Wrong type for field: \(type)")}
Causes:
LLM misunderstood schema
Field name variations
Type differences
Empty Content
Error: Output exists but content is empty
Copy
let output = result.taskOutputs.first!if output.rawOutput.isEmpty { print("Warning: Empty output") // Check if task failed if let task = orbit.tasks.first { print("Task status: \(task.status)") }}
// Good: Logical organizationstruct Report: Codable { let metadata: Metadata let content: Content let appendices: [Appendix] struct Metadata: Codable { let title: String let author: String let date: Date }}// Bad: Flat, disorganizedstruct Report: Codable { let title: String let thing1: String let data: [String] let misc: String}
Appropriate Types
Do: Use specific types
Copy
// Goodstruct Product: Codable { let id: UUID let price: Decimal let inStock: Bool let category: Category enum Category: String, Codable { case electronics, clothing, books }}// Badstruct Product: Codable { let id: String // Should be UUID let price: String // Should be number let inStock: String // Should be Bool let category: String // Should be enum}
Optional vs Required
Do: Make intentional choices
Copy
struct User: Codable { // Required fields let id: UUID let email: String let name: String // Optional fields let phone: String? let bio: String? let avatar: URL? // With defaults let role: String = "user" let active: Bool = true}
Documentation
Do: Document expected structures
Copy
/// Represents an analysis report with findings/// and recommendations.struct AnalysisReport: Codable { /// Report title (max 100 chars) let title: String /// Executive summary (200-500 words) let summary: String /// Detailed findings (3-10 items) let findings: [Finding] /// Actionable recommendations (min 2) let recommendations: [Recommendation]}
// Good: Concise outputsstruct Summary: Codable { let keyPoints: [String] // Top 5 only let metrics: [String: Double] // Essential metrics}// Avoid: Unnecessarily large outputsstruct VerboseSummary: Codable { let entireDocument: String // Don't include full text let everyMetric: [String: Any] // Don't include everything}
2
Use Streaming for Large Outputs
Copy
// For large content generationlet stream = try await manager.generateStreamingCompletion( request: request)var fullOutput = ""for try await chunk in stream { fullOutput += chunk.content ?? "" // Process incrementally await updateUI(chunk.content)}
3
Cache Common Outputs
Copy
actor OutputCache { private var cache: [String: TaskOutput] = [:] func get(_ key: String) -> TaskOutput? { return cache[key] } func set(_ key: String, output: TaskOutput) { cache[key] = output }}// Use for repeated querieslet cacheKey = "\(task.description)-\(inputs.hashValue)"if let cached = await cache.get(cacheKey) { return cached}
struct Analysis: Codable { let status: Status let priority: Priority let category: Category enum Status: String, Codable { case pending, inProgress, completed, failed } enum Priority: String, Codable { case low, medium, high, critical } enum Category: String, Codable { case bug, feature, improvement, documentation }}// Type-safe accessif analysis.priority == .critical { // Handle critical priority}
Use Nested Types
Copy
struct Order: Codable { let id: UUID let customer: Customer let items: [Item] let payment: Payment let shipping: Shipping struct Customer: Codable { let id: UUID let name: String let email: String } struct Item: Codable { let productId: UUID let quantity: Int let price: Decimal } struct Payment: Codable { let method: PaymentMethod let amount: Decimal let status: PaymentStatus enum PaymentMethod: String, Codable { case card, paypal, bankTransfer } enum PaymentStatus: String, Codable { case pending, completed, failed } } struct Shipping: Codable { let address: Address let method: ShippingMethod let tracking: String? struct Address: Codable { let street: String let city: String let state: String let zip: String let country: String } enum ShippingMethod: String, Codable { case standard, express, overnight } }}
// Expected Int, got Stringstruct Data: Codable { let count: Int}// LLM output: {"count": "42"}// Expected Array, got single valuestruct Data: Codable { let tags: [String]}// LLM output: {"tags": "tag1"}
Solutions:
Copy
// Use flexible typesstruct FlexibleData: Codable { let count: FlexibleInt let tags: FlexibleArray<String>}// Custom decodingstruct Data: Codable { let count: Int init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // Try Int first, then String if let intValue = try? container.decode(Int.self, forKey: .count) { count = intValue } else if let stringValue = try? container.decode(String.self, forKey: .count), let intValue = Int(stringValue) { count = intValue } else { count = 0 // Default } }}
Incomplete Outputs
Symptoms: Output missing expected fieldsDebug:
Copy
do { let report = try output.decode(as: Report.self)} catch DecodingError.keyNotFound(let key, let context) { print("Missing key: \(key.stringValue)") print("Context: \(context.codingPath)") print("Debug description: \(context.debugDescription)") // Check what's actually present if let json = try? JSONSerialization.jsonObject( with: output.rawOutput.data(using: .utf8)! ) as? [String: Any] { print("Available keys: \(json.keys)") }}
Solutions:
Copy
// Make fields optionalstruct Report: Codable { let title: String let summary: String let findings: [Finding]? // Optional let recommendations: [Recommendation]? // Optional}// Or provide defaultsstruct Report: Codable { let title: String let summary: String let findings: [Finding] = [] let recommendations: [Recommendation] = []}// Or decode partiallylet partial = try output.decode(as: PartialReport.self)let complete = partial.fillDefaults()