spb/zyquo-agent Public MIT
The autonomous agent that actually operates your Mac — plans, runs real commands, verifies its own work.
Swift 94.7%
Shell 4.1%
Python 0.7%
Makefile 0.5%
1//2// AgentTask.swift3// Zyquo Agent4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//8// The persisted task record: one human↔agent conversation bound to one9// workspace. The user's prompts and each run's steps + final answer are10// embedded (AgentStep is Codable and its tool outputs are already bounded by11// the MemoryManager's offloading), so reopening a past task re-renders its12// full step history even after multiple runs — the workspace transcript13// (`.zyquo/transcript.json`, via Transcript.load) additionally holds the14// latest run for trajectory inspection.15//1617import Foundation1819/// Sidebar/status-pill state of a task.20enum AgentTaskStatus: String, Codable, Sendable {21 /// No run yet, or the last run's outcome was cleared.22 case idle23 /// A run is preparing (workspace, system prompt) or drafting its plan.24 case planning25 /// A run is actively streaming or executing tools.26 case running27 /// A tool call is held at the policy gate, waiting for the user.28 case awaitingApproval29 /// A LoopGuard trip paused the run, waiting for continue/stop.30 case awaitingInput31 case done32 case failed3334 var displayName: String {35 switch self {36 case .idle: return "Idle"37 case .planning: return "Planning"38 case .running: return "Running"39 case .awaitingApproval: return "Awaiting approval"40 case .awaitingInput: return "Awaiting input"41 case .done: return "Done"42 case .failed: return "Failed"43 }44 }4546 /// True while a live run owns this task.47 var isActive: Bool {48 switch self {49 case .planning, .running, .awaitingApproval, .awaitingInput: return true50 case .idle, .done, .failed: return false51 }52 }53}5455/// One entry of the task's human↔agent history: either a user prompt or one56/// completed agent run (its steps, plan, and outcome).57struct TaskMessage: Codable, Identifiable, Sendable {58 enum Kind: String, Codable, Sendable {59 case user60 case agentRun61 }6263 var id: UUID = UUID()64 var kind: Kind65 /// User prompt text, or the run's final answer (empty when it failed).66 var text: String67 /// The run's steps, embedded so past runs re-render verbatim.68 var steps: [AgentStep]?69 /// The plan as it stood when the run ended.70 var plan: TaskPlan?71 /// How the run ended (agentRun entries only).72 var outcome: AgentRunOutcome?73 var createdAt: Date = Date()74}7576/// One agent task (a sidebar row): conversation + model + safety mode +77/// workspace binding.78struct AgentTask: Codable, Identifiable, Sendable {79 var id: UUID = UUID()80 var title: String81 var createdAt: Date = Date()82 var updatedAt: Date = Date()83 var pinned: Bool = false84 var status: AgentTaskStatus = .idle85 var modelID: String86 var providerID: ProviderID87 var safetyMode: SafetyMode = .guarded88 /// Active persona (Phase 6): its system-prompt addition is appended to89 /// the agent system prompt on every run of this task; nil = none.90 var personaID: UUID?91 /// Path of the task's workspace directory; nil until the first run92 /// creates it.93 var workspacePath: String?94 /// The user↔agent history (prompts + completed runs).95 var messages: [TaskMessage] = []9697 /// Default title derived from a prompt's leading words.98 static func title(fromPrompt prompt: String) -> String {99 let firstLine = prompt100 .split(separator: "\n", omittingEmptySubsequences: true)101 .first.map(String.init) ?? prompt102 let trimmed = firstLine.trimmingCharacters(in: .whitespacesAndNewlines)103 guard !trimmed.isEmpty else { return "New Task" }104 if trimmed.count <= 48 { return trimmed }105 let cut = trimmed.prefix(48)106 // Break on the last word boundary inside the prefix.107 if let lastSpace = cut.lastIndex(of: " ") {108 return String(cut[..<lastSpace]) + "…"109 }110 return String(cut) + "…"111 }112113 /// Workspace directory URL, when one has been created.114 var workspaceURL: URL? {115 workspacePath.map { URL(fileURLWithPath: $0) }116 }117118 /// Latest persisted run transcript from the workspace, when present.119 func loadTranscript() -> TranscriptDocument? {120 guard let url = workspaceURL else { return nil }121 return Transcript.load(from: url)122 }123}124