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:
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// PersonalDataApprovalSheet.swift
|
||||
// oAI
|
||||
//
|
||||
// Approval UI for AI-requested Calendar/Reminders write actions
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
// Copyright (C) 2026 Rune Olsen
|
||||
//
|
||||
// This file is part of oAI.
|
||||
//
|
||||
// oAI is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// oAI is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General
|
||||
// Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public
|
||||
// License along with oAI. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct PersonalDataApprovalSheet: View {
|
||||
let pending: MCPService.PendingPersonalDataAction
|
||||
let onApprove: (_ forSession: Bool) -> Void
|
||||
let onDeny: () -> Void
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
// Header
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: "calendar.badge.exclamationmark")
|
||||
.font(.title2)
|
||||
.foregroundStyle(.orange)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Allow This Action?")
|
||||
.font(.system(size: 17, weight: .semibold))
|
||||
Text("The AI wants to make a change to your calendar or reminders")
|
||||
.font(.system(size: 13))
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
|
||||
// Action description
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text("ACTION")
|
||||
.font(.system(size: 11, weight: .medium))
|
||||
.foregroundStyle(.secondary)
|
||||
Text(pending.summary)
|
||||
.font(.system(size: 13))
|
||||
.foregroundStyle(.primary)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.textSelection(.enabled)
|
||||
.padding(12)
|
||||
.background(Color.secondary.opacity(0.08))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.stroke(Color.secondary.opacity(0.2), lineWidth: 1)
|
||||
)
|
||||
}
|
||||
|
||||
// Buttons
|
||||
HStack(spacing: 8) {
|
||||
Button("Deny") {
|
||||
onDeny()
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.tint(.red)
|
||||
.keyboardShortcut(.escape, modifiers: [])
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("Allow Once") {
|
||||
onApprove(false)
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.tint(.orange)
|
||||
|
||||
Button("Allow for Session") {
|
||||
onApprove(true)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(.orange)
|
||||
.keyboardShortcut(.return, modifiers: [])
|
||||
}
|
||||
}
|
||||
.padding(24)
|
||||
.frame(width: 480)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user