Skip to content

feat: Add Apple Intelligence on-device formatting#92

Open
kentaro wants to merge 7 commits intoamicalhq:mainfrom
kentaro:feat/apple-intelligence-formatting
Open

feat: Add Apple Intelligence on-device formatting#92
kentaro wants to merge 7 commits intoamicalhq:mainfrom
kentaro:feat/apple-intelligence-formatting

Conversation

@kentaro
Copy link

@kentaro kentaro commented Feb 9, 2026

Summary

  • Integrate macOS 26 Foundation Models as a text formatting provider (Apple Intelligence)
  • On-device processing with no API key required, following the same formatter pattern as OpenRouter/Ollama
  • Fix formatter prompt instruction that caused on-device models to return empty <formatted_text> tags

Changes

  • Swift: FoundationModelService with availability check and text generation via LanguageModelSession
  • Formatter: AppleIntelligenceFormatter aligned with OpenRouter/Ollama pattern + empty result fallback
  • RPC: checkFoundationModelAvailability, generateWithFoundationModel methods
  • UI: Apple Intelligence provider section in settings with availability detection
  • Prompt fix: Remove "If the text is empty, return <formatted_text></formatted_text>" instruction that misled small on-device models
  • Graceful degradation: Platform checks at every layer (Swift #if canImport, @available, TypeScript platform guard)

Test plan

  • Unit tests for AppleIntelligenceFormatter (10 tests passing)
  • Unit tests for model service Apple Intelligence sync (7 tests passing)
  • Unit tests for Foundation Model schemas
  • Manual test: Japanese text formatting with Foundation Model on macOS 26
  • Verify Ollama/OpenRouter formatting unaffected (only change: removed unused empty-text instruction; empty text guard exists in caller at transcription-service.ts:468)
  • Verify graceful degradation: process.platform guard (TS), #if canImport(FoundationModels) (compile-time), #available(macOS 26, *) (runtime)
  • All existing tests pass (34/34; 11 pre-existing failures in transcriptions.test.ts unrelated to this PR)

Summary by CodeRabbit

  • New Features

    • Apple Intelligence on macOS: provider listing, availability/status badges, sync button, contextual descriptions and toasts in Language Model settings.
    • Use Apple Intelligence as an on-device formatting provider for transcription finalization.
    • Added English UI strings for Apple Intelligence statuses, actions, descriptions and toasts.
  • Chores

    • Platform/native integration to query and call on-device foundation models.
  • Tests

    • New tests covering Apple Intelligence formatting, model sync flows, and related schemas.

@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds macOS Foundation Models ("Apple Intelligence") support: new native RPCs and Swift FoundationModelService, types/schemas, a formatting provider, model sync endpoints and service logic, macOS-only UI for availability/sync, and tests for formatter, model service, and schemas.

Changes

Cohort / File(s) Summary
i18n
apps/desktop/src/i18n/locales/en.json
Added Apple Intelligence provider label and UI strings (status, actions, descriptions, toasts).
Formatting provider
apps/desktop/src/pipeline/providers/formatting/apple-intelligence-formatter.ts, apps/desktop/src/pipeline/providers/formatting/formatter-prompt.ts
Added AppleIntelligenceFormatter calling nativeBridge.generateWithFoundationModel, parsing <formatted_text> tags with fallbacks and logging; removed explicit empty-output instruction from base prompt.
Transcription integration
apps/desktop/src/services/transcription-service.ts
Integrated Apple Intelligence formatting into transcription finalization when NativeBridge is available.
Model service
apps/desktop/src/services/model-service.ts
Added syncAppleIntelligenceModel(nativeBridge) to check availability and upsert or remove the Apple Intelligence model record.
Native bridge surface
apps/desktop/src/services/platform/native-bridge-service.ts
Declared RPC methods checkFoundationModelAvailability and generateWithFoundationModel and registered their result schemas.
TRPC router
apps/desktop/src/trpc/routers/models.ts
Added checkAppleIntelligenceAvailability (query) and syncAppleIntelligenceModel (mutation); note: identical additions appear duplicated in the file (duplicate declarations).
UI (macOS-only)
apps/desktop/src/renderer/main/pages/settings/ai-models/components/apple-intelligence-provider.tsx, apps/desktop/src/renderer/main/pages/settings/ai-models/tabs/LanguageTab.tsx
New macOS-guarded AppleIntelligenceProvider component (availability check, sync mutation, toasts) and added to LanguageTab.
Swift native layer
packages/native-helpers/swift-helper/Sources/SwiftHelper/RpcHandler.swift, packages/native-helpers/swift-helper/Sources/SwiftHelper/services/FoundationModelService.swift
Added FoundationModelService (checkAvailability, generate) with conditional compilation and RPC handlers exposing the two new methods.
Types & schemas
packages/types/src/schemas/methods/check-foundation-model-availability.ts, packages/types/src/schemas/methods/generate-with-foundation-model.ts, packages/types/src/schemas/rpc/request.ts, packages/types/src/index.ts
Added request/result schemas and types for the two new RPC methods; exported them and extended RPC method-name union.
Schema generation scripts
packages/types/scripts/generate-json-schemas.ts, packages/types/scripts/generate-swift-models.ts
Included new Foundation Model schemas in JSON and Swift generation inputs.
Tests
apps/desktop/tests/pipeline/apple-intelligence-formatter.test.ts, apps/desktop/tests/services/model-service-apple-intelligence.test.ts, packages/types/tests/foundation-model-schemas.test.ts
Added tests covering formatter parsing and failures, model-service sync flows (platform, availability, error paths), and schema validation.
Package index
packages/types/src/index.ts
Re-exported new method schema modules.

Sequence Diagram(s)

sequenceDiagram
    participant UI as React UI (AppleIntelligenceProvider)
    participant Router as tRPC Router (models.ts)
    participant Service as ModelService
    participant Bridge as NativeBridge
    participant Swift as Swift Backend (FoundationModelService)
    participant DB as Database

    UI->>Router: checkAppleIntelligenceAvailability()
    Router->>Bridge: checkFoundationModelAvailability()
    Bridge->>Swift: checkAvailability()
    Swift-->>Bridge: {available, reason?}
    Bridge-->>Router: result
    Router-->>UI: {available, reason}

    UI->>Router: syncAppleIntelligenceModel()
    Router->>Service: syncAppleIntelligenceModel(nativeBridge)

    alt available
        Service->>Bridge: checkFoundationModelAvailability()
        Bridge->>Swift: checkAvailability()
        Swift-->>Bridge: {available: true}
        Service->>DB: upsertModel(appleIntelligence metadata)
        DB-->>Service: success
        Service-->>Router: {available: true}
        Router-->>UI: toast: synced
    else unavailable
        Service->>Bridge: checkFoundationModelAvailability()
        Bridge->>Swift: checkAvailability()
        Swift-->>Bridge: {available: false, reason}
        Service->>DB: removeModel(appleIntelligence)
        DB-->>Service: success
        Service-->>Router: {available: false, reason}
        Router-->>UI: toast: notAvailable
    end
Loading
sequenceDiagram
    participant Transcription as TranscriptionService
    participant Formatter as AppleIntelligenceFormatter
    participant Bridge as NativeBridge
    participant Swift as Swift Backend (FoundationModelService)

    Transcription->>Transcription: detect provider = AppleIntelligence
    alt NativeBridge available
        Transcription->>Formatter: format({systemPrompt, userPrompt,...})
        Formatter->>Bridge: generateWithFoundationModel(params)
        Bridge->>Swift: generate(params)
        Swift-->>Bridge: {content}
        Bridge-->>Formatter: result
        Formatter->>Formatter: parse <formatted_text> tags or fallback
        Formatter-->>Transcription: formatted text
        Transcription->>Transcription: update transcript, metrics
    else NativeBridge unavailable
        Transcription->>Transcription: log warning, skip formatting
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • haritabh-z01

Poem

🐰 I hopped through code both day and night,

Foundation models now take flight,
From Swift to bridge and React so spry,
On‑device magic, quick as I fly,
A carrot-toast for builds that light ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Add Apple Intelligence on-device formatting' accurately and concisely summarizes the main change: integrating Apple Intelligence as a new on-device text formatting provider.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In
`@apps/desktop/src/renderer/main/pages/settings/ai-models/components/apple-intelligence-provider.tsx`:
- Around line 15-22: The hooks
(api.models.checkAppleIntelligenceAvailability.useQuery, api.useUtils,
api.models.syncAppleIntelligenceModel.useMutation) are being conditionally
skipped by the early return on isMac; move the platform guard (the if (!isMac)
return null) below all hook calls so hooks run unconditionally and in the same
order, and update the availabilityQuery call to pass an options object with
enabled: isMac so the query only executes on macOS (e.g., availabilityQuery =
api.models.checkAppleIntelligenceAvailability.useQuery(undefined, { enabled:
isMac })); keep other hooks as-is but ensure no other returns occur before the
hooks are declared.

In
`@packages/native-helpers/swift-helper/Sources/SwiftHelper/services/FoundationModelService.swift`:
- Around line 7-37: The generate method uses the wrong LanguageModelSession
initializer and omits passing the system prompt into the session/response;
change LanguageModelSession(instructions: ...) to LanguageModelSession(model:
model) (e.g., let model = SystemLanguageModel.default; let session =
LanguageModelSession(model: model)) and then ensure the systemPrompt
(params.systemPrompt) is provided to the session/respond call per the
FoundationModels API (either by adding the prompt as an initial message/context
to the session or by using the documented respond(...) parameters such as
schema:, generating:, or options: to include system context); update the call to
session.respond(...) to match the official signature and include the
systemPrompt where required.
- Around line 26-37: In generate(params:
GenerateWithFoundationModelParamsSchema) build a GenerationOptions using
params.temperature and params.maxTokens and pass it into
LanguageModelSession.respond(to:options:) instead of the no-options overload;
update the code around LanguageModelSession(instructions:) and the respond call
to create GenerationOptions(temperature: params.temperature,
maximumResponseTokens: params.maxTokens) and call session.respond(to:
params.userPrompt, options: options) so caller-provided temperature/maxTokens
are applied.
🧹 Nitpick comments (5)
packages/native-helpers/swift-helper/Sources/SwiftHelper/RpcHandler.swift (1)

240-277: Consider using [weak self] in the Task closure for consistency.

Other async handlers in this file (Lines 38, 46, 100) use [weak self] in their closures. The Task on Line 257 captures self strongly. While this is unlikely to cause issues given the process lifecycle, using [weak self] would be consistent with the rest of the file.

Proposed diff
                 // Run async Foundation Model call on a background queue
                 let requestId = request.id
-                Task {
+                Task { [weak self] in
+                    guard let self = self else { return }
                     do {
                         let result = try await self.foundationModelService.generate(params: generateParams)
                         self.sendResult(id: requestId, result: result)
packages/types/scripts/generate-json-schemas.ts (1)

127-146: Remove CheckFoundationModelAvailabilityParamsSchema from the Swift model generation since the method doesn't accept params.

The checkFoundationModelAvailability case in RpcHandler.swift ignores params entirely and directly calls foundationModelService.checkAvailability() with no arguments. Unlike generateWithFoundationModel, which decodes and uses GenerateWithFoundationModelParamsSchema, this method doesn't decode or pass params to the service. The optional empty object schema is therefore unnecessary in the quicktype input and can be removed from the command in generate-swift-models.ts.

apps/desktop/src/pipeline/providers/formatting/apple-intelligence-formatter.ts (1)

35-56: Consider trimming the extracted text from XML tags.

The regex captures content between <formatted_text> tags including any leading/trailing whitespace or newlines that the model might insert (e.g., <formatted_text>\nHello world\n</formatted_text>). The empty check on Line 49 uses .trim(), but the returned value on Line 56 does not trim. This could introduce unwanted leading/trailing whitespace in the formatted output.

Optional: Trim extracted text
-      const formattedText = match ? match[1] : result.content;
+      const formattedText = match ? match[1].trim() : result.content.trim();
apps/desktop/src/services/model-service.ts (1)

826-885: Clean implementation with proper platform guarding and error handling.

The method correctly:

  • Short-circuits on non-macOS platforms
  • Delegates availability check to the native bridge
  • Upserts or removes the model based on availability
  • Provides graceful error handling returning a structured result

One minor observation: the provider name "AppleIntelligence" and model id "apple-intelligence" are used as magic strings here and likely referenced elsewhere (formatter, tRPC routes, UI). Consider extracting these to shared constants to prevent drift, but this is not urgent.

apps/desktop/src/services/transcription-service.ts (1)

498-574: Consider extracting the repeated provider-instantiation pattern.

All three formatting branches (OpenRouter, Ollama, AppleIntelligence) follow an identical structure: check precondition → log → instantiate provider → call formatWithProvider → update result. This is a pre-existing pattern, but with a third provider it's becoming worth extracting into a helper (e.g., a factory or a map of provider constructors) to reduce the growing if/else-if chain and make adding future providers less error-prone.

Comment on lines 7 to 37
class FoundationModelService {

func checkAvailability() -> CheckFoundationModelAvailabilityResultSchema {
#if canImport(FoundationModels)
if #available(macOS 26, *) {
let model = SystemLanguageModel.default
switch model.availability {
case .available:
return CheckFoundationModelAvailabilityResultSchema(available: true, reason: nil)
case .unavailable(let reason):
return CheckFoundationModelAvailabilityResultSchema(available: false, reason: String(describing: reason))
@unknown default:
return CheckFoundationModelAvailabilityResultSchema(available: false, reason: "unknown")
}
}
#endif
return CheckFoundationModelAvailabilityResultSchema(available: false, reason: "deviceNotEligible")
}

func generate(params: GenerateWithFoundationModelParamsSchema) async throws -> GenerateWithFoundationModelResultSchema {
#if canImport(FoundationModels)
if #available(macOS 26, *) {
let instructions = params.systemPrompt
let session = LanguageModelSession(instructions: instructions)
let response = try await session.respond(to: params.userPrompt)
return GenerateWithFoundationModelResultSchema(content: response.content)
}
#endif
throw NSError(domain: "FoundationModelService", code: -1,
userInfo: [NSLocalizedDescriptionKey: "Foundation Models not available on this device"])
}
Copy link

@coderabbitai coderabbitai bot Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Apple FoundationModels framework LanguageModelSession macOS 26 Swift API documentation

💡 Result:

Apple’s FoundationModels framework (Swift) docs you’re looking for are in Apple Developer Documentation under the FoundationModels module, with LanguageModelSession as the main entry point for running the on-device LLM.

Key Apple API reference pages (Swift)

https://developer.apple.com/documentation/foundationmodels/systemlanguagemodel
https://developer.apple.com/documentation/foundationmodels/languagemodelsession
https://developer.apple.com/documentation/foundationmodels/languagemodelsession/response
https://developer.apple.com/documentation/foundationmodels/languagemodelsession/respond(to:generating:includeSchemaInPrompt:options:)
https://developer.apple.com/documentation/foundationmodels/languagemodelsession/respond(to:schema:includeSchemaInPrompt:options:)

Sources: Apple Developer Documentation pages for SystemLanguageModel, LanguageModelSession, LanguageModelSession.Response, and LanguageModelSession.respond(...). [1][2][3][4][5]

Minimal Swift usage (session-based)

import FoundationModels

let model = SystemLanguageModel.default
let session = LanguageModelSession(model: model)

let response = try await session.respond(to: "Write a 1-sentence summary of macOS 26.")
print(response.content)

(Types/methods documented on the pages above.) [1][2][4]

macOS 26 note (availability / simulator)

Apple states Foundation Models framework is available on iOS 26, iPadOS 26, and macOS 26. [6]
If you’re testing in the simulator, you may need the host Mac to be running macOS 26 (common error: “Host is not running macOS 26.”). [7]

Sources
[1] Apple Developer Documentation — SystemLanguageModel: (developer.apple.com)
[2] Apple Developer Documentation — LanguageModelSession (reference listing via related Apple doc pages): (developer.apple.com)
[3] Apple Developer Documentation — LanguageModelSession.Response: (developer.apple.com)
[4] Apple Developer Documentation — respond(to:generating:includeSchemaInPrompt:options:): (developer.apple.com)
[5] Apple Developer Documentation — respond(to:schema:includeSchemaInPrompt:options:): (developer.apple.com)
[6] Apple Newsroom — Foundation Models framework availability on iOS 26/iPadOS 26/macOS 26: (apple.com)
[7] Stack Overflow — simulator/macOS 26 host requirement error: (stackoverflow.com)

Citations:


LanguageModelSession constructor signature does not match official Apple documentation.

According to Apple's FoundationModels API reference, LanguageModelSession is initialized with a model parameter, not instructions. The correct constructor is LanguageModelSession(model:), but the code uses LanguageModelSession(instructions:). The system prompt handling is not documented in the official API; verify how to pass instructions/prompts to the session, as the current approach will not work as written.

Also confirm that session.respond(to:) should include the system prompt context. The documented API shows additional parameters like schema:, generating:, and options: that may be necessary for proper functionality.

🤖 Prompt for AI Agents
In
`@packages/native-helpers/swift-helper/Sources/SwiftHelper/services/FoundationModelService.swift`
around lines 7 - 37, The generate method uses the wrong LanguageModelSession
initializer and omits passing the system prompt into the session/response;
change LanguageModelSession(instructions: ...) to LanguageModelSession(model:
model) (e.g., let model = SystemLanguageModel.default; let session =
LanguageModelSession(model: model)) and then ensure the systemPrompt
(params.systemPrompt) is provided to the session/respond call per the
FoundationModels API (either by adding the prompt as an initial message/context
to the session or by using the documented respond(...) parameters such as
schema:, generating:, or options: to include system context); update the call to
session.respond(...) to match the official signature and include the
systemPrompt where required.

Copy link
Author

@kentaro kentaro Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LanguageModelSession(instructions:) is a valid initializer in the macOS 26 FoundationModels API. Verified working at runtime:

[FoundationModel] Raw response type: Response<String>
[FoundationModel] Raw response description: Response<String>(
  userPrompt: "...",
  duration: 1.12,
  content: "<formatted_text>\n私の好きな食べ物は以下の3つです:\n- ラーメン\n- カレー\n- 親子丼\n</formatted_text>"
)

The Apple documentation only lists LanguageModelSession(model:), but the instructions: parameter does exist and functions as the system prompt. The CodeRabbit web search results appear to be incomplete.

The other two issues (Hooks violation and GenerationOptions) have been addressed in 5b9a549.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kentaro ご指摘とランタイムログによる検証をありがとうございます!LanguageModelSession(instructions:) が有効なイニシャライザであることを確認いただき感謝します。

公式ドキュメントに記載されていない API が実際に存在し機能している点、貴重な情報です。実際の動作ログで instructions: パラメータがシステムプロンプトとして正しく機能していることが確認できました。

また、他の2点(Hooks 違反と GenerationOptions)への対応もありがとうございました(5b9a549)。

@haritabh-z01
Copy link
Contributor

@kentaro Thanks for this.
Will give this a check later today

kentaro and others added 3 commits February 9, 2026 13:36
Integrate macOS 26 Foundation Models as a formatting provider for transcribed text.
Apple Intelligence runs entirely on-device with no API key required, providing
text formatting with proper punctuation, capitalization, and structure.

Key changes:
- Add FoundationModelService in Swift helper with availability check and text generation
- Add AppleIntelligenceFormatter following the same pattern as OpenRouter/Ollama formatters
- Add RPC methods: checkFoundationModelAvailability, generateWithFoundationModel
- Add Apple Intelligence provider UI in settings with availability detection
- Add model sync via tRPC routes
- Wire up provider routing in TranscriptionService
- Remove misleading "If the text is empty" instruction from formatter prompt that
  caused on-device models to return empty formatted_text tags
- Graceful degradation on non-macOS and older macOS via platform checks at every layer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix React Hooks violation: move platform guard below all hook calls
  and add `enabled: isMac` to prevent query on non-Mac platforms
- Pass temperature/maxTokens to Foundation Model via GenerationOptions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zod z.number() maps to Swift Double via quicktype, but
GenerationOptions.maximumResponseTokens expects Int.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kentaro kentaro force-pushed the feat/apple-intelligence-formatting branch from 29b9885 to bbaaf11 Compare February 9, 2026 04:36
@haritabh-z01
Copy link
Contributor

@kentaro is the formatting working for you with Apple Intelligence? For me, the responses are very disappointing, to say the least.
CleanShot 2026-02-09 at 15 01 55@2x
the red arrows are the ones with formatting via apple intelligence.

@kentaro
Copy link
Author

kentaro commented Feb 9, 2026

Speak as follows:

私の好きな食べ物は以下の3つですラーメン、親子丼、カレーライスこれをリストにしてください

It has been formatted with Markdown syntax like this:

私の好きな食べ物は以下の3つです:

  • ラーメン
  • 親子丼
  • カレーライス

However, it seems Typeless can format without explicit instruction, but I wasn't able to implement that far.

image

Details are as follows.

[2026-02-09 20:37:28.821] [info] [transcription] Starting formatting { provider: 'AppleIntelligence', model: 'apple-intelligence' }
[2026-02-09 20:37:28.822] [debug] [pipeline] Apple Intelligence formatting request {
  systemPrompt: 'You are a professional text formatter. Your task is to format transcribed text to be clear, readable, and properly structured.\n' +
    '\n' +
    'Instructions:\n' +
    '1. Fix any transcription errors based on context and custom vocabulary\n' +
    '2. Add proper punctuation and capitalization\n' +
    '3. Format paragraphs appropriately with sufficient line breaks\n' +
    '4. Maintain the original meaning and tone\n' +
    '5. Use the custom vocabulary to correct domain-specific terms\n' +
    '6. Remove unnecessary filler words (um, uh, etc.) but keep natural speech patterns\n' +
    '7. Return ONLY the formatted text enclosed in <formatted_text></formatted_text> tags\n' +
    '8. Do not include any commentary, explanations, or text outside the XML tags\n' +
    '9. Apply standard formatting for general text\n' +
    '10. Create logical paragraph breaks based on content flow\n' +
    '11. Maintain consistent formatting throughout\n' +
    '12. Preserve the original tone and style',
  userPrompt: '私の好きな食べ物は以下の3つですラーメン、親子丼、カレーライスこれをリストにしてください'
}
[2026-02-09 20:37:28.822] [debug] [native-bridge] Sending RPC request: generateWithFoundationModel {
  method: 'generateWithFoundationModel',
  id: 'd6fda459-eda3-49e0-ac16-c2362628b880',
  startedAt: '2026-02-09T11:37:28.822Z'
}
[2026-02-09 20:37:28.822] [debug] [native-bridge] Successfully sent RPC request {
  method: 'generateWithFoundationModel',
  id: 'd6fda459-eda3-49e0-ac16-c2362628b880'
}
[2026-02-09 20:37:28.822] [warn] [native-bridge] SwiftHelper stderr output {
  message: '[2026-02-09 20:37:28.823] IOBridge: Received RPC Request ID d6fda459-eda3-49e0-ac16-c2362628b880, Method: generateWithFoundationModel\n' +
    '[2026-02-09 20:37:28.823] [IOBridge] Handling generateWithFoundationModel for ID: d6fda459-eda3-49e0-ac16-c2362628b880\n'
}
[2026-02-09 20:37:30.024] [debug] [native-bridge] Received message from helper {
  message: {
    result: {
      content: '<formatted_text>\n' +
        '私の好きな食べ物は以下の3つです:\n' +
        '- ラーメン\n' +
        '- 親子丼\n' +
        '- カレーライス\n' +
        '</formatted_text>'
    },
    id: 'd6fda459-eda3-49e0-ac16-c2362628b880'
  }
}
[2026-02-09 20:37:30.025] [debug] [native-bridge] Raw RPC response result received {
  method: 'generateWithFoundationModel',
  id: 'd6fda459-eda3-49e0-ac16-c2362628b880',
  result: {
    content: '<formatted_text>\n' +
      '私の好きな食べ物は以下の3つです:\n' +
      '- ラーメン\n' +
      '- 親子丼\n' +
      '- カレーライス\n' +
      '</formatted_text>'
  },
  startedAt: '2026-02-09T11:37:28.822Z',
  completedAt: '2026-02-09T11:37:30.025Z',
  durationMs: 1203
}
[2026-02-09 20:37:30.025] [debug] [pipeline] Apple Intelligence formatting raw response {
  rawResponse: '<formatted_text>\n私の好きな食べ物は以下の3つです:\n- ラーメン\n- 親子丼\n- カレーライス\n</formatted_text>'
}
[2026-02-09 20:37:30.026] [debug] [pipeline] Apple Intelligence formatting completed {
  original: '私の好きな食べ物は以下の3つですラーメン、親子丼、カレーライスこれをリストにしてください',
  formatted: '\n私の好きな食べ物は以下の3つです:\n- ラーメン\n- 親子丼\n- カレーライス\n',
  hadXmlTags: true
}
[2026-02-09 20:37:30.026] [info] [transcription] Text formatted successfully {
  originalLength: 44,
  formattedLength: 41,
  formattingDuration: 1204.2965000011027
}
[2026-02-09 20:37:30.026] [info] [transcription] Saving transcription with audio file {
  sessionId: 'session-2026-02-09T11-37-18-562Z',
  audioFilePath: '/var/folders/qp/by3blcjx3rl7s71kbxdssmpc0000gn/T/amical-audio/audio-session-2026-02-09T11-37-18-562Z-2026-02-09T11-37-28-353Z.wav',
  hasAudioFile: true
}
[2026-02-09 20:37:30.028] [warn] [native-bridge] SwiftHelper stderr output {
  message: '[2026-02-09 20:37:30.025] [Swift Biz Logic] FINAL JSON RESPONSE to stdout: {"result":{"content":"<formatted_text>\\n私の好きな食べ物は以下の3つです:\\n- ラーメン\\n- 親子丼\\n- カレーライス\\n<\\/formatted_text>"},"id":"d6fda459-eda3-49e0-ac16-c2362628b880"}\n'
}

@amadeus-x1
Copy link
Collaborator

Maybe it was a language issue on my end. I will retry and let you know.

…ersationally

The Foundation Model was treating raw transcription text as a
conversational query and responding with "I'm sorry, but I can't
assist with that request" instead of formatting it. Prefix the
user prompt with "Format the following transcribed text:" so the
model understands the task.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kentaro
Copy link
Author

kentaro commented Feb 9, 2026

Thanks for reporting this! The root cause is that the on-device Foundation Model is small and was treating raw transcription text as a conversational query — so instead of formatting it, the model was responding to it ("I'm sorry, but I can't assist with that request.").

I've pushed a fix (9390d6d) that wraps the user prompt with "Format the following transcribed text:\n\n${text}" so the model clearly understands it should format the text rather than respond to it.

It was working for me because I use Japanese as the input language, which is less likely to be interpreted as a conversational query by the model. English text like "hello" or short phrases were being treated as user questions.

Could you try again with the latest changes and let me know if it improves?

Always use amical-notes formatting rules (Markdown with smart
structure detection) for Apple Intelligence on-device formatting.
This ensures consistent output with bullet points, headers, etc.
based on content structure, without the user needing to explicitly
request list formatting.

Added overrideAppType option to constructFormatterPrompt for
future extensibility to other formatters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kentaro
Copy link
Author

kentaro commented Feb 9, 2026

Update: I've added basic implicit formatting for Apple Intelligence (a097068, 426f88f, df11fe6).

The on-device model now uses the amical-notes formatting rules with a few-shot examples, so it can handle basic structure detection — e.g., comma-separated items get formatted as bullet lists, sequential steps as numbered lists. This is still quite basic compared to what a larger cloud model can do, but should improve the output consistency for common cases.

The constructFormatterPrompt function now accepts an overrideAppType option, so this can be easily extended to other formatters (Ollama, OpenRouter) in the future. More advanced formatting improvements will be addressed in a follow-up PR.

kentaro and others added 2 commits February 9, 2026 23:41
On-device Foundation Models need concrete examples to reliably
detect implicit structure in speech (e.g., comma-separated items
should become bullet lists, sequential steps should become
numbered lists). Added three examples covering lists, steps, and
simple sentences.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Output is pasted into text fields that don't render Markdown, so
**bold** and *italic* markers appear as literal characters. Keep
only list and header formatting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants