Apple is explicit in WWDC26: a Dynamic Profile resolves to a single active Profile. Conditionals pick it. Nested instructions can compose, but you still have one running configuration.
Stateorchestrator.mode
Bodyswitch
ActiveOne Profile
enum Mode: String, Sendable { case gather, decide, act, review, done }
@Observable
final class AgentState {
var mode: Mode = .gather
}
struct AgentProfile: LanguageModelSession.DynamicProfile {
let state: AgentState
var body: some LanguageModelSession.DynamicProfile {
switch state.mode {
case .gather:
Profile {
Instructions { "Collect facts. Do not act." }
}
.model(SystemLanguageModel())
case .decide:
Profile {
Instructions { "Choose one legal next action." }
}
.model(SystemLanguageModel())
case .act:
Profile {
Instructions { "Call only the allowed act tool." }
}
.model(SystemLanguageModel())
case .review:
Profile {
Instructions { "Summarize what changed for the user." }
}
.model(SystemLanguageModel())
case .done:
Profile {
Instructions { "The task is finished. Do not call tools." }
}
.model(SystemLanguageModel())
}
}
}
Use the model router if gather should stay on-device and decide should use PCC. The modifier still sits on this one branch. Do not open a second session for a second persona in the same turn.
Re-evaluate each prompt. The body runs again. Change
mode before you call respond, or the old Profile stays active.Next, let tools propose transitions without owning them.
Key concepts
- A Dynamic Profile switches on
state.modeand resolves to one Profile. - Each mode gets its own instructions and model modifier.
- Change
modebeforerespond, or the old Profile stays active. - Do not open a second session for a second persona in the same turn.
Takeaways
- Use the model router if gather stays on-device and decide uses PCC.
- Nested instructions compose but one configuration runs.
- The body re-evaluates each prompt.