chore: initialize EverOS 1.0.0
md-first memory extraction framework for AI agents. Markdown is the single source of truth; SQLite holds state and LanceDB provides the rebuildable vector + BM25 + scalar index. The codebase follows a single-direction DDD layering (entrypoints -> service -> memory -> infra, with component / core / config cross-cutting) enforced by import-linter. Engineering surface: - Coding conventions in .claude/rules/ (path-scoped) and workflows in .claude/skills/ (/commit, /new-branch, /pr). - GitHub Actions CI runs make lint + test + integration; pre-commit mirrors the gates locally (ruff, hygiene hooks, gitlint commit-msg). - Commit messages follow Conventional Commits, enforced by gitlint. - make lint also enforces datetime two-zone discipline and OpenAPI drift.
This commit is contained in:
104
tests/unit/test_infra/test_markdown/test_mds/test_agent_skill.py
Normal file
104
tests/unit/test_infra/test_markdown/test_mds/test_agent_skill.py
Normal file
@ -0,0 +1,104 @@
|
||||
"""Tests for :class:`AgentSkillFrontmatter` — the AgentSkill schema.
|
||||
|
||||
Lives under ``test_infra`` because :class:`AgentSkillFrontmatter` itself
|
||||
lives under ``infra/.../mds`` (it carries business fields + the
|
||||
directory-shape ClassVars). The schema-agnostic chassis tests live
|
||||
under ``test_core/test_persistence/test_markdown/``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from everos.infra.persistence.markdown import AgentSkillFrontmatter
|
||||
|
||||
|
||||
def _kwargs(**overrides: object) -> dict[str, object]:
|
||||
"""Minimal valid kwargs for AgentSkillFrontmatter."""
|
||||
base: dict[str, object] = {
|
||||
"id": "skill_contract_risk_scan",
|
||||
"agent_id": "agent_zhang_legal",
|
||||
"name": "contract_risk_scan",
|
||||
"description": "Scan a contract draft for risk clauses.",
|
||||
"confidence": 0.5,
|
||||
"maturity_score": 0.5,
|
||||
}
|
||||
base.update(overrides)
|
||||
return base
|
||||
|
||||
|
||||
def test_skill_inherits_agent_scope() -> None:
|
||||
"""Skills always live under ``agents/`` — track + SCOPE_DIR confirm."""
|
||||
assert AgentSkillFrontmatter.SCOPE_DIR == "agents"
|
||||
fm = AgentSkillFrontmatter(**_kwargs()) # type: ignore[arg-type]
|
||||
assert fm.track == "agent"
|
||||
assert fm.type == "agent_skill"
|
||||
|
||||
|
||||
def test_skill_requires_name_and_description() -> None:
|
||||
"""Tier-1 prompt injection demands both fields — schema enforces."""
|
||||
bad = _kwargs()
|
||||
del bad["name"]
|
||||
with pytest.raises(ValidationError):
|
||||
AgentSkillFrontmatter(**bad) # type: ignore[arg-type]
|
||||
|
||||
bad = _kwargs()
|
||||
del bad["description"]
|
||||
with pytest.raises(ValidationError):
|
||||
AgentSkillFrontmatter(**bad) # type: ignore[arg-type]
|
||||
|
||||
|
||||
def test_skill_requires_confidence_and_maturity_score() -> None:
|
||||
"""LLM-emitted score fields are required (no default)."""
|
||||
bad = _kwargs()
|
||||
del bad["confidence"]
|
||||
with pytest.raises(ValidationError):
|
||||
AgentSkillFrontmatter(**bad) # type: ignore[arg-type]
|
||||
|
||||
bad = _kwargs()
|
||||
del bad["maturity_score"]
|
||||
with pytest.raises(ValidationError):
|
||||
AgentSkillFrontmatter(**bad) # type: ignore[arg-type]
|
||||
|
||||
|
||||
def test_skill_optional_fields_default() -> None:
|
||||
"""``source_case_ids`` defaults to empty list; ``cluster_id`` to None."""
|
||||
fm = AgentSkillFrontmatter(**_kwargs()) # type: ignore[arg-type]
|
||||
assert fm.source_case_ids == []
|
||||
assert fm.cluster_id is None
|
||||
|
||||
|
||||
def test_skill_lineage_fields_round_trip() -> None:
|
||||
"""``source_case_ids`` + ``cluster_id`` round-trip through model_dump."""
|
||||
fm = AgentSkillFrontmatter(
|
||||
**_kwargs(
|
||||
source_case_ids=["case_a", "case_b"],
|
||||
cluster_id="cl_x",
|
||||
), # type: ignore[arg-type]
|
||||
)
|
||||
dumped = fm.model_dump()
|
||||
assert dumped["source_case_ids"] == ["case_a", "case_b"]
|
||||
assert dumped["cluster_id"] == "cl_x"
|
||||
|
||||
|
||||
def test_skill_extra_fields_still_allowed() -> None:
|
||||
"""L2 system metadata (md_sha256 / last_indexed_at) rides along."""
|
||||
fm = AgentSkillFrontmatter(
|
||||
**_kwargs(
|
||||
md_sha256="deadbeef",
|
||||
last_indexed_at="2026-05-07T08:00:00Z",
|
||||
), # type: ignore[arg-type]
|
||||
)
|
||||
dumped = fm.model_dump()
|
||||
assert dumped["md_sha256"] == "deadbeef"
|
||||
assert dumped["last_indexed_at"] == "2026-05-07T08:00:00Z"
|
||||
|
||||
|
||||
def test_skill_directory_shape_classvars() -> None:
|
||||
"""Path-shape ClassVars pin the wiki layout for the writer/reader pair."""
|
||||
assert AgentSkillFrontmatter.SKILLS_CONTAINER_NAME == "skills"
|
||||
assert AgentSkillFrontmatter.SKILL_DIR_PREFIX == "skill_"
|
||||
assert AgentSkillFrontmatter.SKILL_MAIN_FILENAME == "SKILL.md"
|
||||
assert AgentSkillFrontmatter.SKILL_REFERENCES_DIR_NAME == "references"
|
||||
assert AgentSkillFrontmatter.SKILL_SCRIPTS_DIR_NAME == "scripts"
|
||||
@ -0,0 +1,30 @@
|
||||
"""Tests that every business frontmatter class reports the expected
|
||||
``path_glob()`` — the cascade scanner reads these to enumerate eligible
|
||||
files, so a wrong glob silently drops a whole kind from cascade.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from everos.infra.persistence.markdown import (
|
||||
AgentCaseDailyFrontmatter,
|
||||
AgentSkillFrontmatter,
|
||||
AtomicFactDailyFrontmatter,
|
||||
EpisodeDailyFrontmatter,
|
||||
ForesightDailyFrontmatter,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("schema", "expected"),
|
||||
[
|
||||
(EpisodeDailyFrontmatter, "*/*/users/*/episodes/episode-*.md"),
|
||||
(AtomicFactDailyFrontmatter, "*/*/users/*/.atomic_facts/atomic_fact-*.md"),
|
||||
(ForesightDailyFrontmatter, "*/*/users/*/.foresights/foresight-*.md"),
|
||||
(AgentCaseDailyFrontmatter, "*/*/agents/*/.cases/agent_case-*.md"),
|
||||
(AgentSkillFrontmatter, "*/*/agents/*/skills/skill_*/SKILL.md"),
|
||||
],
|
||||
)
|
||||
def test_path_glob(schema: type, expected: str) -> None:
|
||||
assert schema.path_glob() == expected
|
||||
71
tests/unit/test_infra/test_markdown/test_mds/test_profile.py
Normal file
71
tests/unit/test_infra/test_markdown/test_mds/test_profile.py
Normal file
@ -0,0 +1,71 @@
|
||||
"""Tests for the profile frontmatter duck-typed shape.
|
||||
|
||||
Profile schemas have no shared base class — they only need a
|
||||
``PROFILE_FILENAME`` ClassVar plus inheritance from a scope mixin. This
|
||||
test exercises that contract via a local fixture class.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import ClassVar, Literal
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from everos.core.persistence.markdown import UserScopedFrontmatter
|
||||
|
||||
|
||||
class _SampleUserProfileFM(UserScopedFrontmatter):
|
||||
"""Local fixture: a user-track profile schema."""
|
||||
|
||||
PROFILE_FILENAME: ClassVar[str] = "user.md"
|
||||
|
||||
type: Literal["sample_user_profile"] = "sample_user_profile"
|
||||
display_name: str
|
||||
bio: str
|
||||
interests: list[str] = []
|
||||
|
||||
|
||||
def test_schema_inherits_user_scope() -> None:
|
||||
fm = _SampleUserProfileFM(
|
||||
id="sample_user_profile_u_jason",
|
||||
type="sample_user_profile",
|
||||
user_id="u_jason",
|
||||
display_name="Jason",
|
||||
bio="hiker.",
|
||||
)
|
||||
assert fm.track == "user"
|
||||
assert fm.SCOPE_DIR == "users"
|
||||
|
||||
|
||||
def test_profile_filename_classvar() -> None:
|
||||
"""Path-shape ClassVar is duck-typed onto the schema directly."""
|
||||
assert _SampleUserProfileFM.PROFILE_FILENAME == "user.md"
|
||||
|
||||
|
||||
def test_requires_display_name_and_bio() -> None:
|
||||
with pytest.raises(ValidationError):
|
||||
_SampleUserProfileFM( # type: ignore[call-arg]
|
||||
id="x",
|
||||
type="sample_user_profile",
|
||||
user_id="u_jason",
|
||||
bio="missing display_name",
|
||||
)
|
||||
with pytest.raises(ValidationError):
|
||||
_SampleUserProfileFM( # type: ignore[call-arg]
|
||||
id="x",
|
||||
type="sample_user_profile",
|
||||
user_id="u_jason",
|
||||
display_name="missing bio",
|
||||
)
|
||||
|
||||
|
||||
def test_interests_default_empty() -> None:
|
||||
fm = _SampleUserProfileFM(
|
||||
id="x",
|
||||
type="sample_user_profile",
|
||||
user_id="u_jason",
|
||||
display_name="Jason",
|
||||
bio="hiker.",
|
||||
)
|
||||
assert fm.interests == []
|
||||
Reference in New Issue
Block a user