From 30d0500323b313803a24c152e309b92fb5e21473 Mon Sep 17 00:00:00 2001 From: Rune Olsen Date: Fri, 24 Jul 2026 10:12:39 +0200 Subject: [PATCH] Skip tool guidance, custom prompt, and Agent Skills for tool-incapable models effectiveSystemPrompt now gates tool-usage guidelines, the user's custom system prompt, and active Agent Skills behind whether the selected model actually supports tools (ModelInfo.capabilities.tools). All three assume tool/file/web access and can easily blow past small context windows. Confirmed live against Apple Intelligence: the default system prompt dropped from 16,377 to ~250 tokens (well under the 4K on-device limit), fully resolving the context-exceeded error from the initial Phase 1 rollout. Verified end-to-end with a real successful generation in the app after the fix. Also: .gitignore now excludes *.profraw (stray code-coverage artifact picked up while testing). Co-Authored-By: Claude Sonnet 5 --- .gitignore | 3 +++ oAI/ViewModels/ChatViewModel.swift | 37 +++++++++++++++++++----------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 163d5e2..4dc106a 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,9 @@ DerivedData/ *.dSYM.zip *.dSYM +## Code coverage +*.profraw + ## Playgrounds timeline.xctimeline playground.xcworkspace diff --git a/oAI/ViewModels/ChatViewModel.swift b/oAI/ViewModels/ChatViewModel.swift index 0687d70..5847a93 100644 --- a/oAI/ViewModels/ChatViewModel.swift +++ b/oAI/ViewModels/ChatViewModel.swift @@ -151,8 +151,14 @@ Don't narrate future actions ("Let me...") - just use the tools. /// Builds the complete system prompt by combining default + conditional sections + custom private var effectiveSystemPrompt: String { + // Tool guidance, the user's custom prompt, and Agent Skills all generally assume tool + // access and can easily blow past small context windows (e.g. Apple's on-device 4K + // limit) — skip all three for tool-incapable models. + let modelSupportsTools = selectedModel?.capabilities.tools ?? true + // Check if user wants to replace the default prompt entirely (BYOP mode) - if settings.customPromptMode == .replace, + if modelSupportsTools, + settings.customPromptMode == .replace, let customPrompt = settings.systemPrompt, !customPrompt.isEmpty { // BYOP: Use ONLY the custom prompt @@ -170,29 +176,32 @@ Don't narrate future actions ("Let me...") - just use the tools. } // Add tool-specific guidelines if MCP is enabled (tools are available) - if mcpEnabled { + if mcpEnabled && modelSupportsTools { prompt += toolUsageGuidelines } // Append custom prompt if in append mode and custom prompt exists - if settings.customPromptMode == .append, + if modelSupportsTools, + settings.customPromptMode == .append, let customPrompt = settings.systemPrompt, !customPrompt.isEmpty { prompt += "\n\n---\n\nAdditional Instructions:\n" + customPrompt } // Append active agent skills (SKILL.md-style behavioral instructions) - let activeSkills = settings.agentSkills.filter { $0.isActive } - if !activeSkills.isEmpty { - prompt += "\n\n---\n\n## Installed Skills\n\nThe following skills are active. Apply them when relevant:\n\n" - for skill in activeSkills { - prompt += "### \(skill.name)\n\n\(skill.content)\n\n" - let files = AgentSkillFilesService.shared.readTextFiles(for: skill.id) - if !files.isEmpty { - prompt += "**Skill Data Files:**\n\n" - for (name, content) in files { - let ext = URL(fileURLWithPath: name).pathExtension.lowercased() - prompt += "**\(name):**\n```\(ext)\n\(content)\n```\n\n" + if modelSupportsTools { + let activeSkills = settings.agentSkills.filter { $0.isActive } + if !activeSkills.isEmpty { + prompt += "\n\n---\n\n## Installed Skills\n\nThe following skills are active. Apply them when relevant:\n\n" + for skill in activeSkills { + prompt += "### \(skill.name)\n\n\(skill.content)\n\n" + let files = AgentSkillFilesService.shared.readTextFiles(for: skill.id) + if !files.isEmpty { + prompt += "**Skill Data Files:**\n\n" + for (name, content) in files { + let ext = URL(fileURLWithPath: name).pathExtension.lowercased() + prompt += "**\(name):**\n```\(ext)\n\(content)\n```\n\n" + } } } }