plan-manager-client-dev 0.2.186__py3-none-any.whl
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.
- plan_manager_client/__init__.py +10 -0
- plan_manager_client/_version.py +58 -0
- plan_manager_client/authoring_diagnostics.py +137 -0
- plan_manager_client/client.py +75 -0
- plan_manager_client/config.py +320 -0
- plan_manager_client/delivery/__init__.py +7 -0
- plan_manager_client/delivery/archive.py +140 -0
- plan_manager_client/delivery/atomicity.py +93 -0
- plan_manager_client/delivery/commit.py +113 -0
- plan_manager_client/delivery/destination.py +140 -0
- plan_manager_client/delivery/provenance.py +88 -0
- plan_manager_client/delivery/upload.py +118 -0
- plan_manager_client/dispatch.py +380 -0
- plan_manager_client/export_fetch_chunks.py +166 -0
- plan_manager_client/export_fetch_request.py +88 -0
- plan_manager_client/export_fetch_unpack.py +149 -0
- plan_manager_client/export_fetch_verify.py +101 -0
- plan_manager_client/facade_agent_config_mixin.py +224 -0
- plan_manager_client/facade_bug_project_mixin.py +202 -0
- plan_manager_client/facade_context_gate_mixin.py +303 -0
- plan_manager_client/facade_entity_common_mixin.py +38 -0
- plan_manager_client/facade_hrs_file_mixin.py +206 -0
- plan_manager_client/facade_plan_hrs_mixin.py +200 -0
- plan_manager_client/facade_runtime_mixin/__init__.py +11 -0
- plan_manager_client/facade_runtime_mixin/authoring_part.py +442 -0
- plan_manager_client/facade_runtime_mixin/facade.py +380 -0
- plan_manager_client/facade_runtime_mixin/overlay_part.py +192 -0
- plan_manager_client/facade_step_graph_mixin.py +158 -0
- plan_manager_client/id_rule.py +115 -0
- plan_manager_client/info_walker.py +133 -0
- plan_manager_client/scenario_runtime.py +65 -0
- plan_manager_client/server_api.py +427 -0
- plan_manager_client/server_api_mutating.py +105 -0
- plan_manager_client_dev-0.2.186.dist-info/METADATA +10 -0
- plan_manager_client_dev-0.2.186.dist-info/RECORD +37 -0
- plan_manager_client_dev-0.2.186.dist-info/WHEEL +5 -0
- plan_manager_client_dev-0.2.186.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Export production request and archive reference resolution (Path B).
|
|
2
|
+
|
|
3
|
+
Nothing on the plan_manager command surface enumerates an export: plan_export reports a
|
|
4
|
+
COUNT of files written, never their names. The whole export tree is therefore delivered as
|
|
5
|
+
ONE archive under one known name, and this module obtains the reference to it: it drives the
|
|
6
|
+
queue-bound export production to completion, then asks the synchronous archive command to
|
|
7
|
+
pack the tree it just wrote, and returns the archive's name, size and declared digest. No
|
|
8
|
+
archive byte is read here, and no file list is requested, derived, or guessed.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from typing import Any, Protocol
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SupportsExportProduction(Protocol):
|
|
18
|
+
"""The two calls this module needs from a client facade."""
|
|
19
|
+
|
|
20
|
+
async def plan_export(
|
|
21
|
+
self, plan: str, revision: str | None = None, include_step_uuids: bool = False
|
|
22
|
+
) -> dict[str, Any]:
|
|
23
|
+
...
|
|
24
|
+
|
|
25
|
+
async def export_archive(self, plan: str) -> dict[str, Any]:
|
|
26
|
+
...
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
class ExportArchiveRef:
|
|
31
|
+
"""The reference to one archive holding a whole export tree.
|
|
32
|
+
|
|
33
|
+
Attributes:
|
|
34
|
+
name: The archive's plan-relative name, to be passed to the byte source as-is.
|
|
35
|
+
size_bytes: The archive's size in bytes as the server reported it.
|
|
36
|
+
sha256: The hex sha256 digest of the WHOLE archive, declared by the server.
|
|
37
|
+
file_count: The number of export-tree files packed into the archive.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
name: str
|
|
41
|
+
size_bytes: int
|
|
42
|
+
sha256: str
|
|
43
|
+
file_count: int
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def request_export_archive(
|
|
47
|
+
client: SupportsExportProduction,
|
|
48
|
+
plan: str,
|
|
49
|
+
revision: str | None = None,
|
|
50
|
+
include_step_uuids: bool = False,
|
|
51
|
+
) -> ExportArchiveRef:
|
|
52
|
+
"""Produce a plan's export tree and obtain the reference to its archive.
|
|
53
|
+
|
|
54
|
+
The export production call is queue-bound and is driven to completion by the client
|
|
55
|
+
facade's queued-command auto-polling before the archive is requested. The archive call
|
|
56
|
+
is synchronous and takes no revision of its own: it packs whatever tree the export
|
|
57
|
+
production call just wrote.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
client: An object exposing the plan_export and export_archive coroutines.
|
|
61
|
+
plan: The plan identifier whose export tree is produced and archived.
|
|
62
|
+
revision: Optional revision passed to the export production call only; when None
|
|
63
|
+
that call uses its own default revision selection.
|
|
64
|
+
include_step_uuids: When True the export descriptors carry step_uuid (bug 62cff4e4
|
|
65
|
+
part b); forwarded to plan_export only when True.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
The ExportArchiveRef naming exactly one archive file, with its size, declared
|
|
69
|
+
whole-file digest, and packed-file count.
|
|
70
|
+
"""
|
|
71
|
+
export_params: dict[str, Any] = {"plan": plan, "revision": revision}
|
|
72
|
+
if include_step_uuids:
|
|
73
|
+
export_params["include_step_uuids"] = True
|
|
74
|
+
await client.plan_export(**export_params)
|
|
75
|
+
response = await client.export_archive(plan=plan)
|
|
76
|
+
return ExportArchiveRef(
|
|
77
|
+
name=str(response["archive"]),
|
|
78
|
+
size_bytes=int(response["size_bytes"]),
|
|
79
|
+
sha256=str(response["sha256"]),
|
|
80
|
+
file_count=int(response["file_count"]),
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
__all__ = [
|
|
85
|
+
"ExportArchiveRef",
|
|
86
|
+
"SupportsExportProduction",
|
|
87
|
+
"request_export_archive",
|
|
88
|
+
]
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""Local unpack of the verified export archive, and the retrieval report (Path B).
|
|
2
|
+
|
|
3
|
+
The whole export tree arrives as one gzip-compressed tar whose entries carry paths relative
|
|
4
|
+
to the plan's export directory. This module expands it onto the caller's filesystem so every
|
|
5
|
+
file reappears byte-for-byte under its original name and relative position, and reports what
|
|
6
|
+
landed. The archive's digest is verified before this module runs; the duty here is boundary
|
|
7
|
+
safety: every entry is checked BEFORE anything is written, so an archive that would escape
|
|
8
|
+
the destination is refused whole rather than leaving a partial tree behind.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import io
|
|
14
|
+
import tarfile
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Sequence
|
|
18
|
+
|
|
19
|
+
from plan_manager_client.export_fetch_verify import VerifiedFile
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ExportUnpackError(RuntimeError):
|
|
23
|
+
"""Raised when an archive cannot be unpacked safely.
|
|
24
|
+
|
|
25
|
+
Covers an entry whose path would resolve outside the destination, an entry that is
|
|
26
|
+
neither a regular file nor a directory, and an archive whose bytes are not a readable
|
|
27
|
+
gzip tar. It names only the offending relative entry path: it never carries
|
|
28
|
+
connection, credential, or server-side path information.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, entry: str, detail: str) -> None:
|
|
32
|
+
super().__init__(f"cannot unpack archive entry {entry!r}: {detail}")
|
|
33
|
+
self.entry = entry
|
|
34
|
+
self.detail = detail
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(frozen=True)
|
|
38
|
+
class RetrievalReport:
|
|
39
|
+
"""What the local fetch delivered and what it did not.
|
|
40
|
+
|
|
41
|
+
Attributes:
|
|
42
|
+
unpacked: The relative paths written beneath the destination, in archive order.
|
|
43
|
+
not_retrieved: A description per item that was not retrieved, naming the stage
|
|
44
|
+
at which it failed. Empty when the whole tree was delivered.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
unpacked: tuple[str, ...]
|
|
48
|
+
not_retrieved: tuple[str, ...]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _resolved_within(destination: Path, entry_name: str) -> Path:
|
|
52
|
+
"""Resolve an entry path under the destination, refusing any escape.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
destination: The already-resolved destination directory.
|
|
56
|
+
entry_name: The archive entry's relative path.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
The resolved target path, guaranteed to lie inside destination.
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
ExportUnpackError: If the entry is absolute or resolves outside destination.
|
|
63
|
+
"""
|
|
64
|
+
if entry_name.startswith("/") or Path(entry_name).is_absolute():
|
|
65
|
+
raise ExportUnpackError(entry_name, "entry path is absolute")
|
|
66
|
+
target = (destination / entry_name).resolve()
|
|
67
|
+
if target != destination and destination not in target.parents:
|
|
68
|
+
raise ExportUnpackError(entry_name, "entry path would escape the destination")
|
|
69
|
+
return target
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def unpack_verified_archive(
|
|
73
|
+
archive: VerifiedFile,
|
|
74
|
+
destination: str | Path,
|
|
75
|
+
) -> list[str]:
|
|
76
|
+
"""Expand a verified gzip-tar archive under destination, preserving relative paths.
|
|
77
|
+
|
|
78
|
+
Every entry is validated before any byte is written, so a refusal leaves nothing
|
|
79
|
+
behind. Entries are reproduced under their original names and relative positions.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
archive: The verified archive, carrying its plan-relative name and bytes.
|
|
83
|
+
destination: The local directory under which the tree is reproduced; it is
|
|
84
|
+
created if absent.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
The relative paths of the files written, in archive order.
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
ExportUnpackError: If the bytes are not a readable gzip tar, or any entry is
|
|
91
|
+
absolute, escapes the destination, or is neither a regular file nor a
|
|
92
|
+
directory.
|
|
93
|
+
"""
|
|
94
|
+
root = Path(destination).resolve()
|
|
95
|
+
try:
|
|
96
|
+
with tarfile.open(fileobj=io.BytesIO(archive.content), mode="r:gz") as tar:
|
|
97
|
+
members = tar.getmembers()
|
|
98
|
+
for member in members:
|
|
99
|
+
if not (member.isfile() or member.isdir()):
|
|
100
|
+
raise ExportUnpackError(
|
|
101
|
+
member.name, "entry is neither a regular file nor a directory"
|
|
102
|
+
)
|
|
103
|
+
_resolved_within(root, member.name)
|
|
104
|
+
|
|
105
|
+
root.mkdir(parents=True, exist_ok=True)
|
|
106
|
+
written: list[str] = []
|
|
107
|
+
for member in members:
|
|
108
|
+
target = _resolved_within(root, member.name)
|
|
109
|
+
if member.isdir():
|
|
110
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
continue
|
|
112
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
113
|
+
extracted = tar.extractfile(member)
|
|
114
|
+
if extracted is None:
|
|
115
|
+
raise ExportUnpackError(member.name, "entry carries no readable content")
|
|
116
|
+
with extracted:
|
|
117
|
+
target.write_bytes(extracted.read())
|
|
118
|
+
written.append(member.name)
|
|
119
|
+
except tarfile.TarError as error:
|
|
120
|
+
raise ExportUnpackError(archive.filename, f"archive is not a readable gzip tar: {error}") from error
|
|
121
|
+
return written
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def build_retrieval_report(
|
|
125
|
+
unpacked: Sequence[str],
|
|
126
|
+
not_retrieved: Sequence[str] = (),
|
|
127
|
+
) -> RetrievalReport:
|
|
128
|
+
"""Build the report of what the local fetch delivered.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
unpacked: The relative paths written beneath the destination.
|
|
132
|
+
not_retrieved: Descriptions of what was not retrieved, each naming the stage at
|
|
133
|
+
which it failed; empty when the whole tree was delivered.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
The RetrievalReport carrying both sets.
|
|
137
|
+
"""
|
|
138
|
+
return RetrievalReport(
|
|
139
|
+
unpacked=tuple(unpacked),
|
|
140
|
+
not_retrieved=tuple(not_retrieved),
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
__all__ = [
|
|
145
|
+
"ExportUnpackError",
|
|
146
|
+
"RetrievalReport",
|
|
147
|
+
"build_retrieval_report",
|
|
148
|
+
"unpack_verified_archive",
|
|
149
|
+
]
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Whole-file digest verification gate for Path B export retrieval.
|
|
2
|
+
|
|
3
|
+
Nothing retrieved from the server may reach the caller's filesystem before its whole-file
|
|
4
|
+
sha256 has been recomputed locally and matched against the digest the server declared for
|
|
5
|
+
that file. This module is that gate: it turns a reassembled buffer into a verified file, or
|
|
6
|
+
raises the delivery contract's distinct integrity error. The error is deliberately its own
|
|
7
|
+
type so that a digest mismatch is never confused with a transport or protocol failure.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import hashlib
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from typing import Iterable
|
|
15
|
+
|
|
16
|
+
from plan_manager_client.export_fetch_chunks import ReassembledFile
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ExportIntegrityError(RuntimeError):
|
|
20
|
+
"""Raised when a reassembled file's sha256 does not match its declared digest.
|
|
21
|
+
|
|
22
|
+
This is the distinct integrity error of the delivery contract: it aborts retrieval of
|
|
23
|
+
the offending file and is raised for no other kind of failure. It names only the
|
|
24
|
+
plan-relative file name and the two digests: it never carries connection, credential,
|
|
25
|
+
or server-side path information.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, filename: str, expected_sha256: str, actual_sha256: str) -> None:
|
|
29
|
+
super().__init__(
|
|
30
|
+
f"integrity check failed for {filename!r}: "
|
|
31
|
+
f"expected sha256 {expected_sha256}, computed {actual_sha256}"
|
|
32
|
+
)
|
|
33
|
+
self.filename = filename
|
|
34
|
+
self.expected_sha256 = expected_sha256
|
|
35
|
+
self.actual_sha256 = actual_sha256
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass(frozen=True)
|
|
39
|
+
class VerifiedFile:
|
|
40
|
+
"""One exported file whose content matched the digest the server declared for it.
|
|
41
|
+
|
|
42
|
+
Attributes:
|
|
43
|
+
filename: The plan-relative name of the file, unchanged from retrieval.
|
|
44
|
+
content: The verified bytes of the file, eligible for persistence.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
filename: str
|
|
48
|
+
content: bytes
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def verify_reassembled_file(reassembled: ReassembledFile) -> VerifiedFile:
|
|
52
|
+
"""Verify one reassembled file's whole-file sha256 against its declared digest.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
reassembled: The in-memory file carrying the server-declared digest.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
The VerifiedFile, eligible for persistence, when the digests match.
|
|
59
|
+
|
|
60
|
+
Raises:
|
|
61
|
+
ExportIntegrityError: When the computed digest differs from the declared one.
|
|
62
|
+
"""
|
|
63
|
+
actual_sha256 = hashlib.sha256(reassembled.content).hexdigest()
|
|
64
|
+
if actual_sha256 != reassembled.declared_sha256:
|
|
65
|
+
raise ExportIntegrityError(
|
|
66
|
+
reassembled.filename, reassembled.declared_sha256, actual_sha256
|
|
67
|
+
)
|
|
68
|
+
return VerifiedFile(filename=reassembled.filename, content=reassembled.content)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def verify_reassembled_files(
|
|
72
|
+
reassembled: Iterable[ReassembledFile],
|
|
73
|
+
) -> tuple[list[VerifiedFile], list[ExportIntegrityError]]:
|
|
74
|
+
"""Verify every reassembled file independently, collecting both outcomes.
|
|
75
|
+
|
|
76
|
+
A mismatch on one file does not stop the others from being verified, so the caller
|
|
77
|
+
can report precisely which files passed and which did not.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
reassembled: The in-memory files to verify.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
A tuple of the files that verified and the integrity errors raised for those
|
|
84
|
+
that did not, each list in the order the inputs were given.
|
|
85
|
+
"""
|
|
86
|
+
verified: list[VerifiedFile] = []
|
|
87
|
+
failures: list[ExportIntegrityError] = []
|
|
88
|
+
for item in reassembled:
|
|
89
|
+
try:
|
|
90
|
+
verified.append(verify_reassembled_file(item))
|
|
91
|
+
except ExportIntegrityError as error:
|
|
92
|
+
failures.append(error)
|
|
93
|
+
return verified, failures
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
__all__ = [
|
|
97
|
+
"ExportIntegrityError",
|
|
98
|
+
"VerifiedFile",
|
|
99
|
+
"verify_reassembled_file",
|
|
100
|
+
"verify_reassembled_files",
|
|
101
|
+
]
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"""Agent-configuration data-layer command-family facade mixin (CR-5a: tool/toolset/role/provider/model/role-model-binding/invocation-profile entities and their resolve commands).
|
|
2
|
+
|
|
3
|
+
Author: Vasiliy Zdanovskiy
|
|
4
|
+
email: vasilyvz@gmail.com
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AgentConfigCommandsMixin:
|
|
13
|
+
"""One method per plan_manager command in the CR-5a agent-configuration data-layer family.
|
|
14
|
+
|
|
15
|
+
Covers the seven entity families introduced by CR-5a -- tool (C-001), toolset
|
|
16
|
+
(C-002) plus its ordered membership, role (C-003), provider (C-004), model
|
|
17
|
+
(C-005), role-model binding (C-006), and invocation profile (C-008) -- together
|
|
18
|
+
with the three resolve commands that read the level-indirected configuration for
|
|
19
|
+
a concrete plan/step/role target: role_model_resolve (C-006), step_assignment_resolve
|
|
20
|
+
(C-007), and invocation_profile_resolve (C-008). Assumes it is mixed into a
|
|
21
|
+
class that also inherits plan_manager_client.dispatch._CommandDispatchMixin,
|
|
22
|
+
which supplies the coroutine
|
|
23
|
+
async def _call(self, command: str, params: dict[str, Any] | None = None) -> Any
|
|
24
|
+
used by every method below.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
async def tool_create(self, **params: Any) -> Any:
|
|
28
|
+
"""Create a new tool instrument record (C-001): a server reference, a command name, and a pinned option set."""
|
|
29
|
+
return await self._call("tool_create", params)
|
|
30
|
+
|
|
31
|
+
async def tool_get(self, **params: Any) -> Any:
|
|
32
|
+
"""Retrieve a single tool instrument record (C-001) by its tool identifier."""
|
|
33
|
+
return await self._call("tool_get", params)
|
|
34
|
+
|
|
35
|
+
async def tool_update(self, **params: Any) -> Any:
|
|
36
|
+
"""Patch the mutable fields of an existing tool instrument record (C-001) in place."""
|
|
37
|
+
return await self._call("tool_update", params)
|
|
38
|
+
|
|
39
|
+
async def tool_list(self, **params: Any) -> Any:
|
|
40
|
+
"""List a paginated page of tool instrument records (C-001) filtered by name."""
|
|
41
|
+
return await self._call("tool_list", params)
|
|
42
|
+
|
|
43
|
+
async def tool_delete(self, **params: Any) -> Any:
|
|
44
|
+
"""Delete a tool instrument record (C-001): soft by default, hard=true gated by the inbound-reference integrity check, dry_run previews."""
|
|
45
|
+
return await self._call("tool_delete", params)
|
|
46
|
+
|
|
47
|
+
async def toolset_create(self, **params: Any) -> Any:
|
|
48
|
+
"""Create a new toolset record (C-002): a named, ordered set of tool references describing the equipment list of one kind of work."""
|
|
49
|
+
return await self._call("toolset_create", params)
|
|
50
|
+
|
|
51
|
+
async def toolset_get(self, **params: Any) -> Any:
|
|
52
|
+
"""Retrieve a single toolset record (C-002) by its toolset identifier."""
|
|
53
|
+
return await self._call("toolset_get", params)
|
|
54
|
+
|
|
55
|
+
async def toolset_update(self, **params: Any) -> Any:
|
|
56
|
+
"""Patch the mutable fields of an existing toolset record (C-002) in place."""
|
|
57
|
+
return await self._call("toolset_update", params)
|
|
58
|
+
|
|
59
|
+
async def toolset_list(self, **params: Any) -> Any:
|
|
60
|
+
"""List a paginated page of toolset records (C-002) filtered by name."""
|
|
61
|
+
return await self._call("toolset_list", params)
|
|
62
|
+
|
|
63
|
+
async def toolset_delete(self, **params: Any) -> Any:
|
|
64
|
+
"""Delete a toolset record (C-002): soft by default, hard=true gated by the inbound-reference integrity check, dry_run previews."""
|
|
65
|
+
return await self._call("toolset_delete", params)
|
|
66
|
+
|
|
67
|
+
async def toolset_member_add(self, **params: Any) -> Any:
|
|
68
|
+
"""Add an ordered tool reference to a toolset (C-002 uses C-001): attaches one tool_uuid at a given position without embedding the Tool record."""
|
|
69
|
+
return await self._call("toolset_member_add", params)
|
|
70
|
+
|
|
71
|
+
async def toolset_member_remove(self, **params: Any) -> Any:
|
|
72
|
+
"""Remove (soft-delete) one ordered tool-reference membership from a toolset (C-002 uses C-001)."""
|
|
73
|
+
return await self._call("toolset_member_remove", params)
|
|
74
|
+
|
|
75
|
+
async def toolset_member_get(self, **params: Any) -> Any:
|
|
76
|
+
"""Read one toolset membership by its id (parameters passed through; the server validates them)."""
|
|
77
|
+
return await self._call("toolset_member_get", params)
|
|
78
|
+
|
|
79
|
+
async def toolset_member_list(self, **params: Any) -> Any:
|
|
80
|
+
"""List toolset memberships with filters and pagination (parameters passed through; the server validates them)."""
|
|
81
|
+
return await self._call("toolset_member_list", params)
|
|
82
|
+
|
|
83
|
+
async def toolset_member_delete(self, **params: Any) -> Any:
|
|
84
|
+
"""Delete a toolset membership: mark by default, hard=true removes a marked membership, dry_run previews (parameters passed through; the server validates them)."""
|
|
85
|
+
return await self._call("toolset_member_delete", params)
|
|
86
|
+
|
|
87
|
+
async def role_create(self, **params: Any) -> Any:
|
|
88
|
+
"""Create a new role record (C-003): a first-class stored entity naming who the agent is."""
|
|
89
|
+
return await self._call("role_create", params)
|
|
90
|
+
|
|
91
|
+
async def role_get(self, **params: Any) -> Any:
|
|
92
|
+
"""Retrieve a single role record (C-003) by its role identifier."""
|
|
93
|
+
return await self._call("role_get", params)
|
|
94
|
+
|
|
95
|
+
async def role_update(self, **params: Any) -> Any:
|
|
96
|
+
"""Patch the mutable description field of an existing role record (C-003) in place."""
|
|
97
|
+
return await self._call("role_update", params)
|
|
98
|
+
|
|
99
|
+
async def role_list(self, **params: Any) -> Any:
|
|
100
|
+
"""List a paginated page of role records (C-003)."""
|
|
101
|
+
return await self._call("role_list", params)
|
|
102
|
+
|
|
103
|
+
async def role_delete(self, **params: Any) -> Any:
|
|
104
|
+
"""Delete a role record (C-003): soft by default, hard=true gated by the inbound-reference integrity check, dry_run previews."""
|
|
105
|
+
return await self._call("role_delete", params)
|
|
106
|
+
|
|
107
|
+
async def provider_create(self, **params: Any) -> Any:
|
|
108
|
+
"""Create a new provider record (C-004): the source that serves a model, carrying its type, hardware ownership, activity status, and billing notes."""
|
|
109
|
+
return await self._call("provider_create", params)
|
|
110
|
+
|
|
111
|
+
async def provider_get(self, **params: Any) -> Any:
|
|
112
|
+
"""Retrieve a single provider record (C-004) by its provider identifier."""
|
|
113
|
+
return await self._call("provider_get", params)
|
|
114
|
+
|
|
115
|
+
async def provider_update(self, **params: Any) -> Any:
|
|
116
|
+
"""Patch the mutable fields of an existing provider record (C-004) in place."""
|
|
117
|
+
return await self._call("provider_update", params)
|
|
118
|
+
|
|
119
|
+
async def provider_list(self, **params: Any) -> Any:
|
|
120
|
+
"""List a paginated page of provider records (C-004) filtered by type and status."""
|
|
121
|
+
return await self._call("provider_list", params)
|
|
122
|
+
|
|
123
|
+
async def provider_delete(self, **params: Any) -> Any:
|
|
124
|
+
"""Delete a provider record (C-004): soft by default, hard=true gated by the inbound-reference integrity check, dry_run previews."""
|
|
125
|
+
return await self._call("provider_delete", params)
|
|
126
|
+
|
|
127
|
+
async def provider_set_status(self, **params: Any) -> Any:
|
|
128
|
+
"""Switch a provider's activity status in a single call (C-004): the dedicated switching-axis operation, distinct from the general provider_update."""
|
|
129
|
+
return await self._call("provider_set_status", params)
|
|
130
|
+
|
|
131
|
+
async def model_create(self, **params: Any) -> Any:
|
|
132
|
+
"""Create a new invocable model record (C-005): name, provider reference, capability level, and execution mode."""
|
|
133
|
+
return await self._call("model_create", params)
|
|
134
|
+
|
|
135
|
+
async def model_get(self, **params: Any) -> Any:
|
|
136
|
+
"""Retrieve a single invocable model record (C-005) by its model identifier."""
|
|
137
|
+
return await self._call("model_get", params)
|
|
138
|
+
|
|
139
|
+
async def model_update(self, **params: Any) -> Any:
|
|
140
|
+
"""Patch the mutable fields of an existing invocable model record (C-005) in place."""
|
|
141
|
+
return await self._call("model_update", params)
|
|
142
|
+
|
|
143
|
+
async def model_list(self, **params: Any) -> Any:
|
|
144
|
+
"""List a paginated page of invocable model records (C-005) filtered by provider, level, and execution mode."""
|
|
145
|
+
return await self._call("model_list", params)
|
|
146
|
+
|
|
147
|
+
async def model_delete(self, **params: Any) -> Any:
|
|
148
|
+
"""Delete an invocable model record (C-005): soft by default, hard=true gated by the inbound-reference integrity check, dry_run previews."""
|
|
149
|
+
return await self._call("model_delete", params)
|
|
150
|
+
|
|
151
|
+
async def role_model_binding_create(self, **params: Any) -> Any:
|
|
152
|
+
"""Create a role-model level binding record (C-006) for the given role and required model level."""
|
|
153
|
+
return await self._call("role_model_binding_create", params)
|
|
154
|
+
|
|
155
|
+
async def role_model_binding_get(self, **params: Any) -> Any:
|
|
156
|
+
"""Retrieve a single role-model binding record (C-006) by its binding identifier."""
|
|
157
|
+
return await self._call("role_model_binding_get", params)
|
|
158
|
+
|
|
159
|
+
async def role_model_binding_update(self, **params: Any) -> Any:
|
|
160
|
+
"""Patch the mutable fields of an existing role-model binding record (C-006) in place."""
|
|
161
|
+
return await self._call("role_model_binding_update", params)
|
|
162
|
+
|
|
163
|
+
async def role_model_binding_list(self, **params: Any) -> Any:
|
|
164
|
+
"""List a paginated page of role-model binding records (C-006) filtered by role."""
|
|
165
|
+
return await self._call("role_model_binding_list", params)
|
|
166
|
+
|
|
167
|
+
async def role_model_binding_delete(self, **params: Any) -> Any:
|
|
168
|
+
"""Delete a role-model binding record (C-006): soft by default, hard=true gated by the inbound-reference integrity check, dry_run previews."""
|
|
169
|
+
return await self._call("role_model_binding_delete", params)
|
|
170
|
+
|
|
171
|
+
async def invocation_profile_create(self, **params: Any) -> Any:
|
|
172
|
+
"""Create an invocation profile runtime-configuration record (C-008) for the given scope."""
|
|
173
|
+
return await self._call("invocation_profile_create", params)
|
|
174
|
+
|
|
175
|
+
async def invocation_profile_get(self, **params: Any) -> Any:
|
|
176
|
+
"""Retrieve a single invocation profile record (C-008) by its profile identifier."""
|
|
177
|
+
return await self._call("invocation_profile_get", params)
|
|
178
|
+
|
|
179
|
+
async def invocation_profile_update(self, **params: Any) -> Any:
|
|
180
|
+
"""Patch the mutable informational fields of an existing invocation profile record (C-008) in place."""
|
|
181
|
+
return await self._call("invocation_profile_update", params)
|
|
182
|
+
|
|
183
|
+
async def invocation_profile_list(self, **params: Any) -> Any:
|
|
184
|
+
"""List a paginated page of invocation profile records (C-008) filtered by plan, scope, and role."""
|
|
185
|
+
return await self._call("invocation_profile_list", params)
|
|
186
|
+
|
|
187
|
+
async def invocation_profile_delete(self, **params: Any) -> Any:
|
|
188
|
+
"""Delete an invocation profile record (C-008): soft by default, hard=true gated by the inbound-reference integrity check, dry_run previews."""
|
|
189
|
+
return await self._call("invocation_profile_delete", params)
|
|
190
|
+
|
|
191
|
+
async def step_assignment_create(self, **params: Any) -> Any:
|
|
192
|
+
"""Create a step assignment runtime record (C-007) for the given scope."""
|
|
193
|
+
return await self._call("step_assignment_create", params)
|
|
194
|
+
|
|
195
|
+
async def step_assignment_get(self, **params: Any) -> Any:
|
|
196
|
+
"""Retrieve a single step assignment record (C-007) by its assignment identifier."""
|
|
197
|
+
return await self._call("step_assignment_get", params)
|
|
198
|
+
|
|
199
|
+
async def step_assignment_update(self, **params: Any) -> Any:
|
|
200
|
+
"""Patch the mutable fields of an existing step assignment record (C-007) in place."""
|
|
201
|
+
return await self._call("step_assignment_update", params)
|
|
202
|
+
|
|
203
|
+
async def step_assignment_list(self, **params: Any) -> Any:
|
|
204
|
+
"""List a paginated page of step assignment records (C-007) filtered by plan, scope, and role."""
|
|
205
|
+
return await self._call("step_assignment_list", params)
|
|
206
|
+
|
|
207
|
+
async def step_assignment_delete(self, **params: Any) -> Any:
|
|
208
|
+
"""Delete a step assignment record (C-007): soft by default, hard=true gated by the inbound-reference integrity check, dry_run previews."""
|
|
209
|
+
return await self._call("step_assignment_delete", params)
|
|
210
|
+
|
|
211
|
+
async def role_model_resolve(self, **params: Any) -> Any:
|
|
212
|
+
"""Resolve the effective (provider, model) for a role from active providers, explicit model bindings, and the manual role-model level relation (C-006)."""
|
|
213
|
+
return await self._call("role_model_resolve", params)
|
|
214
|
+
|
|
215
|
+
async def step_assignment_resolve(self, **params: Any) -> Any:
|
|
216
|
+
"""Resolve the effective per-step role and toolset assignment along the six-scope specificity ladder (C-007)."""
|
|
217
|
+
return await self._call("step_assignment_resolve", params)
|
|
218
|
+
|
|
219
|
+
async def invocation_profile_resolve(self, **params: Any) -> Any:
|
|
220
|
+
"""Resolve the effective invocation profile along the six-scope specificity ladder (C-008)."""
|
|
221
|
+
return await self._call("invocation_profile_resolve", params)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
__all__ = ["AgentConfigCommandsMixin"]
|