ms-tau-sdk 2.0.8.dev46__tar.gz → 2.0.8.dev47__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/CHANGELOG.md +8 -0
  2. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/PKG-INFO +1 -1
  3. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/static/app.js +3 -0
  4. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/pyproject.toml +1 -1
  5. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/api/sessions.py +14 -2
  6. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/providers/factory.py +53 -28
  7. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/manager.py +5 -0
  8. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/.gitignore +0 -0
  9. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/README.md +0 -0
  10. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/__init__.py +0 -0
  11. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/app.py +0 -0
  12. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/cli.py +0 -0
  13. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/config.py +0 -0
  14. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/env_file.py +0 -0
  15. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/logs.py +0 -0
  16. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/proxy.py +0 -0
  17. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/state.py +0 -0
  18. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/static/BULMA-LICENSE.txt +0 -0
  19. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/static/board.css +0 -0
  20. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/static/bulma.min.css +0 -0
  21. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/packages/tau-board/src/ms_tau_board/static/index.html +0 -0
  22. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/__init__.py +0 -0
  23. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/agent_skills/tau_a2a_runtime_adapter/SKILL.md +0 -0
  24. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/agent_skills/tau_local_development/SKILL.md +0 -0
  25. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/agent_skills/tau_project_customization/SKILL.md +0 -0
  26. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/agent_skills/tau_repository_integration/SKILL.md +0 -0
  27. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/agent_skills/tau_security_and_access/SKILL.md +0 -0
  28. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/api/__init__.py +0 -0
  29. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/api/a2a.py +0 -0
  30. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/api/chat.py +0 -0
  31. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/api/conversations.py +0 -0
  32. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/api/dependencies.py +0 -0
  33. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/api/health.py +0 -0
  34. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/api/inspection.py +0 -0
  35. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/api/local_chat.py +0 -0
  36. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/api/models.py +0 -0
  37. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/api/request_identity.py +0 -0
  38. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/app.py +0 -0
  39. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/application.py +0 -0
  40. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/backend/__init__.py +0 -0
  41. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/backend/assertions.py +0 -0
  42. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/backend/auth.py +0 -0
  43. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/backend/client.py +0 -0
  44. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/backend/local.py +0 -0
  45. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/backend/mcp.py +0 -0
  46. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/backend/models.py +0 -0
  47. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/backend/routes.py +0 -0
  48. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/cli.py +0 -0
  49. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/errors.py +0 -0
  50. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/logging.py +0 -0
  51. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/protocols/__init__.py +0 -0
  52. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/protocols/a2a_failure.py +0 -0
  53. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/protocols/a2a_message.py +0 -0
  54. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/protocols/a2a_roles.py +0 -0
  55. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/protocols/assistant_ui.py +0 -0
  56. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/protocols/chat_history.py +0 -0
  57. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/protocols/strict_json.py +0 -0
  58. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/providers/__init__.py +0 -0
  59. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/providers/definitions.py +0 -0
  60. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/providers/tau_compat.py +0 -0
  61. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/resources/SYSTEM.md +0 -0
  62. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/resources/__init__.py +0 -0
  63. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/resources/loader.py +0 -0
  64. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/resources/prompts/review-code-repository.md +0 -0
  65. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/__init__.py +0 -0
  66. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/deployment_health.py +0 -0
  67. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/events.py +0 -0
  68. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/extensions.py +0 -0
  69. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/failures.py +0 -0
  70. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/live_turns.py +0 -0
  71. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/observability.py +0 -0
  72. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/provenance.py +0 -0
  73. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/requester.py +0 -0
  74. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/session.py +0 -0
  75. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/snapshots.py +0 -0
  76. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/runtime/task_context.py +0 -0
  77. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/sessions/__init__.py +0 -0
  78. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/sessions/storage.py +0 -0
  79. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/settings.py +0 -0
  80. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/skills.py +0 -0
  81. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/tools/__init__.py +0 -0
  82. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/tools/mainsequence_mcp.py +0 -0
  83. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/tools/mcp_applications.py +0 -0
  84. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/tools/mcp_connection.py +0 -0
  85. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/tools/skill_read.py +0 -0
  86. {ms_tau_sdk-2.0.8.dev46 → ms_tau_sdk-2.0.8.dev47}/src/ms_tau_sdk/tools/task_control.py +0 -0
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - **A thinking level the model cannot run no longer stops the turn
6
+ ([#82](https://github.com/mainsequence-sdk/ms-tau-sdk/issues/82)).** The platform can offer
7
+ levels this Tau release cannot run, such as `max` for the GPT-5.6 Codex models; every turn of
8
+ those models failed with "thinking levels exceed Tau execution support". Tau now uses only the
9
+ levels both support. A selected level outside them runs at the provider's default (`medium` for
10
+ Codex), else Tau's default, else the first shared level, and logs
11
+ `providers.thinking_level_unavailable`. `GET` and `PUT /api/chat/session-model` report the level
12
+ a loaded session runs at, and Tau Board's picker follows it.
5
13
  - **A new local chat reports and accepts its model before the first message
6
14
  ([#50](https://github.com/mainsequence-sdk/ms-tau-sdk/issues/50)).** In local mode,
7
15
  `GET /api/chat/session-model` for a session that has not had a turn returns the model it would
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ms-tau-sdk
3
- Version: 2.0.8.dev46
3
+ Version: 2.0.8.dev47
4
4
  Summary: Workspace-bound Tau application primitives for Main Sequence projects
5
5
  Project-URL: Changelog, https://github.com/mainsequence-sdk/ms-tau-sdk/blob/development/CHANGELOG.md
6
6
  Project-URL: Documentation, https://github.com/mainsequence-sdk/ms-tau-sdk/tree/development/docs
@@ -465,6 +465,9 @@ async function applyModelSelection(kind, sessionUid) {
465
465
  }
466
466
  } else if (current.status !== 404) throw new Error(errorMessage(await current.json().catch(() => ({})), current.status));
467
467
  const data = await json("/tau/api/chat/session-model", { method: "PUT", headers: tauHeaders(kind, { "Content-Type": "application/json" }), body: JSON.stringify({ sessionUid, provider: choice.provider, model: choice.model, thinkingLevel: choice.thinking || null }) });
468
+ // A level the model cannot run falls back to another; the picker follows what Tau runs.
469
+ choice.thinking = data.model.thinkingLevel || "";
470
+ $(`${kind}-thinking`).value = choice.thinking;
468
471
  $(`${kind}-effective`).textContent = `Tau confirmed ${data.model.provider} / ${data.model.model} / ${data.model.thinkingLevel || "default"}`;
469
472
  return data.sessionUid || sessionUid;
470
473
  }
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ms-tau-sdk"
7
- version = "2.0.8.dev46"
7
+ version = "2.0.8.dev47"
8
8
  description = "Workspace-bound Tau application primitives for Main Sequence projects"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -40,9 +40,21 @@ def _session_model(
40
40
  }
41
41
 
42
42
 
43
+ def _thinking_level(
44
+ manager: SessionRuntimeManager,
45
+ session_uid: str,
46
+ selected: str | None,
47
+ ) -> str | None:
48
+ # A loaded session runs a selected level its model cannot run at a fallback level instead.
49
+ if selected is None:
50
+ return None
51
+ return manager.running_thinking_level(session_uid) or selected
52
+
53
+
43
54
  @router.get("/session-model")
44
55
  async def session_model(
45
56
  client: BackendDep,
57
+ manager: RuntimeManagerDep,
46
58
  config: SettingsDep,
47
59
  session_uid: str = Query(alias="sessionUid"),
48
60
  ) -> dict[str, object]:
@@ -68,7 +80,7 @@ async def session_model(
68
80
  session_uid,
69
81
  provider=session.active_provider,
70
82
  model=session.active_model,
71
- thinking_level=session.active_thinking,
83
+ thinking_level=_thinking_level(manager, session_uid, session.active_thinking),
72
84
  custom_id=session.custom_id,
73
85
  )
74
86
 
@@ -107,7 +119,7 @@ async def select_session_model(
107
119
  session_uid,
108
120
  provider=session.active_provider,
109
121
  model=session.active_model,
110
- thinking_level=session.active_thinking,
122
+ thinking_level=_thinking_level(manager, session_uid, session.active_thinking),
111
123
  custom_id=session.custom_id,
112
124
  )
113
125
 
@@ -9,6 +9,7 @@ from dataclasses import dataclass
9
9
  from datetime import UTC, datetime, timedelta
10
10
  from urllib.parse import urlsplit
11
11
 
12
+ import structlog
12
13
  from tau_agent.provider import ModelProvider
13
14
  from tau_ai.anthropic import AnthropicProvider
14
15
  from tau_ai.env import AnthropicConfig, OpenAICompatibleConfig
@@ -69,6 +70,27 @@ BLOCKED_CUSTOM_PROVIDER_HOSTS = frozenset(
69
70
  }
70
71
  )
