cemaf 0.1.0__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.
Files changed (166) hide show
  1. cemaf/__init__.py +34 -0
  2. cemaf/agents/__init__.py +63 -0
  3. cemaf/agents/base.py +191 -0
  4. cemaf/agents/factories.py +141 -0
  5. cemaf/agents/protocols.py +220 -0
  6. cemaf/blueprint/__init__.py +31 -0
  7. cemaf/blueprint/builder.py +260 -0
  8. cemaf/blueprint/factories.py +109 -0
  9. cemaf/blueprint/mock.py +38 -0
  10. cemaf/blueprint/protocols.py +113 -0
  11. cemaf/blueprint/rules.py +264 -0
  12. cemaf/blueprint/schema.py +188 -0
  13. cemaf/cache/__init__.py +52 -0
  14. cemaf/cache/decorators.py +153 -0
  15. cemaf/cache/factories.py +116 -0
  16. cemaf/cache/mock.py +140 -0
  17. cemaf/cache/protocols.py +154 -0
  18. cemaf/cache/stores.py +101 -0
  19. cemaf/citation/__init__.py +34 -0
  20. cemaf/citation/factories.py +121 -0
  21. cemaf/citation/mock.py +44 -0
  22. cemaf/citation/models.py +244 -0
  23. cemaf/citation/protocols.py +116 -0
  24. cemaf/citation/rules.py +211 -0
  25. cemaf/citation/tracker.py +206 -0
  26. cemaf/config/__init__.py +31 -0
  27. cemaf/config/factories.py +66 -0
  28. cemaf/config/loader.py +217 -0
  29. cemaf/config/mock.py +86 -0
  30. cemaf/config/protocols.py +423 -0
  31. cemaf/context/__init__.py +81 -0
  32. cemaf/context/advanced_compiler.py +278 -0
  33. cemaf/context/algorithm.py +350 -0
  34. cemaf/context/budget.py +94 -0
  35. cemaf/context/compiler.py +262 -0
  36. cemaf/context/context.py +286 -0
  37. cemaf/context/factories.py +271 -0
  38. cemaf/context/merge.py +553 -0
  39. cemaf/context/patch.py +353 -0
  40. cemaf/context/paths.py +266 -0
  41. cemaf/context/protocols.py +137 -0
  42. cemaf/context/source.py +390 -0
  43. cemaf/core/__init__.py +63 -0
  44. cemaf/core/constants.py +67 -0
  45. cemaf/core/enums.py +72 -0
  46. cemaf/core/execution.py +393 -0
  47. cemaf/core/registry.py +429 -0
  48. cemaf/core/result.py +123 -0
  49. cemaf/core/storage.py +203 -0
  50. cemaf/core/types.py +24 -0
  51. cemaf/core/utils.py +106 -0
  52. cemaf/evals/__init__.py +48 -0
  53. cemaf/evals/composite.py +297 -0
  54. cemaf/evals/evaluators.py +351 -0
  55. cemaf/evals/factories.py +119 -0
  56. cemaf/evals/llm_judge.py +215 -0
  57. cemaf/evals/protocols.py +233 -0
  58. cemaf/evals/semantic.py +166 -0
  59. cemaf/events/__init__.py +45 -0
  60. cemaf/events/bus.py +96 -0
  61. cemaf/events/factories.py +65 -0
  62. cemaf/events/mock.py +177 -0
  63. cemaf/events/notifiers.py +207 -0
  64. cemaf/events/protocols.py +271 -0
  65. cemaf/generation/__init__.py +49 -0
  66. cemaf/generation/factories.py +219 -0
  67. cemaf/generation/mock.py +350 -0
  68. cemaf/generation/protocols.py +545 -0
  69. cemaf/ingestion/__init__.py +47 -0
  70. cemaf/ingestion/adapters.py +413 -0
  71. cemaf/ingestion/factories.py +195 -0
  72. cemaf/ingestion/protocols.py +155 -0
  73. cemaf/llm/__init__.py +65 -0
  74. cemaf/llm/factories.py +132 -0
  75. cemaf/llm/mock.py +147 -0
  76. cemaf/llm/protocols.py +360 -0
  77. cemaf/llm/response_utils.py +376 -0
  78. cemaf/llm/tiktoken_estimator.py +136 -0
  79. cemaf/mcp/__init__.py +54 -0
  80. cemaf/mcp/adapter.py +766 -0
  81. cemaf/mcp/bridges/__init__.py +7 -0
  82. cemaf/mcp/bridges/prompt_bridge.py +87 -0
  83. cemaf/mcp/bridges/resource_bridge.py +69 -0
  84. cemaf/mcp/bridges/tool_bridge.py +59 -0
  85. cemaf/mcp/factories.py +71 -0
  86. cemaf/mcp/mock.py +82 -0
  87. cemaf/mcp/protocols.py +404 -0
  88. cemaf/mcp/transport/__init__.py +8 -0
  89. cemaf/mcp/transport/base.py +60 -0
  90. cemaf/mcp/transport/sse.py +60 -0
  91. cemaf/mcp/transport/stdio.py +52 -0
  92. cemaf/mcp/transport/websocket.py +44 -0
  93. cemaf/mcp/types.py +138 -0
  94. cemaf/memory/__init__.py +69 -0
  95. cemaf/memory/base.py +272 -0
  96. cemaf/memory/factories.py +130 -0
  97. cemaf/memory/protocols.py +237 -0
  98. cemaf/moderation/__init__.py +62 -0
  99. cemaf/moderation/factories.py +65 -0
  100. cemaf/moderation/gates.py +407 -0
  101. cemaf/moderation/mock.py +519 -0
  102. cemaf/moderation/pipeline.py +397 -0
  103. cemaf/moderation/protocols.py +181 -0
  104. cemaf/moderation/rules.py +443 -0
  105. cemaf/observability/__init__.py +38 -0
  106. cemaf/observability/factories.py +226 -0
  107. cemaf/observability/protocols.py +93 -0
  108. cemaf/observability/run_logger.py +406 -0
  109. cemaf/observability/simple.py +116 -0
  110. cemaf/orchestration/__init__.py +24 -0
  111. cemaf/orchestration/checkpointer.py +289 -0
  112. cemaf/orchestration/dag.py +552 -0
  113. cemaf/orchestration/deep_agent.py +412 -0
  114. cemaf/orchestration/executor.py +723 -0
  115. cemaf/orchestration/factories.py +112 -0
  116. cemaf/orchestration/protocols.py +141 -0
  117. cemaf/persistence/__init__.py +38 -0
  118. cemaf/persistence/entities.py +149 -0
  119. cemaf/persistence/factories.py +190 -0
  120. cemaf/persistence/protocols.py +151 -0
  121. cemaf/replay/__init__.py +15 -0
  122. cemaf/replay/factories.py +51 -0
  123. cemaf/replay/protocols.py +44 -0
  124. cemaf/replay/replayer.py +317 -0
  125. cemaf/resilience/__init__.py +97 -0
  126. cemaf/resilience/circuit_breaker.py +227 -0
  127. cemaf/resilience/decorators.py +163 -0
  128. cemaf/resilience/factories.py +188 -0
  129. cemaf/resilience/protocols.py +269 -0
  130. cemaf/resilience/rate_limiter.py +173 -0
  131. cemaf/resilience/retry.py +197 -0
  132. cemaf/retrieval/__init__.py +51 -0
  133. cemaf/retrieval/factories.py +205 -0
  134. cemaf/retrieval/hybrid.py +171 -0
  135. cemaf/retrieval/memory_store.py +169 -0
  136. cemaf/retrieval/protocols.py +231 -0
  137. cemaf/scheduler/__init__.py +41 -0
  138. cemaf/scheduler/executor.py +198 -0
  139. cemaf/scheduler/factories.py +65 -0
  140. cemaf/scheduler/mock.py +145 -0
  141. cemaf/scheduler/protocols.py +208 -0
  142. cemaf/scheduler/triggers.py +283 -0
  143. cemaf/skills/__init__.py +65 -0
  144. cemaf/skills/base.py +149 -0
  145. cemaf/skills/factories.py +114 -0
  146. cemaf/skills/protocols.py +248 -0
  147. cemaf/skills/registry.py +114 -0
  148. cemaf/streaming/__init__.py +24 -0
  149. cemaf/streaming/factories.py +65 -0
  150. cemaf/streaming/protocols.py +239 -0
  151. cemaf/streaming/sse.py +96 -0
  152. cemaf/tools/__init__.py +71 -0
  153. cemaf/tools/base.py +229 -0
  154. cemaf/tools/factories.py +128 -0
  155. cemaf/tools/protocols.py +275 -0
  156. cemaf/tools/registry.py +156 -0
  157. cemaf/validation/__init__.py +48 -0
  158. cemaf/validation/factories.py +85 -0
  159. cemaf/validation/mock.py +109 -0
  160. cemaf/validation/pipeline.py +128 -0
  161. cemaf/validation/protocols.py +160 -0
  162. cemaf/validation/rules.py +324 -0
  163. cemaf-0.1.0.dist-info/METADATA +371 -0
  164. cemaf-0.1.0.dist-info/RECORD +166 -0
  165. cemaf-0.1.0.dist-info/WHEEL +4 -0
  166. cemaf-0.1.0.dist-info/licenses/LICENSE +21 -0
