mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-27 13:40:37 +00:00
* feat(skills): add guarded evolution host APIs * docs(agents): avoid growing saturated guidance chains * fix(skills): address mutation host review findings * fix(skills): order name fence before projection lock * fix(skills): preserve composite toggle lock order * fix(skills): address catalog and pagination review feedback * docs: keep subagent guidance within merged instruction budget --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
162 lines
4.4 KiB
Python
162 lines
4.4 KiB
Python
"""Host-owned, conditional updates of existing custom skills; no learning policy."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Protocol
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AssetRevision:
|
|
incarnation_id: str
|
|
mutation_seq: int
|
|
content_digest: str
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class SkillRevisionView:
|
|
target_ref: str
|
|
owner_id: str
|
|
name: str
|
|
revision: AssetRevision
|
|
content: str
|
|
enabled: bool
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class MutationCapabilities:
|
|
operations: tuple[str, ...]
|
|
protocol_version: str = "skill-mutations-v1"
|
|
max_main_bytes: int = 131072
|
|
max_package_bytes: int = 16777216
|
|
max_package_files: int = 256
|
|
max_sources: int = 20
|
|
max_pending_proposals: int = 20
|
|
max_model_scan_files: int = 32
|
|
max_model_scan_bytes: int = 1048576
|
|
max_model_scan_file_bytes: int = 131072
|
|
max_concurrent_scans: int = 4
|
|
max_owner_plugin_concurrent_scans: int = 2
|
|
max_owner_plugin_scans_per_hour: int = 20
|
|
check_timeout_seconds: int = 120
|
|
proposal_ttl_seconds: int = 86400
|
|
check_ttl_seconds: int = 900
|
|
rollback_ttl_seconds: int = 2592000
|
|
topology: str = "posix-single-host-local-filesystem"
|
|
|
|
def __post_init__(self):
|
|
object.__setattr__(self, "operations", tuple(self.operations))
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Proposal:
|
|
proposal_id: str
|
|
owner_id: str
|
|
target_ref: str
|
|
name: str
|
|
base_revision: AssetRevision
|
|
candidate_hash: str
|
|
state: str
|
|
expires_at: str
|
|
source_refs: tuple[str, ...]
|
|
operation_id: str | None = None
|
|
|
|
def __post_init__(self):
|
|
object.__setattr__(self, "source_refs", tuple(self.source_refs))
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class BundleFile:
|
|
path: str
|
|
content: bytes
|
|
sha256: str
|
|
executable: bool
|
|
|
|
def __post_init__(self):
|
|
object.__setattr__(self, "content", bytes(self.content))
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ProposalBundle:
|
|
proposal_id: str
|
|
baseline: tuple[BundleFile, ...]
|
|
candidate: tuple[BundleFile, ...]
|
|
base_revision: AssetRevision
|
|
candidate_hash: str
|
|
|
|
def __post_init__(self):
|
|
object.__setattr__(self, "baseline", tuple(self.baseline))
|
|
object.__setattr__(self, "candidate", tuple(self.candidate))
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class HostCheckResult:
|
|
proposal_id: str
|
|
decision: str
|
|
candidate_hash: str
|
|
base_revision: AssetRevision
|
|
policy_version: str
|
|
expires_at: str
|
|
reason_code: str
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AssessmentRef:
|
|
candidate_hash: str
|
|
base_revision: AssetRevision
|
|
evaluator: str
|
|
evaluator_version: str
|
|
report_id: str
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Operation:
|
|
operation_id: str
|
|
owner_id: str
|
|
name: str
|
|
publication: str
|
|
views: str
|
|
before_revision: AssetRevision
|
|
after_revision: AssetRevision
|
|
generation: int
|
|
proposal_id: str | None = None
|
|
reverts_operation_id: str | None = None
|
|
error_code: str | None = None
|
|
superseded_by_generation: int | None = None
|
|
|
|
|
|
class SkillMutationService(Protocol):
|
|
@property
|
|
def capabilities(self) -> MutationCapabilities:
|
|
raise NotImplementedError
|
|
|
|
async def read_skill(self, *, source_ref: str, name: str) -> SkillRevisionView:
|
|
raise NotImplementedError
|
|
|
|
async def stage(self, *, source_refs: tuple[str, ...], target_ref: str, expected_revision: AssetRevision, content: str, idempotency_key: str) -> Proposal:
|
|
raise NotImplementedError
|
|
|
|
async def get_proposal(self, *, proposal_id: str) -> Proposal:
|
|
raise NotImplementedError
|
|
|
|
async def read_proposal_bundle(self, *, proposal_id: str, max_bytes: int = 33554432) -> ProposalBundle:
|
|
raise NotImplementedError
|
|
|
|
async def check(self, *, proposal_id: str) -> HostCheckResult:
|
|
raise NotImplementedError
|
|
|
|
async def commit(self, *, proposal_id: str, idempotency_key: str, assessment_ref: AssessmentRef | None = None) -> Operation:
|
|
raise NotImplementedError
|
|
|
|
async def discard(self, *, proposal_id: str) -> Proposal:
|
|
raise NotImplementedError
|
|
|
|
async def revert(self, *, operation_id: str, expected_current_revision: AssetRevision, idempotency_key: str) -> Operation:
|
|
raise NotImplementedError
|
|
|
|
async def get_operation(self, *, operation_id: str) -> Operation:
|
|
raise NotImplementedError
|
|
|
|
async def find_operation(self, *, idempotency_key: str, method: str = "commit") -> Operation | None:
|
|
raise NotImplementedError
|