Claude for Foundation Models

repository·main·Indexed 42 days ago

https://github.com/anthropics/claudeforfoundationmodels

A Swift package that integrates Claude as a server-side language model into Apple's Foundation Models framework. It enables the use of Claude via the standard LanguageModelSession API, supporting streaming, structured output with @Generable, and server-side tools like web search and code execution. Includes support for App Attest authentication, API keys, and model fallbacks for policy refusals.

Tokens
3.1K
Snippets
13
Records
14
Agent score
6%

What's inside Claude for Foundation Models

  1. Use model fallbacks for policy refusals

    main

    If a model declines a request due to policy areas (e.g., cybersecurity), you can specify fallback models using fallbacks:. The API will automatically retry the request on these models in order.

    • You can specify up to three fallbacks.
    • Use .serverDefault to use the model's recommended fallback configuration.
    • If a fallback occurs mid-response, the fallback model continues from the declining model's text, and the handover is reported in the session transcript.
    // Specify explicit fallback models
    ClaudeLanguageModel(name: .opus5, auth: auth, fallbacks: [.opus4_8])
    
    // Use the server's recommended fallback configuration
    ClaudeLanguageModel(name: .opus5, auth: auth, fallbacks: .serverDefault)
    
    // Detecting a handover in the transcript
    for case .response(let entry) in session.transcript {
      if let handover = entry.claudeHandovers.last {
        print("\(handover.fromModelID) declined, and \(handover.toModelID) finished the answer")
      }
    }
  2. Authenticate with App Attest

    main

    For production apps, .appAttest(clientID:) is the recommended authentication method. It uses Apple's App Attest to prove the app is a genuine, unmodified copy, billing usage to your Anthropic workspace without shipping an API key.

    Requirements:

    1. Register your app's Team ID and Bundle ID in the Anthropic console to get a Client ID.
    2. Add the App Attest entitlement (com.apple.developer.devicecheck.appattest-environment) to your app.
    3. Use a physical device (Simulators/hardware without Secure Enclave will throw ClaudeError.attestationUnsupported).

    Best Practice: Call try await model.authenticateIfNeeded() at app launch to handle the one-time attestation cost before the user's first prompt.

    // Recommended for production
    ClaudeLanguageModel(name: .sonnet5, auth: .appAttest(clientID: "clid_..."))
    
    // Handle attestation at app launch
    try await model.authenticateIfNeeded()
  3. Handle Claude Server Tool activities in transcripts

    main

    When a model uses a server-side tool, the response transcript contains segments representing the activity. In the transcript, prose appears in text segments, while tool calls appear as empty segments holding the call's place.

    To detect and render these activities (like web searches) inline, use entry.claudeServerToolActivity(for: segment). A call appears as soon as the model issues it, and its outcome is filled in when the result arrives in the same response.

    To access all round-trips in a conversation, use session.transcript.claudeServerToolActivities.

    for case .response(let entry) in session.transcript {
      for segment in entry.segments {
        if let activity = entry.claudeServerToolActivity(for: segment) {
          if case .webSearch(let search) = activity.content { print("Searched for \(search.query)") }
        } else if case .text(let text) = segment {
          print(text.content)
        }
      }
    }
  4. Install ClaudeForFoundationModels

    main

    Add the package to your Package.swift dependencies or via Xcode's File ▸ Add Package Dependencies… using the repository URL.

    After adding the dependency, import both FoundationModels and ClaudeForFoundationModels in your Swift files.

    // Package.swift
    dependencies: [
      .package(url: "https://github.com/anthropics/ClaudeForFoundationModels.git", from: "0.1.0")
    ]
    
    // In your Swift file
    import FoundationModels
    import ClaudeForFoundationModels
  5. Quick start with ClaudeLanguageModel

    main

    To use Claude, initialize a ClaudeLanguageModel with a model name (from the ClaudeModel enum) and an authentication method. Pass this model to a LanguageModelSession to interact with the model using the standard LanguageModelSession API, such as respond(to:).

    import FoundationModels
    import ClaudeForFoundationModels
    
    let model = ClaudeLanguageModel(
      name: .sonnet5,
      auth: .apiKey(ProcessInfo.processInfo.environment["ANTHROPIC_API_KEY"] ?? "")
    )
    
    let session = LanguageModelSession(model: model)
    let response = try await session.respond(to: "Plan a 4-day trip to Buenos Aires.")
    print(response.content)
  6. Handle ClaudeError and provider errors

    main

    The library uses two main error categories:

    1. LanguageModelError: Covers Foundation Models specific issues like guardrails, context length, and decoding errors.
    2. ClaudeError: Covers provider-specific errors that do not map to LanguageModelError (e.g., authentication issues).

    Use pattern matching to drive specific product flows, such as prompting for an API key when a credential is missing.

    do {
      let response = try await session.respond(to: prompt)
      print(response.content)
    } catch ClaudeError.missingCredential {
      // Prompt for an API key.
    } catch {
      // Foundation Models errors (guardrails, context length, decoding) and transport errors.
    }
  7. Stream responses with server-side tool activities

    main

    To render searches and tool activities inline while the answer is still streaming, iterate over the session.streamResponse(to:) async sequence and walk the snapshot.transcriptEntries similarly to how you would walk a static transcript.

    for try await snapshot in session.streamResponse(to: prompt) {
      for case .response(let entry) in snapshot.transcriptEntries {
        for segment in entry.segments {
          // Handle text or activity as shown in transcript examples
        }
      }
    }
  8. Configure Server-side tools

    main

    Server-side tools (web search, web fetch, and code execution) run on Anthropic's infrastructure within a single round-trip. You configure them per model using the serverTools: parameter in the ClaudeLanguageModel initializer.

    Note that serverTools: is distinct from the framework's tools: array; tools: is used for client-side tools that the framework invokes on the device, whereas serverTools: are managed by Anthropic.

    Supported tools include:

    • .webSearch(maxUses: Int?, domains: DomainFilter)
    • .webFetch(domains: DomainFilter)
    • .codeExecution

    For .webSearch and .webFetch, the domains: filter can be:

    • .unrestricted (default)
    • .allowing([...])
    • .blocking([...])
    let model = ClaudeLanguageModel(
      name: .sonnet5,
      auth: auth,
      serverTools: [
        .webSearch(maxUses: 5),
        .codeExecution,
      ]
    )
  9. Configure Claude effort levels

    main

    You can pin a specific Claude effort level for every request using the fixedEffort: parameter in ClaudeLanguageModel.

    Supported levels are low, medium, high, xhigh, and max. The API defaults to high if no effort is specified. The framework's reasoning levels map to Claude effort as follows:

    • .light → low
    • .moderate → medium
    • .deep → high
    • .custom → accepts a direct string like "xhigh" or "max".
    ClaudeLanguageModel(name: .opus5, auth: auth, fixedEffort: .xhigh)
  10. Stream responses with streamResponse(to:)

    main

    To receive model responses incrementally, use session.streamResponse(to:). Each element in the resulting stream is a cumulative snapshot of the content.

    let stream = session.streamResponse(to: "Summarize today's top science stories.")
    for try await partial in stream {
      print(partial.content)
    }
  11. Authenticate with API Keys or Proxies

    main

    Depending on your environment, use one of the following authentication methods:

    • .apiKey("..."): Best for simulator development. Do not ship with a bundled key in production.
    • .proxied(headers: [...], baseURL: ...): Use this if you route requests through your own backend. The relay at baseURL adds the credentials. Ensure your relay forwards the anthropic-beta header for fallbacks and the anthropic-user-profile-id header for user profiles.
    // For simulator iteration
    ClaudeLanguageModel(name: .sonnet5, auth: .apiKey("..."))
    
    // For custom backend relays
    ClaudeLanguageModel(
      name: .sonnet5,
      auth: .proxied(headers: ["X-App-Token": "..."]),
      baseURL: URL(string: "https://api.yourapp.com/claude")!
    )