cemaf/__init__.py ADDED
@@ -0,0 +1,34 @@
1
+ """
2
+ CEMAF - Context Engineering Multi-Agent Framework
3
+
4
+ A pluggable, modular framework for building AI agent systems with:
5
+ - Tools: Atomic, stateless functions
6
+ - Skills: Composable capabilities using tools
7
+ - Agents: Autonomous entities with goals and memory
8
+ - DeepAgent: Hierarchical orchestration with context isolation
9
+ - Dynamic DAGs: Runtime workflow composition
10
+
11
+ Author: Hikuri Bado Chinca (@drchinca)
12
+ Email: chincadr@gmail.com
13
+ """
14
+
15
+ __version__ = "0.1.0"
16
+
17
+ from cemaf.core.enums import AgentStatus, MemoryScope, NodeType, RunStatus
18
+ from cemaf.core.types import JSON, AgentID, NodeID, RunID, SkillID, ToolID
19
+
20
+ __all__ = [
21
+ "__version__",
22
+ # Types
23
+ "JSON",
24
+ "AgentID",
25
+ "NodeID",
26
+ "RunID",
27
+ "SkillID",
28
+ "ToolID",
29
+ # Enums
30
+ "AgentStatus",
31
+ "MemoryScope",
32
+ "NodeType",
33
+ "RunStatus",
34
+ ]
@@ -0,0 +1,63 @@
1
+ """
2
+ Agents module - Autonomous entities with goals and memory.
3
+
4
+ Agents are the HIGHEST level of the execution hierarchy:
5
+ - AUTONOMOUS: Make decisions about which skills to use
6
+ - GOAL-ORIENTED: Work toward completing objectives
7
+ - MEMORY-ENABLED: Maintain state across interactions
8
+ - CONTEXT-AWARE: Have isolated context scope
9
+
10
+ Agents USE Skills (which USE Tools).
11
+
12
+ ## Configuration
13
+
14
+ Settings for this module are defined in AgentsSettings.
15
+
16
+ Environment Variables:
17
+ CEMAF_AGENTS_MAX_ITERATIONS: Max agent iterations (default: 10)
18
+ CEMAF_AGENTS_MAX_SKILL_CALLS: Max skill calls per agent (default: 50)
19
+ CEMAF_AGENTS_TIMEOUT_SECONDS: Agent timeout in seconds (default: 300.0)
20
+ CEMAF_AGENTS_DEEP_AGENT_MAX_DEPTH: Max depth for DeepAgent (default: 5)
21
+ CEMAF_AGENTS_DEEP_AGENT_MAX_CHILDREN: Max children per node (default: 10)
22
+ CEMAF_AGENTS_DEEP_AGENT_MAX_TOTAL: Max total agents (default: 100)
23
+ CEMAF_AGENTS_DEEP_AGENT_TIMEOUT_SECONDS: DeepAgent timeout (default: 600.0)
24
+
25
+ ## Usage
26
+
27
+ Protocol-based (Recommended):
28
+ >>> from cemaf.agents import Agent, AgentContext, AgentResult, AgentState
29
+ >>> from cemaf.core.types import AgentID
30
+ >>>
31
+ >>> class MyAgent:
32
+ ... @property
33
+ ... def id(self) -> AgentID:
34
+ ... return AgentID("my_agent")
35
+ ...
36
+ ... @property
37
+ ... def description(self) -> str:
38
+ ... return "My custom agent"
39
+ ...
40
+ ... @property
41
+ ... def skills(self) -> tuple:
42
+ ... return ()
43
+ ...
44
+ ... async def run(self, goal, context: AgentContext) -> AgentResult:
45
+ ... return AgentResult.ok("result", AgentState())
46
+
47
+ ## Extension
48
+
49
+ Agent implementations are discovered via protocols. No registration needed.
50
+ Simply implement the Agent protocol and your agent is compatible with all
51
+ CEMAF orchestration systems.
52
+
53
+ See cemaf.agents.protocols.Agent for the protocol definition.
54
+ """
55
+
56
+ from cemaf.agents.protocols import Agent, AgentContext, AgentResult, AgentState
57
+
58
+ __all__ = [
59
+ "Agent",
60
+ "AgentState",
61
+ "AgentResult",
62
+ "AgentContext",
63
+ ]
cemaf/agents/base.py ADDED
@@ -0,0 +1,191 @@
1
+ """
2
+ Agent base classes.
3
+
4
+ An Agent is:
5
+ - Autonomous entity with a goal
6
+ - Uses skills to accomplish tasks
7
+ - Maintains state/memory
8
+ - Can make decisions
9
+
10
+ ## Best Practices
11
+
12
+ ### Using VectorStore and Memory Stores
13
+
14
+ When skills or agents retrieve from vector stores or memory stores, they should:
15
+
16
+ 1. **Emit context patches** for retrieval results so downstream nodes can reuse them:
17
+
18
+ ```python
19
+ # In a skill or agent:
20
+ retrieved_docs = await vector_store.search(query, top_k=5)
21
+
22
+ # Patch retrieval results into context
23
+ context = context.set("retrieved_docs", retrieved_docs)
24
+ # Or use ContextPatch explicitly for better provenance tracking
25
+ ```
26
+
27
+ 2. **Store retrieval metadata** (query, timestamp, scores) for debugging:
28
+
29
+ ```python
30
+ metadata = {
31
+ "query": query,
32
+ "num_results": len(results),
33
+ "top_score": results[0].score if results else None,
34
+ }
35
+ ```
36
+
37
+ 3. **Use caching** for expensive retrieval operations (see below)
38
+
39
+ ### Resilience Patterns
40
+
41
+ Use resilience decorators around expensive or flaky operations:
42
+
43
+ ```python
44
+ from cemaf.resilience import retry, circuit_breaker
45
+
46
+ class RetrievalSkill(Skill):
47
+ @retry(max_attempts=3, backoff_factor=1.5)
48
+ @circuit_breaker(failure_threshold=5, recovery_timeout=60)
49
+ async def search_vector_store(self, query: str) -> list[Document]:
50
+ # Expensive retrieval operation
51
+ return await self.vector_store.search(query)
52
+ ```
53
+
54
+ ### Caching Patterns
55
+
56
+ Use caching decorators for expensive calls (LLM, retrieval):
57
+
58
+ ```python
59
+ from cemaf.cache import cache_result
60
+
61
+ class AnalysisAgent(Agent):
62
+ @cache_result(ttl=3600) # Cache for 1 hour
63
+ async def analyze_with_llm(self, text: str) -> AnalysisResult:
64
+ # Expensive LLM call
65
+ return await self.llm.complete(...)
66
+
67
+ @cache_result(ttl=600, key_prefix="retrieval")
68
+ async def retrieve_context(self, query: str) -> list[Document]:
69
+ # Expensive retrieval
70
+ return await self.vector_store.search(query)
71
+ ```
72
+
73
+ See examples/retrieval_dag_example.py for a complete working example.
74
+ """
75
+
76
+ from abc import ABC, abstractmethod
77
+ from dataclasses import dataclass, field
78
+ from typing import Any, TypeVar
79
+
80
+ from pydantic import BaseModel, Field
81
+
82
+ from cemaf.core.enums import AgentStatus
83
+ from cemaf.core.types import JSON, AgentID
84
+ from cemaf.skills.base import Skill, SkillResult
85
+
86
+ GoalT = TypeVar("GoalT", bound=BaseModel)
87
+ ResultT = TypeVar("ResultT")
88
+
89
+
90
+ class AgentState(BaseModel):
91
+ """Mutable state during agent execution."""
92
+
93
+ model_config = {"frozen": True}
94
+
95
+ status: AgentStatus = AgentStatus.IDLE
96
+ iteration: int = 0
97
+ skill_calls: int = 0
98
+ messages: tuple[JSON, ...] = ()
99
+ working_memory: JSON = Field(default_factory=dict)
100
+
101
+ def next(self, **updates: Any) -> AgentState:
102
+ """Create new state with updates."""
103
+ data = self.model_dump()
104
+ data.update(updates)
105
+ return AgentState(**data)
106
+
107
+
108
+ @dataclass(frozen=True)
109
+ class AgentResult[ResultT]:
110
+ """Result of agent execution with state trace."""
111
+
112
+ success: bool
113
+ output: ResultT | None = None
114
+ error: str | None = None
115
+ final_state: AgentState | None = None
116
+ skill_results: tuple[SkillResult, ...] = ()
117
+ metadata: JSON = field(default_factory=dict)
118
+
119
+ def __post_init__(self) -> None:
120
+ """Ensure trace collections remain immutable and replay-safe."""
121
+ object.__setattr__(self, "skill_results", tuple(self.skill_results))
122
+
123
+ @classmethod
124
+ def ok(cls, output: ResultT, state: AgentState) -> AgentResult[ResultT]:
125
+ return cls(success=True, output=output, final_state=state)
126
+
127
+ @classmethod
128
+ def fail(cls, error: str, state: AgentState | None = None) -> AgentResult[ResultT]:
129
+ return cls(success=False, error=error, final_state=state)
130
+
131
+
132
+ class AgentContext(BaseModel):
133
+ """Isolated context for agent execution."""
134
+
135
+ model_config = {"frozen": True}
136
+
137
+ run_id: str
138
+ agent_id: str
139
+ parent_agent_id: str | None = None
140
+ depth: int = 0
141
+ global_memory: JSON = Field(default_factory=dict)
142
+ artifacts: JSON = Field(default_factory=dict)
143
+
144
+
145
+ class Agent[GoalT: BaseModel, ResultT](ABC):
146
+ """
147
+ Abstract base class for agents.
148
+
149
+ Example:
150
+ class AnalystAgent(Agent[AnalysisGoal, AnalysisResult]):
151
+ def __init__(self, sql_skill: Skill):
152
+ self._sql = sql_skill
153
+
154
+ @property
155
+ def id(self) -> AgentID:
156
+ return AgentID("analyst")
157
+
158
+ @property
159
+ def skills(self) -> tuple[Skill, ...]:
160
+ return (self._sql,)
161
+
162
+ async def run(self, goal: AnalysisGoal, ctx: AgentContext) -> AgentResult:
163
+ state = AgentState()
164
+ result = await self._sql.execute(...)
165
+ if not result.success:
166
+ return AgentResult.fail(result.error, state)
167
+ return AgentResult.ok(AnalysisResult(data=result.data), state)
168
+ """
169
+
170
+ @property
171
+ @abstractmethod
172
+ def id(self) -> AgentID:
173
+ """Unique identifier."""
174
+ ...
175
+
176
+ @property
177
+ @abstractmethod
178
+ def description(self) -> str:
179
+ """What this agent does."""
180
+ ...
181
+
182
+ @property
183
+ @abstractmethod
184
+ def skills(self) -> tuple[Skill[Any, Any], ...]:
185
+ """Skills available to this agent."""
186
+ ...
187
+
188
+ @abstractmethod
189
+ async def run(self, goal: GoalT, context: AgentContext) -> AgentResult[ResultT]:
190
+ """Execute the agent to accomplish a goal."""
191
+ ...
@@ -0,0 +1,141 @@
1
+ """
2
+ Factory functions for agent components.
3
+
4
+ Provides convenient ways to create agent contexts and configurations
5
+ with sensible defaults while maintaining dependency injection principles.
6
+
7
+ Note:
8
+ Agents are protocol-based abstractions that users implement.
9
+ This module provides factory functions for agent contexts and configurations,
10
+ not for agent instances themselves.
11
+
12
+ Extension Point:
13
+ This module is designed for extension. Add your custom agent
14
+ implementations and register them here if needed.
15
+ """
16
+
17
+ import os
18
+
19
+ from cemaf.agents.protocols import AgentContext
20
+ from cemaf.config.protocols import Settings
21
+ from cemaf.context.context import Context
22
+ from cemaf.core.types import AgentID
23
+
24
+
25
+ def create_agent_context(
26
+ agent_id: AgentID,
27
+ context: Context | None = None,
28
+ max_iterations: int = 10,
29
+ max_skill_calls: int = 50,
30
+ timeout_seconds: float = 300.0,
31
+ ) -> AgentContext:
32
+ """
33
+ Factory for AgentContext with sensible defaults.
34
+
35
+ Args:
36
+ agent_id: Unique agent identifier
37
+ context: Base context (creates new if None)
38
+ max_iterations: Maximum agent iterations
39
+ max_skill_calls: Maximum skill calls per agent
40
+ timeout_seconds: Agent execution timeout
41
+
42
+ Returns:
43
+ Configured AgentContext instance
44
+
45
+ Example:
46
+ # Basic agent context
47
+ from cemaf.core.types import AgentID
48
+ agent_ctx = create_agent_context(AgentID("my_agent"))
49
+
50
+ # With custom limits
51
+ agent_ctx = create_agent_context(
52
+ AgentID("my_agent"),
53
+ max_iterations=20,
54
+ timeout_seconds=600.0
55
+ )
56
+ """
57
+ base_context = context or Context.empty()
58
+
59
+ return AgentContext(
60
+ agent_id=agent_id,
61
+ context=base_context,
62
+ max_iterations=max_iterations,
63
+ max_skill_calls=max_skill_calls,
64
+ timeout_seconds=timeout_seconds,
65
+ )
66
+
67
+
68
+ def create_agent_context_from_config(
69
+ agent_id: AgentID,
70
+ context: Context | None = None,
71
+ settings: Settings | None = None,
72
+ ) -> AgentContext:
73
+ """
74
+ Create AgentContext from environment configuration.
75
+
76
+ Reads from environment variables:
77
+ - CEMAF_AGENTS_MAX_ITERATIONS: Max iterations (default: 10)
78
+ - CEMAF_AGENTS_MAX_SKILL_CALLS: Max skill calls (default: 50)
79
+ - CEMAF_AGENTS_TIMEOUT_SECONDS: Timeout in seconds (default: 300.0)
80
+
81
+ Args:
82
+ agent_id: Unique agent identifier
83
+ context: Base context (creates new if None)
84
+
85
+ Returns:
86
+ Configured AgentContext instance
87
+
88
+ Example:
89
+ # From environment
90
+ from cemaf.core.types import AgentID
91
+ agent_ctx = create_agent_context_from_config(AgentID("my_agent"))
92
+ """
93
+ max_iterations = int(os.getenv("CEMAF_AGENTS_MAX_ITERATIONS", "10"))
94
+ max_skill_calls = int(os.getenv("CEMAF_AGENTS_MAX_SKILL_CALLS", "50"))
95
+ timeout_seconds = float(os.getenv("CEMAF_AGENTS_TIMEOUT_SECONDS", "300.0"))
96
+
97
+ return create_agent_context(
98
+ agent_id=agent_id,
99
+ context=context,
100
+ max_iterations=max_iterations,
101
+ max_skill_calls=max_skill_calls,
102
+ timeout_seconds=timeout_seconds,
103
+ )
104
+
105
+
106
+ # ============================================================================
107
+ # EXTEND HERE: Bring Your Own Agent Implementations
108
+ # ============================================================================
109
+ # This is the extension point for custom agent implementations.
110
+ #
111
+ # To add your own agent type:
112
+ # 1. Implement the Agent protocol (see cemaf.agents.protocols)
113
+ # 2. Add a factory function below
114
+ # 3. Optionally add a config-based factory
115
+ #
116
+ # Example (ReAct Agent):
117
+ # def create_react_agent(
118
+ # agent_id: AgentID,
119
+ # llm: LLMClient,
120
+ # skills: tuple[Skill, ...],
121
+ # ) -> Agent:
122
+ # from your_package import ReActAgent
123
+ # return ReActAgent(agent_id=agent_id, llm=llm, skills=skills)
124
+ #
125
+ # def create_react_agent_from_config(
126
+ # agent_id: AgentID,
127
+ # skills: tuple[Skill, ...],
128
+ # , settings: Settings | None = None) -> Agent:
129
+ # from cemaf.llm.factories import create_llm_client_from_config
130
+ # llm = create_llm_client_from_config()
131
+ # return create_react_agent(agent_id, llm, skills)
132
+ #
133
+ # Example (Planning Agent):
134
+ # def create_planning_agent(
135
+ # agent_id: AgentID,
136
+ # llm: LLMClient,
137
+ # planner: Planner,
138
+ # ) -> Agent:
139
+ # from your_package import PlanningAgent
140
+ # return PlanningAgent(agent_id=agent_id, llm=llm, planner=planner)
141
+ # ============================================================================
@@ -0,0 +1,220 @@
1
+ """
2
+ Agent protocols - Abstract interfaces for autonomous agents.
3
+
4
+ Supports:
5
+ - Goal-oriented execution
6
+ - Skill composition
7
+ - State management
8
+ - Iterative reasoning
9
+
10
+ ## Protocol-First Design
11
+
12
+ This module provides structural typing via @runtime_checkable protocols.
13
+ Any class that implements the required methods is automatically compatible.
14
+
15
+ Extension Point:
16
+ Custom agent implementations should implement these protocols rather than
17
+ inheriting from ABC classes. This allows maximum flexibility and follows
18
+ CEMAF's dependency injection principles.
19
+
20
+ Example:
21
+ >>> from cemaf.agents.protocols import Agent
22
+ >>> from cemaf.core.types import AgentID
23
+ >>>
24
+ >>> class MyCustomAgent:
25
+ ... @property
26
+ ... def id(self) -> AgentID:
27
+ ... return AgentID("my_agent")
28
+ ...
29
+ ... @property
30
+ ... def description(self) -> str:
31
+ ... return "My custom agent"
32
+ ...
33
+ ... @property
34
+ ... def skills(self) -> tuple[Any, ...]:
35
+ ... return ()
36
+ ...
37
+ ... async def run(self, goal: Any, context: AgentContext) -> AgentResult:
38
+ ... return AgentResult.ok("result", AgentState())
39
+ >>>
40
+ >>> # No inheritance needed - structural compatibility!
41
+ >>> assert isinstance(MyCustomAgent(), Agent)
42
+ """
43
+
44
+ from typing import Any, Protocol, runtime_checkable
45
+
46
+ # Re-export data classes from base (these are not changed)
47
+ from cemaf.agents.base import AgentContext, AgentResult, AgentState
48
+ from cemaf.core.types import AgentID
49
+
50
+ __all__ = [
51
+ "Agent",
52
+ "AgentContext",
53
+ "AgentResult",
54
+ "AgentState",
55
+ ]
56
+
57
+
58
+ @runtime_checkable
59
+ class Agent[GoalT, ResultT](Protocol):
60
+ """
61
+ Protocol for agent implementations.
62
+
63
+ An Agent is an autonomous entity that:
64
+ - Has a unique identifier
65
+ - Has a clear purpose/description
66
+ - Composes skills to accomplish goals
67
+ - Maintains state during execution
68
+ - Returns structured results
69
+
70
+ This is a protocol, not an ABC. Any class with these methods is compatible.
71
+
72
+ Type Parameters:
73
+ GoalT: Type of goal this agent accepts (typically a Pydantic model)
74
+ ResultT: Type of result this agent produces
75
+
76
+ Extension Point:
77
+ Implement this protocol for custom agents:
78
+ - ReAct agents (reasoning + acting)
79
+ - Planning agents (goal decomposition)
80
+ - Conversational agents (dialogue management)
81
+ - Domain-specific agents (SQL, code analysis, etc.)
82
+
83
+ Example:
84
+ >>> class AnalystAgent:
85
+ ... def __init__(self, sql_skill):
86
+ ... self._sql_skill = sql_skill
87
+ ...
88
+ ... @property
89
+ ... def id(self) -> AgentID:
90
+ ... return AgentID("analyst")
91
+ ...
92
+ ... @property
93
+ ... def description(self) -> str:
94
+ ... return "Analyzes data using SQL queries"
95
+ ...
96
+ ... @property
97
+ ... def skills(self) -> tuple[Skill, ...]:
98
+ ... return (self._sql_skill,)
99
+ ...
100
+ ... async def run(self, goal: AnalysisGoal, ctx: AgentContext) -> AgentResult[AnalysisResult]:
101
+ ... state = AgentState()
102
+ ... result = await self._sql_skill.execute(goal.query, ctx)
103
+ ... if not result.success:
104
+ ... return AgentResult.fail(result.error, state)
105
+ ... return AgentResult.ok(AnalysisResult(data=result.output), state)
106
+ >>>
107
+ >>> # Automatically compatible - no inheritance!
108
+ >>> agent = AnalystAgent(sql_skill)
109
+ >>> assert isinstance(agent, Agent)
110
+
111
+ Best Practices:
112
+ 1. **Dependency Injection**: Accept all dependencies in __init__
113
+ 2. **Immutable State**: Return new AgentState, never mutate
114
+ 3. **Result Pattern**: Always return AgentResult[T], never raise
115
+ 4. **Skill Composition**: Use skills for reusable capabilities
116
+ 5. **Context Isolation**: Each agent has isolated AgentContext
117
+
118
+ See Also:
119
+ - cemaf.agents.base.Agent (deprecated ABC, use this protocol instead)
120
+ - cemaf.skills.protocols.Skill (skill protocol)
121
+ - cemaf.orchestration.deep_agent.DeepAgent (hierarchical agent orchestration)
122
+ """
123
+
124
+ @property
125
+ def id(self) -> AgentID:
126
+ """
127
+ Unique identifier for this agent.
128
+
129
+ Returns:
130
+ AgentID instance (typically AgentID("name"))
131
+
132
+ Example:
133
+ >>> @property
134
+ >>> def id(self) -> AgentID:
135
+ ... return AgentID("my_agent")
136
+ """
137
+ ...
138
+
139
+ @property
140
+ def description(self) -> str:
141
+ """
142
+ Human-readable description of what this agent does.
143
+
144
+ Returns:
145
+ Clear, concise description of agent's purpose
146
+
147
+ Example:
148
+ >>> @property
149
+ >>> def description(self) -> str:
150
+ ... return "Analyzes data and generates reports"
151
+ """
152
+ ...
153
+
154
+ @property
155
+ def skills(self) -> tuple[Any, ...]:
156
+ """
157
+ Skills available to this agent.
158
+
159
+ Skills are composable capabilities that agents use to accomplish goals.
160
+ This tuple defines which skills this agent has access to.
161
+
162
+ Returns:
163
+ Tuple of Skill instances (empty tuple if no skills)
164
+
165
+ Example:
166
+ >>> @property
167
+ >>> def skills(self) -> tuple[Skill, ...]:
168
+ ... return (self._sql_skill, self._analysis_skill)
169
+ """
170
+ ...
171
+
172
+ async def run(self, goal: GoalT, context: AgentContext) -> AgentResult[ResultT]:
173
+ """
174
+ Execute the agent to accomplish a goal.
175
+
176
+ This is the main entry point for agent execution. The agent should:
177
+ 1. Validate the goal
178
+ 2. Plan approach (if needed)
179
+ 3. Execute skills to accomplish goal
180
+ 4. Track state throughout execution
181
+ 5. Return structured result
182
+
183
+ Args:
184
+ goal: Goal to accomplish (typically a Pydantic model)
185
+ context: Execution context with run metadata, parent info, memory
186
+
187
+ Returns:
188
+ AgentResult containing:
189
+ - success: Whether goal was accomplished
190
+ - output: The result data (if successful)
191
+ - error: Error message (if failed)
192
+ - final_state: Final agent state
193
+ - skill_results: Trace of skill executions
194
+ - metadata: Additional execution metadata
195
+
196
+ Example:
197
+ >>> async def run(self, goal: AnalysisGoal, context: AgentContext) -> AgentResult[AnalysisResult]:
198
+ ... state = AgentState()
199
+ ...
200
+ ... # Execute skills
201
+ ... result = await self._sql_skill.execute(goal.query, context)
202
+ ... state = state.next(skill_calls=1)
203
+ ...
204
+ ... if not result.success:
205
+ ... return AgentResult.fail(result.error, state)
206
+ ...
207
+ ... # Process results
208
+ ... analysis = self._analyze_data(result.output)
209
+ ... state = state.next(status=AgentStatus.COMPLETED)
210
+ ...
211
+ ... return AgentResult.ok(AnalysisResult(data=analysis), state)
212
+
213
+ Best Practices:
214
+ - Always return AgentResult, never raise exceptions
215
+ - Track iterations and skill calls in state
216
+ - Include metadata for debugging/observability
217
+ - Use context patches to share data with downstream nodes
218
+ - Check cancellation tokens if long-running
219
+ """
220
+ ...
@@ -0,0 +1,31 @@
1
+ """
2
+ Blueprint module for defining scene blueprints.
3
+
4
+ Blueprints describe the structure and requirements for content generation scenes.
5
+ """
6
+
7
+ from cemaf.blueprint.builder import BlueprintBuilder
8
+ from cemaf.blueprint.mock import MockBlueprintRegistry, create_mock_blueprint
9
+ from cemaf.blueprint.rules import BlueprintContentRule, BlueprintSchemaRule
10
+ from cemaf.blueprint.schema import (
11
+ Blueprint,
12
+ Participant,
13
+ SceneGoal,
14
+ StyleGuide,
15
+ )
16
+
17
+ __all__ = [
18
+ # Schema models
19
+ "Blueprint",
20
+ "Participant",
21
+ "SceneGoal",
22
+ "StyleGuide",
23
+ # Builder
24
+ "BlueprintBuilder",
25
+ # Validation rules
26
+ "BlueprintContentRule",
27
+ "BlueprintSchemaRule",
28
+ # Mocks for testing
29
+ "MockBlueprintRegistry",
30
+ "create_mock_blueprint",
31
+ ]