ms-tau-sdk 1.2.7.dev10__tar.gz → 1.2.7.dev11__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.
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/PKG-INFO +1 -1
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/pyproject.toml +1 -1
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/api/a2a.py +8 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/api/models.py +7 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/api/sessions.py +35 -2
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/backend/client.py +8 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/backend/local.py +62 -15
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/backend/routes.py +1 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/manager.py +67 -2
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/session.py +2 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/.gitignore +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/CHANGELOG.md +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/README.md +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/__init__.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/agent_skills/tau_a2a_runtime_adapter/SKILL.md +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/agent_skills/tau_local_development/SKILL.md +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/agent_skills/tau_project_customization/SKILL.md +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/agent_skills/tau_repository_integration/SKILL.md +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/api/__init__.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/api/chat.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/api/dependencies.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/api/health.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/app.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/application.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/backend/__init__.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/backend/auth.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/backend/mcp.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/backend/models.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/cli.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/errors.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/logging.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/protocols/__init__.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/protocols/a2a_message.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/protocols/a2a_roles.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/protocols/assistant_ui.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/protocols/strict_json.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/providers/__init__.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/providers/definitions.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/providers/factory.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/resources/SYSTEM.md +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/resources/__init__.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/resources/loader.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/resources/prompts/review-code-repository.md +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/__init__.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/deployment_health.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/events.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/extensions.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/failures.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/observability.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/provenance.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/snapshots.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/task_context.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/sessions/__init__.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/sessions/storage.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/settings.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/skills.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/tools/__init__.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/tools/mainsequence_mcp.py +0 -0
- {ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/tools/task_control.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ms-tau-sdk
|
|
3
|
-
Version: 1.2.7.
|
|
3
|
+
Version: 1.2.7.dev11
|
|
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
|
|
@@ -17,6 +17,7 @@ from typing import Annotated, Any
|
|
|
17
17
|
import structlog
|
|
18
18
|
from fastapi import APIRouter, Depends, Header, HTTPException, Query, Request
|
|
19
19
|
from fastapi.responses import JSONResponse, StreamingResponse
|
|
20
|
+
from structlog.contextvars import bind_contextvars
|
|
20
21
|
from tau_agent.types import JSONValue
|
|
21
22
|
|
|
22
23
|
from ms_tau_sdk.backend.client import MainSequenceClient
|
|
@@ -1054,6 +1055,13 @@ async def _execute_task(
|
|
|
1054
1055
|
dispatch_uid: str | None = None,
|
|
1055
1056
|
claim: _ClaimedTask | None = None,
|
|
1056
1057
|
) -> dict[str, Any]:
|
|
1058
|
+
bind_contextvars(
|
|
1059
|
+
a2a_task_id=task.task_id,
|
|
1060
|
+
task_uid=task.uid,
|
|
1061
|
+
a2a_context_id=task.context_id,
|
|
1062
|
+
session_uid=task.context_id,
|
|
1063
|
+
agent_session_uid=task.context_id,
|
|
1064
|
+
)
|
|
1057
1065
|
if claim is None:
|
|
1058
1066
|
claim = await _claim_backend_task(
|
|
1059
1067
|
client,
|
|
@@ -54,3 +54,10 @@ class CancelRequest(ApiModel):
|
|
|
54
54
|
)
|
|
55
55
|
)
|
|
56
56
|
message: str | None = None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class SessionModelSelection(ApiModel):
|
|
60
|
+
session_uid: str = Field(validation_alias=AliasChoices("sessionUid", "session_uid"))
|
|
61
|
+
provider: str
|
|
62
|
+
model: str
|
|
63
|
+
thinking_level: str | None = Field(default=None, validation_alias="thinkingLevel")
|
|
@@ -4,14 +4,14 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import Annotated
|
|
6
6
|
|
|
7
|
-
from fastapi import APIRouter, Depends, Query
|
|
7
|
+
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
8
8
|
|
|
9
9
|
from ms_tau_sdk.backend.client import MainSequenceClient
|
|
10
10
|
from ms_tau_sdk.runtime.manager import SessionRuntimeManager
|
|
11
11
|
from ms_tau_sdk.settings import TauSDKSettings
|
|
12
12
|
|
|
13
13
|
from .dependencies import backend, runtime_manager, settings
|
|
14
|
-
from .models import CancelRequest
|
|
14
|
+
from .models import CancelRequest, SessionModelSelection
|
|
15
15
|
|
|
16
16
|
router = APIRouter(prefix="/api/chat")
|
|
17
17
|
BackendDep = Annotated[MainSequenceClient, Depends(backend)]
|
|
@@ -38,6 +38,39 @@ async def session_model(
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
@router.get("/model-providers")
|
|
42
|
+
async def model_providers(client: BackendDep, config: SettingsDep) -> dict[str, object]:
|
|
43
|
+
if not config.local_mode:
|
|
44
|
+
raise HTTPException(status_code=409, detail="Provider catalog is local-mode only")
|
|
45
|
+
return await client.list_model_providers()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@router.put("/session-model")
|
|
49
|
+
async def select_session_model(
|
|
50
|
+
body: SessionModelSelection,
|
|
51
|
+
manager: RuntimeManagerDep,
|
|
52
|
+
config: SettingsDep,
|
|
53
|
+
) -> dict[str, object]:
|
|
54
|
+
if not config.local_mode:
|
|
55
|
+
raise HTTPException(status_code=409, detail="Model selection is local-mode only")
|
|
56
|
+
session_uid = config.local_session_uid(body.session_uid)
|
|
57
|
+
await manager.change_session_model(
|
|
58
|
+
session_uid,
|
|
59
|
+
provider=body.provider,
|
|
60
|
+
model=body.model,
|
|
61
|
+
thinking_level=body.thinking_level,
|
|
62
|
+
)
|
|
63
|
+
session = await manager.backend.get_session(session_uid)
|
|
64
|
+
return {
|
|
65
|
+
"sessionUid": session_uid,
|
|
66
|
+
"model": {
|
|
67
|
+
"provider": session.active_provider,
|
|
68
|
+
"model": session.active_model,
|
|
69
|
+
"thinkingLevel": session.active_thinking,
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
41
74
|
@router.post("/session/cancel")
|
|
42
75
|
async def cancel_session(
|
|
43
76
|
body: CancelRequest,
|
|
@@ -50,6 +50,7 @@ from .models import (
|
|
|
50
50
|
)
|
|
51
51
|
from .routes import (
|
|
52
52
|
AGENT_TASKS,
|
|
53
|
+
MODEL_PROVIDERS,
|
|
53
54
|
agent_session,
|
|
54
55
|
agent_session_agent_card,
|
|
55
56
|
agent_session_entries,
|
|
@@ -283,6 +284,13 @@ class MainSequenceClient:
|
|
|
283
284
|
detail=error.errors(include_input=False),
|
|
284
285
|
) from error
|
|
285
286
|
|
|
287
|
+
async def list_model_providers(self) -> dict[str, Any]:
|
|
288
|
+
"""Read the authenticated user's safe provider catalog from Main Sequence."""
|
|
289
|
+
data = await self._request("GET", MODEL_PROVIDERS, idempotent=True)
|
|
290
|
+
if not isinstance(data, dict) or not isinstance(data.get("providers"), list):
|
|
291
|
+
raise BackendError("Backend model-provider catalog response is invalid")
|
|
292
|
+
return data
|
|
293
|
+
|
|
286
294
|
async def update_session_config(
|
|
287
295
|
self,
|
|
288
296
|
session_uid: str,
|
|
@@ -109,6 +109,9 @@ class LocalDevelopmentBackend(MainSequenceClient):
|
|
|
109
109
|
async def aclose(self) -> None:
|
|
110
110
|
await self._services.aclose()
|
|
111
111
|
|
|
112
|
+
async def list_model_providers(self) -> dict[str, Any]:
|
|
113
|
+
return await self._services.list_model_providers()
|
|
114
|
+
|
|
112
115
|
async def _ensure_initialized(self) -> None:
|
|
113
116
|
if self._initialized:
|
|
114
117
|
return
|
|
@@ -269,8 +272,8 @@ class LocalDevelopmentBackend(MainSequenceClient):
|
|
|
269
272
|
raise BackendConflictError("Local provider/model selection is not configured")
|
|
270
273
|
return provider, model, self.settings.local_thinking
|
|
271
274
|
|
|
272
|
-
def _runtime_config_sha256(self) -> str:
|
|
273
|
-
provider, model, thinking = self._selection()
|
|
275
|
+
def _runtime_config_sha256(self, selection: tuple[str, str, str | None] | None = None) -> str:
|
|
276
|
+
provider, model, thinking = selection or self._selection()
|
|
274
277
|
payload = json.dumps(
|
|
275
278
|
{"provider": provider, "model": model, "thinking": thinking},
|
|
276
279
|
sort_keys=True,
|
|
@@ -278,8 +281,10 @@ class LocalDevelopmentBackend(MainSequenceClient):
|
|
|
278
281
|
).encode("utf-8")
|
|
279
282
|
return "sha256:" + hashlib.sha256(payload).hexdigest()
|
|
280
283
|
|
|
281
|
-
async def _hydrate_evidence(
|
|
282
|
-
|
|
284
|
+
async def _hydrate_evidence(
|
|
285
|
+
self, *, holder_id: str, selection: tuple[str, str, str | None] | None = None
|
|
286
|
+
) -> ProviderExecutionEvidence:
|
|
287
|
+
provider, model, thinking = selection or self._selection()
|
|
283
288
|
evidence = await self._services.hydrate_local_provider_credential(
|
|
284
289
|
provider,
|
|
285
290
|
model=model,
|
|
@@ -342,16 +347,24 @@ class LocalDevelopmentBackend(MainSequenceClient):
|
|
|
342
347
|
holder_id: str,
|
|
343
348
|
) -> ProviderExecutionEvidence:
|
|
344
349
|
del agent_uid
|
|
345
|
-
selected_provider, selected_model,
|
|
350
|
+
selected_provider, selected_model, selected_thinking = self._selection()
|
|
351
|
+
if session_uid is not None:
|
|
352
|
+
session = await self.get_session(session_uid)
|
|
353
|
+
selected_provider = session.active_provider or ""
|
|
354
|
+
selected_model = session.active_model or ""
|
|
355
|
+
selected_thinking = session.active_thinking
|
|
346
356
|
if provider != selected_provider or model != selected_model:
|
|
347
357
|
raise BackendConflictError(
|
|
348
|
-
"Local provider refresh does not match the
|
|
358
|
+
"Local provider refresh does not match the session selection"
|
|
349
359
|
)
|
|
350
360
|
if session_uid is not None:
|
|
351
361
|
canonical = self.settings.local_session_uid(session_uid)
|
|
352
362
|
if canonical != session_uid:
|
|
353
363
|
raise SessionNotFoundError("Local session identifier is invalid")
|
|
354
|
-
return await self._hydrate_evidence(
|
|
364
|
+
return await self._hydrate_evidence(
|
|
365
|
+
holder_id=holder_id,
|
|
366
|
+
selection=(selected_provider, selected_model, selected_thinking),
|
|
367
|
+
)
|
|
355
368
|
|
|
356
369
|
async def get_session(self, session_uid: str) -> AgentSession:
|
|
357
370
|
def operation() -> AgentSession:
|
|
@@ -374,11 +387,35 @@ class LocalDevelopmentBackend(MainSequenceClient):
|
|
|
374
387
|
model: str,
|
|
375
388
|
thinking_level: str | None,
|
|
376
389
|
) -> AgentSession:
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
390
|
+
if not provider or not model:
|
|
391
|
+
raise BackendConflictError("A provider and model are required")
|
|
392
|
+
selection = (provider, model, thinking_level)
|
|
393
|
+
await self._hydrate_evidence(
|
|
394
|
+
holder_id=f"local-selection-{self.settings.workspace_digest}",
|
|
395
|
+
selection=selection,
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
def operation() -> None:
|
|
399
|
+
with closing(self._connect()) as connection, connection:
|
|
400
|
+
row = connection.execute(
|
|
401
|
+
"SELECT runtime_activity FROM sessions WHERE uid = ?", (session_uid,)
|
|
402
|
+
).fetchone()
|
|
403
|
+
if row is None:
|
|
404
|
+
raise SessionNotFoundError(f"Local session not found: {session_uid}")
|
|
405
|
+
if row["runtime_activity"] == "working":
|
|
406
|
+
raise BackendConflictError("Cannot change a model while the session is working")
|
|
407
|
+
connection.execute(
|
|
408
|
+
"UPDATE sessions SET provider = ?, model = ?, thinking = ?, "
|
|
409
|
+
"runtime_config_sha256 = ?, updated_at = ? WHERE uid = ?",
|
|
410
|
+
(
|
|
411
|
+
*selection,
|
|
412
|
+
self._runtime_config_sha256(selection),
|
|
413
|
+
_iso(_utcnow()),
|
|
414
|
+
session_uid,
|
|
415
|
+
),
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
await self._run(operation)
|
|
382
419
|
return await self.get_session(session_uid)
|
|
383
420
|
|
|
384
421
|
async def get_agent_card(self, session_uid: str) -> AgentCardEnvelope:
|
|
@@ -669,13 +706,23 @@ class LocalDevelopmentBackend(MainSequenceClient):
|
|
|
669
706
|
session_uid: str,
|
|
670
707
|
request: TauRuntimeBootstrapRequest,
|
|
671
708
|
) -> TauRuntimeBootstrap:
|
|
672
|
-
|
|
673
|
-
|
|
709
|
+
def stored_selection() -> tuple[str, str, str | None]:
|
|
710
|
+
with closing(self._connect()) as connection:
|
|
711
|
+
row = connection.execute(
|
|
712
|
+
"SELECT provider, model, thinking FROM sessions WHERE uid = ?", (session_uid,)
|
|
713
|
+
).fetchone()
|
|
714
|
+
if row is None:
|
|
715
|
+
return self._selection()
|
|
716
|
+
return str(row["provider"]), str(row["model"]), row["thinking"]
|
|
717
|
+
|
|
718
|
+
selection = await self._run(stored_selection)
|
|
719
|
+
provider, model, thinking = selection
|
|
720
|
+
evidence = await self._hydrate_evidence(holder_id=request.holder_id, selection=selection)
|
|
674
721
|
|
|
675
722
|
def operation() -> TauRuntimeBootstrap:
|
|
676
723
|
now = _utcnow()
|
|
677
724
|
expires = now + timedelta(seconds=request.ttl_seconds)
|
|
678
|
-
runtime_config_sha256 = self._runtime_config_sha256()
|
|
725
|
+
runtime_config_sha256 = self._runtime_config_sha256(selection)
|
|
679
726
|
with closing(self._connect()) as connection, connection:
|
|
680
727
|
connection.execute("BEGIN IMMEDIATE")
|
|
681
728
|
row = connection.execute(
|
|
@@ -9,6 +9,7 @@ API_V1_PREFIX = "/api/v1"
|
|
|
9
9
|
RUNTIME_CREDENTIAL_TOKEN = f"{API_V1_PREFIX}/runtime-credentials/token/"
|
|
10
10
|
AGENT_SESSIONS = f"{API_V1_PREFIX}/agent-sessions/"
|
|
11
11
|
MODEL_PROVIDER_CREDENTIALS = f"{API_V1_PREFIX}/model-provider-credentials/"
|
|
12
|
+
MODEL_PROVIDERS = f"{API_V1_PREFIX}/model-providers/"
|
|
12
13
|
AGENT_TASKS = f"{API_V1_PREFIX}/agent-tasks/"
|
|
13
14
|
|
|
14
15
|
type RuntimeLeaseOperation = Literal["acquire", "renew", "release"]
|
|
@@ -970,6 +970,9 @@ class SessionRuntimeManager:
|
|
|
970
970
|
"principal_type",
|
|
971
971
|
"coding_agent_service_uid",
|
|
972
972
|
"agent_session_uid",
|
|
973
|
+
"a2a_task_id",
|
|
974
|
+
"a2a_context_id",
|
|
975
|
+
"task_uid",
|
|
973
976
|
"agent_uid",
|
|
974
977
|
"agent_run_uid",
|
|
975
978
|
"turn_uid",
|
|
@@ -1168,9 +1171,71 @@ class SessionRuntimeManager:
|
|
|
1168
1171
|
with bound_contextvars(session_uid=session_uid):
|
|
1169
1172
|
await self._evict_with_context(session_uid)
|
|
1170
1173
|
|
|
1171
|
-
async def
|
|
1174
|
+
async def change_session_model(
|
|
1175
|
+
self,
|
|
1176
|
+
session_uid: str,
|
|
1177
|
+
*,
|
|
1178
|
+
provider: str,
|
|
1179
|
+
model: str,
|
|
1180
|
+
thinking_level: str | None,
|
|
1181
|
+
) -> None:
|
|
1182
|
+
"""Switch an idle session and reload it with backend-authorized evidence."""
|
|
1183
|
+
if not self.settings.local_mode:
|
|
1184
|
+
raise BackendConflictError("Board model selection requires local mode")
|
|
1185
|
+
async with self._registry_lock:
|
|
1186
|
+
load_lock = self._load_locks.setdefault(session_uid, asyncio.Lock())
|
|
1187
|
+
async with load_lock:
|
|
1188
|
+
runtime = self._runtimes.get(session_uid)
|
|
1189
|
+
if runtime is None:
|
|
1190
|
+
runtime = await self._load(session_uid)
|
|
1191
|
+
async with runtime.lock:
|
|
1192
|
+
if runtime.coding_session.is_running or runtime.runtime_activity == "working":
|
|
1193
|
+
raise BackendConflictError("Cannot change a model while the session is working")
|
|
1194
|
+
if runtime.persistence_task is not None:
|
|
1195
|
+
await asyncio.shield(runtime.persistence_task)
|
|
1196
|
+
previous = await self.backend.get_session(session_uid)
|
|
1197
|
+
if previous.active_provider is None or previous.active_model is None:
|
|
1198
|
+
raise BackendConflictError("Session has no model to restore")
|
|
1199
|
+
runtime.evicting = True
|
|
1200
|
+
try:
|
|
1201
|
+
await self.backend.update_session_config(
|
|
1202
|
+
session_uid,
|
|
1203
|
+
provider=provider,
|
|
1204
|
+
model=model,
|
|
1205
|
+
thinking_level=thinking_level,
|
|
1206
|
+
)
|
|
1207
|
+
except BaseException:
|
|
1208
|
+
runtime.evicting = False
|
|
1209
|
+
raise
|
|
1210
|
+
await self._evict_with_context(session_uid, force=True)
|
|
1211
|
+
try:
|
|
1212
|
+
await self._load(session_uid)
|
|
1213
|
+
except Exception:
|
|
1214
|
+
try:
|
|
1215
|
+
await self.backend.update_session_config(
|
|
1216
|
+
session_uid,
|
|
1217
|
+
provider=previous.active_provider,
|
|
1218
|
+
model=previous.active_model,
|
|
1219
|
+
thinking_level=previous.active_thinking,
|
|
1220
|
+
)
|
|
1221
|
+
await self._load(session_uid)
|
|
1222
|
+
except Exception:
|
|
1223
|
+
logger.exception(
|
|
1224
|
+
"runtime.session.model_change_rollback_failed",
|
|
1225
|
+
session_uid=session_uid,
|
|
1226
|
+
)
|
|
1227
|
+
raise
|
|
1228
|
+
logger.info(
|
|
1229
|
+
"runtime.session.model_changed",
|
|
1230
|
+
session_uid=session_uid,
|
|
1231
|
+
provider=provider,
|
|
1232
|
+
model=model,
|
|
1233
|
+
thinking_level=thinking_level,
|
|
1234
|
+
)
|
|
1235
|
+
|
|
1236
|
+
async def _evict_with_context(self, session_uid: str, *, force: bool = False) -> None:
|
|
1172
1237
|
runtime = self._runtimes.get(session_uid)
|
|
1173
|
-
if runtime is None or runtime.evicting:
|
|
1238
|
+
if runtime is None or (runtime.evicting and not force):
|
|
1174
1239
|
return
|
|
1175
1240
|
runtime.evicting = True
|
|
1176
1241
|
if runtime.lock.locked():
|
|
@@ -62,6 +62,8 @@ class ActiveSessionRuntime:
|
|
|
62
62
|
if self.persistence_task is not None:
|
|
63
63
|
await asyncio.shield(self.persistence_task)
|
|
64
64
|
async with self.lock:
|
|
65
|
+
if self.evicting:
|
|
66
|
+
raise RuntimeError("Session runtime is being reconfigured")
|
|
65
67
|
self.last_used_at = time.monotonic()
|
|
66
68
|
settled_event: TauRuntimeEvent | None = None
|
|
67
69
|
if provenance:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ms_tau_sdk-1.2.7.dev10 → ms_tau_sdk-1.2.7.dev11}/src/ms_tau_sdk/runtime/deployment_health.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|