Add personal data tools, 2nd Brain trust toggle, and research agents
Personal Data Tools: native Calendar, Reminders, Contacts (hidden pending Apple TCC fix in beta), and Location & Maps access via EventKit, Contacts framework, and MapKit. Write actions (create event/reminder, complete reminder) gate through an approval sheet. Four hardened-runtime entitlements added to oAI.entitlements; Info.plist usage strings added for all services. Personal Data section shows a β badge while Contacts is hidden. 2nd Brain always-trust: inline toggle on the Agent Skills row for the skill named "2nd Brain" skips the bash approval dialog when the command contains .brain_helper.py, gated by three runtime checks in MCPService. Research agents: spawn_research_agents tool runs up to 5 concurrent read-only sub-agents (read_file, list_directory, search_files, web_search — no write, no bash, no nesting). Bounded by maxConcurrentAgents setting (default 3) and a hard ceiling of 8 tasks. Added items field to Tool.Function.Parameters.Property for JSON Schema array support; wired into AnthropicProvider.convertParametersToDict. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,18 @@ import Foundation
|
||||
import os
|
||||
import Security
|
||||
|
||||
/// Kill switch for the Personal Data tools (Calendar/Reminders/Contacts/Location & Maps).
|
||||
/// Flip `isHiddenPendingAppleFix` back to `false` once Apple fixes the macOS 27 beta TCC bug
|
||||
/// (filed with Apple). Each flag hides the relevant UI and forces the `*Enabled` getter to
|
||||
/// return `false` regardless of the persisted DB value — no code deleted, just inert.
|
||||
enum PersonalDataTools {
|
||||
/// Hides the entire Personal Data section. Flip to `false` once all four services work.
|
||||
static let isHiddenPendingAppleFix = false
|
||||
/// Hides only the Contacts row. Contacts TCC still broken under hardened runtime on
|
||||
/// macOS 27 beta 2 while Calendar/Reminders/Location are fixed. Flip to `false` once fixed.
|
||||
static let isContactsHiddenPendingAppleFix = true
|
||||
}
|
||||
|
||||
@Observable
|
||||
class SettingsService {
|
||||
static let shared = SettingsService()
|
||||
@@ -577,6 +589,37 @@ class SettingsService {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Research Agents Settings
|
||||
|
||||
/// When true, the AI can call `spawn_research_agents` to run multiple read-only
|
||||
/// sub-agents in parallel. Each sub-agent is its own full chain of model calls, so
|
||||
/// this can noticeably increase cost — opt-in, off by default.
|
||||
var agentsEnabled: Bool {
|
||||
get { cache["agentsEnabled"] == "true" }
|
||||
set {
|
||||
cache["agentsEnabled"] = String(newValue)
|
||||
DatabaseService.shared.setSetting(key: "agentsEnabled", value: String(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
var maxConcurrentAgents: Int {
|
||||
get { cache["maxConcurrentAgents"].flatMap(Int.init) ?? 3 }
|
||||
set {
|
||||
cache["maxConcurrentAgents"] = String(newValue)
|
||||
DatabaseService.shared.setSetting(key: "maxConcurrentAgents", value: String(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
/// When true (and an active "2nd Brain" Agent Skill is installed), bash commands that
|
||||
/// invoke the 2nd Brain helper script skip the approval dialog entirely.
|
||||
var trustSecondBrainSkill: Bool {
|
||||
get { cache["trustSecondBrainSkill"] == "true" }
|
||||
set {
|
||||
cache["trustSecondBrainSkill"] = String(newValue)
|
||||
DatabaseService.shared.setSetting(key: "trustSecondBrainSkill", value: String(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
var bashWorkingDirectory: String {
|
||||
get { cache["bashWorkingDirectory"] ?? "~" }
|
||||
set {
|
||||
@@ -593,6 +636,48 @@ class SettingsService {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Personal Data Settings (Calendar/Reminders/Contacts/Location/Maps)
|
||||
|
||||
var calendarEnabled: Bool {
|
||||
get { !PersonalDataTools.isHiddenPendingAppleFix && cache["calendarEnabled"] == "true" }
|
||||
set {
|
||||
cache["calendarEnabled"] = String(newValue)
|
||||
DatabaseService.shared.setSetting(key: "calendarEnabled", value: String(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
var remindersEnabled: Bool {
|
||||
get { !PersonalDataTools.isHiddenPendingAppleFix && cache["remindersEnabled"] == "true" }
|
||||
set {
|
||||
cache["remindersEnabled"] = String(newValue)
|
||||
DatabaseService.shared.setSetting(key: "remindersEnabled", value: String(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
var contactsEnabled: Bool {
|
||||
get { !PersonalDataTools.isHiddenPendingAppleFix && !PersonalDataTools.isContactsHiddenPendingAppleFix && cache["contactsEnabled"] == "true" }
|
||||
set {
|
||||
cache["contactsEnabled"] = String(newValue)
|
||||
DatabaseService.shared.setSetting(key: "contactsEnabled", value: String(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
var locationMapsEnabled: Bool {
|
||||
get { !PersonalDataTools.isHiddenPendingAppleFix && cache["locationMapsEnabled"] == "true" }
|
||||
set {
|
||||
cache["locationMapsEnabled"] = String(newValue)
|
||||
DatabaseService.shared.setSetting(key: "locationMapsEnabled", value: String(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
var personalDataRequireApproval: Bool {
|
||||
get { cache["personalDataRequireApproval"].map { $0 == "true" } ?? true }
|
||||
set {
|
||||
cache["personalDataRequireApproval"] = String(newValue)
|
||||
DatabaseService.shared.setSetting(key: "personalDataRequireApproval", value: String(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Paperless-NGX Settings
|
||||
|
||||
var paperlessEnabled: Bool {
|
||||
|
||||
Reference in New Issue
Block a user