Main dev - #658
Closed
JayDaniel wants to merge 16 commits into
Closed
Conversation
TCA 1.16.1 does not compile under Swift 6.3, so moving to the new toolchain forces a matching dependency bump. - Upgrade swift-composable-architecture from 1.16.1 to 1.26.2 and adopt the new Shared(value:) signature - Align the Tool and ChatPlugins package platforms to macOS 13, so they match every target in the project - Declare the missing CommandHandler dependency in SuggestionWidget, which was breaking the test bundle link step - Drop stale entries from Package.resolved Claude-Session: https://claude.ai/code/session_01QrUJLx9ppwpa2DFUoSGUYo
The open source build hosts no third-party ExtensionKit extension, so CustomSuggestionServiceForCopilotForXcode cannot run as a separate app. Merge it into the Tool package and expose it as a built-in extension instead. - Add the CustomSuggestionService module to the Tool package - Support seven API shapes: OpenAI compatible, Azure, Claude, Gemini, Ollama, Mistral FIM and Tabby - Add the CompletionModel, FIMModel and TabbyModel types along with the customSuggestion* preference keys - Register through BuiltinExtension, so that Custom Model appears as a suggestion provider - Port the 31 unit tests from the original project Claude-Session: https://claude.ai/code/session_01QrUJLx9ppwpa2DFUoSGUYo
- Replace the Other Suggestion Services promo page in the Service sidebar with a Custom Model settings page - Let the user pick a host chat model, or a custom Completion, FIM or Tabby model, and edit it in place - Expose the request strategy, the FIM template, the line and token limits, and the verbose log switch - Give APIKeyPicker an optional title Claude-Session: https://claude.ai/code/session_01QrUJLx9ppwpa2DFUoSGUYo
Replace the upstream author's team in all 12 DEVELOPMENT_TEAM build settings, so that the fork builds on this machine. Claude-Session: https://claude.ai/code/session_01QrUJLx9ppwpa2DFUoSGUYo
- Add OpenAIResponsesService, covering both the streaming and the non-streaming shape of /v1/responses - Switch OpenAIService to the reasoning request shape once an effort is set - Forward the host chat model's custom headers through the OpenAI and the Anthropic service - Add a Chat Model API section to the settings page for choosing the endpoint and the reasoning effort - Cover SSE parsing and header placeholders with unit tests Claude-Session: https://claude.ai/code/session_01QrUJLx9ppwpa2DFUoSGUYo
A debug build could not reach its services until the launch agent was installed by hand, and the host insisted on being moved to /Applications first. - Add an idempotent debug-only registration path: write the plist, bootstrap it, and kickstart the bridge once it is rebuilt - Register on host launch in debug, and drop the move to Applications prompt there - Let the bridge start ExtensionService in debug as well - Have ExtensionService exit in debug once its binary changes, so it comes back running the new code - Leave release behaviour identical to upstream Claude-Session: https://claude.ai/code/session_01QrUJLx9ppwpa2DFUoSGUYo
- Point Package.resolved at apple/swift-syntax.git, to match Tool/Package.swift - Set all 12 DEVELOPMENT_TEAM settings to $(inherited) and read the real value from an optional Local.xcconfig - Add Local.xcconfig.example and gitignore Local.xcconfig - Drop the unused CodableWrappers dependency, and the unused Parsing import in RequestStrategy
Completion failures used to disappear into an erased stream, so a
misconfigured model looked exactly like a model with nothing to say.
- Drop eraseToStream and let getCompletion throw; Tabby and Gemini
now use AsyncThrowingStream
- Parse a non-SSE response as one JSON body, report a non-200 as
"HTTP <code>: <first 200 bytes>", and stop turning a response that
is not an HTTPURLResponse into a CancellationError
- Raise readable errors from the error.message line of
chat/completions and from Anthropic type=error events
- Recognise the chat shape {"error":{"message":...}} before switching
on the Responses event type, which used to hang
- Stop silently falling back on a dangling model id, clear
customSuggestionModelId when its chat model is deleted, and give an
empty id its own message
- Rate-limit repeated completion errors to silent within 30 seconds
and notice otherwise; the presenter skips silent ones, and
cancellation, URLError.cancelled included, is no longer logged as
an error
- Map Completions chunks onto chat chunks, so the OpenAI completion
path can share CompletionSequence
- Keep parsing Ollama application/x-ndjson line by line, since
streaming NDJSON is not a single JSON document
The Gemini Google SDK session is not intercepted, so its tests cover
the same AsyncThrowingStream wrapper instead. Toasting a wrong API
key was not exercised by hand, this machine having no GUI for it.
- Move OpenAIChatAPI and ReasoningEffort into Preferences, key the API options by ChatModel.id, xhigh and the reasoning token budget included, and migrate the old global keys once - Treat a Responses endpoint as a full URL only for openAICompatible with isFullURL; strip the trailing slash and ignore the query before swapping /chat/completions for /responses - Always truncate on stop words client side; with max lines at 0, stop words become the only limit. Add the budget to max_*_tokens for low, medium, high and xhigh - Send store:false on Responses requests, and temperature:0.2 when no effort is set; send output_config.effort to Anthropic, mapping none and minimal to low, and xhigh to high - Route headers through HeaderValueParser, validating names and newlines; forward extraHeaders to Azure and Ollama; merge customBody with JoinJSON; align org and project, the Gemini base URL and the message order with the host - Show GitHub Copilot models in the picker as needing another choice, and throw from the completion path - Show the reasoning token budget only for OpenAI and compatible CustomSuggestionServiceTests passes with 54 cases. The gateway itself was not verified by hand, this machine having neither a GUI nor gateway credentials.
- Fingerprint a debug build by the mtime and size of <executable>.debug.dylib and quit on change; release keeps the FileChangeChecker MD5 - Skip bridge.quit() from XPCController.quit() in debug, which used to trip launchd's ten second throttle - Return an endpoint only for a live PID, and clear the endpoint and PID when the liveness check fails, rather than holding a stale handle because a bundle id was reused; ping every 5 seconds in debug and every 60 in release - Reuse an instance from launch() only when its bundleURL and appURL normalise to the same path, and go through openApplication otherwise - Build the plist with PropertyListSerialization and compare parsed dictionaries for idempotency; mention login items only when stderr reports an input/output error or a disabled agent - Make setupLaunchAgentIfNeeded cancellable, run the automatic registration once per host process, always re-register from the Setup button, and clear didRunInThisProcess on Remove - Log LaunchAgentManager under Bundle.main.bundleIdentifier Add LaunchAgentManagerTests, covering a Program path containing an ampersand. The three manual checks, pid change after a rebuild, kickstart and single instance, were not run, this machine having no GUI.
- Write back only the model fields when the edit sheet reads from disk, instead of rebuilding the API key and base URL pickers, which raced with an empty tag - Give BuiltInSuggestionFeatureProvider.customModel the raw value 1000. A persisted SuggestionFeatureProvider of Int 2 now fails to decode and falls back to the default provider, so the user has to pick Custom Model once - Keep the key names of the standalone app without migrating its configuration, and treat the old chatModel value as an invalid model - Snapshot modelId, chatModels and strategyId once in the coordinator, save through userDefaults behind a non-empty check, and forward cancellation to the inner task - Populate the Completion picker from the completions list and the FIM picker from the codestral list, and drop the unreachable googleAI view - Fold the three model field views into SharedModelFields, and move RequestStrategyOption and the model lists out of the engine, so HostApp no longer depends on CustomSuggestionService Tests cover saving from CompletionModelEdit and the raw 1000 round trip for SuggestionFeatureProvider. The sheet pickers were not verified in the GUI.
- Give OpenAIService an authentication mode, bearer or api-key, and an Azure endpoint builder; route .azureOpenAI through it and delete AzureOpenAIService - The Azure path now inherits SSELine, custom headers, the reasoning shape with max_completion_tokens, and non-streaming parsing - Delete the unused APIError, decodeError and countToken from the OpenAI and Ollama services, and Models and validateResponse from Anthropic - Log CompletionModel under the Completion type, and fall back to http://127.0.0.1:11434 for Ollama - Show the reasoning effort and token budget on the Azure settings page, move the chat api-version to 2024-09-01-preview, and fail on an empty Azure URL rather than calling api.openai.com Tests assert that an Azure reasoning request carries api-key, max_completion_tokens, /openai/deployments and api-version. CustomSuggestionServiceTests passes with 56 cases.
- Set a same-team code signing requirement on the CommunicationBridge and ExtensionService listeners before resume, and refuse the connection when the team id is unreadable or the requirement invalid - Derive the team id by dropping the trailing dot from TEAM_ID_PREFIX; the bridge reads it from the Info.plist of the neighbouring CopilotForXcodeExtensionService.app - Accept updateServiceEndpoint only from a process whose bundle id is <base>.ExtensionService, and log the rest - Say in the verbose log switch that it writes prompts containing your source code to Console.app - Log the requirement string on refusal, rather than a localized description that is null A signed debug build passes with TEAM_ID_PREFIX=94G4SCKS9Z. The version row on the General page, and the refusal of a client from another team, were not verified in the GUI.
- README: list Custom Model under the features, require macOS 13, and document the Service > Chat Models > Custom Model > Feature > Suggestion setup, the gateway headers that are not forwarded upstream, and the MIT provenance - DEVELOPMENT: running Copilot for Xcode Debug in the fork now starts the host, the bridge and ExtensionService. The launch agent owns CommunicationBridge, so neither that scheme nor ExtensionService should be run directly; keep one dev instance at a time; the .appex still follows Apple's EditorExtension flow; debug by attaching to the process - Document Local.xcconfig under Building: copy DEVELOPMENT_TEAM from the example, it is gitignored - Close the remaining gaps: ChatAPIOptions.current for the default, an invalid raw value and an empty key; getModel and getStrategy, a dangling id included; parseCompletionsStreamLine; and response.incomplete Optionally run the tests on pull_request under macos-15 with Xcode 26 and CODE_SIGNING_ALLOWED=NO. The test step stays continue-on-error while Xcode 26 is unavailable. The full run passes with 272 cases: 63 in CustomSuggestionServiceTests, 5 in HostAppTests and 2 in LaunchAgentManagerTests.
Six changes land together, all of them about whether custom model completion is pleasant to use in practice. - Accept on Tab the way Cursor does: if a suggestion is showing, Tab takes it. The upstream heuristic of letting Tab through when it would not invalidate the suggestion turned one Tab into three whenever a continuation began with whitespace. Deciding this no longer reads the editor content either. - Strip duplicated indentation in post-processing: when the prefix before the cursor ends in whitespace, drop the leading spaces and tabs from the continuation. - Stream the suggestion as it arrives. Add StreamingSuggestionServiceProvider and StreamingSuggestionServiceType, turn CodeCompletionService into a type-erasing factory offering streamCompletion, have the coordinator emit a partial result every 50ms, and refresh the widget on each one. Accepting, rejecting or invalidating a suggestion stops and cancels the request at once. The log gains first token, partial count, output tokens and the endpoint actually called. - Retrieve context. relevantCodeSnippets had always been an empty array, which is why completions felt unrelated to the project. NeighboringSnippetRetriever scores windows of the other open files by Jaccard similarity, the way GitHub Copilot uses neighbouring tabs, with no index, no embeddings and no extra round trip. RecentEditDiff records the last few edits and renders them as a fully commented block, the signal Cursor Tab leans on; commenting it keeps the syntax intact inside a FIM prefix. Candidates come from the filespaces, topped up from the persisted open file list when the service has just restarted. - Default the OpenAI endpoint to /v1/responses. The old global key joins the migration whenever it holds a value, so a configuration that explicitly chose chat completions is not overwritten by the new default. - Stop reporting Plus limits in an unlicensed build: the model and custom command counts are no longer capped. Features implemented in a closed source module stay guarded by canImport at the call site, the browser tab among them. Tests: 21 new cases for neighbouring tab retrieval and recent edits, plus streaming and post-processing cases, 300 passing in total. Four WebSearchServiceTests cases need the public network and pass on their own. Claude-Session: https://claude.ai/code/session_01JWdMNzGfXMq5ptxmB4Vmgs
SwiftUI resolves a Text literal against Bundle.main, so localizations shipped inside an SPM package never apply. Putting the catalog in the three executable bundles instead localizes roughly 550 call sites across the Core and Tool packages without touching any of them. - Add Localization/Localizable.xcstrings with 450 entries in en, zh-Hans and zh-Hant, and attach it to the host app, the extension service and the editor extension - Narrow the title of SettingsDivider, SubSection, SidebarTabView, TabContainer and the pickers from String to LocalizedStringKey, so that their call sites need no edit - Look toast text up as a LocalizedStringKey, and run the status bar menu and the Xcode editor command names through NSLocalizedString - Add AppLanguage and the appLanguage preference, offer a language picker in General settings, and have all three processes write AppleLanguages at launch - Raise the deployment target to macOS 15.6, pin ARCHS to arm64 in both xcconfigs and add EXCLUDED_ARCHS = x86_64, dropping the target-level ARCHS overrides - Bump the version to 0.40.0 (505) A target-level ARCHS overrides the project xcconfig, and Xcode writes one back whenever a build setting is touched, so EXCLUDED_ARCHS is there as a backstop and archives no longer carry an x86_64 slice. Claude-Session: https://claude.ai/code/session_01KFzJ8F9F96FQDwBfRej3ad
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.