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// AgentStep.swift3// Zyquo Agent4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//8// One iteration of the plan→act→observe→reflect loop: the assistant's thought9// and text, the tool call(s) it issued, and the observed result(s). Steps are10// the unit the UI renders as cards, the Transcript persists, and the11// MemoryManager compacts.12//1314import Foundation1516/// Lifecycle of a single step.17enum AgentStepStatus: String, Codable, Sendable {18 /// Model output still streaming in.19 case streaming20 /// Tool call held at the policy gate, waiting for the user.21 case awaitingApproval22 /// Tool call(s) executing.23 case executing24 case completed25 case failed26 /// User denied the action or cancelled mid-step.27 case cancelled28}2930/// One executed (or in-flight) tool call inside a step, with its observation.31struct AgentToolInvocation: Codable, Identifiable, Sendable {32 var id: String { call.id }33 var call: ToolCall34 var result: ToolResult?35 /// Exit code for process-backed tools (bash, osascript).36 var exitCode: Int32?37 /// How the policy gate resolved this action.38 var policyDecision: PolicyDecisionRecord?39 var startedAt: Date?40 var finishedAt: Date?41}4243/// Snapshot of the gate's ruling on an action, kept for the step card and audit.44struct PolicyDecisionRecord: Codable, Sendable {45 enum Ruling: String, Codable, Sendable {46 case autoAllowed47 case approvedByUser48 case editedAndApproved49 case denied50 }51 var ruling: Ruling52 var riskLabel: String?53 /// Explanation shown on the approval card.54 var rationale: String?55}5657/// One iteration of the agent loop.58struct AgentStep: Codable, Identifiable, Sendable {59 var id: UUID = UUID()60 /// 1-based position in the run.61 var index: Int62 var status: AgentStepStatus = .streaming63 /// Reasoning-model thinking (collapsible in UI); nil for non-reasoning models.64 var thinking: String?65 /// The assistant's visible text for this turn (thought line and/or final answer).66 var text: String67 var toolInvocations: [AgentToolInvocation] = []68 var startedAt: Date = Date()69 var finishedAt: Date?70 /// Tokens consumed by this step's model turn (for LoopGuard budgets).71 var inputTokens: Int?72 var outputTokens: Int?7374 /// True when the model produced a final answer (no tool calls) — the loop's75 /// termination signal.76 var isFinal: Bool { toolInvocations.isEmpty && status == .completed }77}78