71
72
 
73
+ logger = structlog.get_logger(__name__)
74
+
75
+
76
+ def _fall_back(
77
+ level: ThinkingLevel,
78
+ *,
79
+ selected: ThinkingLevel | None,
80
+ provider_name: str,
81
+ model: str,
82
+ ) -> ThinkingLevel:
83
+ """Use ``level`` in place of a selected level the model cannot run, and say so."""
84
+ if selected is not None:
85
+ logger.warning(
86
+ "providers.thinking_level_unavailable",
87
+ provider=provider_name,
88
+ model=model,
89
+ selected=selected,
90
+ used=level,
91
+ )
92
+ return level
93
+
72
94
 
73
95
  @dataclass(frozen=True, slots=True)
74
96
  class ProviderRuntime:
@@ -185,25 +207,26 @@ class ProviderFactory:
185
207
  "Platform provider-control thinking levels contradict the "
186
208
  "custom model reasoning capability"
187
209
  )
188
- if thinking_level and normalized_thinking not in projected_thinking:
189
- supported = ", ".join(sorted(projected_thinking)) or "none"
190
- raise ConfigurationError(
191
- f"Thinking level {normalized_thinking!r} is not supported by "
192
- f"{provider_name}:{model}; available levels: {supported}"
193
- )
194
210
  self.validate_input_media(
195
211
  provider_control,
196
212
  media_types=media_types or set(),
197
213
  )
