Release v1.0.127: document executionProfile stream for HTML token streaming
All checks were successful
技能自动化发布 / release (push) Successful in 6s
All checks were successful
技能自动化发布 / release (push) Successful in 6s
This commit is contained in:
@@ -16,7 +16,7 @@ from util.constants import SKILL_SLUG
|
||||
_TEMPLATE_PLACEHOLDER_SLUG = "your-skill-slug"
|
||||
_ALLOWED_PLACEMENTS = frozenset({"toolbar", "row", "batch", "cron", "agent", "skill-detail"})
|
||||
_RESERVED_ACTION_FIELDS = frozenset({"concurrency", "locks"})
|
||||
_ALLOWED_EXECUTION_PROFILES = frozenset({"sync", "async"})
|
||||
_ALLOWED_EXECUTION_PROFILES = frozenset({"sync", "async", "stream"})
|
||||
_REQUIRED_MANIFEST_KEYS = frozenset({"schemaVersion", "skill", "actions"})
|
||||
_REQUIRED_ACTION_KEYS = frozenset(
|
||||
{"id", "label", "description", "placements", "entrypoint", "executionProfile"}
|
||||
@@ -232,7 +232,7 @@ class TestActionsManifest(unittest.TestCase):
|
||||
self.assertIn(
|
||||
profile,
|
||||
_ALLOWED_EXECUTION_PROFILES,
|
||||
msg=f"{action['id']} executionProfile must be sync|async, got {profile!r}",
|
||||
msg=f"{action['id']} executionProfile must be sync|async|stream, got {profile!r}",
|
||||
)
|
||||
|
||||
def test_schema_requires_execution_profile_and_defines_bind(self) -> None:
|
||||
@@ -240,7 +240,7 @@ class TestActionsManifest(unittest.TestCase):
|
||||
action_def = schema["$defs"]["action"]
|
||||
self.assertIn("executionProfile", action_def.get("required") or [])
|
||||
profile = action_def["properties"]["executionProfile"]
|
||||
self.assertEqual(set(profile.get("enum") or []), {"sync", "async"})
|
||||
self.assertEqual(set(profile.get("enum") or []), {"sync", "async", "stream"})
|
||||
self.assertIn("bind", schema["$defs"])
|
||||
self.assertIn("bind", action_def["properties"])
|
||||
bind_def = schema["$defs"]["bind"]
|
||||
@@ -424,14 +424,14 @@ class TestActionsManifest(unittest.TestCase):
|
||||
self.assertEqual(missing, [], msg="\n".join(missing))
|
||||
|
||||
def test_schema_allows_all_placement_execution_profile_combinations(self) -> None:
|
||||
"""POLICY-SKILL-ACTION-004:6 placements × 2 profiles 必须全部通过 Schema。"""
|
||||
"""POLICY-SKILL-ACTION-004:6 placements × 3 profiles 必须全部通过 Schema。"""
|
||||
try:
|
||||
import jsonschema
|
||||
except ImportError:
|
||||
self.fail("jsonschema is required to validate placement×executionProfile orthogonality")
|
||||
schema = _load_actions_schema()
|
||||
placements = ("toolbar", "row", "batch", "cron", "agent", "skill-detail")
|
||||
profiles = ("sync", "async")
|
||||
profiles = ("sync", "async", "stream")
|
||||
for placement in placements:
|
||||
for profile in profiles:
|
||||
action: dict = {
|
||||
|
||||
@@ -1382,12 +1382,12 @@ class TestPolicySkillAction001(unittest.TestCase):
|
||||
"action.properties.executionProfile missing",
|
||||
),
|
||||
)
|
||||
self.assertEqual(set(profile.get("enum") or []), {"sync", "async"})
|
||||
self.assertEqual(set(profile.get("enum") or []), {"sync", "async", "stream"})
|
||||
|
||||
def test_actions_md_documents_execution_profile(self) -> None:
|
||||
path = os.path.join(get_skill_root(), "references", "ACTIONS.md")
|
||||
text = _read_text(path)
|
||||
for marker in ("executionProfile", "async", "任务中心", "SKILL_ACTION_RUNTIME"):
|
||||
for marker in ("executionProfile", "async", "stream", "任务中心", "SKILL_ACTION_RUNTIME"):
|
||||
self.assertIn(
|
||||
marker,
|
||||
text,
|
||||
@@ -1407,7 +1407,7 @@ class TestPolicySkillAction001(unittest.TestCase):
|
||||
for action in manifest.get("actions") or []:
|
||||
action_id = action.get("id", "?")
|
||||
profile = action.get("executionProfile")
|
||||
if profile not in ("sync", "async"):
|
||||
if profile not in ("sync", "async", "stream"):
|
||||
offenders.append(f"{action_id}: executionProfile={profile!r}")
|
||||
self.assertEqual(
|
||||
offenders,
|
||||
@@ -1415,7 +1415,8 @@ class TestPolicySkillAction001(unittest.TestCase):
|
||||
msg=_policy_msg(
|
||||
"POLICY-SKILL-ACTION-001",
|
||||
"assets/actions.json",
|
||||
"every action must set executionProfile to sync|async:\n" + "\n".join(offenders),
|
||||
"every action must set executionProfile to sync|async|stream:\n"
|
||||
+ "\n".join(offenders),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1469,7 +1470,10 @@ class TestPolicySkillAction002(unittest.TestCase):
|
||||
"executionProfile must be in action.required",
|
||||
),
|
||||
)
|
||||
self.assertEqual(set(action["properties"]["executionProfile"].get("enum") or []), {"sync", "async"})
|
||||
self.assertEqual(
|
||||
set(action["properties"]["executionProfile"].get("enum") or []),
|
||||
{"sync", "async", "stream"},
|
||||
)
|
||||
|
||||
def test_manifest_actions_declare_execution_profile(self) -> None:
|
||||
manifest = _load_actions_json(get_skill_root())
|
||||
@@ -1478,7 +1482,7 @@ class TestPolicySkillAction002(unittest.TestCase):
|
||||
offenders: list[str] = []
|
||||
for action in manifest.get("actions") or []:
|
||||
profile = action.get("executionProfile")
|
||||
if profile not in ("sync", "async"):
|
||||
if profile not in ("sync", "async", "stream"):
|
||||
offenders.append(f"{action.get('id', '?')}: {profile!r}")
|
||||
self.assertEqual(
|
||||
offenders,
|
||||
@@ -1486,7 +1490,8 @@ class TestPolicySkillAction002(unittest.TestCase):
|
||||
msg=_policy_msg(
|
||||
"POLICY-SKILL-ACTION-002",
|
||||
"assets/actions.json",
|
||||
"every action must set executionProfile to sync|async:\n" + "\n".join(offenders),
|
||||
"every action must set executionProfile to sync|async|stream:\n"
|
||||
+ "\n".join(offenders),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1588,7 +1593,7 @@ class TestPolicySkillAction004(unittest.TestCase):
|
||||
|
||||
def test_runtime_doc_states_orthogonality(self) -> None:
|
||||
text = _read_text(os.path.join(get_skill_root(), "development", "SKILL_ACTION_RUNTIME.md"))
|
||||
for marker in ("正交", "sync|async", "toolbar"):
|
||||
for marker in ("正交", "sync|async|stream", "toolbar"):
|
||||
self.assertIn(
|
||||
marker,
|
||||
text,
|
||||
|
||||
@@ -24,7 +24,7 @@ def _platform_kit_meets_template_minimum() -> bool:
|
||||
return version_ge(installed, PLATFORM_KIT_MIN_VERSION)
|
||||
|
||||
|
||||
def _run_main(args: list[str], timeout: int = 15) -> subprocess.CompletedProcess[str]:
|
||||
def _run_main(args: list[str], timeout: int = 60) -> subprocess.CompletedProcess[str]:
|
||||
root = get_skill_root()
|
||||
main_py = os.path.join(root, "scripts", "main.py")
|
||||
env = os.environ.copy()
|
||||
|
||||
Reference in New Issue
Block a user