SPB Git

spb/poche Public

Agent personnel 100 % on-device — SwiftUI + Apple Foundation Models + EventKit + SwiftData. Aucune API, aucun serveur.

Swift 100%
3.5 KB · 119 lines swift
Raw Blame History
1//2//  PendingAction.swift3//  Poche4//5//  Author:  Simon-Pierre Boucher6//  Contact: contact@spboucher.ai7//89import Foundation1011/// A side-effect proposed by the model, waiting for the user's explicit12/// confirmation. The model never writes; it proposes, the app decides13/// (CLAUDE.md §3 — the non-negotiable principle).14struct PendingAction: Identifiable, Sendable {15    enum Status: Sendable, Equatable {16        case waiting17        case executing18        case failed(String)19    }2021    enum Payload: Sendable {22        case reminder(ReminderDraft)23        case event(EventDraft)24        case note(NoteDraft)25        case newTask(TaskDraft)26        case taskUpdate(TaskUpdateDraft)27    }2829    let id = UUID()30    let payload: Payload31    var status: Status = .waiting3233    /// Card headline — always future tense: nothing has happened yet.34    var title: String {35        switch payload {36        case .reminder: "Créer un rappel"37        case .event: "Créer un événement"38        case .note: "Enregistrer une note"39        case .newTask: "Créer une tâche"40        case .taskUpdate: "Modifier une tâche"41        }42    }4344    /// Resolved values shown in clear text (dates already validated).45    var fields: [(label: String, value: String)] {46        switch payload {47        case .reminder(let draft):48            [("Titre", draft.title),49             ("Échéance", DateResolver.display(draft.due))]50            + (draft.list.map { [("Liste", $0)] } ?? [])51        case .event(let draft):52            [("Titre", draft.title),53             ("Début", DateResolver.display(draft.start)),54             ("Fin", DateResolver.display(draft.end))]55            + (draft.location.map { [("Lieu", $0)] } ?? [])56        case .note(let draft):57            [("Titre", draft.title),58             ("Contenu", String(draft.content.prefix(140)))]59        case .newTask(let draft):60            [("Titre", draft.title)]61            + (draft.details.map { [("Détails", String($0.prefix(140)))] } ?? [])62            + (draft.due.map { [("Échéance", DateResolver.display($0))] } ?? [])63        case .taskUpdate(let draft):64            [("Tâche", draft.currentTitle)]65            + (draft.newTitle.map { [("Nouveau titre", $0)] } ?? [])66            + (draft.newDue.map { [("Nouvelle échéance", DateResolver.display($0))] } ?? [])67            + (draft.markDone == true ? [("État", "Marquer comme faite")] : [])68        }69    }7071    /// One-line summary used for system notices and agent notes.72    var summary: String {73        switch payload {74        case .reminder(let draft):75            "Rappel « \(draft.title) » pour \(DateResolver.display(draft.due))"76        case .event(let draft):77            "Événement « \(draft.title) » le \(DateResolver.display(draft.start))"78        case .note(let draft):79            "Note « \(draft.title) »"80        case .newTask(let draft):81            "Tâche « \(draft.title) »"82        case .taskUpdate(let draft):83            "Modification de la tâche « \(draft.currentTitle) »"84        }85    }86}8788struct ReminderDraft: Sendable {89    let title: String90    let due: Date91    let list: String?92}9394struct EventDraft: Sendable {95    let title: String96    let start: Date97    let end: Date98    let location: String?99}100101struct NoteDraft: Sendable {102    let title: String103    let content: String104}105106struct TaskDraft: Sendable {107    let title: String108    let details: String?109    let due: Date?110}111112struct TaskUpdateDraft: Sendable {113    let taskID: UUID114    let currentTitle: String115    let newTitle: String?116    let newDue: Date?117    let markDone: Bool?118}119