198
- if thinking_level:
214
+ if thinking_level and normalized_thinking in projected_thinking:
199
215
  return normalized_thinking
200
216
  if not projected_thinking or not provider_control.model.reasoning:
201
- return DEFAULT_THINKING_LEVEL
202
- if DEFAULT_THINKING_LEVEL in projected_thinking:
203
- return DEFAULT_THINKING_LEVEL
204
- if "off" in projected_thinking:
205
- return "off"
206
- return provider_control.model.thinking_levels[0]
217
+ default = DEFAULT_THINKING_LEVEL
218
+ elif DEFAULT_THINKING_LEVEL in projected_thinking:
219
+ default = DEFAULT_THINKING_LEVEL
220
+ elif "off" in projected_thinking:
221
+ default = "off"
222
+ else:
223
+ default = provider_control.model.thinking_levels[0]
224
+ return _fall_back(
225
+ default,
226
+ selected=normalized_thinking if thinking_level else None,
227
+ provider_name=provider_name,
228
+ model=model,
229
+ )
207
230
  if model not in provider.models:
208
231
  raise ConfigurationError(
209
232
  f"Model is not configured for provider {provider_name}: {model}"
@@ -229,30 +252,32 @@ class ProviderFactory:
229
252
  "Platform provider-control input capabilities exceed Tau execution support"
230
253
  )
231
254
  tau_thinking = set(self._thinking_levels(provider, model))
232
- projected_thinking = set(provider_control.model.thinking_levels)
233
- if not projected_thinking.issubset(tau_thinking):
234
- raise ConfigurationError(
235
- "Platform provider-control thinking levels exceed Tau execution support"
236
- )
237
255
  if provider_control.model.reasoning and not tau_thinking:
238
256
  raise ConfigurationError(
239
257
  "Platform provider-control reasoning capability exceeds Tau execution support"
240
258
  )
241
- available = tau_thinking.intersection(projected_thinking)
242
- if thinking_level and normalized_thinking not in available:
243
- supported = ", ".join(sorted(available)) or "none"
244
- raise ConfigurationError(
245
- f"Thinking level {normalized_thinking!r} is not supported by "
246
- f"{provider_name}:{model}; available levels: {supported}"
247
- )
259
+ # The platform may offer levels this Tau release cannot run; only shared ones are used.
260
+ available = [
261
+ level for level in provider_control.model.thinking_levels if level in tau_thinking
262
+ ]
248
263
  self.validate_input_media(
249
264
  provider_control,
250
265
  media_types=media_types or set(),
251
266
  )
252
- if thinking_level:
267
+ if thinking_level and normalized_thinking in available:
253
268
  return normalized_thinking
254
- default = provider.thinking_default
255
- return default if default in available else DEFAULT_THINKING_LEVEL
269
+ if provider.thinking_default is not None and provider.thinking_default in available:
270
+ default = provider.thinking_default
271
+ elif DEFAULT_THINKING_LEVEL in available or not available:
272
+ default = DEFAULT_THINKING_LEVEL
273
+ else:
274
+ default = available[0]
275
+ return _fall_back(
276
+ default,
277
+ selected=normalized_thinking if thinking_level else None,
278
+ provider_name=provider_name,
279
+ model=model,
280
+ )
256
281
 
257
282
  def validate_input_media(
258
283
  self,
@@ -2205,6 +2205,11 @@ class SessionRuntimeManager:
2205
2205
  with bound_contextvars(session_uid=session_uid):
2206
2206
  await self._evict_with_context(session_uid)
2207
2207
 
2208
+ def running_thinking_level(self, session_uid: str) -> str | None:
2209
+ """The thinking level a loaded session runs at, which may differ from its selection."""
2210
+ runtime = self._runtimes.get(session_uid)
2211
+ return runtime.coding_session.thinking_level if runtime is not None else None
2212
+
2208
2213
  async def change_session_model(
2209
2214
  self,
2210
2215
  session_uid: str,